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 不兼容