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.

2477 lines
68 KiB

  1. /*++
  2. Copyright (c) 1994-1998, Microsoft Corporation All rights reserved.
  3. Module Name:
  4. mouseptr.c
  5. Abstract:
  6. This module contains the routines for the Mouse Pointer Property Sheet
  7. page.
  8. Revision History:
  9. --*/
  10. //
  11. // Include Files.
  12. //
  13. #include "main.h"
  14. #include "rc.h"
  15. #include "mousehlp.h"
  16. #include <regstr.h>
  17. //
  18. // From shell\inc\shsemip.h
  19. //
  20. #define ARRAYSIZE(a) (sizeof(a)/sizeof(a[0]))
  21. //
  22. // Constant Declarations.
  23. //
  24. #define gcxAvgChar 8
  25. #define MAX_SCHEME_NAME_LEN 64
  26. #define MAX_SCHEME_SUFFIX 32 // length of " (system scheme)" - update if more space is needed
  27. #define OVERWRITE_TITLE 32 // length of title for the confirm overwrite dialog
  28. #define OVERWRITE_MSG 200 // length of the message for the overwrite dialog
  29. #define PM_NEWCURSOR (WM_USER + 1)
  30. #define PM_PAUSEANIMATION (WM_USER + 2)
  31. #define PM_UNPAUSEANIMATION (WM_USER + 3)
  32. #define ID_PREVIEWTIMER 1
  33. #define CCH_ANISTRING 80
  34. #define CIF_FILE 0x0001
  35. #define CIF_MODIFIED 0x0002
  36. #define CIF_SHARED 0x0004
  37. #define IDT_BROWSE 1
  38. //
  39. // Typedef Declarations.
  40. //
  41. typedef struct _CURSOR_INFO
  42. {
  43. DWORD fl;
  44. HCURSOR hcur;
  45. int ccur;
  46. int icur;
  47. TCHAR szFile[MAX_PATH];
  48. } CURSOR_INFO, *PCURSOR_INFO;
  49. #pragma pack(2)
  50. typedef struct tagNEWHEADER
  51. {
  52. WORD reserved;
  53. WORD rt;
  54. WORD cResources;
  55. } NEWHEADER, *LPNEWHEADER;
  56. #pragma pack()
  57. typedef struct
  58. {
  59. UINT idVisName;
  60. int idResource;
  61. int idDefResource;
  62. LPTSTR pszIniName;
  63. TCHAR szVisName[MAX_PATH];
  64. } CURSORDESC, *PCURSORDESC;
  65. //
  66. // Structure that contains data used within a preview window. This
  67. // data is unique for each preview window, and is used to optimize
  68. // the painting.
  69. //
  70. typedef struct
  71. {
  72. HDC hdcMem;
  73. HBITMAP hbmMem;
  74. HBITMAP hbmOld;
  75. PCURSOR_INFO pcuri;
  76. } PREVIEWDATA, *PPREVIEWDATA;
  77. typedef struct _MOUSEPTRBR
  78. {
  79. HWND hDlg;
  80. CURSOR_INFO curi;
  81. } MOUSEPTRBR, *PMOUSEPTRBR;
  82. //
  83. // Global Variables.
  84. //
  85. extern HINSTANCE g_hInst; // from main.c
  86. int gcxCursor, gcyCursor;
  87. HWND ghwndDlg, ghwndFile, ghwndFileH, ghwndTitle, ghwndTitleH;
  88. HWND ghwndCreator, ghwndCreatorH, ghwndCursors, ghwndPreview, ghwndSchemeCB;
  89. HBRUSH ghbrHighlight, ghbrHighlightText, ghbrWindow, ghbrButton;
  90. UINT guTextHeight = 0;
  91. UINT guTextGap = 0;
  92. COLORREF gcrHighlightText;
  93. TCHAR gszFileName2[MAX_PATH];
  94. UINT wBrowseHelpMessage;
  95. LPTSTR gszFileNotFound = NULL;
  96. LPTSTR gszBrowse = NULL;
  97. LPTSTR gszFilter = NULL;
  98. TCHAR gszNoMem[256] = TEXT("No Memory");
  99. HHOOK ghhkMsgFilter; // hook handle for message filter function
  100. static const TCHAR szRegStr_Setup[] = REGSTR_PATH_SETUP TEXT("\\Setup");
  101. static const TCHAR szSharedDir[] = TEXT("SharedDir");
  102. BOOL gfCursorShadow = FALSE;
  103. //
  104. // Make sure you add new cursors to the end of this array.
  105. // Otherwise the cursor schemes will not work
  106. //
  107. CURSORDESC gacd[] =
  108. {
  109. { IDS_ARROW, OCR_NORMAL, OCR_ARROW_DEFAULT, TEXT("Arrow"), TEXT("") },
  110. { IDS_HELPCUR, OCR_HELP, OCR_HELP_DEFAULT, TEXT("Help"), TEXT("") },
  111. { IDS_APPSTARTING, OCR_APPSTARTING, OCR_APPSTARTING_DEFAULT, TEXT("AppStarting"), TEXT("") },
  112. { IDS_WAIT, OCR_WAIT, OCR_WAIT_DEFAULT, TEXT("Wait"), TEXT("") },
  113. { IDS_CROSS, OCR_CROSS, OCR_CROSS_DEFAULT, TEXT("Crosshair"), TEXT("") },
  114. { IDS_IBEAM, OCR_IBEAM, OCR_IBEAM_DEFAULT, TEXT("IBeam"), TEXT("") },
  115. { IDS_NWPEN, OCR_NWPEN, OCR_NWPEN_DEFAULT, TEXT("NWPen"), TEXT("") },
  116. { IDS_NO, OCR_NO, OCR_NO_DEFAULT, TEXT("No"), TEXT("") },
  117. { IDS_SIZENS, OCR_SIZENS, OCR_SIZENS_DEFAULT, TEXT("SizeNS"), TEXT("") },
  118. { IDS_SIZEWE, OCR_SIZEWE, OCR_SIZEWE_DEFAULT, TEXT("SizeWE"), TEXT("") },
  119. { IDS_SIZENWSE, OCR_SIZENWSE, OCR_SIZENWSE_DEFAULT, TEXT("SizeNWSE"), TEXT("") },
  120. { IDS_SIZENESW, OCR_SIZENESW, OCR_SIZENESW_DEFAULT, TEXT("SizeNESW"), TEXT("") },
  121. { IDS_SIZEALL, OCR_SIZEALL, OCR_SIZEALL_DEFAULT, TEXT("SizeAll"), TEXT("") },
  122. { IDS_UPARROW, OCR_UP, OCR_UPARROW_DEFAULT, TEXT("UpArrow"), TEXT("") },
  123. { IDS_HANDCUR, OCR_HAND, OCR_HAND_DEFAULT, TEXT("Hand"), TEXT("") },
  124. };
  125. #define CCURSORS (sizeof(gacd) / sizeof(gacd[0]))
  126. CURSOR_INFO acuri[CCURSORS];
  127. //
  128. // Registry Keys.
  129. //
  130. const TCHAR szCursorSubdir[] = TEXT("Cursors");
  131. const TCHAR szCursorRegPath[] = REGSTR_PATH_CURSORS;
  132. static const TCHAR c_szRegPathCursors[] = REGSTR_PATH_CURSORS;
  133. static const TCHAR c_szSchemes[] = TEXT("Schemes");
  134. static const TCHAR c_szRegPathCursorSchemes[] = REGSTR_PATH_CURSORS TEXT( "\\Schemes" );
  135. //
  136. // Strings used to read from the combo box must be larger than max length.
  137. //
  138. TCHAR gszSchemeName[MAX_SCHEME_SUFFIX + MAX_SCHEME_NAME_LEN + 1]; // used to store selected scheme name for saving
  139. int iSchemeLocation; // used to store scheme location (HKCU vs HKLM)
  140. static const TCHAR c_szRegPathSystemSchemes[] = REGSTR_PATH_SETUP TEXT("\\Control Panel\\Cursors\\Schemes");
  141. TCHAR szSystemScheme[MAX_SCHEME_SUFFIX];
  142. TCHAR szNone[MAX_SCHEME_NAME_LEN + 1];
  143. const TCHAR szSchemeSource[] = TEXT("Scheme Source");
  144. TCHAR gszPreviousScheme[MAX_SCHEME_SUFFIX + MAX_SCHEME_NAME_LEN + 1]; // used to tell if a different scheme is selected
  145. #define ID_NONE_SCHEME 0
  146. #define ID_USER_SCHEME 1
  147. #define ID_OS_SCHEME 2
  148. //
  149. // Context Help Ids.
  150. //
  151. const static DWORD aMousePtrHelpIDs[] =
  152. {
  153. IDC_GROUPBOX_1, IDH_COMM_GROUPBOX,
  154. ID_SCHEMECOMBO, IDH_MOUSE_POINT_SCHEME,
  155. ID_SAVESCHEME, IDH_MOUSE_POINT_SAVEAS,
  156. ID_REMOVESCHEME, IDH_MOUSE_POINT_DEL,
  157. ID_PREVIEW, IDH_MOUSE_POINT_PREVIEW,
  158. ID_CURSORLIST, IDH_MOUSE_POINT_LIST,
  159. ID_DEFAULT, IDH_MOUSE_POINT_DEFAULT,
  160. ID_BROWSE, IDH_MOUSE_POINT_BROWSE,
  161. ID_CURSORSHADOW, IDH_MOUSE_CURSORSHADOW,
  162. 0, 0
  163. };
  164. const static DWORD aMousePtrBrowseHelpIDs[] =
  165. {
  166. IDC_GROUPBOX_1, IDH_MOUSE_POINT_PREVIEW,
  167. ID_CURSORPREVIEW, IDH_MOUSE_POINT_PREVIEW,
  168. 0, 0
  169. };
  170. const static DWORD aHelpIDs[] =
  171. {
  172. ID_SCHEMEFILENAME, IDH_MOUSE_NEW_SCHEME_NAME,
  173. 0, 0
  174. };
  175. //
  176. // Forward Declarations.
  177. //
  178. void LoadCursorSet(HWND hwnd);
  179. void CreateBrushes(void);
  180. LPTSTR GetResourceString(HINSTANCE hmod,int id);
  181. void DrawCursorListItem(DRAWITEMSTRUCT *pdis);
  182. BOOL GetCursorFromFile(CURSOR_INFO *pcuri);
  183. BOOL Browse(HWND hwndOwner);
  184. void CleanUpEverything(void);
  185. VOID UpdateCursorList(void);
  186. VOID NextFrame(HWND hwnd);
  187. void HourGlass(BOOL fOn);
  188. BOOL TryToLoadCursor(
  189. HWND hwnd,
  190. int i,
  191. CURSOR_INFO *pcuri);
  192. BOOL LoadScheme(void);
  193. BOOL SaveScheme(void);
  194. BOOL SaveSchemeAs(void);
  195. void SaveCurSchemeName(void);
  196. BOOL RemoveScheme(void);
  197. BOOL InitSchemeComboBox(void);
  198. BOOL SchemeUpdate(int i);
  199. LPTSTR MakeFilename(LPTSTR sz);
  200. INT_PTR CALLBACK SaveSchemeDlgProc(
  201. HWND hWnd,
  202. UINT message,
  203. WPARAM wParam,
  204. LPARAM lParam);
  205. void CurStripBlanks(LPTSTR pszString, int cchString);
  206. int SystemOrUser(TCHAR *pszSchemeName);
  207. BOOL UnExpandPath(LPTSTR pszPath, int cchPath);
  208. ////////////////////////////////////////////////////////////////////////////
  209. //
  210. // RegisterPointerStuff
  211. //
  212. ////////////////////////////////////////////////////////////////////////////
  213. BOOL RegisterPointerStuff(
  214. HINSTANCE hi)
  215. {
  216. gcxCursor = GetSystemMetrics(SM_CXCURSOR);
  217. gcyCursor = GetSystemMetrics(SM_CYCURSOR);
  218. return (TRUE);
  219. }
  220. ////////////////////////////////////////////////////////////////////////////
  221. //
  222. // InitCursorsShadow
  223. //
  224. ////////////////////////////////////////////////////////////////////////////
  225. void InitCursorShadow(HWND hwnd)
  226. {
  227. BOOL fPalette;
  228. HDC hdc;
  229. int nCommand;
  230. hdc = GetDC(NULL);
  231. fPalette = (GetDeviceCaps(hdc, NUMCOLORS) != -1);
  232. ReleaseDC(NULL, hdc);
  233. if (!fPalette) {
  234. nCommand = SW_SHOW;
  235. } else {
  236. nCommand = SW_HIDE;
  237. }
  238. ShowWindow(GetDlgItem(hwnd, ID_CURSORSHADOW), nCommand);
  239. if (nCommand == SW_SHOW) {
  240. SystemParametersInfo(SPI_GETCURSORSHADOW, 0, (PVOID)&gfCursorShadow, 0);
  241. CheckDlgButton(hwnd, ID_CURSORSHADOW, gfCursorShadow);
  242. }
  243. }
  244. ////////////////////////////////////////////////////////////////////////////
  245. //
  246. // InitCursorsDlg
  247. //
  248. ////////////////////////////////////////////////////////////////////////////
  249. BOOL InitCursorsDlg(HWND hwnd)
  250. {
  251. int i;
  252. ghwndDlg = hwnd;
  253. gszPreviousScheme[0] = TEXT('\0');
  254. //
  255. // Register the help message from the File Open (Browse) dialog.
  256. //
  257. wBrowseHelpMessage = RegisterWindowMessage(HELPMSGSTRING);
  258. //
  259. // Load Strings.
  260. //
  261. if (gszFileNotFound == NULL)
  262. {
  263. gszFileNotFound = GetResourceString(g_hInst, IDS_CUR_BADFILE);
  264. if (gszFileNotFound == NULL)
  265. {
  266. return (FALSE);
  267. }
  268. }
  269. if (gszBrowse == NULL)
  270. {
  271. gszBrowse = GetResourceString(g_hInst, IDS_CUR_BROWSE);
  272. if (gszBrowse == NULL)
  273. {
  274. return (FALSE);
  275. }
  276. }
  277. #ifdef WINNT
  278. if (gszFilter == NULL)
  279. {
  280. gszFilter = GetResourceString(g_hInst, IDS_ANICUR_FILTER);
  281. if (!gszFilter)
  282. {
  283. return (FALSE);
  284. }
  285. }
  286. #else
  287. if (gszFilter == NULL)
  288. {
  289. HDC dc = GetDC(NULL);
  290. BOOL fAni = (GetDeviceCaps(dc, CAPS1) & C1_COLORCURSOR) != 0;
  291. ReleaseDC(NULL, dc);
  292. gszFilter = GetResourceString( g_hInst,
  293. fAni
  294. ? IDS_ANICUR_FILTER
  295. : IDS_CUR_FILTER );
  296. if (!gszFilter)
  297. {
  298. return (FALSE);
  299. }
  300. }
  301. #endif
  302. //
  303. // Load description strings from the resource file.
  304. //
  305. for (i = 0; i < CCURSORS; i++)
  306. {
  307. if ((!gacd[i].idVisName) ||
  308. (LoadString( g_hInst,
  309. gacd[i].idVisName,
  310. gacd[i].szVisName,
  311. ARRAYSIZE(gacd[i].szVisName) ) <= 0))
  312. {
  313. //
  314. // Show something.
  315. //
  316. StringCchCopy(gacd[i].szVisName, ARRAYSIZE(gacd[i].szVisName), gacd[i].pszIniName);
  317. }
  318. }
  319. //
  320. // As an optimization, remember the window handles of the cursor
  321. // information fields.
  322. //
  323. ghwndPreview = GetDlgItem(hwnd, ID_PREVIEW);
  324. ghwndFile = GetDlgItem(hwnd, ID_FILE);
  325. ghwndFileH = GetDlgItem(hwnd, ID_FILEH);
  326. ghwndTitle = GetDlgItem(hwnd, ID_TITLE);
  327. ghwndTitleH = GetDlgItem(hwnd, ID_TITLEH);
  328. ghwndCreator = GetDlgItem(hwnd, ID_CREATOR);
  329. ghwndCreatorH = GetDlgItem(hwnd, ID_CREATORH);
  330. ghwndCursors = GetDlgItem(hwnd, ID_CURSORLIST);
  331. ghwndSchemeCB = GetDlgItem(hwnd, ID_SCHEMECOMBO);
  332. //
  333. // Create some brushes we'll be using.
  334. //
  335. CreateBrushes();
  336. //
  337. // Initialize the scheme combo box.
  338. //
  339. InitSchemeComboBox();
  340. //
  341. // Pre-clear the cursor info array.
  342. //
  343. ZeroMemory(&acuri, sizeof(acuri));
  344. //
  345. // Load the cursors.
  346. //
  347. LoadCursorSet(hwnd);
  348. //
  349. // Force an update of the preview window and the cursor details.
  350. //
  351. UpdateCursorList();
  352. InitCursorShadow(hwnd);
  353. return (TRUE);
  354. }
  355. ////////////////////////////////////////////////////////////////////////////
  356. //
  357. // LoadCursorSet
  358. //
  359. ////////////////////////////////////////////////////////////////////////////
  360. void LoadCursorSet(
  361. HWND hwnd)
  362. {
  363. CURSOR_INFO *pcuri;
  364. HKEY hkCursors;
  365. int i;
  366. if (RegOpenKeyEx(HKEY_CURRENT_USER, szCursorRegPath, 0, KEY_READ, &hkCursors) != ERROR_SUCCESS)
  367. {
  368. hkCursors = NULL;
  369. }
  370. for (pcuri = &acuri[0], i = 0; i < CCURSORS; i++, pcuri++)
  371. {
  372. if ( hkCursors )
  373. {
  374. DWORD dwType;
  375. DWORD dwCount = sizeof(pcuri->szFile);
  376. DWORD dwErr = RegQueryValueEx( hkCursors,
  377. gacd[i].pszIniName,
  378. NULL,
  379. &dwType,
  380. (LPBYTE)pcuri->szFile,
  381. &dwCount );
  382. if (dwErr == ERROR_SUCCESS)
  383. {
  384. if (TryToLoadCursor(hwnd, i, pcuri))
  385. {
  386. goto EverythingWorked;
  387. }
  388. }
  389. }
  390. // This is actually the failure case. We load the default cursor.
  391. pcuri->hcur =
  392. (HCURSOR)LoadImage( NULL,
  393. MAKEINTRESOURCE(gacd[i].idResource),
  394. IMAGE_CURSOR,
  395. 0,
  396. 0,
  397. LR_SHARED | LR_DEFAULTSIZE | LR_ENVSUBST );
  398. pcuri->fl |= CIF_SHARED;
  399. EverythingWorked:
  400. SendMessage(ghwndCursors, LB_ADDSTRING, 0, (LPARAM)gacd[i].szVisName);
  401. SendMessage(ghwndCursors, LB_SETITEMDATA, i, i);
  402. }
  403. if (hkCursors)
  404. {
  405. RegCloseKey(hkCursors);
  406. }
  407. SendMessage(ghwndCursors, LB_SETCURSEL, 0, 0);
  408. }
  409. ////////////////////////////////////////////////////////////////////////////
  410. //
  411. // CreateBrushes
  412. //
  413. // Creates the brushes that are used to paint within the Cursors applet.
  414. //
  415. ////////////////////////////////////////////////////////////////////////////
  416. VOID CreateBrushes()
  417. {
  418. ghbrHighlight = GetSysColorBrush(COLOR_HIGHLIGHT);
  419. gcrHighlightText = GetSysColor(COLOR_HIGHLIGHTTEXT);
  420. ghbrHighlightText = GetSysColorBrush(COLOR_HIGHLIGHTTEXT);
  421. ghbrWindow = GetSysColorBrush(COLOR_WINDOW);
  422. ghbrButton = GetSysColorBrush(COLOR_BTNFACE);
  423. }
  424. ////////////////////////////////////////////////////////////////////////////
  425. //
  426. // GetResourceString
  427. //
  428. // Gets a string out of the resource file.
  429. //
  430. ////////////////////////////////////////////////////////////////////////////
  431. LPTSTR GetResourceString(
  432. HINSTANCE hmod,
  433. int id)
  434. {
  435. TCHAR szBuffer[256];
  436. LPTSTR psz;
  437. int cch;
  438. if ((cch = LoadString(hmod, id, szBuffer, ARRAYSIZE(szBuffer))) == 0)
  439. {
  440. return (NULL);
  441. }
  442. psz = LocalAlloc(LPTR, (cch + 1) * sizeof(TCHAR));
  443. if (psz != NULL)
  444. {
  445. int i;
  446. for (i = 0; i <= cch; i++)
  447. {
  448. psz[i] = (szBuffer[i] == TEXT('\1')) ? TEXT('\0') : szBuffer[i];
  449. }
  450. }
  451. return (psz);
  452. }
  453. ////////////////////////////////////////////////////////////////////////////
  454. //
  455. // FreeItemCursor
  456. //
  457. ////////////////////////////////////////////////////////////////////////////
  458. void FreeItemCursor(
  459. CURSOR_INFO *pcuri)
  460. {
  461. if (pcuri->hcur)
  462. {
  463. if (!(pcuri->fl & CIF_SHARED))
  464. {
  465. DestroyCursor(pcuri->hcur);
  466. }
  467. pcuri->hcur = NULL;
  468. }
  469. }
  470. ////////////////////////////////////////////////////////////////////////////
  471. //
  472. // MousePtrDlg
  473. //
  474. ////////////////////////////////////////////////////////////////////////////
  475. INT_PTR CALLBACK MousePtrDlg(
  476. HWND hwnd,
  477. UINT msg,
  478. WPARAM wParam,
  479. LPARAM lParam)
  480. {
  481. CURSOR_INFO *pcuri;
  482. HKEY hkCursors;
  483. int i;
  484. switch (msg)
  485. {
  486. case ( WM_INITDIALOG ) :
  487. {
  488. return InitCursorsDlg(hwnd);
  489. }
  490. case ( WM_DISPLAYCHANGE ) :
  491. {
  492. InitCursorShadow(hwnd);
  493. SHPropagateMessage(hwnd, msg, wParam, lParam, TRUE);
  494. break;
  495. }
  496. case ( WM_MEASUREITEM ) :
  497. {
  498. ((MEASUREITEMSTRUCT *)lParam)->itemHeight = gcyCursor + 2;
  499. break;
  500. }
  501. case ( WM_DRAWITEM ) :
  502. {
  503. DrawCursorListItem((DRAWITEMSTRUCT *)lParam);
  504. break;
  505. }
  506. case ( WM_COMMAND ) :
  507. {
  508. switch (LOWORD(wParam))
  509. {
  510. case ( ID_SCHEMECOMBO ) :
  511. {
  512. switch (HIWORD(wParam))
  513. {
  514. case ( CBN_SELCHANGE ) :
  515. {
  516. LoadScheme();
  517. break;
  518. }
  519. }
  520. break;
  521. }
  522. case ( ID_DEFAULT ) :
  523. {
  524. //
  525. // Throw away any fancy new cursor and replace it with
  526. // the system's original.
  527. //
  528. i = (int)SendMessage(ghwndCursors, LB_GETCURSEL, 0, 0);
  529. pcuri = &acuri[i];
  530. if (!(pcuri->fl & CIF_FILE))
  531. {
  532. break;
  533. }
  534. pcuri->fl = CIF_MODIFIED;
  535. SendMessage(GetParent(hwnd), PSM_CHANGED, (WPARAM)hwnd, 0L);
  536. FreeItemCursor(pcuri);
  537. pcuri->hcur =
  538. (HCURSOR)LoadImage( NULL,
  539. MAKEINTRESOURCE(gacd[i].idDefResource),
  540. IMAGE_CURSOR,
  541. 0,
  542. 0,
  543. LR_DEFAULTSIZE | LR_ENVSUBST );
  544. *pcuri->szFile = TEXT('\0');
  545. EnableWindow(GetDlgItem(hwnd, ID_SAVESCHEME), TRUE);
  546. UpdateCursorList();
  547. break;
  548. }
  549. case ( ID_CURSORLIST ) :
  550. {
  551. switch (HIWORD(wParam))
  552. {
  553. case ( LBN_SELCHANGE ) :
  554. {
  555. i = (int)SendMessage((HWND)lParam, LB_GETCURSEL, 0, 0);
  556. pcuri = &acuri[i];
  557. //
  558. // Show a preview (including animation) in the
  559. // preview window.
  560. //
  561. SendMessage( ghwndPreview,
  562. STM_SETICON,
  563. (WPARAM)pcuri->hcur,
  564. 0L );
  565. //
  566. // Enable the "Set Default" button if the cursor
  567. // is from a file.
  568. //
  569. EnableWindow( GetDlgItem(hwnd, ID_DEFAULT),
  570. (pcuri->fl & CIF_FILE ) ? TRUE : FALSE );
  571. break;
  572. }
  573. case ( LBN_DBLCLK ) :
  574. {
  575. Browse(hwnd);
  576. break;
  577. }
  578. }
  579. break;
  580. }
  581. case ( ID_BROWSE ) :
  582. {
  583. Browse(hwnd);
  584. break;
  585. }
  586. case ( ID_SAVESCHEME ) :
  587. {
  588. SaveSchemeAs();
  589. break;
  590. }
  591. case ( ID_REMOVESCHEME ) :
  592. {
  593. RemoveScheme();
  594. break;
  595. }
  596. case ( ID_CURSORSHADOW ) :
  597. {
  598. gfCursorShadow = IsDlgButtonChecked(hwnd, ID_CURSORSHADOW);
  599. SendMessage(GetParent(hwnd), PSM_CHANGED, (WPARAM)hwnd, 0L);
  600. break;
  601. }
  602. }
  603. break;
  604. }
  605. case ( WM_NOTIFY ) :
  606. {
  607. switch(((NMHDR *)lParam)->code)
  608. {
  609. case ( PSN_APPLY ) :
  610. {
  611. //
  612. // Change cursor to hour glass.
  613. //
  614. HourGlass(TRUE);
  615. // Set cursor shadow
  616. SystemParametersInfo( SPI_SETCURSORSHADOW,
  617. 0,
  618. IntToPtr(gfCursorShadow),
  619. SPIF_UPDATEINIFILE);
  620. //
  621. // Save the modified scheme, order of calls important.
  622. //
  623. SaveCurSchemeName();
  624. //
  625. // Set the system cursors.
  626. //
  627. if (RegCreateKeyEx(HKEY_CURRENT_USER, szCursorRegPath, 0, NULL, 0, KEY_SET_VALUE, NULL, &hkCursors, NULL) == ERROR_SUCCESS)
  628. {
  629. for (pcuri = &acuri[0], i = 0; i < CCURSORS; i++, pcuri++)
  630. {
  631. if (pcuri->fl & CIF_MODIFIED)
  632. {
  633. LPCTSTR data;
  634. UINT count;
  635. // Always unexpand before we save a filename
  636. UnExpandPath(pcuri->szFile, ARRAYSIZE(pcuri->szFile));
  637. data = (pcuri->fl & CIF_FILE) ? pcuri->szFile : TEXT("");
  638. count = (pcuri->fl & CIF_FILE) ? (lstrlen(pcuri->szFile) + 1) * sizeof(TCHAR) : sizeof(TCHAR);
  639. RegSetValueEx(hkCursors, gacd[i].pszIniName, 0L, REG_EXPAND_SZ, (CONST LPBYTE)data, count);
  640. }
  641. }
  642. RegCloseKey(hkCursors);
  643. SystemParametersInfo( SPI_SETCURSORS,
  644. 0,
  645. 0,
  646. SPIF_SENDCHANGE );
  647. }
  648. HourGlass(FALSE);
  649. break;
  650. }
  651. default :
  652. {
  653. return (FALSE);
  654. }
  655. }
  656. break;
  657. }
  658. case ( WM_SYSCOLORCHANGE ) :
  659. {
  660. gcrHighlightText = GetSysColor(COLOR_HIGHLIGHTTEXT);
  661. SHPropagateMessage(hwnd, msg, wParam, lParam, TRUE);
  662. break;
  663. }
  664. case ( WM_WININICHANGE ) :
  665. {
  666. SHPropagateMessage(hwnd, msg, wParam, lParam, TRUE);
  667. break;
  668. }
  669. case ( WM_DESTROY ) :
  670. {
  671. //
  672. // Clean up global allocs.
  673. //
  674. CleanUpEverything();
  675. if (gszFileNotFound != NULL)
  676. {
  677. LocalFree(gszFileNotFound);
  678. gszFileNotFound = NULL;
  679. }
  680. if (gszBrowse != NULL)
  681. {
  682. LocalFree(gszBrowse);
  683. gszBrowse = NULL;
  684. }
  685. if (gszFilter != NULL)
  686. {
  687. LocalFree(gszFilter);
  688. gszFilter = NULL;
  689. }
  690. break;
  691. }
  692. case ( WM_HELP ) :
  693. {
  694. WinHelp( ((LPHELPINFO)lParam)->hItemHandle,
  695. HELP_FILE,
  696. HELP_WM_HELP,
  697. (DWORD_PTR)(LPTSTR)aMousePtrHelpIDs );
  698. break;
  699. }
  700. case ( WM_CONTEXTMENU ) :
  701. {
  702. WinHelp( (HWND)wParam,
  703. HELP_FILE,
  704. HELP_CONTEXTMENU,
  705. (DWORD_PTR)(LPVOID)aMousePtrHelpIDs );
  706. break;
  707. }
  708. default :
  709. {
  710. return (FALSE);
  711. }
  712. }
  713. return (TRUE);
  714. }
  715. ////////////////////////////////////////////////////////////////////////////
  716. //
  717. // DrawCursorListItem
  718. //
  719. ////////////////////////////////////////////////////////////////////////////
  720. void DrawCursorListItem(
  721. DRAWITEMSTRUCT *pdis)
  722. {
  723. CURSOR_INFO *pcuri;
  724. COLORREF clrOldText, clrOldBk;
  725. RECT rc;
  726. DWORD dwLayout;
  727. if (!guTextHeight || !guTextGap)
  728. {
  729. TEXTMETRIC tm;
  730. tm.tmHeight = 0;
  731. GetTextMetrics(pdis->hDC, &tm);
  732. if (tm.tmHeight < 0)
  733. {
  734. tm.tmHeight *= -1;
  735. }
  736. guTextHeight = (UINT)tm.tmHeight;
  737. guTextGap = (UINT)tm.tmAveCharWidth;
  738. }
  739. pcuri = &acuri[pdis->itemData];
  740. if (pdis->itemState & ODS_SELECTED)
  741. {
  742. clrOldText = SetTextColor(pdis->hDC, GetSysColor(COLOR_HIGHLIGHTTEXT));
  743. clrOldBk = SetBkColor(pdis->hDC, GetSysColor(COLOR_HIGHLIGHT));
  744. }
  745. else
  746. {
  747. clrOldText = SetTextColor(pdis->hDC, GetSysColor(COLOR_WINDOWTEXT));
  748. clrOldBk = SetBkColor(pdis->hDC, GetSysColor(COLOR_WINDOW));
  749. }
  750. ExtTextOut( pdis->hDC,
  751. pdis->rcItem.left + guTextGap, // fudge factor
  752. (pdis->rcItem.top + pdis->rcItem.bottom - guTextHeight) / 2,
  753. ETO_OPAQUE,
  754. &pdis->rcItem,
  755. gacd[pdis->itemData].szVisName,
  756. lstrlen(gacd[pdis->itemData].szVisName),
  757. NULL );
  758. if (pcuri->hcur != NULL)
  759. {
  760. dwLayout = GetLayout(pdis->hDC);
  761. SetLayout(pdis->hDC, dwLayout | LAYOUT_BITMAPORIENTATIONPRESERVED);
  762. DrawIcon( pdis->hDC,
  763. pdis->rcItem.right - (gcxCursor + guTextGap),
  764. pdis->rcItem.top + 1, pcuri->hcur );
  765. SetLayout(pdis->hDC, dwLayout);
  766. }
  767. if (pdis->itemState & ODS_FOCUS)
  768. {
  769. CopyRect(&rc, &pdis->rcItem);
  770. InflateRect(&rc, -1, -1);
  771. DrawFocusRect(pdis->hDC, &rc);
  772. }
  773. SetTextColor(pdis->hDC, clrOldText);
  774. SetBkColor(pdis->hDC, clrOldBk);
  775. }
  776. ////////////////////////////////////////////////////////////////////////////
  777. //
  778. // TryToLoadCursor
  779. //
  780. ////////////////////////////////////////////////////////////////////////////
  781. BOOL TryToLoadCursor(
  782. HWND hwnd,
  783. int i,
  784. CURSOR_INFO *pcuri)
  785. {
  786. BOOL fRet = TRUE;
  787. BOOL bCustom = (*pcuri->szFile != 0);
  788. if (bCustom && !GetCursorFromFile(pcuri))
  789. {
  790. HWND hwndControl = GetParent(hwnd);
  791. LPTSTR pszText;
  792. LPTSTR pszFilename;
  793. int cchText;
  794. //
  795. // MakeFilename returns the address of a global, so we don't
  796. // need to free pszFilename.
  797. //
  798. pszFilename = MakeFilename(pcuri->szFile);
  799. cchText = lstrlen(gszFileNotFound) + lstrlen(gacd[i].szVisName) + lstrlen(pszFilename) + 1;
  800. pszText = LocalAlloc(LPTR, cchText * sizeof(TCHAR));
  801. if (pszText == NULL)
  802. {
  803. return (FALSE);
  804. }
  805. StringCchPrintf(pszText, cchText, gszFileNotFound, pszFilename, gacd[i].szVisName);
  806. MessageBeep(MB_ICONEXCLAMATION);
  807. MessageBox(hwndControl, pszText, NULL, MB_ICONEXCLAMATION | MB_OK);
  808. pcuri->fl = CIF_MODIFIED;
  809. SendMessage(GetParent(hwnd), PSM_CHANGED, (WPARAM)hwnd, 0L);
  810. bCustom = FALSE;
  811. LocalFree(pszText);
  812. }
  813. if (!bCustom)
  814. {
  815. FreeItemCursor(pcuri);
  816. pcuri->hcur =
  817. (HCURSOR)LoadImage( NULL,
  818. MAKEINTRESOURCE(gacd[i].idDefResource),
  819. IMAGE_CURSOR,
  820. 0,
  821. 0,
  822. LR_DEFAULTSIZE | LR_ENVSUBST );
  823. *pcuri->szFile = TEXT('\0');
  824. EnableWindow(GetDlgItem(hwnd, ID_SAVESCHEME), TRUE);
  825. UpdateCursorList();
  826. }
  827. return (pcuri->hcur != NULL);
  828. }
  829. ////////////////////////////////////////////////////////////////////////////
  830. //
  831. // GetCursorFromFile
  832. //
  833. ////////////////////////////////////////////////////////////////////////////
  834. BOOL GetCursorFromFile(
  835. CURSOR_INFO *pcuri)
  836. {
  837. pcuri->fl = 0;
  838. pcuri->hcur =
  839. (HCURSOR)LoadImage( NULL,
  840. MakeFilename(pcuri->szFile),
  841. IMAGE_CURSOR,
  842. 0,
  843. 0,
  844. LR_LOADFROMFILE | LR_DEFAULTSIZE | LR_ENVSUBST );
  845. if (pcuri->hcur)
  846. {
  847. pcuri->fl |= CIF_FILE;
  848. }
  849. return (pcuri->hcur != NULL);
  850. }
  851. ////////////////////////////////////////////////////////////////////////////
  852. //
  853. // MousePtrBrowsePreview
  854. //
  855. ////////////////////////////////////////////////////////////////////////////
  856. void MousePtrBrowsePreview(
  857. HWND hDlg)
  858. {
  859. PMOUSEPTRBR pPtrBr;
  860. HCURSOR hcurOld;
  861. pPtrBr = (PMOUSEPTRBR)GetWindowLongPtr(hDlg, DWLP_USER);
  862. hcurOld = pPtrBr->curi.hcur;
  863. CommDlg_OpenSave_GetFilePath( GetParent(hDlg),
  864. pPtrBr->curi.szFile,
  865. ARRAYSIZE(pPtrBr->curi.szFile) );
  866. if (!GetCursorFromFile(&pPtrBr->curi))
  867. {
  868. pPtrBr->curi.hcur = NULL;
  869. }
  870. SendDlgItemMessage( hDlg,
  871. ID_CURSORPREVIEW,
  872. STM_SETICON,
  873. (WPARAM)pPtrBr->curi.hcur, 0L );
  874. if (hcurOld)
  875. {
  876. DestroyCursor(hcurOld);
  877. }
  878. }
  879. ////////////////////////////////////////////////////////////////////////////
  880. //
  881. // MousePtrBrowseNotify
  882. //
  883. ////////////////////////////////////////////////////////////////////////////
  884. BOOL MousePtrBrowseNotify(
  885. HWND hDlg,
  886. LPOFNOTIFY pofn)
  887. {
  888. switch (pofn->hdr.code)
  889. {
  890. case ( CDN_SELCHANGE ) :
  891. {
  892. //
  893. // Don't show the cursor until the user stops moving around.
  894. //
  895. if (SetTimer(hDlg, IDT_BROWSE, 250, NULL))
  896. {
  897. //
  898. // Don't destroy the old cursor.
  899. //
  900. SendDlgItemMessage( hDlg,
  901. ID_CURSORPREVIEW,
  902. STM_SETICON,
  903. 0,
  904. 0L );
  905. }
  906. else
  907. {
  908. MousePtrBrowsePreview(hDlg);
  909. }
  910. break;
  911. }
  912. }
  913. return (TRUE);
  914. }
  915. ////////////////////////////////////////////////////////////////////////////
  916. //
  917. // MousePtrBrowseDlgProc
  918. //
  919. ////////////////////////////////////////////////////////////////////////////
  920. INT_PTR CALLBACK MousePtrBrowseDlgProc(
  921. HWND hDlg,
  922. UINT uMsg,
  923. WPARAM wParam,
  924. LPARAM lParam)
  925. {
  926. switch (uMsg)
  927. {
  928. case ( WM_INITDIALOG ) :
  929. {
  930. PMOUSEPTRBR pPtrBr = (PMOUSEPTRBR)((LPOPENFILENAME)lParam)->lCustData;
  931. if (pPtrBr)
  932. {
  933. pPtrBr->hDlg = hDlg;
  934. }
  935. SetWindowLongPtr(hDlg, DWLP_USER, (LONG_PTR) pPtrBr);
  936. break;
  937. }
  938. case ( WM_DESTROY ) :
  939. {
  940. KillTimer(hDlg, IDT_BROWSE);
  941. //
  942. // Don't destroy the old cursor.
  943. //
  944. SendDlgItemMessage(hDlg, ID_CURSORPREVIEW, STM_SETICON, 0, 0L);
  945. break;
  946. }
  947. case ( WM_TIMER ) :
  948. {
  949. KillTimer(hDlg, IDT_BROWSE);
  950. MousePtrBrowsePreview(hDlg);
  951. break;
  952. }
  953. case ( WM_NOTIFY ) :
  954. {
  955. return (MousePtrBrowseNotify(hDlg, (LPOFNOTIFY) lParam));
  956. }
  957. case ( WM_HELP ) :
  958. {
  959. WinHelp( (HWND)((LPHELPINFO)lParam)->hItemHandle,
  960. HELP_FILE,
  961. HELP_WM_HELP,
  962. (DWORD_PTR)(LPTSTR)aMousePtrBrowseHelpIDs );
  963. break;
  964. }
  965. case ( WM_CONTEXTMENU ) :
  966. {
  967. WinHelp( (HWND)wParam,
  968. HELP_FILE,
  969. HELP_CONTEXTMENU,
  970. (DWORD_PTR)(LPVOID)aMousePtrBrowseHelpIDs );
  971. break;
  972. }
  973. default :
  974. {
  975. return (FALSE);
  976. }
  977. }
  978. return (TRUE);
  979. }
  980. ////////////////////////////////////////////////////////////////////////////
  981. //
  982. // Browse
  983. //
  984. // Browse the file system for a new cursor for the selected item.
  985. //
  986. ////////////////////////////////////////////////////////////////////////////
  987. BOOL Browse(HWND hwndOwner)
  988. {
  989. static TCHAR szCustomFilter[80] = TEXT("");
  990. static TCHAR szStartDir[MAX_PATH] = TEXT("");
  991. OPENFILENAME ofn;
  992. CURSOR_INFO curi;
  993. int i;
  994. BOOL fRet = FALSE;
  995. MOUSEPTRBR sPtrBr;
  996. if (!*szStartDir)
  997. {
  998. HKEY key = NULL;
  999. if (RegOpenKeyEx(HKEY_LOCAL_MACHINE, szRegStr_Setup, 0, KEY_READ, &key) == ERROR_SUCCESS)
  1000. {
  1001. LONG len = ARRAYSIZE(szStartDir);
  1002. if (RegQueryValueEx( key,
  1003. szSharedDir,
  1004. NULL,
  1005. NULL,
  1006. (LPBYTE)szStartDir,
  1007. &len ) != ERROR_SUCCESS)
  1008. {
  1009. *szStartDir = TEXT('\0');
  1010. }
  1011. RegCloseKey(key);
  1012. }
  1013. if (!*szStartDir)
  1014. {
  1015. if (0 == GetWindowsDirectory(szStartDir, ARRAYSIZE(szStartDir)))
  1016. {
  1017. goto Error;
  1018. }
  1019. }
  1020. PathAppend(szStartDir, szCursorSubdir);
  1021. }
  1022. curi.szFile[0] = TEXT('\0');
  1023. sPtrBr.curi.szFile[0] = TEXT('\0');
  1024. sPtrBr.curi.hcur = NULL;
  1025. ofn.lStructSize = sizeof(ofn);
  1026. ofn.hwndOwner = hwndOwner;
  1027. ofn.hInstance = g_hInst;
  1028. ofn.lpstrFilter = gszFilter;
  1029. ofn.lpstrCustomFilter = szCustomFilter;
  1030. ofn.nMaxCustFilter = ARRAYSIZE(szCustomFilter);
  1031. ofn.nFilterIndex = 1;
  1032. ofn.lpstrFile = curi.szFile;
  1033. ofn.nMaxFile = ARRAYSIZE(curi.szFile);
  1034. ofn.lpstrFileTitle = NULL;
  1035. ofn.nMaxFileTitle = 0;
  1036. ofn.lpstrInitialDir = szStartDir;
  1037. ofn.lpstrTitle = gszBrowse;
  1038. ofn.Flags = OFN_EXPLORER | OFN_ENABLETEMPLATE | OFN_ENABLEHOOK |
  1039. OFN_FILEMUSTEXIST | OFN_HIDEREADONLY;
  1040. ofn.lpstrDefExt = NULL;
  1041. ofn.lpfnHook = MousePtrBrowseDlgProc;
  1042. ofn.lpTemplateName = MAKEINTRESOURCE(DLG_MOUSE_POINTER_BROWSE);
  1043. ofn.lCustData = (LPARAM)(PMOUSEPTRBR)&sPtrBr;
  1044. fRet = GetOpenFileName(&ofn);
  1045. if (!fRet)
  1046. {
  1047. goto brErrExit;
  1048. }
  1049. // we got a valid value, save the current location
  1050. GetCurrentDirectory(ARRAYSIZE(szStartDir), szStartDir);
  1051. fRet = FALSE;
  1052. //
  1053. // We have probably already gotten this cursor.
  1054. //
  1055. if (lstrcmpi(curi.szFile, sPtrBr.curi.szFile) == 0)
  1056. {
  1057. if (!sPtrBr.curi.hcur)
  1058. {
  1059. goto brErrExit;
  1060. }
  1061. curi = sPtrBr.curi;
  1062. //
  1063. // Clear this so it will not get destroyed in the cleanup code.
  1064. //
  1065. sPtrBr.curi.hcur = NULL;
  1066. }
  1067. else
  1068. {
  1069. //
  1070. // The user must have typed in a name.
  1071. //
  1072. if (!GetCursorFromFile(&curi))
  1073. {
  1074. goto brErrExit;
  1075. }
  1076. }
  1077. //
  1078. // Convert mapped drive letters to UNC.
  1079. //
  1080. if (curi.szFile[1] == TEXT(':'))
  1081. {
  1082. TCHAR szDrive[3];
  1083. TCHAR szNet[MAX_PATH];
  1084. int lenNet = ARRAYSIZE(szNet);
  1085. StringCchCopy(szDrive, ARRAYSIZE(szDrive), curi.szFile);
  1086. if ((WNetGetConnection(szDrive, szNet, &lenNet) == NO_ERROR) &&
  1087. (szNet[0] == TEXT('\\')) &&
  1088. (szNet[1] == TEXT('\\')))
  1089. {
  1090. StringCchCat(szNet, ARRAYSIZE(szNet), curi.szFile + 2);
  1091. StringCchCopy(curi.szFile, ARRAYSIZE(curi.szFile), szNet);
  1092. }
  1093. }
  1094. i = (int)SendMessage(ghwndCursors, LB_GETCURSEL, 0, 0);
  1095. curi.fl |= CIF_MODIFIED;
  1096. SendMessage(GetParent(ghwndDlg), PSM_CHANGED, (WPARAM)ghwndDlg, 0L);
  1097. EnableWindow(GetDlgItem(ghwndDlg, ID_SAVESCHEME), TRUE);
  1098. //
  1099. // Destroy the old cursor before we retain the new one.
  1100. //
  1101. FreeItemCursor(acuri + i);
  1102. acuri[i] = curi;
  1103. UpdateCursorList();
  1104. fRet = TRUE;
  1105. brErrExit:
  1106. if (sPtrBr.curi.hcur)
  1107. {
  1108. DestroyCursor(sPtrBr.curi.hcur);
  1109. }
  1110. Error:
  1111. return (fRet);
  1112. }
  1113. ////////////////////////////////////////////////////////////////////////////
  1114. //
  1115. // CleanUpEverything
  1116. //
  1117. // Destroy all the outstanding cursors.
  1118. //
  1119. ////////////////////////////////////////////////////////////////////////////
  1120. void CleanUpEverything()
  1121. {
  1122. CURSOR_INFO *pcuri;
  1123. int i;
  1124. for (pcuri = &acuri[0], i = 0; i < CCURSORS; i++, pcuri++)
  1125. {
  1126. FreeItemCursor(pcuri);
  1127. }
  1128. }
  1129. ////////////////////////////////////////////////////////////////////////////
  1130. //
  1131. // UpdateCursorList
  1132. //
  1133. // Force the Cursor ListBox to repaint and the cursor information below the
  1134. // listbox to be refreshed as well.
  1135. //
  1136. ////////////////////////////////////////////////////////////////////////////
  1137. VOID UpdateCursorList()
  1138. {
  1139. int i = (int)SendMessage(ghwndCursors, LB_GETCURSEL, 0, 0);
  1140. PCURSOR_INFO pcuri = ((i >= 0) ? &acuri[i] : NULL);
  1141. HCURSOR hcur = pcuri ? pcuri->hcur : NULL;
  1142. HWND hDefaultButton = GetDlgItem(ghwndDlg, ID_DEFAULT);
  1143. BOOL fEnableDefaultButton = (pcuri && (pcuri->fl & CIF_FILE));
  1144. InvalidateRect(ghwndCursors, NULL, FALSE);
  1145. SendMessage(ghwndPreview, STM_SETICON, (WPARAM)hcur, 0L);
  1146. if (!fEnableDefaultButton && (GetFocus() == hDefaultButton))
  1147. {
  1148. SendMessage(ghwndDlg, WM_NEXTDLGCTL, (WPARAM)ghwndCursors, TRUE);
  1149. }
  1150. EnableWindow(hDefaultButton, fEnableDefaultButton);
  1151. }
  1152. ////////////////////////////////////////////////////////////////////////////
  1153. //
  1154. // SaveSchemeAs
  1155. //
  1156. ////////////////////////////////////////////////////////////////////////////
  1157. BOOL SaveSchemeAs()
  1158. {
  1159. BOOL fSuccess = TRUE;
  1160. //
  1161. // Dialog proc returns TRUE & sets gszSchemeName to filename entered
  1162. // on OK.
  1163. //
  1164. if (DialogBox( g_hInst,
  1165. MAKEINTRESOURCE(DLG_MOUSE_POINTER_SCHEMESAVE),
  1166. ghwndDlg,
  1167. SaveSchemeDlgProc ))
  1168. {
  1169. fSuccess = SaveScheme();
  1170. if (fSuccess)
  1171. {
  1172. int index = (int)SendMessage( ghwndSchemeCB,
  1173. CB_FINDSTRINGEXACT,
  1174. (WPARAM)-1,
  1175. (LPARAM)gszSchemeName );
  1176. //
  1177. // If not found, add it.
  1178. //
  1179. if (index < 0)
  1180. {
  1181. index = (int)SendMessage( ghwndSchemeCB,
  1182. CB_ADDSTRING,
  1183. 0,
  1184. (LPARAM)gszSchemeName );
  1185. }
  1186. //
  1187. // Select the name.
  1188. //
  1189. SendMessage(ghwndSchemeCB, CB_SETCURSEL, (WPARAM) index, 0);
  1190. //
  1191. // Since this is now a user saved scheme, activate the delete
  1192. // button.
  1193. //
  1194. EnableWindow(GetDlgItem(ghwndDlg, ID_REMOVESCHEME), TRUE);
  1195. }
  1196. }
  1197. return (fSuccess);
  1198. }
  1199. ////////////////////////////////////////////////////////////////////////////
  1200. //
  1201. // SubstituteString
  1202. //
  1203. // Replaces the string pszRemove with the string pszReplace in the
  1204. // string pszInput and places the output in pszResult. Only looks
  1205. // at the begining of the input string.
  1206. //
  1207. ////////////////////////////////////////////////////////////////////////////
  1208. BOOL SubstituteString(LPCTSTR pszInput, LPCTSTR pszRemove, LPCTSTR pszReplace, LPTSTR pszResult, UINT cchResult)
  1209. {
  1210. UINT cchInput = lstrlen(pszInput);
  1211. UINT cchRemove = lstrlen(pszRemove);
  1212. if (cchRemove <= cchInput)
  1213. {
  1214. if (CompareString(LOCALE_SYSTEM_DEFAULT, NORM_IGNORECASE,
  1215. pszRemove, cchRemove, pszInput, cchRemove) == CSTR_EQUAL)
  1216. {
  1217. int cchReplace = lstrlen(pszReplace);
  1218. if ((cchInput - cchRemove) + cchReplace < cchResult)
  1219. {
  1220. StringCchCopy(pszResult, cchResult, pszReplace);
  1221. StringCchCat(pszResult, cchResult, pszInput + cchRemove);
  1222. return TRUE;
  1223. }
  1224. }
  1225. }
  1226. return FALSE;
  1227. }
  1228. BOOL UnExpandPath(LPTSTR pszPath, int cchPath)
  1229. {
  1230. static TCHAR szUserProfile[MAX_PATH];
  1231. static TCHAR szSystemRoot[MAX_PATH];
  1232. static TCHAR szProgramFiles[MAX_PATH];
  1233. static BOOL bInit = FALSE;
  1234. TCHAR szUnexpandedFilename[MAX_PATH];
  1235. if ( !bInit )
  1236. {
  1237. ExpandEnvironmentStrings( TEXT("%USERPROFILE%"), szUserProfile, ARRAYSIZE(szUserProfile) );
  1238. ExpandEnvironmentStrings( TEXT("%SYSTEMROOT%"), szSystemRoot, ARRAYSIZE(szSystemRoot) );
  1239. ExpandEnvironmentStrings( TEXT("%ProgramFiles%"), szProgramFiles, ARRAYSIZE(szProgramFiles) );
  1240. bInit = TRUE;
  1241. }
  1242. if (!SubstituteString(pszPath, szUserProfile, TEXT("%USERPROFILE%"), szUnexpandedFilename, ARRAYSIZE(szUnexpandedFilename)))
  1243. {
  1244. if (!SubstituteString(pszPath, szSystemRoot, TEXT("%SYSTEMROOT%"), szUnexpandedFilename, ARRAYSIZE(szUnexpandedFilename)))
  1245. {
  1246. if (!SubstituteString(pszPath, szProgramFiles, TEXT("%ProgramFiles%"), szUnexpandedFilename, ARRAYSIZE(szUnexpandedFilename)))
  1247. {
  1248. return FALSE;
  1249. }
  1250. }
  1251. }
  1252. StringCchCopy(pszPath, cchPath, szUnexpandedFilename);
  1253. return TRUE;
  1254. }
  1255. ////////////////////////////////////////////////////////////////////////////
  1256. //
  1257. // SaveScheme
  1258. //
  1259. ////////////////////////////////////////////////////////////////////////////
  1260. BOOL SaveScheme()
  1261. {
  1262. BOOL fSuccess = FALSE;
  1263. if (*gszSchemeName)
  1264. {
  1265. const BUFFER_SIZE = CCURSORS * (MAX_PATH + 1) + 1;
  1266. LPTSTR pszBuffer = (LPTSTR)LocalAlloc( LMEM_FIXED,
  1267. BUFFER_SIZE * sizeof(TCHAR) );
  1268. HKEY hk;
  1269. int i;
  1270. if (!pszBuffer)
  1271. {
  1272. return (FALSE);
  1273. }
  1274. pszBuffer[0] = TEXT('\0');
  1275. for (i = 0; i < CCURSORS; i++)
  1276. {
  1277. if (i)
  1278. {
  1279. StringCchCat(pszBuffer, BUFFER_SIZE, TEXT(","));
  1280. }
  1281. // Replace path with evnironment variables.
  1282. UnExpandPath(acuri[i].szFile, ARRAYSIZE(acuri[i].szFile));
  1283. StringCchCat(pszBuffer, BUFFER_SIZE, acuri[i].szFile);
  1284. }
  1285. if (RegCreateKeyEx( HKEY_CURRENT_USER, c_szRegPathCursors, 0, NULL, 0, KEY_CREATE_SUB_KEY, NULL, &hk, NULL) == ERROR_SUCCESS)
  1286. {
  1287. HKEY hks;
  1288. if (RegCreateKeyEx(hk, c_szSchemes, 0, NULL, 0, KEY_SET_VALUE | KEY_QUERY_VALUE, NULL, &hks, NULL) == ERROR_SUCCESS)
  1289. {
  1290. LPTSTR pszOldValue = (LPTSTR)LocalAlloc(LMEM_FIXED,
  1291. BUFFER_SIZE * sizeof(TCHAR));
  1292. if (NULL != pszOldValue)
  1293. {
  1294. DWORD dwType;
  1295. DWORD dwSize = BUFFER_SIZE*sizeof(TCHAR);
  1296. BOOL bSave = FALSE;
  1297. int ret = RegQueryValueEx(hks, gszSchemeName, NULL, &dwType, (LPBYTE)pszOldValue, &dwSize);
  1298. //
  1299. // If the key already exists, ask to confirm the overwrite.
  1300. //
  1301. if (ret == ERROR_SUCCESS && (dwType==REG_SZ || dwType==REG_EXPAND_SZ))
  1302. {
  1303. // only need to save if value is different from old value
  1304. if (lstrcmp(pszOldValue,pszBuffer)!=0)
  1305. {
  1306. TCHAR szTitle[OVERWRITE_TITLE];
  1307. TCHAR szMsg[OVERWRITE_MSG];
  1308. LoadString(g_hInst, IDS_OVERWRITE_TITLE, szTitle, OVERWRITE_TITLE);
  1309. LoadString(g_hInst, IDS_OVERWRITE_MSG, szMsg, OVERWRITE_MSG);
  1310. if (MessageBox( ghwndDlg,
  1311. szMsg,
  1312. szTitle,
  1313. MB_ICONQUESTION | MB_YESNO ) == IDYES)
  1314. {
  1315. //
  1316. // Overwrite confirmed. Safe to save.
  1317. //
  1318. bSave = TRUE;
  1319. }
  1320. }
  1321. else
  1322. {
  1323. // no need to save since the new value is the same as the old value.
  1324. fSuccess = TRUE;
  1325. }
  1326. }
  1327. else
  1328. {
  1329. //
  1330. // The key doesn't exist, so it's safe to create it.
  1331. //
  1332. bSave = TRUE;
  1333. }
  1334. if (bSave)
  1335. {
  1336. if (RegSetValueEx(hks, gszSchemeName, 0, REG_EXPAND_SZ, (LPBYTE)pszBuffer, (lstrlen(pszBuffer) + 1) * sizeof(TCHAR)) == ERROR_SUCCESS)
  1337. {
  1338. fSuccess = TRUE;
  1339. }
  1340. }
  1341. LocalFree( pszOldValue );
  1342. }
  1343. RegCloseKey(hks);
  1344. }
  1345. RegCloseKey(hk);
  1346. }
  1347. LocalFree(pszBuffer);
  1348. }
  1349. return (fSuccess);
  1350. }
  1351. ////////////////////////////////////////////////////////////////////////////
  1352. //
  1353. // SaveCurSchemeName
  1354. //
  1355. ////////////////////////////////////////////////////////////////////////////
  1356. void SaveCurSchemeName()
  1357. {
  1358. HKEY hk;
  1359. if (RegCreateKeyEx(HKEY_CURRENT_USER, c_szRegPathCursors, 0, NULL, 0, KEY_SET_VALUE, NULL, &hk, NULL) == ERROR_SUCCESS)
  1360. {
  1361. int index = (int)SendMessage(ghwndSchemeCB, CB_GETCURSEL, 0, 0L);
  1362. SendMessage(ghwndSchemeCB, CB_GETLBTEXT, (WPARAM)index, (LPARAM)gszSchemeName);
  1363. //
  1364. // Exclude the "none" pattern.
  1365. //
  1366. if (lstrcmpi(gszSchemeName, szNone) == 0)
  1367. {
  1368. *gszSchemeName = 0;
  1369. iSchemeLocation = ID_NONE_SCHEME;
  1370. }
  1371. else
  1372. {
  1373. iSchemeLocation = SystemOrUser(gszSchemeName);
  1374. }
  1375. RegSetValue(hk, NULL, REG_SZ, gszSchemeName, (lstrlen(gszSchemeName) + 1) * sizeof(TCHAR) );
  1376. RegSetValueEx(hk, szSchemeSource, 0, REG_DWORD, (unsigned char *)&iSchemeLocation, sizeof(iSchemeLocation));
  1377. RegCloseKey(hk);
  1378. if (iSchemeLocation == ID_USER_SCHEME)
  1379. {
  1380. SaveScheme();
  1381. }
  1382. }
  1383. }
  1384. ////////////////////////////////////////////////////////////////////////////
  1385. //
  1386. // LoadScheme
  1387. //
  1388. // This is called whenever a selection is made from the schemes combo box.
  1389. //
  1390. ////////////////////////////////////////////////////////////////////////////
  1391. BOOL LoadScheme()
  1392. {
  1393. const BUFFER_SIZE = CCURSORS * (MAX_PATH + 1) + 1;
  1394. TCHAR pszSchemeName[MAX_SCHEME_SUFFIX + MAX_SCHEME_NAME_LEN + 1];
  1395. LPTSTR pszBuffer;
  1396. BOOL fSuccess = FALSE;
  1397. int index, ret;
  1398. HKEY hk;
  1399. //
  1400. // Allocate buffer for cursor paths.
  1401. //
  1402. pszBuffer = (LPTSTR)LocalAlloc(LMEM_FIXED, BUFFER_SIZE * sizeof(TCHAR));
  1403. if (pszBuffer == NULL)
  1404. {
  1405. return (FALSE);
  1406. }
  1407. HourGlass(TRUE);
  1408. *pszBuffer = *pszSchemeName = 0;
  1409. index = (int)SendMessage(ghwndSchemeCB, CB_GETCURSEL, 0, 0L);
  1410. //
  1411. // Get current scheme name.
  1412. //
  1413. SendMessage( ghwndSchemeCB,
  1414. CB_GETLBTEXT,
  1415. (WPARAM)index,
  1416. (LPARAM)pszSchemeName );
  1417. // Get the text for the item at index, compare to the previous value to see
  1418. // if it changed. We can't simply compare the previous index because new items
  1419. // get inserted into the list so the index can change and still be the same or
  1420. // can be different when nothing has changed.
  1421. if ( 0 == lstrcmp(gszPreviousScheme, pszSchemeName) )
  1422. {
  1423. LocalFree(pszBuffer);
  1424. // nothing to do, we're loading the already selected scheme
  1425. return FALSE;
  1426. }
  1427. // We're loading a different scheme, enable the apply button.
  1428. SendMessage(GetParent(ghwndDlg), PSM_CHANGED, (WPARAM)ghwndDlg, 0L);
  1429. StringCchCopy(gszPreviousScheme, ARRAYSIZE(gszPreviousScheme), pszSchemeName);
  1430. //
  1431. // Exclude the "none" pattern.
  1432. //
  1433. if (lstrcmpi(pszSchemeName, szNone) != 0)
  1434. {
  1435. //
  1436. // If we have an os scheme, then search for the scheme in HKLM,
  1437. // otherwise look in HKCU.
  1438. //
  1439. if ((((ret = SystemOrUser(pszSchemeName)) == ID_OS_SCHEME)
  1440. ? (RegOpenKeyEx(HKEY_LOCAL_MACHINE, c_szRegPathSystemSchemes, 0, KEY_READ, &hk))
  1441. : (RegOpenKeyEx(HKEY_CURRENT_USER, c_szRegPathCursorSchemes, 0, KEY_READ, &hk)))
  1442. == ERROR_SUCCESS)
  1443. {
  1444. DWORD len = BUFFER_SIZE * sizeof(TCHAR);
  1445. if (RegQueryValueEx( hk,
  1446. pszSchemeName, 0, NULL,
  1447. (LPBYTE)pszBuffer,
  1448. &len ) == ERROR_SUCCESS)
  1449. {
  1450. fSuccess = TRUE; // can be reset to FALSE below
  1451. }
  1452. RegCloseKey(hk);
  1453. }
  1454. }
  1455. else
  1456. {
  1457. //
  1458. // "none" pattern is a valid choice.
  1459. //
  1460. ret = ID_NONE_SCHEME;
  1461. fSuccess = TRUE;
  1462. }
  1463. if (fSuccess)
  1464. {
  1465. LPTSTR pszNextFile, pszFile = pszBuffer;
  1466. BOOL fEOL = FALSE;
  1467. int i = 0;
  1468. //
  1469. // Remove an enclosing pair of double quotes from the list
  1470. // of cusor file names associated with the scheme.
  1471. //
  1472. // Why? On 3/29/00 someone changed the setup file accessor.inx
  1473. // placing double quotes around some of the cursor scheme reg values
  1474. // in HKLM. We'll fix the setup file but we should handle this
  1475. // case for all those who have already installed using that
  1476. // setup file.
  1477. //
  1478. if (TEXT('"') == *pszFile)
  1479. {
  1480. const LPTSTR pszLastChar = pszFile + lstrlen(pszFile) - 1;
  1481. if (TEXT('"') == *pszLastChar && pszLastChar > pszFile)
  1482. {
  1483. //
  1484. // Increment passed first dbl quote and truncate
  1485. // string before the last.
  1486. //
  1487. pszFile++;
  1488. *pszLastChar = TEXT('\0');
  1489. }
  1490. }
  1491. //
  1492. // Parse string of format TEXT("filename1, filename2, filename3...")
  1493. // into cursor info array.
  1494. //
  1495. do
  1496. {
  1497. while (*pszFile &&
  1498. (*pszFile == TEXT(' ') ||
  1499. *pszFile == TEXT('\t') ||
  1500. *pszFile == TEXT('\n')))
  1501. {
  1502. pszFile++;
  1503. }
  1504. pszNextFile = pszFile;
  1505. while (*pszNextFile != TEXT('\0'))
  1506. {
  1507. if (*pszNextFile == TEXT(','))
  1508. {
  1509. break;
  1510. }
  1511. pszNextFile = CharNext(pszNextFile);
  1512. }
  1513. if (*pszNextFile == TEXT('\0'))
  1514. {
  1515. fEOL = TRUE;
  1516. }
  1517. else
  1518. {
  1519. *pszNextFile = TEXT('\0');
  1520. }
  1521. if (lstrcmp(pszFile, acuri[i].szFile))
  1522. {
  1523. //
  1524. // It's different than current, update.
  1525. //
  1526. StringCchCopy(acuri[i].szFile, ARRAYSIZE(acuri[i].szFile), pszFile);
  1527. fSuccess &= SchemeUpdate(i);
  1528. }
  1529. pszFile = pszNextFile;
  1530. if (!fEOL)
  1531. {
  1532. pszFile++; // skip TEXT('\0') and move to next path
  1533. }
  1534. i++;
  1535. } while (i < CCURSORS);
  1536. }
  1537. LocalFree(pszBuffer);
  1538. UpdateCursorList();
  1539. EnableWindow(GetDlgItem(ghwndDlg, ID_REMOVESCHEME), (ret == ID_USER_SCHEME));
  1540. HourGlass(FALSE);
  1541. return (fSuccess);
  1542. }
  1543. ////////////////////////////////////////////////////////////////////////////
  1544. //
  1545. // SchemeUpdate
  1546. //
  1547. // Updates the cursor at index i in acuri.
  1548. //
  1549. ////////////////////////////////////////////////////////////////////////////
  1550. BOOL SchemeUpdate(int i)
  1551. {
  1552. BOOL fSuccess = TRUE;
  1553. if (acuri[i].hcur)
  1554. {
  1555. FreeItemCursor(acuri + i);
  1556. }
  1557. //
  1558. // If TEXT("Set Default").
  1559. //
  1560. if (*(acuri[i].szFile) == TEXT('\0'))
  1561. {
  1562. acuri[i].hcur =
  1563. (HCURSOR)LoadImage( NULL,
  1564. MAKEINTRESOURCE(gacd[i].idDefResource),
  1565. IMAGE_CURSOR,
  1566. 0,
  1567. 0,
  1568. LR_DEFAULTSIZE | LR_ENVSUBST );
  1569. acuri[i].fl = 0;
  1570. }
  1571. else
  1572. {
  1573. fSuccess = TryToLoadCursor(ghwndDlg, i, &acuri[i]);
  1574. }
  1575. acuri[i].fl |= CIF_MODIFIED;
  1576. return (fSuccess);
  1577. }
  1578. ////////////////////////////////////////////////////////////////////////////
  1579. //
  1580. // RemoveScheme
  1581. //
  1582. ////////////////////////////////////////////////////////////////////////////
  1583. BOOL RemoveScheme()
  1584. {
  1585. //
  1586. // Only user schemes can be removed, so this only needs to
  1587. // be MAX_SCHEME_NAME_LEN + 1 long.
  1588. //
  1589. TCHAR szSchemeName[MAX_SCHEME_NAME_LEN + 1];
  1590. int index;
  1591. HKEY hk;
  1592. index = (int)SendMessage(ghwndSchemeCB, CB_GETCURSEL, 0, 0L);
  1593. //
  1594. // Get current scheme name.
  1595. //
  1596. SendMessage( ghwndSchemeCB,
  1597. CB_GETLBTEXT,
  1598. (WPARAM)index,
  1599. (LPARAM)szSchemeName );
  1600. //
  1601. // Exclude the "none" pattern from removal.
  1602. //
  1603. if (lstrcmpi(szSchemeName, szNone) == 0)
  1604. {
  1605. return (FALSE);
  1606. }
  1607. //
  1608. // HACK: assume deleting noname needs no confirmation -
  1609. // this is because the scheme won't save properly anyway.
  1610. //
  1611. if (*szSchemeName)
  1612. {
  1613. TCHAR RemoveMsg[MAX_PATH];
  1614. TCHAR DialogMsg[MAX_PATH];
  1615. LoadString(g_hInst, IDS_REMOVESCHEME, RemoveMsg, MAX_PATH);
  1616. StringCchPrintf(DialogMsg, ARRAYSIZE(DialogMsg), RemoveMsg, (LPTSTR)szSchemeName);
  1617. LoadString(g_hInst, IDS_NAME, RemoveMsg, MAX_PATH);
  1618. if (MessageBox( ghwndDlg,
  1619. DialogMsg,
  1620. RemoveMsg,
  1621. MB_ICONQUESTION | MB_YESNO ) != IDYES)
  1622. {
  1623. return (TRUE);
  1624. }
  1625. }
  1626. if (RegOpenKeyEx(HKEY_CURRENT_USER, c_szRegPathCursors, 0, KEY_WRITE, &hk) == ERROR_SUCCESS)
  1627. {
  1628. HKEY hks;
  1629. if (RegOpenKeyEx(hk, c_szSchemes, 0, KEY_WRITE, &hks) == ERROR_SUCCESS)
  1630. {
  1631. RegDeleteValue(hks, szSchemeName);
  1632. RegCloseKey(hks);
  1633. }
  1634. RegCloseKey(hk);
  1635. }
  1636. //
  1637. // Delete from list box.
  1638. //
  1639. index = (int)SendMessage( ghwndSchemeCB,
  1640. CB_FINDSTRINGEXACT,
  1641. (WPARAM)-1,
  1642. (LPARAM)szSchemeName );
  1643. SendMessage(ghwndSchemeCB, CB_DELETESTRING, (WPARAM)index, 0);
  1644. SendMessage(ghwndSchemeCB, CB_SETCURSEL, 0, 0);
  1645. SendMessage(ghwndDlg, WM_NEXTDLGCTL, 1, 0L);
  1646. EnableWindow(GetDlgItem(ghwndDlg, ID_REMOVESCHEME), FALSE);
  1647. return TRUE;
  1648. }
  1649. ////////////////////////////////////////////////////////////////////////////
  1650. //
  1651. // InitSchemeComboBox
  1652. //
  1653. ////////////////////////////////////////////////////////////////////////////
  1654. BOOL InitSchemeComboBox()
  1655. {
  1656. TCHAR szSchemeName[MAX_SCHEME_NAME_LEN + 1];
  1657. TCHAR szDefaultSchemeName[MAX_SCHEME_NAME_LEN + 1];
  1658. TCHAR szLongName[MAX_SCHEME_SUFFIX + MAX_SCHEME_NAME_LEN + 1];
  1659. int index;
  1660. HKEY hk;
  1661. DWORD len;
  1662. LoadString(g_hInst, IDS_NONE, szNone, ARRAYSIZE(szNone));
  1663. LoadString(g_hInst, IDS_SUFFIX, szSystemScheme, ARRAYSIZE(szSystemScheme));
  1664. if (RegOpenKeyEx(HKEY_CURRENT_USER, c_szRegPathCursors, 0, KEY_READ, &hk) == ERROR_SUCCESS)
  1665. {
  1666. HKEY hks;
  1667. //
  1668. // Enumerate the schemes.
  1669. //
  1670. if (RegOpenKeyEx(hk, c_szSchemes, 0, KEY_READ, &hks) == ERROR_SUCCESS)
  1671. {
  1672. DWORD i;
  1673. for (i = 0; ;i++)
  1674. {
  1675. LONG ret;
  1676. //
  1677. // Reset each pass.
  1678. //
  1679. len = ARRAYSIZE(szSchemeName);
  1680. ret = RegEnumValue( hks,
  1681. i,
  1682. szSchemeName,
  1683. &len,
  1684. NULL,
  1685. NULL,
  1686. NULL,
  1687. NULL );
  1688. if (ret == ERROR_MORE_DATA)
  1689. {
  1690. continue;
  1691. }
  1692. if (ret != ERROR_SUCCESS)
  1693. {
  1694. break;
  1695. }
  1696. //
  1697. // HACK to keep "NONE" pure.
  1698. //
  1699. if (lstrcmpi(szSchemeName, szNone) != 0)
  1700. {
  1701. SendMessage( ghwndSchemeCB,
  1702. CB_ADDSTRING,
  1703. 0,
  1704. (LPARAM)szSchemeName );
  1705. }
  1706. }
  1707. //
  1708. // At this point, all of the user defined scheme names have been
  1709. // added to the combo box.
  1710. //
  1711. RegCloseKey(hks);
  1712. }
  1713. //
  1714. // Get name of current one.
  1715. //
  1716. // Reset again.
  1717. //
  1718. len = sizeof(szDefaultSchemeName);
  1719. RegQueryValue(hk, NULL, szDefaultSchemeName, &len);
  1720. //
  1721. // Try to read the value of Scheme Source. If this value doesn't
  1722. // exist, then we have a pre NT 5.0 implementation, so all schemes
  1723. // will be user schemes.
  1724. //
  1725. len = sizeof(iSchemeLocation);
  1726. if (RegQueryValueEx( hk,
  1727. szSchemeSource,
  1728. NULL,
  1729. NULL,
  1730. (unsigned char *)&iSchemeLocation,
  1731. &len ) != ERROR_SUCCESS)
  1732. {
  1733. iSchemeLocation = ID_USER_SCHEME;
  1734. }
  1735. RegCloseKey(hk);
  1736. }
  1737. //
  1738. // Now add the system defined pointer schemes.
  1739. //
  1740. if (RegOpenKeyEx(HKEY_LOCAL_MACHINE, c_szRegPathSystemSchemes, 0, KEY_READ, &hk) == ERROR_SUCCESS)
  1741. {
  1742. DWORD i;
  1743. for (i = 0; ;i++)
  1744. {
  1745. LONG ret;
  1746. //
  1747. // Reset each pass.
  1748. //
  1749. len = ARRAYSIZE(szSchemeName);
  1750. ret = RegEnumValue( hk,
  1751. i,
  1752. szSchemeName,
  1753. &len,
  1754. NULL,
  1755. NULL,
  1756. NULL,
  1757. NULL );
  1758. //
  1759. // If the Scheme name is longer than the allowed length, skip it.
  1760. //
  1761. if (ret == ERROR_MORE_DATA)
  1762. {
  1763. continue;
  1764. }
  1765. //
  1766. // If there's an error, then we're done.
  1767. //
  1768. if (ret != ERROR_SUCCESS)
  1769. {
  1770. break;
  1771. }
  1772. //
  1773. // When we add the system identifier to the string, it could be
  1774. // longer than MAX_SCHEME_NAME, however we only want to read
  1775. // max length from the registry.
  1776. //
  1777. StringCchCopy(szLongName, ARRAYSIZE(szLongName), szSchemeName);
  1778. StringCchCat(szLongName, ARRAYSIZE(szLongName), szSystemScheme);
  1779. SendMessage(ghwndSchemeCB, CB_ADDSTRING, 0, (LPARAM)szLongName);
  1780. }
  1781. RegCloseKey(hk);
  1782. }
  1783. //
  1784. // Add the "none" scheme.
  1785. //
  1786. SendMessage(ghwndSchemeCB, CB_INSERTSTRING, 0, (LPARAM)szNone);
  1787. //
  1788. // Try to find current one in the combobox.
  1789. //
  1790. StringCchCopy(szLongName, ARRAYSIZE(szLongName), szDefaultSchemeName);
  1791. if (iSchemeLocation == ID_OS_SCHEME)
  1792. {
  1793. StringCchCat(szLongName, ARRAYSIZE(szLongName), szSystemScheme);
  1794. }
  1795. index = (int)SendMessage( ghwndSchemeCB,
  1796. CB_FINDSTRINGEXACT,
  1797. 0xFFFF,
  1798. (LPARAM)szLongName );
  1799. //
  1800. // If found, select it.
  1801. //
  1802. if (index < 0) // if we are on the None scheme
  1803. {
  1804. iSchemeLocation = ID_NONE_SCHEME;
  1805. index = 0;
  1806. }
  1807. // We keep around a selection indicator so we know when selection has changed.
  1808. // Initialize that value here.
  1809. StringCchCopy(gszPreviousScheme, ARRAYSIZE(gszPreviousScheme), szLongName);
  1810. SendMessage(ghwndSchemeCB, CB_SETCURSEL, (WPARAM)index, 0);
  1811. EnableWindow( GetDlgItem(ghwndDlg, ID_REMOVESCHEME),
  1812. (iSchemeLocation == ID_USER_SCHEME) );
  1813. return (TRUE);
  1814. }
  1815. ////////////////////////////////////////////////////////////////////////////
  1816. //
  1817. // SaveSchemeDlgProc
  1818. //
  1819. ////////////////////////////////////////////////////////////////////////////
  1820. INT_PTR CALLBACK SaveSchemeDlgProc(
  1821. HWND hWnd,
  1822. UINT message,
  1823. WPARAM wParam,
  1824. LPARAM lParam)
  1825. {
  1826. TCHAR szSchemeName[MAX_SCHEME_SUFFIX + MAX_SCHEME_NAME_LEN + 1];
  1827. switch (message)
  1828. {
  1829. case ( WM_INITDIALOG ) :
  1830. {
  1831. HourGlass(TRUE);
  1832. GetWindowText(ghwndSchemeCB, szSchemeName, ARRAYSIZE(szSchemeName));
  1833. //
  1834. // CANNOT SAVE "NONE" SCHEME.
  1835. //
  1836. if (lstrcmpi(szSchemeName, szNone) == 0)
  1837. {
  1838. *szSchemeName = 0;
  1839. }
  1840. iSchemeLocation = SystemOrUser(szSchemeName);
  1841. SetDlgItemText(hWnd, ID_SCHEMEFILENAME, szSchemeName);
  1842. SendDlgItemMessage(hWnd, ID_SCHEMEFILENAME, EM_SETSEL, 0, 32767);
  1843. SendDlgItemMessage( hWnd,
  1844. ID_SCHEMEFILENAME,
  1845. EM_LIMITTEXT,
  1846. MAX_SCHEME_NAME_LEN,
  1847. 0L );
  1848. EnableWindow(GetDlgItem(hWnd, IDOK), szSchemeName[0] != TEXT('\0'));
  1849. HourGlass(FALSE);
  1850. return (TRUE);
  1851. }
  1852. case ( WM_HELP ) :
  1853. {
  1854. WinHelp( (HWND)((LPHELPINFO)lParam)->hItemHandle,
  1855. HELP_FILE,
  1856. HELP_WM_HELP,
  1857. (DWORD_PTR)(LPTSTR)aHelpIDs );
  1858. return (TRUE);
  1859. }
  1860. case ( WM_CONTEXTMENU ) :
  1861. {
  1862. WinHelp( (HWND)wParam,
  1863. HELP_FILE,
  1864. HELP_CONTEXTMENU,
  1865. (DWORD_PTR)(LPVOID)aHelpIDs );
  1866. return (TRUE);
  1867. }
  1868. case ( WM_COMMAND ) :
  1869. {
  1870. switch (LOWORD(wParam))
  1871. {
  1872. case ( ID_SCHEMEFILENAME ) :
  1873. {
  1874. if (HIWORD(wParam) == EN_CHANGE)
  1875. {
  1876. //
  1877. // CANNOT SAVE "NONE" SCHEME
  1878. // cannot save a scheme ending with szSystemScheme
  1879. //
  1880. EnableWindow(
  1881. GetDlgItem(hWnd, IDOK),
  1882. ((GetDlgItemText( hWnd,
  1883. ID_SCHEMEFILENAME,
  1884. szSchemeName,
  1885. ARRAYSIZE(szSchemeName) ) > 0) &&
  1886. (lstrcmpi(szSchemeName, szNone) != 0) &&
  1887. (SystemOrUser(szSchemeName) != ID_OS_SCHEME)) );
  1888. }
  1889. break;
  1890. }
  1891. case ( IDOK ) :
  1892. {
  1893. GetDlgItemText( hWnd,
  1894. ID_SCHEMEFILENAME,
  1895. szSchemeName,
  1896. MAX_SCHEME_NAME_LEN + 1 );
  1897. CurStripBlanks(szSchemeName, ARRAYSIZE(szSchemeName));
  1898. if (*szSchemeName == TEXT('\0'))
  1899. {
  1900. MessageBeep(0);
  1901. break;
  1902. }
  1903. StringCchCopy(gszSchemeName, ARRAYSIZE(gszSchemeName), szSchemeName);
  1904. // fall through...
  1905. }
  1906. case ( IDCANCEL ) :
  1907. {
  1908. EndDialog(hWnd, LOWORD(wParam) == IDOK);
  1909. return (TRUE);
  1910. }
  1911. }
  1912. }
  1913. }
  1914. //
  1915. // Didn't process a message.
  1916. //
  1917. return (FALSE);
  1918. }
  1919. ////////////////////////////////////////////////////////////////////////////
  1920. //
  1921. // MakeFilename
  1922. //
  1923. // Returns Filename with a default path in system directory if no path
  1924. // is already specified.
  1925. //
  1926. ////////////////////////////////////////////////////////////////////////////
  1927. LPTSTR MakeFilename(
  1928. LPTSTR sz)
  1929. {
  1930. TCHAR szTemp[MAX_PATH];
  1931. ExpandEnvironmentStrings(sz, szTemp, MAX_PATH);
  1932. if (szTemp[0] == TEXT('\\') || szTemp[1] == TEXT(':'))
  1933. {
  1934. StringCchCopy(gszFileName2, ARRAYSIZE(gszFileName2), szTemp);
  1935. return (gszFileName2);
  1936. }
  1937. else
  1938. {
  1939. GetSystemDirectory(gszFileName2, ARRAYSIZE(gszFileName2));
  1940. StringCchCat(gszFileName2, ARRAYSIZE(gszFileName2), TEXT("\\"));
  1941. StringCchCat(gszFileName2, ARRAYSIZE(gszFileName2), szTemp);
  1942. return (gszFileName2);
  1943. }
  1944. }
  1945. ////////////////////////////////////////////////////////////////////////////
  1946. //
  1947. // CurStripBlanks
  1948. //
  1949. // Strips leading and trailing blanks from a string.
  1950. // Alters the memory where the string sits.
  1951. //
  1952. ////////////////////////////////////////////////////////////////////////////
  1953. void CurStripBlanks(LPTSTR pszString, int cchString)
  1954. {
  1955. LPTSTR pszPosn;
  1956. //
  1957. // Strip leading blanks.
  1958. //
  1959. pszPosn = pszString;
  1960. while (*pszPosn == TEXT(' '))
  1961. {
  1962. pszPosn++;
  1963. }
  1964. if (pszPosn != pszString)
  1965. {
  1966. WCHAR szEdit[MAX_PATH];
  1967. StringCchCopy(szEdit, ARRAYSIZE(szEdit), pszPosn);
  1968. StringCchCopy(pszString, cchString, szEdit);
  1969. }
  1970. //
  1971. // Strip trailing blanks.
  1972. //
  1973. if ((pszPosn = pszString + lstrlen(pszString)) != pszString)
  1974. {
  1975. pszPosn = CharPrev(pszString, pszPosn);
  1976. while (*pszPosn == TEXT(' '))
  1977. {
  1978. pszPosn = CharPrev(pszString, pszPosn);
  1979. }
  1980. pszPosn = CharNext(pszPosn);
  1981. *pszPosn = TEXT('\0');
  1982. }
  1983. }
  1984. ////////////////////////////////////////////////////////////////////////////
  1985. //
  1986. // SystemOrUser
  1987. //
  1988. // Attempts to determine if the scheme name selected from the combo
  1989. // box ends with the string szSystemScheme and retuns ID_OS_SCHEME
  1990. // if it does, ID_USER_SCHEME if it doesn't.
  1991. //
  1992. ////////////////////////////////////////////////////////////////////////////
  1993. int SystemOrUser(TCHAR *pszSchemeName)
  1994. {
  1995. TCHAR *pszSN;
  1996. int lenSS, lenSN;
  1997. int i;
  1998. lenSS = lstrlen(szSystemScheme);
  1999. lenSN = lstrlen(pszSchemeName);
  2000. if (lenSN <= lenSS)
  2001. {
  2002. return (ID_USER_SCHEME);
  2003. }
  2004. pszSN = pszSchemeName + (lenSN - lenSS);
  2005. //
  2006. // If these strings are different, it's a user scheme.
  2007. //
  2008. if (lstrcmpi(pszSN, szSystemScheme))
  2009. {
  2010. return (ID_USER_SCHEME);
  2011. }
  2012. //
  2013. // For system schemes, this function also removes the
  2014. // szSystemScheme string from the end.
  2015. //
  2016. *pszSN = TEXT('\0');
  2017. return (ID_OS_SCHEME);
  2018. }