• DLL 延迟加载与资源释放


    DLL 延迟加载与资源释放

    延迟加载

    DLL的延迟加载技术,使用延迟加载方式编译连接可执行文件。这样可执行文件可以先加载执行,而依赖的dll文件会在正式调用的时候被加载进来。

    好处是可以把必须使用的DLL文件以资源方式插入到程序中并且使用延迟加载。在程序运行时把DLL文件释放到本地,然后进行加载。这样exe并不需要依附DLL文件。并且不会担心DLL丢失。

    延迟加载实现

    延迟加载并不需要代码来实现,只需要对VS链接属性进行设置即可

    属性—>链接器—>输入—>延迟加载的DLL—>输入:dll名称

    DLL延迟加载技术的原理,其实就是在导入表中去掉我们想要隐藏的DLL这一项,等到DLL被正式调用的时候,才会加载DLL文件。这样,程序在正式调用DLL之前,都是可以正常执行的。

    资源释放

    #include <iostream>
    #include <iostream>
    #include<windows.h>
    #include "resource.h"
    
    BOOL FreeMyResource(UINT uiResouceName, char* lpszResourceType, char* lpszSaveFileName);
    
    void GetCurrentPath(char* lpszCurrentPath, DWORD dwSize);
    
    void FreeRes_ShowError(char* pszText);
    
    // CDelayLoadDll_TestDlg 消息处理程序
    
    
    void FreeRes_ShowError(char* pszText)
    {
    	char szErr[MAX_PATH] = { 0 };
    	::wsprintf(szErr, "%s Error[%d]
    ", pszText, ::GetLastError());
    	::MessageBox(NULL, szErr, "ERROR", MB_OK);
    }
    
    // 释放资源
    BOOL FreeMyResource(UINT uiResouceName, char* lpszResourceType, char* lpszSaveFileName)
    {
    	HRSRC hRsrc = ::FindResource(NULL, MAKEINTRESOURCE(uiResouceName), lpszResourceType);
    	if (NULL == hRsrc)
    	{
    		FreeRes_ShowError("FindResource");
    		return FALSE;
    	}
    	DWORD dwSize = ::SizeofResource(NULL, hRsrc);
    	if (0 >= dwSize)
    	{
    		FreeRes_ShowError("SizeofResource");
    		return FALSE;
    	}
    	HGLOBAL hGlobal = ::LoadResource(NULL, hRsrc);
    	if (NULL == hGlobal)
    	{
    		FreeRes_ShowError("LoadResource");
    		return FALSE;
    	}
    	LPVOID lpVoid = ::LockResource(hGlobal);
    	if (NULL == lpVoid)
    	{
    		FreeRes_ShowError("LockResource");
    		return FALSE;
    	}
    
    	FILE* fp = NULL;
    	fopen_s(&fp, lpszSaveFileName, "wb+");
    	if (NULL == fp)
    	{
    		FreeRes_ShowError("LockResource");
    		return FALSE;
    	}
    	fwrite(lpVoid, sizeof(char), dwSize, fp);
    	fclose(fp);
    
    	return TRUE;
    }
    
    
    // 获取当前目录
    void GetCurrentPath(char* lpszCurrentPath, DWORD dwSize)
    {
    	::GetModuleFileName(NULL, lpszCurrentPath, dwSize);
    	char* p = ::strrchr(lpszCurrentPath, '\');
    	p[0] = '';
    }
    
    int main()
    {
    	typedef int (*_pHello)(int a,int b);
    	
    	// 释放DLL
    // 获取当前目录
    	char szCurrentPath[MAX_PATH] = { 0 };
    	GetCurrentPath(szCurrentPath, MAX_PATH);
    	// 构造路径
    	::lstrcat(szCurrentPath, "\hello_world.dll");
    	FreeMyResource(IDR_TEST1, "test", szCurrentPath);
    	HINSTANCE hDll = LoadLibrary("hello_world.dll");
    	_pHello hello = (_pHello)GetProcAddress(hDll, "add");
    	int nHello = hello(1,2);
    	std::cout << nHello << std::endl;
    

    查看导入表

    但可以根据PE结构中的资源表IMAGE_RESOURCE_DIRECTORY来解析PE中的所有资源,获取资源的偏移地址和数据大小。

    Tips

    1. 关于如果Visual Studio 2019 出现const char *“ 类型的实参与 “LPCWSTR“ 类型的形参不兼容这类错误。需要修改字符集
    2. 关于如果Visual Studio 2019 出现4996类错误。右击项目文件 — 单击属性 — 配置属性 — c/c++ — 语言 — 符合模式修改符合模式为否。
  • 相关阅读:
    开发中常用js记录(二)
    c# 我所理解的 值类型 and 引用类型
    c# 枚举
    ModelState.IsValid总为false原因
    学习总结 之 WebApi服务监控 log4net记录监控日志
    How to Deinstall Oracle Clusterware Home Manually
    oracle client 低于 oracle server 端,导致报错ORA-01882
    转 zabbix 用户建立和中文化
    转 rman 恢复报错
    10g 升级到11g 失效对象2则
  • 原文地址:https://www.cnblogs.com/nice0e3/p/15178232.html
Copyright © 2020-2023  润新知