Added combo boxes and added some to the main window example.

This commit is contained in:
Pietro Gagliardi 2014-02-10 12:44:11 -05:00
parent 6ae896cd64
commit e9f25362be
4 changed files with 194 additions and 3 deletions

83
comboboxes.go Normal file
View File

@ -0,0 +1,83 @@
// 10 february 2014
package main
import (
// "syscall"
// "unsafe"
)
// Combobox styles.
const (
// from winuser.h
CBS_SIMPLE = 0x0001
CBS_DROPDOWN = 0x0002
CBS_DROPDOWNLIST = 0x0003
CBS_OWNERDRAWFIXED = 0x0010
CBS_OWNERDRAWVARIABLE = 0x0020
CBS_AUTOHSCROLL = 0x0040
CBS_OEMCONVERT = 0x0080
CBS_SORT = 0x0100
CBS_HASSTRINGS = 0x0200
CBS_NOINTEGRALHEIGHT = 0x0400
CBS_DISABLENOSCROLL = 0x0800
CBS_UPPERCASE = 0x2000
CBS_LOWERCASE = 0x4000
)
// Combobox messages.
// TODO filter out messages not provided in windows 2000
const (
// from winuser.h
CB_GETEDITSEL = 0x0140
CB_LIMITTEXT = 0x0141
CB_SETEDITSEL = 0x0142
CB_ADDSTRING = 0x0143
CB_DELETESTRING = 0x0144
CB_DIR = 0x0145
CB_GETCOUNT = 0x0146
CB_GETCURSEL = 0x0147
CB_GETLBTEXT = 0x0148
CB_GETLBTEXTLEN = 0x0149
CB_INSERTSTRING = 0x014A
CB_RESETCONTENT = 0x014B
CB_FINDSTRING = 0x014C
CB_SELECTSTRING = 0x014D
CB_SETCURSEL = 0x014E
CB_SHOWDROPDOWN = 0x014F
CB_GETITEMDATA = 0x0150
CB_SETITEMDATA = 0x0151
CB_GETDROPPEDCONTROLRECT = 0x0152
CB_SETITEMHEIGHT = 0x0153
CB_GETITEMHEIGHT = 0x0154
CB_SETEXTENDEDUI = 0x0155
CB_GETEXTENDEDUI = 0x0156
CB_GETDROPPEDSTATE = 0x0157
CB_FINDSTRINGEXACT = 0x0158
CB_SETLOCALE = 0x0159
CB_GETLOCALE = 0x015A
CB_GETTOPINDEX = 0x015B
CB_SETTOPINDEX = 0x015C
CB_GETHORIZONTALEXTENT = 0x015D
CB_SETHORIZONTALEXTENT = 0x015E
CB_GETDROPPEDWIDTH = 0x015F
CB_SETDROPPEDWIDTH = 0x0160
CB_INITSTORAGE = 0x0161
CB_MULTIPLEADDSTRING = 0x0163
CB_GETCOMBOBOXINFO = 0x0164
)
// Combobox WM_COMMAND notificaitons.
const (
// from winuser.h
CBN_ERRSPACE = (-1) // TODO this will blow up the Go compiler if it's used
CBN_SELCHANGE = 1
CBN_DBLCLK = 2
CBN_SETFOCUS = 3
CBN_KILLFOCUS = 4
CBN_EDITCHANGE = 5
CBN_EDITUPDATE = 6
CBN_DROPDOWN = 7
CBN_CLOSEUP = 8
CBN_SELENDOK = 9
CBN_SELENDCANCEL = 10
)

View File

@ -3,8 +3,11 @@ package main
import (
"syscall"
"unsafe"
)
// TODO filter out commctrl.h stuff because the combobox stuff has values that differ between windows versions and bleh
var (
user32 = syscall.NewLazyDLL("user32.dll")
kernel32 = syscall.NewLazyDLL("kernel32.dll")
@ -37,7 +40,30 @@ func (w WPARAM) HIWORD() uint16 {
return uint16((w >> 16) & 0xFFFF)
}
func LPARAMFromString(str string) LPARAM {
return LPARAM(unsafe.Pointer(syscall.StringToUTF16Ptr(str)))
}
// microsoft's header files do this
func MAKEINTRESOURCE(what uint16) uintptr {
return uintptr(what)
}
// TODO adorn error messages with which step failed?
func getText(hwnd HWND) (text string, err error) {
var tc []uint16
length, err := SendMessage(hwnd, WM_GETTEXTLENGTH, 0, 0)
if err != nil {
return "", err
}
tc = make([]uint16, length + 1)
_, err = SendMessage(hwnd,
WM_GETTEXT,
WPARAM(length + 1),
LPARAM(unsafe.Pointer(&tc[0])))
if err != nil {
return "", err
}
return syscall.UTF16ToString(tc), nil
}

72
main.go
View File

@ -21,17 +21,47 @@ func fatalf(format string, args ...interface{}) {
const (
IDC_BUTTON = 100
IDC_VARCOMBO = 101
IDC_FIXCOMBO = 102
)
var varCombo, fixCombo HWND
func wndProc(hwnd HWND, msg uint32, wParam WPARAM, lParam LPARAM) LRESULT {
switch msg {
case WM_COMMAND:
if wParam.LOWORD() == IDC_BUTTON {
buttonclick := "neither clicked nor double clicked (somehow)"
if wParam.HIWORD() == BN_CLICKED {
MessageBox(hwnd, "clicked", "", MB_OK)
buttonclick = "clicked"
} else if wParam.HIWORD() == BN_DOUBLECLICKED {
MessageBox(hwnd, "double clicked", "", MB_OK)
buttonclick = "double clicked"
}
varText, err := getText(varCombo)
if err != nil {
fatalf("error getting variable combo box text: %v", err)
}
fixTextWM, err := getText(fixCombo)
if err != nil {
fatalf("error getting fixed combo box text with WM_GETTEXT: %v", err)
}
fixTextIndex, err := SendMessage(fixCombo, CB_GETCURSEL, 0, 0)
if err != nil {
fatalf("error getting fixed combo box current selection: %v", err)
}
// TODO get text from index
MessageBox(hwnd,
fmt.Sprintf("button state: %s\n" +
"variable combo box text: %s\n" +
"fixed combo box text with WM_GETTEXT: %s\n" +
"fixed combo box current index: %d\n",
buttonclick, varText, fixTextWM, fixTextIndex),
"note",
MB_OK)
}
return 0
case WM_CLOSE:
@ -103,12 +133,48 @@ func main() {
0,
"BUTTON", "Click Me",
BS_PUSHBUTTON | WS_CHILD | WS_VISIBLE | WS_TABSTOP,
20, 20, 100, 100,
20, 20, 100, 20,
hwnd, HMENU(IDC_BUTTON), hInstance, NULL)
if err != nil {
fatalf("error creating button: %v", err)
}
varCombo, err = CreateWindowEx(
0,
"COMBOBOX", "",
CBS_DROPDOWN | CBS_AUTOHSCROLL | WS_CHILD | WS_VISIBLE | WS_TABSTOP,
140, 20, 100, 20,
hwnd, HMENU(IDC_VARCOMBO), hInstance, NULL)
if err != nil {
fatalf("error creating variable combo box: %v", err)
}
vcItems := []string{"a", "b", "c", "d"}
for _, v := range vcItems {
_, err := SendMessage(varCombo, CB_ADDSTRING, 0,
LPARAMFromString(v))
if err != nil {
fatalf("error adding %q to variable combo box: %v", v, err)
}
}
fixCombo, err = CreateWindowEx(
0,
"COMBOBOX", "",
CBS_DROPDOWNLIST | WS_CHILD | WS_VISIBLE | WS_TABSTOP,
140, 50, 100, 20,
hwnd, HMENU(IDC_FIXCOMBO), hInstance, NULL)
if err != nil {
fatalf("error creating fixed combo box: %v", err)
}
fcItems := []string{"e", "f", "g", "h"}
for _, v := range fcItems {
_, err := SendMessage(fixCombo, CB_ADDSTRING, 0,
LPARAMFromString(v))
if err != nil {
fatalf("error adding %q to fixed combo box: %v", v, err)
}
}
_, err = ShowWindow(hwnd, nCmdShow)
if err != nil {
fatalf("error showing window: %v", err)

View File

@ -6,6 +6,11 @@ import (
"unsafe"
)
// SendMessage constants.
const (
HWND_BROADCAST = HWND(0xFFFF)
)
type MSG struct {
Hwnd HWND
Message uint32
@ -19,6 +24,7 @@ var (
dispatchMessage = user32.NewProc("DispatchMessageW")
getMessage = user32.NewProc("GetMessageW")
postQuitMessage = user32.NewProc("PostQuitMessage")
sendMessage = user32.NewProc("SendMessageW")
translateMessage = user32.NewProc("TranslateMessage")
)
@ -49,6 +55,16 @@ func PostQuitMessage(nExitCode int) (err error) {
return nil
}
// TODO handle errors
func SendMessage(hWnd HWND, Msg uint32, wParam WPARAM, lParam LPARAM) (result LRESULT, err error) {
r1, _, _ := sendMessage.Call(
uintptr(hWnd),
uintptr(Msg),
uintptr(wParam),
uintptr(lParam))
return LRESULT(r1), nil
}
// TODO handle errors
func TranslateMessage(lpMsg *MSG) (translated bool, err error) {
r1, _, _ := translateMessage.Call(uintptr(unsafe.Pointer(lpMsg)))