SP_DEVICE_INTERFACE_DETAIL_DATA 结构:

typedef struct _SP_DEVICE_INTERFACE_DETAIL_DATA {
  DWORD cbSize;
  TCHAR DevicePath[ANYSIZE_ARRAY];
} SP_DEVICE_INTERFACE_DETAIL_DATA, *PSP_DEVICE_INTERFACE_DETAIL_DATA;

如何在C#中声明它以使Marshal.SizeOf正常工作?

我分配动态缓冲区没有问题。 我只想以适当的,非硬编码的方式计算cbSize

definition at PInvoke.net是错误的。
PInvoke.net上的解释也是错误的:



不要相信他4 + Marshal.SystemDefaultCharSize仅在x86上有效。与sizeof(int) + Marshal.SystemDefaultCharSize相同。在x64上,它失败了。

这是非托管C++所提供的:



我尝试了StructLayoutMarshalAs参数的所有可能组合,但是我无法获取它来返回上述值。

什么是正确的声明?

最佳答案

该结构的关键是您不知道它应该多大。您必须调用SetupDiGetDeviceInterfaceDetail()两次,在第一次调用时,您有意将DeviceInterfaceDetailSize参数传递0。这当然会失败,但是RequiredSize参数将告诉您结构需要多大。然后,您分配一个合适大小的结构并再次调用它。

pinvoke编码器或C#语言不直接支持动态调整结构的大小。因此,声明结构根本没有帮助,请不要尝试。您应该使用Marshal.AllocHGlobal()。这为您提供了一个指针,您可以将其作为DeviceInterfaceDetailData参数传递。使用Marshal.WriteInt32设置cbSize。现在拨打电话。并使用Marshal.PtrToStringUni()检索返回的字符串。 Marshal.FreeHGlobal进行清理。您可以毫不费力地从方法名称中搜索执行此操作的代码。

cbSize成员是一个问题,SetupApi.h SDK头文件包含以下内容:

#ifdef _WIN64
#include <pshpack8.h>   // Assume 8-byte (64-bit) packing throughout
#else
#include <pshpack1.h>   // Assume byte packing throughout (32-bit processor)
#endif

这很丑陋,C编译器会认为数组之后有2个字节的填充,即使没有。在C#代码中,对于32位代码和64位代码,StructLayoutAttribute.Pack值需要不同。如果没有声明两个结构,就无法干净地做到这一点。然后根据IntPtr.Size的值在它们之间进行选择。或者只是硬编码它,因为无论如何结构声明都没有用,在32位模式下为6,在64位模式下为8。在两种情况下,字符串都从偏移量4开始。当然假设Unicode字符串,那么使用ansi字符串毫无意义。

关于c# - 为PInvoke正确声明SP_DEVICE_INTERFACE_DETAIL_DATA,我们在Stack Overflow上找到一个类似的问题:https://stackoverflow.com/questions/10728644/

10-10 14:01