问题
I just completed a proof of concept, or so I thought, of feeding Microsoft Visual Studio 2010 some C++ code as a console program. The C++ code that compiled is given below:
#include "stdafx.h"
#include <stdio.h>
#include <Windows.h>
#include <stdlib.h>
#include <sndfile.h>
//The following libraries are related to parsing the text files
#include <iostream> //Open the file
#include <fstream> //Reading to and from files
//The following libraries are for conducting the DTW analysis
#include "dtw.h"
using namespace std;
int _tmain(int argc, _TCHAR* argv[])
{
printf("This is a test\n");
//This will be the length of the buffer used to hold samples while the program processes them.
//A SNDFILE is like FILE in a standard C library. Consequently, the sf_open_read and sf_open_write functions will return an
//SNDFILE* pointer when they successfully open the specified file.
SNDFILE* sf = NULL;
/*SF_INFO will obtain information of the file we wish to load into our program. */
SF_INFO info;
/*The following is descriptive information to obtain from wave files. These are declarations*/
int num_channels;
double num, num_items;S
double *buf;
int f, sr, c;
int i,j;
FILE *out;
/*This is where the program will open the WAV file */
info.format = 0;
sf = sf_open("C:\\Users\\GeekyOmega\\Desktop\\gameon.wav", SFM_READ, &info);
if(sf == NULL)
{
printf("Failed to open the file.\n");
getchar();
exit(-1);
}
/*Print some file information */
f = info.frames;
sr = info.samplerate;
c = info.channels;
/*Print information related to file*/
printf("frames = %d\n",f);
printf("sample rate = %d\n",sr);
printf("channels = %d\n",c);
/*Calculate and print the number of items*/
num_items = f*c;
printf("Read %lf items\n", num_items);
/*Allocate space for the data to be read*/
buf = (double *) malloc(num_items*sizeof(double));
num = sf_read_double(sf,buf,num_items);
sf_close(sf);
/*print the information*/
printf("Read %lf items\n", num);
/*Write the data to the filedata.out*/
out = fopen("filedata.txt", "w");
for(i = 0; i < num; i+=c)
{
for(j = 0; j < c; ++j)
{
fprintf(out, "%lf ", buf[i +j]);
}
fprintf(out,"\n");
}
fclose(out);
}
So next, and this is critical, I want this to work with a GUI. That is, I load in any file I want and it converts that wav file to text. I provide that code below:
#pragma once
//Libraries required for libsndfile
#include <sndfile.h>
#include <stdlib.h>
#include <stdio.h>
#include <iostream>
#include <fstream>
namespace WaveGui {
using namespace System;
using namespace System::ComponentModel;
using namespace System::Collections;
using namespace System::Windows::Forms;
using namespace System::Data;
using namespace System::Drawing;
using namespace System::Runtime::InteropServices;
using namespace std;
/// <summary>
/// Summary for Form1
/// </summary>
I edited this for readability. It was a standard MSVS2010 form. I only added a button and open file dialog.
private: System::Void button1_Click(System::Object^ sender, System::EventArgs^ e)
{
if(openFileDialog1->ShowDialog() == System::Windows::Forms::DialogResult::OK)
{
//Note: Ask Gustafson how we might free the memory for this strign
// http://support.microsoft.com/?id=311259
char* str2 = (char*)(void*)Marshal::StringToHGlobalAnsi(openFileDialog1->FileName);
SNDFILE* sf = NULL;
SF_INFO info;
/*The following is descriptive information to obtain from wave files. These are declarations*/
int num_channels;
double num, num_items;
double *buf;
int f, sr, c;
int i,j;
FILE *out;
/*This is where the program will open the WAV file */
info.format = 0;
sf = sf_open(str2, SFM_READ, &info);
if(sf == NULL)
{
exit(-1);
}
/*Print some file information */
f = info.frames;
sr = info.samplerate;
c = info.channels;
/*Calculate and print the number of items*/
num_items = f*c;
/*Allocate space for the data to be read*/
buf = (double *) malloc(num_items*sizeof(double));
num = sf_read_double(sf,buf,num_items);
sf_close(sf);
/*Write the data to the filedata.out*/
out = fopen("filedata.txt", "w");
for(i = 0; i < num; i+=c)
{
for(j = 0; j < c; ++j)
{
fprintf(out, "%lf ", buf[i +j]);
}
fprintf(out,"\n");
}
fclose(out);
}
}
};
}
In the code for the button, I convert from a system string to regular string and then try to use the C++ code above to convert my wave file to txt information. I know the conversion code works, and I know the button code works as I have tested them separately. However, my library sndfile.h really dies when I try to use it now.
The error it gives me when I added the libraries stdio.h, Windows.H, stdlib.h, iostream, fstream is as follows:
1>WaveGui.obj : error LNK2031: unable to generate p/invoke for "extern "C" int __clrcall sf_close(struct SNDFILE_tag *)" (?sf_close@@$$J0YMHPAUSNDFILE_tag@@@Z); calling convention missing in metadata
1>WaveGui.obj : error LNK2031: unable to generate p/invoke for "extern "C" __int64 __clrcall sf_read_double(struct SNDFILE_tag *,double *,__int64)" (?sf_read_double@@$$J0YM_JPAUSNDFILE_tag@@PAN_J@Z); calling convention missing in metadata
1>WaveGui.obj : error LNK2031: unable to generate p/invoke for "extern "C" struct SNDFILE_tag * __clrcall sf_open(char const *,int,struct SF_INFO *)" (?sf_open@@$$J0YMPAUSNDFILE_tag@@PBDHPAUSF_INFO@@@Z); calling convention missing in metadata
1>WaveGui.obj : warning LNK4248: unresolved typeref token (01000027) for 'SNDFILE_tag'; image may not run
1>WaveGui.obj : error LNK2028: unresolved token (0A000022) "extern "C" int __clrcall sf_close(struct SNDFILE_tag *)" (?sf_close@@$$J0YMHPAUSNDFILE_tag@@@Z) referenced in function "private: void __clrcall WaveGui::Form1::button1_Click(class System::Object ^,class System::EventArgs ^)" (?button1_Click@Form1@WaveGui@@$$FA$AAMXP$AAVObject@System@@P$AAVEventArgs@4@@Z)
1>WaveGui.obj : error LNK2028: unresolved token (0A000023) "extern "C" __int64 __clrcall sf_read_double(struct SNDFILE_tag *,double *,__int64)" (?sf_read_double@@$$J0YM_JPAUSNDFILE_tag@@PAN_J@Z) referenced in function "private: void __clrcall WaveGui::Form1::button1_Click(class System::Object ^,class System::EventArgs ^)" (?button1_Click@Form1@WaveGui@@$$FA$AAMXP$AAVObject@System@@P$AAVEventArgs@4@@Z)
1>WaveGui.obj : error LNK2028: unresolved token (0A000025) "extern "C" struct SNDFILE_tag * __clrcall sf_open(char const *,int,struct SF_INFO *)" (?sf_open@@$$J0YMPAUSNDFILE_tag@@PBDHPAUSF_INFO@@@Z) referenced in function "private: void __clrcall WaveGui::Form1::button1_Click(class System::Object ^,class System::EventArgs ^)" (?button1_Click@Form1@WaveGui@@$$FA$AAMXP$AAVObject@System@@P$AAVEventArgs@4@@Z)
1>WaveGui.obj : error LNK2019: unresolved external symbol "extern "C" int __clrcall sf_close(struct SNDFILE_tag *)" (?sf_close@@$$J0YMHPAUSNDFILE_tag@@@Z) referenced in function "private: void __clrcall WaveGui::Form1::button1_Click(class System::Object ^,class System::EventArgs ^)" (?button1_Click@Form1@WaveGui@@$$FA$AAMXP$AAVObject@System@@P$AAVEventArgs@4@@Z)
1>WaveGui.obj : error LNK2019: unresolved external symbol "extern "C" __int64 __clrcall sf_read_double(struct SNDFILE_tag *,double *,__int64)" (?sf_read_double@@$$J0YM_JPAUSNDFILE_tag@@PAN_J@Z) referenced in function "private: void __clrcall WaveGui::Form1::button1_Click(class System::Object ^,class System::EventArgs ^)" (?button1_Click@Form1@WaveGui@@$$FA$AAMXP$AAVObject@System@@P$AAVEventArgs@4@@Z)
1>WaveGui.obj : error LNK2019: unresolved external symbol "extern "C" struct SNDFILE_tag * __clrcall sf_open(char const *,int,struct SF_INFO *)" (?sf_open@@$$J0YMPAUSNDFILE_tag@@PBDHPAUSF_INFO@@@Z) referenced in function "private: void __clrcall WaveGui::Form1::button1_Click(class System::Object ^,class System::EventArgs ^)" (?button1_Click@Form1@WaveGui@@$$FA$AAMXP$AAVObject@System@@P$AAVEventArgs@4@@Z)
1>c:\users\geekyomega\documents\visual studio 2010\Projects\WaveGui\Debug\WaveGui.exe : fatal error LNK1120: 6 unresolved externals
As near as I can tell, I installed the library right. After all, it works perfectly fine with these libraries in a console situation. However, when I try to use the exact same code and libraries with my GUI form, it seems that the libraries are not playing nice with each other and as a result, I can't read my .h file right and access structs like SNDFILE.
Can someone please let me know what is going wrong? I have spent hours on this and I hope I don't have to scrap the libsndfile library. I really want to get it to work with MSVS2010, with the GUI and as far as I can tell, there is no reason this shouldn't be working. But you know what they say, computers don't lie.
As always, thanks for your patient help. GeekyOmega
回答1:
So, your console app is native code, but your GUI app is managed C++. Was that intentional, or did you intend for your GUI app to be native (Win32) code too?
I think you'll have better luck if you either go with 100% native code, or perhaps create a DLL to encapsulate your native code and call that via P/Invoke from your .NET GUI. Here's an example of using P/Invoke:
http://manski.net/2012/05/29/pinvoke-tutorial-basics-part-1/
来源:https://stackoverflow.com/questions/13189650/msvs2010-c-console-code-ported-to-msvs2010-c-gui-is-failing-why