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.

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