我尝试在64位架构上从C#调用Window API函数 SetupDiEnumDeviceInterfaces 。 我导入函数并声明其他结构。
[DllImport("setupapi.dll", SetLastError = true, CharSet = CharSet.Auto)]
internal static extern bool SetupDiEnumDeviceInterfaces(
IntPtr deviceInfoSet,
SP_DEVINFO_DATA deviceInfoData,
ref Guid interfaceClassGuid,
int memberIndex,
SP_DEVICE_INTERFACE_DATA deviceInterfaceData);
[StructLayout(LayoutKind.Sequential)]
internal class SP_DEVINFO_DATA
{
internal int cbSize = Marshal.SizeOf(typeof(SP_DEVINFO_DATA));
internal Guid classGuid = Guid.Empty; // temp
internal int devInst = 0; // dumy
internal int reserved = 0;
}
[StructLayout(LayoutKind.Sequential, Pack = 2)]
internal struct SP_DEVICE_INTERFACE_DETAIL_DATA
{
internal int cbSize;
internal short devicePath;
}
然后我按如下方式调用此函数:
int index = 0;
Guid _classGuid = Guid.Empty;
IntPtr _deviceInfoSet = IntPtr.Zero;
Native.SP_DEVICE_INTERFACE_DATA interfaceData = new Native.SP_DEVICE_INTERFACE_DATA();
if (!Native.SetupDiEnumDeviceInterfaces(_deviceInfoSet, null, ref _classGuid, index, interfaceData))
{
int error = Marshal.GetLastWin32Error();
if (error != Native.ERROR_NO_MORE_ITEMS)
throw new Win32Exception(error);
break;
}
如果在 32bits 架构上运行,那么一切都很顺利。
如果在 64bits 架构上运行,则 SetupDiEnumDeviceInterfaces 将返回false,最后一次获胜错误等于1784。 原因是在struct interfaceData 字段中 cbSize对于64位体系结构没有有效值(作为int别名Int32)。
来自官方文件
DeviceInterfaceData [out]指向调用者分配的缓冲区的指针 成功返回时,包含已完成的SP_DEVICE_INTERFACE_DATA 标识符合搜索的接口的结构 参数。调用者必须将DeviceInterfaceData.cbSize设置为 调用此函数之前的sizeof(SP_DEVICE_INTERFACE_DATA)。
尝试替换Int64类型的int(别名Int32)类型为:cbSize,devInt,reserved。
如何为64位架构替换类Guid?
如果我尝试使用long类型替换Guid:
[StructLayout(LayoutKind.Sequential)]
internal class SP_DEVICE_INTERFACE_DATA
{
internal Int64 cbSize = Marshal.SizeOf(typeof(SP_DEVICE_INTERFACE_DATA));
internal long interfaceClassGuid = 0; // temp
internal Int64 flags = 1;
internal Int64 reserved = 0;
}
这样的结构定义一切正常但我失去了使用guid特殊类的便利性。在类定义中,Guid也使用了int类型,因此不会在64位架构上计算正确的大小。
答案 0 :(得分:0)
问题不在于您的GUID声明; SetupDiEnumDeviceInterfaces
在64位平台上失败的原因是您没有在reserved
和SP_DEVINFO_DATA
的每个SP_DEVICE_INTERFACE_DATA
字段上使用正确的数据类型。< / p>
SP_DEVINFO_DATA
和SP_DEVICE_INTERFACE_DATA
的结构定义表明reserved
字段声明为UINT_PTR
,这是一种指针类型。这些应在P / Invoke类型中声明为IntPtr
。
(此外,您的所有int
字段都应定义为uint
,因为这些字段会映射到DWORD
原生类型。)
[StructLayout(LayoutKind.Sequential)]
internal class SP_DEVINFO_DATA
{
internal uint cbSize = (uint)Marshal.SizeOf(typeof(SP_DEVINFO_DATA));
internal Guid classGuid;
internal uint devInst;
internal IntPtr reserved;
}
[StructLayout(LayoutKind.Sequential, Pack = 2)]
internal struct SP_DEVICE_INTERFACE_DETAIL_DATA
{
internal uint cbSize;
internal short devicePath;
}
[StructLayout(LayoutKind.Sequential)]
internal class SP_DEVICE_INTERFACE_DATA
{
internal uint cbSize = (uint)Marshal.SizeOf(typeof(SP_DEVICE_INTERFACE_DATA));
internal Guid interfaceClassGuid;
internal uint flags;
internal IntPtr reserved;
}
答案 1 :(得分:0)
您可以尝试设置
[StructLayout(LayoutKind.Sequential, Pack = 2)]
internal struct SP_DEVICE_INTERFACE_DETAIL_DATA
为:
[StructLayout(LayoutKind.Sequential, Pack = 1)]
internal struct SP_DEVICE_INTERFACE_DETAIL_DATA
根据我的阅读,Pack = 8表示32位,Pack = 1表示64位。
答案 2 :(得分:0)
您需要在保留字段中的所有字段(不是 int )和 IntPtr 中使用 uint 。
[StructLayout(LayoutKind.Sequential, CharSet = CharSet.Auto)]
public struct SP_DEVINFO_DATA
{
public uint cbSize;
public Guid ClassGuid;
public uint DevInst;
public IntPtr Reserved;
}
[StructLayout(LayoutKind.Sequential, CharSet = CharSet.Auto)]
public struct SP_DEVICE_INTERFACE_DATA
{
public uint cbSize;
public Guid InterfaceClassGuid;
public uint Flags;
public IntPtr Reserved;
}
[StructLayout(LayoutKind.Sequential, CharSet = CharSet.Auto)]
public struct SP_DEVICE_INTERFACE_DETAIL_DATA
{
public uint cbSize;
[MarshalAs(UnmanagedType.ByValTStr, SizeConst = 256)]
public string DevicePath;
}
要在代码中设置 cbSize ,请使用:
Win32.SP_DEVICE_INTERFACE_DATA did = new Win32.SP_DEVICE_INTERFACE_DATA();
did.cbSize = (uint)Marshal.SizeOf(did);
Win32.SP_DEVICE_INTERFACE_DETAIL_DATA didd = new Win32.SP_DEVICE_INTERFACE_DETAIL_DATA();
didd.cbSize = (uint)Marshal.SizeOf(didd);