Скачать файл из библиотеки DLL в C ++ - PullRequest
0 голосов
/ 05 марта 2020

Я пытался загрузить файл, используя код внутри dll, встроенной в C ++ на Windows. DLL будет загружена с помощью функции LoadLibraryA, и я пытаюсь загрузить файл в момент его первой загрузки.

Поиск по inte rnet Мне удалось реализовать URLDownloadToFile(), который работает нормально для консольное приложение, но не в библиотеке Dynami c -Link, встроенной в Visual Studio. В project properties->Linker->Input я добавил дополнительные зависимости Urlmon.lib;Wininet.lib;.

. Код строится успешно (Release, x64), когда я тестирую его с rundll32.exe C:\Users\John\Desktop\Dll1\x64\Release\Dll1.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;
}

1 Ответ

1 голос
/ 05 марта 2020

Точка входа DllMain предназначена для выполнения только простых задач инициализации или завершения. По техническим причинам то, что вам разрешено делать в DllMain, очень ограничено. См. эту ссылку для получения дополнительной информации.

Инициируя загрузку файла, вы, вероятно, вызываете загрузку новых DLL, что не следует делать в DllMain, так как это может вызвать тупик.

Если вы хотите, чтобы ваша DLL имела функцию инициализации без этих ограничений, то вам не следует использовать функцию точки входа DllMain (за исключением простой инициализации). Скорее, вам следует подождать, пока операционная система полностью завершит загрузку вашей DLL.

Например, вам может потребоваться, чтобы все программы, использующие вашу DLL, вызывали специальную функцию инициализации внутри вашей DLL, прежде чем вызывать какие-либо другие функции. внутри вашей DLL. Это довольно часто для DLL, чтобы требовать этого. Например, библиотека DLL библиотеки Microsoft Windows Sockets 2 (Ws2_32.dll) требует, чтобы вы вызывали WSAStartup перед вызовом любых других ее других функций. Эта специальная функция инициализации не имеет тех же ограничений, что и DllMain, потому что технически это обычный вызов функции. Следовательно, он позволяет вам выполнять такие вещи, как загрузка файлов.

В качестве альтернативы ваша DLL может отслеживать, инициализировалась ли она в глобальной переменной. В DllMain вы ничего не делаете, кроме как задаете для этой глобальной переменной значение 0 (false). Всякий раз, когда вызывается экспортированная функция в вашей DLL, ваша функция DLL может проверить эту глобальную переменную, и если ваша DLL еще не инициализировала себя, она вызовет специальную функцию инициализации вашей DLL, которая выполняет загрузку и устанавливает для глобальной переменной значение 1 ( true).

Однако проверка глобальной переменной при каждом вызове функции может быть дорогой с точки зрения производительности. Поэтому первый метод может быть предпочтительнее второго.

...