4

我正在编写一个代码来检查我的虚拟打印机是否已安装,为此我使用 EnumMonitors winapi,代码编译,但是当我尝试运行我的程序时,它崩溃了。EnumMonitors(NULL, 0, (LPBYTE)buffer, sizeof(buffer), &capacity, &returned); 调试我的程序时,我在这一行遇到了分段错误错误LIBS += "C:\Program Files\Microsoft SDKs\Windows\v7.1\Lib\WinSpool.Lib"

我的代码:

#include <windows.h>
#include <winspool.h>

void Enum()
{
    char buffer[4096];
    DWORD capacity;
    DWORD returned;
    QString monitorname = "Redirected Port";

    /*Program crashes here*/ EnumMonitors(NULL, 1, (LPBYTE)buffer, sizeof(buffer), &capacity, &returned);

    MONITOR_INFO_1 *mi = (MONITOR_INFO_1*)buffer;
    for (uint i = 0; i < returned; i++)
    {
        if (QString::fromWCharArray(mi[i].pName) == monitorname)
        {
            //Do something
        }
    }
}

编辑:我已将我的代码从 0 更新为 1 作为第二个参数

4

3 回答 3

2

您使用的是哪个编译器?当我在 C++Builder 中按原样尝试您的代码时,EnumMonitors()不会崩溃并按ERROR_INVALID_LEVEL预期返回错误。这让我觉得你的编译器可能没有EnumMonitors()正确声明,例如调用堆栈管理不善。

于 2013-03-15T19:06:20.057 回答
1

以下注释代码似乎适用于 VS2010 SP1 (VC10)。

按照评论了解如何调用EnumMonitors()API。

基本上,在第一次调用中,您要求输出缓冲区大小,调用EnumMonitors()cbBuf设置为零。

然后,您std::vector使用适当的输出缓冲区大小正确调整 a 的大小,并将向量中第一个字节的地址(使用std::vector::data())传递给对 的第二次调用EnumMonitors(),以用结构填充输出缓冲区MONITOR_INFO_1

(请注意,在函数退出时,无论是在成功路径上还是在失败异常抛出路径上,std::vector都会自动释放自己分配的内存。)

#include <exception>        // for std::exception
#include <iostream>         // for std::wcout, std::wcerr, std::endl
#include <sstream>          // for std::ostringstream
#include <stdexcept>        // for std::runtime_error
#include <vector>           // for std::vector
#include <windows.h>        // Win32 SDK main header
#include <winspool.h>       // for EnumMonitors()
using namespace std;

void ThrowOnApiFailure(const char* apiName, DWORD errorCode)
{
    ostringstream errorMessage;
    errorMessage << apiName << "() failed with error code " << errorCode;
    throw runtime_error(errorMessage.str());    
}

void PrintMonitors()
{
    static const int kMonitorInfoLevel = 1; // for MONITOR_INFO_1

    // Ask output buffer size
    DWORD bufferSize = 0;
    DWORD infoCount = 0;
    ::EnumMonitors(
        nullptr, 
        kMonitorInfoLevel,
        nullptr,
        0,          // ask buffer size
        &bufferSize,
        &infoCount);
    DWORD error = ::GetLastError();
    if (error != ERROR_INSUFFICIENT_BUFFER)
    {
        ThrowOnApiFailure("EnumMonitors", error);
    }   

    // Size output buffer
    vector<BYTE> buffer(bufferSize);

    // Fill buffer with monitor info
    if ( ! ::EnumMonitors(
        nullptr,
        kMonitorInfoLevel,
        buffer.data(),
        buffer.size(),
        &bufferSize,
        &infoCount       
        ) )    
    {
        error = ::GetLastError();
        ThrowOnApiFailure("EnumMonitors", error);
    }

    // Print monitor info
    const MONITOR_INFO_1 * monitorInfo = 
        reinterpret_cast<const MONITOR_INFO_1*>(buffer.data());    
    for (DWORD i = 0; i < infoCount; i++)
    {
        wcout << monitorInfo[i].pName << endl;
    }
}

int main()
{
    try
    {
        PrintMonitors();    
    }
    catch(const exception& e)
    {
        wcerr << "\n*** ERROR: " << e.what() << endl;
    }
}
于 2013-03-15T18:59:05.367 回答
0

您正在为第二个参数传递“0”。它应该是 1(或 2)。

根据MSDN

Level [in] pMonitors 指向的结构版本。

该值可以是 1 或 2。

于 2013-03-15T18:37:58.733 回答