DragExt.cpp 21 KB

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