我想从C#调用DISM API以找出安装了哪些可选的Windows功能。 DISM功能没有出现在知名的pinvoke.net网站上,所以我开始使用P / Invoke Interop Assistant工具来解决它。
问题涉及一个如下所示的结构:
[StructLayout(LayoutKind.Sequential)]
public struct DismFeatureInfo
{
/// PCWSTR->WCHAR*
[MarshalAs(UnmanagedType.LPWStr)]
public string FeatureName;
/// DismPackageFeatureState
[MarshalAs(UnmanagedType.I4)]
public DismPackageFeatureState FeatureState;
/// PCWSTR->WCHAR*
[MarshalAs(UnmanagedType.LPWStr)]
public string DisplayName;
我有一个指向非托管DismFeatureInfo
的指针。当我使用Marshal.PtrToStructure
时,我会收到FatalExecutionEngineError
例外。
如果我从DisplayName
开始注释掉所有字段(仅保留前两个字段),那么它可以正常工作,我在FeatureName
中得到一个有效的字符串。
如果我使用调试器内存窗口来检查结构地址处的内存,则按预期布局。我正在运行64位,它开始了:
[ 8 bytes ] // pointer to a string containing the feature name
[ 4 bytes ] // enum value
[ 8 bytes ] // pointer to a string containing the display name
更重要的是,如果我手动执行偏移来读取指针然后从中获取字符串:
var featureName = Marshal.PtrToStringUni(Marshal.ReadIntPtr(featureInfoPtr));
var displayName = Marshal.PtrToStringUni(Marshal.ReadIntPtr(featureInfoPtr, 8 + 4));
工作正常 - displayName
包含显示名称。
所有这些都表明enum DismPackageFeatureState
被编组为错误的大小。从检查原始内存来看,它绝对应该是4个字节。我提出了一个属性,说它应该是I4
。
如果我将FeatureState
字段更改为:
public UInt32 FeatureState;
然后我仍然得到例外。那是怎么回事?
(注意:我对P / Invoke方面特别感兴趣,而不是我原来的问题。我已经通过new ManagementClass("Win32_OptionalFeature")
更容易找到了我需要的信息,但我仍然对此感到困惑我在尝试让P / Invoke工作时发现并且想知道发生了什么。)
答案 0 :(得分:2)
这似乎是对齐而不是大小的不匹配。 DisplayName
指针有8字节对齐。但根据您对布局的分析,它被放置在4字节边界上。你问题中的C#代码会给DisplayName
一个16的偏移量。但你的分析表明它的偏移量为12.这使我怀疑本机struct
实际上是打包的。
[StructLayout(LayoutKind.Sequential, Pack=1)]
public struct DismFeatureInfo
....
应该解决你的问题。
<强>更新强>
我可以确认我的预感是正确的。以下内容可以在dismapi.h中找到包装结构声明:
#pragma pack(push, 1)