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

Classic Shell

, 23 Feb 2010
Classic Start menu and other shell features for Windows 7 and Vista.
ClassicShellSetup.zip
ClassicShellSetup.exe
ClassicShellSrc.zip
ClassicShell
ClassicExplorer
ClassicCopyExt.rgs
ClassicExplorer.rgs
ClassicExplorer32.def
ClassicExplorer64.def
Explorer.ini
ExplorerBand.rgs
ExplorerBHO.rgs
ExplorerL10N.ini
up.ico
up2Disabled.ico
up2Hot.ico
up2Normal.ico
up2Pressed.ico
upDisabled.ico
ClassicShellSetup
ClassicShell.ico
ClassicShellBanner.jpg
ClassicShellSetup.manifest
ClassicShellSetup32
ClassicShellSetup32.vdproj
ClassicShellSetup64
ClassicShellSetup64.vdproj
ClassicStartMenu
ClassicStartMenu.manifest
ClassicStartMenuDLL
StartMenu.ini
StartMenuItems.ini
StartMenuL10N.ini
Docs
ClassicExplorer_files
after.png
before.png
ClassicShell.png
FolderView.gif
iconoffset.png
statusbar.png
titlebar.png
toolbar.png
ClassicShellEULA.rtf
ClassicShellReadme.rtf
ClassicStartMenu_files
ClassicShell.png
screenshot.png
skins.gif
ParseSettings
Skins
ClassicSkin
main_bitmap.bmp
selection.bmp
VistaAero
main_bitmap.bmp
selection.bmp
Win7Aero
main_bitmap.bmp
selection.bmp
Win7Basic
main_bitmap.bmp
selection.bmp
// Classic Shell (c) 2009-2010, Ivo Beltchev
// The sources for Classic Shell are distributed under the MIT open source license

#include <windows.h>
#include <atlbase.h>
#include <atlcom.h>
#include <atlctl.h>
#include <atlstr.h>
#include <commctrl.h>
#include <shlobj.h>

#include "ClassicStartMenuDLL\ClassicStartMenuDLL.h"

#define HOOK_EXPLORER // when this is not defined the start menu runs directly in this process (for debugging)

#if defined(BUILD_SETUP) && !defined(HOOK_EXPLORER)
#define HOOK_EXPLORER // make sure it is defined in Setup
#endif

static HHOOK g_StartHook;
static HWND g_StartButton;

static void UnhookStartMenu( void )
{
	if (g_StartHook)
		UnhookWindowsHookEx(g_StartHook);
	g_StartHook=NULL;
}

static HWND HookStartMenu( void )
{
	HMODULE hHookModule=GetModuleHandle(L"ClassicStartMenuDLL.dll");

	// find the Progman window and the start button
	HWND progWin=FindWindowEx(NULL,NULL,L"Progman",NULL);
	if (!progWin) return NULL; // the Progman window may not be created yet (if Explorer is currently restarting)

	DWORD process;
	DWORD thread=GetWindowThreadProcessId(progWin,&process);

	g_StartButton=FindStartButton(process);
	if (!g_StartButton) return NULL; // the start button may not be created yet (if Explorer is currently restarting)

#ifdef HOOK_EXPLORER
	// install hooks in the explorer process
	thread=GetWindowThreadProcessId(g_StartButton,NULL);
	g_StartHook=SetWindowsHookEx(WH_GETMESSAGE,HookInject,hHookModule,thread);
	PostMessage(g_StartButton,WM_NULL,0,0); // make sure there is one message in the queue

	return NULL;
#else
	return ToggleStartMenu(g_StartButton,false);
#endif
}

static UINT g_TaskbarCreatedMsg; // the "TaskbarCreated" message

// CStartHookWindow is a hidden window that waits for the "TaskbarCreated" message and rehooks the explorer process
// Also when the start menu wants to shut down it sends WM_CLOSE to this window, which unhooks explorer and exits

const int WM_OPEN=WM_USER+10;

const int TIMER_HOOK=1;

class CStartHookWindow: public CWindowImpl<CStartHookWindow>
{
public:

	DECLARE_WND_CLASS(L"ClassicStartMenu.CStartHookWindow")

	BEGIN_MSG_MAP( CStartHookWindow )
		MESSAGE_HANDLER( WM_OPEN, OnOpen )
		MESSAGE_HANDLER( WM_CLOSE, OnClose )
		MESSAGE_HANDLER( WM_CLEAR, OnClear )
		MESSAGE_HANDLER( WM_TIMER, OnTimer )
		MESSAGE_HANDLER( g_TaskbarCreatedMsg, OnTaskbarCreated )
	END_MSG_MAP()

protected:
	// Handler prototypes:
	//  LRESULT MessageHandler(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL& bHandled);
	//  LRESULT CommandHandler(WORD wNotifyCode, WORD wID, HWND hWndCtl, BOOL& bHandled);
	//  LRESULT NotifyHandler(int idCtrl, LPNMHDR pnmh, BOOL& bHandled);
	LRESULT OnOpen( UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL& bHandled );
	LRESULT OnClose( UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL& bHandled );
	LRESULT OnClear( UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL& bHandled );
	LRESULT OnTimer( UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL& bHandled );
	LRESULT OnTaskbarCreated( UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL& bHandled );
};

LRESULT CStartHookWindow::OnOpen( UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL& bHandled )
{
	if (g_StartButton) ::PostMessage(g_StartButton,RegisterWindowMessage(L"ClassicStartMenu.StartMenuMsg"),wParam,lParam);
	return 0;
}

LRESULT CStartHookWindow::OnClose( UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL& bHandled )
{
	UnhookStartMenu();
	PostQuitMessage(0);
	return 0;
}

LRESULT CStartHookWindow::OnClear( UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL& bHandled )
{
	UnhookStartMenu();
	return 0;
}

LRESULT CStartHookWindow::OnTaskbarCreated( UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL& bHandled )
{
	SetTimer(TIMER_HOOK,100);
	return 0;
}

LRESULT CStartHookWindow::OnTimer( UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL& bHandled )
{
	if (wParam==TIMER_HOOK)
	{
		UnhookStartMenu();
		HookStartMenu();
		if (g_StartHook)
			KillTimer(TIMER_HOOK);
	}
	return 0;
}

int WINAPI wWinMain( HINSTANCE hInstance, HINSTANCE hPrevInstance, LPTSTR lpstrCmdLine, int nCmdShow )
{
	int open=-1;
	if (wcsstr(lpstrCmdLine,L"-togglenew")!=NULL) open=-2;
	else if (wcsstr(lpstrCmdLine,L"-toggle")!=NULL) open=0;
	else if (wcsstr(lpstrCmdLine,L"-open")!=NULL) open=1;
	// prevent multiple instances from hooking the same explorer process
	HWND progWin=FindWindowEx(NULL,NULL,L"Progman",NULL);
	DWORD process;
	DWORD thread=GetWindowThreadProcessId(progWin,&process);
#ifdef HOOK_EXPLORER
	wchar_t mutexName[256];
	swprintf_s(mutexName,L"ClassicStartMenu.Mutex.%08x",process);
	HANDLE hMutex=CreateMutex(NULL,FALSE,mutexName);
	if (GetLastError()==ERROR_ALREADY_EXISTS || GetLastError()==ERROR_ACCESS_DENIED)
	{
		if (open>=0)
		{
			AllowSetForegroundWindow(process);
			HWND hwnd=FindWindow(L"ClassicStartMenu.CStartHookWindow",L"StartHookWindow");
			if (hwnd) PostMessage(hwnd,WM_OPEN,open,0);
		}
		if (open==-2 && progWin)
		{
			AllowSetForegroundWindow(process);
			PostMessage(progWin,WM_SYSCOMMAND,SC_TASKLIST,'CLSM');
		}
		return 0;
	}
#endif
	OleInitialize(NULL);
	g_TaskbarCreatedMsg=RegisterWindowMessage(L"TaskbarCreated");
	ChangeWindowMessageFilter(g_TaskbarCreatedMsg,MSGFLT_ADD);
	CStartHookWindow window;
	window.Create(NULL,NULL,L"StartHookWindow",WS_POPUP);

	MSG msg;
	HWND menu=HookStartMenu();
#ifdef HOOK_EXPLORER
	if (open>=0) window.PostMessage(WM_OPEN,open,0);
	while (GetMessage(&msg,0,0,0))
#else
	while (IsWindow(menu) && GetMessage(&msg,0,0,0))
#endif
	{
		TranslateMessage(&msg);
		DispatchMessage(&msg);
	}
	window.DestroyWindow();
	OleUninitialize();
	return 0;
}

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, along with any associated source code and files, is licensed under The MIT License

Share

About the Author

Ivo Beltchev
Software Developer (Senior)
United States United States
Ivo started programming in 1985 on an Apple ][ clone. He graduated from Sofia University, Bulgaria with a MSCS degree. Ivo has been working as a professional programmer for over 12 years, and as a professional game programmer for over 10. He is currently employed in Pandemic Studios, a video game company in Los Angeles, California.

| Advertise | Privacy | Mobile
Web02 | 2.8.140916.1 | Last Updated 23 Feb 2010
Article Copyright 2009 by Ivo Beltchev
Everything else Copyright © CodeProject, 1999-2014
Terms of Service
Layout: fixed | fluid