golang dll で int の参照、どうやってコールするんか悩んだ
— mik o (@oki_mik) September 26, 2016
var usb_no int = 0
ret, _, _ := find_usb.Call(uintptr(unsafe.Pointer(&usb_no)))
golang で簡単に DLL を呼び出す方法は syscall.NewLazyDLL を使う事です。
package main
var (
    times = 0
    dll   = syscall.NewLazyDLL("mydll.dll")
    proc  = dll.NewProc("MyFunc")
)
func main() {
    i := int32(123)
    proc.Call(uintptr(unsafe.Pointer(&i)))
}
ですが Call の引数は全て uintptr なので間違いが起きやすくなります。
※余談ですが cgo だと Go のポインタをC側に渡す事は出来ない(panicする)のですが、DLL の場合は許されています。
そこで golang には mksyscall_windows.go というツールが付属していいます。例えば Windows の API、FormatMessage を呼び出したいとします。
FormatMessage function (Windows)
https://msdn.microsoft.com/en-us/library/windows/desktop/ms679351(v=vs.85).aspx
MSDN のサイトを見ながら golang の型に合うよう、以下の様に記述します。この例ではファイル名は syscall_windows.go であるとします。
package main
//go:generate go run $GOROOT/src/syscall/mksyscall_windows.go -output zsyscall_windows.go syscall_windows.go
//sys   FormatMessage(flags uint32, source syscall.Handle, messageID uint32, languageID uint32, buffer *byte, bufferSize uint32, arguments uintptr) (numChars uint32, err error) = kernel32.FormatMessageW
そしてコンソールから go generate を実行すれば以下の zsyscall_windows.go というファイルが生成されます。
// MACHINE GENERATED BY 'go generate' COMMAND; DO NOT EDIT
package main
import (
    "syscall"
    "unsafe"
    "golang.org/x/sys/windows"
)
var _ unsafe.Pointer
// Do the interface allocations only once for common
// Errno values.
var (
    errERROR_IO_PENDING error = syscall.Errno(ERROR_IO_PENDING)
)
// errnoErr returns common boxed Errno values, to prevent
// allocations at runtime.
func errnoErr(e syscall.Errno) error {
    switch e {
    case 0:
        return nil
    case ERROR_IO_PENDING:
        return errERROR_IO_PENDING
    }
    // TODO: add more here, after collecting data on the common
    // error values see on Windows. (perhaps when running
    // all.bat?)
    return e
}
var (
    modkernel32 = windows.NewLazySystemDLL("kernel32.dll")
    procFormatMessageW = modkernel32.NewProc("FormatMessageW")
)
func FormatMessage(flags uint32, source syscall.Handle, messageID uint32, languageID uint32, buffer *byte, bufferSize uint32, arguments uintptr) (numChars uint32, err error) {
    r0, _, e1 := syscall.Syscall9(procFormatMessageW.Addr(), 7, uintptr(flags), uintptr(source), uintptr(messageID), uintptr(languageID), uintptr(unsafe.Pointer(buffer)), uintptr(bufferSize), uintptr(arguments), 0, 0)
    numChars = uint32(r0)
    if numChars == 0 {
        if e1 != 0 {
            err = errnoErr(e1)
        } else {
            err = syscall.EINVAL
        }
    }
    return
}
エディタや IDE からも補完できるので渡す引数の型が分かりやすくなります。
あとはプログラムから FormatMessage を呼び出すだけになりますが、Windows の API はプログラムを落とす事もできる危険な物もあります。internal パッケージを使って外部のパッケージからは見えない様にしておきましょう。

 
 
 
 
 
 

 
 
  
 
