SetWindowPos not working for browsers
I've been trying to make a simple program in C#, to launch different software, and move it to a specific screen, to be able to automatically set up different windows, on a machine with a total of 12 monitors.
Most of these windows is launched in either Chrome or Internet Explorer.
The code I use to move the appplications is the following: [DllImport("User32.dll")] static extern int SetForegroundWindow(IntPtr hWnd);
[DllImport("user32.dll", EntryPoint = "SetWindowPos")]
public static extern IntPtr SetWindowPos(IntPtr hWnd, int hWndInsertAfter, int x, int Y, int cx, int cy, int wFlags);
this.process = Process.Start(this.startInfo);
process.WaitForInputIdle();
SetForegroundWindow(this.process.MainWindowHandle);
Console.WriteLine("Process ID: "+ this.process.Handle);
this.process.Refresh();
Console.WriteLine("Main window handle: " + this.process.MainWindowHandle);
Point screenlocation = Screen.AllScreens[MonitorNum].Bounds.Location;
SetWindowPos(this.process.MainWindowHandle, -1, screenlocation.X, screenlocation.Y, Screen.AllScreens[MonitorNum].Bounds.Width, Screen.AllScreens[MonitorNum].Bounds.Height, 1);
It seems to be working just fine with Notepad, but when it's a browser MainWindowHandle always return IntPtr.Zero, even if I refresh the Process.
Any advice?
Modern browsers use complex multi-process architectures.
If a chrome process is already running when you launch a new chrome.exe process, then some Inter Process Communication takes place between the two processes and a new child process is launched (child of the old preexisting process) to host the new tab rendering. The process you launched then exit immediately, and there is no way you can grab a Main window for that now dead process. The new Chrome Main Window is created is the preexisting process.
You can experiment with the following C++ source
#include <Windows.h>
#include <stdio.h>
int main( void ) {
STARTUPINFO SI;
memset( &SI, 0, sizeof SI );
SI.cb = sizeof SI;
PROCESS_INFORMATION PI;
BOOL bWin32Success =
CreateProcess( L"C:UsersmanuelAppDataLocalGoogleChromeApplicationchrome.exe",
NULL, NULL, NULL, FALSE, 0, NULL,
L"C:UsersmanuelAppDataLocalGoogleChromeApplication",
&SI, &PI );
if ( bWin32Success ) {
printf( "PID %un", PI.dwProcessId );
DWORD dwRet = WaitForInputIdle( PI.hProcess, 1000 );
switch ( dwRet ) {
case 0:
printf( "WaitForInputIdle succeedeedn" );
break;
case WAIT_TIMEOUT:
printf( "WaitForInputIdle timed outn" );
break;
case WAIT_FAILED:
printf( "WaitForInputIdle Error %un", GetLastError() );
break;
default:
printf( "WaitForInputIdle Unknown return value %dn", dwRet );
}
CloseHandle( PI.hThread );
CloseHandle( PI.hProcess );
} else {
printf( "CreateProcess Error %un", GetLastError() );
}
return 0;
}
Using Spy++ and the Windows Task Manager, or better Process Explorer, you will see that, when chrome is already running, the new Chrome Main Window is hosted by the already running chrome.exe, and that the process launched by CreateProcess
is terminated.
Solution:
上一篇: 获取WPF过程中所有窗口的句柄
下一篇: SetWindowPos不适用于浏览器