Skip to content

dll延迟加载技术

之前说给团队的兄弟们说下dll延迟加载的东西,现在出来了

随便生成一个dll,dll代码如下:

// dllmain.cpp : 定义 DLL 应用程序的入口点。
#include "pch.h"
#include <iostream>
#include <cstring>
using namespace std;

BOOL APIENTRY DllMain( HMODULE hModule,
                       DWORD  ul_reason_for_call,
                       LPVOID lpReserved
                     )
{
    switch (ul_reason_for_call)
    {
    case DLL_PROCESS_ATTACH:
    case DLL_THREAD_ATTACH:
    case DLL_THREAD_DETACH:
    case DLL_PROCESS_DETACH:
        break;
    }
    return TRUE;
}


extern "C" __declspec(dllexport) int hello()
{
    int a = 666;
    return a;
}

添加资源后,cpp代码如下:

#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]\n", 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] = '\0';
}

int main()
{
    typedef int (*_pHello)();
    //std::cout << "Hello World!\n";
    // 释放DLL
// 获取当前目录
    char szCurrentPath[MAX_PATH] = { 0 };
    GetCurrentPath(szCurrentPath, MAX_PATH);
    // 构造路径
    ::lstrcat(szCurrentPath, "\\dlltest.dll");
    FreeMyResource(IDR_DLLS1, "dlls", szCurrentPath);
    HINSTANCE hDll = LoadLibrary("dlltest.dll");
    _pHello hello = (_pHello)GetProcAddress(hDll, "hello");
    int nHello = hello();
    std::cout << nHello << std::endl;
}

FindResource函数原型:

FindResourceA(
    _In_opt_ HMODULE hModule,
    _In_     LPCSTR lpName,
    _In_     LPCSTR lpType
);

不得不说,这个函数原型的命名有点东西,上网查也说的和命名的情况差不多,,但是实际上传入的参数如图:

img

真狗啊。。。

在vs上有需要配置的地方否则会报错,都如图所示:

  1. image-20230705000236574

第三个配置顾名思义,前面两个不改的话,会报什么错可以自己尝试下,后面运行结果:

查看程序导入表,并没有这个用到的dll:

Comments