精华内容
下载资源
问答
  • DLL动态库多次加载问题

    千次阅读 2019-09-29 22:54:05
    原因涉及DLL加载和运行机制,主要有两点:1)DLL动态链接库无法独立运行,必须由...第1次调用DLL或第1次加载DLL时,宿主进程将DLL引入进程空间。一旦宿主进程成功加载DLL,随后的重复调用或重复加载只会增加“引用计...

    原因涉及DLL加载和运行机制,主要有两点:
    1)DLL动态链接库无法独立运行,必须由一个应用程序进程加载到进程空间后才能使用。加载DLL的进程称为宿主进程。被加载的DLL属于宿主进程,不属于宿主进程内某个线程。
    2)宿主进程可以重复调用,甚至重复加载DLL。第1次调用DLL或第1次加载DLL时,宿主进程将DLL引入进程空间。一旦宿主进程成功加载DLL,随后的重复调用或重复加载只会增加“引用计数”,而不会加载多份DLL,所以进程中只有一份DLL。

    所以全局变量可能会引起多线程同步问题。

    转载于:https://www.cnblogs.com/2018shawn/p/10305302.html

    展开全文
  • 在同个应用程序中不关闭程序实现动态加载同个DLL多次,且DLL内容有更新,程序不会认为是同个DLL 最近做个项目,需要挂载DLL,在DLL更新后不能立刻关闭旧的DLL,因为DLL是一系列的WCF服务。在这种情况下就需要实现...

    在同个应用程序中不关闭程序实现动态加载同个DLL多次,且DLL内容有更新,程序不会认为是同个DLL

    最近做个项目,需要挂载DLL,在DLL更新后不能立刻关闭旧的DLL,因为DLL是一系列的WCF服务。在这种情况下就需要实现动态挂载和卸载DLL,但是一个应用程序在不关闭的情况下只能加载同个DLL一次。

    入正题:

    private void GetSevList(string dllPath, string sevUri)
    {
      //创建程序域
      AppDomainSetup setup = new AppDomainSetup();   ProxyObject po = new ProxyObject();   setup.LoaderOptimization = LoaderOptimization.SingleDomain;   setup.ApplicationName = "Test";   setup.ApplicationBase = AppDomain.CurrentDomain.BaseDirectory;   setup.PrivateBinPath = Path.Combine(AppDomain.CurrentDomain.BaseDirectory, "private");   setup.CachePath = setup.ApplicationBase;   setup.ShadowCopyFiles = "true";   setup.ShadowCopyDirectories = setup.ApplicationBase;
      //使用指定的名称、证据和应用程序域设置信息创建新的应用程序域。(sevUri 是一个文本值 不重复)   AppDomain domain = AppDomain.CreateDomain(sevUri.Split('/')[sevUri.Split('/').Length - 1], null, setup);
      string name = Assembly.GetExecutingAssembly().GetName().FullName;
      //加载DLL(这个就是需要多次加载的那个DLL)   Assembly MyAssembly = po.LoadAssembly(dllPath);   po = (ProxyObject)domain.CreateInstanceAndUnwrap(name, typeof(ProxyObject).FullName);
      
      
      Assembly[] abs = AppDomain.CurrentDomain.GetAssemblies();
    }

    class ProxyObject : MarshalByRefObject
    {
      Assembly assembly = null;
      public Assembly LoadAssembly(string dllPath)
      {
        assembly = Assembly.LoadFile(dllPath);
        return assembly;
      }
     
      public string FullName
      {
        get { return assembly.FullName; }
      }   
    }
    ------------付截图--------------


    转载说明出处

    转载于:https://www.cnblogs.com/weivyuan/archive/2012/10/25/2738919.html

    展开全文
  • Windows加载DLL

    千次阅读 2016-09-28 09:34:02
    Windows系统平台上,你可以将独立的程序模块创建为较小的DLL(Dynamic ...这种方式不仅减少了EXE文件的大小和对内存空间的需求,而且使这些DLL模块可以同时被个应用程序使用。Microsoft Windows自己就将一些主

     Windows系统平台上,你可以将独立的程序模块创建为较小的DLL(Dynamic Linkable Library)文件,并可对它们单独编译和测试。在运行时,只有当EXE程序确实要调用这些DLL模块的情况下,系统才会将它们装载到内存空间中。这种方式不仅减少了EXE文件的大小和对内存空间的需求,而且使这些DLL模块可以同时被多个应用程序使用。Microsoft Windows自己就将一些主要的系统功能以DLL模块的形式实现。例如IE中的一些基本功能就是由DLL文件实现的,它可以被其它应用程序调用和集成。一般来说,DLL是一种磁盘文件(通常带有DLL扩展名,是标准win32可执行文件-“PE”格式),它由全局数据、服务函数和资源组成,在运行时被系统加载到进程的虚拟空间中,成为调用进程的一部分,进程中所有线程都可以调用其中的函数。如果与其它DLL之间没有冲突,该文件通常映射到进程虚拟空间的同一地址上。DLL模块中包含各种导出函数,用于向外界提供服务。Windows在加载DLL模块时将进程函数调用与DLL文件的导出函数相匹配。

             Win32环境中,每个进程都复制了自己的读/写全局变量。如果想要与其它进程共享内存,必须使用内存映射文件或者声明一个共享数据段。DLL模块需要的堆栈内存都是从运行进程的堆栈中分配出来的。

             DLL文件中包含一个导出函数表(存在于PE.edata节中)。这些导出函数由它们的符号名和称为标识号的整数与外界联系起来。函数表中还包含了DLL中函数的地址。当应用程序加载DLL模块时时,它并不知道调用函数的实际地址,但它知道函数的符号名和标识号。动态链接过程在加载的DLL模块时动态建立一个函数调用与函数地址的对应表。如果重新编译和重建DLL文件,并不需要修改应用程序,除非你改变了导出函数的符号名和参数序列。

    简单的DLL文件只为应用程序提供导出函数,比较复杂的DLL文件除了提供导出函数以外,还调用其它DLL文件中的函数。

             每个DLL都有一个入口函数(DLLMain),系统在特定环境下会调用DLLMain。在下面的事件发生时会调用dll入口函数:1.进程装载DLL2.进程卸载DLL3.DLL在被装载之后创建了新线程。4. DLL在被装载之后一个线程被终止了。

             应用程序导入函数与DLL文件中的导出函数进行链接有两种方式:隐式链接和显式链接。

             隐式链接(load-time dynamic linking)是指在应用程序中不需指明DLL文件的实际存储路径,程序员不需关心DLL文件的实际装载(由编译器自动完成地址分配)。采用隐式链接方式,程序员在建立一个DLL文件时,链接程序会自动生成一个与之对应的LIB导入文件。该文件包含了每一个DLL导出函数的符号名和可选的标识号,但是并不含有实际的代码。LIB文件作为DLL的替代文件被编译到应用程序项目中。当程序员通过静态链接方式编译生成应用程序时,应用程序中的调用函数与LIB文件中导出符号相匹配,这些符号或标识号进入到生成的EXE文件中。LIB文件中也包含了对应的DLL文件名(但不是完全的路径名),链接程序将其存储在EXE文件内部。当应用程序运行过程中需要加载DLL文件时,Windows根据这些信息发现并加载DLL,然后通过符号名或标识号实现对DLL函数的动态链接。我们使用的大部分系统Dll就是通过这样的方式链接的。若找不到需要的Dll则会给出一个Dll缺少的错误消息。

             显式链接(run-time dynamic linking)与此相反。用户程序在编译的时候并没有指明需要哪些Dll,而是在运行起来之后调用Win32 LoadLibary()函数,去装载Dll。若没有找到Dll则这个函数就会返回一个错误。在用LoadLibary()函数装载Dll之后,应用程序还需要用GetProcAdress()函数去获得Dll输出函数的地址。显式链接方式对于集成化的开发语言比较适合。有了显式链接,程序员就不必再使用导入文件,而是直接调用Win32 LoadLibary()函数,并指定DLL的路径作为参数。还要说明一点的就是Known Dlls就是保证在通过LoadLibary()去装载系统Dll的时候,只从特定的系统目录去装载,防止装载错。装载的时候会去看注册表下是否有一样的注册表键名。如果是装载windows\system32\目录下的对应的Dll

             Dll的搜索顺序,在Windows上有个注册表键值决定了Dll的搜索顺序:HKLM\System\CurrentControlSet\SessionManager\SafeDllSearchMode。在vista,server2003,xp sp2中这个值为1,在xp,2000 sp4中为01值时的搜素顺序为:1.可执行文件所在目录,2.系统目录windows\system32\3. 16位系统目录,4.windows目录,5.当前进程目录。6.环境变量PATH中的目录。0值时的搜素顺序为:1.可执行文件所在目录,2. 当前进程目录。3.系统目录windows\system32\4. 16位系统目录,5.windows目录,6.环境变量PATH中的目录。

    DLL的加载与连接

        Windows DLL装入(ntdll.dll)和连接是通过ntdll.dll中一个函数LdrInitializeThunk实现的。先对LdrInitializeThunk()这个函数名作些解释“Ldr显然是“Loader”的缩写。而“Thunk”意为“翻译”、“转换”、或者某种起着“桥梁”作用的东西。这个词在一般的字典中是查不到的,但却是个常见于微软的资料、文档中术语。这个术语起源于编译技术,表示一小片旨在获取某个地址的代码,最初用于函数调用时“形参”和“实参”结合。后来这个术语有了不少新的特殊含义和使用,但是DLL的动态连接与函数调用时“形实结合”确实有着本质的相似。

             由于Windows没有公开这个函数的代码,所以学习起来比较困难,只能通过查阅一些资料来大概猜测这个函数的实现。这个过程中也参看了很多ReactOSReactOS是一个免费而且完全兼容 Microsoft Windows XP 的操作系统。ReactOS 旨在通过使用类似构架和提供完整公共接口实现与 NT 操作系统二进制下的应用程序和驱动设备的完全兼容。)的LdrInitializeThunk()函数实现源代码。

             在进入这个函数之前,目标 EXE映像已经被映射到当前进程的用户空间,系统DLL ntdll.dll的映像也已经被映射,但是并没有在EXE映像与ntdll.dll映像之间建立连接 (实际上 EXE映像未必就直接调用ntdll.dll中的函数)LdrInitializeThunk()ntdll.dll中不经连接就可进入的函数,实质上就是ntdll.dll的入口。除ntdll.dll以外,别的 DLL都还没有被装入(映射)。此外,当前进程(除内核中的“进程控制块”EPROCESS等数据结构外)在用户空间已经有了一个“进程环境块”PEB,以及该进程的第一个“线程环境块”TEB。这就是进入 LdrInitializeThunk()前的“当前形势”。

             PEB中有一个字段Ldr是个PEB_LDR_DATA结构指针,所指向的数据结构用来为本进程维持三个“模块”队列、即InLoadOrderModuleListInMemoryOrderModuleList、和InInitializationOrderModuleList。这里所谓“模块”就是PE格式的可执行映像,包括EXE映像和DLL映像。前两个队列都是模块队列,第三个是初始化队列。两个模块队列的不同之处在于排列的次序,一个是按装入的先后,一个是按装入的位置。每当为本进程装入一个模块、即.exe映像或DLL映像时,就要为其分配,创建一个LDR_DATA_TABLE_ENTRY数据结构,并将其挂入InLoadOrderModuleList。然后,完成对这个模块的动态连接以后,就把它挂入InInitializationOrderModuleList队列,以便依次调用它们的初始化函数。相应地,LDR_DATA_TABLE_ENTRY数据结构中有三个队列头,因而可以同时挂在三个队列中。在我做的小实验当中就是通过查找这三个队列,来将当前进程的Dll加载信息显示出来的。具体的实例请见我的实验说明文档。

             LdrInitializeThunk()中,最开始为做的事情就是将加载的模块信息存放在PEB中的ldr字段,如上面一段文字中所述。之后,LdrInitializeThunk()函数又调用了一个叫LdrPEStartup()的函数。LdrPEStartup()函数首先判断了“期望地址”是否可用,PE映像的NtHeader(peb中有个ImageBaseAddress的地址,代表exe映像在用户空间的位置,在这个地址指向的数据结构中就有NtHeader的结构)中有个指针,指向一个OptionalHeader。在OptionalHeader中有个字段ImageBase,是具体映像建议、或者说希望被装入的地址,我们称之为“愿望地址”。在装入一个映像时,只要相应的区间(取决于它的期望地址和大小)空闲,就总正常装入。但是如果与已经被占用的区间相冲突,就只好利用LdrPerformRelocations()换个地方。

             那么映像的愿望地址有着什么物理的或者逻辑的意义呢?我们知道,软件在编译以后有个连接的过程,即为函数的调用者落实被调用函数的入口地址、为全局变量(按绝对地址)的使用者落实变量地址的过程。连接有静态和动态两种,静态连接是在“制造”软件时进行的,而动态连接则是在使用软件时进行的。尽管EXE模块和DLL模块之间的连接是动态连接,但是EXEDLL模块内部的连接却是静态连接。既是静态连接,就必须为模块的映像提供一个假定的起点地址。如果以此假定地址为基础进行连接以后就不可变更,使用时必须装入到这个地址上,那么这个地址就是固定的“指定地址”了。早期的静态连接往往都是使用指定地址的。但是,如果允许按假定地址连接的映像在实际使用时进行“重定位”,那么这假定地址就是可浮动的“愿望地址”了。可“重定位”的静态连接当然比固定的静态连接灵活。事实上,要是没有可“重定位”的静态连接技术,DLL的使用就无法实现,因为根本就不可能事先为所有可能的DLL划定它们的装入位置和大小。至于可“重定位”静态连接的实现,则一般都是采用间接寻址,通过指针来实现。

             所谓重定位,就是计算出实际装入地址与建议装入地址间的位移a,然后调整每个重定位块中的每一个重定位项、即指针,具体就是在指针上加a。而映像中使用的所有绝对地址(包括函数入口、全局量数据的位置)实际上用的都是间接寻址,每个这样的地址都有个指针存在于某个重定位块中。

             完成了可能需要的EXE映像重定位以后,下一个主要的操作就是LdrFixupImports()了。实际上这才是关键所在,它所处理的就是当前模块所需DLL模块的装入和连接。各DLL的程序入口记录在它们的LDR_DATA_TABLE_ENTRY数据结构中借助InInitializationOrderModuleList队列就可依次调用所有DLL的初始化函数。

             NtHeaderOptionalHeader中有个数组DataDirectory[],其中之一是重定位目录。除此之外,数组中还有“(普通)引入(import)”、“绑定引入(bound import)”以及其它多种目录,但是我们在这里只关心“引入”和“绑定引入”。这两个目录都是用于库函数的引入,但是作用不同,目录项的数据结构也不同。每个引入目录项都代表着一个被引入模块,其模块名、即文件名在dwRVAModuleNameReactOS中的名字,下同)所指的地方。需要从同一个被引入模块引入的函数通常有很多个,dwRVAFunctionNameList指向一个字符串数组,数组中的每一个字符串都是一个函数名;与此相对应,dwRVAFunctionAddressList则指向一个指针数组。这两个数组是平行的,同一个函数在两个数组中具有相同的下标。从一个被引入模块中引入一个函数的过程大体上就是:根据函数名在被引入模块的引出目录中搜索,找到目标函数以后就把它实际装入后的入口地址填写到指针数组中的相应位置上。但是,这个过程可能是个开销相当大、速度比较慢的过程。为此,又发展起一种称为“绑定”的优化。

    所谓绑定,就是在软件的编译,连接过程中先对使用时的动态连接来一次预演,预演时假定所有的DLL都被装入到它们的愿望地址上,然后把预演中得到的被引入函数的地址直接记录在引入者模块中相应引入目录下的指针数组中。这样,使用软件时的动态连接就变得很简单快捷,因为实际上已经事先连接好了。其实“绑定引入”和静态连接并无实质的不同。但是,各模块的版本配套就成为一个问题,因为万一使用的某个DLL不是当初绑定时的版本,而且其引出目录又发生了变化,就有可能引起混乱。为此,PE格式增加了一种“绑定引入”目录,相关的机制会进行判断。但是,“绑定引入”毕竟不是很可靠的,万一发现版本不符就不能使用原先的绑定了。所以“绑定引入”不能单独存在,而必须有普通引入作为后备。如果不符就不能按“绑定引入”目录处理引入,而只好退而求其次,改成按普通“引入”目录处理引入。另一方面,所谓“绑定”是指当被引入模块装入在预定位置上时的地址绑定,如果被引入模块的装入位置变了,就得对原先所绑定的地址作相应的调整、即“重定位”。

    LdrFixupImports()函数首先从映像头部获取指向“引入”目录和“绑定引入”目录的指针。若存在“绑定引入”目录,则先通过LdrpGetOrLoadModule()找到或装入(映射)被引入模块的映像。首先当然是在模块队列中寻找,找不到就从被引入模块的磁盘文件装入。之后检查绑定版本是否一致,如果不一致就退而求其次,通过LdrpProcessImportDirectory()处理引入。当然,那样一来效率就要降低了。如果一致,则返回(因为在“预演”中已经连接好,效率当然高了)。而LdrpProcessImportDirectory()才是真正意义上的动态连接!!(说了这么多原来才开始……)。

    LdrpProcessImportDirectory()首先根据目录项中的两个位移量取得分别指向函数名字符串数组和函数指针数组的指针。这两个数组是平行的(前面有介绍),然后对字符串数组中的元素计数,得到该数组的大小IATSize。显然,函数指针数组的大小也是IATSize。这里IAT是“引入地址表(Imported Address Table)”的缩写,其实就是函数指针数组。这个数组在映像内部,其所在的页面在装入映像时已被加上写保护,而下面要做的事正是要改变这些指针的值,所以先要通过NtProtectVirtualMemory()把这些页面的访问模式改成可读可写。做完这些准备之后,下面就是连接的过程了,那就是根据需要把被引入模块所引出的函数入口(地址)填写到引入者模块的IAT中。与当前模块中的两个数组相对应,在被引入模块的“引出”目录中也有两个数组,说明本模块引出函数的名称和入口地址(在映像中的位移)。当然,这两个数组也是平行的。要获取被引入模块中的函数入口有两种方法,即按序号(Ordinal)引入和按函数名引入。从而分别调用LdrGetExportByOrdinal()LdrGetExportByName()。这两个函数都返回目标函数在本进程用户空间中的入口地址,把它填写入当前模块引入目录函数指针数组中的相应元素,就完成了一个函数的连接。当然,同样的操作要循环实施于当前模块需要从给定模块引入的所有函数,并且(在上一层)循环实施于所有的被引入模块。完成了对一个被引入模块的连接之后,又调用NtProtectVirtualMemory()恢复当前模块中给定目录项内函数指针数组所在页面的保护。

    到此,我们大概的清楚Windows Dll的加载与连接过程。

    展开全文
  • /************************************************************************//* resDef.h /* 资源DLL提供给外部使用的头文件/* nick/* 4-10-2009/*************************************************************...

    /************************************************************************/

    /* resDef.h      
    /* 资源DLL提供给外部使用的头文件
    /* nick
    /* 4-10-2009

    /************************************************************************/

    #pragma once

    //位图ID定义
    #define IDB_BITMAP1             0
    #define IDB_BITMAP2             1
    #define IDB_BITMAP3             2
    #define IDB_BITMAP4             3
    #define IDB_BITMAP5             4
    #define IDB_BITMAP6             5
    #define IDB_BITMAP7             6

    #define MAX_BITMAP_WIDTH 1000
    #define MAX_BITMAP_HEIGHT 900
    #define PIX_BIT 16

    //实际位图的大小不应该大小MAX_BMP_SIZE,否则显示将不正常
    #define MAX_BMP_SIZE  MAX_BITMAP_WIDTH*MAX_BITMAP_HEIGHT*(PIX_BIT>>3)

    //位图结构体定义
    typedef struct{
     LONG bmWidth;
     LONG bmHeight;
     WORD bmBitsPixel;
     DWORD bmSize;
     BYTE bits[MAX_BMP_SIZE];
    }rgbBITMAP;


    ==========================================================End

     

     
    //DllDef.h 头文件,DLL内部使用
    #pragma once

    #include "resDef.h"

    #define DEBUG_DLL 1
    #define MAX_BITMAPS 7
    #define ALL_MEM_ALLOCATED

    //内存映射的文件名
    #define  lpResourceFileMapName          L"ResourceShared"

    //图片的长宽
    #define DEFAULT_WIDTH 800
    #define DEFAULT_HEIGHT 480

    //图片与应用程序启动路径的相对位置
    #define BITMAP1_PATH L"images//BITMAP1.rgb"
    #define BITMAP2_PATH L"images//BITMAP2.rgb"
    #define BITMAP3_PATH L"images//BITMAP3.rgb"
    #define BITMAP4_PATH L"images//BITMAP4.rgb"
    #define BITMAP5_PATH L"images//BITMAP5.rgb"
    #define BITMAP6_PATH L"images//BITMAP6.rgb"
    #define BITMAP7_PATH L"images//BITMAP7.rgb"

    //图片的长宽
    #define BITMAP1_WIDTH              DEFAULT_WIDTH
    #define BITMAP1_HEIGHT             DEFAULT_HEIGHT
    #define BITMAP2_WIDTH              808
    #define BITMAP2_HEIGHT             461
    #define BITMAP3_WIDTH              722
    #define BITMAP3_HEIGHT             505
    #define BITMAP4_WIDTH              DEFAULT_WIDTH
    #define BITMAP4_HEIGHT             DEFAULT_HEIGHT
    #define BITMAP5_WIDTH              DEFAULT_WIDTH
    #define BITMAP5_HEIGHT             DEFAULT_HEIGHT
    #define BITMAP6_WIDTH              1290
    #define BITMAP6_HEIGHT             535
    #define BITMAP7_WIDTH              1290
    #define BITMAP7_HEIGHT              535

    //图片的信息,包括长宽和路径
    typedef struct{
     LONG width;
     LONG height;
     LPTSTR path;
     HANDLE handle;
    } FILE_INFO;

    //内存映射文件结构体定义
    typedef struct{
     rgbBITMAP hResBitmap[MAX_BITMAPS];
     } RESOURCE_BITMAP, *PRESOURCE_BITMAP;

     
    =======================================================End

     
     
    //resDll.h DLL接口头文件

    #ifdef COMMDRAW_EXPORTS
    #define COMMDRAW_API __declspec(dllimport)
    #else
    #define COMMDRAW_API __declspec(dllexport)
    #endif

    extern "C" COMMDRAW_API   HANDLE GetBitmapResourceFile( int resID );

     

    =======================================================End

     

    //resDll.cpp  DLL的代码文件
    //
    #include "stdafx.h"
    #include "DllDef.h"
    #include "resDll.h"

    //共享bDllInit变量,以便在所有模块加载本DLL时可以共享此变量,以判断在此之前是否DLL已被初始化
    #pragma   data_seg(".Shared")  
    BOOL bDllInit = TRUE;
    PRESOURCE_BITMAP m_bitmapRes =NULL;
    #pragma   data_seg()  
    #pragma   comment(linker,"/SECTION:.Shared,RWS") 

    //函数申明
    BOOL CreateMapFile();
    BOOL CloseMapFile();
    BOOL LoadResource();

    rgbBITMAP *OpenResourceMapFile( int resID );
    BOOL CloseResourceMapFile();

    //变量定义
    #ifdef ALL_MEM_ALLOCATED
          PRESOURCE_BITMAP resFile = NULL;
    #else
          rgbBITMAP *resFile = NULL;
    #endif
    HANDLE hResourceMap = NULL;
    HANDLE hMap = NULL;

     

    //DLL入口
    BOOL APIENTRY DllMain( HANDLE hModule,
                           DWORD  ul_reason_for_call,
                           LPVOID lpReserved
          )
    {
     switch (ul_reason_for_call)
     {
     case DLL_PROCESS_ATTACH:
      { 
       //如果DLL第一次被加载,则初始化共享内存和加载图片资源
       if( bDllInit )
       {
          LoadResource();
          bDllInit = FALSE;
       }
       else
       {
    #ifdef ALL_MEM_ALLOCATED
          //加载共享内存到本地进程中
          OpenResourceMapFile( 0 );
    #endif
       }
      }
      break;
     case DLL_THREAD_ATTACH:
      break;
     case DLL_THREAD_DETACH:
      break;
     case DLL_PROCESS_DETACH:
      {
         //此DLL被设计为永远不会释放
         //CloseMapFile();

    #ifdef ALL_MEM_ALLOCATED
       //释放本地进程中的内存拷贝
       CloseResourceMapFile();
    #endif
       RETAILMSG(DEBUG_DLL,(L"[resDll]: DLL_PROCESS_DETACH /r/n"));
      }
      break;
     }
        return TRUE;
    }

    /************************************************************************/
    /*    获取右边"/"之前的字符长度                                         */
    /************************************************************************/
    UINT8  SrightNo(WCHAR* Firststr,WCHAR c)
    {
     int i,len;
     len=wcslen(Firststr);
     for(i=len-1; i>0; i--)
     {
      if(*(Firststr+i) == c) 
       return i;
     }
     return 0;
    }


    /************************************************************************/
    /*     获取调用DLL的程序启动路径                                        */
    /************************************************************************/
    TCHAR* GetModulePath( TCHAR* filePath)
    {
     TCHAR temp[MAX_PATH]; 

     GetModuleFileName(NULL,temp,MAX_PATH);
     wcsncpy(filePath,temp,SrightNo(temp,'//')+1);
     return filePath;
    }
     

    /************************************************************************/
    /*    加载图片资源,并初始化内存共享数据                                */
    /************************************************************************/
    BOOL LoadResource()
    {
     //只加载一次资源
     if( hMap != NULL )
      return TRUE;

     RETAILMSG(DEBUG_DLL,(TEXT("[resDll]: start loading bitmap resource..../r/n")));

     if( CreateMapFile() )
     {
      //映射需要共享的模块数据到数组内,以便下面读文件
      FILE_INFO fileInfo[MAX_BITMAPS] =
      {
       {
        BITMAP1_WIDTH,BITMAP1_HEIGHT,BITMAP1_PATH,(HANDLE)(&m_bitmapRes->hResBitmap[IDB_BITMAP1])
       }
       ,
       {
        BITMAP2_BITMAP_WIDTH,BITMAP2_BITMAP_HEIGHT,BITMAP2_PATH,(HANDLE)(&m_bitmapRes->hResBitmap[IDB_BITMAP2])
       }
       ,
       {
        BITMAP3_WIDTH,BITMAP3_HEIGHT,COMM_CLOCK_PATH,(HANDLE)(&m_bitmapRes->hResBitmap[IDB_BITMAP3])
       }
       ,
       {
        BITMAP4_WIDTH,BITMAP4_HEIGHT,BT01_PATH,(HANDLE)(&m_bitmapRes->hResBitmap[IDB_BITMAP4])
       }
       ,
       {
        BITMAP5_WIDTH,BITMAP5_HEIGHT,BTT_PATH,(HANDLE)(&m_bitmapRes->hResBitmap[IDB_BITMAP5])
       }
       ,
       {
        BITMAP6_WIDTH,BITMAP6_HEIGHT,BTT_PATH,(HANDLE)(&m_bitmapRes->hResBitmap[IDB_BITMAP6])
       }
       ,
       {
        BITMAP6_WIDTH,BITMAP6_HEIGHT,BTT_PATH,(HANDLE)(&m_bitmapRes->hResBitmap[IDB_BITMAP6])
       }
      };

      DWORD dwLength =0;
      FILE *mStream =NULL;
      TCHAR tempPath[MAX_PATH] ={0};
      TCHAR filePath[MAX_PATH] ={0};

      GetModulePath(tempPath);
      wcscpy(filePath,tempPath);
      rgbBITMAP * pBitmap =NULL;

      int i=0;
      for( i; i< MAX_BITMAPS; i++ )
      {
       memset(tempPath,0,MAX_PATH);
       wcscpy(tempPath,filePath);
       wcscat(tempPath, fileInfo[i].path);
       if((mStream = _wfopen(tempPath, L"rb")))
       { 
        //获得文件的长度
        fseek(mStream, 0, SEEK_END); //文件指针移动到最后
        dwLength = ftell( mStream ); //获得文件字节数
        fseek(mStream, 0, SEEK_SET); //文件指针移动到开始

        pBitmap = (rgbBITMAP*)fileInfo[i].handle;
        //写入BUFFER的实际长度
        pBitmap->bmSize = min(MAX_BMP_SIZE, dwLength);

        pBitmap->bmBitsPixel = PIX_BIT;
        pBitmap->bmWidth = fileInfo[i].width;
        pBitmap->bmHeight = fileInfo[i].height;

        fread(pBitmap->bits, pBitmap->bmSize, 1, mStream);
        fclose(mStream);
        mStream = NULL;
       }
       else
       {
        RETAILMSG(DEBUG_DLL,(TEXT("[resDll]: Load /"%s/" failed! /r/n"),filePath));
        return FALSE;
       }
      }
     }
     else
     {
      RETAILMSG(DEBUG_DLL,(L"[resDll]: CreateMapFile failed /r/n"));
      return FALSE;
     }
     return TRUE;
    }


    /************************************************************************/
    /*       创建内存共享文件                                               */
    /************************************************************************/
    BOOL CreateMapFile()
    {
     hMap = CreateFileMapping(
      INVALID_HANDLE_VALUE,     //HANDLE hFile,
      NULL,                     //LPSECURITY_ATTRIBUTES lpFileMappingAttributes,
      PAGE_READWRITE,           //DWORD flProtect,
      0,                        //DWORD dwMaximumSizeHigh,
      sizeof(RESOURCE_BITMAP),  //DWORD dwMaximumSizeLow,
      lpResourceFileMapName     //LPCTSTR lpName
      );

     if(hMap == NULL)
     {
      return false;
     }
     else if (hMap != NULL && GetLastError() == ERROR_ALREADY_EXISTS)
     {
      CloseHandle(hMap);
      hMap = NULL;
         RETAILMSG(DEBUG_DLL,(L"[resDll]: Mapping file already exist /r/n"));
      return false;
     }
     m_bitmapRes = (PRESOURCE_BITMAP)MapViewOfFile(
      hMap,                               //HANDLE hFileMappingObject,
      FILE_MAP_WRITE | FILE_MAP_READ,     //DWORD dwDesiredAccess,
      0,                                  //DWORD dwFileOffsetHigh,
      0,                                  //DWORD dwFileOffsetLow,
      0                                   //DWORD dwNumberOfBytesToMap
      );
     if(m_bitmapRes)
     {
         RETAILMSG(DEBUG_DLL,(L"[resDll]: Mapping file address %x,hMap:%x/r/n",m_bitmapRes,hMap));
     }
     else
     {
      return false;
     }

     return true;
    }


    /************************************************************************/
    /*   此DLL被主进程加载,按照系统设计将不会退出,
         所以所有的DLL资源可以不写释放代码,但需了解!                      */
    /************************************************************************/
    BOOL CloseMapFile()
    {
     if(hMap)
     {
      CloseHandle(hMap);
      hMap = NULL;
     }
     if(m_bitmapRes)
     {
      UnmapViewOfFile(m_bitmapRes);
      m_bitmapRes = NULL;
     }
     return true;
    }


    /************************************************************************/
    /*       打开内存共享文件                                               */
    /************************************************************************/
    rgbBITMAP *OpenResourceMapFile( int resID )
    {
     //如果图片资源无效,则直接返回
     if( m_bitmapRes == NULL )
     {
      RETAILMSG(DEBUG_DLL,(L"[resDll]: invalid shared memory!/r/n"));
      return NULL;
     }

    #ifdef ALL_MEM_ALLOCATED
     hResourceMap = CreateFileMapping(
      INVALID_HANDLE_VALUE,    //HANDLE hFile,
      NULL,                    //LPSECURITY_ATTRIBUTES lpFileMappingAttributes,
      PAGE_READONLY,           //DWORD flProtect,
      0,                       //DWORD dwMaximumSizeHigh,
      0,                       //DWORD dwMaximumSizeLow,
      lpResourceFileMapName    //LPCTSTR lpName
      );

     if(hResourceMap == NULL)
     {
      DWORD ret;
      ret = GetLastError();
      RETAILMSG(DEBUG_DLL,(L"[resDll]: OpenResourceMapFile failed, error = %x/r/n",ret));
      return NULL;
     }

     resFile = (PRESOURCE_BITMAP)MapViewOfFile(
      hResourceMap,                //HANDLE hFileMappingObject,
      FILE_MAP_READ,               //DWORD dwDesiredAccess,
      0,                           //DWORD dwFileOffsetHigh,
      0,                           //DWORD dwFileOffsetLow,
      sizeof(RESOURCE_BITMAP)      //DWORD dwNumberOfBytesToMap
      );
     return NULL;

    #else

     hResourceMap = CreateFileMapping(
      INVALID_HANDLE_VALUE,    //HANDLE hFile,
      NULL,                    //LPSECURITY_ATTRIBUTES lpFileMappingAttributes,
      PAGE_READONLY,           //DWORD flProtect,
      0,                       //DWORD dwMaximumSizeHigh,
      sizeof(rgbBITMAP),       //DWORD dwMaximumSizeLow,
      lpResourceFileMapName    //LPCTSTR lpName
      );

     if(hResourceMap == NULL)
     {
      DWORD ret;
      ret = GetLastError();
      RETAILMSG(DEBUG_DLL,(L"[resDll]: OpenResourceMapFile failed, error = %x/r/n",ret));
      return NULL;
     }


     resFile = (rgbBITMAP *)MapViewOfFile(
      hResourceMap,               //HANDLE hFileMappingObject,
      FILE_MAP_READ,              //DWORD dwDesiredAccess,
      0,                          //DWORD dwFileOffsetHigh,
      sizeof(rgbBITMAP)*resID,    //DWORD dwFileOffsetLow,
      sizeof(rgbBITMAP)           //DWORD dwNumberOfBytesToMap
      );
     return resFile;

    #endif
    }


    /************************************************************************/
    /*       关闭内存共享文件                                               */
    /************************************************************************/
    BOOL CloseResourceMapFile()
    {
     if( hResourceMap )
     {
      CloseHandle(hResourceMap);
      hResourceMap= NULL;
     }

     if(resFile)
     {
      UnmapViewOfFile(resFile);
      resFile = NULL;
     }

     return true;
    }

     
    /************************************************************************/
    /* 函数:  GetBitmapResourceFile 获取指定图片的数据                     */
    /* 返回值:HANDLE为指向rgbBitmap数据的指针                              */

    /* 说明:
            在DLL初始化时一次性加载所有共享内存到本地进程中                
     这样会大大提高获取共享内存的速度(几乎不耗时间,1MS内),           
     但带来比较大的内存消耗问题,而动态加载内存比较耗费时间(大概30MS左右,    */
    /************************************************************************/
    HANDLE GetBitmapResourceFile( int resID )
    {
     DWORD dwTest = GetTickCount();
    #ifdef ALL_MEM_ALLOCATED

     if( resFile == NULL )
      return NULL;
     HANDLE pTemp = (HANDLE)&resFile->hResBitmap[resID];

    #else

     HANDLE pTemp = (HANDLE)OpenResourceMapFile( resID );
     CloseResourceMapFile();
     HANDLE pTemp = (HANDLE)&resFile->hResBitmap[resID];

    #endif
     RETAILMSG(DEBUG_DLL,(TEXT("[resDll]: GetBitmapResource....%x, spend %d ms/r/n"),pTemp,GetTickCount()-dwTest));
     return pTemp;
    }

     

    (完)

    展开全文
  • 在这里我做了一个试验,编写一个DLL和一个加载DLL并调用DLL中一个函数的程序,分别用二个OD加载这二个可执行程序调用DLL中的函数,为了说明加载的这个DLL分别位于不同的进程,没有任何的共享关系,我把二个进程同时...
  • 场景是这样的。开发了一个activex的dll,被IE浏览器进程加载。...所以这个dll实例会被IE初始化多次。 现在有一个文件配置。想做成所有dll的实例共用一份。有没有什么办法可以做到。 欢迎大家反馈!
  • [解决]无法加载 DLL "SQLite.Interop.DLL

    万次阅读 2012-02-22 18:25:30
    [解决]System.DllNotFoundException: 无法加载 DLL“SQLite.Interop.DLL” -- 绿化System.Data.SQLite.dll 这个问题是在绿化System.Data.SQLite.dll的时候出现的 [1]在下面的网站下载的1.0.66版本的单文件...
  • 今天项目需要进行同一个dll线程同时操作。 解决办法 :通过动态加载的办法 将dll复制重命名 即 线程A-----复制test.dll并重命名为test_A.dll--动态加载test_A.dll 线程B-----复制test.dll并重命名为test_B...
  • 动态Dll加载若干问题

    2011-10-08 16:00:17
    进程加载动态Dll步骤: 1. 当进程加载动态Dll时,进程给动态Dll分配了虚拟内存空间。 2.进程开始初始化Dll的全部变量和静态变量。初始化的顺序不定(太因素影响了。。。)。 3.进程开始调用DllMain函数。函数...
  • 感觉讲得挺详细 注: ln 命令用法 ln –s 源文件 目标文件 (目标文件即为软链接文件) 可用ls -l查看软链接文件具体指向哪个...针对同一动态组件的不同版本链接和加载。 一、概念   DLL HELL字面意思是DLL"灾难...
  • NX二开发时,如果软件过大,可能拆分成小模块给不同的小组开发,即个外挂 但不同模块之间数据可能需要相互调用,这时就会出现不同的外挂间同名 dll 文件的问题。 比如A模块生成了 a.dll, B模块生成了 b.dll, a...
  • 每个进程加载DLL的时候都会将该DLL加载到自身进程的地址空间中,只有定义在共享段中的一些简单的类型可以。每个进程使用的不是同一个副本,映射到了不同的地址空间上。
  • 用LoadLibrary加载同一个DLL文件两, 发现返回的 hModule 是一样的, 是同一个实例,有什么办法可以在不 FreeLibrary 的情况下,加载多一个实例? 同一个dll的话,加载第二只会增加dll的引用计数,返回的...
  • 动态库dll加载

    2016-04-07 11:43:22
    Windows DLL基本原理 Windows系统平台上,你可以将独立的程序模块创建为较小的DLL(Dynamic ...这种方式不仅减少了EXE文件的大小和对内存空间的需求,而且使这些DLL模块可以同时被个应用程序使用。Microsoft
  • 从这篇文章开始,作者将带着大家来...第一篇文章主要包括两部分内容,开发环境(VS、编译设置)、基础技术、运行单一实例(互斥对象示例)、DLL延迟加载(skin++换皮肤示例)、资源释放(MFC示例)。希望对您有所帮助~
  • 这个问题是在绿化System.Data.SQLite.dll的时候出现的[1]在下面的网站下载的1.0.66版本的单文件整合型的dll是可以直接使用的http://sqlite.phxsoftware.com/[2]在下面的网站下载的Setups for 32-bit Windows (.NET ...
  • 这个问题是在绿化System.Data.SQLite.dll的时候出现的 [1]在下面的网站下载的1.0.66版本的单文件整合型的dll是可以直接使用的 http://sqlite.phxsoftware.com/ [2]在下面的网站下载的Setups for 32-bit Windows ...
  • 优化 DLL 加载时间性能

    千次阅读 2008-01-04 13:56:00
    优化 DLL 加载时间性能 发布日期: 7/28/2004 | 更新日期: 7/28/2004Matt Pietrek 请下载本文的代码: UnderTheHood0500.exe (264KB)近年来,在我的专栏文章和技术讲座中,其中一个主要主题一直是优化可执行文件...
  • Optimizing DLL Load Time PerformanceMatt Pietrek Download the code for this article: UnderTheHood0500.exe (264KB) Over the years, one of the dominant themes in my columns and seminars...
  • Windows DLL基本原理 Windows系统平台上,你可以将独立的程序模块创建为较小的DLL(Dynamic Linkable Library...这种方式不仅减少了EXE文件的大小和对内存空间的需求,而且使这些DLL模块可以同时被个应用程序使用。Mi
  • 线程调用: 1、动态库只有一个导出函数: 这种情况非常少,也是最容易处理的情况。这种情况下编写函数时,只需要考虑不要有冲突的全局数据就可以了。这里的全局数据包括了在堆中分配的数据块和静态全局变量等。...
  • Windows DLL基本原理 Windows系统平台上,你可以将独立的程序模块创建为较小的DLL(Dynamic Linkable Library...这种方式不仅减少了EXE文件的大小和对内存空间的需求,而且使这些DLL模块可以同时被个应用程序使用。Mi
  • dll

    2013-10-22 23:12:53
    一、DLL个进程调用问题 Win32系统会确保内存中只有一个该DLL的拷贝,这是通过内存映射文件来实现的。不同的进程分别将这份DLL的代码段地址映射到自己的进程空间中,同时不同的进程在自己的进程空间分别有各自的...
  • DLL线程

    万次阅读 2016-04-06 11:02:35
    DLL中可以处理线程,WIN32对于线程的支持是操作系统本身提供的一种能力,并不在于用户编写的是哪一类程序。即便是一个控制台程序,我们都可以使用线程: #include #include void ThreadFun(void) { while...
  • (完整版)原因可能是堆被损坏,这也说明 中或它所加载的任何DLL 中有bug】的解决... 最近在开发项目的时候被这个错误郁闷很久,本来以为是dll加载出错或者是分配内存出错。找了很久都没找出。在...
  • DLL模块的显示载入和符号链接 LoadLibrary/Ex 显示加载dll,映射到进程的地址空间 ...同一进程中多次加载一个dll会递增使用计数 不同进程之间维护各自的dll使用计数 可以使用GetModuleHanle检测dll是否被映射...
  • DLL

    2011-04-27 10:10:00
    ,缩写为DLL ),又称为动态连结库 ,是微软公司 在微软视窗操作系统 中实现共享函数库 概念的一种实作方式。这些库函数的扩展名 是.DLL 、.OCX (包含ActiveX 控制的库)或者.DRV (旧式的系统驱动程序

空空如也

空空如也

1 2 3 4 5 ... 20
收藏数 16,708
精华内容 6,683
关键字:

多次加载同一dll