关于DLL动态库调用
- 格式:doc
- 大小:72.50 KB
- 文档页数:11
python调用dll的例程Python是一种高级编程语言,它可以通过调用动态链接库(DLL)来扩展其功能。
DLL是一种可重用的代码库,它包含在Windows操作系统中,可以被多个应用程序共享。
在本文中,我们将介绍如何使用Python调用DLL的例程。
我们需要了解如何使用Python调用DLL。
Python提供了一个称为ctypes的标准库,它允许我们使用Python调用C函数。
ctypes库提供了一种简单的方法来加载DLL并调用其中的函数。
下面是一个简单的例子:```pythonimport ctypes# Load the DLLmydll = ctypes.WinDLL("mydll.dll")# Call a function in the DLLresult = mydll.myfunction()```在这个例子中,我们首先使用ctypes.WinDLL()函数加载了一个名为“mydll.dll”的DLL。
然后,我们调用了DLL中的一个名为“myfunction”的函数,并将其结果存储在变量“result”中。
接下来,我们将介绍如何编写一个简单的DLL,并使用Python调用其中的函数。
我们将使用C语言编写DLL,并使用Python调用其中的函数。
下面是一个简单的DLL代码:```c#include <stdio.h>__declspec(dllexport) int myfunction(){printf("Hello from myfunction!\n");return 42;}```在这个例子中,我们定义了一个名为“myfunction”的函数,并使用__declspec(dllexport)关键字将其标记为可导出的。
这意味着我们可以在其他应用程序中使用这个函数。
现在,我们可以使用Python调用这个DLL中的函数。
下面是一个简单的Python代码:```pythonimport ctypes# Load the DLLmydll = ctypes.WinDLL("mydll.dll")# Call the function in the DLLresult = mydll.myfunction()# Print the resultprint("Result:", result)```在这个例子中,我们首先使用ctypes.WinDLL()函数加载了一个名为“mydll.dll”的DLL。
JAVA调用SDK动态链接库一、案例简述JA V A作为跨平台语言,开发中难免遇到跨平台调用接口方法,近期在项目定制开发过程中,现场需要JA V A平台通过DLL动态链接库设置DVR设备功能,如设置获取DVR设备白名单功能、开启关闭白名单功能、获取设置DVR设备码流是否加密、设置获取DVR设备的AES码流加密信息(包括加密密码、加密方式、加密瞬间等信息)等功能。
二、案例分析和解决过程初始化DLL动态库需要通过接口实体初始化DLL动态库,详细定义格式如下:public interface HCNetSDK extends StdCallLibrary {public static final String path ="C:\\Tools\\HCNetSDK_v4.1.5.61_20151015_WIN64\\lib\\HCNetSDK";HCNetSDK INSTANCE = (HCNetSDK)Native.loadLibrary(path, HCNetSDK.class);}其中:path为DLL动态库的路径,定义DLL动态库方法中的对象INSTANCE为DLL 动态库初始化的实例动态库方法的对象定义需要实现Structure,并重写Structure中的getFieldOrder方法,详细声明如下:public static class LPNET_DVR_DEVICEINFO_V40 extends Structure {public NET_DVR_DEVICEINFO_V30 struDeviceV30;public byte bySupportLock;public byte byRetryLoginTime;public byte byPasswordLevel;public byte byRes1;public int dwSurplusLockTime;public byte[] byRes2 = new byte[256];@Overrideprotected List getFieldOrder() {return Arrays.asList(new String[] {"struDeviceV30", "bySupportLock","byRetryLoginTime", "byPasswordLevel","byRes1", "dwSurplusLockTime", "byRes2"});}}其中:变量属性中byte[]对字节长度有严格要求,必须长度一致,否则调用时会出现JDK源代码错误。
C#调用C++编写的COM DLL封装库时会出现两个问题:1.数据类型转换问题2.指针或地址参数传送问题首先是数据类型转换问题。
因为C#是.NET语言,利用的是.NET的基本数据类型,所以实际上是将C++的数据类型与.NET的基本数据类型进行对应。
例如C++的原有函数是:int __stdcall FunctionName(unsigned char param1, unsigned short param2) 其中的参数数据类型在C#中,必须转为对应的数据类型。
如:[DllImport(“ COM DLL path/file ”)]extern static int FunctionName(byte param1, ushort param2)因为调用的是__stdcall函数,所以使用了P/Invoke的调用方法。
其中的方法FunctionName必须声明为静态外部函数,即加上extern static声明头。
我们可以看到,在调用的过程中,unsigned char变为了byte,unsigned short变为了ushort。
变换后,参数的数据类型不变,只是声明方式必须改为.NET语言的规范。
我们可以通过下表来进行这种转换:之后再将CLR的数据类型表示方式转换为C#的表示方式。
这样一来,函数的参数类型问题就可以解决了。
现在,我们再来考虑下一个问题,如果要调用的函数参数是指针或是地址变量,怎么办?对于这种情况可以使用C#提供的非安全代码来进行解决,但是,毕竟是非托管代码,垃圾资源处理不好的话对应用程序是很不利的。
所以还是使用C#提供的ref以及out修饰字比较好。
同上面一样,我们也举一个例子:int __stdcall FunctionName(unsigned char ¶m1, unsigned char *param2)在C#中对其进行调用的方法是:[DllImport(“ COM DLL path/file ”)]extern static int FunctionName(ref byte param1, ref byte param2)看到这,可能有人会问,&是取地址,*是传送指针,为何都只用ref就可以了呢?一种可能的解释是ref是一个具有重载特性的修饰符,会自动识别是取地址还是传送指针。
利⽤C#的反射机制动态调⽤DLL类库1、使⽤Assembly类定义和加载程序集,加载在程序集清单中列出模块,以及从此程序集中查找类型并创建该类型的实例。
2、使⽤MethodInfo了解⽅法的名称、返回类型、参数、访问修饰符(如pulic 或private)和实现详细信息(如abstract或virtual)等。
使⽤Type的GetMethods或GetMethod⽅法来调⽤特定的⽅法。
⼀、创建⽤于反射调⽤的DLLusing System;using System.Collections.Generic;using System.Text;namespace RefDll{/// <summary>/// 创建需要被调⽤的DLL类库/// </summary>public class RefTest{/// <summary>/// 求和⽅法/// </summary>/// <param name="x">第⼀个值</param>/// <param name="y">第⼆个值</param>/// <param name="sum">结果(和)</param>public void TestSum(int x,int y,out int sum){sum = 0;sum = x + y;}/// <summary>/// 求和⽅法/// 第⼆种⽅式/// </summary>/// <param name="x">第⼀个值</param>/// <param name="y">第⼆个值</param>/// <returns>结果(和)</returns>public int TestSumTwo(int x, int y){return x + y;}/// <summary>/// 求和⽅法/// 第三种⽅式/// </summary>/// <param name="x">第⼀个值</param>/// <param name="y">第⼆个值</param>/// <param name="sum">结果(和)</param>public static void TestSumThree(int x, int y, out int sum){sum = 0;sum = x + y;}}}⼆、应⽤于反射的例⼦注:可以创建⼀个控制台的⼯程。
C#中如何调用动态链接库DLL动态链接库(也称为DLL,即为“Dynamic Link Library”的缩写)是Microsoft Windows最重要的组成要素之一,打开Windows系统文件夹,你会发现文件夹中有很多DLL 文件,Windows就是将一些主要的系统功能以DLL模块的形式实现。
动态链接库是不能直接执行的,也不能接收消息,它只是一个独立的文件,其中包含能被程序或其它DLL调用来完成一定操作的函数(方法。
注:C#中一般称为“方法”),但这些函数不是执行程序本身的一部分,而是根据进程的需要按需载入,此时才能发挥作用。
DLL只有在应用程序需要时才被系统加载到进程的虚拟空间中,成为调用进程的一部分,此时该DLL也只能被该进程的线程访问,它的句柄可以被调用进程所使用,而调用进程的句柄也可以被该DLL所使用。
在内存中,一个DLL只有一个实例,且它的编制与具体的编程语言和编译器都没有关系,所以可以通过DLL来实现混合语言编程。
DLL函数中的代码所创建的任何对象(包括变量)都归调用它的线程或进程所有。
下面列出了当程序使用 DLL 时提供的一些优点:[1]1) 使用较少的资源当多个程序使用同一个函数库时,DLL 可以减少在磁盘和物理内存中加载的代码的重复量。
这不仅可以大大影响在前台运行的程序,而且可以大大影响其他在 Windows 操作系统上运行的程序。
2) 推广模块式体系结构DLL 有助于促进模块式程序的开发。
这可以帮助您开发要求提供多个语言版本的大型程序或要求具有模块式体系结构的程序。
模块式程序的一个示例是具有多个可以在运行时动态加载的模块的计帐程序。
3) 简化部署和安装当 DLL 中的函数需要更新或修复时,部署和安装 DLL 不要求重新建立程序与该 DLL 的链接。
此外,如果多个程序使用同一个 DLL,那么多个程序都将从该更新或修复中获益。
当您使用定期更新或修复的第三方 DLL 时,此问题可能会更频繁地出现。
Windows下C语⾔调⽤dll动态链接库dll是windows下的动态链接库⽂件,下⾯记录⼀下在windows下如何调⽤C语⾔开发的dll动态链接库。
1.dll动态链接库的源代码hello_dll.c#include "stdio.h"_declspec(dllexport) void test_print(char const *str){printf("%s\n", str);}_declspec(dllexport) int test_add(int a, int b){return a + b;}上⾯的代码定义了两个函数,第⼀个函数需要传⼊⼀个字符串,然后打印出这个字符串,第⼆个函数需要转⼊两个int型整数,然后返回这两个整数的和。
执⾏ cl -LD hello_dll.c 会⽣成hello_dll.dll⽂件2.main函数的源代码test_hello_dll.c#include <stdlib.h>#include <windows.h>int main(int argc, char const *argv[]){// define two functional pointervoid(*p_test_print)(char const *) = NULL;int(*p_test_add)(int, int) = NULL;int add_result;// load dll file, require window.h fileHMODULE module = LoadLibraryA("hello_dll.dll");if (module == NULL) {system("error load");}p_test_print = (void(*)(char const *))GetProcAddress(module, "test_print");p_test_add = (int(*)(int, int))GetProcAddress(module, "test_add");if (p_test_print != NULL) {p_test_print("Hello This is from dll");} else {system("function p_test_print can not excute");}if (p_test_add != NULL) {add_result = p_test_add(5, 5);printf("Add result is %d\n", add_result);} else {system("function p_test_print can not excute");}FreeLibrary(module);system("pause");return0;}执⾏ cl test_hello_dll.c 会⽣成test_hello_dll.exe的可执⾏⽂件。
C++动态与静态调用dll一).静态调用其步骤如下:1.把你的youApp.DLL拷到你目标工程(需调用youApp.DLL的工程)的Debug目录下;2.把你的youApp.lib拷到你目标工程(需调用youApp.DLL的工程)目录下;3.把你的youApp.h(包含输出函数的定义)拷到你目标工程(需调用youApp.DLL的工程)目录下;4.打开你的目标工程选中工程,选择Visual C++的Project主菜单的Settings菜单;5.执行第4步后,VC将会弹出一个对话框,在对话框的多页显示控件中选择Link页。
然后在Object/library modules输入框中输入:youApp.lib6.选择你的目标工程Head Files加入:youApp.h文件;7.最后在你目标工程(*.cpp,需要调用DLL中的函数)中包含你的:#include "youApp.h"注:youApp是你DLL的工程名。
2.动态调用其程序如下:动态调用时只需做静态调用步骤1.{HINSTANCE hDllInst = LoadLibrary("youApp.DLL");if(hDllInst){typedef DWORD (WINAPI *MYFUNC)(DWORD,DWORD);MYFUNC youFuntionNameAlias = NULL; // youFuntionNameAlias 函数别名youFuntionNameAlias = (MYFUNC)GetProcAddress (hDllInst,"youFuntionName");// youFuntionName 在DLL中声明的函数名if(youFuntionNameAlias){youFuntionNameAlias(param1,param2);}FreeLibrary(hDllInst);}}采用动态库技术对于升级软件版本更加容易。
python调⽤dll动态链接库结构体参数及回调函数等⽰例结构体⽰例:这⾥是 C 代码的部分,主要是结构体的声明和回调函数定义。
// 新版本定义typedef enum {DevCard,DevLocator,DevReader} DevType;typedef enum {MsgLocate, // 定位信号MsgCut, // 剪断信号MsgHeartBeat, // ⼼跳信号MsgCall, // 呼叫信号MsgShake, // 震动信号MsgLeave, // 离开信号MsgOffAlarm, // 报警灯关闭信号MsgCheckPower, // 电量检测信号MsgHeartRate, // ⼼率信号MsgExtra, // 补发信号MsgNoPower, // 没电信号MsgReset, // 重置信号MsgBoundary, // 跨界信号// 此消息会跟随着MsgLocate消息出现MsgPower,// 当checkOffline设置为1时有效。
如果在offlineTime时间内没有收到此设备的信号,则发出离线信号MsgOffline,MsgLast} MsgType;// 由于消息类型的不同,不是所有的值都有意义typedef struct {MsgType type;DevType device; // 硬件类型int32_t cardID; // 标签/腕带ID,当DevType为DevCard时有意义int32_t readerID; // 阅读器ID,总是有意义int32_t locatorID; // ⼤于0时有意义,表⽰定位器IDint32_t readerRSSI; // 阅读器信号强度,由于硬件版本的差异,此值要么全有意义,要么全没意义(总是0)int32_t locatorRssiX; // 当MsgType为[MsgLocate, MsgExtra]时,此值有意义,表⽰定位器的信号强度int32_t locatorRssiY; // 定位器的信号强度uint8_t isCut; // 如果此值为1,表⽰硬件被破坏。
C#直接使⽤DllImport调⽤CC++动态库(dll⽂件)1.C/C++动态库的编写下⾯是我编写的⼀个⽐较简单的C++dll⽂件⽤来测试,关于如何编写dll⽂件,我这⾥便不再赘述,不懂得⾃⾏查询,(1).h⽂件#ifdef MYDLL_EXPORTS#define MYDLL_API __declspec(dllexport)#else#define MYDLL_API __declspec(dllimport)#endif//求两个整数的和(普通类型的参数)extern"C" MYDLL_API int GetSum(int nNum1, int nNum2);//获取两个整数中的最⼤值(含有整数类型的指针为参数)extern"C" MYDLL_API int GetMaxValue(int *pValue1, int* pValue2);//获取两个整数中的最⼩值,最⼩值以传出参数获取extern"C" MYDLL_API void GetMinValue(int *pValue1, int* pValue2, int *pMinValue);//带有char[]与char*参数extern"C" MYDLL_API int GetLength(char szName[64], char* szBirth);(2).cpp⽂件//求两个整数的和(普通类型的参数)extern"C" MYDLL_API int GetSum(int nNum1, int nNum2){return (nNum1 + nNum2);}//获取整个整数中的最⼤值extern"C" MYDLL_API int GetMaxValue(int *pValue1, int* pValue2){return (*pValue1 > *pValue2) ? *pValue1 : *pValue2;}//获取两个整数中的最⼩值,最⼩值以传出参数获取extern"C" MYDLL_API void GetMinValue(int *pValue1, int* pValue2, int *pMinValue){if (*pValue1 < *pValue2){*pMinValue = *pValue1;}else{*pMinValue = *pValue2;}}//带有char[]与char*参数extern"C" MYDLL_API int GetLength(char szName[64], char* szBirth){return (strlen(szName) + strlen(szBirth));}2.在C#项⽬中封装上述库⽂件为C#接⼝上述库⽂件编译成功后,需要把它拷贝到C#项⽬的运⾏⽬录下,然后代码中使⽤using System.Runtime.InteropService命名空间即可引⽤如果不想直接拷贝,可在C#项⽬中建⽴⼀个⽂件夹,如名称为Dll,将上述库⽂件拷贝到此⽂件夹,然后打开C#项⽬,点击项⽬->属性->⽣成事件中添加copy "$(SolutionDir)Dll\*.dll" "$(TargetDir)此批处理语句。
关于DLL动态库调用小结引言比较大的应用程序都由很多模块组成,这些模块分别完成相对独立的功能,它们彼此协作来完成整个软件系统的工作。
可能存在一些模块的功能较为通用,在构造其它软件系统时仍会被使用。
在构造软件系统时,如果将所有模块的源代码都静态编译到整个应用程序EXE 文件中,会产生一些问题:一个缺点是增加了应用程序的大小,它会占用更多的磁盘空间,程序运行时也会消耗较大的内存空间,造成系统资源的浪费;另一个缺点是,在编写大的EXE程序时,在每次修改重建时都必须调整编译所有源代码,增加了编译过程的复杂性,也不利于阶段性的单元测试。
Windows系统平台上提供了一种完全不同的较有效的编程和运行环境,你可以将独立的程序模块创建为较小的DLL(Dynamic Linkable Library)文件,并可对它们单独编译和测试。
在运行时,只有当EXE程序确实要调用这些DLL模块的情况下,系统才会将它们装载到内存空间中。
这种方式不仅减少了EXE文件的大小和对内存空间的需求,而且使这些DLL模块可以同时被多个应用程序使用。
Windows自己就将一些主要的系统功能以DLL 模块的形式实现。
一般来说,DLL是一种磁盘文件,以.dll、.DRV、.FON、.SYS和许多以.EXE为扩展名的系统文件都可以是DLL。
它由全局数据、服务函数和资源组成,在运行时被系统加载到进程的虚拟空间中,成为调用进程的一部分。
如果与其它DLL之间没有冲突,该文件通常映射到进程虚拟空间的同一地址上。
DLL模块中包含各种导出函数,用于向外界提供服务。
DLL可以有自己的数据段,但没有自己的堆栈,使用与调用它的应用程序相同的堆栈模式;一个DLL在内存中只有一个实例;DLL实现了代码封装性;DLL的编制与具体的编程语言及编译器无关。
在Win32环境中,每个进程都复制了自己的读/写全局变量。
如果想要与其它进程共享内存,必须使用内存映射文件或者声明一个共享数据段。
DLL模块需要的堆栈内存都是从运行进程的堆栈中分配出来的。
Windows在加载DLL模块时将进程函数调用与DLL文件的导出函数相匹配。
Windows操作系统对DLL的操作仅仅是把DLL映射到需要它的进程的虚拟地址空间里去。
DLL函数中的代码所创建的任何对象(包括变量)都归调用它的线程或进程所有.调用方式1、静态调用方式(隐式调用):由编译系统完成对DLL的加载和应用程序结束时DLL 卸载的编码(如还有其它程序使用该DLL,则Windows对DLL的应用记录减1,直到所有相关程序都结束对该DLL的使用时才释放它),简单实用,但不够灵活,只能满足一般要求。
隐式的调用:需要把产生动态连接库时产生的.LIB文件加入到应用程序的工程中,想使用DLL中的函数时,只须说明一下。
隐式调用不需要调用LoadLibrary()和FreeLibrary()。
程序员在建立一个DLL文件时,链接程序会自动生成一个与之对应的LIB导入文件。
该文件包含了每一个DLL导出函数的符号名和可选的标识号,但是并不含有实际的代码。
LIB 文件作为DLL的替代文件被编译到应用程序项目中。
当程序员通过静态链接方式编译生成应用程序时,应用程序中的调用函数与LIB文件中导出符号相匹配,这些符号或标识号进入到生成的EXE文件中。
LIB文件中也包含了对应的DLL文件名(但不是完全的路径名),链接程序将其存储在EXE文件内部。
当应用程序运行过程中需要加载DLL文件时,Windows根据这些信息发现并加载DLL,然后通过符号名或标识号实现对DLL函数的动态链接。
所有被应用程序调用的DLL文件都会在应用程序EXE文件加载时被加载在到内存中。
可执行程序链接到一个包含DLL输出函数信息的输入库文件(.LIB文件)。
操作系统在加载使用可执行程序时加载DLL。
可执行程序直接通过函数名调用DLL的输出函数,调用方法和程序内部其他的函数是一样的。
2、动态调用方式(显式调用):是由编程者用API函数加载和卸载DLL来达到调用DLL的目的,使用上较复杂,但能更加有效地使用内存,是编制大型应用程序时的重要方式。
显式的调用:是指在应用程序中用LoadLibrary或MFC提供的AfxLoadLibrary显式的将自己所做的动态连接库调进来,动态连接库的文件名即是上面两个函数的参数,再用GetProcAddress()获取想要引入的函数。
自此,你就可以象使用如同本应用程序自定义的函数一样来调用此引入函数了。
在应用程序退出之前,应该用FreeLibrary或MFC提供的AfxFreeLibrary释放动态连接库。
直接调用Win32 的LoadLibary函数,并指定DLL的路径作为参数。
LoadLibary返回HINSTANCE参数,应用程序在调用GetProcAddress 函数时使用这一参数。
GetProcAddress函数将符号名或标识号转换为DLL内部的地址。
程序员可以决定DLL文件何时加载或不加载,显式链接在运行时决定加载哪个DLL文件。
使用DLL的程序在使用之前必须加载(LoadLibrary)加载DLL从而得到一个DLL模块的句柄,然后调用GetProcAddress函数得到输出函数的指针,在退出之前必须卸载DLL(FreeLibrary)。
Windows将遵循下面的搜索顺序来定位DLL:1.包含EXE文件的目录2.进程的当前工作目录3.Windows系统目录4.Windows目录5.列在Path环境变量中的一系列目录MFC中的DLLa、Non-MFC DLL:指的是不用MFC的类库结构,直接用C语言写的DLL,其输出的函数一般用的是标准C接口,并能被非MFC或MFC编写的应用程序所调用。
b、Regular DLL:和下述的Extension DLLs一样,是用MFC类库编写的。
明显的特点是在源文件里有一个继承CWinApp的类。
其又可细分成静态连接到MFC和动态连接到MFC上的。
静态连接到MFC的动态连接库只被VC的专业般和企业版所支持。
该类DLL应用程序里头的输出函数可以被任意Win32程序使用,包括使用MFC的应用程序。
输入函数有如下形式:extern "C" EXPORT YourExportedFunction( );如果没有extern "C"修饰,输出函数仅仅能从C++代码中调用。
DLL应用程序从CWinApp派生,但没有消息循环。
动态链接到MFC的规则DLL应用程序里头的输出函数可以被任意Win32程序使用,包括使用MFC的应用程序。
但是,所有从DLL输出的函数应该以如下语句开始:AFX_MANAGE_STATE(AfxGetStaticModuleState( ))此语句用来正确地切换MFC模块状态。
Regular DLL能够被所有支持DLL技术的语言所编写的应用程序所调用。
在这种动态连接库中,它必须有一个从CWinApp继承下来的类,DLLMain函数被MFC所提供,不用自己显式的写出来。
c、Extension DLL:用来实现从MFC所继承下来的类的重新利用,也就是说,用这种类型的动态连接库,可以用来输出一个从MFC所继承下来的类。
它输出的函数仅可以被使用MFC且动态链接到MFC的应用程序使用。
可以从MFC继承你所想要的、更适于你自己用的类,并把它提供给你的应用程序。
你也可随意的给你的应用程序提供MFC或MFC继承类的对象指针。
Extension DLL使用MFC的动态连接版本所创建的,并且它只被用MFC 类库所编写的应用程序所调用。
Extension DLLs 和Regular DLLs不一样,它没有一个从CWinApp继承而来的类的对象,所以,你必须为自己DLLMain函数添加初始化代码和结束代码。
和规则DLL相比,有以下不同:1、它没有一个从CWinApp派生的对象;2、它必须有一个DLLMain函数;3、DLLMain调用AfxInitExtensionModule函数,必须检查该函数的返回值,如果返回0,DLLMmain也返回0;4、如果它希望输出CRuntimeClass类型的对象或者资源(Resources),则需要提供一个初始化函数来创建一个CDynLinkLibrary对象。
并且,有必要把初始化函数输出;5、使用扩展DLL的MFC应用程序必须有一个从CWinApp派生的类,而且,一般在InitInstance里调用扩展DLL的初始化函数。
DLL入口函数1、每一个DLL必须有一个入口点,DLLMain是一个缺省的入口函数。
DLLMain负责初始化(Initialization)和结束(Termination)工作,每当一个新的进程或者该进程的新的线程访问DLL时,或者访问DLL的每一个进程或者线程不再使用DLL或者结束时,都会调用DLLMain。
但是,使用TerminateProcess或TerminateThread结束进程或者线程,不会调用DLLMain。
DLLMain的函数原型:BOOL APIENTRY DLLMain(HANDLE hModule,DWORDul_reason_for_call,LPVOIDlpReserved){switch(ul_reason_for_call){case DLL_PROCESS_ATTACH:.......case DLL_THREAD_ATTACH:.......case DLL_THREAD_DETACH:.......case DLL_PROCESS_DETACH:.......return TRUE;}}参数:hMoudle:是动态库被调用时所传递来的一个指向自己的句柄(实际上,它是指向_DGROUP段的一个选择符);ul_reason_for_call:是一个说明动态库被调原因的标志。
当进程或线程装入或卸载动态连接库的时候,操作系统调用入口函数,并说明动态连接库被调用的原因。
它所有的可能值为:DLL_PROCESS_ATTACH: 进程被调用;DLL_THREAD_ATTACH: 线程被调用;DLL_PROCESS_DETACH: 进程被停止;DLL_THREAD_DETACH: 线程被停止;lpReserved:是一个被系统所保留的参数。
2、_DLLMainCRTStartup为了使用"C"运行库(CRT,C Run time Library)的DLL版本(多线程),一个DLL 应用程序必须指定_DLLMainCRTStartup为入口函数,DLL的初始化函数必须是DLLMain。
_DLLMainCRTStartup完成以下任务:当进程或线程捆绑(Attach)到DLL时为"C"运行时的数据(C Runtime Data)分配空间和初始化并且构造全局"C++"对象,当进程或者线程终止使用DLL(Detach)时,清理C Runtime Data并且销毁全局"C++"对象。