Introduction
Appender appends your own customized menu to the popup menu that you get when you right click on a folder, or start menu. It's useful when you require a specific tool at your hand any time. Since some people use command prompt consistently, it's very uncomfortable to switch between windows to command prompt, that will open in specific folder. Once you do require changes by Appender, it's easy to open command prompt in that particular folder. No need to go through a lengthy process as START->RUN->cmd->PATH (required to reach a particular folder).
Background
Original version of Appender from which I got an idea, is in assembly. It is a tool which comes with MASM32 8.0. I converted it to a C/SDK application. It doesn't require knowledge of registry API. Though, I think this article will be good for those who want to learn registry access through C/SDK. I have used my own makefile (not standard one that you get through export makefile option from VC++). MSDN presents "NMAKE Reference" on how to start with makefile. Note that learning makefile will tend you to learn Cl.EXE (C compiler) options plus LINK.EXE (Linker) options. But it will be an added advantage, that you will get extra understanding of how these tools craft our executables to load it in memory. (Matt Pietrek, "Under the hood", MSDN).
Using the code
Type the name of the menu that you want to append, in the edit box against Menu:-. You can use & in front of the menu name so that the menu name will be underlined. Example, &Cmd causes it to appear as Cmd. In the command edit box, type the path to the application, in our case on Win 2000, C:\Winnt\System32\cmd.exe, and on Win 98, C:\Windows\Command.com. Click Apply to apply changes to registry, or click Remove to already appended menu. Note that after clicking Apply/Remove, Explorer.exe is to be refreshed. I have extensively used the standard registry API to access the registry, and compiled it with STRICT enabled.
#ifndef _Appender_
#define _Appender_
#pragma once
BOOL CALLBACK dlgProc(HWND,UINT,WPARAM,LPARAM);
__inline void _MB(HWND hDlg,LONG nResult);
#define DIM(a) ( sizeof(a)/sizeof(a[0]) )
#define MAXBUF 100
#endif
DIM
macro works with Unicode as well.
BOOL CALLBACK dlgProc(HWND hDlg,UINT uMsg,WPARAM wParam,LPARAM lParam)
{
HINSTANCE hInst = NULL;
HICON hIcon = NULL;
HKEY hKey = NULL;
HWND hEditMenu = NULL;
LONG nResultMenu,nResultCommand,nResult = 0;
TCHAR szAppName[MAXBUF],szCopyright[MAXBUF];
TCHAR szMenu[MAXBUF],szCommand[MAXBUF];
TCHAR szRegKeyMenu[MAXBUF],szRegKeyCommand[MAXBUF];
hInst = (HINSTANCE) GetWindowLong(hDlg,GWL_HINSTANCE);
LoadString(hInst,IDS_MENU,szRegKeyMenu,DIM(szRegKeyMenu));
LoadString(hInst,IDS_COMMAND,szRegKeyCommand,DIM(szRegKeyCommand));
switch( uMsg )
{
case WM_INITDIALOG:
nResult = RegOpenKeyEx(HKEY_CLASSES_ROOT, szRegKeyMenu,
0,KEY_QUERY_VALUE,&hKey);
if( nResult == ERROR_SUCCESS )
{
int nMaxLen = 100;
RegQueryValueEx(hKey,NULL,NULL,NULL,szMenu,&nMaxLen);
RegCloseKey(hKey);
SetDlgItemText(hDlg,IDMENU,szMenu);
}
nResult = RegOpenKeyEx(HKEY_CLASSES_ROOT, szRegKeyCommand,
0,KEY_QUERY_VALUE,&hKey);
if( nResult == ERROR_SUCCESS )
{
int nMaxLen = 100;
RegQueryValueEx(hKey,NULL,NULL,NULL,szCommand,&nMaxLen);
RegCloseKey(hKey);
SetDlgItemText(hDlg,IDCOMMAND,szCommand);
}
hEditMenu = GetDlgItem(hDlg,IDMENU);
SetFocus(hEditMenu);
return FALSE;
case WM_COMMAND:
switch( wParam )
{
case IDAPPLY:
GetDlgItemText(hDlg,IDMENU,szMenu,DIM(szMenu));
GetDlgItemText(hDlg,IDCOMMAND,szCommand,DIM(szCommand));
RegCreateKeyEx(HKEY_CLASSES_ROOT,szRegKeyMenu,0,NULL,
REG_OPTION_NON_VOLATILE,KEY_SET_VALUE,NULL,&hKey,0);
nResultMenu = RegSetValue(HKEY_CLASSES_ROOT,
szRegKeyMenu,REG_SZ,szMenu,DIM(szMenu));
RegCloseKey(hKey);
RegCreateKeyEx(HKEY_CLASSES_ROOT,szRegKeyCommand,0,NULL,
REG_OPTION_NON_VOLATILE,KEY_SET_VALUE,NULL,&hKey,0);
nResultCommand = RegSetValue(HKEY_CLASSES_ROOT,
szRegKeyCommand,REG_SZ,szCommand,DIM(szCommand));
if( (nResultMenu && nResultCommand) == ERROR_SUCCESS )
MessageBox(hDlg,_T("New menu option appended"),
_T("Success!..."),MB_OK);
RegCloseKey(hKey);
return TRUE;
case IDQUIT:
EndDialog(hDlg,0);
return TRUE;
case IDREMOVE:
nResult = RegOpenKeyEx(HKEY_CLASSES_ROOT,szRegKeyCommand,
0,KEY_ALL_ACCESS,&hKey);
if( nResult == ERROR_SUCCESS )
{
nResultCommand = RegDeleteKey(HKEY_CLASSES_ROOT,szRegKeyCommand);
}
nResult = RegOpenKeyEx(HKEY_CLASSES_ROOT,szRegKeyMenu,
0,KEY_ALL_ACCESS,&hKey);
if( nResult == ERROR_SUCCESS )
{
nResultMenu = RegDeleteKey(HKEY_CLASSES_ROOT,szRegKeyMenu);
}
if( (nResultMenu && nResultCommand) == ERROR_SUCCESS )
MessageBox(hDlg,_T("New menu option removed"),
_T("Success!..."),MB_OK);
RegCloseKey(hKey);
SetDlgItemText(hDlg,IDMENU,NULL);
SetDlgItemText(hDlg,IDCOMMAND,NULL);
return TRUE;
case ID_EXIT:
EndDialog(hDlg,0);
return TRUE;
case ID_ABOUT:
hIcon = LoadIcon(hInst,MAKEINTRESOURCE(IDI_ICON));
LoadString(hInst,IDS_WNDNAME,szAppName,DIM(szAppName));
LoadString(hInst,IDS_COPYRIGHT,szCopyright,DIM(szCopyright));
ShellAbout(hDlg,szAppName,szCopyright,hIcon);
return TRUE;
}
}
return FALSE;
}
Points of Interest
Code is much more straightforward and you will get information about every function on MSDN. Good thing is writing quality code with "0 errors 0 warnings". Writing STRICT compliant code is an art. Right now, this code doesn't support error handling.