none
Windows10で他プロセスのリストコントロールの内容を取得したい RRS feed

  • 質問

  • Windows10で他プロセスのリストコントロールの内容を取得したいです。

    方法を教えてください。

    発生している問題

    C++にて他プロセスのリストコントロールのテキストを取得するためにSendMessage関数にLVM_GETITEMコマンドでWPARAMにテキストを取りたい行のインデックス、LPARAMにVirtualAllocEx関数で取得した仮想メモリを指定して使用しています。
    結果は正常(true)で返ってくるのですが、テキスト(szText)の中身は全て'\0'です。

    該当のソースコード

    <button class="btnClipboardCopy js-clipboardCopy" data-clipboard-target="#clipboardCopy0" style="outline:none;right:8px;display:inline;border-width:initial;border-style:none;border-color:initial;width:12px;height:12px;background-color:#f8f8f8;background-image:url("/img/common/icnCopy.png?d41d8cd98f00b204e9800998ecf8427e");background-size:12px 12px;background-repeat:no-repeat;cursor:pointer;opacity:0.5;" title="このコードをクリップボードにコピー"></button>#include "stdafx.h"
    #include <psapi.h>
    #include <tlhelp32.h>
    #include "rpa_operation.h"
    
    ///////////////////////
    //ファイル内での構造体
    ///////////////////////
    //プロセス検索構造体
    struct stProcessSearch
    {
        DWORD    m_dwProcessIDs[1024];
        int        m_nProcessCount;
        stApplication_info* m_pApplication_info;
    };
    
    //子ウィンドウ検索構造体
    struct stChildWindow
    {
        CString m_strTitleName;
        CString m_strClassName;
        int        m_iControlID;
        int        m_nCount[2];
        CWnd*    m_pWnd;
    };
    
    ///////////////////////
    //プロトタイプ宣言
    ///////////////////////
    CWnd* ControlSerach(stApplication_info& application_info, LPCTSTR pszChildWindowTitle, LPCTSTR pszTitle, LPCTSTR pszClassName, int iControlID);    //コントロールの検索
    BOOL GetProcessIdByName(DWORD dwProcessID, CString& exeName);    //プロセスIDに対するexe名を取得する
    BOOL CALLBACK EnumWndProc(HWND hWnd, LPARAM lParam);            //他のプログラムのウインドウハンドルを取得する
    BOOL CALLBACK EnumChildProc(HWND hWnd, LPARAM lParam);            //子ウィンドウのウインドウハンドルを取得する
    int FindMenu(CMenu* pMenu, LPCTSTR pszTitle);                    //メニューの検索
    
    #define GWL_HWNDPARENT      (-8)
    
    class CVirtualMemory
    {
    private:
        HANDLE m_hProcess;
        CArray<LPVOID> m_arrayAlloc;
    public:
        CVirtualMemory(CWnd* pWnd)
        {
            DWORD dwPID;
            GetWindowThreadProcessId(pWnd->m_hWnd, &dwPID);
            m_hProcess = OpenProcess(PROCESS_ALL_ACCESS, FALSE, dwPID);
        }
        LPVOID VirtualAlloc(SIZE_T dwSize)
        {
            LPVOID pAlloc = VirtualAllocEx(m_hProcess, NULL, dwSize, MEM_RESERVE | MEM_COMMIT, PAGE_READWRITE);
            if (pAlloc != NULL) {
                m_arrayAlloc.Add(pAlloc);
            }
            return pAlloc;
        }
    
        BOOL Write(LPVOID lpBaseAddress, LPCVOID lpBuffer, SIZE_T  nSize)
        {
            return WriteProcessMemory(m_hProcess, lpBaseAddress, lpBuffer, nSize, NULL);
        }
    
        BOOL Read(LPVOID lpBaseAddress, LPVOID lpBuffer, SIZE_T  nSize)
        {
            return ReadProcessMemory(m_hProcess, lpBaseAddress, lpBuffer, nSize, NULL);
        }
    
        CVirtualMemory()
        {
            for(int i = 0; i < m_arrayAlloc.GetCount(); i++)
            {
                VirtualFreeEx(m_hProcess, m_arrayAlloc[i], 0, MEM_RELEASE);
            }
            CloseHandle(m_hProcess);
        }
    };
    
    //アプリケーション情報の取得
    BOOL GetApplicationInfo(stApplication_info& application_info)
    {
        stProcessSearch processSearch;
        processSearch.m_pApplication_info = &application_info;
    
        // PID一覧を取得
        DWORD cbNeeded;
        if (!EnumProcesses(processSearch.m_dwProcessIDs, sizeof(processSearch.m_dwProcessIDs), &cbNeeded)) {
            return FALSE;
        }
        processSearch.m_nProcessCount = cbNeeded / sizeof(DWORD);
    
        EnumWindows(EnumWndProc, (LPARAM)&processSearch);
    
        if (application_info.m_dwProcessID != 0) {
            return TRUE;
        }
        return FALSE;
    }
    
    //プロセスIDに対するexe名を取得する
    BOOL GetProcessIdByName(DWORD dwProcessID, CString& exeName)
    {
        auto entry = PROCESSENTRY32{ sizeof(PROCESSENTRY32) };
    
        auto hSnapshot = CreateToolhelp32Snapshot(TH32CS_SNAPPROCESS, 0);
    
        if (Process32First(hSnapshot, &entry)) {
            do {
                if (dwProcessID == entry.th32ProcessID) {
                    exeName = entry.szExeFile;
                    CloseHandle(hSnapshot);
                    return TRUE;
                }
            } while (Process32Next(hSnapshot, &entry));
        }
    
        CloseHandle(hSnapshot);
        return FALSE;
    }
    
    //他のプログラムのウインドウハンドルを取得する
    BOOL CALLBACK EnumWndProc(HWND hWnd, LPARAM lParam)
    {
        stProcessSearch* pProcessSearch = (stProcessSearch*)lParam;
        stApplication_info* pApplication_info = pProcessSearch->m_pApplication_info;
        CWnd* pWnd = CWnd::FromHandle(hWnd);
        // ウィンドウとプロセスIDを比較
        DWORD dwProcessID;
        ::GetWindowThreadProcessId(hWnd, &dwProcessID);
        for (int i = 0; i < pProcessSearch->m_nProcessCount; i++) {
            if (dwProcessID == pProcessSearch->m_dwProcessIDs[i]) {
                //ウインドウタイトル取得
                CString strTitle;
                pWnd->GetWindowText(strTitle);
                if (!strTitle.IsEmpty() && GetWindowLong(hWnd, GWL_HWNDPARENT) == 0 && pWnd->IsWindowVisible()) {
                    // プロセス名を取得
                    CString strProcName;
                    GetProcessIdByName(dwProcessID, strProcName);
                    if (strProcName.Compare(pApplication_info->m_strApplicationName) == 0)
                    {
                        pApplication_info->m_dwProcessID = dwProcessID;
                        pApplication_info->m_strWindowName = strTitle;
                        pApplication_info->m_pWnd = pWnd;
                    }
                }
                break;
            }
        }
        return TRUE;
    }
    
    //リストビュー選択メッセージ
    BOOL ListViewSelect(stApplication_info& application_info, LPCTSTR pszChildWindowTitle, int iControlID, LPCTSTR pszText, int nSelect, BOOL bLeftClick)
    {
        CWnd* pWnd = NULL;
        if ((pWnd = ControlSerach(application_info, pszChildWindowTitle, NULL, L"SysListView32", iControlID)) == NULL) {
            return FALSE;
        }
        CListCtrl ListCtrl;
        ListCtrl.Attach(pWnd->m_hWnd);
    
        if (wcslen(pszText) > 0) {
            TCHAR szText[256] = { 0 };
            // テキストを取得する
            CVirtualMemory vm(application_info.m_pWnd);
            LVITEM *pLvItem_vm = (LVITEM*)vm.VirtualAlloc(sizeof(LVITEM));
            LPTSTR pText_vm = (LPTSTR)vm.VirtualAlloc(sizeof(szText));
    
            LVITEM LvItem = { 0 };
            LvItem.mask = LVIF_TEXT;
            LvItem.iSubItem = 0;
            LvItem.pszText = pText_vm;
            LvItem.cchTextMax = sizeof(szText) / sizeof(TCHAR);
    
            for (int i = 0; i < ListCtrl.GetItemCount(); i++) {
                LvItem.iItem = i;
    
                vm.Write(pLvItem_vm, &LvItem, sizeof(LVITEM));
    
                BOOL bRes = (BOOL)ListCtrl.SendMessage(LVM_GETITEM, nSelect, (LPARAM)pLvItem_vm);
    
                if (bRes == TRUE) {
                    vm.Read(pText_vm, szText, sizeof(szText));
                    if (wcscmp(szText, pszText) == 0) {
                        nSelect = i;
                        break;
                    }
                }
            }
        }
        if (nSelect < 0 || nSelect >= ListCtrl.GetItemCount()) {
            ListCtrl.Detach();
            return FALSE;
        }
    
        // 矩形を取得する
        RECT rect;
        CVirtualMemory vm(application_info.m_pWnd);
        LVITEMINDEX *plvItemIndex_vm = (LVITEMINDEX*)vm.VirtualAlloc(sizeof(LVITEMINDEX));
        LPTSTR pRect_vm = (LPTSTR)vm.VirtualAlloc(sizeof(rect));
    
        LVITEMINDEX lvItemIndex = { 0 };
        lvItemIndex.iGroup = 0;
        lvItemIndex.iItem = nSelect;
    
        vm.Write(plvItemIndex_vm, &lvItemIndex, sizeof(LVITEMINDEX));
    
        BOOL bRes = (BOOL)ListCtrl.SendMessage(LVM_GETITEMINDEXRECT, (WPARAM)plvItemIndex_vm, (LPARAM)pRect_vm);
    
        if (bRes == TRUE) {
            vm.Read(plvItemIndex_vm, &lvItemIndex, sizeof(LVITEMINDEX));
            vm.Read(pRect_vm, &rect, sizeof(RECT));
    
            application_info.m_pWnd->SetForegroundWindow();
    
            if (bLeftClick) {
                ListCtrl.PostMessage(WM_LBUTTONDOWN, MK_LBUTTON, MAKELPARAM(rect.left, rect.top));
            }
            else {
                ListCtrl.PostMessage(WM_RBUTTONDOWN, MK_RBUTTON, MAKELPARAM(rect.left, rect.top));
            }
        }
    
        ListCtrl.Detach();
        return TRUE;
    }
    //コントロールの検索
    CWnd* ControlSerach(stApplication_info& application_info, LPCTSTR pszChildWindowTitle, LPCTSTR pszTitle, LPCTSTR pszClassName, int iControlID)
    {
        stChildWindow ChildWindow;
        ChildWindow.m_pWnd = NULL;
        ChildWindow.m_strClassName = pszClassName;
        ChildWindow.m_strTitleName = pszTitle;
        ChildWindow.m_iControlID = iControlID;
        CWnd* pWnd = application_info.m_pWnd;
        if (pszChildWindowTitle != NULL && wcslen(pszChildWindowTitle) != 0) {
            CWnd* pFind = application_info.m_pWnd->FindWindow(NULL, pszChildWindowTitle);
            if (pFind) {
                pWnd = pFind;
            }
        }
        EnumChildWindows(pWnd->m_hWnd, EnumChildProc, (LPARAM)&ChildWindow);
        return ChildWindow.m_pWnd;
    }
    
    //子ウィンドウのウインドウハンドルを取得する
    BOOL CALLBACK EnumChildProc(HWND hWnd, LPARAM lParam)
    {
        stChildWindow* pChildWindow = (stChildWindow*)lParam;
        CWnd* pWnd = CWnd::FromHandle(hWnd);
    
        CString strTitle;
        pWnd->GetWindowText(strTitle);
        int iCtrlID = pWnd->GetDlgCtrlID();
        TCHAR szClassName[1024];
        GetClassName(hWnd, szClassName, sizeof(szClassName));
    
        if (!pChildWindow->m_strTitleName.IsEmpty()) {
            if (pChildWindow->m_iControlID != 0) {
                if (!pChildWindow->m_strClassName.IsEmpty()) {
                    if (pChildWindow->m_strTitleName.Compare(strTitle) == 0 &&
                        pChildWindow->m_iControlID == iCtrlID &&
                        pChildWindow->m_strClassName.Compare(szClassName) == 0) {
                        pChildWindow->m_pWnd = pWnd;
                        return FALSE;
                    }
                }
                else {
                    if (pChildWindow->m_strTitleName.Compare(strTitle) == 0 &&
                        pChildWindow->m_iControlID == iCtrlID) {
                        pChildWindow->m_pWnd = pWnd;
                        return FALSE;
                    }
                }
            }
            else if (!pChildWindow->m_strClassName.IsEmpty()) {
                if (pChildWindow->m_strTitleName.Compare(strTitle) == 0 &&
                    pChildWindow->m_strClassName.Compare(szClassName) == 0) {
                    pChildWindow->m_pWnd = pWnd;
                    return FALSE;
                }
            }
            else {
                if (pChildWindow->m_strTitleName.Compare(strTitle) == 0) {
                    pChildWindow->m_pWnd = pWnd;
                    return FALSE;
                }
            }
        }
        else {
            if (pChildWindow->m_iControlID != 0) {
                if (!pChildWindow->m_strClassName.IsEmpty()) {
                    if (pChildWindow->m_iControlID == iCtrlID &&
                        pChildWindow->m_strClassName.Compare(szClassName) == 0) {
                        pChildWindow->m_pWnd = pWnd;
                        return FALSE;
                    }
                }
                else {
                    if (pChildWindow->m_iControlID == iCtrlID) {
                        pChildWindow->m_pWnd = pWnd;
                        return FALSE;
                    }
                }
            }
            else if (!pChildWindow->m_strClassName.IsEmpty()) {
                if (pChildWindow->m_strClassName.Compare(szClassName) == 0) {
                    pChildWindow->m_pWnd = pWnd;
                    return FALSE;
                }
            }
        }
        return TRUE;
    }
    <button class="btnClipboardCopy js-clipboardCopy" data-clipboard-target="#clipboardCopy1" style="outline:none;right:8px;display:inline;border-width:initial;border-style:none;border-color:initial;width:12px;height:12px;background-color:#f8f8f8;background-image:url("/img/common/icnCopy.png?d41d8cd98f00b204e9800998ecf8427e");background-size:12px 12px;background-repeat:no-repeat;cursor:pointer;opacity:0.5;" title="このコードをクリップボードにコピー"></button>#pragma once
    
    //アプリケーション情報の構造体
    struct stApplication_info
    {
        CString    m_strApplicationName;    //exe
        DWORD    m_dwProcessID;
        CString m_strWindowName;
        CWnd*    m_pWnd;
    };
    
    //アプリケーション情報の取得
    BOOL GetApplicationInfo(stApplication_info& application_info);
    //リストビュー選択メッセージ
    BOOL ListViewSelect(stApplication_info& application_info, LPCTSTR pszChildWindowTitle, int iControlID, LPCTSTR pszTitle, int nSelect, BOOL bLeftClick);

    試したこと

    Windows7では取得できたのですが、Windows10では取得できません。

    補足情報

    VS2017で作成しました。



    2019年12月2日 23:35

すべての返信

  • ベンチャー社長さん、こんにちは。フォーラムオペレーターのクモです。
    MSDNフォーラムにご投稿くださいましてありがとうございます。

    ご説明によると、これはWindows SDKに関連してると思いますが、
    より良いサポートのため、Windows SDKにご投稿のほどお願いします。

    どうぞよろしくお願いいたします。 

    MSDN/ TechNet Community Support Kumo ~参考になった投稿には「回答としてマーク」をご設定ください。なかった場合は「回答としてマークされていない」も設定できます。同じ問題で後から参照した方が、情報を見つけやすくなりますので、 ご協力くださいますようお願いいたします。また、MSDNサポートに賛辞や苦情がある場合は、MSDNFSF@microsoft.comまでお気軽にお問い合わせください。~

    2019年12月9日 1:44
  • 32bit / 64bitの差は考慮されていますでしょうか? また、Windows 7 / Windows 10両環境はそれぞれどちらだったのでしょうか?
    2019年12月9日 3:55
  • ありがとうございます。

    32bit / 64bitの差は考慮に入れていませんでした。64bitアプリケーションから32bitアプリケーションを操作しようとしていました。

    32bitアプリケーション用の構造体を用意するか、32bitアプリケーションとして作るかでした。

    2019年12月10日 12:38
  • 考慮していなかったことはわかりましたが、取得できるとされていたWindows 7が32bit / 64bitの影響を受けていたかいなかったは答えていただけませんでした。OS差異による問題なのか、32bit / 64bitによる問題なのか、原因を特定しないことには対処は難しいと思います。
    2019年12月11日 2:31