Reputation: 3
I 've been trying to download a file by using code inside a dll built in C++ on Windows. The DLL will be loaded with LoadLibraryA function, and I am trying to download the file the moment it is first loaded.
Searching through the internet I managed to implement the URLDownloadToFile()
that works normally for a console app but not on a Dynamic-Link Library built in Visual Studio. In the project properties->Linker->Input
I have added the additional dependencies Urlmon.lib;Wininet.lib;
.
The code builds successfully (Release, x64), when I test it with rundll32.exe C:\Users\John\Desktop\Dll1\x64\Release\Dll1.dll, main
I get the message "Starting" and then it freezes. No network activity shown (checked with eset and process monitor), no writing to file kkk.bin
.
The code I am using so far looks like this:
// 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;
}
Upvotes: 0
Views: 2130
Reputation: 25385
The DllMain
entry point is intended to do only simple initialization or termination tasks. For technical reasons, the things that you are allowed to do in DllMain
is very restricted. See this link for further information.
By initiating the download of a file, you are likely causing new DLLs to get loaded, which should not be done in DllMain
, as it could cause a deadlock.
If you want your DLL to have an initialization function without these restrictions, then you should not use the DllMain
entry point function (except for simple initialization). Rather, you should wait until the operating system has fully finished with loading your DLL.
For example, you could require that all programs that use your DLL to call a special initialization function inside your DLL before calling any other functions inside your DLL. It is quite common for DLLs to require this. For example, the DLL of the Microsoft Windows Sockets 2 Library (Ws2_32.dll) requires that you call WSAStartup
before calling any other of its other functions. This special initialization function does not have the same restrictions as DllMain
, because it is technically a normal function call. Therefore, it allows you to do things such as downloading files.
Alternatively, your DLL could keep track of whether it has initialized itself in a global variable. In DllMain
, you do nothing else than set this global variable to 0 (false). Whenever an exported function in your DLL is called, your DLL function could check this global variable, and if your DLL has not yet initialized itself, it will call your DLL's special initialization function, which performs the download and sets the global variable to 1 (true).
However, checking a global variable on every function call could be expensive in terms of performance. Therefore, the first method may be preferable to the second method.
Upvotes: 1