Click here to Skip to main content
Click here to Skip to main content
Add your own
alternative version
Go to top

The Mini Shell Extension Framework – Part III

, 18 Sep 2005
Discussion of a small C++ framework to create Windows shell extensions (IShellFolderImpl).
msf091.zip
include
columnprovider.rgs
contextmenu.rgs
contextmenu_sf.rgs
extension.rgs
extractimage_sf.rgs
infotip.rgs
infotip_sf.rgs
propertysheetext.rgs
propertysheetext_sf.rgs
shell32missing.def
shell32missing.lib
shellfolder.rgs
shellfolderwin98.rgs
vvvsample
Copy of sample1.vvv
menuicon.bmp
sample.def
sample.manifest
sample1.vvv
vvv.ico
vvvtest
sample.yyy
sample1.vvv
sample2.vvv
//
// (C) Copyright by Victor Derks <vba64@xs4all.nl>
//
// See README.TXT for the details of the software licence.
//
#pragma once


// Purpose: this file contains small helper functions. 

#include <algorithm>
#include <shellapi.h>
#include "macros.h"


namespace MSF
{

inline CString GetModuleDirectory()
{
	TCHAR sz[MAX_PATH];
	ATLVERIFY(::GetModuleFileName(GetModuleHandle(NULL), sz,  MAX_PATH));

	PathRemoveFileSpec(sz);

	return sz + CString(_T("\\"));
}


inline CStringW GetModuleDirectoryW()
{
	wchar_t wz[MAX_PATH];
	ATLVERIFY(::GetModuleFileNameW(GetModuleHandle(NULL), wz,  MAX_PATH));

	PathRemoveFileSpecW(wz);

	return wz + CStringW(L"\\");
}


inline CString GetSystemDirectory()
{
	TCHAR tsz[MAX_PATH];
	ATLVERIFY(::GetSystemDirectory(tsz,MAX_PATH));

	return tsz;
}


inline DWORD GetFileSize(const CString& strFile)
{
	HANDLE hFile = CreateFile(strFile, 0, 0, NULL, OPEN_EXISTING, 0, 0);
	RaiseExceptionIf(hFile == INVALID_HANDLE_VALUE);

	DWORD dwSize = ::GetFileSize(hFile, NULL);
	CloseHandle(hFile);
	RaiseExceptionIf(dwSize == INVALID_FILE_SIZE && GetLastError() != NO_ERROR);

	return dwSize;
}


// Purpose: 'StrCmp' for numeric values. Usefull for IShellFolder::CompareIDs
inline int IntCmp(int n1, int n2) throw()
{
	if (n1 < n2)
		return -1;

	if (n1 > n2)
		return 1;

	return 0;
}


inline int UIntCmp(unsigned int n1, unsigned int n2) throw()
{
	if (n1 < n2)
		return -1;

	if (n1 > n2)
		return 1;

	return 0;
}


inline CString FormatLastError(DWORD dwLastError)
{
	LPTSTR lpMsgBuf;
	FormatMessage(FORMAT_MESSAGE_ALLOCATE_BUFFER |
	              FORMAT_MESSAGE_FROM_SYSTEM |
	              FORMAT_MESSAGE_IGNORE_INSERTS,
	              NULL,
	              dwLastError,
	              MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), // Default language
	              (LPTSTR) &lpMsgBuf,
	              0,
	              NULL);

	CString str(lpMsgBuf);
	LocalFree(lpMsgBuf);

	return str;
}


#ifdef ISOLATION_AWARE_ENABLED

// Purpose: Helper function to enable visual Windows XP styles.
inline void IsolationAwareDllMain(DWORD dwReason)
{
	switch (dwReason)
	{
	case DLL_PROCESS_ATTACH:
		// Note1: IsolationawareInit will leak a HINSTANCE LoadLibrary handle.
		// Note2: IsolationAwareInit will fail on a OS that doesn't support it (win98, nt4, etc)
		IsolationAwareInit();
		break;

	case DLL_PROCESS_DETACH:
		IsolationAwareCleanup();
		break;

	default:
		break;
	}
}

#endif // ISOLATION_AWARE_ENABLED


// Small helper class that initializes WIN32-STARTUPINFO use by Win32 CreateProcess function.
class CStartupInfo : public STARTUPINFO
{
public:
	CStartupInfo()
	{
		ATLASSERT(sizeof(CStartupInfo) == sizeof(STARTUPINFO) && "Helper should not add size!");

		ZeroMemory(static_cast<STARTUPINFO*>(this), sizeof(STARTUPINFO));
		cb = sizeof(STARTUPINFO);
	}
};


// Small helper class that initializes and cleans PROCESS_INFORMATION (used by CreateProcess)
class CProcessInformation : public PROCESS_INFORMATION
{
public:
	CProcessInformation()
	{
		hProcess = NULL;
		hThread  = NULL;
	}


	~CProcessInformation()
	{
		CloseHandle(hProcess);
		CloseHandle(hThread);
	}
};


// Purpose: 'short' version of Win32 function CreateProcess. 
//          Usefull for shell extensions that just need a quick way to start apps.
inline void CreateProcess(LPCTSTR szApplicationName, LPTSTR szCmdLine, LPCTSTR lpCurrentDirectory = NULL)
{
	CStartupInfo startupinfo;
	CProcessInformation process_information; 

	RaiseLastErrorExceptionIf(!::CreateProcess(szApplicationName, szCmdLine, 
		NULL, NULL, false, 0, NULL, lpCurrentDirectory, &startupinfo, &process_information));
}


// Purpose: The App Path registry entry is used by the shell to find apps 
// (.exe's) that are not in the PATH. The user can start these apps by 
// using the 'run' menu.
// Shell extensions can use these entries to detect installed software.
//
inline CString GetAppPath(const CString& strApp)
{
	CRegKey key;

	if (key.Open(HKEY_LOCAL_MACHINE,
		_T("Software\\Microsoft\\Windows\\CurrentVersion\\App Paths\\") + strApp,
		KEY_READ) != ERROR_SUCCESS)
		return CString();

	TCHAR tszBuf[MAX_PATH];
	ULONG nChars = MAX_PATH;
	if (key.QueryStringValue(NULL, tszBuf, &nChars) != ERROR_SUCCESS)
		return CString();

	return tszBuf;
}


// Purpose: allocates memory that can be used in OLE clipboard transactions.
//          The SDK docs are very uncleary about GMEM_FIXED / GMEM_MOVEABLE.
//          The shell itself uses GMEM_FIXED, which is easier to use as there
//          is no need to lock/unlock (GMEM_FIXED is ofcourse still just virtual memory).
inline HGLOBAL GlobalAllocThrow(SIZE_T dwBytes, UINT uFlags = GMEM_FIXED)
{
	HGLOBAL hg = GlobalAlloc(uFlags, dwBytes);
	RaiseExceptionIf(hg == NULL, E_OUTOFMEMORY);
	return hg;
}


inline CLIPFORMAT RegisterCf(LPCTSTR lpszFormat)
{
	unsigned int n = RegisterClipboardFormat(lpszFormat);
	RaiseExceptionIf(n == 0);

	return static_cast<CLIPFORMAT>(n);
}


inline CString GetClipboardFormatName(UINT format)
{
	switch (format)
	{
	case 0:               return _T("Undefined");
	case CF_TEXT:         return _T("Text");
	case CF_BITMAP:       return _T("Bitmap");
	case CF_METAFILEPICT: return _T("Metafilepct");
	case CF_SYLK:         return _T("Sylk");
	case CF_DIF:          return _T("Dif");
	case CF_TIFF:         return _T("Tiff");
	case CF_OEMTEXT:      return _T("Oemtext");
	case CF_DIB:          return _T("Dib");
	case CF_PALETTE:      return _T("Palette");
	case CF_PENDATA:      return _T("Pendata");
	case CF_RIFF:         return _T("Riff");
	case CF_WAVE:         return _T("Wave");
	case CF_UNICODETEXT:  return _T("Unicodetext");
	case CF_ENHMETAFILE:  return _T("Enhmetafile");
	case CF_HDROP:        return _T("Hdrop");
	case CF_LOCALE:       return _T("Locale");
	default:
		{
			TCHAR szName[255];

			ATLVERIFY(::GetClipboardFormatName(format, szName, MSF_ARRAY_SIZE(szName)));
			return szName;
		}
	}
}


inline IDataObjectPtr OleGetClipboard()
{
	IDataObjectPtr dataobject;

	RaiseExceptionIfFailed(::OleGetClipboard(&dataobject));

	return dataobject;
}


inline DWORD MSF_PACKVERSION(DWORD major, DWORD minor)
{
	return static_cast<DWORD>(MAKELONG(minor, major));
}


#pragma warning(push)
#pragma warning(disable: 4191) // unsafe conversion from FARPROC

inline DWORD GetDllVersion(LPCTSTR lpszDllName)
{
	DWORD dwVersion = 0;

	HINSTANCE hinstDll = LoadLibrary(lpszDllName);
	if (hinstDll)
	{
		DLLGETVERSIONPROC pDllGetVersion = 
			reinterpret_cast<DLLGETVERSIONPROC>(GetProcAddress(hinstDll, "DllGetVersion"));

		// Because some DLLs might not implement this function, you
		// must test for it explicitly. Depending on the particular 
		// DLL, the lack of a DllGetVersion function can be a useful
		// indicator of the version.

		if (pDllGetVersion != NULL)
		{
			DLLVERSIONINFO dvi;

			ZeroMemory(&dvi, sizeof(dvi));
			dvi.cbSize = sizeof(dvi);

			HRESULT hr = (*pDllGetVersion)(&dvi);
			if (SUCCEEDED(hr))
			{
				dwVersion = MSF_PACKVERSION(dvi.dwMajorVersion, dvi.dwMinorVersion);
			}
		}

		FreeLibrary(hinstDll);
	}

	return dwVersion;
}

#pragma warning(pop)


inline bool IsShell5OrHigher()
{
	return GetDllVersion(_T("shell32.dll")) >= MSF_PACKVERSION(5, 00);
}


// Source: Effective STL, by Scott Meyers. ISBN: 0-201-74968-9, Item 7, page 38
class CDeleteObject
{
public:
	template <typename T>
	void operator()(const T* p) const throw()
	{
		delete p;
	}
};


template <typename TContainer, typename TFunctor>
inline TFunctor for_each(TContainer container, TFunctor functor)
{
	return std::for_each(container.begin(), container.end(), functor);
}


inline int GetSystemImageListIndex(const TCHAR* pszPath)
{
	SHFILEINFO sfi;
	if (!SHGetFileInfo(pszPath, FILE_ATTRIBUTE_NORMAL, &sfi, sizeof(sfi),
	                   SHGFI_USEFILEATTRIBUTES | SHGFI_ICON))
		return 0;

	// Only need the index: clean-up the icon.
	ATLVERIFY(DestroyIcon(sfi.hIcon));

	return sfi.iIcon;
}

} // end namespace.

By viewing downloads associated with this article you agree to the Terms of Service and the article's licence.

If a file you wish to view isn't highlighted, and is a text file (not binary), please let us know and we'll add colourisation support for it.

License

This article has no explicit license attached to it but may contain usage terms in the article text or the download files themselves. If in doubt please contact the author via the discussion board below.

A list of licenses authors might use can be found here

Share

About the Author

Victor Derks
Software Developer (Senior) Schneider Electric
Netherlands Netherlands
Victor lives in Nijmegen, the oldest city in The Netherlands.
He studied Applied Physics in Delft and now works for GE Healthcare.

| Advertise | Privacy | Mobile
Web04 | 2.8.140905.1 | Last Updated 18 Sep 2005
Article Copyright 2005 by Victor Derks
Everything else Copyright © CodeProject, 1999-2014
Terms of Service
Layout: fixed | fluid