//--------------------------------------------------------------------------- // // Copyright (c) Microsoft Corporation 1993-1995 // // File: ring.c // // This files contains the dialog code for the Voice settings // property pages. // // History: // 07-05-95 ScottH Created // //--------------------------------------------------------------------------- #include "proj.h" // common headers #if defined(WIN95) && defined(CS_HELP) #include "..\..\..\..\win\core\inc\help.h" #endif #define CX_PATTERN 40 #define CY_PATTERN 5 typedef struct tagRING { HWND hdlg; // dialog handle LPMODEMINFO pmi; // modeminfo struct passed into dialog HBITMAP hbmStrip; HDC hdcStrip; HFONT hfont; int cyText; } RING, FAR * PRING; typedef struct tagRINGPAT { DWORD dwPattern; LPARAM lParam; } RINGPAT, FAR * PRINGPAT; static RINGPAT s_rgrp[] = { { DRP_NONE, 0 }, { DRP_SHORT, 0 }, { DRP_LONG, 0 }, { DRP_SHORTSHORT, 0 }, { DRP_SHORTLONG, 0 }, { DRP_LONGSHORT, 0 }, { DRP_LONGLONG, 0 }, { DRP_SHORTSHORTLONG, 0 }, { DRP_SHORTLONGSHORT, 0 }, { DRP_LONGSHORTSHORT, 0 }, { DRP_LONGSHORTLONG, 0 }, }; #pragma data_seg(DATASEG_READONLY) const static UINT c_rgidcPattern[] = { IDC_ADDR_PRI, IDC_ADDR1, IDC_ADDR2, IDC_ADDR3, IDC_PRI_CALLERS, IDC_CALLBACK, }; const static UINT c_rgidcTypeOfCalls[] = { IDC_TYPE_ADDR_PRI, IDC_TYPE_ADDR1, IDC_TYPE_ADDR2, IDC_TYPE_ADDR3, IDC_TYPE_PRI_CALLERS, IDC_TYPE_CALLBACK, }; static DWORD c_rgdwCheapPatterns[] = { DRP_SINGLE, DRP_DOUBLE, DRP_TRIPLE, }; const static UINT c_rgidcTypeOfCheapCalls[] = { IDC_TYPE_RING1, IDC_TYPE_RING2, IDC_TYPE_RING3, }; TCHAR const FAR c_szUnimdmHelpFile[] = TEXT("unimdm.hlp"); #pragma data_seg() #define Ring_GetPtr(hwnd) (PRING)GetWindowLong(hwnd, DWL_USER) #define Ring_SetPtr(hwnd, lp) (PRING)SetWindowLong(hwnd, DWL_USER, (LONG)(lp)) //----------------------------------------------------------------------------------- // Voice settings dialog code //----------------------------------------------------------------------------------- /*---------------------------------------------------------- Purpose: Initialize the bitmap strip Returns: -- Cond: -- */ void PRIVATE Ring_InitStrip( PRING this, HDC hdc) { ASSERT(hdc); this->hbmStrip = LoadBitmap(g_hinst, MAKEINTRESOURCE(IDB_PATTERNS)); ASSERT(this->hbmStrip); this->hdcStrip = CreateCompatibleDC(hdc); if (this->hdcStrip) { SelectObject(this->hdcStrip, this->hbmStrip); } } /*---------------------------------------------------------- Purpose: Initialize the specified Pattern combobox. Returns: -- Cond: -- */ void PRIVATE Ring_InitPattern( PRING this, HWND hwndCB, DWORD dwPattern) { int i; int iSel = 0; int n; // Fill the listbox for (i = 0; i < ARRAY_ELEMENTS(s_rgrp); i++) { n = ComboBox_AddString(hwndCB, &s_rgrp[i]); // Keep our eyes peeled for the selected type if (dwPattern == s_rgrp[i].dwPattern) { iSel = n; } } ComboBox_SetCurSel(hwndCB, iSel); } /*---------------------------------------------------------- Purpose: Initialize the specified Type of Call combobox. Returns: -- Cond: -- */ void PRIVATE Ring_InitTypeOfCall( PRING this, HWND hwndCB, DWORD dwType) { #pragma data_seg(DATASEG_READONLY) static const struct { UINT ids; DWORD dwType; // DRT_* } s_rgTypes[] = { { IDS_UNSPECIFIED, DRT_UNSPECIFIED }, { IDS_DATA, DRT_DATA }, { IDS_FAX, DRT_FAX }, { IDS_VOICE, DRT_VOICE }, }; #pragma data_seg() int i; int iSel = 0; int n; TCHAR sz[MAXMEDLEN]; // Fill the listbox for (i = 0; i < ARRAY_ELEMENTS(s_rgTypes); i++) { n = ComboBox_AddString(hwndCB, SzFromIDS(g_hinst, s_rgTypes[i].ids, sz, SIZECHARS(sz))); ComboBox_SetItemData(hwndCB, n, s_rgTypes[i].dwType); // Keep our eyes peeled for the selected type if (dwType == s_rgTypes[i].dwType) { iSel = n; } } ComboBox_SetCurSel(hwndCB, iSel); } /*---------------------------------------------------------- Purpose: Enable/disable all the controls Returns: -- Cond: -- */ void PRIVATE Ring_EnableControls( PRING this, BOOL bEnable) { HWND hwnd = this->hdlg; EnableWindow(GetDlgItem(hwnd, IDC_LBL_ADDR_PRI), bEnable); EnableWindow(GetDlgItem(hwnd, IDC_ADDR_PRI), bEnable); EnableWindow(GetDlgItem(hwnd, IDC_TYPE_ADDR_PRI), bEnable); EnableWindow(GetDlgItem(hwnd, IDC_LBL_ADDR1), bEnable); EnableWindow(GetDlgItem(hwnd, IDC_ADDR1), bEnable); EnableWindow(GetDlgItem(hwnd, IDC_TYPE_ADDR1), bEnable); EnableWindow(GetDlgItem(hwnd, IDC_LBL_ADDR2), bEnable); EnableWindow(GetDlgItem(hwnd, IDC_ADDR2), bEnable); EnableWindow(GetDlgItem(hwnd, IDC_TYPE_ADDR2), bEnable); EnableWindow(GetDlgItem(hwnd, IDC_LBL_ADDR3), bEnable); EnableWindow(GetDlgItem(hwnd, IDC_ADDR3), bEnable); EnableWindow(GetDlgItem(hwnd, IDC_TYPE_ADDR3), bEnable); EnableWindow(GetDlgItem(hwnd, IDC_LBL_PRI_CALLERS), bEnable); EnableWindow(GetDlgItem(hwnd, IDC_PRI_CALLERS), bEnable); EnableWindow(GetDlgItem(hwnd, IDC_TYPE_PRI_CALLERS), bEnable); EnableWindow(GetDlgItem(hwnd, IDC_LBL_CALLBACK), bEnable); EnableWindow(GetDlgItem(hwnd, IDC_CALLBACK), bEnable); EnableWindow(GetDlgItem(hwnd, IDC_TYPE_CALLBACK), bEnable); } /*---------------------------------------------------------- Purpose: WM_INITDIALOG Handler Returns: FALSE when we assign the control focus Cond: -- */ BOOL PRIVATE Ring_OnInitDialog( PRING this, HWND hwndFocus, LPARAM lParam) // expected to be PROPSHEETINFO { LPPROPSHEETPAGE lppsp = (LPPROPSHEETPAGE)lParam; HWND hwnd = this->hdlg; HWND hwndCtl; LPDWORD lpdw; BOOL bEnable; int i; PVOICEFEATURES pvs; HDC hdc; LOGFONT lf; ASSERT((LPTSTR)lppsp->lParam); this->pmi = (LPMODEMINFO)lppsp->lParam; pvs = &this->pmi->pglobal->vs; // Determine some font things SystemParametersInfo(SPI_GETICONTITLELOGFONT, sizeof(lf), &lf, FALSE); this->hfont = CreateFontIndirect(&lf); // Create bitmap strip hdc = GetDC(hwnd); if (hdc) { Ring_InitStrip(this, hdc); ReleaseDC(hwnd, hdc); } // Enable/disable controls bEnable = IsFlagSet(this->pmi->pglobal->vs.dwFlags, VSF_DIST_RING); Button_SetCheck(GetDlgItem(hwnd, IDC_RING_CHECK), bEnable); Ring_EnableControls(this, bEnable); // Initialize controls for (i = 0; i < ARRAY_ELEMENTS(c_rgidcPattern); i++) { hwndCtl = GetDlgItem(hwnd, c_rgidcPattern[i]); lpdw = &pvs->DistRing[i].dwPattern; Ring_InitPattern(this, hwndCtl, *lpdw); } for (i = 0; i < ARRAY_ELEMENTS(c_rgidcTypeOfCalls); i++) { hwndCtl = GetDlgItem(hwnd, c_rgidcTypeOfCalls[i]); lpdw = &pvs->DistRing[i].dwMediaType; Ring_InitTypeOfCall(this, hwndCtl, *lpdw); } return TRUE; // default initial focus } /*---------------------------------------------------------- Purpose: WM_COMMAND Handler Returns: -- Cond: -- */ void PRIVATE Ring_OnCommand( PRING this, int id, HWND hwndCtl, UINT uNotifyCode) { BOOL bCheck; switch (id) { case IDC_RING_CHECK: bCheck = Button_GetCheck(hwndCtl); Ring_EnableControls(this, bCheck); break; default: break; } } /*---------------------------------------------------------- Purpose: Validate the user's settings. The ring patterns must be unique, except that any/all may be set to DRP_NONE. Returns: TRUE if valid Cond: -- */ BOOL PRIVATE Ring_ValidateSettings( PRING this) { HWND hwnd = this->hdlg; int i; int iSel; HWND hwndCtl; PRINGPAT prp; for (i = 0; i < ARRAY_ELEMENTS(s_rgrp); i++) { // Initialize lParam to 0 s_rgrp[i].lParam = 0; } // Get the ring pattern settings for (i = 0; i < ARRAY_ELEMENTS(c_rgidcPattern); i++) { hwndCtl = GetDlgItem(hwnd, c_rgidcPattern[i]); iSel = ComboBox_GetCurSel(hwndCtl); ASSERT(LB_ERR != iSel); ComboBox_GetLBText(hwndCtl, iSel, &prp); // Is this pattern already selected, // and is it something other than none? if (DRP_NONE != prp->dwPattern && prp->lParam) { // Yes; can't have duplicate values MsgBox(g_hinst, hwnd, MAKEINTRESOURCE(IDS_ERR_DUP_PATTERN), MAKEINTRESOURCE(IDS_CAP_RING), NULL, MB_ERROR); // Set the focus on the offending control PostMessage(hwnd, WM_NEXTDLGCTL, (WPARAM)hwndCtl, (LPARAM)TRUE); return FALSE; } prp->lParam = TRUE; } return TRUE; } /*---------------------------------------------------------- Purpose: PSN_APPLY handler Returns: TRUE if validation succeeded FALSE if not Cond: -- */ BOOL PRIVATE Ring_OnApply( PRING this) { BOOL bRet; HWND hwnd = this->hdlg; HWND hwndCtl; LPDWORD lpdw; int i; int iSel; PVOICEFEATURES pvs = &this->pmi->pglobal->vs; PRINGPAT prp; bRet = Ring_ValidateSettings(this); // Are the user's settings valid? if (bRet) { // Yes if (Button_GetCheck(GetDlgItem(hwnd, IDC_RING_CHECK))) { SetFlag(pvs->dwFlags, VSF_DIST_RING); } else { ClearFlag(pvs->dwFlags, VSF_DIST_RING); } // Get the ring pattern settings for (i = 0; i < ARRAY_ELEMENTS(c_rgidcPattern); i++) { hwndCtl = GetDlgItem(hwnd, c_rgidcPattern[i]); lpdw = &pvs->DistRing[i].dwPattern; iSel = ComboBox_GetCurSel(hwndCtl); ASSERT(LB_ERR != iSel); ComboBox_GetLBText(hwndCtl, iSel, &prp); *lpdw = prp->dwPattern; } // Get the type of call settings for (i = 0; i < ARRAY_ELEMENTS(c_rgidcTypeOfCalls); i++) { hwndCtl = GetDlgItem(hwnd, c_rgidcTypeOfCalls[i]); lpdw = &pvs->DistRing[i].dwMediaType; iSel = ComboBox_GetCurSel(hwndCtl); ASSERT(LB_ERR != iSel); *lpdw = ComboBox_GetItemData(hwndCtl, iSel); } } return bRet; } /*---------------------------------------------------------- Purpose: WM_NOTIFY handler Returns: varies Cond: -- */ LRESULT PRIVATE Ring_OnNotify( PRING this, int idFrom, NMHDR FAR * lpnmhdr) { LRESULT lRet = 0; switch (lpnmhdr->code) { case PSN_SETACTIVE: break; case PSN_KILLACTIVE: // N.b. This message is not sent if user clicks Cancel! // N.b. This message is sent prior to PSN_APPLY // break; case PSN_APPLY: lRet = Ring_OnApply(this) ? PSNRET_NOERROR : PSNRET_INVALID; break; default: break; } return lRet; } /*---------------------------------------------------------- Purpose: WM_DESTROY handler Returns: -- Cond: -- */ void PRIVATE Ring_OnDestroy( PRING this) { if (this->hdcStrip) DeleteDC(this->hdcStrip); if (this->hbmStrip) DeleteObject(this->hbmStrip); if (this->hfont) DeleteFont(this->hfont); } /*---------------------------------------------------------- Purpose: WM_MEASUREITEM handler Returns: -- Cond: !!! WM_MEASUREITEM is received before WM_INITDIALOG !!! The contents of 'this' will be uninitialized. */ void PRIVATE Ring_OnMeasureItem( PRING this, LPMEASUREITEMSTRUCT lpmis) { HWND hwnd = this->hdlg; HDC hdc; ASSERT(ODT_COMBOBOX == lpmis->CtlType); hdc = GetDC(hwnd); if (hdc) { TEXTMETRIC tm; GetTextMetrics(hdc, &tm); lpmis->itemHeight = max(tm.tmHeight, CY_PATTERN); ReleaseDC(hwnd, hdc); } } /*---------------------------------------------------------- Purpose: WM_DRAWITEM handler Returns: -- Cond: -- */ void PRIVATE Ring_OnDrawCBItem( PRING this, const DRAWITEMSTRUCT FAR * lpcdis) { HWND hwnd = this->hdlg; PRINGPAT prp = (PRINGPAT)lpcdis->itemData; ASSERT(ODT_COMBOBOX == lpcdis->CtlType); ASSERT(prp); if (prp) { HDC hdc = lpcdis->hDC; RECT rc = lpcdis->rcItem; RECT rcFrame; POINT ptSav; int x; int y; int nBkMode; COLORREF crText; COLORREF crBk; COLORREF crTextSav; COLORREF crBkSav; ASSERT(hdc); SetViewportOrgEx(hdc, rc.left, rc.top, &ptSav); rcFrame.top = 0; rcFrame.left = 0; rcFrame.bottom = rc.bottom - rc.top; rcFrame.right = rc.right - rc.left; // Set the colors nBkMode = SetBkMode(hdc, TRANSPARENT); TextAndBkCr(lpcdis, &crText, &crBk); crTextSav = SetTextColor(hdc, crText); crBkSav = SetBkColor(hdc, crBk); // Do we need to redraw everything? if (IsFlagSet(lpcdis->itemAction, ODA_DRAWENTIRE) || IsFlagSet(lpcdis->itemAction, ODA_SELECT)) { // Yes TCHAR sz[MAXSHORTLEN]; LPTSTR psz = sz; int cch; HFONT hfontSav; // Show bitmap or text? if (DRP_NONE == prp->dwPattern) { // Text hfontSav = SelectFont(hdc, this->hfont); SzFromIDS(g_hinst, IDS_AUTOMATIC, sz, SIZECHARS(sz)); cch = lstrlen(sz); } else { // Bitmap hfontSav = NULL; *psz = 0; cch = 0; } ASSERT(rc.right - rc.left >= CX_PATTERN); ASSERT(rc.bottom - rc.top >= CY_PATTERN); x = (rc.right - rc.left - CX_PATTERN) / 2; y = (rc.bottom - rc.top - CY_PATTERN) / 2; // Fill background (with optional text) ExtTextOut(hdc, 2, 2, ETO_OPAQUE, &rcFrame, psz, cch, NULL); if (DRP_NONE != prp->dwPattern) { // Draw bitmap BitBlt(hdc, x, y, CX_PATTERN, CY_PATTERN, this->hdcStrip, ((int)prp->dwPattern - 1) * CX_PATTERN, 0, SRCCOPY); } if (hfontSav) SelectFont(hdc, hfontSav); } // Draw the caret? if (IsFlagSet(lpcdis->itemAction, ODA_FOCUS) || IsFlagSet(lpcdis->itemState, ODS_FOCUS)) { // Yes DrawFocusRect(hdc, &rcFrame); } // Clean up SetTextColor(hdc, crTextSav); SetBkColor(hdc, crBkSav); SetBkMode(hdc, nBkMode); SetViewportOrgEx(hdc, ptSav.x, ptSav.y, NULL); } } /*---------------------------------------------------------- Purpose: WM_DRAWITEM handler Returns: -- Cond: -- */ void PRIVATE Ring_OnDrawStaticItem( PRING this, const DRAWITEMSTRUCT FAR * lpcdis) { HWND hwnd = this->hdlg; HDC hdc = lpcdis->hDC; RECT rc = lpcdis->rcItem; int x; int y; int nBkMode; COLORREF crText; COLORREF crBk; COLORREF crTextSav; COLORREF crBkSav; ASSERT(ODT_STATIC == lpcdis->CtlType); ASSERT(hdc); // Set the colors nBkMode = SetBkMode(hdc, TRANSPARENT); TextAndBkCr(lpcdis, &crText, &crBk); crTextSav = SetTextColor(hdc, crText); crBkSav = SetBkColor(hdc, crBk); ASSERT(rc.right - rc.left >= CX_PATTERN); ASSERT(rc.bottom - rc.top >= CY_PATTERN); x = (rc.right - rc.left - CX_PATTERN) / 2; y = (rc.bottom - rc.top - CY_PATTERN) / 2; // Fill background (with optional text) ExtTextOut(hdc, 0, 0, ETO_OPAQUE, &rc, TEXT(""), 0, NULL); // Draw bitmap BitBlt(hdc, x, y, CX_PATTERN, CY_PATTERN, this->hdcStrip, (int)(DRP_LONG - 1) * CX_PATTERN, 0, SRCCOPY); // Clean up SetTextColor(hdc, crTextSav); SetBkColor(hdc, crBkSav); SetBkMode(hdc, nBkMode); } /*---------------------------------------------------------- Purpose: WM_DRAWITEM handler Returns: -- Cond: -- */ void PRIVATE Ring_OnDrawItem( PRING this, const DRAWITEMSTRUCT FAR * lpcdis) { switch (lpcdis->CtlType) { case ODT_COMBOBOX: Ring_OnDrawCBItem(this, lpcdis); break; case ODT_STATIC: Ring_OnDrawStaticItem(this, lpcdis); break; default: ASSERT(0); break; } } /*---------------------------------------------------------- Purpose: WM_DELETEITEM handler Returns: -- Cond: !!! WM_DELETEITEM is received after WM_DESTROY !!! */ void Ring_OnDeleteItem( PRING this, const DELETEITEMSTRUCT FAR * lpcdis) { PRINGPAT prp = (PRINGPAT)lpcdis->itemData; ASSERT(NULL == this); // this will be NULL ASSERT(ODT_COMBOBOX == lpcdis->CtlType); ASSERT(prp); } static BOOL s_bRingRecurse = FALSE; LRESULT INLINE Ring_DefProc( HWND hDlg, UINT msg, WPARAM wParam, LPARAM lParam) { ENTER_X() { s_bRingRecurse = TRUE; } LEAVE_X() return DefDlgProc(hDlg, msg, wParam, lParam); } /*---------------------------------------------------------- Purpose: Real dialog proc Returns: varies Cond: -- */ LRESULT Ring_DlgProc( PRING this, UINT message, WPARAM wParam, LPARAM lParam) { #ifdef CS_HELP // UE used the control IDs as help IDs. To prevent mix-ups in // the future (ie, when the control IDs change), here are the // help IDs. #define IDH_UNI_RING_SERVICES 1069 #define IDH_UNI_RING_LBL_ADDR_PRI 1070 #define IDH_UNI_RING_ADDR_PRI 1073 #define IDH_UNI_RING_TYPE_ADDR_PRI 1082 #define IDH_UNI_RING_LBL_ADDR1 1071 #define IDH_UNI_RING_ADDR1 1074 #define IDH_UNI_RING_TYPE_ADDR1 1083 #define IDH_UNI_RING_LBL_ADDR2 1072 #define IDH_UNI_RING_ADDR2 1075 #define IDH_UNI_RING_TYPE_ADDR2 1084 #define IDH_UNI_RING_LBL_ADDR3 1076 #define IDH_UNI_RING_ADDR3 1077 #define IDH_UNI_RING_TYPE_ADDR3 1085 #define IDH_UNI_RING_LBL_PRI_CALLERS 1078 #define IDH_UNI_RING_PRI_CALLERS 1079 #define IDH_UNI_RING_TYPE_PRI_CALLERS 1086 #define IDH_UNI_RING_LBL_CALLBACK 1080 #define IDH_UNI_RING_CALLBACK 1081 #define IDH_UNI_RING_TYPE_CALLBACK 1087 #pragma data_seg(DATASEG_READONLY) const static DWORD rgHelpIDs[] = { IDC_RING_CHECK, IDH_UNI_RING_SERVICES, IDC_LBL_ADDR_PRI, IDH_UNI_RING_LBL_ADDR_PRI, IDC_ADDR_PRI, IDH_UNI_RING_ADDR_PRI, IDC_TYPE_ADDR_PRI, IDH_UNI_RING_TYPE_ADDR_PRI, IDC_LBL_ADDR1, IDH_UNI_RING_LBL_ADDR1, IDC_ADDR1, IDH_UNI_RING_ADDR1, IDC_TYPE_ADDR1, IDH_UNI_RING_TYPE_ADDR1, IDC_LBL_ADDR2, IDH_UNI_RING_LBL_ADDR2, IDC_ADDR2, IDH_UNI_RING_ADDR2, IDC_TYPE_ADDR2, IDH_UNI_RING_TYPE_ADDR2, IDC_LBL_ADDR3, IDH_UNI_RING_LBL_ADDR3, IDC_ADDR3, IDH_UNI_RING_ADDR3, IDC_TYPE_ADDR3, IDH_UNI_RING_TYPE_ADDR3, IDC_LBL_PRI_CALLERS, IDH_UNI_RING_LBL_PRI_CALLERS, IDC_PRI_CALLERS, IDH_UNI_RING_PRI_CALLERS, IDC_TYPE_PRI_CALLERS, IDH_UNI_RING_TYPE_PRI_CALLERS, IDC_LBL_CALLBACK, IDH_UNI_RING_LBL_CALLBACK, IDC_CALLBACK, IDH_UNI_RING_CALLBACK, IDC_TYPE_CALLBACK, IDH_UNI_RING_TYPE_CALLBACK, 0, 0 }; #pragma data_seg() #endif switch (message) { HANDLE_MSG(this, WM_INITDIALOG, Ring_OnInitDialog); HANDLE_MSG(this, WM_COMMAND, Ring_OnCommand); HANDLE_MSG(this, WM_NOTIFY, Ring_OnNotify); HANDLE_MSG(this, WM_DESTROY, Ring_OnDestroy); HANDLE_MSG(this, WM_MEASUREITEM, Ring_OnMeasureItem); HANDLE_MSG(this, WM_DRAWITEM, Ring_OnDrawItem); HANDLE_MSG(this, WM_DELETEITEM, Ring_OnDeleteItem); #ifdef CS_HELP case WM_HELP: WinHelp(((LPHELPINFO)lParam)->hItemHandle, c_szUnimdmHelpFile, HELP_WM_HELP, (DWORD)(LPVOID)rgHelpIDs); return 0; case WM_CONTEXTMENU: WinHelp((HWND)wParam, c_szUnimdmHelpFile, HELP_CONTEXTMENU, (DWORD)(LPVOID)rgHelpIDs); return 0; #endif default: return Ring_DefProc(this->hdlg, message, wParam, lParam); } } /*---------------------------------------------------------- Purpose: Dialog Wrapper Returns: varies Cond: -- */ BOOL CALLBACK Ring_WrapperProc( HWND hDlg, // std params UINT message, WPARAM wParam, LPARAM lParam) { PRING this; // Cool windowsx.h dialog technique. For full explanation, see // WINDOWSX.TXT. This supports multiple-instancing of dialogs. // ENTER_X() { if (s_bRingRecurse) { s_bRingRecurse = FALSE; LEAVE_X() return FALSE; } } LEAVE_X() this = Ring_GetPtr(hDlg); if (this == NULL) { // (WM_SETFONT is the first message received by dialogs) if (WM_SETFONT == message) { this = (PRING)LocalAlloc(LPTR, sizeof(RING)); if (!this) { MsgBox(g_hinst, hDlg, MAKEINTRESOURCE(IDS_OOM_SETTINGS), MAKEINTRESOURCE(IDS_CAP_RING), NULL, MB_ERROR); EndDialog(hDlg, IDCANCEL); return (BOOL)Ring_DefProc(hDlg, message, wParam, lParam); } this->hdlg = hDlg; Ring_SetPtr(hDlg, this); } else { return (BOOL)Ring_DefProc(hDlg, message, wParam, lParam); } } if (message == WM_DESTROY) { Ring_DlgProc(this, message, wParam, lParam); LocalFree((HLOCAL)OFFSETOF(this)); Ring_SetPtr(hDlg, NULL); return 0; } return SetDlgMsgResult(hDlg, message, Ring_DlgProc(this, message, wParam, lParam)); } //----------------------------------------------------------------------------------- // Cheap ring dialog code //----------------------------------------------------------------------------------- #define CheapRing_GetPtr(hwnd) (PRING)GetWindowLong(hwnd, DWL_USER) #define CheapRing_SetPtr(hwnd, lp) (PRING)SetWindowLong(hwnd, DWL_USER, (LONG)(lp)) /*---------------------------------------------------------- Purpose: Initialize the specified Type of Call combobox. Returns: -- Cond: -- */ void PRIVATE CheapRing_InitTypeOfCall( PRING this, HWND hwndCB, DWORD dwType) { #pragma data_seg(DATASEG_READONLY) static const struct { UINT ids; DWORD dwType; // DRT_* } s_rgTypes[] = { { IDS_UNSPECIFIED, DRT_UNSPECIFIED }, { IDS_DATA, DRT_DATA }, { IDS_FAX, DRT_FAX }, { IDS_VOICE, DRT_VOICE }, }; #pragma data_seg() int i; int iSel = 0; int n; TCHAR sz[MAXMEDLEN]; // Fill the listbox for (i = 0; i < ARRAY_ELEMENTS(s_rgTypes); i++) { n = ComboBox_AddString(hwndCB, SzFromIDS(g_hinst, s_rgTypes[i].ids, sz, SIZECHARS(sz))); ComboBox_SetItemData(hwndCB, n, s_rgTypes[i].dwType); // Keep our eyes peeled for the selected type if (dwType == s_rgTypes[i].dwType) { iSel = n; } } ComboBox_SetCurSel(hwndCB, iSel); } /*---------------------------------------------------------- Purpose: Enable/disable all the controls Returns: -- Cond: -- */ void PRIVATE CheapRing_EnableControls( PRING this, BOOL bEnable) { HWND hwnd = this->hdlg; EnableWindow(GetDlgItem(hwnd, IDC_LBL_RING1), bEnable); EnableWindow(GetDlgItem(hwnd, IDC_TYPE_RING1), bEnable); EnableWindow(GetDlgItem(hwnd, IDC_LBL_RING2), bEnable); EnableWindow(GetDlgItem(hwnd, IDC_TYPE_RING2), bEnable); EnableWindow(GetDlgItem(hwnd, IDC_LBL_RING3), bEnable); EnableWindow(GetDlgItem(hwnd, IDC_TYPE_RING3), bEnable); } /*---------------------------------------------------------- Purpose: WM_INITDIALOG Handler Returns: FALSE when we assign the control focus Cond: -- */ BOOL PRIVATE CheapRing_OnInitDialog( PRING this, HWND hwndFocus, LPARAM lParam) // expected to be PROPSHEETINFO { LPPROPSHEETPAGE lppsp = (LPPROPSHEETPAGE)lParam; HWND hwnd = this->hdlg; HWND hwndCtl; LPDWORD lpdw; BOOL bEnable; int i; PVOICEFEATURES pvs; ASSERT((LPTSTR)lppsp->lParam); this->pmi = (LPMODEMINFO)lppsp->lParam; pvs = &this->pmi->pglobal->vs; // Enable/disable controls bEnable = IsFlagSet(this->pmi->pglobal->vs.dwFlags, VSF_DIST_RING); Button_SetCheck(GetDlgItem(hwnd, IDC_RING_CHECK), bEnable); CheapRing_EnableControls(this, bEnable); // Initialize controls for (i = 0; i < ARRAY_ELEMENTS(c_rgidcTypeOfCheapCalls); i++) { hwndCtl = GetDlgItem(hwnd, c_rgidcTypeOfCheapCalls[i]); lpdw = &pvs->DistRing[i].dwMediaType; CheapRing_InitTypeOfCall(this, hwndCtl, *lpdw); } return TRUE; // default initial focus } /*---------------------------------------------------------- Purpose: WM_COMMAND Handler Returns: -- Cond: -- */ void PRIVATE CheapRing_OnCommand( PRING this, int id, HWND hwndCtl, UINT uNotifyCode) { BOOL bCheck; switch (id) { case IDC_RING_CHECK: bCheck = Button_GetCheck(hwndCtl); CheapRing_EnableControls(this, bCheck); break; default: break; } } /*---------------------------------------------------------- Purpose: PSN_APPLY handler Returns: TRUE if validation succeeded FALSE if not Cond: -- */ BOOL PRIVATE CheapRing_OnApply( PRING this) { HWND hwnd = this->hdlg; HWND hwndCtl; LPDWORD lpdw; int i; int iSel; PVOICEFEATURES pvs = &this->pmi->pglobal->vs; if (Button_GetCheck(GetDlgItem(hwnd, IDC_RING_CHECK))) { SetFlag(pvs->dwFlags, VSF_DIST_RING); } else { ClearFlag(pvs->dwFlags, VSF_DIST_RING); } // Get the ring pattern settings for (i = 0; i < ARRAY_ELEMENTS(c_rgdwCheapPatterns); i++) { pvs->DistRing[i].dwPattern = c_rgdwCheapPatterns[i]; } // Get the type of call settings for (i = 0; i < ARRAY_ELEMENTS(c_rgidcTypeOfCheapCalls); i++) { hwndCtl = GetDlgItem(hwnd, c_rgidcTypeOfCheapCalls[i]); lpdw = &pvs->DistRing[i].dwMediaType; iSel = ComboBox_GetCurSel(hwndCtl); ASSERT(LB_ERR != iSel); *lpdw = ComboBox_GetItemData(hwndCtl, iSel); } return TRUE; } /*---------------------------------------------------------- Purpose: WM_NOTIFY handler Returns: varies Cond: -- */ LRESULT PRIVATE CheapRing_OnNotify( PRING this, int idFrom, NMHDR FAR * lpnmhdr) { LRESULT lRet = 0; switch (lpnmhdr->code) { case PSN_SETACTIVE: break; case PSN_KILLACTIVE: // N.b. This message is not sent if user clicks Cancel! // N.b. This message is sent prior to PSN_APPLY // break; case PSN_APPLY: lRet = CheapRing_OnApply(this) ? PSNRET_NOERROR : PSNRET_INVALID; break; default: break; } return lRet; } static BOOL s_bCheapRingRecurse = FALSE; LRESULT INLINE CheapRing_DefProc( HWND hDlg, UINT msg, WPARAM wParam, LPARAM lParam) { ENTER_X() { s_bCheapRingRecurse = TRUE; } LEAVE_X() return DefDlgProc(hDlg, msg, wParam, lParam); } /*---------------------------------------------------------- Purpose: Real dialog proc Returns: varies Cond: -- */ LRESULT CheapRing_DlgProc( PRING this, UINT message, WPARAM wParam, LPARAM lParam) { #ifdef CS_HELP // UE used the control IDs as help IDs. To prevent mix-ups in // the future (ie, when the control IDs change), here are the // help IDs. #define IDH_UNI_RING_LBL_RING1 1088 #define IDH_UNI_RING_TYPE_RING1 1091 #define IDH_UNI_RING_LBL_RING2 1089 #define IDH_UNI_RING_TYPE_RING2 1092 #define IDH_UNI_RING_LBL_RING3 1090 #define IDH_UNI_RING_TYPE_RING3 1093 #pragma data_seg(DATASEG_READONLY) const static DWORD rgHelpIDs[] = { IDC_RING_CHECK, IDH_UNI_RING_SERVICES, IDC_LBL_RING1, IDH_UNI_RING_LBL_RING1, IDC_TYPE_RING1, IDH_UNI_RING_TYPE_RING1, IDC_LBL_RING2, IDH_UNI_RING_LBL_RING2, IDC_TYPE_RING2, IDH_UNI_RING_TYPE_RING2, IDC_LBL_RING3, IDH_UNI_RING_LBL_RING3, IDC_TYPE_RING3, IDH_UNI_RING_TYPE_RING3, 0, 0 }; #pragma data_seg() #endif switch (message) { HANDLE_MSG(this, WM_INITDIALOG, CheapRing_OnInitDialog); HANDLE_MSG(this, WM_COMMAND, CheapRing_OnCommand); HANDLE_MSG(this, WM_NOTIFY, CheapRing_OnNotify); #ifdef CS_HELP case WM_HELP: WinHelp(((LPHELPINFO)lParam)->hItemHandle, c_szUnimdmHelpFile, HELP_WM_HELP, (DWORD)(LPVOID)rgHelpIDs); return 0; case WM_CONTEXTMENU: WinHelp((HWND)wParam, c_szUnimdmHelpFile, HELP_CONTEXTMENU, (DWORD)(LPVOID)rgHelpIDs); return 0; #endif default: return CheapRing_DefProc(this->hdlg, message, wParam, lParam); } } /*---------------------------------------------------------- Purpose: Dialog Wrapper Returns: varies Cond: -- */ BOOL CALLBACK CheapRing_WrapperProc( HWND hDlg, // std params UINT message, WPARAM wParam, LPARAM lParam) { PRING this; // Cool windowsx.h dialog technique. For full explanation, see // WINDOWSX.TXT. This supports multiple-instancing of dialogs. // ENTER_X() { if (s_bCheapRingRecurse) { s_bCheapRingRecurse = FALSE; LEAVE_X() return FALSE; } } LEAVE_X() this = CheapRing_GetPtr(hDlg); if (this == NULL) { // (WM_SETFONT is the first message received by dialogs) if (WM_SETFONT == message) { this = (PRING)LocalAlloc(LPTR, sizeof(RING)); if (!this) { MsgBox(g_hinst, hDlg, MAKEINTRESOURCE(IDS_OOM_SETTINGS), MAKEINTRESOURCE(IDS_CAP_RING), NULL, MB_ERROR); EndDialog(hDlg, IDCANCEL); return (BOOL)CheapRing_DefProc(hDlg, message, wParam, lParam); } this->hdlg = hDlg; CheapRing_SetPtr(hDlg, this); } else { return (BOOL)CheapRing_DefProc(hDlg, message, wParam, lParam); } } if (message == WM_DESTROY) { CheapRing_DlgProc(this, message, wParam, lParam); LocalFree((HLOCAL)OFFSETOF(this)); CheapRing_SetPtr(hDlg, NULL); return 0; } return SetDlgMsgResult(hDlg, message, CheapRing_DlgProc(this, message, wParam, lParam)); } //----------------------------------------------------------------------------------- // DTMF edit box proc //----------------------------------------------------------------------------------- /*---------------------------------------------------------- Purpose: Handle WM_CHAR Returns: TRUE to let the characters by FALSE to prohibit Cond: -- */ BOOL PRIVATE DTMFEditProc_OnChar( HWND hwnd, UINT ch, int cRepeat) { BOOL bRet; // Is this a numerical digit, // a backspace, // or a valid DTMF digit? if (IsCharAlphaNumeric((TCHAR)ch) && !IsCharAlpha((TCHAR)ch) || VK_BACK == LOBYTE(VkKeyScan((TCHAR)ch)) || 'A' == ch || 'B' == ch || 'C' == ch || 'D' == ch || '*' == ch || '#' == ch) { // Yes bRet = TRUE; } else { // No MessageBeep(MB_OK); bRet = FALSE; } return bRet; } /*---------------------------------------------------------- Purpose: Number proc. Only allow numbers to be entered into this edit box. Returns: varies Cond: -- */ LRESULT CALLBACK DTMFEditProc( HWND hwnd, // std params UINT message, WPARAM wParam, LPARAM lParam) { WNDPROC pfn = (WNDPROC)GetWindowLong(hwnd, GWL_USERDATA); // BUGBUG: doesn't handle paste correctly! switch (message) { case WM_CHAR: if (!DTMFEditProc_OnChar(hwnd, (UINT)wParam, LOWORD(lParam))) return 1; // Don't process this character break; } return CallWindowProc(pfn, hwnd, message, wParam, lParam); } //----------------------------------------------------------------------------------- // Call forwarding dialog code //----------------------------------------------------------------------------------- typedef struct tagCALLFWD { HWND hdlg; // dialog handle LPMODEMINFO pmi; // modeminfo struct passed into dialog } CALLFWD, FAR * PCALLFWD; #define CallFwd_GetPtr(hwnd) (PCALLFWD)GetWindowLong(hwnd, DWL_USER) #define CallFwd_SetPtr(hwnd, lp) (PCALLFWD)SetWindowLong(hwnd, DWL_USER, (LONG)(lp)) /*---------------------------------------------------------- Purpose: Enable/disable all the controls Returns: -- Cond: -- */ void PRIVATE CallFwd_EnableControls( PCALLFWD this, BOOL bEnable) { HWND hwnd = this->hdlg; EnableWindow(GetDlgItem(hwnd, IDC_FWD_ACT), bEnable); EnableWindow(GetDlgItem(hwnd, IDC_ACT), bEnable); EnableWindow(GetDlgItem(hwnd, IDC_FWD_DEACT), bEnable); EnableWindow(GetDlgItem(hwnd, IDC_DEACT), bEnable); } /*---------------------------------------------------------- Purpose: WM_INITDIALOG Handler Returns: FALSE when we assign the control focus Cond: -- */ BOOL PRIVATE CallFwd_OnInitDialog( PCALLFWD this, HWND hwndFocus, LPARAM lParam) // expected to be PROPSHEETINFO { LPPROPSHEETPAGE lppsp = (LPPROPSHEETPAGE)lParam; HWND hwnd = this->hdlg; HWND hwndCtl; BOOL bEnable; PVOICEFEATURES pvs; WNDPROC pfn; ASSERT((LPTSTR)lppsp->lParam); this->pmi = (LPMODEMINFO)lppsp->lParam; pvs = &this->pmi->pglobal->vs; // Subclass the edit boxes that only accept DTMF digits hwndCtl = GetDlgItem(hwnd, IDC_ACT); pfn = SubclassWindow(hwndCtl, DTMFEditProc); SetWindowLong(hwndCtl, GWL_USERDATA, (LONG)pfn); hwndCtl = GetDlgItem(hwnd, IDC_DEACT); pfn = SubclassWindow(hwndCtl, DTMFEditProc); SetWindowLong(hwndCtl, GWL_USERDATA, (LONG)pfn); // Enable/disable controls bEnable = IsFlagSet(pvs->dwFlags, VSF_CALL_FWD); Button_SetCheck(GetDlgItem(hwnd, IDC_FWD_CHECK), bEnable); CallFwd_EnableControls(this, bEnable); // Initialize controls hwndCtl = GetDlgItem(hwnd, IDC_ACT); Edit_SetText(hwndCtl, pvs->szActivationCode); Edit_LimitText(hwndCtl, SIZECHARS(pvs->szActivationCode)-1); hwndCtl = GetDlgItem(hwnd, IDC_DEACT); Edit_SetText(hwndCtl, pvs->szDeactivationCode); Edit_LimitText(hwndCtl, SIZECHARS(pvs->szDeactivationCode)-1); return TRUE; // default initial focus } /*---------------------------------------------------------- Purpose: WM_COMMAND Handler Returns: -- Cond: -- */ void PRIVATE CallFwd_OnCommand( PCALLFWD this, int id, HWND hwndCtl, UINT uNotifyCode) { BOOL bCheck; switch (id) { case IDC_FWD_CHECK: bCheck = Button_GetCheck(hwndCtl); CallFwd_EnableControls(this, bCheck); break; default: break; } } /*---------------------------------------------------------- Purpose: Validate the user's settings. The call forwarding fields must be filled in if the service is turned on. Returns: TRUE if valid Cond: -- */ BOOL PRIVATE CallFwd_ValidateSettings( PCALLFWD this) { HWND hwnd = this->hdlg; HWND hwndCtl; // Is the service turned on? if (Button_GetCheck(GetDlgItem(hwnd, IDC_FWD_CHECK))) { // Yes; are the fields filled in? hwndCtl = GetDlgItem(hwnd, IDC_ACT); if (0 == Edit_GetTextLength(hwndCtl)) { // No; this is naughty MsgBox(g_hinst, hwnd, MAKEINTRESOURCE(IDS_ERR_NEED_VALUE), MAKEINTRESOURCE(IDS_CAP_CALLFWD), NULL, MB_ERROR); // Set the focus on the offending control PostMessage(hwnd, WM_NEXTDLGCTL, (WPARAM)hwndCtl, (LPARAM)TRUE); return FALSE; } hwndCtl = GetDlgItem(hwnd, IDC_DEACT); if (0 == Edit_GetTextLength(hwndCtl)) { // No; this is naughty MsgBox(g_hinst, hwnd, MAKEINTRESOURCE(IDS_ERR_NEED_VALUE), MAKEINTRESOURCE(IDS_CAP_CALLFWD), NULL, MB_ERROR); // Set the focus on the offending control PostMessage(hwnd, WM_NEXTDLGCTL, (WPARAM)hwndCtl, (LPARAM)TRUE); return FALSE; } } return TRUE; } /*---------------------------------------------------------- Purpose: PSN_APPLY handler Returns: -- Cond: -- */ BOOL PRIVATE CallFwd_OnApply( PCALLFWD this) { BOOL bRet; HWND hwnd = this->hdlg; HWND hwndCtl; PVOICEFEATURES pvs = &this->pmi->pglobal->vs; bRet = CallFwd_ValidateSettings(this); if (bRet) { if (Button_GetCheck(GetDlgItem(hwnd, IDC_FWD_CHECK))) { SetFlag(pvs->dwFlags, VSF_CALL_FWD); } else { ClearFlag(pvs->dwFlags, VSF_CALL_FWD); } hwndCtl = GetDlgItem(hwnd, IDC_ACT); Edit_GetText(hwndCtl, pvs->szActivationCode, SIZECHARS(pvs->szActivationCode)); hwndCtl = GetDlgItem(hwnd, IDC_DEACT); Edit_GetText(hwndCtl, pvs->szDeactivationCode, SIZECHARS(pvs->szDeactivationCode)); } return bRet; } /*---------------------------------------------------------- Purpose: WM_NOTIFY handler Returns: varies Cond: -- */ LRESULT PRIVATE CallFwd_OnNotify( PCALLFWD this, int idFrom, NMHDR FAR * lpnmhdr) { LRESULT lRet = 0; switch (lpnmhdr->code) { case PSN_SETACTIVE: break; case PSN_KILLACTIVE: // N.b. This message is not sent if user clicks Cancel! // N.b. This message is sent prior to PSN_APPLY // break; case PSN_APPLY: lRet = CallFwd_OnApply(this) ? PSNRET_NOERROR : PSNRET_INVALID; break; default: break; } return lRet; } static BOOL s_bCallFwdRecurse = FALSE; LRESULT INLINE CallFwd_DefProc( HWND hDlg, UINT msg, WPARAM wParam, LPARAM lParam) { ENTER_X() { s_bCallFwdRecurse = TRUE; } LEAVE_X() return DefDlgProc(hDlg, msg, wParam, lParam); } /*---------------------------------------------------------- Purpose: Real dialog proc Returns: varies Cond: -- */ LRESULT CallFwd_DlgProc( PCALLFWD this, UINT message, WPARAM wParam, LPARAM lParam) { #ifdef CS_HELP // UE used the control IDs as help IDs. To prevent mix-ups in // the future (ie, when the control IDs change), here are the // help IDs. #define IDH_UNI_CALLFWD_SERVICES 1062 #define IDH_UNI_CALLFWD_FWD_ACT 1063 #define IDH_UNI_CALLFWD_ACT 1068 #define IDH_UNI_CALLFWD_FWD_DEACT 1064 #define IDH_UNI_CALLFWD_DEACT 1067 #pragma data_seg(DATASEG_READONLY) const static DWORD rgHelpIDs[] = { IDC_FWD_CHECK, IDH_UNI_CALLFWD_SERVICES, IDC_FWD_ACT, IDH_UNI_CALLFWD_FWD_ACT, IDC_ACT, IDH_UNI_CALLFWD_ACT, IDC_FWD_DEACT, IDH_UNI_CALLFWD_FWD_DEACT, IDC_DEACT, IDH_UNI_CALLFWD_DEACT, 0, 0 }; #pragma data_seg() #endif switch (message) { HANDLE_MSG(this, WM_INITDIALOG, CallFwd_OnInitDialog); HANDLE_MSG(this, WM_COMMAND, CallFwd_OnCommand); HANDLE_MSG(this, WM_NOTIFY, CallFwd_OnNotify); #ifdef CS_HELP case WM_HELP: WinHelp(((LPHELPINFO)lParam)->hItemHandle, c_szUnimdmHelpFile, HELP_WM_HELP, (DWORD)(LPVOID)rgHelpIDs); return 0; case WM_CONTEXTMENU: WinHelp((HWND)wParam, c_szUnimdmHelpFile, HELP_CONTEXTMENU, (DWORD)(LPVOID)rgHelpIDs); return 0; #endif default: return CallFwd_DefProc(this->hdlg, message, wParam, lParam); } } /*---------------------------------------------------------- Purpose: Dialog Wrapper Returns: varies Cond: -- */ BOOL CALLBACK CallFwd_WrapperProc( HWND hDlg, // std params UINT message, WPARAM wParam, LPARAM lParam) { PCALLFWD this; // Cool windowsx.h dialog technique. For full explanation, see // WINDOWSX.TXT. This supports multiple-instancing of dialogs. // ENTER_X() { if (s_bCallFwdRecurse) { s_bCallFwdRecurse = FALSE; LEAVE_X() return FALSE; } } LEAVE_X() this = CallFwd_GetPtr(hDlg); if (this == NULL) { if (message == WM_INITDIALOG) { this = (PCALLFWD)LocalAlloc(LPTR, sizeof(CALLFWD)); if (!this) { MsgBox(g_hinst, hDlg, MAKEINTRESOURCE(IDS_OOM_SETTINGS), MAKEINTRESOURCE(IDS_CAP_RING), NULL, MB_ERROR); EndDialog(hDlg, IDCANCEL); return (BOOL)CallFwd_DefProc(hDlg, message, wParam, lParam); } this->hdlg = hDlg; CallFwd_SetPtr(hDlg, this); } else { return (BOOL)CallFwd_DefProc(hDlg, message, wParam, lParam); } } if (message == WM_DESTROY) { CallFwd_DlgProc(this, message, wParam, lParam); LocalFree((HLOCAL)OFFSETOF(this)); CallFwd_SetPtr(hDlg, NULL); return 0; } return SetDlgMsgResult(hDlg, message, CallFwd_DlgProc(this, message, wParam, lParam)); }