Krombik / keysender

Node.js Desktop Automation for Windows.
MIT License
75 stars 6 forks source link

how to active the second window with the same className or similiar title with workwindow #3

Closed YMC-GitHub closed 2 years ago

YMC-GitHub commented 2 years ago

dear keysender: hi!i am please to use keysender to do Desktop Automation task. but i am in thinking--how to active the second window with the same className or similiar title with workwindow easyily?the windows is under the same icon in destop task menu!

                                                                                        ymc
ShenHongFei commented 2 years ago

@YMC-GitHub

EnumWindows(cb_enum_window, reinterpret_cast<LPARAM>(&search));

image

ShenHongFei commented 2 years ago

@YMC-GitHub

full code of `find_window` in a nodejs addon ```cpp enum struct WinFilter { TITLE, CLASSNAME, PATH, CALLBACK }; struct WinSearch { const Env env; const WinFilter by; const Object pattern; const Function pattern_test; const Object pattern_exclude; const Function pattern_exclude_test; int index; HWND hwin; u16string title; u16string path; u16string classname; }; BOOL __stdcall cb_enum_window (HWND hwin, LPARAM lparam) { WinSearch& search = *reinterpret_cast(lparam); const Env& env = search.env; wchar_t buf[MAX_PATH]; u16string* field; if (search.by == WinFilter::TITLE) { GetWindowTextW(hwin, buf, MAX_PATH); search.title = u16string(w2uchar(buf)); field = &search.title; } else if (search.by == WinFilter::CLASSNAME) { GetClassNameW(hwin, buf, MAX_PATH); search.classname = u16string(w2uchar(buf)); field = &search.classname; } else if (search.by == WinFilter::PATH) { /* GetWindowModuleFileNameW(hwin, buf, MAX_PATH); 只能获取当前进程的窗口,没用 GetModuleFileNameExW(static_cast(h_ps), buf, MAX_PATH); 不建议使用 https://docs.microsoft.com/en-us/windows/win32/api/psapi/nf-psapi-getmodulefilenameexa https://stackoverflow.com/questions/1933113/c-windows-how-to-get-process-path-from-its-pid https://docs.microsoft.com/en-us/windows/win32/api/psapi/nf-psapi-getprocessimagefilenamew https://docs.microsoft.com/en-us/windows/win32/api/winbase/nf-winbase-queryfullprocessimagenamew 获得进程可执行文件的路径: GetModuleFileNameEx, GetProcessImageFileName, QueryFullProcessImageName https://www.cnblogs.com/findumars/p/5812185.html */ DWORD pid; GetWindowThreadProcessId(hwin, &pid); HANDLE h_ps = OpenProcess(PROCESS_QUERY_LIMITED_INFORMATION, FALSE, pid); if (!h_ps) return TRUE; DWORD len = MAX_PATH; BOOL code = QueryFullProcessImageNameW(h_ps, 0, buf, &len); CloseHandle(h_ps); if (!code || !len) return TRUE; search.path = u16string(w2uchar(buf), len); field = &search.path; } else { GetWindowTextW(hwin, buf, MAX_PATH); search.title = u16string(w2uchar(buf)); GetClassNameW(hwin, buf, MAX_PATH); search.classname = u16string(w2uchar(buf)); Object win = Object::New(env); win["hwin"s] = String::New(env, to_string(reinterpret_cast(search.hwin))); win["title"s] = search.title; win["classname"s] = search.classname; win["path"s] = String::New(env, u""s); if (search.pattern.As().Call({ win }).As().Value()) { search.hwin = hwin; if (!search.index--) return FALSE; } return TRUE; } // wcout << u2wchar(field->c_str()) << endl; // if (/xxx/.test(field)) found if ( search.pattern_test.Call(search.pattern, { String::New(env, *field) }).As().Value() && (search.pattern_exclude_test.IsEmpty() || !search.pattern_exclude_test.Call(search.pattern_exclude, { String::New(env, *field) }).As().Value()) ) { search.hwin = hwin; // --- 补齐字段 if (search.by != WinFilter::TITLE) { GetWindowTextW(hwin, buf, MAX_PATH); search.title = u16string(w2uchar(buf)); } if (search.by != WinFilter::CLASSNAME) { GetClassNameW(hwin, buf, MAX_PATH); search.classname = u16string(w2uchar(buf)); } if (!search.index--) return FALSE; } return TRUE; } /** addon.find_window(0, pattern: RegExp | Function, index = 0, options = { exclude: RegExp }) */ Object find_window (const CallbackInfo& info) { Env env = info.Env(); const WinFilter by = static_cast(info[0].As().Int32Value()); const Object pattern = info[1].As(); const Object options = info[3].As(); const Object pattern_exclude = options["exclude"s].As(); WinSearch search = { .env = env, .by = by, .pattern = pattern, .pattern_test = by == WinFilter::CALLBACK ? Function() : pattern["test"s].As(), .pattern_exclude = pattern_exclude, .pattern_exclude_test = pattern_exclude.IsUndefined() ? Function() : pattern_exclude["test"s].As(), .index = info[2].As().Int32Value(), }; EnumWindows(cb_enum_window, reinterpret_cast(&search)); Object ret = Object::New(env); ret["hwin"s] = String::New(env, to_string(reinterpret_cast(search.hwin))); ret["title"s] = move(search.title); ret["path"s] = move(search.path); ret["classname"s] = move(search.classname); return ret; } ```
Krombik commented 2 years ago

Try to use this method

YMC-GitHub commented 2 years ago

@ShenHongFei @Krombik It's a great honor to receive your reply. I have used other tick to achieve it with keysender ,to active the second window.