Goで画面上の複数のウィンドウのサイズを変更できるツールを作成したいとします。例として、自分のFirefoxウィンドウとAtom(テキストエディタ)ウィンドウを見つけて配置して、画面の半分(FF左、Atomの右)を使用すると仮定します。Go for Windowsでウィンドウジオメトリを取得する
これまでのところ、Windows APIを使用する必要があることに気付きました。私はすべてのハンドルとすべてのウィンドウのタイトルを私に与えるメソッドを作成しましたが、私はジオメトリ情報に苦しんでいます。私はAPI呼び出しGetWindowRect
が助けになることを理解していますが、どのようにしてrectへのポインタから情報を得ることができますか?
質問1:私は窓について他にどんな情報を得ることができますか? 質問2:画面サイズのちょうど半分になるようにウィンドウのサイズを変更するにはどうすればよいですか?私は、モニターの寸法を得るために別の呼び出しが必要だと思います。
これまでのコードは以下のとおりです。メインプログラムはすべてのハンドルを見つけ、タイトルに「Atom」を含むものを表示します。 Windowsパッケージには、Windows APIにアクセスするコードが含まれています。
私の現在の結果は、原子のハンドルが2つあることです。私は、Windows APIについてもっと知る必要があると思います。基本を理解するための良い要約はありますか?
main.go:
package main
import (
"resizer/windows"
"fmt"
"log"
"strings"
)
func main() {
const title = "Atom"
m := windows.GetAllWindows()
fmt.Printf("Map of windows: \n")
for handle := range m {
if strings.Contains(m[handle].Title(), title) {
fmt.Printf("'%v'\n", 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
}
キャプションの代わりにウィンドウクラス名を使用する方が良いです。ファイル名が 'Firefox.txt'のオープンテキストエディタです。また、ウィンドウを移動するには、MoveWindowのAPIラッパーを実装する必要があります。また、GetSystemMetricsを使用して画面サイズを取得します。 – mattn
クラス名は間違いなく役に立ちます。しかし、私はまだ2つのAtomハンドル(そして1つのウィンドウ)しか持っていません。どのように2つの画面のサイズを取得する任意のアイデア? –
フォローアップの質問は非常に曖昧です。あなたは窓でできることがたくさんあり、そこから出ることができるものはたくさんあります。あなたはあなたが知りたいことに固執しているほうが良いです。また、 'GetWindowTextW()'のような関数を呼び出すときには、渡す長さがC文字列の最後に来る終了NUL文字(整数値0)を正しく考慮していることを確認するためにMSDNをチェックする必要があります。 'syscall.UTF16ToString()'は取り除きます。必要な正確な長さを得る方法もあります。 – andlabs