DragExt.cpp 21 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777
  1. //---------------------------------------------------------------------------
  2. #pragma hdrstop
  3. //---------------------------------------------------------------------------
  4. #ifndef STRICT
  5. #define STRICT
  6. #endif
  7. //---------------------------------------------------------------------------
  8. #ifdef MSVC
  9. #include <objbase.h>
  10. #define snprintf _snprintf
  11. #endif
  12. //---------------------------------------------------------------------------
  13. #include <initguid.h>
  14. #include <shlguid.h>
  15. #include <stdio.h>
  16. #include <shlobj.h>
  17. #include <olectl.h>
  18. #include <time.h>
  19. #include "DragExt.h"
  20. //---------------------------------------------------------------------------
  21. #ifdef __BORLANDC__
  22. #undef STDAPI
  23. #define STDAPI EXTERN_C __declspec(dllexport) HRESULT STDAPICALLTYPE
  24. #endif
  25. //---------------------------------------------------------------------------
  26. #define DEBUG(MSG) \
  27. if (GLogOn) \
  28. { \
  29. Debug(MSG); \
  30. }
  31. //---------------------------------------------------------------------------
  32. #define DRAG_EXT_REG_KEY "Software\\Martin Prikryl\\WinSCP 2\\DragExt"
  33. #define DRAG_EXT_NAME "WinSCP Shell Extension"
  34. #define THREADING_MODEL "Apartment"
  35. #define CLSID_SIZE 39
  36. //---------------------------------------------------------------------------
  37. class CShellExtClassFactory : public IClassFactory
  38. {
  39. public:
  40. CShellExtClassFactory();
  41. ~CShellExtClassFactory();
  42. // IUnknown members
  43. STDMETHODIMP QueryInterface(REFIID, LPVOID FAR*);
  44. STDMETHODIMP_(ULONG) AddRef();
  45. STDMETHODIMP_(ULONG) Release();
  46. // IClassFactory members
  47. STDMETHODIMP CreateInstance(LPUNKNOWN, REFIID, LPVOID FAR*);
  48. STDMETHODIMP LockServer(BOOL);
  49. protected:
  50. unsigned long FReferenceCounter;
  51. };
  52. //---------------------------------------------------------------------------
  53. class CShellExt : public IShellExtInit, ICopyHook
  54. {
  55. public:
  56. CShellExt();
  57. ~CShellExt();
  58. // IUnknown members
  59. STDMETHODIMP QueryInterface(REFIID, LPVOID FAR*);
  60. STDMETHODIMP_(ULONG) AddRef();
  61. STDMETHODIMP_(ULONG) Release();
  62. // IShellExtInit methods
  63. STDMETHODIMP Initialize(LPCITEMIDLIST pIDFolder, LPDATAOBJECT pDataObj, HKEY hKeyID);
  64. // ICopyHook method
  65. STDMETHODIMP_(UINT) CopyCallback(HWND Hwnd, UINT Func, UINT Flags,
  66. LPCSTR SrcFile, DWORD SrcAttribs, LPCSTR DestFile, DWORD DestAttribs);
  67. protected:
  68. unsigned long FReferenceCounter;
  69. LPDATAOBJECT FDataObj;
  70. HANDLE FMutex;
  71. unsigned long FLastTicks;
  72. };
  73. //---------------------------------------------------------------------------
  74. unsigned int GRefThisDll = 0;
  75. bool GEnabled = false;
  76. char GLogFile[MAX_PATH] = "";
  77. bool GLogOn = false;
  78. FILE* GLogHandle = NULL;
  79. HANDLE GLogMutex;
  80. HINSTANCE GInstance;
  81. //---------------------------------------------------------------------------
  82. void Debug(const char* Message)
  83. {
  84. if (GLogOn)
  85. {
  86. unsigned long WaitResult = WaitForSingleObject(GLogMutex, 1000);
  87. if (WaitResult != WAIT_TIMEOUT)
  88. {
  89. try
  90. {
  91. if (GLogHandle == NULL)
  92. {
  93. if (strlen(GLogFile) == 0)
  94. {
  95. GLogOn = false;
  96. }
  97. else
  98. {
  99. GLogHandle = fopen(GLogFile, "at");
  100. if (GLogHandle == NULL)
  101. {
  102. GLogOn = false;
  103. }
  104. else
  105. {
  106. setbuf(GLogHandle, NULL);
  107. fprintf(GLogHandle, "----------------------------\n");
  108. }
  109. }
  110. }
  111. if (GLogOn)
  112. {
  113. SYSTEMTIME Time;
  114. GetSystemTime(&Time);
  115. fprintf(GLogHandle, "[%2d/%2d/%4d %2d:%02d:%02d.%03d][%04x] %s\n",
  116. Time.wDay, Time.wMonth, Time.wYear, Time.wHour, Time.wMinute,
  117. Time.wSecond, Time.wMilliseconds, GetCurrentThreadId(), Message);
  118. }
  119. }
  120. catch(...)
  121. {
  122. }
  123. ReleaseMutex(GLogMutex);
  124. }
  125. }
  126. }
  127. //---------------------------------------------------------------------------
  128. void LogVersion(HINSTANCE HInstance)
  129. {
  130. if (GLogOn)
  131. {
  132. char FileName[MAX_PATH];
  133. if (GetModuleFileName(HInstance, FileName, sizeof(FileName)) > 0)
  134. {
  135. Debug(FileName);
  136. unsigned long InfoHandle, Size;
  137. Size = GetFileVersionInfoSize(FileName, &InfoHandle);
  138. if (Size > 0)
  139. {
  140. void* Info;
  141. Info = new char[Size];
  142. if (GetFileVersionInfo(FileName, InfoHandle, Size, Info) != 0)
  143. {
  144. VS_FIXEDFILEINFO* VersionInfo;
  145. unsigned int VersionInfoSize;
  146. if (VerQueryValue(Info, "\\", reinterpret_cast<void**>(&VersionInfo),
  147. &VersionInfoSize) != 0)
  148. {
  149. char VersionStr[100];
  150. snprintf(VersionStr, sizeof(VersionStr), "LogVersion %d.%d.%d.%d",
  151. HIWORD(VersionInfo->dwFileVersionMS),
  152. LOWORD(VersionInfo->dwFileVersionMS),
  153. HIWORD(VersionInfo->dwFileVersionLS),
  154. LOWORD(VersionInfo->dwFileVersionLS));
  155. Debug(VersionStr);
  156. }
  157. else
  158. {
  159. Debug("LogVersion no fixed version info");
  160. }
  161. }
  162. else
  163. {
  164. Debug("LogVersion cannot read version info");
  165. }
  166. }
  167. else
  168. {
  169. Debug("LogVersion no version info");
  170. }
  171. }
  172. }
  173. }
  174. //---------------------------------------------------------------------------
  175. extern "C" int APIENTRY
  176. DllMain(HINSTANCE HInstance, DWORD Reason, LPVOID Reserved)
  177. {
  178. if (Reason == DLL_PROCESS_ATTACH)
  179. {
  180. GInstance = HInstance;
  181. }
  182. if (GRefThisDll == 0)
  183. {
  184. GLogMutex = CreateMutex(NULL, false, "WinSCPDragExtLogMutex");
  185. for (int Root = 0; Root <= 1; Root++)
  186. {
  187. HKEY Key;
  188. if (RegOpenKeyEx(Root == 0 ? HKEY_LOCAL_MACHINE : HKEY_CURRENT_USER,
  189. DRAG_EXT_REG_KEY, 0,
  190. STANDARD_RIGHTS_READ | KEY_QUERY_VALUE | KEY_ENUMERATE_SUB_KEYS,
  191. &Key) == ERROR_SUCCESS)
  192. {
  193. unsigned long Type;
  194. unsigned long Value;
  195. unsigned long Size;
  196. char Buf[MAX_PATH];
  197. Size = sizeof(Value);
  198. if ((RegQueryValueEx(Key, "Enable", NULL, &Type,
  199. reinterpret_cast<unsigned char*>(&Value), &Size) == ERROR_SUCCESS) &&
  200. (Type == REG_DWORD))
  201. {
  202. GEnabled = (Value != 0);
  203. }
  204. Size = sizeof(Buf);
  205. if ((RegQueryValueEx(Key, "LogFile", NULL, &Type,
  206. reinterpret_cast<unsigned char*>(&Buf), &Size) == ERROR_SUCCESS) &&
  207. (Type == REG_SZ))
  208. {
  209. strncpy(GLogFile, Buf, sizeof(GLogFile));
  210. GLogFile[sizeof(GLogFile) - 1] = '\0';
  211. GLogOn = true;
  212. }
  213. RegCloseKey(Key);
  214. }
  215. }
  216. DEBUG("DllMain loaded settings");
  217. DEBUG(GEnabled ? "DllMain enabled" : "DllMain disabled");
  218. LogVersion(HInstance);
  219. }
  220. else
  221. {
  222. DEBUG("DllMain settings already loaded");
  223. }
  224. DEBUG("DllMain leave");
  225. return 1; // ok
  226. }
  227. //---------------------------------------------------------------------------
  228. STDAPI DllCanUnloadNow(void)
  229. {
  230. bool CanUnload = (GRefThisDll == 0);
  231. DEBUG(CanUnload ? "DllCanUnloadNow can" : "DllCanUnloadNow cannot");
  232. return (CanUnload ? S_OK : S_FALSE);
  233. }
  234. //---------------------------------------------------------------------------
  235. STDAPI DllGetClassObject(REFCLSID Rclsid, REFIID Riid, LPVOID* PpvOut)
  236. {
  237. DEBUG("DllGetClassObject");
  238. *PpvOut = NULL;
  239. if (IsEqualIID(Rclsid, CLSID_ShellExtension))
  240. {
  241. DEBUG("DllGetClassObject is ShellExtension");
  242. CShellExtClassFactory* Pcf = new CShellExtClassFactory;
  243. return Pcf->QueryInterface(Riid, PpvOut);
  244. }
  245. return CLASS_E_CLASSNOTAVAILABLE;
  246. }
  247. //---------------------------------------------------------------------------
  248. bool RegisterServer(bool AllUsers)
  249. {
  250. DEBUG("RegisterServer enter");
  251. DEBUG(AllUsers ? "RegisterServer all users" : "RegisterServer current users");
  252. bool Result = false;
  253. HKEY RootKey = AllUsers ? HKEY_LOCAL_MACHINE : HKEY_CURRENT_USER;
  254. HKEY HKey;
  255. DWORD Unused;
  256. wchar_t wClassID[CLSID_SIZE];
  257. // double size will guarante char to fit space
  258. char ClassID[CLSID_SIZE * 2];
  259. StringFromGUID2(CLSID_ShellExtension, wClassID, CLSID_SIZE);
  260. ZeroMemory(ClassID, CLSID_SIZE * 2);
  261. wcstombs(ClassID, wClassID, CLSID_SIZE * 2);
  262. if ((RegOpenKeyEx(RootKey, "Software\\Classes", 0, KEY_WRITE, &HKey) ==
  263. ERROR_SUCCESS) &&
  264. (RegCreateKeyEx(HKey, "CLSID", 0, NULL,
  265. REG_OPTION_NON_VOLATILE, KEY_WRITE, NULL, &HKey, &Unused) ==
  266. ERROR_SUCCESS))
  267. {
  268. if (RegCreateKey(HKey, ClassID, &HKey) == ERROR_SUCCESS)
  269. {
  270. RegSetValueEx(HKey, NULL, 0, REG_SZ,
  271. reinterpret_cast<unsigned char*>(DRAG_EXT_NAME), sizeof(DRAG_EXT_NAME));
  272. if (RegCreateKey(HKey, "InProcServer32", &HKey) == ERROR_SUCCESS)
  273. {
  274. char Filename[MAX_PATH];
  275. GetModuleFileName(GInstance, Filename, sizeof(Filename));
  276. RegSetValueEx(HKey, NULL, 0, REG_SZ,
  277. reinterpret_cast<unsigned char*>(Filename), strlen(Filename) + 1);
  278. RegSetValueEx(HKey, "ThreadingModel", 0, REG_SZ,
  279. reinterpret_cast<unsigned char*>(THREADING_MODEL),
  280. sizeof(THREADING_MODEL));
  281. }
  282. }
  283. RegCloseKey(HKey);
  284. if ((RegOpenKeyEx(RootKey, "Software\\Classes",
  285. 0, KEY_WRITE, &HKey) == ERROR_SUCCESS) &&
  286. (RegCreateKeyEx(HKey,
  287. "directory\\shellex\\CopyHookHandlers\\WinSCPCopyHook",
  288. 0, NULL, REG_OPTION_NON_VOLATILE, KEY_WRITE, NULL, &HKey,
  289. &Unused) == ERROR_SUCCESS))
  290. {
  291. RegSetValueEx(HKey, NULL, 0, REG_SZ,
  292. reinterpret_cast<unsigned char*>(ClassID), strlen(ClassID) + 1);
  293. RegCloseKey(HKey);
  294. if ((RegCreateKeyEx(RootKey, DRAG_EXT_REG_KEY,
  295. 0, NULL, REG_OPTION_NON_VOLATILE, KEY_WRITE, NULL, &HKey,
  296. &Unused) == ERROR_SUCCESS))
  297. {
  298. unsigned long Value = 1;
  299. RegSetValueEx(HKey, "Enable", 0, REG_DWORD,
  300. reinterpret_cast<unsigned char*>(&Value), sizeof(Value));
  301. RegCloseKey(HKey);
  302. Result = true;
  303. }
  304. SHChangeNotify(SHCNE_ASSOCCHANGED, SHCNF_IDLIST, 0, 0);
  305. }
  306. }
  307. DEBUG("RegisterServer leave");
  308. return Result;
  309. }
  310. //---------------------------------------------------------------------------
  311. STDAPI DllRegisterServer()
  312. {
  313. DEBUG("DllRegisterServer enter");
  314. HRESULT Result;
  315. if (RegisterServer(true) || RegisterServer(false))
  316. {
  317. Result = S_OK;
  318. }
  319. else
  320. {
  321. Result = SELFREG_E_CLASS;
  322. }
  323. DEBUG("DllRegisterServer leave");
  324. return Result;
  325. }
  326. //---------------------------------------------------------------------------
  327. bool UnregisterServer(bool AllUsers)
  328. {
  329. DEBUG("UnregisterServer enter");
  330. DEBUG(AllUsers ? "UnregisterServer all users" : "UnregisterServer current users");
  331. bool Result = false;
  332. wchar_t wClassID[CLSID_SIZE];
  333. char ClassID[CLSID_SIZE * 2];
  334. StringFromGUID2(CLSID_ShellExtension, wClassID, CLSID_SIZE);
  335. ZeroMemory(ClassID, CLSID_SIZE * 2);
  336. wcstombs(ClassID, wClassID, CLSID_SIZE * 2);
  337. HKEY RootKey = AllUsers ? HKEY_LOCAL_MACHINE : HKEY_CURRENT_USER;
  338. HKEY HKey;
  339. if ((RegOpenKeyEx(RootKey, "Software\\Classes", 0, KEY_WRITE, &HKey) ==
  340. ERROR_SUCCESS) &&
  341. (RegOpenKeyEx(HKey, "directory\\shellex\\CopyHookHandlers",
  342. 0, KEY_WRITE, &HKey) == ERROR_SUCCESS))
  343. {
  344. RegDeleteKey(HKey, "WinSCPCopyHook");
  345. RegCloseKey(HKey);
  346. }
  347. if ((RegOpenKeyEx(RootKey, "Software\\Classes", 0, KEY_WRITE, &HKey) ==
  348. ERROR_SUCCESS) &&
  349. (RegOpenKeyEx(HKey, "CLSID", 0, KEY_WRITE, &HKey) ==
  350. ERROR_SUCCESS))
  351. {
  352. if (RegOpenKeyEx(HKey, ClassID, 0, KEY_WRITE, &HKey) == ERROR_SUCCESS)
  353. {
  354. RegDeleteKey(HKey, "InProcServer32");
  355. RegCloseKey(HKey);
  356. if ((RegOpenKeyEx(RootKey, "Software\\Classes", 0, KEY_WRITE, &HKey) ==
  357. ERROR_SUCCESS) &&
  358. (RegOpenKeyEx(HKey, "CLSID", 0, KEY_WRITE, &HKey) ==
  359. ERROR_SUCCESS))
  360. {
  361. RegDeleteKey(HKey, ClassID);
  362. RegCloseKey(HKey);
  363. Result = true;
  364. }
  365. }
  366. }
  367. if ((RegOpenKeyEx(RootKey, DRAG_EXT_REG_KEY, 0, KEY_WRITE, &HKey) ==
  368. ERROR_SUCCESS))
  369. {
  370. unsigned long Value = 0;
  371. RegSetValueEx(HKey, "Enable", 0, REG_DWORD,
  372. reinterpret_cast<unsigned char*>(&Value), sizeof(Value));
  373. RegCloseKey(HKey);
  374. Result = true;
  375. }
  376. SHChangeNotify(SHCNE_ASSOCCHANGED, SHCNF_IDLIST, 0, 0);
  377. DEBUG("UnregisterServer leave");
  378. return Result;
  379. }
  380. //---------------------------------------------------------------------------
  381. STDAPI DllUnregisterServer()
  382. {
  383. DEBUG("DllUnregisterServer enter");
  384. HRESULT Result = SELFREG_E_CLASS;
  385. if (UnregisterServer(true))
  386. {
  387. Result = S_OK;
  388. }
  389. if (UnregisterServer(false))
  390. {
  391. Result = S_OK;
  392. }
  393. DEBUG("DllUnregisterServer leave");
  394. return Result;
  395. }
  396. //---------------------------------------------------------------------------
  397. CShellExtClassFactory::CShellExtClassFactory()
  398. {
  399. DEBUG("CShellExtClassFactory");
  400. FReferenceCounter = 0;
  401. GRefThisDll++;
  402. }
  403. //---------------------------------------------------------------------------
  404. CShellExtClassFactory::~CShellExtClassFactory()
  405. {
  406. DEBUG("~CShellExtClassFactory");
  407. GRefThisDll--;
  408. }
  409. //---------------------------------------------------------------------------
  410. STDMETHODIMP CShellExtClassFactory::QueryInterface(REFIID Riid, LPVOID FAR* Ppv)
  411. {
  412. DEBUG("QueryInterface");
  413. *Ppv = NULL;
  414. // Any interface on this object is the object pointer
  415. if (IsEqualIID(Riid, IID_IUnknown) || IsEqualIID(Riid, IID_IClassFactory))
  416. {
  417. DEBUG("QueryInterface is IUnknown or IClassFactory");
  418. *Ppv = (LPCLASSFACTORY)this;
  419. AddRef();
  420. return NOERROR;
  421. }
  422. return E_NOINTERFACE;
  423. }
  424. //---------------------------------------------------------------------------
  425. STDMETHODIMP_(ULONG) CShellExtClassFactory::AddRef()
  426. {
  427. DEBUG("AddRef");
  428. return ++FReferenceCounter;
  429. }
  430. //---------------------------------------------------------------------------
  431. STDMETHODIMP_(ULONG) CShellExtClassFactory::Release()
  432. {
  433. DEBUG("Release");
  434. if (--FReferenceCounter)
  435. {
  436. return FReferenceCounter;
  437. }
  438. delete this;
  439. return 0;
  440. }
  441. //---------------------------------------------------------------------------
  442. STDMETHODIMP CShellExtClassFactory::CreateInstance(LPUNKNOWN UnkOuter,
  443. REFIID Riid, LPVOID* PpvObj)
  444. {
  445. DEBUG("CreateInstance");
  446. *PpvObj = NULL;
  447. // Shell extensions typically don't support aggregation (inheritance)
  448. if (UnkOuter)
  449. {
  450. return CLASS_E_NOAGGREGATION;
  451. }
  452. // Create the main shell extension object. The shell will then call
  453. // QueryInterface with IID_IShellExtInit--this is how shell extensions are
  454. // initialized.
  455. CShellExt* ShellExt = new CShellExt(); //Create the CShellExt object
  456. if (NULL == ShellExt)
  457. {
  458. return E_OUTOFMEMORY;
  459. }
  460. return ShellExt->QueryInterface(Riid, PpvObj);
  461. }
  462. //---------------------------------------------------------------------------
  463. STDMETHODIMP CShellExtClassFactory::LockServer(BOOL Lock)
  464. {
  465. DEBUG("LockServer");
  466. return NOERROR;
  467. }
  468. //---------------------------------------------------------------------------
  469. // CShellExt
  470. CShellExt::CShellExt()
  471. {
  472. DEBUG("CShellExt enter");
  473. FReferenceCounter = 0L;
  474. FDataObj = NULL;
  475. FMutex = CreateMutex(NULL, false, DRAG_EXT_MUTEX);
  476. FLastTicks = 0;
  477. GRefThisDll++;
  478. DEBUG("CShellExt leave");
  479. }
  480. //---------------------------------------------------------------------------
  481. CShellExt::~CShellExt()
  482. {
  483. DEBUG("~CShellExt enter");
  484. if (FDataObj)
  485. {
  486. FDataObj->Release();
  487. }
  488. CloseHandle(FMutex);
  489. GRefThisDll--;
  490. DEBUG("~CShellExt leave");
  491. }
  492. //---------------------------------------------------------------------------
  493. STDMETHODIMP CShellExt::QueryInterface(REFIID Riid, LPVOID FAR* Ppv)
  494. {
  495. DEBUG("CShellExt::QueryInterface enter");
  496. HRESULT Result = E_NOINTERFACE;
  497. *Ppv = NULL;
  498. if (!GEnabled)
  499. {
  500. DEBUG("CShellExt::QueryInterface shelext disabled");
  501. }
  502. else
  503. {
  504. if (IsEqualIID(Riid, IID_IShellExtInit) || IsEqualIID(Riid, IID_IUnknown))
  505. {
  506. DEBUG("CShellExt::QueryInterface is IShellExtInit or IUnknown");
  507. *Ppv = (LPSHELLEXTINIT)this;
  508. }
  509. else if (IsEqualIID(Riid, IID_IShellCopyHook))
  510. {
  511. DEBUG("CShellExt::QueryInterface is IShellCopyHook");
  512. *Ppv = (LPCOPYHOOK)this;
  513. }
  514. if (*Ppv)
  515. {
  516. AddRef();
  517. Result = NOERROR;
  518. }
  519. }
  520. DEBUG("CShellExt::QueryInterface leave");
  521. return Result;
  522. }
  523. //---------------------------------------------------------------------------
  524. STDMETHODIMP_(ULONG) CShellExt::AddRef()
  525. {
  526. DEBUG("CShellExt::AddRef");
  527. return ++FReferenceCounter;
  528. }
  529. //---------------------------------------------------------------------------
  530. STDMETHODIMP_(ULONG) CShellExt::Release()
  531. {
  532. DEBUG("CShellExt::Release");
  533. if (--FReferenceCounter)
  534. {
  535. return FReferenceCounter;
  536. }
  537. delete this;
  538. return 0;
  539. }
  540. //---------------------------------------------------------------------------
  541. STDMETHODIMP CShellExt::Initialize(LPCITEMIDLIST IDFolder,
  542. LPDATAOBJECT DataObj, HKEY RegKey)
  543. {
  544. DEBUG("CShellExt::Initialize enter");
  545. if (FDataObj != NULL)
  546. {
  547. FDataObj->Release();
  548. FDataObj = NULL;
  549. }
  550. // duplicate the object pointer and registry handle
  551. if (DataObj != NULL)
  552. {
  553. FDataObj = DataObj;
  554. DataObj->AddRef();
  555. }
  556. DEBUG("CShellExt::Initialize leave");
  557. return NOERROR;
  558. }
  559. //---------------------------------------------------------------------------
  560. STDMETHODIMP_(UINT) CShellExt::CopyCallback(HWND Hwnd, UINT Func, UINT Flags,
  561. LPCSTR SrcFile, DWORD SrcAttribs, LPCSTR DestFile, DWORD DestAttribs)
  562. {
  563. DEBUG("CShellExt::CopyCallback enter");
  564. UINT Result = IDYES;
  565. if (GEnabled && ((Func == FO_COPY) || (Func == FO_MOVE)))
  566. {
  567. DEBUG("CShellExt::CopyCallback copy or move");
  568. unsigned long Ticks = GetTickCount();
  569. if (((Ticks - FLastTicks) >= 100) ||
  570. (FLastTicks > Ticks))
  571. {
  572. DEBUG("CShellExt::CopyCallback interval elapsed");
  573. DEBUG("CShellExt::CopyCallback source / dest:");
  574. DEBUG(SrcFile);
  575. DEBUG(DestFile);
  576. FLastTicks = Ticks;
  577. const char* BackPtr = strrchr(SrcFile, '\\');
  578. if ((BackPtr != NULL) &&
  579. (strncmp(BackPtr + 1, DRAG_EXT_DUMMY_DIR_PREFIX,
  580. DRAG_EXT_DUMMY_DIR_PREFIX_LEN) == 0))
  581. {
  582. DEBUG("CShellExt::CopyCallback filename has prefix");
  583. HANDLE MapFile = OpenFileMapping(FILE_MAP_ALL_ACCESS,
  584. false, DRAG_EXT_MAPPING);
  585. if (MapFile != NULL)
  586. {
  587. DEBUG("CShellExt::CopyCallback mapfile found");
  588. TDragExtCommStruct* CommStruct;
  589. CommStruct = static_cast<TDragExtCommStruct*>(MapViewOfFile(MapFile,
  590. FILE_MAP_ALL_ACCESS, 0, 0, 0));
  591. if (CommStruct != NULL)
  592. {
  593. DEBUG("CShellExt::CopyCallback mapview created");
  594. unsigned long WaitResult = WaitForSingleObject(FMutex, 1000);
  595. if (WaitResult != WAIT_TIMEOUT)
  596. {
  597. DEBUG("CShellExt::CopyCallback mutex got");
  598. if (CommStruct->Version >= TDragExtCommStruct::MinVersion)
  599. {
  600. DEBUG("CShellExt::CopyCallback supported structure version");
  601. if (CommStruct->Dragging)
  602. {
  603. DEBUG("CShellExt::CopyCallback dragging");
  604. if (strcmp(CommStruct->DropDest, SrcFile) == 0)
  605. {
  606. CommStruct->Dragging = false;
  607. strncpy(CommStruct->DropDest, DestFile, sizeof(CommStruct->DropDest));
  608. CommStruct->DropDest[sizeof(CommStruct->DropDest)-1] = '\0';
  609. Result = IDNO;
  610. DEBUG("CShellExt::CopyCallback dragging refused");
  611. }
  612. else
  613. {
  614. DEBUG("CShellExt::CopyCallback dragged file does NOT match");
  615. }
  616. }
  617. else
  618. {
  619. DEBUG("CShellExt::CopyCallback NOT dragging");
  620. }
  621. }
  622. else
  623. {
  624. DEBUG("CShellExt::CopyCallback unsupported structure version");
  625. }
  626. ReleaseMutex(FMutex);
  627. DEBUG("CShellExt::CopyCallback mutex released");
  628. }
  629. else
  630. {
  631. DEBUG("CShellExt::CopyCallback mutex timeout");
  632. }
  633. UnmapViewOfFile(CommStruct);
  634. }
  635. else
  636. {
  637. DEBUG("CShellExt::CopyCallback mapview NOT created");
  638. }
  639. CloseHandle(MapFile);
  640. }
  641. else
  642. {
  643. DEBUG("CShellExt::CopyCallback mapfile NOT found");
  644. }
  645. }
  646. else
  647. {
  648. DEBUG("CShellExt::CopyCallback filename has NOT prefix");
  649. }
  650. }
  651. else
  652. {
  653. DEBUG("CShellExt::CopyCallback interval NOT elapsed");
  654. }
  655. }
  656. else
  657. {
  658. DEBUG("CShellExt::CopyCallback NOT copy nor move");
  659. }
  660. DEBUG("CShellExt::CopyCallback leave");
  661. return Result;
  662. }