From 5ff75e5aac42dd26fc99cfaa28802f1f67f24fdf Mon Sep 17 00:00:00 2001 From: "dbosst@gmail.com" Date: Mon, 3 Nov 2014 19:43:47 -0500 Subject: [PATCH] Support for teracopy shell extension on file copy/move to override internal file copy. The scroll lock key override to disable/enable teracopy does not work. Signed-off-by: dbosst@gmail.com --- Explorer++/Helper/DropHandler.cpp | 37 ++++++++- Explorer++/Helper/DropHandler.h | 4 + Explorer++/Helper/ShellHelper.cpp | 132 +++++++++++++++++++++++++++++- Explorer++/Helper/ShellHelper.h | 1 + 4 files changed, 171 insertions(+), 3 deletions(-) diff --git a/Explorer++/Helper/DropHandler.cpp b/Explorer++/Helper/DropHandler.cpp index 4a54509bc4..621a4f72cc 100644 --- a/Explorer++/Helper/DropHandler.cpp +++ b/Explorer++/Helper/DropHandler.cpp @@ -977,8 +977,41 @@ void CDropHandler::CopyDroppedFiles(const HDROP &hd,BOOL bPreferredEffect,DWORD } } - CopyDroppedFilesInternal(CopyFilenameList,TRUE,bRenameOnCollision); - CopyDroppedFilesInternal(MoveFilenameList,FALSE,bRenameOnCollision); + LPITEMIDLIST pidlDirectory = NULL; + HRESULT hr; + BOOL ret; + /* create pidl for target directory + /* --"For nondefault drag-and-drop menu extensions, this parameter specifies the target folder." */ + hr = GetIdlFromParsingName(m_szDestDirectory, &pidlDirectory); + if(SUCCEEDED(hr)) { + LPCITEMIDLIST pidlDirectoryC = pidlDirectory; + + /* create IDataObject of the file lists */ + FORMATETC copy_ftc, move_ftc; + STGMEDIUM copy_stg, move_stg; + BuildHDropList(©_ftc, ©_stg, CopyFilenameList); + BuildHDropList(&move_ftc, &move_stg, MoveFilenameList); + IDataObject *copy_pDataObject = NULL; + IDataObject *move_pDataObject = NULL; + hr = CreateDataObject(©_ftc,©_stg,©_pDataObject,1); + hr = CreateDataObject(&move_ftc,&move_stg,&move_pDataObject,1); + + /* Check against shell extensions before executing internal copy/move */ + ret = LoadShellExtensionHandlers(TRUE, pidlDirectoryC, copy_pDataObject); + if(ret) + { + CopyDroppedFilesInternal(CopyFilenameList,TRUE,bRenameOnCollision); + } + + ret = LoadShellExtensionHandlers(FALSE, pidlDirectoryC, move_pDataObject); + if(ret) + { + CopyDroppedFilesInternal(MoveFilenameList,FALSE,bRenameOnCollision); + } + + /* cleanup ... TODO ... what about pidlDirectoryC? */ + CoTaskMemFree(pidlDirectory); + } } void CDropHandler::CopyDroppedFilesInternal(const std::list &FullFilenameList, diff --git a/Explorer++/Helper/DropHandler.h b/Explorer++/Helper/DropHandler.h index 47c2f27fd8..03f30fb6f8 100644 --- a/Explorer++/Helper/DropHandler.h +++ b/Explorer++/Helper/DropHandler.h @@ -5,6 +5,10 @@ #include "FileOperations.h" #include "ReferenceCount.h" +/* now using in drop handler for shell extension file copy */ +HRESULT CreateDataObject(FORMATETC *,STGMEDIUM *,IDataObject **,int); + + enum DragTypes_t { DRAG_TYPE_LEFTCLICK, diff --git a/Explorer++/Helper/ShellHelper.cpp b/Explorer++/Helper/ShellHelper.cpp index 11f9257294..9249b6120e 100644 --- a/Explorer++/Helper/ShellHelper.cpp +++ b/Explorer++/Helper/ShellHelper.cpp @@ -18,6 +18,9 @@ #include "RegistrySettings.h" #include "Macros.h" +const TCHAR SEH_DIRECTORY_BACKGROUND[] = _T("Directory\\Background\\shellex\\ContextMenuHandlers"); +const TCHAR SEH_DRIVE_DRAG_AND_DROP[] = _T("Drive\\shellex\\DragDropHandlers"); +const TCHAR SEH_FOLDER_DRAG_AND_DROP[] = _T("Folder\\ShellEx\\DragDropHandlers"); HRESULT AddJumpListTasksInternal(IObjectCollection *poc, const std::list &TaskList); @@ -1127,6 +1130,131 @@ BOOL LoadIUnknownFromCLSID(const TCHAR *szCLSID, return bSuccess; } +/* loosely following and reusing::: CContextMenuManager::CContextMenuManager and LoadContextMenuHandlers */ +BOOL LoadShellExtensionHandlers(bool bCopy, LPCITEMIDLIST pidlDirectory, IDataObject *pDataObject) { + BOOL ret; + /* return true if none of the shells succeeded */ + ret = 1; + + const TCHAR *pszRegContexts[] = { SEH_FOLDER_DRAG_AND_DROP }; + std::list m_ShellExtensionHandlers; + + BOOL bRet; + + for each(auto pszRegContext in pszRegContexts) + { + /* load handler interfaces from registry */ + bRet = LoadContextMenuHandlers(pszRegContext,m_ShellExtensionHandlers); + + if(bRet == 0) + { + continue; + } + /* initialize extensions and extract interfaces, as in contextmenumanager */ + + for each(auto ContextMenuHandler in m_ShellExtensionHandlers) { + IShellExtInit *pShellExtInit = NULL; + HRESULT hr; + + IUnknown *pUnknown = ContextMenuHandler.pUnknown; + + hr = pUnknown->QueryInterface(IID_PPV_ARGS(&pShellExtInit)); + + if(SUCCEEDED(hr)) + { + IContextMenu *pContextMenu = NULL; + IContextMenu2 *pContextMenu2 = NULL; + IContextMenu3 *pContextMenu3 = NULL; + IContextMenu *pContextMenuActual = NULL; + + /* TODO: don't know what this is... */ + IUnknown *pUnkSite = NULL; + + /* Initialize shell extension */ + try { + pShellExtInit->Initialize(pidlDirectory,pDataObject,NULL); + pShellExtInit->Release(); + } catch(...) { + continue; + } + + if(pUnkSite != NULL) + { + IObjectWithSite *pObjectSite = NULL; + + hr = pUnknown->QueryInterface(IID_PPV_ARGS(&pObjectSite)); + + if(SUCCEEDED(hr)) + { + pObjectSite->SetSite(pUnkSite); + pObjectSite->Release(); + } + } + + hr = pUnknown->QueryInterface(IID_PPV_ARGS(&pContextMenu3)); + pContextMenuActual = pContextMenu3; + + if(FAILED(hr) || pContextMenu3 == NULL) + { + hr = pUnknown->QueryInterface(IID_PPV_ARGS(&pContextMenu2)); + pContextMenuActual = pContextMenu2; + + if(FAILED(hr) || pContextMenu2 == NULL) + { + hr = pUnknown->QueryInterface(IID_PPV_ARGS(&pContextMenu)); + pContextMenuActual = pContextMenu; + } + } + + CMINVOKECOMMANDINFO pici; + + pici.cbSize = sizeof(CMINVOKECOMMANDINFO); + /* no hotkey pressed? */ + pici.dwHotKey = 0; + pici.fMask = 0; + pici.hIcon = NULL; + pici.hwnd = NULL; + /* no working directory */ + pici.lpDirectory = NULL; + /* no parameters to pass */ + pici.lpParameters = NULL; + pici.nShow = 0; + /* the common verb is dword(0) for copy, dword(1) for move */ + if(bCopy) { + pici.lpVerb = reinterpret_cast(DWORD(0)) ; + } else { + pici.lpVerb = reinterpret_cast(DWORD(1)) ; + } + + /* execute command */ + hr = pContextMenuActual->InvokeCommand(&pici); + + /* cleanup */ + + if(pContextMenuActual != NULL) + { + pContextMenuActual->Release(); + } + + /* ...and free the necessary DLL's. */ + ContextMenuHandler.pUnknown->Release(); + if(ContextMenuHandler.hDLL != NULL) + { + FreeLibrary(ContextMenuHandler.hDLL); + } + + if(hr == S_OK) { + ret = 0; + break; + } + } + continue; + } + } + + return ret; +} + HRESULT GetItemInfoTip(const TCHAR *szItemPath, TCHAR *szInfoTip, size_t cchMax) { LPITEMIDLIST pidlItem = NULL; @@ -1175,4 +1303,6 @@ HRESULT GetItemInfoTip(LPCITEMIDLIST pidlComplete, TCHAR *szInfoTip, size_t cchM } return hr; -} \ No newline at end of file +} + + diff --git a/Explorer++/Helper/ShellHelper.h b/Explorer++/Helper/ShellHelper.h index b39b8698f0..c0b70f2788 100644 --- a/Explorer++/Helper/ShellHelper.h +++ b/Explorer++/Helper/ShellHelper.h @@ -112,6 +112,7 @@ BOOL CompareIdls(LPCITEMIDLIST pidl1,LPCITEMIDLIST pidl2); HRESULT AddJumpListTasks(const std::list &TaskList); BOOL LoadContextMenuHandlers(const TCHAR *szRegKey, std::list &ContextMenuHandlers); BOOL LoadIUnknownFromCLSID(const TCHAR *szCLSID, ContextMenuHandler_t *pContextMenuHandler); +BOOL LoadShellExtensionHandlers(bool bCopy, LPCITEMIDLIST pidlDirectory, IDataObject *pDataObject); HRESULT GetItemAttributes(const TCHAR *szItemParsingPath, SFGAOF *pItemAttributes); HRESULT GetItemAttributes(LPCITEMIDLIST pidl, SFGAOF *pItemAttributes); BOOL ExecuteFileAction(HWND hwnd, const TCHAR *szVerb, const TCHAR *szParameters, const TCHAR *szStartDirectory, LPCITEMIDLIST pidl);