1. 程式人生 > 其它 >C#呼叫C和C++函式的一點區別

C#呼叫C和C++函式的一點區別

最近做U800電話的二次開發,需要呼叫廠商的C函式庫來打電話,後來想加入通話錄音功能,但發現程式預設生產的WAV檔案過大,又找了個WAV轉MP3的C++函式庫程式,出了點問題。下面是轉MP3的程式介面(標頭檔案):

#ifndef _MP3ENC_H_
#define _MP3ENC_H_

int mp3_enc(const char* inWavName,int nRate,const char* outMP3Name);

#endif

按照C#呼叫非託管程式的約定,宣告一個對應的C#函式介面:

 [DllImport("mp3enc.dll", CharSet = CharSet.Ansi)]
 public static extern int mp3_enc(string inWavName, int nRate, string outMP3Name);

然後這樣呼叫改函式:

 mp3_enc(txtWavFile.Text, 32, "222.mp3");

結果出現這樣的異常資訊:

1 對 PInvoke 函式“U800Test!U800Test.Form1::mp3_enc”的呼叫導致堆疊不對稱。原因可能是託管的 PInvoke 簽名與非託管的目標籤名不匹配。請檢查 PInvoke 簽名的呼叫約定和引數與非託管的目標籤名是否匹配。

跟原來呼叫C函式庫的方法仔細對比,發現沒有區別,而C函式程式碼卻可以正常使用: 打電話的C函式介面:

USBDLL_API int _stdcall StartDial(int iDevIdx,const char* szDest);    //傳送撥號命令

對應的C#函式介面:

  [DllImport("UsbDll.dll", CharSet = CharSet.Ansi)]
  public static extern int StartDial(int iDevIdx,string szDest);

再看看C++的呼叫函式的錯誤資訊,難道是C++字串型別不一致?需要C++使用Unicode 字元?於是將C#的函式介面改成:

 [DllImport("mp3enc.dll", CharSet = CharSet.Unicode)]
public static extern int mp3_enc(string inWavName, int nRate, string outMP3Name);

結果C#程式直接崩潰,連Try....Catch.... 都沒用。

最後,在網上搜索了半天,發現有這個說法:

DllImport還有一個CallingConvention的屬性,預設值是CallingCovention.Stdcall,  此處更改成Cdecl(c/c++預設呼叫方式)就可以了。VS2010下必須得指定這個屬性才能執行, 同樣的程式碼在VS2008下卻不存在這樣的問題, 奇怪 ...

正確的C++ 函式C#呼叫介面應該是這樣:

[DllImport("mp3enc.dll", CharSet = CharSet.Ansi, CallingConvention = CallingConvention.Cdecl)]
 public static extern int mp3_enc(string inWavName, int nRate, string outMP3Name);