提问人:Plaje 提问时间:7/21/2023 最后编辑:Plaje 更新时间:7/21/2023 访问量:109
如何在 c 中封送此 c 结构并调用其方法#
How to marshal this c struct and call its method in c#
问:
我在其他地方看到过类似的答案,但这些解决方案都不起作用,而且通常它们的问题略有不同。我还没有看到任何其他问题的解决方案在这里有所帮助。
我有一个dll,其中包含一个包含uint数组的结构类型的方法参数,作为指针传递给该方法。以下是旧 c 标头的内容:
typedef struct HandleArrayType
{
uint32_t HandleArray[max_number_100];
}HandleArrayType;
typedef HandleArrayType *HandleArrayPtrType;
typedef bool (*type_connectToMultiple)(char *CommaSeparatedString, HandleArrayPtrType ArrayPointer, uint32_t numberOfOpensAttempted) __attribute__((cdecl));
我们尝试了几种方法来编组这个问题,这是我们尝试的最后一个建议,它给了我们内存访问冲突:
[StructLayout(LayoutKind.Sequential)]
public struct HandleArrayType
{
[MarshalAs(UnmanagedType.ByValArray, SizeConst = 100)]
public uint[] HandleArray;
}
[DllImport("file", CallingConvention = CallingConvention.Cdecl)]
internal static extern bool ConnectToMultiple(string[] nameArray, ref HandleArrayType myStruct, uint numAttempted);
我想我之前也尝试过几次这样的东西,它确实连接了,但是我们得到了一个句柄而不是两个句柄,并且句柄编号相差甚远(表明应该的结构编组不正确):
[DllImport("file", CallingConvention = CallingConvention.Cdecl)]
internal static extern bool ConnectToMultiple(IntPtr commaSepHandlesString, uint[] handles , ref uint numAttempted);
(然后,当我们调用它时,我们将封送组为句柄字符串的 IntPtr) 如果有人知道正确编组的方法,请发布解决方案,我们现在正在使用一种糟糕的解决方法,这将使我们的过程非常缓慢(并且速度是一个问题)。
编辑:我们能够通过安装最新版本的dll来更快地解决,因此这对我们来说不再是一个大问题。但是 connectToMultiple 方法仍然被破坏。仍然很好奇它是否能发挥作用
答:
-1赞
jdweng
7/21/2023
#1
该结构需要位于非托管空间中。
[StructLayout(LayoutKind.Sequential)]
public struct HandleArrayType
{
[MarshalAs(UnmanagedType.ByValArray, SizeConst = 100)]
public IntPtr[] HandleArray;
}
[DllImport("file", CallingConvention = CallingConvention.Cdecl)]
internal static extern bool ConnectToMultiple(string nameArray, IntPtr myStruct, uint numAttempted);
static void Main(string[] args)
{
HandleArrayType handleArrayType = new HandleArrayType();
IntPtr ptr = Marshal.AllocHGlobal(Marshal.SizeOf(handleArrayType));
string nameArray = "abc";
uint numAttempted = 100;
bool results = ConnectToMultiple(nameArray, ptr, numAttempted);
}
评论
1赞
Ben Voigt
7/21/2023
为什么要更改数组中的元素类型?C 代码在任何平台上都绝对是 32 位整数。不,该结构不需要位于非托管内存中。
0赞
jdweng
7/21/2023
@BenVoigt:INTPTR 是一个 32 位整数。这并没有真正的区别。我怀疑这真的是一个指针。
0赞
Plaje
7/21/2023
这导致在调用 connectomultiple 方法时发生访问冲突
0赞
Plaje
7/21/2023
更正:我将 uint numAttempt 更改为 ref uint numAttempted,并且它还报告它已连接(返回 true,numattempt 更改为 2)。但是,我不知道我应该如何引用返回的句柄,因为它们隐藏在 intptr 后面。我会环顾四周,看看是否能找到一种方法来获取这些值
1赞
Ben Voigt
7/21/2023
@jdweng:不,IntPtr 是一个指针大小的整数,如 .它不是到处都是 32 位的。uintptr_t
1赞
Charlieface
7/21/2023
#2
看来 C 声明是错误的,并且是一个指针。此外,您需要指定字符串的字符集,通常为 .numAttempted
LPStr
此外,目前尚不清楚是否应该是 or 或 。myStruct
[In, Out] ref
[Out] out
in
[StructLayout(LayoutKind.Sequential)]
public struct HandleArrayType
{
[MarshalAs(UnmanagedType.ByValArray, SizeConst = 100)]
public int[] HandleArray;
}
[DllImport("file", CallingConvention = CallingConvention.Cdecl)]
internal static extern bool ConnectToMultiple(
[MarshalAs(UnmanagedType.LPStr)] string nameArray,
[In, Out] ref HandleArrayType myStruct,
[Out] out uint numAttempted);
static void Main(string[] args)
{
var handleArrayType = new HandleArrayType();
bool results = ConnectToMultiple("abc", ref handleArrayType, out var numAttempted);
}
评论
0赞
Plaje
7/21/2023
谢谢,我实际上并没有使用 handlearray 定义,我只是使用常规数组。出于某种原因,它确实连接并返回了“句柄”值,但是当以后使用句柄时,我可以看到它们不正确。这是在我意识到输入是一个结构而不是实际数组之前。我很快就会尝试一下,看看会发生什么
0赞
Plaje
7/21/2023
同样为了清楚起见,IntPtr 确实有效,因为 IntPtr 字符串中的逗号数决定了调用中“numattempted”返回的数字。唯一不起作用的是返回的句柄
1赞
Charlieface
7/21/2023
是的,这就是我说的,当你这样做时它不起作用的原因是因为你没有指定字符集,所以它被修改为 Unicode 而不是 ANSIstring nameArray
0赞
Plaje
7/21/2023
我试了一下,类似于我在 OP 中的最后一次尝试,它似乎确实连接了,但返回的句柄是“2069910436”(应该有两个句柄)。我想当我做我的时,句柄是一个较小的数字,例如 14000000/15000000 或其他什么,但句柄在这两种情况下都不起作用
1赞
Charlieface
7/21/2023
就像其他人说的,可能是包装关闭了,或者可能被定义为其他东西,很难知道。uint32_t
评论
fixed
string[]
? 而是......应标记为非托管 LPStr...char *
string
static extern bool ConnectToMultiple(string nameArray, ref HandleArrayType myStruct, uint numAttempted);
ref