Click Here to Install Silverlight*
United StatesChange|All Microsoft Sites
|Developer Centers|Library|Downloads|Code Center|Subscriptions|MSDN Worldwide
Search for

Advanced Search

April 1996

Microsoft Systems Journal Homepage

Fusing Your Applications to the System Through the Windows95 Shell

Jeff Richter

Jeffrey Richter is the author of Advanced Windows (Microsoft Press, 1995) and Windows 95: A Developer's Guide (M&T Books, 1995). Jeff is a consultant and teaches Win32-based programming seminars. He can be reached at

Microsoft has spent an enormous amount of time and effort fine-tuning the new shell that appears with Windows┬« 95 and the upcoming Windows NT™ Shell Update Release to make it easier for users to start and use software, including your applications. In this two-part series I'll show you how to integrate your applications with the key features of the new Windows shell that will make life easier for you and the user.

Users, Files, and Directories

When installing an application, the setup program usually prompts the user for an installation path. Setup then creates this subdirectory path and begins copying files into the new directory. Directory hierarchies have been one of the most confusing issues for users, who frequently have trouble navigating a hard disk and forget where they installed various files. The short 8.3 file and directory names don't help matters. Now that file and directory names can use up to 255 characters, users should have a much easier time. However, since many networks do not support long filenames yet, the names of all your distributed (application) files should continue to use the old 8.3 naming convention. Use long files names only for a user's documents. If you use long filenames for application files, some users may not be able to access the files. As long file names for the PC become more pervasive, you can start using long filenames for distributed files as well.

To make finding installed applications easier, Microsoft proposed a standard directory hierarchy. Windows 95 creates a \Program Files directory. This directory is the default location where all applications should be installed. In other words, your setup application should choose a default installation path of \Program Files\YourAppName. You should allow the user to change this default path, but most users will want to leave it alone. If all applications install themselves under \Program Files, users will have a pretty easy time locating applications. You can get the name of this directory by examining the HKEY_LOCAL_MACHINE\Software\Microsoft\Windows\CurrentVersion key, which contains the value ProgramFilesDir="C:\Program Files".

Users also get confused about which files are executable. For example, many applications copy all EXEs, DLLs, and data files into a single directory. When users look for an executable program, they end up faced with a bunch of files; they may try executing your DLLs or data files with less-than-desirable results. To resolve this problem, Microsoft proposes that your setup program create a \Program Files\YourAppName\System directory. This subdirectory should contain all of your application's non-executable files (like DLLs). In addition, the System subdirectory and its files should be hidden so that users are less likely to look into it and be confused. I can already hear some of you wondering how your application is going to find the DLLs it needs in a subdirectory. Well, Microsoft solved the problem by adding application-specific paths to the shell (which I'll explain later).

Many applications install files that are used by other applications. It would be a terrible waste of disk space if every company installed a separate copy of MSVCRT20.DLL in their System directory. Microsoft proposes that you create a hidden \Program Files\Common Files directory for these shared files. You can get the name of this directory by examining the HKEY_LOCAL_MACHINE\Software\Microsoft\Windows\CurrentVersion key, which contains the value CommonFilesDir="C:\Program Files\Common Files". (You should always get the directory name by examining the registry since these names are localized on foreign language versions of Windows, see Figure 1.)

Figure 1 Examining the registry

In addition, your company may produce some files that are shared by your own applications. Obviously, if the user purchases several of your company's products, you should not install multiple copies of the same DLL. Microsoft proposes that you create a \Program Files\Common Files\YourCompanyName directory and store files common to your applications there.

So far, I've focused on files that ship with an application. However, many applications also allow users to create data or document files. Microsoft proposes that your applications put these user-created files in a different directory from your application's executable files. Windows 95 creates a \My Documents directory for user documents. This directory should be your process's working directory when it is invoked.

Remember that Microsoft is moving Windows toward a more document-centric way of doing things (versus the old application-centric way). When users want to work on a document, they don't care which application is required to modify it. For example, to modify a 1994 fiscal report, the user should be able find the report, open it, and have the appropriate application start. In addition, many users work on large, diverse projects. The 1994 fiscal report may include a word-processing document, a spreadsheet document, and a slide presentation document. The user should be able to create a \My Documents\1994 fiscal year report directory and put all of the files related to this project in there.

This (feature) is my personal favorite. First, it makes it very easy to locate documents and projects. Second, all of the user's files are in one location; only the files in the \MyDocuments directory need to be backed up. None of the files under the \Program Files directory need to be backed up since they can all be reinstalled from the original product disks.

I mentioned previously that the Windows shell supports application-specific paths. If you use Microsoft's proposed directory hierarchy, this feature is necessary so an application can find the DLLs it needs. Here's how to use this feature: when the user installs an application, the setup program should create the registry key

App Paths\AppName.EXE

where AppName.EXE is the name of your executable file (without a path). Under this registry key, you should create two values:

 (Default) = FullPathName
Path = Path

(Default) should be set to the full pathname (path and filename) of your application's executable file. The Path value has the same format as the PATH environment variable. Usually, the Path value contains a single subdirectory.

 Path = C:\Program Files\YourAppName\System

Depending on the files you use, you may also need to add the directories for common files and for your company's shared files.

When the user runs an application via the Windows shell, the shell tries to execute the specified file. If the file can't be found and the user did not specify a complete path, the shell looks in the registry for a key that matches the executable's file name. If a match is found, the shell attempts to execute the pathname identified by (Default). Because of this scheme, it's not necessary to explicitly create a PATH environment variable. When the user moves or renames an executable file with the shell, the shell scans the App Paths registry tree and automatically updates the (Default) value so it reflects the new path of the executable file.

Like all Win32® applications, the shell executes an application by calling the CreateProcess function.

 BOOL CreateProcess(LPCTSTR lpApplicationName, 
         LPTSTR lpCommandLine, 
         LPSECURITY_ATTRIBUTES lpProcessAttributes,
LPSECURITY_ATTRIBUTES lpThreadAttributes, BOOL bInheritHandles, DWORD dwCreationFlags, LPVOID lpEnvironment, LPCTSTR lpCurrentDirectory,

The lpEnvironment parameter is a pointer to a block of memory that contains a set of environment strings. Usually, you pass NULL for this parameter and the new process inherits a copy of the parent process's environment block, which includes the PATH environment variable. When the Windows shell calls CreateProcess, it creates its own environment block for the child process by allocating a block of memory and filling this block with a copy of the shell's environment block. The shell changes the PATH environment variable by inserting the string indicated by the Path registry value before the current PATH value, then the shell spawns the new process. Whenever threads in this process attempt to open a DLL, the system knows to look in the application's System directory.

You should always store absolute paths in the Path registry value because the user may change the working directory when opening or saving a file. A relative path always refers to a subdirectory of the working directory, so when the working directory changes, the DLLs won't be found. Also, since the shell sets the process's PATH environment variable, the application-specific path information is not used if the user runs the application from the command line. However, if the user executes the application from the command line using the START command

 C:\>START AppName

the application-specific path information is used.

Tracking Shared Files

In addition to a setup program, Microsoft highly recommends that you also ship an uninstall program with your application. This uninstall program allows the user to easily remove all the files installed for your application. (The user has to manually remove their own document files.) However imagine a scenario where a user installs two applications from different companies. Both applications require MSVCRT20.DLL. If the user uninstalls one of these applications, should MSVCRT20.DLL be removed? Of course not, since this keeps the other application from running. On the other hand, when the user uninstalls the other application it would be nice if MSVCRT20.DLL were deleted (as it is no longer needed).

Microsoft recommends that your setup program create a registry key whenever it installs a shared DLL. The key looks like this:


Under this key are many values like

 PathName = Count

where PathName is the full path (directory and file name) of the shared file. Count indicates the number of applications that require this shared file. If a value does not exist for a shared file, you should create one and give it an initial count of 1. If there's already a value, you should simply increment the count by 1. Your setup program should not increment the count if the user installs a new version of your application over an existing one. Doing so would make the count unnecessarily high. However, if the new version of your software doesn't require the shared file anymore, you can decrement the count.

When your uninstall program attempts to delete a shared file, it should first examine the value in the registry and decrement it by 1. If the count reaches zero, the uninstall program should prompt the user with a dialog box that says something like this:

 The file "SharedFile.DLL" may no longer be in use. You can choose to delete this file but doing so may prevent other applications from running correctly.

The user can decide whether to delete the file or not.

Maintaining Settings Between Invocations

In the past, applications often used private INI files to save application settings. This is no longer a good approach for several reasons: lots of INI files are hard to manage; INI files eat up a lot of disk space; INI files have a shallow hierarchy; INI files can only store text information; INI files cannot easily separate different users' settings; INI files aren't easy for users or remote administrators to modify. Also, you should not store information in

CONFIG.SYS, AUTOEXEC.BAT, WIN.INI, or SYSTEM.INI or your app will not work in Windows NT. Windows 95 does allow you to do this for backward-compatibility reasons, but new applications should not require that these files be touched in any way in order for the application to function properly.

A much better way to store an application's persistent settings is by using the registry. Each application can create its own keys in the registry for its settings. If your application has settings that apply to the machine (as opposed to a user), your application should create the registry key


where CompanyName, AppName, and Version identify your company's application. (Version is optional; if you don't expect users to keep multiple versions of your application installed simultaneously, you don't need it.)

Most applications keep settings for a specific user. These settings should be placed in the following registry key:


Again, you may want to leave off the Version subkey. The format of the information contained under your application's key is totally up to you. You can create additional subkeys and you can store binary data.

Invoking Applications Automatically

You may have noticed that some of the applications shipping with Windows 95 run themselves automatically after the system starts up. To see what I mean, open a few Explorer windows on your desktop and then log off or shutdown. The next time you log on, you'll notice that the same windows automatically pop back up so that the system is exactly the way you left it.

This is a pretty nice feature and is very easy to take advantage of yourself. When a user logs on, the system examines the following registry key:


Each of the values in this key has the following format:

 UniqueId = CommandLine

UniqueID is a placeholder that the shell doesn't actually use, but is required because there cannot be two values with the same ID. The system simply enumerates the values under the RunOnce key and executes each of the command lines.

If you want your application to start automatically when the user logs on, all you have to do is add an entry to this key when the user logs off or shuts down. Your application's main window can detect when the user is logging off or shutting down by intercepting WM_ENDSESSION. When your window receives this message, it can add a value to the RunOnce key as follows:

 MyApp1 = "C:\ProgramFiles\MyApp\MyApp.Exe" DocumentName

After the system executes all of the command lines under the RunOnce key, all of the values are deleted.

It is also possible to add values to a RunOnce key, this time under HKEY_LOCAL_MACHINE, so the command lines are executed when any user logs on.


When you do this, Windows prompts the user to log on, and then executes whatever command line values are contained under this key. Entries in the HKEY_LOCAL_MACHINE RunOnce key are executed immediately after any user logs on while entries under the HKEY_CURRENT_USER key are not executed until the user for whom the entries were saved logs on again.

In addition to the RunOnce keys, the system also supports Run keys:


These keys behave the same as their respective RunOnce keys except the system doesn't delete the command line values after executing them.

Windows 95 supports two more keys, RunServicesOnce and RunServices, that also have similar behavior.


These keys can only appear under the HKEY_LOCAL_MACHINE key. When the system boots, it executes whatever command lines appear under these keys, before any user logs on to the system. This would be a good place to execute a virus detection program, for example. Because these service applications are executed before the user logs onto the system, they should not assume any particular networking permissions. These two service keys are not required by Windows NT because it has full support for services.

Defining your own Data Types

By default, the Windows shell doesn't display file extensions. This is done for two reasons. First, the extension identifies an application and the user should not need to know about applications. Second, the user shouldn't be able to change the extension, thereby changing the document type. Changing the document type is dangerous because, when the user tries to open the document, it may be "unreadable"-a very scary thing indeed. With hidden extensions, the user cannot accidentally change the file's extension.

To make Windows a more document-centric operating system, the shell offers a number of features that allow it to be "aware" of your application's document types. The system identifies file types by their extension. Unfortunately, extensions have always been at most three letters long and a number of companies choose the same extension for different data types. For example, the MFC Scribble application and the Windows Screen Saver both use the SCR extension. However, both Windows NT and Windows 95 support extensions that can be much longer than three characters. You can take advantage of this feature to create extensions that have a better chance of being unique.

Users should not have to work with file extensions at all and for the most part, users should not have to know what applications work with a particular file. However, sometimes, a user will need this information. For those cases, the user can select the details view in the Explorer to see the file types for all files in a directory (see Figure 2). In order to display the information shown in the Type column the Explorer must search for this key in the registry


where ext identifies each document type's extension. (The period before the extension is required but the extension itself may be any length.)

Figure 2 Details View

Once you have created your document's extension key, you must set its (Default) value to a string that uniquely identifies the document type.

 (Default) = AppId

The AppId string is never shown to the user. It is only used internally by the system and the system doesn't care what this string is. It only uses this string in order to look for another registry key that you must also create.


All of the interesting information about the new document type is stored under this AppId key. You will definitely want to set the (Default) value as follows:

 (Default) = CompanyName AppName Version DataType

This is the string that is shown to the user in the Explorer. It should be no longer than 40 characters. You are not required to supply all the fields. For example, DLLs have only the DataType field, specified as "Application Extension".

It is possible, and sometimes useful, to create multiple extension keys whose (Default) values reference a single AppId. For example, C, CPP, and H files might all reference a single AppId that identifies Visual C++.

The Explorer shows an icon for every file it finds. For executable files and icon files, this is easy since these files contain icon resources. However, document files usually do not. It is easy to tell the shell what icon should be displayed for a document type by creating the following registry value:

DefaultIcon = Pathname [,Index]

Path identifies the full pathname of a file that contains icon resources. This is usually the executable file that creates or edits the document. The optional zero-based Index value indicates which icon to take from this executable. Since the application's icon is usually at Index zero, the document icon will have an Index of 1 or more. A negative Index indicates an actual icon resource ID instead of an Index. The icon you use should include 16x16 pixel (16 color), 32x32 pixel (16 color), and 48x48 pixel (256 color) renderings.

If you do not add the DefaultIcon value for your application files, the system creates an icon. This icon looks like a dog-eared page with a miniature of the application icon placed inside the page (see Figure 3).

Figure 3 Startup Icon

Constructing Documents With the Shell

To support a more document-centric view of the system, the shell allows the user to create new documents by specifying the document type rather than the application. The user does this by selecting the Explorer's File.New menu option.

To add your own data type to this menu, all you have to do is create the following registry key:


You must also have the application's description set so that the shell knows what text to display in the menu. The table in Figure 4 describes the values that can appear under the ShellNew key.

The first three entries in the table describe the contents of the new data file. You would use NullFile if your application can successfully edit an empty file. If NullFile is specified, the shell creates an empty file. The name of this file will be something like "New AppDesc.ext". For example, creating a new Text Document file results in an empty file called "New Text Document.txt". After the file is created, the user can edit it simply by double-clicking.

Use FileName if your application cannot successfully edit an empty file. Many applications have a complex data structure for their document files and have been designed so that the application itself always creates its document files. In this case, before you ship your product, you might invoke your application and immediately execute the application's File Save command. This produces the minimum document file needed to invoke your application successfully. Then, ship this minimum document file with your application. During the setup process, set FileName to this file's full pathname. You should store the file in the C:\Windows\ShellNew directory. When the user creates a new document for your application, the shell just copies your minimum document file to the proper location and gives it a new name.

Instead of shipping the minimum document file, you can instead set the Data value so it contains the binary data for a minimum document file. When the user creates a new document for your application, the shell creates a new file and copies the contents of the Data value into this file.

Command does not create a file at all. Instead, if the shell sees the Command value, it executes the specified command line. Use this value if you want to run a Wizard-like application. For example, creating a new shortcut uses the Command value to present a shortcut Wizard that prompts the user for a command line and title.

When creating a new document file, the shell uses the following algorithm (shown in pseudo-code) to determine what it should do:

 if (fNullFileValueExists) {
if (fCommandValueExists) {
// Execute the command
} else {
// Create a new, empty file
} else {
if (fFileNameValueExists) {
// Create a new file by copying the FileName file
} else {
if (fDataValueExists) {
// Create new file initializing it with the Data // value's binary data
} else {
// Do nothing.
// Note: The user is not given an error message

The most important thing to note is that Command is used by the shell only if NullFile is also specified.

Adding Document-Specific Commands to the Shell

The Explorer's File menu and context menu (when you right click an item in the Explorer) display options that operate on the selected object. You can add options to these menus that appear only when one of your application's documents is selected. For example, you could easily add an Unzip menu option that appears only when a ZIP file is selected.

To add your own menu options, you must first create the following registry key:


Under this key, create an additional key for each menu option that you want to appear in the menu.


For example, REG files support three different options and therefore have three subkeys under the Shell key.


If you do not assign a (Default) value for one of these keys, the key name appears when the menu is displayed. However, if you assign a (Default) value to these keys, the text of the (Default) value is displayed instead. You have more flexibility when using the (Default) value because you can add an ampersand in front of the mnemonic character. The (Default) values for the REG file's options are shown in Figure 5.

After you tell the shell what menu options to display, you must also tell it the command line to execute when the user selects one of these options. To do this, create the following key:


The (Default) value of this key must specify the desired command line. For REG files, the three keys and their (Default) values are shown below:

                              C:\WINDOWS\NOTEPAD.EXE %1

You may also want to tell the shell the order in which these options should appear in the menu. You do this by setting a (Default) value for this key:


The (Default) value's string must look like this:

 OptionKey1, OptionKey2, ...

where OptionKeyn identifies the name of the option subkeys. The order in which the subkeys appear is the same order in which the options appear in the menu. The first entry also becomes the default option. In other words, if the user double-clicks on the document file, the command associated with OptionKey1 is executed.

The system has built-in support for the following menu options: Open, Print, Find, and Explore. This means that the system knows to localize the text that appears in the menu for any of these options. However, if you specify a (Default) string for any of these options, you override the string that the system would normally display.

Enabling Printing

If the following subkey exists for a document type, the shell will print the document to the default printer.


However, the shell also allows a user to drag and drop a document onto a printer icon. If the user drops a file on a printer that is not the default printer, the shell displays a message box (see Figure 6). If you want to allow the user to print to any printer, you must create the following key:


Figure 6 Shell displays a message box

This option doesn't appear on any menu but tells the shell what command to execute when the user drops your document on any printer. Of course, you must also create a


key and set its (Default) value to the command line string that you want executed.

Getting Serious About Shell Integration

All of the methods discussed previously for extending the shell are pretty simple. Once the registry is set up, the shell takes care of everything else. Sometimes, you may want to be more sophisticated about how you extend the shell. For example, viewing the properties of an AVI file includes a property page that allows the user to actually play the file. Likewise, an application like Microsoft Word might want to print a document one way but print a document template another way. To handle this, your application might need to examine the data in the file to see what type of file it is.

You can get much fancier with many of these shell extensions by writing code and getting the shell to execute your code. To write a sophisticated shell extension, you write an in-process DLL that exports some Component Object Model (COM) interfaces. These interfaces are defined by Microsoft in the SHLOBJ.H header file. Figure 7 provides a list of shell extensions that you can perform.

To tell the shell that you wish to use an in-process server DLL, you must create the following registry key:


Then, depending on which types of shell extensions you want to support, you must create additional subkeys. Figure 8 shows each shell extension and the additional key that you must create.

Normally, you create a single DLL that exports a single COM object that handles any combination of the seven types of shell extensions. However, having multiple keys makes things very flexible. For a single document type, you can have a COM object in one DLL that handles context menus and another COM object in a different DLL that handles property sheets. The shell also allows several context menu handlers to be installed for a given document type at once. If several context menu handlers are installed, the system loads all of them and gives all of them a chance to add menu options. The order of the context menu handlers in the registry determines the order of the options in the menu. The shell always places the handler-supplied menu options after any options appearing under the HKEY_CLASS_ROOT\.ext\Shell key.

In fact, all of the shell extension handlers except for the icon handler, drop handler, and data handler can have multiple DLLs associated with them. An icon handler can only have one DLL associated with it. Each DLL that is associated with a specific handler must have its own subkey. For example, if there are two context menu handlers associated with a document type, the registry must look like this:


ShExDll1 and ShExDll2 are two subkeys of the ContextMenuHandler key. The actual names of the ShExDlln subkeys are not important, since the shell doesn't use the names at all. The (Default) value of each of these subkeys must be the string value that identifies the CLSID of the COM object containing the code for the specified handler. The handler's CLSID must also be registered as a subkey under the HKEY_CLASSES_ROOT\CLSID key.

The shell also permits you to create handlers for folders, drives, and printers. To do this, just create the ShellEx subkey under the keys


and add the handlers. This special key allows you to add a handler to any and all objects:


Whenever the shell checks to see if handlers exist for any file type, it always checks the asterisk (*) key's ShellEx subkey and calls any handlers specified there. This key is usually added to let system-level utilities or tools get involved in file manipulations.

Shell Links

Shell links (also known as shortcuts) are a powerful and flexible feature of Windows. They allow you to create an object that refers to another object in the system. This means that an application can reside anywhere on your system, but you can create multiple links to it so that you can start the application from several different locations. This is an efficient approach because shell link files are only about 300 to 500 bytes each. Shell links can directly take you to drives, folders, applications, data files, network resources, and even attach you to resources accessible through your modem (like Remote Networking and the Microsoft Network).

Shell link files can reside anywhere on your system. You can put these files in a folder and you can also put them on your desktop. (Your desktop is really just showing you icons for all the files that you have in the \Windows\Desktop or \Windows\Profiles\UserName\Desktop directories, depending on whether you have turned the individual user profiles option on or not.)

If you want another icon on your desktop, just create a file in one of these two directories and the shell automatically updates your desktop. You can create shell link files by using the IShellLink COM interface defined in SHLOBJ.H. Figure 9 describes the components that make up a shell link.

I have created a function called Shell_CreateLink that creates a shell link file whose attributes are set based on this data structure (see Figure 10). After you initialize the data structure, you can create the shell link by passing the desired pathname of the shell link file (this should end with a LNK extension) and the address of the data structure to the Shell_CreateLink function (see Figure 11).

This is a very simple function. It first initializes the component object model libraries by calling CoInitialize. It is OK to do this even if the library was previously initialized by this thread. Then, it creates a new shell link object and gets its IShellLink interface pointer by calling

CoCreateInstance. This new shell link object is currently maintained in memory-it is not on the disk yet. The new shell link's attributes are set by calling ShellLink's various member functions. After all the attributes are set, the shell link is saved by getting its IPersistFile interface pointer and calling this interface's Save function. The Save function is passed the desired pathname of the shell link. (Note that the Save function accepts only Unicode pathnames.) Finally, the shell link object's two interface pointers are released so that the shell link is freed from memory and the COM libraries are uninitialized by the call to CoUninitialize.

Adding your Application to the Programs Menu

Most users will invoke applications using the Start button's Programs menu. When your application is installed, you should create entries in this menu. If you are familiar with the old way of communicating with the Program Manager using dynamic-data exchange (DDE), you'll really appreciate how easy it is to add menu options to the Programs menu.

When the user traverses the Programs menu, the shell just looks in the \Windows\Start Menu\Programs or the \Windows\Profiles\UserName\Start Menu directory. Creating subdirectories under these two directories causes the shell to create a hierarchical menu structure. To add menu hierarchies and menu options, you simply create subdirectories and shell links, respectively. The next time the user pops open the Programs menu, your options will automatically appear.

Take care when creating Program menu shell links. Do not create links for every file that ships with your application. Instead, just create link files for the applications that the user is most likely to use on a regular basis. A user is easily confused when confronted with too many choices.


As I've shown you, the Windows 95 shell and its document-centric approach to files and applications provides new features that can really make everything much easier for your users (and for you, if you think about it). I covered this first because it provides the basis for everything you need to do during installation.

In a future issue I'll go into more of the details surrounding software installation. Specifically, I'll discuss how Windows 95 and the Windows NT Shell Update Release support AutoPlay; a feature that allows your application to install itself on the user's machine with little or no intervention from the user. I'll also cover some other features of software installation such as file compression and version control. Finally, I'll discuss the features of the system that allow a user to uninstall your application-a requirement in order for an app to sport the Designed for Windows 95 Logo.

From the April 1996 issue of Microsoft Systems Journal.

© 2017 Microsoft Corporation. All rights reserved. Contact Us |Terms of Use |Trademarks |Privacy & Cookies