静态调用不同的dll中相同函数名,如何链接?

jamesking 2009-06-08 11:17:01
我有几个dll文件,a.dll和b.dll都有一个输出函数test。
a.dll的源码
======================================================================================
a.cpp
#include <windows.h>
namespace a
{
int WINAPI test(void)
{
return 0;
}
}
BOOL APIENTRY DllMain( HMODULE hModule,DWORD ul_reason_for_call,LPVOID lpReserved)
{
return TRUE;
}
--------------------------------------------------------------------------------------
a.def
LIBRARY a
EXPORTS
test
======================================================================================

b.dll的源码
======================================================================================
b.cpp
#include <windows.h>
namespace b
{
int WINAPI test(void)
{
return 1;
}
}
BOOL APIENTRY DllMain( HMODULE hModule,DWORD ul_reason_for_call,LPVOID lpReserved)
{
return TRUE;
}
--------------------------------------------------------------------------------------
b.def
LIBRARY b
EXPORTS
test
======================================================================================

我现在想做一个c.dll,也包含test输出函数,在奇数时调用a.dll中的test,偶数时调用b.dll中的test。
于是我将a.lib,b.lib复制到c的目录下。
c.dll的源码如下:
======================================================================================
c.cpp
#include <windows.h>
#pragma comment(lib, "a.lib")
#pragma comment(lib, "b.lib")

namespace a
{
int WINAPI test(void);
}
namespace b
{
int WINAPI test(void);
}
namespace c
{
int WINAPI test(void)
{
static int i;
i++;
if(i%2)
{
return a::test();
}
else
{
return b::test();
}
}
}
BOOL APIENTRY DllMain( HMODULE hModule,DWORD ul_reason_for_call,LPVOID lpReserved)
{
return TRUE;
}
--------------------------------------------------------------------------------------
c.def
LIBRARY c
EXPORTS
test
======================================================================================

c.dll程序可以通过编译,却无法链接。请问高手,这样的程序该如何链接。
我不要LoadLibrary动态加载,动态加载dll我也会。只要静态编译链接,如何实现?
...全文
340 9 打赏 收藏 转发到动态 举报
写回复
用AI写文章
9 条回复
切换为时间正序
请发表友善的回复…
发表回复
jamesking 2009-06-09
  • 打赏
  • 举报
回复
sorry,上面方法二中函数声明少了WINAPI
int WINAPI mytest(void)
jamesking 2009-06-09
  • 打赏
  • 举报
回复
谢谢大家,我已经找到了方法。
方法1:取消def中的test输出,用__declspec(dllexport)
c.dll的源码:
======================================================================================
c.cpp
#include <windows.h>
#pragma comment(lib, "a.lib")
#pragma comment(lib, "b.lib")

extern "C" {
__declspec(dllexport) int test(void);
}

namespace a
{
int WINAPI test(void);
}
namespace b
{
int WINAPI test(void);
}

int test(void)
{
static int i;
i++;
if(i%2)
{
return a::test();
}
else
{
return b::test();
}
}
BOOL APIENTRY DllMain( HMODULE hModule,DWORD ul_reason_for_call,LPVOID lpReserved)
{
return TRUE;
}
--------------------------------------------------------------------------------------
c.def
LIBRARY c
EXPORTS
======================================================================================

方法二:将test改名,然后在def中重命名
c.dll的源码:
======================================================================================
c.cpp
#include <windows.h>
#pragma comment(lib, "a.lib")
#pragma comment(lib, "b.lib")

namespace a
{
int WINAPI test(void);
}
namespace b
{
int WINAPI test(void);
}

int mytest(void)
{
static int i;
i++;
if(i%2)
{
return a::test();
}
else
{
return b::test();
}
}
BOOL APIENTRY DllMain( HMODULE hModule,DWORD ul_reason_for_call,LPVOID lpReserved)
{
return TRUE;
}
--------------------------------------------------------------------------------------
c.def
LIBRARY c
EXPORTS
test = mytest
======================================================================================
wltg2001 2009-06-09
  • 打赏
  • 举报
回复
还是用LoadLorbray吧
jamesking 2009-06-09
  • 打赏
  • 举报
回复
谢谢你们的帮助。

不管是方法一还是方法二,它的原理都是让c.obj中test函数的标示符发生改变,让他与a.lib和b.lib中test函数的标示符不一样。
extern "C" {
__declspec(dllexport) int test(void);
}
生成的标示符是_test
int WINAPI mytest(void)
生成的标示符是?mytest@@YGHXZ

我推测def定义沿用的是c的标准,不知道区分?test@a@@YGHXZ、?test@b@@YGHXZ和?test@c@@YGHXZ,统一识别为test
改了标识符后,链接器就能确切的知道该导出的是哪个函数了。
arong1234 2009-06-09
  • 打赏
  • 举报
回复
是你找到的还是大家告诉你的?方法1是我在1楼提到的,方法2是2楼提到的。做人要实在。
尽管如此,我还是不赞同你使用其中任何一种方法。方法1是对namespace的滥用,我个人更倾向于防止不同的函数提供者直接的命名冲突,你自己不应该故意创造冲突,至于方法2:这违背了c++对重载支持的初衷。
个人还是喜欢使用定义公共接口,然后dll中分别实现的方法

[Quote=引用 5 楼 jamesking 的回复:]
谢谢大家,我已经找到了方法。
方法1:取消def中的test输出,用__declspec(dllexport)
c.dll的源码:
======================================================================================
c.cpp
#include <windows.h>
#pragma comment(lib, "a.lib")
#pragma comment(lib, "b.lib")

extern "C" {
__declspec(dllexport) int test(void);
}

namespace a
{
int WINAPI test(void);
}…
[/Quote]
Gothic_girl 2009-06-09
  • 打赏
  • 举报
回复
一个用静态载入
令一个用LoaLibrary动态载入
skyxie 2009-06-08
  • 打赏
  • 举报
回复
[Quote=引用楼主 jamesking 的帖子:]
c.dll程序可以通过编译,却无法链接。
[/Quote]

namespace a
{
int WINAPI test(void);
}
namespace b
{
int WINAPI test(void);
}
因为你这里只声明了函数,没有定义函数体。



根据你的意思是要分别调用 dll a b中的test函数,但是implicit link貌似没有办法解决名字冲突.
neohope 2009-06-08
  • 打赏
  • 举报
回复
当你静态加载时,由于你的函数名及函数参数完全一样,所以生成的标识符一样,对于编译器来说,它无法识别究竟是哪一个函数,也就是产生了重名,自然无法链接
同样,在你的各个namespcae之间,你没有办法区分链接的是哪个函数,所以你无法调用正确的函数

你可以尝试将他们封装在类中,但与你的要求不符

要是你非要重名,那就要动态加载,

建议你将dll中函数改名。
arong1234 2009-06-08
  • 打赏
  • 举报
回复
似乎在def文件中定义变量,会隐藏掉你的那个命名空间的效果
个人觉得,虽然命名空间允许你定义同名函数,但是你这种情况显然应该用接口实现,然后通过“动态载入”而不是“静态载入”方式调用。使用“命名空间”和“def”文件这种混合方式是否能真的有解决方法,我很怀疑。即使有解决方法,也不是平凡解法(也就是不是大众所熟知的解法),这在软件工程中要努力避免的。

16,551

社区成员

发帖
与我相关
我的任务
社区描述
VC/MFC相关问题讨论
社区管理员
  • 基础类社区
  • Creator Browser
  • encoderlee
加入社区
  • 近7日
  • 近30日
  • 至今
社区公告

        VC/MFC社区版块或许是CSDN最“古老”的版块了,记忆之中,与CSDN的年龄几乎差不多。随着时间的推移,MFC技术渐渐的偏离了开发主流,若干年之后的今天,当我们面对着微软的这个经典之笔,内心充满着敬意,那些曾经的记忆,可以说代表着二十年前曾经的辉煌……
        向经典致敬,或许是老一代程序员内心里面难以释怀的感受。互联网大行其道的今天,我们期待着MFC技术能够恢复其曾经的辉煌,或许这个期待会永远成为一种“梦想”,或许一切皆有可能……
        我们希望这个版块可以很好的适配Web时代,期待更好的互联网技术能够使得MFC技术框架得以重现活力,……

试试用AI创作助手写篇文章吧