#QT# #Windows# #启动第三方软件# #窗口句柄查找# #获取软件PID# #操作权限#
1. 启动第三方软件:使用QT编程,启动第三方软件,使用QProcess类,效果较好。QProcess中启动第三方软件包括三个方法:start() startDetarch() execute(),其中start()能返回启动第三方程序的PID。但是实际测试中发现,有的第三方软件不允许用start()启动,但是startDetarch()都测试成功。
2. 窗口句柄获取/查找:启动第三方软件后,可以根据PID查找窗口句柄。但windows的API中只提供了一个GetWindowThreadProcessId(HWND,&PID),该方法输入窗口句柄得到PID。所以需要遍历一下顶级的窗口句柄,写成一个如下方法获取窗口句柄。
//回调函数,遍历所有顶层窗体
BOOL CALLBACK EnumWindowsProc(HWND hwnd, LPARAM lParam)
{
EnumWindowsArg *pArg = (EnumWindowsArg *)lParam;
DWORD dwProcessID = 0;
// 通过窗口句柄取得进程ID
::GetWindowThreadProcessId(hwnd, &dwProcessID);
if (dwProcessID == pArg->dwProcessID)
{
pArg->hwndWindow = hwnd;
// 找到了返回FALSE
return FALSE;
}
// 没找到,继续找,返回TRUE
return TRUE;
}
//查找窗体的函数。
HWND TFormDoc::GetWindowHwndByPID(DWORD dwProcessID)
{
HWND hwndRet = NULL;
EnumWindowsArg ewa;
ewa.dwProcessID = dwProcessID;
ewa.hwndWindow = NULL;
EnumWindows(EnumWindowsProc, (LPARAM)&ewa);
if (ewa.hwndWindow)
{
hwndRet = ewa.hwndWindow;
}
return hwndRet;
}
3. 窗口句柄查找,根据已知的窗体名称,查找窗体句柄。这是相对通用的做法,使用windows的API函数 FindWindow()。经测试很方便使用,但经验是,第三方软件的名称可能并不是其软件名称本身,尤其是有的是英文名称,有的则是中文名称。可以根据软件启动后的进程观察其名字。反复多试几次就能找到窗体。
QString name = "软件名称";
hwnd = FindWindow(nullptr,(LPCWSTR)name.unicode());
4. 窗口句柄不唯一。有的软件只有一个窗体句柄,但现在流行的大多桌面软件有很多个窗体,如每当开启一个新的功能界面,就出现要给新的窗体,其窗体句柄也是新的。一个软件的多个窗体之间,关系可能是多种的,有的是父子关系,有的是平行关系,也有的是完全没关系。需要具体分析。使用Windows的API函数FindWindowEx(),方法变化很多样。如下行代码就是查找同一个名字的多个平行窗体句柄。hwnd1是通过FindWindow()获取的第一个窗体。
HWND hwnd2 = FindWindowEx(nullptr,hwnd1,nullptr,(LPCWSTR)name.unicode());
还有windows的API函数:GetWindow()方法,能够获取窗体的子窗体childwindow或者owner等。
5. 对窗口的操作,主要是激活、置顶操作。使用windows的API函数 ::SetWindowPos()方法,能够设置窗体的置顶、置底等。如果返回错误,则可调用GetLastError()查看错误原因。这里提示一下权限问题,如果第三方软件需要管理员操作,那调用该软件的程序也必须是管理员启动。
::SetWindowPos(hwnd1, HWND_TOPMOST, 0, 0, 0, 0, SWP_NOMOVE | SWP_NOSIZE|SWP_SHOWWINDOW);
这是将窗口置顶的方法实例,如果一个软件有多个窗体,那么需要将他们全部置顶才能保证软件的运行置顶。