Archive for 7月 21st, 2012

  1. Hello, Win32 GUI(Go) World!

    Posted on 7月 21st, 2012 by cx20

    Win32 GUI(Go)

    Win32 アプリケーションは Windows 標準 API である Win32 API を使用した Windows アプリケーションである。
    以下は Go言語 における Win32 GUI アプリケーション の例となっている。

    ソースコード

    package main
     
    import (
        "syscall"
        "unsafe"
    )
     
    const (
        WS_OVERLAPPED   = 0x00000000
        WS_POPUP        = 0x80000000
        WS_CHILD        = 0x40000000
        WS_MINIMIZE     = 0x20000000
        WS_VISIBLE      = 0x10000000
        WS_DISABLED     = 0x08000000
        WS_CLIPSIBLINGS = 0x04000000
        WS_CLIPCHILDREN = 0x02000000
        WS_MAXIMIZE     = 0x01000000
        WS_CAPTION      = 0x00C00000 // WS_BORDER | WS_DLGFRAME
        WS_BORDER       = 0x00800000
        WS_DLGFRAME     = 0x00400000
        WS_VSCROLL      = 0x00200000
        WS_HSCROLL      = 0x00100000
        WS_SYSMENU      = 0x00080000
        WS_THICKFRAME   = 0x00040000
        WS_GROUP        = 0x00020000
        WS_TABSTOP      = 0x00010000
     
        WS_MINIMIZEBOX  = 0x00020000
        WS_MAXIMIZEBOX  = 0x00010000
     
        WS_TILED        = WS_OVERLAPPED
        WS_ICONIC       = WS_MINIMIZE
        WS_SIZEBOX      = WS_THICKFRAME
        WS_TILEDWINDOW  = WS_OVERLAPPEDWINDOW
     
        WS_OVERLAPPEDWINDOW = WS_OVERLAPPED | WS_CAPTION | WS_SYSMENU | WS_THICKFRAME | WS_MINIMIZEBOX | WS_MAXIMIZEBOX
        WS_POPUPWINDOW  = WS_POPUP | WS_BORDER | WS_SYSMENU
        WS_CHILDWINDOW  = WS_CHILD
     
        WM_CREATE       = 0x0001
        WM_DESTROY      = 0x0002
        WM_PAINT        = 0x000F
        WM_CLOSE        = 0x0010
        WM_COMMAND      = 0x0111
     
        COLOR_WINDOW    = 5
        COLOR_BTNFACE   = 15
     
        CS_VREDRAW      = 0x0001
        CS_HREDRAW      = 0x0002
     
        CW_USEDEFAULT   = -2147483648 // ((int)0x80000000)
     
        SW_SHOWDEFAULT  = 10
    )
     
    type WNDCLASSEX struct {
        cbSize         uint32
        style          uint32
        lpfnWndProc    uintptr
        cbClsExtra     int32
        cbWndExtra     int32
        hInstance      syscall.Handle
        hIcon          syscall.Handle
        hCursor        syscall.Handle
        hbrBackground  syscall.Handle
        lpszMenuName   *uint16
        lpszClassName  *uint16
        hIconSm        syscall.Handle
    }
     
    type POINT struct {
        x uintptr
        y uintptr
    }
     
    type MSG struct {
        hWnd    syscall.Handle
        message uint32
        wParam  uintptr
        lParam  uintptr
        time    uint32
        pt      POINT
    }
     
    type RECT struct {
        Left int32
        Top  int32
        Right int32
        Bottom  int32
    }
     
    type PAINTSTRUCT struct {
        hdc syscall.Handle
        fErace uint32
        rcPaint RECT
        fRestore uint32
        fIncUpdate uint32
        rgbReserved byte
    }
     
    var (
        kernel32, _ = syscall.LoadLibrary("kernel32.dll")
        user32, _   = syscall.LoadLibrary("user32.dll")
        gdi32, _    = syscall.LoadLibrary("gdi32.dll")
     
        procGetModuleHandleW, _ = syscall.GetProcAddress(kernel32, "GetModuleHandleW")
        procLoadIconW, _        = syscall.GetProcAddress(user32, "LoadIconW")
        procLoadCursorW, _      = syscall.GetProcAddress(user32, "LoadCursorW")
        procRegisterClassExW, _ = syscall.GetProcAddress(user32, "RegisterClassExW")
        procCreateWindowExW, _  = syscall.GetProcAddress(user32, "CreateWindowExW")
        procDefWindowProcW, _   = syscall.GetProcAddress(user32, "DefWindowProcW")
        procDestroyWindow, _    = syscall.GetProcAddress(user32, "DestroyWindow")
        procPostQuitMessage, _  = syscall.GetProcAddress(user32, "PostQuitMessage")
        procShowWindow, _       = syscall.GetProcAddress(user32, "ShowWindow")
        procUpdateWindow, _     = syscall.GetProcAddress(user32, "UpdateWindow")
        procGetMessageW, _      = syscall.GetProcAddress(user32, "GetMessageW")
        procTranslateMessage, _ = syscall.GetProcAddress(user32, "TranslateMessage")
        procDispatchMessageW, _ = syscall.GetProcAddress(user32, "DispatchMessageW")
        procSendMessageW, _     = syscall.GetProcAddress(user32, "SendMessageW")
        procPostMessageW, _     = syscall.GetProcAddress(user32, "PostMessageW")
        procBeginPaint, _       = syscall.GetProcAddress(user32, "BeginPaint")
        procEndPaint, _         = syscall.GetProcAddress(user32, "EndPaint")
        procTextOutW, _         = syscall.GetProcAddress(gdi32, "TextOutW")
     
        IDC_ARROW = MakeIntResource(32512)
        IDI_APPLICATION = MakeIntResource(32512)
    )
     
    func GetModuleHandle(lpModuleName *uint16) (syscall.Handle) {
        ret, _, _ := syscall.Syscall(uintptr(procGetModuleHandleW), 1, uintptr(unsafe.Pointer(lpModuleName)), 0, 0)
        return syscall.Handle(ret)
    }
     
    func LoadIcon(instance syscall.Handle, iconname *uint16) (syscall.Handle) {
        ret, _, _ := syscall.Syscall(uintptr(procLoadIconW), 2, uintptr(instance), uintptr(unsafe.Pointer(iconname)), 0)
        return syscall.Handle(ret)
    }
     
    func LoadCursor(instance syscall.Handle, cursorname *uint16) (syscall.Handle) {
        ret, _, _ := syscall.Syscall(uintptr(procLoadCursorW), 2, uintptr(instance), uintptr(unsafe.Pointer(cursorname)), 0)
        return syscall.Handle(ret)
    }
     
    func RegisterClassEx(lpwcx *WNDCLASSEX) (uint16) {
        ret, _, _ := syscall.Syscall(uintptr(procRegisterClassExW), 1, uintptr(unsafe.Pointer(lpwcx)), 0, 0)
        return uint16(ret)
     
    }
     
    func CreateWindowEx(dwExStyle uint32, lpClassName *uint16, lpWindowName *uint16, dwStyle uint32, x int32, y int32, nWidth int32, nHeight int32, hWndParent syscall.Handle, hMenu syscall.Handle, hInstance syscall.Handle, lpParam uintptr) (syscall.Handle) {
        ret, _, _ := syscall.Syscall12(uintptr(procCreateWindowExW), 12, uintptr(dwExStyle), uintptr(unsafe.Pointer(lpClassName)), uintptr(unsafe.Pointer(lpWindowName)), uintptr(dwStyle), uintptr(x), uintptr(y), uintptr(nWidth), uintptr(nHeight), uintptr(hWndParent), uintptr(hMenu), uintptr(hInstance), uintptr(lpParam))
        return syscall.Handle(ret)
    }
     
    func DefWindowProc(hWnd syscall.Handle, Msg uint32, wParam uintptr, lParam uintptr) (uintptr) {
        ret, _, _ := syscall.Syscall6(uintptr(procDefWindowProcW), 4, uintptr(hWnd), uintptr(Msg), uintptr(wParam), uintptr(lParam), 0, 0)
        return uintptr(ret)
    }
     
    func DestroyWindow(hWnd syscall.Handle) {
        syscall.Syscall(uintptr(procDestroyWindow), 1, uintptr(hWnd), 0, 0)
        return
    }
     
    func PostQuitMessage(nExitCode int32) {
        syscall.Syscall(uintptr(procPostQuitMessage), 1, uintptr(nExitCode), 0, 0)
        return
    }
     
    func ShowWindow(hWnd syscall.Handle, nCmdShow int32) (bool) {
        ret, _, _ := syscall.Syscall(uintptr(procShowWindow), 2, uintptr(hWnd), uintptr(nCmdShow), 0)
        return bool(ret != 0)
    }
     
    func UpdateWindow(hWnd syscall.Handle) {
        syscall.Syscall(uintptr(procUpdateWindow), 1, uintptr(hWnd), 0, 0)
        return
    }
     
    func GetMessage(lpMsg *MSG, hWnd syscall.Handle, wMsgFilterMin uint32, wMsgFilterMax uint32) (int32) {
        ret, _, _ := syscall.Syscall6(uintptr(procGetMessageW), 4, uintptr(unsafe.Pointer(lpMsg)), uintptr(hWnd), uintptr(wMsgFilterMin), uintptr(wMsgFilterMax), 0, 0)
        return int32(ret)
    }
     
    func TranslateMessage(lpMsg *MSG) (bool) {
        r, _, _ := syscall.Syscall(uintptr(procTranslateMessage), 1, uintptr(unsafe.Pointer(lpMsg)), 0, 0)
        return bool(r != 0)
    }
     
    func DispatchMessage(lpMsg *MSG) (int32) {
        ret, _, _ := syscall.Syscall(uintptr(procDispatchMessageW), 1, uintptr(unsafe.Pointer(lpMsg)), 0, 0)
        return int32(ret)
    }
     
    func SendMessage(hWnd syscall.Handle, Msg uint32, wParam uintptr, lParam uintptr) (uintptr) {
        ret, _, _ := syscall.Syscall6(uintptr(procSendMessageW), 4, uintptr(hWnd), uintptr(Msg), uintptr(wParam), uintptr(lParam), 0, 0)
        return uintptr(ret)
    }
     
    func PostMessage(hWnd syscall.Handle, Msg uint32, wParam uintptr, lParam uintptr) {
        syscall.Syscall6(uintptr(procPostMessageW), 4, uintptr(hWnd), uintptr(Msg), uintptr(wParam), uintptr(lParam), 0, 0)
        return
    }
     
    func BeginPaint(hDC syscall.Handle, lpPaint *PAINTSTRUCT ) (syscall.Handle) {
        ret, _, _ := syscall.Syscall(uintptr(procBeginPaint), 2, uintptr(hDC), uintptr(unsafe.Pointer(lpPaint)), 0)
        return syscall.Handle(ret)
    }
     
    func EndPaint(hDC syscall.Handle, lpPaint *PAINTSTRUCT ) (syscall.Handle) {
        ret, _, _ := syscall.Syscall(uintptr(procEndPaint), 2, uintptr(hDC), uintptr(unsafe.Pointer(lpPaint)), 0)
        return syscall.Handle(ret)
    }
     
    func TextOut(hDC syscall.Handle, x int32, y int32, text string, cbString int32 ) (bool) {
        ret, _, _ := syscall.Syscall6(uintptr(procTextOutW), 5, uintptr(hDC), uintptr(x), uintptr(y), uintptr(unsafe.Pointer(syscall.StringToUTF16Ptr(text))), uintptr(cbString), 0)
        return bool(ret != 0)
    }
     
    func MakeIntResource(id uint16) (*uint16) {
        return (*uint16)(unsafe.Pointer(uintptr(id)))
    }
     
    func WndProc(hWnd syscall.Handle, msg uint32, wParam, lParam uintptr) (uintptr) {
        switch msg {
        case WM_PAINT:
            var strMessage = "Hello, Win32 GUI(Go) World!"
            var ps PAINTSTRUCT
            hdc := BeginPaint(hWnd, &ps)
            TextOut( hdc, 0, 0, strMessage, int32(len(strMessage)) )
            EndPaint( hWnd, &ps )
        case WM_DESTROY:
            PostQuitMessage(0)
        default:
            return DefWindowProc(hWnd, msg, wParam, lParam)
        }
        return 0
    }
     
    func WinMain() int {
        hInstance := GetModuleHandle(nil)
        lpszClassName := syscall.StringToUTF16Ptr("helloWindow")
        lpszWindowName := syscall.StringToUTF16Ptr("Hello, World!")
        var wcex WNDCLASSEX
        wcex.cbSize        = uint32(unsafe.Sizeof(wcex))
        wcex.style         = CS_HREDRAW | CS_VREDRAW
        wcex.lpfnWndProc   = syscall.NewCallback(WndProc)
        wcex.cbClsExtra    = 0
        wcex.cbWndExtra    = 0
        wcex.hInstance     = hInstance
        wcex.hIcon         = LoadIcon(hInstance, IDI_APPLICATION)
        wcex.hCursor       = LoadCursor(0, IDC_ARROW)
        wcex.hbrBackground = COLOR_WINDOW + 1
        wcex.lpszMenuName  = nil
        wcex.lpszClassName = lpszClassName
        wcex.hIconSm       = LoadIcon(hInstance, IDI_APPLICATION)
        RegisterClassEx(&wcex)
     
        hWnd := CreateWindowEx(
            0,
            lpszClassName,
            lpszWindowName,
            WS_OVERLAPPEDWINDOW,
            CW_USEDEFAULT, CW_USEDEFAULT, 640, 480,
            0, 0, hInstance, 0)
     
        ShowWindow(hWnd, SW_SHOWDEFAULT)
        UpdateWindow(hWnd)
     
        var msg MSG
        for {
            if GetMessage(&msg, 0, 0, 0) == 0 {
                break
            }
            TranslateMessage(&msg)
            DispatchMessage(&msg)
        }
        return int(msg.wParam)
    }
     
    func main() {
        WinMain()
        return
    }

    コンパイル方法

    C:¥> SET GOROOT=C:go
    C:¥> go build -ldflags -Hwindowsgui hello.go

    実行結果

    +------------------------------------------+
    |Hello, World!                    [_][~][X]|
    +------------------------------------------+
    |Hello, Win32 GUI(Go) World!               |
    |                                          |
    |                                          |
    |                                          |
    |                                          |
    |                                          |
    |                                          |
    |                                          |
    |                                          |
    |                                          |
    +------------------------------------------+