windows-nt/Source/XPSP1/NT/shell/cpls/main/mouseptr.c
2020-09-26 16:20:57 +08:00

2517 lines
65 KiB
C

/*++
Copyright (c) 1994-1998, Microsoft Corporation All rights reserved.
Module Name:
mouseptr.c
Abstract:
This module contains the routines for the Mouse Pointer Property Sheet
page.
Revision History:
--*/
//
// Include Files.
//
#include "main.h"
#include "rc.h"
#include "mousehlp.h"
#include <regstr.h>
//
// From shell\inc\shsemip.h
//
#define ARRAYSIZE(a) (sizeof(a)/sizeof(a[0]))
//
// Constant Declarations.
//
#define gcxAvgChar 8
#define MAX_SCHEME_NAME_LEN 64
#define MAX_SCHEME_SUFFIX 32 // length of " (system scheme)" - update if more space is needed
#define OVERWRITE_TITLE 32 // length of title for the confirm overwrite dialog
#define OVERWRITE_MSG 200 // length of the message for the overwrite dialog
#define PM_NEWCURSOR (WM_USER + 1)
#define PM_PAUSEANIMATION (WM_USER + 2)
#define PM_UNPAUSEANIMATION (WM_USER + 3)
#define ID_PREVIEWTIMER 1
#define CCH_ANISTRING 80
#define CIF_FILE 0x0001
#define CIF_MODIFIED 0x0002
#define CIF_SHARED 0x0004
#define IDT_BROWSE 1
//
// Typedef Declarations.
//
typedef struct _CURSOR_INFO
{
DWORD fl;
HCURSOR hcur;
int ccur;
int icur;
TCHAR szFile[MAX_PATH];
} CURSOR_INFO, *PCURSOR_INFO;
#pragma pack(2)
typedef struct tagNEWHEADER
{
WORD reserved;
WORD rt;
WORD cResources;
} NEWHEADER, *LPNEWHEADER;
#pragma pack()
typedef struct
{
UINT idVisName;
int idResource;
int idDefResource;
LPTSTR pszIniName;
TCHAR szVisName[MAX_PATH];
} CURSORDESC, *PCURSORDESC;
//
// Structure that contains data used within a preview window. This
// data is unique for each preview window, and is used to optimize
// the painting.
//
typedef struct
{
HDC hdcMem;
HBITMAP hbmMem;
HBITMAP hbmOld;
PCURSOR_INFO pcuri;
} PREVIEWDATA, *PPREVIEWDATA;
typedef struct _MOUSEPTRBR
{
HWND hDlg;
CURSOR_INFO curi;
} MOUSEPTRBR, *PMOUSEPTRBR;
//
// Global Variables.
//
extern HINSTANCE g_hInst; // from main.c
int gcxCursor, gcyCursor;
HWND ghwndDlg, ghwndFile, ghwndFileH, ghwndTitle, ghwndTitleH;
HWND ghwndCreator, ghwndCreatorH, ghwndCursors, ghwndPreview, ghwndSchemeCB;
HBRUSH ghbrHighlight, ghbrHighlightText, ghbrWindow, ghbrButton;
UINT guTextHeight = 0;
UINT guTextGap = 0;
COLORREF gcrHighlightText;
TCHAR gszFileName2[MAX_PATH];
UINT wBrowseHelpMessage;
LPTSTR gszFileNotFound = NULL;
LPTSTR gszBrowse = NULL;
LPTSTR gszFilter = NULL;
TCHAR gszNoMem[256] = TEXT("No Memory");
HHOOK ghhkMsgFilter; // hook handle for message filter function
static const TCHAR szRegStr_Setup[] = REGSTR_PATH_SETUP TEXT("\\Setup");
static const TCHAR szSharedDir[] = TEXT("SharedDir");
BOOL gfCursorShadow = FALSE;
//
// Make sure you add new cursors to the end of this array.
// Otherwise the cursor schemes will not work
//
CURSORDESC gacd[] =
{
{ IDS_ARROW, OCR_NORMAL, OCR_ARROW_DEFAULT, TEXT("Arrow"), TEXT("") },
{ IDS_HELPCUR, OCR_HELP, OCR_HELP_DEFAULT, TEXT("Help"), TEXT("") },
{ IDS_APPSTARTING, OCR_APPSTARTING, OCR_APPSTARTING_DEFAULT, TEXT("AppStarting"), TEXT("") },
{ IDS_WAIT, OCR_WAIT, OCR_WAIT_DEFAULT, TEXT("Wait"), TEXT("") },
{ IDS_CROSS, OCR_CROSS, OCR_CROSS_DEFAULT, TEXT("Crosshair"), TEXT("") },
{ IDS_IBEAM, OCR_IBEAM, OCR_IBEAM_DEFAULT, TEXT("IBeam"), TEXT("") },
{ IDS_NWPEN, OCR_NWPEN, OCR_NWPEN_DEFAULT, TEXT("NWPen"), TEXT("") },
{ IDS_NO, OCR_NO, OCR_NO_DEFAULT, TEXT("No"), TEXT("") },
{ IDS_SIZENS, OCR_SIZENS, OCR_SIZENS_DEFAULT, TEXT("SizeNS"), TEXT("") },
{ IDS_SIZEWE, OCR_SIZEWE, OCR_SIZEWE_DEFAULT, TEXT("SizeWE"), TEXT("") },
{ IDS_SIZENWSE, OCR_SIZENWSE, OCR_SIZENWSE_DEFAULT, TEXT("SizeNWSE"), TEXT("") },
{ IDS_SIZENESW, OCR_SIZENESW, OCR_SIZENESW_DEFAULT, TEXT("SizeNESW"), TEXT("") },
{ IDS_SIZEALL, OCR_SIZEALL, OCR_SIZEALL_DEFAULT, TEXT("SizeAll"), TEXT("") },
{ IDS_UPARROW, OCR_UP, OCR_UPARROW_DEFAULT, TEXT("UpArrow"), TEXT("") },
{ IDS_HANDCUR, OCR_HAND, OCR_HAND_DEFAULT, TEXT("Hand"), TEXT("") },
};
#define CCURSORS (sizeof(gacd) / sizeof(gacd[0]))
CURSOR_INFO acuri[CCURSORS];
//
// Registry Keys.
//
const TCHAR szCursorSubdir[] = TEXT("Cursors");
const TCHAR szCursorRegPath[] = REGSTR_PATH_CURSORS;
static const TCHAR c_szRegPathCursors[] = REGSTR_PATH_CURSORS;
static const TCHAR c_szSchemes[] = TEXT("Schemes");
static const TCHAR c_szRegPathCursorSchemes[] = REGSTR_PATH_CURSORS TEXT( "\\Schemes" );
//
// Strings used to read from the combo box must be larger than max length.
//
TCHAR gszSchemeName[MAX_SCHEME_SUFFIX + MAX_SCHEME_NAME_LEN + 1]; // used to store selected scheme name for saving
int iSchemeLocation; // used to store scheme location (HKCU vs HKLM)
static const TCHAR c_szRegPathSystemSchemes[] = REGSTR_PATH_SETUP TEXT("\\Control Panel\\Cursors\\Schemes");
TCHAR szSystemScheme[MAX_SCHEME_SUFFIX];
TCHAR szNone[MAX_SCHEME_NAME_LEN + 1];
const TCHAR szSchemeSource[] = TEXT("Scheme Source");
TCHAR gszPreviousScheme[MAX_SCHEME_SUFFIX + MAX_SCHEME_NAME_LEN + 1]; // used to tell if a different scheme is selected
#define ID_NONE_SCHEME 0
#define ID_USER_SCHEME 1
#define ID_OS_SCHEME 2
//
// Context Help Ids.
//
const static DWORD aMousePtrHelpIDs[] =
{
IDC_GROUPBOX_1, IDH_COMM_GROUPBOX,
ID_SCHEMECOMBO, IDH_MOUSE_POINT_SCHEME,
ID_SAVESCHEME, IDH_MOUSE_POINT_SAVEAS,
ID_REMOVESCHEME, IDH_MOUSE_POINT_DEL,
ID_PREVIEW, IDH_MOUSE_POINT_PREVIEW,
ID_CURSORLIST, IDH_MOUSE_POINT_LIST,
ID_DEFAULT, IDH_MOUSE_POINT_DEFAULT,
ID_BROWSE, IDH_MOUSE_POINT_BROWSE,
ID_CURSORSHADOW, IDH_MOUSE_CURSORSHADOW,
0, 0
};
const static DWORD aMousePtrBrowseHelpIDs[] =
{
IDC_GROUPBOX_1, IDH_MOUSE_POINT_PREVIEW,
ID_CURSORPREVIEW, IDH_MOUSE_POINT_PREVIEW,
0, 0
};
const static DWORD aHelpIDs[] =
{
ID_SCHEMEFILENAME, IDH_MOUSE_NEW_SCHEME_NAME,
0, 0
};
//
// Forward Declarations.
//
void LoadCursorSet(HWND hwnd);
void CreateBrushes(void);
LPTSTR GetResourceString(HINSTANCE hmod,int id);
void DrawCursorListItem(DRAWITEMSTRUCT *pdis);
BOOL GetCursorFromFile(CURSOR_INFO *pcuri);
BOOL Browse(HWND hwndOwner);
void CleanUpEverything(void);
VOID UpdateCursorList(void);
VOID NextFrame(HWND hwnd);
void HourGlass(BOOL fOn);
BOOL TryToLoadCursor(
HWND hwnd,
int i,
CURSOR_INFO *pcuri);
BOOL LoadScheme(void);
BOOL SaveScheme(void);
BOOL SaveSchemeAs(void);
void SaveCurSchemeName(void);
BOOL RemoveScheme(void);
BOOL InitSchemeComboBox(void);
BOOL SchemeUpdate(int i);
LPTSTR MakeFilename(LPTSTR sz);
INT_PTR CALLBACK SaveSchemeDlgProc(
HWND hWnd,
UINT message,
WPARAM wParam,
LPARAM lParam);
void CurStripBlanks(LPTSTR pszString);
int SystemOrUser(TCHAR *pszSchemeName);
BOOL UnExpandPath( LPTSTR pszPath );
////////////////////////////////////////////////////////////////////////////
//
// RegisterPointerStuff
//
////////////////////////////////////////////////////////////////////////////
BOOL RegisterPointerStuff(
HINSTANCE hi)
{
gcxCursor = GetSystemMetrics(SM_CXCURSOR);
gcyCursor = GetSystemMetrics(SM_CYCURSOR);
return (TRUE);
}
////////////////////////////////////////////////////////////////////////////
//
// InitCursorsShadow
//
////////////////////////////////////////////////////////////////////////////
void InitCursorShadow(HWND hwnd)
{
BOOL fPalette;
HDC hdc;
int nCommand;
hdc = GetDC(NULL);
fPalette = (GetDeviceCaps(hdc, NUMCOLORS) != -1);
ReleaseDC(NULL, hdc);
if (!fPalette) {
nCommand = SW_SHOW;
} else {
nCommand = SW_HIDE;
}
ShowWindow(GetDlgItem(hwnd, ID_CURSORSHADOW), nCommand);
if (nCommand == SW_SHOW) {
SystemParametersInfo(SPI_GETCURSORSHADOW, 0, (PVOID)&gfCursorShadow, 0);
CheckDlgButton(hwnd, ID_CURSORSHADOW, gfCursorShadow);
}
}
////////////////////////////////////////////////////////////////////////////
//
// InitCursorsDlg
//
////////////////////////////////////////////////////////////////////////////
BOOL InitCursorsDlg(
HWND hwnd)
{
int i;
ghwndDlg = hwnd;
gszPreviousScheme[0] = TEXT('\0');
//
// Register the help message from the File Open (Browse) dialog.
//
wBrowseHelpMessage = RegisterWindowMessage(HELPMSGSTRING);
//
// Load Strings.
//
if (gszFileNotFound == NULL)
{
gszFileNotFound = GetResourceString(g_hInst, IDS_CUR_BADFILE);
if (gszFileNotFound == NULL)
{
return (FALSE);
}
}
if (gszBrowse == NULL)
{
gszBrowse = GetResourceString(g_hInst, IDS_CUR_BROWSE);
if (gszBrowse == NULL)
{
return (FALSE);
}
}
#ifdef WINNT
if (gszFilter == NULL)
{
gszFilter = GetResourceString(g_hInst, IDS_ANICUR_FILTER);
if (!gszFilter)
{
return (FALSE);
}
}
#else
if (gszFilter == NULL)
{
HDC dc = GetDC(NULL);
BOOL fAni = (GetDeviceCaps(dc, CAPS1) & C1_COLORCURSOR) != 0;
ReleaseDC(NULL, dc);
gszFilter = GetResourceString( g_hInst,
fAni
? IDS_ANICUR_FILTER
: IDS_CUR_FILTER );
if (!gszFilter)
{
return (FALSE);
}
}
#endif
//
// Load description strings from the resource file.
//
for (i = 0; i < CCURSORS; i++)
{
if ((!gacd[i].idVisName) ||
(LoadString( g_hInst,
gacd[i].idVisName,
gacd[i].szVisName,
ARRAYSIZE(gacd[i].szVisName) ) <= 0))
{
//
// Show something.
//
lstrcpy(gacd[i].szVisName, gacd[i].pszIniName);
}
}
//
// As an optimization, remember the window handles of the cursor
// information fields.
//
ghwndPreview = GetDlgItem(hwnd, ID_PREVIEW);
ghwndFile = GetDlgItem(hwnd, ID_FILE);
ghwndFileH = GetDlgItem(hwnd, ID_FILEH);
ghwndTitle = GetDlgItem(hwnd, ID_TITLE);
ghwndTitleH = GetDlgItem(hwnd, ID_TITLEH);
ghwndCreator = GetDlgItem(hwnd, ID_CREATOR);
ghwndCreatorH = GetDlgItem(hwnd, ID_CREATORH);
ghwndCursors = GetDlgItem(hwnd, ID_CURSORLIST);
ghwndSchemeCB = GetDlgItem(hwnd, ID_SCHEMECOMBO);
//
// Create some brushes we'll be using.
//
CreateBrushes();
//
// Initialize the scheme combo box.
//
InitSchemeComboBox();
//
// Pre-clear the cursor info array.
//
ZeroMemory(&acuri, sizeof(acuri));
//
// Load the cursors.
//
LoadCursorSet(hwnd);
//
// Force an update of the preview window and the cursor details.
//
UpdateCursorList();
InitCursorShadow(hwnd);
return (TRUE);
}
////////////////////////////////////////////////////////////////////////////
//
// LoadCursorSet
//
////////////////////////////////////////////////////////////////////////////
void LoadCursorSet(
HWND hwnd)
{
CURSOR_INFO *pcuri;
HKEY hkCursors;
int i;
if (RegOpenKey( HKEY_CURRENT_USER,
szCursorRegPath,
&hkCursors ) != ERROR_SUCCESS)
{
hkCursors = NULL;
}
for (pcuri = &acuri[0], i = 0; i < CCURSORS; i++, pcuri++)
{
if ( hkCursors )
{
DWORD dwType;
DWORD dwCount = sizeof(pcuri->szFile);
DWORD dwErr = RegQueryValueEx( hkCursors,
gacd[i].pszIniName,
NULL,
&dwType,
(LPBYTE)pcuri->szFile,
&dwCount );
if (dwErr == ERROR_SUCCESS)
{
if (TryToLoadCursor(hwnd, i, pcuri))
{
goto EverythingWorked;
}
}
}
// This is actually the failure case. We load the default cursor.
pcuri->hcur =
(HCURSOR)LoadImage( NULL,
MAKEINTRESOURCE(gacd[i].idResource),
IMAGE_CURSOR,
0,
0,
LR_SHARED | LR_DEFAULTSIZE | LR_ENVSUBST );
pcuri->fl |= CIF_SHARED;
EverythingWorked:
SendMessage(ghwndCursors, LB_ADDSTRING, 0, (LPARAM)gacd[i].szVisName);
SendMessage(ghwndCursors, LB_SETITEMDATA, i, i);
}
if (hkCursors)
{
RegCloseKey(hkCursors);
}
SendMessage(ghwndCursors, LB_SETCURSEL, 0, 0);
}
////////////////////////////////////////////////////////////////////////////
//
// CreateBrushes
//
// Creates the brushes that are used to paint within the Cursors applet.
//
////////////////////////////////////////////////////////////////////////////
VOID CreateBrushes()
{
ghbrHighlight = GetSysColorBrush(COLOR_HIGHLIGHT);
gcrHighlightText = GetSysColor(COLOR_HIGHLIGHTTEXT);
ghbrHighlightText = GetSysColorBrush(COLOR_HIGHLIGHTTEXT);
ghbrWindow = GetSysColorBrush(COLOR_WINDOW);
ghbrButton = GetSysColorBrush(COLOR_BTNFACE);
}
////////////////////////////////////////////////////////////////////////////
//
// GetResourceString
//
// Gets a string out of the resource file.
//
////////////////////////////////////////////////////////////////////////////
LPTSTR GetResourceString(
HINSTANCE hmod,
int id)
{
TCHAR szBuffer[256];
LPTSTR psz;
int cch;
if ((cch = LoadString(hmod, id, szBuffer, ARRAYSIZE(szBuffer))) == 0)
{
return (NULL);
}
psz = LocalAlloc(LPTR, (cch + 1) * sizeof(TCHAR));
if (psz != NULL)
{
int i;
for (i = 0; i <= cch; i++)
{
psz[i] = (szBuffer[i] == TEXT('\1')) ? TEXT('\0') : szBuffer[i];
}
}
return (psz);
}
////////////////////////////////////////////////////////////////////////////
//
// FreeItemCursor
//
////////////////////////////////////////////////////////////////////////////
void FreeItemCursor(
CURSOR_INFO *pcuri)
{
if (pcuri->hcur)
{
if (!(pcuri->fl & CIF_SHARED))
{
DestroyCursor(pcuri->hcur);
}
pcuri->hcur = NULL;
}
}
////////////////////////////////////////////////////////////////////////////
//
// MousePtrDlg
//
////////////////////////////////////////////////////////////////////////////
INT_PTR CALLBACK MousePtrDlg(
HWND hwnd,
UINT msg,
WPARAM wParam,
LPARAM lParam)
{
CURSOR_INFO *pcuri;
HKEY hkCursors;
int i;
switch (msg)
{
case ( WM_INITDIALOG ) :
{
return InitCursorsDlg(hwnd);
}
case ( WM_DISPLAYCHANGE ) :
{
InitCursorShadow(hwnd);
SHPropagateMessage(hwnd, msg, wParam, lParam, TRUE);
break;
}
case ( WM_MEASUREITEM ) :
{
((MEASUREITEMSTRUCT *)lParam)->itemHeight = gcyCursor + 2;
break;
}
case ( WM_DRAWITEM ) :
{
DrawCursorListItem((DRAWITEMSTRUCT *)lParam);
break;
}
case ( WM_COMMAND ) :
{
switch (LOWORD(wParam))
{
case ( ID_SCHEMECOMBO ) :
{
switch (HIWORD(wParam))
{
case ( CBN_SELCHANGE ) :
{
LoadScheme();
break;
}
}
break;
}
case ( ID_DEFAULT ) :
{
//
// Throw away any fancy new cursor and replace it with
// the system's original.
//
i = (int)SendMessage(ghwndCursors, LB_GETCURSEL, 0, 0);
pcuri = &acuri[i];
if (!(pcuri->fl & CIF_FILE))
{
break;
}
pcuri->fl = CIF_MODIFIED;
SendMessage(GetParent(hwnd), PSM_CHANGED, (WPARAM)hwnd, 0L);
FreeItemCursor(pcuri);
pcuri->hcur =
(HCURSOR)LoadImage( NULL,
MAKEINTRESOURCE(gacd[i].idDefResource),
IMAGE_CURSOR,
0,
0,
LR_DEFAULTSIZE | LR_ENVSUBST );
*pcuri->szFile = TEXT('\0');
EnableWindow(GetDlgItem(hwnd, ID_SAVESCHEME), TRUE);
UpdateCursorList();
break;
}
case ( ID_CURSORLIST ) :
{
switch (HIWORD(wParam))
{
case ( LBN_SELCHANGE ) :
{
i = (int)SendMessage((HWND)lParam, LB_GETCURSEL, 0, 0);
pcuri = &acuri[i];
//
// Show a preview (including animation) in the
// preview window.
//
SendMessage( ghwndPreview,
STM_SETICON,
(WPARAM)pcuri->hcur,
0L );
//
// Enable the "Set Default" button if the cursor
// is from a file.
//
EnableWindow( GetDlgItem(hwnd, ID_DEFAULT),
(pcuri->fl & CIF_FILE ) ? TRUE : FALSE );
break;
}
case ( LBN_DBLCLK ) :
{
Browse(hwnd);
break;
}
}
break;
}
case ( ID_BROWSE ) :
{
Browse(hwnd);
break;
}
case ( ID_SAVESCHEME ) :
{
SaveSchemeAs();
break;
}
case ( ID_REMOVESCHEME ) :
{
RemoveScheme();
break;
}
case ( ID_CURSORSHADOW ) :
{
gfCursorShadow = IsDlgButtonChecked(hwnd, ID_CURSORSHADOW);
SendMessage(GetParent(hwnd), PSM_CHANGED, (WPARAM)hwnd, 0L);
break;
}
}
break;
}
case ( WM_NOTIFY ) :
{
switch(((NMHDR *)lParam)->code)
{
case ( PSN_APPLY ) :
{
//
// Change cursor to hour glass.
//
HourGlass(TRUE);
// Set cursor shadow
SystemParametersInfo( SPI_SETCURSORSHADOW,
0,
IntToPtr(gfCursorShadow),
SPIF_UPDATEINIFILE);
//
// Save the modified scheme, order of calls important.
//
SaveCurSchemeName();
//
// Set the system cursors.
//
if (RegCreateKey( HKEY_CURRENT_USER,
szCursorRegPath,
&hkCursors ) == ERROR_SUCCESS)
{
for (pcuri = &acuri[0], i = 0; i < CCURSORS; i++, pcuri++)
{
if (pcuri->fl & CIF_MODIFIED)
{
LPCTSTR data;
UINT count;
// Always unexpand before we save a filename
UnExpandPath(pcuri->szFile);
data = (pcuri->fl & CIF_FILE) ? pcuri->szFile : TEXT("");
count = (pcuri->fl & CIF_FILE) ? (lstrlen(pcuri->szFile) + 1) * sizeof(TCHAR) : sizeof(TCHAR);
RegSetValueEx( hkCursors,
gacd[i].pszIniName,
0L,
REG_EXPAND_SZ,
(CONST LPBYTE)data,
count );
}
}
RegCloseKey(hkCursors);
SystemParametersInfo( SPI_SETCURSORS,
0,
0,
SPIF_SENDCHANGE );
}
HourGlass(FALSE);
break;
}
default :
{
return (FALSE);
}
}
break;
}
case ( WM_SYSCOLORCHANGE ) :
{
gcrHighlightText = GetSysColor(COLOR_HIGHLIGHTTEXT);
SHPropagateMessage(hwnd, msg, wParam, lParam, TRUE);
break;
}
case ( WM_WININICHANGE ) :
{
SHPropagateMessage(hwnd, msg, wParam, lParam, TRUE);
break;
}
case ( WM_DESTROY ) :
{
//
// Clean up global allocs.
//
CleanUpEverything();
if (gszFileNotFound != NULL)
{
LocalFree(gszFileNotFound);
gszFileNotFound = NULL;
}
if (gszBrowse != NULL)
{
LocalFree(gszBrowse);
gszBrowse = NULL;
}
if (gszFilter != NULL)
{
LocalFree(gszFilter);
gszFilter = NULL;
}
break;
}
case ( WM_HELP ) :
{
WinHelp( ((LPHELPINFO)lParam)->hItemHandle,
HELP_FILE,
HELP_WM_HELP,
(DWORD_PTR)(LPTSTR)aMousePtrHelpIDs );
break;
}
case ( WM_CONTEXTMENU ) :
{
WinHelp( (HWND)wParam,
HELP_FILE,
HELP_CONTEXTMENU,
(DWORD_PTR)(LPVOID)aMousePtrHelpIDs );
break;
}
default :
{
return (FALSE);
}
}
return (TRUE);
}
////////////////////////////////////////////////////////////////////////////
//
// DrawCursorListItem
//
////////////////////////////////////////////////////////////////////////////
void DrawCursorListItem(
DRAWITEMSTRUCT *pdis)
{
CURSOR_INFO *pcuri;
COLORREF clrOldText, clrOldBk;
RECT rc;
DWORD dwLayout;
if (!guTextHeight || !guTextGap)
{
TEXTMETRIC tm;
tm.tmHeight = 0;
GetTextMetrics(pdis->hDC, &tm);
if (tm.tmHeight < 0)
{
tm.tmHeight *= -1;
}
guTextHeight = (UINT)tm.tmHeight;
guTextGap = (UINT)tm.tmAveCharWidth;
}
pcuri = &acuri[pdis->itemData];
if (pdis->itemState & ODS_SELECTED)
{
clrOldText = SetTextColor(pdis->hDC, GetSysColor(COLOR_HIGHLIGHTTEXT));
clrOldBk = SetBkColor(pdis->hDC, GetSysColor(COLOR_HIGHLIGHT));
}
else
{
clrOldText = SetTextColor(pdis->hDC, GetSysColor(COLOR_WINDOWTEXT));
clrOldBk = SetBkColor(pdis->hDC, GetSysColor(COLOR_WINDOW));
}
ExtTextOut( pdis->hDC,
pdis->rcItem.left + guTextGap, // fudge factor
(pdis->rcItem.top + pdis->rcItem.bottom - guTextHeight) / 2,
ETO_OPAQUE,
&pdis->rcItem,
gacd[pdis->itemData].szVisName,
lstrlen(gacd[pdis->itemData].szVisName),
NULL );
if (pcuri->hcur != NULL)
{
dwLayout = GetLayout(pdis->hDC);
SetLayout(pdis->hDC, dwLayout | LAYOUT_BITMAPORIENTATIONPRESERVED);
DrawIcon( pdis->hDC,
pdis->rcItem.right - (gcxCursor + guTextGap),
pdis->rcItem.top + 1, pcuri->hcur );
SetLayout(pdis->hDC, dwLayout);
}
if (pdis->itemState & ODS_FOCUS)
{
CopyRect(&rc, &pdis->rcItem);
InflateRect(&rc, -1, -1);
DrawFocusRect(pdis->hDC, &rc);
}
SetTextColor(pdis->hDC, clrOldText);
SetBkColor(pdis->hDC, clrOldBk);
}
////////////////////////////////////////////////////////////////////////////
//
// TryToLoadCursor
//
////////////////////////////////////////////////////////////////////////////
BOOL TryToLoadCursor(
HWND hwnd,
int i,
CURSOR_INFO *pcuri)
{
BOOL fRet = TRUE;
BOOL bCustom = (*pcuri->szFile != 0);
if (bCustom && !GetCursorFromFile(pcuri))
{
HWND hwndControl = GetParent(hwnd);
LPTSTR pszText;
LPTSTR pszFilename;
//
// MakeFilename returns the address of a global, so we don't
// need to free pszFilename.
//
pszFilename = MakeFilename(pcuri->szFile);
pszText = LocalAlloc( LPTR,
(lstrlen(gszFileNotFound) +
lstrlen(gacd[i].szVisName) +
lstrlen(pszFilename) +
1) * sizeof(TCHAR) );
if (pszText == NULL)
{
return (FALSE);
}
wsprintf(pszText, gszFileNotFound, pszFilename, gacd[i].szVisName);
MessageBeep(MB_ICONEXCLAMATION);
MessageBox(hwndControl, pszText, NULL, MB_ICONEXCLAMATION | MB_OK);
pcuri->fl = CIF_MODIFIED;
SendMessage(GetParent(hwnd), PSM_CHANGED, (WPARAM)hwnd, 0L);
bCustom = FALSE;
LocalFree(pszText);
}
if (!bCustom)
{
FreeItemCursor(pcuri);
pcuri->hcur =
(HCURSOR)LoadImage( NULL,
MAKEINTRESOURCE(gacd[i].idDefResource),
IMAGE_CURSOR,
0,
0,
LR_DEFAULTSIZE | LR_ENVSUBST );
*pcuri->szFile = TEXT('\0');
EnableWindow(GetDlgItem(hwnd, ID_SAVESCHEME), TRUE);
UpdateCursorList();
}
return (pcuri->hcur != NULL);
}
////////////////////////////////////////////////////////////////////////////
//
// GetCursorFromFile
//
////////////////////////////////////////////////////////////////////////////
BOOL GetCursorFromFile(
CURSOR_INFO *pcuri)
{
pcuri->fl = 0;
pcuri->hcur =
(HCURSOR)LoadImage( NULL,
MakeFilename(pcuri->szFile),
IMAGE_CURSOR,
0,
0,
LR_LOADFROMFILE | LR_DEFAULTSIZE | LR_ENVSUBST );
if (pcuri->hcur)
{
pcuri->fl |= CIF_FILE;
}
return (pcuri->hcur != NULL);
}
////////////////////////////////////////////////////////////////////////////
//
// MousePtrBrowsePreview
//
////////////////////////////////////////////////////////////////////////////
void MousePtrBrowsePreview(
HWND hDlg)
{
PMOUSEPTRBR pPtrBr;
HCURSOR hcurOld;
pPtrBr = (PMOUSEPTRBR)GetWindowLongPtr(hDlg, DWLP_USER);
hcurOld = pPtrBr->curi.hcur;
CommDlg_OpenSave_GetFilePath( GetParent(hDlg),
pPtrBr->curi.szFile,
ARRAYSIZE(pPtrBr->curi.szFile) );
if (!GetCursorFromFile(&pPtrBr->curi))
{
pPtrBr->curi.hcur = NULL;
}
SendDlgItemMessage( hDlg,
ID_CURSORPREVIEW,
STM_SETICON,
(WPARAM)pPtrBr->curi.hcur, 0L );
if (hcurOld)
{
DestroyCursor(hcurOld);
}
}
////////////////////////////////////////////////////////////////////////////
//
// MousePtrBrowseNotify
//
////////////////////////////////////////////////////////////////////////////
BOOL MousePtrBrowseNotify(
HWND hDlg,
LPOFNOTIFY pofn)
{
switch (pofn->hdr.code)
{
case ( CDN_SELCHANGE ) :
{
//
// Don't show the cursor until the user stops moving around.
//
if (SetTimer(hDlg, IDT_BROWSE, 250, NULL))
{
//
// Don't destroy the old cursor.
//
SendDlgItemMessage( hDlg,
ID_CURSORPREVIEW,
STM_SETICON,
0,
0L );
}
else
{
MousePtrBrowsePreview(hDlg);
}
break;
}
}
return (TRUE);
}
////////////////////////////////////////////////////////////////////////////
//
// MousePtrBrowseDlgProc
//
////////////////////////////////////////////////////////////////////////////
INT_PTR CALLBACK MousePtrBrowseDlgProc(
HWND hDlg,
UINT uMsg,
WPARAM wParam,
LPARAM lParam)
{
switch (uMsg)
{
case ( WM_INITDIALOG ) :
{
PMOUSEPTRBR pPtrBr = (PMOUSEPTRBR)((LPOPENFILENAME)lParam)->lCustData;
if (pPtrBr)
{
pPtrBr->hDlg = hDlg;
}
SetWindowLongPtr(hDlg, DWLP_USER, (LONG_PTR) pPtrBr);
break;
}
case ( WM_DESTROY ) :
{
KillTimer(hDlg, IDT_BROWSE);
//
// Don't destroy the old cursor.
//
SendDlgItemMessage(hDlg, ID_CURSORPREVIEW, STM_SETICON, 0, 0L);
break;
}
case ( WM_TIMER ) :
{
KillTimer(hDlg, IDT_BROWSE);
MousePtrBrowsePreview(hDlg);
break;
}
case ( WM_NOTIFY ) :
{
return (MousePtrBrowseNotify(hDlg, (LPOFNOTIFY) lParam));
}
case ( WM_HELP ) :
{
WinHelp( (HWND)((LPHELPINFO)lParam)->hItemHandle,
HELP_FILE,
HELP_WM_HELP,
(DWORD_PTR)(LPTSTR)aMousePtrBrowseHelpIDs );
break;
}
case ( WM_CONTEXTMENU ) :
{
WinHelp( (HWND)wParam,
HELP_FILE,
HELP_CONTEXTMENU,
(DWORD_PTR)(LPVOID)aMousePtrBrowseHelpIDs );
break;
}
default :
{
return (FALSE);
}
}
return (TRUE);
}
////////////////////////////////////////////////////////////////////////////
//
// Browse
//
// Browse the file system for a new cursor for the selected item.
//
////////////////////////////////////////////////////////////////////////////
BOOL Browse(HWND hwndOwner)
{
static TCHAR szCustomFilter[80] = TEXT("");
static TCHAR szStartDir[MAX_PATH] = TEXT("");
OPENFILENAME ofn;
CURSOR_INFO curi;
int i;
BOOL fRet = FALSE;
MOUSEPTRBR sPtrBr;
if (!*szStartDir)
{
HKEY key = NULL;
if (RegOpenKey(HKEY_LOCAL_MACHINE, szRegStr_Setup, &key) == ERROR_SUCCESS)
{
LONG len = sizeof(szStartDir) / sizeof(szStartDir[0]);
if (RegQueryValueEx( key,
szSharedDir,
NULL,
NULL,
(LPBYTE)szStartDir,
&len ) != ERROR_SUCCESS)
{
*szStartDir = TEXT('\0');
}
RegCloseKey(key);
}
if (!*szStartDir)
{
if (0 == GetWindowsDirectory(szStartDir, MAX_PATH))
{
goto Error;
}
}
PathAppend(szStartDir, szCursorSubdir);
}
curi.szFile[0] = TEXT('\0');
sPtrBr.curi.szFile[0] = TEXT('\0');
sPtrBr.curi.hcur = NULL;
ofn.lStructSize = sizeof(ofn);
ofn.hwndOwner = hwndOwner;
ofn.hInstance = g_hInst;
ofn.lpstrFilter = gszFilter;
ofn.lpstrCustomFilter = szCustomFilter;
ofn.nMaxCustFilter = ARRAYSIZE(szCustomFilter);
ofn.nFilterIndex = 1;
ofn.lpstrFile = curi.szFile;
ofn.nMaxFile = ARRAYSIZE(curi.szFile);
ofn.lpstrFileTitle = NULL;
ofn.nMaxFileTitle = 0;
ofn.lpstrInitialDir = szStartDir;
ofn.lpstrTitle = gszBrowse;
ofn.Flags = OFN_EXPLORER | OFN_ENABLETEMPLATE | OFN_ENABLEHOOK |
OFN_FILEMUSTEXIST | OFN_HIDEREADONLY;
ofn.lpstrDefExt = NULL;
ofn.lpfnHook = MousePtrBrowseDlgProc;
ofn.lpTemplateName = MAKEINTRESOURCE(DLG_MOUSE_POINTER_BROWSE);
ofn.lCustData = (LPARAM)(PMOUSEPTRBR)&sPtrBr;
fRet = GetOpenFileName(&ofn);
if (!fRet)
{
goto brErrExit;
}
// we got a valid value, save the current location
GetCurrentDirectory(ARRAYSIZE(szStartDir), szStartDir);
fRet = FALSE;
//
// We have probably already gotten this cursor.
//
if (lstrcmpi(curi.szFile, sPtrBr.curi.szFile) == 0)
{
if (!sPtrBr.curi.hcur)
{
goto brErrExit;
}
curi = sPtrBr.curi;
//
// Clear this so it will not get destroyed in the cleanup code.
//
sPtrBr.curi.hcur = NULL;
}
else
{
//
// The user must have typed in a name.
//
if (!GetCursorFromFile(&curi))
{
goto brErrExit;
}
}
//
// Convert mapped drive letters to UNC.
//
#ifdef UNICODE
if (curi.szFile[1] == TEXT(':'))
#else
if (!IsDBCSLeadByte(curi.szFile[0]) && (curi.szFile[1] == TEXT(':')))
#endif
{
TCHAR szDrive[3];
TCHAR szNet[MAX_PATH];
int lenNet = ARRAYSIZE(szNet);
lstrcpyn(szDrive, curi.szFile, ARRAYSIZE(szDrive));
if ((WNetGetConnection(szDrive, szNet, &lenNet) == NO_ERROR) &&
(szNet[0] == TEXT('\\')) &&
(szNet[1] == TEXT('\\')))
{
lstrcat(szNet, curi.szFile + 2);
lstrcpy(curi.szFile, szNet);
}
}
i = (int)SendMessage(ghwndCursors, LB_GETCURSEL, 0, 0);
curi.fl |= CIF_MODIFIED;
SendMessage(GetParent(ghwndDlg), PSM_CHANGED, (WPARAM)ghwndDlg, 0L);
EnableWindow(GetDlgItem(ghwndDlg, ID_SAVESCHEME), TRUE);
//
// Destroy the old cursor before we retain the new one.
//
FreeItemCursor(acuri + i);
acuri[i] = curi;
UpdateCursorList();
fRet = TRUE;
brErrExit:
if (sPtrBr.curi.hcur)
{
DestroyCursor(sPtrBr.curi.hcur);
}
Error:
return (fRet);
}
////////////////////////////////////////////////////////////////////////////
//
// CleanUpEverything
//
// Destroy all the outstanding cursors.
//
////////////////////////////////////////////////////////////////////////////
void CleanUpEverything()
{
CURSOR_INFO *pcuri;
int i;
for (pcuri = &acuri[0], i = 0; i < CCURSORS; i++, pcuri++)
{
FreeItemCursor(pcuri);
}
}
////////////////////////////////////////////////////////////////////////////
//
// UpdateCursorList
//
// Force the Cursor ListBox to repaint and the cursor information below the
// listbox to be refreshed as well.
//
////////////////////////////////////////////////////////////////////////////
VOID UpdateCursorList()
{
int i = (int)SendMessage(ghwndCursors, LB_GETCURSEL, 0, 0);
PCURSOR_INFO pcuri = ((i >= 0) ? &acuri[i] : NULL);
HCURSOR hcur = pcuri ? pcuri->hcur : NULL;
HWND hDefaultButton = GetDlgItem(ghwndDlg, ID_DEFAULT);
BOOL fEnableDefaultButton = (pcuri && (pcuri->fl & CIF_FILE));
InvalidateRect(ghwndCursors, NULL, FALSE);
SendMessage(ghwndPreview, STM_SETICON, (WPARAM)hcur, 0L);
if (!fEnableDefaultButton && (GetFocus() == hDefaultButton))
{
SendMessage(ghwndDlg, WM_NEXTDLGCTL, (WPARAM)ghwndCursors, TRUE);
}
EnableWindow(hDefaultButton, fEnableDefaultButton);
}
////////////////////////////////////////////////////////////////////////////
//
// SaveSchemeAs
//
////////////////////////////////////////////////////////////////////////////
BOOL SaveSchemeAs()
{
BOOL fSuccess = TRUE;
//
// Dialog proc returns TRUE & sets gszSchemeName to filename entered
// on OK.
//
if (DialogBox( g_hInst,
MAKEINTRESOURCE(DLG_MOUSE_POINTER_SCHEMESAVE),
ghwndDlg,
SaveSchemeDlgProc ))
{
fSuccess = SaveScheme();
if (fSuccess)
{
int index = (int)SendMessage( ghwndSchemeCB,
CB_FINDSTRINGEXACT,
(WPARAM)-1,
(LPARAM)gszSchemeName );
//
// If not found, add it.
//
if (index < 0)
{
index = (int)SendMessage( ghwndSchemeCB,
CB_ADDSTRING,
0,
(LPARAM)gszSchemeName );
}
//
// Select the name.
//
SendMessage(ghwndSchemeCB, CB_SETCURSEL, (WPARAM) index, 0);
//
// Since this is now a user saved scheme, activate the delete
// button.
//
EnableWindow(GetDlgItem(ghwndDlg, ID_REMOVESCHEME), TRUE);
}
}
return (fSuccess);
}
////////////////////////////////////////////////////////////////////////////
//
// SubstituteString
//
// Replaces the string pszRemove with the string pszReplace in the
// string pszInput and places the output in pszResult. Only looks
// at the begining of the input string.
//
////////////////////////////////////////////////////////////////////////////
BOOL SubstituteString(LPCTSTR pszInput, LPCTSTR pszRemove, LPCTSTR pszReplace, LPTSTR pszResult, UINT cchResult)
{
DWORD cchRemove = lstrlen(pszRemove);
if (CompareString(LOCALE_SYSTEM_DEFAULT, NORM_IGNORECASE,
pszRemove, cchRemove, pszInput, cchRemove) == 2)
{
if (lstrlen(pszInput) + cchRemove < cchResult)
{
lstrcpy(pszResult, pszReplace);
lstrcat(pszResult, pszInput + cchRemove);
return TRUE;
}
}
return FALSE;
}
BOOL UnExpandPath( LPTSTR pszPath )
{
static TCHAR szUserProfile[MAX_PATH];
static TCHAR szSystemRoot[MAX_PATH];
static TCHAR szProgramFiles[MAX_PATH];
static BOOL bInit = FALSE;
TCHAR szUnexpandedFilename[MAX_PATH];
if ( !bInit )
{
ExpandEnvironmentStrings( TEXT("%USERPROFILE%"), szUserProfile, ARRAYSIZE(szUserProfile) );
ExpandEnvironmentStrings( TEXT("%SYSTEMROOT%"), szSystemRoot, ARRAYSIZE(szSystemRoot) );
ExpandEnvironmentStrings( TEXT("%ProgramFiles%"), szProgramFiles, ARRAYSIZE(szProgramFiles) );
bInit = TRUE;
}
if (!SubstituteString(pszPath, szUserProfile, TEXT("%USERPROFILE%"), szUnexpandedFilename, ARRAYSIZE(szUnexpandedFilename)))
{
if (!SubstituteString(pszPath, szSystemRoot, TEXT("%SYSTEMROOT%"), szUnexpandedFilename, ARRAYSIZE(szUnexpandedFilename)))
{
if (!SubstituteString(pszPath, szProgramFiles, TEXT("%ProgramFiles%"), szUnexpandedFilename, ARRAYSIZE(szUnexpandedFilename)))
{
return FALSE;
}
}
}
lstrcpy(pszPath, szUnexpandedFilename);
return TRUE;
}
////////////////////////////////////////////////////////////////////////////
//
// SaveScheme
//
////////////////////////////////////////////////////////////////////////////
BOOL SaveScheme()
{
BOOL fSuccess = FALSE;
if (*gszSchemeName)
{
const BUFFER_SIZE = CCURSORS * (MAX_PATH + 1) + 1;
LPTSTR pszBuffer = (LPTSTR)LocalAlloc( LMEM_FIXED,
BUFFER_SIZE * sizeof(TCHAR) );
HKEY hk;
int i;
if (!pszBuffer)
{
return (FALSE);
}
pszBuffer[0] = TEXT('\0');
for (i = 0; i < CCURSORS; i++)
{
if (i)
{
lstrcat(pszBuffer, TEXT(","));
}
// Replace path with evnironment variables.
UnExpandPath(acuri[i].szFile);
lstrcat(pszBuffer, acuri[i].szFile);
}
if (RegCreateKey( HKEY_CURRENT_USER,
c_szRegPathCursors,
&hk ) == ERROR_SUCCESS)
{
HKEY hks;
if (RegCreateKey(hk, c_szSchemes, &hks) == ERROR_SUCCESS)
{
LPTSTR pszOldValue = (LPTSTR)LocalAlloc( LMEM_FIXED,
BUFFER_SIZE * sizeof(TCHAR) );
if (NULL != pszOldValue)
{
DWORD dwType;
DWORD dwSize = BUFFER_SIZE*sizeof(TCHAR);
BOOL bSave = FALSE;
int ret = RegQueryValueEx(hks, gszSchemeName, NULL, &dwType, (LPBYTE)pszOldValue, &dwSize);
//
// If the key already exists, ask to confirm the overwrite.
//
if (ret == ERROR_SUCCESS && (dwType==REG_SZ || dwType==REG_EXPAND_SZ))
{
// only need to save if value is different from old value
if (lstrcmp(pszOldValue,pszBuffer)!=0)
{
TCHAR szTitle[OVERWRITE_TITLE];
TCHAR szMsg[OVERWRITE_MSG];
LoadString(g_hInst, IDS_OVERWRITE_TITLE, szTitle, OVERWRITE_TITLE);
LoadString(g_hInst, IDS_OVERWRITE_MSG, szMsg, OVERWRITE_MSG);
if (MessageBox( ghwndDlg,
szMsg,
szTitle,
MB_ICONQUESTION | MB_YESNO ) == IDYES)
{
//
// Overwrite confirmed. Safe to save.
//
bSave = TRUE;
}
}
else
{
// no need to save since the new value is the same as the old value.
fSuccess = TRUE;
}
}
else
{
//
// The key doesn't exist, so it's safe to create it.
//
bSave = TRUE;
}
if (bSave)
{
if (RegSetValueEx( hks,
gszSchemeName,
0,
REG_EXPAND_SZ,
(LPBYTE)pszBuffer,
(lstrlen(pszBuffer) + 1) * sizeof(TCHAR) )
== ERROR_SUCCESS)
{
fSuccess = TRUE;
}
}
LocalFree( pszOldValue );
}
RegCloseKey(hks);
}
RegCloseKey(hk);
}
LocalFree(pszBuffer);
}
return (fSuccess);
}
////////////////////////////////////////////////////////////////////////////
//
// SaveCurSchemeName
//
////////////////////////////////////////////////////////////////////////////
void SaveCurSchemeName()
{
HKEY hk;
if (RegCreateKey( HKEY_CURRENT_USER,
c_szRegPathCursors,
&hk ) == ERROR_SUCCESS)
{
int index = (int)SendMessage(ghwndSchemeCB, CB_GETCURSEL, 0, 0L);
SendMessage( ghwndSchemeCB,
CB_GETLBTEXT,
(WPARAM)index,
(LPARAM)gszSchemeName );
//
// Exclude the "none" pattern.
//
if (lstrcmpi(gszSchemeName, szNone) == 0)
{
*gszSchemeName = 0;
iSchemeLocation = ID_NONE_SCHEME;
}
else
{
iSchemeLocation = SystemOrUser(gszSchemeName);
}
RegSetValue( hk,
NULL,
REG_SZ,
gszSchemeName,
(lstrlen(gszSchemeName) + 1) * sizeof(TCHAR) );
RegSetValueEx( hk,
szSchemeSource,
0,
REG_DWORD,
(unsigned char *)&iSchemeLocation,
sizeof(iSchemeLocation) );
RegCloseKey(hk);
if (iSchemeLocation == ID_USER_SCHEME)
{
SaveScheme();
}
}
}
////////////////////////////////////////////////////////////////////////////
//
// LoadScheme
//
// This is called whenever a selection is made from the schemes combo box.
//
////////////////////////////////////////////////////////////////////////////
BOOL LoadScheme()
{
const BUFFER_SIZE = CCURSORS * (MAX_PATH + 1) + 1;
TCHAR pszSchemeName[MAX_SCHEME_SUFFIX + MAX_SCHEME_NAME_LEN + 1];
LPTSTR pszBuffer;
BOOL fSuccess = FALSE;
int index, ret;
HKEY hk;
//
// Allocate buffer for cursor paths.
//
pszBuffer = (LPTSTR)LocalAlloc(LMEM_FIXED, BUFFER_SIZE * sizeof(TCHAR));
if (pszBuffer == NULL)
{
return (FALSE);
}
HourGlass(TRUE);
*pszBuffer = *pszSchemeName = 0;
index = (int)SendMessage(ghwndSchemeCB, CB_GETCURSEL, 0, 0L);
//
// Get current scheme name.
//
SendMessage( ghwndSchemeCB,
CB_GETLBTEXT,
(WPARAM)index,
(LPARAM)pszSchemeName );
// Get the text for the item at index, compare to the previous value to see
// if it changed. We can't simply compare the previous index because new items
// get inserted into the list so the index can change and still be the same or
// can be different when nothing has changed.
if ( 0 == lstrcmp(gszPreviousScheme, pszSchemeName) )
{
LocalFree(pszBuffer);
// nothing to do, we're loading the already selected scheme
return FALSE;
}
// We're loading a different scheme, enable the apply button.
SendMessage(GetParent(ghwndDlg), PSM_CHANGED, (WPARAM)ghwndDlg, 0L);
lstrcpy(gszPreviousScheme, pszSchemeName);
//
// Exclude the "none" pattern.
//
if (lstrcmpi(pszSchemeName, szNone) != 0)
{
//
// If we have an os scheme, then search for the scheme in HKLM,
// otherwise look in HKCU.
//
if ((((ret = SystemOrUser(pszSchemeName)) == ID_OS_SCHEME)
? (RegOpenKey(HKEY_LOCAL_MACHINE, c_szRegPathSystemSchemes, &hk))
: (RegOpenKey(HKEY_CURRENT_USER, c_szRegPathCursorSchemes, &hk)))
== ERROR_SUCCESS)
{
DWORD len = BUFFER_SIZE * sizeof(TCHAR);
if (RegQueryValueEx( hk,
pszSchemeName, 0, NULL,
(LPBYTE)pszBuffer,
&len ) == ERROR_SUCCESS)
{
fSuccess = TRUE; // can be reset to FALSE below
}
RegCloseKey(hk);
}
}
else
{
//
// "none" pattern is a valid choice.
//
ret = ID_NONE_SCHEME;
fSuccess = TRUE;
}
if (fSuccess)
{
LPTSTR pszNextFile, pszFile = pszBuffer;
BOOL fEOL = FALSE;
int i = 0;
//
// Remove an enclosing pair of double quotes from the list
// of cusor file names associated with the scheme.
//
// Why? On 3/29/00 someone changed the setup file accessor.inx
// placing double quotes around some of the cursor scheme reg values
// in HKLM. We'll fix the setup file but we should handle this
// case for all those who have already installed using that
// setup file.
//
if (TEXT('"') == *pszFile)
{
const LPTSTR pszLastChar = pszFile + lstrlen(pszFile) - 1;
if (TEXT('"') == *pszLastChar && pszLastChar > pszFile)
{
//
// Increment passed first dbl quote and truncate
// string before the last.
//
pszFile++;
*pszLastChar = TEXT('\0');
}
}
//
// Parse string of format TEXT("filename1, filename2, filename3...")
// into cursor info array.
//
do
{
while (*pszFile &&
(*pszFile == TEXT(' ') ||
*pszFile == TEXT('\t') ||
*pszFile == TEXT('\n')))
{
pszFile++;
}
pszNextFile = pszFile;
while (*pszNextFile != TEXT('\0'))
{
if (*pszNextFile == TEXT(','))
{
break;
}
pszNextFile = CharNext(pszNextFile);
}
if (*pszNextFile == TEXT('\0'))
{
fEOL = TRUE;
}
else
{
*pszNextFile = TEXT('\0');
}
if (lstrcmp(pszFile, acuri[i].szFile))
{
//
// It's different than current, update.
//
lstrcpy(acuri[i].szFile, pszFile);
fSuccess &= SchemeUpdate(i);
}
pszFile = pszNextFile;
if (!fEOL)
{
pszFile++; // skip TEXT('\0') and move to next path
}
i++;
} while (i < CCURSORS);
}
LocalFree(pszBuffer);
UpdateCursorList();
EnableWindow(GetDlgItem(ghwndDlg, ID_REMOVESCHEME), (ret == ID_USER_SCHEME));
HourGlass(FALSE);
return (fSuccess);
}
////////////////////////////////////////////////////////////////////////////
//
// SchemeUpdate
//
// Updates the cursor at index i in acuri.
//
////////////////////////////////////////////////////////////////////////////
BOOL SchemeUpdate(int i)
{
BOOL fSuccess = TRUE;
if (acuri[i].hcur)
{
FreeItemCursor(acuri + i);
}
//
// If TEXT("Set Default").
//
if (*(acuri[i].szFile) == TEXT('\0'))
{
acuri[i].hcur =
(HCURSOR)LoadImage( NULL,
MAKEINTRESOURCE(gacd[i].idDefResource),
IMAGE_CURSOR,
0,
0,
LR_DEFAULTSIZE | LR_ENVSUBST );
acuri[i].fl = 0;
}
else
{
fSuccess = TryToLoadCursor(ghwndDlg, i, &acuri[i]);
}
acuri[i].fl |= CIF_MODIFIED;
return (fSuccess);
}
////////////////////////////////////////////////////////////////////////////
//
// RemoveScheme
//
////////////////////////////////////////////////////////////////////////////
BOOL RemoveScheme()
{
//
// Only user schemes can be removed, so this only needs to
// be MAX_SCHEME_NAME_LEN + 1 long.
//
TCHAR szSchemeName[MAX_SCHEME_NAME_LEN + 1];
int index;
HKEY hk;
index = (int)SendMessage(ghwndSchemeCB, CB_GETCURSEL, 0, 0L);
//
// Get current scheme name.
//
SendMessage( ghwndSchemeCB,
CB_GETLBTEXT,
(WPARAM)index,
(LPARAM)szSchemeName );
//
// Exclude the "none" pattern from removal.
//
if (lstrcmpi(szSchemeName, szNone) == 0)
{
return (FALSE);
}
//
// HACK: assume deleting noname needs no confirmation -
// this is because the scheme won't save properly anyway.
//
if (*szSchemeName)
{
TCHAR RemoveMsg[MAX_PATH];
TCHAR DialogMsg[MAX_PATH];
LoadString(g_hInst, IDS_REMOVESCHEME, RemoveMsg, MAX_PATH);
wsprintf(DialogMsg, RemoveMsg, (LPTSTR)szSchemeName);
LoadString(g_hInst, IDS_NAME, RemoveMsg, MAX_PATH);
if (MessageBox( ghwndDlg,
DialogMsg,
RemoveMsg,
MB_ICONQUESTION | MB_YESNO ) != IDYES)
{
return (TRUE);
}
}
if (RegOpenKey( HKEY_CURRENT_USER,
c_szRegPathCursors,
&hk ) == ERROR_SUCCESS)
{
HKEY hks;
if (RegOpenKey(hk, c_szSchemes, &hks) == ERROR_SUCCESS)
{
RegDeleteValue(hks, szSchemeName);
RegCloseKey(hks);
}
RegCloseKey(hk);
}
//
// Delete from list box.
//
index = (int)SendMessage( ghwndSchemeCB,
CB_FINDSTRINGEXACT,
(WPARAM)-1,
(LPARAM)szSchemeName );
SendMessage(ghwndSchemeCB, CB_DELETESTRING, (WPARAM)index, 0);
SendMessage(ghwndSchemeCB, CB_SETCURSEL, 0, 0);
SendMessage(ghwndDlg, WM_NEXTDLGCTL, 1, 0L);
EnableWindow(GetDlgItem(ghwndDlg, ID_REMOVESCHEME), FALSE);
return TRUE;
}
////////////////////////////////////////////////////////////////////////////
//
// InitSchemeComboBox
//
////////////////////////////////////////////////////////////////////////////
BOOL InitSchemeComboBox()
{
TCHAR pszSchemeName[MAX_SCHEME_NAME_LEN + 1];
TCHAR pszDefaultSchemeName[MAX_SCHEME_NAME_LEN + 1];
TCHAR pszLongName[MAX_SCHEME_SUFFIX + MAX_SCHEME_NAME_LEN + 1];
int index;
HKEY hk;
DWORD len;
LoadString(g_hInst, IDS_NONE, szNone, ARRAYSIZE(szNone));
LoadString(g_hInst, IDS_SUFFIX, szSystemScheme, ARRAYSIZE(szSystemScheme));
if (RegOpenKey(HKEY_CURRENT_USER, c_szRegPathCursors, &hk) == ERROR_SUCCESS)
{
HKEY hks;
//
// Enumerate the schemes.
//
if (RegOpenKey(hk, c_szSchemes, &hks) == ERROR_SUCCESS)
{
DWORD i;
for (i = 0; ;i++)
{
LONG ret;
//
// Reset each pass.
//
len = ARRAYSIZE(pszSchemeName);
ret = RegEnumValue( hks,
i,
pszSchemeName,
&len,
NULL,
NULL,
NULL,
NULL );
if (ret == ERROR_MORE_DATA)
{
continue;
}
if (ret != ERROR_SUCCESS)
{
break;
}
//
// HACK to keep "NONE" pure.
//
if (lstrcmpi(pszSchemeName, szNone) != 0)
{
SendMessage( ghwndSchemeCB,
CB_ADDSTRING,
0,
(LPARAM)pszSchemeName );
}
}
//
// At this point, all of the user defined scheme names have been
// added to the combo box.
//
RegCloseKey(hks);
}
//
// Get name of current one.
//
// Reset again.
//
len = sizeof(pszDefaultSchemeName);
RegQueryValue(hk, NULL, pszDefaultSchemeName, &len);
//
// Try to read the value of Scheme Source. If this value doesn't
// exist, then we have a pre NT 5.0 implementation, so all schemes
// will be user schemes.
//
len = sizeof(iSchemeLocation);
if (RegQueryValueEx( hk,
szSchemeSource,
NULL,
NULL,
(unsigned char *)&iSchemeLocation,
&len ) != ERROR_SUCCESS)
{
iSchemeLocation = ID_USER_SCHEME;
}
RegCloseKey(hk);
}
//
// Now add the system defined pointer schemes.
//
if (RegOpenKey(HKEY_LOCAL_MACHINE, c_szRegPathSystemSchemes, &hk) == ERROR_SUCCESS)
{
DWORD i;
for (i = 0; ;i++)
{
LONG ret;
//
// Reset each pass.
//
len = ARRAYSIZE(pszSchemeName);
ret = RegEnumValue( hk,
i,
pszSchemeName,
&len,
NULL,
NULL,
NULL,
NULL );
//
// If the Scheme name is longer than the allowed length, skip it.
//
if (ret == ERROR_MORE_DATA)
{
continue;
}
//
// If there's an error, then we're done.
//
if (ret != ERROR_SUCCESS)
{
break;
}
//
// When we add the system identifier to the string, it could be
// longer than MAX_SCHEME_NAME, however we only want to read
// max length from the registry.
//
lstrcpy(pszLongName, pszSchemeName);
lstrcat(pszLongName, szSystemScheme);
SendMessage(ghwndSchemeCB, CB_ADDSTRING, 0, (LPARAM)pszLongName);
}
RegCloseKey(hk);
}
//
// Add the "none" scheme.
//
SendMessage(ghwndSchemeCB, CB_INSERTSTRING, 0, (LPARAM)szNone);
//
// Try to find current one in the combobox.
//
lstrcpy(pszLongName, pszDefaultSchemeName);
if (iSchemeLocation == ID_OS_SCHEME)
{
lstrcat(pszLongName, szSystemScheme);
}
index = (int)SendMessage( ghwndSchemeCB,
CB_FINDSTRINGEXACT,
0xFFFF,
(LPARAM)pszLongName );
//
// If found, select it.
//
if (index < 0) // if we are on the None scheme
{
iSchemeLocation = ID_NONE_SCHEME;
index = 0;
}
// We keep around a selection indicator so we know when selection has changed.
// Initialize that value here.
lstrcpy(gszPreviousScheme, pszLongName);
SendMessage(ghwndSchemeCB, CB_SETCURSEL, (WPARAM)index, 0);
EnableWindow( GetDlgItem(ghwndDlg, ID_REMOVESCHEME),
(iSchemeLocation == ID_USER_SCHEME) );
return (TRUE);
}
////////////////////////////////////////////////////////////////////////////
//
// SaveSchemeDlgProc
//
////////////////////////////////////////////////////////////////////////////
INT_PTR CALLBACK SaveSchemeDlgProc(
HWND hWnd,
UINT message,
WPARAM wParam,
LPARAM lParam)
{
TCHAR szSchemeName[MAX_SCHEME_SUFFIX + MAX_SCHEME_NAME_LEN + 1];
switch (message)
{
case ( WM_INITDIALOG ) :
{
HourGlass(TRUE);
GetWindowText(ghwndSchemeCB, szSchemeName, ARRAYSIZE(szSchemeName));
//
// CANNOT SAVE "NONE" SCHEME.
//
if (lstrcmpi(szSchemeName, szNone) == 0)
{
*szSchemeName = 0;
}
iSchemeLocation = SystemOrUser(szSchemeName);
SetDlgItemText(hWnd, ID_SCHEMEFILENAME, szSchemeName);
SendDlgItemMessage(hWnd, ID_SCHEMEFILENAME, EM_SETSEL, 0, 32767);
SendDlgItemMessage( hWnd,
ID_SCHEMEFILENAME,
EM_LIMITTEXT,
MAX_SCHEME_NAME_LEN,
0L );
EnableWindow(GetDlgItem(hWnd, IDOK), szSchemeName[0] != TEXT('\0'));
HourGlass(FALSE);
return (TRUE);
}
case ( WM_HELP ) :
{
WinHelp( (HWND)((LPHELPINFO)lParam)->hItemHandle,
HELP_FILE,
HELP_WM_HELP,
(DWORD_PTR)(LPTSTR)aHelpIDs );
return (TRUE);
}
case ( WM_CONTEXTMENU ) :
{
WinHelp( (HWND)wParam,
HELP_FILE,
HELP_CONTEXTMENU,
(DWORD_PTR)(LPVOID)aHelpIDs );
return (TRUE);
}
case ( WM_COMMAND ) :
{
switch (LOWORD(wParam))
{
case ( ID_SCHEMEFILENAME ) :
{
if (HIWORD(wParam) == EN_CHANGE)
{
//
// CANNOT SAVE "NONE" SCHEME
// cannot save a scheme ending with szSystemScheme
//
EnableWindow(
GetDlgItem(hWnd, IDOK),
((GetDlgItemText( hWnd,
ID_SCHEMEFILENAME,
szSchemeName,
ARRAYSIZE(szSchemeName) ) > 0) &&
(lstrcmpi(szSchemeName, szNone) != 0) &&
(SystemOrUser(szSchemeName) != ID_OS_SCHEME)) );
}
break;
}
case ( IDOK ) :
{
GetDlgItemText( hWnd,
ID_SCHEMEFILENAME,
szSchemeName,
MAX_SCHEME_NAME_LEN + 1 );
CurStripBlanks(szSchemeName);
if (*szSchemeName == TEXT('\0'))
{
MessageBeep(0);
break;
}
lstrcpy(gszSchemeName, szSchemeName);
// fall through...
}
case ( IDCANCEL ) :
{
EndDialog(hWnd, LOWORD(wParam) == IDOK);
return (TRUE);
}
}
}
}
//
// Didn't process a message.
//
return (FALSE);
}
////////////////////////////////////////////////////////////////////////////
//
// MakeFilename
//
// Returns Filename with a default path in system directory if no path
// is already specified.
//
////////////////////////////////////////////////////////////////////////////
LPTSTR MakeFilename(
LPTSTR sz)
{
TCHAR szTemp[MAX_PATH];
ExpandEnvironmentStrings(sz, szTemp, MAX_PATH);
if (szTemp[0] == TEXT('\\') || szTemp[1] == TEXT(':'))
{
lstrcpy(gszFileName2, szTemp);
return (gszFileName2);
}
else
{
GetSystemDirectory(gszFileName2, ARRAYSIZE(gszFileName2));
lstrcat(gszFileName2, TEXT("\\"));
lstrcat(gszFileName2, szTemp);
return (gszFileName2);
}
}
////////////////////////////////////////////////////////////////////////////
//
// CurStripBlanks
//
// Strips leading and trailing blanks from a string.
// Alters the memory where the string sits.
//
////////////////////////////////////////////////////////////////////////////
void CurStripBlanks(LPTSTR pszString)
{
LPTSTR pszPosn;
//
// Strip leading blanks.
//
pszPosn = pszString;
while (*pszPosn == TEXT(' '))
{
pszPosn++;
}
if (pszPosn != pszString)
{
lstrcpy(pszString, pszPosn);
}
//
// Strip trailing blanks.
//
if ((pszPosn = pszString + lstrlen(pszString)) != pszString)
{
pszPosn = CharPrev(pszString, pszPosn);
while (*pszPosn == TEXT(' '))
{
pszPosn = CharPrev(pszString, pszPosn);
}
pszPosn = CharNext(pszPosn);
*pszPosn = TEXT('\0');
}
}
////////////////////////////////////////////////////////////////////////////
//
// SystemOrUser
//
// Attempts to determine if the scheme name selected from the combo
// box ends with the string szSystemScheme and retuns ID_OS_SCHEME
// if it does, ID_USER_SCHEME if it doesn't.
//
////////////////////////////////////////////////////////////////////////////
int SystemOrUser(TCHAR *pszSchemeName)
{
TCHAR *pszSN;
int lenSS, lenSN;
int i;
lenSS = lstrlen(szSystemScheme);
lenSN = lstrlen(pszSchemeName);
if (lenSN <= lenSS)
{
return (ID_USER_SCHEME);
}
pszSN = pszSchemeName + (lenSN - lenSS);
//
// If these strings are different, it's a user scheme.
//
if (lstrcmpi(pszSN, szSystemScheme))
{
return (ID_USER_SCHEME);
}
//
// For system schemes, this function also removes the
// szSystemScheme string from the end.
//
*pszSN = TEXT('\0');
return (ID_OS_SCHEME);
}