Shell problem

P

Paul W

Hello,

My problem concerns the shell. If there's a better forum for this post,
please let me know.

I'm trying to create a ListView control that displays the contents of a
folder with all the appropriate icons etc. I first tried this in c# with
reasonable success, but this is really a job for c++. However I've run into
a problem.

I have pretty much got the code down to do what I need it to do, but if I
access a folder with many items, problems begin. The controls within my
program and the entire windows environment start to not paint themselves
correctly. For example, icons show up in my ListView but no text...text
disappears from the column headers and from the menu, and if you keep going,
entire blocks of Window start paint themselves erraticly. I have a couple
of screen shots.


Here's the code that sets things up:

virtual void OnCreateControl()
{
__super::OnCreateControl();
CoInitializeEx(NULL, COINIT_APARTMENTTHREADED);
UINT uFlags = SHGFI_SYSICONINDEX | SHGFI_ICON | SHGFI_USEFILEATTRIBUTES;
HIMAGELIST himl;
SHFILEINFO sfi;
HRESULT hr;
LPMALLOC pMalloc;
LPSHELLFOLDER pDesktopFolder = NULL;
LPSHELLFOLDER pParentFolder = NULL;
hr = SHGetDesktopFolder(&pDesktopFolder); // Desktop's IShellFolder
interface
hr = SHGetMalloc(&pMalloc); // IMalloc interface, for releasing PIDLs
if (SUCCEEDED(hr))
{
// Assisn the Desktop's IShellFolder interface and the IMalloc interface to
global variables
// Calling the above functions and passing in these global variables results
in a compiler
// error; error C2664: : cannot convert parameter 1 from 'LPSHELLFOLDER __gc
* ' to 'IShellFolder ** '
m_pDesktopFolder = pDesktopFolder;
m_pMalloc = pMalloc;
// Set the ListView's SmallImage list to the system's SmallImageList
himl =
(HIMAGELIST)SHGetFileInfo((LPCWSTR)Marshal::StringToCoTaskMemUni(Application
::StartupPath).ToPointer(), FILE_ATTRIBUTE_NORMAL, &sfi, sizeof(SHFILEINFO),
uFlags | SHGFI_SMALLICON);
ListView_SetImageList((HWND)hWnd.ToPointer(), himl, LVSIL_SMALL);
// Set the ListView's LargeImage list to the system's LargeImageList
himl =
(HIMAGELIST)SHGetFileInfo((LPCWSTR)Marshal::StringToCoTaskMemUni(Application
::StartupPath).ToPointer(), FILE_ATTRIBUTE_NORMAL, &sfi, sizeof(SHFILEINFO),
uFlags | SHGFI_LARGEICON);
ListView_SetImageList((HWND)hWnd.ToPointer(), himl, LVSIL_NORMAL);
} //if (SUCCEEDED(hr))
} //OnCreateControl

This is the code that enumerates a folder and stores the relevant info. I
wanted this to be simpler. Originally I only wanted to store the PIDL for
each item and use that to retrieve the info needed (icon index, display
text, file type etc.) but I found that when I did that the same problem also
happens, only sooner. The problem seems to be in the repeated calls to
SHGetFileInfo.

virtual int GetFiles(LPITEMIDLIST pidl)
{
int retVal = -1;
IEnumIDList* pEnumIDList = NULL;
HRESULT hr = NULL;
LPITEMIDLIST apidl = NULL;
LPITEMIDLIST fullPidl = NULL;
SHCONTF grfFlags = SHCONTF_FOLDERS | SHCONTF_NONFOLDERS |
SHCONTF_INCLUDEHIDDEN;
UINT uFlags = SHGFI_PIDL | SHGFI_ICON | SHGFI_USEFILEATTRIBUTES |
SHGFI_TYPENAME | SHGFI_DISPLAYNAME | SHGFI_OVERLAYINDEX;
SHFILEINFO sfi;
m_fileList = new ArrayList();
// m_pParentFolder is a global variable for the current folder's
IShellFolder interface
hr = m_pParentFolder->EnumObjects(NULL, grfFlags, &pEnumIDList);
if (SUCCEEDED(hr))
{
while (HRESULT_CODE(pEnumIDList->Next(1, &apidl, NULL)) == NOERROR)
{
// PIDL is a class with static methods for working with PIDLs, Append joins
two PIDLs into one,
// taking a relative PIDL and its parent, and making a fully qualified PIDL
// (code for Append is from the Microsoft help file)
fullPidl = PIDL::Append(m_currentFolderPidl, apidl);
hr = SHGetFileInfo((LPCWSTR)fullPidl, FILE_ATTRIBUTE_NORMAL, &sfi,
sizeof(SHFILEINFO), uFlags);
if (SUCCEEDED(hr))
{
// ShellItem is a class that holds the shell object's PIDL, name, type,
image index and image overlay index
// ShellItem's destructor frees the PIDL using the IMalloc interface.
m_fileList is an ArrayList of ShellItems.
m_fileList->Add(new ShellItem(apidl, sfi.szDisplayName, sfi.szTypeName,
sfi.iIcon & 0x00FFFFFF, sfi.iIcon >> 24));
} //if (SUCCEEDED(hr))
m_pMalloc->Free(fullPidl);
} //while (HRESULT_CODE(pEnumIDList->Next(1, &apidl, NULL)) == NOERROR)
pEnumIDList->Release();
m_fileList->Sort(NULL); // ShellItem implements the IComparable interface.
ShellItems are sorted by their PIDLs
retVal = m_fileList->Count;
} //if (SUCCEEDED(hr))
return retVal;
} //GetFiles


The base class is a virtual ListView meaning that the ListView doesn't store
any info about the items it contains. The client is responsible for that
and the ListView calls back the client when it needs to know how to display
an item. This is the code that gets called.

virtual void OnGetInfo(VirtualList::GetInfoEventArgs* e)
{
HRESULT hr = NULL;
ULONG rgfInOut = SFGAO_GHOSTED;
LPITEMIDLIST apidl =
static_cast<ShellItem*>(m_fileList->Item[e->Index])->ItemIdList;
e->ImageIndex =
static_cast<ShellItem*>(m_fileList->Item[e->Index])->ImageIndex;
e->OverlayIndex =
static_cast<ShellItem*>(m_fileList->Item[e->Index])->OverlayIndex;
// m_pParentFolder is a global variable for the current folder's
IShellFolder interface
hr = m_pParentFolder->GetAttributesOf(1, (LPCITEMIDLIST*)&apidl, &rgfInOut);
if (SUCCEEDED(hr))
{
e->Ghosted = (rgfInOut & SFGAO_GHOSTED) == SFGAO_GHOSTED;
} //if (SUCCEEDED(hr))
switch (e->Column)
{
case 0:
e->Text = static_cast<ShellItem*>(m_fileList->Item[e->Index])->Text;
break;
case 1:
e->Text = static_cast<ShellItem*>(m_fileList->Item[e->Index])->TypeName;
break;
} //switch (e->Column)
} //OnGetInfo

Thank you for reading this. Any help would be appreciated.

Paul
 
W

William DePalo [MVP VC++]

Paul W said:
My problem concerns the shell. If there's a better forum for this post,
please let me know.

If your task is to extend the shell in some way then

microsoft.public.platformsdk.shell

is where you find the shell experts.

If your question is about using the List View control in a more ordinary
application the

microsoft.public.win32.programmer.ui

is better.

That said, the regulars of this group have an extensive set of specialties
so it is possible that you will get a reply here so it's wise to check in
occaisionally.

Regards,
Will
www.ivrforbeginners.com
 
P

Paul W

Thanks Will.

William DePalo said:
If your task is to extend the shell in some way then

microsoft.public.platformsdk.shell

is where you find the shell experts.

If your question is about using the List View control in a more ordinary
application the

microsoft.public.win32.programmer.ui

is better.

That said, the regulars of this group have an extensive set of specialties
so it is possible that you will get a reply here so it's wise to check in
occaisionally.

Regards,
Will
www.ivrforbeginners.com
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Top