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.

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