Added the rest of the skeleton necessary for opening a simple window as well as the code to actually open one. Now for custom window procedures!
This commit is contained in:
parent
ecc00bd1f5
commit
3482c9c541
95
main.go
95
main.go
|
@ -1,12 +1,95 @@
|
||||||
// 7 february 2014
|
// 7 february 2014
|
||||||
package main
|
package main
|
||||||
|
|
||||||
import "fmt"
|
import (
|
||||||
|
"fmt"
|
||||||
|
"os"
|
||||||
|
"runtime"
|
||||||
|
)
|
||||||
|
|
||||||
func main() {
|
func fatalf(format string, args ...interface{}) {
|
||||||
fmt.Println(MessageBox(NULL,
|
s := fmt.Sprintf(format, args...)
|
||||||
"hello, world",
|
_, err := MessageBox(NULL,
|
||||||
"hello",
|
"An internal error has occured:\n" + s,
|
||||||
0))
|
os.Args[0],
|
||||||
|
MB_OK | MB_ICONERROR)
|
||||||
|
if err == nil {
|
||||||
|
os.Exit(1)
|
||||||
|
}
|
||||||
|
panic(fmt.Sprintf("error trying to warn user of internal error: %v\ninternal error:\n%s", err, s))
|
||||||
|
}
|
||||||
|
|
||||||
|
const className = "mainwin"
|
||||||
|
|
||||||
|
func main() {
|
||||||
|
runtime.LockOSThread()
|
||||||
|
|
||||||
|
hInstance, err := getWinMainhInstance()
|
||||||
|
if err != nil {
|
||||||
|
fatalf("error getting WinMain hInstance: %v", err)
|
||||||
|
}
|
||||||
|
nCmdShow, err := getWinMainnCmdShow()
|
||||||
|
if err != nil {
|
||||||
|
fatalf("error getting WinMain nCmdShow: %v", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
icon, err := LoadIcon_ResourceID(NULL, IDI_APPLICATION)
|
||||||
|
if err != nil {
|
||||||
|
fatalf("error getting window icon: %v", err)
|
||||||
|
}
|
||||||
|
cursor, err := LoadCursor_ResourceID(NULL, IDC_ARROW)
|
||||||
|
if err != nil {
|
||||||
|
fatalf("error getting window cursor: %v", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
wc := &WNDCLASS{
|
||||||
|
LpszClassName: className,
|
||||||
|
LpfnWndProc: DefWindowProc,
|
||||||
|
HInstance: hInstance,
|
||||||
|
HIcon: icon,
|
||||||
|
HCursor: cursor,
|
||||||
|
HbrBackground: HBRUSH(COLOR_WINDOW + 1),
|
||||||
|
}
|
||||||
|
_, err = RegisterClass(wc)
|
||||||
|
if err != nil {
|
||||||
|
fatalf("error registering window class: %v", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
hwnd, err := CreateWindowEx(
|
||||||
|
WS_EX_OVERLAPPEDWINDOW,
|
||||||
|
className, "Main Window",
|
||||||
|
WS_OVERLAPPEDWINDOW,
|
||||||
|
CW_USEDEFAULT, CW_USEDEFAULT, 320, 240,
|
||||||
|
NULL, NULL, hInstance, NULL)
|
||||||
|
if err != nil {
|
||||||
|
fatalf("error creating window: %v", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
_, err = ShowWindow(hwnd, nCmdShow)
|
||||||
|
if err != nil {
|
||||||
|
fatalf("error showing window: %v", err)
|
||||||
|
}
|
||||||
|
err = UpdateWindow(hwnd)
|
||||||
|
if err != nil {
|
||||||
|
fatalf("error updating window: %v", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
for {
|
||||||
|
msg, done, err := GetMessage(NULL, 0, 0)
|
||||||
|
if err != nil {
|
||||||
|
fatalf("error getting message: %v", err)
|
||||||
|
}
|
||||||
|
if done {
|
||||||
|
break
|
||||||
|
}
|
||||||
|
_, err = TranslateMessage(msg)
|
||||||
|
if err != nil {
|
||||||
|
fatalf("error translating message: %v", err)
|
||||||
|
}
|
||||||
|
_, err = DispatchMessage(msg)
|
||||||
|
if err != nil {
|
||||||
|
fatalf("error dispatching message: %v", err)
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -0,0 +1,49 @@
|
||||||
|
// 9 february 2014
|
||||||
|
package main
|
||||||
|
|
||||||
|
import (
|
||||||
|
// "syscall"
|
||||||
|
"unsafe"
|
||||||
|
)
|
||||||
|
|
||||||
|
type MSG struct {
|
||||||
|
Hwnd HWND
|
||||||
|
Message uint32
|
||||||
|
WParam WPARAM
|
||||||
|
LParam LPARAM
|
||||||
|
Time uint32
|
||||||
|
Pt POINT
|
||||||
|
}
|
||||||
|
|
||||||
|
var (
|
||||||
|
dispatchMessage = user32.NewProc("DispatchMessageW")
|
||||||
|
getMessage = user32.NewProc("GetMessageW")
|
||||||
|
translateMessage = user32.NewProc("TranslateMessage")
|
||||||
|
)
|
||||||
|
|
||||||
|
// TODO handle errors
|
||||||
|
func DispatchMessage(lpmsg *MSG) (result LRESULT, err error) {
|
||||||
|
r1, _, _ := dispatchMessage.Call(uintptr(unsafe.Pointer(lpmsg)))
|
||||||
|
return LRESULT(r1), nil
|
||||||
|
}
|
||||||
|
|
||||||
|
var getMessageFail = -1 // because Go doesn't let me
|
||||||
|
|
||||||
|
func GetMessage(hWnd HWND, wMsgFilterMin uint32, wMsgFilterMax uint32) (lpMsg *MSG, quit bool, err error) {
|
||||||
|
lpMsg = new(MSG)
|
||||||
|
r1, _, err := getMessage.Call(
|
||||||
|
uintptr(unsafe.Pointer(lpMsg)),
|
||||||
|
uintptr(hWnd),
|
||||||
|
uintptr(wMsgFilterMin),
|
||||||
|
uintptr(wMsgFilterMax))
|
||||||
|
if r1 == uintptr(getMessageFail) { // failure
|
||||||
|
return nil, false, err
|
||||||
|
}
|
||||||
|
return lpMsg, r1 == 0, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// TODO handle errors
|
||||||
|
func TranslateMessage(lpMsg *MSG) (translated bool, err error) {
|
||||||
|
r1, _, _ := translateMessage.Call(uintptr(unsafe.Pointer(lpMsg)))
|
||||||
|
return r1 != 0, nil
|
||||||
|
}
|
|
@ -0,0 +1,20 @@
|
||||||
|
// 9 february 2014
|
||||||
|
package main
|
||||||
|
|
||||||
|
import (
|
||||||
|
// "syscall"
|
||||||
|
// "unsafe"
|
||||||
|
)
|
||||||
|
|
||||||
|
var (
|
||||||
|
updateWindow = user32.NewProc("UpdateWindow")
|
||||||
|
)
|
||||||
|
|
||||||
|
// TODO is error handling valid here? MSDN just says zero on failure; syscall.LazyProc.Call() always returns non-nil
|
||||||
|
func UpdateWindow(hWnd HWND) (err error) {
|
||||||
|
r1, _, err := updateWindow.Call(uintptr(hWnd))
|
||||||
|
if r1 == 0 { // failure
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
|
@ -0,0 +1,14 @@
|
||||||
|
// 9 february 2014
|
||||||
|
package main
|
||||||
|
|
||||||
|
import (
|
||||||
|
// "syscall"
|
||||||
|
// "unsafe"
|
||||||
|
)
|
||||||
|
|
||||||
|
// TODO merge with common.go?
|
||||||
|
|
||||||
|
type POINT struct {
|
||||||
|
X int32
|
||||||
|
Y int32
|
||||||
|
}
|
64
windows.go
64
windows.go
|
@ -6,6 +6,37 @@ import (
|
||||||
"unsafe"
|
"unsafe"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
// Window styles.
|
||||||
|
const (
|
||||||
|
WS_BORDER = 0x00800000
|
||||||
|
WS_CAPTION = 0x00C00000
|
||||||
|
WS_CHILD = 0x40000000
|
||||||
|
WS_CHILDWINDOW = 0x40000000
|
||||||
|
WS_CLIPCHILDREN = 0x02000000
|
||||||
|
WS_CLIPSIBLINGS = 0x04000000
|
||||||
|
WS_DISABLED = 0x08000000
|
||||||
|
WS_DLGFRAME = 0x00400000
|
||||||
|
WS_GROUP = 0x00020000
|
||||||
|
WS_HSCROLL = 0x00100000
|
||||||
|
WS_ICONIC = 0x20000000
|
||||||
|
WS_MAXIMIZE = 0x01000000
|
||||||
|
WS_MAXIMIZEBOX = 0x00010000
|
||||||
|
WS_MINIMIZE = 0x20000000
|
||||||
|
WS_MINIMIZEBOX = 0x00020000
|
||||||
|
WS_OVERLAPPED = 0x00000000
|
||||||
|
WS_OVERLAPPEDWINDOW = (WS_OVERLAPPED | WS_CAPTION | WS_SYSMENU | WS_THICKFRAME | WS_MINIMIZEBOX | WS_MAXIMIZEBOX)
|
||||||
|
WS_POPUP = 0x80000000
|
||||||
|
WS_POPUPWINDOW = (WS_POPUP | WS_BORDER | WS_SYSMENU)
|
||||||
|
WS_SIZEBOX = 0x00040000
|
||||||
|
WS_SYSMENU = 0x00080000
|
||||||
|
WS_TABSTOP = 0x00010000
|
||||||
|
WS_THICKFRAME = 0x00040000
|
||||||
|
WS_TILED = 0x00000000
|
||||||
|
WS_TILEDWINDOW = (WS_OVERLAPPED | WS_CAPTION | WS_SYSMENU | WS_THICKFRAME | WS_MINIMIZEBOX | WS_MAXIMIZEBOX)
|
||||||
|
WS_VISIBLE = 0x10000000
|
||||||
|
WS_VSCROLL = 0x00200000
|
||||||
|
)
|
||||||
|
|
||||||
// Extended window styles.
|
// Extended window styles.
|
||||||
const (
|
const (
|
||||||
WS_EX_ACCEPTFILES = 0x00000010
|
WS_EX_ACCEPTFILES = 0x00000010
|
||||||
|
@ -36,7 +67,12 @@ const (
|
||||||
WS_EX_WINDOWEDGE = 0x00000100
|
WS_EX_WINDOWEDGE = 0x00000100
|
||||||
)
|
)
|
||||||
|
|
||||||
// TODO CW_USEDEFAULT
|
// bizarrely, this value is given on the page for CreateMDIWindow, but not CreateWindow or CreateWindowEx
|
||||||
|
// I do it this way because Go won't let me shove the exact value into an int
|
||||||
|
var (
|
||||||
|
_uCW_USEDEFAULT uint = 0x80000000
|
||||||
|
CW_USEDEFAULT = int(_uCW_USEDEFAULT)
|
||||||
|
)
|
||||||
|
|
||||||
// GetSysColor values. These can be cast to HBRUSH (after adding 1) for WNDCLASS as well.
|
// GetSysColor values. These can be cast to HBRUSH (after adding 1) for WNDCLASS as well.
|
||||||
const (
|
const (
|
||||||
|
@ -78,8 +114,26 @@ const (
|
||||||
COLOR_WINDOWTEXT = 8
|
COLOR_WINDOWTEXT = 8
|
||||||
)
|
)
|
||||||
|
|
||||||
|
// ShowWindow settings.
|
||||||
|
const (
|
||||||
|
SW_FORCEMINIMIZE = 11
|
||||||
|
SW_HIDE = 0
|
||||||
|
SW_MAXIMIZE = 3
|
||||||
|
SW_MINIMIZE = 6
|
||||||
|
SW_RESTORE = 9
|
||||||
|
SW_SHOW = 5
|
||||||
|
SW_SHOWDEFAULT = 10
|
||||||
|
SW_SHOWMAXIMIZED = 3
|
||||||
|
SW_SHOWMINIMIZED = 2
|
||||||
|
SW_SHOWMINNOACTIVE = 7
|
||||||
|
SW_SHOWNA = 8
|
||||||
|
SW_SHOWNOACTIVATE = 4
|
||||||
|
SW_SHOWNORMAL = 1
|
||||||
|
)
|
||||||
|
|
||||||
var (
|
var (
|
||||||
createWindowEx = user32.NewProc("CreateWindowExW")
|
createWindowEx = user32.NewProc("CreateWindowExW")
|
||||||
|
showWindow = user32.NewProc("ShowWindow")
|
||||||
)
|
)
|
||||||
|
|
||||||
// TODO use lpParam
|
// TODO use lpParam
|
||||||
|
@ -102,3 +156,11 @@ func CreateWindowEx(dwExStyle uint32, lpClassName string, lpWindowName string, d
|
||||||
}
|
}
|
||||||
return HWND(r1), nil
|
return HWND(r1), nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// TODO figure out how to handle errors
|
||||||
|
func ShowWindow(hWnd HWND, nCmdShow int) (previouslyVisible bool, err error) {
|
||||||
|
r1, _, _ := showWindow.Call(
|
||||||
|
uintptr(hWnd),
|
||||||
|
uintptr(nCmdShow))
|
||||||
|
return r1 != 0, nil
|
||||||
|
}
|
||||||
|
|
|
@ -21,7 +21,7 @@ type WNDCLASS struct {
|
||||||
|
|
||||||
type _WNDCLASSW struct {
|
type _WNDCLASSW struct {
|
||||||
style uint32
|
style uint32
|
||||||
lpfnWndProc WNDPROC
|
lpfnWndProc uintptr
|
||||||
cbClsExtra int
|
cbClsExtra int
|
||||||
cbWndExtra int
|
cbWndExtra int
|
||||||
hInstance HANDLE
|
hInstance HANDLE
|
||||||
|
@ -39,7 +39,7 @@ func (w *WNDCLASS) toNative() *_WNDCLASSW {
|
||||||
}
|
}
|
||||||
return &_WNDCLASSW{
|
return &_WNDCLASSW{
|
||||||
style: w.Style,
|
style: w.Style,
|
||||||
lpfnWndProc: w.LpfnWndProc,
|
lpfnWndProc: syscall.NewCallback(w.LpfnWndProc),
|
||||||
cbClsExtra: w.CbClsExtra,
|
cbClsExtra: w.CbClsExtra,
|
||||||
cbWndExtra: w.CbWndExtra,
|
cbWndExtra: w.CbWndExtra,
|
||||||
hInstance: w.HInstance,
|
hInstance: w.HInstance,
|
||||||
|
|
Loading…
Reference in New Issue