2016-03-07 76 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