Installing Handlers on Windows NT
Because shell extensions handlers run in a system process, namely the shell process, Windows NT administrators require control over which shell handlers are allowed to run. Administrators will have control over which shell handlers can run in much the same way they can now control which device drivers can run.
For the Windows NT shell to recognize and run a shell-extension handler, you must follow the instructions in Registering Shell Extensions, then the handler's CLSID must also be listed under another new registry key. This registry key contains a list of the handlers that are approved for the shell to run. By default, this key's access control permissions allow only someone with administrator privileges to modify the list.
The CLSID for the extension must be registered at the following location:
HKEY_LOCAL_MACHINE\Software\Microsoft\Windows\CurrentVersion\Shell Extensions\Approved
To register the extension, a "named value" should be added to the "Approved" key. The name of the value must be the string form of the CLSID as obtained from the StringFromCLSID() function, which is used elsewhere in the registry. The value itself should be the ProgID. The ProgID is stored here simply to make inspection of the registry easier, as it is easier to decipher than a CLSID. The Windows NT shell does not look at this value, however, only at the presence or absence of the CLSID.
Your setup application may or may not be able to write to this key, depending on the privileges of the person installing the application. The setup application should attempt to open the key described above, requesting the KEY_SET_VALUE permission. If it succeeds, the new CLSID can be added to fully register the corresponding shell extension. If the request fails with a security violation, then the person installing the application does not have permission to register new shell extensions. In this case, the setup application might warn the user that some application features will not be available unless an administrator turns them on (by installing the application, or by writing the registry keys directly). Or, if the shell extension is crucial to the application's functioning, the setup application might cause the installation to fail completely, notifying the user that the program must be installed by an administrator.
When setting up on Windows 95, it is not necessary to write the CLSID to this key, although writing it is harmless. Note, however, that the key may not exist in a Windows 95 installation, so that if your setup application does attempt to open the key, it may fail.
The following sample code details this process. Full error handling has been omitted.
#include <windows.h>
#include <string.h>
void main(void)
{
//
// First, attempt to open the registry key where approved extensions are
// listed. Note the extra slashes within the second parameter (the
// registry path string).
//
long err;
HKEY hkApproved;
err = RegOpenKeyEx(
HKEY_LOCAL_MACHINE,
"Software\\Microsoft\\Windows\\CurrentVersion\\Shell Extensions\\Approved",
0,
KEY_SET_VALUE,
&hkApproved);
if (err == ERROR_ACCESS_DENIED)
{
//
// The user does not have permissions to add a new value to this key. In this
// case, a reasonable action would be to warn the user that some
// application features will not be available unless an administrator
// installs the application. If the shell extension is central to the
// functioning of the application, tell the user that the install
// can only be performed by an administrator, and stop the install.
//
}
else if (err == ERROR_FILE_NOT_FOUND)
{
//
// The key does not exist. This should only happen if setup is running
// on Windows 95 instead of Windows NT, or if you are installing on an older
// version of either operating system that does not have the new shell.
//
}
else if (err != ERROR_SUCCESS)
{
//
// some other problem...
//
}
else
{
//
// The open of the key succeeded. Now register the new shell extension
// under this key. This requires having the ProgID and string form of the
// CLSID handy.
//
//
// Assume that lpstrProgID contains our ProgID string.
//
LPSTR lpstrProgID = "My Bogus Class";
//
// Assume that clsidExtension contains the CLSID struct. The code below
// creates a string form this CLSID. If a string version of
// the CLSID is already handy, skip this code.
//
CLSID clsidExtension = {0x11111111, 0x1111, 0x1111, 0x11, 0x11,
0x11, 0x11, 0x11, 0x11, 0x11, 0x11};
HRESULT hr;
LPOLESTR lpolestrCLSID;
CHAR rgchCLSID[40];
CoInitialize(NULL);
hr = StringFromCLSID(clsidExtension, &lpolestrCLSID);
//
// StringFromCLSID returns a Unicode string, so convert to ANSI for
// calling the registry. Note that on Windows NT you can call the Unicode
// version of the registry API instead.
//
WideCharToMultiByte(CP_ACP, 0, lpolestrCLSID, -1, rgchCLSID, 40,
NULL, NULL);
CoTaskMemFree(lpolestrCLSID);
CoUninitialize();
//
// Now add the new value to the registry.
// Note that each new shell extension CLSID must be registered here.
//
err = RegSetValueEx(
hkApproved,
rgchCLSID,
0,
REG_SZ,
(const BYTE *)lpstrProgID,
strlen(lpstrProgID));
//
// Finally, close the key.
//
err = RegCloseKey(hkApproved);
}
}