2011-04-02 31 views
2

我有一個用C++編寫的dll,我想從C#調用它。該函數輸出outputChar和deadChar,deadChar變量也由C++函數讀取。如何將PWCHAR傳遞到C++的C++ dll#

我試圖以不同的方式從C#中調用函數,但是所有的時間我都得到了AccessViolationException:「嘗試讀取或寫入受保護的內存,這通常表示其他內存已損壞。

C++ DLL:

extern "C" _declspec (dllexport) int convertVirtualKeyToWChar(int virtualKey, PWCHAR outputChar, PWCHAR deadChar); 

C#代碼1:

[DllImport("keylib.dll")] 
static extern int convertVirtualKeyToWChar(int virtualKey, 
       StringBuilder output, 
       StringBuilder deadchar); 

C#代碼2:

static extern int convertVirtualKeyToWChar(int virtualKey, 
      out char output, 
      ref char deadchar); 

回答

5

注:兩個PWCHAR參數你功能convertVirtualKeyToWChar不明確。它們可以是指向單個WCHAR的指針或指向WCHAR字符串的指針。鑑於函數和參數的名稱,這個答案假定它們是指向單個的WCHAR

你想使用以下方法:DllImport默認爲ANSI字符集和stdcall調用:

[DllImport("keylib.dll", CharSet=CharSet.Unicode, CallingConvention=CallingConvention.Cdecl)] 
static extern int convertVirtualKeyToWChar(int virtualKey, 
     out char output, 
     ref char deadchar); 

你的崩潰是由兩個原因造成的。您的C++ DLL不指定任何調用約定,因此它將默認爲CDecl。

DllImportAttribute.CallingConventionDllImportAttribute.CharSet

+0

從技術上說,字符集是編組如何處理字符串。無論CharSet如何,ref/out char都將編組爲wchar_t *。 – 2011-04-03 00:30:42

+0

@peter CharSet設置確實會影響單個字符上的封送處理。我做了一個測試程序來驗證。如果我有一個C#'char'並將該值設置爲''\ x1042',則C++函數將接收與Unicode CharSet相同的值,但如果CharSet是Ansi或未指定,則爲\ x3F。 – 2011-04-03 01:08:59

+0

你確實是對的。我認爲編組不會爲單個字符而煩惱,但它確實如此。 – 2011-04-03 01:59:51

1

這是在黑暗中刺,所以買者自負。 ..

static extern int convertVirtualKeyToWChar(int virtualKey, 
              char[] output, 
              char[] deadchar); 

將一個單元陣列傳遞給每個char[]參數。

0

試試這個(記住,如果有異常的Alloc和免費之間拋出你會泄漏內存軸承,因此,建立一些錯誤處理):

static void Main(string[] args) 
    { 
     IntPtr pout = Marshal.AllocHGlobal(2); 
     IntPtr pdead = Marshal.AllocHGlobal(2); 

     int ret = convertVirtualKeyToWChar(1, pout, pdead); 
     char output = (char)Marshal.ReadInt16(pout); 
     char dead = (char)Marshal.ReadInt16(pdead); 

     Marshal.FreeHGlobal(pout); 
     Marshal.FreeHGlobal(pdead); 
    } 

    static extern int convertVirtualKeyToWChar(int virtualKey, 
     IntPtr output, 
     IntPtr deadchar);