/* 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); }