2016-03-07 33 views
0

我正在使用來自第三方供應商的C API DLL。我的問題是,我似乎無法找到編組下面的C代碼的好模板:void **使用P/Invoke處理

API_Open(void ** handle); 
API_Close(void * handle); 

的呼聲被簡化,但手柄是一個void *,這是(在C)通過進入API_Open調用爲&的句柄,然後作爲句柄傳入API_Close

我試過在C#中做同樣的事情,但不知道如何正確處理元帥。我的C#版本(最新的嘗試)是:

[DllImport("External.dll",EntryPoint="API_Open")] 
public static extern int API_Open(out IntPtr handle); 
[DllImport("External.dll",EntryPoint="API_Close")] 
public static extern int API_Close(IntPtr handle); 

public static int Wrapper_API_Open(ref Int32 handle) 
{ 
    int rc = SUCCESS; 

    // Get a 32bit region to act as our void** 
    IntPtr voidptrptr = Marshal.AllocHGlobal(sizeof(Int32)); 

    // Call our function. 
    rc = API_Open(out voidptrptr); 

    // In theory, the value that voidptrptr points to should be the 
    // RAM address of our handle. 
    handle = Marshal.ReadInt32(Marshal.ReadIntPtr(voidptrptr)); 

    return rc; 
} 

public static int Wrapper_API_Close(ref Int32 handle) 
{ 
    int rc = SUCCESS; 

    // Get a 32bit region to act as our void * 
    IntPtr voidptr = Marshal.AllocHGlobal(sizeof(Int32)); 

    // Write the handle into it. 
    Marshal.WriteInt32(voidptr,handle); 

    // Call our function. 
    rc = API_Close(voidptr); 

    return rc; 
} 


public void SomeRandomDrivingFunction() 
{ 
    . 
    . 
    . 
    Int32 handle; 
    Wrapper_API_Open(ref handle); 
    . 
    . 
    . 
    Wrapper_API_Close(ref handle); 
    . 
    . 
    . 
} 

API返回代碼總是INVALID_DEVICE_OBJECT當我打電話API_Close。有什麼想法嗎?我認爲這會非常簡單,但是我無法繞過函數調用的void **和void *部分。

謝謝

+0

看起來你應該只是'IntPtr句柄; API_Open(出處理);'然後'API_Close(處理);'。 –

+0

只需刪除Marshal.AllocHGlobal()hokey-pokey,IntPtr就是句柄。改進錯誤檢查,當API_Open()返回錯誤代碼時拋出異常。 –

回答

3

你似乎太過複雜這顯着。我不知道你爲什麼要爲句柄引入Int32,因爲它們確實需要指針大小。您應該使用IntPtr

API_Open接受返回句柄的變量的地址。調用者分配該變量並將其傳遞給填充變量的被調用者。 C函數可能是這樣的:

int API_Open(void **handle) 
{ 
    *handle = InternalCreateHandle(); 
    return CODE_SUCCESS; 
} 

你會打電話來,在C這樣的:

void *handle; 
int retval = API_Open(&handle); 
if (retval != CODE_SUCCESS) 
    // handle error 
// go one and use handle 

翻譯成C#中,void*映射到IntPtr,並使用雙指針的是隻是一種解決C僅支持按值傳遞的方法。在C#中,您將使用傳遞引用。

對於API_Close那麼就更簡單了,因爲我們是按值傳遞手柄:

int API_Close(void *handle) 
{ 
    InternalCloseHandle(handle); 
    return CODE_SUCCESS; 
} 

而且調用的代碼很簡單:

int retval = API_Close(handle); 
if (retval != CODE_SUCCESS) 
    // handle error 

因此,C#包裝函數應該是:

public static int Wrapper_API_Open(out IntPtr handle) 
{ 
    return API_Open(out handle); 
} 

public static int Wrapper_API_Close(IntPtr handle) 
{ 
    return API_Close(handle); 
} 

在這一點上這些包裝方法看起來有些沒有意義!

+0

啊,它的優雅簡潔 - 解釋了爲什麼我無法找到任何示例。謝謝。 – Brian