Thread: Subitems in ListView and

  1. #16
    train spotter
    Join Date
    Aug 2001
    Location
    near a computer
    Posts
    3,868
    Break the parts down and test each.

    Test your LV code with test data (comment out the process enum).

    What does GetLastError() return?

    Have you already added the columns successfully?
    Does ListView_SetItemText() work any better?
    What happens if OpenProcess() returns NULL && i==0?
    What happens if OpenProcess() returns NULL && i!=0?
    [two test cases, prev success and no prev success]

    What happens if the process name is more than the 10 chars you are allowing in the LV? (I would use lstrlen(text) for max text )


    I use an array / linked list of data structures (inc display strings, display colour codes etc).

    I save the index/node pointer as the LPARAM of each LV item.

    >>itoa(dwProcesses[i],PIDbuf,10);

    I prefer something like

    _snprintf(PIDbuf,9,"%03d",dwProcesses[i]);
    "Man alone suffers so excruciatingly in the world that he was compelled to invent laughter."
    Friedrich Nietzsche

    "I spent a lot of my money on booze, birds and fast cars......the rest I squandered."
    George Best

    "If you are going through hell....keep going."
    Winston Churchill

  2. #17
    HelpingYouHelpUsHelpUsAll
    Join Date
    Dec 2007
    Location
    In your nightmares
    Posts
    223
    I have tried testing with test data, but I still cann't place anything into a column other than the first, without forcing i to be a specific int eg. AddIndex(PIDbuf, 2, 1).
    ListView_InsertItem returns the index of the new item if successful, or -1 otherwise and LVM_SETITEM returns TRUE if successful, or FALSE otherwise. So would GetLastError() be helpful?
    I am sure I have added the columns successfully as I used to be able to add items into any column and I have not changed the function that configures them since. Also the columns appear and can be resized.
    What happens if the process name is more than the 10 chars you are allowing in the LV?
    ****Sorry for this i just realised what you were talking about - I have now changed it to your suggestion - LvI.cchTextMax = lstrlen(text); - even though it did allow more than 10 chars anyway****
    This is extremely unlikely to happen as Windows doesn't use PIDs that are that long. Every PID I have seen is 4chars long and mostly <5000. However if I force 10000000000 into PIDbuf it comes out with 1410065408. Also 1000000000000000000000000000 comes out as negative. Unexpected...
    Last edited by P4R4N01D; 12-30-2007 at 12:46 AM. Reason: Stuffup (confusion)
    long time no C; //seige
    You miss 100% of the people you don't C;
    Code:
    if (language != LANG_C && language != LANG_CPP)
        drown(language);

  3. #18
    C++まいる!Cをこわせ!
    Join Date
    Oct 2007
    Location
    Inside my computer
    Posts
    24,654
    I'm not sure if you actually can't add items or just can't see them, if which is true, have you tried applying the LVS_REPORT style? Otherwise subitems won't show.
    InsertItem doesn't set GetLastError if it fails... not to my knowledge anyway.
    Quote Originally Posted by Adak View Post
    io.h certainly IS included in some modern compilers. It is no longer part of the standard for C, but it is nevertheless, included in the very latest Pelles C versions.
    Quote Originally Posted by Salem View Post
    You mean it's included as a crutch to help ancient programmers limp along without them having to relearn too much.

    Outside of your DOS world, your header file is meaningless.

  4. #19
    HelpingYouHelpUsHelpUsAll
    Join Date
    Dec 2007
    Location
    In your nightmares
    Posts
    223
    My intention was to create the listview in LVS_REPORT style, from which I had from the begining. Here is wht I have now:
    Code:
    int getProcesses() {
    
    	HMODULE hModule;
    	char szProcessName[MAX_PATH] = {0};
    	DWORD dwProcesses[1024], cbNeeded, cProcesses;
    	unsigned int i;
    	char PIDbuf[10];
    
    	if (!EnumProcesses(dwProcesses, sizeof(dwProcesses), &cbNeeded))
    		return -1;
    	cProcesses = cbNeeded / sizeof(DWORD);
    	for (i = 0; i < cProcesses; i++)
    		if(dwProcesses[i] != 0)
    		{
    			HANDLE hProcess = OpenProcess(PROCESS_QUERY_INFORMATION |
    				PROCESS_VM_READ, FALSE, dwProcesses[i]);
    			if (NULL != hProcess)
    			{
    				strcpy(szProcessName, "System");
    				if (EnumProcessModules(hProcess, &hModule, sizeof(hModule),
    					&cbNeeded))
    				{
    					GetModuleBaseName(hProcess, hModule, szProcessName,
    						sizeof(szProcessName)/sizeof(CHAR));
    				}
    			}
    			AddIndex(szProcessName, i, 0);
    			CloseHandle(hProcess);
    		}
    
    	for (i = 0; i < cProcesses; i++) {
    		_snprintf(PIDbuf,9,"%01d",dwProcesses[i]);
    		AddIndex(PIDbuf, i, 1);
    	}
    	return cProcesses;
    }
    However, this leads me back to the problem I started with:
    However, I think EnumProcesses() is getting the Process IDs in a different order to PdhEnumObjectItems() gets the names of all the processes. The result is the PIDs don't match the process names they are against...
    I think it would be a better approach using structs to store the data to go into the listview, as then it will be easier to enter additional information about each process. How would I implement this?
    long time no C; //seige
    You miss 100% of the people you don't C;
    Code:
    if (language != LANG_C && language != LANG_CPP)
        drown(language);

  5. #20
    train spotter
    Join Date
    Aug 2001
    Location
    near a computer
    Posts
    3,868
    Try changing the unsigned int 'i' to just an int.

    You still have a logic error in your main loop.

    What is added to the LV if OpenProcess() fails? [either garbage, null or a copy of the last process that succeed is added to both columns]

    I suggest you init all variables to NULL/empty as a general rule in all your code. In debug mode the complier inits them to NULL/empty. Not so in release mode. I have lost track of the number of bugs I have hunted down due to incorrect init of variables (usually combined with some other 'feature').

    Did you fix the adding to the LV issue?
    I was wondering if it was memory error due to the buffer over run from setting the max text to 10 (even if the string for the name (not PID) was longer than 9 characters).

    GetLastError() tells you WHAT went wrong, not just that something went wrong. ie access denied is 5 or incorrect param is 87.

    You can add a call to SetLastError(ERROR_SUCCESS) to ensure that the error is actually being set when debugging a line that is failing.


    Create a structure to hold data on a processes.

    Change functions to work on this array or elements of it. ie AddIndex() takes a struct and adds item and all subitems at once, then set the LPARAM to the index or node (pointer to element).

    Something like........
    Code:
    typedef struct PROC_DATA
    {
                    //linked list?
    	PROC_DATA             *pPrev;
    	PROC_DATA             *pNext;
                    //OR index for array?
    	int		iIndex;
    
    	int		iPID; 
    	char		szName[MAX_PATH]; 
    	char		szDir[MAX_PATH]; 
    
    	char		szDisplayStrings[NUM_LV_COLS][MAX_PATH]; 
    };
    
    void AddIndex(PROC_DATA *pProcess) 
    {
            //add test for incorrect input
           //set the index here?
           pProcess->iIndex=Listview_GetItemCount();
    
            LVITEM LvI;
            for (int iCol=0;iCol<NUM_LV_COLS;iCol++)
            {
                     if (iCol== 0)
                     {
                            ZeroMemory(&lvI,sizeof(LVITEM)); 	
                            LvI.mask = LVIF_TEXT | LVIF_LPARAM;
                            LvI.cchTextMax = lstrlen(pProcess->szDisplayStrings[0]);
                            LvI.iItem = pProcess->iIndex;
                            LvI.iSubItem = 0;
                            //for a linked list
                            LvI.lParam = &pProcess;//or pProcess->iIndex
                            LvI.pszText = pProcess->szDisplayStrings[0];
                            ListView_InsertItem(GetDlgItem(hwndMain, 3001), &LvI);
                   }
                   else
                            Listview_SetItemText(GetDlgItem(hwndMain, 3001) ,pProcess->iIndex, iCol, pProcess->szDisplayStrings[i])
             }
    }

    Declare an array of the struct (or linked list)
    Create LV
    Add Columns to LV
    Find number of processes
    Alloc array (different for linked list)
    Fill array with data (I call ZeroMemory() on each elelment first)
    Fill LV with data
    Free array on exit
    "Man alone suffers so excruciatingly in the world that he was compelled to invent laughter."
    Friedrich Nietzsche

    "I spent a lot of my money on booze, birds and fast cars......the rest I squandered."
    George Best

    "If you are going through hell....keep going."
    Winston Churchill

  6. #21
    Registered User
    Join Date
    Mar 2005
    Location
    Mountaintop, Pa
    Posts
    1,058
    It seems like we're just "pulling at straws" on this issue. So, I hacked one of my listview apps to perform the necessary process enumeration. I've used the following code to load the listview with the process names.

    Code:
    void InsertRow (HWND hWnd, char *col1, char *col2)
    {
    	LV_ITEM     lvItem;
    
    	lvItem.mask = 0;
    	lvItem.iItem = 0;
    	lvItem.iSubItem = 0;
    	lvItem.iItem = ListView_InsertItem (hWnd, &lvItem);
    
    	lvItem.mask = LVIF_TEXT;
    	lvItem.pszText = col1;
    	lvItem.cchTextMax = strlen (lvItem.pszText);
    	ListView_SetItem (hWnd, &lvItem);
    
    	lvItem.iSubItem = 1;
    	lvItem.pszText = col2;
    	lvItem.cchTextMax = strlen (lvItem.pszText);
    	ListView_SetItem (hWnd, &lvItem);
    }
    
       // Following code is in your calling function
    	HMODULE hModule;
    	char szProcessName[MAX_PATH] = {0};
    	DWORD dwProcesses[1024], cbNeeded, cProcesses;
    	unsigned int i;
    	char PIDbuf[10];
    	if (!EnumProcesses(dwProcesses, sizeof(dwProcesses), &cbNeeded))
    		return;
    	cProcesses = cbNeeded / sizeof(DWORD);
    	for (i = 0; i < cProcesses; i++)
    		if(dwProcesses[i] != 0)
    		{
    			HANDLE hProcess = OpenProcess(PROCESS_QUERY_INFORMATION |
    				PROCESS_VM_READ, FALSE, dwProcesses[i]);
    			if (NULL != hProcess)
    			{
    				strcpy(szProcessName, "Unknown");
    
    				if (EnumProcessModules(hProcess, &hModule, sizeof(hModule),
    					&cbNeeded))
    				{
    					GetModuleBaseName(hProcess, hModule, szProcessName,
    						sizeof(szProcessName)/sizeof(CHAR));
    				}
    			}
    			sprintf(PIDbuf, "%d", dwProcesses[i]);
    			InsertRow (hWndListView, PIDbuf, szProcessName );
    			CloseHandle(hProcess);
    		}

  7. #22
    HelpingYouHelpUsHelpUsAll
    Join Date
    Dec 2007
    Location
    In your nightmares
    Posts
    223

    Smile Solved...Finally

    Thanks esp. to BobS0327 and all the people who posted in the thread, as I finally have this ListView sorted. So happy, that I can now get on with finishing the program as alot of features depended upon that working properly. I won't post the final solution up unless someone wants it, as BobS0327 was spot on. I hope I won't need any more help with ListViews - one of the hardest controls to work with.
    long time no C; //seige
    You miss 100% of the people you don't C;
    Code:
    if (language != LANG_C && language != LANG_CPP)
        drown(language);

  8. #23
    HelpingYouHelpUsHelpUsAll
    Join Date
    Dec 2007
    Location
    In your nightmares
    Posts
    223

    Question Last thing...

    Really sorry for bringing this up again (i didn't want to start a new thread), what is the best way to refresh a listview? I have got a timer set up and have the following code handling the WM_TIMER message:
    Code:
    BOOL lResult = -1;
            lResult = SendMessage(GetDlgItem(hwndMain, 3001),LVM_FIRST+66,0,0);
    	SendDlgItemMessage(hwndMain, 3001, LVM_DELETEALLITEMS, 0, 0);
    	SetDlgItemText(hwndMain,1024,itoa(getProcesses(),processBuf,10));
    	LVITEM LVI;
    	LVI.mask = LVIF_STATE;
    	LVI.iItem = lResult;
    	LVI.iSubItem = 0;
    	LVI.state = LVIS_SELECTED;
    	LVI.stateMask = LVIS_SELECTED;
    	SendMessage(GetDlgItem(hwndMain, 3001), LVM_SETITEM,0, (LPARAM) &LVI);
    This gets the selection mark (LVM_FIRST+66 = LVM_GETSELECTIONMARK), deletes all items from the LV, refreshes it (SetDlgItemText...) then selects the previously selected index. This only seems to work through one refresh, then the selection is cleared. I was wondering is there a better way? If an item is deleted in the refresh it doesn't need to be selected again.
    long time no C; //seige
    You miss 100% of the people you don't C;
    Code:
    if (language != LANG_C && language != LANG_CPP)
        drown(language);

  9. #24
    C++まいる!Cをこわせ!
    Join Date
    Oct 2007
    Location
    Inside my computer
    Posts
    24,654
    Well, if the control handles WM_PAINT, then you can call RedrawWindow.
    Quote Originally Posted by Adak View Post
    io.h certainly IS included in some modern compilers. It is no longer part of the standard for C, but it is nevertheless, included in the very latest Pelles C versions.
    Quote Originally Posted by Salem View Post
    You mean it's included as a crutch to help ancient programmers limp along without them having to relearn too much.

    Outside of your DOS world, your header file is meaningless.

  10. #25
    Registered User
    Join Date
    Mar 2005
    Location
    Mountaintop, Pa
    Posts
    1,058
    Give the following a try.


    Code:
    BOOL lResult = -1;
            lResult = SendMessage(GetDlgItem(hwndMain, 3001),LVM_FIRST+66,0,0);
    	SendDlgItemMessage(hwndMain, 3001, LVM_DELETEALLITEMS, 0, 0);
    	SetDlgItemText(hwndMain,1024,itoa(getProcesses(),processBuf,10));
    	LVITEM LVI;
    	LVI.mask = LVIF_STATE;
    	LVI.iItem = lResult;
    	LVI.iSubItem = 0;
    	LVI.state = LVIS_SELECTED;
    	LVI.stateMask = LVIS_SELECTED;
    	SendMessage(GetDlgItem(hwndMain, 3001), LVM_SETITEM,0, (LPARAM) &LVI);
    	SendMessage(GetDlgItem(hwndMain, 3001), WM_SETREDRAW, TRUE, 0);
    	UpdateWindow(GetDlgItem(hwndMain, 3001));

  11. #26
    HelpingYouHelpUsHelpUsAll
    Join Date
    Dec 2007
    Location
    In your nightmares
    Posts
    223

    Smile Well there's how to use a ListView

    ****Fixed. Solved with the following code, i was right about the focus****
    Sorry, that works the same as before. It reselects the item fine except for the the fact that there are none of those dots surrounding the item saying the ListView is in focus. I think this may be the problem as if the LV refreshes when the dots are surrounding the selected item, it stays selected. Another weird thing, upon using the arrow keys to go up or down, after the LV has been refreshed, the selection jups to the top of the list (even if the selected item was 1/2 way down). I think it maybe some focus problem in the way it is selecting the item (as such I beleive the mistake lies here:
    Code:
    LVITEM LVI;
    LVI.mask = LVIF_STATE;
    LVI.iItem = lResult;
    LVI.iSubItem = 0;
    LVI.state = LVIS_SELECTED | LVIS_FOCUSED;
    LVI.stateMask = LVIS_SELECTED | LVIS_FOCUSED;
    SendMessage(GetDlgItem(hwndMain, 3001), LVM_SETITEM,0, (LPARAM) &LVI);
    I have tried applying the LVS_SHOWSELALWAYS style to the LV and that still doesn't fix the problem.
    Last edited by P4R4N01D; 01-02-2008 at 06:43 PM. Reason: Fixed
    long time no C; //seige
    You miss 100% of the people you don't C;
    Code:
    if (language != LANG_C && language != LANG_CPP)
        drown(language);

Popular pages Recent additions subscribe to a feed

Similar Threads

  1. ListView Refresh, Update
    By de4th in forum C++ Programming
    Replies: 1
    Last Post: 12-23-2006, 09:13 AM
  2. Replies: 6
    Last Post: 07-10-2006, 12:05 AM
  3. Moving items in a ListView
    By Cactus_Hugger in forum Windows Programming
    Replies: 1
    Last Post: 01-18-2006, 09:40 PM
  4. Troubles with ListView and Toolbar
    By cornholio in forum Windows Programming
    Replies: 8
    Last Post: 11-14-2005, 01:26 AM
  5. Listview??
    By SuperNewbie in forum C# Programming
    Replies: 4
    Last Post: 02-13-2003, 03:34 AM