Antonio Dias
Antonio Dias

Reputation: 2881

Segmentation fault on EnumMonitors WinAPI

I'm writing a code to check if my virtual printer is installed, for this i'm using the EnumMonitors winapi, the code compiles, but when i try to run my program, it crashes. Debugging my program, i got Segmentation fault error at this line: EnumMonitors(NULL, 0, (LPBYTE)buffer, sizeof(buffer), &capacity, &returned); In the .pro file i added LIBS += "C:\Program Files\Microsoft SDKs\Windows\v7.1\Lib\WinSpool.Lib" What i can do to make the EnumMonitors WinAPI work?

My code:

#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
        }
    }
}

Edit: I've updated my code from 0 to 1 as second argument

Upvotes: 4

Views: 594

Answers (3)

Mr.C64
Mr.C64

Reputation: 42984

The following commented code seems to work with VS2010 SP1 (VC10).

Follow the comments for an idea on how to call the EnumMonitors() API.

Basically, in a first call you ask for the output buffer size, calling EnumMonitors() with cbBuf set to zero.

Then you properly size a std::vector with proper output buffer size, and pass the address of the first byte in the vector (using std::vector::data()) to a second call to EnumMonitors(), to fill the output buffer with MONITOR_INFO_1 structures.

(Note that std::vector will automatically release its own allocated memory on function exit, both on success path and on failure exception-throwing paths.)

#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;
    }
}

Upvotes: 1

Remy Lebeau
Remy Lebeau

Reputation: 597061

Which compiler are you using? When I try your code as-is in C++Builder, EnumMonitors() does not crash and returns an ERROR_INVALID_LEVEL error as expected. That makes me think that maybe your compiler is not declaring EnumMonitors() correctly, mismanaging the call stack, for instance.

Upvotes: 2

selbie
selbie

Reputation: 104559

You are passing in "0" for the second parameter. It should 1 (or 2).

As per MSDN

Level [in] The version of the structure pointed to by pMonitors.

This value can be 1 or 2.

Upvotes: 0

Related Questions