Back to Amir Israeli Homepage

[CNewFileMenu : A wrapper around the New-File Menu within Windows Explorer]

This article was contributed by Amir Israeli Amir Israeli.
Amir Israeli Web Site

Environment: Win 95/98 VC6 SP4

This article assumes you are femiliar with the Registry . It uses some wrapper classes I wrote disscussing the Registry .(Look for CRegistry + CRegistryShell classes' documentation) CRegistry wraps registry functions
CRegistryShell implements some specific actions related to the shell (searching for certain keys etc.

This picture is a representation of the new file menu : The funny letters on top are Hebrew script (New Folder, New Link) (Since it turned out well , I hopefully believe that it works on diffenet languages with special characters ... I havent checked yet whether it works !!! Please tell mail me ... (I'm interested especially in Latin + Slavic languages . Thanks.

This class is usefull for those of you who write Explorer like application or want your application to have a generic ability of Creating new documents the way Explorer does. Using it is simple . instantiate , call Create() , if it return TRUE you can get a menu handle by calling GetMenu() what you do with that menu is your concern :
The companion application instatiates a CNewFileMenu object within the Frame , Then it gets the main menu and appends the CNewFileMenu menu-handle ( got from GetMenu()) to the File sub menu. Since the menu handle is under your responsibily you need to delete it yourself (here appended to main menu so the frame , deletes it) Commands of the menu start with ...(you define the starting value) therefore you need command handlers for these :
a good practice is ON_COMMAND_RANGE macro : I assume that 50 id handlers are quite sufficient on any machine.

Creating the menu in OnCreate handler , you see that I used a wait cursor , Unfortunately Create() takes a long time : You should consider calling Create from a secondary Thread that is created in CWinApp::InitInstance() and storing returned result (of Create) in a boolean value accessible from OnCreate() of CFrameWnd , there when main menu is already created call GetMenu() and insert the handle to ... wherever you want.

CWaitCursor wait;
if (menu.Create()) {
	HMENU hMenu = menu.GetMenu(WM_USER+1);
	CMenu *pMenu = GetMenu(); //getting the main menu
	if (pMenu)
		pMenu = pMenu->GetSubMenu(0);
	if (pMenu)
		pMenu->AppendMenu( MF_POPUP, (UINT)hMenu, _T("New"));
}

Creating a handler for that range (of 50 id's) in .cpp file

ON_COMMAND_RANGE( WM_USER+1, WM_USER+50, OnNewFileMenu)
ON_UPDATE_COMMAND_UI_RANGE(WM_USER+1, WM_USER+50, OnUpdateNewFileMenu )

In .h file

afx_msg void OnNewFileMenu( UINT uID);
afx_msg void OnUpdateNewFileMenu(CCmdUI *pCmdUI);

Most importent is to call methods : database entries always begin with 1 Therefore any returned command (which begins with WM_USER+1 needs to drop that value.
Invoke has 2 parameters : the first is command id : (id you got - first id in menu) the second is your reference direcrtory. (or current directory or any ...)

BOOL Invoke( int iCommand, LPCTSTR lpszDirectory = NULL ) {
	return CreateItem( iCommand, lpszDirectory );
}
BOOL CreateItem( int iCommand, LPCTSTR lpszDirectory = NULL );

For information on command uncomment the first 3 lines of "OnNewFileMenu" function:

void CMainFrame::OnNewFileMenu( UINT uID)
{
//	CString s;
//	s.Format("got id=%d",uID-WM_USER-1);
//	CMessage::msg(s);
	menu.Invoke(uID-WM_USER-1,"c:\\");
}
void CMainFrame::OnUpdateNewFileMenu(CCmdUI *pCmdUI) //just to enable
{
}

How it works?

The function Create() builds a database : it first enumerates all file extensions (for example : *.bmp , *jpeg) into a CStringArray and then delete those that don't contain a key named "ShellNew" in their branch . Most keys are now being deleted , and few are left:
this is done in members of CRegistryShell object:

EnumRecursive( strKey, &arrTmp) : enumerates all sub keys of branch.
DeletePathWhichNotIncludes(...) : deletes Registry paths that dont include some key ...
Then for every path of key a function "EnumShellNewOfSingleKey( strKey, &arrTmp)" is called with 2 parameters : the first : path to file extension (example: "HKEY_CURRENR_ROOT\\*.doc") the second : all paths to shellnew keys , In this example of *.doc extension , which is generally related to Microsoft Winword , there may be several paths , (and several types of documents). Explorer menu should contain only the default file type .
Other file types contain only 1 path .
EnumShellNewOfSingleKey finds where data of file types is located : On every file type it searches the default value : where it finds the string that represents the partial path under HKCR where all information is to be found :
for path "HKEY_CURRENT_ROOT\\*.cpp" (related to default C++ environment) it finds a string named "cppfile" so it look for inforamtion under "HKEY_CURRENT_ROOT\\cppfile"
"DealSpecialFlags" checks paths of shellnew of any file type path , and removes all non-default paths (in case ther are more then 1 possiblities of file types). Then "EnumShellNewOfSingleKey" calls "FindDataOfKey" which looks for the caption that will be within the menu. and all the data. whenever it succeeds it inserts all the data accepted into a database :
Captions are located as the default value (of previous example) in "HKEY_CURRENT_ROOT\\cppfile" for Microsoft Winword 8 : "HKEY_CURRENT_ROOT\\*.doc = "Word.Document.8" so a check at "HKEY_CURRENT_ROOT\\Word.Document.8" reveals a caption "Microsoft Word Document"
Data : There are 4 options how you crate a file :
"NullFile" key : create an empty file with required extension.(Most file Types : *.bmp etc)
"Data" key : create an empty file and insert int it the bytes in the data , (*.html require you to insert 13 bytes : "")
"Template" key : create by coping the file template (File templates reside in hidden directory : often "c:\windows\shellnew" , you can get that directory from GetSpecialFolderLocation(...) or data of:
HKCU\\Software\\Microsoft\\Windows\\Current Version\\Explorer\\Shell Folders\\Templates = " Directory ..." (most office templates created that way)
"Command" key : you run a command in ShellExecute (example: link (*.lnk) files)
Data is entered to and array of "CNewFileInformation" structure , the function "AddCommand" creates a new structure and inserts into the array.
SetIconsOfNewFileMenu allows checking for icons of every item (if you'd like to make owner-drown menus with icons , in addition you'll have to get the global image list handle.

You see here the code of "AddCommand" it accepts 7 parameters :
1) iNewCommand = index in array
2) iCode = code of file craetion (if "Command" , "NullFile" ...)
3) lpszDescription = Caption to be presented in menu
4) lpszExtension = file extension (such as .bmp .cpp ...)
5) lpszData = additional data (in case of "Template" : template name , or shell command ("COMMND"))
6) pData = pointer to the data (only in case of "DATA")
7) cbData = length of data (" ...)

BOOL CNewFileMenu::AddCommand(int iNewCommand, int iCode , 
		LPCTSTR lpszDescription, LPCTSTR lpszExtension, LPCTSTR lpszData, 
		BYTE *pData , DWORD cbData)
{
	if ((iCode<=0) || (iCode>5)) //invalid code
		return FALSE;//checking to be sure

	CNewFileInformation *pInfo = new CNewFileInformation;
	if (!pInfo)  return FALSE;

	if (!pInfo->SetInfo( iNewCommand, lpszDescription, lpszExtension)) {
		delete pInfo;
		return FALSE;
	}

	//1=NULLFILE 2=FILENAME (template) 
	//3=COMMAND  4=DATA	 5=New Directory
	switch (iCode)
	{
	case 1:	pInfo->SetFileOfTypeNull();	break;
	case 2:	pInfo->SetFileOfTypeTemplate(lpszData);	break;
	case 3:	pInfo->SetFileOfTypeCommand(lpszData);	break;
	case 4:	pInfo->SetFileOfTypeData( pData, cbData);  break;
	case 5:	pInfo->SetFileOfTypeDirectory();	break;
	}

	m_NewFiles.Add(pInfo);
	return TRUE;
}

Notice
Documentation isn't complete for more , read source code and comments , There is some more ...
The code requires more multi-lingual testing , I mean need to be check if works well on veriety of languages , Please tell me if captions are OK and extraction of file templates (and template directory). This code was tested on Hebrew-English machines . (works ok)

Downloads

Download demo project - 108 Kb
Download source - 16.1 Kb

History

Date Posted: August 4, 2000

Home  |  Links  |  About