Click here to Skip to main content
Click here to Skip to main content
Add your own
alternative version

Shell Extension with Keyboard Hook

, 31 Aug 2008
Shell Extension with Keyboard Hook
ATLSmartMove.zip
ATLSmartMove - Copy
ATLSmartMove.suo
ATLSmartMove
ATLSmartMove.aps
ATLSmartMove.def
ATLSmartMove.rgs
ATLSmartMove.vcproj.joj-PC.joj.user
ATLSmartMove.vcproj.vspscc
ATLSmartMoveps.def
ATLSmartMovePS.vcproj.joj-PC.joj.user
ATLSmartMovePS.vcproj.vspscc
Debug
ATLSmartMove.dll
Release
ATLSmartMove.dll
ShellExtension.rgs
// 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();
    }
}

By viewing downloads associated with this article you agree to the Terms of Service and the article's licence.

If a file you wish to view isn't highlighted, and is a text file (not binary), please let us know and we'll add colourisation support for it.

License

This article, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)

Share

About the Author

joaquinjares
Software Developer (Senior) Independent
Argentina Argentina
I have been working as a developer for 15 years now, starting with gwbasic, moving to C and VB and then to VB.Net and later C#. I've used many languages, as languages is what I really like.

| Advertise | Privacy | Mobile
Web01 | 2.8.140827.1 | Last Updated 31 Aug 2008
Article Copyright 2008 by joaquinjares
Everything else Copyright © CodeProject, 1999-2014
Terms of Service
Layout: fixed | fluid