前言:
没有系统学习过Win32,对windows的shell效果经常惊讶。一直想实现这种游戏大厅的效果,但是总是不能深入。
昨天,偶然有幸进行了一次测试,花费了3个小时,终于搞清了其中的道理,现罗列如下,以敬同道中人。
成果:
HANDLE handle;//process handle
HWND apphwnd;//window handle
/*************Global functions for hosting******************/
//Function to enumerate all windows.
int CALLBACK EnumWindowsProc(HWND hwnd, LPARAM param)
{
DWORD pID;
DWORD TpID = GetWindowThreadProcessId(hwnd, &pID);//get process id
if (TpID == (DWORD)param)
{
apphwnd=hwnd;//hwnd is the window handle
return false;
}
return true;
}
//Functio to start a orocess and return the process handle
HANDLE StartProcess(LPCTSTR program, LPCTSTR args)
{
HANDLE hProcess = NULL;
PROCESS_INFORMATION processInfo;
STARTUPINFO startupInfo;
::ZeroMemory(&startupInfo, sizeof(startupInfo));
startupInfo.cb = sizeof(startupInfo);
startupInfo.dwFlags = STARTF_USESHOWWINDOW;
startupInfo.wShowWindow = SW_HIDE;
if(::CreateProcess(program, (LPTSTR)args,
NULL, // process security
NULL, // thread security
FALSE, // no inheritance
0, // no startup flags
NULL, // no special environment
NULL, // default startup directory
&startupInfo,
&processInfo))
{
Sleep(1000);
::EnumWindows(&EnumWindowsProc, processInfo.dwThreadId);//Iterate all windows
hProcess = processInfo.hProcess;
}
return hProcess;
}
void CXXXXXDlg::OnButton1()
{
CRect rect;
GetClientRect(&rect);
handle=StartProcess("C:\\WINDOWS\\system32\\mspaint.exe","");
if(apphwnd!=NULL)
{
::SetParent(apphwnd,m_hWnd);
SetWindowLong(apphwnd, GWL_STYLE, WS_VISIBLE);
::MoveWindow(apphwnd, rect.left, rect.top,rect.right, rect.bottom, true);
}
else
{
MessageBox("Cannot find Window");
}
}
中间过程:
1、当时对ShellExecute情有独钟,CreateProcess还没有测试创建后立即隐藏的方式,所以当时希望也能通过ShellExecuteEx进行窗口的检索。
这样必须从ShellExecuteEx得到的进程句柄中获取窗口,枚举、遍历后发现进程的ID唯一,但是进程每次打开后的句柄却各不相同。
2小时后,不得不返回思路,重新考虑CreateProcess创建隐藏进程的方式。很快就发现可以行得通。
2、痛苦的过程总是令人痛苦不堪,只有经过痛苦的人,才能逐渐积累、减少痛苦,化悲痛为喜悦。
遗留问题:
如果碰到没有窗口句柄的程序,这种方式显然就不行了,该怎么办?