Google Groups no longer supports new Usenet posts or subscriptions. Historical content remains viewable.
Dismiss

Explorer type TreeView in Vista

9 views
Skip to first unread message

Mehmet Caner

unread,
Jul 16, 2008, 4:34:45 AM7/16/08
to
Hi,

The following code fills TreeView1 component with the drives of the computer
in Windows XP SP2 successfully, but failed in Vista. What's wrong with the
code?

Thanks in advance!

void __fastcall TForm1::FirstTree(void)
{
LPMALLOC lpMalloc;

if (SUCCEEDED(SHGetMalloc(&lpMalloc))) {
LPSHELLFOLDER lpsf;
SHFILEINFO FileInfo;
unsigned int uSHFlags = SHGFI_SYSICONINDEX | SHGFI_DISPLAYNAME |
SHGFI_PIDL;
TTreeNode *TNode;

if (SUCCEEDED(SHGetDesktopFolder(&lpsf))) {
LPITEMIDLIST lpidl;
if (SUCCEEDED(SHGetFolderLocation(Handle, CSIDL_DRIVES, NULL, 0,
&lpidl))) {
LPSHELLFOLDER lpsfSub;
if (SUCCEEDED(lpsf->BindToObject(lpidl, NULL, IID_IShellFolder,
reinterpret_cast<void **>(&lpsfSub)))) {
SHGetFileInfo((LPCSTR)lpidl, 0, &FileInfo, sizeof(SHFILEINFO),
uSHFlags);
FillTree(lpsfSub, lpidl);
lpsfSub->Release();
}
}
lpMalloc->Free(lpidl);
lpsf->Release();
}
lpMalloc->Release();
}
}
//---------------------------------------------------------------------------
void __fastcall TForm1::FillTree (LPSHELLFOLDER lpsf, LPITEMIDLIST lpidl)
{
LPMALLOC lpMalloc;
Screen->Cursor = crHourGlass;

if (SUCCEEDED(SHGetMalloc(&lpMalloc))) {
LPENUMIDLIST lpeidl;
HRESULT HRes;

HRes = lpsf->EnumObjects(NULL, SHCONTF_NONFOLDERS, &lpeidl);

if (HRes == NOERROR) {
TreeView1->Items->BeginUpdate();
LPITEMIDLIST lpidlCurrent;
unsigned long ulFetched;
while (lpeidl->Next(1, &lpidlCurrent, &ulFetched) == S_OK) {
LPITEMIDLIST lpidlFQ = MergeIDLists (lpMalloc, lpidl, lpidlCurrent);
if (lpidlFQ) {
SHFILEINFO FileInfo;
DWORD FileAttrib;
unsigned int uSHFlags;
TTreeNode *Node;
uSHFlags = SHGFI_SYSICONINDEX | SHGFI_DISPLAYNAME | SHGFI_PIDL;
SHGetFileInfo(reinterpret_cast<LPCSTR>(lpidlFQ), FileAttrib,
&FileInfo, sizeof(SHFILEINFO), uSHFlags);

Node = TreeView1->Items->AddChild(NULL, FileInfo.szDisplayName);
Node->ImageIndex = FileInfo.iIcon;
Node->SelectedIndex = FileInfo.iIcon;
Node->Data = reinterpret_cast<void *>(lpidlFQ);
TTreeNode *ChildNode = TreeView1->Items->AddChild(Node, "");
ChildNode->ImageIndex = -1;
}
lpMalloc->Free(lpidlCurrent);
}
TreeView1->Items->EndUpdate();

lpeidl->Release();
}
else {
ShowMessage ("Error Code: 001");
}
lpMalloc->Release();
}
else {
Screen->Cursor = crArrow;

ShowMessage ("Error Code: 002");
}
Screen->Cursor = crArrow;
}
//---------------------------------------------------------------------------


Bob Gonder

unread,
Jul 16, 2008, 1:30:45 PM7/16/08
to
Mehmet Caner wrote:

>The following code fills TreeView1 component with the drives of the computer
>in Windows XP SP2 successfully, but failed in Vista. What's wrong with the
>code?

I would start by replacing the SUCCEEDED macro
with a function that reports what the error is.

> if (SUCCEEDED(SHGetDesktopFolder(&lpsf))) {

BOOL SUCCEEDED( HRESULT code )
{
if( code < 0 )
{
//report error;
return FALSE;
}
return TRUE;
}

Remy Lebeau (TeamB)

unread,
Jul 16, 2008, 2:45:24 PM7/16/08
to

"Mehmet Caner" <mcan...@hotmail.com> wrote in message
news:487db2ae$1...@newsgroups.borland.com...

> The following code fills TreeView1 component with the drives of the
> computer in Windows XP SP2 successfully, but failed in Vista.
> What's wrong with the code?

You did not say where it is failing. Can you step through the code and find
the particular line that is not working?

Have you tried using Vista's new KNOWNFOLDERIDs instead of CSIDLs? In this
case, CSIDL_DRIVES maps to FOLDERID_ComputerFolder. Have a look at MSDN for
more details:

Known Folders
http://msdn.microsoft.com/en-us/library/bb776911(VS.85).aspx


Gambit


Mehmet Caner

unread,
Jul 17, 2008, 8:41:43 AM7/17/08
to
Hi Remy,

Thank you very much for your quick answer.

> You did not say where it is failing. Can you step through the code and
> find the particular line that is not working?

The code does not enter the while loop in function FillTree:

// while (lpeidl->Next(1, &lpidlCurrent, &ulFetched) == S_OK) {

void __fastcall TForm1::FirstTree(void)
{
LPMALLOC lpMalloc;

if (SUCCEEDED(SHGetMalloc(&lpMalloc))) {
LPSHELLFOLDER lpsf;
SHFILEINFO FileInfo;
unsigned int uSHFlags = SHGFI_SYSICONINDEX | SHGFI_DISPLAYNAME |
SHGFI_PIDL;
TTreeNode *TNode;

if (SUCCEEDED(SHGetDesktopFolder(&lpsf))) {
LPITEMIDLIST lpidl;
if (SUCCEEDED(SHGetFolderLocation(Handle, CSIDL_DRIVES, NULL, 0,
&lpidl))) {
LPSHELLFOLDER lpsfSub;
if (SUCCEEDED(lpsf->BindToObject(lpidl, NULL, IID_IShellFolder,
reinterpret_cast<void **>(&lpsfSub)))) {
SHGetFileInfo((LPCSTR)lpidl, 0, &FileInfo, sizeof(SHFILEINFO),
uSHFlags);
FillTree(lpsfSub, lpidl);
lpsfSub->Release();
}

else ErrorFunc();
}
else ErrorFunc();
lpMalloc->Free(lpidl);
lpsf->Release();
}
else ErrorFunc();
lpMalloc->Release();
}
else ErrorFunc();


}
//---------------------------------------------------------------------------
void __fastcall TForm1::FillTree (LPSHELLFOLDER lpsf, LPITEMIDLIST lpidl)
{
LPMALLOC lpMalloc;
Screen->Cursor = crHourGlass;

if (SUCCEEDED(SHGetMalloc(&lpMalloc))) {
LPENUMIDLIST lpeidl;
HRESULT HRes;

HRes = lpsf->EnumObjects(NULL, SHCONTF_NONFOLDERS, &lpeidl);

if (HRes == NOERROR) {
TreeView1->Items->BeginUpdate();
LPITEMIDLIST lpidlCurrent;
unsigned long ulFetched;

while (lpeidl->Next(1, &lpidlCurrent, &ulFetched) == S_OK) { ////////
failing line


LPITEMIDLIST lpidlFQ = MergeIDLists (lpMalloc, lpidl, lpidlCurrent);
if (lpidlFQ) {
SHFILEINFO FileInfo;
DWORD FileAttrib;
unsigned int uSHFlags;
TTreeNode *Node;
uSHFlags = SHGFI_SYSICONINDEX | SHGFI_DISPLAYNAME | SHGFI_PIDL;
SHGetFileInfo(reinterpret_cast<LPCSTR>(lpidlFQ), FileAttrib,
&FileInfo, sizeof(SHFILEINFO), uSHFlags);

Node = TreeView1->Items->AddChild(NULL, FileInfo.szDisplayName);
Node->ImageIndex = FileInfo.iIcon;
Node->SelectedIndex = FileInfo.iIcon;
Node->Data = reinterpret_cast<void *>(lpidlFQ);
TTreeNode *ChildNode = TreeView1->Items->AddChild(Node, "");
ChildNode->ImageIndex = -1;
}
lpMalloc->Free(lpidlCurrent);
}

ErrorFunc();
TreeView1->Items->EndUpdate();

lpeidl->Release();
}
else {
ErrorFunc();


}
lpMalloc->Release();
}
else {
Screen->Cursor = crArrow;

ErrorFunc();


}
Screen->Cursor = crArrow;
}
//---------------------------------------------------------------------------

void __fastcall TForm1::ErrorFunc (void)
{
LPTSTR MsgBuf;

FormatMessage (FORMAT_MESSAGE_ALLOCATE_BUFFER |
FORMAT_MESSAGE_FROM_SYSTEM, NULL,
GetLastError(), MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT),
(LPTSTR) &MsgBuf, 0, NULL);

MessageBox (NULL, MsgBuf, "Error Message", MB_OK|MB_ICONINFORMATION);
LocalFree (MsgBuf);
}
//-----------------------------------------------------------------------------

> Have you tried using Vista's new KNOWNFOLDERIDs instead of CSIDLs? In
> this case, CSIDL_DRIVES maps to FOLDERID_ComputerFolder. Have a look at
> MSDN for more details:
>
> Known Folders
> http://msdn.microsoft.com/en-us/library/bb776911(VS.85).aspx

Thanks for the tip. I think it requires Vista SDK. I have download and
installed it. I have begun studying on KNOWNFOLDERID.


Remy Lebeau (TeamB)

unread,
Jul 17, 2008, 2:05:47 PM7/17/08
to

"Mehmet Caner" <mcan...@hotmail.com> wrote in message
news:487f...@newsgroups.borland.com...

> The code does not enter the while loop in function FillTree:

Is FillTree() being entered at all? If so, then the binding to CSIDL_DRIVES
is fine, but either SHGetMalloc() failed or the drives cannot be enumerated.
You need to more specific.


Gambit


Mehmet Caner

unread,
Jul 17, 2008, 3:48:13 PM7/17/08
to
> Is FillTree() being entered at all? If so, then the binding to
> CSIDL_DRIVES is fine, but either SHGetMalloc() failed or the drives cannot
> be enumerated. You need to more specific.

I stepped through the code. FillTree() function is called.

SHGetMalloc() and EnumObjects() functions are successfully called in
FillTree().

The code only does not enter the while loop:

Bob Gonder

unread,
Jul 17, 2008, 4:00:41 PM7/17/08
to
Mehmet Caner wrote:

>SHGetMalloc() and EnumObjects() functions are successfully called in
>FillTree().

I suppose it might be the second case in this note:

http://msdn.microsoft.com/en-us/library/bb775066(VS.85).aspx
If the folder contains no suitable subobjects, then the IShellFolder::EnumObjects method
is permitted either to set *ppenumIDList to NULL and return S_FALSE, or to set
*ppenumIDList to an enumerator that produces no objects and return S_OK. Calling
applications must be prepared for both success cases.


Remy Lebeau (TeamB)

unread,
Jul 17, 2008, 4:36:24 PM7/17/08
to

"Mehmet Caner" <mcan...@hotmail.com> wrote in message
news:487f...@newsgroups.borland.com...

> EnumObjects() functions are successfully called in FillTree().

If that were the case, then your while loop would be entered.

> The code only does not enter the while loop:
>
> while (lpeidl->Next(1, &lpidlCurrent, &ulFetched) == S_OK) {

Are you saying that Next() returns something other than S_OK? That would
mean the drives are not enumerable.


Gambit


Mehmet Caner

unread,
Jul 17, 2008, 5:27:10 PM7/17/08
to
> Are you saying that Next() returns something other than S_OK? That would
> mean the drives are not enumerable.

Next() returns S_OK, but the while loop is not entered. It is really very
interesting.


Mehmet Caner

unread,
Jul 17, 2008, 5:30:06 PM7/17/08
to
Hi Bob,

Thanks for your answer.

> http://msdn.microsoft.com/en-us/library/bb775066(VS.85).aspx
> If the folder contains no suitable subobjects, then the
> IShellFolder::EnumObjects method
> is permitted either to set *ppenumIDList to NULL and return S_FALSE, or to
> set
> *ppenumIDList to an enumerator that produces no objects and return S_OK.
> Calling
> applications must be prepared for both success cases.

EnumObjects() returns S_OK.


Remy Lebeau (TeamB)

unread,
Jul 17, 2008, 5:54:23 PM7/17/08
to

"Mehmet Caner" <mcan...@hotmail.com> wrote in message
news:487f...@newsgroups.borland.com...

> Next() returns S_OK

If EnumObjects() return S_OK and Next() return S_OK, then your while() loop
is guaranteed to be entered.


Gambit


Mehmet Caner

unread,
Jul 17, 2008, 9:23:41 PM7/17/08
to
> If EnumObjects() return S_OK and Next() return S_OK, then your while()
> loop is guaranteed to be entered.

Sorry. It was a big mistake. Next() return S_FALSE.


Remy Lebeau (TeamB)

unread,
Jul 17, 2008, 9:44:37 PM7/17/08
to

"Mehmet Caner" <mcan...@hotmail.com> wrote in message
news:487f...@newsgroups.borland.com...

> Sorry. It was a big mistake. Next() return S_FALSE.

There you go then. That means the CSIDL_DRIVES enumerator is empty.


Gambit


Mehmet Caner

unread,
Jul 18, 2008, 4:35:58 AM7/18/08
to
> There you go then. That means the CSIDL_DRIVES enumerator is empty.

Dear Remy and Bob,

Thanks both of you.

I have changed the line:

HRes = lpsf->EnumObjects(NULL, SHCONTF_NONFOLDERS, &lpeidl); // Works in XP
SP2

to:

HRes = lpsf->EnumObjects(Handle, SHCONTF_STORAGE, &lpeidl); // Works in
Vista

It works perfectly.

0 new messages