DOCUMENT:Q298109 23-JUL-2002 [visualc]
TITLE :SAMPLE: Create a Context Menu Handler by Using ATL
PRODUCT :Microsoft C Compiler
PROD/VER::6.0
OPER/SYS:
KEYWORDS:kbfile kbATL kbContMenu kbATL300 kbDSupport kbGrpDSMFCATL kbgrpdsvc
======================================================================
-------------------------------------------------------------------------------
The information in this article applies to:
- Microsoft Visual C++, 32-bit Enterprise Edition, version 6.0
-------------------------------------------------------------------------------
SUMMARY
=======
Context menu handlers extend the functionality of the Windows shell and can be
easily created through the use of the Active Template Library (ATL). This
article provides an example of a handler that registers and unregisters modules
with .dll and .ocx extensions.
MORE INFORMATION
================
The following files are available for download from the Microsoft Download
Center:
Visual C++ 6.0:
DownloadDownload Rscontext.exe now
(http://download.microsoft.com/download/vc60ent/sample03/1.0/WIN98MeXP/EN-US/RSContext.exe)
For additional information about how to download Microsoft Support files, click
the following article number to view the article in the Microsoft Knowledge
Base:
Q119591 How to Obtain Microsoft Support Files from Online Services
Microsoft scanned this file for viruses. Microsoft used the most current
virus-detection software that was available on the date that the file was
posted. The file is stored on secure servers that prevent any unauthorized
changes to the file.
The RSContext sample is an ATL DLL project created with Visual C++ 6.0 with
Service Pack 5. The "RS" is short for RegisterServer. The project can be rebuilt
and registered from the sample files and will be loaded by Windows Explorer when
a context menu is displayed for .dll and .ocx files.
The new context menu items will be called Register and Unregister. The
implementation will look for Regsvr32.exe and try to register and unregister
these file types with COM. Normally, Regsvr32.exe is located in the System32
folder for Windows NT, Windows 2000, and Windows XP-based systems or the System
folder for Windows 95, Windows 98 or Windows Millennium Edition-based computers,
so it should not be necessary to include the full path to the module, but it can
be added if necessary.
The following steps demonstrate creation of a simple context menu handler.
1. Create an ATL DLL project and add a simple object with all the defaults.
Include shlobj.h and comdef.h in stdafx.h. Then add two more interfaces to
inherit from: IShellExtInit and IContextMenu:
public IShellExtInit,
public IContextMenu,
Add these interfaces to the COM map as well:
COM_INTERFACE_ENTRY(IShellExtInit)
COM_INTERFACE_ENTRY(IContextMenu)
2. The IShellExtInit interface has one method, called Initialize(). Initialize
receives three parameters: an ITEMIDLIST, an IDataObject, and a ProgID
registry key (if one exists). The Initialize method must just store the file
name so DragQueryFile can be called on the IDataObject pointer to retrieve
it.
IContextMenu has three methods: GetCommandString, InvokeCommand, and
QueryContextMenu. QueryContextMenu inserts the new menu options,
GetCommandString asks for help text for the options, and InvokeCommand
executes the option the user selected.
Declare the methods in the class header:
// IContextMenu
STDMETHOD(GetCommandString)(UINT idCmd, UINT uFlags,
UINT *pwReserved, LPSTR pszName, UINT cchMax);
STDMETHOD(InvokeCommand)(LPCMINVOKECOMMANDINFO pici);
STDMETHOD(QueryContextMenu)(HMENU hmenu, UINT indexMenu,
UINT idCmdFirst, UINT idCmdLast,
UINT uFlags);
// IShellExtInit
STDMETHOD(Initialize)(LPCITEMIDLIST pidlFolder,
LPDATAOBJECT lpdobj,
HKEY hkeyProgID);
3. In addition, add two member variables to hold the file name and path:
TCHAR m_szPath[MAX_PATH];
TCHAR m_szFile[MAX_PATH];
4. Implement the methods as follows:
HRESULT CRSMenu::QueryContextMenu(HMENU hmenu, UINT indexMenu,
UINT idCmdFirst,
UINT idCmdLast,
UINT uFlags)
{
if (!(CMF_DEFAULTONLY & uFlags))
{
int nCmdRegister = idCmdFirst;
int nCmdUnregister = idCmdFirst+1;
InsertMenu(hmenu, indexMenu++, MF_STRING|MF_BYPOSITION,
nCmdRegister, _T("&Register"));
InsertMenu(hmenu, indexMenu++, MF_STRING|MF_BYPOSITION,
nCmdUnregister, _T("&Unregister"));
// A successful return code should be the offset of
// the largest command identifier assigned, plus one
return MAKE_HRESULT(SEVERITY_SUCCESS, FACILITY_NULL,
nCmdUnregister - idCmdFirst + 1);
}
return MAKE_HRESULT(SEVERITY_SUCCESS,
FACILITY_NULL, USHORT(0));
}
HRESULT CRSMenu::InvokeCommand(LPCMINVOKECOMMANDINFO pici)
{
TCHAR szParms[MAX_PATH+6];
// The offset will determine which option was requested:
// 0 for Register, 1 for Unregister
UINT idOffset = LOWORD(pici->lpVerb);
// Embed a '/u' for the Unregister command into the
// parameters, and always put quotes around the path
// so spaces in the path won't be a problem
if (1 == idOffset)
{
lstrcpy(szParms, _T("/u \""));
lstrcat(szParms, m_szFile);
lstrcat(szParms, _T("\""));
}
else
{
lstrcpy(szParms, _T("\""));
lstrcat(szParms, m_szFile);
lstrcat(szParms, _T("\""));
}
ShellExecute(pici->hwnd, NULL, _T("regsvr32.exe"), szParms,
NULL, 0);
return S_OK;
}
HRESULT CRSMenu::GetCommandString(UINT idCmd, UINT uFlags,
UINT* pwReserved,
LPSTR pszName, UINT cchMax)
{
if (uFlags & GCS_HELPTEXT)
{
// Windows NT will ask for Unicode strings
switch(idCmd)
{
case 0:
if (uFlags & GCS_VERBA)
lstrcpynA(pszName,
"Perform COM registration for this module",
cchMax);
else
lstrcpynW((LPWSTR)pszName,
L"Perform COM registration for this module",
cchMax);
break;
case 1:
if (uFlags & GCS_VERBA)
lstrcpynA(pszName,
"Perform COM unregistration for this module",
cchMax);
else
lstrcpynW((LPWSTR)pszName,
L"Perform COM unregistration for this module",
cchMax);
break;
default:
break;
}
}
return S_OK;
}
HRESULT CRSMenu::Initialize(LPCITEMIDLIST pidlFolder,
LPDATAOBJECT lpdobj, HKEY hkeyProgID)
{
if (lpdobj == NULL)
return E_INVALIDARG;
// The file can be referenced through the STGMEDIUM structure
// that is retrievable through the IDataObject pointer, and
// DragQueryFile can then be used to retrieve the file name.
STGMEDIUM medium;
FORMATETC fe = {CF_HDROP, NULL, DVASPECT_CONTENT, -1,
TYMED_HGLOBAL};
HRESULT hr = lpdobj->GetData(&fe, &medium);
if (FAILED(hr))
return E_INVALIDARG;
DragQueryFile(reinterpret_cast(medium.hGlobal), 0,
m_szFile, MAX_PATH);
ReleaseStgMedium(&medium);
return hr;
}
5. Add the following to the .rgs file to register the context menu handlers for
the file types:
Ocxfile
{
Shellex
{
ContextMenuHandlers
{
{A9F3EE64-2047-49CF-8522-FE41C75C158B}
}
}
}
Dllfile
{
Shellex
{
ContextMenuHandlers
{
{A9F3EE64-2047-49CF-8522-FE41C75C158B}
}
}
}
6. Build and register the extension and test it with Windows Explorer. The
InvokeCommand method runs Regsvr32.exe, which should be in System32 on
Windows NT, Windows 2000, or Windows XP, or System on Windows 95, Windows 98,
or Windows Millennium Edition, so the full path should not be necessary. The
extensions will try to register (or unregister) any .dll or .ocx file. If a
.dll does not export DllRegisterServer, the registration will fail, and an
error message will appear indicating that either the function is not exported
or the file is corrupt. Note that for a non-COM .dll, this failure is normal,
and no corrective measures are needed.
Additional query words: kbContMenu IContextMenu IShellExtInit RSContext
======================================================================
Keywords : kbfile kbATL kbContMenu kbATL300 kbDSupport kbGrpDSMFCATL kbgrpdsvc
Technology : kbVCsearch kbAudDeveloper kbVC600 kbVC32bitSearch
Version : :6.0
Issue type : kbhowto
=============================================================================
THE INFORMATION PROVIDED IN THE MICROSOFT KNOWLEDGE BASE IS
PROVIDED "AS IS" WITHOUT WARRANTY OF ANY KIND. MICROSOFT DISCLAIMS
ALL WARRANTIES, EITHER EXPRESS OR IMPLIED, INCLUDING THE WARRANTIES
OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. IN NO
EVENT SHALL MICROSOFT CORPORATION OR ITS SUPPLIERS BE LIABLE FOR
ANY DAMAGES WHATSOEVER INCLUDING DIRECT, INDIRECT, INCIDENTAL,
CONSEQUENTIAL, LOSS OF BUSINESS PROFITS OR SPECIAL DAMAGES, EVEN IF
MICROSOFT CORPORATION OR ITS SUPPLIERS HAVE BEEN ADVISED OF THE
POSSIBILITY OF SUCH DAMAGES. SOME STATES DO NOT ALLOW THE EXCLUSION
OR LIMITATION OF LIABILITY FOR CONSEQUENTIAL OR INCIDENTAL DAMAGES
SO THE FOREGOING LIMITATION MAY NOT APPLY.
Copyright Microsoft Corporation 2002.