Меняем позицию и размеры окна Windows программно

129-1

July 06, 2018

Я часто использую 2 монитора, программы открыты то на одном, то на другом из них.

И в какой-то момент я открыл Sublime Text, а он отобразил свое окно на втором мониторе, который не был подключен.

И "вытащить" окно из такой западни я сразу не сумел.

Немного поискав в интернете, нашел способ установить новую позицию окна, используя C# .Net

Итак, немного кода.

Определим класс, который будет хранить необходимые нам данные об открытых окнах

public class WindowInfo {
    public HWND hWnd;
    public string name;
    public string title;

    public WindowInfo(HWND hWnd, string name, string title) {
        this.hWnd = hWnd;
        this.name = name;
        this.title = title;
    }

    public override string ToString() {
        return "" + hWnd.ToString() + " | " + name + " | " + title.ToString();
    }
}

При открытии окна нашей программы просканируем открытые окна и сохраним информацию о них в список

using HWND = System.IntPtr;

private void preloadProcesses() {
    HashSet<WindowInfo> allWindows = GetOpenWindows();
    foreach (WindowInfo windowData in allWindows) {
        comboBox1.Items.Add(windowData);
    }
}

Получение информации обо всех открытых окнах

[DllImport("USER32.DLL")]
private static extern IntPtr GetShellWindow();

[DllImport("USER32.DLL")]
private static extern bool IsWindowVisible(HWND hWnd);

[DllImport("USER32.DLL")]
private static extern int GetWindowTextLength(HWND hWnd);
        
[DllImport("USER32.DLL")]
private static extern int GetWindowText(HWND hWnd, StringBuilder lpString, int nMaxCount);



public static HashSet<WindowInfo> GetOpenWindows() {
    HWND shellWindow = GetShellWindow();
    
    HashSet<WindowInfo> windows = new HashSet<WindowInfo>();

    EnumWindows(delegate (HWND hWnd, int lParam)
    {
        if (hWnd == shellWindow) return true;
        if (!IsWindowVisible(hWnd)) return true;

        int length = GetWindowTextLength(hWnd);
        if (length == 0) return true;

        StringBuilder builder = new StringBuilder(length);
        GetWindowText(hWnd, builder, length + 1);

        Int32 pid = GetWindowProcessID(hWnd.ToInt32());
        Process p = Process.GetProcessById(pid);
        string appName = p.ProcessName;

        WindowInfo window = new WindowInfo(hWnd, appName, builder.ToString());

        windows.Add(window);
        return true;

    }, 0);

    return windows;
}

И теперь при нажатии на кнопку подвинем выбранное пользователем окно

[DllImport("user32.dll")]
[return: MarshalAs(UnmanagedType.Bool)]
static extern bool SetWindowPos(IntPtr hWnd, IntPtr hWndInsertAfter, int X, int Y, int cx, int cy, SetWindowPosFlags uFlags);

private void btnSet_Click(object sender, EventArgs e) {

    // Get the target window's handle.
    IntPtr target_hwnd = ((WindowInfo) comboBox1.SelectedItem).hWnd;
    if (target_hwnd == IntPtr.Zero)
    {
        MessageBox.Show(
            "Could not find a window with the title \"" +
            ((WindowInfo) comboBox1.SelectedItem).title+ "\"");
        return;
    }
    

    // Set the window's position.
    int width = int.Parse(txtWidth.Text);
    int height = int.Parse(txtHeight.Text);
    int x = int.Parse(txtX.Text);
    int y = int.Parse(txtY.Text);
    SetWindowPos(target_hwnd, IntPtr.Zero, x, y, width, height, 0);
}

Полный код проекта

доступен в репозитории на гитхабе

on July 06, 2018