在可执行文件中使用嵌入式 .dll

Posted

技术标签:

【中文标题】在可执行文件中使用嵌入式 .dll【英文标题】:Using an embedded .dll in an executable 【发布时间】:2013-07-21 15:50:36 【问题描述】:

好的。所以我知道有很多关于如何在 exe 中嵌入 dll 的问题,但我的问题是完全不同的。 (具体来说,我正在使用 fmod 库在我的程序中播放声音,并且我正在嵌入 fmod.dll,但这不是重点。)

我正在使用 Visual C++ 2010 Ultimate。我已成功将 .dll 嵌入到 .exe 中。我的 resources.h 文件包含

#define IDR_DLL1  144

我的 .rc 文件包含

IDR_DLL1  DLL  MOVEABLE PURE  "data\\fmod.dll"

我的代码中有以下函数(我完全是从另一个 *** 问题中偷来的):

bool extractResource(const HINSTANCE hInstance, WORD resourceID, LPCTSTR szFilename)

bool bSuccess = false; 
try

    // Find and load the resource
    HRSRC hResource = FindResource(hInstance, MAKEINTRESOURCE(resourceID), L"DLL");
    HGLOBAL hFileResource = LoadResource(hInstance, hResource);

    // Open and map this to a disk file
    LPVOID lpFile = LockResource(hFileResource);
    DWORD dwSize = SizeofResource(hInstance, hResource);            

    // Open the file and filemap
    HANDLE hFile = CreateFile(szFilename, GENERIC_READ | GENERIC_WRITE, 0, NULL, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL);
    HANDLE hFileMap = CreateFileMapping(hFile, NULL, PAGE_READWRITE, 0, dwSize, NULL);            
    LPVOID lpAddress = MapViewOfFile(hFileMap, FILE_MAP_WRITE, 0, 0, 0);            

    // Write the file
    CopyMemory(lpAddress, lpFile, dwSize);            

    // Un-map the file and close the handles
    UnmapViewOfFile(lpAddress);
    CloseHandle(hFileMap);
    CloseHandle(hFile);
    bSuccess = true;

catch(...)

    // Whatever
 
return bSuccess;

然后,我首先在 WinMain 函数中调用以下代码:

int WINAPI WinMain(HINSTANCE h1, HINSTANCE h2, LPSTR l, int a)

    extractResource(h1, IDR_DLL1, L"fmod.dll");
    /* etc */

它有效。它成功地提取出嵌入的 fmod.dll 的内容,并将其保存为同一目录中的文件...仅... 当事先已经存在 fmod.dll 时。 如果 fmod .dll 还没有,我只是收到一条弹出消息,上面写着

The program can't start because fmod.dll is missing from your computer. Try reinstalling the program to fix this problem.

...换句话说,我只能覆盖已经存在的 fmod.dll。例如,如果我改为将代码更改为

extractResource(h1, IDR_DLL1, L"fmod2.dll");

它将写出完全相同的文件,具有完全相同的内容,名为 fmod2.dll。到时候我可以把原来的fmod.dll去掉,把新建的fmod2.dll重命名为fmod.dll,就可以了。

很明显,问题在于它会在访问我的程序入口点之前寻找 fmod.dll 的存在。在需要实际使用任何 fmod 内容之前,我的程序甚至无法执行任何代码。这似乎……非常不公平。那么,即使能够嵌入 dll 又有什么意义呢?

那么,我的问题是

    是否可以直接从 .exe 内部使用 .dll,而无需将其解压缩为文件? (我的首选方法)

    如果 1.) 是不可能的,那么我如何至少修改我的代码以在检查文件存在之前写出文件?

【问题讨论】:

我认为你需要设置延迟加载,例如this(我希望它不会过时)。 MSDN page 用于延迟加载 DLL 已经有很多很好的方法可以嵌入 DLL 并使其可执行。也适用于 UAC 和病毒扫描程序。 Setup.exe,你肯定知道。 啊,谢谢你,DyP!做到了!哈,我简直不敢相信这是多么容易。 【参考方案1】:

嗯,解决方案非常简单。我刚刚关注DyP's suggestion 延迟加载 dll。

我刚刚在我的项目属性中添加了一件事,如下所示:

就是这样!

当编程问题有简单的解决方案时,我喜欢它。 :)

【讨论】:

这可能是您的解决方案,但它不是问题的答案。延迟加载迟早会变成真正的加载。那就克拉布姆吧。 @HansPassant:你真的试图理解这个问题吗? OP 立即加载 DLL。因此,在实际需要 DLL 时(如您所说的实际加载),它已经存在了。

以上是关于在可执行文件中使用嵌入式 .dll的主要内容,如果未能解决你的问题,请参考以下文章

将类从可执行文件导出到 dll

在已编译的可执行文件中嵌入 DLL

Struts2无法在可执行的战争中初始化Dispatcher - 嵌入式Tomcat

在可执行 jar 中访问 derby 数据库

是否可以使用命令行在可执行文件之间切换

在可执行文件中使用 GNU 标准目录变量