summaryrefslogtreecommitdiff
path: root/catchcopy-windows-explorer-plugin
diff options
context:
space:
mode:
Diffstat (limited to 'catchcopy-windows-explorer-plugin')
-rwxr-xr-xcatchcopy-windows-explorer-plugin/CatchCopy.cpp115
-rwxr-xr-xcatchcopy-windows-explorer-plugin/CatchCopy.def7
-rwxr-xr-xcatchcopy-windows-explorer-plugin/CatchCopy.pro49
-rwxr-xr-xcatchcopy-windows-explorer-plugin/ClassFactory.cpp84
-rwxr-xr-xcatchcopy-windows-explorer-plugin/ClassFactory.h22
-rwxr-xr-xcatchcopy-windows-explorer-plugin/ClientCatchcopy.cpp455
-rwxr-xr-xcatchcopy-windows-explorer-plugin/ClientCatchcopy.h68
-rwxr-xr-xcatchcopy-windows-explorer-plugin/DDShellExt.cpp188
-rwxr-xr-xcatchcopy-windows-explorer-plugin/DDShellExt.h46
-rwxr-xr-xcatchcopy-windows-explorer-plugin/Deque.cpp100
-rwxr-xr-xcatchcopy-windows-explorer-plugin/Deque.h29
-rwxr-xr-xcatchcopy-windows-explorer-plugin/Reg.cpp403
-rwxr-xr-xcatchcopy-windows-explorer-plugin/Reg.h103
-rwxr-xr-xcatchcopy-windows-explorer-plugin/Variable.h7
-rwxr-xr-xcatchcopy-windows-explorer-plugin/resource.h18
15 files changed, 1694 insertions, 0 deletions
diff --git a/catchcopy-windows-explorer-plugin/CatchCopy.cpp b/catchcopy-windows-explorer-plugin/CatchCopy.cpp
new file mode 100755
index 0000000..58d36fb
--- /dev/null
+++ b/catchcopy-windows-explorer-plugin/CatchCopy.cpp
@@ -0,0 +1,115 @@
+// Implementation of DLL Exports.
+#include "resource.h"
+#include "DDShellExt.h"
+#include "ClassFactory.h"
+#include "Reg.h"
+
+#ifndef _M_X64
+const CLSID CLSID_DDShellExt = {0x68D44A27,0xFFB6,0x4B89,{0xA3,0xE5,0x7B,0x0E,0x50,0xA7,0xAB,0x33}};
+#else
+const CLSID CLSID_DDShellExt = {0x68ff37c4,0x51bc,0x4c2a,{0xa9,0x92,0x7e,0x39,0xbc,0xe,0x70,0x6f}};
+#endif
+
+HINSTANCE g_hInst = NULL;
+long g_cDllRef = 0;
+
+// DLL Entry Point
+extern "C" BOOL WINAPI DllMain(HINSTANCE hInstance, DWORD dwReason, LPVOID lpReserved)
+{
+ (void)lpReserved;
+ switch(dwReason){
+ case DLL_PROCESS_ATTACH:
+ //MessageBox ( NULL,L"DLL_PROCESS_ATTACH", L"DLL_PROCESS_ATTACH", MB_OK);
+ // Hold the instance of this DLL module, we will use it to get the
+ // path of the DLL to register the component.
+ g_hInst = hInstance;
+ DisableThreadLibraryCalls(hInstance);
+ break;
+ case DLL_PROCESS_DETACH:
+ //MessageBox ( NULL,L"DLL_PROCESS_DETACH", L"DLL_PROCESS_DETACH", MB_OK);
+ break;
+ }
+
+ return TRUE; //_AtlModule.DllMain(hInstance, dwReason, lpReserved,ObjectMap,NULL);
+}
+
+
+// Used to determine whether the DLL can be unloaded by OLE
+STDAPI DllCanUnloadNow(void)
+{
+ return g_cDllRef > 0 ? S_FALSE : S_OK;
+}
+
+
+// Returns a class factory to create an object of the requested type
+STDAPI DllGetClassObject(REFCLSID rclsid, REFIID riid, LPVOID* ppv)
+{
+ HRESULT hr = CLASS_E_CLASSNOTAVAILABLE;
+ if (IsEqualCLSID(CLSID_DDShellExt, rclsid))
+ {
+ hr = E_OUTOFMEMORY;
+ ClassFactory *pClassFactory = new ClassFactory();
+ if (pClassFactory)
+ {
+ hr = pClassFactory->QueryInterface(riid, ppv);
+ pClassFactory->Release();
+ }
+ }
+ return hr;
+}
+
+
+// DllRegisterServer - Adds entries to the system registry
+STDAPI DllRegisterServer(void)
+{
+// registers object, typelib and all interfaces in typelib
+
+ HRESULT hr;
+
+ wchar_t szModule[MAX_PATH];
+ if (GetModuleFileName(g_hInst, szModule, ARRAYSIZE(szModule)) == 0)
+ {
+ hr = HRESULT_FROM_WIN32(GetLastError());
+ return hr;
+ }
+ // Register the component.
+ hr = RegisterInprocServer(szModule, CLSID_DDShellExt, L"CatchCopy Class", L"Apartment");
+ if (SUCCEEDED(hr))
+ {
+ // Register the context menu handler. The context menu handler is
+ // associated with the * file class.
+ hr = RegisterShellExtContextMenuHandler(L"textfile", CLSID_DDShellExt, L"CatchCopy");
+ hr = RegisterShellExtContextMenuHandler(L"Drive", CLSID_DDShellExt, L"CatchCopy");
+ hr = RegisterShellExtContextMenuHandler(L"Directory", CLSID_DDShellExt, L"CatchCopy");
+ hr = RegisterShellExtContextMenuHandler(L"Folder", CLSID_DDShellExt, L"CatchCopy");
+ }
+ return hr;
+}
+
+
+// DllUnregisterServer - Removes entries from the system registry
+STDAPI DllUnregisterServer(void)
+{
+ m_ac.disconnectFromServer();
+ HRESULT hr = S_OK;
+
+ wchar_t szModule[MAX_PATH];
+ if (GetModuleFileName(g_hInst, szModule, ARRAYSIZE(szModule)) == 0)
+ {
+ hr = HRESULT_FROM_WIN32(GetLastError());
+ return hr;
+ }
+
+ // Unregister the component.
+ hr = UnregisterInprocServer(CLSID_DDShellExt);
+ if (SUCCEEDED(hr))
+ {
+ // Unregister the context menu handler.
+ hr = UnregisterShellExtContextMenuHandler(L"textfile", CLSID_DDShellExt);
+ hr = UnregisterShellExtContextMenuHandler(L"Drive", CLSID_DDShellExt);
+ hr = UnregisterShellExtContextMenuHandler(L"Directory", CLSID_DDShellExt);
+ hr = UnregisterShellExtContextMenuHandler(L"Folder", CLSID_DDShellExt);
+ return hr;
+ }
+ return S_OK;
+}
diff --git a/catchcopy-windows-explorer-plugin/CatchCopy.def b/catchcopy-windows-explorer-plugin/CatchCopy.def
new file mode 100755
index 0000000..78582f4
--- /dev/null
+++ b/catchcopy-windows-explorer-plugin/CatchCopy.def
@@ -0,0 +1,7 @@
+LIBRARY "CatchCopy.DLL"
+
+EXPORTS
+ DllGetClassObject = DllGetClassObject@12
+ DllCanUnloadNow = DllCanUnloadNow@0
+ DllRegisterServer = DllRegisterServer@0
+ DllUnregisterServer = DllUnregisterServer@0
diff --git a/catchcopy-windows-explorer-plugin/CatchCopy.pro b/catchcopy-windows-explorer-plugin/CatchCopy.pro
new file mode 100755
index 0000000..99dcd62
--- /dev/null
+++ b/catchcopy-windows-explorer-plugin/CatchCopy.pro
@@ -0,0 +1,49 @@
+QT -= core gui
+
+CONFIG += 64bit
+CONFIG -= exceptions rtti
+
+#DEFINES += CATCHCOPY_EXPLORER_PLUGIN_DEBUG
+
+CONFIG(32bit) {
+ TARGET = catchcopy32
+ QMAKE_CFLAGS = -march=i586 -m32
+ QMAKE_CXXFLAGS = -march=i586 -m32
+ QMAKE_LFLAGS += -m32
+}
+CONFIG(64bit) {
+ TARGET = catchcopy64
+ LIBS += -LC:\x86_64-4.9.3-release-win32-seh-rt_v4-rev1\mingw64\lib64
+ DEFINES += _M_X64
+ QMAKE_CFLAGS = -m64
+ QMAKE_CXXFLAGS = -m64
+ QMAKE_LFLAGS += -m64
+}
+
+QMAKE_CFLAGS -= -fexceptions -mthreads -O2
+QMAKE_CXXFLAGS -= -fexceptions -mthreads -O2
+QMAKE_CFLAGS += -std=c++98 -fno-keep-inline-dllexport -mtune=generic -fno-exceptions -Os -Wall -Wextra -fno-rtti -s -static -static-libgcc -static-libstdc++
+QMAKE_CXXFLAGS += -std=c++98 -fno-keep-inline-dllexport -mtune=generic -fno-exceptions -Os -Wall -Wno-write-strings -Wextra -fno-rtti -s -static -static-libgcc -static-libstdc++
+
+DEF_FILE += CatchCopy.def
+
+LIBS+= -lws2_32 -lole32 -luuid -static-libstdc++ -static-libgcc -static
+
+TEMPLATE = lib
+
+HEADERS += \
+ Variable.h \
+ Deque.h \
+ resource.h \
+ Reg.h \
+ ClientCatchcopy.h \
+ DDShellExt.h \
+ ClassFactory.h
+
+SOURCES += \
+ Deque.cpp \
+ ClientCatchcopy.cpp \
+ Reg.cpp \
+ DDShellExt.cpp \
+ ClassFactory.cpp \
+ CatchCopy.cpp
diff --git a/catchcopy-windows-explorer-plugin/ClassFactory.cpp b/catchcopy-windows-explorer-plugin/ClassFactory.cpp
new file mode 100755
index 0000000..9ad7a5c
--- /dev/null
+++ b/catchcopy-windows-explorer-plugin/ClassFactory.cpp
@@ -0,0 +1,84 @@
+
+#include "ClassFactory.h"
+#include "DDShellExt.h"
+#include <new>
+#include <Shlwapi.h>
+
+extern long g_cDllRef;
+
+ClassFactory::ClassFactory() : m_cRef(1)
+{
+ InterlockedIncrement(&g_cDllRef);
+}
+
+ClassFactory::~ClassFactory()
+{
+ InterlockedDecrement(&g_cDllRef);
+}
+
+// IUnknown
+HRESULT __stdcall ClassFactory::QueryInterface(const IID& iid, void **ppv)
+{
+ if(iid == IID_IUnknown || iid == IID_IClassFactory)
+ {
+ *ppv = static_cast<IClassFactory*>(this);
+ }
+ else
+ {
+ *ppv = NULL;
+ return E_NOINTERFACE;
+ }
+ reinterpret_cast<IUnknown*>(*ppv)->AddRef();
+ return S_OK;
+}
+ULONG __stdcall ClassFactory::AddRef()
+{
+ return InterlockedIncrement(&m_cRef);
+}
+
+ULONG __stdcall ClassFactory::Release()
+{
+ ULONG cRef = InterlockedDecrement(&m_cRef);
+ if (0 == cRef)
+ {
+ delete this;
+ }
+ return cRef;
+}
+
+//CreateInstance
+HRESULT __stdcall ClassFactory::CreateInstance(IUnknown *pIUnknownOuter, const IID& iid, void **ppv)
+{
+ HRESULT hr = CLASS_E_NOAGGREGATION;
+
+ // pIUnknownOuter is used for aggregation. We do not support it in the sample.
+ if (pIUnknownOuter == NULL)
+ {
+ hr = E_OUTOFMEMORY;
+
+ //// Create the COM component.
+ CDDShellExt *pExt = new (std::nothrow) CDDShellExt();
+ if (pExt)
+ {
+ // Query the specified interface.
+ hr = pExt->QueryInterface(iid, ppv);
+ pExt->Release();
+ }
+ }
+
+ return hr;
+}
+
+HRESULT __stdcall ClassFactory::LockServer(BOOL bLock)
+{
+ if(bLock == TRUE)
+ {
+ InterlockedIncrement(&g_cDllRef);
+ }
+ else
+ {
+ InterlockedDecrement(&g_cDllRef);
+ }
+ return S_OK;
+}
+
diff --git a/catchcopy-windows-explorer-plugin/ClassFactory.h b/catchcopy-windows-explorer-plugin/ClassFactory.h
new file mode 100755
index 0000000..203ff40
--- /dev/null
+++ b/catchcopy-windows-explorer-plugin/ClassFactory.h
@@ -0,0 +1,22 @@
+#pragma once
+
+#include <unknwn.h> // For IClassFactory
+#include <windows.h>
+
+
+class ClassFactory : public IClassFactory
+{
+public:
+ //interface iunknown
+ virtual HRESULT __stdcall QueryInterface(const IID& iid, void **ppv);
+ virtual ULONG __stdcall AddRef();
+ virtual ULONG __stdcall Release();
+ //interface iclassfactory
+ virtual HRESULT __stdcall CreateInstance(IUnknown *pIUnknownOuter, const IID& iid, void **ppv);
+ virtual HRESULT __stdcall LockServer(BOOL bLock);
+
+ ClassFactory();
+ ~ClassFactory();
+private:
+ long m_cRef;
+};
diff --git a/catchcopy-windows-explorer-plugin/ClientCatchcopy.cpp b/catchcopy-windows-explorer-plugin/ClientCatchcopy.cpp
new file mode 100755
index 0000000..2491795
--- /dev/null
+++ b/catchcopy-windows-explorer-plugin/ClientCatchcopy.cpp
@@ -0,0 +1,455 @@
+/** \file ClientCatchcopy.cpp
+\brief Define the catchcopy client
+\author alpha_one_x86
+\version 0002
+\date 2010 */
+
+#include <stdio.h>
+
+#include "ClientCatchcopy.h"
+#include <WinSock.h>
+//#pragma comment(lib, "Ws2_32.lib")
+
+#undef NONBLOCK_FLAG
+ClientCatchcopy::ClientCatchcopy()
+{
+ m_hpipe=NULL;
+ idNextOrder=0;
+ const char prefix[]="\\\\.\\pipe\\advanced-copier-";
+ char uname[1024];
+ DWORD len=1023;
+ char *data;
+ // false ??
+ if(GetUserNameA(uname, &len)!=FALSE)
+ {
+ // convert into hexa
+ data = toHex(uname);
+ m_pipename = (char *) malloc(sizeof(prefix)+strlen(data)+2);
+ #if defined(_MFC_VER)
+ strcpy_s(m_pipename, _countof(prefix) ,prefix);
+ strcat_s(m_pipename, sizeof(prefix)+strlen(data)+2,data);
+ #else
+ strcpy(m_pipename, prefix);
+ strcat(m_pipename, data);
+ #endif
+ free(data);
+ m_blk=NULL;
+ m_len=0;
+ m_tot=0;
+
+ canConnect=true;
+ }
+ else
+ {
+ #ifdef CATCHCOPY_EXPLORER_PLUGIN_DEBUG
+ void* lpBuffer;
+ FormatMessage( FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM,
+ NULL,
+ ::GetLastError(),
+ MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), // Default language
+ (LPTSTR) &lpBuffer,
+ 0,
+ NULL );
+ MessageBox(NULL,(LPCTSTR)lpBuffer, L"GetUserName Failed", MB_OK);
+ LocalFree( lpBuffer );
+ #endif // CATCHCOPY_EXPLORER_PLUGIN_DEBUG
+ canConnect=false;
+ }
+}
+
+ClientCatchcopy::~ClientCatchcopy()
+{
+ disconnectFromServer();
+}
+
+// Dump UTF16 (little endian)
+char * ClientCatchcopy::toHex(const char *str)
+{
+ char *p, *sz;
+ size_t len;
+ if (str==NULL)
+ return NULL;
+ len= strlen(str);
+ p = sz = (char *) malloc((len+1)*4);
+ // username goes hexa...
+ for (size_t i=0; i<len; i++)
+ {
+ #if defined(_MFC_VER)
+ sprintf_s(p, (len+1)*4, "%.2x00", str[i]);
+ #else
+ sprintf(p, "%.2x00", str[i]);
+ #endif
+ p+=4;
+ }
+ *p=0;
+ return sz;
+}
+
+bool ClientCatchcopy::connectToServer()
+{
+ if(!canConnect)
+ {
+ #ifdef CATCHCOPY_EXPLORER_PLUGIN_DEBUG
+ MessageBox(NULL,L"Can't connect due to previous error",L"Checking", MB_OK);
+ #endif // CATCHCOPY_EXPLORER_PLUGIN_DEBUG
+ return false;
+ }
+ if (m_hpipe==NULL)
+ {
+ #ifdef CATCHCOPY_EXPLORER_PLUGIN_DEBUG
+ char uname[1024];
+ DWORD len=1023;
+ GetUserNameA(uname, &len);
+ char temp_char_debug[1024];
+ sprintf(temp_char_debug, "user name: %s, pipe name: %s",uname , m_pipename);
+ MessageBoxA(NULL,temp_char_debug,"Pipe name", MB_OK);
+ #endif // CATCHCOPY_EXPLORER_PLUGIN_DEBUG
+ // create pipe
+ m_hpipe = CreateFileA(m_pipename, GENERIC_READ|GENERIC_WRITE|FILE_FLAG_OVERLAPPED , 0, NULL, OPEN_EXISTING, 0, NULL);
+ if (m_hpipe==INVALID_HANDLE_VALUE)
+ {
+ m_hpipe=NULL;
+ if (GetLastError()!= ERROR_PIPE_BUSY)
+ {
+ #ifdef CATCHCOPY_EXPLORER_PLUGIN_DEBUG
+ void* lpBuffer;
+ FormatMessage( FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM,
+ NULL,
+ ::GetLastError(),
+ MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), // Default language
+ (LPTSTR) &lpBuffer,
+ 0,
+ NULL );
+ MessageBox(NULL,(LPCTSTR)lpBuffer, L"Can't connect to catchcopy application compatible: GetLastError()!= ERROR_PIPE_BUSY", MB_OK);
+ LocalFree( lpBuffer );
+ #endif // CATCHCOPY_EXPLORER_PLUGIN_DEBUG
+ return false;
+ }
+ #ifdef NONBLOCK_FLAG
+ return false;
+ #else
+ if (!WaitNamedPipeA(m_pipename, 10000))
+ {
+ #ifdef CATCHCOPY_EXPLORER_PLUGIN_DEBUG
+ void* lpBuffer;
+ FormatMessage( FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM,
+ NULL,
+ ::GetLastError(),
+ MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), // Default language
+ (LPTSTR) &lpBuffer,
+ 0,
+ NULL );
+ MessageBox(NULL,(LPCTSTR)lpBuffer, L"Named pipe too long to responds", MB_OK);
+ LocalFree( lpBuffer );
+ #endif // CATCHCOPY_EXPLORER_PLUGIN_DEBUG
+ CloseHandle(m_hpipe);
+ m_hpipe=NULL;
+ return false;
+ }
+ #endif
+ }
+
+ #ifdef NONBLOCK_FLAG
+ // The pipe connected; change to pipe_nowait mode.
+ DWORD dwMode;
+ BOOL fSuccess = FALSE;
+ dwMode = PIPE_READMODE_BYTE|PIPE_NOWAIT;
+
+ fSuccess = SetNamedPipeHandleState(
+ m_hpipe, // pipe handle
+ &dwMode, // new pipe mode
+ NULL, // don't set maximum bytes
+ NULL); // don't set maximum time
+ if ( ! fSuccess)
+ {
+ #ifdef CATCHCOPY_EXPLORER_PLUGIN_DEBUG
+ char error_str[1024];
+ sprintf(error_str, "SetNamedPipeHandleState failed. GLE=%d\n", ::GetLastError() );
+ MessageBoxA( NULL, error_str,"SetNamedPipeHandleState error", MB_OK);
+ #endif // CATCHCOPY_EXPLORER_PLUGIN_DEBUG
+ return false;
+ }
+ #endif //NONBLOCK_FLAG
+ }
+ #ifdef CATCHCOPY_EXPLORER_PLUGIN_DEBUG
+ MessageBox(NULL,L"The explorer is now connected to the catchcopy compatible application",L"Checking", MB_OK);
+ #endif // CATCHCOPY_EXPLORER_PLUGIN_DEBUG
+
+ bool f = sendProtocol();
+ if(f!=true)
+ return false;
+ #if defined(_M_X64)
+ setClientName(L"Windows Explorer 64Bits");
+ #else
+ setClientName(L"Windows Explorer 32Bits");
+ #endif
+ return true;
+}
+
+void ClientCatchcopy::disconnectFromServer()
+{
+ clear();
+ if(m_hpipe!=NULL)
+ {
+ /* needed to not crash the server when have data to read */
+ FlushFileBuffers(m_hpipe);
+ CloseHandle(m_hpipe);
+ m_hpipe=NULL;
+ #ifdef CATCHCOPY_EXPLORER_PLUGIN_DEBUG
+ MessageBox(NULL, L"The explorer is now disconnected of the catchcopy compatible application",L"Checking", MB_OK);
+ #endif // CATCHCOPY_EXPLORER_PLUGIN_DEBUG
+ }
+}
+
+/// \brief to send order
+bool ClientCatchcopy::sendProtocol()
+{
+ CDeque data;
+ data.push_back(L"protocol");
+ data.push_back(L"0002");
+ return sendRawOrderList(data);
+}
+
+bool ClientCatchcopy::setClientName(wchar_t *name)
+{
+ CDeque data;
+ data.push_back(L"client");
+ data.push_back(name);
+ return sendRawOrderList(data);
+}
+
+bool ClientCatchcopy::addCopyWithDestination(CDeque sources,wchar_t *destination)
+{
+ sources.push_front(L"cp");
+ sources.push_back(destination);
+ #ifdef CATCHCOPY_EXPLORER_PLUGIN_DEBUG
+ MessageBox(NULL, "sources size: "+sources.size()+", first: "+sources.at(0),L"Checking", MB_OK);
+ #endif // CATCHCOPY_EXPLORER_PLUGIN_DEBUG
+ return sendRawOrderList(sources);
+}
+
+bool ClientCatchcopy::addCopyWithoutDestination(CDeque sources)
+{
+ sources.push_front(L"cp-?");
+ #ifdef CATCHCOPY_EXPLORER_PLUGIN_DEBUG
+ MessageBox(NULL, "sources size: "+sources.size()+", first: "+sources.at(0),L"Checking", MB_OK);
+ #endif // CATCHCOPY_EXPLORER_PLUGIN_DEBUG
+ return sendRawOrderList(sources);
+}
+
+bool ClientCatchcopy::addMoveWithDestination(CDeque sources, wchar_t *destination)
+{
+ sources.push_front(L"mv");
+ sources.push_back(destination);
+ #ifdef CATCHCOPY_EXPLORER_PLUGIN_DEBUG
+ MessageBox(NULL, "sources size: "+sources.size()+", first: "+sources.at(0),L"Checking", MB_OK);
+ #endif // CATCHCOPY_EXPLORER_PLUGIN_DEBUG
+ return sendRawOrderList(sources);
+}
+
+bool ClientCatchcopy::addMoveWithoutDestination(CDeque sources)
+{
+ sources.push_front(L"mv-?");
+ #ifdef CATCHCOPY_EXPLORER_PLUGIN_DEBUG
+ MessageBox(NULL, "sources size: "+sources.size()+", first: "+sources.at(0),L"Checking", MB_OK);
+ #endif // CATCHCOPY_EXPLORER_PLUGIN_DEBUG
+ return sendRawOrderList(sources);
+}
+
+/// \brief to send stream of string list
+bool ClientCatchcopy::sendRawOrderList(CDeque order, bool first_try)
+{
+ if(m_hpipe!=NULL)
+ {
+ int data_size=sizeof(int)*3;
+ for(int i=0;i<order.size();i++)
+ {
+ if (order.at(i) == NULL)
+ continue;
+
+ data_size+=(int)sizeof(int);
+ data_size+=(int)sizeof(wchar_t)*(int)wcslen(order.at(i));
+ }
+ addInt32(data_size);
+ addInt32(idNextOrder++);
+ addInt32((int)order.size());
+ for(int i=0;i<order.size();i++)
+ {
+ if (order.at(i) == NULL)
+ continue;
+
+ //set string contenant
+ addStr(order.at(i));
+ }
+ if(dataToPipe()<0)
+ {
+ if(first_try)
+ {
+ disconnectFromServer();
+ connectToServer();
+ return sendRawOrderList(order,false);
+ }
+ else
+ clear();
+ }
+ return true;
+ }
+ else
+ {
+ clear();
+ return false;
+ }
+}
+
+// Send data block to named pipe
+int ClientCatchcopy::dataToPipe()
+{
+ byte_t *ptr;
+ int ret=0, max;
+ if (m_hpipe!=NULL)
+ {
+ ptr = m_blk;
+ while (!ret && m_len)
+ {
+ max=(m_len>BUFFER_PIPE) ? BUFFER_PIPE:m_len;
+ #ifdef NONBLOCK_FLAG
+ writePipe_nonBlock(m_hpipe, ptr, max);
+ break;
+ #else
+ if(writePipe(m_hpipe, ptr, max)!=0)
+ {
+ ret=-2;
+ break;
+ }
+ m_len-=max;
+ ptr+=max;
+ #endif
+ }
+ }
+ return ret;
+}
+
+int ClientCatchcopy::writePipe(HANDLE hPipe, byte_t *ptr, int len)
+{
+ DWORD cbWritten;
+ if (!WriteFile(hPipe, ptr, len, &cbWritten, NULL))
+ return -4;
+ return 0;
+}
+
+#ifdef NONBLOCK_FLAG
+int ClientCatchcopy::writePipe_nonBlock(HANDLE hPipe, byte_t *ptr, int len)
+{
+ DWORD cbWritten;
+ WriteFile(hPipe, ptr, len, &cbWritten, NULL);
+ return 0;
+}
+#endif
+
+// Add int32 (big-endian) into binary block
+int ClientCatchcopy::addInt32(int value)
+{
+ blkGrowing(sizeof(int));
+ // add value
+ setInt32(m_len, value);
+ m_len+=sizeof(int);
+ return m_len-sizeof(int);
+}
+
+void ClientCatchcopy::setInt32(int offset, int value)
+{
+ C_INT(m_blk+offset)=htonl(value);
+}
+
+// Add unicode string into binary block from ASCIIZ
+int ClientCatchcopy::addStr(WCHAR *data)
+{
+ int ret=-1, len;
+ WCHAR *x;
+ if (data!=NULL && *data)
+ {
+ // le => be
+ x = _wcsdup(data);
+ len = toBigEndian(x);
+ // set size of string
+ ret = addInt32(len);
+ // and add it to block
+ blkGrowing(len);
+ memmove(m_blk+m_len, x, len);
+ m_len+=len;
+ free(x);
+ }
+ return ret;
+}
+
+// resize binary block (if needed)
+byte_t *ClientCatchcopy::blkGrowing(int added)
+{
+ if (m_len+added>m_tot)
+ {
+ // check if added isn't bigger than buffer itself...
+ m_tot+= (added>BLOCK_SIZ) ? added:BLOCK_SIZ;
+ m_blk = (byte_t *) realloc(m_blk, m_tot);
+ }
+ return m_blk+m_len;
+}
+
+int ClientCatchcopy::toBigEndian(WCHAR *p)
+{
+ WCHAR tmp;
+ int ret=0;
+ while(*p)
+ {
+ tmp = htons(*p);
+ *p++=tmp;
+ ret+=2;
+ }
+ return ret;
+}
+
+void ClientCatchcopy::clear()
+{
+ m_tot=0;
+ m_len=0;
+ idNextOrder=0;
+ if (m_blk!=NULL)
+ {
+ free(m_blk);
+ m_blk=NULL;
+ }
+}
+
+bool ClientCatchcopy::isConnected()
+{
+ if(m_hpipe==NULL)
+ return false;
+
+ bool fSuccess = PeekNamedPipe(
+ m_hpipe,
+ NULL,
+ 0,
+ 0,
+ 0,
+ 0
+ );
+
+ if(!fSuccess && GetLastError() != ERROR_MORE_DATA)
+ {
+ #ifdef CATCHCOPY_EXPLORER_PLUGIN_DEBUG
+ void* lpBuffer;
+ FormatMessage( FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM,
+ NULL,
+ ::GetLastError(),
+ MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), // Default language
+ (LPTSTR) &lpBuffer,
+ 0,
+ NULL );
+ MessageBox(NULL,(LPCTSTR)lpBuffer, L"Error detected with the connexion", MB_OK);
+ LocalFree( lpBuffer );
+ #endif // CATCHCOPY_EXPLORER_PLUGIN_DEBUG
+ disconnectFromServer();
+ return false;
+ }
+ else
+ return true;
+}
diff --git a/catchcopy-windows-explorer-plugin/ClientCatchcopy.h b/catchcopy-windows-explorer-plugin/ClientCatchcopy.h
new file mode 100755
index 0000000..954bff7
--- /dev/null
+++ b/catchcopy-windows-explorer-plugin/ClientCatchcopy.h
@@ -0,0 +1,68 @@
+/** \file ClientCatchcopy.h
+\brief Define the catchcopy client
+\author alpha_one_x86
+\version 0002
+\date 2010 */
+
+#ifndef CLIENTCATCHCOPY_H
+#define CLIENTCATCHCOPY_H
+
+#define NONBLOCK_FLAG
+#define BUFSIZE 512
+#define S_LEN 8
+
+#define C_INT(p) *((int *) (p))
+#define BLOCK_SIZ 64000
+#define BUFFER_PIPE 32000
+
+#include <windows.h>
+#include <string>
+#include <deque>
+#include <stdlib.h>
+
+#include "Variable.h"
+#include "Deque.h"
+
+typedef unsigned char byte_t;
+
+class ClientCatchcopy
+{
+ public:
+ ClientCatchcopy();
+ ~ClientCatchcopy();
+ bool connectToServer();
+ void disconnectFromServer();
+ /// \brief to send order
+ bool sendProtocol();
+ bool setClientName(wchar_t *name);
+ bool addCopyWithDestination(CDeque sources,wchar_t *destination);
+ bool addCopyWithoutDestination(CDeque sources);
+ bool addMoveWithDestination(CDeque sources,wchar_t *destination);
+ bool addMoveWithoutDestination(CDeque sources);
+ /// \brief to send stream of string list
+ bool sendRawOrderList(CDeque order,bool first_try=true);
+ bool isConnected();
+ private:
+ HANDLE m_hpipe;
+ unsigned int idNextOrder;
+ char *m_pipename;
+ byte_t *m_blk;
+ int m_tot;
+ int m_len;
+
+ char * toHex(const char *str);
+ int dataToPipe();
+ int addInt32(int value);
+ int addStr(WCHAR *data);
+ byte_t *blkGrowing(int added);
+ void setInt32(int offset, int value);
+ int toBigEndian(WCHAR *p);
+ void clear();
+ int writePipe(HANDLE hPipe, byte_t *ptr, int len);
+ #ifdef NONBLOCK_FLAG
+ int writePipe_nonBlock(HANDLE hPipe, byte_t *ptr, int len);
+ #endif
+ bool canConnect;
+};
+
+#endif // CLIENTCATCHCOPY_H
diff --git a/catchcopy-windows-explorer-plugin/DDShellExt.cpp b/catchcopy-windows-explorer-plugin/DDShellExt.cpp
new file mode 100755
index 0000000..25142d5
--- /dev/null
+++ b/catchcopy-windows-explorer-plugin/DDShellExt.cpp
@@ -0,0 +1,188 @@
+// DDShellExt.cpp : Implementation of CDDShellExt
+
+#include "tchar.h"
+#include "DDShellExt.h"
+#include "ClientCatchcopy.h"
+
+#include <Shlwapi.h>
+
+extern HINSTANCE g_hInst;
+extern long g_cDllRef;
+
+CDDShellExt::CDDShellExt(): m_cRef(1)
+{
+ InterlockedIncrement(&g_cDllRef);
+}
+
+CDDShellExt::~CDDShellExt()
+{
+ InterlockedDecrement(&g_cDllRef);
+}
+
+// Query to the interface the component supported.
+IFACEMETHODIMP CDDShellExt::QueryInterface(REFIID riid, void **ppv)
+{
+ if(riid == IID_IUnknown || riid == IID_IContextMenu)
+ {
+ *ppv = static_cast<IContextMenu*>(this);
+ }
+ else if (riid == IID_IShellExtInit)
+ {
+ *ppv = static_cast<IShellExtInit*>(this);
+ }
+ else
+ {
+ *ppv = NULL;
+ return E_NOINTERFACE;
+ }
+ reinterpret_cast<IUnknown*>(*ppv)->AddRef();
+ return S_OK;
+}
+
+// Increase the reference count for an interface on an object.
+IFACEMETHODIMP_(ULONG) CDDShellExt::AddRef()
+{
+ return InterlockedIncrement(&m_cRef);
+}
+
+// Decrease the reference count for an interface on an object.
+IFACEMETHODIMP_(ULONG) CDDShellExt::Release()
+{
+ ULONG cRef = InterlockedDecrement(&m_cRef);
+ if (0 == cRef)
+ delete this;
+ return cRef;
+}
+
+STDMETHODIMP CDDShellExt::Initialize(LPCITEMIDLIST pidlFolder,LPDATAOBJECT pDO,HKEY hProgID)
+{
+ (void)hProgID;
+ if(!connected)
+ {
+ bool b = m_ac.connectToServer();
+
+ if (b==true)
+ {
+ connected=true;
+ }
+ else
+ return E_FAIL;
+ }
+
+ FORMATETC fmt={CF_HDROP,NULL,DVASPECT_CONTENT,-1,TYMED_HGLOBAL};
+ STGMEDIUM stg={TYMED_HGLOBAL};
+ HDROP hDrop;
+
+ fDestDir[0]=0;
+ if (!SHGetPathFromIDList(pidlFolder,fDestDir))
+ {
+ #ifdef CATCHCOPY_EXPLORER_PLUGIN_DEBUG
+ MessageBox(NULL,L"Initialize",L"E_FAIL 1",MB_OK);
+ #endif // CATCHCOPY_EXPLORER_PLUGIN_DEBUG
+ return E_FAIL;
+ }
+
+ // Detect if it's explorer that started the operation by enumerating available
+ // clipboard formats and searching for one that only explorer uses
+ IEnumFORMATETC *en;
+ FORMATETC fmt2;
+ WCHAR fmtName[65535]=L"\0";
+ fFromExplorer=false;
+ pDO->EnumFormatEtc(DATADIR_GET,&en);
+ while(en->Next(1,&fmt2,NULL)==S_OK){
+ GetClipboardFormatName(fmt2.cfFormat,fmtName,sizeof(fmtName));
+ if (!wcscmp(fmtName,CFSTR_SHELLIDLIST)) fFromExplorer=true;
+ }
+ en->Release();
+
+ // Look for CF_HDROP data in the data object. If there
+ // is no such data, return an error back to Explorer.
+ if (FAILED(pDO->GetData(&fmt,&stg)))
+ {
+ #ifdef CATCHCOPY_EXPLORER_PLUGIN_DEBUG
+ MessageBox(NULL,L"Initialize",L"E_INVALIDARG 2",MB_OK);
+ #endif // CATCHCOPY_EXPLORER_PLUGIN_DEBUG
+ return E_INVALIDARG;
+ }
+
+ // Get a pointer to the actual data.
+ hDrop=(HDROP)GlobalLock(stg.hGlobal);
+
+ // Make sure it worked.
+ if (hDrop==NULL)
+ {
+ #ifdef CATCHCOPY_EXPLORER_PLUGIN_DEBUG
+ MessageBox(NULL,L"Initialize",L"E_INVALIDARG 1",MB_OK);
+ #endif // CATCHCOPY_EXPLORER_PLUGIN_DEBUG
+ return E_INVALIDARG;
+ }
+
+ UINT numFiles,i;
+ WCHAR fn[MAX_PATH]=L"";
+
+ numFiles=DragQueryFile(hDrop,0xFFFFFFFF,NULL,0);
+
+ if (numFiles)
+ {
+ for(i=0;i<numFiles;++i)
+ {
+ if(DragQueryFile(hDrop,i,fn,MAX_PATH))
+ sources.push_back(fn);
+ }
+ }
+
+ GlobalUnlock(stg.hGlobal);
+ ReleaseStgMedium(&stg);
+
+ return S_OK;
+}
+
+STDMETHODIMP CDDShellExt::QueryContextMenu(HMENU hmenu,UINT uMenuIndex,UINT uidFirstCmd,UINT uidLastCmd,UINT uFlags)
+{
+ (void)uidLastCmd;
+ if(!m_ac.isConnected())
+ {
+ if(!m_ac.connectToServer())
+ return E_FAIL;
+ }
+ if (uFlags&CMF_DEFAULTONLY)
+ return MAKE_HRESULT(SEVERITY_SUCCESS,FACILITY_NULL,0);
+
+ int x=uidFirstCmd;
+
+ InsertMenu(hmenu,uMenuIndex++,MF_STRING|MF_BYPOSITION,x++,L"Copy with advanced software");
+ InsertMenu(hmenu,uMenuIndex++,MF_STRING|MF_BYPOSITION,x++,L"Move with advanced software");
+
+ int defItem=GetMenuDefaultItem(hmenu,false,0);
+ if (defItem==1) // 1: Copy
+ {
+ if (fFromExplorer)
+ SetMenuDefaultItem(hmenu,uidFirstCmd,false);
+ }
+ else if (defItem==2) //2: Move
+ {
+ SetMenuDefaultItem(hmenu,uidFirstCmd+1,false);
+ }
+ return MAKE_HRESULT(SEVERITY_SUCCESS,FACILITY_NULL,2);
+}
+
+
+STDMETHODIMP CDDShellExt::InvokeCommand ( LPCMINVOKECOMMANDINFO pInfo )
+{
+ if(HIWORD(pInfo->lpVerb))
+ return E_INVALIDARG;
+ switch(LOWORD(pInfo->lpVerb))
+ {
+ case 0:// copy
+ if(!m_ac.addCopyWithDestination(sources,fDestDir))
+ return E_FAIL;
+ break;
+ case 1:// move
+ if(!m_ac.addMoveWithDestination(sources,fDestDir))
+ return E_FAIL;
+ break;
+ default :
+ return S_OK;
+ }
+ return S_OK;
+}
diff --git a/catchcopy-windows-explorer-plugin/DDShellExt.h b/catchcopy-windows-explorer-plugin/DDShellExt.h
new file mode 100755
index 0000000..9e9f68f
--- /dev/null
+++ b/catchcopy-windows-explorer-plugin/DDShellExt.h
@@ -0,0 +1,46 @@
+// DDShellExt.h : Declaration of the CDDShellExt
+
+#pragma once
+#include "resource.h" // main symbols
+#include "shlobj.h"
+#include "ClientCatchcopy.h"
+#include "Variable.h"
+#include "Deque.h"
+
+static bool connected=false;
+static ClientCatchcopy m_ac;
+
+// CDDShellExt
+
+extern const CLSID CLSID_DDShellExt;
+
+class CDDShellExt :
+ public IShellExtInit,
+ public IContextMenu
+{
+private:
+ static int fBaselistHandle;
+ bool fFromExplorer;
+ WCHAR fDestDir[MAX_PATH];
+ //static ClientCatchcopy m_ac;
+ CDeque sources;
+ //static bool connected;
+
+ // Reference count of component.
+ long m_cRef;
+public:
+ // IUnknown
+ IFACEMETHODIMP QueryInterface(REFIID riid, void **ppv);
+ IFACEMETHODIMP_(ULONG) AddRef();
+ IFACEMETHODIMP_(ULONG) Release();
+
+ // IShellExtInit
+ STDMETHODIMP Initialize(LPCITEMIDLIST, LPDATAOBJECT, HKEY);
+
+ CDDShellExt(void);
+ ~CDDShellExt(void);
+ // IContextMenu
+ STDMETHODIMP GetCommandString(UINT_PTR idCmd,UINT uFlags,UINT* pwReserved,LPSTR pszName,UINT cchMax){(void)idCmd;(void)uFlags;(void)pwReserved;(void)pszName;(void)cchMax;(void)connected;return E_NOTIMPL;};
+ STDMETHODIMP InvokeCommand(LPCMINVOKECOMMANDINFO);
+ STDMETHODIMP QueryContextMenu(HMENU,UINT,UINT,UINT,UINT);
+};
diff --git a/catchcopy-windows-explorer-plugin/Deque.cpp b/catchcopy-windows-explorer-plugin/Deque.cpp
new file mode 100755
index 0000000..93a9fcb
--- /dev/null
+++ b/catchcopy-windows-explorer-plugin/Deque.cpp
@@ -0,0 +1,100 @@
+#include "Deque.h"
+#include <windows.h>
+
+CDeque::CDeque(void)
+{
+ top1=0;
+ top2=0;
+ head=NULL;
+ tail=NULL;
+}
+
+CDeque::~CDeque(void)
+{
+}
+
+void CDeque::push_front(wchar_t *str)
+{
+ CNode *temp;
+ if(top1+top2 >= MAX_DEQUE)
+ {
+ return ;
+ }
+
+ if(top1+top2 == 0)
+ {
+ head = new CNode;
+ wcscpy(head->str, str);
+ head->next=NULL;
+ head->prev=NULL;
+ tail=head;
+ top1++;
+ }
+ else
+ {
+ top1++;
+ temp=new CNode;
+ wcscpy(temp->str, str);
+ temp->next=head;
+ temp->prev=NULL;
+ head->prev=temp;
+ head=temp;
+ }
+}
+
+void CDeque::push_back(wchar_t *str)
+{
+ CNode *temp;
+ if(top1+top2 >= MAX_DEQUE)
+ {
+ return ;
+ }
+ if(top1+top2 == 0)
+ {
+ head = new CNode;
+ wcscpy(head->str, str);
+ head->next=NULL;
+ head->prev=NULL;
+ tail=head;
+ top1++;
+ }
+ else
+ {
+ top2++;
+ temp=new CNode;
+ wcscpy(temp->str, str);
+ temp->next=NULL;
+ temp->prev=tail;
+ tail->next=temp;
+ tail=temp;
+ }
+}
+
+int CDeque::size()
+{
+ return top1 + top2;
+}
+
+wchar_t *CDeque::at(int pos)
+{
+ int i=0;
+ CNode *temp;
+
+ if(top1+top2 <= 0)
+ {
+ return NULL;
+ }
+
+ temp=head;
+ while(temp!=NULL)
+ {
+ if(i==pos)
+ return temp->str;
+
+ temp=temp->next;
+
+ i++;
+ }
+
+ return NULL;
+}
diff --git a/catchcopy-windows-explorer-plugin/Deque.h b/catchcopy-windows-explorer-plugin/Deque.h
new file mode 100755
index 0000000..e0e1f28
--- /dev/null
+++ b/catchcopy-windows-explorer-plugin/Deque.h
@@ -0,0 +1,29 @@
+#pragma once
+
+#define MAX_STR_LEN 512
+#define MAX_DEQUE 512
+
+class CNode
+{
+public:
+ wchar_t str[MAX_STR_LEN];
+ class CNode *next;
+ class CNode *prev;
+};
+
+class CDeque : public CNode
+{
+public:
+ CDeque(void);
+ ~CDeque(void);
+
+private:
+ CNode *head,*tail;
+ int top1,top2;
+
+public:
+ void push_front(wchar_t *str);
+ void push_back(wchar_t *str);
+ int size();
+ wchar_t *at(int pos);
+};
diff --git a/catchcopy-windows-explorer-plugin/Reg.cpp b/catchcopy-windows-explorer-plugin/Reg.cpp
new file mode 100755
index 0000000..37f7cc1
--- /dev/null
+++ b/catchcopy-windows-explorer-plugin/Reg.cpp
@@ -0,0 +1,403 @@
+#include "Reg.h"
+#include <strsafe.h>
+
+//
+// FUNCTION: SetHKCRRegistryKeyAndValue
+//
+// PURPOSE: The function creates a HKCR registry key and sets the specified
+// registry value.
+//
+// PARAMETERS:
+// * pszSubKey - specifies the registry key under HKCR. If the key does not
+// exist, the function will create the registry key.
+// * pszValueName - specifies the registry value to be set. If pszValueName
+// is NULL, the function will set the default value.
+// * pszData - specifies the string data of the registry value.
+//
+// RETURN VALUE:
+// If the function succeeds, it returns S_OK. Otherwise, it returns an
+// HRESULT error code.
+//
+HRESULT SetHKCRRegistryKeyAndValue(PCWSTR pszSubKey, PCWSTR pszValueName,
+ PCWSTR pszData)
+{
+ HRESULT hr;
+ HKEY hKey = NULL;
+
+ // Creates the specified registry key. If the key already exists, the
+ // function opens it.
+ hr = HRESULT_FROM_WIN32(RegCreateKeyEx(
+ #ifdef CATCHCOPY_ROOT_MODE
+ HKEY_CLASSES_ROOT
+ #else
+ HKEY_CURRENT_USER
+ #endif
+ , pszSubKey, 0,
+ NULL, REG_OPTION_NON_VOLATILE, KEY_ALL_ACCESS | KEY_WOW64_64KEY, NULL, &hKey, NULL));
+
+ if (SUCCEEDED(hr))
+ {
+ if (pszData != NULL)
+ {
+ // Set the specified value of the key.
+ DWORD cbData = lstrlen(pszData) * sizeof(*pszData);
+ hr = HRESULT_FROM_WIN32(RegSetValueEx(hKey, pszValueName, 0,
+ REG_SZ, reinterpret_cast<const BYTE *>(pszData), cbData));
+ }
+
+ RegCloseKey(hKey);
+ }
+
+ return hr;
+}
+
+LONG RecursiveDeleteKey(HKEY hKeyParent, PCWSTR szKeyChild)
+{
+ // Open the child.
+ HKEY hKeyChild ;
+ LONG lRes = RegOpenKeyEx(hKeyParent, szKeyChild, 0,
+ KEY_ALL_ACCESS | KEY_WOW64_64KEY, &hKeyChild) ;
+ if (lRes != ERROR_SUCCESS)
+ {
+ return lRes ;
+ }
+ // Enumerate all of the decendents of this child.
+ FILETIME time ;
+ wchar_t szBuffer[MAX_PATH];
+ DWORD dwSize = MAX_PATH ;
+ while (RegEnumKeyEx(hKeyChild, 0, (LPWSTR)szBuffer, &dwSize, NULL,
+ NULL, NULL, &time) == ERROR_SUCCESS)
+ {
+ // Delete the decendents of this child.
+ lRes = RecursiveDeleteKey(hKeyChild, (PCWSTR)szBuffer) ;
+ if (lRes != ERROR_SUCCESS)
+ {
+ // Cleanup before exiting.
+ RegCloseKey(hKeyChild) ;
+ return lRes;
+ }
+ dwSize = MAX_PATH ;
+ }
+
+ // Close the child.
+ RegCloseKey(hKeyChild) ;
+
+ // Delete this child.
+ return RegDeleteKey(hKeyParent, szKeyChild) ;
+}
+
+//
+// FUNCTION: GetHKCRRegistryKeyAndValue
+//
+// PURPOSE: The function opens a HKCR registry key and gets the data for the
+// specified registry value name.
+//
+// PARAMETERS:
+// * pszSubKey - specifies the registry key under HKCR. If the key does not
+// exist, the function returns an error.
+// * pszValueName - specifies the registry value to be retrieved. If
+// pszValueName is NULL, the function will get the default value.
+// * pszData - a pointer to a buffer that receives the value's string data.
+// * cbData - specifies the size of the buffer in bytes.
+//
+// RETURN VALUE:
+// If the function succeeds, it returns S_OK. Otherwise, it returns an
+// HRESULT error code. For example, if the specified registry key does not
+// exist or the data for the specified value name was not set, the function
+// returns COR_E_FILENOTFOUND (0x80070002).
+//
+HRESULT GetHKCRRegistryKeyAndValue(PCWSTR pszSubKey, PCWSTR pszValueName,
+ PWSTR pszData, DWORD cbData)
+{
+ HRESULT hr;
+ HKEY hKey = NULL;
+
+ // Try to open the specified registry key.
+ hr = HRESULT_FROM_WIN32(RegOpenKeyEx(
+ #ifdef CATCHCOPY_ROOT_MODE
+ HKEY_CLASSES_ROOT
+ #else
+ HKEY_CURRENT_USER
+ #endif
+ , pszSubKey, 0,
+ KEY_READ, &hKey));
+
+ if (SUCCEEDED(hr))
+ {
+ // Get the data for the specified value name.
+ hr = HRESULT_FROM_WIN32(RegQueryValueEx(hKey, pszValueName, NULL,
+ NULL, reinterpret_cast<LPBYTE>(pszData), &cbData));
+
+ RegCloseKey(hKey);
+ }
+
+ return hr;
+}
+
+//
+// FUNCTION: RegisterInprocServer
+//
+// PURPOSE: Register the in-process component in the registry.
+//
+// PARAMETERS:
+// * pszModule - Path of the module that contains the component
+// * clsid - Class ID of the component
+// * pszFriendlyName - Friendly name
+// * pszThreadModel - Threading model
+//
+// NOTE: The function creates the HKCR\CLSID\{<CLSID>} key in the registry.
+//
+// HKCR
+// {
+// NoRemove CLSID
+// {
+// ForceRemove {<CLSID>} = s '<Friendly Name>'
+// {
+// InprocServer32 = s '%MODULE%'
+// {
+// val ThreadingModel = s '<Thread Model>'
+// }
+// }
+// }
+// }
+//
+HRESULT RegisterInprocServer(PCWSTR pszModule, const CLSID& clsid, PCWSTR pszFriendlyName, PCWSTR pszThreadModel)
+{
+ if (pszModule == NULL || pszThreadModel == NULL)
+ {
+ return E_INVALIDARG;
+ }
+
+ HRESULT hr;
+
+ wchar_t szCLSID[MAX_PATH];
+ StringFromGUID2(clsid, szCLSID, ARRAYSIZE(szCLSID));
+
+ wchar_t szSubkey[MAX_PATH];
+
+ // Create the HKCR\CLSID\{<CLSID>} key.
+ hr = StringCchPrintf(szSubkey, ARRAYSIZE(szSubkey),
+ #ifdef CATCHCOPY_ROOT_MODE
+ L"CLSID\\%s"
+ #else
+ L"Software\\Classes\\CLSID\\%s"
+ #endif
+ , szCLSID);
+ if (SUCCEEDED(hr))
+ {
+ hr = SetHKCRRegistryKeyAndValue(szSubkey, NULL, pszFriendlyName);
+
+ // Create the HKCR\CLSID\{<CLSID>}\InprocServer32 key.
+ if (SUCCEEDED(hr))
+ {
+ hr = StringCchPrintf(szSubkey, ARRAYSIZE(szSubkey),
+ #ifdef CATCHCOPY_ROOT_MODE
+ L"CLSID\\%s\\InprocServer32"
+ #else
+ L"Software\\Classes\\CLSID\\%s\\InprocServer32"
+ #endif
+ , szCLSID);
+ if (SUCCEEDED(hr))
+ {
+ // Set the default value of the InprocServer32 key to the
+ // path of the COM module.
+ hr = SetHKCRRegistryKeyAndValue(szSubkey, NULL, pszModule);
+ if (SUCCEEDED(hr))
+ {
+ // Set the threading model of the component.
+ hr = SetHKCRRegistryKeyAndValue(szSubkey, L"ThreadingModel", pszThreadModel);
+ }
+ }
+ }
+ }
+
+ return hr;
+}
+
+
+//
+// FUNCTION: UnregisterInprocServer
+//
+// PURPOSE: Unegister the in-process component in the registry.
+//
+// PARAMETERS:
+// * clsid - Class ID of the component
+//
+// NOTE: The function deletes the HKCR\CLSID\{<CLSID>} key in the registry.
+//
+HRESULT UnregisterInprocServer(const CLSID& clsid)
+{
+ HRESULT hr = S_OK;
+
+ wchar_t szCLSID[MAX_PATH];
+ StringFromGUID2(clsid, szCLSID, ARRAYSIZE(szCLSID));
+
+ wchar_t szSubkey[MAX_PATH];
+
+ // Delete the HKCR\CLSID\{<CLSID>} key.
+ hr = StringCchPrintf(szSubkey, ARRAYSIZE(szSubkey),
+ #ifdef CATCHCOPY_ROOT_MODE
+ L"CLSID\\%s"
+ #else
+ L"Software\\Classes\\CLSID\\%s"
+ #endif
+ , szCLSID);
+
+ if (SUCCEEDED(hr))
+ {
+ hr = HRESULT_FROM_WIN32(RecursiveDeleteKey(
+ #ifdef CATCHCOPY_ROOT_MODE
+ HKEY_CLASSES_ROOT
+ #else
+ HKEY_CURRENT_USER
+ #endif
+ , szSubkey));
+ }
+
+ return hr;
+}
+//
+// FUNCTION: RegisterShellExtContextMenuHandler
+//
+// PURPOSE: Register the context menu handler.
+//
+// PARAMETERS:
+// * pszFileType - The file type that the context menu handler is
+// associated with. For example, '*' means all file types; '.txt' means
+// all .txt files. The parameter must not be NULL.
+// * clsid - Class ID of the component
+// * pszFriendlyName - Friendly name
+//
+// NOTE: The function creates the following key in the registry.
+//
+// HKCR
+// {
+// NoRemove <File Type>
+// {
+// NoRemove shellex
+// {
+// NoRemove ContextMenuHandlers
+// {
+// {<CLSID>} = s '<Friendly Name>'
+// }
+// }
+// }
+// }
+//
+HRESULT RegisterShellExtContextMenuHandler(
+ PCWSTR pszFileType, const CLSID& clsid, PCWSTR pszFriendlyName)
+{
+ if (pszFileType == NULL)
+ {
+ return E_INVALIDARG;
+ }
+
+ HRESULT hr;
+
+ wchar_t szCLSID[MAX_PATH];
+ StringFromGUID2(clsid, szCLSID, ARRAYSIZE(szCLSID));
+
+ wchar_t szSubkey[MAX_PATH];
+
+ // If pszFileType starts with '.', try to read the default value of the
+ // HKCR\<File Type> key which contains the ProgID to which the file type
+ // is linked.
+ if (*pszFileType == L'.')
+ {
+ wchar_t szDefaultVal[260];
+ hr = GetHKCRRegistryKeyAndValue(pszFileType, NULL, szDefaultVal,
+ sizeof(szDefaultVal));
+
+ // If the key exists and its default value is not empty, use the
+ // ProgID as the file type.
+ if (SUCCEEDED(hr) && szDefaultVal[0] != L'\0')
+ {
+ pszFileType = szDefaultVal;
+ }
+ }
+
+ // Create the key HKCR\<File Type>\shellex\DragDropHandlers\{<CLSID>}
+ hr = StringCchPrintf(szSubkey, ARRAYSIZE(szSubkey),
+ #ifdef CATCHCOPY_ROOT_MODE
+ L"%s\\shellex\\DragDropHandlers\\%s"
+ #else
+ L"Software\\Classes\\%s\\shellex\\DragDropHandlers\\%s"
+ #endif
+ , pszFileType, szCLSID);
+ if (SUCCEEDED(hr))
+ {
+ // Set the default value of the key.
+ hr = SetHKCRRegistryKeyAndValue(szSubkey, NULL, pszFriendlyName);
+ }
+
+ return hr;
+}
+
+
+//
+// FUNCTION: UnregisterShellExtContextMenuHandler
+//
+// PURPOSE: Unregister the context menu handler.
+//
+// PARAMETERS:
+// * pszFileType - The file type that the context menu handler is
+// associated with. For example, '*' means all file types; '.txt' means
+// all .txt files. The parameter must not be NULL.
+// * clsid - Class ID of the component
+//
+// NOTE: The function removes the {<CLSID>} key under
+// HKCR\<File Type>\shellex\ContextMenuHandlers in the registry.
+//
+HRESULT UnregisterShellExtContextMenuHandler(
+ PCWSTR pszFileType, const CLSID& clsid)
+{
+ if (pszFileType == NULL)
+ {
+ return E_INVALIDARG;
+ }
+
+ HRESULT hr;
+
+ wchar_t szCLSID[MAX_PATH];
+ StringFromGUID2(clsid, szCLSID, ARRAYSIZE(szCLSID));
+
+ wchar_t szSubkey[MAX_PATH];
+
+ // If pszFileType starts with '.', try to read the default value of the
+ // HKCR\<File Type> key which contains the ProgID to which the file type
+ // is linked.
+ if (*pszFileType == L'.')
+ {
+ wchar_t szDefaultVal[260];
+ hr = GetHKCRRegistryKeyAndValue(pszFileType, NULL, szDefaultVal,
+ sizeof(szDefaultVal));
+
+ // If the key exists and its default value is not empty, use the
+ // ProgID as the file type.
+ if (SUCCEEDED(hr) && szDefaultVal[0] != L'\0')
+ {
+ pszFileType = szDefaultVal;
+ }
+ }
+
+ // Remove the HKCR\<File Type>\shellex\DragDropHandlers\{<CLSID>} key.
+ hr = StringCchPrintf(szSubkey, ARRAYSIZE(szSubkey),
+ #ifdef CATCHCOPY_ROOT_MODE
+ L"%s\\shellex\\DragDropHandlers\\%s"
+ #else
+ L"Software\\Classes\\%s\\shellex\\DragDropHandlers\\%s"
+ #endif
+ , pszFileType, szCLSID);
+ if (SUCCEEDED(hr))
+ {
+ hr = HRESULT_FROM_WIN32(RecursiveDeleteKey(
+ #ifdef CATCHCOPY_ROOT_MODE
+ HKEY_CLASSES_ROOT
+ #else
+ HKEY_CURRENT_USER
+ #endif
+ , szSubkey));
+ }
+
+ return hr;
+}
diff --git a/catchcopy-windows-explorer-plugin/Reg.h b/catchcopy-windows-explorer-plugin/Reg.h
new file mode 100755
index 0000000..6bc9a26
--- /dev/null
+++ b/catchcopy-windows-explorer-plugin/Reg.h
@@ -0,0 +1,103 @@
+#ifndef _REG_H_
+#define _REG_H_
+#pragma once
+
+//#define CATCHCOPY_ROOT_MODE
+
+#include <windows.h>
+#include <winreg.h>
+//
+// FUNCTION: RegisterInprocServer
+//
+// PURPOSE: Register the in-process component in the registry.
+//
+// PARAMETERS:
+// * pszModule - Path of the module that contains the component
+// * clsid - Class ID of the component
+// * pszFriendlyName - Friendly name
+// * pszThreadModel - Threading model
+//
+// NOTE: The function creates the HKCR\CLSID\{<CLSID>} key in the registry.
+//
+// HKCR
+// {
+// NoRemove CLSID
+// {
+// ForceRemove {<CLSID>} = s '<Friendly Name>'
+// {
+// InprocServer32 = s '%MODULE%'
+// {
+// val ThreadingModel = s '<Thread Model>'
+// }
+// }
+// }
+// }
+//
+HRESULT RegisterInprocServer(PCWSTR pszModule, const CLSID& clsid,
+ PCWSTR pszFriendlyName, PCWSTR pszThreadModel);
+
+
+//
+// FUNCTION: UnregisterInprocServer
+//
+// PURPOSE: Unegister the in-process component in the registry.
+//
+// PARAMETERS:
+// * clsid - Class ID of the component
+//
+// NOTE: The function deletes the HKCR\CLSID\{<CLSID>} key in the registry.
+//
+HRESULT UnregisterInprocServer(const CLSID& clsid);
+
+
+//
+// FUNCTION: RegisterShellExtContextMenuHandler
+//
+// PURPOSE: Register the context menu handler.
+//
+// PARAMETERS:
+// * pszFileType - The file type that the context menu handler is
+// associated with. For example, '*' means all file types; '.txt' means
+// all .txt files. The parameter must not be NULL.
+// * clsid - Class ID of the component
+// * pszFriendlyName - Friendly name
+//
+// NOTE: The function creates the following key in the registry.
+//
+// HKCR
+// {
+// NoRemove <File Type>
+// {
+// NoRemove shellex
+// {
+// NoRemove ContextMenuHandlers
+// {
+// {<CLSID>} = s '<Friendly Name>'
+// }
+// }
+// }
+// }
+//
+HRESULT RegisterShellExtContextMenuHandler(
+ PCWSTR pszFileType, const CLSID& clsid, PCWSTR pszFriendlyName);
+
+
+//
+// FUNCTION: UnregisterShellExtContextMenuHandler
+//
+// PURPOSE: Unregister the context menu handler.
+//
+// PARAMETERS:
+// * pszFileType - The file type that the context menu handler is
+// associated with. For example, '*' means all file types; '.txt' means
+// all .txt files. The parameter must not be NULL.
+// * clsid - Class ID of the component
+//
+// NOTE: The function removes the {<CLSID>} key under
+// HKCR\<File Type>\shellex\ContextMenuHandlers in the registry.
+//
+HRESULT UnregisterShellExtContextMenuHandler(
+ PCWSTR pszFileType, const CLSID& clsid);
+
+LONG RecursiveDeleteKey(HKEY hKeyParent, PCWSTR szKeyChild);
+#endif //_REG_H_
diff --git a/catchcopy-windows-explorer-plugin/Variable.h b/catchcopy-windows-explorer-plugin/Variable.h
new file mode 100755
index 0000000..292e2a0
--- /dev/null
+++ b/catchcopy-windows-explorer-plugin/Variable.h
@@ -0,0 +1,7 @@
+#ifndef VARIABLE_H
+#define VARIABLE_H
+
+/// \brief Un-comment this next line to put ultracopier in debug mode
+//#define CATCHCOPY_EXPLORER_PLUGIN_DEBUG
+
+#endif // VARIABLE_H
diff --git a/catchcopy-windows-explorer-plugin/resource.h b/catchcopy-windows-explorer-plugin/resource.h
new file mode 100755
index 0000000..4823355
--- /dev/null
+++ b/catchcopy-windows-explorer-plugin/resource.h
@@ -0,0 +1,18 @@
+//{{NO_DEPENDENCIES}}
+// Microsoft Visual C++ generated include file.
+// Used by CatchCopy.rc
+//
+#define IDS_PROJNAME 100
+#define IDR_CATCHCOPY 101
+#define IDR_DDSHELLEXT 102
+
+// Next default values for new objects
+//
+#ifdef APSTUDIO_INVOKED
+#ifndef APSTUDIO_READONLY_SYMBOLS
+#define _APS_NEXT_RESOURCE_VALUE 201
+#define _APS_NEXT_COMMAND_VALUE 32768
+#define _APS_NEXT_CONTROL_VALUE 201
+#define _APS_NEXT_SYMED_VALUE 103
+#endif
+#endif