• Golang下通过syscall调用win32的dll(calling Windows DLLs from Go )


    很多同学比如我虽然很喜欢golang,但是还是需要调用很多遗留项目或者其他优秀的开源项目,这时怎么办呢?我们想到的方法是用package里的syscall结合cgo

    注意此处有坑:

    在我调试时显示not enough arguments in call to syscall.Syscall

    [ `go run dms.go` | done: 260.3744ms ]
    # command-line-arguments
    .dms.go:72: not enough arguments in call to syscall.Syscall

    exit status 2

    因为我参照的是http://golang.org/pkg/syscall/#Syscall ,而其默认的是Linux/Unix的syscall API doc说明,

    如何看windows的golang doc呢?

    通过godoc command, 调用 godoc -http=:6060
    然后在浏览器打开
    http://localhost:6060/pkg/syscall/#Syscall,这才是windows的golang pakage api

    func Syscall

    func Syscall(trap, nargs, a1, a2, a3 uintptr) (r1, r2 uintptr, err Errno)

    Implemented in ../runtime/syscall_windows.goc.

    func Syscall12

    func Syscall12(trap, nargs, a1, a2, a3, a4, a5, a6, a7, a8, a9, a10, a11, a12 uintptr) (r1, r2 uintptr, err Errno)

    func Syscall15

    func Syscall15(trap, nargs, a1, a2, a3, a4, a5, a6, a7, a8, a9, a10, a11, a12, a13, a14, a15 uintptr) (r1, r2 uintptr, err Errno)

    func Syscall6

    func Syscall6(trap, nargs, a1, a2, a3, a4, a5, a6 uintptr) (r1, r2 uintptr, err Errno)

    func Syscall9

    func Syscall9(trap, nargs, a1, a2, a3, a4, a5, a6, a7, a8, a9 uintptr) (r1, r2 uintptr, err Errno)

    例子1:

    func test(){
    //首先,准备输入参数, GetDiskFreeSpaceEx需要4个参数, 可查MSDN
    lpFreeBytesAvailable := int64(0) //注意类型需要跟API的类型相符
    lpTotalNumberOfBytes := int64(0)
    lpTotalNumberOfFreeBytes := int64(0)
    
    
    //获取方法的引用
    kernel32, _ := syscall.LoadLibrary("Kernel32.dll") // 严格来说需要加上 defer syscall.FreeLibrary(kernel32)
    GetDiskFreeSpaceEx, _ := syscall.GetProcAddress(syscall.Handle(kernel32), "GetDiskFreeSpaceExW")
    
    
    //执行之. 因为有4个参数,故取Syscall6才能放得下. 最后2个参数,自然就是0了
    r, _, _ := 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)
    }
    }
    

     

    例子2,弹出一个简单的对话框messagebox, http://code.google.com/p/go-wiki/wiki/WindowsDLLs

    package main
    
    import(
            "fmt"
            "syscall"
            "unsafe")
    
    func abort(funcname string, err error){
            panic(fmt.Sprintf("%s failed: %v", funcname, err))}var(
            kernel32, _        = syscall.LoadLibrary("kernel32.dll")
            getModuleHandle, _ = syscall.GetProcAddress(kernel32,"GetModuleHandleW")
    
            user32, _     = syscall.LoadLibrary("user32.dll")
            messageBox, _ = syscall.GetProcAddress(user32,"MessageBoxW"))const(
            MB_OK                =0x00000000
            MB_OKCANCEL          =0x00000001
            MB_ABORTRETRYIGNORE  =0x00000002
            MB_YESNOCANCEL       =0x00000003
            MB_YESNO             =0x00000004
            MB_RETRYCANCEL       =0x00000005
            MB_CANCELTRYCONTINUE =0x00000006
            MB_ICONHAND          =0x00000010
            MB_ICONQUESTION      =0x00000020
            MB_ICONEXCLAMATION   =0x00000030
            MB_ICONASTERISK      =0x00000040
            MB_USERICON          =0x00000080
            MB_ICONWARNING       = MB_ICONEXCLAMATION
            MB_ICONERROR         = MB_ICONHAND
            MB_ICONINFORMATION   = MB_ICONASTERISK
            MB_ICONSTOP          = MB_ICONHAND
    
            MB_DEFBUTTON1 =0x00000000
            MB_DEFBUTTON2 =0x00000100
            MB_DEFBUTTON3 =0x00000200
            MB_DEFBUTTON4 =0x00000300)
    
    func MessageBox(caption, text string, style uintptr)(result int){
            var nargs uintptr =4
            ret, _, callErr := syscall.Syscall9(uintptr(messageBox),
                    nargs,
                    0,
                    uintptr(unsafe.Pointer(syscall.StringToUTF16Ptr(text))),
                    uintptr(unsafe.Pointer(syscall.StringToUTF16Ptr(caption))),
                    style,
                    0,
                    0,
                    0,
                    0,
                    0)
            if callErr !=0{
                    abort("Call MessageBox", callErr)
            }
            result =int(ret)
            return}
    
    func GetModuleHandle()(handle uintptr){
            var nargs uintptr =0
            if ret, _, callErr := syscall.Syscall(uintptr(getModuleHandle), nargs,0,0,0); callErr !=0{
                    abort("Call GetModuleHandle", callErr)
            }else{
                    handle = ret
            }
            return}
    
    func main(){
            defer syscall.FreeLibrary(kernel32)
            defer syscall.FreeLibrary(user32)
    
            fmt.Printf("Return: %d
    ",MessageBox("Done Title","This test is Done.", MB_YESNOCANCEL))}
    
    func init(){
            fmt.Print("Starting Up
    ")}
    http://golang.org/pkg/syscall/#Syscall 里默认的是Linux/Unix的syscall API doc说明,
  • 相关阅读:
    搬家来博客园了
    公司初印象
    毕业之殇觉醒
    毕业之殇天意弄人
    毕业之殇预告篇
    scribe 安装文档
    毕业之殇寻找
    IOS 资料整理(转)
    IOS IPHONE相册应用 资料整理
    NSFileManager和NSFileHandle(附:获取文件大小 )
  • 原文地址:https://www.cnblogs.com/keanuyaoo/p/3357816.html
Copyright © 2020-2023  润新知