从C#调用C ++函数传递一个void类型剥离的指针 [英] Invoking C++ function from C# passing a void pointer that is type stripped

查看:176
本文介绍了从C#调用C ++函数传递一个void类型剥离的指针的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我试图使用以ANSI C(编译为C ++)编写的第三方DLL。其中一个函数具有以下C ++原型:

I am trying to use a third-party DLL written in ANSI C (compiled as C++). One of the functions has the following C++ prototype:

tResultCode GetAttrib
(
    tHandle     handle,
    tAttrib     attrib,
    void *      value,
    tAttribType valueType,
    int         valueMaxSize
);

GetAttrib 的参数如下:


  • 句柄是指向DLL中不透明结构的void指针< / code>指向 valueType
  • 所指示类型的变量的指针
  • valueType 表示分配用于保存
    属性值的缓冲区的C ++类型

  • valueMaxSize 分配给值指向的变量的字节

  • handle is a void pointer to an opaque structure within the DLL
  • attrib indicates which attribute to retrieve from the structure
  • value a pointer to a variable of the type indicated by valueType
  • valueType indicates the C++ type of the buffer allocated to hold the attribute value
  • valueMaxSize is the number of bytes allocated to variable pointed to by value

eAttribType 枚举定义如下:

typedef enum eAttribType
{
    eHandle,
    eBool,
    eEnum,
    eInt,
    eLong,
    eFloat,
    eDouble,
    eDate,
    eTime,
    eTimestamp,
    eString,     // char *
    eChar,       // char
    eVoid,
    eHandle,
    eFunctionPointer
} tAttribType;

eAttrib 枚举定义如下:

typedef enum eAttrib
{
    eInvoiceNumber, // eString
    eInvoiceDate,   // eTimestamp
    eUnits,         // eLong
    ePrice,         // eFloat
    eDiscount,      // eDouble
    ePreferredFlag, // eBool
    ...
} tAttrib;

我在C#中声明了非托管函数指针,如下所示:

I declare the unmanaged function pointer in C# as follows:

    [UnmanagedFunctionPointer(CallingConvention.StdCall)]
    internal delegate eResultCode getAttrib(void** handle, eAttrib attrib, void* value, eAttribType attribType, int valueMaxSize);
    internal unsafe getAttrib GetAttrib;

其中:


  • handle 是指向C ++库结构的指针的 void **

  • attrib 模仿指示要检索的属性的C ++枚举

  • value 是C ++变量的 void *

  • attribType mimics指示 value

  • valueMaxSize 的C ++类型的C ++枚举是整数,表示值指向的变量的大小

  • handle is a void ** for the pointer to the C++ library structure
  • attrib mimics the C++ enumeration that indicates the attribute to retrieve
  • value is a void * to the C++ variable
  • attribType mimics the C++ enumeration that indicated the C++ type of value
  • valueMaxSize is an integer meant to represent the size of the variable pointed to by value

问题是我不知道如何从C#调用GetAttrib()为不同的数据类型为 void * value variable)。有时这个变量将是一个C ++ char * ,其他时候它将是一个C ++ int 它将是一个C ++ 枚举

My problem is that I don't know how call GetAttrib() from C# with different data types for the void * (the value variable). Sometimes this variable will be a C++ char *, and other times it will be a C++ int, and still other times it will be a C++ enum, etc

如果有人可以告诉我如何正确分配/填充 char * eString )和 long

If someone can show me how to properly allocate/populate a char * (eString) and a long (eLong) from C# I think that the rest will fall into place (hopefilly).

推荐答案

首先, eString 是一种特殊情况,因为它是唯一的可变长度类型。其他类型是固定大小的,应该更容易检索。

First, eString is a special case, since it's the only variable-length type. The other types are of a fixed size and should be easier to retrieve.

因此,让我们从 eLong 开始。这映射到C ++ long ,其依次应该 映射到C# int -

So let's start with eLong. This maps to a C++ long, which in turn should probably map to a C# int - but this is architecture dependent so your mileage my vary.


  • 在C#中, int 始终为32位, long 始终为64位。

  • 在C ++中,无固定大小。对于所有你知道, int 定义为至少16位,并且 long 为至少32位,位。在Visual C ++中,他们都是32位的。 li>
  • In C#, an int is always 32-bit, and a long is always 64-bit.
  • In C++, there's no fixed size. For all you know, an int is defined as at least 16-bit, and a long as at least 32-bit. In Visual C++, they're both 32-bit though.

确保您知道自己正在做什么,并确保尺寸正确。

Make sure you know what you're doing and you get the sizes right.

现在,您需要一个指向不可移动内存的指针,非托管函数可以安全地写入。发生时,值类型堆栈变量不会被GC移动,所以你可以简单地写下面的代码:

Now, you need a pointer to unmovable memory the unmanaged function can safely write to. As it happens, value type stack variables won't be moved by the GC, so you can simply write the following:

internal static unsafe int GetUnits(void** handle)
{
    int value;
    GetAttrib(handle, eAttrib.eUnits, &value, eAttribType.eLong, sizeof(int));
    return value;
}

另一种方法会涉及 stackalloc

Another method would involve stackalloc:

internal static unsafe int GetUnits(void** handle)
{
    var buffer = stackalloc int[1];
    GetAttrib(handle, eAttrib.eUnits, buffer, eAttribType.eLong, sizeof(int));
    return *buffer;
}

您可以使用 stackalloc byte [ ] 如果没有C#内置类型可以适合。

You could use this with a stackalloc byte[whatever] if there's no C# built-in type that could fit.

这显然是未经测试,因为我没有lib,

That's obviously untested as I don't have the lib, but it should do it.

对于字符串,您需要一个托管数组,因此您可以将它们提供给 Encoding.GetString 。是的,你还需要知道编码。我将在这里假设ASCII。

As for strings, you'd need a managed array, so you can feed them into Encoding.GetString. Yeah, you need to know the encoding too. I'll assume ASCII here.

internal static unsafe string GetInvoiceNumber(void** handle)
{
    var buffer = new byte[512];
    fixed (byte* bufAddr = &buffer[0])
    {
        GetAttrib(handle, eAttrib.eInvoiceNumber, bufAddr, eAttribType.eString, buffer.Length);
        return Encoding.ASCII.GetString(buffer);
    }
}

由于受管阵列位于托管堆上,需要 pin ,所以它在操作过程中不会被GC移动。这就是 固定语句

As a managed array lives on the managed heap, you need to pin it so it won't be moved by the GC during operation. That's what the fixed statement does.

这篇关于从C#调用C ++函数传递一个void类型剥离的指针的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆