0

我想从 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;

我有一个指向 unmanaged 的​​指针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 工作时发现的内容感到困惑,并且想知道发生了什么。)

4

1 回答 1

2

这似乎是对齐而不是大小的不匹配。DisplayName指针有 8 字节对齐。但是根据你对布局的分析,它被放置在一个 4 字节的边界上。您问题中的 C# 代码将给出DisplayName16 的偏移量。但您的分析表明它的偏移量为 12。这使我怀疑本机struct实际上已打包。

[StructLayout(LayoutKind.Sequential, Pack=1)]
public struct DismFeatureInfo
....

应该可以解决您的问题。

更新

我可以确认我的预感是正确的。在包装结构声明的 dismapi.h 中可以找到以下内容:

#pragma pack(push, 1)
于 2012-12-13T14:59:29.190 回答