Go win32

上次说到,我们的GO可以执行系统调用,嘿嘿

不假,但如果你认为你已经掌握了,哈哈,那么不然

网上的例子,总是不深入,不彻底,除非是官网上的demo,也就是说只有设计者才知道告诉你什么才是它设计的正真意义

好了,就让windows上的本地dll调用,来说明问题吧

//构造win32本地库

//test.h

#ifndef _TEST_
# define _TEST_

# ifdef TEST
# define Export _declspec(dllexport)
# else
# define Export _declspec(dllimport)

#endif

Export double add(double da ,double db);
Export double subtract(double da , double db);
Export int add_ex(int a, int b, int* result);
Export int add_ex_ex(double a, double b, double* result);
Export int add_ex_ex_ex(double* a, double* b, double* result);

#endif

//test.c

#define TEST
#include "test.h"

Export double add(double da ,double db)
{
return da+db;
}
Export double subtract(double da , double db)
{
return da-db;
}

Export int add_ex(int a, int b, int* result)
{
*result = a+b;
return 1;
}

Export int add_ex_ex(double a, double b, double* result)
{
printf("input param1:=%lf ", a);
printf("input param2:=%lf ", b);
*result = a+b;
printf("result:=%lf ", *result);
return 1;
}

Export int add_ex_ex_ex(double* a, double* b, double* result)
{
printf("input param1:=%lf ", *a);
printf("input param2:=%lf ", *b);
*result = *a+*b;
printf("result:=%lf ", *result);
return 1;
}

//生成库

cl -c test.c

link -dll test.obj

我们会得到test.dll的win32动态链接库

//go 通过syscall来调用test.dll本地库

//win32.go

package main

import (
"fmt"
"syscall"
"unsafe"
)

func main() {

const f = "%T(%v) "
test, err := syscall.LoadLibrary("test.dll")
if (err!=nil) {
fmt.Println("test.dll not found")
return
}
defer syscall.FreeLibrary(test)
add, err := syscall.GetProcAddress(syscall.Handle(test), "add")
if (err!=nil) {
fmt.Println("add not found")
return
}
add_ex, err := syscall.GetProcAddress(syscall.Handle(test), "add_ex")
if (err!=nil) {
fmt.Println("add_ex not found")
return
}
add_ex_ex, err := syscall.GetProcAddress(syscall.Handle(test), "add_ex_ex")
if (err!=nil) {
fmt.Println("add_ex_ex not found")
return
}
add_ex_ex_ex, err := syscall.GetProcAddress(syscall.Handle(test), "add_ex_ex_ex")
if (err!=nil) {
fmt.Println("add_ex_ex not found")
return
}
fmt.Printf(f, add, add)
fmt.Printf(f, add_ex, add_ex)
var a1 float64 = float64(1.0276)
var a2 float64 = float64(2.7865)
fmt.Printf(f, a1, a1)
fmt.Printf(f, a2, a2)
fmt.Println("a1+a2", a1+a2)

r, _, retstr := syscall.Syscall(uintptr(add), 2,
uintptr(a1),
uintptr(a2),
0)
fmt.Println("add ", retstr)
fmt.Printf(f, r, r)
add_value := int32(0)
r, _, retstr = syscall.Syscall(uintptr(add_ex), 3,
uintptr(1),
uintptr(2),
uintptr(unsafe.Pointer(&add_value)))
fmt.Println("add_ex", retstr)
fmt.Printf(f, r, r)
fmt.Printf(f, add_value,add_value)
add_value_ex := float64(0)
r, _, retstr = syscall.Syscall(uintptr(add_ex_ex), 3,
uintptr(a1),
uintptr(a2),
uintptr(unsafe.Pointer(&add_value_ex)))
fmt.Printf(f, uintptr(a1), uintptr(a1))
fmt.Println("add_ex_ex", retstr)
fmt.Printf(f, r, r)
fmt.Printf(f, add_value_ex, add_value_ex)

r, _, retstr = syscall.Syscall(uintptr(add_ex_ex_ex), 3,
uintptr(unsafe.Pointer(&a1)),
uintptr(unsafe.Pointer(&a2)),
uintptr(unsafe.Pointer(&add_value_ex)))
fmt.Println("add_ex_ex_ex", retstr)
fmt.Printf(f, r, r)
fmt.Printf(f, add_value_ex, add_value_ex)
}

//运行

go build win32.go

win32.exe

//结果

uintptr(140729033560064)
uintptr(140729033560128)
float64(1.0276)
float64(2.7865)
a1+a2 3.8141000000000003
add The operation completed successfully.
uintptr(140729033560064)
add_ex The operation completed successfully.
uintptr(1)
int32(3)
input param1:=0.000000
input param2:=0.000000
result:=0.000000
uintptr(1)
add_ex_ex The operation completed successfully.
uintptr(1)
float64(1.5e-323)
input param1:=1.027600
input param2:=2.786500
result:=3.814100
add_ex_ex_ex The operation completed successfully.
uintptr(1)
float64(3.8141000000000003)

Finally:

我在这里告诉你事实如下,这个很重要。。。。。。

GO与win32本地交互时,只能给win32接口函数传递uiintptr类型参数

uintptr在GO里被当作指针来看待,它本身是整形(32/64位),但要命的是网上的例子会拿这个来做数值参数举例子调用系统函数,读者会误以为这是数值参数的模板(int, float, double)

其实不然,我给你更正:

1. 接口只能返回uintptr类型(一般用0表示失败,1表示成功)

2. 无论GO什么类型,往win32本地库接口里传递时都得传递指针进去(网上会有GO取字符串的指针的例子,很实用)

3. 自己设计的本地库接口得操作相应的指针类型(char*,wchar_t*, int*, float*,double*)

好了,听我的,你就又活了

最后,我认为,如果你已经懂了,那么,你的路(Windows+GO)将会一番风顺

哈哈哈,祝你成功!

原文地址:https://www.cnblogs.com/woodzcl/p/7562629.html