Using the Shell Namespace To Get Network Computers, Printers and Recycle Bin Items

Environment: VC6
This article explains how to make use of the COM interfaces implemented by Shell Extensions to get the required information on a local machine or network. In this example I have demonstrated it to get the list of all user machines logged onto the network, printers attached to network and items in the recycle bin of local machine. The CShellExt wrapper class can be extended to include the functionality to extract all kind of information. Although there are a lot of wrapper shell functions present to get the same information, but use of COM interfaces gives an insight into what foes on behind the scene in windows explorer and how we can extend the shell's namespace.
Before we ask for any information from Shell, there are couple of environment variables, which needs to be initialized. First we need to allocate memory in Shell's address space. Asking for IMalloc interface pointer, which we will release before we exit our application, can do this. The Desktop folder is the root of Shell's name space, therefore we will need the interface pointer to that. These steps have been implemented in InitializeEnvironment function of CShellExt class.
HRESULT hr = SHGetMalloc (&m_pMalloc); HRESULT hr = SHGetDesktopFolder (&m_pDesktopFolder);
Network Neighborhood, Printers, RecycleBin, etc. fall under the category of Special Folders a.k.a Virtual Folders. Windows API provides bunch of functions to work with them. We use SHGetSpecialFolderPath function to obtain the path to required folder. E.g. to obtain path to printers folder
HRESULT hr = SHGetSpecialFolderLocation (NULL, CSIDL_PRINTERS, &netItemIdLst);
To get more information about second argument to this function call, look in the on-line help. This argument specifies the special folder for which IShellFolder interface is needed. The link between special folders and their paths is stored in the registry as:
HKEY_CURRENT_USER
\Software
\Microsoft
\Windows
\CurrentVersion
\Explorer
\Shell Folders
After we have IShellFolder interface pointer to special folder, we can ask for contents of folder by creating an item enumeration object (a set of item identifiers) that can be retrieved using the IEnumIDList interface. E.g. for printer folder
HRESULT hr = pPrinterFolder->EnumObjects (NULL, SHCONTF_FOLDERS | SHCONTF_NONFOLDERS, &pEnumIds);
After we have ID list enumeration, the display name for each item can be obtained by using GetDisplayNameOf method of IShellFolder interface.
while ((hr = pEnumIds->Next (1, &pidlItems, &celtFetched)) != S_FALSE && celtFetched == 1)
{
hr = pPrinterFolder->GetDisplayNameOf (pidlItems, SHGDN_INFOLDER, &strDispName);
if (FAILED (hr))
{
goto FreeInterfaces;
}
.
.
}
After we have obtained the display name of the folder, we need to extract icons. Every shell object which has icon(s) associated with it, implements IExtractIcon interface. This can be obtained by using GetUIObjectOf method of IShellFolder interface. After getting the IExtractIcon interface pointer, use its two methods to get handles to small and large icons. This has been implemented in GetIconsForFolderNode function of CShellExt class.
IExtractIcon *pExtractIcon = NULL;
hr = pFolderNode->GetUIObjectOf (NULL, 1, const_cast<LPCITEMIDLIST *>(&pidlItems),
IID_IExtractIcon, NULL, reinterpret_cast<LPVOID *>(&pExtractIcon));
if (SUCCEEDED (hr)) {
TCHAR str[MAX_PATH] = {0};
int index;
UINT flags;
// Get the file location where the icons are stored.
hr = pExtractIcon->GetIconLocation (0, str, MAX_PATH, &index, &flags);
if (SUCCEEDED (hr)) {
HICON hiconLarge = NULL;
HICON hiconSmall = NULL;
UINT nIconSize = MAKELONG (32, 16);
LPCSTR pszFile = (LPCSTR)str;
// Extract the icon handles from the location.
hr = pExtractIcon->Extract (str, index, &hIconLg, &hIconSm, nIconSize);
pExtractIcon->Release ();
}
}
To show the use of this extension class, I have created a dialog-based application, which has a tool bar with 3 buttons for NetWork compuetrs, Printers, RecycleBin items. Click on one of them to see the results. The sample application also shows the usage of CTreeCtrl and how to implement CToolBar in dialog based applications.
Downloads
Download demo project - 28.3 Kb

Comments
Drag-Drop Across Virtual Folders and Windows File System in the Windows Explorer
Posted by Legacy on 03/03/2000 12:00amOriginally posted by: Suneel Kumar.P
How to get the target folder PIDL? ( folder on which the user dorps the files being dragged ).
Some body please help me as soon as possible.
ReplyHow to add stuff to my computer ?
Posted by Legacy on 03/02/2000 12:00amOriginally posted by: Matthew Campbell
Does anyone know how to add icons to "My computer". For say a program.
ReplyFailing when i try to use CSIDL_HISTORY !!!!?
Posted by Legacy on 02/24/2000 12:00amOriginally posted by: jabarooth
This sample is failing at SHGetSpecialFolderLocation() function calling when i use CSIDL_HISTORY. Help me Pls...
ReplyCan i Create Special Folders Or Virtual Folders
Posted by Legacy on 01/25/2000 12:00amOriginally posted by: Ashutosh
ReplyHow to open Add Printers dialog programmatically
Posted by Legacy on 09/21/1999 12:00amOriginally posted by: Pramendra
Does anybody know how to open the Add Printers Dialog Programmatically.
My idea is :
1. Get the PIDL of the 'Add Printer' folder.
2. Fill Up a SHELLEXECUTEINFO Structure.
3. Use ShellExecuteEx to open the dialog.
has anybody done this before?
Replybest regards
Pramendra Dadhwal
Where's the Comment?
Posted by Legacy on 08/11/1999 12:00amOriginally posted by: Carsten Witte
Hi Gurus,
I'v done a similar shell-enum, getting all machines, every shared folder (I don't care for printers), entire network... so far so good, but I (or the function) fail miserably when it comes to the comments. Explorer is displaying those fine, so I guess it must be part of it.
At the point, where I got a correct folder and item (must be correct since I get the correct name and icon, what is predicable, since lpItem came from lpFolder->EnumObjects) and tried a:
NETRESOURCE nrc;
::ZeroMemory (&nrc, sizeof (nrc));
hResult= SHGetDataFromIDList (lpFolder, lpItem, SHGDFIL_NETRESOURCE, (PVOID) &nrc, sizeof (nrc));
It simply fails on all machines that are part of my workgroup and therefore childen of the CSIDL_NETWORK and works fine on anything under "Entire Network". But not even then it wouldn't fill *any* of the nrc.lp* entries.
What's wrong?
TIA, Carsten Witte
ReplyMapping an internet drive(using FTP) just like a native drive.
Posted by Legacy on 08/11/1999 12:00amOriginally posted by: Anand
How can I map an internet drive using FTP, just like a native network drive. The mapped drive should be listed in the windows explorer just like any other logical drive and should provide all the functions e.g copying,renamin, etc.
Replyregards
Anand
...
Posted by Legacy on 07/21/1999 12:00amOriginally posted by: Mihai
ReplyCode for getting icon for control pannel items ..
Posted by Legacy on 07/16/1999 12:00amOriginally posted by: Naveen Kohli
//
HRESULT
CShellExt::GetIconsForControlPanel (LPCTSTR lpszFile, HICON &hIconSm, HICON &hIconLg)
{
HRESULT hr = S_OK;
NEWCPLINFO ncpInfo;
ZeroMemory (&ncpInfo, sizeof (ncpInfo));
ncpInfo.dwSize = sizeof (ncpInfo);
// Load the CPL for the control pannel applet.
HINSTANCE hlibCPL = ::LoadLibrary (lpszFile);
// Get the process address of the Applet's entry point DLL i.e. CPiApplet which all the
// control panel applets are supposed to provide.
APPLET_PROC fCPLApplet = (APPLET_PROC)GetProcAddress (hlibCPL, "CPlApplet");
// Initialize the Applet.
if (fCPLApplet (NULL, CPL_INIT, 0, 0)) {
// Get the number of aplets supported by this control pannel object.
LONG numApplets = fCPLApplet (NULL, CPL_GETCOUNT, 0, 0);
// Inquire the applet.
LONG retVal = fCPLApplet (NULL, CPL_NEWINQUIRE, 0, (LONG)&ncpInfo);
HICON hSmIcon, hLgIcon;
ExtractIconEx (lpszFile, 0, &hSmIcon, &hLgIcon, 2);
hIconSm = ::CopyIcon (hSmIcon);
hIconLg = ::CopyIcon (hLgIcon);
if (hIconSm == NULL) {
hIconSm = ::CopyIcon (hLgIcon);
}
}
// Before we free the applet dll, notify it to exit.
fCPLApplet (NULL, CPL_EXIT, 0, 0);
// Free the loaded library
FreeLibrary (hlibCPL);
return hr;
}
// changes to be made in GetIconsForFolderNode function...
Replyif (m_bControlPanelSearch) {
try {
hr = GetIconsForControlPanel (pszFile, hIconSm, hIconLg);
}
catch (...) {
TRACE (_T ("Exception thrown\n"));
}
}
else {
hr = pExtractIcon->Extract (str, index, &hIconLg, &hIconSm, nIconSize);
pExtractIcon->Release ();
}
How about the control panel?
Posted by Legacy on 06/02/1999 12:00amOriginally posted by: Byron Montgomerie
I know how to get the control panel labels using enum, but
getting the icons for control panels with multiple entries
seems to be a rather tricky task, any ideas? (Some control panels use several icons, descriptions etc when communicating with the control panel application, you can call them "manually" using various argument like 1, 2, @1, @2 etc using shell32.dll, but that is icky) Differentiating between mouse/keyboard/etc when they all resolve to one control panel is my problem, any clue? Is there a standard
argument convention for this kind of thing? Looking for
something that kind apply to control panels, Dialup networking entries etc.
Thanks for any info
Byron
ReplyLoading, Please Wait ...