[英]void ** handles with P/Invoke
I am using a C API DLL from a 3rd party vendor. 我正在使用来自第三方供应商的C API DLL。 The problem I have is that I can't seem to find a good template for Marshalling the following C code:
我的问题是,我似乎找不到用于编组以下C代码的好的模板:
API_Open( void ** handle );
API_Close( void * handle );
The calls are simplified, but the handle is a void *, which is (in C) passed into the API_Open
call as &handle, and then passed into API_Close
as handle. 调用得到了简化,但句柄是一个空*,(在C中)作为&handle传递给
API_Open
调用,然后作为句柄传递给API_Close
。
I've tried to do the same in C#, but can't figure out how to Marshal handle properly. 我试图在C#中执行相同的操作,但无法弄清楚如何正确处理元帅。 My C# version (latest try) is:
我的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 );
.
.
.
}
The API return code is always INVALID_DEVICE_OBJECT when I call API_Close. 当我调用API_Close时,API返回代码始终为INVALID_DEVICE_OBJECT。 Any thoughts?
有什么想法吗? I thought this would be pretty straightforward, but I'm having trouble wrapping my head around the void** and void* parts of the function calls.
我以为这很简单,但是我在将函数调用的void **和void *部分包裹起来时遇到了麻烦。
Thanks 谢谢
You seem to be over-complicating this significantly. 您似乎过于复杂了。 I don't know why you want to introduce
Int32
for the handles since they do need to be pointer sized. 我不知道为什么要为句柄引入
Int32
,因为它们确实需要指针大小。 You should use IntPtr
. 您应该使用
IntPtr
。
The API_Open
accepts the address of the variable where the handle is returned. API_Open
接受返回句柄的变量的地址。 The caller allocates that variable and passes it to the callee, which populates the variable. 调用方分配该变量并将其传递给被调用方,后者将填充该变量。 The C function might look like this:
C函数可能如下所示:
int API_Open(void **handle)
{
*handle = InternalCreateHandle();
return CODE_SUCCESS;
}
You'd call that in C like this: 您可以像这样在C中调用它:
void *handle;
int retval = API_Open(&handle);
if (retval != CODE_SUCCESS)
// handle error
// go one and use handle
Translated to C#, the void*
maps to IntPtr
, and the use of the double pointer is just a means to get around the fact that C only supports pass-by-value. 转换为C#后,
void*
映射到IntPtr
,并且使用双指针只是一种避免C仅支持传递值这一事实的方法。 In C# you would use pass-by-reference. 在C#中,您将使用传递引用。
For API_Close
it is even simpler because we are passing the handle by value: 对于
API_Close
它甚至更简单,因为我们通过值传递了句柄:
int API_Close(void *handle)
{
InternalCloseHandle(handle);
return CODE_SUCCESS;
}
And the calling code is simply: 调用代码很简单:
int retval = API_Close(handle);
if (retval != CODE_SUCCESS)
// handle error
So, the C# wrapper functions should be: 因此,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);
}
At which point these wrapper methods do look somewhat pointless! 在这些时候,这些包装器方法看起来毫无意义!
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.