我正在制作一个 C# 程序,通过 PInvoking Win32 函数 PowerReadFriendlyName 从电源管理方案的 GUID 中检索其名称。然而,该函数似乎报告错误的缓冲区长度。
Guid id = new Guid("381b4222-f694-41f0-9685-ff5bb260df2e"); // "Balanced" scheme GUID
uint length = 0;
IntPtr ptr = GCHandle.ToIntPtr(GCHandle.Alloc(id));
Marshal.StructureToPtr(id, ptr, true);
PowerReadFriendlyName(IntPtr.Zero, ptr, IntPtr.Zero, IntPtr.Zero, null, ref length);
byte[] buffer = new byte[length];
PowerReadFriendlyName(IntPtr.Zero, ptr, IntPtr.Zero, IntPtr.Zero, buffer, ref length);
PowerReadFriendlyName
被调用两次。一次使用空指针作为缓冲区,用于检索所需的缓冲区长度。再次使用具有正确长度的缓冲区,用于实际读取名称。
第一次调用后,
length
是一个大得离谱的数字,但对于Balanced方案来说它始终是
126
。
第二次调用后,
buffer
已填充了正确的字符,length
突然变成了20
,听起来更正确。
两个调用都会返回
ERROR_SUCCESS
。
TL;DR: 根据 MSDN 上的文档,作为缓冲区的空引用使函数报告所需的缓冲区长度。但是,当存在空引用时,会报告错误的最小长度。传递数组(空或非空)使函数报告正确的最小长度。
是什么原因导致这种行为以及如何预防?
PowerReadFriendlyName
声明如下:
[DllImport("powrprof.dll")]
public static extern UInt32 PowerReadFriendlyName
(
IntPtr RootPowerKey,
IntPtr SchemeGuid,
IntPtr SubGroupOfPowerSettingsGuid,
IntPtr PowerSettingGuid,
Byte[] Buffer,
ref UInt32 BufferSize
);
测试不同的方案:高性能方案使第一个调用报告
114
,而第二个调用报告22
。
编辑:可能值得注意的是,Balanced已本地化Balansert,而高性能在调试环境中是Høy ytelse。
至于为什么返回的大小大于(/不匹配)所需的确切数量,“返回所需缓冲区大小的函数通常返回上限,而不是严格的界限” - https://devblogs.microsoft。 com/oldnewthing/20240214-00/?p=109400