⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 shellcontextmenu.cpp

📁 vc座的资源管理器源代码
💻 CPP
📖 第 1 页 / 共 2 页
字号:
/***************************************************************************/
/* 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 + -