从C++中的DLL内部下载文件



我一直在尝试使用Windows上C++中构建的dll中的代码下载文件。DLL将使用LoadLibraryA函数加载,我正试图在第一次加载时下载该文件。

通过互联网搜索,我成功地实现了URLDownloadToFile(),它通常适用于控制台应用程序,但不适用于Visual Studio中构建的动态链接库。在project properties->Linker->Input中,我添加了额外的依赖项Urlmon.lib;Wininet.lib;

代码构建成功(Release,x64(,当我用rundll32.exe C:UsersJohnDesktopDll1x64ReleaseDll1.dll, main测试它时,我收到消息"正在启动",然后它冻结了。未显示网络活动(使用eset和进程监视器进行检查(,未写入文件kkk.bin

到目前为止,我使用的代码如下:

// dllmain.cpp : Defines the entry point for the DLL application.
#include "pch.h"
#include <stdio.h>
#include <windows.h>
#include <tchar.h>
#include <iostream>
#include <Urlmon.h>
#include <iomanip> 
#include <thread>
#include <Wininet.h>
#pragma comment(lib,"WinInet.Lib" )
#pragma comment(lib,"Urlmon.Lib" )
__declspec(dllexport) void sample() {
MessageBox(NULL, (LPCWSTR)L"Starting", (LPCWSTR)L"title", MB_ICONWARNING);
const TCHAR url[] = _T("http://techslides.com/demos/samples/sample.txt");
const TCHAR filePath[] = _T("C:\Users\John\Desktop\kkk.bin");
DeleteUrlCacheEntry(url);
HRESULT hr = URLDownloadToFile(
NULL,  
url,
filePath,
0,      
NULL);
if (SUCCEEDED(hr))
{
MessageBox(NULL, (LPCWSTR)L"success", (LPCWSTR)L"title", MB_ICONWARNING);
}
else
{
MessageBox(NULL, (LPCWSTR)L"failed", (LPCWSTR)L"title", MB_ICONWARNING);
}
}

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

DllMain入口点仅用于执行简单的初始化或终止任务。由于技术原因,允许您在DllMain中执行的操作非常受限。有关详细信息,请参阅此链接。

通过启动文件下载,您可能会导致加载新的DLL,这不应该在DllMain中完成,因为这可能会导致死锁。

如果您希望DLL具有没有这些限制的初始化函数,则不应使用DllMain入口点函数(简单初始化除外(。相反,您应该等到操作系统完全完成加载DLL。

例如,您可以要求所有使用DLL的程序在调用DLL中的任何其他函数之前,先调用DLL内的特殊初始化函数。DLL要求这样做是很常见的。例如,Microsoft Windows Sockets 2 Library(Ws2_32.DLL(的DLL要求在调用其任何其他函数之前先调用WSAStartup。这个特殊的初始化函数与DllMain没有相同的限制,因为从技术上讲,它是一个正常的函数调用。因此,它允许您执行诸如下载文件之类的操作。

或者,DLL可以跟踪它是否在全局变量中初始化了自己。在DllMain中,您只需将此全局变量设置为0(false(即可。每当调用DLL中的导出函数时,DLL函数都可以检查此全局变量,如果DLL尚未初始化,它将调用DLL的特殊初始化函数,该函数将执行下载并将全局变量设置为1(true(。

然而,就性能而言,在每次函数调用中检查全局变量可能代价高昂。因此,第一种方法可能比第二种方法更可取。

最新更新