blob: 2de7986c7bec05bdb3543a033e2145089dce2516 [file] [log] [blame] [view]
Andrew Gerrand5bc444d2014-12-10 11:35:11 +11001# Calling a Windows DLL
2
3There are a few ways to call "C" code from inside Go
4
Ian Lance Taylor0f16ea92016-06-23 19:37:04 -07005First way: Dynamically load a dll, then call a method on it. You can call the method via "syscallXX" (the XX is number of parameters, but if it has few than that, like if you need seven parameter, then syscall9 will still work, you just tell it the number of arguments is 7).
Andrew Gerrand5bc444d2014-12-10 11:35:11 +11006
7A sample program that calls Windows DLLs from Go:
8
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
97Second way is via syscall.NewProc (etc.) 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
98
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
nathanye7bf74d2014-12-10 22:51:09 -0800122A third way would be to call into libraries basically by "linking" against the library, using the "[[cgo]]" method (this way works in Linux and Windows):
Andrew Gerrand5bc444d2014-12-10 11:35:11 +1100123
124This way would look something like this
125
nathanye7bf74d2014-12-10 22:51:09 -0800126```go
Andrew Gerrand5bc444d2014-12-10 11:35:11 +1100127import ("C")
128...
129C.MessageBoxW(...)
Andrew Gerrand5bc444d2014-12-10 11:35:11 +1100130```
131
nathanye7bf74d2014-12-10 22:51:09 -0800132See [[cgo]] for further details.