Figure 1
Windows Shell Extensions
Type
|
Apply to
|
Version
|
Interface Involved
|
Description
|
Context Menu
|
File class and shell's object
|
Windows 95+
|
IContextMenu, IContextMenu2, or IContextMenu3
|
Allows you to add new items to a shell object's context menu.
|
Right drag and drop
|
File class and shell's object
|
Windows 95+
|
IContextMenu, IContextMenu2, or IContextMenu3
|
Allows you to add new items to the context menu that appears after you right drag and drop files.
|
Drawing shell Icons
|
File class and shell's object
|
Windows 95+
|
IExtractIcon
|
Lets you decide at runtime which icon should be displayed for a given file within a file class.
|
Property Sheet
|
File class and shell's object
|
Windows 95+
|
IShellPropSheetExt
|
Lets you insert additional property sheet pages to the file class Properties dialog. It also works for Control Panel applets.
|
Left drag and drop
|
File class and shell's object
|
Windows 95+
|
IDropTarget
|
Lets you decide what to do when an object is being dropped (using the left mouse button) onto another one within the shell.
|
Clipboard
|
File class and shell's object
|
Windows 95+
|
IDataObject
|
Lets you define how an object is to be copied to and extracted from the clipboard.
|
File Hook
|
|
Windows 95+
|
ICopyHook
|
Lets you control any file operation that goes through the shell. While you can permit or deny them, you aren't informed about success or failure.
|
Program Execution
|
Explorer
|
Desktop Update
|
IShellExecuteHook
|
Lets you hook any program's execution that passes through the shell.
|
Infotip
|
File class and shell's object
|
Desktop Update
|
IQueryInfo
|
Lets you display a short text message when the mouse hovers over documents of a certain file type.
|
Column
|
Folders
|
Windows 2000
|
IColumnProvider
|
Lets you add a new column to the Details view of Explorer.
|
Icon Overlay
|
Explorer
|
Windows 2000
|
IShellIconOverlay
|
Lets you define custom images to be used as icon overlays.
|
Search
|
Explorer
|
Windows 2000
|
IContextMenu
|
Lets you add a new entry on the Start menu's Search menu.
|
Cleanup
|
Cleanup Manager
|
Windows 2000
|
IEmptyVolumeCache2
|
Lets you add a new entry to the Cleanup Manager to recover disk space.
|
Figure 3
Implementing the BMP Infotip
// IPersistFileImpl.h
#include <AtlCom.h>
class ATL_NO_VTABLE IPersistFileImpl : public IPersistFile{
public:
TCHAR m_szFile[MAX_PATH];
// IUnknown
STDMETHOD(QueryInterface)(REFIID riid, void** ppvObject) = 0;
_ATL_DEBUG_ADDREF_RELEASE_IMPL(IPersistFileImpl)
// IPersistFile
STDMETHOD(Load)(LPCOLESTR wszFile, DWORD dwMode){
USES_CONVERSION;
_tcscpy(m_szFile, OLE2T((WCHAR*)wszFile));
return S_OK;
};
STDMETHOD(GetClassID)(LPCLSID){ return E_NOTIMPL; }
STDMETHOD(IsDirty)(VOID){ return E_NOTIMPL; }
STDMETHOD(Save)(LPCOLESTR, BOOL){ return E_NOTIMPL; }
STDMETHOD(SaveCompleted)(LPCOLESTR){ return E_NOTIMPL; }
STDMETHOD(GetCurFile)(LPOLESTR FAR*){ return E_NOTIMPL; }
};
// IQueryInfoImpl.h
#include <AtlCom.h>
#include <ShlObj.h>
class ATL_NO_VTABLE IQueryInfoImpl : public IQueryInfo{
public:
// IUnknown
STDMETHOD(QueryInterface)(REFIID riid, void** ppvObject) = 0;
_ATL_DEBUG_ADDREF_RELEASE_IMPL(IQueryInfoImpl)
// IQueryInfo::GetInfoTip
STDMETHOD(GetInfoTip)(DWORD dwFlags, LPWSTR *ppwszTip){
wcscpy(*ppwszTip, L"InfoTip");
return S_OK;
}
// IQueryInfo::GetInfoFlags
STDMETHOD(GetInfoFlags)(LPDWORD pdwFlags){
*pdwFlags = 0;
return E_NOTIMPL;
}
};
// BmpTip.h : Declaration of the CBmpTip coclass
#ifndef __BMPTIP_H_
#define __BMPTIP_H_
#include "resource.h" // main symbols
#include "comdef.h" // GUIDs
#include "IPersistFileImpl.h" // IPersistFile
#include "IQueryInfoImpl.h" // IQueryInfo
// CBmpTip
class ATL_NO_VTABLE CBmpTip :
public CComObjectRootEx<CComSingleThreadModel>,
public CComCoClass<CBmpTip, &CLSID_BmpTip>,
public IQueryInfoImpl,
public IPersistFileImpl,
public IDispatchImpl<IBmpTip, &IID_IBmpTip,
&LIBID_BMPEXTLib>{
public:
CBmpTip(){
HRESULT hr;
hr = SHGetMalloc(&m_pAlloc);
if (FAILED(hr)) m_pAlloc = NULL;
}
~CBmpTip(){
m_pAlloc->Release();
}
DECLARE_REGISTRY_RESOURCEID(IDR_BMPTIP)
DECLARE_PROTECT_FINAL_CONSTRUCT()
BEGIN_COM_MAP(CBmpTip)
COM_INTERFACE_ENTRY(IBmpTip)
COM_INTERFACE_ENTRY(IQueryInfo)
COM_INTERFACE_ENTRY(IPersistFile)
COM_INTERFACE_ENTRY(IDispatch)
END_COM_MAP()
// IQueryInfo
public:
STDMETHOD(GetInfoTip)(DWORD, LPWSTR*);
private:
STDMETHOD(GetBitmapInfo)(CComBSTR*);
LPMALLOC m_pAlloc;
};
#endif //__BMPTIP_H_
Figure 7
A Column Handler Extension
// IColumnProviderImpl.h
#include <AtlCom.h>
#include <ShlObj.h>
class ATL_NO_VTABLE IColumnProviderImpl : public IColumnProvider
{
protected:
TCHAR m_szFolder[MAX_PATH];
public:
// IUnknown
STDMETHOD(QueryInterface)(REFIID riid, void** ppvObject) = 0;
_ATL_DEBUG_ADDREF_RELEASE_IMPL(IColumnProviderImpl)
// IColumnProvider
// IColumnProvider::Initialize
STDMETHOD(Initialize)(LPCSHCOLUMNINIT psci){
USES_CONVERSION;
_tcscpy(m_szFolder, OLE2T((WCHAR*)psci->wszFolder));
return S_OK;
}
// IColumnProvider::GetColumnInfo
STDMETHOD(GetColumnInfo)(DWORD dwIndex,
SHCOLUMNINFO *psci){
return S_FALSE;
}
// IColumnProvider::GetItemData
STDMETHOD(GetItemData)(LPCSHCOLUMNID pscid,
LPCSHCOLUMNDATA pscd,
VARIANT *pvarData){
return S_FALSE;
}
};
// BmpColInfo.h : Declaration of the CBmpColInfo
#ifndef __BMPCOLINFO_H_
#define __BMPCOLINFO_H_
#include "resource.h" // main symbols
#include <shlguid.h> // GUID of IColumnProvider
#include "IColumnProviderImpl.h" // IColumnProvider base impl
const UINT BMPCH_DEFWIDTH = 16;// column default width in chars
const UINT BMPCH_MAXSIZE = 80; // max text size
const DWORD BMPCH_NUMOFCOLS = 1;// number of columns handled
// here
// CBmpColInfo
class ATL_NO_VTABLE CBmpColInfo :
public CComObjectRootEx<CComSingleThreadModel>,
public CComCoClass<CBmpColInfo, &CLSID_BmpColInfo>,
public IColumnProviderImpl,
public IDispatchImpl<IBmpColInfo, &IID_IBmpColInfo,
&LIBID_BMPCOLLib>{
public:
CBmpColInfo(){}
DECLARE_REGISTRY_RESOURCEID(IDR_BMPCOLINFO)
DECLARE_PROTECT_FINAL_CONSTRUCT()
BEGIN_COM_MAP(CBmpColInfo)
COM_INTERFACE_ENTRY(IBmpColInfo)
COM_INTERFACE_ENTRY_IID(IID_IColumnProvider, CBmpColInfo)
COM_INTERFACE_ENTRY(IDispatch)
END_COM_MAP()
// IColumnProvider
public:
STDMETHOD(GetColumnInfo)(DWORD, SHCOLUMNINFO *);
STDMETHOD(GetItemData)(LPCSHCOLUMNID, LPCSHCOLUMNDATA,
VARIANT *);
private:
STDMETHOD(GetBitmapInfo)(LPCWSTR, LPTSTR);
};
#endif //__BMPCOLINFO_H_
// BmpColInfo.cpp : Implementation of CBmpColInfo
#include "stdafx.h"
#include "BmpCol.h"
#include "BmpColInfo.h"
HRESULT CBmpColInfo::GetColumnInfo(DWORD dwIndex,
SHCOLUMNINFO *psci){
// Since this extension might provide more columns, the
// index is used to enumerate them. The shell calls
// this method repeatedly with progressive indexes, until
// you return S_FALSE. Return S_FALSE only when you've
// finished with all your columns. dwIndex is a 0-based
// index. Notice that without this checking you enter
// an infinite loop!
if (dwIndex >= BMPCH_NUMOFCOLS)
return S_FALSE;
// Now fills out the SHCOLUMNINFO structure to let the
// shell know about general-purpose features of the column
// Identifies the column with a FMTID/PID pair. You'd
// define one of these pairs for each column you're
// adding here.
psci->scid.fmtid = *_Module.pguidVer; // use object's CLSID
psci->scid.pid = 1;
// Sets type, alignment and default width
psci->vt = VT_LPSTR; // data is LPSTR
psci->fmt = LVCFMT_LEFT; // left alignment
psci->cChars = BMPCH_DEFWIDTH; // default width in chars
// Other flags
psci->csFlags = SHCOLSTATE_TYPE_STR;
// Caption and description
wcsncpy(psci->wszTitle, L"Dimensions", MAX_COLUMN_NAME_LEN);
wcsncpy(psci->wszDescription,
L"Provides dimensions and colors for BMPs",
MAX_COLUMN_DESC_LEN);
return S_OK;
}
// IColumnProvider::GetItemData
HRESULT CBmpColInfo::GetItemData(LPCSHCOLUMNID pscid,
LPCSHCOLUMNDATA pscd,
VARIANT *pvarData){
USES_CONVERSION;
// The shell calls this method for each file displayed
// in the folder where this column has been selected.
// The SHCOLUMNID structure identifies the column
// unequivocally just in case you're handling more than one.
// In this case, I'm managing just one column so I'll
// ignore the SHCOLUMNID param.
// Information about the specific file is contained in the
// SHCOLUMNDATA structure. I'm interested only in .BMP.
if (wcsicmp(pscd->pwszExt, L".bmp")) return S_FALSE;
// Reads dimensions and palette size from the BMP file
TCHAR szBuf[BMPCH_MAXSIZE];
GetBitmapInfo(pscd->wszFile, szBuf);
// The return value (a string in this case) must be
// packed as a Variant.
CComVariant cv(szBuf);
cv.Detach(pvarData);
return S_OK;
}
HRESULT CBmpColInfo::GetBitmapInfo(LPCWSTR wszFile, LPTSTR p){
USES_CONVERSION;
BITMAPFILEHEADER bf;
BITMAPINFOHEADER bi;
HFILE h;
// Reads the file header
h = _lopen(OLE2T(wszFile), OF_READ);
if (h==HFILE_ERROR) return S_OK;
_lread(h, (LPBITMAPFILEHEADER)&bf, sizeof(BITMAPFILEHEADER));
_lread(h, (LPBITMAPINFOHEADER)&bi, sizeof(BITMAPINFOHEADER));
_lclose(h);
// Formats the string
wsprintf(p, _T("%d x %d x %d"), bi.biWidth, bi.biHeight,
bi.biBitCount);
return S_OK;
}
Figure 11
Cleanup Extension
// IEmptyVolumeCache2Impl.h
#include <AtlCom.h>
#include <emptyvc.h>
class ATL_NO_VTABLE IEmptyVolumeCache2Impl : public IEmptyVolumeCache2{
public:
// IUnknown
STDMETHOD(QueryInterface)(REFIID riid, void** ppvObject) =
0;
_ATL_DEBUG_ADDREF_RELEASE_IMPL(IEmptyVolumeCache2Impl)
// IEmptyVolumeCache::Initialize
STDMETHOD(Initialize)(HKEY hkRegKey, LPCWSTR pcwszVolume,
LPWSTR *ppwszDisplayName,
LPWSTR *ppwszDescription,
DWORD *pdwFlags){
// Allows to initialize a Windows 98 handler
MessageBox(0, _T("Initialize"), 0, 0);
return S_OK;
}
// IEmptyVolumeCache::Deactivate
STDMETHOD(Deactivate)(DWORD *pdwFlags){
// Called when the handler is going to be unloaded
MessageBox(0, _T("Deactivate"), 0, 0);
return S_OK;
}
// IEmptyVolumeCache::GetSpaceUsed
STDMETHOD(GetSpaceUsed)(DWORDLONG *pdwSpaceUsed,
IEmptyVolumeCacheCallBack *picb){
// Returns the amount of space the handler can free
MessageBox(0, _T("GetSpaceUsed"), 0, 0);
return S_OK;
}
// IEmptyVolumeCache::Purge
STDMETHOD(Purge)(DWORDLONG dwSpaceToFree,
IEmptyVolumeCacheCallBack *picb){
// Actually deletes the files
MessageBox(0, _T("Purge"), 0, 0);
return S_OK;
}
// IEmptyVolumeCache::ShowProperties
STDMETHOD(ShowProperties)(HWND hwnd){
// Provides a UI
MessageBox(0, _T("ShowProperties"), 0, 0);
return S_OK;
}
// IEmptyVolumeCache2::InitializeEx
STDMETHOD(InitializeEx)(HKEY hkRegKey, LPCWSTR pcwszVolume,
LPCWSTR pcwszKeyName,
LPWSTR *ppwszDisplayName,
LPWSTR *ppwszDescription,
LPWSTR *ppwszBtnText,
DWORD *pdwFlags){
// Initializes the handler under Windows 2000
MessageBox(0, _T("InitializeEx"), 0, 0);
return S_OK;
}
};
// CleanSomething.h : Declaration of the CCleanSomething
#ifndef __CLEANSOMETHING_H_
#define __CLEANSOMETHING_H_
#include "resource.h" // main symbols
#include "IEmptyVolumeCache2Impl.h" // IEmptyVolumeCache2
/////////////////////////////////////////////////////////////////
// CCleanSomething
class ATL_NO_VTABLE CCleanSomething :
public CComObjectRootEx<CComSingleThreadModel>,
public CComCoClass<CCleanSomething, &CLSID_CleanSomething>,
public IEmptyVolumeCache2Impl,
public IDispatchImpl<ICleanSomething, &IID_ICleanSomething,
&LIBID_DCHDEMOLib>{
public:
CCleanSomething(){}
DECLARE_REGISTRY_RESOURCEID(IDR_CLEANSOMETHING)
DECLARE_PROTECT_FINAL_CONSTRUCT()
BEGIN_COM_MAP(CCleanSomething)
COM_INTERFACE_ENTRY(IEmptyVolumeCache)
COM_INTERFACE_ENTRY(IEmptyVolumeCache2)
COM_INTERFACE_ENTRY(ICleanSomething)
COM_INTERFACE_ENTRY(IDispatch)
END_COM_MAP()
// IEmptyVolumeCache2
public:
STDMETHOD(InitializeEx)(HKEY hkRegKey, LPCWSTR pcwszVolume,
LPCWSTR pcwszKeyName,
LPWSTR *ppwszDisplayName,
LPWSTR *ppwszDescription,
LPWSTR *ppwszBtnText,
DWORD *pdwFlags);
STDMETHOD(GetSpaceUsed)(DWORDLONG *pdwSpaceUsed,
IEmptyVolumeCacheCallBack *picb);
};
#endif //__CLEANSOMETHING_H_
// CleanSomething.cpp : Implementation of CCleanSomething
#include "stdafx.h"
#include "DCHDemo.h"
#include "CleanSomething.h"
// CCleanSomething
HRESULT CCleanSomething::InitializeEx(HKEY hkRegKey,
LPCWSTR pcwszVolume, LPCWSTR pcwszKeyName,
LPWSTR *ppwszDisplayName, LPWSTR *ppwszDescription,
LPWSTR *ppwszBtnText, DWORD *pdwFlags){
USES_CONVERSION;
MessageBoxW(0, pcwszVolume, 0, 0);
*ppwszDisplayName = (LPWSTR)CoTaskMemAlloc(100);
*ppwszDescription = (LPWSTR)CoTaskMemAlloc(100);
*ppwszBtnText = (LPWSTR)CoTaskMemAlloc(100);
lstrcpyW(*ppwszDisplayName, T2OLE("DCHDemo"));
lstrcpyW(*ppwszDescription, T2OLE("Clean Something"));
lstrcpyW(*ppwszBtnText, T2OLE("Click Me!"));
*pdwFlags |= EVCF_HASSETTINGS;
return S_OK;
}
HRESULT CCleanSomething::GetSpaceUsed(DWORDLONG *pdwSpaceUsed,
IEmptyVolumeCacheCallBack *picb){
*pdwSpaceUsed = 1024000;
return S_OK;
}
Figure 16
Invoking the Command Prompt
TCHAR szCommand[MAX_PATH] = TEXT("");
STARTUPINFO sui;
PROCESS_INFORMATION pi;
OSVERSIONINFO osi;
GetEnvironmentVariable(TEXT("ComSpec"), szCommand,
ARRAYSIZE(szCommand));
if(!*szCommand){
osi.dwOSVersionInfoSize = sizeof(osi);
GetVersionEx(&osi);
if(VER_PLATFORM_WIN32_NT == osi.dwPlatformId){
lstrcpy(szCommand, TEXT("cmd.exe"));
} else{
lstrcpy(szCommand, TEXT("command.com"));
}
}
//set up the STARTUPINFO structure
ZeroMemory(&sui, sizeof(sui));
sui.cb = sizeof(sui);
//create the process
CreateProcess( NULL, szCommand, NULL, NULL,
FALSE, NORMAL_PRIORITY_CLASS,
NULL, szInitialDirectory,
&sui, &pi);
|