📄 shellcontextmenu.cpp
字号:
/***************************************************************************/
/* NOTE: */
/* This document is copyright (c) by Oz Solomonovich. All non-commercial */
/* use is allowed, as long as this document is not altered in any way, and */
/* due credit is given. */
/***************************************************************************/
// ShellContextMenu.cpp : implementation file
//
// Handles the creation of the shell context menu, including the "Send To..."
// sub-menu.
// Personal note: I think that MS should have made the code to populate and
// handle the "Send To..." sub-menu a part of the shell context menu code.
// But they didn't, so now we're forced to write a whole lot of spaghetti COM
// code to do what should have been a trivial part of the OS. See the code
// below and judge for yourself.
//
// ==========================================================================
// HISTORY:
// ==========================================================================
// 1.01 7 Jul 2000 - Philip Oldaker [philip@masmex.com] - Fixed a problem
// with the SendTo menu now checking for menu id.
// Added support for the new OpenWith menu.
// The SendTo Menu is now sorted.
#include "stdafx.h"
#include "ShellContextMenu.h"
#include "UICoolMenu.h"
#include <atlbase.h>
#include "PIDL.h"
#ifdef _DEBUG
#define new DEBUG_NEW
#undef THIS_FILE
static char THIS_FILE[] = __FILE__;
#endif
#define IDM_SHELLCTXFIRST 20000
#define IDM_SHELLCTXLAST 29999
#define IDM_SENDTOFIRST 30000
#define IDM_SENDTOLAST 32000
#define IDM_OPENWITHFIRST 32001
#define IDM_OPENWITHLAST 32767
#define IDM_SENDTOID 20028
#define IDM_OPENWITHID1 20127
#define IDM_OPENWITHID2 20128
LPSHELLFOLDER is_less_than_pidl::psf;
LPSHELLFOLDER is_greater_than_pidl::psf;
// OpenWith menu registry keys
static LPCTSTR szAppKey = _T("Applications");
static LPCTSTR szOpenWithListKey = _T("OpenWithList");
static LPCTSTR szShellKey = _T("shell");
static LPCTSTR szCommandKey = _T("command");
static LPCTSTR szFileExtKey = _T("Software\\Microsoft\\Windows\\CurrentVersion\\Explorer\\FileExts");
// OpenWith menu entries
static LPCTSTR szMRUListEntry = _T("MRUList");
static LPCTSTR szDisplayNameEntry = _T("FriendlyCache");
static class CShCMInitializer
{
public:
CShCMInitializer();
~CShCMInitializer();
static LPSHELLFOLDER m_sfDesktop;
static LPSHELLFOLDER m_sfSendTo;
static CImageList * m_pShellImageList;
static CPIDL m_pidlSendTo;
} stat_data;
LPSHELLFOLDER CShCMInitializer::m_sfDesktop = NULL;
LPSHELLFOLDER CShCMInitializer::m_sfSendTo = NULL;
CImageList * CShCMInitializer::m_pShellImageList = NULL;
CPIDL CShCMInitializer::m_pidlSendTo;
CShCMInitializer::CShCMInitializer()
{
HRESULT hr;
SHFILEINFO sfi;
SHGetDesktopFolder(&m_sfDesktop);
hr = SHGetSpecialFolderLocation(NULL, CSIDL_SENDTO, m_pidlSendTo);
if (SUCCEEDED(hr))
{
hr = m_sfDesktop->BindToObject(m_pidlSendTo, NULL, IID_IShellFolder,
(LPVOID *)&m_sfSendTo);
if (!SUCCEEDED(hr))
{
m_sfSendTo = NULL;
}
}
else
{
m_sfSendTo = NULL;
}
m_pShellImageList = CImageList::FromHandle((HIMAGELIST)
SHGetFileInfo((LPCTSTR)_T("C:\\"), 0, &sfi, sizeof(SHFILEINFO),
SHGFI_SYSICONINDEX | SHGFI_SMALLICON));
}
CShCMInitializer::~CShCMInitializer()
{
m_sfSendTo->Release();
m_sfDesktop->Release();
}
CShellContextMenu::CShellContextMenu(HWND hWnd,const CString &sAbsPath, LPITEMIDLIST *ppidl, UINT cidl, LPSHELLFOLDER psfParent)
: m_hWnd(hWnd),
m_sAbsPath(sAbsPath),
m_psfParent(psfParent),
m_ppidl(ppidl),
m_cidl(cidl),
m_pSendToMenu(NULL)
{
m_lpcm = NULL;
m_pidl = *ppidl;
// Initialize button sizes
m_szOldButtonSize = g_CoolMenuManager.SetButtonSize();
}
CShellContextMenu::~CShellContextMenu()
{
if (m_lpcm) m_lpcm->Release();
if (m_pSendToMenu)
{
int i = IDM_SENDTOFIRST;
void * pData;
pData = CCoolMenuManager::GetItemData(*m_pSendToMenu, i);
while (pData)
{
CPIDL toFree((LPITEMIDLIST)pData);
pData = CCoolMenuManager::GetItemData(*m_pSendToMenu, ++i);
}
g_CoolMenuManager.UnconvertMenu(m_pSendToMenu);
m_pSendToMenu = NULL;
}
// Clean up owner draw menus
STL_FOR_ITERATOR(vecODMenu,m_OwnerDrawMenus)
{
g_CoolMenuManager.UnconvertMenu(STL_GET_CURRENT(m_OwnerDrawMenus));
}
STL_ERASE_ALL(m_OwnerDrawMenus);
g_CoolMenuManager.SetButtonSize(m_szOldButtonSize);
//////////////////////////////
}
/////////////////////////////
// Addition: Philip Oldaker
/////////////////////////////
CString CShellContextMenu::GetExt(const CString &sPath) const
{
TCHAR szDir[_MAX_PATH];
TCHAR szDrive[_MAX_DRIVE];
TCHAR szFileName[_MAX_FNAME];
TCHAR szExt[_MAX_EXT];
szDir[0] = szDrive[0] = szFileName[0] = szExt[0] = 0;
_tsplitpath(sPath,szDrive,szDir,szFileName,szExt);
return szExt;
}
// A bunch of registry nonsense to return all relevant details
// but especially the application icon
void CShellContextMenu::GetAppDetails(const CString &sAppName,CString &sDisplayName,CString &sCommand,HICON &hIconApp) const
{
hIconApp = NULL;
sDisplayName.Empty();
sCommand.Empty();
CString sAppKey(szAppKey);
AddKey(sAppKey,sAppName);
AddKey(sAppKey,szShellKey);
HKEY hKey;
if (RegOpenKeyEx(HKEY_CLASSES_ROOT,sAppKey,0,KEY_READ,&hKey) != ERROR_SUCCESS)
return;
BYTE szDisplayName[_MAX_PATH];
DWORD dwSize=sizeof(szDisplayName);
DWORD dwType=REG_SZ;
LONG nRet = RegQueryValueEx(hKey,szDisplayNameEntry,NULL,&dwType,szDisplayName,&dwSize);
if (nRet != ERROR_SUCCESS)
{
RegCloseKey(hKey);
return;
}
sDisplayName = szDisplayName;
TCHAR szSubKey[_MAX_PATH];
TCHAR szClass[_MAX_PATH];
DWORD dwSizeSubKey = sizeof(szSubKey)-1;
DWORD dwSizeClass = sizeof(szClass)-1;
ZeroMemory(szSubKey,sizeof(szSubKey));
ZeroMemory(szClass,sizeof(szClass));
FILETIME ftLastWriteTime;
HKEY hCmdKey=NULL;
CString sCmdKey;
// Search for a key that contains the "command" key as it may not be under "open"
for(DWORD dwIndex=0;RegEnumKeyEx(hKey,dwIndex,
szSubKey,
&dwSizeSubKey,
NULL,
szClass,
&dwSizeClass,
&ftLastWriteTime) == ERROR_SUCCESS;dwIndex++)
{
sCmdKey = szSubKey;
AddKey(sCmdKey,szCommandKey);
if (RegOpenKeyEx(hKey,sCmdKey,0,KEY_READ,&hCmdKey) == ERROR_SUCCESS)
{
break;
}
dwSizeSubKey = sizeof(szSubKey)-1;
dwSizeClass = sizeof(szClass)-1;
}
RegCloseKey(hKey);
hKey = NULL;
if (hCmdKey == NULL)
return;
dwType=REG_SZ | REG_EXPAND_SZ;
BYTE szCommand[_MAX_PATH];
dwSize=sizeof(szCommand);
nRet = RegQueryValueEx(hCmdKey,NULL,NULL,&dwType,szCommand,&dwSize);
if (nRet != ERROR_SUCCESS)
return;
TCHAR szPath[MAX_PATH];
sCommand = szCommand;
if (ExpandEnvironmentStrings(sCommand,szPath,sizeof(szPath)))
sCommand = szPath;
CString sIconPath(sCommand);
sIconPath.MakeLower();
// Only extract icons from exe's at the moment
int nPos = sIconPath.Find(_T(".exe"));
if (nPos == -1)
return;
sIconPath = sIconPath.Left(nPos+4);
// Remove auy quotes
if (sIconPath.Left(1) == '\"')
sIconPath = sIconPath.Right(sIconPath.GetLength()-1);
if (sIconPath.Right(1) == '\"')
sIconPath = sIconPath.Left(sIconPath.GetLength()-1);
ExtractIconEx(sIconPath, 0, NULL, &hIconApp, 1);
RegCloseKey(hCmdKey);
}
// reg helper
void CShellContextMenu::AddKey(CString &sDestKey,const CString &sSrcKey) const
{
if (sDestKey.Right(1) != '\\')
sDestKey += '\\';
sDestKey += sSrcKey;
}
////////////////////////////////////////
bool CShellContextMenu::IsMenuCommand(int iCmd) const
{
return (
(IDM_SENDTOFIRST <= iCmd && iCmd <= IDM_SENDTOLAST) ||
(IDM_SHELLCTXFIRST <= iCmd && iCmd <= IDM_SHELLCTXLAST)
);
}
void CShellContextMenu::InvokeCommand(int iCmd) const
{
if (!iCmd)
return;
USES_CONVERSION;
/////////////////////////////
if (IDM_SENDTOFIRST <= iCmd && iCmd <= IDM_SENDTOLAST)
{
// "Send To..." item
CPIDL pidlFile(m_sAbsPath), pidlDrop;
LPDROPTARGET pDT;
LPDATAOBJECT pDO;
HRESULT hr;
hr = pidlFile.GetUIObjectOf(IID_IDataObject, (LPVOID *)&pDO,
m_hWnd);
if (SUCCEEDED(hr))
{
pidlDrop.Set((LPITEMIDLIST)
CCoolMenuManager::GetItemData(*m_pSendToMenu, iCmd));
hr = pidlDrop.GetUIObjectOf(IID_IDropTarget,
(LPVOID *)&pDT, m_hWnd);
if (SUCCEEDED(hr))
{
// do the drop
POINTL pt = { 0, 0 };
DWORD dwEffect =
DROPEFFECT_COPY | DROPEFFECT_MOVE | DROPEFFECT_LINK;
hr = pDT->DragEnter(pDO, MK_LBUTTON, pt, &dwEffect);
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -