diff --git a/common.go b/common.go index 8b4daa5..f4c769e 100644 --- a/common.go +++ b/common.go @@ -7,11 +7,25 @@ import ( var ( user32 = syscall.NewLazyDLL("user32.dll") + kernel32 = syscall.NewLazyDLL("kernel32.dll") ) -type HWND uintptr +type HANDLE uintptr +type HWND HANDLE +type HBRUSH HANDLE const ( NULL = 0 ) +type ATOM uint16 + +// TODO pull the thanks for these three from the old wingo source +type WPARAM uintptr +type LPARAM uintptr +type LRESULT uintptr + +// microsoft's header files do this +func MAKEINTRESOURCE(what uint16) uintptr { + return uintptr(what) +} diff --git a/cursors.go b/cursors.go new file mode 100644 index 0000000..78fb1f8 --- /dev/null +++ b/cursors.go @@ -0,0 +1,41 @@ +// 8 february 2014 +package main + +import ( +// "syscall" +// "unsafe" +) + +// Predefined cursor resource IDs. +const ( + IDC_APPSTARTING = 32650 + IDC_ARROW = 32512 + IDC_CROSS = 32515 + IDC_HAND = 32649 + IDC_HELP = 32651 + IDC_IBEAM = 32513 +// IDC_ICON = 32641 // [Obsolete for applications marked version 4.0 or later.] + IDC_NO = 32648 +// IDC_SIZE = 32640 // [Obsolete for applications marked version 4.0 or later. Use IDC_SIZEALL.] + IDC_SIZEALL = 32646 + IDC_SIZENESW = 32643 + IDC_SIZENS = 32645 + IDC_SIZENWSE = 32642 + IDC_SIZEWE = 32644 + IDC_UPARROW = 32516 + IDC_WAIT = 32514 +) + +var ( + loadCursor = user32.NewProc("LoadCursorW") +) + +func LoadCursor_ResourceID(hInstance HANDLE, lpCursorName uint16) (cursor HANDLE, err error) { + r1, _, err := loadCursor.Call( + uintptr(hInstance), + MAKEINTRESOURCE(lpCursorName)) + if r1 == 0 { // failure + return NULL, err + } + return HANDLE(r1), nil +} diff --git a/icons.go b/icons.go new file mode 100644 index 0000000..c28f158 --- /dev/null +++ b/icons.go @@ -0,0 +1,35 @@ +// 8 february 2014 +package main + +import ( +// "syscall" +// "unsafe" +) + +// Predefined icon resource IDs. +const ( + IDI_APPLICATION = 32512 + IDI_ASTERISK = 32516 + IDI_ERROR = 32513 + IDI_EXCLAMATION = 32515 + IDI_HAND = 32513 + IDI_INFORMATION = 32516 + IDI_QUESTION = 32514 + IDI_SHIELD = 32518 + IDI_WARNING = 32515 + IDI_WINLOGO = 32517 +) + +var ( + loadIcon = user32.NewProc("LoadIconW") +) + +func LoadIcon_ResourceID(hInstance HANDLE, lpIconName uint16) (icon HANDLE, err error) { + r1, _, err := loadIcon.Call( + uintptr(hInstance), + MAKEINTRESOURCE(lpIconName)) + if r1 == 0 { // failure + return NULL, err + } + return HANDLE(r1), nil +} diff --git a/windows.go b/windows.go new file mode 100644 index 0000000..5cfa53d --- /dev/null +++ b/windows.go @@ -0,0 +1,104 @@ +// 8 february 2014 +package main + +import ( + "syscall" + "unsafe" +) + +// Extended window styles. +const ( + WS_EX_ACCEPTFILES = 0x00000010 + WS_EX_APPWINDOW = 0x00040000 + WS_EX_CLIENTEDGE = 0x00000200 +// WS_EX_COMPOSITED = 0x02000000 // [Windows 2000:This style is not supported.] + WS_EX_CONTEXTHELP = 0x00000400 + WS_EX_CONTROLPARENT = 0x00010000 + WS_EX_DLGMODALFRAME = 0x00000001 + WS_EX_LAYERED = 0x00080000 + WS_EX_LAYOUTRTL = 0x00400000 + WS_EX_LEFT = 0x00000000 + WS_EX_LEFTSCROLLBAR = 0x00004000 + WS_EX_LTRREADING = 0x00000000 + WS_EX_MDICHILD = 0x00000040 + WS_EX_NOACTIVATE = 0x08000000 + WS_EX_NOINHERITLAYOUT = 0x00100000 + WS_EX_NOPARENTNOTIFY = 0x00000004 + WS_EX_OVERLAPPEDWINDOW = (WS_EX_WINDOWEDGE | WS_EX_CLIENTEDGE) + WS_EX_PALETTEWINDOW = (WS_EX_WINDOWEDGE | WS_EX_TOOLWINDOW | WS_EX_TOPMOST) + WS_EX_RIGHT = 0x00001000 + WS_EX_RIGHTSCROLLBAR = 0x00000000 + WS_EX_RTLREADING = 0x00002000 + WS_EX_STATICEDGE = 0x00020000 + WS_EX_TOOLWINDOW = 0x00000080 + WS_EX_TOPMOST = 0x00000008 + WS_EX_TRANSPARENT = 0x00000020 + WS_EX_WINDOWEDGE = 0x00000100 +) + +// TODO CW_USEDEFAULT + +// GetSysColor values. These can be cast to HBRUSH (after adding 1) for WNDCLASS as well. +const ( + COLOR_3DDKSHADOW = 21 + COLOR_3DFACE = 15 + COLOR_3DHIGHLIGHT = 20 + COLOR_3DHILIGHT = 20 + COLOR_3DLIGHT = 22 + COLOR_3DSHADOW = 16 + COLOR_ACTIVEBORDER = 10 + COLOR_ACTIVECAPTION = 2 + COLOR_APPWORKSPACE = 12 + COLOR_BACKGROUND = 1 + COLOR_BTNFACE = 15 + COLOR_BTNHIGHLIGHT = 20 + COLOR_BTNHILIGHT = 20 + COLOR_BTNSHADOW = 16 + COLOR_BTNTEXT = 18 + COLOR_CAPTIONTEXT = 9 + COLOR_DESKTOP = 1 + COLOR_GRADIENTACTIVECAPTION = 27 + COLOR_GRADIENTINACTIVECAPTION = 28 + COLOR_GRAYTEXT = 17 + COLOR_HIGHLIGHT = 13 + COLOR_HIGHLIGHTTEXT = 14 + COLOR_HOTLIGHT = 26 + COLOR_INACTIVEBORDER = 11 + COLOR_INACTIVECAPTION = 3 + COLOR_INACTIVECAPTIONTEXT = 19 + COLOR_INFOBK = 24 + COLOR_INFOTEXT = 23 + COLOR_MENU = 4 +// COLOR_MENUHILIGHT = 29 // [Windows 2000:This value is not supported.] +// COLOR_MENUBAR = 30 // [Windows 2000:This value is not supported.] + COLOR_MENUTEXT = 7 + COLOR_SCROLLBAR = 0 + COLOR_WINDOW = 5 + COLOR_WINDOWFRAME = 6 + COLOR_WINDOWTEXT = 8 +) + +var ( + createWindowEx = user32.NewProc("CreateWindowExW") +) + +// TODO use lpParam +func CreateWindowEx(dwExStyle uint32, lpClassName string, lpWindowName string, dwStyle uint32, x int, y int, nWidth int, nHeight int, hwndParent HWND, hMenu HANDLE, hInstance HANDLE, lpParam interface{}) (hwnd HWND, err error) { + r1, _, err := createWindowEx.Call( + uintptr(dwExStyle), + uintptr(unsafe.Pointer(syscall.StringToUTF16Ptr(lpClassName))), + uintptr(unsafe.Pointer(syscall.StringToUTF16Ptr(lpWindowName))), + uintptr(dwStyle), + uintptr(x), + uintptr(y), + uintptr(nWidth), + uintptr(nHeight), + uintptr(hwndParent), + uintptr(hMenu), + uintptr(hInstance), + uintptr(0)) + if r1 == 0 { // failure + return NULL, err + } + return HWND(r1), nil +} diff --git a/winmain.go b/winmain.go new file mode 100644 index 0000000..b79ad81 --- /dev/null +++ b/winmain.go @@ -0,0 +1,59 @@ +// 8 february 2014 +package main + +import ( +// "syscall" + "unsafe" +) + +// this provides the hInstance and nCmdShow that are normally passed to WinMain() + +const ( + STARTF_USESHOWWINDOW = 0x00000001 +) + +var ( + getModuleHandle = kernel32.NewProc("GetModuleHandleW") + getStartupInfo = kernel32.NewProc("GetStartupInfoW") +) + +// TODO is this trick documented in MSDN? +func getWinMainhInstance() (hInstance HANDLE, err error) { + r1, _, err := getModuleHandle.Call(uintptr(NULL)) + if r1 == 0 { + return NULL, err + } + return HANDLE(r1), nil +} + +// TODO this is what MinGW-w64's crt (svn revision xxx) does; is it best? is any of this documented anywhere on MSDN? +// TODO I highly doubt Windows API functions ever not fail, so figure out what to do should an error actually occur +func getWinMainnCmdShow() (nCmdShow int, err error) { + var info struct { + cb uint32 + lpReserved *uint16 + lpDesktop *uint16 + lpTitle *uint16 + dwX uint32 + dwY uint32 + dwXSize uint32 + dwYSzie uint32 + dwXCountChars uint32 + dwYCountChars uint32 + dwFillAttribute uint32 + dwFlags uint32 + wShowWindow uint16 + cbReserved2 uint16 + lpReserved2 *byte + hStdInput HANDLE + hStdOutput HANDLE + hStdError HANDLE + } + + // does not fail according to MSDN + getStartupInfo.Call(uintptr(unsafe.Pointer(&info))) + if info.dwFlags & STARTF_USESHOWWINDOW != 0 { + return int(info.wShowWindow), nil + } + return SW_SHOWDEFAULT, nil +} diff --git a/wndclass.go b/wndclass.go new file mode 100644 index 0000000..7296369 --- /dev/null +++ b/wndclass.go @@ -0,0 +1,64 @@ +// 8 february 2014 +package main + +import ( + "syscall" + "unsafe" +) + +type WNDCLASS struct { + Style uint32 + LpfnWndProc WNDPROC + CbClsExtra int // TODO exact Go type for C int? MSDN says C int + CbWndExtra int // TODO exact Go type for C int? MSDN says C int + HInstance HANDLE // actually HINSTANCE + HIcon HANDLE // actually HICON + HCursor HANDLE // actually HCURSOR + HbrBackground HBRUSH + LpszMenuName *string // TODO this should probably just be a regular string with "" indicating no name but MSDN doesn't say if that's legal or not + LpszClassName string +} + +type _WNDCLASSW struct { + style uint32 + lpfnWndProc WNDPROC + cbClsExtra int + cbWndExtra int + hInstance HANDLE + hIcon HANDLE + hCursor HANDLE + hbrBackground HBRUSH + lpszMenuName *uint16 + lpszClassName *uint16 +} + +func (w *WNDCLASS) toNative() *_WNDCLASSW { + menuName := (*uint16)(nil) + if w.LpszMenuName != nil { + menuName = syscall.StringToUTF16Ptr(*w.LpszMenuName) + } + return &_WNDCLASSW{ + style: w.Style, + lpfnWndProc: w.LpfnWndProc, + cbClsExtra: w.CbClsExtra, + cbWndExtra: w.CbWndExtra, + hInstance: w.HInstance, + hIcon: w.HIcon, + hCursor: w.HCursor, + hbrBackground: w.HbrBackground, + lpszMenuName: menuName, + lpszClassName: syscall.StringToUTF16Ptr(w.LpszClassName), + } +} + +var ( + registerClass = user32.NewProc("RegisterClassW") +) + +func RegisterClass(lpWndClass *WNDCLASS) (class ATOM, err error) { + r1, _, err := registerClass.Call(uintptr(unsafe.Pointer(lpWndClass.toNative()))) + if r1 == 0 { // failure + return 0, err + } + return ATOM(r1), nil +} diff --git a/wndproc.go b/wndproc.go new file mode 100644 index 0000000..b9c13f2 --- /dev/null +++ b/wndproc.go @@ -0,0 +1,24 @@ +// 8 february 2014 +package main + +import ( +// "syscall" +// "unsafe" +) + +// TODO error handling +type WNDPROC func(hwnd HWND, uMsg uint32, wParam WPARAM, lParam LPARAM) LRESULT + +var ( + defWindowProc = user32.NewProc("DefWindowProcW") +) + +// TODO error handling +func DefWindowProc(hwnd HWND, uMsg uint32, wParam WPARAM, lParam LPARAM) LRESULT { + r1, _, _ := defWindowProc.Call( + uintptr(hwnd), + uintptr(uMsg), + uintptr(wParam), + uintptr(lParam)) + return LRESULT(r1) +}