简体   繁体   English

void **使用P / Invoke处理

[英]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.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM