Source code of Windows XP (NT5)
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.

844 lines
22 KiB

  1. /*
  2. * template - Dialog box property sheet for "Templates"
  3. */
  4. #include "tweakui.h"
  5. #define ctchProgMax 80
  6. #pragma BEGIN_CONST_DATA
  7. const static DWORD CODESEG rgdwHelp[] = {
  8. IDC_TEMPLATETEXT, IDH_TEMPLATE,
  9. IDC_TEMPLATE, IDH_TEMPLATE,
  10. IDC_LVDELETE, IDH_TEMPLATEDEL,
  11. 0, 0,
  12. };
  13. #pragma END_CONST_DATA
  14. typedef struct TI { /* ti - template info */
  15. BYTE isi; /* Index to state icon */
  16. HKEY hkRoot; /* Root for locating the key */
  17. /* HKCR or HKCR\CLSID */
  18. TCH tszExt[10]; /* Filename extension (for icon refresh) */
  19. TCH tszKey[ctchKeyMax + 6]; /* 6 = strlen("\\CLSID") */
  20. } TI, *PTI;
  21. #define itiPlvi(plvi) ((UINT)(plvi)->lParam)
  22. #define ptiIti(iti) (&ptdii->pti[iti])
  23. #define ptiPlvi(plvi) ptiIti(itiPlvi(plvi))
  24. typedef struct TDII {
  25. Declare_Gxa(TI, ti);
  26. WNDPROC wpTemplate;
  27. BOOL fRundll; /* Need to run Rundll on Apply */
  28. } TDII, *PTDII;
  29. TDII tdii;
  30. #define ptdii (&tdii)
  31. /*****************************************************************************
  32. *
  33. * ptszStrRChr
  34. *
  35. * Get the rightmost occurrence.
  36. *
  37. *****************************************************************************/
  38. PTSTR PASCAL
  39. ptszStrRChr(PCTSTR ptsz, TCH tch)
  40. {
  41. PTSTR ptszRc = 0;
  42. for (ptsz = ptszStrChr(ptsz, tch); ptsz; ptsz = ptszStrChr(ptsz + 1, tch)) {
  43. ptszRc = (PTSTR)ptsz;
  44. }
  45. return ptszRc;
  46. }
  47. /*****************************************************************************
  48. *
  49. * ptszFilenameCqn
  50. *
  51. * Get the filename part of a cqn.
  52. *
  53. *****************************************************************************/
  54. PTSTR PASCAL
  55. ptszFilenameCqn(PCTSTR cqn)
  56. {
  57. PTSTR ptsz = ptszStrRChr(cqn, TEXT('\\'));
  58. return ptsz ? ptsz + 1 : (PTSTR)cqn;
  59. }
  60. /*****************************************************************************
  61. *
  62. * Path_Append
  63. *
  64. * Append a filename to a directory, inserting a backslash
  65. * as necessary.
  66. *
  67. *****************************************************************************/
  68. void
  69. Path_Append(LPTSTR ptszDir, LPCTSTR ptszFile)
  70. {
  71. ptszDir = TweakUi_TrimTrailingBs(ptszDir);
  72. *ptszDir++ = TEXT('\\');
  73. lstrcpy(ptszDir, ptszFile);
  74. }
  75. /*****************************************************************************
  76. *
  77. * Template_NudgeExplorer
  78. *
  79. * Explorer doesn't recognize changes to templates until an application
  80. * terminates, so we simply execute Rundll spuriously. It realizes that
  81. * there is nothing to do and exits. This exit triggers Explorer to
  82. * rebuild the filename extension list.
  83. *
  84. * This nudge doesn't work on NT 5, so we also have to nuke the
  85. * ShellNew cache.
  86. *
  87. *****************************************************************************/
  88. #pragma BEGIN_CONST_DATA
  89. ConstString(c_tszRundll, "rundll32");
  90. #pragma END_CONST_DATA
  91. void PASCAL
  92. Template_NudgeExplorer(void)
  93. {
  94. WinExec(c_tszRundll, SW_HIDE);
  95. RegDeleteTree(g_hkCUSMWCV, TEXT("Explorer\\Discardable\\PostSetup\\ShellNew"));
  96. }
  97. /*****************************************************************************
  98. *
  99. * Template_SubkeyExists
  100. *
  101. *****************************************************************************/
  102. BOOL PASCAL
  103. Template_SubkeyExists(HKEY hk, PCTSTR ptszSubkey)
  104. {
  105. return GetRegStr(hk, 0, ptszSubkey, 0, 0);
  106. }
  107. /*****************************************************************************
  108. *
  109. * Template_AddTemplateInfo
  110. *
  111. * pti must be the next ti in the array (i.e., Misc_AllocPx)
  112. *
  113. * Returns the icon index, if successful, or -1 on error.
  114. *
  115. *****************************************************************************/
  116. int PASCAL
  117. Template_AddTemplateInfo(HWND hwnd, PCTSTR ptszExt, PTI pti, BOOL fCheck)
  118. {
  119. int iRc;
  120. SHFILEINFO sfi;
  121. if (SHGetFileInfo(ptszExt, 0, &sfi, cbX(sfi),
  122. SHGFI_TYPENAME | SHGFI_USEFILEATTRIBUTES |
  123. SHGFI_SYSICONINDEX | SHGFI_SMALLICON)) {
  124. pti->isi = fCheck + 1;
  125. iRc = LV_AddItem(hwnd, ptdii->cti++, sfi.szTypeName, sfi.iIcon, fCheck);
  126. } else {
  127. iRc = -1;
  128. }
  129. return iRc;
  130. }
  131. /*****************************************************************************
  132. *
  133. * TemplateCallbackInfo
  134. *
  135. * Information handed to a template callback.
  136. *
  137. * hk - The ptszShellNew subkey itself
  138. *
  139. *****************************************************************************/
  140. typedef BOOL (PASCAL *TCICALLBACK)(struct TCI *ptci, HKEY hk,
  141. PCTSTR ptszShellNew);
  142. typedef struct TCI {
  143. TCICALLBACK pfn;
  144. PTI pti; /* Template info containing result */
  145. HWND hwnd; /* Listview window handle */
  146. PCTSTR ptszExt; /* The .ext being studied */
  147. } TCI, *PTCI;
  148. /*****************************************************************************
  149. *
  150. * Template_CheckShellNew
  151. *
  152. * Look for the ShellNew stuff (or ShellNew- if temporarily disabled).
  153. *
  154. * Returns boolean success/failure.
  155. *
  156. * If ptszExt exists, then we create the key, too.
  157. *
  158. *****************************************************************************/
  159. BOOL PASCAL
  160. Template_CheckShellNew(PTCI ptci, HKEY hkBase, PCTSTR ptszShellNew)
  161. {
  162. HKEY hk;
  163. BOOL fRc;
  164. if (_RegOpenKey(hkBase, ptszShellNew, &hk) == 0) {
  165. if (Template_SubkeyExists(hk, c_tszNullFile) ||
  166. Template_SubkeyExists(hk, c_tszFileName) ||
  167. Template_SubkeyExists(hk, c_tszCommand) ||
  168. Template_SubkeyExists(hk, c_tszData)) {
  169. fRc = ptci->pfn(ptci, hk, ptszShellNew);
  170. } else {
  171. fRc = 0;
  172. }
  173. RegCloseKey(hk);
  174. } else {
  175. fRc = 0;
  176. }
  177. return fRc;
  178. }
  179. /*****************************************************************************
  180. *
  181. * Template_AddHkeyTemplate
  182. *
  183. * We have a candidate location for a ShellNew.
  184. *
  185. * There is some weirdness here. The actual ShellNew can live at
  186. * a sublevel. For example, the ".doc" extension contains several
  187. * ShellNew's:
  188. *
  189. * HKCR\.doc = WordPad.Document.1
  190. * HKCR\.doc\WordDocument\ShellNew
  191. * HKCR\.doc\Word.Document.6\ShellNew
  192. * HKCR\.doc\WordPad.Document.1\ShellNew
  193. *
  194. * Based on the main value (HKCR\.doc), we choose to use the template
  195. * for "Wordpad.Document.1".
  196. *
  197. * pti->hkRoot - hkey at which to start (either HKCR or HKCR\CLSID)
  198. * pti->tszKey - subkey to open (.ext or {guid})
  199. *
  200. * pti->hkRoot\pti->tszKey = actual key to open
  201. *
  202. * hkBase = the key at hkRoot\ptszKey
  203. * hk = the key where ShellNew actually lives
  204. *
  205. *****************************************************************************/
  206. BOOL PASCAL
  207. Template_AddHkeyTemplate(PTCI ptci)
  208. {
  209. HKEY hkBase;
  210. BOOL fRc;
  211. PTI pti = ptci->pti;
  212. if (_RegOpenKey(pti->hkRoot, pti->tszKey, &hkBase) == 0) {
  213. TCH tszProg[ctchProgMax+1];
  214. if (GetRegStr(hkBase, 0, 0, tszProg, cbX(tszProg))) {
  215. HKEY hk = NULL;
  216. if (_RegOpenKey(hkBase, tszProg, &hk) == 0) {
  217. lstrcatnBsA(pti->tszKey, tszProg);
  218. } else {
  219. _RegOpenKey(hkBase, 0, &hk); /* hk = AddRef(hkBase) */
  220. }
  221. if (hk) {
  222. /* Now open the ShellNew subkey or the ShellNew- subkey */
  223. fRc = fLorFF(Template_CheckShellNew(ptci, hk, c_tszShellNew),
  224. Template_CheckShellNew(ptci, hk, c_tszShellNewDash));
  225. RegCloseKey(hk);
  226. } else {
  227. fRc = 0;
  228. }
  229. } else {
  230. fRc = 0;
  231. }
  232. } else {
  233. fRc = 0;
  234. }
  235. return fRc;
  236. }
  237. /*****************************************************************************
  238. *
  239. * Template_LocateExtension
  240. *
  241. * We have a filename extension (ptci->ptszExt).
  242. *
  243. * Get its program id (progid).
  244. *
  245. * We look in two places. If the progid has a registered CLSID
  246. * (HKCR\progid\CLSID), then we look in HKCR\CLSID\{guid}.
  247. *
  248. * If the CLSID fails to locate anything, then we look under
  249. * HKCR\.ext directly.
  250. *
  251. *****************************************************************************/
  252. BOOL PASCAL
  253. Template_LocateExtension(PTCI ptci)
  254. {
  255. BOOL fRc;
  256. PTI pti = ptci->pti = (PTI)Misc_AllocPx(&ptdii->gxa);
  257. if (pti) {
  258. TCH tszProg[ctchProgMax + ctchKeyMax + 6]; /* 6 = strlen(\\CLSID) */
  259. lstrcpyn(pti->tszExt, ptci->ptszExt, cA(pti->tszExt));
  260. if (GetRegStr(hkCR, ptci->ptszExt, 0, tszProg, cbCtch(ctchProgMax)) &&
  261. tszProg[0]) {
  262. /*
  263. * Make sure the progid exists, or we end up putting garbage
  264. * into the listview.
  265. */
  266. if (RegKeyExists(hkCR, tszProg)) {
  267. /*
  268. * Is this an OLE class?
  269. */
  270. lstrcatnBsA(tszProg, c_tszClsid);
  271. if (GetRegStr(hkCR, tszProg, 0,
  272. pti->tszKey, cbX(pti->tszKey))) {
  273. pti->hkRoot = pcdii->hkClsid;
  274. fRc = Template_AddHkeyTemplate(ptci);
  275. } else {
  276. fRc = 0;
  277. }
  278. /*
  279. * If we haven't succeeded yet, then try under the extension
  280. * itself.
  281. */
  282. if (!fRc) {
  283. pti->hkRoot = hkCR;
  284. lstrcpyn(pti->tszKey, ptci->ptszExt, cA(pti->tszKey));
  285. fRc = Template_AddHkeyTemplate(ptci);
  286. }
  287. } else {
  288. fRc = 0;
  289. }
  290. } else {
  291. fRc = 0;
  292. }
  293. } else {
  294. fRc = 0;
  295. }
  296. return fRc;
  297. }
  298. /*****************************************************************************
  299. *
  300. * Template_AddTemplates_AddMe
  301. *
  302. * Add any templates that exist.
  303. *
  304. * For each filename extension, get its corresponding class.
  305. * Then ask Template_LocateExtension to do the rest.
  306. *
  307. *****************************************************************************/
  308. BOOL PASCAL
  309. Template_AddTemplates_AddMe(PTCI ptci, HKEY hk, PCTSTR ptszShellNew)
  310. {
  311. return Template_AddTemplateInfo(ptci->hwnd, ptci->ptszExt,
  312. ptci->pti,
  313. ptszShellNew == c_tszShellNew) + 1;
  314. }
  315. /*****************************************************************************
  316. *
  317. * Template_AddTemplates
  318. *
  319. * Add any templates that exist.
  320. *
  321. * For each filename extension, get its corresponding class.
  322. * Then ask Template_LocateExtension to do the rest.
  323. *
  324. *****************************************************************************/
  325. void PASCAL
  326. Template_AddTemplates(HWND hwnd)
  327. {
  328. int i;
  329. TCI tci;
  330. TCH tszExt[10];
  331. tci.pfn = Template_AddTemplates_AddMe;
  332. tci.hwnd = hwnd;
  333. tci.ptszExt = tszExt;
  334. HCURSOR hcurPrev = SetCursor(LoadCursor(0, IDC_WAIT));
  335. for (i = 0; ; i++) {
  336. switch (RegEnumKey(HKEY_CLASSES_ROOT, i, tszExt, cbX(tszExt))) {
  337. case ERROR_SUCCESS:
  338. /*
  339. * Don't show ".lnk" in the templates list because it's weird.
  340. */
  341. if (tszExt[0] == TEXT('.') && lstrcmpi(tszExt, c_tszDotLnk)) {
  342. Template_LocateExtension(&tci);
  343. }
  344. break;
  345. case ERROR_MORE_DATA: /* Can't be a .ext if > 10 */
  346. break;
  347. default: goto endenum;
  348. }
  349. }
  350. endenum:;
  351. SetCursor(hcurPrev);
  352. }
  353. /*****************************************************************************
  354. *
  355. * File template callback info
  356. *
  357. *****************************************************************************/
  358. typedef struct FTCI {
  359. TCI tci;
  360. PCTSTR ptszSrc;
  361. PCTSTR ptszDst;
  362. PCTSTR ptszLastBS;
  363. PCTSTR ptszShellNew;
  364. } FTCI, *PFTCI;
  365. /*****************************************************************************
  366. *
  367. * Template_CopyFile
  368. *
  369. * Copy a file with the hourglass.
  370. *
  371. *****************************************************************************/
  372. BOOL PASCAL
  373. Template_CopyFile(PFTCI pftci)
  374. {
  375. HCURSOR hcurPrev;
  376. BOOL fRc;
  377. hcurPrev = SetCursor(LoadCursor(0, MAKEINTRESOURCE(IDC_WAIT)));
  378. fRc = CopyFile(pftci->ptszSrc, pftci->ptszDst, 0);
  379. SetCursor(hcurPrev);
  380. return fRc;
  381. }
  382. /*****************************************************************************
  383. *
  384. * Template_AddFileTemplate_CheckMe
  385. *
  386. * Make sure the key isn't a Command key.
  387. *
  388. *****************************************************************************/
  389. BOOL PASCAL
  390. Template_AddFileTemplate_CheckMe(PTCI ptci, HKEY hk, PCTSTR ptszShellNew)
  391. {
  392. PFTCI pftci = (PFTCI)ptci;
  393. pftci->ptszShellNew = ptszShellNew;
  394. if (Template_SubkeyExists(hk, c_tszCommand)) {
  395. ptci->ptszExt = 0;
  396. }
  397. return 1;
  398. }
  399. /*****************************************************************************
  400. *
  401. * Template_IsTemplatable
  402. *
  403. * Determine whether there is an application that can handle this
  404. * extension. We assume it's okay if the item is not self-executing.
  405. *
  406. *****************************************************************************/
  407. BOOL PASCAL
  408. Template_IsTemplatable(PCTSTR ptszFile)
  409. {
  410. LONG cb;
  411. TCH tszShort[MAX_PATH];
  412. DWORD ctch;
  413. ctch = GetFullPathName(ptszFile, cA(tszShort), tszShort, NULL);
  414. if (ctch && ctch < MAX_PATH) {
  415. /* If this fails, just proceed with the value from GFPN */
  416. GetShortPathName(ptszFile, tszShort, cA(tszShort));
  417. TCH tszExe[MAX_PATH];
  418. if (FindExecutable(tszShort, NULL, tszExe) >= (HINSTANCE)IntToPtr(HINSTANCE_ERROR)) {
  419. return lstrcmpi(tszExe, tszShort) != 0;
  420. }
  421. }
  422. return 0;
  423. }
  424. /*****************************************************************************
  425. *
  426. * Template_ReplaceTemplate
  427. *
  428. * Replace the current template with the new one.
  429. *
  430. *****************************************************************************/
  431. UINT PASCAL
  432. Template_ReplaceTemplate(PFTCI pftci)
  433. {
  434. #define ptci (&pftci->tci)
  435. UINT id;
  436. if (ptci->ptszExt) {
  437. if (MessageBoxId(GetParent(ptci->hwnd), IDS_CONFIRMNEWTEMPLATE,
  438. pftci->ptszSrc,
  439. MB_YESNO | MB_DEFBUTTON2 | MB_SETFOREGROUND)
  440. == IDYES) {
  441. HKEY hk;
  442. lstrcatnBsA(ptci->pti->tszKey, pftci->ptszShellNew);
  443. if (_RegOpenKey(ptci->pti->hkRoot, ptci->pti->tszKey, &hk) == 0) {
  444. if (Template_CopyFile(pftci)) {
  445. RegDeleteValue(hk, c_tszNullFile);
  446. RegDeleteValue(hk, c_tszData);
  447. RegSetValuePtsz(hk, c_tszFileName, pftci->ptszLastBS+1);
  448. id = 0;
  449. } else {
  450. id = IDS_COPYFAIL;
  451. }
  452. RegCloseKey(hk);
  453. } else {
  454. id = IDS_REGFAIL;
  455. }
  456. } else {
  457. id = 0;
  458. }
  459. } else {
  460. id = IDS_CANNOTTEMPLATE;
  461. }
  462. return id;
  463. }
  464. #undef ptci
  465. /*****************************************************************************
  466. *
  467. * Template_AddFileTemplate
  468. *
  469. * Add the file as a new template type.
  470. *
  471. *****************************************************************************/
  472. UINT PASCAL
  473. Template_AddFileTemplate(HWND hwnd, PCTSTR ptszSrc)
  474. {
  475. #define pftci (&ftci)
  476. UINT id;
  477. FTCI ftci;
  478. pftci->tci.pfn = Template_AddFileTemplate_CheckMe;
  479. pftci->tci.hwnd = hwnd;
  480. pftci->ptszSrc = ptszSrc;
  481. pftci->ptszLastBS = ptszFilenameCqn(ptszSrc) - 1; /* -> \filename.ext */
  482. if (pftci->ptszLastBS) {
  483. pftci->tci.ptszExt = ptszStrRChr(pftci->ptszLastBS, '.'); /* -> .ext */
  484. if (pftci->tci.ptszExt) {
  485. HKEY hk;
  486. if (_RegOpenKey(hkCR, pftci->tci.ptszExt, &hk) == 0) {
  487. if (Template_IsTemplatable(ptszSrc)) {
  488. PTI pti;
  489. TCH tszDst[MAX_PATH];
  490. pftci->ptszDst = tszDst;
  491. SHGetPathFromIDList(pcdii->pidlTemplates, tszDst);
  492. lstrcatnBsA(tszDst, pftci->ptszLastBS+1);
  493. /* Snoop at the next pti to ensure we can get it later */
  494. pti = (PTI)Misc_AllocPx(&ptdii->gxa);
  495. if (pti) {
  496. if (Template_LocateExtension(&pftci->tci)) {
  497. id = Template_ReplaceTemplate(pftci);
  498. } else {
  499. if (Template_CopyFile(pftci)) {
  500. HKEY hk2;
  501. if (RegCreateKey(hk, c_tszShellNew, &hk2) == 0) {
  502. RegSetValuePtsz(hk2, c_tszFileName, pftci->ptszLastBS+1);
  503. RegCloseKey(hk2);
  504. Misc_LV_SetCurSel(hwnd,
  505. Template_AddTemplateInfo(hwnd,
  506. pftci->tci.ptszExt, pti, 1));
  507. Template_NudgeExplorer();
  508. id = 0; /* No problemo */
  509. } else {
  510. id = IDS_REGFAIL;
  511. }
  512. } else {
  513. id = IDS_COPYFAIL;
  514. }
  515. }
  516. } else {
  517. id = 0; /* out of memory! */
  518. }
  519. } else {
  520. id = IDS_BADEXT;
  521. }
  522. RegCloseKey(hk);
  523. } else {
  524. id = IDS_BADEXT;
  525. }
  526. } else {
  527. id = IDS_BADEXT;
  528. }
  529. } else {
  530. id = 0; /* This can't happen! */
  531. }
  532. return id;
  533. }
  534. /*****************************************************************************
  535. *
  536. * Tools_Template_OnDropFiles
  537. *
  538. * Put the file into the template edit control.
  539. *
  540. *****************************************************************************/
  541. void PASCAL
  542. Tools_Template_OnDropFiles(HWND hwnd, HDROP hdrop)
  543. {
  544. if (DragQueryFile(hdrop, (UINT)-1, 0, 0) == 1) {
  545. UINT id;
  546. TCH tszSrc[MAX_PATH];
  547. DragQueryFile(hdrop, 0, tszSrc, cA(tszSrc));
  548. id = Template_AddFileTemplate(hwnd, tszSrc);
  549. if (id) {
  550. MessageBoxId(GetParent(hwnd), id, tszSrc, MB_OK | MB_SETFOREGROUND);
  551. }
  552. } else {
  553. MessageBoxId(GetParent(hwnd), IDS_TOOMANY, g_tszName,
  554. MB_OK | MB_SETFOREGROUND);
  555. }
  556. DragFinish(hdrop);
  557. }
  558. /*****************************************************************************
  559. *
  560. * Tools_Template_WndProc
  561. *
  562. * Subclass procedure so we can handle drag-drop to the template
  563. * edit control.
  564. *
  565. *****************************************************************************/
  566. LRESULT EXPORT
  567. Tools_Template_WndProc(HWND hwnd, UINT wm, WPARAM wParam, LPARAM lParam)
  568. {
  569. switch (wm) {
  570. case WM_DROPFILES:
  571. Tools_Template_OnDropFiles(hwnd, (HDROP)wParam);
  572. return 0;
  573. }
  574. return CallWindowProc(ptdii->wpTemplate, hwnd, wm, wParam, lParam);
  575. }
  576. /*****************************************************************************
  577. *
  578. * Template_GetIcon
  579. *
  580. * Produce the icon associated with an item. This is called when
  581. * we need to rebuild the icon list after the icon cache has been
  582. * purged.
  583. *
  584. *****************************************************************************/
  585. int PASCAL
  586. Template_GetIcon(LPARAM iti)
  587. {
  588. SHFILEINFO sfi;
  589. PTI pti = ptiIti(iti);
  590. sfi.iIcon = 0;
  591. OutputDebugString(pti->tszExt);
  592. SHGetFileInfo(pti->tszExt, 0, &sfi, cbX(sfi),
  593. SHGFI_USEFILEATTRIBUTES | SHGFI_SYSICONINDEX | SHGFI_SMALLICON);
  594. return sfi.iIcon;
  595. }
  596. /*****************************************************************************
  597. *
  598. * Template_OnInitDialog
  599. *
  600. * Turn the "drop a file here" gizmo into a valid drop target.
  601. *
  602. *****************************************************************************/
  603. BOOL PASCAL
  604. Template_OnInitDialog(HWND hwnd)
  605. {
  606. ptdii->wpTemplate = SubclassWindow(hwnd, Tools_Template_WndProc);
  607. DragAcceptFiles(hwnd, 1);
  608. if (Misc_InitPgxa(&ptdii->gxa, cbX(TI))) {
  609. Template_AddTemplates(hwnd);
  610. }
  611. return 1;
  612. }
  613. /*****************************************************************************
  614. *
  615. * Template_OnDelete
  616. *
  617. * Really nuke it. The interaction between this and adding a new
  618. * template is sufficiently weird that I don't want to try to do
  619. * delayed-action.
  620. *
  621. *****************************************************************************/
  622. void PASCAL
  623. Template_OnDelete(HWND hwnd, int iItem)
  624. {
  625. LV_ITEM lvi;
  626. HKEY hk;
  627. PTI pti;
  628. TCH tszDesc[MAX_PATH];
  629. lvi.pszText = tszDesc;
  630. lvi.cchTextMax = cA(tszDesc);
  631. Misc_LV_GetItemInfo(hwnd, &lvi, iItem, LVIF_PARAM | LVIF_TEXT);
  632. pti = ptiPlvi(&lvi);
  633. if (MessageBoxId(GetParent(hwnd), IDS_TEMPLATEDELETEWARN,
  634. lvi.pszText, MB_YESNO | MB_DEFBUTTON2) == IDYES) {
  635. if (_RegOpenKey(pti->hkRoot, pti->tszKey, &hk) == 0) {
  636. RegDeleteTree(hk, c_tszShellNewDash);
  637. RegDeleteTree(hk, c_tszShellNew);
  638. ListView_DeleteItem(hwnd, iItem);
  639. Misc_LV_EnsureSel(hwnd, iItem);
  640. Common_SetDirty(GetParent(hwnd));
  641. RegCloseKey(hk);
  642. }
  643. }
  644. }
  645. /*****************************************************************************
  646. *
  647. * Template_OnSelChange
  648. *
  649. * Disable the Remove button if we can't remove the thing.
  650. *
  651. *****************************************************************************/
  652. void PASCAL
  653. Template_OnSelChange(HWND hwnd, int iItem)
  654. {
  655. PTI pti = ptiIti(Misc_LV_GetParam(hwnd, iItem));
  656. HKEY hk;
  657. BOOL fEnable;
  658. if (_RegOpenKey(pti->hkRoot, pti->tszKey, &hk) == 0) {
  659. if (GetRegStr(hk, pti->isi == isiUnchecked ?
  660. c_tszShellNewDash : c_tszShellNew, c_tszCommand, 0, 0)) {
  661. fEnable = 0;
  662. } else {
  663. fEnable = 1;
  664. }
  665. RegCloseKey(hk);
  666. } else {
  667. fEnable = 0;
  668. }
  669. EnableWindow(GetDlgItem(GetParent(hwnd), IDC_LVDELETE), fEnable);
  670. }
  671. /*****************************************************************************
  672. *
  673. * Template_OnApply
  674. *
  675. *****************************************************************************/
  676. void PASCAL
  677. Template_OnApply(HWND hdlg)
  678. {
  679. HWND hwnd = GetDlgItem(hdlg, IDC_TEMPLATE);
  680. int cItems = ListView_GetItemCount(hwnd);
  681. BOOL fDirty;
  682. LV_ITEM lvi;
  683. fDirty = 0;
  684. for (lvi.iItem = 0; lvi.iItem < cItems; lvi.iItem++) {
  685. PTI pti;
  686. lvi.stateMask = LVIS_STATEIMAGEMASK;
  687. Misc_LV_GetItemInfo(hwnd, &lvi, lvi.iItem, LVIF_PARAM | LVIF_STATE);
  688. pti = ptiPlvi(&lvi);
  689. if (pti->isi != isiPlvi(&lvi)) {
  690. PCTSTR ptszFrom, ptszTo;
  691. if (pti->isi == isiUnchecked) {
  692. ptszFrom = c_tszShellNewDash;
  693. ptszTo = c_tszShellNew;
  694. } else {
  695. ptszFrom = c_tszShellNew;
  696. ptszTo = c_tszShellNewDash;
  697. }
  698. if (Misc_RenameReg(pti->hkRoot, pti->tszKey, ptszFrom, ptszTo)) {
  699. pti->isi = isiPlvi(&lvi);
  700. }
  701. fDirty = 1;
  702. }
  703. }
  704. if (fDirty) {
  705. Template_NudgeExplorer();
  706. }
  707. }
  708. /*****************************************************************************
  709. *
  710. * Template_OnDestroy
  711. *
  712. * Free the memory we allocated.
  713. *
  714. *****************************************************************************/
  715. void PASCAL
  716. Template_OnDestroy(HWND hdlg)
  717. {
  718. Misc_FreePgxa(&ptdii->gxa);
  719. }
  720. /*****************************************************************************
  721. *
  722. * Oh yeah, we need this too.
  723. *
  724. *****************************************************************************/
  725. #pragma BEGIN_CONST_DATA
  726. LVCI lvciTemplate[] = {
  727. { IDC_LVDELETE, Template_OnDelete },
  728. { 0, 0 },
  729. };
  730. LVV lvvTemplate = {
  731. 0, /* Template_OnCommand */
  732. 0, /* Template_OnInitContextMenu */
  733. 0, /* Template_Dirtify */
  734. Template_GetIcon,
  735. Template_OnInitDialog,
  736. Template_OnApply,
  737. Template_OnDestroy,
  738. Template_OnSelChange,
  739. 3,
  740. rgdwHelp,
  741. 0, /* Double-click action */
  742. lvvflIcons | /* We need icons */
  743. lvvflCanCheck | /* And check boxes */
  744. lvvflCanDelete, /* and you can delete them too */
  745. lvciTemplate,
  746. };
  747. #pragma END_CONST_DATA
  748. /*****************************************************************************
  749. *
  750. * Our window procedure.
  751. *
  752. *****************************************************************************/
  753. INT_PTR EXPORT
  754. Template_DlgProc(HWND hdlg, UINT wm, WPARAM wParam, LPARAM lParam)
  755. {
  756. return LV_DlgProc(&lvvTemplate, hdlg, wm, wParam, lParam);
  757. }