运行编译后的Golang DLL文件的方法与技巧

运行编译后的Golang DLL文件的方法与技巧 大家好,

我是Go语言的新手。

我正在寻找如何从Go创建DLL文件,并使用了以下命令:

go build -o client.dll -buildmode c-shared

我的文件有一个主函数,里面没有任何代码,还有另一个名为“TestMain”的函数,其中包含了脚本所需的所有代码。现在我该如何运行这个DLL?我尝试使用:rundll32 client.dll,TestMain,但遇到了错误“Missing Entry: TestMain”。因此,我需要了解如何编译和运行它。

4 回复

我需要输出一个DLL文件,用于其他测试目的。

更多关于运行编译后的Golang DLL文件的方法与技巧的实战系列教程也可以访问 https://www.itying.com/category-94-b0.html


为什么你要把它编译成DLL?为什么不直接使用 go build . 然后执行 .\program.exe 呢?

func main() {
    fmt.Println("hello world")
}

已解决 问题似乎是因为我在主函数中没有编写任何代码,所以我添加了一个简单的打印语句,然后使用以下命令进行编译:

go build  -ldflags “-s -w”  -buildmode=c-shared -o file.dll ./file.go

然后使用 rundll32 file.dll,TestMain 运行。

要正确运行Go编译的DLL,你需要理解Go的C共享库构建模式与标准Windows DLL的差异。以下是关键步骤和示例:

1. 修正Go代码结构

Go的c-shared模式要求导出函数必须使用//export注释,且包名必须是main。你的TestMain函数需要按以下方式声明:

package main

import "C"

//export TestMain
func TestMain() {
    // 你的实际代码
    println("Hello from Go DLL")
}

func main() {
    // 空main函数是必需的,但不会在DLL中被调用
}

2. 编译DLL

使用你原来的命令:

go build -o client.dll -buildmode c-shared

这会生成两个文件:client.dllclient.h(包含C头文件)。

3. 创建C/C++加载器

由于Go的DLL使用C调用约定,你需要一个C或C++程序来加载它:

test_dll.c:

#include <windows.h>
#include <stdio.h>

// 声明函数原型
void TestMain();

int main() {
    HINSTANCE hDll = LoadLibrary("client.dll");
    if (!hDll) {
        printf("无法加载DLL\n");
        return 1;
    }
    
    // 获取函数地址
    void (*pTestMain)() = (void(*)())GetProcAddress(hDll, "TestMain");
    if (!pTestMain) {
        printf("找不到TestMain函数\n");
        FreeLibrary(hDll);
        return 1;
    }
    
    // 调用Go函数
    pTestMain();
    
    FreeLibrary(hDll);
    return 0;
}

4. 编译并运行

使用MinGW或Visual Studio编译C加载器:

gcc -o test_dll.exe test_dll.c
test_dll.exe

5. 直接使用rundll32的注意事项

rundll32要求特定的函数签名:

//export TestMain
func TestMain(hwnd uintptr, hinst uintptr, lpszCmdLine uintptr, nCmdShow int) {
    // 你的代码
}

但即使这样,由于Go运行时的初始化需求,直接使用rundll32仍可能遇到问题。

完整示例

dll_example.go:

package main

import "C"
import "fmt"

//export Add
func Add(a, b int) int {
    return a + b
}

//export PrintMessage
func PrintMessage(msg *C.char) {
    fmt.Println("Message:", C.GoString(msg))
}

func main() {}

编译后,在C中调用:

int result = Add(5, 3);
PrintMessage("Hello from C");

这种方法确保了Go运行时正确初始化,并允许从外部代码调用导出的函数。

回到顶部