【发布时间】:2010-12-21 06:29:25
【问题描述】:
我有一个用 C 编写的 Windows 应用程序(使用 gcc/MinGW),除了一些 UI 问题外,它运行良好。一,我根本无法从线程更新进度条。事实上,我可能无法更新任何 UI 内容。
基本上,我有一个生成的线程进行一些处理,并且我尝试从该线程更新主线程中的进度条。我通过对主 hwnd 使用 PostMessage() 进行了尝试,但即使我可以做其他事情,例如打开消息框,也没有运气。但是,尚不清楚消息框是在线程中调用还是在主线程中调用。
这里有一些代码:
// in header/globally accessible
HWND wnd; // main application window
HWND progress_bar; //progress bar
typedef struct { //to pass to thread
DWORD mainThreadId;
HWND mainHwnd;
char *filename;
} THREADSTUFF;
//callback function
LRESULT CALLBACK WndProc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam){
switch (msg){
case WM_CREATE:{
// create progress bar
progress_bar = CreateWindowEx(
0,
PROGRESS_CLASS,
(LPCTSTR) NULL,
WS_CHILD | WS_VISIBLE,
79,164,455,15,
hwnd,
(HMENU)20,
NULL,
NULL);
SendMessage(progress_bar, PBM_SETSTEP, 1, 0 );
SendMessage(progress_bar, PBM_SETPOS, 0, 0 );
//test to make sure it actually works
SendMessage(progress_bar, PBM_STEPIT, 0, 0 ); //works fine
SendMessage(progress_bar, PBM_STEPIT, 0, 0 ); //works fine
SendMessage(progress_bar, PBM_STEPIT, 0, 0 ); //works fine
SendMessage(progress_bar, PBM_STEPIT, 0, 0 ); //works fine
break;
}
case WM_COMMAND: {
if(LOWORD(wParam)==2){ //do some processing in a thread
//struct of stuff I need to pass to thread
THREADSTUFF *threadStuff;
threadStuff = (THREADSTUFF*)malloc(sizeof(*threadStuff));
threadStuff->mainThreadId = GetCurrentThreadId();
threadStuff->mainHwnd = hwnd;
threadStuff->filename = (void*)&filename;
hThread1 = CreateThread(NULL,0,convertFile (LPVOID)threadStuff,0,NULL);
}else if(LOWORD(wParam)==5){ //update progress bar
MessageBox(hwnd,"I got a message!", "Message", MB_OK | MB_ICONINFORMATION);
PostMessage(progress_bar,PBM_STEPIT,0,0);
}
break;
}
}
}
这一切似乎都正常。问题出在线程中:
DWORD WINAPI convertFile(LPVOID params){
//get passed params, this works perfectly fine
THREADSTUFF *tData = (THREADSTUFF*)params;
MessageBox(tData->mainHwnd,tData->filename,"File name",MB_OK | MB_ICONINFORMATION); //yep
PostMessage(tData->mainHwnd,WM_COMMAND,5,0); //only shows message
PostThreadMessage(tData->mainThreadId,WM_COMMAND,5,0); //does nothing
}
当我说“只显示消息”时,这意味着回调中的 MessageBox() 函数有效,但 PostMessage() 不能更新进度条的位置。
如果我使用 PostThreadMessage() 将消息发送到主线程的消息循环,我可以拦截它并启动 MessageBoxes,因此它肯定可以工作。但是,即使我尝试以这种方式更新进度条。它仍然不会更新。
我错过了什么?
【问题讨论】:
-
这看起来像你的主窗口的窗口过程,对吧?现场没有模态对话框?假设是这种情况,那么这里有一根救命稻草:MSDN 说 PBM_STEPIT 消息参数都必须为零,但您传递的是 0xff000000 的 CLR_DEFAULT。我还假设您没有将范围设置为 0-0 或类似的东西。
-
我注意到了,但这并没有什么不同。当从主线程调用时,任何一个值都可以工作,但从工作线程调用时,这两个值都不会工作。我更新了代码以显示 0,0。
-
我想通了。问题是我在它为自己创建的线程中有另一个 HWND,但 WNDCLASSEX 变量名称与主线程中的名称相同。我将变量名称更改为其他名称,现在它可以工作了。然而,我不知道这是为什么。即使 var 名称相同,它也不应该影响线程,因为它不在同一个范围内,对吧?
-
对不起,我的意思是“类名”,而不是变量名。您使用 RegisterClassEx() 注册的类。如果它与主线程的窗口类命名相同,则进度条不会更新。
-
您的意思是您在两次调用RegisterClassEx 时使用了相同的名称(PROGRESS_CLASS)?第二次这样的调用将失败。变量范围在这里不相关——在内部,Windows 保留了一个已注册类的列表。然后,当您创建进度条窗口时,它将与主窗口具有相同的类,这意味着它将使用相同的窗口过程。该窗口过程没有 WM_COMMAND/PBM_STEPIT 的处理程序。
标签: windows multithreading winapi mingw