/****************************************************************************/ /* */ /* Microsoft Confidential */ /* */ /* Copyright (c) Microsoft Corp. 1987, 1990 */ /* All Rights Reserved */ /* */ /****************************************************************************/ /****************************** Module Header ******************************* * Module Name: dlgedit.c * * Main function and window procedure for the Dialog Box Editor. * * Notes: * * Because of the need for a dialog in both work and test mode to be * shown relative to the client area of its parent, and because the * editor has a ribbon control along the top of its client area, there * needed to be another window created that will be the actual parent * of the dialog being edited. This window, called the ghwndSubClient * window, is sized to be the size of the editors client area minus * the height of the ribbon window at the top. This makes it so that * a dialog that has an origin of 0,0 will have the top edge of its * client area just below the bottom of the ribbon window in the * editor. This window does not need any special processing. It simply * paints its background with the app workspace color, and is used as * the basis for coordinate conversion for the dialog. * * History: * * Feb 1991, Byron Dazey [byrond] - Ported back to Windows from * PM after a major rewrite. * Mar 1992, Byron Dazey [byrond] - Ported to Windows NT. Reads/writes the * new Win32 format resource file. * ****************************************************************************/ #include "dlgedit.h" #include "dlgfuncs.h" #include "dlgextrn.h" #include "dialogs.h" #include #include #include #if defined(DBCS) && !defined(UNICODE) #define _MBCS #include #define strtok _mbstok #endif STATICFN BOOL InitApplication(HANDLE hInstance); STATICFN BOOL InitInstance(HANDLE hInstance, INT nCmdShow); STATICFN VOID PenWinRegister(VOID); STATICFN VOID GetSystemValues(VOID); STATICFN VOID ReadEnv(VOID); STATICFN VOID WriteEnv(VOID); STATICFN VOID LoadSysColorBitmaps(VOID); STATICFN HBITMAP LoadAlterBitmap(INT idbm, DWORD rgbNew, DWORD rgbNew2); STATICFN DWORD RGBInvertRGB(DWORD rgb); STATICFN VOID SizeRibbons(HWND hwnd); STATICFN VOID DialogTerminate(VOID); static RECT grcAppPos; // Saves the app's window pos. static UINT gmsgHelp; // Registered help message from commdlg. static BOOL fStartAsIcon = FALSE; // TRUE if app is started minimized. /* * Contains the address of the Pen Windows callback. */ typedef VOID (FAR PASCAL *LPFNPENWIN)(WORD, BOOL); static LPFNPENWIN lpfnRegisterPenApp; /************************************************************************ * WinMain * * This is the main function for the dialog editor. * ************************************************************************/ INT WINAPI WinMain( HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine, INT nCmdShow) { MSG msg; if (!hPrevInstance) { if (!InitApplication(hInstance)) { Message(MSG_NOINIT); return FALSE; } } if (!InitInstance(hInstance, nCmdShow)) { Message(MSG_NOINIT); return FALSE; } while (GetMessage(&msg, NULL, 0, 0)) { if (!ghwndTestDlg || !IsDialogMessage(ghwndTestDlg, &msg)) { if (!hwndStatus || !IsDialogMessage(hwndStatus, &msg)) { if (!TranslateAccelerator(ghwndMain, ghAccTable, &msg)) { TranslateMessage(&msg); DispatchMessage(&msg); } } } } DialogTerminate(); /* * Return the value from PostQuitMessage. */ return msg.wParam; } /************************************************************************ * InitApplication * * * Arguments: * HANDLE hInstance - Instance handle from WinMain. * * History: * ************************************************************************/ STATICFN BOOL InitApplication( HANDLE hInstance) { WNDCLASS wc; wc.style = CS_DBLCLKS; wc.lpfnWndProc = MainWndProc; wc.cbClsExtra = 0; wc.cbWndExtra = sizeof(DWORD); wc.hInstance = hInstance; wc.hIcon = LoadIcon(hInstance, MAKEINTRESOURCE(IDICON_DLGEDIT)); wc.hCursor = LoadCursor(NULL, IDC_ARROW); wc.hbrBackground = (HBRUSH)(COLOR_APPWORKSPACE + 1); wc.lpszMenuName = MAKEINTRESOURCE(IDMENU_MAIN); wc.lpszClassName = szMainClass; if (!RegisterClass(&wc)) return FALSE; wc.style = 0; wc.lpfnWndProc = DefWindowProc; wc.cbClsExtra = 0; wc.cbWndExtra = 0; wc.hInstance = hInstance; wc.hIcon = NULL; wc.hCursor = LoadCursor(NULL, IDC_ARROW); wc.hbrBackground = (HBRUSH)(COLOR_APPWORKSPACE + 1); wc.lpszMenuName = NULL; wc.lpszClassName = szSubClientClass; if (!RegisterClass(&wc)) return FALSE; wc.style = CS_DBLCLKS; wc.lpfnWndProc = DragWndProc; wc.cbClsExtra = 0; wc.cbWndExtra = sizeof(DWORD); wc.hInstance = hInstance; wc.hIcon = NULL; wc.hCursor = LoadCursor(NULL, IDC_ARROW); wc.hbrBackground = (HBRUSH)(COLOR_WINDOW + 1); wc.lpszMenuName = NULL; wc.lpszClassName = szDragClass; if (!RegisterClass(&wc)) return FALSE; wc.style = 0; wc.lpfnWndProc = ToolboxWndProc; wc.cbClsExtra = 0; wc.cbWndExtra = 0; wc.hInstance = hInstance; wc.hIcon = NULL; wc.hCursor = LoadCursor(NULL, IDC_ARROW); wc.hbrBackground = GetStockObject(LTGRAY_BRUSH); wc.lpszMenuName = NULL; wc.lpszClassName = szToolboxClass; if (!RegisterClass(&wc)) return FALSE; wc.style = 0; wc.lpfnWndProc = ToolBtnWndProc; wc.cbClsExtra = 0; wc.cbWndExtra = 0; wc.hInstance = hInstance; wc.hIcon = NULL; wc.hCursor = LoadCursor(NULL, IDC_ARROW); wc.hbrBackground = (HBRUSH)(COLOR_WINDOW + 1); wc.lpszMenuName = NULL; wc.lpszClassName = szToolBtnClass; if (!RegisterClass(&wc)) return FALSE; wc.style = CS_DBLCLKS | CS_HREDRAW | CS_VREDRAW; wc.lpfnWndProc = CustomWndProc; wc.cbClsExtra = 0; wc.cbWndExtra = 0; wc.hInstance = hInstance; wc.hIcon = NULL; wc.hCursor = LoadCursor(NULL, IDC_ARROW); wc.hbrBackground = (HBRUSH)(COLOR_WINDOW + 1); wc.lpszMenuName = NULL; wc.lpszClassName = szCustomClass; if (!RegisterClass(&wc)) return FALSE; return TRUE; } /************************************************************************ * InitInstance * * * Arguments: * HANDLE hInstance - Instance handle from WinMain. * int nCmdShow - Show command from WinMain. * * History: * ************************************************************************/ STATICFN BOOL InitInstance( HANDLE hInstance, INT nCmdShow) { HDC hDC; TEXTMETRIC tm; INT x; INT y; INT cx; INT cy; BOOL fMaximized; INT i; TCHAR szArg1[CCHTEXTMAX]; ghInst = hInstance; /* * We need a mouse - make sure we have one. */ if (!GetSystemMetrics(SM_MOUSEPRESENT)) { Message(MSG_NOMOUSE); return FALSE; } /* * Register for Pen Windows, if it is present. */ PenWinRegister(); ghAccTable = LoadAccelerators(ghInst, MAKEINTRESOURCE(IDACCEL_MAIN)); /* * Create a dark gray pen for use in borders later. */ if (!(hpenDarkGray = CreatePen(PS_SOLID, 1, DARKGRAY))) return FALSE; /* * Get some system constants. */ GetSystemValues(); /* * Note that this must be done instead of using the text metrics, * because Windows internally generates a better average value for * proportional fonts, and we must match it or our dialogs will * be out of proportion. */ gcxSysChar = LOWORD(GetDialogBaseUnits()); gcySysChar = HIWORD(GetDialogBaseUnits()); /* * Because some useful worker routines like WinToDUPoint use * the values in gcd.c*Char, set them to be the default font right * away. When a dialog is loaded with a different font, they * will be modified. */ gcd.cxChar = gcxSysChar; gcd.cyChar = gcySysChar; /* * Build the help file name path. Assume the help file is in the * same directory as the executable. */ GetModuleFileName(ghInst, gszHelpFile, CCHMAXPATH); *FileInPath(gszHelpFile) = CHAR_NULL; lstrcat(gszHelpFile, ids(IDS_HELPFILE)); /* * Register the message for help from the common dialogs. */ gmsgHelp = RegisterWindowMessage(HELPMSGSTRING); /* * Hook the message filter stream so that we can detect F1 keystrokes. */ ghhkMsgFilter = SetWindowsHook(WH_MSGFILTER, MsgFilterHookFunc); /* * Read the last position for the app. */ if (!ReadWindowPos(szAppPos, &x, &y, &cx, &cy, &fMaximized)) { x = CW_USEDEFAULT; y = CW_USEDEFAULT; cx = CW_USEDEFAULT; cy = CW_USEDEFAULT; fMaximized = FALSE; } /* * Create the main window. */ if (!(ghwndMain = CreateWindow(szMainClass, NULL, WS_OVERLAPPEDWINDOW | WS_CLIPCHILDREN, x, y, cx, cy, NULL, NULL, hInstance, NULL))) return FALSE; ShowFileStatus(TRUE); /* * Read the Preferences data. */ ReadEnv(); /* * If the app was saved when maximized (and they didn't start it up * with some kind of an option to have it minimized or in some * other funny initial state from the shell), then cause it to * be maximized when shown. */ if (fMaximized && (nCmdShow == SW_SHOWNORMAL || nCmdShow == SW_SHOW)) nCmdShow = SW_SHOWMAXIMIZED; ShowWindow(ghwndMain, nCmdShow); UpdateWindow(ghwndMain); /* * Did the user start this app minimized from the program manager? */ if (IsIconic(ghwndMain)) { /* * Set a flag. The showing of the toolbox will be deferred * until the app is restored. */ fStartAsIcon = TRUE; } else { /* * If they had the Toolbox before, show it now. */ if (gfShowToolbox) ToolboxShow(TRUE); } hcurArrow = LoadCursor(NULL, IDC_ARROW); hcurWait = LoadCursor(NULL, IDC_WAIT); hcurOutSel = LoadCursor(ghInst, MAKEINTRESOURCE(IDCUR_OUTSEL)); hcurMove = LoadCursor(ghInst, MAKEINTRESOURCE(IDCUR_MOVE)); hcurInsert = LoadCursor(ghInst, MAKEINTRESOURCE(IDCUR_INSERT)); hcurDropTool = LoadCursor(ghInst, MAKEINTRESOURCE(IDCUR_DROPTOOL)); hcurSizeNESW = LoadCursor(NULL, IDC_SIZENESW); hcurSizeNS = LoadCursor(NULL, IDC_SIZENS); hcurSizeNWSE = LoadCursor(NULL, IDC_SIZENWSE); hcurSizeWE = LoadCursor(NULL, IDC_SIZEWE); if (!hcurArrow || !hcurWait || !hcurOutSel || !hcurMove || !hcurDropTool || !hcurInsert) return FALSE; if ((hDC = GetDC(ghwndMain)) == NULL) return FALSE; GetTextMetrics(hDC, &tm); gcyPixelsPerInch = GetDeviceCaps(hDC, LOGPIXELSY); /* * Create a memory DC for drawing bitmaps. */ ghDCMem = CreateCompatibleDC(hDC); ReleaseDC(ghwndMain, hDC); /* * Load the bitmaps that depend on system colors. */ LoadSysColorBitmaps(); fmtDlg = RegisterClipboardFormat(L"DIALOG"); /* * Initialize the icon control ordinal to the icon id from our exe * that we will use to show these kind of controls. */ WriteOrd(&gordIcon, IDICON_ICON); /* * Initialize the default text fields in the awcd array. Because * CCONTROLS does not include the dialog type, it has to be done * separately. */ awcd[W_DIALOG].pszTextDefault = ids(awcd[W_DIALOG].idsTextDefault); for (i = 0; i < CCONTROLS; i++) awcd[i].pszTextDefault = ids(awcd[i].idsTextDefault); /* * If there was a command line argument specified, try and open * it as the initial file. */ if (__argc > 1) { MultiByteToWideChar(CP_ACP, 0, __argv[1], -1, szArg1, CCHTEXTMAX); OpenCmdLineFile(szArg1); } /* * Be sure the focus is on the main window. This corrects a * problem where the accelerators don't initially work because * the focus gets placed on the Properties Bar. */ SetFocus(ghwndMain); return TRUE; } /************************************************************************ * PenWinRegister * * This function will register for Pen Windows, if it is present. * ************************************************************************/ STATICFN VOID PenWinRegister(VOID) { HANDLE hmod; if (!(hmod = (HANDLE)GetSystemMetrics(SM_PENWINDOWS))) return; if (lpfnRegisterPenApp = (LPFNPENWIN)GetProcAddress(hmod, "RegisterPenApp")) (*lpfnRegisterPenApp)(1, TRUE); // Be Pen-Enhanced! } /************************************************************************ * GetSystemValues * * This function reads various system values. It is called at init time, * as well as if we are informed by a WM_SYSVALUECHANGED message that * some of these values have been changed. * ************************************************************************/ STATICFN VOID GetSystemValues(VOID) { gcyBorder = GetSystemMetrics(SM_CYBORDER); /* * The distance that the mouse can move during a pre-drag operation * before starting to drag the control anyways is based on the * mouse double-click movement distances in the system. */ gcxPreDragMax = GetSystemMetrics(SM_CXDOUBLECLK); gcyPreDragMax = GetSystemMetrics(SM_CYDOUBLECLK); /* * The number of milliseconds that the pre-drag debounce time lasts. */ gmsecPreDrag = 250; } /************************************************************************ * ReadWindowPos * * This function retrieves the saved window position for a window and * returns it in the specified variables. It is used between sessions * to restore the application windows to the position they had when * the editor was last exited. * * Returns TRUE if the position could be read, or FALSE otherwise. * If FALSE is returned, the values in the specified variables are * not valid! The caller must be able to handle a FALSE return and * supply a default position for the window. * * Arguments: * LPTSTR pszKeyName - KeyName the position was saved under. * PINT px - Saved x position. * PINT py - Saved y position. * PINT pcx - Saved width. * PINT pcy - Saved height. * BOOL *pfMaximized - Set to TRUE if window was maximized when saved. * * History: * ************************************************************************/ BOOL ReadWindowPos( LPTSTR pszKeyName, PINT px, PINT py, PINT pcx, PINT pcy, BOOL *pfMaximized) { static CHAR szSep[] = " ,"; TCHAR szBuf[CCHTEXTMAX]; CHAR szBufAnsi[CCHTEXTMAX]; PSTR psz; BOOL fDefCharUsed; if (!GetPrivateProfileString(ids(IDS_APPNAME), pszKeyName, szEmpty, szBuf, CCHTEXTMAX, ids(IDS_DLGEDITINI))) return FALSE; WideCharToMultiByte(CP_ACP, 0, szBuf, -1, szBufAnsi, CCHTEXTMAX, NULL, &fDefCharUsed); if (!(psz = strtok(szBufAnsi, szSep))) return FALSE; *px = atoi(psz); if (!(psz = strtok(NULL, szSep))) return FALSE; *py = atoi(psz); if (!(psz = strtok(NULL, szSep))) return FALSE; *pcx = atoi(psz); if (!(psz = strtok(NULL, szSep))) return FALSE; *pcy = atoi(psz); /* * If there is a "1" following the coordinates, the window was * maximized when it was saved. */ *pfMaximized = FALSE; if ((psz = strtok(NULL, szSep)) && atoi(psz) == 1) *pfMaximized = TRUE; /* * Don't allow a zero sized window. */ if (*pcx == 0 || *pcy == 0) return FALSE; /* * Return success. */ return TRUE; #if 0 static TCHAR szSep[] = L" ,"; TCHAR szBuf[CCHTEXTMAX]; LPTSTR psz; if (!GetPrivateProfileString(ids(IDS_APPNAME), pszKeyName, szEmpty, szBuf, CCHTEXTMAX, ids(IDS_DLGEDITINI))) return FALSE; if (!(psz = wcstok(szBuf, szSep))) return FALSE; *px = awtoi(psz); if (!(psz = wcstok(NULL, szSep))) return FALSE; *py = awtoi(psz); if (!(psz = wcstok(NULL, szSep))) return FALSE; *pcx = awtoi(psz); if (!(psz = wcstok(NULL, szSep))) return FALSE; *pcy = awtoi(psz); /* * If there is a "1" following the coordinates, the window was * maximized when it was saved. */ *pfMaximized = FALSE; if ((psz = wcstok(NULL, szSep)) && awtoi(psz) == 1) *pfMaximized = TRUE; /* * Don't allow a zero sized window. */ if (*pcx == 0 || *pcy == 0) return FALSE; /* * Return success. */ return TRUE; #endif //BUGBUG UNICODE } /************************************************************************ * WriteWindowPos * * This function writes the position of a window to the * editor's profile file under the specified keyname. * The ReadWindowPos function is the counterpart of this * function. * * Arguments: * PRECT prc - Rectangle for the "restored" window size. * BOOL fMaximized - TRUE if the window is maximized. * LPTSTR pszKeyName - KeyName to save the position under. * * History: * ************************************************************************/ VOID WriteWindowPos( PRECT prc, BOOL fMaximized, LPTSTR pszKeyName) { TCHAR szBuf[CCHTEXTMAX]; wsprintf(szBuf, L"%d %d %d %d", prc->left, prc->top, prc->right - prc->left, prc->bottom - prc->top); if (fMaximized) lstrcat(szBuf, L" 1"); WritePrivateProfileString(ids(IDS_APPNAME), pszKeyName, szBuf, ids(IDS_DLGEDITINI)); } /************************************************************************* * ReadEnv * * This function initializes variables from their counterparts * in the private profile file for DlgEdit. The application * merely needs to construct an array of INIENTRY structures * to describe the variables that must be initialized. * * Note that the original value read from the profile is saved when * it is read. This allows us to optimize what needs to be written * out with WriteEnv. * * History: * *************************************************************************/ STATICFN VOID ReadEnv(VOID) { register INT i; for (i = 0; gaie[i].pszKeyName; i++) { *gaie[i].pnVar = gaie[i].nSave = GetPrivateProfileInt(ids(IDS_APPNAME), gaie[i].pszKeyName, gaie[i].nDefault, ids(IDS_DLGEDITINI)); } ReadCustomProfile(); } /************************************************************************* * WriteEnv * * This function is the counterpart to ReadEnv. It saves values * in the profile file. * * History: * *************************************************************************/ STATICFN VOID WriteEnv(VOID) { register INT i; TCHAR szBuf[17]; for (i = 0; gaie[i].pszKeyName; i++) { /* * Has the user changed the value since it was read? */ if (gaie[i].nSave != *gaie[i].pnVar) { /* * If the new value is the same as the default value, * erase the entry from the ini file. Otherwise, * write the user-specified value out. */ if (*gaie[i].pnVar == gaie[i].nDefault) { WritePrivateProfileString(ids(IDS_APPNAME), gaie[i].pszKeyName, NULL, ids(IDS_DLGEDITINI)); } else { itoaw(*gaie[i].pnVar, szBuf, 10); WritePrivateProfileString(ids(IDS_APPNAME), gaie[i].pszKeyName, szBuf, ids(IDS_DLGEDITINI)); } } } WriteCustomProfile(); } /************************************************************************ * MainWndProc * * This is the window procedure for the "dlgedit" class. This is the * class of the main dialog editor "client" window. * ************************************************************************/ WINDOWPROC MainWndProc( HWND hwnd, UINT msg, WPARAM wParam, LONG lParam) { switch (msg) { case WM_CREATE: { RECT rc; /* * Create the status window. */ CreateDialog(ghInst, MAKEINTRESOURCE(DID_STATUS), hwnd, StatusDlgProc); /* * Save away its height for sizing later (like when * the app is minimized then restored). */ GetWindowRect(hwndStatus, &rc); gcyStatus = rc.bottom - rc.top; ghwndSubClient = CreateWindow(szSubClientClass, NULL, WS_CHILD | WS_VISIBLE, 0, 0, 0, 0, hwnd, NULL, ghInst, NULL); ghMenuMain = GetMenu(hwnd); LoadMenuBitmaps(ghMenuMain); } break; case WM_ACTIVATE: /* * If the main window is getting activated, there is no * currently active dialog. */ if (GET_WM_ACTIVATE_STATE(wParam, lParam)) gidCurrentDlg = 0; goto DoDefault; case WM_INITMENU: if (GetMenu(ghwndMain) == (HMENU)wParam) InitMenu((HMENU)wParam); break; case WM_MENUSELECT: if (GET_WM_MENUSELECT_FLAGS(wParam, lParam) & (MF_POPUP | MF_SYSMENU)) gMenuSelected = 0; else gMenuSelected = GET_WM_MENUSELECT_CMD(wParam, lParam); break; case WM_COMMAND: DialogMenu(GET_WM_COMMAND_ID(wParam, lParam)); break; case WM_KEYDOWN: switch (wParam) { case VK_UP: case VK_DOWN: case VK_LEFT: case VK_RIGHT: if ((GetKeyState(VK_SHIFT) & 0x8000) || (GetKeyState(VK_CONTROL) & 0x8000)) break; /* * Ignore it if we are not in a normal state * (don't allow when dragging). */ if (gState != STATE_NORMAL) break; /* * Be sure any outstanding changes get applied * without errors. */ if (!StatusApplyChanges()) break; /* * Move the control in the specified direction. */ MoveControl(wParam); break; case VK_TAB: if (GetKeyState(VK_CONTROL) & 0x8000) break; /* * Ignore it if we are not in a normal state * (don't allow when dragging). */ if (gState != STATE_NORMAL) break; /* * Be sure any outstanding changes get applied * without errors. */ if (!StatusApplyChanges()) break; /* * Is the shift key pressed also? */ if (GetKeyState(VK_SHIFT) & 0x8000) SelectPrevious(); else SelectNext(); break; case VK_ESCAPE: if ((GetKeyState(VK_SHIFT) & 0x8000) || (GetKeyState(VK_CONTROL) & 0x8000)) break; /* * Be sure any outstanding changes get applied * without errors. */ if (!StatusApplyChanges()) break; if (gState == STATE_SELECTING) OutlineSelectCancel(); /* * Cancel any drag operation they might have been doing. */ if (gState != STATE_NORMAL) DragCancel(); break; case VK_RETURN: if ((GetKeyState(VK_SHIFT) & 0x8000) || (GetKeyState(VK_CONTROL) & 0x8000)) break; /* * Be sure any outstanding changes get applied * without errors. */ if (!StatusApplyChanges()) break; switch (gState) { MPOINT mpt; POINT pt; DWORD dwPos; case STATE_SELECTING: /* * In outline selection mode. Map the * location of the mouse at the time that * the user pressed Enter into a point * relative to the dialog client and complete * the selection operation. */ dwPos = GetMessagePos(); mpt = MAKEMPOINT(dwPos); MPOINT2POINT(mpt, pt); ScreenToClient(gcd.npc->hwnd, &pt); OutlineSelectEnd(pt.x, pt.y); break; case STATE_DRAGGING: case STATE_DRAGGINGNEW: /* * We are dragging something. Map the * location of the mouse at the time * that the user pressed Enter into a * point relative to the proper window * and complete the drag operation. */ dwPos = GetMessagePos(); mpt = MAKEMPOINT(dwPos); MPOINT2POINT(mpt, pt); /* * The point must be changed to be relative to * the window that the ending mouse up message * would have come through, which will be the * capture window for the drag. This will be * the dialog if we are adding a new control, * or it will be the selected control if we are * dragging an existing control. */ ScreenToClient((gState == STATE_DRAGGING) ? gnpcSel->hwnd : gcd.npc->hwnd, &pt); /* * If the dialog is selected, map the points from * the client area to the window. */ if (gfDlgSelected) MapDlgClientPoint(&pt, TRUE); DragEnd(pt.x, pt.y); break; } break; } break; case WM_NCCALCSIZE: /* * Save away what is going to be the new window position. */ if (!IsIconic(hwnd) && !IsZoomed(hwnd)) grcAppPos = *((LPRECT)lParam); /* * Now let the DefWindowProc calculate the client area normally. */ goto DoDefault; case WM_MOVE: if (gfEditingDlg) RepositionDialog(); break; case WM_SIZE: SizeRibbons(hwnd); /* * Did the app start minimized and is it being restored * for the first time? If so, show the toolbox if * the user has requested it. */ if (fStartAsIcon && !IsIconic(hwnd)) { if (gfShowToolbox) ToolboxShow(TRUE); fStartAsIcon = FALSE; } break; case WM_SYSCOLORCHANGE: LoadSysColorBitmaps(); break; case WM_CLOSE: if (ghwndTestDlg) DestroyTestDialog(); if (DoWeSave(FILE_INCLUDE) == IDCANCEL || DoWeSave(FILE_RESOURCE) == IDCANCEL) break; /* * First destroy the Properties Bar. */ DestroyWindow(hwndStatus); hwndStatus = NULL; DestroyWindow(hwnd); break; case WM_QUERYENDSESSION: if (ghwndTestDlg) DestroyTestDialog(); if (DoWeSave(FILE_INCLUDE) == IDCANCEL || DoWeSave(FILE_RESOURCE) == IDCANCEL) return FALSE; else return TRUE; case WM_DESTROY: /* * Save the position of the app's window. */ WriteWindowPos(&grcAppPos, IsZoomed(hwnd), szAppPos); WinHelp(hwnd, gszHelpFile, HELP_QUIT, 0L); FreeMenuBitmaps(); PostQuitMessage(0); break; default: /* * Is this the registered help message from one of the common * dialogs? If so, show the help for it. * * The check to be sure gmsgHelp is non-zero is just in * case the call to register the help message failed * (it will return zero) and there happens to be a zero * message that gets sent to this window somehow. */ if (msg == gmsgHelp && gmsgHelp) { ShowHelp(FALSE); return 0; } DoDefault: return DefWindowProc(hwnd, msg, wParam, lParam); } return 0; } /************************************************************************ * LoadSysColorBitmaps * * This function loads bitmaps that depend on the system window and * highlight colors. As it loads them, it replaces two special colors * in them with some system colors. * * This is used for the control type bitmaps that appear in lines * in the listbox in the Order/Group dialog. * * History: * ************************************************************************/ STATICFN VOID LoadSysColorBitmaps(VOID) { DWORD rgbWindow; DWORD rgbWindowText; DWORD rgbHighlight; DWORD rgbHighlightText; INT i; rgbWindow = GetSysColor(COLOR_WINDOW); rgbWindowText = GetSysColor(COLOR_WINDOWTEXT); rgbHighlight = GetSysColor(COLOR_HIGHLIGHT); rgbHighlightText = GetSysColor(COLOR_HIGHLIGHTTEXT); if (hbmTabStop) DeleteObject(hbmTabStop); hbmTabStop = LoadAlterBitmap(IDBM_TABSTOP, rgbWindow, rgbWindowText); if (hbmTabStopSel) DeleteObject(hbmTabStopSel); hbmTabStopSel = LoadAlterBitmap(IDBM_TABSTOP, rgbHighlight, rgbHighlightText); for (i = 0; i < CCONTROLS; i++) { if (awcd[i].hbmCtrlType) DeleteObject(awcd[i].hbmCtrlType); awcd[i].hbmCtrlType = LoadAlterBitmap( awcd[i].idbmCtrlType, rgbWindow, rgbWindowText); if (awcd[i].hbmCtrlTypeSel) DeleteObject(awcd[i].hbmCtrlTypeSel); awcd[i].hbmCtrlTypeSel = LoadAlterBitmap( awcd[i].idbmCtrlType, rgbHighlight, rgbHighlightText); } if (ghbmDragHandle) DeleteObject(ghbmDragHandle); ghbmDragHandle = LoadAlterBitmap(IDBM_DRAGHANDLE, rgbWindow, rgbHighlight); if (ghbmDragHandle2) DeleteObject(ghbmDragHandle2); ghbmDragHandle2 = LoadAlterBitmap(IDBM_DRAGHANDLE2, rgbWindow, rgbHighlight); } /************************************************************************ * LoadAlterBitmap * * This function loads a single bitmap. As it does, it replaces a * couple special RGB colors (REPLACECOLOR1 and REPLACECOLOR2) with * the passed in RGB colors. * * It returns a handle to the bitmap, or NULL if an error occurs. * * Arguments: * INT idbm - Integer ID of the bitmap to load. * DWORD rgbNew - Color to replace the special color with. * DWORD rgbNew2 - A second color to replace the second special color with. * * History: * ************************************************************************/ STATICFN HBITMAP LoadAlterBitmap( INT idbm, DWORD rgbNew, DWORD rgbNew2) { register INT i; LPBITMAPINFOHEADER lpbihInfo; HDC hdcScreen; HANDLE hresLoad; DWORD FAR *qlng; LPBYTE lpbBits; HANDLE hbmp; DWORD rgbReplace1; DWORD rgbReplace2; hresLoad = FindResource(ghInst, MAKEINTRESOURCE(idbm), RT_BITMAP); if (!hresLoad) return NULL; lpbihInfo = (LPBITMAPINFOHEADER)CloneResource(ghInst, hresLoad); if (lpbihInfo == NULL) return NULL; rgbNew = RGBInvertRGB(rgbNew); rgbNew2 = RGBInvertRGB(rgbNew2); rgbReplace1 = RGBInvertRGB(REPLACECOLOR1); rgbReplace2 = RGBInvertRGB(REPLACECOLOR2); qlng = (LPDWORD)((PBYTE)(lpbihInfo) + lpbihInfo->biSize); for (i = 0; i < (1 << lpbihInfo->biBitCount); i++, qlng++) { if (*qlng == rgbReplace1) *qlng = rgbNew; else if (*qlng == rgbReplace2) *qlng = rgbNew2; } /* * First skip over the header structure. */ lpbBits = (LPBYTE)(lpbihInfo + 1); /* * Skip the color table entries, if any. */ lpbBits += (1 << (lpbihInfo->biBitCount)) * sizeof(RGBQUAD); /* * Create a color bitmap compatible with the display device. */ if (hdcScreen = GetDC(NULL)) { hbmp = CreateDIBitmap(hdcScreen, lpbihInfo, (LONG)CBM_INIT, lpbBits, (LPBITMAPINFO)lpbihInfo, DIB_RGB_COLORS); ReleaseDC(NULL, hdcScreen); } LocalFree(lpbihInfo); return hbmp; } /************************************************************************ * CloneResource * * Make a duplicate of a resource that can be edited in place. The * handle returned must be freed with LocalFree when done with the copy * of the resource. * * History: * 22-Jun-1993 JonPa Created it. * ************************************************************************/ PVOID CloneResource(HINSTANCE hinst, HRSRC hres) { DWORD cb; PVOID pvData, pvRes; HGLOBAL hglb; cb = SizeofResource(hinst, hres); if (cb == 0) return NULL; pvData = LocalAlloc(LPTR, cb); if (pvData != NULL) { hglb = LoadResource(hinst, hres); if (!hglb) { LocalFree(pvData); return NULL; } pvRes = LockResource(hglb); if (!pvRes) { LocalFree(pvData); return NULL; } CopyMemory(pvData, pvRes, cb); } /* * Note: in NT, it is not necessary to unlock or unload resources. */ return pvData; } /************************************************************************ * RGBInvertRGB * * Reverses the RGB order of a color. This needs to be done to match * the resource file format of the color table. * * * History: * ************************************************************************/ STATICFN DWORD RGBInvertRGB( DWORD rgb) { return (DWORD)RGB(GetBValue(rgb), GetGValue(rgb), GetRValue(rgb)); } /************************************************************************ * SizeRibbons * * This function positions and sizes the child ribbon and subclient * windows in the dialog editor. It needs to be called any time the * size of the main windows changes. * * Arguments: * HWND hwnd - Parent window handle. * * History: * ************************************************************************/ STATICFN VOID SizeRibbons( HWND hwnd) { RECT rcClient; if (hwndStatus && !IsIconic(hwnd)) { /* * Get the client area. */ GetClientRect(hwnd, &rcClient); /* * Size/move the status and subclient window to fit * the new client area. */ SetWindowPos(hwndStatus, NULL, 0, 0, rcClient.right - rcClient.left, min(rcClient.bottom - rcClient.top, gcyStatus), SWP_NOACTIVATE | SWP_NOZORDER); SetWindowPos(ghwndSubClient, NULL, 0, gcyStatus, rcClient.right - rcClient.left, max((rcClient.bottom - rcClient.top) - gcyStatus, 0), SWP_NOACTIVATE | SWP_NOZORDER); } } /**************************************************************************** * DialogTerminate * * This undoes what DialogInit does. It should be called before terminating * and after a DialogInit. * * History: * ****************************************************************************/ STATICFN VOID DialogTerminate(VOID) { register INT i; /* * Save the Preferences data. */ WriteEnv(); if (hbmTabStop) DeleteObject(hbmTabStop); if (hbmTabStopSel) DeleteObject(hbmTabStopSel); if (ghbmDragHandle) DeleteObject(ghbmDragHandle); if (ghbmDragHandle2) DeleteObject(ghbmDragHandle2); if (ghDCMem) DeleteDC(ghDCMem); /* * Free the control type bitmaps. */ for (i = 0; i < CCONTROLS; i++) { if (awcd[i].hbmCtrlType) DeleteObject(awcd[i].hbmCtrlType); if (awcd[i].hbmCtrlTypeSel) DeleteObject(awcd[i].hbmCtrlTypeSel); } /* * Free all the custom control links. This must be done before the * app exits so that any loaded DLL's get unloaded! */ while (gpclHead) RemoveCustomLink(gpclHead); if (hpenDarkGray) DeleteObject(hpenDarkGray); if (ghhkMsgFilter) UnhookWindowsHookEx(ghhkMsgFilter); if (lpfnRegisterPenApp) (*lpfnRegisterPenApp)((WORD)1, FALSE); }