• golang实现打包dll文件到exe


    最近学习golang,调用了dll文件,打包后没有dll文件,没能单文件部署就想办法实现单文件部署

    微信群里有人建议`go-bindata`实现打包静态资源

    1. golang调用dll的实现

    基础类`Dll`实现dll文件的加载及方法通用的调用

    1. package dll
    2. import (
    3. "errors"
    4. "fmt"
    5. "syscall"
    6. "unsafe"
    7. "github.com/hbh112233abc/seal/internal/pkg"
    8. )
    9. type Dll struct {
    10. DllPath string
    11. dll *syscall.DLL
    12. }
    13. func NewDLL(dllPath string) (*Dll, error) {
    14. if !pkg.IsFile(dllPath) {
    15. panic(fmt.Errorf("dllPath not found: %v", dllPath))
    16. }
    17. d := &Dll{
    18. DllPath: dllPath,
    19. }
    20. d.init()
    21. return d, nil
    22. }
    23. func (d *Dll) init() {
    24. handle, err := syscall.LoadDLL(d.DllPath)
    25. if err != nil {
    26. panic(fmt.Errorf("dll load error: %v", err))
    27. }
    28. d.dll = handle
    29. }
    30. func (d *Dll) Call(procName string, params ...unsafe.Pointer) error {
    31. proc, err := d.dll.FindProc(procName)
    32. if err != nil {
    33. return err
    34. }
    35. data := make([]uintptr, len(params))
    36. for _, p := range params {
    37. data = append(data, uintptr(p))
    38. }
    39. ret, _, err := proc.Call(data...)
    40. if int(ret) != 0 {
    41. return errors.New(DllCallErr.Error(int(ret)))
    42. }
    43. return nil
    44. }

    `edccom.go`实现具体的dll调用方法封装

    1. package dll
    2. /*
    3. #cgo windows CFLAGS: -DX86=1
    4. #cgo !windows LDFLAGS: -lm
    5. #include
    6. #include
    7. */
    8. import "C"
    9. import (
    10. "bytes"
    11. "encoding/json"
    12. "fmt"
    13. "os"
    14. "path/filepath"
    15. "strings"
    16. "unsafe"
    17. "github.com/hbh112233abc/seal/internal/pkg"
    18. )
    19. type SealParser struct {
    20. PageCount int
    21. SealInfo []SealInfo
    22. }
    23. type SealInfo struct {
    24. HandlerName string
    25. IdCard string
    26. SealCount int8
    27. SealName string
    28. SealTime string
    29. Type string
    30. NPage int8 `json:"nPage"`
    31. PosLeft float32 `json:"posLeft"`
    32. PosTop float32 `json:"posTop"`
    33. }
    34. type EDCCom struct {
    35. *Dll
    36. }
    37. func NewEDCCom(dllPath string) (*EDCCom, error) {
    38. if !strings.HasSuffix(dllPath, "EDCCom.dll") {
    39. panic(fmt.Errorf("dllPath must `EDCCom.dll`: %v", dllPath))
    40. }
    41. d, err := NewDLL(dllPath)
    42. if err != nil {
    43. return nil, fmt.Errorf("DLL load failed: %v", err)
    44. }
    45. return &EDCCom{d}, nil
    46. }
    47. func (ec *EDCCom) GetSealInfo(file string) (SealParser, error) {
    48. exist := pkg.IsFile(file)
    49. if !exist {
    50. return SealParser{}, fmt.Errorf("file not found: %s", file)
    51. }
    52. ext := filepath.Ext(file)
    53. ext = strings.ToLower(ext)
    54. var procName string
    55. switch ext {
    56. case ".edc":
    57. procName = "Com_GetEdcSealInfo"
    58. case ".pdf":
    59. procName = "Com_GetPdfSealInfo"
    60. default:
    61. return SealParser{}, fmt.Errorf("unsupported ext: %s", ext)
    62. }
    63. return ec.sealInfo(procName, file)
    64. }
    65. //获取印章信息
    66. func (ec *EDCCom) sealInfo(procName string, file string) (SealParser, error) {
    67. proc, err := ec.dll.FindProc(procName)
    68. if err != nil {
    69. fmt.Printf("proc %s not found,err:%v \n", procName, err)
    70. return SealParser{}, err
    71. }
    72. var sealParser SealParser
    73. //转换成GBK编码
    74. gbkDecode, _ := pkg.Utf8ToGbk([]byte(file))
    75. file = string(gbkDecode)
    76. input := C.CString(file)
    77. defer C.free(unsafe.Pointer(input))
    78. var result C.char
    79. var size int
    80. ret, _, err := proc.Call(
    81. uintptr(unsafe.Pointer(input)),
    82. uintptr(unsafe.Pointer(&result)),
    83. uintptr(unsafe.Pointer(&size)),
    84. )
    85. if ret != 0 {
    86. fmt.Println("Com_GetEdcSealInfo failed: ", DllCallErr.Error(int(ret)), err)
    87. return sealParser, err
    88. }
    89. resultString := C.GoStringN(&result, C.int(4096))
    90. // fmt.Println(resultString)
    91. resultDecode, err := pkg.GbkToUtf8([]byte(resultString))
    92. if err != nil {
    93. fmt.Println("GBK to utf8 failed: ", err)
    94. return sealParser, err
    95. }
    96. // fmt.Println(string(resultDecode))
    97. index := bytes.IndexByte(resultDecode, 0)
    98. resultDecodeTrim := resultDecode[:index]
    99. err = json.Unmarshal(resultDecodeTrim, &sealParser)
    100. if err != nil {
    101. fmt.Println("json.Unmarshal failed: ", err)
    102. return sealParser, err
    103. }
    104. return sealParser, nil
    105. }

    最终调用方法

    1. func GetSealInfo() error {
    2. pwd := pkg.CurrentAbPath()
    3. dllPath := filepath.Join(pwd, "EDCCom.dll")
    4. fmt.Println("dll:", dllPath)
    5. dll, err := dll.NewEDCCom(dllPath)
    6. if err != nil {
    7. return err
    8. }
    9. edcFile := filepath.Join(pwd, "tests", "files", "signed.edc")
    10. res, err := dll.GetSealInfo(edcFile)
    11. if err != nil {
    12. return err
    13. }
    14. fmt.Printf("%s seal info: \n %#v \n", edcFile, res)
    15. return nil
    16. }

    有关dll调用可以参考: Go调用dll及大部分问题的解决方案,附源码 - 灯火消逝的码头 - 博客园

    2. 打包dll到exe的实现

    我调用的dll如下:

     安装`go-bindata`

    go install -a -v github.com/go-bindata/go-bindata/...@latest

    在`main.go`添加

    //go:generate go-bindata -fs -o=EDCCom.go -prefix=./ -nocompress -nomemcopy ./docs/dll

    命令行执行

    go generate

    此时main.go目录下将生成`EDCCom.go`

    main.go中增加`init`方法,释放dll文件

    1. func init() {
    2. pwd := pkg.CurrentAbPath()
    3. dllFiles, err := AssetDir("docs/dll")
    4. if err != nil {
    5. log.Fatal(err)
    6. return
    7. }
    8. for _, dllFile := range dllFiles {
    9. // fmt.Println(dllFile)
    10. localDll := filepath.Join(pwd, dllFile)
    11. if !pkg.IsFile(localDll) {
    12. bytes, err := Asset(fmt.Sprintf("docs/dll/%s", dllFile))
    13. if err != nil {
    14. log.Fatal(err)
    15. return
    16. }
    17. ioutil.WriteFile(localDll, bytes, 0644)
    18. }
    19. }
    20. }

    此时运行`go run .`就会先检查目录下有没有dll文件,如果没有则先生成dll文件

    打包后的exe文件也变大了,单文件部署就没问题了.

    参考 使用go-bindata将文件编译进二进制 | 二丫讲梵 

  • 相关阅读:
    Python图像处理丨图像的灰度线性变换
    如何使用 Xshell 连接 Linux 服务器
    几个时间戳相关函数
    Kotlin 开发Android app(十五):使用Broadcast收发广播
    python中的预编译正则表达式
    Spring IOC复习与回顾
    IPv4报文头部
    到此一游︱2022 Google 开发者大会
    隐藏label标签中指定文字
    TypeError: res.data.map is not a function微信小程序报错
  • 原文地址:https://blog.csdn.net/hbh112233abc/article/details/126937604