CodeGuru Home VC++ / MFC / C++ .NET / C# Visual Basic VB Forums Developer.com
Results 1 to 6 of 6
  1. #1
    Join Date
    May 2002
    Posts
    1,798

    [RESOLVED] Help needed setting a file-type icon in a CListView

    I want to put a small icon at the beginning of each entry of a CListView. Most of the entry data is contained in a wstring matrix, m_wS. In addition, there are two vectors, std::vector<HICON> m_hIcon and std::vector<UINT> m_iIcon which contain the handle and the index of the icon needed to accomplish the task. For reasons not relevant to this discussion, there is an offset of 2 between the matrix and the vectors.


    The code to attach the image list to the system image list is executed only once when the application first initializes:
    Code:
    	m_ImageList.Attach(GetSystemImageListHandle(TRUE));
    
    
    //..
    
    /// Gets the system's small image list handle which can be attached to a CImageList object
    HIMAGELIST  CCabManView::GetSystemImageListHandle( BOOL bSmallIcon )
    {
    	HIMAGELIST  hSystemImageList; 
    	SHFILEINFO    ssfi; 
    
       if (bSmallIcon)
       {
    	hSystemImageList = 
        (HIMAGELIST)SHGetFileInfo( 
        (LPCTSTR)_T("c:\\"), 
         0, 
         &ssfi, 
         sizeof(SHFILEINFO), 
         SHGFI_SYSICONINDEX | SHGFI_SMALLICON); 
       }
       else
       {
    		hSystemImageList = 
        (HIMAGELIST)SHGetFileInfo( 
        (LPCTSTR)_T("c:\\"), 
         0, 
         &ssfi, 
         sizeof(SHFILEINFO), 
         SHGFI_SYSICONINDEX | SHGFI_LARGEICON); 
       }
       return hSystemImageList;
    }

    The code used to fill in the view is fairly standard:
    Code:
    void CCabManView::OnLvnGetdispinfo(NMHDR *pNMHDR, LRESULT *pResult)
    {
    	LV_DISPINFO* pDispInfo = (LV_DISPINFO*)pNMHDR;
    	CString csValue;
    	wchar_t csErr[256];
    	UINT nMessageID = 0;
    	UINT nMaxError = 256;
    
    	m_pDataset = GetDataSet();
    	if(!m_pDataset) return;
    
    	long index = pDispInfo->item.iItem;    
    	short subItem = 	pDispInfo->item.iSubItem;
    	
    	if(pDispInfo->item.mask & LVIF_TEXT)
    	{
    		try
    		{
    			index++; //TRACE1("INDEX = %d\n", index);
    
    		}
    		catch(CException* e)
    		{
    			e->ReportError(MB_OK, nMessageID);
    			e->Delete();
    			return;
    		}
    
    		try
    		{
    			csValue = (wchar_t*)m_wS(index+1, subItem+1).c_str();
    		}
    		catch(CException* e)
    		{
    			e->ReportError(MB_OK, nMessageID);
    			e->Delete();
    			return;
    		}
    
    		lstrcpyn(pDispInfo->item.pszText, csValue, pDispInfo->item.cchTextMax);
    
    		if(pDispInfo->item.mask & LVIF_IMAGE)
    		{
    			TRACE1("index = %d\n", index);
    			TRACE2("m_iIcon[%d] = %d\n", index-1, m_iIcon[index-1]);
    			TRACE2("m_hIcon[%d] = %d\n", index-1, m_hIcon[index-1]);
    			pDispInfo->item.iImage = m_iIcon[index-1];
    
    		}
    
    	}
    	
    
    	*pResult = 0;
    
    }// OnLvnGetdispinfo(NMHDR *pNMHDR, LRESULT *pResult)

    The icon handles contained in m_hIcon and the icon indexes contained in m_iIcon all check out. But no icon is set into the listview. Clearly, I am missing a step in the process.

    I found an example of how to do this in a simpler dialog-based app. Those interested should take a look at:
    An ShGetFileInfo Wrapper Class By Doru Cioata 6 Feb 2003
    A class built around the use of ShGetFileInfo() function.
    http://69.10.233.10/KB/files/cuseshgetfileinfo.aspx

    But because my app is an SDI CListView and I have tried to combine additional data using the wstring matrix, the demo code provided by Doru Cioata doesnt seem to work (or I am using it incorrectly). Anyway, attempting to use:
    Code:
    GetListCtrl().SetIcon(m_hIcon[index-1], FALSE);
    or any of it's variants results in a crashed app.

    I realize this is a bit of a long harangue, but if anyone can help, I sure would appreciate it. Thanks.
    mpliam

  2. #2
    Join Date
    May 2002
    Posts
    1,798

    Re: Help needed setting a file-type icon in a CListView

    I think I see the problem. (I would have removed this thread but cannot figure out how to.)

    I used two image list elements:
    Code:
    	CImageList * m_pImageList;
    	CImageList m_ImageList;
    The image list object is attacted to the system image list (see first post):
    Code:
    m_ImageList.Attach(GetSystemImageListHandle(TRUE));
    For each OnInitialUpdate (new data loaded), provided a dataset exists, the member imagelist pointer is set to the m_ImageList address, AND (here's where I forgot to include), the CListView control is used to set the image list.

    Code:
    m_pImageList = &m_ImageList;
    		GetListCtrl().SetImageList(m_pImageList, LVSIL_SMALL);  // set the image list to this control
    Now it WORKS! Well, mostly. because it will only work once. Any attempt to repeat this marvelous maneuver results in a crash.

    Debug shows the following in the file: afxstate.cpp

    Code:
    BOOL AFXAPI AfxDeactivateActCtx(DWORD dwFlags, ULONG_PTR ulCookie)
    {	
    	BOOL rc = pfnDeactivateActCtx != 0 ? pfnDeactivateActCtx(dwFlags, ulCookie) : FALSE;
    	return rc;
    }
    What this means is not readily apparent to me.

    So as long as we've gotten this far, can anyone clue me in as to why the thing crashes after performing so beautifully one time. (Sort of reminds me of an old girlfriend.
    mpliam

  3. #3
    Join Date
    Apr 1999
    Posts
    3,585

    Re: Help needed setting a file-type icon in a CListView

    Just where exactly does it Assert or crash?
    Gort...Klaatu, Barada Nikto!

  4. #4
    Join Date
    May 2002
    Posts
    1,798

    Re: Help needed setting a file-type icon in a CListView

    Thanks for responding, Mike. I found the problem.

    The application is a CListView Doc-View SDI app that loads files from the Doc using OpenDocument, CloseDocument, and DeleteContents in a standard manner. However, my early versions simply used a built-in image list bitmap. As such, when a view was closed, it was probably appropriate to 'clean up' by deleting the image list.

    Code:
    // OnCloseDocument()
    //..
    		CImageList* pImageList = pCurrentView->GetListCtrl().SetImageList(NULL, LVSIL_SMALL);
    		delete pImageList;
    //..
    // OnDeleteContents()
    //..
    		CImageList* pImageList = pCurrentView->GetListCtrl().SetImageList(NULL, LVSIL_SMALL);
    		delete pImageList;
    The recent versions used the system image list (see above) which was attached to the CListView m_ImageList just once at initialization. By deleting this list, a cascade of adverse events ensued because of the callback update nature of the CListView interface. By simply eliminating the 'delete pImageList' lines in the Doc, the problem went away. And there is no memory leak.

    I have only one further question. When, if ever, is appropriate to use m_ImageList.Detach() in this scenario?
    mpliam

  5. #5
    Join Date
    Apr 1999
    Posts
    3,585

    Re: Help needed setting a file-type icon in a CListView

    I probably would designed it a little differently since the system image list is a 'special' image list, and, you need to be careful with it or you run the risk of affecting the Windows OS. With that in mid, I would have established the image list once and save it in globally. Then when it was needed, I would attach it to the list control. It would be detached when the application closes.
    Gort...Klaatu, Barada Nikto!

  6. #6
    Join Date
    May 2002
    Posts
    1,798

    Re: Help needed setting a file-type icon in a CListView

    I'll give that a try. But so far, I havnt seen any ill-effects doing it as I have described. But it does make sense to detach the image list when the application closes. On the other hand, it would be mandatory if an application was switching from the system image list to some other one during runtime.

    Thanks
    mpliam

Posting Permissions

  • You may not post new threads
  • You may not post replies
  • You may not post attachments
  • You may not edit your posts
  •  





Click Here to Expand Forum to Full Width

Featured