Я публикую новый ответ, который больше соответствует вашему обновленному вопросу (и для того, чтобы иметь право на получение награды). Рассмотрим сначала этот минимальный источник для обычного исполняемого файла, который содержит индикатор выполнения:
#include <Windows.h>
#include <CommCtrl.h>
#pragma comment(lib, "Comctl32.lib")
#include "resource.h"
#pragma comment(linker,"\"/manifestdependency:type='win32' \
name='Microsoft.Windows.Common-Controls' version='6.0.0.0' \
processorArchitecture='*' publicKeyToken='6595b64144ccf1df' language='*'\"")
#define PROGRESSBAR_TIMER_ID 1
/*
* This callback is invoked each time the main window receives a message.
*/
INT_PTR CALLBACK DialogFunc(HWND hwndDlg, UINT uMsg, WPARAM wParam, LPARAM lParam)
{
switch(uMsg) {
case WM_INITDIALOG: {
/*
* Fire a timer event each second.
*/
SetTimer(hwndDlg, PROGRESSBAR_TIMER_ID, 1000, NULL);
break;
}
case WM_TIMER: {
/*
* Catch the timer event that is fired each second. Increment the progress
* bar by 10% each time.
*/
HWND hwndProgressBar = GetDlgItem(hwndDlg, IDC_PROGRESS1);
UINT iPos = SendMessage(hwndProgressBar, PBM_GETPOS, 0, 0);
/*
* If the position is already full then kill the timer. Else increment the
* progress bar.
*/
if(iPos >= 100) {
KillTimer(hwndDlg, PROGRESSBAR_TIMER_ID);
} else {
SendMessage(hwndProgressBar, PBM_SETPOS, iPos + 10, 0);
}
break;
}
case WM_CLOSE:
EndDialog(hwndDlg, 0);
break;
default:
return FALSE;
}
return TRUE;
}
BOOL LaunchGUI(HINSTANCE hInstance)
{
return DialogBox(hInstance, MAKEINTRESOURCE(IDD_DIALOG1), NULL, DialogFunc) == 0;
}
int CALLBACK WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine, int nCmdShow)
{
/*
* Initialise the common controls DLL.
*/
INITCOMMONCONTROLSEX iccex;
iccex.dwSize = sizeof(iccex);
iccex.dwICC = ICC_PROGRESS_CLASS | ICC_STANDARD_CLASSES | ICC_WIN95_CLASSES;
if(!InitCommonControlsEx(&iccex)) {
MessageBox(NULL, L"Problem initialising common controls DLL.", NULL, MB_OK);
return -1;
}
/*
* Launches the main GUI window.
*/
LaunchGUI(hInstance);
return ERROR_SUCCESS;
}
Если хотите, я могу опубликовать соответствующий файл ресурсов .rc
для этой программы, хотя этот код в основном предназначен для того, чтобы вы получили правильное концептуальное понимание. Итак, чтобы быстро подвести итог, эта программа:
- Содержит одно диалоговое окно, содержащее один индикатор выполнения
- Устанавливает таймер для срабатывания каждую секунду
- Каждый раз, когда срабатывает таймер, сообщение таймера запускает индикатор выполнения для обновления
Графически это выглядит так:
Ваш вопрос состоит в том, как вместо этого увеличить эту панель из DLL. То, что вам нужно сделать, это дать возможность DLL взаимодействовать с окном, содержащим индикатор выполнения. Я не совсем уверен, как вы загружаете DLL, но такой подход я бы использовал, предполагая, что это происходит путем внедрения DLL:
- Загрузить / вставить DLL в цель
- Пусть DLL экспортирует некоторую процедуру инициализации, позволяющую ей получать информацию о процессе инжектора / клиента.
- Используйте
GetProcAddress
и CreateRemoteThread
от клиента для вызова этой процедуры инициализации.
- В DLL используйте полученную информацию для получения
HWND
клиента.
Конкретно, процедура инициализации будет выглядеть так:
HWND hwndClient = NULL;
BOOL CALLBACK EnumProc(HWND hwnd, LPARAM lParam)
{
DWORD dwPID;
GetWindowThreadProcessId(hwnd, &dwPID);
if(dwPID == lParam) {
hwndClient = hwnd;
}
}
/*
* This code assumes the client has only one window. Given a PID, it populates
* a global to hold the window handle associated with the PID.
*/
DWORD WINAPI ReceiveClientPID(LPVOID dwPID)
{
EnumWindows(EnumProc, (LPARAM)dwPID);
}
Код клиента может выглядеть примерно так:
/*
* Depending on your method of injection, you should have a handle to the
* target process as well as a HMODULE of the injected DLL.
*/
void InitDLL(HANDLE hProcess, HMODULE hModule)
{
FARPROC lpInit = GetProcAddress(hModule, "ReceiveClientPID");
HANDLE hThread = CreateRemoteThread(hProcess, NULL, NULL,
(LPTHREAD_START_ROUTINE)lpInit, (LPVOID)GetCurrentProcessId(), NULL, NULL);
if(hThread == NULL) {
MessageBox(NULL, L"Problem calling init routine in DLL", NULL, MB_OK);
} else {
CloseHandle(hThread);
}
}
Итак, теперь у вас есть HWND
клиента в DLL и, следовательно, способ связи. Затем вы можете указать пользовательское сообщение в клиенте, чтобы изменить индикатор выполнения:
/*
* The new progress position can be passed in wParam.
*/
#define WM_UPDATE_PROGRESS_BAR (WM_APP + 1)
Также добавьте соответствующий регистр в DialogFunc
(мы можем удалить код WM_TIMER
сейчас, потому что он был только там, чтобы продемонстрировать, как взаимодействовать с индикаторами выполнения):
case WM_UPDATE_PROGRESS_BAR:
SendMessage(GetDlgItem(hwndDlg, IDC_PROGRESS1), PBM_SETPOS, wParam, 0);
break;
А теперь, чтобы вызвать изменения в индикаторе выполнения клиента, DLL просто нужно сделать:
SendMessage(hwndClient, WM_UPDATE_PROGRESS_BAR, ..., 0);
Обратите внимание, что WM_UPDATE_PROGRESS_BAR
также необходимо переопределить в DLL.
Чтобы все это соответствовало вашему текущему коду:
/*
* Assumed progress is between 0 and 100. Otherwise it has to be
* normalised so this is the case (or the range of the progress bar
* in the client has to be changed).
*/
int my_progressor_callback(long progress)
{
SendMessage(hwndClient, WM_UPDATE_PROGRESS_BAR, progress, 0);
return 0;
}