当前位置: 首页>开发笔记>正文

Go标准库syscall调用dll

Go标准库syscall调用dll

什么是系统调用

  了解syscall包之前先了解下什么是系统调用。系统调用是程序向操作系统内核请求服务的过程,通常包含硬件相关的服务(例如访问硬盘),创建新进程等。系统调用提供了一个进程和操作系统之间的接口。

fmt中的syscall

  最常见的关于syscall的使用是在fmt.Println中,具体代码的大家可以一步步往下看怎么调用的,这里使用了系统的syscall.Stdout

func Println(a ...interface{}) (n int, err error) {return Fprintln(os.Stdout, a...)
}Stdout = NewFile(uintptr(syscall.Stdout), "/dev/stdout")

Go调用dll库

  dll是windows动态库,go去调用动态库使用的是syscall标准库,一般dll库会提供两个固定函数,申请内存和释放内存,先申请完内存再执行业务逻辑的函数,执行完后释放内存。

dll, err := syscall.LoadDLL("scan.dll")
//根据名称从dll中查找proc
MemoryStream_Get = dll.FindProc("AllocateMemory")
MemoryStream_Get.Call()

  主要就是三步:LoadDLL加载dll文件名,然后用FindProc判断查找调用的dll库函数名,然后Call进行调用。整体的调用方式还是比较简单。

  LoadDLL会返回一个结构体DLL,注意Handle是一个uinptr类型(uintptr 是 Go 内置类型,表示无符号整数,可存储一个完整的地址,常用于指针运算),也就是会返回方法的地址值,后面的传参和解析通过结合只 unsafe.Pointer 类型转换成 uintptr 类型,做完加减法后,转换成 unsafe.Pointer,通过 * 操作,取值或者修改值都可以。

type DLL struct {Name   stringHandle Handle
}

调用dll如何传参

  Proc的Call()方法是可接收多个uintptr的所以在传参的试试需要将参数转为uintptr

func (p *Proc) Call(a ...uintptr) (r1, r2 uintptr, lastErr error) {

  传递整型参数,将整型转为uintptr

func IntToPtr(n int) uintptr {return uintptr(n)
}

  传递字符串参数,将字符串转为uintptr,但是这里使用到了unsafe.Pointer,它是可以指向任意类型的指针,而syscall.StringBytePtr是将string转为 *btye指针。进而一步步转为uintptr

func StringToUintPtr(val string) uintptr {return uintptr(unsafe.Pointer(syscall.StringBytePtr(val)))
}

接收dll库中返回值

  读取调用库的返回值其实真正涉及到指针偏移的计算。因为uintptr指向的实际的整型地址值(申请内存方法会返回),我们可以根据返回的比如字符串在内存中长度来进行计算,比如长度是length(业务函数:GetDeviceInfo会返回),mem是实际调用dll库后返回的uintptr。因为调用dll库一般是返回char,所以这里转为byte即可。

type MemoryStream struct {handle    uintptr //空间地址值lenHandle uintptr //数据长度
}
//获取设备信息 m.handle是申请内存的地址
func (m *MemoryStream) GetDeviceInfo() (result string) {pd, _, _ := GetDeviceInfo.Call(m.handle)m.lenHandle = pdresult = string(m.Bytes())return result
}
//返回内存的数据内容byte[]
func (m *MemoryStream) Bytes() []byte {buffer := new(bytes.Buffer)length := m.Size()mem := m.Memory()if length == 0 {return []byte{}}//根据长度,unsafe.Pointer进行指针运算for i := int64(0); i < length; i++ {buffer.WriteByte(*(*byte)(unsafe.Pointer(mem + uintptr(i)))) //byte是uint8, sizeof长度是1}return buffer.Bytes()
}

总结

  syscall库支持对dll库的调用,当然它的功能很强大,可以实现很多我们没有接触过的业务场景。调用的方式比较清晰,但是设计到传参和解析返回值的时候需要用到unsafe.Pointer和uintpre之间的转换、dll库返回的char强制转换为byte,这一块有点逻辑转换。下次专门做个笔记记录下指针、uintptr、unsafe.Pointer之间的使用。

https://www.zydui.com/af413V28CBQZT.html
>

相关文章:

  • go命令行应用
  • c的dll调用com
  • dll lib
  • go调用c库
  • go生成动态链接库
  • java dll调用
  • go第三方库管理
  • dll调用
  • IQVIA醫藥咨詢隨筆雜談
  • 爬取英雄聯盟英雄皮膚數據
  • 英雄聯盟 連接服務器失敗 請檢查您的網絡 是否啟用修復程序進行修復,英雄聯盟玩不了,提示未知的directx錯誤...
  • 三位千萬富翁告訴你:錢是怎么賺來的
  • 芳香之城傳奇的美麗神話故事
  • Solid Converter PDF注冊碼
  • 修改linux下面的字符集
  • 30個不可思議的好玩又實用的HTML5移動應用
  • 安卓新出病毒幽靈推,回顧android歷史上的那些吸費病毒
  • 游戲編程技術貼:AI設計的若干規則闡述
  • mac啟動自動運行程序_什么啟動了,為什么在我的Mac上運行?
  • 什么是UserEventAgent,它為什么在Mac上運行?
  • 蔚來汽車新財報超預期,短期或難盈利互聯網造車行不通嗎?
  • 車行的進貨問題
  • spring BeanFactory 家族介紹
  • 地址家族/名字解析
  • VS中怎么調出資源方案管理器
  • 告別低效工作,幫你重新找回工作的掌控感
  • 從Mac連接Windows共享打印機(1)
  • c4d流體插件_Cinema 4D 流體模擬插件 TurbulenceFD C4D v1.0 Build 1425 Win64
  • 經典生活總結語錄(搞笑欣賞)
  • 項目打包打的是什么包_早安打工人是什么梗,朋友圈打工人文案語錄表情包!...
  • 前端學習從入門到高級全程記錄之25(webapi)
  • 中職計算機應用普測考試試題及答案,2017職稱計算機考試WPS_Office檢測練習及答案9...
  • 微型計算機的主板又稱為,供電設計比7999元的主板還猛,ROG M11A主板首次亮相
  • webStorm使用斷點
  • 逆風翻盤?順豐大股東聯手本來集團上演O2O+B2C生鮮大戲
  • 三國志戰略版:Daniel_“坦克兵種”象兵分析
  • RISK-V品牌的中國化歷程(下)
  • 網游找call通殺方法之另辟蹊徑