VC++2008 用空工程创建 DLL

时间:2022-08-26 07:52:45

VC++2008 用空工程创建 DLL

一、创建 DLL 工程项目:
 1)点击菜单[File] -> [New] -> [Project...] 弹出 “New Project” 对话框;
 2)在左侧 [Project types:] 树形框中展开 [Visual C++] 选择 [Win32];
 3)在右侧 [Templates:] 视图框中选择 [Win32 Project];
 4)在 [Name:] 对应的文本框中填写好项目名称;
 5)在 [Location:] 对应的文本框中选好项目位置;
 6)点击 [OK] 按钮,弹出 “Win32 Application Wizard - 你起的项目名称” 对话框;
 7)点击左侧的 [Application Settings] 或 点击 [Next >] 进入 “Application Settings” 选项页;
 8)在 [Application type:] 中选择 “DLL”;
 9)在 [Additional options:] 中选择 “Empty project”;
10)最后点击 [Finish] 按钮。

二、编写 DLL 导出函数头文件(exampledll.h):
#ifdef DLL_EXPORTS
#define DLL_API_INT _declspec(dllexport) int __stdcall
#else
#define DLL_API_INT _declspec(dllimport) int __stdcall
#endif

#ifdef __cplusplus
// extern "C" 是 C++ 的关键字
extern "C"
{
#endif

DLL_API_INT sum( int a, int b );
DLL_API_INT sub( int a, int b );

#ifdef __cplusplus
}
#endif

注:
1. __declspec(dllexport) 声明函数为 DLL 的导出函数,
   它就是为了省掉在 *.def 文件中手工定义导出哪些函数的一个方法,
   如果你的 DLL 里全是 C++ 的类的话,你无法在 *.def 里指定导出的函数,
   只能用 __declspec(dllexport) 导出类;

; 举例 exampledll.def 文件内容
LIBRARY exampledll
EXPORTS
sum @ 1
sub @ 2
var DATA

.def文件的规则为:
注:需要在工程属性中指定该*.def文件,位置:
[Configuration Properties] -> [Linker] -> [Input] -> "Module Definition File"
不用 *.def 文件导出函数的话,函数名将是按编译器的命名规则导出。

1)LIBRARY 关键字后跟该 def 文件对应的 DLL 工程名;
2)EXPORTS 关键字独占一行,下面每行列出要导出函数或变量的名称;
  可以在要导出的函数名后加 @ 数字,即为要导出函数排序,在动态加载导出函数时,此序号有用;
  若要导出某全局变量,要有如下格式:
  变量名 CONSTANT <-- 过时的方法,变量名后跟 CONSTANT 关键字
  或
  变量名 DATA   <-- VC++提示的新方法,变量名后跟 DATA 关键字
  注意:
  用 extern 声明导入的并不是 DLL 中全局变量本身,而是其地址,
  应用程序必须先通过类型强制转换指针,再间接取/赋值来使用 DLL 中的全局变量,如:
  extern int var;
  *(int*)var = 1;
  通过 _declspec(dllimport) 方式导入的就是DLL中全局变量本身而不再是其地址了,
  建议尽可能的情使用这种方式,如:
  extern int _declspec(dllimport) var;
  var = 1;
3)分号(;) 为行注释符且注释不能与语句共享一行,要独占一行,以分号开头。

2. __declspec(dllimport) 声明函数为 DLL 的导入函数,
   不使用 __declspec(dllimport) 也能正确编译代码,
   但使用 __declspec(dllimport) 使编译器可以生成更好的代码,
   编译器之所以能够生成更好的代码,是因为它可以确定函数是否存在于 DLL 中,
   这使得编译器可以生成跳过间接寻址级别的代码,而这些代码通常会出现在跨 DLL 边界的函数调用中。
   但是必须使用 __declspec(dllimport) 才能导入 DLL 中使用的变量,
   原来 __declspec(dllimport) 是为了更好的处理类中的静态成员变量的,
   如果没有静态成员变量,那么这个 __declspec(dllimport) 无所谓;

3. 函数的调用方式更改:
   方法一:
   1)右击 "Solution Explorer" 中的项目名;
   2)选择 "Properties";
   3)在弹出的对话框左侧树形框中选择 [Configuration Properties] -> [C/C++] -> [Advanced];
   4)在弹出的对话框右侧栅栏框中修改 "Calling Convention" 项对应值。
   方法二:
   microsoft 的 VC 默认的是 __cdecl 方式,而 windows API 则是 __stdcall ,
   如果用 VC 开发 dll 给其他语言用,则应该指定 __stdcall 方式。
   如果是 __cdecl   方式的函数,则函数本身则不需要关心保存参数的堆栈的清除,
   如果是 __stdcall 方式的函数,则一定要在函数退出前恢复堆栈。

1)__cdecl 所谓的 C 调用规则。按从右至左的顺序压参数入栈,由调用者把参数弹出栈。
     切记:对于传送参数的内存栈是由调用者来维护的。
        返回值在 EAX 中因此,对于象 printf 这样变参数的函数必须用这种规则。
        编译器在编译的时候对这种调用规则的函数生成修饰名的时候,
        仅在输出函数名前加上一个下划线前缀,格式为 _functionname 。

2)__stdcall 按从右至左的顺序压参数入栈,由被调用者把参数弹出栈。
     __stdcall 是 Pascal 程序的缺省调用方式,
     通常用于 Win32 Api 中,切记:函数自己在退出时清空堆栈,返回值在EAX中。
     __stdcall 调用约定在输出函数名前加上一个下划线前缀,后面加上一个 @ 符号和其参数的字节数,
     格式为 _functionname@number 。
     如函数 int func(int a, double b) 的修饰名是 _func@12 。

3)__fastcall 调用的主要特点就是快,
     因为它是通过寄存器来传送参数的,
     实际上,它用 ECX 和 EDX 传送前两个双字(DWORD)或更小的参数,
     剩下的参数仍旧自右向左压栈传送,被调用的函数在返回前清理传送参数的内存栈。
     __fastcall 调用约定在输出函数名前加上一个 @ 符号,后面也是一个 @ 符号和其参数的字节数,
     格式为 @functionname@number 。
     这个和 __stdcall 很象,唯一差别就是头两个参数通过寄存器传送。
     注意通过寄存器传送的两个参数是从左向右的,即第一个参数进ECX,第2个进EDX,
     其他参数是从右向左的入栈。返回仍然通过EAX。

4)__pascal 这种规则从左向右传递参数,通过 EAX 返回,堆栈由被调用者清除。

5)__thiscall 仅仅应用于 C++ 成员函数。
     this 指针存放于 CX 寄存器,参数从右到左压。thiscall不是关键词,因此不能被程序员指定。

修饰符的书写顺序如下:
   extern "C" _declspec(dllexport) int __stdcall sum(int a, int b);
   typedef int (__cdecl *FunPointer)(int a, int b);

4.如果要对编译器提示使用 C 的方式来处理函数的话,那么就要使用 extern "C" 来说明。

三、编写 DLL 导出函数实现文件(exampledll.c):
#ifndef DLL_EXPORTS
#define DLL_EXPORTS
#endif

#include "windows.h"  
#include "exampledll.h"

#pragma comment(linker,"/section:shared,rws")  
#pragma data_seg("shared")
int var = 0;  
#pragma data_seg()

extern "C" BOOL __stdcall 
DllMain( HINSTANCE hInstance, 
         DWORD     dwReason, 
         LPVOID    lpReserved)
{  
    switch( dwReason )
    {
        case DLL_PROCESS_ATTACH:
            return TRUE;
        case DLL_PROCESS_DETACH:
            return TRUE;
        case DLL_THREAD_ATTACH:
            return TRUE;
        case DLL_THREAD_DETACH:
            return TRUE;
        default:
            return TRUE;
    }
}

DLL_API_INT sum( int a, int b )
{
    return a + b;
}

DLL_API_INT sub( int a, int b )
{
    return a - b;
}

四、编译生成 DLL 即可!

 

VC++2008 用空工程创建 DLL的更多相关文章

  1. 在VC&plus;&plus;空工程中使用MFC类,采用Unicode字符集后,运行工程程序报错的解决方案

    创建一个VC++空工程,将Project Properties->General->Use of MFC改为Use MFC in a Shared DLL 新建一个源文件,内容如下 #in ...

  2. DCMTK354之VC&plus;&plus; 2008 MFC应用程序配置完整过程

    花了一个礼拜,终于在VC++2008 MFC 应用程序中完成了首个基于DCMTK354的首个程序ECHOSCUWIN32,现将过程记录下来,便于日后查阅,同时也提供给那些有幸看到此博文而对他们又有帮助 ...

  3. VC 2008 Express下安装OpenCV2&period;3&period;1

    VC 2008 Express下安装OpenCV2.3.1   注意: 下列文档以VC2008 Express为例,VC2010下的配置应与本文档类似. VC 6.0不被OpenCV 2.3.1支持. ...

  4. windows编程&colon;创建DLL

    创建DLL Dll是动态链接库的缩写,可以作为附加代码动态映射到进程的地址空间中. 动态库的一般创建方法如下 方法1.使用 __declspec(dllexport)  方式导出 一般的框架如下 // ...

  5. VS2010环境下用ANSI C创建DLL和使用方法(转)

    源:VS2010环境下用ANSI C创建DLL和使用方法 . 创建DLL工程 1.2 创建一个dll工程. 操作:a.文件->新建->项目->Win32控制台应用程序. b.输入工程 ...

  6. Android开发之基于AndroidStudio环境搭建和工程创建

    断断续续的学习安卓也有一段时间了.因为之前是搞iOS开发的, 之前有关iOS的博客请看<我的iOS开发系列博文>.<我的Objective-C系列文章>和<窥探Swift ...

  7. 创建dll教程

    先看我的总结: 总结: 1.头文件中如果想以C形式提供,要判断,如果定义了 _cplusplus, extern "c"{  这里写接口声明 } 2.接口声明中,要表明接口接入点的 ...

  8. 在VS2015中用C&plus;&plus;创建DLL并用C&num;调用且同时实现对DLL的调试

    from:http://m.blog.csdn.net/article/details?id=51075023 在VS2015中先创建C#项目,然后再创建要编写的动态库DLL项目,这样做的好处是整个解 ...

  9. 利用C&plus;&plus;创建DLL并C&num;调用

    日期:2018年11月26日 环境:window 10,VS2015 community 一.利用C++创建DLL 1.新建项目: 2.打开CreateDLL.cpp文件,并输入测试代码 #inclu ...

随机推荐

  1. DependencyResolver&period;Current

    描述: 获取依赖关系解析程序的实现. 命名空间: System.Web.Mvc 程序集: System.Web.Mvc(在 System.Web.Mvc.dll 中) 用例: IRecLockServ ...

  2. rsync同步

    本地同步: rsync -avz /boot /test C/S架构: 远程同步:rsync+ssh 远程浏览器目录文件:rsync  用户@192.168.0.250:/boot 下行:rsync ...

  3. Javascript&period;ReactNative-2-javascript-syntax-in-react-native

    JavaScript Syntax in React Native Contents: Arrow Function Let+Const Default + Rest + Spread Destruc ...

  4. Python搜索目录下指定的文件&comma;并返回绝对路径&lpar;包括子目录&rpar;

    #!/usr/bin/python #coding=UTF-8 #FileName:search.py #文件搜索 import os; import sys; returnList = []; de ...

  5. Github开源编辑器Atom

    Atom是Github社区开发的一款开源编辑器,很有sublime text特色,相当于开源的sublime text. sublime text用了很长时间了,为什么会重新学习使用另外一款编辑器呢? ...

  6. 单击事件的处理方式及注册窗体的创建之(四)Intent实现界面跳转传值

    跳转开发步骤: 创建Intent对象  设置Intent对象的跳转路径  启动Intent //Register_Activity.java case R.id.btnRegister: Inte ...

  7. CentOS7 Redis安装

    Redis介绍 1.安装Redis 官方下载地址:http://download.redis.io 使用Linux下载:wget http://download.redis.io/redis-stab ...

  8. JVM的内存区域模型

    首先要明白一个概念,就是JVM的内存区域划分与java的内存区域模型是两个不同的概念,前者指的是在java中jvm会将一个程序划分为哪些块来存储对应的数据,后者是一个更宏观上的j概念,指的是java线 ...

  9. Ubuntu16&period;04搭建OpenVPN

    Ubuntu16.04搭建OpenVPN 2018年12月27日 15:50:59 VinQin 阅读数:21042   简介 如果在一个非信任网络下比如旅社或者咖啡店的WiFi网络下,想要通过你的智 ...

  10. 【练习】Python第四次:实现对文件的增删改查

    一,实现对文件的增删改查 (一),三级菜单的处理结构及退出技巧:使用TAG标记 tag=True while tag: print('leve1') choice=input("level1 ...