简体   繁体   中英

PowerEnumerate PInvoke resizes array

I'm trying to write a C# program that enumerates Windows power management schemes by calling PowerEnumerate , but after debugging the following code, I notice that the length of buffer is 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 is declared as follows:

[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 is called twice. The first time for getting the required buffer length. The second time for actually reading into the buffer.

While debugging, I noticed that the first call to PowerEnumerate (line 4) sets length to 16 (which is weird because I have more than one power scheme in debugged environment, while one GUID is 16 bytes, but that is probably another story), and resizes buffer to 1 byte.

After instantiating buffer for the second time (line 5) with the length specified by the first call to PowerEnumerate , buffer is 16 bytes long. But the second call to PowerEnumerate (line 6) resizes buffer to 1 byte again.

I've read my code over and over, but I can't spot any mistakes, and my head is soon running out of hair!

Why don't I get the expected results from the above code? Is there something wrong with the declaration?

The Buffer parameter is declared incorrectly. A byte array is already a reference, and passing by ref makes it a double pointer. It should be:

byte[] Buffer

Pass null for the buffer parameter on the first call.

It also looks like you should be passing NULL for the GUIDs. You may need to declare those parameters as IntPtr and pass IntPtr.Zero .

It is also a terrible mistake to ignore the return value and so neglect error checking. You must address that immediately.

I'd use the following declaration:

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

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM