Leaked source code of windows server 2003
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

1001 lines
28 KiB

  1. #include "shole.h"
  2. #include "ids.h"
  3. #include "scguid.h"
  4. #ifdef FEATURE_SHELLEXTENSION
  5. extern "C" const TCHAR c_szCLSID[];
  6. class CTemplateFolder : public IShellFolder, public IPersistFolder
  7. {
  8. public:
  9. CTemplateFolder();
  10. ~CTemplateFolder();
  11. inline BOOL ConstructedSuccessfully() { return _hdpaMap != NULL; }
  12. // IUnKnown
  13. virtual HRESULT __stdcall QueryInterface(REFIID,void **);
  14. virtual ULONG __stdcall AddRef(void);
  15. virtual ULONG __stdcall Release(void);
  16. // IShellFolder
  17. virtual HRESULT __stdcall ParseDisplayName(HWND hwndOwner,
  18. LPBC pbcReserved, LPOLESTR lpszDisplayName,
  19. ULONG * pchEaten, LPITEMIDLIST * ppidl, ULONG *pdwAttributes);
  20. virtual HRESULT __stdcall EnumObjects( THIS_ HWND hwndOwner, DWORD grfFlags, LPENUMIDLIST * ppenumIDList);
  21. virtual HRESULT __stdcall BindToObject(LPCITEMIDLIST pidl, LPBC pbcReserved,
  22. REFIID riid, LPVOID * ppvOut);
  23. virtual HRESULT __stdcall BindToStorage(LPCITEMIDLIST pidl, LPBC pbcReserved,
  24. REFIID riid, LPVOID * ppvObj);
  25. virtual HRESULT __stdcall CompareIDs(LPARAM lParam, LPCITEMIDLIST pidl1, LPCITEMIDLIST pidl2);
  26. virtual HRESULT __stdcall CreateViewObject (HWND hwndOwner, REFIID riid, LPVOID * ppvOut);
  27. virtual HRESULT __stdcall GetAttributesOf(UINT cidl, LPCITEMIDLIST * apidl,
  28. ULONG * rgfInOut);
  29. virtual HRESULT __stdcall GetUIObjectOf(HWND hwndOwner, UINT cidl, LPCITEMIDLIST * apidl,
  30. REFIID riid, UINT * prgfInOut, LPVOID * ppvOut);
  31. virtual HRESULT __stdcall GetDisplayNameOf(LPCITEMIDLIST pidl, DWORD uFlags, LPSTRRET lpName);
  32. virtual HRESULT __stdcall SetNameOf(HWND hwndOwner, LPCITEMIDLIST pidl,
  33. LPCOLESTR lpszName, DWORD uFlags,
  34. LPITEMIDLIST * ppidlOut);
  35. // IPersistFolder
  36. virtual HRESULT __stdcall GetClassID(LPCLSID lpClassID);
  37. virtual HRESULT __stdcall Initialize(LPCITEMIDLIST pidl);
  38. protected:
  39. // Defview callback
  40. friend HRESULT CALLBACK DefViewCallback(
  41. LPSHELLVIEW psvOuter, LPSHELLFOLDER psf,
  42. HWND hwndOwner, UINT uMsg,
  43. WPARAM wParam, LPARAM lParam);
  44. HRESULT GetDetailsOfDVM(UINT ici, DETAILSINFO *pdi);
  45. BOOL IsMyPidl(LPCITEMIDLIST pidl)
  46. { return (pidl->mkid.abID[0] == 'S' && pidl->mkid.abID[1] == 'N'); }
  47. UINT _cRef;
  48. //
  49. // To speed up name lookups, we cache the mapping between CLSIDs and
  50. // display names. We cannot persist this mapping because it won't
  51. // survive localization or ANSI/UNICODE interop.
  52. //
  53. typedef struct {
  54. CLSID clsid;
  55. TCHAR achName[MAX_PATH];
  56. } CLSIDMAP, *PCLSIDMAP;
  57. HDPA _hdpaMap;
  58. HRESULT GetNameOf(LPCITEMIDLIST pidl, LPCTSTR *ppsz);
  59. };
  60. class CEnumTemplate : public IEnumIDList
  61. {
  62. public:
  63. CEnumTemplate(DWORD grfFlags);
  64. ~CEnumTemplate();
  65. protected:
  66. // IUnKnown
  67. virtual HRESULT __stdcall QueryInterface(REFIID,void **);
  68. virtual ULONG __stdcall AddRef(void);
  69. virtual ULONG __stdcall Release(void);
  70. virtual HRESULT __stdcall Next(ULONG celt,
  71. LPITEMIDLIST *rgelt,
  72. ULONG *pceltFetched);
  73. virtual HRESULT __stdcall Skip(ULONG celt);
  74. virtual HRESULT __stdcall Reset();
  75. virtual HRESULT __stdcall Clone(IEnumIDList **ppenum);
  76. UINT _cRef;
  77. const DWORD _grfFlags;
  78. UINT _iCur;
  79. HKEY _hkeyCLSID;
  80. };
  81. //
  82. // For Win95/NT interop, our PIDLs are always UNICODE.
  83. // Use explicit packing for Win32/64 interop.
  84. #include <pshpack1.h>
  85. typedef struct _TIDL {
  86. USHORT cb; // This matches SHITEMID
  87. BYTE abID[2]; // This matches SHITEMID
  88. CLSID clsid;
  89. } TIDL;
  90. typedef const UNALIGNED TIDL *PTIDL;
  91. //
  92. // This is the TIDL constructor -- it has the cbZero at the end.
  93. //
  94. typedef struct _TIDLCONS {
  95. TIDL tidl;
  96. USHORT cbZero;
  97. } TIDLCONS;
  98. #include <poppack.h>
  99. class CTemplateUIObj : public IExtractIcon, public IDataObject, public IContextMenu
  100. {
  101. public:
  102. static HRESULT Create(REFCLSID, REFIID, LPVOID*);
  103. protected:
  104. CTemplateUIObj(REFCLSID rclsid)
  105. : _clsid(rclsid), _cRef(1)
  106. { DllAddRef(); }
  107. ~CTemplateUIObj() { DllRelease(); }
  108. HRESULT _CreateInstance(IStorage* pstg);
  109. // IUnKnown
  110. virtual HRESULT __stdcall QueryInterface(REFIID,void **);
  111. virtual ULONG __stdcall AddRef(void);
  112. virtual ULONG __stdcall Release(void);
  113. // *** IExtractIcon methods ***
  114. virtual HRESULT __stdcall GetIconLocation(
  115. UINT uFlags, LPTSTR szIconFile,
  116. UINT cchMax, int * piIndex,
  117. UINT * pwFlags);
  118. virtual HRESULT __stdcall Extract(
  119. LPCTSTR pszFile, UINT nIconIndex,
  120. HICON *phiconLarge, HICON *phiconSmall,
  121. UINT nIconSize);
  122. // IDataObject
  123. virtual HRESULT __stdcall GetData(FORMATETC *pformatetcIn, STGMEDIUM *pmedium);
  124. virtual HRESULT __stdcall GetDataHere(FORMATETC *pformatetc, STGMEDIUM *pmedium);
  125. virtual HRESULT __stdcall QueryGetData(FORMATETC *pformatetc);
  126. virtual HRESULT __stdcall GetCanonicalFormatEtc(FORMATETC *pformatectIn, FORMATETC *pformatetcOut);
  127. virtual HRESULT __stdcall SetData(FORMATETC *pformatetc, STGMEDIUM *pmedium, BOOL fRelease);
  128. virtual HRESULT __stdcall EnumFormatEtc(DWORD dwDirection, IEnumFORMATETC **ppenumFormatEtc);
  129. virtual HRESULT __stdcall DAdvise(FORMATETC *pformatetc, DWORD advf, IAdviseSink *pAdvSink, DWORD *pdwConnection);
  130. virtual HRESULT __stdcall DUnadvise(DWORD dwConnection);
  131. virtual HRESULT __stdcall EnumDAdvise(IEnumSTATDATA **ppenumAdvise);
  132. // IContextMenu
  133. virtual HRESULT __stdcall QueryContextMenu(
  134. HMENU hmenu,
  135. UINT indexMenu,
  136. UINT idCmdFirst,
  137. UINT idCmdLast,
  138. UINT uFlags);
  139. virtual HRESULT __stdcall InvokeCommand(
  140. LPCMINVOKECOMMANDINFO lpici);
  141. virtual HRESULT __stdcall GetCommandString(
  142. UINT idCmd,
  143. UINT uType,
  144. UINT * pwReserved,
  145. LPSTR pszName,
  146. UINT cchMax);
  147. UINT _cRef;
  148. CLSID _clsid;
  149. };
  150. CTemplateFolder::CTemplateFolder() : _cRef(1)
  151. {
  152. _hdpaMap = DPA_Create(10);
  153. OleInitialize(NULL);
  154. DllAddRef();
  155. }
  156. CTemplateFolder::~CTemplateFolder()
  157. {
  158. if (_hdpaMap) {
  159. for (int i = DPA_GetPtrCount(_hdpaMap) - 1; i >= 0; i--) {
  160. PCLSIDMAP pmap = (PCLSIDMAP)DPA_FastGetPtr(_hdpaMap, i);
  161. LocalFree(pmap);
  162. }
  163. DPA_Destroy(_hdpaMap);
  164. }
  165. OleUninitialize();
  166. DllRelease();
  167. }
  168. HRESULT CTemplateFolder::QueryInterface(REFIID riid, LPVOID * ppvObj)
  169. {
  170. if (IsEqualIID(riid, IID_IShellFolder) || IsEqualIID(riid, IID_IUnknown))
  171. {
  172. *ppvObj = (IShellFolder*)this;
  173. _cRef++;
  174. return S_OK;
  175. }
  176. else if (IsEqualIID(riid, IID_IPersistFolder))
  177. {
  178. *ppvObj = (IPersistFolder*)this;
  179. _cRef++;
  180. return S_OK;
  181. }
  182. *ppvObj = NULL;
  183. return E_NOINTERFACE;
  184. }
  185. ULONG CTemplateFolder::AddRef()
  186. {
  187. _cRef++;
  188. return _cRef;
  189. }
  190. ULONG CTemplateFolder::Release()
  191. {
  192. _cRef--;
  193. if (_cRef > 0)
  194. return _cRef;
  195. delete this;
  196. return 0;
  197. }
  198. HRESULT CTemplateFolder_CreateInstance(LPUNKNOWN * ppunk)
  199. {
  200. *ppunk = NULL;
  201. CTemplateFolder* ptfld = new CTemplateFolder();
  202. if (ptfld) {
  203. if (ptfld->ConstructedSuccessfully()) {
  204. *ppunk = (IShellFolder *)ptfld;
  205. return S_OK;
  206. }
  207. ptfld->Release();
  208. }
  209. return E_OUTOFMEMORY;
  210. }
  211. HRESULT CTemplateFolder::ParseDisplayName(HWND hwndOwner,
  212. LPBC pbcReserved, LPOLESTR lpszDisplayName,
  213. ULONG * pchEaten, LPITEMIDLIST * ppidl, ULONG *pdwAttributes)
  214. {
  215. return E_NOTIMPL;
  216. }
  217. HRESULT CTemplateFolder::EnumObjects(HWND hwndOwner, DWORD grfFlags, LPENUMIDLIST * ppenumIDList)
  218. {
  219. *ppenumIDList = new CEnumTemplate(grfFlags);
  220. return *ppenumIDList ? S_OK : E_OUTOFMEMORY;
  221. }
  222. HRESULT CTemplateFolder::BindToObject(LPCITEMIDLIST pidl, LPBC pbcReserved,
  223. REFIID riid, LPVOID * ppvOut)
  224. {
  225. return E_NOTIMPL;
  226. }
  227. HRESULT CTemplateFolder::BindToStorage(LPCITEMIDLIST pidl, LPBC pbcReserved,
  228. REFIID riid, LPVOID * ppvObj)
  229. {
  230. return E_NOTIMPL;
  231. }
  232. //
  233. // If the name is in the cache, celebrate our good fortune and return it.
  234. // Else, go get the name from the registry and cache it for later.
  235. //
  236. HRESULT CTemplateFolder::GetNameOf(LPCITEMIDLIST pidl, LPCTSTR *ppsz)
  237. {
  238. if (!IsMyPidl(pidl))
  239. return E_INVALIDARG;
  240. HRESULT hres;
  241. PTIDL ptidl = (PTIDL)pidl;
  242. CLSIDMAP map;
  243. map.clsid = ptidl->clsid; // Align the CLSID
  244. PCLSIDMAP pmap;
  245. for (int i = DPA_GetPtrCount(_hdpaMap) - 1; i >= 0; i--) {
  246. pmap = (PCLSIDMAP)DPA_FastGetPtr(_hdpaMap, i);
  247. if (IsEqualGUID(pmap->clsid, map.clsid)) {
  248. *ppsz = pmap->achName;
  249. return S_OK;
  250. }
  251. }
  252. //
  253. // Not in cache -- go find it in the registry
  254. //
  255. TCHAR szKey[GUIDSTR_MAX + 6];
  256. _KeyNameFromCLSID(map.clsid, szKey, ARRAYSIZE(szKey));
  257. LONG dwSize = ARRAYSIZE(map.achName);
  258. LONG lError = RegQueryValue(HKEY_CLASSES_ROOT, szKey, map.achName, &dwSize);
  259. if (lError == ERROR_SUCCESS)
  260. {
  261. UINT cb = FIELD_OFFSET(CLSIDMAP, achName[lstrlen(map.achName)+1]);
  262. pmap = (PCLSIDMAP)LocalAlloc(LMEM_FIXED, cb);
  263. if (pmap) {
  264. CopyMemory(pmap, &map, cb);
  265. if (DPA_AppendPtr(_hdpaMap, pmap) >= 0) {
  266. *ppsz = pmap->achName;
  267. hres = S_OK;
  268. } else {
  269. LocalFree(pmap);
  270. hres = E_OUTOFMEMORY;
  271. }
  272. } else {
  273. hres = E_OUTOFMEMORY;
  274. }
  275. }
  276. else
  277. {
  278. hres = HRESULT_FROM_WIN32(lError);
  279. }
  280. return hres;
  281. }
  282. HRESULT CTemplateFolder::CompareIDs(LPARAM lParam, LPCITEMIDLIST pidl1, LPCITEMIDLIST pidl2)
  283. {
  284. LPCTSTR psz1, psz2;
  285. HRESULT hres;
  286. hres = GetNameOf(pidl1, &psz1);
  287. if (SUCCEEDED(hres)) {
  288. hres = GetNameOf(pidl2, &psz2);
  289. if (SUCCEEDED(hres)) {
  290. hres = ResultFromShort(lstrcmpi(psz1, psz2));
  291. }
  292. }
  293. return hres;
  294. }
  295. HRESULT CTemplateFolder::GetDetailsOfDVM(UINT ici, DETAILSINFO *pdi)
  296. {
  297. HRESULT hres;
  298. switch (ici) {
  299. case 0:
  300. if (pdi->pidl) {
  301. hres = GetDisplayNameOf(pdi->pidl, SHGDN_NORMAL, &pdi->str);
  302. } else {
  303. pdi->fmt = LVCFMT_LEFT;
  304. pdi->cxChar = 30;
  305. pdi->str.uType = STRRET_CSTR;
  306. lstrcpyA(pdi->str.cStr, "Name");
  307. hres = S_OK;
  308. }
  309. break;
  310. default:
  311. hres = E_NOTIMPL;
  312. break;
  313. }
  314. return hres;
  315. }
  316. HRESULT CALLBACK DefViewCallback(LPSHELLVIEW psvOuter, LPSHELLFOLDER psf,
  317. HWND hwndOwner, UINT uMsg, WPARAM wParam, LPARAM lParam)
  318. {
  319. // DefView GPF if I don't pass the callback function!
  320. // DebugMsg(DM_TRACE, "sc TR - DefViewCallBack %d,%x,%x", uMsg, wParam, lParam);
  321. switch(uMsg)
  322. {
  323. case DVM_WINDOWDESTROY:
  324. DebugMsg(DM_TRACE, TEXT("sc TR - DefViewCallBack Calling OleFlushClipboard"));
  325. OleFlushClipboard();
  326. return S_OK;
  327. case DVM_GETDETAILSOF:
  328. return ((CTemplateFolder*)psf)->GetDetailsOfDVM((UINT)wParam, (DETAILSINFO*)lParam);
  329. }
  330. // DefView GPF if it returns S_FALSE as the default!
  331. return E_FAIL; // S_FALSE;
  332. }
  333. HRESULT CTemplateFolder::CreateViewObject (HWND hwndOwner, REFIID riid, LPVOID * ppvOut)
  334. {
  335. if (IsEqualIID(riid, IID_IShellView))
  336. {
  337. CSFV csfv = {
  338. SIZEOF(CSFV), // cbSize
  339. this, // pshf
  340. NULL, // psvOuter
  341. NULL, // pidl
  342. 0,
  343. DefViewCallback, // pfnCallback
  344. FVM_ICON,
  345. };
  346. return SHCreateShellFolderViewEx(&csfv, (LPSHELLVIEW *)ppvOut);
  347. }
  348. return E_NOINTERFACE;
  349. }
  350. HRESULT CTemplateFolder::GetAttributesOf(UINT cidl, LPCITEMIDLIST * apidl,
  351. ULONG * rgfInOut)
  352. {
  353. if (cidl==1)
  354. {
  355. UINT rgfOut = SFGAO_CANCOPY /* | SFGAO_HASPROPSHEET */;
  356. *rgfInOut &= rgfOut;
  357. }
  358. else
  359. {
  360. *rgfInOut = 0;
  361. }
  362. return S_OK;
  363. }
  364. HRESULT CTemplateFolder::GetUIObjectOf(HWND hwndOwner, UINT cidl, LPCITEMIDLIST * apidl,
  365. REFIID riid, UINT * prgfInOut, LPVOID * ppvOut)
  366. {
  367. HRESULT hres = E_INVALIDARG;
  368. if (cidl==1 && IsMyPidl(apidl[0]))
  369. {
  370. PTIDL ptidl = (PTIDL)apidl[0];
  371. hres = CTemplateUIObj::Create(ptidl->clsid, riid, ppvOut);
  372. }
  373. return hres;
  374. }
  375. HRESULT _KeyNameFromCLSID(REFCLSID rclsid, LPTSTR pszKey, UINT cchMax)
  376. {
  377. ASSERT(cchMax - 6 >= GUIDSTR_MAX);
  378. lstrcpyn(pszKey, TEXT("CLSID\\"), cchMax);
  379. SHStringFromGUID(rclsid, pszKey + 6, cchMax - 6);
  380. return S_OK;
  381. }
  382. HRESULT CTemplateFolder::GetDisplayNameOf(LPCITEMIDLIST pidl, DWORD uFlags, LPSTRRET lpName)
  383. {
  384. LPCTSTR psz;
  385. HRESULT hres;
  386. hres = GetNameOf(pidl, &psz);
  387. if (SUCCEEDED(hres)) {
  388. #ifdef UNICODE
  389. lpName->uType = STRRET_WSTR;
  390. hres = SHStrDupW(psz, &lpName->pOleStr);
  391. #else
  392. lstrcpyn(lpName->cStr, psz, ARRAYSIZE(lpName->cStr));
  393. hres = S_OK;
  394. #endif
  395. }
  396. return hres;
  397. }
  398. HRESULT CTemplateFolder::SetNameOf(HWND hwndOwner, LPCITEMIDLIST pidl,
  399. LPCOLESTR lpszName, DWORD uFlags,
  400. LPITEMIDLIST * ppidlOut)
  401. {
  402. return E_NOTIMPL;
  403. }
  404. HRESULT __stdcall CTemplateFolder::GetClassID(LPCLSID lpClassID)
  405. {
  406. *lpClassID = CLSID_CTemplateFolder;
  407. return S_OK;
  408. }
  409. HRESULT __stdcall CTemplateFolder::Initialize(LPCITEMIDLIST pidl)
  410. {
  411. return S_OK;
  412. }
  413. CEnumTemplate::CEnumTemplate(DWORD grfFlags)
  414. : _cRef(1), _grfFlags(grfFlags), _iCur(0), _hkeyCLSID(NULL)
  415. {
  416. DllAddRef();
  417. }
  418. CEnumTemplate::~CEnumTemplate()
  419. {
  420. if (_hkeyCLSID) {
  421. RegCloseKey(_hkeyCLSID);
  422. }
  423. DllRelease();
  424. }
  425. HRESULT CEnumTemplate::QueryInterface(REFIID riid, LPVOID * ppvObj)
  426. {
  427. if (IsEqualIID(riid, IID_IEnumIDList) || IsEqualIID(riid, IID_IUnknown))
  428. {
  429. *ppvObj = (IEnumIDList*)this;
  430. _cRef++;
  431. return S_OK;
  432. }
  433. *ppvObj = NULL;
  434. return E_NOINTERFACE;
  435. }
  436. ULONG CEnumTemplate::AddRef()
  437. {
  438. _cRef++;
  439. return _cRef;
  440. }
  441. ULONG CEnumTemplate::Release()
  442. {
  443. _cRef--;
  444. if (_cRef > 0)
  445. return _cRef;
  446. delete this;
  447. return 0;
  448. }
  449. HRESULT CEnumTemplate::Next(ULONG celt,
  450. LPITEMIDLIST *rgelt,
  451. ULONG *pceltFetched)
  452. {
  453. // Assume error
  454. if (pceltFetched) {
  455. *pceltFetched = 0;
  456. }
  457. if (!(_grfFlags & SHCONTF_NONFOLDERS)) {
  458. return S_FALSE;
  459. }
  460. if (!_hkeyCLSID)
  461. {
  462. if (RegOpenKey(HKEY_CLASSES_ROOT, c_szCLSID, &_hkeyCLSID) != ERROR_SUCCESS)
  463. {
  464. return E_FAIL;
  465. }
  466. }
  467. TCHAR szKeyBuf[128]; // enough for {CLSID} or "ProgId/XXX"
  468. // Subtract 64 to allow room for the goo we append later on
  469. while (RegEnumKey(HKEY_CLASSES_ROOT, _iCur++, szKeyBuf, ARRAYSIZE(szKeyBuf) - 64) == ERROR_SUCCESS)
  470. {
  471. TCHAR szT[128];
  472. LONG dwRead;
  473. int cchKey = lstrlen(szKeyBuf);
  474. // Check for \NotInsertable.
  475. lstrcpy(szKeyBuf+cchKey, TEXT("\\NotInsertable"));
  476. dwRead = ARRAYSIZE(szT);
  477. if (RegQueryValue(HKEY_CLASSES_ROOT, szKeyBuf, szT, &dwRead) == ERROR_SUCCESS) {
  478. continue;
  479. }
  480. BOOL fInsertable = FALSE;
  481. //
  482. // Let's stop supporting OLE1 servers anymore.
  483. //
  484. #if 0
  485. lstrcpy(szKeyBuf+cchKey, TEXT("\\protocol\\StdFileEditing\\server"));
  486. dwRead = ARRAYSIZE(szT);
  487. if (RegQueryValue(HKEY_CLASSES_ROOT, szKeyBuf, szT, &dwRead) == ERROR_SUCCESS)
  488. {
  489. fInsertable = TRUE;
  490. }
  491. else
  492. #endif
  493. {
  494. lstrcpy(szKeyBuf+cchKey, TEXT("\\Insertable"));
  495. dwRead = ARRAYSIZE(szT);
  496. if (RegQueryValue(HKEY_CLASSES_ROOT, szKeyBuf, szT, &dwRead) == ERROR_SUCCESS)
  497. {
  498. fInsertable = TRUE;
  499. }
  500. }
  501. if (fInsertable)
  502. {
  503. lstrcpy(szKeyBuf+cchKey, TEXT("\\CLSID"));
  504. dwRead = ARRAYSIZE(szT);
  505. if (RegQueryValue(HKEY_CLASSES_ROOT, szKeyBuf, szT, &dwRead) == ERROR_SUCCESS)
  506. {
  507. TIDLCONS tidlCons;
  508. CLSID clsid; // Aligned version
  509. tidlCons.tidl.cb = sizeof(TIDL);
  510. tidlCons.tidl.abID[0] = 'S';
  511. tidlCons.tidl.abID[1] = 'N';
  512. if (GUIDFromString(szT, &clsid))
  513. {
  514. tidlCons.tidl.clsid = clsid;
  515. tidlCons.cbZero = 0;
  516. rgelt[0] = ILClone((LPITEMIDLIST)&tidlCons);
  517. *pceltFetched = 1;
  518. return S_OK;
  519. }
  520. }
  521. }
  522. }
  523. return S_FALSE; // no more element
  524. }
  525. HRESULT CEnumTemplate::Skip(ULONG celt)
  526. {
  527. return E_NOTIMPL;
  528. }
  529. HRESULT CEnumTemplate::Reset()
  530. {
  531. return E_NOTIMPL;
  532. }
  533. HRESULT CEnumTemplate::Clone(IEnumIDList **ppenum)
  534. {
  535. return E_NOTIMPL;
  536. }
  537. //==========================================================================
  538. // CTemplateUIObj members (IUnknown override)
  539. //==========================================================================
  540. HRESULT CTemplateUIObj::QueryInterface(REFIID riid, LPVOID * ppvObj)
  541. {
  542. if (IsEqualIID(riid, IID_IExtractIcon) || IsEqualIID(riid, IID_IUnknown))
  543. {
  544. *ppvObj = (IExtractIcon*)this;
  545. _cRef++;
  546. return S_OK;
  547. }
  548. else if (IsEqualIID(riid, IID_IDataObject))
  549. {
  550. *ppvObj = (IDataObject*)this;
  551. _cRef++;
  552. return S_OK;
  553. }
  554. else if (IsEqualIID(riid, IID_IContextMenu))
  555. {
  556. *ppvObj = (IContextMenu*)this;
  557. _cRef++;
  558. return S_OK;
  559. }
  560. *ppvObj = NULL;
  561. return E_NOINTERFACE;
  562. }
  563. ULONG CTemplateUIObj::AddRef()
  564. {
  565. _cRef++;
  566. return _cRef;
  567. }
  568. ULONG CTemplateUIObj::Release()
  569. {
  570. _cRef--;
  571. if (_cRef > 0)
  572. return _cRef;
  573. delete this;
  574. return 0;
  575. }
  576. //
  577. // NOTES: This logic MUST be identical to the one in the shell.
  578. //
  579. int _ParseIconLocation(LPTSTR pszIconFile)
  580. {
  581. int iIndex = 0;
  582. LPTSTR pszComma = StrChr(pszIconFile, TEXT(','));
  583. if (pszComma) {
  584. *pszComma++ = 0; // terminate the icon file name.
  585. iIndex = StrToInt(pszComma);
  586. }
  587. PathRemoveBlanks(pszIconFile);
  588. return iIndex;
  589. }
  590. //==========================================================================
  591. // CTemplateUIObj members (IExtractIcon override)
  592. //==========================================================================
  593. //
  594. // szClass -- Specifies either CLSID\{CLSID} or ProgID
  595. //
  596. HRESULT _GetDefaultIcon(LPCTSTR szClass, LPTSTR szIconFile, UINT cchMax, int *piIndex)
  597. {
  598. TCHAR szKey[256];
  599. wsprintf(szKey, TEXT("%s\\DefaultIcon"), szClass);
  600. TCHAR szValue[MAX_PATH+40];
  601. LONG dwSize = ARRAYSIZE(szValue);
  602. if (RegQueryValue(HKEY_CLASSES_ROOT, szKey, szValue, &dwSize) == ERROR_SUCCESS)
  603. {
  604. *piIndex = _ParseIconLocation(szValue);
  605. lstrcpyn(szIconFile, szValue, cchMax);
  606. return S_OK;
  607. }
  608. return E_FAIL;
  609. }
  610. HRESULT CTemplateUIObj::GetIconLocation(
  611. UINT uFlags, LPTSTR szIconFile,
  612. UINT cchMax, int * piIndex,
  613. UINT * pwFlags)
  614. {
  615. *pwFlags = GIL_PERCLASS; // Always per-class
  616. TCHAR szKey[128];
  617. HRESULT hres = _KeyNameFromCLSID(_clsid, szKey, ARRAYSIZE(szKey));
  618. if (SUCCEEDED(hres))
  619. {
  620. //
  621. // First, look at "CLSID\{CLSID}\DefautlIcon"
  622. //
  623. hres = _GetDefaultIcon(szKey, szIconFile, cchMax, piIndex);
  624. if (FAILED(hres))
  625. {
  626. //
  627. // Then, look at "ProgID\DefaultIcon" to work-around a bug
  628. // of "Wave Sound".
  629. //
  630. lstrcat(szKey, TEXT("\\ProgID"));
  631. TCHAR szValue[MAX_PATH+40];
  632. LONG dwSize = ARRAYSIZE(szValue);
  633. if (RegQueryValue(HKEY_CLASSES_ROOT, szKey, szValue, &dwSize) == ERROR_SUCCESS)
  634. {
  635. hres = _GetDefaultIcon(szValue, szIconFile, cchMax, piIndex);
  636. }
  637. }
  638. }
  639. return hres;
  640. }
  641. HRESULT CTemplateUIObj::Extract(
  642. LPCTSTR pszFile, UINT nIconIndex,
  643. HICON *phiconLarge, HICON *phiconSmall,
  644. UINT nIconSize)
  645. {
  646. return S_FALSE;
  647. }
  648. HRESULT CTemplateUIObj::Create(REFCLSID rclsid, REFIID riid, LPVOID* ppvOut)
  649. {
  650. CTemplateUIObj *pti = new CTemplateUIObj(rclsid);
  651. HRESULT hres;
  652. if (pti) {
  653. hres = pti->QueryInterface(riid, ppvOut);
  654. pti->Release();
  655. return hres;
  656. }
  657. *ppvOut=NULL;
  658. return E_OUTOFMEMORY;
  659. }
  660. //==========================================================================
  661. // CTemplateUIObj members (IDataObject override)
  662. //==========================================================================
  663. HRESULT CTemplateUIObj::_CreateInstance(IStorage* pstg)
  664. {
  665. HRESULT hres;
  666. IPersistStorage* pps = NULL;
  667. hres = OleCreate(_clsid, IID_IPersistStorage, OLERENDER_DRAW,
  668. NULL, NULL, pstg, (LPVOID*)&pps);
  669. DebugMsg(DM_TRACE, TEXT("so TR - TUO:CI OleCreate returned (%x)"), hres);
  670. if (SUCCEEDED(hres))
  671. {
  672. hres = OleSave(pps, pstg, TRUE);
  673. DebugMsg(DM_TRACE, TEXT("so TR - TUO:CI OleSave returned (%x)"), hres);
  674. pps->HandsOffStorage();
  675. pps->Release();
  676. if (SUCCEEDED(hres))
  677. {
  678. hres = pstg->Commit(STGC_OVERWRITE);
  679. DebugMsg(DM_TRACE, TEXT("so TR - TUO:CI pstg->Commit returned (%x)"), hres);
  680. }
  681. }
  682. return hres;
  683. }
  684. HRESULT CTemplateUIObj::GetData(LPFORMATETC pformatetcIn, LPSTGMEDIUM pmedium)
  685. {
  686. HRESULT hres = DATA_E_FORMATETC;
  687. pmedium->pUnkForRelease = NULL;
  688. pmedium->pstg = NULL;
  689. //
  690. // NOTES: We should avoid calling _OpenStorage if we don't support
  691. // the format.
  692. //
  693. if (pformatetcIn->cfFormat == CF_EMBEDDEDOBJECT
  694. && pformatetcIn->tymed == TYMED_ISTORAGE)
  695. {
  696. IStorage* pstg = NULL;
  697. hres = StgCreateDocfile(NULL, STGM_DIRECT | STGM_CREATE | STGM_READWRITE | STGM_SHARE_EXCLUSIVE, 0, &pstg);
  698. DebugMsg(DM_TRACE, TEXT("so TR - TUO:GD StgCreateDocfile returned (%x)"), hres);
  699. if (SUCCEEDED(hres))
  700. {
  701. hres = _CreateInstance(pstg);
  702. if (SUCCEEDED(hres)) {
  703. pmedium->tymed = TYMED_ISTORAGE;
  704. pmedium->pstg = pstg;
  705. } else {
  706. pstg->Release();
  707. }
  708. }
  709. }
  710. else if (pformatetcIn->cfFormat == CF_OBJECTDESCRIPTOR
  711. && pformatetcIn->tymed == TYMED_HGLOBAL)
  712. {
  713. DebugMsg(DM_TRACE, TEXT("so TR - TUO:GD cfFormat==CF_OBJECTDESCRIPTOR"));
  714. static WCHAR szUserTypeName[] = L"Foo"; // REARCHITECT: this code is really miss, and might end up returning Foo
  715. static WCHAR szSrcOfCopy[] = L"Bar";
  716. UINT cbUserTypeName = sizeof(szUserTypeName);
  717. UINT cbSrcOfCopy = sizeof(szSrcOfCopy);
  718. pmedium->hGlobal = GlobalAlloc(GPTR, sizeof(OBJECTDESCRIPTOR)+cbUserTypeName+cbSrcOfCopy);
  719. if (pmedium->hGlobal)
  720. {
  721. OBJECTDESCRIPTOR* podsc = (OBJECTDESCRIPTOR*)pmedium->hGlobal;
  722. podsc->cbSize = sizeof(OBJECTDESCRIPTOR);
  723. podsc->clsid = _clsid;
  724. podsc->dwDrawAspect = 0; // The source does not draw the object
  725. // podsc->sizel = { 0, 0 }; // The source does not draw the object
  726. // podsc->pointl = { 0, 0 };
  727. podsc->dwStatus = 0; // FEATURE: read it from registry! CLSID/MiscStatus
  728. podsc->dwFullUserTypeName = sizeof(OBJECTDESCRIPTOR);
  729. podsc->dwSrcOfCopy = sizeof(OBJECTDESCRIPTOR)+cbUserTypeName;
  730. LPBYTE pbT = (LPBYTE)(podsc+1);
  731. lstrcpyW((LPWSTR)pbT, szUserTypeName);
  732. lstrcpyW((LPWSTR)(pbT+cbUserTypeName), szSrcOfCopy);
  733. Assert(pbT == ((LPBYTE)podsc)+podsc->dwFullUserTypeName);
  734. Assert(pbT+cbUserTypeName == ((LPBYTE)podsc)+podsc->dwSrcOfCopy);
  735. pmedium->tymed = TYMED_HGLOBAL;
  736. hres = S_OK;
  737. }
  738. else
  739. {
  740. hres = E_OUTOFMEMORY;
  741. }
  742. }
  743. return hres;
  744. }
  745. HRESULT CTemplateUIObj::GetDataHere(LPFORMATETC pformatetcIn, LPSTGMEDIUM pmedium)
  746. {
  747. HRESULT hres = DATA_E_FORMATETC;
  748. if (pformatetcIn->cfFormat == CF_EMBEDDEDOBJECT
  749. && pformatetcIn->tymed == TYMED_ISTORAGE && pmedium->tymed == TYMED_ISTORAGE)
  750. {
  751. hres = _CreateInstance(pmedium->pstg);
  752. }
  753. return hres;
  754. }
  755. HRESULT CTemplateUIObj::QueryGetData(LPFORMATETC pformatetcIn)
  756. {
  757. if (pformatetcIn->cfFormat == CF_EMBEDDEDOBJECT
  758. && pformatetcIn->tymed == TYMED_ISTORAGE)
  759. {
  760. return S_OK;
  761. }
  762. else if (pformatetcIn->cfFormat == CF_OBJECTDESCRIPTOR
  763. && pformatetcIn->tymed == TYMED_HGLOBAL)
  764. {
  765. return S_OK;
  766. }
  767. return DATA_E_FORMATETC;
  768. }
  769. HRESULT CTemplateUIObj::GetCanonicalFormatEtc(LPFORMATETC pformatetc, LPFORMATETC pformatetcOut)
  770. {
  771. //
  772. // This is the simplest implemtation. It means we always return
  773. // the data in the format requested.
  774. //
  775. return ResultFromScode(DATA_S_SAMEFORMATETC);
  776. }
  777. HRESULT CTemplateUIObj::SetData(LPFORMATETC pformatetc, STGMEDIUM * pmedium, BOOL fRelease)
  778. {
  779. return E_FAIL;
  780. }
  781. HRESULT CTemplateUIObj::EnumFormatEtc(DWORD dwDirection, LPENUMFORMATETC * ppenumFormatEtc)
  782. {
  783. static FORMATETC s_afmt[] = { { (CLIPFORMAT)CF_EMBEDDEDOBJECT }, {(CLIPFORMAT)CF_OBJECTDESCRIPTOR} };
  784. return SHCreateStdEnumFmtEtc(ARRAYSIZE(s_afmt), s_afmt, ppenumFormatEtc);
  785. }
  786. HRESULT CTemplateUIObj::DAdvise(FORMATETC * pFormatetc, DWORD advf, LPADVISESINK pAdvSink, DWORD * pdwConnection)
  787. {
  788. return ResultFromScode(OLE_E_ADVISENOTSUPPORTED);
  789. }
  790. HRESULT CTemplateUIObj::DUnadvise(DWORD dwConnection)
  791. {
  792. return ResultFromScode(OLE_E_ADVISENOTSUPPORTED);
  793. }
  794. HRESULT CTemplateUIObj::EnumDAdvise(LPENUMSTATDATA * ppenumAdvise)
  795. {
  796. return ResultFromScode(OLE_E_ADVISENOTSUPPORTED);
  797. }
  798. #define TIDC_INVALID -1
  799. #define TIDC_COPY 0
  800. #define TIDC_MAX 1
  801. HRESULT CTemplateUIObj::QueryContextMenu(
  802. HMENU hmenu,
  803. UINT indexMenu,
  804. UINT idCmdFirst,
  805. UINT idCmdLast,
  806. UINT uFlags)
  807. {
  808. DebugMsg(DM_TRACE, TEXT("sc TR - CTUI::QCM called (uFlags=%x)"), uFlags);
  809. //
  810. // REVIEW: Checking CMF_DVFILE is subtle, need to be documented clearly!
  811. //
  812. if (!(uFlags & (CMF_VERBSONLY|CMF_DVFILE)))
  813. {
  814. MENUITEMINFO mii = {
  815. sizeof(MENUITEMINFO),
  816. MIIM_STATE|MIIM_ID|MIIM_TYPE,
  817. MFT_STRING,
  818. MFS_DEFAULT,
  819. idCmdFirst+TIDC_COPY,
  820. NULL, NULL, NULL, 0,
  821. TEXT("&Copy"), // FEATURE: Support NLS, the Copy operation might have a different name in other languages
  822. 5
  823. };
  824. InsertMenuItem(hmenu, indexMenu++, TRUE, &mii);
  825. }
  826. return ResultFromShort(TIDC_MAX);
  827. }
  828. HRESULT CTemplateUIObj::InvokeCommand(
  829. LPCMINVOKECOMMANDINFO lpici)
  830. {
  831. HRESULT hres;
  832. DebugMsg(DM_TRACE, TEXT("sc TR - CTUI::IC called (%x)"), lpici->lpVerb);
  833. int idCmd = TIDC_INVALID;
  834. if (HIWORD(lpici->lpVerb))
  835. {
  836. if (lstrcmpiA(lpici->lpVerb, "copy") == 0) {
  837. idCmd = TIDC_COPY;
  838. }
  839. }
  840. else
  841. {
  842. idCmd = LOWORD(lpici->lpVerb);
  843. }
  844. switch(idCmd)
  845. {
  846. case TIDC_COPY:
  847. hres = OleSetClipboard(this);
  848. break;
  849. default:
  850. hres = E_INVALIDARG;
  851. break;
  852. }
  853. return hres;
  854. }
  855. HRESULT CTemplateUIObj::GetCommandString(
  856. UINT idCmd,
  857. UINT uType,
  858. UINT * pwReserved,
  859. LPSTR pszName,
  860. UINT cchMax)
  861. {
  862. DebugMsg(DM_TRACE, TEXT("sc TR - CTUI::GCS called (%d, %x)"), idCmd, uType);
  863. return E_NOTIMPL;
  864. }
  865. #endif // FEATURE_SHELLEXTENSION