Golang中调用DLL示例—Win32 API

不断的会有人问:在go中可以调用dll么?如何做?

这里提供一个示例(获取当前Windows版本):

  1. package main
  2. import (
  3. "syscall"
  4. )
  5. func abort(funcname string, err error) {
  6. panic(funcname + " failed: " + err.Error())
  7. }
  8. func print_version(v uint32) {
  9. major := byte(v)
  10. minor := uint8(v >> 8)
  11. build := uint16(v >> 16)
  12. print("windows version ", major, ".", minor, " (Build ", build, ")\n")
  13. }
  14. func main() {
  15. h, err := syscall.LoadLibrary("kernel32.dll")
  16. if err != nil {
  17. abort("LoadLibrary", err)
  18. }
  19. defer syscall.FreeLibrary(h)
  20. proc, err := syscall.GetProcAddress(h, "GetVersion")
  21. if err != nil {
  22. abort("GetProcAddress", err)
  23. }
  24. r, _, _ := syscall.Syscall(uintptr(proc), 0, 0, 0, 0)
  25. print_version(uint32(r))
  26. }

另外,转载一篇文章《Golang下通过syscall调用win32的api》,原文内容如下:

源于golang群中再次提到windows下获取磁盘空间的方法

由于golang的api并非完全跨平台, golang本身并没有直接提供windows下的方式

syscall.Syscall系列方法

当前共5个方法

  1. syscall.Syscall
  2. syscall.Syscall6
  3. syscall.Syscall9
  4. syscall.Syscall12
  5. syscall.Syscall15

分别对应 3个/6个/9个/12个/15个参数或以下的调用

参数都形如

  1. syscall.Syscall(trap, nargs, a1, a2, a3)

第二个参数, nargs 即参数的个数,一旦传错, 轻则调用失败,重者直接APPCARSH

多余的参数, 用0代替

调用示例

获取磁盘空间

  1. //首先,准备输入参数, GetDiskFreeSpaceEx需要4个参数, 可查MSDN
  2. dir := "C:"
  3. lpFreeBytesAvailable := int64(0) //注意类型需要跟API的类型相符
  4. lpTotalNumberOfBytes := int64(0)
  5. lpTotalNumberOfFreeBytes := int64(0)
  6. //获取方法的引用
  7. kernel32, err := syscall.LoadLibrary("Kernel32.dll") // 严格来说需要加上 defer syscall.FreeLibrary(kernel32)
  8. GetDiskFreeSpaceEx, err := syscall.GetProcAddress(syscall.Handle(kernel32), "GetDiskFreeSpaceExW")
  9. //执行之. 因为有4个参数,故取Syscall6才能放得下. 最后2个参数,自然就是0了
  10. r, _, errno := syscall.Syscall6(uintptr(GetDiskFreeSpaceEx), 4,
  11. uintptr(unsafe.Pointer(syscall.StringToUTF16Ptr("C:"))),
  12. uintptr(unsafe.Pointer(&lpFreeBytesAvailable)),
  13. uintptr(unsafe.Pointer(&lpTotalNumberOfBytes)),
  14. uintptr(unsafe.Pointer(&lpTotalNumberOfFreeBytes)), 0, 0)
  15. // 注意, errno并非error接口的, 不可能是nil
  16. // 而且,根据MSDN的说明,返回值为0就fail, 不为0就是成功
  17. if r != 0 {
  18. log.Printf("Free %dmb", lpTotalNumberOfFreeBytes/1024/1024)
  19. }

简单点的方式? 用syscall.Call

跟Syscall系列一样, Call方法最多15个参数. 这里用来Must开头的方法, 如不存在,会panic.

  1. h := syscall.MustLoadDLL("kernel32.dll")
  2. c := h.MustFindProc("GetDiskFreeSpaceExW")
  3. lpFreeBytesAvailable := int64(0)
  4. lpTotalNumberOfBytes := int64(0)
  5. lpTotalNumberOfFreeBytes := int64(0)
  6. r2, _, err := c.Call(uintptr(unsafe.Pointer(syscall.StringToUTF16Ptr("F:"))),
  7. uintptr(unsafe.Pointer(&lpFreeBytesAvailable)),
  8. uintptr(unsafe.Pointer(&lpTotalNumberOfBytes)),
  9. uintptr(unsafe.Pointer(&lpTotalNumberOfFreeBytes)))
  10. if r2 != 0 {
  11. log.Println(r2, err, lpFreeBytesAvailable/1024/1024)
  12. }

小提示

传struct不是个好想法, 不同语言之间的差异不好磨合

ft_authoradmin  ft_create_time2019-07-02 23:24
 ft_update_time2019-07-02 23:25