CallNtPowerInformation函数失败,返回值为STATUS_BUFFER_TOO_SMALL

问题描述 投票:0回答:1

这是我的代码,我发现a的值永远不会改变,然后我检查返回值,它是STATUS_BUFFER_TOO_SMALL

#include "stdafx.h"
#include <Windows.h>  
extern "C" {
#include <Powrprof.h>
}
#pragma comment(lib, "Powrprof.lib")
typedef struct _PROCESSOR_POWER_INFORMATION {
    ULONG  Number;
    ULONG  MaxMhz;
    ULONG  CurrentMhz;
    ULONG  MhzLimit;
    ULONG  MaxIdleState;
    ULONG  CurrentIdleState;
} PROCESSOR_POWER_INFORMATION, *PPROCESSOR_POWER_INFORMATION;

int main(int argc, char* argv[])
{

    PROCESSOR_POWER_INFORMATION a;
    while (1)
    {
        CallNtPowerInformation(ProcessorInformation, NULL, 0, &a, sizeof(a));       
    }

    system("pause");
    return 0;
}

OutputBufferSize是sizeof(a),但为什么它返回STATUS_BUFFER_TOO_SMALL,以及如何修复它?

c++ winapi
1个回答
2
投票

根据CallNtPowerInformation()文档:

ProcessorInformation 11

lpInBuffer参数必须为NULL;否则该函数返回ERROR_INVALID_PARAMETER。

lpOutputBuffer缓冲区为系统上安装的每个处理器接收一个PROCESSOR_POWER_INFORMATION结构。使用GetSystemInfo函数检索处理器的数量。

您的缓冲区太小,因为您只分配了1个PROCESSOR_POWER_INFORMATION,而不是每个已安装的处理器分配1个。现在非常罕见,PC只安装了1个处理器。多核和超线程CPU为操作系统提供多个处理器。

尝试更像这样的东西:

#include "stdafx.h"
#include <Windows.h>  

extern "C" {
#include <Powrprof.h>
}

#include <vector>

#pragma comment(lib, "Powrprof.lib")

typedef struct _PROCESSOR_POWER_INFORMATION {
    ULONG  Number;
    ULONG  MaxMhz;
    ULONG  CurrentMhz;
    ULONG  MhzLimit;
    ULONG  MaxIdleState;
    ULONG  CurrentIdleState;
} PROCESSOR_POWER_INFORMATION, *PPROCESSOR_POWER_INFORMATION;

int main(int argc, char* argv[])
{
    SYSTEM_INFO si = {0};
    GetSystemInfo(&si);

    std::vector<PROCESSOR_POWER_INFORMATION> a(si.dwNumberOfProcessors);
    DWORD dwSize = sizeof(PROCESSOR_POWER_INFORMATION) * si.dwNumberOfProcessors;

    do
    {
        CallNtPowerInformation(ProcessorInformation, NULL, 0, &a[0], dwSize);
    }
    while (true);

    a.clear();

    system("pause");
    return 0;
}

请注意SYSTEM_INFO文档中的以下警告:

dwNumberOfProcessors 当前组中的逻辑处理器数。要检索此值,请使用GetLogicalProcessorInformation函数。

32位系统最多只支持64个逻辑处理器。 64位系统通过Processor Groups支持更多处理器。

如果您的PC安装了64个或更少的逻辑处理器,上述代码将正常工作。但是,如果您的PC安装了超过64个逻辑处理器,请使用GetActiveProcessorCount()GetLogicalProcessorInformation()确定安装的逻辑处理器总数。

以下代码是根据GetLogicalProcessorInformation()文档中提供的示例调整的:

#include "stdafx.h"
#include <Windows.h>  

extern "C" {
#include <Powrprof.h>
}

#include <vector>

#pragma comment(lib, "Powrprof.lib")

typedef struct _PROCESSOR_POWER_INFORMATION {
    ULONG  Number;
    ULONG  MaxMhz;
    ULONG  CurrentMhz;
    ULONG  MhzLimit;
    ULONG  MaxIdleState;
    ULONG  CurrentIdleState;
} PROCESSOR_POWER_INFORMATION, *PPROCESSOR_POWER_INFORMATION;

typedef BOOL (WINAPI *LPFN_GLPI)(PSYSTEM_LOGICAL_PROCESSOR_INFORMATION, PDWORD);
typedef BOOL (WINAPI *LPFN_GLPIEX)(LOGICAL_PROCESSOR_RELATIONSHIP, PSYSTEM_LOGICAL_PROCESSOR_INFORMATION_EX, PDWORD);
typedef DWORD (WINAPI *LPFN_GAPC)(WORD);

#define ALL_PROCESSOR_GROUPS 0xffff

// Helper function to count set bits in the processor mask.
DWORD CountSetBits(ULONG_PTR bitMask)
{
    DWORD LSHIFT = sizeof(ULONG_PTR)*8 - 1;
    DWORD bitSetCount = 0;
    ULONG_PTR bitTest = (ULONG_PTR)1 << LSHIFT;    
    DWORD i;

    for (i = 0; i <= LSHIFT; ++i)
    {
        bitSetCount += ((bitMask & bitTest)?1:0);
        bitTest/=2;
    }

    return bitSetCount;
}

DWORD GetInstalledProcessorCount()
{
    // on Windows 7 and later, use GetActiveProcessorCount() ...

    LPFN_GAPC gapc = (LPFN_GAPC) GetProcAddress(GetModuleHandle(TEXT("kernel32")), "GetActiveProcessorCount");
    if (gapc)
        return gapc(ALL_PROCESSOR_GROUPS);

    // on Vista and later, try GetLogicalProcessorInformationEx() next ...

    LPFN_GLPIEX glpiex = (LPFN_GLPIEX) GetProcAddress(GetModuleHandle(TEXT("kernel32")), "GetLogicalProcessorInformationEx");
    if (glpiex) 
    {
        std::vector<BYTE> buffer;
        PSYSTEM_LOGICAL_PROCESSOR_INFORMATION_EX info = NULL;
        DWORD bufsize = 0;

        // not using RelationGroup because it does not return accurate info under WOW64...
        while (!glpiex(RelationProcessorCore, info, &bufsize))
        {
            if (GetLastError() != ERROR_INSUFFICIENT_BUFFER)
                return 0;

            buffer.resize(bufsize);
            info = (PSYSTEM_LOGICAL_PROCESSOR_INFORMATION_EX) &buffer[0];
        } 

        DWORD logicalProcessorCount = 0;

        while (bufsize >= sizeof(SYSTEM_LOGICAL_PROCESSOR_INFORMATION_EX))
        {
            // for RelationProcessorCore, info->Processor.GroupCount is always 1...
            logicalProcessorCount += CountSetBits(info->Processor.GroupMask[0].Mask);
            bufsize -= info->Size;
            info = (PSYSTEM_LOGICAL_PROCESSOR_INFORMATION_EX) ((LPBYTE)info) + info->Size);
        }

        return logicalProcessorCount;
    }

    // on XP and later, try GetLogicalProcessorInformation() next...

    LPFN_GLPI glpi = (LPFN_GLPI) GetProcAddress(GetModuleHandle(TEXT("kernel32")), "GetLogicalProcessorInformation");
    if (glpi) 
    {
        std::vector<BYTE> buffer;
        PSYSTEM_LOGICAL_PROCESSOR_INFORMATION info = NULL;
        DWORD bufsize = 0;

        while (!glpi(info, &bufsize))
        {
            if (GetLastError() != ERROR_INSUFFICIENT_BUFFER)
                return 0;

            buffer.resize(bufsize);
            info = (PSYSTEM_LOGICAL_PROCESSOR_INFORMATION) &buffer[0];
        } 

        DWORD logicalProcessorCount = 0;

        while (bufsize >= sizeof(SYSTEM_LOGICAL_PROCESSOR_INFORMATION))
        {
            if (info->Relationship == RelationProcessorCore)
            {
                // A hyperthreaded core supplies more than one logical processor.
                logicalProcessorCount += CountSetBits(info->ProcessorMask);
            }

            bufsize -= sizeof(SYSTEM_LOGICAL_PROCESSOR_INFORMATION);
            ++info;
        }

        return logicalProcessorCount;
    }

    // fallback to GetSystemInfo() last ...

    SYSTEM_INFO si = {0};
    GetSystemInfo(&si);

    return si.dwNumberOfProcessors;
}

int main(int argc, char* argv[])
{
    DWORD dwNumProcessors = GetInstalledProcessorCount();

    std::vector<PROCESSOR_POWER_INFORMATION> a(dwNumProcessors);
    DWORD dwSize = sizeof(PROCESSOR_POWER_INFORMATION) * dwNumProcessors;

    while (CallNtPowerInformation(ProcessorInformation, NULL, 0, &a[0], dwSize) == STATUS_SUCCESS)
    {
        // use data in `a` as needed...
    }

    a.clear();

    system("pause");
    return 0;
}

UPDATE

根据@DanielWiddis的评论,CallNtProcessInformation()只返回调用线程当前处理器组的电源信息。因此,如果您的PC安装了超过64个逻辑处理器,您可以循环调用CallNtProcessInformation(),根据需要在每次迭代时根据需要通过SetThreadGroupAffinity()更改调用线程的当前进程组,这是我在网上找到的this discussion。要确定存在哪些处理器组以及每组有多少逻辑处理器,请使用GetLogicalProcessorInformationEx()GetActiveProcessorGroupCount()GetActiveProcessorCount()

最新问题
© www.soinside.com 2019 - 2024. All rights reserved.