5

このコードを使用してウィンドウ名を取得します。

#include <Windows.h>
#include <stdio.h>

int main() {
    TCHAR title[500];
    int i=0;
    while(i<10) {
        GetWindowText(GetForegroundWindow(), title, 500);
        printf("%s\n",title);
        i++;
        system("pause");
    }
}

ただし、前景ウィンドウのみを取得します。

  1. すべてのウィンドウ名を取得する必要があります

  2. または、実際には、「notepad.exe」プロセスに属する特定のウィンドウ名を1つ取得する必要があります。

ご協力いただきありがとうございます :)

4

3 に答える 3

8

生のwinapiを使用することで、これ以上簡単な方法はないと思いますが、次のようになります。

  1. Toolhelp32 APIを使用して、実行可能ファイル名が「notepad.exe」と一致するプロセスIDのリストを取得します。
  2. ウィンドウを列挙して、PIDがリスト内の1つと一致するものを見つけます。
  3. そのウィンドウのタイトルを取得し、それを使ってやりたいことをします。

これが私が思いついたコードです:

#include <iostream>
#include <string>
#include <vector>

#include <windows.h>
#include <tlhelp32.h>

bool isNotepad(const PROCESSENTRY32W &entry) {
    return std::wstring(entry.szExeFile) == L"notepad.exe";
}

BOOL CALLBACK enumWindowsProc(HWND hwnd, LPARAM lParam) {
    const auto &pids = *reinterpret_cast<std::vector<DWORD>*>(lParam);

    DWORD winId;
    GetWindowThreadProcessId(hwnd, &winId);

    for (DWORD pid : pids) {
        if (winId == pid) {
            std::wstring title(GetWindowTextLength(hwnd) + 1, L'\0');
            GetWindowTextW(hwnd, &title[0], title.size()); //note: C++11 only

            std::cout << "Found window:\n";
            std::cout << "Process ID: " << pid << '\n';
            std::wcout << "Title: " << title << "\n\n";
        }
    }

    return TRUE;
}

int main() {
    std::vector<DWORD> pids;

    HANDLE snap = CreateToolhelp32Snapshot(TH32CS_SNAPPROCESS, 0);
    // Do use a proper RAII type for this so it's robust against exceptions and code changes.
    auto cleanupSnap = [snap] { CloseHandle(snap); };

    PROCESSENTRY32W entry;
    entry.dwSize = sizeof entry;

    if (!Process32FirstW(snap, &entry)) {
        cleanupSnap();
        return 0;
    }

    do {
        if (isNotepad(entry)) {
            pids.emplace_back(entry.th32ProcessID);
        }
    } while (Process32NextW(snap, &entry));
    cleanupSnap();

    EnumWindows(enumWindowsProc, reinterpret_cast<LPARAM>(&pids));
}

順番に通過する:

まず、関数と文字列の幅広いバージョンに注意してください。TCHAR使用するのは良くありません。タイトルの1つにUTF-16が含まれているとしたら残念です。

isNotepad構造体の実行可能ファイル名のメンバーをチェックして、PROCESSENTRY32W「notepad.exe」と等しいかどうかを確認するだけです。これは、メモ帳がこのプロセス名を使用し、メモ帳以外のものがプロセス名を使用しないことを前提としています。誤検知を排除するには、さらにチェックを行う必要がありますが、確信が持てないことはありません。

で、これは実際にはPIDのベクトルへのポインタであるenumWindowsProcことに注意してください(グローバルを使用する必要がないようにするため)。lParamこれは、関数の最初のキャストを構成します。次に、見つけたウィンドウのPIDを取得します。次に、渡されたPIDのリストをループして、一致するかどうかを確認します。もしそうなら、私はタイトルをつかんで、PIDとウィンドウタイトルを出力することを選択しました。標準の文字列をバッファとして使用することは、C ++ 11でのみ機能することが保証されており、余分なヌル文字(長さの一部ではない)を上書きしてはならないことに注意してください。最後に、TRUEすべてのトップレベルウィンドウを通過するまで列挙し続けるように戻ります。

main最初に表示されるのは、最初は空のPIDのリストです。プロセスのスナップショットを取り、それらを調べます。ヘルパー関数を使用してisNotepad、プロセスが「notepad.exe」であるかどうかを確認し、そうである場合は、そのPIDを保存します。最後にEnumWindows、ウィンドウを列挙するために呼び出し、必要なものに偽装したPIDのリストを渡しますLPARAM

このようなことをしていなければ少し注意が必要ですが、それが理にかなっていることを願っています。子ウィンドウが必要な場合、正しい方法は、見つかったウィンドウに関する情報を出力する場所で、を追加しEnumChildWindowsProcて呼び出すことです。EnumChildWindows私が正しければ、EnumChildWindows孫などを取得するために再帰的に電話をかける必要はありません。孫などは最初の電話に含まれるからです。

于 2012-12-25T10:34:32.920 に答える
3

を呼び出しEnumWindowsます。トップレベルウィンドウごとに1回呼び出されるコールバック関数を提供します。次に、特定の基準で各ウィンドウのプロパティを確認できます。呼び出しGetWindowTextて、探している値と照合することができます。

于 2012-12-25T11:36:18.317 に答える
0

メモ帳ウィンドウのタイトルを取得する方法。

あなたが尋ねる、

「「notepad.exe」プロセスに属する特定のウィンドウ名を1つ取得する必要があります」

ええと、C++はそのタスクにとって間違った言語です。これは、スクリプトによってより自然かつ簡単に実行できるタスクです。たとえば、すべてのメモ帳ウィンドウのタイトルを報告するWindowsバッチファイルは次のとおりです。

@echo off
for /f "usebackq delims=, tokens=1,9" %%t in (`tasklist /v /fo csv`) do (
    if %%t=="notepad.exe" echo %%u
    )

使用例:

[d:\ dev \ misc \ so \ notepad_window_name]
>タイトル
「無題-メモ帳」

[d:\ dev \ misc \ so \ notepad_window_name]
> _

最新のUnicodeC++Windowsプログラムの書き方。

また、言語の選択に加えて、C ++コードがTCHAR型を使用してアドバタイズし、UnicodeとANSIの両方としてコンパイルできることを考慮してください。ただし、を使用しているため、Unicodeとしてコンパイルすることはできませんprintf。これは、愚かTCHARすぎると、バグを導入するようにあなたを誤解させたことを意味します。T単純に次のようなものを使用しないでくださいTCHAR。これは、コードを難読化してバグを導入するための唯一の方法です。

Unicodeのみのプログラムを作成する方法を例示するコードを次に示します。

バッチファイルとは対照的に、これは1つのメモ帳ウィンドウのタイトルのみを取得します。

#include <iostream>     // std::wcout, std::endl
#include <stdlib.h>     // EXIT_FAILURE, EXIT_SUCCESS
#include <string>       // std::wstring
using namespace std;

#define UNICODE
#include <windows.h>

int main()
{
    HWND const window = FindWindow( L"Notepad", nullptr );
    if( window == 0 )
    {
        wcerr << "!Didn't find any Notepad window." << endl;
    }
    else
    {
        int const   nAttempts   = 3;
        for( int i = 1;  i <= nAttempts;  ++i )
        {
            int const   bufferSize  = 1 + GetWindowTextLength( window );
            wstring     title( bufferSize, L'\0' );
            int const   nChars  = GetWindowText( window, &title[0], bufferSize );

            if( nChars == 0 || nChars < GetWindowTextLength( window ) )
            {
                Sleep( 20 );  continue;
            }
            title.resize( nChars );
            wcout << "'" << title << "'" << endl;
            return EXIT_SUCCESS;
        }
        wcerr << "!Found a Notepad window but unable to obtain the title." << endl;
    }
    return EXIT_FAILURE;
}

したがって、C ++は間違った言語の選択でありTCHAR、完全に間違ったデータ型の選択です。


他の要件が言語の選択を強制する場合のC++の使用方法。

何らかの理由でコードをC++として必要とすべてのメモ帳ウィンドウのタイトルが必要な場合、バッチファイルは機能せず、上記のC++コードは機能しません。この場合、DavidHeffermanが提案EnumWindowsするようにWindowsAPI関数を使用します。また、コードを読む人の難読化、微妙なバグ、誤解を招くことを避けるために、上記のコードで例示されているように、ではなくベースの文字列を使用してください。wchar_tTCHAR

于 2012-12-25T13:43:51.003 に答える