Reputation: 2881
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
}
}
}
Upvotes: 4
Views: 594
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
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