我有几个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我也会。只要静态编译链接,如何实现?

解决方案 »

  1.   

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

  2.   

    当你静态加载时,由于你的函数名及函数参数完全一样,所以生成的标识符一样,对于编译器来说,它无法识别究竟是哪一个函数,也就是产生了重名,自然无法链接
    同样,在你的各个namespcae之间,你没有办法区分链接的是哪个函数,所以你无法调用正确的函数你可以尝试将他们封装在类中,但与你的要求不符要是你非要重名,那就要动态加载,建议你将dll中函数改名。
      

  3.   


    namespace a 

        int WINAPI test(void); 

    namespace b 

        int WINAPI test(void); 

    因为你这里只声明了函数,没有定义函数体。根据你的意思是要分别调用 dll a b中的test函数,但是implicit link貌似没有办法解决名字冲突.
      

  4.   

    谢谢大家,我已经找到了方法。
    方法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
    ====================================================================================== 
      

  5.   

    sorry,上面方法二中函数声明少了WINAPI
    int WINAPI mytest(void) 
      

  6.   

    一个用静态载入
    令一个用LoaLibrary动态载入
      

  7.   

    是你找到的还是大家告诉你的?方法1是我在1楼提到的,方法2是2楼提到的。做人要实在。
    尽管如此,我还是不赞同你使用其中任何一种方法。方法1是对namespace的滥用,我个人更倾向于防止不同的函数提供者直接的命名冲突,你自己不应该故意创造冲突,至于方法2:这违背了c++对重载支持的初衷。
    个人还是喜欢使用定义公共接口,然后dll中分别实现的方法
      

  8.   

    谢谢你们的帮助。不管是方法一还是方法二,它的原理都是让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
    改了标识符后,链接器就能确切的知道该导出的是哪个函数了。