2012-11-19 17 views
6

說,我已經得到了原型的函數是一個DLL暴露:如何調用一個非託管函數,它具有char#[]作爲來自C#的OUT參數?

int CALLBACK worker (char* a_inBuf, int a_InLen, 
        char** a_pOutBuf, int* a_pOutLen, 
        char** a_pErrBuf, int* a_pErrLen) 

我敢肯定,這是可笑容易調用DLL函數從我的C#代碼,但它不工作與此代碼:

[DllImport("mydll.dll")] 
    public static extern int worker(
     [In, MarshalAs(UnmanagedType.LPArray)] byte[] inBuf, 
     int inputLen, 
     [Out, MarshalAs(UnmanagedType.LPArray)] byte[] outBuf, 
     out int outputLen, 
     [Out, MarshalAs(UnmanagedType.LPArray)] byte[] errBuf, 
     out int errorLen); 

... 

int outputXmlLength = 0; 
int errorXmlLength = 0; 

byte[] outputXml = null; 
byte[] errorXml = null; 
worker(input, input.Length, output, out outputLength, error, out errorLength); 

我拿到的時候我要去找我的非託管庫中爲outputerror內存(並因此取消引用傳遞指針)訪問衝突:

*a_ppBuffer = (char*) malloc(size*sizeof(char)); 
  1. 如何在我的C#代碼中爲此函數編寫DLLIMPORT語句?

  2. 如何實際調用該函數,以便a_pOutBufa_pErrBuf都可以訪問,並從內部workernull(即使用一個真正的雙指針)?

+1

您可以更改工作人員功能簽名嗎? –

+0

@SimonMourier:沒有。它是一個在C++程序(建立的API)中使用的DLL,現在也應該從新開發的.net應用程序調用。因此API是固定的。 – eckes

回答

7

您當前的定義不起作用。 worker函數在函數內部分配內存並寫入該內存。

P/Invoke layer不支持以這種方式分配的封送C風格的數組,因爲它無法知道在調用返回時數組有多大(不像說,SAFEARRAY)。

這也是爲什麼從API函數返回指向數組的指針通常是個壞主意,而且Windows API的編寫方式是由內存分配由調用者來處理。

這就是說,你想改變的P/Invoke的worker聲明如下:

[DllImport("mydll.dll")] 
public static extern int worker(
    [In, MarshalAs(UnmanagedType.LPArray)] byte[] inBuf, 
    int inputLen, 
    ref IntPtr outBuf, ref int outputLen, 
    ref IntPtr errBuf, ref int errorLen); 

在這一過程中,就表示你要手動(元帥陣列outBuferrBuf參數將會爲你設定);您將參考傳遞給指針(雙向間接,這是您的char**),然後必須使用其他指標進行邊界檢查(本例中爲outputLenerrorLen參數)。

您若返回集結了三分球的數據,像這樣:

int outputXmlLength = 0; 
int errorXmlLength = 0; 

IntPtr output = IntPtr.Zero; 
IntPtr error = IntPtr.Zero; 

worker(input, input.Length, ref output, ref outputLength, 
    ref error, ref errorLength); 

// Get the strings. 
string outputString = Marshal.PtrToStringAnsi(output, outputLength); 
string errorString = Marshal.PtrToStringAnsi(error, errorLength); 

這就是說,你有另一個問題。由於內存是在內部分配的,所以你必須釋放內存。由於您使用malloc來分配內存,因此您需要將兩個IntPtr實例返回到非託管代碼,以便調用free

如果你在非託管代碼使用LocalAllocCoTaskMemAlloc,那麼你可以使用FreeHGlobalFreeCoTaskMem方法分別對Marshal class釋放被管理方的內存分配內存。

+0

我已經有了一個清理(void)方法,用於清理分配的內存。假設(即工作在非託管'C++')是我的DLL的狀態不會調用'worker'和'cleanup'之間切換。國家在國內舉行。 – eckes

+0

@eckes你的意思是'清理(void *)',對吧? – casperOne

+0

nope。該方法採用** no **參數,因爲除非調用'cleanup',否則存儲其他內容。 – eckes

相關問題