// ShellExtension.cpp : Implementation of CShellExtension
#include "stdafx.h"
#include "ShellExtension.h"
// CShellExtension
static HHOOK g_hHook;
CShellExtension::~CShellExtension()
{
if (m_Subclassed)
{
SubclassExplorer(false);
m_Subclassed = false;
}
}
STDMETHODIMP CShellExtension::SetSite(IUnknown *pUnkSite)
{
if (!m_Subclassed)
{
HRESULT hr = SubclassExplorer(true);
if (SUCCEEDED(hr))
{
m_Subclassed = true;
return S_OK;
}
else
{
return E_FAIL;
}
}
return S_OK;
}
CShellExtension::CShellExtension()
{
m_Subclassed = false;
}
STDMETHODIMP CShellExtension::SubclassExplorer(bool bSubclass)
{
if (bSubclass && !m_Subclassed)
{
g_hHook = SetWindowsHookEx(WH_KEYBOARD, KeyboardProc, NULL, GetCurrentThreadId());
}
if (!bSubclass && m_Subclassed)
{
UnhookWindowsHookEx(g_hHook);
}
return S_OK;
}
LRESULT CALLBACK CShellExtension::KeyboardProc(int nCode, WPARAM wParam, LPARAM lParam)
{
if (nCode < 0)
return CallNextHookEx(g_hHook, nCode, wParam, lParam);
if ((lParam & 0x80000000) || (lParam & 0x40000000))
return CallNextHookEx(g_hHook, nCode, wParam, lParam);
if (wParam == NEWFOLDERKEY)
{
MoveSelectedFiles((GetAsyncKeyState(VK_CONTROL) & 0x80000000) == 0x80000000);
}
return CallNextHookEx(g_hHook, nCode, wParam, lParam);
}
BOOL CALLBACK CShellExtension::WndEnumProc(HWND hwnd, LPARAM lParam)
{
TCHAR szClassName[MAX_PATH] = {0};
GetClassName(hwnd, szClassName, MAX_PATH);
if (!lstrcmpi(szClassName, __TEXT("CabinetWClass")))
{
HWND* phWnd = reinterpret_cast<HWND*>(lParam);
*phWnd = hwnd;
return FALSE;
}
return TRUE;
}
BOOL CShellExtension::FindIShellView(HWND hwnd, IShellView** psv)
{
BOOL fFound = FALSE;
IShellWindows *psw;
if (SUCCEEDED(CoCreateInstance(CLSID_ShellWindows, NULL, CLSCTX_ALL,
IID_IShellWindows, (void**)&psw))) {
VARIANT v;
V_VT(&v) = VT_I4;
IDispatch *pdisp;
for (V_I4(&v) = 0; !fFound && psw->Item(v, &pdisp) == S_OK;
V_I4(&v)++) {
IWebBrowserApp *pwba;
if (SUCCEEDED(pdisp->QueryInterface(IID_IWebBrowserApp, (void**)&pwba))) {
HWND hwndWBA;
if (SUCCEEDED(pwba->get_HWND((LONG_PTR*)&hwndWBA)) &&
hwndWBA == hwnd) {
IServiceProvider *psp;
if (SUCCEEDED(pwba->QueryInterface(IID_IServiceProvider, (void**)&psp))) {
IShellBrowser *psb;
if (SUCCEEDED(psp->QueryService(SID_STopLevelBrowser,
IID_IShellBrowser, (void**)&psb))) {
if (SUCCEEDED(psb->QueryActiveShellView(psv))) {
fFound = TRUE;
}
psb->Release();
}
psp->Release();
}
}
pwba->Release();
}
pdisp->Release();
}
psw->Release();
}
return fFound;
}
void CShellExtension::MoveSelectedFiles(bool fCopy)
{
HWND m_hwndExplorer;
HWND g_hwndExplorer;
PWSTR ppszDocumentsPath[MAX_PATH];
PWSTR ppszMusicPath[MAX_PATH];
PWSTR ppszPicturesPath[MAX_PATH];
PWSTR ppszVideosPath[MAX_PATH];
EnumThreadWindows(GetCurrentThreadId(), WndEnumProc, reinterpret_cast<LPARAM>(&m_hwndExplorer));
if (!IsWindow(m_hwndExplorer))
{
return;
}
else
g_hwndExplorer = m_hwndExplorer;
SHGetKnownFolderPath(FOLDERID_Documents, 0, NULL, ppszDocumentsPath);
SHGetKnownFolderPath(FOLDERID_Music, 0, NULL, ppszMusicPath);
SHGetKnownFolderPath(FOLDERID_Pictures, 0, NULL, ppszPicturesPath);
SHGetKnownFolderPath(FOLDERID_Videos, 0, NULL, ppszVideosPath);
IShellView* psv;
if (FindIShellView(g_hwndExplorer, &psv))
{
CComPtr<IDataObject> spDataObject;
if (SUCCEEDED(psv->GetItemObject(SVGIO_SELECTION,
IID_PPV_ARGS(&spDataObject))))
{
FORMATETC fmt = { CF_HDROP, NULL, DVASPECT_CONTENT,
-1, TYMED_HGLOBAL };
STGMEDIUM stg;
stg.tymed = TYMED_HGLOBAL;
if (SUCCEEDED(spDataObject->GetData(&fmt, &stg)))
{
HDROP hDrop = (HDROP) GlobalLock ( stg.hGlobal );
UINT uNumFiles = DragQueryFile ( hDrop, 0xFFFFFFFF, NULL, 0 );
HRESULT hr = S_OK;
IFileOperation *pfo;
hr = CoCreateInstance(CLSID_FileOperation,
NULL,
CLSCTX_ALL,
IID_PPV_ARGS(&pfo));
pfo->SetOperationFlags(FOFX_SHOWELEVATIONPROMPT | FOF_ALLOWUNDO);
for(UINT i = 0; i < uNumFiles; i++)
{
TCHAR szPath[MAX_PATH];
szPath[0] = 0;
DragQueryFile(hDrop, i, szPath, MAX_PATH);
if (szPath[0] != 0)
if (!(PathIsDirectory(szPath) || PathIsRoot(szPath)))
{
if (!PathMatchSpecEx(szPath, GRAPHICFILES, PMSF_MULTIPLE))
AddFileToArray(szPath, *ppszPicturesPath, pfo, fCopy);
else if (!PathMatchSpecEx(szPath, VIDEOFILES, PMSF_MULTIPLE))
AddFileToArray(szPath, *ppszVideosPath, pfo, fCopy);
else if (!PathMatchSpecEx(szPath, MUSICFILES, PMSF_MULTIPLE))
AddFileToArray(szPath, *ppszMusicPath, pfo, fCopy);
else
AddFileToArray(szPath, *ppszDocumentsPath, pfo, fCopy);
}
}
pfo->PerformOperations();
pfo->Release();
GlobalUnlock ( stg.hGlobal );
ReleaseStgMedium ( &stg );
}
}
psv->Release();
}
CoTaskMemFree(*ppszDocumentsPath);
CoTaskMemFree(*ppszMusicPath);
CoTaskMemFree(*ppszPicturesPath);
CoTaskMemFree(*ppszVideosPath);
}
void CShellExtension::AddFileToArray(LPCWSTR szPath, LPWSTR pszDest, IFileOperation* pfo, bool fCopy)
{
IShellItem *psiFrom = NULL;
int hr = SHCreateItemFromParsingName(szPath, NULL, IID_PPV_ARGS(&psiFrom));
if (SUCCEEDED(hr))
{
IShellItem *psiTo = NULL;
if (NULL != pszDest)
hr = SHCreateItemFromParsingName(pszDest, NULL, IID_PPV_ARGS(&psiTo));
if (SUCCEEDED(hr))
{
if (fCopy)
hr = pfo->CopyItem(psiFrom, psiTo, NULL, NULL);
else
hr = pfo->MoveItem(psiFrom, psiTo, NULL, NULL);
if (NULL != psiTo)
psiTo->Release();
}
psiFrom->Release();
}
}