/** Copyright (c) Microsoft Corporation 1999-2000 Module Name: monitor.cpp Abstract: This module implements the fax monitor dialog. **/ #include #include #include #include #include #include #include #include using namespace std; #include "monitor.h" #include "resource.h" #define DURATION_TIMER_RESOLUTION 500 // Resolution (millisecs) of duration text update timer ////////////////////////////////////////////////////////////// // Global data // extern HINSTANCE g_hModule; // DLL Global instance extern HINSTANCE g_hResource; // Resource DLL handle extern HANDLE g_hFaxSvcHandle; extern DWORD g_dwCurrentJobID; extern CONFIG_OPTIONS g_ConfigOptions; extern TCHAR g_szRemoteId[MAX_PATH]; // Sender ID or Recipient ID extern HCALL g_hCall; // Handle to call (from FAX_EVENT_TYPE_NEW_CALL) // // Events log // struct EVENT_ENTRY { eIconType eIcon; // Event icon TCHAR tszTime[30]; // Event time string TCHAR tszEvent[MAX_PATH]; // Event string }; typedef EVENT_ENTRY *PEVENT_ENTRY; typedef list EVENTS_LIST, *PEVENTS_LIST; EVENTS_LIST g_lstEvents; // Global list of events #define MAX_EVENT_LIST_SIZE 50 // Maximal number of events in log // // Monitor dialog // HWND g_hMonitorDlg = NULL; // // Controls // HWND g_hStatus = NULL; // Status line (static text) HWND g_hElapsedTime = NULL; // Elapsed time line (static text) HWND g_hToFrom = NULL; // To/From line (static text) HWND g_hListDetails = NULL; // Details list control HWND g_hAnimation = NULL; // Animation control HWND g_hDisconnect = NULL; // Disconnect button HICON g_hDlgIcon = NULL; // Dialog main icon HIMAGELIST g_hDlgImageList = NULL; // Dialog's image list // // Data // BOOL g_bAnswerNow = FALSE; // TRUE if the dialog button shows 'Answer Now'. FALSE if it shows 'Disconnect'. DWORD g_dwHeightDelta = 0; // Used when pressing "More >>>" / "Less <<<" to resize the dialog DWORD g_dwDlgHeight = 0; // The dialog height BOOL g_bDetails = FALSE; // Is the "More >>>" button pressed? DeviceState g_devState = FAX_IDLE; // Current fax state (animation) DWORD g_dwStartTime = 0; // Activity start time (tick counts) UINT_PTR g_nElapsedTimerId = 0; // Timer id for elapsed time (ticks every 1 second) TCHAR g_tszTimeSeparator[5] = {0}; DWORD g_dwCurrentAnimationId = 0; // Current animation resource ID TCHAR g_tszLastEvent[MAX_PATH] = {0}; // The last event string POINT g_ptPosition = {-1, -1}; // Dialog position BOOL g_bTopMost = FALSE; // Is the monitor dialog always visible? #define DETAILS_TIME_COLUMN_WIDTH 90 ///////////////////////////////////////////////////////////////////// // Function prototypes // // public BOOL IsUserGrantedAccess(DWORD); DWORD OpenFaxMonitor(VOID); void SetStatusMonitorDeviceState(DeviceState devState); void OnDisconnect(); void FreeMonitorDialogData (BOOL bShutdown); // Private INT_PTR CALLBACK FaxMonitorDlgProc(HWND hwndDlg, UINT uMsg, WPARAM wParam, LPARAM lParam); VOID CALLBACK ElapsedTimerProc(HWND hwnd, UINT uMsg, UINT_PTR idEvent, DWORD dwTime); void InitMonitorDlg(HWND hDlg); DWORD UpdateMonitorData(HWND hDlg); void AddEventToView(PEVENT_ENTRY pEvent); void OnAlwaysOnTop(HWND hDlg); void OnDetailsButton(HWND hDlg, BOOL bDetails); void OnClearLog(); int FaxMessageBox(HWND hWnd, DWORD dwTextID, UINT uType); DWORD RefreshImageList (); ////////////////////////////////////////////////////////////////////// // Implementation // void FreeMonitorDialogData ( BOOL bShutdown /* = FALSE */ ) /*++ Routine name : FreeMonitorDialogData Routine description: Frees up all the data allocated by the monitor module Author: Eran Yariv (EranY), Mar, 2001 Arguments: bShutdown - [in] TRUE only is the module is shutting down. Return Value: None. --*/ { DWORD dwRes = ERROR_SUCCESS; DBG_ENTER(TEXT("FreeMonitorDialogData"), dwRes); RECT rc = {0}; if(GetWindowRect(g_hMonitorDlg, &rc)) { g_ptPosition.x = rc.left; g_ptPosition.y = rc.top; } g_hMonitorDlg = NULL; g_hStatus = NULL; g_hElapsedTime = NULL; g_hToFrom = NULL; g_hListDetails = NULL; g_hDisconnect = NULL; g_hAnimation = NULL; g_dwCurrentAnimationId = 0; if (g_hDlgImageList) { ImageList_Destroy (g_hDlgImageList); g_hDlgImageList = NULL; } if (bShutdown) { // // DLL is shutting down. // // // The icon is cached in memory even when the dialog is closed. // This is a good time to free it. // if(g_nElapsedTimerId) { if (!KillTimer(NULL, g_nElapsedTimerId)) { CALL_FAIL (GENERAL_ERR, TEXT("KillTimer"), GetLastError ()); } g_nElapsedTimerId = NULL; } if (g_hDlgIcon) { if (!DestroyIcon (g_hDlgIcon)) { CALL_FAIL (WINDOW_ERR, TEXT("DestroyIcon"), GetLastError ()); } g_hDlgIcon = NULL; } // // Also delete all the events from the list // try { g_lstEvents.clear(); } catch (exception &ex) { VERBOSE (MEM_ERR, TEXT("Got an STL exception while clearing the events list (%S)"), ex.what()); } g_ptPosition.x = -1; g_ptPosition.y = -1; } } // FreeMonitorDialogData INT_PTR CALLBACK FaxMonitorDlgProc( HWND hwndDlg, // handle to dialog box UINT uMsg, // message WPARAM wParam, // first message parameter LPARAM lParam // second message parameter ) /*++ Routine description: fax monitor dialog procedure Arguments: HWND hwndDlg, // handle to dialog box UINT uMsg, // message WPARAM wParam, // first message parameter LPARAM lParam // second message parameter Return Value: return TRUE if it processed the message --*/ { switch ( uMsg ) { case WM_INITDIALOG: InitMonitorDlg(hwndDlg); return TRUE; case WM_DESTROY: FreeMonitorDialogData (); return TRUE; case WM_COMMAND: switch(LOWORD(wParam)) { case IDC_DETAILS: g_bDetails = !g_bDetails; OnDetailsButton(hwndDlg, g_bDetails); return TRUE; case IDC_ALWAYS_ON_TOP: OnAlwaysOnTop(hwndDlg); return TRUE; case IDC_CLEAR_LOG: OnClearLog(); return TRUE; case IDC_DISCONNECT: OnDisconnect(); return TRUE; case IDCANCEL: DestroyWindow( hwndDlg ); return TRUE; } // switch(LOWORD(wParam)) break; case WM_HELP: WinHelpContextPopup(((LPHELPINFO)lParam)->dwContextId, hwndDlg); return TRUE; case WM_CONTEXTMENU: WinHelpContextPopup(GetWindowContextHelpId((HWND)wParam), hwndDlg); return TRUE; case WM_SYSCOLORCHANGE: RefreshImageList (); return TRUE; } // switch ( uMsg ) return FALSE; } // FaxMonitorDlgProc DWORD RefreshImageList () /*++ Routine name : RefreshImageList Routine description: Refreshes the image list and list view background color Author: Eran Yariv (EranY), May, 2001 Arguments: Return Value: Standard Win32 error code --*/ { DWORD dwRes = ERROR_SUCCESS; DBG_ENTER(TEXT("RefreshImageList"), dwRes); ListView_SetExtendedListViewStyle(g_hListDetails, LVS_EX_FULLROWSELECT | LVS_EX_INFOTIP | LVS_EX_ONECLICKACTIVATE); if (NULL != g_hDlgImageList) { ImageList_Destroy (g_hDlgImageList); g_hDlgImageList = NULL; } g_hDlgImageList = ImageList_Create (16, 16, ILC_COLOR8, 4, 0); if(!g_hDlgImageList) { dwRes = GetLastError(); CALL_FAIL (WINDOW_ERR, TEXT("ImageList_Create"), dwRes); return dwRes; } HBITMAP hBmp = (HBITMAP) LoadImage ( g_hModule, MAKEINTRESOURCE(IDB_LIST_IMAGES), IMAGE_BITMAP, 0, 0, LR_DEFAULTSIZE | LR_LOADTRANSPARENT); if (!hBmp) { dwRes = GetLastError(); CALL_FAIL (WINDOW_ERR, TEXT("LoadBitmap"), dwRes); ImageList_Destroy (g_hDlgImageList); g_hDlgImageList = NULL; return dwRes; } ImageList_Add (g_hDlgImageList, hBmp, NULL); // // ImageList_Add creates a copy of the bitmap - it's now safe to delete it // ::DeleteObject ((HGDIOBJ)hBmp); ListView_SetImageList(g_hListDetails, g_hDlgImageList, LVSIL_SMALL); ListView_SetBkColor (g_hListDetails, ::GetSysColor(COLOR_WINDOW)); return dwRes; } // RefreshImageList void InitMonitorDlg( HWND hDlg ) /*++ Routine description: Initialize fax monitor dialog Arguments: hDlg [in] - fax monitor dialog handle Return Value: none --*/ { DWORD dwRes = ERROR_SUCCESS; DBG_ENTER(TEXT("InitMonitorDlg"), dwRes); // // Set the dialog icon // if (NULL == g_hDlgIcon) { // // 1st time the dialog is opened - load the icons // g_hDlgIcon = LoadIcon(g_hModule, MAKEINTRESOURCE(IDI_FAX_MONITOR)); if(!g_hDlgIcon) { dwRes = GetLastError(); CALL_FAIL (WINDOW_ERR, TEXT ("LoadIcon"), dwRes); return; } } SendMessage(hDlg, WM_SETICON, ICON_BIG, (LPARAM)g_hDlgIcon); SendMessage(hDlg, WM_SETICON, ICON_SMALL, (LPARAM)g_hDlgIcon); // // Calculate the height of the details part // RECT rcList, rcDialog; if(!GetWindowRect(hDlg, &rcDialog)) { dwRes = GetLastError(); CALL_FAIL (WINDOW_ERR, TEXT ("GetWindowRect"), dwRes); return; } g_dwDlgHeight = rcDialog.bottom - rcDialog.top; g_hListDetails = GetDlgItem(hDlg, IDC_LIST_DETAILS); ASSERTION (g_hListDetails); if(!GetWindowRect(g_hListDetails, &rcList)) { dwRes = GetLastError(); CALL_FAIL (WINDOW_ERR, TEXT ("GetWindowRect"), dwRes); return; } g_dwHeightDelta = rcDialog.bottom - rcList.top; // // Shrink down to small size (initially) // OnDetailsButton(hDlg, g_bDetails); // // Init the list view // RefreshImageList (); // // Add time column // TCHAR tszHeader[MAX_PATH]; LVCOLUMN lvColumn = {0}; lvColumn.mask = LVCF_TEXT | LVCF_WIDTH; lvColumn.cx = DETAILS_TIME_COLUMN_WIDTH; lvColumn.pszText = tszHeader; if (ERROR_SUCCESS != (dwRes = LoadAndFormatString (IDS_DETAIL_TIME_HEADER, tszHeader, ARR_SIZE(tszHeader)))) { return; } ListView_InsertColumn(g_hListDetails, 0, &lvColumn); // // add event column // if (ERROR_SUCCESS != (dwRes = LoadAndFormatString (IDS_DETAIL_EVENT_HEADER, tszHeader, ARR_SIZE(tszHeader)))) { return; } ListView_InsertColumn(g_hListDetails, 1, &lvColumn); // // Autosize the last column width // ListView_SetColumnWidth(g_hListDetails, 1, LVSCW_AUTOSIZE_USEHEADER); // // Animation control // g_hAnimation = GetDlgItem(hDlg, IDC_ANIMATE); ASSERTION (g_hAnimation); // // Get static text controls // g_hStatus = GetDlgItem(hDlg, IDC_STATUS); ASSERTION (g_hStatus); g_hElapsedTime = GetDlgItem(hDlg, IDC_ELAPSED_TIME); ASSERTION (g_hElapsedTime); g_hToFrom = GetDlgItem(hDlg, IDC_MON_TITLE); ASSERTION (g_hToFrom); // // Disconnect button // g_hDisconnect = GetDlgItem(hDlg, IDC_DISCONNECT); ASSERTION (g_hDisconnect); // // Get the time separator string // if(!GetLocaleInfo(LOCALE_USER_DEFAULT, LOCALE_STIME, g_tszTimeSeparator, ARR_SIZE(g_tszTimeSeparator) - 1)) { dwRes = GetLastError(); CALL_FAIL (WINDOW_ERR, TEXT ("GetLocaleInfo(LOCALE_STIME)"), dwRes); } if(g_ptPosition.x != -1 && g_ptPosition.y != -1) { SetWindowPos(hDlg, 0, g_ptPosition.x, g_ptPosition.y, 0, 0, SWP_NOSIZE | SWP_NOZORDER); } UpdateMonitorData(hDlg); } // InitMonitorDlg DWORD UpdateMonitorData( HWND hDlg ) /*++ Routine description: Update monitor data and controls Arguments: hDlg [in] - fax monitor dialog handle Return Value: standard error code --*/ { DWORD dwRes = ERROR_SUCCESS; DBG_ENTER(TEXT("UpdateMonitorData"), dwRes); if(!hDlg || !g_hStatus || !g_hElapsedTime || !g_hToFrom || !g_hListDetails || !g_hDisconnect) { return dwRes; } // // elapsed time // if(FAX_IDLE == g_devState) { if(!SetWindowText(g_hElapsedTime, TEXT(""))) { dwRes = GetLastError(); CALL_FAIL (WINDOW_ERR, TEXT ("SetWindowText"), dwRes); } } // // Disconnect/Answer button // BOOL bButtonEnable = FALSE; DWORD dwButtonTitleID = IDS_BUTTON_DISCONNECT; TCHAR tszButtonTitle[MAX_PATH] = {0}; g_bAnswerNow = FALSE; if (ERROR_SUCCESS == CheckAnswerNowCapability (FALSE, // Don't force service to be up NULL)) // Don't care about device id { // // Answer Now option is valid // g_bAnswerNow = TRUE; bButtonEnable = TRUE; dwButtonTitleID = IDS_BUTTON_ANSWER; } else if((FAX_SENDING == g_devState || FAX_RECEIVING == g_devState) && (IsUserGrantedAccess(FAX_ACCESS_SUBMIT) || IsUserGrantedAccess(FAX_ACCESS_SUBMIT_NORMAL) || IsUserGrantedAccess(FAX_ACCESS_SUBMIT_HIGH) || IsUserGrantedAccess(FAX_ACCESS_MANAGE_JOBS))) { // // Fax in progress // bButtonEnable = TRUE; dwButtonTitleID = IDS_BUTTON_DISCONNECT; } EnableWindow(g_hDisconnect, bButtonEnable); if (ERROR_SUCCESS == LoadAndFormatString (dwButtonTitleID, tszButtonTitle, ARR_SIZE(tszButtonTitle))) { SetWindowText(g_hDisconnect, tszButtonTitle); } else { ASSERTION_FAILURE; } // // Animation // DWORD dwAnimationId = IDR_FAX_IDLE; switch(g_devState) { case FAX_IDLE: dwAnimationId = IDR_FAX_IDLE; break; case FAX_RINGING: dwAnimationId = IDR_FAX_RINGING; break; case FAX_SENDING: dwAnimationId = IDR_FAX_SEND; break; case FAX_RECEIVING: dwAnimationId = IDR_FAX_RECEIVE; break; } if(g_dwCurrentAnimationId != dwAnimationId) { if(!Animate_OpenEx(g_hAnimation, g_hModule, MAKEINTRESOURCE(dwAnimationId))) { CALL_FAIL (WINDOW_ERR, TEXT ("Animate_Open"), 0); } else { if(!Animate_Play(g_hAnimation, 0, -1, -1)) { CALL_FAIL (WINDOW_ERR, TEXT ("Animate_Play"), 0); } else { g_dwCurrentAnimationId = dwAnimationId; } } } // // Status // if(FAX_IDLE != g_devState) // Non-idle state and { if(!SetWindowText(g_hStatus, g_tszLastEvent)) { dwRes = GetLastError(); CALL_FAIL (WINDOW_ERR, TEXT ("SetWindowText"), dwRes); } } else // idle { DWORD dwStrId = IDS_FAX_READY; TCHAR tszReady[MAX_PATH]; if(g_ConfigOptions.bSend && (g_ConfigOptions.bReceive || g_ConfigOptions.dwManualAnswerDeviceId == g_ConfigOptions.dwMonitorDeviceId)) { dwStrId = IDS_READY_TO_SND_AND_RCV; } else if(g_ConfigOptions.bSend) { dwStrId = IDS_READY_TO_SND; } else if(g_ConfigOptions.bReceive || g_ConfigOptions.dwManualAnswerDeviceId == g_ConfigOptions.dwMonitorDeviceId) { dwStrId = IDS_READY_TO_RCV; } if (ERROR_SUCCESS != (dwRes = LoadAndFormatString (dwStrId, tszReady, ARR_SIZE(tszReady)))) { return dwRes; } if(!SetWindowText(g_hStatus, tszReady)) { dwRes = GetLastError(); CALL_FAIL (WINDOW_ERR, TEXT ("SetWindowText"), dwRes); } } // // to/from // TCHAR tszToFrom[MAX_PATH] = {0}; if(FAX_SENDING == g_devState || FAX_RECEIVING == g_devState) { LPCTSTR lpctstrAddressParam = NULL; DWORD dwStringResId = (FAX_SENDING == g_devState) ? IDS_SENDING : IDS_RECEIVING; if(_tcslen(g_szRemoteId)) { // // Remote ID is known // lpctstrAddressParam = g_szRemoteId; dwStringResId = (FAX_SENDING == g_devState) ? IDS_SENDING_TO : IDS_RECEIVING_FROM; } if (ERROR_SUCCESS != (dwRes = LoadAndFormatString (dwStringResId, tszToFrom, ARR_SIZE(tszToFrom), lpctstrAddressParam))) { return dwRes; } } if(!SetWindowText(g_hToFrom, tszToFrom)) { dwRes = GetLastError(); CALL_FAIL (WINDOW_ERR, TEXT ("SetWindowText"), dwRes); } // // Details log list // if(ListView_GetItemCount(g_hListDetails) == 0) { // // Log is empty - fill it with list data // ASSERTION (g_lstEvents.size() <= MAX_EVENT_LIST_SIZE); for (EVENTS_LIST::iterator it = g_lstEvents.begin(); it != g_lstEvents.end(); ++it) { EVENT_ENTRY &Event = *it; AddEventToView(&Event); } } if(!CheckDlgButton(hDlg, IDC_ALWAYS_ON_TOP, g_bTopMost ? BST_CHECKED : BST_UNCHECKED)) { dwRes = GetLastError(); CALL_FAIL (WINDOW_ERR, TEXT ("CheckDlgButton(IDC_ALWAYS_ON_TOP)"), dwRes); } OnAlwaysOnTop(hDlg); return dwRes; } // UpdateMonitorData void OnDetailsButton( HWND hDlg, BOOL bDetails ) /*++ Routine description: Show/Hide event log and change the details button text according to bDetails value Arguments: hDlg [in] - fax monitor dialog handle bDetails [in] - new details state Return Value: none --*/ { DBG_ENTER(TEXT("OnDetailsButton")); if(!hDlg) { ASSERTION (FALSE); return; } // // Show/Hide the event log // RECT rc; GetWindowRect(hDlg, &rc); BOOL bLogOpened = (rc.bottom - rc.top > g_dwDlgHeight - g_dwHeightDelta/2); // // If the current dialog heigh more then // dlialog heigh with open log minus half log heigh // we suppose that the log is opened. // This done due to different dialog size in the high contrast mode. // if(bLogOpened != bDetails) { // // Current log state does not fit the new state // rc.bottom += g_dwHeightDelta * (bDetails ? 1 : -1); MoveWindow(hDlg, rc.left, rc.top, rc.right - rc.left, rc.bottom - rc.top, TRUE); } // // Set More/Less button text // TCHAR tszButtonText[MAX_PATH]; if (ERROR_SUCCESS != LoadAndFormatString (bDetails ? IDS_BUTTON_LESS : IDS_BUTTON_MORE, tszButtonText, ARR_SIZE(tszButtonText))) { return; } if(!SetDlgItemText(hDlg, IDC_DETAILS, tszButtonText)) { CALL_FAIL (WINDOW_ERR, TEXT ("SetDlgItemText"), GetLastError()); } } // OnDetailsButton void OnAlwaysOnTop( HWND hDlg ) /*++ Routine description: Change monitor "on top" state and save it to the registry Arguments: hDlg [in] - fax monitor dialog handle Return Value: none --*/ { DBG_ENTER(TEXT("OnAlwaysOnTop")); if(!hDlg) { ASSERTION (FALSE); return; } g_bTopMost = (IsDlgButtonChecked(hDlg, IDC_ALWAYS_ON_TOP) == BST_CHECKED) ? 1:0; DWORD dwRes; if(!SetWindowPos(hDlg, g_bTopMost ? HWND_TOPMOST : HWND_NOTOPMOST, 0, 0, 0, 0, SWP_SHOWWINDOW | SWP_NOMOVE | SWP_NOSIZE)) { dwRes = GetLastError(); CALL_FAIL (WINDOW_ERR, TEXT ("SetWindowPos"), dwRes); } HKEY hKey; dwRes = RegOpenKeyEx(HKEY_CURRENT_USER, REGKEY_FAX_USERINFO, 0, KEY_WRITE, &hKey); if (ERROR_SUCCESS == dwRes) { dwRes = RegSetValueEx(hKey, REGVAL_ALWAYS_ON_TOP, 0, REG_DWORD, (CONST BYTE*)&g_bTopMost, sizeof(g_bTopMost)); if(ERROR_SUCCESS != dwRes) { CALL_FAIL (WINDOW_ERR, TEXT ("RegSetValueEx(REGVAL_ALWAYS_ON_TOP)"), dwRes); } RegCloseKey( hKey ); } else { CALL_FAIL (WINDOW_ERR, TEXT ("RegOpenKeyEx"), dwRes); } } // OnAlwaysOnTop void SetStatusMonitorDeviceState( DeviceState devState ) /*++ Routine description: Change device state Start/stop elapsed timer Arguments: devState - [in] device state Return Value: none --*/ { DWORD dwRes = ERROR_SUCCESS; DBG_ENTER(TEXT("SetStatusMonitorDeviceState"), dwRes); if(g_devState != devState) { // // State has changed // if(g_nElapsedTimerId) { // // Old timer exists // if(!KillTimer(NULL, g_nElapsedTimerId)) { dwRes = GetLastError(); CALL_FAIL (WINDOW_ERR, TEXT ("KillTimer"), dwRes); } g_nElapsedTimerId = 0; } } if(!g_nElapsedTimerId && (devState == FAX_SENDING || devState == FAX_RECEIVING)) { // // We need to count elapsed time for send / receive states. // g_dwStartTime = GetTickCount(); g_nElapsedTimerId = SetTimer(NULL, 0, DURATION_TIMER_RESOLUTION, ElapsedTimerProc); if(!g_nElapsedTimerId) { dwRes = GetLastError(); CALL_FAIL (WINDOW_ERR, TEXT ("SetTimer"), dwRes); } } g_devState = devState; UpdateMonitorData(g_hMonitorDlg); } // SetStatusMonitorDeviceState VOID CALLBACK ElapsedTimerProc( HWND hwnd, // handle to window UINT uMsg, // WM_TIMER message UINT_PTR idEvent, // timer identifier DWORD dwTime // current system time ) /*++ Routine description: Timer precedure to update elapsed time value Arguments: HWND hwnd, // handle to window UINT uMsg, // WM_TIMER message UINT_PTR idEvent, // timer identifier DWORD dwTime // current system time Return Value: none --*/ { DBG_ENTER(TEXT("ElapsedTimerProc")); if(!g_hElapsedTime) { return; } TCHAR tszTime[MAX_PATH] = {0}; TCHAR tszTimeFormat[MAX_PATH] = {0}; DWORD dwRes; if (ERROR_SUCCESS != (dwRes = LoadAndFormatString (IDS_ELAPSED_TIME, tszTimeFormat, ARR_SIZE(tszTimeFormat)))) { return; } DWORD dwElapsedTime = (GetTickCount() - g_dwStartTime)/1000; _sntprintf(tszTime, ARR_SIZE(tszTime) - 1, tszTimeFormat, dwElapsedTime/60, g_tszTimeSeparator, dwElapsedTime%60); if(!SetWindowText(g_hElapsedTime, tszTime)) { dwRes = GetLastError(); CALL_FAIL (WINDOW_ERR, TEXT ("SetWindowText"), dwRes); } } // ElapsedTimerProc DWORD LoadAndFormatString ( IN DWORD dwStringResourceId, OUT LPTSTR lptstrFormattedString, IN DWORD dwOutStrSize, IN LPCTSTR lpctstrAdditionalParam /* = NULL */ ) /*++ Routine name : LoadAndFormatString Routine description: Loads a string from the resource and optionally formats it with another string Author: Eran Yariv (EranY), Dec, 2000 Arguments: dwStringResourceId [in] - String resource id lptstrFormattedString [out] - Result buffer. Must be at least MAX_PATH charactes long. dwOutStrSize [in] - size of lptstrFormattedString in TCHARs lpctstrAdditionalParam [in] - Optional string paramter. If non-NULL, this loaded strings is used as a format specifier (sprintf-like) to format this additional string. Return Value: Standard Win32 error code --*/ { DWORD dwRes = ERROR_SUCCESS; DBG_ENTER(TEXT("LoadAndFormatString"), dwRes, TEXT("ResourceId=%d, Param=%s"), dwStringResourceId, lpctstrAdditionalParam); ASSERTION (lptstrFormattedString && dwStringResourceId); TCHAR tszString[MAX_PATH] = {0}; if (!LoadString(g_hResource, dwStringResourceId, tszString, ARR_SIZE(tszString)-1)) { dwRes = GetLastError(); CALL_FAIL (RESOURCE_ERR, TEXT("LoadString"), dwRes); return dwRes; } if (lpctstrAdditionalParam) { _sntprintf(lptstrFormattedString, dwOutStrSize - 1, tszString, lpctstrAdditionalParam); lptstrFormattedString[dwOutStrSize -1] = _T('\0'); } else { lstrcpyn (lptstrFormattedString, tszString, dwOutStrSize - 1); } return dwRes; } // LoadAndFormatString DWORD AddStatusMonitorLogEvent ( IN eIconType eIcon, IN DWORD dwStringResourceId, IN LPCTSTR lpctstrAdditionalParam /* = NULL */, OUT LPTSTR lptstrFormattedEvent /* = NULL */, IN DWORD dwOutStrSize /* = 0 */ ) /*++ Routine name : AddStatusMonitorLogEvent Routine description: Adds a status monitor event log line Author: Eran Yariv (EranY), Dec, 2000 Arguments: eIcon [in] - Icon to display in log entry dwStringResourceId [in] - String resource id to use lpctstrAdditionalParam [in] - Optional string. If non-NULL, the string loaded from dwStringResourceId is used to format the additional parameter. lptstrFormattedEvent [out] - Optional, if non-NULL, points to a buffer to receive the final status string. Buffer must be at least MAX_PATH characters long. dwOutStrSize [in] - Optional size of lptstrFormattedEvent in TCHARs Return Value: Standard Win32 error code --*/ { DWORD dwRes = ERROR_SUCCESS; DBG_ENTER(TEXT("AddStatusMonitorLogEvent"), dwRes, TEXT("Icon=%d, ResourceId=%d, Param=%s"), eIcon, dwStringResourceId, lpctstrAdditionalParam); TCHAR tszStatus[MAX_PATH * 2] = {0}; dwRes = LoadAndFormatString (dwStringResourceId, tszStatus, ARR_SIZE(tszStatus), lpctstrAdditionalParam); if (ERROR_SUCCESS != dwRes) { return dwRes; } if (lptstrFormattedEvent) { lstrcpyn (lptstrFormattedEvent, tszStatus, dwOutStrSize - 1); } dwRes = AddStatusMonitorLogEvent (eIcon, tszStatus); return dwRes; } // AddStatusMonitorLogEvent DWORD AddStatusMonitorLogEvent ( eIconType eIcon, LPCTSTR lpctstrString ) /*++ Routine description: Add new event to the event list Arguments: eIcon - [in] icon index lpctstrString - [in] event description Return Value: standard error code --*/ { DWORD dwRes = ERROR_SUCCESS; DBG_ENTER(TEXT("AddStatusMonitorLogEvent"), dwRes, TEXT("Icon=%d, Status=%s"), eIcon, lpctstrString); TCHAR tszTime [MAX_PATH] = {0}; ASSERTION (lpctstrString); static TCHAR tszRinging[MAX_PATH] = {0}; if(_tcslen(tszRinging) == 0) { if (ERROR_SUCCESS != (dwRes = LoadAndFormatString (IDS_RINGING, tszRinging, ARR_SIZE(tszRinging)))) { ASSERTION_FAILURE; return dwRes; } } if(_tcscmp(lpctstrString, g_tszLastEvent) == 0 && _tcscmp(lpctstrString, tszRinging) != 0) { // // Do not display the same string twice // except "Ringing" // return dwRes; } EVENT_ENTRY Event; Event.eIcon = eIcon; SYSTEMTIME sysTime; GetLocalTime(&sysTime); if(!FaxTimeFormat(LOCALE_USER_DEFAULT, 0, &sysTime, NULL, Event.tszTime, ARR_SIZE(Event.tszTime) - 1)) { dwRes = GetLastError(); CALL_FAIL (WINDOW_ERR, TEXT ("FaxTimeFormat"), dwRes); return dwRes; } lstrcpyn (Event.tszEvent, lpctstrString, ARR_SIZE(Event.tszEvent) - 1); lstrcpyn (g_tszLastEvent, lpctstrString, ARR_SIZE(g_tszLastEvent) - 1); try { g_lstEvents.push_back (Event); if (g_lstEvents.size() > MAX_EVENT_LIST_SIZE) { // // We exceeded the maximal size we permit - remove the most ancient entry // g_lstEvents.pop_front (); } } catch (exception &ex) { VERBOSE (MEM_ERR, TEXT("Got an STL exception while handling with event list (%S)"), ex.what()); return ERROR_NOT_ENOUGH_MEMORY; } AddEventToView(&Event); dwRes = UpdateMonitorData(g_hMonitorDlg); return dwRes; } // AddStatusMonitorLogEvent void AddEventToView( PEVENT_ENTRY pEvent ) /*++ Routine description: Add event to the list view Arguments: pEvent - event data Return Value: none --*/ { DBG_ENTER(TEXT("AddEventToView")); ASSERTION (pEvent); if(!g_hListDetails) { return; } LV_ITEM lvi = {0}; DWORD dwItem; lvi.pszText = pEvent->tszTime ? pEvent->tszTime : TEXT(""); lvi.iItem = ListView_GetItemCount( g_hListDetails ); lvi.iSubItem = 0; lvi.mask = LVIF_TEXT | LVIF_IMAGE; lvi.iImage = pEvent->eIcon; dwItem = ListView_InsertItem( g_hListDetails, &lvi ); lvi.pszText = pEvent->tszEvent ? pEvent->tszEvent : TEXT(""); lvi.iItem = dwItem; lvi.iSubItem = 1; lvi.mask = LVIF_TEXT; ListView_SetItem( g_hListDetails, &lvi ); ListView_EnsureVisible(g_hListDetails, dwItem, FALSE); if(ListView_GetItemCount(g_hListDetails) > MAX_EVENT_LIST_SIZE) { ListView_DeleteItem(g_hListDetails, 0); } // // Autosize the last column to get rid of unnecessary horizontal scroll bar // ListView_SetColumnWidth(g_hListDetails, 1, LVSCW_AUTOSIZE_USEHEADER); } // AddEventToView DWORD OpenFaxMonitor(VOID) /*++ Routine description: Opens fax monitor dialog Arguments: none Return Value: Standard error code. --*/ { DWORD dwRes = ERROR_SUCCESS; DBG_ENTER(TEXT("OpenFaxMonitor"), dwRes); if(!g_hMonitorDlg) { // // Read 'top most' value // HKEY hKey; dwRes = RegOpenKeyEx(HKEY_CURRENT_USER, REGKEY_FAX_USERINFO, 0, KEY_READ, &hKey); if (ERROR_SUCCESS == dwRes) { g_bTopMost = GetRegistryDword(hKey, REGVAL_ALWAYS_ON_TOP); RegCloseKey( hKey ); } else { CALL_FAIL (WINDOW_ERR, TEXT ("RegOpenKeyEx"), dwRes); } // // Create the dialog // g_hMonitorDlg = CreateDialogParam(g_hResource, MAKEINTRESOURCE(IDD_MONITOR), NULL, FaxMonitorDlgProc, NULL); if(!g_hMonitorDlg) { dwRes = GetLastError(); CALL_FAIL (WINDOW_ERR, TEXT ("CreateDialogParam"), dwRes); return dwRes; } } // // Set the focus on the dialog and make it the top window // SetFocus(g_hMonitorDlg); SetActiveWindow(g_hMonitorDlg); SetWindowPos(g_hMonitorDlg, HWND_TOPMOST, 0, 0, 0, 0, SWP_SHOWWINDOW | SWP_NOMOVE | SWP_NOSIZE); if (!g_bTopMost) { SetWindowPos(g_hMonitorDlg, HWND_NOTOPMOST, 0, 0, 0, 0, SWP_SHOWWINDOW | SWP_NOMOVE | SWP_NOSIZE); } return dwRes; } // OpenFaxMonitor void OnDisconnect() /*++ Routine description: Abort current transmission OR Answer a call Return Value: none --*/ { DWORD dwRes = ERROR_SUCCESS; DBG_ENTER(TEXT("OnDisconnect"), dwRes); if(g_bAnswerNow) { // // The button shows 'Answer Now' // AnswerTheCall(); return; } // // Else, the button shows 'Disconnect' // if(!g_dwCurrentJobID) { // // No job - nothing to disconnect // SetStatusMonitorDeviceState(FAX_IDLE); return; } DWORD dwMsgId = (FAX_SENDING == g_devState) ? IDS_ABORT_SEND_CONFIRM : IDS_ABORT_RECEIVE_CONFIRM; if(IDYES != FaxMessageBox(g_hMonitorDlg, dwMsgId, MB_YESNO | MB_DEFBUTTON2 | MB_ICONQUESTION)) { return; } if(!Connect()) { dwRes = GetLastError(); CALL_FAIL (RPC_ERR, TEXT ("Connect"), dwRes); return; } FAX_JOB_ENTRY fje = {0}; fje.SizeOfStruct = sizeof(FAX_JOB_ENTRY); if(g_hDisconnect) { EnableWindow(g_hDisconnect, FALSE); } if (!FaxSetJob (g_hFaxSvcHandle, g_dwCurrentJobID, JC_DELETE, &fje)) { dwRes = GetLastError(); CALL_FAIL (RPC_ERR, TEXT ("FaxSetJob"), dwRes); if(g_hDisconnect) { EnableWindow(g_hDisconnect, TRUE); } if(ERROR_ACCESS_DENIED == dwRes) { FaxMessageBox(g_hMonitorDlg, IDS_DELETE_ACCESS_DENIED, MB_OK | MB_ICONSTOP); } } } // OnDisconnect void OnClearLog() /*++ Routine description: Clear the monitor event log Return Value: none --*/ { DBG_ENTER(TEXT("OnClearLog")); ASSERTION (g_hListDetails); try { g_lstEvents.clear(); } catch (exception &ex) { VERBOSE (MEM_ERR, TEXT("Got an STL exception while clearing the events list (%S)"), ex.what()); } if(!ListView_DeleteAllItems(g_hListDetails)) { CALL_FAIL (WINDOW_ERR, TEXT ("ListView_DeleteAllItems"), 0); } } // OnClearLog int FaxMessageBox( HWND hWnd, DWORD dwTextID, UINT uType ) /*++ Routine description: Open standard message box Arguments: hWnd - handle to owner window dwTextID - text resource ID in message box uType - message box style Return Value: MessageBox() return value --*/ { int iRes; DBG_ENTER(TEXT("FaxMessageBox"), iRes); TCHAR tsCaption[MAX_PATH]; TCHAR tsText[MAX_PATH]; DWORD dwRes; if (ERROR_SUCCESS != (dwRes = LoadAndFormatString (IDS_MESSAGE_BOX_CAPTION, tsCaption, ARR_SIZE(tsCaption)))) { SetLastError (dwRes); iRes = 0; return iRes; } if (ERROR_SUCCESS != (dwRes = LoadAndFormatString (dwTextID, tsText, ARR_SIZE(tsText)))) { SetLastError (dwRes); iRes = 0; return iRes; } iRes = AlignedMessageBox(hWnd, tsText, tsCaption, uType); return iRes; } // FaxMessageBox