PowerEnumerate PInvoke 调整数组大小

Posted

技术标签:

【中文标题】PowerEnumerate PInvoke 调整数组大小【英文标题】:PowerEnumerate PInvoke resizes array 【发布时间】:2014-10-23 19:17:12 【问题描述】:

我正在尝试编写一个通过调用PowerEnumerate 枚举Windows 电源管理方案的C# 程序,但是在调试以下代码后,我注意到buffer 的长度是1

uint length = 0;
byte[] buffer = new byte[0];
Guid id = Guid.Empty;
PowerEnumerate(IntPtr.Zero, ref id, ref id, 16, 0, ref buffer, ref length);
buffer = new byte[length];
PowerEnumerate(IntPtr.Zero, ref id, ref id, 16, 0, ref buffer, ref bufferSize);

PowerEnumerate 声明如下:

[DllImport("powrprof.dll")]
public static extern UInt32 PowerEnumerate
(
    IntPtr RootPowerKey, 
    ref Guid SchemeGuid, 
    ref Guid SubGroupOfPowerSettingsGuid, 
    PowerDataAccessor AccessFlags,
    UInt32 Index, 
    ref Byte[] Buffer, 
    ref UInt32 BufferSize
);

PowerEnumerate 被调用了两次。第一次获得所需的缓冲区长度。第二次实际读入缓冲区。

在调试时,我注意到对PowerEnumerate 的第一次调用(第4 行)length 设置为16(这很奇怪,因为我在调试环境中有多个电源方案,虽然一个 GUID 是 16 个字节,但这可能是另一回事),并将 buffer 的大小调整为 1 个字节。

在第二次实例化 buffer 之后(第 5 行) 使用第一次调用 PowerEnumerate 指定的长度,buffer 的长度为 16 个字节。但是对PowerEnumerate 的第二次调用(第6 行) 再次将buffer 的大小调整为1 个字节。

我一遍又一遍地阅读我的代码,但我找不到任何错误,而且我的头很快就没有头发了!

为什么我没有从上面的代码中得到预期的结果?声明有问题吗?

【问题讨论】:

对于第二个问题(只接收一个GUID):PowerEnumerate只检索一个项目——Index参数指定的项目;一种常见的方法是使用for 循环。此外,在枚举电源方案时(AccessFlags 参数为16),最小缓冲区长度始终为 16 字节,因此不需要第一次调用PowerEnumerate 【参考方案1】:

Buffer 参数声明不正确。一个字节数组已经是一个引用,并且通过ref 使其成为一个双指针。应该是:

byte[] Buffer

在第一次调用时为缓冲区参数传递null

看起来您应该为 GUID 传递 NULL。您可能需要将这些参数声明为IntPtr 并传递IntPtr.Zero

忽略返回值从而忽略错误检查也是一个可怕的错误。你必须立即解决这个问题。

我会使用以下声明:

[DllImport("powrprof.dll")]
public static extern uint PowerEnumerate
(
    IntPtr RootPowerKey,
    IntPtr SchemeGuid,
    IntPtr SubGroupOfPowerSettingsGuid,
    PowerDataAccessor AccessFlags,
    uint Index,
    byte[] Buffer,
    ref uint BufferSize
);

【讨论】:

该死,我从来没有得到正确的 PInvocations,现在我为忽略返回值感到很糟糕。无论如何,这似乎可行(尽管仍然只列举了一个 GUID,但我稍后会研究)。谢谢!

以上是关于PowerEnumerate PInvoke 调整数组大小的主要内容,如果未能解决你的问题,请参考以下文章

调用外部 SetWindowsHookEx 和 GetModuleHandle 的 PInvoke 错误

PInvoke - 方法的类型签名与 PInvoke 不兼容

调用 PInvoke 函数 ... 使堆栈不平衡

PInvoke - 如何编组'SomeType * []'?

Pinvoke 中的一个问题

PInvoke:返回的双精度数组有问题吗?