您现在的位置是:网站首页> Go语言
Go动态调用dll
- Go语言
- 2021-04-09
- 801人已阅读
VC写一个 DLL
// TestDll.cpp : Defines the entry point for the DLL application.
//
#include "stdafx.h"
BOOL APIENTRY DllMain( HANDLE hModule,
DWORD ul_reason_for_call,
LPVOID lpReserved
)
{
return TRUE;
}
int __stdcall myadd(int a,int b)
{
return a+b;
}
Go中动态调用
package main
import (
"fmt"
"syscall"
)
func main() {
fmt.Println("你好Hello World!")
addfile, err := syscall.LoadLibrary("TestDll.dll") //动态库加载
if err != nil {
fmt.Printf("cgo:err:%v\n", err)
}
myaddcall, _ := syscall.GetProcAddress(addfile, "myadd")
var nargs uintptr = 3
ret, _, callErr := syscall.Syscall(uintptr(myaddcall), nargs, 5, 3, 0)
if callErr != 0 {
fmt.Printf("call myaddcall:%v\n", callErr)
}
fmt.Printf("myadd:%v\n", ret)
}
syscall.Syscall系列方法
syscall.Syscall syscall.Syscall6 syscall.Syscall9 syscall.Syscall12 syscall.Syscall15
分别对应 3个/6个/9个/12个/15个参数或以下的调用
syscall.Syscall(trap, nargs, a1, a2, a3)
第二个参数, nargs 即参数的个数,一旦传错, 轻则调用失败,重者直接APPCARSH
多余的参数, 用0代替
调用示例
获取磁盘空间
//首先,准备输入参数, GetDiskFreeSpaceEx需要4个参数, 可查MSDNdir := "C:"lpFreeBytesAvailable := int64(0)
//注意类型需要跟API的类型相符lpTotalNumberOfBytes := int64(0)lpTotalNumberOfFreeBytes := int64(0)
//获取方法的引用kernel32, err := syscall.LoadLibrary("Kernel32.dll")
// 严格来说需要加上 defer syscall.FreeLibrary(kernel32)
// GetDiskFreeSpaceEx, err := syscall.GetProcAddress(syscall.Handle(kernel32), "GetDiskFreeSpaceExW")
//执行之. 因为有4个参数,故取Syscall6才能放得下. 最后2个参数,自然就是0了r, _, errno := syscall.Syscall6(uintptr(GetDiskFreeSpaceEx), 4,
uintptr(unsafe.Pointer(syscall.StringToUTF16Ptr("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.
h := syscall.MustLoadDLL("kernel32.dll")
c := h.MustFindProc("GetDiskFreeSpaceExW")
lpFreeBytesAvailable := int64(0)
lpTotalNumberOfBytes := int64(0)
lpTotalNumberOfFreeBytes := int64(0)
r2, _, err := c.Call(uintptr(unsafe.Pointer(syscall.StringToUTF16Ptr("F:"))),
uintptr(unsafe.Pointer(&lpFreeBytesAvailable)),
uintptr(unsafe.Pointer(&lpTotalNumberOfBytes)),
uintptr(unsafe.Pointer(&lpTotalNumberOfFreeBytes)))
if r2 != 0 {
log.Println(r2, err, lpFreeBytesAvailable/1024/1024)
调用例子:
var (
// kernel32, _ = syscall.LoadLibrary("kernel32.dll")
// getModuleHandle, _ = syscall.GetProcAddress(kernel32, "GetModuleHandleW")
user32, _ = syscall.LoadLibrary("user32.dll")
messageBox, _ = syscall.GetProcAddress(user32, "MessageBoxW")
)
func IntPtr(n int) uintptr {
return uintptr(n)
}
func StrPtr(s string) uintptr {
return uintptr(unsafe.Pointer(syscall.StringToUTF16Ptr(s)))
}
func MessageBox(caption, text string, style uintptr) (result int) {
ret, _, callErr := syscall.Syscall9(uintptr(messageBox),
4,
0,
StrPtr(text),
StrPtr(caption),
style,
0, 0, 0, 0, 0)
if callErr != 0 {
abort("Call MessageBox", callErr)
}
result = int(ret)
return
}