2016-11-10 65 views
0

我有一個第三方DLL,我想在C#中編寫一個包裝,並有C++示例代碼,它的工作,但是當我嘗試調用方法在DLL中,我得到的錯誤:從C#調用方法從C#沒有任何信息,只有頭文件

無法在DLL'scard-com.dll'中找到名爲'scan'的入口點。

請幫忙指出我的問題:

這裏是樣品C++應用程序

interface ISCard_CardReaderDevices : IUnknown { 
virtual UINT __stdcall scan(void) = 0; 
virtual UINT __stdcall getDeviceCount(void) = 0; 
virtual const CHAR * __stdcall getDeviceName(UINT id) = 0; 
virtual const CHAR * __stdcall getSerialName(UINT id) = 0; 
virtual ISCard_CardReader * __stdcall connectById(UINT id) = 0; 
virtual ISCard_CardReader * __stdcall connectByName(const CHAR *name) = 0; 
virtual ISCard_CardReader * __stdcall connectBySerial(const CHAR *serial) = 0; 
virtual BOOL __stdcall disconnect(ISCard_CardReader *reader) = 0; 
virtual ISCard_SecMsg * __stdcall attachSecMsg(ISCard_CardReader *reader) = 0; 
virtual void __stdcall detachSecMsg(ISCard_SecMsg *secMsg) = 0; 
virtual ISCard_Script * __stdcall attachScript(ISCard_CardReader *reader) = 0; 
virtual void __stdcall detachScript(ISCard_Script *script) = 0; 
virtual ISCard_IsoCard * __stdcall attachIsoCardByReader(ISCard_CardReader *reader) = 0; 
virtual ISCard_IsoCard * __stdcall attachIsoCardBySecMSG(ISCard_SecMsg *secMsg) = 0; 
virtual void __stdcall detachIsoCard(ISCard_IsoCard *isocard) = 0; 
virtual ISCard_MTCOS * __stdcall attachMTCOSByReader(ISCard_CardReader *reader) = 0; 
virtual ISCard_MTCOS * __stdcall attachMTCOSBySecMSG(ISCard_SecMsg *secMsg) = 0; 
virtual void __stdcall detachMTCOS(ISCard_MTCOS *os) = 0; 
virtual ISCard_IcaoConverter * __stdcall attachIcaoConverter(void) = 0; 
virtual void __stdcall detachIcaoConverter(ISCard_IcaoConverter *icaoconv) = 0; 
virtual ISCard_ImageConverter * __stdcall attachImageConverter(void) = 0; 
virtual void __stdcall detachImageConverter(ISCard_ImageConverter *imgconv) = 0; 
#ifdef MULTIAPP_EXT 
virtual ISCard_IDLConverter * __stdcall attachIDLConverter(void) = 0; 
virtual void __stdcall detachIDLConverter(ISCard_IDLConverter *idlconv) = 0; 
virtual ISCard_sscdConverter * __stdcall attachSSCDConverter(void) = 0; 
virtual void __stdcall detachSSCDConverter(ISCard_sscdConverter *sscdconv) = 0; 
virtual ISCard_eHealthConverter * __stdcall attacheHealthConverter(void) = 0; 
virtual void __stdcall detacheHealthConverter(ISCard_eHealthConverter *eHealthconv) = 0; 
#endif // MULTIAPP_EXT 
}; 

用在我的C#項目.h文件的一部分,我加入這個類:

public class SCardWrapper 
{ 
    [DllImport("scard-com.dll", CallingConvention = CallingConvention.Cdecl)] 
    public static extern uint scan(); 

// And call it like this: 

public int listReaders() 
    { 
     try 
     { 
      uint numreaders = scan(); 
      if (numreaders < 1) 
      { 
       return 0; 
      } 
      for (int i = 0; i < numreaders; i++) 
      { 
       IntPtr iDevice = getDeviceName(uint.Parse(i.ToString())); 
       String sDevice = Marshal.PtrToStringAuto(iDevice); 
       Debug.WriteLine(string.Format("{0} : " + sDevice, i)); 
      } 
      return int.Parse(numreaders.ToString()); 
     } 
     catch 
     { 
      return -1; 
     } 
    } 
} 

但是,只要它碰到scan()方法,我就會得到上面的錯誤。任何幫助將不勝感激!

+1

你發佈的標題部分沒有'scan'。 – Chris

+0

DLL名稱中的「COM」一詞值得注意。就像標題中的聲明一樣,這是一個COM接口。不,他們不會導出這些功能。您只需添加對類型庫的引用即可。通常嵌入在DLL本身中,所以使用Project> Add Reference> Browse按鈕>選擇scard-com.dll。 –

+0

對不起,添加了錯誤的界面描述,編輯後顯示正確。 – Thys

回答

0

這種scan聲明:

public class SCardWrapper 
{ 
    [DllImport("scard-com.dll", CallingConvention = CallingConvention.Cdecl)] 
    public static extern uint scan(); 
} 

是用於從DLL scard-com.dll與名稱scan的功能的結合。在您的scard-com.dll DLL接口中檢查該功能。要做到這一點,你可以使用Dependency Walker

scan名稱可以在您的DLL中爲mangled。在這種情況下,您可以在非託管代碼中將其定義爲extern "C",或將EntryPoint = "mangled_scan_name"添加到您的PInvoke聲明中。

順便說一句,scan不是以上interface ISCard_CardReader的一部分。但是,如果它是一個班的方法,那麼與CallingConvention = CallingConvention.Cdecl不正確。

1

P/Invoke不是真的支持C++。你試圖在界面上調用一個方法,而不是C風格的函數。

有一些黑客可以讓你得到你想要的結果,但通常最好的選擇是編寫一個C++/CLI互操作庫,你可以從你的C#項目中使用它。

此外,通常,頭文件不足以正確調用本機庫。你需要文檔 - 沒有辦法來處理這樣的問題,比如「字符串緩衝區應該有多大?誰負責分配/釋放內存?當緩衝區不夠大時會發生什麼?可能的情況是什麼錯誤條件?「如果你沒有這些文檔,你可以做的事情很少,但是要享受逆向工程:)