从C#调用C ++函数传递一个void类型剥离的指针 [英] Invoking C++ function from C# passing a void pointer that is type stripped
问题描述
我试图使用以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 DLLattrib
indicates which attribute to retrieve from the structurevalue
a pointer to a variable of the type indicated byvalueType
valueType
indicates the C++ type of the buffer allocated to hold the attribute valuevalueMaxSize
is the number of bytes allocated to variable pointed to byvalue
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 avoid **
for the pointer to the C++ library structureattrib
mimics the C++ enumeration that indicates the attribute to retrievevalue
is avoid *
to the C++ variableattribType
mimics the C++ enumeration that indicated the C++ type ofvalue
valueMaxSize
is an integer meant to represent the size of the variable pointed to byvalue
问题是我不知道如何从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 along
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 along
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屋!