|
-
March 16th, 2007, 02:20 PM
#1
ListView control creates 2 threads and other strange behaviour
Hello everybody. Back with a few questions about Windows GUI programming, this time about a ListView control. The program fully works so far, no problems, just a few weird things happening with it.
This ListView control is declared and created by a resource file as follows:
Code:
IDD_TAB_CACHE DIALOGEX 2, 68, 224, 179
STYLE DS_SETFONT | DS_FIXEDSYS | DS_CONTROL | WS_CHILD | WS_CLIPCHILDREN
FONT 8, "MS Shell Dlg", 400, 0, 0x1
BEGIN
CONTROL "",IDC_CACHE_LIST,"SysListView32",LVS_REPORT | LVS_SHOWSELALWAYS | WS_TABSTOP,0,0,223,161,WS_EX_CLIENTEDGE
PUSHBUTTON "Select All",IDC_CACHE_SELALL,0,164,50,14
PUSHBUTTON "Select None",IDC_CACHE_SELNONE,53,164,50,14
PUSHBUTTON "Move",IDC_CACHE_MOVESEL,107,164,50,14,WS_DISABLED
PUSHBUTTON "Delete",IDC_CACHE_DELSEL,161,164,50,14,WS_DISABLED
END
Now, I'm using OutputDebugString to write some info to VC++'s debug window in my WndMsgHandler, and I've noticed some strange behaviour coming from this control. Take a look at this bit from my debug window:
Code:
--> cUTool2k4::Setup() returned 0.
--> Tabproc WM_NOTIFY: pNMHDR.idFrom = 1009, pNMHDR.hwndFrom = 0x00050422, pNMHDR.code = -12.
Before the cUTool2k4::Setup() function returns, the dialogs are created and the list is populated with a few entries. After the Setup function, I switch to the tab that holds the ListView control, which makes it send a WM_NOTIFY message with code -12 (NM_CUSTOMDRAW). I don't understand why it's sending this message. I don't want to draw it myself, I want to let the system draw it (which it does anyway). So why am I receiving this? Or is it just to let me know that drawing is about to start?
The next bit:
Code:
--> Tabproc WM_NOTIFY: pNMHDR.idFrom = 1009, pNMHDR.hwndFrom = 0x00050422, pNMHDR.code = -16.
'UTool2k4.exe': Loaded 'C:\WINDOWS\system32\winmm.dll', No symbols loaded.
'UTool2k4.exe': Loaded 'C:\WINDOWS\system32\wdmaud.drv', No symbols loaded.
'UTool2k4.exe': Loaded 'C:\WINDOWS\system32\setupapi.dll', No symbols loaded.
'UTool2k4.exe': Loaded 'C:\WINDOWS\system32\wintrust.dll', No symbols loaded.
'UTool2k4.exe': Loaded 'C:\WINDOWS\system32\crypt32.dll', No symbols loaded.
'UTool2k4.exe': Loaded 'C:\WINDOWS\system32\msasn1.dll', No symbols loaded.
'UTool2k4.exe': Loaded 'C:\WINDOWS\system32\imagehlp.dll', No symbols loaded.
'UTool2k4.exe': Unloaded 'C:\WINDOWS\system32\setupapi.dll'
'UTool2k4.exe': Unloaded 'C:\WINDOWS\system32\wdmaud.drv'
'UTool2k4.exe': Loaded 'C:\WINDOWS\system32\wdmaud.drv', No symbols loaded.
'UTool2k4.exe': Loaded 'C:\WINDOWS\system32\setupapi.dll', No symbols loaded.
'UTool2k4.exe': Unloaded 'C:\WINDOWS\system32\setupapi.dll'
'UTool2k4.exe': Loaded 'C:\WINDOWS\system32\msacm32.drv', No symbols loaded.
'UTool2k4.exe': Loaded 'C:\WINDOWS\system32\msacm32.dll', No symbols loaded.
'UTool2k4.exe': Loaded 'C:\WINDOWS\system32\midimap.dll', No symbols loaded.
--> Tabproc WM_NOTIFY: pNMHDR.idFrom = 1009, pNMHDR.hwndFrom = 0x00050422, pNMHDR.code = -100.
--> Tabproc WM_NOTIFY: pNMHDR.idFrom = 1009, pNMHDR.hwndFrom = 0x00050422, pNMHDR.code = -101.
--> Tabproc WM_NOTIFY: pNMHDR.idFrom = 1009, pNMHDR.hwndFrom = 0x00050422, pNMHDR.code = -12.
--> Tabproc WM_NOTIFY: pNMHDR.idFrom = 1009, pNMHDR.hwndFrom = 0x00050422, pNMHDR.code = -7.
--> Tabproc WM_NOTIFY: pNMHDR.idFrom = 1009, pNMHDR.hwndFrom = 0x00050422, pNMHDR.code = -2.
The above is what happens in my debug window when I left-click an entry in my list. First the ListView control sends WM_NOTIFY with code -16 (NM_RELEASEDCAPTURE). Apparently the control had previously captured mouse input and is now releasing it... I have no idea what this actually means, but I don't think an event like that should start new threads, should it? Because that's what appears to be happening next, with all the symbols not loading (?!). Again, I have no idea what the hell is going on here.
After that, I receive the -100 (LVN_ITEMCHANGING) and -101 (LVN_ITEMCHANGED) notifications to let me know the items appearance is changing (the selection highlight appears).
Then, I receive another -12 (NM_CUSTOMDRAW) notification. Again, I don't want to draw the control myself so I don't know why I am receiving this.
The -7 and -2 notifications are NM_SETFOCUS and NM_CLICK, which are obvious.
Here are some other messages I don't understand:
Code:
--> Tabproc WM_NOTIFY: pNMHDR.idFrom = 1009, pNMHDR.hwndFrom = 0x00050422, pNMHDR.code = -104.
--> Tabproc WM_NOTIFY: pNMHDR.idFrom = 1009, pNMHDR.hwndFrom = 0x00050422, pNMHDR.code = -103.
This happens when I'm closing the main window. The -104 notification is LVN_DELETEALLITEMS. MSDN says the following about its return value:
 Originally Posted by MSDN
To suppress subsequent LVN_DELETEITEM notification messages, return TRUE.
To receive subsequent LVN_DELETEITEM notification messages, return FALSE.
My code is this:
Code:
if (((NMHDR *)lParam)->hwndFrom == GetDlgItem(hTabWnd, IDC_CACHE_LIST)) {
if (((NMHDR *)lParam)->code == LVN_DELETEALLITEMS) {
return true;
}
So why do I still receive a -103 (LVN_DELETEITEM) for every item that's deleted?
Moving on:
Code:
--> Tabproc WM_NOTIFY: pNMHDR.idFrom = 1009, pNMHDR.hwndFrom = 0x00050422, pNMHDR.code = -103.
--> cDlgHax::Cleanup() returned 0.
The thread 'Win32 Thread' (0x5a8) has exited with code 0 (0x0).
The thread 'Win32 Thread' (0x108) has exited with code 0 (0x0).
The program '[1692] UTool2k4.exe: Native' has exited with code 0 (0x0).
After receiving the last LVN_DELETEITEM notification my Cleanup function is done, and WinMain returns. As you can see, 2 threads are terminated as well. I didn't create these threads. These threads seem to be created when I click an entry in the list (remember a few paragraphs up when the "No symbols loaded" messages appeared in the debug window). The only things I've done with the program at this point is run it, switch to tab with ListView control, click an entry, and close it again. This can't be right, can it? I can't imagine any reason the ListView control can have to start threads... What's more, I don't think controls should start threads period. Or they should atleast inform the owning process of it... So what's wrong here?
Well, this turned out to be another beast of a post, and I'm sorry for that. I'm just trying to be as thorough and clear as possible. Thanks for reading if you made it this far!  
As I've said, the program works as expected, no weird errors, but we all know how it goes. If you leave things you're unsure about just hanging around in there, it's going to come back and bite you in the *** later on. So I'm just trying to tighten up the loose ends.
Who can clarify?
Last edited by Jehjoa; March 16th, 2007 at 02:27 PM.
I am a beginning C++ Win32 programmer with LOTS of questions. Hopefully matching answers can be found here... 
-
March 16th, 2007, 04:43 PM
#2
Re: ListView control creates 2 threads and other strange behaviour
Let's clarify then 
Before the cUTool2k4::Setup() function returns, the dialogs are created and the list is populated with a few entries. After the Setup function, I switch to the tab that holds the ListView control, which makes it send a WM_NOTIFY message with code -12 ( NM_CUSTOMDRAW). I don't understand why it's sending this message. I don't want to draw it myself, I want to let the system draw it (which it does anyway). So why am I receiving this? Or is it just to let me know that drawing is about to start?
The NM_CUSTOMDRAW notification is sent whenever (or less) the listview is redrawn. If you read the docs, you'll see that NM_CUSTOMDRAW doesn't ask you to draw anything, it's just used to fill some variables which will be used by windows to draw the listview item (ie, item color, item background color, item font...).
So, in the end, this message "has the rights" to be sent. If you don't handle it, you don't have any custom draw (literally) done by Windows.
The above is what happens in my debug window when I left-click an entry in my list. First the ListView control sends WM_NOTIFY with code -16 ( NM_RELEASEDCAPTURE). Apparently the control had previously captured mouse input and is now releasing it... I have no idea what this actually means, but I don't think an event like that should start new threads, should it? Because that's what appears to be happening next, with all the symbols not loading (?!). Again, I have no idea what the hell is going on here.
This is strange, does TaskManager too display two threads for your application? Maybe it's just the tool you're using for that "debugging"...
So why do I still receive a -103 ( LVN_DELETEITEM) for every item that's deleted?
This is because you're using a dialog, which needs DWL_MSGRESULT to be set to TRUE if the docs say you should return TRUE:
Code:
LPNMHDR nmh = (LPNMHDR)lParam;
if ((nmh->hwndFrom == GetDlgItem(hTabWnd, IDC_CACHE_LIST)) {
if (nmh->code == LVN_DELETEALLITEMS)
{
SetWindowLong(hwnd, DWL_MSGRESULT, TRUE);
return TRUE;
}
Last edited by kkez; March 16th, 2007 at 04:46 PM.
-
March 16th, 2007, 06:13 PM
#3
Re: ListView control creates 2 threads and other strange behaviour
Wow, you managed to clarify a lot with that post! Nice one, thanks. kkez for prez.
 Originally Posted by kkez
So, in the end, this message "has the rights" to be sent. If you don't handle it, you don't have any custom draw (literally) done by Windows.
Aha I see. I suspected it was something along those lines.
 Originally Posted by kkez
This is because you're using a dialog, which needs DWL_MSGRESULT to be set to TRUE if the docs say you should return TRUE:
About the SetWindowLong(hwnd, DWL_MSGRESULT, TRUE) call. I knew about this, but thought it was only needed when you need to return something else than a bool... Does that mean that the actual return value of the dialog procedure doesn't really matter? That I can return true or false?
By the way, I noticed you changed some other code around in your example too. You made a pointer to NMHDR on the stack, and then gave it lParam's value, while I simply used (NMHDR *)lParam constantly. Is your way better? I thought my way is, simply because I don't need extra memory on the stack. Isn't that more efficient?
 Originally Posted by kkez
This is strange, does TaskManager too display two threads for your application? Maybe it's just the tool you're using for that "debugging"...
I had a look at TaskManager while running it in the debugger, and it had 3 threads running. Couldn't get more info than that from TaskManager. As a test, I compiled a release version, closed Visual C++ (and so, the debugger) and ran the .exe by double clicking its icon. Still 3 threads in TaskManager... Again, the only thing I did was switching to the tab and clicking an item in the list.
How do I stop this from happening? Or should it happen? Could there be some kind of project configuration property tied to this? Guess I should go googling for an app that can tell me more about those threads.
If it matters, I'm using Visual Studio 2005 version 8.0.50727.42... (Makes you think about how many internal releases MS must've had... omg)
I am a beginning C++ Win32 programmer with LOTS of questions. Hopefully matching answers can be found here... 
-
March 18th, 2007, 04:02 AM
#4
Re: ListView control creates 2 threads and other strange behaviour
 Originally Posted by Jehjoa
About the SetWindowLong(hwnd, DWL_MSGRESULT, TRUE) call. I knew about this, but thought it was only needed when you need to return something else than a bool... Does that mean that the actual return value of the dialog procedure doesn't really matter? That I can return true or false?
I think you must do both things, but you can try...
 Originally Posted by Jehjoa
By the way, I noticed you changed some other code around in your example too. You made a pointer to NMHDR on the stack, and then gave it lParam's value, while I simply used (NMHDR *)lParam constantly. Is your way better? I thought my way is, simply because I don't need extra memory on the stack. Isn't that more efficient?
Well, copying a pointer doesn't affect the efficiency or the speed of your software. And it's more readable, don't you think? 
 Originally Posted by Jehjoa
I had a look at TaskManager while running it in the debugger, and it had 3 threads running. Couldn't get more info than that from TaskManager. As a test, I compiled a release version, closed Visual C++ (and so, the debugger) and ran the .exe by double clicking its icon. Still 3 threads in TaskManager...  Again, the only thing I did was switching to the tab and clicking an item in the list.
How do I stop this from happening? Or should it happen? Could there be some kind of project configuration property tied to this? Guess I should go googling for an app that can tell me more about those threads.
Believe me, this is not a listview bug. I've got plenty of software that uses listview, and none of them create threads on click. If you can, try to compile with older version of VisualC++ or try to use MinGW and the winapi headers.
BTW, you're not using MFC, do you?
-
March 18th, 2007, 06:12 AM
#5
Re: ListView control creates 2 threads and other strange behaviour
Well, I downloaded Process Explorer from MSDN to have a look at those threads. The first thread's starting address is wdmaud.drv!midMessage+0x306 (screenshot), the second's is winmm.dll!PlaySoundW+0x77f (screenshot). Both of these appear to have something to do with playing sounds, but my program doesn't do anything related to audio (it hardly does anything at all at the moment, as it's mostly GUI code). I don't have any experience with using threads yet, so I don't understand most of the info on the screenshots. I'm hoping you guys can help there. 
I also tried something else to learn more about what's going on. I subclassed the ListView controls window procedure. All it does though, is log the message to the debug window, call the original procedure, and finally log its return value. Now check my debug window:
Code:
/* Notice how most messages return a value immediately */
--> MESSAGE: UINT 0x00000087 (WPARAM 0x00000000, LPARAM 0x00000000)
<-- 0x00000087 returned 0x00000081.
--> MESSAGE: UINT 0x00000201 (WPARAM 0x00000001, LPARAM 0x001A0032)
/* ^^^^ Except for this one, which is WM_LBUTTONDOWN */
--> MESSAGE: UINT 0x00000215 (WPARAM 0x00000000, LPARAM 0x00000000)
<-- 0x00000215 returned 0x00000000.
--> Tabproc WM_NOTIFY: pNMHDR.idFrom = 1009, pNMHDR.hwndFrom = 0x000405BA, pNMHDR.code = -16.
'UTool2k4.exe': Loaded 'C:\WINDOWS\system32\winmm.dll', No symbols loaded.
'UTool2k4.exe': Loaded 'C:\WINDOWS\system32\wdmaud.drv', No symbols loaded.
'UTool2k4.exe': Loaded 'C:\WINDOWS\system32\setupapi.dll', No symbols loaded.
'UTool2k4.exe': Loaded 'C:\WINDOWS\system32\wintrust.dll', No symbols loaded.
'UTool2k4.exe': Loaded 'C:\WINDOWS\system32\crypt32.dll', No symbols loaded.
'UTool2k4.exe': Loaded 'C:\WINDOWS\system32\msasn1.dll', No symbols loaded.
'UTool2k4.exe': Loaded 'C:\WINDOWS\system32\imagehlp.dll', No symbols loaded.
'UTool2k4.exe': Unloaded 'C:\WINDOWS\system32\setupapi.dll'
'UTool2k4.exe': Unloaded 'C:\WINDOWS\system32\wdmaud.drv'
'UTool2k4.exe': Loaded 'C:\WINDOWS\system32\wdmaud.drv', No symbols loaded.
'UTool2k4.exe': Loaded 'C:\WINDOWS\system32\setupapi.dll', No symbols loaded.
'UTool2k4.exe': Unloaded 'C:\WINDOWS\system32\setupapi.dll'
'UTool2k4.exe': Loaded 'C:\WINDOWS\system32\msacm32.drv', No symbols loaded.
'UTool2k4.exe': Loaded 'C:\WINDOWS\system32\msacm32.dll', No symbols loaded.
'UTool2k4.exe': Loaded 'C:\WINDOWS\system32\midimap.dll', No symbols loaded.
--> Tabproc WM_NOTIFY: pNMHDR.idFrom = 1009, pNMHDR.hwndFrom = 0x000405BA, pNMHDR.code = -100.
--> Tabproc WM_NOTIFY: pNMHDR.idFrom = 1009, pNMHDR.hwndFrom = 0x000405BA, pNMHDR.code = -101.
--> MESSAGE: UINT 0x00001032 (WPARAM 0x00000000, LPARAM 0x00000000)
<-- 0x00001032 returned 0x00000001.
--> MESSAGE: UINT 0x00000215 (WPARAM 0x00000000, LPARAM 0x00000000)
<-- 0x00000215 returned 0x00000000.
--> MESSAGE: UINT 0x00000007 (WPARAM 0x00050592, LPARAM 0x00000000)
--> MESSAGE: UINT 0x0000000F (WPARAM 0x00000000, LPARAM 0x00000000)
--> Tabproc WM_NOTIFY: pNMHDR.idFrom = 1009, pNMHDR.hwndFrom = 0x000405BA, pNMHDR.code = -12.
<-- 0x0000000F returned 0x00000000.
--> Tabproc WM_NOTIFY: pNMHDR.idFrom = 1009, pNMHDR.hwndFrom = 0x000405BA, pNMHDR.code = -7.
<-- 0x00000007 returned 0x00000000.
--> Tabproc WM_NOTIFY: pNMHDR.idFrom = 1009, pNMHDR.hwndFrom = 0x000405BA, pNMHDR.code = -2.
<-- 0x00000201 returned 0x00000000.
/* ^^^^ The WM_LBUTTONDOWN isn't returned untill here */
--> MESSAGE: UINT 0x00000084 (WPARAM 0x00000000, LPARAM 0x015B01CC)
<-- 0x00000084 returned 0x00000001.
I tried using the keyboard to select an item, but the same thing happens. Just substitute WM_LBUTTONDOWN with WM_KEYDOWN...
 Originally Posted by kkez
Believe me, this is not a listview bug. I've got plenty of software that uses listview, and none of them create threads on click. If you can, try to compile with older version of VisualC++ or try to use MinGW and the winapi headers.
Oh, I'm sure it's really nothing to do with the control itself. Millions of programs use it without problems, and if I as a newbie programmer get unexpected results it's probably not Microsoft's fault. Unfortunately I don't have another compiler, so I can't try that...
The program is most definitely not using MFC. I've started by creating an empty Win32 project, so it doesn't even have any afx includes. I've set a resource property called "Uses MFC" to false and I even #defined WIN32_LEAN_AND_MEAN!
Last edited by Jehjoa; March 18th, 2007 at 06:30 AM.
I am a beginning C++ Win32 programmer with LOTS of questions. Hopefully matching answers can be found here... 
-
March 20th, 2007, 03:53 AM
#6
Re: ListView control creates 2 threads and other strange behaviour
Well that is funny. I was just working on a little side project (the Process Explorer program made me interested in trying to make a similar program myself), it uses a ListView control as well, and that also creates 2 extra threads when clicked.
This is the second time I've used a ListView control and both times it creates the threads, so I'm beginning to think this is just default behaviour... But on the other hand, that just can't be right.
I wish one of the elite Microsoft MVP dudes would notice this thread, I'd really like this explained...
I am a beginning C++ Win32 programmer with LOTS of questions. Hopefully matching answers can be found here... 
-
March 20th, 2007, 05:41 PM
#7
Re: ListView control creates 2 threads and other strange behaviour
Is your project open-source? If yes, just send me the code and i'll try to see what's happening.
-
March 21st, 2007, 12:05 PM
#8
Re: ListView control creates 2 threads and other strange behaviour
Sure, I don't mind sharing my code... There's hardly anything interesting in it at the moment, anyway. Thanks for having a look kkez, that's pretty cool.
I uploaded a file here so anyone can have a look if they want. It contains the UTool project, but because the ListView control won't be shown unless you have a certain game installed, I also included the code for the process utility I started on. It's very, very simple, but atleast it shows the ListView control and it has the same problem.
Since I'm still new to all of this, I also wouldn't mind some general comments or critiques on my coding style, if you have the time... 
Thanks again!
Last edited by Jehjoa; March 21st, 2007 at 12:08 PM.
I am a beginning C++ Win32 programmer with LOTS of questions. Hopefully matching answers can be found here... 
-
March 21st, 2007, 04:29 PM
#9
Re: ListView control creates 2 threads and other strange behaviour
I modified the source to let mingw compile it, here's the source and the executable. The resulting exe has only one thread as TaskManager reports.
As for the coding style, there's just a little disorder, put some space between different parts of code - ie this is hard to read:
Code:
ListView_SetExtendedListViewStyle(hList, LVS_EX_FULLROWSELECT);
LVCOLUMN lvc;
ZeroMemory(&lvc, sizeof(lvc));
lvc.mask = LVCF_FMT | LVCF_WIDTH | LVCF_TEXT | LVCF_SUBITEM | LVCF_ORDER;
lvc.fmt = LVCFMT_LEFT;
lvc.cx = 190;
lvc.pszText = TEXT("Process name");
lvc.iSubItem = 0;
lvc.iOrder = 0;
ListView_InsertColumn(hList, 0, &lvc);
lvc.cx = 50;
lvc.pszText = TEXT("ID");
lvc.iSubItem = 1;
lvc.iOrder = 1;
ListView_InsertColumn(hList, 0, &lvc);
HANDLE hSnap; hSnap = NULL;
PROCESSENTRY32 pe32;
ZeroMemory(&pe32, sizeof(pe32));
pe32.dwSize = sizeof(pe32);
hSnap = CreateToolhelp32Snapshot(TH32CS_SNAPPROCESS, 0);
TCHAR szPID[10];
ZeroMemory(&szPID, sizeof(szPID));
int iCount = 0;
LVITEM lvi;
ZeroMemory(&lvi, sizeof(lvi));
if (Process32First(hSnap, &pe32)) {
lvi.iItem = iCount;
ListView_InsertItem(hList, &lvi);
lvi.mask = LVIF_TEXT;
lvi.iSubItem = 1;
lvi.pszText = pe32.szExeFile;
ListView_SetItem(hList, &lvi);
lvi.iSubItem = 0;
_stprintf(szPID, TEXT("%d"), pe32.th32ProcessID);
lvi.pszText = szPID;
ListView_SetItem(hList, &lvi);
iCount ++;
ZeroMemory(&szPID, sizeof(szPID));
ZeroMemory(&lvi, sizeof(lvi));
ZeroMemory(&pe32, sizeof(pe32));
pe32.dwSize = sizeof(pe32);
while (Process32Next(hSnap, &pe32)) {
lvi.iItem = iCount;
ListView_InsertItem(hList, &lvi);
lvi.mask = LVIF_TEXT;
lvi.iSubItem = 1;
lvi.pszText = pe32.szExeFile;
ListView_SetItem(hList, &lvi);
lvi.iSubItem = 0;
_stprintf(szPID, TEXT("%d"), pe32.th32ProcessID);
lvi.pszText = szPID;
ListView_SetItem(hList, &lvi);
iCount ++;
ZeroMemory(&szPID, sizeof(szPID));
ZeroMemory(&lvi, sizeof(lvi));
ZeroMemory(&pe32, sizeof(pe32));
pe32.dwSize = sizeof(pe32);
}
}
-
March 21st, 2007, 04:37 PM
#10
-
March 22nd, 2007, 04:44 AM
#11
Re: ListView control creates 2 threads and other strange behaviour
Well I ran the listview_thread.exe and sure enough, after clicking a list item the threadcount in Task Manager changes from 1 to 3... You did click an item while testing, right?
Yes i did, and still one thread.
If you did, how can it happen on my PC but not on yours?
Are you on windows xp?
-
March 22nd, 2007, 05:50 AM
#12
Re: ListView control creates 2 threads and other strange behaviour
Yeah, Windows XP SP2...
I am a beginning C++ Win32 programmer with LOTS of questions. Hopefully matching answers can be found here... 
Posting Permissions
- You may not post new threads
- You may not post replies
- You may not post attachments
- You may not edit your posts
-
Forum Rules
|
Click Here to Expand Forum to Full Width
|