精华内容
下载资源
问答
  • DLL动态链接库调用C#源代码DLL动态链接库调用C#源代码DLL动态链接库调用C#源代码
  • MFC动态链接库调用详解

    千次阅读 2016-11-04 23:09:37
    MFC动态链接库调用,有好多种方式,这里只介绍一种简单的调用的方式,只需要把动态链接库编译后的.dll文件放到调用界面的Debug下面。再在界面需要调用动态链接库里添加相关函数就行了。找了好多资料,发现没有详细...

    MFC动态链接库的调用,有好多种方式,这里只介绍一种简单的调用的方式,只需要把动态链接库编译后的.dll文件放到调用界面的Debug下面。再在界面需要调用动态链接库里添加相关函数就行了。找了好多资料,发现没有详细的介绍,下面就是从动态链接库建立开始,一点点详细的介绍。

    首先是,动态链接库的建立。我们这里讲的是MFC的标准库的建立。用的是vs2010。
    我们建立一个名为TestDLL的动态链接库。
    这里写图片描述

    然后,我们这里实现一个小程序,在动态链接库里返回四个点,用来画一个矩形。

    首先,我们写的是动态链接库里的内容,先不考虑界面的问题。

    我们在动态链接库里新建一个类,用来储存矩形的四个点。注意,这里的类名不要起的很常见,例如,CDrawRect这样的类,因为很有可能和MFC内部已有的类冲突,从而会出现显示调用不明确的情况。
    这里写图片描述

    上面出现的warning“找不到符号唯一的匹配项错误”,是因为在mfc中已经有定义。

    这里写图片描述

    所以,我们起类名字时,要注意这点。
    这里写图片描述

    然后,我们在新建的类中添加一个公有成员函数,名字叫做

    CPoint* GetPoint();

    这样,就建立一个函数,里面返回的是矩形的点的数组的指针。这样,就能通过地址来调用数组里面的一串值了。

    在.cpp里,写下:

    CPoint* CDrawRectPoint::GetPoint()
    {
        CPoint getPoint[4];
    
        getPoint[0].x=100;
        getPoint[0].y=100;
        getPoint[1].x=100;
        getPoint[1].y=500;
        getPoint[2].x=500;
        getPoint[2].y=500;
        getPoint[3].x=500;
        getPoint[3].y=500;
    
        return getPoint;
    }

    这里,我们为了养成一个良好的习惯,要把动态链接库的接口专门在一个派生类中写出来,这样,就会在导出的时候,我们只需要对接口进行处理就好了。并且,在提交项目时,也只需要提供.dll和接口类就好,可以有效的保证自己代码的安全和核心代码的利益。

    于是,我们新建一个派生类,从CDrawRectPoint类里派生出来一个类,名字叫做CDrawRectPointIO。

    #include "drawrectpoint.h"
    
    class CDrawRectPointIO:
        public CDrawRectPoint
    {
        //说明:没有把构造函数析构函数写出来
        CPoint* GetPoint();
    }

    在.cpp里:

    CPoint* CDrawRectPointIO::GetPointIO()
    {
        return GetPoint();
    }

    好了,上面是动态链接库里的内容已经写出来,下面是写出动态链接库的调出。

    在CDrawRectPointIO.h文件中,在最开始的部分,加上:

    //即把导出的函数声明为全局的,并且声明为外部可调用
    extern "C" __declspec(dllexport)CPoint* __stdcall GetPointIO();

    这里写图片描述

    然后,再在源文件里的.def文件里,添加导出的函数的名称,因为这个是不加变量,只有函数名称的,所以,这也是前面提到的为什么函数命名时尽量不要用太常见的函数名的原因。

    这里写图片描述

    之后是调试,在Debug里得到.dll。到这里就是动态链接库的导出过程。

    然后是动态链接库在界面中的调用。

    新建一个MFC单文档类。名字叫做TestEXE,设置成MFC标准。这里为了方便画,直接就在OnDraw(CDC*pDC)函数里写了,实际上不推荐在这个函数里调用动态链接库,因为系统里会不断的自动刷新OnDraw()函数,所以,为了安全起见,我们最好不要用在OnDraw()函数里写。这里,我们用一个控制变量来控制是否启用动态链接库。

    首先,是建立之后,F5调试程序。生成Debug,把前面动态链接库生成的.dll复制粘贴到界面的Debug里。

    在资源视图里的Menu里添加菜单栏,并把ID修改。类向导到view里。

    这里写图片描述

    在view.h里添加成员变量,int m_nControl;在构造函数里初始化为0。

    在view.cpp里,对刚才添加的OnRect()函数里,添加控制变量。

    void CTestEXEView::OnRect()
    {
        // TODO: 在此添加命令处理程序代码
        m_nControl = 1;
        Invalidate();
    }

    下面先是对动态链接库的调用,在view.cpp里,在文件头下添加如下:

    typedef CPoint*(WINAPI *dllDraw)();

    在OnDraw里添加:

    if(1 == m_nControl)
        {
            HINSTANCE hDLL; 
            hDLL=LoadLibrary("TestDLL.dll");//加载动态链接库MyDll.dll文件;
            if(hDLL == NULL)  
            {  
                MessageBox("无法载入dll\n");  
                FreeLibrary(hDLL);  
            }
    
            dllDraw DrawNew;
            DrawNew=(dllDraw)GetProcAddress(hDLL,"GetPointIO");
    
            if(DrawNew == NULL)  
            {  
                MessageBox("第二步无法载入dll\n");  
                FreeLibrary(hDLL);   
            } 
    
            CPoint *m_point = new CPoint[4];
            m_point = DrawNew();
    
            CPoint point[4];
            for(int i=0;i<4;i++)
            {
                point[i]=m_point[i];
            }
    
            pDC->MoveTo(m_point[0]);
            pDC->LineTo(m_point[1]);
            pDC->LineTo(m_point[2]);
            pDC->LineTo(m_point[3]);
            pDC->LineTo(m_point[0]);
    
            FreeLibrary(hDLL);
            m_nControl=0;
            delete []m_point;
            m_point = NULL;
        }

    最后得到结果如图:

    这里写图片描述

    以上就是全部内容了。

    展开全文
  • C++基础:动态链接库调用方法总结

    千次阅读 2016-09-03 17:59:02
    虽说在08年就学习了静态库,动态链接库的使用方法,但是在最近的工作中才发现,动态链接库的动态调用(也叫显式调用)我是可以运用了,但是静态调用(也叫隐式调用)我其实还是没有掌握,这次就借这个机会把动态库的...

    from  http://blog.csdn.net/crich_moon/article/details/6039939

    虽说在08年就学习了静态库,动态链接库的使用方法,但是在最近的工作中才发现,动态链接库的动态调用(也叫显式调用)我是可以运用了,但是静态调用(也叫隐式调用)我其实还是没有掌握,这次就借这个机会把动态库的两种用法再熟悉一下。

    (一)先回顾一下,动态链接库和静态链接库

     

    静态链接库:lib中的函数不仅被连接,全部实现都被直接包含在最终生成的EXE文件中,只是实现是不可见的。

    动态链接库:dll不必被包含在最终的EXE中,静态调用时仅把函数名或者变量名或者类名链接到EXE文件中,而这些东西的实体都只有在运行时才从动态库中导入到可执行文件中,动态调用的时候EXE文件执行时可以直接动态地引用和卸载DLL文件。

    同时,静态链接库中不能再包含其他的动态链接库或静态库,而动态链接库中可以包含其他的动态或静态库。

     

    (二)回顾一下VC++支持的DLL:

     

    DLL的编制与具体的编程语言及编译器无关,动态链接库随处可见,VC++支持三种DLL:非MFC动态库、MFC规则DLL和MFC扩展DLL。DLL导出函数(或变量、类)可供应用程序调用;DLL内部函数只能在DLL程序内使用,应用程序无法调用它们。

     

    (三)导出函数的声明方式:

     

    一种在函数声明类型和函数名之间加上“_declspec(dllexport)”。

    另外一种采用模块定义(.def)文件声明,需要在库工程中添加模块文件,格式如下:

    LIBRARY 库工程名称

    EXPORTS 导出函数名

     

    (四)DLL的调用方式:

     

    静态调用中,由编译系统完成对DLL的加载和应用程序结束时DLL的卸载。

    动态调用中,由编程者用API函数加载和卸载DLL(DLL加载—DLL函数地址获取—DLL释放)方式。

    接下来写个例子把上面提到的理论都实践一遍

    一、 函数----创建动态链接库(MFC规则DLL)

    1. New--projects--MFC AppWizard(dll)--Regular DLL using shared MFC DLL //取名为MFC_dll

    2. def文件中添加:函数名(Add_new)

    3. h文件中添加:外部函数声明//求和函数,函数名为Add_new

    extern "C" __declspec(dllexport) int __stdcall Add_new(int a,int b);

    4. cpp文件中添加: 外部函数实现

    extern "C" __declspec(dllexport) int __stdcall Add_new(int a,int b)

    {

    return a+b;

    }

    5. build--set active configuration--win32 release--ok

    6. 生成

    7. 根目录下release文件夹中dll,lib与根目录下h文件即为所需

    二、 函数----调用动态链接库(把MFC_dll.dll和MFC_dll.lib拷到工程所在目录)

    //静态调用(.h可以写到.cpp文件中)

    1. new--projects--win32 console application--an empty project

    2. 添加h文件:(test.h)

    #pragma comment(lib,"MFC_dll.lib") //告诉编译器DLL相对应的lib文件所在路径和文件名

    extern "C" _declspec(dllimport) int _stdcall Add_new(int a,int b);//声明导入函数

    3. 添加cpp文件:(main.cpp)

    #include "test.h"

    int main()

    {

    cout<<Add_new(10,3);

    return 0;

    }

    //动态调用

    #include <stdio.h>

    #include <windows.h>

    typedef int (* lpAddFun)(int ,int);//定义一个与Add_new函数接受参数类型和返回值均相同的函数指针类型

    int main()

    {

    HINSTANCE hDll;//句柄

    lpAddFun addFun;//函数指针

    hDll=LoadLibrary("dllTest.dll");//动态加载DLL模块句柄

    if(hDll)

    {

    addFun=(lpAddFun) GetProcAddress(hDll,"Add_new");//得到所加载DLL模块中函数的地址

    if(addFun)

    {

    int result=addFun(2,3);

    printf("%d",result); } FreeLibrary(hDll);//释放已经加载的DLL模块

    }

    return 0;

    }

    三、 变量----创建动态链接库(非MFC DLL)

    1. new---projects---win32 dynamic-link library----an empty project(Sample)

    2. 添加sample.h

    #ifndef SAMPLE_H

    #define SAMPLE_H

    extern int dllGlobalVar;

    #endif

    3. 添加 sample.cpp

    #include "sample.h"

    #include <windows.h>

    int dllGlobalVar;

    bool APIENTRY DllMain(HANDLE hModule,DWORD ul_reason_for_call,LPVOID lpReserved)

    //windows在加载DLL时,需要一个入口函数,就如同控制台或DOS程序需要main函数、win32程序需要winmain函数一样。所以引入一个不做任何操作的缺省DllMain的函数版本。是DLL的内部函数。

     

     

    有一点要注意,如果看到此类宏定义
    #ifdef KSCANBAR_EXPORTS
    #define KSCANBAR_API __declspec(dllexport)
    #else
    #define KSCANBAR_API __declspec(dllimport)
    #endif
    是因为

    这样定义一般出现在含有多个项目的解决方案中,这样可以使从 DLL 导出更简单的宏的标准方法。此 DLL 中的所有文件都是用命令行上定义的 KSCANBAR_EXPORTS符号编译的。在使用此 DLL 的任何其他项目上不应定义此符号。这样,源文件中包含此文件的任何其他项目都会将KSCANBAR_API 函数视为是从 DLL 导入的,而此 DLL 则将用此宏定义的符号视为是被导出的。


    展开全文
  • 如果动态链接库发布x64版本,中文的路径和文件名都正常,可是如果动态链接库发布86版本,传递过去的字符串如果带有中文路径就会出现乱码,而如果只是中文文件名,。目录是英文和数字,就正常。 据我所知系统位数不会...
  • 创建一个win32项目,起名mylib(因为我已经创建过mylib了,所以这里用的mylib2)。 下面开始编写C模块: ...由于C++支持函数重载,因此编译器编译函数的...如此就完成了整个lua采用动态链接库调用C模块的过程。

    创建一个win32项目,起名mylib(因为我已经创建过mylib了,所以这里用的mylib2)。

    这里写图片描述
    下面开始编写C模块:

    mylib.h如下:

    /*mylib.h*/
    
    #define _CRT_SECURE_NO_WARNINGS
    #include <iostream>
    #include <string>
    #include <dirent.h>
    #include <errno.h>
    
    extern "C" {
        #include "lua.h"
        #include "lauxlib.h"
        #include "lualib.h"
    }
    
    using namespace std;
    
    #ifdef MYLIB_EXPORTS
    #define MYLIB_API __declspec(dllexport)
    #else
    #define MYLIB_API __declspec(dllimport)
    #endif
    
    extern "C"  __declspec(dllexport) MYLIB_API int luaopen_mylib(lua_State* L);
    

    mylib.cpp如下(这里包含了两个函数功能,一个是l_sin函数,一个是遍历目录的l_dir函数):

    // mylib.cpp : 定义 DLL 应用程序的导出函数。
    
    #define _CRT_SECURE_NO_WARNINGS
    #include "stdafx.h"
    #include "mylib.h"
    #include <iostream>
    #include <string>
    #include <dirent.h>
    #include <errno.h>
    
    extern "C" {
    #include "lua.h"
    #include "lauxlib.h"
    #include "lualib.h"
    }
    
    extern "C" int l_sin(lua_State *L) {
        double d = luaL_checknumber(L, 1);
        lua_pushnumber(L, sin(d));
        return 1;
    }
    
    extern "C" int l_dir(lua_State *L) {
        DIR *dir;
        struct dirent *entry;
        int i;
        const char *path = luaL_checkstring(L, 1);
        dir = opendir(path);
        if (dir == NULL) {
            lua_pushnil(L);
            lua_pushstring(L, strerror(errno));
            return 2;
        }
    
        lua_newtable(L);
        i = 1;
        while ((entry = readdir(dir)) != NULL) {
            lua_pushnumber(L, i++);
            lua_pushstring(L, entry->d_name);
            lua_settable(L, -3);
        }
    
        closedir(dir);
        return 1;
    }
    
    static const struct luaL_reg mylib[] = {
        { "mydir", l_dir },
        { "mysin", l_sin },
        { NULL, NULL }
    };
    
    
    extern "C"  __declspec(dllexport)
    MYLIB_API int luaopen_mylib(lua_State* L) {
        luaL_register(L, "mylib", mylib);
        return 1;
    }

    这里尤其注意

    extern "C"  __declspec(dllexport)
    MYLIB_API int luaopen_mylib(lua_State* L)

    extern “C” 和 dllexport,dll需要导出符号。

    同时extern “C”避免名字粉碎。
    extern “C”的主要作用就是为了能够正确实现C++代码调用其他C语言代码。加上extern “C”后,会指示编译器这部分代码按C语言的进行编译,而不是C++的。由于C++支持函数重载,因此编译器编译函数的过程中会将函数的参数类型也加到编译后的代码中,而不仅仅是函数名;而C语言并不支持函数重载,因此编译C语言代码的函数时不会带上函数的参数类型,一般之包括函数名。

    比如说你用C 开发了一个DLL 库,为了能够让C ++语言也能够调用你的DLL输出(Export)的函数,你需要用extern “C”来强制编译器不要修改你的函数名

    编写好程序后,直接点击编辑生成mylib.dll和mylib.lib文件,会出现如下提示,忽略它就好。

    这里写图片描述

    然后将生成的mylib.dll和mylib.lib文件放到与lua程序的同目录下,这里创建一个lua文件叫做lib.lua:

    mylib = require ("mylib");
    print (mylib.mysin (3.14 / 2));
    t = mylib.mydir ("D:\\Lua-5.1\\lua-5.1.5\\lua-5.1.5");
    for k, v in pairs (t) do
        print (k, v);
    end

    如此lib.lua会通过require将动态库mylib链接到lua,并寻找luaopen_mylib函数,将其注册为一个lua函数,然后调用它以打开模块。运行结果如下:

    这里写图片描述

    如此就完成了整个lua采用动态链接库调用C模块的过程。

    展开全文
  • 首先建立__cdecl 调用约定函数的动态链接库。 FirstDll.cpp #include BOOL APIENTRY DllMain( HANDLE hModule, DWORD ul_reason_for_call, LPVOID lpReserved )

    首先建立__cdecl 调用约定函数的动态链接库。

    FirstDll.cpp

    #include <windows.h>
    
    BOOL APIENTRY DllMain( HANDLE hModule, 
                           DWORD  ul_reason_for_call, 
                           LPVOID lpReserved
    					 )
    {
        return TRUE;
    }

    DLL入口函数。

    lib.h

    #ifndef LIB_H
    #define LIB_H
    extern "C" int __declspec(dllexport) add(int x, int y);
    #endif
    
    
    申明导出函数。

    lib.cpp

    #include "lib.h"
    
    int add(int x, int y)
    {
    	return x + y;
    }
    实现函数,采用默认的__cdecl调用约定。

    编译:

    cl FirstDll.cpp /c
    cl lib.cpp /c

    这里用缺省C运行时库libc.lib,相当于/ML

    链接:

    link FirstDll.obj lib.obj /nodefaultlib kernel32.lib libc.lib /dll

    生成两个文件:FirstDll.lib,FirstDll.dll,前者为后者的导入库

    主函数调用,这里先考虑静态调用方式。

    //Main.cpp
    
    #include <stdio.h>
    #include <stdlib.h>
    extern "C" int add(int , int );
    int main()
    {
        int a, b;
        a = b = 1;
    
        int c = add(a, b);
        printf("%d\n", c);
        system("pause");
    
        return 0;
    }
    

    编译:

    cl Main.cpp /c

    链接:

    link MainD.obj FirstDll.lib /nodefaultlib kernel32.lib libc.lib

    调用成功,屏幕输出2,再考虑动态链接:

    //MainD.cpp
    
    #include <stdio.h>
    #include <stdlib.h>
    #include <windows.h>
    int main()
    {
    	int a, b;
    	a = b = 1;
        HMODULE hMod = LoadLibrary("FirstDll.dll");
        typedef int (*pfunc)(int,int);
        pfunc add = (pfunc)GetProcAddress(hMod, "add");
    	int c = add(a, b);
    	FreeLibrary(hMod);
    	printf("%d\n", c);
    	system("pause");
    
    	return 0;
    }

    可以得到同样的结果,用dumpbin查看FirstDll.dll 中的函数:

    dumpbin FirstDll.dll /exports > info.txt

    可以看到

        ordinal hint RVA      name


              1    0 00001010 add


    也就是说 cdecl 调用约定没有对函数进行重命名。接下去考虑 stdcall 调用约定。

    分别调整lib.h,lib.cpp

    //lib.h
    #ifndef LIB_H
    #define LIB_H
    extern "C" int __declspec(dllexport) __stdcall add(int x, int y);
    #endif
    
    lib.cpp
    #include "lib.h"
    
    int __stdcall add(int x, int y)
    {
    	return x + y;
    }
    
    其中,显示申明为stdcall调用约定。

    编译链接后同样生成lib文件和dll文件。

    调整Main.cpp中的函数申明语句为:

    extern "C" int __stdcall add(int , int );

    编译链接后可以使用,但是用dumpbin查看此时的dll则有

              1    0 00001010 _add@8

    这里显示stdcall以将函数重命名。其中8指的是参数占8个字节。


    那么再考虑动态链接:

    将MainD.cpp中的

        typedef int (*pfunc)(int,int);
    改为

        typedef int (__stdcall *pfunc)(int,int);
    运行时出错,而用"_add@8"函数名调用成功。说明显式调用dll函数在stdcall调用约定时需要额外的步骤。


    这里考虑两种解决方案:

    (1) 使用 link.exe 的 EXPORT 参数;

    (2) 使用 DEF 文件。


    先考虑第一种方案,调整 FirstDll 的链接命令:

    link FirstDll.obj lib.obj /nodefaultlib kernel32.lib libc.lib /dll /export:add=_add@8

    替换掉原先的lib和dll,此时调用GetProcAddress中的函数名为"add" 和 "_add@8" 都可以调用成功。


    再考虑第二种方案,使用DEF文件:

    写一个 t.der 文件:

    LIBRARY "FirstDll"
    EXPORTS
        add @ 1
    此外可以调整lib.h中的导出函数申明:

    int __stdcall add(int x, int y);

    即省略 extern "C" (2013.5.28 批注:静态调用时函数申明也应当省略,并且确保dll的编译器和主调程序的编译器为同一,以确保编译器生成的函数名相同,链接器可以找到外部函数)和 __declspec(dllexport) ,调整FirstDll的链接命令:

    link FirstDll.obj lib.obj /nodefaultlib kernel32.lib libc.lib /dll /def:t.def

    此时GetProcAddress 中 "add" 为有效函数名,调用成功。除此之外,还可以用函数序号调用:

        pfunc add = (pfunc)GetProcAddress(hMod, (LPCSTR)1);

    无论是显式动态加载链接(LoadLibrary , GetProcAddress),还是隐式申明函数、链接导入库FirstDll.lib ,都能使用此DLL文件。


    小结:当导出函数使用stdcall调用约定时,推荐的方案为:定义一个DEF文件,重新命名函数,同时在dll头文件与调用文件中申明应相同,即同时存在或不存在extern "C" 。


    对于 extern "C"

    附:lib.h 中申明,lib.cpp 包含 lib.h ,lib.cpp 无论申明与否都按C语言导出函数名

    lib.h 中不申明,lib.cpp 包含 lib.h ,lib.cpp 申明则编译不通过

    抛开 lib.h ,直接在 lib.cpp 中申明按C语言导出函数名

    除此之外按C++导出函数名


    展开全文
  • dll中文件名都变成add,但不影响导入库lib文件,也就是静态调用动态链接库时,仍要确保 两边 编译器 生成的函数名一样,所以通常推荐两边同时声明 extern "C" ,不然很难确保不同的c++编译器生成相同的函数名,这里...
  • 动态链接库显式调用

    2018-07-12 11:01:29
    动态链接库显式调用
  • 调用动态链接库 1 - 动态链接库导入工具
  • 69.调用动态链接库 1 - 动态链接库导入工具.doc
  • 动态链接库的隐式调用 动态链接库的隐式调用 动态链接库的隐式调用
  • 易语言汇编调用动态链接库源码,汇编调用动态链接库,API,CALL_API,取变量数据地址_
  • 动态链接库的显示调用 动态链接库的显示调用 动态链接库的显示调用 动态链接库的显示调用
  • Python 调用动态链接库

    千次阅读 2018-05-30 22:55:24
    Python 调用动态链接库 ctypes是Python调用c的动态链接库的一个内置模块。 通过 CMake 构建动态链接库 项目结构 ├── CMakeLists.txt # CMake 构建配置文件 ├── library.h # 动态链接库头文件 └── ...
  • 动态链接库的建立与调用 动态链接库的建立与调用
  • Java调用动态链接库 Java 调用 DLL 源码
  • QT生成动态链接库及其调用过程

    千次阅读 2019-06-11 16:13:14
    一、生成动态链接库 1:新建工程,选择Library的C++库选项,如下图: 2:选择库类型 3:选择核心模块(根据自己实际项目决定选择...二、在程序中调用刚生成的动态链接库 现在我们可以在程序里面调用刚生成的...
  • c# 调用动态链接库方法 c#调用dll,包含源码
  • C#调用C++动态链接库

    千次阅读 2018-12-25 18:37:53
    用vc调用动态链接库5. 将静态链接库做成动态链接库新的改变功能快捷键合理的创建标题,有助于目录的生成如何改变文本的样式插入链接与图片如何插入一段漂亮的代码片生成一个适合你的列表创建一个表格设定内容居中、...

空空如也

空空如也

1 2 3 4 5 ... 20
收藏数 246,769
精华内容 98,707
关键字:

动态链接库怎么调用