summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--main.go93
-rw-r--r--messages.go49
-rw-r--r--painting.go20
-rw-r--r--rectangles.go14
-rw-r--r--windows.go64
-rw-r--r--wndclass.go4
6 files changed, 236 insertions, 8 deletions
diff --git a/main.go b/main.go
index c8162ef..b16378e 100644
--- a/main.go
+++ b/main.go
@@ -1,12 +1,95 @@
// 7 february 2014
package main
-import "fmt"
+import (
+ "fmt"
+ "os"
+ "runtime"
+)
+
+func fatalf(format string, args ...interface{}) {
+ s := fmt.Sprintf(format, args...)
+ _, err := MessageBox(NULL,
+ "An internal error has occured:\n" + s,
+ 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() {
- fmt.Println(MessageBox(NULL,
- "hello, world",
- "hello",
- 0))
+ 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)
+ }
+ }
}
diff --git a/messages.go b/messages.go
new file mode 100644
index 0000000..aa01a7e
--- /dev/null
+++ b/messages.go
@@ -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
+}
diff --git a/painting.go b/painting.go
new file mode 100644
index 0000000..069fd2d
--- /dev/null
+++ b/painting.go
@@ -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
+}
diff --git a/rectangles.go b/rectangles.go
new file mode 100644
index 0000000..d503edc
--- /dev/null
+++ b/rectangles.go
@@ -0,0 +1,14 @@
+// 9 february 2014
+package main
+
+import (
+// "syscall"
+// "unsafe"
+)
+
+// TODO merge with common.go?
+
+type POINT struct {
+ X int32
+ Y int32
+}
diff --git a/windows.go b/windows.go
index 5cfa53d..bf840fb 100644
--- a/windows.go
+++ b/windows.go
@@ -6,6 +6,37 @@ import (
"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.
const (
WS_EX_ACCEPTFILES = 0x00000010
@@ -36,7 +67,12 @@ const (
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.
const (
@@ -78,8 +114,26 @@ const (
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 (
createWindowEx = user32.NewProc("CreateWindowExW")
+ showWindow = user32.NewProc("ShowWindow")
)
// TODO use lpParam
@@ -102,3 +156,11 @@ func CreateWindowEx(dwExStyle uint32, lpClassName string, lpWindowName string, d
}
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
+}
diff --git a/wndclass.go b/wndclass.go
index 7296369..38ff4ae 100644
--- a/wndclass.go
+++ b/wndclass.go
@@ -21,7 +21,7 @@ type WNDCLASS struct {
type _WNDCLASSW struct {
style uint32
- lpfnWndProc WNDPROC
+ lpfnWndProc uintptr
cbClsExtra int
cbWndExtra int
hInstance HANDLE
@@ -39,7 +39,7 @@ func (w *WNDCLASS) toNative() *_WNDCLASSW {
}
return &_WNDCLASSW{
style: w.Style,
- lpfnWndProc: w.LpfnWndProc,
+ lpfnWndProc: syscall.NewCallback(w.LpfnWndProc),
cbClsExtra: w.CbClsExtra,
cbWndExtra: w.CbWndExtra,
hInstance: w.HInstance,