【问题标题】:SetWindowPos not working for browsers - no MainWindowHandle?SetWindowPos 不适用于浏览器 - 没有 MainWindowHandle?
【发布时间】:2014-03-11 00:47:07
【问题描述】:

我一直在尝试用 C# 编写一个简单的程序,以启动不同的软件,并将其移动到特定的屏幕,以便能够在总共有 12 个显示器的机器上自动设置不同的窗口。

这些窗口中的大多数都是在 Chrome 或 Internet Explorer 中启动的。

我用来移动应用程序的代码如下:

[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);

它似乎在记事本上工作得很好,但是当它是一个浏览器时,MainWindowHandle 总是返回 IntPtr.Zero,即使我刷新了进程。

有什么建议吗?

【问题讨论】:

  • 几个错误。您的 Console.WriteLine() 调用已损坏,您需要附加 this.process.MainWindowHandle.ToInt64()。请改用调试器。您的 SetWindowPos() 已损坏、错误的 pinvoke 声明和错误的使用。请改用 MoveWindow(),访问 pinvoke.net 网站以获得良好的声明。
  • 谢谢。我会看看 pinvoke.net。我对 C# 不是很熟悉。 :)
  • MoveWindow 也适用于记事本。但是,它不适用于 Chrome,因为 process.MainWindowHandle.ToInt64() 返回 IntPtr.Zero 。 process.Handle 返回进程的有效 ID。
  • 联系 Google 寻求支持。或者使用 iexplore.exe
  • @Drejer 我的回答对你有帮助吗?

标签: c# winapi window-handles


【解决方案1】:

现代浏览器使用复杂的多进程架构。

如果在您启动新的 chrome.exe 进程时 chrome 进程已经在运行,那么两个进程之间会发生一些进程间通信,并且会启动一个新的子进程(旧的预先存在的进程的子进程)来托管新进程选项卡渲染。您启动的进程然后立即退出,并且您无法为该死进程获取主窗口。创建的新 Chrome 主窗口是预先存在的进程。

您可以尝试以下 C++ 源代码

#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:\\Users\\manuel\\AppData\\Local\\Google\\Chrome\\Application\\chrome.exe",
                   NULL, NULL, NULL, FALSE, 0, NULL,
                   L"C:\\Users\\manuel\\AppData\\Local\\Google\\Chrome\\Application",
                   &SI, &PI );
    if ( bWin32Success ) {
        printf( "PID %u\n", PI.dwProcessId );
        DWORD dwRet = WaitForInputIdle( PI.hProcess, 1000 );
        switch ( dwRet ) {
            case 0:
                printf( "WaitForInputIdle succeedeed\n" );
                break;
            case WAIT_TIMEOUT:
                printf( "WaitForInputIdle timed out\n" );
                break;
            case WAIT_FAILED:
                printf( "WaitForInputIdle Error %u\n", GetLastError() );
                break;
            default:
                printf( "WaitForInputIdle Unknown return value %d\n", dwRet );
        }
        CloseHandle( PI.hThread );
        CloseHandle( PI.hProcess );

    } else {
        printf( "CreateProcess Error %u\n", GetLastError() );
    }
    return 0;
}

使用 Spy++ 和 Windows 任务管理器,或者更好的进程资源管理器,您会看到,当 chrome 已经在运行时,新的 Chrome 主窗口由已经运行的 chrome.exe 托管,并且CreateProcess启动的进程被终止。

解决方案:

  1. 使用一些窗口枚举 API 对当前显示的 Chrome 主窗口进行快照
  2. 启动一个新的 chrome.exe
  3. 拍摄新快照。新窗口是第一个快照中不存在的窗口。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2023-03-13
    • 1970-01-01
    • 1970-01-01
    • 2020-08-26
    • 2012-05-23
    • 2015-09-29
    • 2016-10-13
    • 1970-01-01
    相关资源
    最近更新 更多