我正在使用来自第三方供应商的C API DLL。我遇到的问题是,我似乎无法找到一个很好的模板来编组以下C代码:
API_Open( void ** handle );
API_Close( void * handle );
调用是简化的,但句柄是一个void *,它是(在C中)作为&句柄传递给API_Open
调用,然后作为句柄传递给API_Close
。
我曾试图在C#中做同样的事情,但无法弄清楚如何正确处理Marshal。我的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_Close时,API返回码始终为INVALID_DEVICE_OBJECT。有什么想法吗?我认为这将非常简单,但是我无法绕着虚空包裹我的头**和无效*部分函数调用。
由于
答案 0 :(得分:3)
你似乎过度复杂了。我不知道你为什么要为句柄引入Int32
,因为它们确实需要指针大小。您应该使用IntPtr
。
API_Open
接受返回句柄的变量的地址。调用者分配该变量并将其传递给callee,后者填充变量。 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#中,您将使用pass-by-reference。
对于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);
}
此时这些包装器方法确实看起来毫无意义!