blob: e3df9ff5b3e68d1b09d7d8f7c35233f74270553d [file] [log] [blame] [view]
Andrew Gerrand5bc444d2014-12-10 11:35:11 +11001# Calling a Windows DLL
2
Gopal Adhikari551aafc2018-04-28 17:42:59 -04003Go allows you to call native Windows function in several different ways.
Andrew Gerrand5bc444d2014-12-10 11:35:11 +11004
Gopal Adhikari551aafc2018-04-28 17:42:59 -040051. Dynamically load a DLL, then call a function in it. You can call the function via `SyscallX` (where X is the number of parameters. If the function has fewer parameters than that, for example passing 7 arguments to a function that accepts 9, `Syscall9` will still work, you just need to specify 7 as your second argument to `Syscall9`).
Andrew Gerrand5bc444d2014-12-10 11:35:11 +11006
Gopal Adhikari551aafc2018-04-28 17:42:59 -04007A sample Go program that calls a Windows DLL function using this method:
Andrew Gerrand5bc444d2014-12-10 11:35:11 +11008
nathanye7bf74d2014-12-10 22:51:09 -08009```go
Andrew Gerrand5bc444d2014-12-10 11:35:11 +110010package main
11
12import (
13 "fmt"
14 "syscall"
15 "unsafe"
16)
17
18func abort(funcname string, err error) {
19 panic(fmt.Sprintf("%s failed: %v", funcname, err))
20}
21
22var (
23 kernel32, _ = syscall.LoadLibrary("kernel32.dll")
24 getModuleHandle, _ = syscall.GetProcAddress(kernel32, "GetModuleHandleW")
25
26 user32, _ = syscall.LoadLibrary("user32.dll")
27 messageBox, _ = syscall.GetProcAddress(user32, "MessageBoxW")
28)
29
30const (
31 MB_OK = 0x00000000
32 MB_OKCANCEL = 0x00000001
33 MB_ABORTRETRYIGNORE = 0x00000002
34 MB_YESNOCANCEL = 0x00000003
35 MB_YESNO = 0x00000004
36 MB_RETRYCANCEL = 0x00000005
37 MB_CANCELTRYCONTINUE = 0x00000006
38 MB_ICONHAND = 0x00000010
39 MB_ICONQUESTION = 0x00000020
40 MB_ICONEXCLAMATION = 0x00000030
41 MB_ICONASTERISK = 0x00000040
42 MB_USERICON = 0x00000080
43 MB_ICONWARNING = MB_ICONEXCLAMATION
44 MB_ICONERROR = MB_ICONHAND
45 MB_ICONINFORMATION = MB_ICONASTERISK
46 MB_ICONSTOP = MB_ICONHAND
47
48 MB_DEFBUTTON1 = 0x00000000
49 MB_DEFBUTTON2 = 0x00000100
50 MB_DEFBUTTON3 = 0x00000200
51 MB_DEFBUTTON4 = 0x00000300
52)
53
54func MessageBox(caption, text string, style uintptr) (result int) {
55 var nargs uintptr = 4
56 ret, _, callErr := syscall.Syscall9(uintptr(messageBox),
57 nargs,
58 0,
59 uintptr(unsafe.Pointer(syscall.StringToUTF16Ptr(text))),
60 uintptr(unsafe.Pointer(syscall.StringToUTF16Ptr(caption))),
61 style,
62 0,
63 0,
64 0,
65 0,
66 0)
67 if callErr != 0 {
68 abort("Call MessageBox", callErr)
69 }
70 result = int(ret)
71 return
72}
73
74func GetModuleHandle() (handle uintptr) {
75 var nargs uintptr = 0
76 if ret, _, callErr := syscall.Syscall(uintptr(getModuleHandle), nargs, 0, 0, 0); callErr != 0 {
77 abort("Call GetModuleHandle", callErr)
78 } else {
79 handle = ret
80 }
81 return
82}
83
84func main() {
85 defer syscall.FreeLibrary(kernel32)
86 defer syscall.FreeLibrary(user32)
87
88 fmt.Printf("Return: %d\n", MessageBox("Done Title", "This test is Done.", MB_YESNOCANCEL))
89}
90
91func init() {
92 fmt.Print("Starting Up\n")
93}
Andrew Gerrand5bc444d2014-12-10 11:35:11 +110094```
95
96
Gopal Adhikari551aafc2018-04-28 17:42:59 -0400972. Using syscall.NewProc instead of syscall.GetProcAddress. These are basically some helper methods over the syscall ones, you saw above, and are available in Windows only: http://golang.org/src/pkg/syscall/dll_windows.go
Andrew Gerrand5bc444d2014-12-10 11:35:11 +110098
nathanye7bf74d2014-12-10 22:51:09 -080099```go
Andrew Gerrand5bc444d2014-12-10 11:35:11 +1100100package main
101
102import (
Dave Day0d6986a2014-12-10 15:02:18 +1100103 "fmt"
104 "syscall"
105 "unsafe"
Andrew Gerrand5bc444d2014-12-10 11:35:11 +1100106)
107
108func main() {
Dave Day0d6986a2014-12-10 15:02:18 +1100109 var mod = syscall.NewLazyDLL("user32.dll")
110 var proc = mod.NewProc("MessageBoxW")
111 var MB_YESNOCANCEL = 0x00000003
Andrew Gerrand5bc444d2014-12-10 11:35:11 +1100112
Dave Day0d6986a2014-12-10 15:02:18 +1100113 ret, _, _ := proc.Call(0,
Dave Day0d6986a2014-12-10 15:02:18 +1100114 uintptr(unsafe.Pointer(syscall.StringToUTF16Ptr("This test is Done."))),
Danyil Bohdan2c4387a2016-08-19 11:23:16 +0300115 uintptr(unsafe.Pointer(syscall.StringToUTF16Ptr("Done Title"))),
Dave Day0d6986a2014-12-10 15:02:18 +1100116 uintptr(MB_YESNOCANCEL))
117 fmt.Printf("Return: %d\n", ret)
118
Andrew Gerrand5bc444d2014-12-10 11:35:11 +1100119}
Andrew Gerrand5bc444d2014-12-10 11:35:11 +1100120```
121
Gopal Adhikari551aafc2018-04-28 17:42:59 -04001223. By "linking" against the library, using the "[[cgo]]" method (this way works in Linux and Windows). Example:
Andrew Gerrand5bc444d2014-12-10 11:35:11 +1100123
nathanye7bf74d2014-12-10 22:51:09 -0800124```go
Andrew Gerrand5bc444d2014-12-10 11:35:11 +1100125import ("C")
126...
127C.MessageBoxW(...)
Andrew Gerrand5bc444d2014-12-10 11:35:11 +1100128```
129
nathanye7bf74d2014-12-10 22:51:09 -0800130See [[cgo]] for further details.