none
公共运行库支持的DLL调用问题 RRS feed

  • 问题

  • 我做了一个DLL,选择了“公共运行库支持”(因为我的DLL中要调用c#的组件),编译正常。但是我在调用这个DLL时,提示“错误 2 error LNK2019: 无法解析的外部符号 __imp__abc,该符号在函数 _wmain 中被引用 “,这是什么原因啊?

     

    2011年3月9日 9:41

答案

  • 可能的问题点有2个,

    1.添加了 链接器 对 导出库testdll.lib的引用没?

    或者在app工程的链接器页里设置,或者用下面的方式设置

    #pragma comment( lib ,"testdll.lib" )
    2._imp_add这个名字有点奇怪,按理说extern "C"应该是用add原始名称,不知道为啥你的还有个_imp前缀修饰?检查一下你的EXTERN_C究竟是怎么定义的?可以用depends工具(http://www.dependencywalker.com/)查看一下dll和exe里究竟导出和导入的是哪个名称
    2011年3月10日 2:50
  • 1.如果exe项目添加引用另一个dll项目,那vs环境会自动帮你干这个.

      build一个C++工程时,先要用compiler编译器把cpp文件编译为obj文件;搞完这些玩意,再用链接器linker把这些obj和外部输入的dll链接起来. linker需要知道你用的那个add在哪儿,所以他需要你提供一堆lib文件,这些lib文件里记录了某个dll里的什么位置,是什么函数的入口位置;你可以发现,生成dll时,会附带有一个lib文件生成,即我们需要提供给linker的"导入库",然后linker会搞些jmp指令,以便程序执行时,指令从exe jump到dll中的正确位置

    这些工作很繁琐无趣,所以vs集成环境尽可能自动帮你干了.

    2.带_imp前缀的名称应该只是linker链接器自已用的一个占位符,哈哈,我多虑了.LNK2019有时可能是修饰名引起的.

        所有C编译器生成的函数名称都是一样的,而C++编译器生成的是修饰名,会有前后缀,你可以用depends查看不带extern "C"编译出来的名称.不同厂家的C++编译器的修饰名不同,这会给linker带来麻烦,所以c++编译器都认识一个extern "C",遇到这玩意编译器生成不带任何修饰名的函数.dll导出的东西由于很可能会给其它编译器生成的exe用,所以往往带extern "C".如果你只用microsoft的编译器,那不用这个extern "C"也没关系,但如果dll和exe是不同厂家的编译器生成的,却没有带extern "C",那么也会搞出LNK2019错误

    2011年3月10日 7:40

全部回复

  • 怎么无人回答,我再仔细描述一下吧:

    开发环境vs2008:

    dll开发过程:新建项目->win32->win32->dll 选择MFC ,项目属性更改为“共公语言运行时支持(/clr)”

    加入代码:testdll.h

    #ifdef TESTDLL_EXPORTS

    #define TESTDLL_API __declspec(dllexport)

    #else

    #define TESTDLL_API __declspec(dllimport)

    #endif

     

     

    EXTERN_C TESTDLL_API int add(int a,int b );

    testdll.cpp
    #include "stdafx.h"
    #include "testdll.h"

    #ifdef _DEBUG
    #define new DEBUG_NEW
    #endif
    #using "mscorlib.dll"

    // 唯一的应用程序对象

    CWinApp theApp;

    using namespace std;

    int _tmain(int argc, TCHAR* argv[], TCHAR* envp[])
    {
    int nRetCode = 0;

    // 初始化 MFC 并在失败时显示错误
    if (!AfxWinInit(::GetModuleHandle(NULL), NULL, ::GetCommandLine(), 0))
    {
    // TODO: 更改错误代码以符合您的需要
    _tprintf(_T("错误: MFC 初始化失败\n"));
    nRetCode = 1;
    }
    else
    {
    // TODO: 在此处为应用程序的行为编写代码。
    }

    return nRetCode;
    }


    TESTDLL_API int add(int a,int b )
    {
    return a +b;
    }

    测试dll的app 项目建立过程
    新建项目->win32->win32项目- >控制台程序  
    引入testdll项目,调试环境为PATH=<testdll目录>
    c++附加目录选择testdll.h的跟径
    testdllapp.cpp
    #include "stdafx.h"
    #include "windows.h"
    #include "testdll.h"


    int _tmain(int argc, _TCHAR* argv[])
    {
    int i = add(1,2);
    return 0;
    }

    运行结果 :
    错误 1 error LNK2019: 无法解析的外部符号 __imp__add,该符号在函数 _wmain 中被引用 testdllapp.obj testdllapp
    错误 2 fatal error LNK1120: 1 个无法解析的外部命令 D:\expVC2008\IVRQUERY\testdll\Debug\testdllapp.exe 1 testdllapp



     

    2011年3月10日 1:44
  • 可能的问题点有2个,

    1.添加了 链接器 对 导出库testdll.lib的引用没?

    或者在app工程的链接器页里设置,或者用下面的方式设置

    #pragma comment( lib ,"testdll.lib" )
    2._imp_add这个名字有点奇怪,按理说extern "C"应该是用add原始名称,不知道为啥你的还有个_imp前缀修饰?检查一下你的EXTERN_C究竟是怎么定义的?可以用depends工具(http://www.dependencywalker.com/)查看一下dll和exe里究竟导出和导入的是哪个名称
    2011年3月10日 2:50
  • 可能的问题点有2个,

    1.添加了 链接器 对 导出库testdll.lib的引用没?

    或者在app工程的链接器页里设置,或者用下面的方式设置

    #pragma comment( lib ,"testdll.lib" )
    2._imp_add这个名字有点奇怪,按理说extern "C"应该是用add原始名称,不知道为啥你的还有个_imp前缀修饰?检查一下你的EXTERN_C究竟是怎么定义的?可以用depends工具(http://www.dependencywalker.com/)查看一下dll和exe里究竟导出和导入的是哪个名称

    1、我加了#pragma comment( lib ,"testdll.lib" )以后问题解决了,但为什么我以前我只是添加项目引用程序也没问题啊?

    2、我用depends查看了一下,是add,EXTERN_C是这样定义的

    #ifdef __cplusplus

        #define EXTERN_C    extern "C"

    #else

        #define EXTERN_C    extern

    #endif

    感觉没什么问题。

     

    2011年3月10日 5:21
  • 1.如果exe项目添加引用另一个dll项目,那vs环境会自动帮你干这个.

      build一个C++工程时,先要用compiler编译器把cpp文件编译为obj文件;搞完这些玩意,再用链接器linker把这些obj和外部输入的dll链接起来. linker需要知道你用的那个add在哪儿,所以他需要你提供一堆lib文件,这些lib文件里记录了某个dll里的什么位置,是什么函数的入口位置;你可以发现,生成dll时,会附带有一个lib文件生成,即我们需要提供给linker的"导入库",然后linker会搞些jmp指令,以便程序执行时,指令从exe jump到dll中的正确位置

    这些工作很繁琐无趣,所以vs集成环境尽可能自动帮你干了.

    2.带_imp前缀的名称应该只是linker链接器自已用的一个占位符,哈哈,我多虑了.LNK2019有时可能是修饰名引起的.

        所有C编译器生成的函数名称都是一样的,而C++编译器生成的是修饰名,会有前后缀,你可以用depends查看不带extern "C"编译出来的名称.不同厂家的C++编译器的修饰名不同,这会给linker带来麻烦,所以c++编译器都认识一个extern "C",遇到这玩意编译器生成不带任何修饰名的函数.dll导出的东西由于很可能会给其它编译器生成的exe用,所以往往带extern "C".如果你只用microsoft的编译器,那不用这个extern "C"也没关系,但如果dll和exe是不同厂家的编译器生成的,却没有带extern "C",那么也会搞出LNK2019错误

    2011年3月10日 7:40
  • 谢谢,AceBear
    2011年3月10日 7:59