c ++ dll created with calls


Benefits presumably Needless to say, the so-called black box reuse, modular source code while avoiding exposure and so on. You can make a generic function blocks for easy reuse, and update software update If only a few modules, dll can be replaced without the need of a complete update, easy to program expansion. The following tutorial is based on VS2015, similar to the other versions. Article reference links

1.dll creation

  1. Create a project. In the win32 vs new application, given an arbitrary name, such as MyDll, overview click Next, application settings of the application type selection DLL (D), is completed.

  2. Add the header file. In the Project - Add New Item - ** Visaul C ++ ** Select the header file, set the file name as MyDll.h.

  3. Add the following code in the header file:

    #ifdef MYDLL_EXPORTS
    #define MYDLL_API __declspec(dllexport)//注意decl前面是两个下划线
    #else
    #define MYDLL_API __declspec(dllimport)
    #endif
    
    namespace MyDllSpace
    {
    	//导出类
    	class MyDllClass
    	{
    	private:
    		double a;
    	public:
    		//导出的函数
    		MYDLL_API MyDllClass();
    		MYDLL_API MyDllClass(double a_);
    		MYDLL_API double multiply(double b);
    		MYDLL_API void display();
    		MYDLL_API static void conbine(MyDllClass m1, MyDllClass m2);
    	};
    }
    

    Note: Because this header file can be included dll source file, also includes the use of party, so at the beginning of the use of conditional compilation - when dll file that contains the source (#ifdef MYDLL_EXPORTS, because the generated DLL project defaults vs defines DLL名称_EXPORTSthis macro), to add the former exported function __declspec(dllexport)macros; if the consumer is included, before export function to increase __declspec(dllimport)the macro

  4. Add the following code in the source file:

    #include "MyDll.h"
    #include <iostream>
    
    MyDllSpace::MyDllClass::MyDllClass()
    {
    	a = 0;
    }
    
    MyDllSpace::MyDllClass::MyDllClass(double a_)
    {
    	a = a_;
    }
    
    MYDLL_API double MyDllSpace::MyDllClass::multiply(double b)
    {
    	return a*b;
    }
    
    MYDLL_API void MyDllSpace::MyDllClass::display()
    {
    	std::cout << "a=" << a << std::endl;
    }
    
    MYDLL_API void MyDllSpace::MyDllClass::conbine(MyDllClass m1, MyDllClass m2)
    {
    	std::cout << "(" << m1.a << "," << m2.a << ")" << std::endl;
    }
    

    Note: The function here is through the header file for the function fast operation defined automatically generated in the source file (of course, the function body still have to write), their code words may be used namespaces MyDllSpace these definitions enclose, so do not always in namespaces are defined by a space which is defined function

  5. Click on the menu bar of generation - generation solutions that create dll completed in the Debug directory of your project can see the generated dll and lib files.

2.dll use

  1. Click File - New - Project , choose win32 console application, set an arbitrary name, such as UseMyDll, determine the next step in the application settings in the additional options in the precompiled header checkbox to remove selected to complete.

  2. Copy the previous step generated dll, lib, .h header file to your project directory, in the Solution Explorer to add an existing item to join the project.

  3. Add the following code UseMyDll.cpp file:

    #include <iostream>
    #include "MyDll.h"//加入模块的头文件
    
    using namespace std;
    
    int main()
    {
    	double a = 8;
    	MyDllSpace::MyDllClass c(4);//创建模块里的类实例
    	MyDllSpace::MyDllClass c2;
    	c.display();//使用实例方法
    	cout << "8*4=" << c.multiply(a) << endl;
    	MyDllSpace::MyDllClass::conbine(c, c2);//使用模块里的类的静态方法
    	system("pause");//暂停以便能看到输出
        return 0;
    }
    

    Output is as follows:
    Here Insert Picture Description

note:

  1. If you choose to project when the new project is added to the solution , that is, in the new program under the dll solution, you can add a reference to the dll - Direct Solution Explorer, right-click in the references, add a reference, dll will add previously created reference (this is the official tutorial in usage) - without the dll into the current folder and added to the project. But because we assume that the more general case, reuse of the code have to ask in their own project is not realistic.
  2. Header files must not be added to the current project, for convenience only found. Also in the project - property - C / C ++ - General add the directory where the file header contains additional directories under, and even can head files in the system directory contains, can be found as long as you can include the header file. In addition .lib file is not essential to the project, the .lib can also add the folder to the library catalog, and then add the .lib file as an additional dependency.

3. Use only the DLL (explicit links)

The above method to use to write their own dll, but only if others give a dll does not contain any other information about how to use? Step 1 is a DLL is called implicit link (call), there is a further explicit links, no header file and the lib. Explicit links can always be loaded during program execution DLL can also uninstall at any time, more flexibility, suitable for an interpreted language, of course, also use some more trouble. VS provides a dumpbin.exe program in VC \ bin directory to see the structure function DLL file. Reference links .

  1. As in step 1 to create a dll project

    Header code as follows:

    //FuncOnlyDll.h
    #ifdef FUNCONLYDLL_EXPORTS
    #define FUNCONLYDLL_API __declspec(dllexport)
    #else
    #define FUNCONLYDLL_API __declspec(dllimport)
    #endif
    
    namespace Funcs
    {
    	FUNCONLYDLL_API double minValue(double a, double b);
    	FUNCONLYDLL_API double maxValue(double a, double b);
    	FUNCONLYDLL_API double add(double a, double b);
    	FUNCONLYDLL_API double subtract(double a, double b);
    }
    

    Source code is as follows:

    //FuncOnlyDll.cpp
    #include "FuncOnlyDll.h"
    
    FUNCONLYDLL_API double Funcs::minValue(double a, double b)
    {
    	return a < b ? a : b;
    }
    
    FUNCONLYDLL_API double Funcs::maxValue(double a, double b)
    {
    	return a > b ? a : b;
    }
    
    FUNCONLYDLL_API double Funcs::add(double a, double b)
    {
    	return a + b;
    }
    
    FUNCONLYDLL_API double Funcs::subtract(double a, double b)
    {
    	return a - b;
    }
    

    Click on the menu bar generation - generation solutions , open project directory folder where the dll files generated using dumpbin.exe view the dll function in the structure, as shown below:
    Here Insert Picture Description

    可以看到有四个函数,但是显示的就像乱码,顶多只能看出每个函数叫啥,这样对于使用的用户来说是不友好的,因为看一堆乱码是无法知道这些函数是干啥的,有哪些参数和返回值,这样是无法使用的,我们可以在菜单栏项目-添加新项-Visaul C++-代码选择模块定义文件(.def),设置文件名,在添加的def文件中给出如下代码:

    LIBRARY
    EXPORTS
    double_add_double_double=?add@Funcs@@YANNN@Z
    double_maxValue_double_double=?maxValue@Funcs@@YANNN@Z
    double_minValue_double_double=?minValue@Funcs@@YANNN@Z
    double_subtract_double_double=?subtract@Funcs@@YANNN@Z
    

    其中后面的乱码对应之前dump出来的dll函数名乱码,写这个def文件相当于把乱码重新定义名字,让它更好识别,这里我定义的规则是返回类型_函数名_参数列表类型,当然你可以定义自己的规则,这样使用者一看就知道这个函数干啥的,有啥参数和返回值,再dump一下dll看看:

Here Insert Picture Description

发现后面四个函数输出了我们想要的结果,但是前面仍然有四个乱码函数(其实是同样四个函数),可以将头文件中的*#define FUNCONLYDLL_API __declspec(dllexport)改成#define FUNCONLYDLL_API*这样就不会输出前面的乱码(但是这样会使得dll使用隐式链接出错):

Here Insert Picture Description

至此,dll创建完毕。

  1. 新建一个项目使用创建的dll

    显式链接是不用配置项目属性的,直接将dll文件放在项目目录下,或是其他能查找到的目录比如系统path路径之类的,代码如下:

    #include <iostream>
    //为了使用LoadLibrary和FreeLibrary等函数以及LPCWSTR和LPCSTR类型加入的头文件
    #include <Windows.h>
    using namespace std;
    //定义要加载的各种函数指针,通过dumpbin查看dll函数中函数签名从而得知,或者查看API
    typedef double(*pMin)(double, double);
    typedef double(*pMax)(double, double);
    typedef double(*pAdd)(double, double);
    typedef double(*pSub)(double, double);
    int main()
    {
    	LPCWSTR dllName = TEXT("FuncOnlyDll.dll");
    	LPCSTR funName1 = "double_minValue_double_double";
    	LPCSTR funName2 = "double_maxValue_double_double";
    	LPCSTR funName3 = "double_add_double_double";
    	LPCSTR funName4 = "double_subtract_double_double";
    	HMODULE hDll = LoadLibrary(dllName);//加载dll
    	if (hDll != NULL) {
    		pMin fp1 = (pMin)(GetProcAddress(hDll, funName1));//加载函数
    		if (fp1 != NULL) {
    			cout << "min value of 5 and 6:" << fp1(5, 6) << endl;
    		}
    		else {
    			cout << "函数min加载失败" << endl;
    		}
    		pMax fp2 = (pMax)(GetProcAddress(hDll, funName2));
    		if (fp2 != NULL) {
    			cout << "max value of 5 and 6:" << fp2(5, 6) << endl;
    		}
    		else {
    			cout << "函数max加载失败" << endl;
    		}
    		pAdd fp3 = (pAdd)(GetProcAddress(hDll, funName3));
    		if (fp3 != NULL) {
    			cout << "sum value of 5 and 6:" << fp3(5, 6) << endl;
    		}
    		else {
    			cout << "函数add加载失败" << endl;
    		}
    		pSub fp4 = (pSub)(GetProcAddress(hDll, funName4));
    		if (fp2 != NULL) {
    			cout << "difference of 5 and 6:" << fp4(5, 6) << endl;
    		}
    		else {
    			cout << "函数sub加载失败" << endl;
    		}
    		FreeLibrary(hDll);//卸载dll,一般用完就卸载,避免占用内存
    	}
    	else {
    		cout << "加载dll文件失败" << endl;
    	}
    	system("pause");
        return 0;
    }
    

    从上述使用方法可以看出,因为我们之前创建dll文件的时候贴心地把导出的函数名设置了下,才可以在dumpbin中查看到比较有意义的函数名信息,所以如果第三方给的dll没有这么做,那么你就根据dump出来的函数名乱码猜吧,祝你好运。

  2. 显式链接的不足

    Obviously, if dll not only gave to the interface (API header files or corresponding document), and dump out the function name is garbled, it is not reuse the dll. In addition dll explicit link is not supported export classes and variables, at least no one is recommended.


4. A little advice

After reading various online tutorial is highly recommended that if dll reuse, then we must use .h, .lib, .dll three-piece, that is an implicit link method

Not so that any other solution, because the dll file structure hidden function, do not know the structure function is not used

Even if only to ascertain something that looks like gibberish function name by dumbin.exe, is unable to understand the specific function of doing

Unless already know the interface, such as implicit linking, use the dll source code corresponding to the first document, apparently a way to expose the interface

Published 28 original articles · won praise 14 · views 20000 +

Guess you like

Origin blog.csdn.net/liyunxin_c_language/article/details/83210788