windows-nt/Source/XPSP1/NT/shell/osshell/themes/themesw/etcdlg.c
2020-09-26 16:20:57 +08:00

2552 lines
84 KiB
C

/* ETCDLG.C
Resident Code Segment // Tweak: make non-resident?
Routines for Pointers/Sounds/Etc preview dialog
Frosting: Master Theme Selector for Windows '95
Copyright (c) 1994-1999 Microsoft Corporation. All rights reserved.
*/
// ---------------------------------------------
// Brief file history:
// Alpha:
// Beta:
// Bug fixes
// ---------
//
// ---------------------------------------------
#define OEMRESOURCE 1 // for OBM_*
#include "windows.h"
#include "frost.h"
#include "global.h"
#include "prsht.h"
#include "commdlg.h"
#include "stdlib.h"
#include "mmsystem.h"
#include "..\inc\addon.h"
#include "loadimag.h"
#include "adutil.h"
#include "schedule.h" // IsPlatformNT()
// Local Routines
BOOL EtcInit(void );
void EtcDestroy(void );
INT_PTR FAR PASCAL PtrsPageProc(HWND, UINT, WPARAM, LPARAM);
INT_PTR FAR PASCAL SndsPageProc(HWND, UINT, WPARAM, LPARAM);
INT_PTR FAR PASCAL PicsPageProc(HWND, UINT, WPARAM, LPARAM);
void CreateDataStr(LPTSTR, LPTSTR, LPTSTR);
void GetFileStr(LPTSTR, LPTSTR);
void GetDisplayStr(LPTSTR, LPTSTR);
HBITMAP PASCAL GetSoundBitmap(LPTSTR lpszFile);
HANDLE PASCAL GetRiffAll(HMMIO hmmio, LPTSTR szText, int iLen);
void PASCAL SetDlgItemFile(HWND, UINT, LPCTSTR);
// stuff from DIB.C
HPALETTE WINAPI bmfCreateDIBPalette(HANDLE);
HBITMAP WINAPI bmfBitmapFromDIB(HANDLE, HPALETTE);
HPALETTE CreateBIPalette (LPBITMAPINFOHEADER);
DWORD WINAPI bmfDIBSize(HANDLE);
WORD PaletteSize (VOID FAR *pv);
WORD NumDIBColors (VOID FAR * pv);
// globals
HBITMAP hbmpCheck, hbmpQ;
BITMAP bmCheck, bmQ;
int iItemHeight; // height of listbox items
int xTextOffset; // leave room for checkmark when drawing text
RECT rPreview; // area of preview image
HCURSOR hCurCursor = NULL;
HBITMAP hbmpCurSnd = NULL;
HANDLE hCurImage = NULL; // icon or bitmap
TCHAR szCurPreviewFile[MAX_PATHLEN+1];
#define bThemed (*szCurThemeFile)
typedef struct {
int idStr; // resource id of display string
int indexF; // index into approp FROST_* struct
} STR_TO_KEY;
// stuff from DIB.C
#define PALVERSION 0x300
#define MAXPALETTE 256 /* max. # supported palette entries */
#define WIDTHBYTES(i) (((i)+31)/32*4)
//
// These arrays match the resource string ids of the strings displayed in
// the listboxes to the index into the appropriate FROST_* array -- to find
// the theme-file key needed to retrieve the filename of the associated
// cursor/icon/bitmap.
//
//
// WARNING: keep indices current with any changes in fvCursors[] in keys.h!
//
// THIS ARRAY SHOWS THE ORDER THAT THE ITEMS APPEAR IN THE LISTBOX!
STR_TO_KEY stkCursors[] = {
{STR_CUR_ARROW, 0 },
{STR_CUR_HELP, 1 },
{STR_CUR_APPSTART, 2 },
{STR_CUR_WAIT, 3 },
{STR_CUR_CROSSHAIR, 8 },
{STR_CUR_IBEAM, 9 },
{STR_CUR_NWPEN, 4 },
{STR_CUR_NO, 5 },
{STR_CUR_SIZENS, 6 },
{STR_CUR_SIZEWE, 7 },
{STR_CUR_SIZENWSE, 10 },
{STR_CUR_SIZENESW, 11 },
{STR_CUR_SIZEALL, 12 },
{STR_CUR_UPARROW, 13 }
};
//
// WARNING: keep indices current with any changes in fsCurUser[] in keys.h!
//
// This listbox has its items sorted. Currently.
STR_TO_KEY stkSounds[] = {
{STR_SND_DEF, 2 },
{STR_SND_GPF, 3 },
{STR_SND_MAX, 4 },
{STR_SND_MENUCMD, 5 },
{STR_SND_MENUPOP, 6 },
{STR_SND_MIN, 7 },
{STR_SND_OPEN, 8 },
{STR_SND_CLOSE, 9 },
{STR_SND_MAILBEEP, 10 },
{STR_SND_RESTDOWN, 11 },
{STR_SND_RESTUP, 12 },
{STR_SND_RINGIN, 13 },
{STR_SND_RINGOUT, 14 },
{STR_SND_SYSASTER, 15 },
{STR_SND_SYSDEF, 16 },
{STR_SND_SYSEXCL, 17 },
{STR_SND_SYSEXIT, 18 },
{STR_SND_SYSHAND, 19 },
{STR_SND_SYSQUEST, 20 },
{STR_SND_SYSSTART, 21 },
{STR_SND_TOSSTRASH, 22 }
};
// WARNING: keep current with any changes in number of items in visuals dlg
#define SCRSAV_NDX 6 // zero-based
// max number of items is in the sound listbox
#define MAX_ETC_ITEMS (sizeof(stkSounds)/sizeof(STR_TO_KEY))
// this array is init'd with the listbox init to keep track of
// which files actually exist
BOOL bCursorExists[MAX_ETC_ITEMS+1];
BOOL bSoundExists[MAX_ETC_ITEMS+1];
BOOL bVisualExists[MAX_ETC_ITEMS+1];
//
// HELP CONTEXT ID to CONTROL ID pairings for context help
//
POPUP_HELP_ARRAY phaPtrsDlg[] = {
{ (DWORD)LB_PTRS , (DWORD)IDH_THEME_POINTERS_LIST},
{ (DWORD)RECT_PREVIEW , (DWORD)IDH_THEME_POINTERS_PREV},
{ (DWORD)TXT_FILENAME , (DWORD)IDH_THEME_POINTERS_FILE},
{ (DWORD)0, (DWORD)0 } // double-null terminator
};
POPUP_HELP_ARRAY phaSndsDlg[] = {
{ (DWORD)LB_SNDS , (DWORD)IDH_THEME_SOUNDS_LIST},
{ (DWORD)RECT_PREVIEW , (DWORD)IDH_THEME_SOUNDS_ICON_PREV},
{ (DWORD)PB_PLAY , (DWORD)IDH_THEME_SOUNDS_PLAYS},
{ (DWORD)TXT_FILENAME , (DWORD)IDH_THEME_SOUNDS_FILE},
{ (DWORD)0, (DWORD)0 } // double-null terminator
};
POPUP_HELP_ARRAY phaPicsDlg[] = {
{ (DWORD)LB_PICS , (DWORD)IDH_THEME_PICS_LIST},
{ (DWORD)RECT_PREVIEW , (DWORD)IDH_THEME_PICS_PREV},
{ (DWORD)TXT_FILENAME , (DWORD)IDH_THEME_PICS_FILE},
{ (DWORD)0, (DWORD)0 } // double-null terminator
};
//
// DoEtcDlgs
//
// Sets up the property sheet for Pointers, Sounds, Pictures.
//
// Returns: BOOL success of setup.
//
INT_PTR FAR DoEtcDlgs(HWND hParent)
{
PROPSHEETPAGE psp[3];
PROPSHEETHEADER psh;
INT_PTR iret;
//
// Set up each of the three pages
ZeroMemory(psp, sizeof(psp));
psp[0].dwSize = sizeof(PROPSHEETPAGE);
psp[0].dwFlags = PSP_USETITLE;
psp[0].hInstance = hInstApp;
psp[0].pszTemplate = MAKEINTRESOURCE(DLGPROP_PTRS);
psp[0].pszIcon = (LPCTSTR)NULL;
psp[0].pszTitle = MAKEINTRESOURCE(STR_TITLE_PTRS);
psp[0].pfnDlgProc = PtrsPageProc;
psp[0].lParam = (LPARAM)0;
psp[0].pfnCallback = (LPFNPSPCALLBACK)0;
psp[0].pcRefParent = (UINT FAR *)0;
psp[1].dwSize = sizeof(PROPSHEETPAGE);
psp[1].dwFlags = PSP_USETITLE;
psp[1].hInstance = hInstApp;
psp[1].pszTemplate = MAKEINTRESOURCE(DLGPROP_SNDS);
psp[1].pszIcon = (LPCTSTR)NULL;
psp[1].pszTitle = MAKEINTRESOURCE(STR_TITLE_SNDS);
psp[1].pfnDlgProc = SndsPageProc;
psp[1].lParam = (LPARAM)0;
psp[1].pfnCallback = (LPFNPSPCALLBACK)0;
psp[1].pcRefParent = (UINT FAR *)0;
psp[2].dwSize = sizeof(PROPSHEETPAGE);
psp[2].dwFlags = PSP_USETITLE;
psp[2].hInstance = hInstApp;
psp[2].pszTemplate = MAKEINTRESOURCE(DLGPROP_PICS);
psp[2].pszIcon = (LPCTSTR)NULL;
psp[2].pszTitle = MAKEINTRESOURCE(STR_TITLE_PICS);
psp[2].pfnDlgProc = PicsPageProc;
psp[2].lParam = (LPARAM)0;
psp[2].pfnCallback = (LPFNPSPCALLBACK)0;
psp[2].pcRefParent = (UINT FAR *)0;
//
// set up the property sheet info header
psh.dwSize = sizeof(PROPSHEETHEADER);
psh.dwFlags = PSH_PROPSHEETPAGE | PSH_NOAPPLYNOW;
psh.hwndParent = hParent;
psh.hInstance = hInstApp;
psh.pszIcon = NULL;
psh.pszCaption = MAKEINTRESOURCE(STR_TITLE_ETC);
psh.nPages = sizeof(psp)/sizeof(PROPSHEETPAGE);
psh.nStartPage = 0;
psh.ppsp = (LPCPROPSHEETPAGE) &psp;
//
// object, etc init
if (!EtcInit())
return (FALSE); // couldn't initalize things EXIT
//
// create the property sheet and cleanup
iret = PropertySheet( (LPCPROPSHEETHEADER) &psh);
//
// object, etc cleanup
EtcDestroy();
return (iret >= 0); // TRUE if successful
}
//
// EtcInit/Destroy
//
// Init/Destroy things used in common by all three dialogs.
//
// Destroy returns: success
//
BOOL EtcInit(void)
{
BOOL bret = TRUE;
// owner-draw listboxes' checkmark and question mark
hbmpCheck = LoadBitmap(NULL, MAKEINTRESOURCE(OBM_CHECK));
hbmpQ = LoadBitmap(hInstApp, MAKEINTRESOURCE(BMP_QUESTION));
if (hbmpCheck && hbmpQ) {
// keep specs on bitmap
GetObject(hbmpCheck, sizeof(BITMAP), (LPVOID)(LPBITMAP)&bmCheck);
GetObject(hbmpQ, sizeof(BITMAP), (LPVOID)(LPBITMAP)&bmQ);
}
else
bret = FALSE;
// cleanup
return (bret);
}
void EtcDestroy(void)
{
if (hbmpCheck) DeleteObject(hbmpCheck);
hbmpCheck = NULL;
if (hbmpQ) DeleteObject(hbmpQ);
hbmpQ = NULL;
if (hCurCursor) DestroyCursor(hCurCursor);
hCurCursor = NULL;
if (hbmpCurSnd) DeleteObject(hbmpCurSnd);
hbmpCurSnd = NULL;
if (hCurImage) DestroyCursor(hCurImage);
hCurImage = NULL;
}
//
// *PageProc
//
// Property sheet page procedures for the Etc preview sheet.
//
TCHAR szCursors[] = TEXT("Control Panel\\Cursors");
INT_PTR FAR PASCAL PtrsPageProc(hDlg, message, wParam, lParam)
HWND hDlg;
UINT message;
WPARAM wParam;
LPARAM lParam;
{
switch (message) {
// set up listbox, initial selection, etc.
case WM_INITDIALOG:
{ // var scope
int iter;
extern FROST_VALUE fvCursors[]; // for theme file keys
HWND hText, hLBox;
RECT rText;
TCHAR szDispStr[MAX_STRLEN+1];
// just in first of these dialogs, need to init page OK to disabled
EnableWindow(GetDlgItem(GetParent(hDlg), IDCANCEL), FALSE);
SendMessage(GetParent(hDlg), PSM_CANCELTOCLOSE, (WPARAM)0, (LPARAM)0);
// just in first of these dialogs, need to init dialog title
LoadString(hInstApp, STR_PREVIEWDLG, (LPTSTR)szMsg, MAX_MSGLEN);
lstrcat((LPTSTR)szMsg,
bThemed ? FileFromPath((LPTSTR)szCurThemeFile)
: szCurSettings
);
TruncateExt((LPTSTR)szMsg);
SetWindowText(GetParent(hDlg), (LPTSTR)szMsg);
//
// get metrics for drawitem size
hText = GetDlgItem(hDlg, TXT_FILENAME); // 12 dialog box units high
GetWindowRect(hText, (LPRECT)&rText);
iItemHeight = ((rText.bottom - rText.top) * 8) / 12; // dialog font height
xTextOffset = (iItemHeight * 3) / 2; // proportional spacing
Assert(iItemHeight > 0, TEXT("didn't get positive text height for preview listbox!\n"));
#if 0 // this is when we painted the cursor by ourself
// other metrics, etc.
xCursor = GetSystemMetrics(SM_CXCURSOR);
yCursor = GetSystemMetrics(SM_CYCURSOR);
//
// save away preview rect area
GetWindowRect(GetDlgItem(hDlg, RECT_PREVIEW), (LPRECT)&rPreview);
GetWindowRect(hDlg, (LPRECT)&rText);
OffsetRect((LPRECT)&rPreview, -rText.left, -rText.top);
DestroyWindow(GetDlgItem(hDlg, RECT_PREVIEW));
#endif
//
// init the listbox with combined strings
// init
hLBox = GetDlgItem(hDlg, LB_PTRS);
Assert (sizeof(stkCursors)/sizeof(STR_TO_KEY) == NUM_CURSORS,
TEXT("size mismatch stkCursors and NUM_CURSORS\n"));
// for each cursor
for (iter = 0; iter < NUM_CURSORS; iter++) {
// get display string
LoadString(hInstApp, stkCursors[iter].idStr,
(LPTSTR)szDispStr, MAX_STRLEN);
// CPLs don't check for success on LoadString in INITDIALOG, so OK!?
// get filename if any
if (bThemed) {
GetPrivateProfileString((LPTSTR)szCursors,
(LPTSTR)( fvCursors[stkCursors[iter].indexF].szValName ),
(LPTSTR)szNULL,
(LPTSTR)szMsg, MAX_MSGLEN,
(LPTSTR)szCurThemeFile);
// expand filename string as necessary
InstantiatePath((LPTSTR)szMsg, MAX_MSGLEN);
}
else {
// cur system settings
HandGet(HKEY_CURRENT_USER,
(LPTSTR)szCursors,
(LPTSTR)( fvCursors[stkCursors[iter].indexF].szValName ),
(LPTSTR)szMsg);
}
// store whether the file exists
bCursorExists[iter] = szMsg[0] &&
(CF_NOTFOUND != ConfirmFile(szMsg, FALSE)); // don't alter str
// combine strings into data string to load up in
// owner-draw hasstrings listbox!
CreateDataStr((LPTSTR)pValue, (LPTSTR)szDispStr, (LPTSTR)szMsg);
// now, finally, go ahead and assign string to listbox
SendMessage(hLBox, LB_ADDSTRING, 0, (LPARAM)(LPTSTR)pValue);
}
// setup initial focus conditions
SetFocus(hLBox);
SendMessage(hLBox, LB_SETCURSEL, 0, 0);
// need to ensure it gets initial update of cur file
PostMessage(hDlg, WM_COMMAND, MAKEWPARAM(LB_PTRS, LBN_SELCHANGE),
MAKELPARAM(0, 0) );
} // var scope
break;
case WM_MEASUREITEM:
{
LPMEASUREITEMSTRUCT lpmis;
/* Set the height of the list box items. */
lpmis = (LPMEASUREITEMSTRUCT) lParam;
// lpmis->itemHeight = iItemHeight;
lpmis->itemHeight = 0; // DavidBa says they want these big default item hts
// Assert(iItemHeight > 0, TEXT("set non-positive item height for preview listbox!\n"));
// Assert(iItemHeight <= 0, TEXT("OK, set a positive item height for preview listbox!\n"));
}
break;
case WM_DRAWITEM:
{ // var scope
TEXTMETRIC tm;
LPDRAWITEMSTRUCT lpdis;
int yTextOffset;
LPTSTR lpszFile;
HDC hdcMem;
HBITMAP hbmpOld;
lpdis = (LPDRAWITEMSTRUCT) lParam;
/* If there are no list box items, skip this message. */
if (lpdis->itemID == -1) {
break;
} // jdk: well, what about focus rect in empty lbox?
//
// Inits
// get the filename assoc with this item, if any
SendMessage(lpdis->hwndItem, LB_GETTEXT, lpdis->itemID,
(LPARAM)(LPTSTR)szMsg);
GetDisplayStr((LPTSTR)szMsg, (LPTSTR)szMsg); // Ok src and dst same
// you now have "displaystr\0filename" in szMsg[]
lpszFile = (LPTSTR)(szMsg + lstrlen((LPTSTR)szMsg) + 1);
//
// draw right background color
if (lpdis->itemState & ODS_SELECTED) {
// if item is selected, draw highlight background here
FillRect(lpdis->hDC, (LPRECT)&(lpdis->rcItem),
GetSysColorBrush(COLOR_HIGHLIGHT));
// set text color to highlight text
SetBkColor(lpdis->hDC, GetSysColor(COLOR_HIGHLIGHT));
SetTextColor(lpdis->hDC, GetSysColor(COLOR_HIGHLIGHTTEXT));
}
else { // not selected
// need to do normal background fill to undo prev selection
FillRect(lpdis->hDC, (LPRECT)&(lpdis->rcItem),
GetSysColorBrush(COLOR_WINDOW));
// set text color to foreground
SetBkColor(lpdis->hDC, GetSysColor(COLOR_WINDOW));
SetTextColor(lpdis->hDC, GetSysColor(COLOR_WINDOWTEXT));
}
// if there is a file associated with this item
if (*lpszFile) {
HBITMAP hbmpLeading;
BITMAP bmLeading;
//
// find the right leading bitmap: checkmark or question mark
if (bCursorExists[lpdis->itemID]) {
hbmpLeading = hbmpCheck;
bmLeading = bmCheck;
}
else {
hbmpLeading = hbmpQ;
bmLeading = bmQ;
}
//
// paint in the leading bitmap!
hdcMem = CreateCompatibleDC(lpdis->hDC);
if (hdcMem)
{
hbmpOld = SelectObject(hdcMem, hbmpLeading);
// if item height is less than bitmap height
if (lpdis->rcItem.bottom - lpdis->rcItem.top < bmLeading.bmHeight)
{
// stretch down bitmap size to fit
StretchBlt(lpdis->hDC,
lpdis->rcItem.left, lpdis->rcItem.top,
lpdis->rcItem.bottom - lpdis->rcItem.top, // width = height
lpdis->rcItem.bottom - lpdis->rcItem.top,
hdcMem, 0, 0, bmLeading.bmWidth, bmLeading.bmHeight, SRCCOPY);
}
else // item height taller than checkmark bitmap
{
// just center vertically
BitBlt(lpdis->hDC,
lpdis->rcItem.left,
lpdis->rcItem.top +
(lpdis->rcItem.bottom - lpdis->rcItem.top - bmLeading.bmHeight)/2,
bmLeading.bmWidth, bmLeading.bmHeight,
hdcMem, 0, 0, SRCCOPY);
}
SelectObject(hdcMem, hbmpOld);
DeleteDC(hdcMem);
}
// who cares
// Assert(lpdis->rcItem.bottom - lpdis->rcItem.top == iItemHeight,
// TEXT("MEASUREITEM and DRAWITEM have different heights!\n"));
}
//
// now draw the display string for this item
// figure y offset to vert center text in draw item
GetTextMetrics(lpdis->hDC, &tm);
yTextOffset = (lpdis->rcItem.bottom - lpdis->rcItem.top - tm.tmHeight) / 2;
Assert(yTextOffset >= 0, TEXT("negative text vert offset in DRAWITEM\n"));
if (yTextOffset < 0) yTextOffset = 0;
// do the out
SetBkMode(lpdis->hDC, TRANSPARENT);
TextOut(lpdis->hDC,
lpdis->rcItem.left + xTextOffset,
lpdis->rcItem.top + yTextOffset,
(LPTSTR)szMsg, lstrlen((LPTSTR)szMsg));
//
// if item is selected, draw a focus rect
if (lpdis->itemState & ODS_FOCUS) {
DrawFocusRect(lpdis->hDC, (LPRECT)&(lpdis->rcItem));
}
} // var scope
break;
case WM_COMMAND:
switch ((int)LOWORD(wParam)) {
case LB_PTRS:
// if new selection in listbox
if (HIWORD(wParam) == LBN_SELCHANGE) {
int iSeln, ilen;
// get new selection if any
iSeln = (int)SendDlgItemMessage(hDlg, LB_PTRS, LB_GETCURSEL, 0, 0);
if (LB_ERR == iSeln)
break; // no selection EXIT
// get selection text
SendDlgItemMessage(hDlg, LB_PTRS, LB_GETTEXT,
(WPARAM)iSeln, (LPARAM)(LPTSTR)szMsg);
// update global current filename string
GetFileStr(szCurPreviewFile, szMsg);
// reset dialog static text of filename string
SetDlgItemFile(hDlg, TXT_FILENAME, szCurPreviewFile);
// and scroll end into view
ilen = lstrlen((LPTSTR)szCurPreviewFile);
SendDlgItemMessage(hDlg, TXT_FILENAME, EM_SETSEL,
(WPARAM)0, MAKELPARAM(-1, ilen));
// update cursor
if (hCurCursor) DestroyCursor(hCurCursor);
hCurCursor = NULL;
if (*szCurPreviewFile)
{
hCurCursor = LoadImage(NULL, szCurPreviewFile, IMAGE_CURSOR,
0, 0, LR_LOADFROMFILE | LR_DEFAULTSIZE);
}
// set cursor to static, even if null: null clears prev
SendDlgItemMessage(hDlg, RECT_PREVIEW, STM_SETICON,
(WPARAM)hCurCursor, (LPARAM)0);
#if 0 // this is when we painted the cursor by ourself
// force repaint of preview area
InvalidateRect(hDlg, (LPRECT)&rPreview, TRUE);
#endif
}
break;
// case PB_TEST:
// break;
}
break;
#if 0 // this is when we painted the cursor by ourself
case WM_PAINT:
BeginPaint(hDlg, &ps);
//
// preview area
DrawEdge(ps.hdc, (LPRECT)&rPreview, EDGE_SUNKEN, BF_RECT); // always edge
// if there's a file to preview
if (*szCurPreviewFile) {
// add the cursor
if (hCurCursor)
DrawIcon(ps.hdc,
rPreview.left + (rPreview.right-rPreview.left-xCursor)/2,
rPreview.top + (rPreview.bottom-rPreview.top-yCursor)/2,
hCurCursor);
}
EndPaint(hDlg, &ps);
break;
#endif
case WM_NOTIFY:
switch ( ((NMHDR FAR *)lParam)->code) {
// OK or Apply button pressed
case PSN_APPLY:
// apply any changes made on this page
SetWindowLongPtr(hDlg, DWLP_MSGRESULT, PSNRET_NOERROR); // accept changes
break;
// cancel button pressed
case PSN_RESET:
// don't accept any of the changes made on this page
break;
case PSN_SETACTIVE:
break;
case PSN_KILLACTIVE:
// need to say that it's OK by us to lose the activation
SetWindowLongPtr(hDlg, DWLP_MSGRESULT, FALSE); // OK to kill focus now
break;
}
break;
case WM_HELP:
{
LPHELPINFO lphi;
lphi = (LPHELPINFO)lParam;
if (lphi->iContextType == HELPINFO_WINDOW) {
WinHelp(lphi->hItemHandle, (LPTSTR)szHelpFile, HELP_WM_HELP,
(DWORD_PTR)((POPUP_HELP_ARRAY FAR *)phaPtrsDlg));
}
}
break;
case WM_CONTEXTMENU:
WinHelp((HWND)wParam, (LPTSTR)szHelpFile, HELP_CONTEXTMENU,
(DWORD_PTR)((POPUP_HELP_ARRAY FAR *)phaPtrsDlg));
break;
default:
return(FALSE); // didn't process message
break;
}
return TRUE; // processed message
}
INT_PTR FAR PASCAL SndsPageProc(hDlg, message, wParam, lParam)
HWND hDlg;
UINT message;
WPARAM wParam;
LPARAM lParam;
{
static BOOL gfWaveExists = FALSE;
static HBITMAP hbmpPlay = NULL;
BOOL bDoubleClick = FALSE;
switch (message) {
// set up listbox, initial selection, etc.
case WM_INITDIALOG:
{ // var scope
int iter;
int iRet;
extern FROST_SUBKEY fsCurUser[]; // for theme file keys
HWND hText, hLBox;
RECT rText;
TCHAR szDispStr[MAX_STRLEN+1];
extern FROST_SUBKEY fsCurUser[];
WAVEOUTCAPS woCaps;
// Taken right from the Sounds cpl.
gfWaveExists = waveOutGetNumDevs() > 0 &&
(waveOutGetDevCaps(0,&woCaps,sizeof(woCaps)) == 0) &&
woCaps.dwFormats != 0L;
if ((hbmpPlay = LoadBitmap(hInstApp, MAKEINTRESOURCE(PLAY_BITMAP))) !=
NULL)
SendDlgItemMessage(hDlg, PB_PLAY, BM_SETIMAGE, IMAGE_BITMAP,
(LPARAM) hbmpPlay);
//
// get metrics for drawitem size
hText = GetDlgItem(hDlg, TXT_FILENAME); // 12 dialog box units high
GetWindowRect(hText, (LPRECT)&rText);
iItemHeight = ((rText.bottom - rText.top) * 8) / 12; // dialog font height
xTextOffset = (iItemHeight * 3) / 2; // proportional spacing
Assert(iItemHeight > 0, TEXT("didn't get positive text height for preview listbox!\n"));
//
// init the listbox with combined strings
// init
hLBox = GetDlgItem(hDlg, LB_SNDS);
Assert (sizeof(stkSounds)/sizeof(STR_TO_KEY) == NUM_SOUNDS,
TEXT("size mismatch stkSounds and NUM_SOUNDS\n"));
// for each sound
for (iter = 0; iter < NUM_SOUNDS; iter++) {
// get display string
LoadString(hInstApp, stkSounds[iter].idStr,
(LPTSTR)szDispStr, MAX_STRLEN);
// CPLs don't check for success on LoadString in INITDIALOG, so OK!?
// get filename if any
if (bThemed) {
GetPrivateProfileString((LPTSTR)(fsCurUser[stkSounds[iter].indexF].szSubKey),
(LPTSTR)FROST_DEFSTR,
(LPTSTR)szNULL,
(LPTSTR)szMsg, MAX_MSGLEN,
(LPTSTR)szCurThemeFile);
// expand filename string as necessary
InstantiatePath((LPTSTR)szMsg, MAX_MSGLEN);
}
else {
// cur system settings
HandGet(HKEY_CURRENT_USER,
(LPTSTR)(fsCurUser[stkSounds[iter].indexF].szSubKey),
(LPTSTR)szNULL,
(LPTSTR)szMsg);
}
// combine strings into data string to load up in
// owner-draw hasstrings listbox!
CreateDataStr((LPTSTR)pValue, (LPTSTR)szDispStr, (LPTSTR)szMsg);
// now, finally, go ahead and assign string to listbox
SendMessage(hLBox, LB_ADDSTRING, 0, (LPARAM)(LPTSTR)pValue);
}
//
// check them all for file existence. have to do here, LBOX IS SORTED!
//
for (iter = 0; iter < MAX_ETC_ITEMS; iter++) {
// get this item's listbox string
iRet = (int) SendMessage(hLBox, LB_GETTEXT, iter, (LPARAM)(LPTSTR)szMsg);
if (iRet == LB_ERR)
break; // past end of listbox items CONTINUE
// get the filename assoc with this item, if any
GetFileStr((LPTSTR)pValue, (LPTSTR)szMsg);
// store whether the file exists
bSoundExists[iter] = *pValue &&
(CF_NOTFOUND != ConfirmFile((LPTSTR)pValue, FALSE));
}
// save away preview rect area
GetWindowRect(GetDlgItem(hDlg, RECT_PREVIEW), (LPRECT)&rPreview);
GetWindowRect(hDlg, (LPRECT)&rText);
OffsetRect((LPRECT)&rPreview, -rText.left, -rText.top);
// setup initial focus conditions
SetFocus(hLBox);
SendMessage(hLBox, LB_SETCURSEL, 0, 0);
// need to ensure it gets initial update of cur file
PostMessage(hDlg, WM_COMMAND, MAKEWPARAM(LB_SNDS, LBN_SELCHANGE),
MAKELPARAM(0, 0) );
} // var scope
break;
case WM_DESTROY:
{
if (hbmpPlay) {
DeleteObject(hbmpPlay);
hbmpPlay = NULL;
}
}
break;
case WM_MEASUREITEM:
{
LPMEASUREITEMSTRUCT lpmis;
/* Set the height of the list box items. */
lpmis = (LPMEASUREITEMSTRUCT) lParam;
// lpmis->itemHeight = iItemHeight;
lpmis->itemHeight = 0; // DavidBa says they want these big default item hts
// Assert(iItemHeight > 0, TEXT("set non-positive item height for preview listbox!\n"));
// Assert(iItemHeight <= 0, TEXT("OK, set a positive item height for preview listbox!\n"));
}
break;
case WM_DRAWITEM:
{ // var scope
TEXTMETRIC tm;
LPDRAWITEMSTRUCT lpdis;
int yTextOffset;
LPTSTR lpszFile;
HDC hdcMem;
HBITMAP hbmpOld;
lpdis = (LPDRAWITEMSTRUCT) lParam;
/* If there are no list box items, skip this message. */
if (lpdis->itemID == -1) {
break;
} // jdk: well, what about focus rect in empty lbox?
//
// Inits
// get the filename assoc with this item, if any
SendMessage(lpdis->hwndItem, LB_GETTEXT, lpdis->itemID,
(LPARAM)(LPTSTR)szMsg);
GetDisplayStr((LPTSTR)szMsg, (LPTSTR)szMsg); // Ok src and dst same
// you now have "displaystr\0filename" in szMsg[]
lpszFile = (LPTSTR)(szMsg + lstrlen((LPTSTR)szMsg) + 1);
//
// draw right background color
if (lpdis->itemState & ODS_SELECTED) {
// if item is selected, draw highlight background here
FillRect(lpdis->hDC, (LPRECT)&(lpdis->rcItem),
GetSysColorBrush(COLOR_HIGHLIGHT));
// set text color to highlight text
SetBkColor(lpdis->hDC, GetSysColor(COLOR_HIGHLIGHT));
SetTextColor(lpdis->hDC, GetSysColor(COLOR_HIGHLIGHTTEXT));
}
else { // not selected
// need to do normal background fill to undo prev selection
FillRect(lpdis->hDC, (LPRECT)&(lpdis->rcItem),
GetSysColorBrush(COLOR_WINDOW));
// set text color to foreground
SetBkColor(lpdis->hDC, GetSysColor(COLOR_WINDOW));
SetTextColor(lpdis->hDC, GetSysColor(COLOR_WINDOWTEXT));
}
// if there is a file associated with this item
if (*lpszFile) {
HBITMAP hbmpLeading;
BITMAP bmLeading;
//
// find the right leading bitmap: checkmark or question mark
if (bSoundExists[lpdis->itemID]) {
hbmpLeading = hbmpCheck;
bmLeading = bmCheck;
}
else {
hbmpLeading = hbmpQ;
bmLeading = bmQ;
}
//
// paint in the leading bitmap!
hdcMem = CreateCompatibleDC(lpdis->hDC);
if (hdcMem)
{
hbmpOld = SelectObject(hdcMem, hbmpLeading);
// if item height is less than bitmap height
if (lpdis->rcItem.bottom - lpdis->rcItem.top < bmLeading.bmHeight)
{
// stretch down bitmap size to fit
StretchBlt(lpdis->hDC,
lpdis->rcItem.left, lpdis->rcItem.top,
lpdis->rcItem.bottom - lpdis->rcItem.top, // width = height
lpdis->rcItem.bottom - lpdis->rcItem.top,
hdcMem, 0, 0, bmLeading.bmWidth, bmLeading.bmHeight, SRCCOPY);
}
else // item height taller than checkmark bitmap
{
// just center vertically
BitBlt(lpdis->hDC,
lpdis->rcItem.left,
lpdis->rcItem.top +
(lpdis->rcItem.bottom - lpdis->rcItem.top - bmLeading.bmHeight)/2,
bmLeading.bmWidth, bmLeading.bmHeight,
hdcMem, 0, 0, SRCCOPY);
}
SelectObject(hdcMem, hbmpOld);
DeleteDC(hdcMem);
}
// who cares
// Assert(lpdis->rcItem.bottom - lpdis->rcItem.top == iItemHeight,
// TEXT("MEASUREITEM and DRAWITEM have different heights!\n"));
}
//
// now draw the display string for this item
// figure y offset to vert center text in draw item
GetTextMetrics(lpdis->hDC, &tm);
yTextOffset = (lpdis->rcItem.bottom - lpdis->rcItem.top - tm.tmHeight) / 2;
Assert(yTextOffset >= 0, TEXT("negative text vert offset in DRAWITEM\n"));
if (yTextOffset < 0) yTextOffset = 0;
// do the out
SetBkMode(lpdis->hDC, TRANSPARENT);
TextOut(lpdis->hDC,
lpdis->rcItem.left + xTextOffset,
lpdis->rcItem.top + yTextOffset,
(LPTSTR)szMsg, lstrlen((LPTSTR)szMsg));
//
// if item is selected, draw a focus rect
if (lpdis->itemState & ODS_FOCUS) {
DrawFocusRect(lpdis->hDC, (LPRECT)&(lpdis->rcItem));
}
} // var scope
break;
case WM_COMMAND:
switch ((int)LOWORD(wParam)) {
case LB_SNDS:
// if new selection in listbox
if (HIWORD(wParam) == LBN_SELCHANGE) {
int iSeln, ilen;
// get new selection if any
iSeln = (int)SendDlgItemMessage(hDlg, LB_SNDS, LB_GETCURSEL, 0, 0);
if (LB_ERR == iSeln)
break; // no selection EXIT
// get selection text
SendDlgItemMessage(hDlg, LB_SNDS, LB_GETTEXT,
(WPARAM)iSeln, (LPARAM)(LPTSTR)szMsg);
// update global current filename string
GetFileStr(szCurPreviewFile, szMsg);
// reset dialog static text of filename string
SetDlgItemFile(hDlg, TXT_FILENAME, szCurPreviewFile);
// and scroll end into view
ilen = lstrlen((LPTSTR)szCurPreviewFile);
SendDlgItemMessage(hDlg, TXT_FILENAME, EM_SETSEL,
(WPARAM)0, MAKELPARAM(-1, ilen));
// update snd file icon
if (hbmpCurSnd) DeleteObject(hbmpCurSnd);
hbmpCurSnd = NULL;
if (*szCurPreviewFile)
hbmpCurSnd = GetSoundBitmap((LPTSTR)szCurPreviewFile);
// set snd file bmp to static
if (hbmpCurSnd) {
SendDlgItemMessage(hDlg, RECT_PREVIEW, STM_SETIMAGE,
(WPARAM)IMAGE_BITMAP, (LPARAM)hbmpCurSnd);
}
else {
// else need to clear it to empty
SendDlgItemMessage(hDlg, RECT_PREVIEW, STM_SETIMAGE,
(WPARAM)NULL, (LPARAM)NULL);
InvalidateRect(hDlg, (LPRECT)&rPreview, TRUE);
#ifdef SHOULDAWORKED
InvalidateRect(GetDlgItem(hDlg, RECT_PREVIEW), (LPRECT)NULL, TRUE);
UpdateWindow(GetDlgItem(hDlg, RECT_PREVIEW));
#endif
}
// update play button
EnableWindow(GetDlgItem(hDlg, PB_PLAY), *szCurPreviewFile &&
bSoundExists[iSeln] && gfWaveExists);
}
// if just a selection, we're done here
if (HIWORD(wParam) != LBN_DBLCLK)
break;
// else double-click means fall through and play
bDoubleClick = TRUE;
case PB_PLAY:
if (((HIWORD(wParam) == BN_CLICKED) || bDoubleClick) && gfWaveExists) {
int iSeln;
// check that sound file exists
iSeln = (int)SendDlgItemMessage(hDlg, LB_SNDS, LB_GETCURSEL, 0, 0);
if (!bSoundExists[iSeln])
break;
if (*szCurPreviewFile) {
// disable and wait
EnableWindow((HWND)lParam, FALSE);
WaitCursor();
PlaySound((LPTSTR)szCurPreviewFile, NULL, SND_SYNC | SND_FILENAME);
// reenable and normal
EnableWindow((HWND)lParam, TRUE);
NormalCursor();
SetFocus((HWND)lParam);
}
}
break;
}
break;
case WM_NOTIFY:
switch ( ((NMHDR FAR *)lParam)->code) {
// OK or Apply button pressed
case PSN_APPLY:
// apply any changes made on this page
SetWindowLongPtr(hDlg, DWLP_MSGRESULT, PSNRET_NOERROR); // accept changes
break;
// cancel button pressed
case PSN_RESET:
// don't accept any of the changes made on this page
break;
case PSN_SETACTIVE:
break;
case PSN_KILLACTIVE:
// need to say that it's OK by us to lose the activation
SetWindowLongPtr(hDlg, DWLP_MSGRESULT, FALSE); // OK to kill focus now
break;
}
break;
case WM_HELP:
{
LPHELPINFO lphi;
lphi = (LPHELPINFO)lParam;
if (lphi->iContextType == HELPINFO_WINDOW) {
WinHelp(lphi->hItemHandle, (LPTSTR)szHelpFile, HELP_WM_HELP,
(DWORD_PTR)((POPUP_HELP_ARRAY FAR *)phaSndsDlg));
}
}
break;
case WM_CONTEXTMENU:
WinHelp((HWND)wParam, (LPTSTR)szHelpFile, HELP_CONTEXTMENU,
(DWORD_PTR)((POPUP_HELP_ARRAY FAR *)phaSndsDlg));
break;
default:
return(FALSE); // didn't process message
break;
}
return TRUE; // processed message
}
HBITMAP PASCAL GetSoundBitmap(LPTSTR lpszFile)
{
HANDLE hDib = NULL;
HMMIO hmmio = NULL;
TCHAR szValue[MAX_MSGLEN+1];
// HPALETTE hPal;
HBITMAP hbmpRet = NULL;
if (!lpszFile || !*lpszFile)
return ((HBITMAP)NULL);
/* Open the file */
hmmio = mmioOpen(lpszFile, NULL, MMIO_ALLOCBUF | MMIO_READ);
// get the DIB
if (hmmio) {
szValue[0] = TEXT('\0');
hDib = GetRiffAll(hmmio, szValue, sizeof(szValue));
mmioClose(hmmio, 0);
}
if (hDib) {
HPALETTE hPal;
hPal = bmfCreateDIBPalette(hDib);
if (hPal)
{
hbmpRet = bmfBitmapFromDIB(hDib, hPal); // hPal can be null
DeleteObject(hPal);
}
GlobalFree(hDib);
}
return(hbmpRet);
}
// guessing that this is the right addition
#define FOURCC_DISP mmioFOURCC('D', 'I', 'S', 'P')
#define FOURCC_INFO mmioFOURCC('I', 'N', 'F', 'O')
#define FOURCC_INAM mmioFOURCC('I', 'N', 'A', 'M')
HANDLE PASCAL GetRiffAll(HMMIO hmmio, LPTSTR szText, int iLen)
{
MMCKINFO ck;
MMCKINFO ckINFO;
MMCKINFO ckRIFF;
HANDLE h = NULL;
LONG lSize;
DWORD dw;
mmioSeek(hmmio, 0, SEEK_SET);
/* descend the input file into the RIFF chunk */
if (mmioDescend(hmmio, &ckRIFF, NULL, 0) != 0)
goto error;
if (ckRIFF.ckid != FOURCC_RIFF)
goto error;
while (!mmioDescend(hmmio, &ck, &ckRIFF, 0))
{
if (ck.ckid == FOURCC_DISP)
{
/* Read dword into dw, break if read unsuccessful */
if (mmioRead(hmmio, (LPVOID)&dw, sizeof(dw)) != sizeof(dw))
goto error;
/* Find out how much memory to allocate */
lSize = ck.cksize - sizeof(dw);
if ((int)dw == CF_DIB && h == NULL)
{
/* get a handle to memory to hold the description and
lock it down */
if ((h = GlobalAlloc(GHND, lSize+4)) == NULL)
goto error;
if (mmioRead(hmmio, GlobalLock(h), lSize) != lSize)
goto error;
}
else if ((int)dw == CF_TEXT && szText[0] == 0)
{
if (lSize > iLen-1)
lSize = iLen-1;
szText[lSize] = 0;
if (mmioRead(hmmio, (LPVOID)szText, lSize) != lSize)
goto error;
}
}
else if (ck.ckid == FOURCC_LIST &&
ck.fccType == FOURCC_INFO &&
szText[0] == 0)
{
while (!mmioDescend(hmmio, &ckINFO, &ck, 0))
{
switch (ckINFO.ckid)
{
case FOURCC_INAM:
// case FOURCC_ISBJ:
lSize = ck.cksize;
if (lSize > iLen-1)
lSize = iLen-1;
szText[lSize] = 0;
if (mmioRead(hmmio, (LPVOID)szText, lSize) != lSize)
goto error;
break;
}
if (mmioAscend(hmmio, &ckINFO, 0))
break;
}
}
//
// if we have both a picture and a title, then exit.
//
if (h != NULL && szText[0] != 0)
break;
/* Ascend so that we can descend into next chunk
*/
if (mmioAscend(hmmio, &ck, 0))
break;
}
goto exit;
error:
if (h)
GlobalFree(h);
h = NULL;
exit:
return h;
}
/***************************************************************************
*
* FUNCTION :bmfCreateDIBPalette(HANDLE hDib)
*
* PURPOSE :Creates a palette suitable for displaying hDib.
*
* RETURNS :A handle to the palette if successful, NULL otherwise.
*
****************************************************************************/
HPALETTE WINAPI bmfCreateDIBPalette (HANDLE hDib)
{
HPALETTE hPal;
LPBITMAPINFOHEADER lpbi;
if (!hDib)
return NULL; //bail out if handle is invalid
lpbi = (LPBITMAPINFOHEADER)GlobalLock(hDib);
if (!lpbi)
return NULL;
hPal = CreateBIPalette(lpbi);
GlobalUnlock(hDib);
return hPal;
}
/***************************************************************************
*
* FUNCTION :CreateBIPalette(LPBITMAPINFOHEADER lpbi)
*
* PURPOSE :Given a Pointer to a BITMAPINFO struct will create a
* a GDI palette object from the color table.
*
* RETURNS :A handle to the palette if successful, NULL otherwise.
*
****************************************************************************/
HPALETTE CreateBIPalette (LPBITMAPINFOHEADER lpbi)
{
LPLOGPALETTE pPal;
HPALETTE hPal = NULL;
WORD nNumColors;
BYTE red;
BYTE green;
BYTE blue;
int i;
RGBQUAD FAR *pRgb;
HANDLE hMem;
if (!lpbi)
return NULL;
if (lpbi->biSize != sizeof(BITMAPINFOHEADER))
return NULL;
/* Get a pointer to the color table and the number of colors in it */
pRgb = (RGBQUAD FAR *)((LPTSTR)lpbi + (WORD)lpbi->biSize);
nNumColors = NumDIBColors(lpbi);
if (nNumColors)
{
/* Allocate for the logical palette structure */
hMem = GlobalAlloc(GMEM_MOVEABLE,
sizeof(LOGPALETTE) + nNumColors * sizeof(PALETTEENTRY));
if (!hMem)
return NULL;
pPal = (LPLOGPALETTE)GlobalLock(hMem);
if (!pPal)
{
GlobalFree(hMem);
return NULL;
}
pPal->palNumEntries = nNumColors;
pPal->palVersion = PALVERSION;
/* Fill in the palette entries from the DIB color table and
* create a logical color palette.
*/
for (i = 0; (unsigned)i < nNumColors; i++)
{
pPal->palPalEntry[i].peRed = pRgb[i].rgbRed;
pPal->palPalEntry[i].peGreen = pRgb[i].rgbGreen;
pPal->palPalEntry[i].peBlue = pRgb[i].rgbBlue;
pPal->palPalEntry[i].peFlags = (BYTE)0;
}
hPal = CreatePalette(pPal);
/* note that a NULL return value for the above CreatePalette call
* is acceptable, since this value will be returned, and is not
* used again here
*/
GlobalUnlock(hMem);
GlobalFree(hMem);
}
else if (lpbi->biBitCount == 24)
{
/* A 24 bitcount DIB has no color table entries so, set the number of
* to the maximum value (256).
*/
nNumColors = MAXPALETTE;
hMem =GlobalAlloc(GMEM_MOVEABLE,
sizeof(LOGPALETTE) + nNumColors * sizeof(PALETTEENTRY));
if (!hMem)
return NULL;
pPal = (LPLOGPALETTE)GlobalLock(hMem);
if (!pPal)
{
GlobalFree(hMem);
return NULL;
}
pPal->palNumEntries = nNumColors;
pPal->palVersion = PALVERSION;
red = green = blue = 0;
/* Generate 256 (= 8*8*4) RGB combinations to fill the palette
* entries.
*/
for (i = 0; (unsigned)i < pPal->palNumEntries; i++)
{
pPal->palPalEntry[i].peRed = red;
pPal->palPalEntry[i].peGreen = green;
pPal->palPalEntry[i].peBlue = blue;
pPal->palPalEntry[i].peFlags = (BYTE)0;
if (!(red += 32))
if (!(green += 32))
blue += 64;
}
hPal = CreatePalette(pPal);
/* note that a NULL return value for the above CreatePalette call
* is acceptable, since this value will be returned, and is not
* used again here
*/
GlobalUnlock(hMem);
GlobalFree(hMem);
}
return hPal;
}
/***************************************************************************
*
* FUNCTION :NumDIBColors(VOID FAR * pv)
*
* PURPOSE :Determines the number of colors in the DIB by looking at
* the BitCount field in the info block.
* For use only internal to DLL.
*
* RETURNS :The number of colors in the DIB.
*
****************************************************************************/
WORD NumDIBColors (VOID FAR * pv)
{
int bits;
LPBITMAPINFOHEADER lpbi;
LPBITMAPCOREHEADER lpbc;
lpbi = ((LPBITMAPINFOHEADER)pv);
lpbc = ((LPBITMAPCOREHEADER)pv);
/* With the BITMAPINFO format headers, the size of the palette
* is in biClrUsed, whereas in the BITMAPCORE - style headers, it
* is dependent on the bits per pixel ( = 2 raised to the power of
* bits/pixel).
*/
if (lpbi->biSize != sizeof(BITMAPCOREHEADER))
{
if (lpbi->biClrUsed != 0)
return (WORD)lpbi->biClrUsed;
bits = lpbi->biBitCount;
}
else
bits = lpbc->bcBitCount;
switch (bits)
{
case 1:
return 2;
case 4:
return 16;
case 8:
return 256;
default:
/* A 24 bitcount DIB has no color table */
return 0;
}
}
/***************************************************************************
*
* FUNCTION :bmfBitmapFromDIB(HANDLE hDib, HPALETTE hPal)
*
* PURPOSE :Converts DIB information into a device-dependent BITMAP
* suitable for display on the current display device. hDib is
* a global handle to a memory block containing the DIB
* information in CF_DIB format. hPal is a handle to a palette
* to be used for displaying the bitmap. If hPal is NULL, the
* default system palette is used during the conversion.
*
* RETURNS :Returns a handle to a bitmap is successful, NULL otherwise.
*
* HISTORY:
* 92/08/29 - BUG 2123: (w-markd)
* Check if DIB is has a valid size, and bail out if not.
* If no palette is passed in, try to create one. If we
* create one, we must destroy it before we exit.
*
****************************************************************************/
HBITMAP WINAPI bmfBitmapFromDIB(HANDLE hDib, HPALETTE hPal)
{
LPBITMAPINFOHEADER lpbi;
HPALETTE hPalT;
HDC hdc;
HBITMAP hBmp;
DWORD dwSize;
BOOL bMadePalette = FALSE;
if (!hDib)
return NULL; //bail out if handle is invalid
/* BUG 2123: (w-markd)
** Check to see if we can get the size of the DIB. If this call
** fails, bail out.
*/
dwSize = bmfDIBSize(hDib);
if (!dwSize)
return NULL;
lpbi = (VOID FAR *)GlobalLock(hDib);
if (!lpbi)
return NULL;
/* prepare palette */
/* BUG 2123: (w-markd)
** If the palette is NULL, we create one suitable for displaying
** the dib.
*/
if (!hPal)
{
hPal = bmfCreateDIBPalette(hDib);
if (!hPal)
{
GlobalUnlock(hDib);
#ifdef V101
#else
bMadePalette = TRUE;
#endif
return NULL;
}
#ifdef V101
/* BUGFIX: mikeroz 2123 - this flag was in the wrong place */
bMadePalette = TRUE;
#endif
}
hdc = GetDC(NULL);
hPalT = SelectPalette(hdc,hPal,FALSE);
RealizePalette(hdc); // GDI Bug...????
/* Create the bitmap. Note that a return value of NULL is ok here */
hBmp = CreateDIBitmap(hdc, (LPBITMAPINFOHEADER)lpbi, (LONG)CBM_INIT,
(LPSTR)lpbi + lpbi->biSize + PaletteSize(lpbi),
(LPBITMAPINFO)lpbi, DIB_RGB_COLORS );
/* clean up and exit */
/* BUG 2123: (w-markd)
** If we made the palette, we need to delete it.
*/
if (bMadePalette)
DeleteObject(SelectPalette(hdc,hPalT,FALSE));
else
SelectPalette(hdc,hPalT,FALSE);
ReleaseDC(NULL,hdc);
GlobalUnlock(hDib);
return hBmp;
}
/***************************************************************************
*
* FUNCTION :bmfDIBSize(HANDLE hDIB)
*
* PURPOSE :Return the size of a DIB.
*
* RETURNS :DWORD with size of DIB, include BITMAPINFOHEADER and
* palette. Returns 0 if failed.
*
* HISTORY:
* 92/08/13 - BUG 1642: (w-markd)
* Added this function so Quick Recorder could find out the
* size of a DIB.
* 92/08/29 - BUG 2123: (w-markd)
* If the biSizeImage field of the structure we get is zero,
* then we have to calculate the size of the image ourselves.
* Also, after size is calculated, we bail out if the
* size we calculated is larger than the size of the global
* object, since this indicates that the structure data
* we used to calculate the size was invalid.
*
****************************************************************************/
DWORD WINAPI bmfDIBSize(HANDLE hDIB)
{
LPBITMAPINFOHEADER lpbi;
DWORD dwSize;
/* Lock down the handle, and cast to a LPBITMAPINFOHEADER
** so we can read the fields we need
*/
lpbi = (LPBITMAPINFOHEADER)GlobalLock(hDIB);
if (!lpbi)
return 0;
/* BUG 2123: (w-markd)
** Since the biSizeImage could be zero, we may have to calculate
** the size ourselves.
*/
dwSize = lpbi->biSizeImage;
if (dwSize == 0)
dwSize = WIDTHBYTES((WORD)(lpbi->biWidth) * lpbi->biBitCount) *
lpbi->biHeight;
/* The size of the DIB is the size of the BITMAPINFOHEADER
** structure (lpbi->biSize) plus the size of our palette plus
** the size of the actual data (calculated above).
*/
dwSize += lpbi->biSize + (DWORD)PaletteSize(lpbi);
/* BUG 2123: (w-markd)
** Check to see if the size is greater than the size
** of the global object. If it is, the hDIB is corrupt.
*/
GlobalUnlock(hDIB);
if (dwSize > GlobalSize(hDIB))
return 0;
else
return(dwSize);
}
/***************************************************************************
*
* FUNCTION :PaletteSize(VOID FAR * pv)
*
* PURPOSE :Calculates the palette size in bytes. If the info. block
* is of the BITMAPCOREHEADER type, the number of colors is
* multiplied by 3 to give the palette size, otherwise the
* number of colors is multiplied by 4.
*
* RETURNS :Palette size in number of bytes.
*
****************************************************************************/
WORD PaletteSize (VOID FAR *pv)
{
LPBITMAPINFOHEADER lpbi;
WORD NumColors;
lpbi = (LPBITMAPINFOHEADER)pv;
NumColors = NumDIBColors(lpbi);
if (lpbi->biSize == sizeof(BITMAPCOREHEADER))
return (NumColors * sizeof(RGBTRIPLE));
else
return (NumColors * sizeof(RGBQUAD));
}
//
// globals for PicsPageProc
//int xCursor, yCursor;
TCHAR szRMineIcon[] = TEXT("CLSID\\{20D04FE0-3AEA-1069-A2D8-08002B30309D}\\DefaultIcon");
TCHAR szRNhbdIcon[] = TEXT("CLSID\\{208D2C60-3AEA-1069-A2D7-08002B30309D}\\DefaultIcon");
TCHAR szRTrashIcon[] = TEXT("CLSID\\{645FF040-5081-101B-9F08-00AA002F954E}\\DefaultIcon");
TCHAR szRMyDocsIcon[] = TEXT("CLSID\\{450D8FBA-AD25-11D0-98A8-0800361B1103}\\DefaultIcon");
TCHAR szCUMineIcon[] = TEXT("Software\\Classes\\CLSID\\{20D04FE0-3AEA-1069-A2D8-08002B30309D}\\DefaultIcon");
TCHAR szCUNhbdIcon[] = TEXT("Software\\Classes\\CLSID\\{208D2C60-3AEA-1069-A2D7-08002B30309D}\\DefaultIcon");
TCHAR szCUTrashIcon[] = TEXT("Software\\Classes\\CLSID\\{645FF040-5081-101B-9F08-00AA002F954E}\\DefaultIcon");
TCHAR szCUMyDocsIcon[] = TEXT("Software\\Classes\\CLSID\\{450D8FBA-AD25-11D0-98A8-0800361B1103}\\DefaultIcon");
TCHAR szTrashFull[] = TEXT("full");
TCHAR szTrashEmpty[] = TEXT("empty");
INT_PTR FAR PASCAL PicsPageProc(hDlg, message, wParam, lParam)
HWND hDlg;
UINT message;
WPARAM wParam;
LPARAM lParam;
{
switch (message) {
// set up listbox, initial selection, etc.
case WM_INITDIALOG:
{ // var scope
extern FROST_SUBKEY fsRoot[]; // for theme file/registry keys
extern FROST_SUBKEY fsCUIcons[]; // for theme file/registry keys
extern TCHAR c_szSoftwareClassesFmt[]; // for NT reg path/keys.h
int iter;
int iRet;
HWND hText, hLBox;
RECT rText;
TCHAR szDispStr[MAX_STRLEN+1];
extern TCHAR szCP_DT[];
extern TCHAR szWP[];
extern TCHAR szDT[];
extern TCHAR szSS_Section[];
extern TCHAR szSS_Key[];
extern TCHAR szSS_File[];
TCHAR szNTReg[MAX_PATH];
//
// get metrics for drawitem size
hText = GetDlgItem(hDlg, TXT_FILENAME); // 12 dialog box units high
GetWindowRect(hText, (LPRECT)&rText);
iItemHeight = ((rText.bottom - rText.top) * 8) / 12; // dialog font height
xTextOffset = (iItemHeight * 3) / 2; // proportional spacing
Assert(iItemHeight > 0, TEXT("didn't get positive text height for preview listbox!\n"));
#if 0 // to do own drawing for wallpaper and scr saver?
// other metrics, etc.
xCursor = GetSystemMetrics(SM_CXCURSOR);
yCursor = GetSystemMetrics(SM_CYCURSOR);
//
// save away preview rect area
GetWindowRect(GetDlgItem(hDlg, RECT_PREVIEW), (LPRECT)&rPreview);
GetWindowRect(hDlg, (LPRECT)&rText);
OffsetRect((LPRECT)&rPreview, -rText.left, -rText.top);
DestroyWindow(GetDlgItem(hDlg, RECT_PREVIEW));
#endif
//
// init the listbox with combined strings
// init
hLBox = GetDlgItem(hDlg, LB_PICS);
// unlike the ptrs and snds, have to do each item by hand here
// since they are three different types (actually four ways of
// retrieving associated file
//
// WALLPAPER BITMAP
// get display string
LoadString(hInstApp, STR_PIC_WALL,
(LPTSTR)szDispStr, MAX_STRLEN);
// CPLs don't check for success on LoadString in INITDIALOG, so OK!?
// get filename if any
if (bThemed) { // get from theme
GetPrivateProfileString((LPTSTR)szCP_DT, (LPTSTR)szWP,
(LPTSTR)szNULL,
(LPTSTR)szMsg, MAX_MSGLEN,
(LPTSTR)szCurThemeFile);
// expand filename string as necessary
InstantiatePath((LPTSTR)szMsg, MAX_MSGLEN);
}
else { // get from system
// If ActiveDesktop is on we should query AD for this
// setting instead of reading from the registry.
if (IsActiveDesktopOn()) {
if (!GetADWallpaper(szMsg)) {
// Failed to read AD setting so get it from the registry
GetRegString(HKEY_CURRENT_USER, szCP_DT, szWP,
szNULL, szMsg, MAX_MSGLEN);
}
}
// ActiveDesktop is off so get the setting from the registry
else {
GetRegString(HKEY_CURRENT_USER, szCP_DT, szWP,
szNULL, szMsg, MAX_MSGLEN);
}
// If this isn't an HTM or HTML wallpaper file then we
// should extract the image title.
if ((lstrcmpi(FindExtension(szMsg), TEXT(".htm")) != 0) &&
(lstrcmpi(FindExtension(szMsg), TEXT(".html")) != 0)) {
// Not an HTM/L file so extract the image title
GetImageTitle(szMsg, szMsg, MAX_MSGLEN);
}
}
// combine strings into data string to load up in
// owner-draw hasstrings listbox!
CreateDataStr((LPTSTR)pValue, (LPTSTR)szDispStr, (LPTSTR)szMsg);
// now, finally, go ahead and assign string to listbox
SendMessage(hLBox, LB_ADDSTRING, 0, (LPARAM)(LPTSTR)pValue);
//
// MY COMPUTER ICON
LoadString(hInstApp, STR_PIC_MYCOMP,
(LPTSTR)szDispStr, MAX_STRLEN);
// CPLs don't check for success on LoadString in INITDIALOG, so OK!?
// get filename if any
if (bThemed) { // get from theme
// Get the CURRENT_USER My Computer icon setting
GetPrivateProfileString((LPTSTR)szCUMineIcon, (LPTSTR)FROST_DEFSTR,
(LPTSTR)szNULL,
(LPTSTR)szMsg, MAX_MSGLEN,
(LPTSTR)szCurThemeFile);
// If the string is NULL, try the "old" style Win95
// CLASSES_ROOT setting instead
if (!*szMsg) {
GetPrivateProfileString((LPTSTR)szRMineIcon,
(LPTSTR)FROST_DEFSTR,
(LPTSTR)szNULL,
(LPTSTR)szMsg, MAX_MSGLEN,
(LPTSTR)szCurThemeFile);
}
// expand filename string as necessary
InstantiatePath((LPTSTR)szMsg, MAX_MSGLEN);
}
else { // get from system
// First try reading from the appropriate CURRENT_USER
// section for this platform.
szMsg[0] = TEXT('\0');
if (IsPlatformNT())
{
lstrcpy(szNTReg, c_szSoftwareClassesFmt);
lstrcat(szNTReg, szRMineIcon);
HandGet(HKEY_CURRENT_USER,
(LPTSTR)szNTReg,
(LPTSTR)szNULL, // null string for default value
(LPTSTR)szMsg);
}
else // Not NT
{
HandGet(HKEY_CURRENT_USER,
(LPTSTR)szCUMineIcon,
(LPTSTR)szNULL, // null string for default value
(LPTSTR)szMsg);
}
// If we didn't get a good string from CURRENT_USER branch
// try the CLASSES_ROOT branch instead.
if (!*szMsg) {
HandGet(HKEY_CLASSES_ROOT,
(LPTSTR)szRMineIcon,
(LPTSTR)szNULL, // null string for default value
(LPTSTR)szMsg);
}
}
InstantiatePath((LPTSTR)szMsg, MAX_MSGLEN);
// combine strings into data string to load up in
// owner-draw hasstrings listbox!
CreateDataStr((LPTSTR)pValue, (LPTSTR)szDispStr, (LPTSTR)szMsg);
// now, finally, go ahead and assign string to listbox
SendMessage(hLBox, LB_ADDSTRING, 0, (LPARAM)(LPTSTR)pValue);
//
// NETWORK NHBD ICON
LoadString(hInstApp, STR_PIC_NETHOOD,
(LPTSTR)szDispStr, MAX_STRLEN);
// CPLs don't check for success on LoadString in INITDIALOG, so OK!?
// get filename if any
if (bThemed) { // get from theme
// Get the CURRENT_USER Net Neighborhood icon setting
GetPrivateProfileString((LPTSTR)szCUNhbdIcon, (LPTSTR)FROST_DEFSTR,
(LPTSTR)szNULL,
(LPTSTR)szMsg, MAX_MSGLEN,
(LPTSTR)szCurThemeFile);
// If the string is NULL, try the "old" style Win95
// CLASSES_ROOT setting instead
if (!*szMsg) {
GetPrivateProfileString((LPTSTR)szRNhbdIcon,
(LPTSTR)FROST_DEFSTR,
(LPTSTR)szNULL,
(LPTSTR)szMsg, MAX_MSGLEN,
(LPTSTR)szCurThemeFile);
}
// expand filename string as necessary
InstantiatePath((LPTSTR)szMsg, MAX_MSGLEN);
}
else { // get from system
// First try reading from the appropriate CURRENT_USER
// section for this platform.
szMsg[0] = TEXT('\0');
if (IsPlatformNT())
{
lstrcpy(szNTReg, c_szSoftwareClassesFmt);
lstrcat(szNTReg, szRNhbdIcon);
HandGet(HKEY_CURRENT_USER,
(LPTSTR)szNTReg,
(LPTSTR)szNULL, // null string for default value
(LPTSTR)szMsg);
}
else // Not NT
{
HandGet(HKEY_CURRENT_USER,
(LPTSTR)szCUNhbdIcon,
(LPTSTR)szNULL, // null string for default value
(LPTSTR)szMsg);
}
// If we didn't get a good string from CURRENT_USER branch
// try the CLASSES_ROOT branch instead.
if (!*szMsg) {
HandGet(HKEY_CLASSES_ROOT,
(LPTSTR)szRNhbdIcon,
(LPTSTR)szNULL, // null string for default value
(LPTSTR)szMsg);
}
}
InstantiatePath((LPTSTR)szMsg, MAX_MSGLEN);
// combine strings into data string to load up in
// owner-draw hasstrings listbox!
CreateDataStr((LPTSTR)pValue, (LPTSTR)szDispStr, (LPTSTR)szMsg);
// now, finally, go ahead and assign string to listbox
SendMessage(hLBox, LB_ADDSTRING, 0, (LPARAM)(LPTSTR)pValue);
//
// RECYCLE BIN FULL
LoadString(hInstApp, STR_PIC_RECBINFULL,
(LPTSTR)szDispStr, MAX_STRLEN);
// CPLs don't check for success on LoadString in INITDIALOG, so OK!?
// get filename if any
if (bThemed) { // get from theme
// Get the CURRENT_USER Recycle Bin Full icon setting
GetPrivateProfileString((LPTSTR)szCUTrashIcon, (LPTSTR)szTrashFull,
(LPTSTR)szNULL,
(LPTSTR)szMsg, MAX_MSGLEN,
(LPTSTR)szCurThemeFile);
// If the string is NULL, try the "old" style Win95
// CLASSES_ROOT setting instead
if (!*szMsg) {
GetPrivateProfileString((LPTSTR)szRTrashIcon,
(LPTSTR)szTrashFull,
(LPTSTR)szNULL,
(LPTSTR)szMsg, MAX_MSGLEN,
(LPTSTR)szCurThemeFile);
}
// expand filename string as necessary
InstantiatePath((LPTSTR)szMsg, MAX_MSGLEN);
}
else { // get from system
// First try reading from the appropriate CURRENT_USER
// section for this platform.
szMsg[0] = TEXT('\0');
if (IsPlatformNT())
{
lstrcpy(szNTReg, c_szSoftwareClassesFmt);
lstrcat(szNTReg, szRTrashIcon);
HandGet(HKEY_CURRENT_USER,
(LPTSTR)szNTReg,
(LPTSTR)szTrashFull,
(LPTSTR)szMsg);
}
else // Not NT
{
HandGet(HKEY_CURRENT_USER,
(LPTSTR)szCUTrashIcon,
(LPTSTR)szTrashFull,
(LPTSTR)szMsg);
}
// If we didn't get a good string from CURRENT_USER branch
// try the CLASSES_ROOT branch instead.
if (!*szMsg) {
HandGet(HKEY_CLASSES_ROOT,
(LPTSTR)szRTrashIcon,
(LPTSTR)szTrashFull,
(LPTSTR)szMsg);
}
}
InstantiatePath((LPTSTR)szMsg, MAX_MSGLEN);
// combine strings into data string to load up in
// owner-draw hasstrings listbox!
CreateDataStr((LPTSTR)pValue, (LPTSTR)szDispStr, (LPTSTR)szMsg);
// now, finally, go ahead and assign string to listbox
SendMessage(hLBox, LB_ADDSTRING, 0, (LPARAM)(LPTSTR)pValue);
//
// RECYCLE BIN EMPTY
LoadString(hInstApp, STR_PIC_RECBINEMPTY,
(LPTSTR)szDispStr, MAX_STRLEN);
// CPLs don't check for success on LoadString in INITDIALOG, so OK!?
// get filename if any
if (bThemed) { // get from theme
// Get the CURRENT_USER Recycle Bin Empty icon setting
GetPrivateProfileString((LPTSTR)szCUTrashIcon,
(LPTSTR)szTrashEmpty,
(LPTSTR)szNULL,
(LPTSTR)szMsg, MAX_MSGLEN,
(LPTSTR)szCurThemeFile);
// If the string is NULL, try the "old" style Win95
// CLASSES_ROOT setting instead
if (!*szMsg) {
GetPrivateProfileString((LPTSTR)szRTrashIcon,
(LPTSTR)szTrashEmpty,
(LPTSTR)szNULL,
(LPTSTR)szMsg, MAX_MSGLEN,
(LPTSTR)szCurThemeFile);
}
// expand filename string as necessary
InstantiatePath((LPTSTR)szMsg, MAX_MSGLEN);
}
else { // get from system
// First try reading from the appropriate CURRENT_USER
// section for this platform.
szMsg[0] = TEXT('\0');
if (IsPlatformNT())
{
lstrcpy(szNTReg, c_szSoftwareClassesFmt);
lstrcat(szNTReg, szRTrashIcon);
HandGet(HKEY_CURRENT_USER,
(LPTSTR)szNTReg,
(LPTSTR)szTrashEmpty,
(LPTSTR)szMsg);
}
else // Not NT
{
HandGet(HKEY_CURRENT_USER,
(LPTSTR)szCUTrashIcon,
(LPTSTR)szTrashEmpty,
(LPTSTR)szMsg);
}
// If we didn't get a good string from CURRENT_USER branch
// try the CLASSES_ROOT branch instead.
if (!*szMsg) {
HandGet(HKEY_CLASSES_ROOT,
(LPTSTR)szRTrashIcon,
(LPTSTR)szTrashEmpty,
(LPTSTR)szMsg);
}
}
InstantiatePath((LPTSTR)szMsg, MAX_MSGLEN);
// combine strings into data string to load up in
// owner-draw hasstrings listbox!
CreateDataStr((LPTSTR)pValue, (LPTSTR)szDispStr, (LPTSTR)szMsg);
// now, finally, go ahead and assign string to listbox
SendMessage(hLBox, LB_ADDSTRING, 0, (LPARAM)(LPTSTR)pValue);
//
// MY DOCUMENTS ICON
LoadString(hInstApp, STR_PIC_MYDOCS,
(LPTSTR)szDispStr, MAX_STRLEN);
// CPLs don't check for success on LoadString in INITDIALOG, so OK!?
// get filename if any
if (bThemed) { // get from theme
// Get the CURRENT_USER My Documetns icon setting
GetPrivateProfileString((LPTSTR)szCUMyDocsIcon, (LPTSTR)FROST_DEFSTR,
(LPTSTR)szNULL,
(LPTSTR)szMsg, MAX_MSGLEN,
(LPTSTR)szCurThemeFile);
// If the string is NULL, try the "old" style Win95
// CLASSES_ROOT setting instead
if (!*szMsg) {
GetPrivateProfileString((LPTSTR)szRMyDocsIcon,
(LPTSTR)FROST_DEFSTR,
(LPTSTR)szNULL,
(LPTSTR)szMsg, MAX_MSGLEN,
(LPTSTR)szCurThemeFile);
}
// expand filename string as necessary
InstantiatePath((LPTSTR)szMsg, MAX_MSGLEN);
}
else { // get from system
// First try reading from the appropriate CURRENT_USER
// section for this platform.
szMsg[0] = TEXT('\0');
if (IsPlatformNT())
{
lstrcpy(szNTReg, c_szSoftwareClassesFmt);
lstrcat(szNTReg, szRMyDocsIcon);
HandGet(HKEY_CURRENT_USER,
(LPTSTR)szNTReg,
(LPTSTR)szNULL, // null string for default value
(LPTSTR)szMsg);
}
else // Not NT
{
HandGet(HKEY_CURRENT_USER,
(LPTSTR)szCUMyDocsIcon,
(LPTSTR)szNULL, // null string for default value
(LPTSTR)szMsg);
}
// If we didn't get a good string from CURRENT_USER branch
// try the CLASSES_ROOT branch instead.
if (!*szMsg) {
HandGet(HKEY_CLASSES_ROOT,
(LPTSTR)szRMyDocsIcon,
(LPTSTR)szNULL, // null string for default value
(LPTSTR)szMsg);
}
}
InstantiatePath((LPTSTR)szMsg, MAX_MSGLEN);
// combine strings into data string to load up in
// owner-draw hasstrings listbox!
CreateDataStr((LPTSTR)pValue, (LPTSTR)szDispStr, (LPTSTR)szMsg);
// now, finally, go ahead and assign string to listbox
SendMessage(hLBox, LB_ADDSTRING, 0, (LPARAM)(LPTSTR)pValue);
//
// SCREEN SAVER
LoadString(hInstApp, STR_PIC_SCRSAV,
(LPTSTR)szDispStr, MAX_STRLEN);
// CPLs don't check for success on LoadString in INITDIALOG, so OK!?
// get filename if any
if (bThemed) { // get from theme
GetPrivateProfileString((LPTSTR)szSS_Section, (LPTSTR)szSS_Key,
(LPTSTR)szNULL,
(LPTSTR)szMsg, MAX_MSGLEN,
(LPTSTR)szCurThemeFile);
// expand filename string as necessary
InstantiatePath((LPTSTR)szMsg, MAX_MSGLEN);
// For NT with old (Plus95/98) theme files that refer to
// windows\system we should update string to say system32
if (IsPlatformNT()) ConfirmFile(szMsg, TRUE);
}
else { // get from system
GetPrivateProfileString((LPTSTR)szSS_Section, (LPTSTR)szSS_Key,
(LPTSTR)szNULL,
(LPTSTR)szMsg, MAX_MSGLEN,
(LPTSTR)szSS_File);
// make into nice long filename for display
if (FilenameToLong(szMsg, (LPTSTR)pValue))
lstrcpy(FileFromPath(szMsg), (LPTSTR)pValue);
}
// combine strings into data string to load up in
// owner-draw hasstrings listbox!
CreateDataStr((LPTSTR)pValue, (LPTSTR)szDispStr, (LPTSTR)szMsg);
// now, finally, go ahead and assign string to listbox
SendMessage(hLBox, LB_ADDSTRING, 0, (LPARAM)(LPTSTR)pValue);
//
// check them all for file existence. have to do here, no prev loop
//
for (iter = 0; iter < MAX_ETC_ITEMS; iter++) {
// get this item's listbox string
iRet = (int) SendMessage(hLBox, LB_GETTEXT, iter, (LPARAM)(LPTSTR)szMsg);
if (iRet == LB_ERR)
break; // past end of listbox items CONTINUE
// get the filename assoc with this item, if any
GetFileStr((LPTSTR)pValue, (LPTSTR)szMsg);
// store whether the file exists
bVisualExists[iter] = *pValue &&
(CF_NOTFOUND != ConfirmFile((LPTSTR)pValue, FALSE));
}
//
// setup initial focus conditions
SetFocus(hLBox);
SendMessage(hLBox, LB_SETCURSEL, 0, 0);
// need to ensure it gets initial update of cur file
PostMessage(hDlg, WM_COMMAND, MAKEWPARAM(LB_PICS, LBN_SELCHANGE),
MAKELPARAM(0, 0) );
} // var scope
break;
case WM_MEASUREITEM:
{
LPMEASUREITEMSTRUCT lpmis;
/* Set the height of the list box items. */
lpmis = (LPMEASUREITEMSTRUCT) lParam;
// lpmis->itemHeight = iItemHeight;
lpmis->itemHeight = 0; // DavidBa says they want these big default item hts
// Assert(iItemHeight > 0, TEXT("set non-positive item height for preview listbox!\n"));
// Assert(iItemHeight <= 0, TEXT("OK, set a positive item height for preview listbox!\n"));
}
break;
case WM_DRAWITEM:
{ // var scope
TEXTMETRIC tm;
LPDRAWITEMSTRUCT lpdis;
int yTextOffset;
LPTSTR lpszFile;
HDC hdcMem;
HBITMAP hbmpOld;
lpdis = (LPDRAWITEMSTRUCT) lParam;
/* If there are no list box items, skip this message. */
if (lpdis->itemID == -1) {
break;
} // jdk: well, what about focus rect in empty lbox?
//
// Inits
// get the filename assoc with this item, if any
SendMessage(lpdis->hwndItem, LB_GETTEXT, lpdis->itemID,
(LPARAM)(LPTSTR)szMsg);
GetDisplayStr((LPTSTR)szMsg, (LPTSTR)szMsg); // Ok src and dst same
// you now have "displaystr\0filename" in szMsg[]
lpszFile = (LPTSTR)(szMsg + lstrlen((LPTSTR)szMsg) + 1);
//
// draw right background color
if (lpdis->itemState & ODS_SELECTED) {
// if item is selected, draw highlight background here
FillRect(lpdis->hDC, (LPRECT)&(lpdis->rcItem),
GetSysColorBrush(COLOR_HIGHLIGHT));
// set text color to highlight text
SetBkColor(lpdis->hDC, GetSysColor(COLOR_HIGHLIGHT));
SetTextColor(lpdis->hDC, GetSysColor(COLOR_HIGHLIGHTTEXT));
}
else { // not selected
// need to do normal background fill to undo prev selection
FillRect(lpdis->hDC, (LPRECT)&(lpdis->rcItem),
GetSysColorBrush(COLOR_WINDOW));
// set text color to foreground
SetBkColor(lpdis->hDC, GetSysColor(COLOR_WINDOW));
SetTextColor(lpdis->hDC, GetSysColor(COLOR_WINDOWTEXT));
}
// if there is a file associated with this item
if (*lpszFile) {
HBITMAP hbmpLeading;
BITMAP bmLeading;
//
// find the right leading bitmap: checkmark or question mark
if (bVisualExists[lpdis->itemID]) {
hbmpLeading = hbmpCheck;
bmLeading = bmCheck;
}
else {
hbmpLeading = hbmpQ;
bmLeading = bmQ;
}
//
// paint in the leading bitmap!
hdcMem = CreateCompatibleDC(lpdis->hDC);
if (hdcMem)
{
hbmpOld = SelectObject(hdcMem, hbmpLeading);
// if item height is less than bitmap height
if (lpdis->rcItem.bottom - lpdis->rcItem.top < bmLeading.bmHeight)
{
// stretch down bitmap size to fit
StretchBlt(lpdis->hDC,
lpdis->rcItem.left, lpdis->rcItem.top,
lpdis->rcItem.bottom - lpdis->rcItem.top, // width = height
lpdis->rcItem.bottom - lpdis->rcItem.top,
hdcMem, 0, 0, bmLeading.bmWidth, bmLeading.bmHeight, SRCCOPY);
}
else // item height taller than checkmark bitmap
{
// just center vertically
BitBlt(lpdis->hDC,
lpdis->rcItem.left,
lpdis->rcItem.top +
(lpdis->rcItem.bottom - lpdis->rcItem.top - bmLeading.bmHeight)/2,
bmLeading.bmWidth, bmLeading.bmHeight,
hdcMem, 0, 0, SRCCOPY);
}
SelectObject(hdcMem, hbmpOld);
DeleteDC(hdcMem);
}
// who cares
// Assert(lpdis->rcItem.bottom - lpdis->rcItem.top == iItemHeight,
// TEXT("MEASUREITEM and DRAWITEM have different heights!\n"));
}
//
// now draw the display string for this item
// figure y offset to vert center text in draw item
GetTextMetrics(lpdis->hDC, &tm);
yTextOffset = (lpdis->rcItem.bottom - lpdis->rcItem.top - tm.tmHeight) / 2;
Assert(yTextOffset >= 0, TEXT("negative text vert offset in DRAWITEM\n"));
if (yTextOffset < 0) yTextOffset = 0;
// do the out
SetBkMode(lpdis->hDC, TRANSPARENT);
TextOut(lpdis->hDC,
lpdis->rcItem.left + xTextOffset,
lpdis->rcItem.top + yTextOffset,
(LPTSTR)szMsg, lstrlen((LPTSTR)szMsg));
//
// if item is selected, draw a focus rect
if (lpdis->itemState & ODS_FOCUS) {
DrawFocusRect(lpdis->hDC, (LPRECT)&(lpdis->rcItem));
}
} // var scope
break;
case WM_COMMAND:
switch ((int)LOWORD(wParam)) {
case LB_PICS:
// if new selection in listbox
if (HIWORD(wParam) == LBN_SELCHANGE) {
int iSeln, ilen;
// get new selection if any
iSeln = (int)SendDlgItemMessage(hDlg, LB_PICS, LB_GETCURSEL, 0, 0);
if (LB_ERR == iSeln)
break; // no selection EXIT
// get selection text
SendDlgItemMessage(hDlg, LB_PICS, LB_GETTEXT,
(WPARAM)iSeln, (LPARAM)(LPTSTR)szMsg);
// update global current filename string
GetFileStr(szCurPreviewFile, szMsg);
// reset dialog static text of filename string
if (iSeln == SCRSAV_NDX) {
// if you can get a long filename, then use it
if (FilenameToLong((LPTSTR)szCurPreviewFile, (LPTSTR)szMsg))
lstrcpy(FileFromPath((LPTSTR)szCurPreviewFile), (LPTSTR)szMsg);
SetDlgItemFile(hDlg, TXT_FILENAME, szCurPreviewFile);
}
else
SetDlgItemFile(hDlg, TXT_FILENAME, szCurPreviewFile);
// and scroll end into view
ilen = lstrlen((LPTSTR)szCurPreviewFile);
SendDlgItemMessage(hDlg, TXT_FILENAME, EM_SETSEL,
(WPARAM)0, MAKELPARAM(-1, ilen));
//
// Update Image
//
// init by destroying old
if (hCurImage) DestroyCursor(hCurImage);
hCurImage = NULL;
// get new image...
if (*szCurPreviewFile) {
// ... unless the screen saver was selected
if (iSeln != SCRSAV_NDX) {
int index;
LPTSTR lpszIndex;
#ifdef UNICODE
char szTempA[10];
#endif
// load as icon; works for bmps too
// init: copy global filename to destructive-OK location
lstrcpy((LPTSTR)szMsg, (LPTSTR)szCurPreviewFile);
// may have index into file. format: "file,index"
lpszIndex = FindChar((LPTSTR)szMsg, TEXT(','));
if (*lpszIndex) { // if found a comma, then indexed icon
#ifdef UNICODE
wcstombs(szTempA, CharNext(lpszIndex), sizeof(szTempA));
index = latoi(szTempA);
#else
index = latoi(CharNext(lpszIndex));
#endif
*lpszIndex = 0; // got index then null term filename in szMsg
}
else { // just straight icon file or no index
index = 0;
}
// OK, now you can do the load!
ExtractPlusColorIcon(szMsg, index, &((HICON)hCurImage), 0, 0);
}
// else SCREEN SAVER: just leave hCurImage NULL for blank
}
// set image to static ctl, even if null: null clears prev
SendDlgItemMessage(hDlg, RECT_PREVIEW, STM_SETICON,
(WPARAM)hCurImage, (LPARAM)0);
// if it's the screen saver, then start up the preview
if (iSeln == SCRSAV_NDX) {
// TBA
}
#if 0 // this is when we painted the cursor by ourself
// force repaint of preview area
InvalidateRect(hDlg, (LPRECT)&rPreview, TRUE);
#endif
}
break;
// case PB_TEST:
// break;
}
break;
#if 0 // this is when we painted the cursor by ourself
case WM_PAINT:
BeginPaint(hDlg, &ps);
//
// preview area
DrawEdge(ps.hdc, (LPRECT)&rPreview, EDGE_SUNKEN, BF_RECT); // always edge
// if there's a file to preview
if (*szCurPreviewFile) {
// add the cursor
if (hCurCursor)
DrawIcon(ps.hdc,
rPreview.left + (rPreview.right-rPreview.left-xCursor)/2,
rPreview.top + (rPreview.bottom-rPreview.top-yCursor)/2,
hCurCursor);
}
EndPaint(hDlg, &ps);
break;
#endif
case WM_NOTIFY:
switch ( ((NMHDR FAR *)lParam)->code) {
// OK or Apply button pressed
case PSN_APPLY:
// apply any changes made on this page
SetWindowLongPtr(hDlg, DWLP_MSGRESULT, PSNRET_NOERROR); // accept changes
break;
// cancel button pressed
case PSN_RESET:
// don't accept any of the changes made on this page
break;
case PSN_SETACTIVE:
break;
case PSN_KILLACTIVE:
// need to say that it's OK by us to lose the activation
SetWindowLongPtr(hDlg, DWLP_MSGRESULT, FALSE); // OK to kill focus now
break;
}
break;
case WM_HELP:
{
LPHELPINFO lphi;
lphi = (LPHELPINFO)lParam;
if (lphi->iContextType == HELPINFO_WINDOW) {
WinHelp(lphi->hItemHandle, (LPTSTR)szHelpFile, HELP_WM_HELP,
(DWORD_PTR)((POPUP_HELP_ARRAY FAR *)phaPicsDlg));
}
}
break;
case WM_CONTEXTMENU:
WinHelp((HWND)wParam, (LPTSTR)szHelpFile, HELP_CONTEXTMENU,
(DWORD_PTR)((POPUP_HELP_ARRAY FAR *)phaPicsDlg));
break;
default:
return(FALSE); // didn't process message
break;
}
return TRUE; // processed message
}
//
// CreateDataStr
// GetFileStr
// GetDisplayStr
//
// When initializing the owner-draw listbox in each of these dialogs,
// they are filled with strings of the form:
// displaystring;filename
// where "filename" is the associated full-path filename string AND CAN BE NULL
// and where "displaystring" is the string that appears in the listbox.
//
// CreateDataStr() puts the two pieces together into one string to store.
// The other two functions retrieve one of the pieces from the concatenated
// stored string.
//
TCHAR szSepStr[] = TEXT(";"); // separator character, as null-term str
// Input: file and display strings NON-DESTRUCTIVE TO INPUT
// Output: combined data string
void CreateDataStr(LPTSTR lpData, LPTSTR lpDisp, LPTSTR lpFile)
{
lstrcpy(lpData, lpDisp); // filename can be null
lstrcat(lpData, (LPTSTR)szSepStr);
lstrcat(lpData, lpFile);
}
// Input: combined data string NON-DESTRUCTIVE TO INPUT
// Output: display string
void GetDisplayStr(LPTSTR lpDisp, LPTSTR lpData)
{
LPTSTR lpScan, lpCopy;
// just do it all in a loop
for (lpScan = lpData, lpCopy = lpDisp;
*lpScan && // paranoid
(*lpScan != szSepStr[0]); // stop when you hit the sep char
lpScan++, lpCopy++) {
*lpCopy = *lpScan; // copy over chars one by one
}
// null term filename result to finish
*lpCopy = 0; // null filename yields lpDisp[0] = 0
}
// Input: combined data string NON-DESTRUCTIVE TO INPUT
// Output: file string
void GetFileStr(LPTSTR lpFile, LPTSTR lpData)
{
LPTSTR lpScan;
// just loop until you hit sep char
for (lpScan = lpData;
*lpScan && // paranoid
(*lpScan != szSepStr[0]); // stop when you hit the sep char
lpScan++) { } // do nothing
// now just take the rest of the string and return it
if (*lpScan) // paranoid
lstrcpy(lpFile, ++lpScan); // should never be nullstr, but that works too
else
*lpFile = 0; // 'impossible' error case
}
#ifdef FOOBAR
// Sets the dialog item to the path name as "prettied" by the shell.
// jdk 6/95: prev funtion just showed filename no path!
#endif
//
// SetDlgItemFile
//
// The whole point of these dialogs is to let the user see where the
// constituent resource files of a theme are, so we need to include the
// full pathnames. No reason not to pretty up the filename part, though.
//
// FUTURE: we can check here for indexed icon files, and make some
// more user-readable form of it.
// e.g. iconfile.dll,17 --> iconfile.dll [icon #17]
//
void PASCAL SetDlgItemFile(HWND hwnd, UINT DlgItem, LPCTSTR lpszPath)
{
TCHAR szFullPath[MAX_PATH+1];
TCHAR szPrettyFilename[MAX_PATH+1];
LPTSTR lpszFilename;
// inits
lstrcpy(szFullPath, lpszPath);
lpszFilename = FileFromPath(szFullPath);
// prettify via API if you can
if (*lpszPath != TEXT('\0')) {
// what does this do? it gives you the filename with the user's options
// e.g. Explorer View/Options Show/Don'tShow extensions
GetFileTitle(lpszPath, szPrettyFilename, ARRAYSIZE(szPrettyFilename));
lstrcpy(lpszFilename, szPrettyFilename);
}
// do it
SetDlgItemText(hwnd, DlgItem, szFullPath);
}