背景需求
需要使用golang在windows下调用调用一个exe程序。
刚开始使用exec去启动,但如果用exec启动exe程序时如果遇到一些错误,例如缺少dll,则exec的错误需要自己进行处理后在展示给用户看。
所以直接使用windowsApi调用exe程序。
系统位数导致的dll导出方法名和所想不同
在使用golang调用C函数时可以使用FindProc
我的dll函数名为 foobar(int)
例如
proc, err := dll.FindProc("foobar")
因为有一些用户是32位系统,会提示找不到dll的函数。
把32位和64位的dll扔到depends发现,导出的函数名和自己所定义的不同。
32位:
_foobar@4
64位:
foobar
那么在64位系统下使用是正常的,但换到32位就会出现上边说的找不到foobar这个函数,它被修饰了。
_foobar@4的下划线的意思目前不清楚,后边的@4意思是参数字节
问了GPT:
问:为什么32位的dll为:_foobar@4 ,而64位是foobar
答:这是因为在 Windows 平台上,32位和64位的 DLL 根据不同的调用约定会使用不同的名称修饰规则。32位 DLL 中,如果我们使用了 __stdcall
调用约定,函数名会被修饰以包含 ‘@’ 字符以及函数参数所占字节数。例如,如果你有一个 __stdcall
导出函数 RunGame
,它接收一个指针作为参数,所以在 32 位 DLL 中,它将被修饰为 _RunGame@4
。然而,在 64 位 DLL 中,无论你使用哪种调用约定(__cdecl
、__stdcall
或其他),名字都不会被修饰。所以,在 64 位 DLL 中,你的 RunGame
函数名在导出时会保持不变,即 RunGame
。这就是为什么你会发现同样的函数在 32 位 DLL 中被修饰,而在 64 位 DLL 中却不会被修饰。这主要归因于 Windows 平台对 32位和 64位 DLL 导出函数的处理方式有所不同。
在windows下使用golang调用C语言dll时候需要注意的几点:
- golang build位数要和dll位数相同,即要么都是32位,要么都是64位。
- windows默认是__stdcall,go默认是____cdecl
- win32位下的dll函数名会增加修饰,那么边以后的导出函数名到底是什么,可以把dll扔到Dependency Walker里边查看。