DragExt.cpp 23 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822
  1. //---------------------------------------------------------------------------
  2. #pragma hdrstop
  3. //---------------------------------------------------------------------------
  4. #ifndef STRICT
  5. #define STRICT
  6. #endif
  7. //---------------------------------------------------------------------------
  8. #ifdef _MSC_VER
  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. virtual ~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. virtual ~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. if (GRefThisDll == 0)
  182. {
  183. GLogMutex = CreateMutex(NULL, false, "WinSCPDragExtLogMutex");
  184. for (int Root = 0; Root <= 1; Root++)
  185. {
  186. HKEY Key;
  187. if (RegOpenKeyEx(Root == 0 ? HKEY_LOCAL_MACHINE : HKEY_CURRENT_USER,
  188. DRAG_EXT_REG_KEY, 0,
  189. STANDARD_RIGHTS_READ | KEY_QUERY_VALUE | KEY_ENUMERATE_SUB_KEYS,
  190. &Key) == ERROR_SUCCESS)
  191. {
  192. unsigned long Type;
  193. unsigned long Value;
  194. unsigned long Size;
  195. char Buf[MAX_PATH];
  196. Size = sizeof(Value);
  197. if ((RegQueryValueEx(Key, "Enable", NULL, &Type,
  198. reinterpret_cast<unsigned char*>(&Value), &Size) == ERROR_SUCCESS) &&
  199. (Type == REG_DWORD))
  200. {
  201. GEnabled = (Value != 0);
  202. }
  203. Size = sizeof(Buf);
  204. if ((RegQueryValueEx(Key, "LogFile", NULL, &Type,
  205. reinterpret_cast<unsigned char*>(&Buf), &Size) == ERROR_SUCCESS) &&
  206. (Type == REG_SZ))
  207. {
  208. strncpy(GLogFile, Buf, sizeof(GLogFile));
  209. GLogFile[sizeof(GLogFile) - 1] = '\0';
  210. GLogOn = true;
  211. }
  212. RegCloseKey(Key);
  213. }
  214. }
  215. DEBUG("DllMain loaded settings");
  216. DEBUG(GEnabled ? "DllMain enabled" : "DllMain disabled");
  217. LogVersion(HInstance);
  218. }
  219. else
  220. {
  221. DEBUG("DllMain settings already loaded");
  222. }
  223. DEBUG("DllMain attach leave");
  224. }
  225. else if (Reason == DLL_PROCESS_DETACH)
  226. {
  227. DEBUG("DllMain detach enter");
  228. CloseHandle(GLogMutex);
  229. }
  230. return 1; // ok
  231. }
  232. //---------------------------------------------------------------------------
  233. STDAPI DllCanUnloadNow(void)
  234. {
  235. bool CanUnload = (GRefThisDll == 0);
  236. DEBUG(CanUnload ? "DllCanUnloadNow can" : "DllCanUnloadNow cannot");
  237. return (CanUnload ? S_OK : S_FALSE);
  238. }
  239. //---------------------------------------------------------------------------
  240. STDAPI DllGetClassObject(REFCLSID Rclsid, REFIID Riid, LPVOID* PpvOut)
  241. {
  242. DEBUG("DllGetClassObject");
  243. *PpvOut = NULL;
  244. if (IsEqualIID(Rclsid, CLSID_ShellExtension))
  245. {
  246. DEBUG("DllGetClassObject is ShellExtension");
  247. CShellExtClassFactory* Pcf = new CShellExtClassFactory;
  248. return Pcf->QueryInterface(Riid, PpvOut);
  249. }
  250. return CLASS_E_CLASSNOTAVAILABLE;
  251. }
  252. //---------------------------------------------------------------------------
  253. bool RegisterServer(bool AllUsers)
  254. {
  255. DEBUG("RegisterServer enter");
  256. DEBUG(AllUsers ? "RegisterServer all users" : "RegisterServer current users");
  257. bool Result = false;
  258. HKEY RootKey = AllUsers ? HKEY_LOCAL_MACHINE : HKEY_CURRENT_USER;
  259. HKEY HKey;
  260. DWORD Unused;
  261. wchar_t wClassID[CLSID_SIZE];
  262. // double size will guarante char to fit space
  263. char ClassID[CLSID_SIZE * 2];
  264. StringFromGUID2(CLSID_ShellExtension, wClassID, CLSID_SIZE);
  265. ZeroMemory(ClassID, CLSID_SIZE * 2);
  266. wcstombs(ClassID, wClassID, CLSID_SIZE * 2);
  267. if ((RegOpenKeyEx(RootKey, "Software\\Classes", 0, KEY_WRITE, &HKey) ==
  268. ERROR_SUCCESS) &&
  269. (RegCreateKeyEx(HKey, "CLSID", 0, NULL,
  270. REG_OPTION_NON_VOLATILE, KEY_WRITE, NULL, &HKey, &Unused) ==
  271. ERROR_SUCCESS))
  272. {
  273. if (RegCreateKey(HKey, ClassID, &HKey) == ERROR_SUCCESS)
  274. {
  275. RegSetValueEx(HKey, NULL, 0, REG_SZ,
  276. reinterpret_cast<const unsigned char*>(DRAG_EXT_NAME), sizeof(DRAG_EXT_NAME));
  277. if (RegCreateKey(HKey, "InProcServer32", &HKey) == ERROR_SUCCESS)
  278. {
  279. char Filename[MAX_PATH];
  280. GetModuleFileName(GInstance, Filename, sizeof(Filename));
  281. RegSetValueEx(HKey, NULL, 0, REG_SZ,
  282. reinterpret_cast<unsigned char*>(Filename), strlen(Filename) + 1);
  283. RegSetValueEx(HKey, "ThreadingModel", 0, REG_SZ,
  284. reinterpret_cast<unsigned char*>(THREADING_MODEL),
  285. sizeof(THREADING_MODEL));
  286. }
  287. }
  288. RegCloseKey(HKey);
  289. if ((RegOpenKeyEx(RootKey, "Software\\Classes",
  290. 0, KEY_WRITE, &HKey) == ERROR_SUCCESS) &&
  291. (RegCreateKeyEx(HKey,
  292. "directory\\shellex\\CopyHookHandlers\\WinSCPCopyHook",
  293. 0, NULL, REG_OPTION_NON_VOLATILE, KEY_WRITE, NULL, &HKey,
  294. &Unused) == ERROR_SUCCESS))
  295. {
  296. RegSetValueEx(HKey, NULL, 0, REG_SZ,
  297. reinterpret_cast<unsigned char*>(ClassID), strlen(ClassID) + 1);
  298. RegCloseKey(HKey);
  299. if ((RegCreateKeyEx(RootKey, DRAG_EXT_REG_KEY,
  300. 0, NULL, REG_OPTION_NON_VOLATILE, KEY_WRITE, NULL, &HKey,
  301. &Unused) == ERROR_SUCCESS))
  302. {
  303. unsigned long Value = 1;
  304. RegSetValueEx(HKey, "Enable", 0, REG_DWORD,
  305. reinterpret_cast<unsigned char*>(&Value), sizeof(Value));
  306. RegCloseKey(HKey);
  307. Result = true;
  308. }
  309. SHChangeNotify(SHCNE_ASSOCCHANGED, SHCNF_IDLIST, 0, 0);
  310. }
  311. }
  312. DEBUG("RegisterServer leave");
  313. return Result;
  314. }
  315. //---------------------------------------------------------------------------
  316. STDAPI DllRegisterServer()
  317. {
  318. DEBUG("DllRegisterServer enter");
  319. HRESULT Result;
  320. if (RegisterServer(true) || RegisterServer(false))
  321. {
  322. Result = S_OK;
  323. }
  324. else
  325. {
  326. Result = SELFREG_E_CLASS;
  327. }
  328. DEBUG("DllRegisterServer leave");
  329. return Result;
  330. }
  331. //---------------------------------------------------------------------------
  332. bool UnregisterServer(bool AllUsers)
  333. {
  334. DEBUG("UnregisterServer enter");
  335. DEBUG(AllUsers ? "UnregisterServer all users" : "UnregisterServer current users");
  336. bool Result = false;
  337. wchar_t wClassID[CLSID_SIZE];
  338. char ClassID[CLSID_SIZE * 2];
  339. StringFromGUID2(CLSID_ShellExtension, wClassID, CLSID_SIZE);
  340. ZeroMemory(ClassID, CLSID_SIZE * 2);
  341. wcstombs(ClassID, wClassID, CLSID_SIZE * 2);
  342. HKEY RootKey = AllUsers ? HKEY_LOCAL_MACHINE : HKEY_CURRENT_USER;
  343. HKEY HKey;
  344. if ((RegOpenKeyEx(RootKey, "Software\\Classes", 0, KEY_WRITE, &HKey) ==
  345. ERROR_SUCCESS) &&
  346. (RegOpenKeyEx(HKey, "directory\\shellex\\CopyHookHandlers",
  347. 0, KEY_WRITE, &HKey) == ERROR_SUCCESS))
  348. {
  349. RegDeleteKey(HKey, "WinSCPCopyHook");
  350. RegCloseKey(HKey);
  351. }
  352. if ((RegOpenKeyEx(RootKey, "Software\\Classes", 0, KEY_WRITE, &HKey) ==
  353. ERROR_SUCCESS) &&
  354. (RegOpenKeyEx(HKey, "CLSID", 0, KEY_WRITE, &HKey) ==
  355. ERROR_SUCCESS))
  356. {
  357. if (RegOpenKeyEx(HKey, ClassID, 0, KEY_WRITE, &HKey) == ERROR_SUCCESS)
  358. {
  359. RegDeleteKey(HKey, "InProcServer32");
  360. RegCloseKey(HKey);
  361. if ((RegOpenKeyEx(RootKey, "Software\\Classes", 0, KEY_WRITE, &HKey) ==
  362. ERROR_SUCCESS) &&
  363. (RegOpenKeyEx(HKey, "CLSID", 0, KEY_WRITE, &HKey) ==
  364. ERROR_SUCCESS))
  365. {
  366. RegDeleteKey(HKey, ClassID);
  367. RegCloseKey(HKey);
  368. Result = true;
  369. }
  370. }
  371. }
  372. if (RegOpenKeyEx(RootKey, DRAG_EXT_REG_KEY, 0, KEY_WRITE, &HKey) ==
  373. ERROR_SUCCESS)
  374. {
  375. unsigned long Value = 0;
  376. RegSetValueEx(HKey, "Enable", 0, REG_DWORD,
  377. reinterpret_cast<unsigned char*>(&Value), sizeof(Value));
  378. RegCloseKey(HKey);
  379. Result = true;
  380. }
  381. SHChangeNotify(SHCNE_ASSOCCHANGED, SHCNF_IDLIST, 0, 0);
  382. DEBUG("UnregisterServer leave");
  383. return Result;
  384. }
  385. //---------------------------------------------------------------------------
  386. STDAPI DllUnregisterServer()
  387. {
  388. DEBUG("DllUnregisterServer enter");
  389. HRESULT Result = SELFREG_E_CLASS;
  390. if (UnregisterServer(true))
  391. {
  392. Result = S_OK;
  393. }
  394. if (UnregisterServer(false))
  395. {
  396. Result = S_OK;
  397. }
  398. DEBUG("DllUnregisterServer leave");
  399. return Result;
  400. }
  401. //---------------------------------------------------------------------------
  402. CShellExtClassFactory::CShellExtClassFactory()
  403. {
  404. DEBUG("CShellExtClassFactory");
  405. FReferenceCounter = 0;
  406. GRefThisDll++;
  407. }
  408. //---------------------------------------------------------------------------
  409. CShellExtClassFactory::~CShellExtClassFactory()
  410. {
  411. DEBUG("~CShellExtClassFactory");
  412. GRefThisDll--;
  413. }
  414. //---------------------------------------------------------------------------
  415. STDMETHODIMP CShellExtClassFactory::QueryInterface(REFIID Riid, LPVOID FAR* Ppv)
  416. {
  417. DEBUG("QueryInterface");
  418. *Ppv = NULL;
  419. // Any interface on this object is the object pointer
  420. if (IsEqualIID(Riid, IID_IUnknown) || IsEqualIID(Riid, IID_IClassFactory))
  421. {
  422. DEBUG("QueryInterface is IUnknown or IClassFactory");
  423. *Ppv = (LPCLASSFACTORY)this;
  424. AddRef();
  425. return NOERROR;
  426. }
  427. return E_NOINTERFACE;
  428. }
  429. //---------------------------------------------------------------------------
  430. STDMETHODIMP_(ULONG) CShellExtClassFactory::AddRef()
  431. {
  432. DEBUG("AddRef");
  433. return ++FReferenceCounter;
  434. }
  435. //---------------------------------------------------------------------------
  436. STDMETHODIMP_(ULONG) CShellExtClassFactory::Release()
  437. {
  438. DEBUG("Release");
  439. if (--FReferenceCounter)
  440. {
  441. return FReferenceCounter;
  442. }
  443. delete this;
  444. return 0;
  445. }
  446. //---------------------------------------------------------------------------
  447. STDMETHODIMP CShellExtClassFactory::CreateInstance(LPUNKNOWN UnkOuter,
  448. REFIID Riid, LPVOID* PpvObj)
  449. {
  450. DEBUG("CreateInstance");
  451. *PpvObj = NULL;
  452. // Shell extensions typically don't support aggregation (inheritance)
  453. if (UnkOuter)
  454. {
  455. return CLASS_E_NOAGGREGATION;
  456. }
  457. // Create the main shell extension object. The shell will then call
  458. // QueryInterface with IID_IShellExtInit--this is how shell extensions are
  459. // initialized.
  460. CShellExt* ShellExt = new CShellExt(); //Create the CShellExt object
  461. if (NULL == ShellExt)
  462. {
  463. return E_OUTOFMEMORY;
  464. }
  465. return ShellExt->QueryInterface(Riid, PpvObj);
  466. }
  467. //---------------------------------------------------------------------------
  468. STDMETHODIMP CShellExtClassFactory::LockServer(BOOL Lock)
  469. {
  470. DEBUG("LockServer");
  471. return NOERROR;
  472. }
  473. //---------------------------------------------------------------------------
  474. // CShellExt
  475. CShellExt::CShellExt()
  476. {
  477. DEBUG("CShellExt enter");
  478. FReferenceCounter = 0L;
  479. FDataObj = NULL;
  480. FMutex = CreateMutex(NULL, false, DRAG_EXT_MUTEX);
  481. FLastTicks = 0;
  482. GRefThisDll++;
  483. DEBUG("CShellExt leave");
  484. }
  485. //---------------------------------------------------------------------------
  486. CShellExt::~CShellExt()
  487. {
  488. DEBUG("~CShellExt enter");
  489. if (FDataObj)
  490. {
  491. FDataObj->Release();
  492. }
  493. CloseHandle(FMutex);
  494. GRefThisDll--;
  495. DEBUG("~CShellExt leave");
  496. }
  497. //---------------------------------------------------------------------------
  498. STDMETHODIMP CShellExt::QueryInterface(REFIID Riid, LPVOID FAR* Ppv)
  499. {
  500. DEBUG("CShellExt::QueryInterface enter");
  501. HRESULT Result = E_NOINTERFACE;
  502. *Ppv = NULL;
  503. if (!GEnabled)
  504. {
  505. DEBUG("CShellExt::QueryInterface shelext disabled");
  506. }
  507. else
  508. {
  509. if (IsEqualIID(Riid, IID_IShellExtInit) || IsEqualIID(Riid, IID_IUnknown))
  510. {
  511. DEBUG("CShellExt::QueryInterface is IShellExtInit or IUnknown");
  512. *Ppv = (LPSHELLEXTINIT)this;
  513. }
  514. else if (IsEqualIID(Riid, IID_IShellCopyHook))
  515. {
  516. DEBUG("CShellExt::QueryInterface is IShellCopyHook");
  517. *Ppv = (LPCOPYHOOK)this;
  518. }
  519. if (*Ppv)
  520. {
  521. AddRef();
  522. Result = NOERROR;
  523. }
  524. }
  525. DEBUG("CShellExt::QueryInterface leave");
  526. return Result;
  527. }
  528. //---------------------------------------------------------------------------
  529. STDMETHODIMP_(ULONG) CShellExt::AddRef()
  530. {
  531. DEBUG("CShellExt::AddRef");
  532. return ++FReferenceCounter;
  533. }
  534. //---------------------------------------------------------------------------
  535. STDMETHODIMP_(ULONG) CShellExt::Release()
  536. {
  537. DEBUG("CShellExt::Release");
  538. if (--FReferenceCounter)
  539. {
  540. return FReferenceCounter;
  541. }
  542. delete this;
  543. return 0;
  544. }
  545. //---------------------------------------------------------------------------
  546. STDMETHODIMP CShellExt::Initialize(LPCITEMIDLIST IDFolder,
  547. LPDATAOBJECT DataObj, HKEY RegKey)
  548. {
  549. DEBUG("CShellExt::Initialize enter");
  550. if (FDataObj != NULL)
  551. {
  552. FDataObj->Release();
  553. FDataObj = NULL;
  554. }
  555. // duplicate the object pointer and registry handle
  556. if (DataObj != NULL)
  557. {
  558. FDataObj = DataObj;
  559. DataObj->AddRef();
  560. }
  561. DEBUG("CShellExt::Initialize leave");
  562. return NOERROR;
  563. }
  564. //---------------------------------------------------------------------------
  565. STDMETHODIMP_(UINT) CShellExt::CopyCallback(HWND Hwnd, UINT Func, UINT Flags,
  566. LPCSTR SrcFile, DWORD SrcAttribs, LPCSTR DestFile, DWORD DestAttribs)
  567. {
  568. DEBUG("CShellExt::CopyCallback enter");
  569. UINT Result = IDYES;
  570. if (GEnabled && ((Func == FO_COPY) || (Func == FO_MOVE)))
  571. {
  572. DEBUG("CShellExt::CopyCallback copy or move");
  573. unsigned long Ticks = GetTickCount();
  574. if (((Ticks - FLastTicks) >= 100) ||
  575. (FLastTicks > Ticks))
  576. {
  577. DEBUG("CShellExt::CopyCallback interval elapsed");
  578. DEBUG("CShellExt::CopyCallback source / dest:");
  579. DEBUG(SrcFile);
  580. DEBUG(DestFile);
  581. FLastTicks = Ticks;
  582. const char* BackPtr = strrchr(SrcFile, '\\');
  583. if ((BackPtr != NULL) &&
  584. (strncmp(BackPtr + 1, DRAG_EXT_DUMMY_DIR_PREFIX,
  585. DRAG_EXT_DUMMY_DIR_PREFIX_LEN) == 0))
  586. {
  587. DEBUG("CShellExt::CopyCallback filename has prefix");
  588. HANDLE MapFile = OpenFileMapping(FILE_MAP_ALL_ACCESS,
  589. false, DRAG_EXT_MAPPING);
  590. if (MapFile != NULL)
  591. {
  592. DEBUG("CShellExt::CopyCallback mapfile found");
  593. TDragExtCommStruct* CommStruct;
  594. CommStruct = static_cast<TDragExtCommStruct*>(MapViewOfFile(MapFile,
  595. FILE_MAP_ALL_ACCESS, 0, 0, 0));
  596. if (CommStruct != NULL)
  597. {
  598. DEBUG("CShellExt::CopyCallback mapview created");
  599. unsigned long WaitResult = WaitForSingleObject(FMutex, 1000);
  600. if (WaitResult != WAIT_TIMEOUT)
  601. {
  602. DEBUG("CShellExt::CopyCallback mutex got");
  603. if (CommStruct->Version >= TDragExtCommStruct::MinVersion)
  604. {
  605. DEBUG("CShellExt::CopyCallback supported structure version");
  606. if (CommStruct->Dragging)
  607. {
  608. DEBUG("CShellExt::CopyCallback dragging");
  609. DEBUG(CommStruct->DropDest);
  610. bool IsDropDest;
  611. if (stricmp(CommStruct->DropDest, SrcFile) == 0)
  612. {
  613. IsDropDest = true;
  614. DEBUG("CShellExt::CopyCallback dragged file match as is");
  615. }
  616. else
  617. {
  618. char DropDestShort[MAX_PATH];
  619. char SrcFileShort[MAX_PATH];
  620. size_t DropDestSize = GetShortPathName(CommStruct->DropDest,
  621. DropDestShort, sizeof(DropDestShort));
  622. size_t SrcFileSize = GetShortPathName(SrcFile,
  623. SrcFileShort, sizeof(SrcFileShort));
  624. if ((DropDestSize == 0) || (SrcFileSize == 0))
  625. {
  626. DEBUG("CShellExt::CopyCallback cannot convert paths to short form");
  627. IsDropDest = false;
  628. }
  629. else if ((DropDestSize >= sizeof(DropDestShort)) ||
  630. (SrcFileSize >= sizeof(SrcFileShort)))
  631. {
  632. DEBUG("CShellExt::CopyCallback short paths too long");
  633. IsDropDest = false;
  634. }
  635. else
  636. {
  637. DEBUG(DropDestShort);
  638. DEBUG(SrcFileShort);
  639. if (stricmp(DropDestShort, SrcFileShort) == 0)
  640. {
  641. DEBUG("CShellExt::CopyCallback dragged file match after converted to short form");
  642. IsDropDest = true;
  643. }
  644. else
  645. {
  646. DEBUG("CShellExt::CopyCallback dragged file does NOT match");
  647. IsDropDest = false;
  648. }
  649. }
  650. }
  651. if (IsDropDest)
  652. {
  653. CommStruct->Dragging = false;
  654. strncpy(CommStruct->DropDest, DestFile, sizeof(CommStruct->DropDest));
  655. CommStruct->DropDest[sizeof(CommStruct->DropDest)-1] = '\0';
  656. Result = IDNO;
  657. DEBUG("CShellExt::CopyCallback dragging refused");
  658. }
  659. }
  660. else
  661. {
  662. DEBUG("CShellExt::CopyCallback NOT dragging");
  663. }
  664. }
  665. else
  666. {
  667. DEBUG("CShellExt::CopyCallback unsupported structure version");
  668. }
  669. ReleaseMutex(FMutex);
  670. DEBUG("CShellExt::CopyCallback mutex released");
  671. }
  672. else
  673. {
  674. DEBUG("CShellExt::CopyCallback mutex timeout");
  675. }
  676. UnmapViewOfFile(CommStruct);
  677. }
  678. else
  679. {
  680. DEBUG("CShellExt::CopyCallback mapview NOT created");
  681. }
  682. CloseHandle(MapFile);
  683. }
  684. else
  685. {
  686. DEBUG("CShellExt::CopyCallback mapfile NOT found");
  687. }
  688. }
  689. else
  690. {
  691. DEBUG("CShellExt::CopyCallback filename has NOT prefix");
  692. }
  693. }
  694. else
  695. {
  696. DEBUG("CShellExt::CopyCallback interval NOT elapsed");
  697. }
  698. }
  699. else
  700. {
  701. DEBUG("CShellExt::CopyCallback NOT copy nor move");
  702. }
  703. DEBUG("CShellExt::CopyCallback leave");
  704. return Result;
  705. }