dongnai8013 2017-07-02 17:11
浏览 98
已采纳

在Go for Windows中获取窗口几何

I want to create a tool with Go that lets me resize multiple windows on my screen. As an example lets assume that I want to find my Firefox window and my Atom (text editor) window and place them, so that they take up exactly half of my screen (FF left, Atom right).

So far I realized, that I need to use the Windows API for that. I created a method that gives me all handles and the titles of all windows, but I'm struggling with geometry information. I understand that the api call GetWindowRect will help, but how can I get the information out of a pointer to a rect?

Follow up question 1: what other information can I get about the windows? Follow up question 2: How do I resize the window so that it takes exactly half my screen size? I guess, I need another call to get the monitor dimensions.

What I have so far is the code below. The main program finds all handles and displays those containing 'Atom' in the title. The windows package contains the code accessing the windows API.

My current result is that I get 2 handles for atom (why not just 1?). I guess, I have to learn more about the Windows API, too. Are there good summaries to understand the basics?

main.go:

package main

import (
    "resizer/windows"
    "fmt"
    "log"
    "strings"
)

func main() {
    const title = "Atom"    
    m := windows.GetAllWindows()
    fmt.Printf("Map of windows: 
")
    for handle := range m {
        if strings.Contains(m[handle].Title(), title) {
            fmt.Printf("'%v'
", m[handle])
        }
    }
}

windows.go:

package windows

import (
    "fmt"
    "log"
    "syscall"
    "unsafe"
)

var (
    user32             = syscall.MustLoadDLL("user32.dll")
    procEnumWindows    = user32.MustFindProc("EnumWindows")
    procGetWindowTextW = user32.MustFindProc("GetWindowTextW")
)

// Window represents any Window that is opened in the Windows OS
type Window struct {
    handle syscall.Handle
    title  string
}

// Title returns the title of the window
func (w Window) Title() string {
    return w.title
}

// GetAllWindows finds all currently opened windows
func GetAllWindows() map[syscall.Handle]Window {
    m := make(map[syscall.Handle]Window)
    cb := syscall.NewCallback(func(h syscall.Handle, p uintptr) uintptr {
        bytes := make([]uint16, 200)
        _, err := GetWindowText(h, &bytes[0], int32(len(bytes)))
        title := "||| no title found |||"
        if err == nil {
            title = syscall.UTF16ToString(bytes)
        }
        m[h] = Window{h, title}
        return 1 // continue enumeration
    })
    EnumWindows(cb, 0)
    return m
}

// EnumWindows loops through all windows and calls a callback function on each
func EnumWindows(enumFunc uintptr, lparam uintptr) (err error) {
    r1, _, e1 := syscall.Syscall(procEnumWindows.Addr(), 2, uintptr(enumFunc), uintptr(lparam), 0)
    if r1 == 0 {
        if e1 != 0 {
            err = error(e1)
        } else {
            err = syscall.EINVAL
        }
    }
    return
}

// GetWindowText gets the title of a Window given by a certain handle
func GetWindowText(hwnd syscall.Handle, str *uint16, maxCount int32) (len int32, err error) {
    r0, _, e1 := syscall.Syscall(procGetWindowTextW.Addr(), 3, uintptr(hwnd), uintptr(unsafe.Pointer(str)), uintptr(maxCount))
    len = int32(r0)
    if len == 0 {
        if e1 != 0 {
            err = error(e1)
        } else {
            err = syscall.EINVAL
        }
    }
    return
}
  • 写回答

1条回答 默认 最新

  • dongxia4880 2017-07-02 22:27
    关注

    GetWindowRect() writes the geometry to the RECT structure you pass the pointer to in. It operates exactly like the GetWindowText() call you already have; the difference is you have to provide the RECT structure yourself.

    You should be able to just get away with copying the structure verbatim. To substitute data types, use this page. The definition for RECT says all the fields are LONG, which that page says is "[a] 32-bit signed integer". So this should suffice:

    type RECT struct {
        left   int32 // or Left, Top, etc. if this type is to be exported
        top    int32
        right  int32
        bottom int32
    }
    

    (Most likely irrelevant, but it's worth pointing out that RECT operates identically to image.Rectangle, with left and top being Min and right and bottom being Max. They are not identical because image.Rectangle uses int, so you may want to consider providing conversion functions if you want to use image's geometry functions to manipulate rectangles instead of GDI's.)

    本回答被题主选为最佳回答 , 对您是否有帮助呢?
    评论

报告相同问题?

悬赏问题

  • ¥15 微信公众号自制会员卡没有收款渠道啊
  • ¥15 stable diffusion
  • ¥100 Jenkins自动化部署—悬赏100元
  • ¥15 关于#python#的问题:求帮写python代码
  • ¥20 MATLAB画图图形出现上下震荡的线条
  • ¥15 关于#windows#的问题:怎么用WIN 11系统的电脑 克隆WIN NT3.51-4.0系统的硬盘
  • ¥15 perl MISA分析p3_in脚本出错
  • ¥15 k8s部署jupyterlab,jupyterlab保存不了文件
  • ¥15 ubuntu虚拟机打包apk错误
  • ¥199 rust编程架构设计的方案 有偿