使用C++获取应用程序“主窗体”的IUIAutomationElement?

yyhrrdl8  于 2023-05-02  发布在  其他
关注(0)|答案(1)|浏览(162)

我正在Visual Studio 2022中用C++编程一个控制台应用程序,我想获取特定应用程序的“主窗体”(大的外部窗体)的IUIAutomationElement,以便以后可以获取它的子窗体。我看到两种方法:
1.使用进程ID或进程名称。我有工作源代码,可以从进程名称中获取进程ID,当然,还有进程名称(以。exe)是已知的。
1.以“查找所有应用程序”的方式,然后通过比较 * 子字符串 *(不是完整的字符串,因为这可能会有所不同!)在表单的标题中。
请注意,我 * 不想使用任何位置 *(e。例如,鼠标位置)来定位IUIAutomationElement。有人能帮帮我吗?

hmae6n7t

hmae6n7t1#

在@SimonMourier和一些谷歌的帮助下,我终于解决了这个问题。首先,我需要从我的dwProcessId中获取第一个dwThreadId,我使用函数GetFirstThreadId:

// Found this function (original name was ListProcessModules) on 
// https://learn.microsoft.com/en-us/windows/win32/toolhelp/taking-a-snapshot-and-viewing-processes
static DWORD GetFirstThreadId(DWORD dwProcessId) {
    HANDLE hThreadSnap = INVALID_HANDLE_VALUE;
    THREADENTRY32 te32;

    // Take a snapshot of all running threads  
    hThreadSnap = CreateToolhelp32Snapshot(TH32CS_SNAPTHREAD, 0);
    if (hThreadSnap == INVALID_HANDLE_VALUE) {
        return(FALSE);
    }

    // Fill in the size of the structure before using it. 
    te32.dwSize = sizeof(THREADENTRY32);

    // Retrieve information about the first thread,
    // and exit if unsuccessful
    if (!Thread32First(hThreadSnap, &te32)) {
        wprintf(L"Thread32First"); // show cause of failure
        CloseHandle(hThreadSnap);          // clean the snapshot object
        return(FALSE);
    }

    // Now walk the thread list of the system,
    // and display information about each thread
    // associated with the specified process
    do {
        if (te32.th32OwnerProcessID == dwProcessId) {
//            wprintf(L"\n\n     THREAD ID      = 0x%08X", te32.th32ThreadID);
//            wprintf(L"\n     Base priority  = %d", te32.tpBasePri);
//            wprintf(L"\n     Delta priority = %d", te32.tpDeltaPri);
//            wprintf(L"\n");
            CloseHandle(hThreadSnap);          // clean the snapshot object
            return te32.th32ThreadID;
        }
    } while (Thread32Next(hThreadSnap, &te32));

    CloseHandle(hThreadSnap);          // clean the snapshot object
    return 0;
}

然后调用EnumThreadWindows和ElementFromHandle:

static UIA_HWND g_hwnd;
static int numCallbackCallsLeft;

int _tmain(int argc, _TCHAR* argv[]) {
    const std::wstring processName = L"myExecutable.exe";
    DWORD dwProcessID = FindProcessId(processName);
    DWORD dwThreadID = GetFirstThreadId(dwProcessID);
    HWND hTop = NULL;
    numCallbackCallsLeft = 1;
    BOOL bResult = EnumThreadWindows(dwThreadID, EnumWindowsCallBackFnc, (LPARAM)&hTop);
    while (0 < numCallbackCallsLeft) {
        Sleep(1);
    }
    if (SUCCEEDED(CoInitialize(NULL))) {
        if (SUCCEEDED(g_pAutomation.CoCreateInstance(CLSID_CUIAutomation8))) { // or CLSID_CUIAutomation 
            CComPtr<IUIAutomationElement> pElement;
            if (SUCCEEDED(g_pAutomation->ElementFromHandle(g_hwnd, &pElement))) {
                // Hooray, we now have pElement!!!
            }
        }
    }
    CoUninitialize();
    return 0;
}

// Pointer to this function is passed as parameter to EnumThreadWindows function
static BOOL CALLBACK EnumWindowsCallBackFnc(HWND hwnd, LPARAM lParam) {
    wprintf(L"EnumWindowsCallBackFnc. hwnd: %d\n", (int)hwnd);
    g_hwnd = hwnd;

    // This function is called for all siblings windows owned by given thread
    // So, store hwnd for the later use...
    numCallbackCallsLeft--;
    return (0 < numCallbackCallsLeft); // return TRUE if you want to continue windows enumeration.
    // If you found the proper window, just return FALSE and windows enumeration will stop
}

相关问题