概述

以下举例程序的效果是会弹出消息框。

lqi765ks.png

四种方式

方式 1-立即加载


func LoadDll() {
    user32Dll, err := syscall.LoadLibrary("user32.dll")
    if err != nil {
        panic(err)
    }
    // 获取dll里的函数
    proc, err := syscall.GetProcAddress(user32Dll, "MessageBoxW")
    if err != nil {
        panic(err)
    }
    // 宽字节
    fromString, err := syscall.UTF16PtrFromString("你好世界")
    if err != nil {
        panic(err)
    }

    // https://learn.microsoft.com/zh-cn/windows/win32/api/winuser/nf-winuser-messageboxw
    //  参数和返回值,见上面地址
    r1, _, _ := syscall.SyscallN(proc,
        0,
        uintptr(unsafe.Pointer(fromString)), // 因为syscalN适配所有类型的调用,所以统一转这个类型
        uintptr(unsafe.Pointer(fromString)),
        0,
    )
    if int(r1) == 1 {
        fmt.Println("用户点击了确定")
    }
}

方式 2-懒加载


func LoadDll2() {
    u32Dll := syscall.NewLazyDLL("user32.dll")
    proc := u32Dll.NewProc("MessageBoxW")
    // 宽字节
    fromString, err := syscall.UTF16PtrFromString("你好世界")
    if err != nil {
        panic(err)
    }
    r1, _, _ := proc.Call(
        0,
        uintptr(unsafe.Pointer(fromString)), // 因为syscalN适配所有类型的调用,所以统一转这个类型
        uintptr(unsafe.Pointer(fromString)),
        0,
    )
    if int(r1) == 1 {
        fmt.Println("用户点击了确定")
    }
    r0, _, _ := syscall.SyscallN(proc.Addr(),
        0,
        uintptr(unsafe.Pointer(fromString)), // 因为syscalN适配所有类型的调用,所以统一转这个类型
        uintptr(unsafe.Pointer(fromString)),
        0,
    )
    if int(r0) == 1 {
        fmt.Println("用户点击了确定")
    }
}

方式 3-对第 1 种的封装


func LoadDll3() {
    u32dll, err := syscall.LoadDLL("user32.dll")
    if err != nil {
        panic(err)
    }
    proc, err := u32dll.FindProc("MessageBoxW")

    // 宽字节
    fromString, err := syscall.UTF16PtrFromString("你好世界")
    if err != nil {
        panic(err)
    }
    r1, _, _ := proc.Call(
        0,
        uintptr(unsafe.Pointer(fromString)), // 因为syscalN适配所有类型的调用,所以统一转这个类型
        uintptr(unsafe.Pointer(fromString)),
        0,
    )
    if int(r1) == 1 {
        fmt.Println("用户点击了确定")
    }
    r0, _, _ := syscall.SyscallN(proc.Addr(),
        0,
        uintptr(unsafe.Pointer(fromString)), // 因为syscalN适配所有类型的调用,所以统一转这个类型
        uintptr(unsafe.Pointer(fromString)),
        0,
    )
    if int(r0) == 1 {
        fmt.Println("用户点击了确定")
    }
}

方式 4-使用 windows 包

需要安装 go get golang.org/x/sys/windows,实际上是对 NewLazyDLL 的封装,用起来很方便


func LoadDll4() {
    u32Dll := windows.NewLazySystemDLL("user32.dll")
    proc := u32Dll.NewProc("MessageBoxW")

    // 宽字节
    fromString, err := syscall.UTF16PtrFromString("你好世界")
    if err != nil {
        panic(err)
    }
    r1, _, _ := proc.Call(
        0,
        uintptr(unsafe.Pointer(fromString)), // 因为syscalN适配所有类型的调用,所以统一转这个类型
        uintptr(unsafe.Pointer(fromString)),
        0,
    )
    if int(r1) == 1 {
        fmt.Println("用户点击了确定")
    }
    r0, _, _ := syscall.SyscallN(proc.Addr(),
        0,
        uintptr(unsafe.Pointer(fromString)), // 因为syscalN适配所有类型的调用,所以统一转这个类型
        uintptr(unsafe.Pointer(fromString)),
        0,
    )
    if int(r0) == 1 {
        fmt.Println("用户点击了确定")
    }
}
最后修改:2023 年 12 月 23 日
如果觉得我的文章对你有用,请随意赞赏