I am using a C API DLL from a 3rd party vendor. The problem I have is that I can't seem to find a good template for Marshalling the following C code:
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.
I've tried to do the same in C#, but can't figure out how to Marshal handle properly. My C# version (latest try) is:
[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. 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.
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. You should use IntPtr
.
The API_Open
accepts the address of the variable where the handle is returned. The caller allocates that variable and passes it to the callee, which populates the variable. The C function might look like this:
int API_Open(void **handle)
{
*handle = InternalCreateHandle();
return CODE_SUCCESS;
}
You'd call that in C like this:
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. In C# you would use pass-by-reference.
For API_Close
it is even simpler because we are passing the handle by value:
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:
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!
The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.