How to obtain the list of visible columns in a shell view
I was recently looking into how to obtain the list of columns displayed in the shell view for a namespace extension that uses the default shell view (DefView). DefView provides the IColumnManager interface to manage the columns that can be displayed in in the view window. The following sample code demonstrates listing the visible columns for each shell view hosted in a shell browser window contained in the ShellWindows collection:
#include <windows.h>
#include <ShlObj.h>
#include <Shlwapi.h>
#include <propsys.h>
#include <stdio.h>
#pragma comment(lib, "propsys.lib")
#pragma comment (lib, "shlwapi.lib")
HRESULT PrintShellViewColumns(IShellView *);
int wmain(int argc, wchar_t *argv[])
{
//
// For each item in the ShellWindows collection that has an active
// IShellView, print the list of visible columns in the view window
HRESULT hr = CoInitialize(NULL);
if (SUCCEEDED(hr))
{
IShellWindows *pShellWindows;
hr = CoCreateInstance(CLSID_ShellWindows, NULL, CLSCTX_LOCAL_SERVER,
IID_PPV_ARGS(&pShellWindows));
if (SUCCEEDED(hr))
{
long cWindows = 0;
hr = pShellWindows->get_Count(&cWindows);
for (long iWindow = 0;
SUCCEEDED(hr) && iWindow < cWindows;
iWindow++)
{
VARIANT vtIndex;
vtIndex.vt = VT_I4;
vtIndex.lVal = iWindow;
IDispatch *pDispatch;
hr = pShellWindows->Item(vtIndex, &pDispatch);
if (S_OK == hr))
{
IShellBrowser *pShellBrowser;
hr = IUnknown_QueryService(pDispatch,
SID_STopLevelBrowser,
IID_PPV_ARGS(&pShellBrowser));
if (SUCCEEDED(hr))
{
IShellView *pShellView;
hr = pShellBrowser->QueryActiveShellView(&pShellView);
if (SUCCEEDED(hr))
{
PrintShellViewColumns(pShellView);
}
pShellBrowser->Release();
}
pDispatch->Release();
}
}
pShellWindows->Release();
}
CoUninitialize();
}
return (int)hr;
}
void PrintHeader(IShellView *pShellView)
{
//
// Print a header that includes the display name of the folder displayed
// in the view window
IFolderView *pFolderView;
HRESULT hr = pShellView->QueryInterface(IID_PPV_ARGS(&pFolderView));
if (SUCCEEDED(hr))
{
IShellItemArray *pShellItemArray;
hr = pFolderView->GetFolder(IID_PPV_ARGS(&pShellItemArray));
if (SUCCEEDED(hr))
{
IShellItem *pShellItem;
hr = pShellItemArray->GetItemAt(0, &pShellItem);
if (SUCCEEDED(hr))
{
LPWSTR pszDisplayName;
hr = pShellItem->GetDisplayName(SIGDN_NORMALDISPLAY,
&pszDisplayName);
if (SUCCEEDED(hr))
{
wprintf(L"IShellView: %p Folder: %s\r\n",
pShellView, pszDisplayName);
CoTaskMemFree(pszDisplayName);
}
pShellItem->Release();
}
pShellItemArray->Release();
}
pFolderView->Release();
}
if (FAILED(hr))
{
//
// Print a generic header on an error
wprintf(L"IShellView: %p\r\n", pShellView);
}
wprintf(L"----------------------------------------\r\n");
}
void PrintFooter(IShellView *pShellView)
{
UNREFERENCED_PARAMETER(pShellView);
wprintf(L"\r\n");
}
void PrintPropertyKey(PROPERTYKEY &propkey)
{
LPWSTR pszCanonicalName = NULL;
HRESULT hr = PSGetNameFromPropertyKey(propkey, &pszCanonicalName);
if (SUCCEEDED(hr))
{
wprintf(L" %s\r\n", pszCanonicalName);
CoTaskMemFree(pszCanonicalName);
}
else
{
WCHAR szGuid[50];
ZeroMemory(szGuid, sizeof(szGuid));
hr = StringFromGUID2(propkey.fmtid, szGuid, ARRAYSIZE(szGuid));
if (SUCCEEDED(hr))
{
wprintf(L" %s,%d\r\n", szGuid, propkey.pid);
}
else
{
wprintf(L" Unknown. Error=%X\r\n", hr);
}
}
}
HRESULT PrintShellViewColumns(IShellView *pShellView)
{
IColumnManager *pColumnManager;
HRESULT hr = pShellView->QueryInterface(IID_PPV_ARGS(&pColumnManager));
if (SUCCEEDED(hr))
{
PrintHeader(pShellView);
UINT nColumns = 0;
hr = pColumnManager->GetColumnCount(CM_ENUM_VISIBLE, &nColumns);
if (SUCCEEDED(hr) && nColumns)
{
PROPERTYKEY *columns = new PROPERTYKEY[nColumns];
hr = pColumnManager->GetColumns(CM_ENUM_VISIBLE,
columns,
nColumns);
if (SUCCEEDED(hr))
{
for (UINT index = 0; index < nColumns; index++)
{
PrintPropertyKey(columns[index]);
}
}
delete columns;
}
pColumnManager->Release();
PrintFooter(pShellView);
}
return hr;
}