zoukankan      html  css  js  c++  java
  • windows dll的def文件

    DLL(testcase_1.dll )源码:myfun.h

    #pragma once
    
    #ifdef TESTCASE_1_EXPORTS
    #define MY_API  __declspec(dllexport)
    #else
    #define MY_API __declspec(dllimport)
    #endif
    #include <iostream>
    #include <string>
    
    namespace APICore
    {
        class MY_API ExportInterface
        {
        public:
            virtual void foo() = 0;
        };
    
        extern "C" MY_API ExportInterface* getInstance();
    
    #ifdef TESTCASE_1_EXPORTS
        class ExportClass :public ExportInterface
        {
        private:
            std::string m_str;
        public:
            void foo();
        };
    #endif
    };

    mufun.cpp

    #include <iostream>
    
    #include "myfun.h"
    //#include "myfun2.h"
    
    using namespace  std;
    
    namespace APICore
    {
        extern "C" MY_API ExportInterface* getInstance()
        {
            //APICore2::printInfo();
            static ExportClass ec;
            return &ec;
        }
    
        void ExportClass::foo()
        {
            cout << "Hi, I'm ExportClass::foo" << endl;
        }
    }

    可执行文件(alltest.exe)源码:

    main.cpp

    #include <iostream>
    
    //#include "..\testcase_1\myfun.h"
    //#pragma comment(lib, "..\Debug\testcase_1.lib")
    
    
    #include <Windows.h>
    #include "myfun.h"
    
    int main(int argc, char *argv[])
    {
        //// 动态加载dll,不需要lib文件,
        //HINSTANCE handle = GetModuleHandle("testcase_1.dll");
        //    
        //if (handle == NULL)
        //{
        //    handle = LoadLibrary("testcase_1.dll");
        //    typedef APICore::ExportInterface* (*FUNTYPE)() ;
    
        //    FUNTYPE fun = (FUNTYPE)GetProcAddress(handle, "getInstance");
        //    if (fun)
        //    {
        //        fun()->foo();
        //    }
        //    FreeLibrary(handle);
        //}
        
        // 静态加载调用,无法使用def文件,因为静态加载用的是lib文件
        APICore::getInstance()->foo();
    
        getchar();
    
        return 0;
    }

    如果都使用默认配置编译,只要设置好可执行文件的头文件包含目录(myfun.h所在目录),导入对应的lib(testcase_1.dll.lib)文件,然后把testcase_1.dll.dll放到alltest.exe同一目录。程序便可以正常运行。

    那么def文件有什么用呢?

    我们先改变一下testcase_1.dll的项目属性,调用约定由__cdecl改为__fastcall,可执行文件alltest.exe保持__cdecl调用约定不变

    这个时候再次编译dll,生产成功

     

    再重新编译生产可执行文件alltest.exe,编译失败,说找不到我们要使用的dll中的函数符号。

    这是因为上面改了dll调用约定,而exe没有改。我们可以吧exe和dll的调用约定改成一样的,就没问题了。

    这里我介绍另一种方法,就是使用我们的def文件。我们在testcase_1.dll这个项目中新添加一个def文件,

    叫做sourc.def。内容如下

    LIBRARY "testcase_1.lib"
    
    EXPORTS
        getInstance
    EXPORTS下的getInstance告诉编译器要导出的符号是getInstance,而是其他的,比如@getInstance@0,然后修改
    项目属性如下:
     

    再重新编译生产testcase_1.dll。这时候我们再次编译可执行文件,发现还是找不到符号,编译不通过。然后我们对可执行文件alltest.exe的代码做一点修改,
    把dll加载有静态加载改为动态加载。修改main.cpp如下
    #include <iostream>
    
    //#include "..\testcase_1\myfun.h"
    //#pragma comment(lib, "..\Debug\testcase_1.lib")
    
    
    #include <Windows.h>
    #include "myfun.h"
    
    int main(int argc, char *argv[])
    {
        // 动态加载dll,不需要lib文件,
        HINSTANCE handle = GetModuleHandle("testcase_1.dll");
            
        if (handle == NULL)
        {
            handle = LoadLibrary("testcase_1.dll");
            typedef APICore::ExportInterface* (*FUNTYPE)() ;
    
            FUNTYPE fun = (FUNTYPE)GetProcAddress(handle, "getInstance");
            if (fun)
            {
                fun()->foo();
            }
            FreeLibrary(handle);
        }
        
        //// 静态加载调用,无法使用def文件,因为静态加载用的是lib文件
        //APICore::getInstance()->foo();
    
        getchar();
    
        return 0;
    }

    然后重新编译运行,就可以了

    总结

    def文件可以用于当dll的调用约定(__fastcall),与宿主(本例的alltest.exe)程序的调用约定不一致时(__cdecl),导致可执行文件在

    使用dll时的链接出错。不过要注意的是,def文件从实验来看,只会影响dll中的输出符号,而不会影响lib中的输出符号。这也是为什么

    我们不能再使用静态加载的方式,而要改为动态加载的方式。因为动态加载只使用dll,而静态加载链接时使用的是lib中的符号。

  • 相关阅读:
    01_3_创建一个Action
    01_2_Namespace命名空间
    01_1_Socket实现
    03_2_JAVA中的面向对象与内存解析
    01_1_Struts环境搭建
    Zabbix通过Orabbix监控Oracle数据库
    Zabbix通过JMX方式监控java中间件
    nginx启用status状态页
    zabbix数据库分表的实现
    配置sudo记录日志
  • 原文地址:https://www.cnblogs.com/fisherman-luo/p/10189309.html
Copyright © 2011-2022 走看看