4

仮想プリンターがインストールされているかどうかを確認するコードを書いています。このために、EnumMonitors winapi を使用しています。コードはコンパイルされますが、プログラムを実行しようとするとクラッシュします。私のプログラムをデバッグすると、次の行でセグメンテーション違反エラーが発生しました:EnumMonitors(NULL, 0, (LPBYTE)buffer, sizeof(buffer), &capacity, &returned); 追加した .pro ファイルLIBS += "C:\Program Files\Microsoft SDKs\Windows\v7.1\Lib\WinSpool.Lib" に EnumMonitors WinAPI を機能させるために何ができるでしょうか?

私のコード:

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

編集: 2 番目の引数としてコードを 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を適切な出力バッファ サイズで適切にサイズ設定し、( を使用して) ベクトルの最初のバイトのアドレスをstd::vector::data()の 2 番目の呼び出しに渡し、出力バッファを構造体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

2番目のパラメーターに「0」を渡します。1(または2)にする必要があります。

MSDNによると

レベル[in]pMonitorsが指す構造のバージョン。

この値は1または2にすることができます。

于 2013-03-15T18:37:58.733 に答える