zoukankan      html  css  js  c++  java
  • Win32 的dll导入问题总结

    dll 文件可以导入变量,函数,和C++类,但是导入变量会使执行程序与dll紧耦合,而C++类导入则需要两个文件的开发商所用的编译器相兼容,所以做好只导入函数;
    创建dll :
    头文件:
    #ifdef               MYLIBAPI                    //在dll源文件中必须定义这个宏为导出宏
    #else                    //因为执行文件中必然没有定义这个宏所以
    #define MYLIBAPI   __declspec(dllimport) //在执行文件中必定为导入宏
    #endif
    MYLIBAPI int g_nResult;                        //导入变量
    MYLIBAPI int Add(int nLeft, int nRight);  //导入函数

    源文件:
    #include <windows.h>
    #define MYLIBAPI   __declspec(dllexport)    //屏蔽掉头文件的导入宏为导出宏
    #include "MyLib.h"
    int g_nResult;
    int Add(int nLeft, int nRight) {g_nResult = nLeft + nRight;   return(g_nResult);  }

    隐式链接:
    在mfc中调用win32 dll 的步骤:   (导出函数 /一般不导出c++类:可以只导出部分public函数)
    1: 不要用extern "C",单独用_declspec (dllexport) ..... 生成dll 及 lib 文件;
    2: 将lib 文件复制到当前程序目录,且将链接器的   输入->付加依赖项 中写入库文件;
    3: 复制dll文件到debug 目录(必须的);
    4:在调用函数时, 采用先声明外部函数 在使用;
     4.1: 用extern 来声明函数;
     4.2: 用_declspec(dllimport) 来声明导入的函数 ;  (采用后者效率通常会更高)
    对于带头文件的导入方式:
    1: 其中第二三步不变, 采用文上的定义方式;
    2:将头文件装置程序目录,并在原来声明外部函数的地方 #include<文件.h>,而不需要在显示声明函数原型了;

    其中的 extern "C" 的作用是告诉c++编译器 不要改动所要导出的类型的名称,以防在别的模块中无法访问; (当在写c和c++的混合代码的时候,如果不加则会导致严重的链接问题)
    当你用C++编译器写的dll,再用c语言的编译器来导入就会出错,而还是用同一种编译器便宜的话则不会出错;
    可以通过dumpbin.exe 来查看所谓导出或者需要导入的dll 的信息;(exports /imports)
    名字改编: 为了支持重载,按照自己的一套规则来改变函数的名字
    这就导致了,要就要在客户端,和服务端同时用extern "C" 来用相同的规则来寻找同一个函数名;(要不就不要加)(用这个特性的话就不可以导出类函数;)


    显示链接:(动态加载一个动态链接库) 这时候即使采用不同的调用约定(当然访问时,约定也要相同),其函数名也没有改变;
    且不会dumpbin出需要动态加载的文件;  
    1. 包含一个 .def文件  :文件中含有  EXPORTS    functionname  (这样就会只导出一个不会变的函数名称) 如果不用.def文件的话,可以在加载的时候,显示的使用变化后的函数名
    将次dll文件的项目属性的   输入->模块定义文件-> 为 name.def                    就可以生成相应的.lib 文件了
    (1)或者是                #pragma comment(linker, "/export:MyFunc=_MyFunc@8")
    2.HMODULE LoadLibrary("dll or exe name ");           导入模块                                       这里返回的HMODULE句柄就相当于HINSTANCE,其实是dll文件加载后所在的虚拟内存地址
    3.FARPROC GetProAddress();   获得函数入口地址
    例如: typedef  int (* addproc)(int a ,int b);
    addproc Add=(addproc)GetProcAddress(hmoudle,"add");                     或者使第二个函数为 MAKEINTERESOURCE(序号);
    Add(10,10);
    FreeLibrary(hmoudle);    卸载动态链接库
    注: 在非vc情况下调用一个c++(非改名的c++或者是C)的dll 通常会出现的问题:是不是标准调用,如果是的话则函数名即使指定extern也会改变
    原因:由于:ms 的c编译器即使在你没有使用c++代码的时候也会改变c 函数的名字, 只要在你调用函数的时候使用了WINAPI 的_stdcall(绝大多数的情况), 这时候编译器会产生一个有下划线起始的,以@+参数所占有的字节数 结尾的函数; 而ms的编译器可以正确翻译出相应的名字;
    在使用其它非ms编译器来调用可用dll的时候,必须要使用以下两种方法:(指示其不要将函数改名)
       
    DllMain() dll 文件的入口函数 (是可选的)   可以为自己的函数提供一个本dll文件的句柄来供dll 函数来使用;


    如果在dll文件中分配内存的话,那么一定要提供相应的释放函数在dll中释放内存,即一个模块提供了分配内存的函数,那么它就同时也要提供释放内存的函数.

  • 相关阅读:
    按单生产案例
    【转】linux中执行外部命令提示" error while loading shared libraries"时的解决办法
    【转】WARNING! File system needs to be upgraded. You have version null and I want version 7. Run the '${HBASE_HOME}/bin/hbase migrate' script. 的解决办法
    根据Rowkey从HBase中查询数据
    【转】在一个Job中同时写入多个HBase的table
    sqoop 使用
    给VMware下的Linux扩展磁盘空间(以CentOS6.3为例)
    chrome 版本 29.0.1547.76 m 解决打开新标签页后的恶心页面的问题
    tomcat7+jdk的keytool生成证书 配置https
    如何打包和生成你的Android应用程序
  • 原文地址:https://www.cnblogs.com/wenhuisun/p/1735987.html
Copyright © 2011-2022 走看看