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.

661 lines
18 KiB

  1. #include "shellprv.h"
  2. #include "ids.h"
  3. #include "help.h"
  4. #include "ascstr.h"
  5. #include "ftdlg.h"
  6. #include "ftedit.h"
  7. #include "ftcmmn.h"
  8. #define ID_TIMER 2222
  9. const static DWORD cs_rgdwHelpIDsArray[] =
  10. { // Context Help IDs
  11. IDC_FT_EDIT_EXT_EDIT_TEXT, IDH_FCAB_FT_NE_FILEEXT,
  12. IDC_FT_EDIT_EXT_EDIT, IDH_FCAB_FT_NE_FILEEXT,
  13. IDC_FT_EDIT_PID_COMBO_TEXT, IDH_FCAB_FT_NE_FILETYPE,
  14. IDC_FT_EDIT_PID_COMBO, IDH_FCAB_FT_NE_FILETYPE,
  15. IDC_FT_EDIT_ADVANCED, IDH_FCAB_FT_NE_ADV_BUT,
  16. IDC_NO_HELP_1, NO_HELP,
  17. 0, 0
  18. };
  19. CFTEditDlg::CFTEditDlg(FTEDITPARAM* pftEditParam) :
  20. CFTDlg((ULONG_PTR)cs_rgdwHelpIDsArray), _pftEditParam(pftEditParam),
  21. _iLVSel(-1)
  22. {
  23. }
  24. CFTEditDlg::~CFTEditDlg()
  25. {
  26. }
  27. ///////////////////////////////////////////////////////////////////////////////
  28. // Logic specific to our problem
  29. LRESULT CFTEditDlg::OnInitDialog(WPARAM wParam, LPARAM lParam)
  30. {
  31. HRESULT hres = E_FAIL;
  32. if (_pftEditParam)
  33. {
  34. hres = _InitAssocStore();
  35. if (SUCCEEDED(hres))
  36. {
  37. _hHeapProgID = HeapCreate(0, 8 * 1024, 0);
  38. if (!_hHeapProgID)
  39. hres = E_OUTOFMEMORY;
  40. }
  41. if (SUCCEEDED(hres))
  42. SetDlgItemText(_hwnd, IDC_FT_EDIT_EXT_EDIT, TEXT(""));
  43. }
  44. if (FAILED(hres))
  45. EndDialog(_hwnd, -1);
  46. else
  47. Edit_LimitText(GetDlgItem(_hwnd, IDC_FT_EDIT_EXT_EDIT), MAX_EXT - 1);
  48. // Return TRUE so that system set focus
  49. return TRUE;
  50. }
  51. LRESULT CFTEditDlg::OnEdit(WORD wNotif)
  52. {
  53. if (_fAdvanced)
  54. {
  55. if (EN_CHANGE == wNotif)
  56. {
  57. if (_nTimer)
  58. {
  59. KillTimer(_hwnd, _nTimer);
  60. _nTimer = 0;
  61. }
  62. _nTimer = SetTimer(_hwnd, ID_TIMER, 400, NULL);
  63. }
  64. }
  65. return FALSE;
  66. }
  67. LRESULT CFTEditDlg::OnTimer(UINT nTimer)
  68. {
  69. // Kill the timer
  70. KillTimer(_hwnd, _nTimer);
  71. _nTimer = 0;
  72. _ProgIDComboHelper();
  73. return TRUE;
  74. }
  75. HRESULT CFTEditDlg::_ProgIDComboHelper()
  76. {
  77. TCHAR szExt[MAX_EXT];
  78. TCHAR szProgIDDescr[MAX_PROGIDDESCR];
  79. DWORD cchProgIDDescr = ARRAYSIZE(szProgIDDescr);
  80. HRESULT hres = E_FAIL;
  81. GetDlgItemText(_hwnd, IDC_FT_EDIT_EXT_EDIT, szExt, ARRAYSIZE(szExt));
  82. hres = _GetProgIDDescrFromExt(szExt, szProgIDDescr, &cchProgIDDescr);
  83. if (SUCCEEDED(hres))
  84. _SelectProgIDDescr(szProgIDDescr);
  85. return hres;
  86. }
  87. HRESULT CFTEditDlg::_GetProgIDDescrFromExt(LPTSTR pszExt, LPTSTR pszProgIDDescr,
  88. DWORD* pcchProgIDDescr)
  89. {
  90. IAssocInfo* pAI = NULL;
  91. HRESULT hres = _pAssocStore->GetAssocInfo(pszExt, AIINIT_EXT, &pAI);
  92. if (SUCCEEDED(hres))
  93. {
  94. hres = pAI->GetString(AISTR_PROGIDDESCR, pszProgIDDescr, pcchProgIDDescr);
  95. pAI->Release();
  96. }
  97. return hres;
  98. }
  99. LRESULT CFTEditDlg::OnAdvancedButton(WORD wNotif)
  100. {
  101. DECLAREWAITCURSOR;
  102. TCHAR szAdvBtnText[50];
  103. SetWaitCursor();
  104. _fAdvanced = !_fAdvanced;
  105. LoadString(g_hinst, _fAdvanced ? IDS_FT_ADVBTNTEXTEXPAND : IDS_FT_ADVBTNTEXTCOLLAPS,
  106. szAdvBtnText, ARRAYSIZE(szAdvBtnText));
  107. SetWindowText(GetDlgItem(_hwnd, IDC_FT_EDIT_ADVANCED), szAdvBtnText);
  108. _ConfigureDlg();
  109. UpdateWindow(_hwnd);
  110. if (_fAdvanced)
  111. {
  112. HWND hwndCombo = GetDlgItem(_hwnd, IDC_FT_EDIT_PID_COMBO);
  113. // Is the combobox filled yet?
  114. if (!ComboBox_GetCount(hwndCombo))
  115. {
  116. _FillProgIDDescrCombo();
  117. // Select the <New> item
  118. if (FAILED(_ProgIDComboHelper()))
  119. {
  120. TCHAR szNew[20];
  121. if (LoadString(g_hinst, IDS_FT_NEW, szNew, ARRAYSIZE(szNew)))
  122. {
  123. int iIndex = ComboBox_FindStringExact(hwndCombo, -1, szNew);
  124. if (CB_ERR != iIndex)
  125. ComboBox_SetCurSel(hwndCombo, iIndex);
  126. }
  127. }
  128. }
  129. }
  130. ResetWaitCursor();
  131. return FALSE;
  132. }
  133. void CFTEditDlg::_ConfigureDlg()
  134. {
  135. // Need to:
  136. // - position OK and Cancel
  137. // - resize dlg
  138. // - Show/hide Combo and its text
  139. RECT rcControl;
  140. RECT rcDialog;
  141. RECT rcCancel;
  142. RECT rcOK;
  143. int iStdMargins = 0;
  144. int iStdSpaceBetweenControls = 0;
  145. GetWindowRect(_hwnd, &rcDialog);
  146. GetWindowRect(GetDlgItem(_hwnd, IDC_FT_EDIT_PID_COMBO_TEXT),
  147. &rcControl);
  148. // Calculate the folowing (cannot be fixed, varies with dialog font)
  149. // [msadek]; screen coordinates. need to consider the mirrored case
  150. if(IS_WINDOW_RTL_MIRRORED(_hwnd))
  151. {
  152. iStdMargins = rcDialog.right - rcControl.right;
  153. }
  154. else
  155. {
  156. iStdMargins = rcControl.left - rcDialog.left;
  157. }
  158. iStdSpaceBetweenControls = MulDiv(4, iStdMargins, 7);
  159. // Move Cancel and OK button
  160. GetWindowRect(GetDlgItem(_hwnd,
  161. _fAdvanced ? IDC_FT_EDIT_PID_COMBO : IDC_FT_EDIT_EXT_EDIT),
  162. &rcControl);
  163. MapWindowRect(HWND_DESKTOP, _hwnd, &rcControl);
  164. GetWindowRect(GetDlgItem(_hwnd, IDCANCEL), &rcCancel);
  165. MapWindowRect(HWND_DESKTOP, _hwnd, &rcCancel);
  166. OffsetRect(&rcCancel, 0, -rcCancel.top);
  167. GetWindowRect(GetDlgItem(_hwnd, IDOK), &rcOK);
  168. MapWindowRect(HWND_DESKTOP, _hwnd, &rcOK);
  169. OffsetRect(&rcOK, 0, -rcOK.top);
  170. OffsetRect(&rcCancel, 0, rcControl.bottom + iStdSpaceBetweenControls);
  171. OffsetRect(&rcOK, 0, rcControl.bottom + iStdSpaceBetweenControls);
  172. SetWindowPos(GetDlgItem(_hwnd, IDOK), NULL,
  173. rcOK.left, rcOK.top, 0, 0, SWP_NOSIZE|SWP_SHOWWINDOW|SWP_NOZORDER);
  174. SetWindowPos(GetDlgItem(_hwnd, IDCANCEL), NULL,
  175. rcCancel.left, rcCancel.top, 0, 0, SWP_NOSIZE|SWP_SHOWWINDOW|SWP_NOZORDER);
  176. // Resize Dlg
  177. ClientToScreen(_hwnd, ((POINT*)&rcCancel) + 1);
  178. rcDialog.bottom = rcCancel.bottom + iStdMargins;
  179. SetWindowPos(_hwnd, NULL,
  180. 0, 0, rcDialog.right - rcDialog.left, rcDialog.bottom - rcDialog.top,
  181. SWP_NOMOVE|SWP_SHOWWINDOW|SWP_NOZORDER);
  182. // Show/Hide Combo and its text
  183. ShowWindow(GetDlgItem(_hwnd, IDC_FT_EDIT_PID_COMBO_TEXT), _fAdvanced);
  184. ShowWindow(GetDlgItem(_hwnd, IDC_FT_EDIT_PID_COMBO), _fAdvanced);
  185. // Set focus to combo
  186. SetFocus(GetDlgItem(_hwnd, IDC_FT_EDIT_PID_COMBO));
  187. }
  188. LRESULT CFTEditDlg::OnOK(WORD wNotif)
  189. {
  190. HRESULT hres = S_FALSE;
  191. // Pick up the extension
  192. GetDlgItemText(_hwnd, IDC_FT_EDIT_EXT_EDIT, _pftEditParam->szExt,
  193. _pftEditParam->dwExt);
  194. // Is it empty?
  195. if (0 != (*_pftEditParam->szExt))
  196. {
  197. // No, that's good
  198. // FEATURE: do some check for valid extension name
  199. IAssocInfo* pAI = NULL;
  200. hres = _pAssocStore->GetAssocInfo(_pftEditParam->szExt,
  201. AIINIT_EXT, &pAI);
  202. if (SUCCEEDED(hres))
  203. {
  204. BOOL fExist = FALSE;
  205. hres = pAI->GetBOOL(AIBOOL_EXTEXIST, &fExist);
  206. // Is this extension already existing?
  207. if (SUCCEEDED(hres) && !fExist)
  208. {
  209. // No, create it
  210. // Check for spaces in the ext name
  211. LPTSTR pszExt = _pftEditParam->szExt;
  212. while (*pszExt && (S_FALSE != hres))
  213. {
  214. if (TEXT(' ') == *pszExt)
  215. {
  216. hres = S_FALSE;
  217. ShellMessageBox(g_hinst, _hwnd,
  218. MAKEINTRESOURCE(IDS_FT_MB_NOSPACEINEXT),
  219. MAKEINTRESOURCE(IDS_FT), MB_OK | MB_ICONSTOP);
  220. // Set focus to Ext combo
  221. PostMessage(_hwnd, WM_CTRL_SETFOCUS, (WPARAM)0,
  222. (LPARAM)GetDlgItem(_hwnd, IDC_FT_EDIT_EXT_EDIT));
  223. }
  224. ++pszExt;
  225. }
  226. if (S_OK==hres)
  227. hres = pAI->Create();
  228. }
  229. if (S_OK==hres)
  230. hres = _HandleProgIDAssoc(pAI, _pftEditParam->szExt, fExist);
  231. pAI->Release();
  232. }
  233. }
  234. else
  235. {
  236. ShellMessageBox(g_hinst, _hwnd, MAKEINTRESOURCE(IDS_FT_MB_NOEXT),
  237. MAKEINTRESOURCE(IDS_FT), MB_OK | MB_ICONSTOP);
  238. // Set focus to Ext combo
  239. PostMessage(_hwnd, WM_CTRL_SETFOCUS, (WPARAM)0,
  240. (LPARAM)GetDlgItem(_hwnd, IDC_FT_EDIT_EXT_EDIT));
  241. }
  242. // If we fail, we are in serious trouble, so we just close the dialog
  243. ASSERT(SUCCEEDED(hres));
  244. if (S_FALSE != hres)
  245. EndDialog(_hwnd, IDOK);
  246. return FALSE;
  247. }
  248. HRESULT CFTEditDlg::_GetProgIDInfo(IAssocInfo* pAI, LPTSTR pszProgID,
  249. DWORD* pcchProgID, BOOL* pfNewProgID, BOOL* pfExplicitNew)
  250. {
  251. HWND hwndCombo = GetDlgItem(_hwnd, IDC_FT_EDIT_PID_COMBO);
  252. *pfNewProgID = FALSE;
  253. *pfExplicitNew = FALSE;
  254. if (ComboBox_GetCount(hwndCombo))
  255. {
  256. int iSel = ComboBox_GetCurSel(hwndCombo);
  257. if (CB_ERR != iSel)
  258. {
  259. LPTSTR pszTmpProgID = (LPTSTR)ComboBox_GetItemData(hwndCombo, iSel);
  260. // Is this the "<New>" item (the only one with a ProgID == NULL)?
  261. if (!pszTmpProgID)
  262. {
  263. // Yes
  264. *pfNewProgID = TRUE;
  265. *pfExplicitNew = TRUE;
  266. }
  267. else
  268. {
  269. // No
  270. StrCpyN(pszProgID, pszTmpProgID, *pcchProgID);
  271. }
  272. }
  273. }
  274. else
  275. {
  276. *pfNewProgID = TRUE;
  277. }
  278. return S_OK;
  279. }
  280. HRESULT CFTEditDlg::_HandleProgIDAssoc(IAssocInfo* pAI, LPTSTR pszExt, BOOL fExtExist)
  281. {
  282. TCHAR szProgID[MAX_PROGID];
  283. DWORD cchProgID = ARRAYSIZE(szProgID);
  284. BOOL fNewProgID = FALSE;
  285. BOOL fExplicitNew = FALSE;
  286. *szProgID = 0;
  287. HRESULT hres = _GetProgIDInfo(pAI, szProgID, &cchProgID, &fNewProgID, &fExplicitNew);
  288. if (SUCCEEDED(hres))
  289. {
  290. // Is this Extension already existing?
  291. if (fExtExist)
  292. {
  293. //
  294. // First make sure it's not the exact same ext - progID assoc
  295. //
  296. TCHAR szTmpProgID[MAX_PROGID];
  297. DWORD cchTmpProgID = ARRAYSIZE(szTmpProgID);
  298. hres = pAI->GetString(AISTR_PROGID, szTmpProgID, &cchTmpProgID);
  299. // Did we got a progID?
  300. if (SUCCEEDED(hres))
  301. {
  302. // Yes
  303. // Are they the same?
  304. if (0 == lstrcmpi(szTmpProgID, szProgID))
  305. {
  306. // Yes, fail, nothing more to do
  307. hres = E_FAIL;
  308. }
  309. else
  310. {
  311. // No, go on
  312. hres = S_OK;
  313. }
  314. }
  315. else
  316. {
  317. // No, there probably is no ProgID, go on
  318. hres = S_OK;
  319. }
  320. //
  321. // Unless the user chose <New> explicitly ask if he wants to break the assoc
  322. //
  323. // Did the user explicitly chose <New> (and we did not failed already)?
  324. if (!fExplicitNew && SUCCEEDED(hres))
  325. {
  326. // We need to warn user that he will break existing assoc
  327. TCHAR szProgIDDescr[MAX_PROGIDDESCR];
  328. DWORD cchProgIDDescr = ARRAYSIZE(szProgIDDescr);
  329. hres = pAI->GetString(AISTR_PROGIDDESCR, szProgIDDescr, &cchProgIDDescr);
  330. if (SUCCEEDED(hres))
  331. {
  332. if (IDNO == ShellMessageBox(g_hinst, _hwnd, MAKEINTRESOURCE(IDS_FT_EDIT_ALREADYASSOC),
  333. MAKEINTRESOURCE(IDS_FT_EDIT_ALRASSOCTITLE), MB_YESNO | MB_ICONEXCLAMATION,
  334. pszExt, szProgIDDescr, pszExt, szProgIDDescr))
  335. {
  336. // S_FALSE means user does not want to go on
  337. hres = S_FALSE;
  338. }
  339. }
  340. else
  341. {
  342. // no progIDDescr... Check if we have a progID
  343. TCHAR szProgID[MAX_PROGID];
  344. DWORD cchProgID = ARRAYSIZE(szProgID);
  345. hres = pAI->GetString(AISTR_PROGID, szProgID, &cchProgID);
  346. if (FAILED(hres))
  347. {
  348. // no progID, set hres to S_OK so that we go on and create one
  349. hres = S_OK;
  350. }
  351. }
  352. }
  353. }
  354. // Should we go on and create new progID?
  355. if (S_OK==hres && fNewProgID)
  356. {
  357. // Yes, create it
  358. IAssocInfo* pAIProgID = NULL;
  359. hres = _pAssocStore->GetAssocInfo(NULL, AIINIT_PROGID, &pAIProgID);
  360. if (SUCCEEDED(hres))
  361. {
  362. hres = pAIProgID->Create();
  363. if (SUCCEEDED(hres))
  364. {
  365. TCHAR szExt[MAX_EXT];
  366. DWORD cchExt = ARRAYSIZE(szExt);
  367. TCHAR szProgIDDescr[MAX_PROGIDDESCR];
  368. HRESULT hresTmp = pAI->GetString(AISTR_EXT, szExt, &cchExt);
  369. if (SUCCEEDED(hresTmp) && *szExt)
  370. {
  371. MakeDefaultProgIDDescrFromExt(szProgIDDescr, ARRAYSIZE(szProgIDDescr), szExt);
  372. hresTmp = pAIProgID->SetString(AISTR_PROGIDDESCR, szProgIDDescr);
  373. }
  374. // Get the ProgID for later use
  375. pAIProgID->GetString(AISTR_PROGID, szProgID, &cchProgID);
  376. }
  377. pAIProgID->Release();
  378. }
  379. }
  380. if (S_OK==hres)
  381. {
  382. // Set the new extension progID
  383. hres = pAI->SetString(AISTR_PROGID, szProgID);
  384. if (SUCCEEDED(hres))
  385. {
  386. // Get the description
  387. pAI->GetString(AISTR_PROGIDDESCR, _pftEditParam->szProgIDDescr,
  388. &(_pftEditParam->dwProgIDDescr));
  389. }
  390. }
  391. }
  392. return hres;
  393. }
  394. LRESULT CFTEditDlg::OnCancel(WORD wNotif)
  395. {
  396. EndDialog(_hwnd, IDCANCEL);
  397. return FALSE;
  398. }
  399. HRESULT CFTEditDlg::_FillProgIDDescrCombo()
  400. {
  401. HWND hwndCombo = GetDlgItem(_hwnd, IDC_FT_EDIT_PID_COMBO);
  402. // Data stuff
  403. IEnumAssocInfo* pEnum = NULL;
  404. HRESULT hres = _pAssocStore->EnumAssocInfo(
  405. ASENUM_PROGID | ASENUM_ASSOC_ALL, NULL, AIINIT_NONE, &pEnum);
  406. if (SUCCEEDED(hres))
  407. {
  408. IAssocInfo* pAI = NULL;
  409. while ((E_OUTOFMEMORY != hres) && (S_OK == pEnum->Next(&pAI)))
  410. {
  411. TCHAR szProgIDDescr[MAX_PROGIDDESCR];
  412. DWORD cchProgIDDescr = ARRAYSIZE(szProgIDDescr);
  413. hres = pAI->GetString(AISTR_PROGIDDESCR, szProgIDDescr, &cchProgIDDescr);
  414. if (SUCCEEDED(hres))
  415. {
  416. int iIndex = CB_ERR;
  417. if (*szProgIDDescr)
  418. {
  419. if (CB_ERR == ComboBox_FindStringExact(hwndCombo, -1, szProgIDDescr))
  420. iIndex = ComboBox_AddString(hwndCombo, szProgIDDescr);
  421. }
  422. if ((CB_ERR != iIndex) && (CB_ERRSPACE != iIndex))
  423. {
  424. TCHAR szProgID[MAX_PROGID];
  425. DWORD cchProgID = ARRAYSIZE(szProgID);
  426. hres = pAI->GetString(AISTR_PROGID, szProgID, &cchProgID);
  427. if (SUCCEEDED(hres))
  428. {
  429. LPTSTR pszProgID = _AddProgID(szProgID);
  430. if (pszProgID)
  431. {
  432. lstrcpy(pszProgID, szProgID);
  433. ComboBox_SetItemData(hwndCombo, iIndex, pszProgID);
  434. }
  435. else
  436. {
  437. // Out of memory
  438. hres = E_OUTOFMEMORY;
  439. ShellMessageBox(g_hinst, _hwnd, MAKEINTRESOURCE(IDS_ERROR +
  440. ERROR_NOT_ENOUGH_MEMORY), MAKEINTRESOURCE(IDS_FT),
  441. MB_OK | MB_ICONSTOP);
  442. // Already allocated mem will be cleaned-up in OnDestroy
  443. }
  444. }
  445. }
  446. }
  447. pAI->Release();
  448. }
  449. pEnum->Release();
  450. if (SUCCEEDED(hres))
  451. {
  452. TCHAR szNew[20];
  453. if (LoadString(g_hinst, IDS_FT_NEW, szNew, ARRAYSIZE(szNew)))
  454. {
  455. int iIndex = ComboBox_InsertString(hwndCombo, 0, szNew);
  456. if (CB_ERR != iIndex)
  457. ComboBox_SetItemData(hwndCombo, iIndex, NULL);
  458. }
  459. }
  460. }
  461. return hres;
  462. }
  463. BOOL CFTEditDlg::_SelectProgIDDescr(LPTSTR pszProgIDDescr)
  464. {
  465. int iIndex = ComboBox_SelectString(GetDlgItem(_hwnd, IDC_FT_EDIT_PID_COMBO),
  466. -1, pszProgIDDescr);
  467. return ((CB_ERR != iIndex) ? TRUE : FALSE);
  468. }
  469. LRESULT CFTEditDlg::OnDestroy(WPARAM wParam, LPARAM lParam)
  470. {
  471. _CleanupProgIDs();
  472. CFTDlg::OnDestroy(wParam, lParam);
  473. return FALSE;
  474. }
  475. LPTSTR CFTEditDlg::_AddProgID(LPTSTR pszProgID)
  476. {
  477. ASSERT(_hHeapProgID);
  478. return (LPTSTR)HeapAlloc(_hHeapProgID, 0, (lstrlen(pszProgID) + 1) * sizeof(TCHAR));
  479. }
  480. void CFTEditDlg::_CleanupProgIDs()
  481. {
  482. if (_hHeapProgID)
  483. HeapDestroy(_hHeapProgID);
  484. }
  485. ///////////////////////////////////////////////////////////////////////////////
  486. // Windows boiler plate code
  487. LRESULT CFTEditDlg::OnCommand(WPARAM wParam, LPARAM lParam)
  488. {
  489. LRESULT lRes = FALSE;
  490. switch(GET_WM_COMMAND_ID(wParam, lParam))
  491. {
  492. case IDC_FT_EDIT_ADVANCED:
  493. lRes = OnAdvancedButton(GET_WM_COMMAND_CMD(wParam, lParam));
  494. break;
  495. case IDC_FT_EDIT_EXT_EDIT:
  496. lRes = OnEdit(GET_WM_COMMAND_CMD(wParam, lParam));
  497. break;
  498. default:
  499. lRes = CFTDlg::OnCommand(wParam, lParam);
  500. break;
  501. }
  502. return lRes;
  503. }
  504. LRESULT CFTEditDlg::WndProc(UINT uMsg, WPARAM wParam, LPARAM lParam)
  505. {
  506. LRESULT lRes = FALSE;
  507. switch(uMsg)
  508. {
  509. case WM_TIMER:
  510. if (ID_TIMER == wParam)
  511. lRes = OnTimer((UINT)wParam);
  512. else
  513. lRes = CFTDlg::WndProc(uMsg, wParam, lParam);
  514. break;
  515. default:
  516. lRes = CFTDlg::WndProc(uMsg, wParam, lParam);
  517. break;
  518. }
  519. return lRes;
  520. }