问题
I have a situation where I'm starting a process in my code in order to set up an IPC channel. The process I'm starting is an MFC application with no CLR support. The application from which I am starting this process is a C# module in a WPF application (thought I don't think that that is consequential to my problem). This works with a version of the application that does support CLR, and it works on every computer except the deployment target, a touch screen computer with Windows 7. But for some reason, when I try it with this exact scenario, the Process object never resolves a main window handle (Process.MainWindowHandle
). Is there another (perhaps even pinvoke) method of doing this? Is this a security thing? I'm the one staring the process. The process's main window handle does exist. I don't see what could be wrong.
If it helps, here is my code.
_applicationProcess = new Process();
_applicationProcess.StartInfo.FileName = _strProcessPath;
_applicationProcess.StartInfo.Arguments = _strProcessArguments;
_applicationProcess.Start();
long nTicks = Environment.TickCount;
if (_applicationProcess.WaitForInputIdle(1 /*minute(s)*/ * 60000))
{
try
{
do
{
// Don't let total processing take more than 1 minute(s).
if (Environment.TickCount > nTicks + 1 /*minute(s)*/ * 60000)
throw new ApplicationException("MFCApplication.Startup failed! The main window handle is zero!");
_applicationProcess.Refresh();
}
while (_applicationProcess.MainWindowHandle.ToInt32() == 0);
_applicationHandle = new IntPtr(_applicationProcess.MainWindowHandle.ToInt32());
}
catch (Exception ex)
{
//Do some stuff...
throw;
}
}
else
{
// Do exception handling.
}
The ApplicationException
is hit after a minute of trying to get a main window handle other than zero.
回答1:
The value you get out of Process.MainWindowHandle is unfortunately a guess. There is no API function available to a program that lets it tell Windows "this is my main window". The rule it uses is documented, it is the first window that's created by a process when it gets started. That causes trouble if that first window is, say, a login window or a splash screen.
Not much you can do about this, you have to know more about how the program behaves to find that real main window. Enumerating windows with EnumThreadWindows() could help you find it, as long as the first window was created on the same thread as the main window. A more elaborate EnumWindows() will be necessary if that is not the case.
回答2:
My habit is to call EnumWindows in a loop combined with GetWindowThreadProcessId to find the window handle.
C Code, adapt to your language
DWORD TargetHWND;
//...
while (EnumWindows(EnumWndProc, (LPARAM)(DWORD)pid)) {
Sleep(100);
}
//...
BOOL EnumWndProc(HWND hWnd, LPARAM lParam) {
DWORD pid = (DWORD)-1;
GetWindowThreadProcessId(hWnd, &pid);
if (pid == (DWORD)lParam) {
TargetHWND = hWnd;
return FALSE;
}
return TRUE;
}
回答3:
In order to get MainWindowHandle
by means of your process, please make sure your WPF application is shown on the taskbar i.e ShowInTaskbar="True"
and set Application.Current.MainWindow
property to the window that you'd like to set as your main window.
If I execute code below in my WPF main window without setting ShowInTaskbar="True"
I always got 0 as the MainWindowHandle
because my WPF window was full screen and not displayed on the taskbar.
Application.Current.MainWindow = this;
var Query = System.Diagnostics.Process.GetProcessesByName("ProcessName");
if (Query.Any())
{
Query.FirstOrDefault().Refresh();
MessageBox.Show(Query.FirstOrDefault().MainWindowHandle.ToInt32().ToString());
}
回答4:
I don't know why it could be different, but after you create the process, try doing:
Process[] allProcesses = Process.GetProcessesByName("YourWindowTitle");
and see if any of the processes returned have a MainWindowHandle.
来源:https://stackoverflow.com/questions/4727023/why-cant-get-the-main-window-handle-for-a-started-process