SetWindowPos не работает в браузерах - нет MainWindowHandle?

Я пытался создать простую программу на 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, даже если я обновляю процесс.

Любой совет?


person Drejer    schedule 11.03.2014    source источник
comment
Несколько ошибок. Ваш вызов Console.WriteLine () не работает, вам нужно добавить this.process.MainWindowHandle.ToInt64 (). Вместо этого используйте отладчик. Ваш SetWindowPos () сломан, неверное объявление pinvoke и неправильное использование. Вместо этого используйте MoveWindow (), посетите сайт pinvoke.net, чтобы получить хорошее объявление.   -  person Hans Passant    schedule 11.03.2014
comment
Спасибо. Я посмотрю на pinvoke.net. Я не очень знаком с C #. :)   -  person Drejer    schedule 11.03.2014
comment
MoveWindow также хорошо работает с Блокнотом. Однако это не работает с Chrome, потому что process.MainWindowHandle.ToInt64 () возвращает IntPtr.Zero. Process.Handle возвращает действительный идентификатор процесса.   -  person Drejer    schedule 11.03.2014
comment
Обратитесь в Google за поддержкой. Или используйте iexplore.exe   -  person Hans Passant    schedule 11.03.2014
comment
@Drejer Мой ответ тебе помог?   -  person manuell    schedule 13.03.2014
comment
@manuell Я так считаю. У меня еще не было времени попробовать. Надеюсь, смогу попробовать на выходных.   -  person Drejer    schedule 13.03.2014


Ответы (1)


Современные браузеры используют сложные многопроцессорные архитектуры.

Если процесс chrome уже запущен, когда вы запускаете новый процесс chrome.exe, то между двумя процессами происходит некоторая межпроцессная связь, и запускается новый дочерний процесс (дочерний по отношению к старому ранее существовавшему процессу) для размещения рендеринга новой вкладки. Затем процесс, который вы запустили, немедленно завершается, и вы не можете захватить главное окно для этого теперь мертвого процесса. Новое главное окно 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 или, лучше, Process Explorer, вы увидите, что когда Chrome уже запущен, новое главное окно Chrome размещается в уже запущенном chrome.exe, и что процесс запущено CreateProcess, прекращено.

Решение:

  1. Сделайте снимок текущего отображаемого главного окна Chrome, используя некоторые API-интерфейсы перечисления окон.
  2. Запустите новый chrome.exe
  3. Сделайте новый снимок. Новое окно - это окно, отсутствующее в первом снимке.
person manuell    schedule 11.03.2014