Sid*_*Bob 1 dll winapi frameworks
我正在编写一个dll,它是另一个没有COM支持的dll(内部dll)的COM包装器.内部dll执行冗长的计算,并让外部dll通过回调函数知道进度如何.外部dll只是使函数在COM上可见.
但是,我需要外部dll弹出一个进度条对话框(我正在服务的COM客户端因各种原因无法自行完成).那我该怎么做呢?到目前为止,我看到的所有示例都围绕着具有WinMain入口点的Win32应用程序; 如果我们在需要对话时已经在dll调用中可以做什么?
我是Windows GUI编程的新手,所以我的深度非常深入.现有代码包含在下面 - 具体的建议,如何调用哪里将受到赞赏.我猜我可能需要启动第二个线程来刷新进度对话框.
内部dll .h文件(用于隐式链接):
#define INNER_API extern "C" __declspec(dllimport)
//create calculation, passing callbacks for warning messages and progress bar
INNER_API Calculation* __stdcall calc_create(...blah...,
int (__cdecl *set_progressor_callback)(long),
int (__cdecl *print_warning_callback)(const char*));
INNER_API void __stdcall calc_run(Calculation *c);
Run Code Online (Sandbox Code Playgroud)
然后在外部dll中,com包装器,ComWrapperObject.cpp:
int my_progressor_callback(long progress)
{
//set progressor to equal progress, but how?
return 0;
}
STDMETHODIMP ComWrapperObject::do_calculation()
{
//fire up progress bar and message window here, but how?
Calculation *calc = calc_create(...blah..., &my_progressor_callback);
calc_run(calc);
//wait for user to dismiss message window, but how?
return S_OK;
}
Run Code Online (Sandbox Code Playgroud)
我发布的新答案与您更新的问题更相关(并且有资格获得赏金).首先考虑这个包含进度条的常规可执行文件的最小来源:
#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;
}
Run Code Online (Sandbox Code Playgroud)
如果您愿意,我可以发布.rc此程序的相关资源文件,尽管代码主要是为了您获得正确的概念性理解.所以要快速总结一下,这个程序:
从图形上看,它看起来像这样:

您的问题是如何从DLL增加此栏.您需要做的是允许DLL以某种方式与包含进度条的窗口进行通信.我不太确定你是如何加载DLL的,但这是我假设通过DLL注入完成的方法:
GetProcAddress和CreateRemoteThread从客户端调用此初始化例程.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);
}
Run Code Online (Sandbox Code Playgroud)
客户端代码可能是这样的:
/*
* 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);
}
}
Run Code Online (Sandbox Code Playgroud)
所以现在你拥有HWNDDLL中的客户端,因此你可以进行通信.然后,您可以在客户端中指定自定义消息以更改进度条:
/*
* The new progress position can be passed in wParam.
*/
#define WM_UPDATE_PROGRESS_BAR (WM_APP + 1)
Run Code Online (Sandbox Code Playgroud)
同时添加相应的大小写DialogFunc(我们WM_TIMER现在可以删除代码,因为那只是为了演示如何与进度条进行交互):
case WM_UPDATE_PROGRESS_BAR:
SendMessage(GetDlgItem(hwndDlg, IDC_PROGRESS1), PBM_SETPOS, wParam, 0);
break;
Run Code Online (Sandbox Code Playgroud)
现在要触发客户端进度条的更改,DLL只需执行以下操作:
SendMessage(hwndClient, WM_UPDATE_PROGRESS_BAR, ..., 0);
Run Code Online (Sandbox Code Playgroud)
请注意,还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;
}
Run Code Online (Sandbox Code Playgroud)
| 归档时间: |
|
| 查看次数: |
5468 次 |
| 最近记录: |