不断的会有人问:在go中可以调用dll么?如何做?
这里提供一个示例(获取当前Windows版本):
01 02 03 04 05 06 07 08 09 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 | package main
import (
"syscall"
)
func abort ( funcname string , err error ) {
panic ( funcname + " failed: " + err.Error ( ) )
}
func print_version ( v uint 32 ) {
major : = byte ( v )
minor : = uint 8 ( v > > 8 )
build : = uint 16 ( v > > 16 )
print ( "windows version " , major , "." , minor , " (Build " , build , ")\n" )
}
func main ( ) {
h , err : = syscall.LoadLibrary ( "kernel32.dll" )
if err ! = nil {
abort ( "LoadLibrary" , err )
}
defer syscall.FreeLibrary ( h )
proc , err : = syscall.GetProcAddress ( h , "GetVersion" )
if err ! = nil {
abort ( "GetProcAddress" , err )
}
r , _ , _ : = syscall.Syscall ( uintptr ( proc ) , 0 , 0 , 0 , 0 )
print_version ( uint 32 ( r ) )
}
|
另外,转载一篇文章《golang下通过syscall调用win32的api》,原文内容如下:
源于golang群中再次提到windows下获取磁盘空间的方法
由于golang的api并非完全跨平台, golang本身并没有直接提供windows下的方式
syscall.Syscall系列方法
当前共5个方法
1 2 3 4 5 | syscall.Syscall
syscall.Syscall 6
syscall.Syscall 9
syscall.Syscall 12
syscall.Syscall 15
|
分别对应 3个/6个/9个/12个/15个参数或以下的调用
参数都形如
1 | syscall.Syscall ( trap , nargs , a 1 , a 2 , a 3 )
|
第二个参数, nargs 即参数的个数,一旦传错, 轻则调用失败,重者直接APPCARSH
多余的参数, 用0代替
调用示例
获取磁盘空间
01 02 03 04 05 06 07 08 09 10 11 12 13 14 15 16 17 18 19 20 21 22 | / / 首先 , 准备输入参数 , GetDiskFreeSpaceEx需要 4 个参数 , 可查MSDN
dir : = "C:"
lpFreeBytesAvailable : = int 64 ( 0 ) / / 注意类型需要跟API的类型相符
lpTotalNumberOfBytes : = int 64 ( 0 )
lpTotalNumberOfFreeBytes : = int 64 ( 0 )
/ / 获取方法的引用
kernel 32 , err : = syscall.LoadLibrary ( "Kernel32.dll" ) / / 严格来说需要加上 defer syscall.FreeLibrary ( kernel 32 )
GetDiskFreeSpaceEx , err : = syscall.GetProcAddress ( syscall.Handle ( kernel 32 ) , "GetDiskFreeSpaceExW" )
/ / 执行之. 因为有 4 个参数 , 故取Syscall 6 才能放得下. 最后 2 个参数 , 自然就是 0 了
r , _ , errno : = syscall.Syscall 6 ( uintptr ( GetDiskFreeSpaceEx ) , 4 ,
uintptr ( unsafe.Pointer ( syscall.StringToUTF 16 Ptr ( "C:" ) ) ) ,
uintptr ( unsafe.Pointer ( & lpFreeBytesAvailable ) ) ,
uintptr ( unsafe.Pointer ( & lpTotalNumberOfBytes ) ) ,
uintptr ( unsafe.Pointer ( & lpTotalNumberOfFreeBytes ) ) , 0 , 0 )
/ / 注意 , errno并非 error 接口的 , 不可能是nil
/ / 而且 , 根据MSDN的说明 , 返回值为 0 就fail , 不为 0 就是成功
if r ! = 0 {
log .Printf ( "Free %dmb" , lpTotalNumberOfFreeBytes / 1024 / 1024 )
}
|
简单点的方式? 用syscall.Call
跟Syscall系列一样, Call方法最多15个参数. 这里用来Must开头的方法, 如不存在,会panic.
01 02 03 04 05 06 07 08 09 10 11 12 | h : = syscall.MustLoadDLL ( "kernel32.dll" )
c : = h.MustFindProc ( "GetDiskFreeSpaceExW" )
lpFreeBytesAvailable : = int 64 ( 0 )
lpTotalNumberOfBytes : = int 64 ( 0 )
lpTotalNumberOfFreeBytes : = int 64 ( 0 )
r 2 , _ , err : = c.Call ( uintptr ( unsafe.Pointer ( syscall.StringToUTF 16 Ptr ( "F:" ) ) ) ,
uintptr ( unsafe.Pointer ( & lpFreeBytesAvailable ) ) ,
uintptr ( unsafe.Pointer ( & lpTotalNumberOfBytes ) ) ,
uintptr ( unsafe.Pointer ( & lpTotalNumberOfFreeBytes ) ) )
if r 2 ! = 0 {
log .Println ( r 2 , err , lpFreeBytesAvailable / 1024 / 1024 )
}
|
小提示
传struct不是个好想法, 不同语言之间的差异不好磨合 |
|
|