📄 shellext.cpp
字号:
static char *shellext_id =
"@(#)Copyright (C) H.Shirouzu 2005 shellext.cpp Ver1.21";
/* ========================================================================
Project Name : Shell Extension for Fast Copy
Create : 2005-01-23(Sun)
Update : 2005-07-06(Wed)
Copyright : H.Shirouzu
Reference :
======================================================================== */
#include "..\tlib.h"
#include <olectl.h>
#include "resource.h"
#pragma data_seg(".text")
#define INITGUID
#include <initguid.h>
#include <shlguid.h>
#include "shellext.h"
#pragma data_seg()
ShellExtSystem *SysObj = NULL;
// 儗僕僗僩儕搊榐僉乕乮Ref: tortoise subversion乯
char *DllRegKeys[] = {
"*\\shellex\\ContextMenuHandlers",
"*\\shellex\\DragDropHandlers",
"Folder\\shellex\\ContextMenuHandlers",
"Folder\\shellex\\DragDropHandlers",
"Directory\\shellex\\ContextMenuHandlers",
"Directory\\Background\\shellex\\ContextMenuHandlers",
"Directory\\shellex\\DragDropHandlers",
"Drive\\shellex\\ContextMenuHandlers",
"Drive\\shellex\\DragDropHandlers",
"InternetShortcut\\shellex\\ContextMenuHandlers",
"lnkfile\\shellex\\ContextMenuHandlers",
NULL
};
UINT (WINAPI *DragQueryFileV)(HDROP, UINT, void *, UINT);
BOOL (WINAPI *SHGetPathFromIDListV)(LPCITEMIDLIST, void *);
int (*strlenV)(const void *);
int (WINAPI *wsprintfV)(void *, const void *,...);
int (*MakePathV)(void *, const void *, const void *);
int CHAR_LEN_V;
BOOL IS_WINNT_V;
void *EMPTY_STR_V;
void *FMT_TOSTR_V;
/*=========================================================================
僋儔僗 丗 ShellExt
奣 梫 丗 僔僃儖奼挘僋儔僗
愢 柧 丗
拲 堄 丗
=========================================================================*/
ShellExt::ShellExt(void)
{
cmdFirst = cmdLast = 0;
refCnt = 0;
dataObj = NULL;
if (SysObj)
SysObj->DllRefCnt++;
}
ShellExt::~ShellExt()
{
if (dataObj)
dataObj->Release();
if (SysObj)
SysObj->DllRefCnt--;
}
STDMETHODIMP ShellExt::Initialize(const ITEMIDLIST *pIDFolder, IDataObject *pDataObj, HKEY hRegKey)
{
srcArray.Init();
dstArray.Init();
if (dataObj)
dataObj->Release();
if (!pDataObj)
return E_FAIL;
dataObj = pDataObj;
pDataObj->AddRef();
STGMEDIUM medium;
FORMATETC fe = { CF_HDROP, NULL, DVASPECT_CONTENT, -1, TYMED_HGLOBAL };
if (pDataObj->GetData(&fe, &medium) < 0)
return E_INVALIDARG;
WCHAR path[MAX_PATH_EX];
HDROP hDrop = (HDROP)::GlobalLock(medium.hGlobal);
int max = DragQueryFileV(hDrop, 0xffffffff, NULL, 0);
for (int i=0; i < max; i++) {
DragQueryFileV(hDrop, i, path, sizeof(path) / CHAR_LEN_V);
srcArray.RegisterPath(path);
}
::GlobalUnlock(medium.hGlobal);
::ReleaseStgMedium(&medium);
if (pIDFolder && SHGetPathFromIDListV(pIDFolder, path)) {
dstArray.RegisterPath(path);
}
return NOERROR;
}
STDMETHODIMP ShellExt::QueryInterface(REFIID riid, void **ppv)
{
*ppv = NULL;
if (IsEqualIID(riid, IID_IShellExtInit) || IsEqualIID(riid, IID_IUnknown)) {
*ppv = (IShellExtInit *)this;
}
else if (IsEqualIID(riid, IID_IContextMenu)) {
*ppv = (IContextMenu *)this;
}
if (*ppv) {
AddRef();
return NOERROR;
}
return E_NOINTERFACE;
}
STDMETHODIMP ShellExt::QueryContextMenu(HMENU hMenu, UINT iMenu, UINT _cmdFirst, UINT _cmdLast, UINT flg)
{
HMENU hTargetMenu = hMenu;
BOOL is_dd = dstArray.Num();
int menu_flags = GetMenuFlags();
int mask_menu_flags = (menu_flags & (is_dd ? SHEXT_DD_MENUS : SHEXT_RIGHT_MENUS));
BOOL is_submenu = (menu_flags & (is_dd ? SHEXT_SUBMENU_DD : SHEXT_SUBMENU_RIGHT));
BOOL is_separator = (menu_flags & SHEXT_SUBMENU_NOSEP) ? FALSE : TRUE;
if (!is_dd && (flg == CMF_NORMAL) || (flg & (CMF_VERBSONLY|CMF_DEFAULTONLY))) {
return ResultFromScode(MAKE_SCODE(SEVERITY_SUCCESS, 0, 0));
}
cmdFirst = cmdLast = _cmdFirst;
// 儊僯儏乕傾僀僥儉偺捛壛
if (mask_menu_flags && srcArray.Num() > 0) {
if (!is_dd && is_separator)
::InsertMenu(hMenu, iMenu++, MF_SEPARATOR|MF_BYPOSITION, 0, 0);
if (is_separator)
::InsertMenu(hMenu, iMenu, MF_SEPARATOR|MF_BYPOSITION, 0, 0);
if (is_submenu) {
hTargetMenu = ::CreatePopupMenu();
::InsertMenu(hMenu, iMenu, MF_POPUP|MF_BYPOSITION, (UINT)hTargetMenu, FASTCOPY);
iMenu = 0;
}
if (mask_menu_flags & (SHEXT_RIGHT_COPY|SHEXT_DD_COPY)) {
::InsertMenu(hTargetMenu, iMenu++, MF_STRING|MF_BYPOSITION, cmdLast, is_dd ? GetLoadStr(IDS_DDCOPY) : GetLoadStr(IDS_RIGHTCOPY));
}
cmdLast++;
if (mask_menu_flags & (SHEXT_RIGHT_DELETE|SHEXT_DD_MOVE)) {
::InsertMenu(hTargetMenu, iMenu++, MF_STRING|MF_BYPOSITION, cmdLast, is_dd ? GetLoadStr(IDS_DDMOVE) : GetLoadStr(IDS_RIGHTDEL));
}
cmdLast++;
}
return ResultFromScode(MAKE_SCODE(SEVERITY_SUCCESS, 0, cmdLast - cmdFirst));
}
STDMETHODIMP ShellExt::InvokeCommand(CMINVOKECOMMANDINFO *info)
{
int cmd = LOWORD(info->lpVerb);
if (cmd >= 0 && cmd <= 1 && srcArray.Num() > 0) {
HANDLE hRead, hWrite;
SECURITY_ATTRIBUTES sa = { sizeof(SECURITY_ATTRIBUTES), 0, TRUE };
::CreatePipe(&hRead, &hWrite, &sa, 0);
::DuplicateHandle(::GetCurrentProcess(), hWrite, ::GetCurrentProcess(), &hWrite, 0, FALSE, DUPLICATE_CLOSE_SOURCE|DUPLICATE_SAME_ACCESS);
STARTUPINFO st_info;
memset(&st_info, 0, sizeof(st_info));
st_info.cb = sizeof(st_info);
st_info.dwFlags = STARTF_USESTDHANDLES;
st_info.hStdInput = hRead;
st_info.hStdOutput = ::GetStdHandle(STD_OUTPUT_HANDLE);
st_info.hStdError = ::GetStdHandle(STD_ERROR_HANDLE);
BOOL is_dd = dstArray.Num();
char arg[MAX_PATH_EX];
PROCESS_INFORMATION pr_info;
wsprintf(arg, "\"%s\" %s %s", SysObj->ExeName, cmd == 1 ? is_dd ? "/cmd=move" : "/cmd=delete" : "", SHELLEXT_OPT);
BOOL ret = ::CreateProcess(SysObj->ExeName, arg, 0, 0, TRUE, CREATE_DEFAULT_ERROR_MODE, 0, 0, &st_info, &pr_info);
::CloseHandle(hRead);
if (ret) {
DWORD len = srcArray.GetMultiPathLen();
WCHAR *buf = new WCHAR[max(len, MAX_PATH_EX)];
// dstArray 偑柍偄応崌偼丄\0 傑偱弌椡
len = srcArray.GetMultiPath(buf, len) + (!is_dd ? 1 : 0);
::WriteFile(hWrite, buf, len * CHAR_LEN_V, &len, 0);
if (is_dd) {
WCHAR dir[MAX_PATH_EX];
MakePathV(dir, dstArray.Path(0), EMPTY_STR_V); // 枛旜偵 \\ 傪晅梌
len = wsprintfV(buf, FMT_TOSTR_V, dir) + 1;
::WriteFile(hWrite, buf, len * CHAR_LEN_V, &len, 0);
}
delete [] buf;
::CloseHandle(pr_info.hProcess);
::CloseHandle(pr_info.hThread);
}
::CloseHandle(hWrite);
return NOERROR;
}
return E_INVALIDARG;
}
STDMETHODIMP ShellExt::GetCommandString(UINT cmd, UINT flg, UINT *, char *name, UINT cchMax)
{
BOOL is_dd = dstArray.Num();
if (flg == GCS_HELPTEXT) {
switch (cmd) {
case 0:
strncpy(name, is_dd ? GetLoadStr(IDS_DDCOPY) : GetLoadStr(IDS_RIGHTCOPY), cchMax);
return S_OK;
case 1:
strncpy(name, is_dd ? GetLoadStr(IDS_DDMOVE) : GetLoadStr(IDS_RIGHTDEL), cchMax);
return S_OK;
}
}
return E_INVALIDARG;
}
STDMETHODIMP_(ULONG) ShellExt::AddRef()
{
return ++refCnt;
}
STDMETHODIMP_(ULONG) ShellExt::Release()
{
if (--refCnt)
return refCnt;
delete this;
return 0;
}
/*=========================================================================
僋儔僗 丗 ShellExtClassFactory
奣 梫 丗 僔僃儖奼挘僋儔僗
愢 柧 丗
拲 堄 丗
=========================================================================*/
ShellExtClassFactory::ShellExtClassFactory(void)
{
refCnt = 0;
if (SysObj)
SysObj->DllRefCnt++;
}
ShellExtClassFactory::~ShellExtClassFactory()
{
if (SysObj)
SysObj->DllRefCnt--;
}
STDMETHODIMP ShellExtClassFactory::CreateInstance(IUnknown *pUnkOuter, REFIID riid, void **ppvObj)
{
*ppvObj = NULL;
if (pUnkOuter)
return CLASS_E_NOAGGREGATION;
ShellExt *shellExt = new ShellExt;
if (NULL == shellExt)
return E_OUTOFMEMORY;
return shellExt->QueryInterface(riid, ppvObj);
}
STDMETHODIMP ShellExtClassFactory::LockServer(BOOL fLock)
{
return NOERROR;
}
STDMETHODIMP ShellExtClassFactory::QueryInterface(REFIID riid, void **ppv)
{
*ppv = NULL;
if (IsEqualIID(riid, IID_IUnknown) || IsEqualIID(riid, IID_IClassFactory)) {
*ppv = (IClassFactory *)this;
AddRef();
return NOERROR;
}
return E_NOINTERFACE;
}
STDMETHODIMP_(ULONG) ShellExtClassFactory::AddRef()
{
return ++refCnt;
}
STDMETHODIMP_(ULONG) ShellExtClassFactory::Release()
{
if (--refCnt)
return refCnt;
delete this;
return 0;
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -