 |
|
 |
Hi, The CShellTreeCtrl code works very well, and Paolo gave me a lot of help with my Bulk Rename Utiltiy tpoject which uses the code. Can anyone suggest an effective way of jumping directly to a network share path? Obviously I can expand out \\Network\Server\Share etc. using the mouse within the tree, but it would be nice to be able to jump directly to a share automatically - for example by receiving a UNC pathname as a parameter to the .EXE The FindItemByPath() method doesn't seem to handle network shares particularly well, and I have written my own FindItemByNearestPath to try to handle situations where a stored path no longer exists - my function will look for C:\A\B\C, then C:\A\B, then C:\A etc until it finds a maatch. But neither Paolo's excellent code, nor my own poor code, can correctly handle jumping directly to a UNC path. Any ideas? For reference, my FindItemByNearestPath fucntion is below.
Jim
<code>// Find an item by the nearest path, navigating up the tree if required // Added by Jim Willsher HTREEITEM CShellTreeCtrl::FindItemByNearestPath(CString sPath, HTREEITEM hParentItem) { CShellPidl pidlItem; HTREEITEM hRes = NULL; // Navigate up the tree until we find a suitable path while (hRes == NULL) { // Append a trailing slash, if this is a root folder (e.g. C , as the tree contains trailing slashes for the roots if (sPath.GetLength() == 2) sPath += "\\"; // Path is a directory? Find it in the tree if (PathIsDirectory(sPath)) hRes = FindItemByPath(sPath, hParentItem); // Not found in the tree as a directory? if (hRes == NULL) { int nPos = sPath.ReverseFind('\\'); // No tree left to search? if (nPos == -1) hRes = GetChildItem(CSIDL_DESKTOP); // If the only slash is at position two then we've drawn back to the root (e.g. C:\) if (nPos == 2) { // If the last slash indicates the root, and we ONLY have the root, then see if the root actually exists! if (sPath.GetLength() == 3 && !PathIsDirectory(sPath)) { // We are at a root, but even that doesn;t exist, so it's a missing drive letter! hRes = GetChildItem(CSIDL_DESKTOP); } else sPath = sPath.Left(nPos); // Truncate back to before the slash } else sPath = sPath.Left(nPos); // Truncate back to before the slash } } return hRes; }</code>
|
|
|
|
 |
|
 |
I integrated the CChildView tree in a CDialog.
I want to check at OnInitDialog() the checkboxes that was checked last time.
I load last settings from a file.
extern CChildView m_tree;
BOOL CBDBrowseFFDlg::OnInitDialog()
{
CDialog::OnInitDialog();
//............
m_tree.ModifyStyle( TVS_CHECKBOXES, 0 );
m_tree.ModifyStyle( 0, TVS_CHECKBOXES ); //a known bug
m_tree.AddRootFolderContent(NULL,STCF_INCLUDEHIDDEN);
HTREEITEM desktop;
desktop = m_tree.GetFirstVisibleItem();
m_tree.Expand(desktop,TVE_EXPAND);
//AfxMessageBox("Check");
m_tree.SetCheck(desktop,TRUE);
HTREEITEM item = m_tree.GetChildItem(desktop);
while(item)
{
m_tree.SetCheck(item);
item = m_tree.GetNextSiblingItem(item);
}
return TRUE;
}
So.... I've checked(theoretical) the desktop item and all its children.
But after returning TRUE, all the checkboxes are unchecked.
If I'll uncomment row with AfxMessageBox("Check");, the checkboxes appears to be checked.
If i change the type of m_tree to CTreeCtrl, I don't need to uncomment the MessageBox: the checkboxes appears to be checked.
I suppose there is a reinitialization of the control after OnInitDialog...
Thank you in advance :P
|
|
|
|
 |
|
 |
Hi, I am trying to compile the project with unicode enabled, but I got stuck at:
BOOL CShellContextMenu::InvokeCommand(UINT nCmdID)
{
if (!IsValid() || !IsCommandInRange(nCmdID))
return FALSE;
CMINVOKECOMMANDINFOEX cmi;
ZeroMemory(&cmi, sizeof(CMINVOKECOMMANDINFOEX));
cmi.cbSize = sizeof(CMINVOKECOMMANDINFOEX);
cmi.hwnd = m_pShellOwner->GetSafeHwnd();
cmi.lpVerbW = MAKEINTRESOURCE(nCmdID - m_nCmdFirstID);
cmi.nShow = SW_SHOWNORMAL;
return (NOERROR == m_pCtxMenu->InvokeCommand(&cmi)); <------- Error
}
BOOL CShellContextMenu::InvokeCommandByVerb(LPCTSTR pszVerb)
{
CMINVOKECOMMANDINFOEX cmi;
ZeroMemory(&cmi, sizeof(CMINVOKECOMMANDINFOEX));
cmi.cbSize = sizeof(CMINVOKECOMMANDINFOEX);
cmi.hwnd = m_pShellOwner->GetSafeHwnd();
cmi.lpVerbW = pszVerb;
cmi.nShow = SW_SHOWNORMAL;
return (NOERROR == m_pCtxMenu->InvokeCommand(&cmi)); <----- Error
}
The error stated "cannot convert parameter 1 from CMINVOKECOMMANDINFOEX * to LPCMINVOKECOMMANDINFOEX"
Do you know how to solve this problem?
Thanks,
-Andrew
|
|
|
|
 |
|
 |
Hallo vg8open,
here is a code snippet, which will work for Unicode and Ansi. It uses the
ATL conversion macro USES_CONVERSION. You have to set the CMIC_MASK_UNICODE flag, if you use the CMINVOKECOMMANDINFOEX structure with Unicode. Additional you must also set the lpVerb parameter and pass a casted parameter &cmi in base class function call m_pCtxMenu->InvokeCommand(... . My code looks as follows:
BOOL CShellContextMenu::InvokeCommand(UINT nCmdID)
{
USES_CONVERSION;
if (!IsValid() || !IsCommandInRange(nCmdID))
return FALSE;
CMINVOKECOMMANDINFOEX cmi;
ZeroMemory(&cmi, sizeof(CMINVOKECOMMANDINFOEX));
#ifdef _UNICODE
cmi.fMask &= CMIC_MASK_UNICODE;
cmi.lpVerbW = MAKEINTRESOURCEW(nCmdID - m_nCmdFirstID);
#endif
cmi.lpVerb = MAKEINTRESOURCEA(nCmdID - m_nCmdFirstID);
cmi.cbSize = sizeof(CMINVOKECOMMANDINFOEX);
cmi.hwnd = m_pShellOwner->GetSafeHwnd();
cmi.nShow = SW_SHOWNORMAL;
return (NOERROR == m_pCtxMenu->InvokeCommand((LPCMINVOKECOMMANDINFO) &cmi));
}
BOOL CShellContextMenu::InvokeCommandByVerb(LPCTSTR pszVerb)
{
USES_CONVERSION;
CMINVOKECOMMANDINFOEX cmi;
ZeroMemory(&cmi, sizeof(CMINVOKECOMMANDINFOEX));
#ifdef _UNICODE
cmi.fMask &= CMIC_MASK_UNICODE;
cmi.lpVerbW = T2CW(pszVerb);
#endif
cmi.lpVerb = T2CA(pszVerb);
cmi.cbSize = sizeof(CMINVOKECOMMANDINFOEX);
cmi.hwnd = m_pShellOwner->GetSafeHwnd();
cmi.nShow = SW_SHOWNORMAL;
return (NOERROR == m_pCtxMenu->InvokeCommand((LPCMINVOKECOMMANDINFO) &cmi));
}
I hope this version works for you.
pap
|
|
|
|
 |
|
|
 |
|
 |
Dear Paolo,
I got problem again
How to ask the tree control to select a item automatically
if I only konw the string of the path of the item?
For example, I know the path string "C:\Documents and Settings",
then, how do I set the tree so that
the item of "C:\Documents and Settings" can be set selected automatically?
Thank you very very very much!!!
|
|
|
|
 |
|
 |
First, if you can, download the latest code from CVS at SourceForge (link at the end of the article). Then have a look at the "find" dialog.
Basically, what you need to do is:
1) obtain a PIDL from the system path with a CShellPidl(path)
2) call CShellTreeCtrl::FindItemByPidl to get the HTREEITEM
3) call CTreeCtrl::SelectItem(hItem)
Paolo
------
Why spend 2 minutes doing it by hand when you can spend all night plus most of the following day writing a system to do it for you? - (Chris Maunder)
|
|
|
|
 |
|
 |
It works correctly!!!
Thank you very very very much!!!
|
|
|
|
 |
|
 |
Hi,
I can use this API in my project but my folder tree dosen't have the Desktop ico as the first root
like the first picture shown on this web page.
How can I do such that my tree can have a Desktop ico as root?
Thank you very much!
|
|
|
|
 |
|
 |
If the item is not showing at all, then make sure you called AddRootFolderContent(NULL).
If the icon only is not showing correctly, then make sure you did initialize the COM support in your project (see AfxOleInit).
By the way, what is your root item showing?
Paolo
------
Why spend 2 minutes doing it by hand when you can spend all night plus most of the following day writing a system to do it for you? - (Chris Maunder)
|
|
|
|
 |
|
 |
The item is not showing at all.
But I found that it is not shown becuase I used the old source code.
Now, I used the beta one in my dialog based project.
The Desktop Icon can be shown now.
Really thank you very much!
|
|
|
|
 |
|
|
 |
|
 |
That's because I never made a release packaged for download. The latest code is in the CVS repository, you may download it from there.
Paolo
------
Why spend 2 minutes doing it by hand when you can spend all night plus most of the following day writing a system to do it for you? - (Chris Maunder)
|
|
|
|
 |
|
 |
Hey Paolo, great article, thank you for posting it.
I compiled the project in Unicode mode successfully, the problem is the tree control still cannot display the Unicode names for objects. It shows black squares instead of the unicode names. Can u help me with this?
Thanks
|
|
|
|
 |
|
 |
Well, I don't use Unicode very much, but I tried to make a Unicode build of the project and it worked to me.
Only I got an access violation with the shell menu on some item, but I would need to investigate this further.
I might send you a zip archive with the latest code and the new build configuration, so you can try it out. It's not yet on CVS as I would like to be sure it works before committing the changes to the repository.
Cheers,
Paolo
------
Why spend 2 minutes doing it by hand when you can spend all night plus most of the following day writing a system to do it for you? - (Chris Maunder)
|
|
|
|
 |
|
 |
http://www.codeproject.com/treectrl/shelltreectrl.asp?forumid=1341&select=1373571&df=100#xx1373571xx
http://www.codeproject.com/treectrl/shelltreectrl.asp?forumid=1341&select=1373588&df=100#xx1373588xx
Thanks very much
Best Regards;P
|
|
|
|
 |
|
 |
I found IMalloc::getsize in your function :
void TSharedObject::Copy(const TSharedObject& shobj)
{
...
// obj to copy must have been allocated this way
SMallocPtr pMalloc;
ULONG size = pMalloc->GetSize((void*)shobj.m_pObj);
...
}
and PIDL::GetLength in
LPITEMIDLIST PIDL::Combine(LPCITEMIDLIST pidl1, LPCITEMIDLIST pidl2)
{
UINT cb1 = GetLength(pidl1);
UINT cb2 = GetLength(pidl2);
}
They both return the length of LPCITEMIDLIST,so they seems to do the same thing,do they?
Thanks very much
BTW,The more i use your class ,the more i like it, your project is the best in the world.
BEST REGARDS;P
-- modified at 10:49 Thursday 16th February, 2006
|
|
|
|
 |
|
 |
If I remember correctly, GetLength() walks the list of ITEMIDs to find its actual length. The size of the memory area may be larger than that. Consider that Shell functions and interfaces too use the IMalloc interface to allocate memory for PIDLs, not only my CShellPidl class, so I can't rely on the memory block size to get the PIDL length.
Paolo
------
Why spend 2 minutes doing it by hand when you can spend all night plus most of the following day writing a system to do it for you? - (Chris Maunder)
|
|
|
|
 |
|
 |
ok,i seems to get it.
is your means if it is CShellPidl class,so they both do the same thing?
so GetLength(PIDL) and getsize(PIDL) are always return the actual length of PIDL
thanks .
|
|
|
|
 |
|
 |
oh god,I am wrong
I found
PIDL::GetLength = IMalloc::getsize - sizeof(USHORT);
so,is it always correct about PIDL::GetLength = IMalloc::getsize - sizeof(USHORT); in DEBUG and Release
|
|
|
|
 |
|
 |
Well, they're two different things. It depends on what you're going to do with this value.
If you're working with PIDLs, use GetLength(). If you're working with memory allocation, use IMalloc::GetSize(). I guess it's not a requirement for GetSize() to return the size you've requested when you allocated that block of memory.
What do you need this for?
Paolo
------
Why spend 2 minutes doing it by hand when you can spend all night plus most of the following day writing a system to do it for you? - (Chris Maunder)
|
|
|
|
 |
|
|
 |
|
 |
If you look at the PIDL namespace I have two functions:
UINT GetRawLength(LPCITEMIDLIST pidl)
{
if (pidl == NULL)
return 0;
UINT length = sizeof(USHORT), cb;
do
{
cb = pidl->mkid.cb;
pidl = (LPCITEMIDLIST)((LPBYTE)pidl + cb);
length += cb;
}
while (cb != 0);
return length;
}
And:
UINT GetLength(LPCITEMIDLIST pidl)
{
UINT length = GetRawLength(pidl);
return (length == 0) ? length : length - sizeof(USHORT);
}
From that you can see why you are adding sizeof(USHORT) to GetLength(), but you'll probably want to call the first function instead.
The size returned from the "raw" version covers all the memory needed for the PIDL. The second version does not include the terminator (0x0000) and covers only the "contents" of a PIDL. I use the second version for concatenating PIDLs.
Don't ever use the IMalloc interface to get the size of a PIDL. That is surely wrong.
Now, about the serialization feature, you can see why I left it out. The Shell documentation say that you should never store a PIDL in binary form. But if you want to go with the GetDisplayName/ParseDisplayName method you are also warned that not all implementations of IShellFolder could do the job correctly. Now, I'm sure that system folders are ok, and that you could only have some troubles with Shell extensions.
All in all, however, I could never make a decision about it and so I simply omitted an implementation, although I would have liked to have one in my CShellPidl class.
Choice is yours now.
Best regards,
Paolo
------
Why spend 2 minutes doing it by hand when you can spend all night plus most of the following day writing a system to do it for you? - (Chris Maunder)
|
|
|
|
 |
|
 |
Thanks your reply.
Would you please to tell me Why The Shell documentation say that you should never store a PIDL in binary form? I don't find any resource about it,or Would you like to give me a URL link about it?
Thanks a lot.
Best Regards
|
|
|
|
 |
|
 |
I really appreciate when people post projects like this, but jeeze! Make sure the stuff compiles before posting!
Below are your errors. Sorry, but I'm done debugging your stuff.
WINVER not defined. Defaulting to 0x0501 (Windows XP and Windows .NET Server)
Compiling...
WaitingTreeCtrl.cpp
TestShellDlg.cpp
d:\Experiments\ShellTreeCtrl (OLD)\ProgressFX.h(113) : error C2668: 'exp' : ambiguous call to overloaded function
c:\Program Files\Microsoft Visual Studio .NET 2003\Vc7\include\math.h(600): could be 'long double exp(long double)'
c:\Program Files\Microsoft Visual Studio .NET 2003\Vc7\include\math.h(552): or 'float exp(float)'
c:\Program Files\Microsoft Visual Studio .NET 2003\Vc7\include\math.h(189): or 'double exp(double)'
while trying to match the argument list '(int)'
d:\Experiments\ShellTreeCtrl (OLD)\HourglassFX.h(37) : while compiling class-template member function 'void CProgressFX<BASE_TYPE>::DoAnimation(BOOL,int,int)'
with
[
BASE_TYPE=CHourglassShellTreeCtrl
]
d:\Experiments\ShellTreeCtrl (OLD)\TestShellDlg.h(35) : see reference to class template instantiation 'CProgressFX<BASE_TYPE>' being compiled
with
[
BASE_TYPE=CHourglassShellTreeCtrl
]
ShellTreeCtrl.cpp
d:\Experiments\ShellTreeCtrl (OLD)\ShellTreeCtrl.cpp(303) : error C2065: 'SHGDN_INCLUDE_NONFILESYS' : undeclared identifier
d:\Experiments\ShellTreeCtrl (OLD)\ShellTreeCtrl.cpp(303) : error C2676: binary '|' : 'tagSHGDN' does not define this operator or a conversion to a type acceptable to the predefined operator
ResizableDialog.cpp
d:\Experiments\ShellTreeCtrl (OLD)\ResizableDialog.cpp(221) : warning C4554: '&' : check operator precedence for possible error; use parentheses to clarify precedence
Demo.cpp
d:\Experiments\ShellTreeCtrl (OLD)\ProgressFX.h(113) : error C2668: 'exp' : ambiguous call to overloaded function
c:\Program Files\Microsoft Visual Studio .NET 2003\Vc7\include\math.h(600): could be 'long double exp(long double)'
c:\Program Files\Microsoft Visual Studio .NET 2003\Vc7\include\math.h(552): or 'float exp(float)'
c:\Program Files\Microsoft Visual Studio .NET 2003\Vc7\include\math.h(189): or 'double exp(double)'
while trying to match the argument list '(int)'
c:\Program Files\Microsoft Visual Studio .NET 2003\Vc7\atlmfc\include\afxtempl.h(1869) : while compiling class-template member function 'void CProgressFX<BASE_TYPE>::DoAnimation(BOOL,int,int)'
with
[
BASE_TYPE=CHourglassShellTreeCtrl
]
d:\Experiments\ShellTreeCtrl (OLD)\TestShellDlg.h(35) : see reference to class template instantiation 'CProgressFX<BASE_TYPE>' being compiled
with
[
BASE_TYPE=CHourglassShellTreeCtrl
]
Generating Code...
|
|
|
|
 |