在 windows 系统平台上,dll 动态库没有提供 .lib 文件,又不想动态获取函数地址怎么办?
使用 lib.exe 工具可以根据 .def 定义文件生成 .lib 文件。
例如,我这里有一个 test.dll 动态库文件,我想要生成 lib 链接库文件可以这样操作。
- 打开
Developer Command Prompt for VS 2022
开发工具命令行,用来设置运行变量。 - 使用
dumpbin.exe /EXPORTS test.dll > test.txt
,此时会把输出重定向到test.txt
文件 - 使用 golang 写的工具(完整代码在下面)执行命令
libhelper.exe test.txt
,此时会生成test.def
文件。 - 使用
lib /def:test.def /machine:x64 /out:test.lib
命令,会生成test.lib
链接库文件 。
# 1
dumpbin /exports test.dll > test.def
# 2
修改 test.def 文件
类似这样
LIBRARY
EXPORTS
MyFunction
_cgo_dummy_export
# 3
lib /def:test.def /machine:x64 /out:test.lib
package main
import "C"
import (
"bufio"
"flag"
"fmt"
"log"
"os"
"strings"
)
//export HelloWorld
func HelloWorld() {
println("HelloWorld!")
}
var (
InputFilename string
)
func init(){
flag.StringVar(&InputFilename,"input filename","","eg. input filename exports.txt | output filename exports.def")
}
func main() {
flag.Parse()
if !flag.Parsed() {
println("please input *.txt -h get help.")
os.Exit(0)
}
//
//var filename string = "exports.txt"
var filename string = InputFilename
file, err := os.OpenFile(filename, os.O_RDONLY, os.ModePerm)
if err != nil {
log.Fatalln(err)
}
var (
dllName string
isStart = false
functionName []string
)
scanner := bufio.NewScanner(file)
for scanner.Scan() {
s := scanner.Text()
// 获取 dll 名字
if strings.Contains(s,"Section contains the following exports for") {
fields := strings.Fields(s)
name := fields[len(fields) - 1]
dllName = strings.Split(name,".")[0]
}
if strings.Contains(s, "Summary") {
isStart = false
}
// 获取 dll 导出函数名称
if isStart {
if len(s) > 0 {
s = strings.TrimSpace(s)
fields := strings.Fields(s)
functionName = append(functionName,fields[len(fields) - 1])
}
}
if strings.Contains(s, "ordinal hint RVA") {
isStart = true
}
//fmt.Println(scanner.Text())
}
if err := scanner.Err(); err != nil {
fmt.Fprintln(os.Stderr, "reading standard input:", err)
}
// 输出 def 文件
out,err := os.Create(strings.Split(filename,".")[0] + ".def")
if err != nil {
panic(err)
}
out.WriteString(fmt.Sprintf("LIBRARY %s\n",dllName))
out.WriteString("EXPORTS\n")
for _, s := range functionName {
out.WriteString(fmt.Sprintf(" %s\n",s))
}
}