//+------------------------------------------------------------------------- // // Microsoft Windows // // Copyright (C) Microsoft Corporation, 1999 - 1999 // // File: statdlg.cpp // //-------------------------------------------------------------------------- // StatDlg.cpp : implementation file // #include "stdafx.h" #include "ScAlert.h" #include "miscdef.h" #include "statmon.h" #include "StatDlg.h" #ifdef _DEBUG #define new DEBUG_NEW #undef THIS_FILE static char THIS_FILE[] = __FILE__; #endif //////////////////////////////////////////////////////////////////////////// #ifdef __cplusplus extern "C" { // Assume C declarations for C++ #endif // __cplusplus #ifdef __cplusplus } #endif /* __cplusplus */ ///////////////////////////////////////////////////////////////////////////////////// // // CSCStatusDlgThrd // IMPLEMENT_DYNCREATE(CSCStatusDlgThrd, CWinThread) /*++ InitInstance Must override init instance to perform UI thread initialization Arguments: Return Value: TRUE on build start message loop. FALSE otherwise Author: Chris Dudley 2/27/1997 --*/ BOOL CSCStatusDlgThrd::InitInstance( void ) { INT_PTR nResult = -1; // error creating dialog LONG lReturn = SCARD_S_SUCCESS; SCARDCONTEXT hSCardContext = NULL; // Acquire context with resource manager lReturn = SCardEstablishContext( SCARD_SCOPE_USER, NULL, NULL, &hSCardContext); if (lReturn != SCARD_S_SUCCESS) { nResult = IDCANCEL; } else { m_StatusDlg.SetContext(hSCardContext); // Run the dialog as Modal m_fStatusDlgUp = TRUE; nResult = m_StatusDlg.DoModal();// if the dialog is shut down by a // cancellation of the SCARDCONTEXT, // it will return IDCANCEL m_fStatusDlgUp = FALSE; } // Release context if (NULL != hSCardContext) { SCardReleaseContext(hSCardContext); } // Post message that the thread is exiting, based on return... if (NULL != m_hCallbackWnd) { ::PostMessage( m_hCallbackWnd, WM_SCARD_STATUS_DLG_EXITED, // CANCELLATION (0), or ERROR (1) 0, 0); } AfxEndThread(0); return TRUE; // to make compiler happy } /*++ void ShowDialog: Brings dialog to front if already open Arguments: None. Return Value: None. Author: Chris Dudley 7/30/1997 Note: --*/ void CSCStatusDlgThrd::ShowDialog( int nCmdShow, CStringArray* paIdleList ) { if (m_fStatusDlgUp) { m_StatusDlg.ShowWindow(nCmdShow); m_StatusDlg.SetIdleList(paIdleList); } } /*++ void UpdateStatus: If the dialog is up, updates idle list and status text Arguments: None. Return Value: None. Author: Chris Dudley 7/30/1997 Note: --*/ void CSCStatusDlgThrd::UpdateStatus( CStringArray* paIdleList ) { if (m_fStatusDlgUp) { m_StatusDlg.UpdateLogonLockInfo(); m_StatusDlg.SetIdleList(paIdleList); m_StatusDlg.UpdateStatusText(); } } /*++ void UpdateStatusText: If the dialog is up, updates Status Text and Arguments: None. Return Value: None. Author: Chris Dudley 7/30/1997 Note: --*/ void CSCStatusDlgThrd::UpdateStatusText( void ) { if (m_fStatusDlgUp) { m_StatusDlg.UpdateStatusText(); } } /*++ void Close: Closes modal dialog if already open Arguments: None. Return Value: None. Author: Chris Dudley 7/30/1997 Note: --*/ void CSCStatusDlgThrd::Close( void ) { // Setup for close if (m_fStatusDlgUp) { m_StatusDlg.EndDialog(IDOK); } m_fStatusDlgUp = FALSE; } /*++ void Update: This routine updates the UI. Arguments: None. Return Value: None. Author: Chris Dudley 7/30/1997 Note: --*/ void CSCStatusDlgThrd::Update( void ) { // Tell the dialog to update its statmonitor, if it's up. if (m_fStatusDlgUp) { m_StatusDlg.RestartMonitor(); } // Do other updating UpdateStatusText(); } ///////////////////////////////////////////////////////////////////////////// // // CSCStatusDlg dialog // CSCStatusDlg::CSCStatusDlg(CWnd* pParent /*=NULL*/) : CDialog(CSCStatusDlg::IDD, pParent) { //{{AFX_DATA_INIT(CSCStatusDlg) // NOTE: the ClassWizard will add member initialization here //}}AFX_DATA_INIT // Note that LoadIcon does not require a subsequent DestroyIcon in Win32 m_hIcon = AfxGetApp()->LoadIcon(IDI_SC_READERLOADED_V2); // Other initialization m_fEventsGood = FALSE; m_hSCardContext = NULL; m_aIdleList.RemoveAll(); UpdateLogonLockInfo(); } void CSCStatusDlg::UpdateLogonLockInfo(void) { m_pstrLogonReader = &(((CSCStatusApp*)AfxGetApp())->m_strLogonReader); m_pstrRemovalText = &(((CSCStatusApp*)AfxGetApp())->m_strRemovalText); m_fLogonLock = (!(m_pstrLogonReader->IsEmpty())); } void CSCStatusDlg::DoDataExchange(CDataExchange* pDX) { CDialog::DoDataExchange(pDX); //{{AFX_DATA_MAP(CSCStatusDlg) DDX_Control(pDX, IDC_SCARD_LIST, m_SCardList); DDX_Control(pDX, IDC_ALERT, m_btnAlert); DDX_Control(pDX, IDC_INFO, m_ediInfo); //}}AFX_DATA_MAP } BEGIN_MESSAGE_MAP(CSCStatusDlg, CDialog) //{{AFX_MSG_MAP(CSCStatusDlg) ON_WM_PAINT() ON_WM_QUERYDRAGICON() ON_WM_CLOSE() ON_MESSAGE( WM_READERSTATUSCHANGE, OnReaderStatusChange ) ON_WM_DESTROY() ON_BN_CLICKED(IDC_ALERT, OnAlertOptions) //}}AFX_MSG_MAP END_MESSAGE_MAP() ///////////////////////////////////////////////////////////////////////////// // // CSCStatusDlg Implementation /*++ BOOL SetContext: Sets the Context with the resource manager Arguments: SCardContext - the context Return Value: None. Author: Chris Dudley 3/6/1997 Revision History: Chris Dudley 5/13/1997 --*/ void CSCStatusDlg::SetContext(SCARDCONTEXT hSCardContext) { m_hSCardContext = hSCardContext; } /*++ void CleanUp: Routine cleans up for exit Arguments: None. Return Value: None. Author: Chris Dudley 3/11/1997 Revision History: Chris Dudley 5/13/1997 --*/ void CSCStatusDlg::CleanUp ( void ) { m_monitor.Stop(); m_SCardList.DeleteAllItems(); } /*++ void SetIdleList: Make a local copy of the app's list of readers with idle cards. Notes: --*/ void CSCStatusDlg::SetIdleList(CStringArray* paIdleList) { m_aIdleList.Copy(*paIdleList); long lResult = UpdateSCardListCtrl(); } /*++ void UpdateStatusText: Reflect card usage status in text. (alert message, howto, etc.) Notes: Not localization friendly. Move strings to resources. --*/ void CSCStatusDlg::UpdateStatusText( void ) { CString str; if (k_State_CardIdle == ((CSCStatusApp*)AfxGetApp())->m_dwState) { str = _T("A smart card has been left idle. You may safely remove it now."); } else { str = _T("Click the button on the left to change your alert options."); } m_ediInfo.SetWindowText(str); } /*++ void InitSCardListCtrl: This routine sets up the CListCtrl properly for display Arguments: None. Return Value: None. Author: Chris Dudley 3/6/1997 Revision History: Chris Dudley 5/13/1997 --*/ void CSCStatusDlg::InitSCardListCtrl( void ) { CString strHeader; CImageList imageList; HICON hicon; // Create columns in list control strHeader.LoadString(IDS_SC_READER); m_SCardList.InsertColumn(READER_COLUMN, strHeader, LVCFMT_LEFT, 100, -1); strHeader.LoadString(IDS_SC_CARDSTATUS); m_SCardList.InsertColumn(STATUS_COLUMN, strHeader, LVCFMT_LEFT, 600, -1); strHeader.LoadString(IDS_SC_CARD); m_SCardList.InsertColumn(CARD_COLUMN, strHeader, LVCFMT_LEFT, 100, -1); // Create the image list & give it to the list control imageList.Create ( IMAGE_WIDTH, IMAGE_HEIGHT, TRUE, // list does not include masks NUMBER_IMAGES, 0); // list won't grow // Build the list for (int ix = 0; ix < NUMBER_IMAGES; ix++ ) { // Load icon and add it to image list hicon = ::LoadIcon(AfxGetInstanceHandle(), MAKEINTRESOURCE(IMAGE_LIST_IDS[ix]) ); imageList.Add(hicon); } // Be sure that all the small icons were added. _ASSERTE(imageList.GetImageCount() == NUMBER_IMAGES); m_SCardList.SetImageList(&imageList, (int) LVSIL_SMALL); imageList.Detach(); // leave the images intact when we go out of scope } /*++ LONG UpdateSCardListCtrl: This routine updates the list box display. Arguments: None. Return Value: A LONG value indicating the status of the requested action. Please see the Smartcard header files for additional information. Author: Chris Dudley 3/7/1997 Revision History: Chris Dudley 5/13/1997 Notes: 1. Strings need to be converted from type stored in the smartcard thread help classes to this dialog's build type (i.e. UNICODE/ANSI)!!!! --*/ LONG CSCStatusDlg::UpdateSCardListCtrl( void ) { LONG lReturn = SCARD_S_SUCCESS; LONG lMoreReaders = SCARD_S_SUCCESS; CSCardReaderState* pReader; int nImage = 0; LV_ITEM lv_item; CString strCardStatus, strCardName; // // If the status monitor is not running, // Don't bother to update SCardListCtrl // If there used to be readers, display an error and shut down dialog // if (CScStatusMonitor::running != m_monitor.GetStatus()) { m_SCardList.EnableWindow(FALSE); DoErrorMessage(); return lReturn; } // Setup LV_ITEM struct lv_item.mask = LVIF_TEXT | LVIF_IMAGE | LVIF_PARAM | LVIF_STATE; // Remove old items from list if required m_SCardList.DeleteAllItems(); // // Update the reader information // m_monitor.GetReaderStatus(m_aReaderState); // // Recreate the items in the reader list (UI) // int nNumReaders = (int)m_aReaderState.GetSize(); for(int nIndex = 0; nIndex < nNumReaders; nIndex++) { // Setup struct for system reader list pReader = m_aReaderState[nIndex]; lv_item.state = 0; lv_item.stateMask = 0; lv_item.iItem = nIndex; lv_item.iSubItem = 0; lv_item.pszText = _T(""); lv_item.cchTextMax = MAX_ITEMLEN; lv_item.iImage = (int)READEREMPTY; if (NULL != pReader) { lv_item.pszText = (LPTSTR)(LPCTSTR)((m_aReaderState[nIndex])->strReader); // Get the card status: image DWORD dwState = (m_aReaderState[nIndex])->dwState; if (dwState == SC_STATUS_NO_CARD) { lv_item.iImage = (int)READEREMPTY; } else if (dwState == SC_STATUS_ERROR) { lv_item.iImage = (int)READERERROR; } else { // normally, this would be a "card loaded"... lv_item.iImage = (int)READERLOADED; // ...unless the card is the logon/locked card or idle if (m_fLogonLock && (0 == m_pstrLogonReader->Compare((m_aReaderState[nIndex])->strReader))) { lv_item.iImage = (int)READERLOCK; } else { for (int n1=(int)m_aIdleList.GetUpperBound(); n1>=0; n1--) { if (m_aIdleList[n1] == (m_aReaderState[nIndex])->strReader) { lv_item.iImage = (int)READERINFO; break; } } } } // Add Reader Item m_SCardList.InsertItem(&lv_item); // Add Card Name sub item if (dwState != SC_STATUS_NO_CARD && dwState != SC_STATUS_ERROR) { // Set card name if not available strCardName = (LPCTSTR)(m_aReaderState[nIndex])->strCard; if (strCardName.IsEmpty()) { strCardName.LoadString(IDS_SC_NAME_UNKNOWN); } m_SCardList.SetItemText(nIndex, CARD_COLUMN, strCardName); } // Add Card Status sub item ASSERT(dwState >= SC_STATUS_FIRST && dwState <= SC_STATUS_LAST); strCardStatus.LoadString(CARD_STATUS_IDS[dwState]); if (m_fLogonLock && (0 == m_pstrLogonReader->Compare((m_aReaderState[nIndex])->strReader))) { CString strTemp = *m_pstrRemovalText + strCardStatus; strCardStatus = strTemp; } m_SCardList.SetItemText(nIndex, STATUS_COLUMN, strCardStatus); strCardStatus.Empty(); strCardName.Empty(); } } // If we got this far, things are OK. Make sure the window is enabled. m_SCardList.EnableWindow(TRUE); return lReturn; } /*++ void RestartMonitor: This routine forces the monitor to refresh its list of readers. Arguments: None. Return Value: None. Author: Amanda Matlosz 11/04/1998 Notes: --*/ void CSCStatusDlg::RestartMonitor( void ) { m_monitor.Start(m_hWnd, WM_READERSTATUSCHANGE); } ///////////////////////////////////////////////////////////////////////////// // // CSCStatusDlg message handlers // /*++ void OnInitDialog: Performs dialog initialization. Arguments: None. Return Value: TRUE if successful and dialog should be displayed. FALSE otherwise. Author: Chris Dudley 7/30/1997 Note: --*/ BOOL CSCStatusDlg::OnInitDialog() { LONG lReturn = SCARD_S_SUCCESS; CDialog::OnInitDialog(); // // Initialize the CScStatusMonitor // m_monitor.Start(m_hWnd, WM_READERSTATUSCHANGE); // // Initialize the list control -- whether or not the monitor has started! // InitSCardListCtrl(); lReturn = UpdateSCardListCtrl(); // // Show the dialog IFF the above succeeded // if (SCARD_S_SUCCESS == lReturn) { // Set the status text UpdateStatusText(); // Set the icon for this dialog. The framework does this automatically // when the application's main window is not a dialog SetIcon(m_hIcon, TRUE); // Set big icon SetIcon(m_hIcon, FALSE); // Set small icon // set icon for Alerts button HICON hIcon = AfxGetApp()->LoadIcon(IDI_SC_INFO); SendDlgItemMessage(IDC_ALERT, BM_SETIMAGE, IMAGE_ICON, (LPARAM)hIcon); // Center the dialog and bring it to top CenterWindow(); SetWindowPos( &wndTop, 0,0,0,0, SWP_NOMOVE | SWP_NOSIZE); SetActiveWindow(); // Set Parent to desktop SetParent(NULL); } else { // // If any of the initialization depending on the resource manager failed, // give up and report a death-due-to-some-error to the caller // PostMessage(WM_CLOSE, 0, 0); // need to CANCEL, instead of close... TRACE_CATCH_UNKNOWN(_T("OnInitDialog")); } return TRUE; // return TRUE unless you set the focus to a control } /*++ void OnPaint: Used to paint dialog. In this case, used to draw the icon for the dialog while minimized/maximized. Arguments: None. Return Value: None. Author: Chris Dudley 7/30/1997 Note: --*/ void CSCStatusDlg::OnPaint() { if (IsIconic()) { CPaintDC dc(this); // device context for painting SendMessage(WM_ICONERASEBKGND, (WPARAM) dc.GetSafeHdc(), 0); // Center icon in client rectangle int cxIcon = GetSystemMetrics(SM_CXICON); int cyIcon = GetSystemMetrics(SM_CYICON); CRect rect; GetClientRect(&rect); int x = (rect.Width() - cxIcon + 1) / 2; int y = (rect.Height() - cyIcon + 1) / 2; // Draw the icon dc.DrawIcon(x, y, m_hIcon); } else { CDialog::OnPaint(); } } /*++ void OnQueryDragIcon: The system calls this to obtain the cursor to display while the user drags the minimized window. Arguments: None. Return Value: HCURSOR handle to cursor to display Author: Chris Dudley 7/30/1997 Note: --*/ HCURSOR CSCStatusDlg::OnQueryDragIcon() { return (HCURSOR) m_hIcon; } /*++ void DestroyWindow: This is called by MFC whenever the dialog is closed, whether that is through WM_CLOSE (sysmenu "X") or EndDialog(IDOK/IDCANCEL)... Arguments: None. Return Value: Base class version of DestroyWindow. Author: Amanda Matlosz 4/29/98 Note: --*/ BOOL CSCStatusDlg::DestroyWindow() { CleanUp(); return CDialog::DestroyWindow(); } /*++ void OnReaderStatusChange: This message handler is called by the status thread when smartcard status has changed. Arguments: None. Return Value: None Author: Chris Dudley 3/9/1997 Revision History: Chris Dudley 5/13/1997 Note: 1. No formal parameters are declared. These are not used and will stop compiler warnings from being generated. --*/ LONG CSCStatusDlg::OnReaderStatusChange( UINT , LONG ) { // Update the display UpdateSCardListCtrl(); return 0; } /*++ allow user to set alert options (sound, pop-up, neither) --*/ void CSCStatusDlg::OnAlertOptions() { COptionsDlg dlg; dlg.DoModal(); } /*++ void DoErrorMessage: This is a helper routine to keep the UI stuff in one place and make sure the same error messages are handled consistently throughout. Arguments: None. Return Value: None Author: Amanda Matlosz 5/21/98 Revision History: Note: 1. Consider taking an error code as well as m_monitor.GetStatus() --*/ void CSCStatusDlg::DoErrorMessage( void ) { CString strMsg; BOOL fShutDownDlg = FALSE; switch(m_monitor.GetStatus()) { case CScStatusMonitor::no_service: fShutDownDlg = TRUE; strMsg.LoadString(IDS_NO_SYSTEM_STATUS); break; case CScStatusMonitor::no_readers: // for now, do nothing! break; case CScStatusMonitor::stopped: // do nothing! This is a clean stop on the way to shutting down. break; case CScStatusMonitor::uninitialized: case CScStatusMonitor::unknown: case CScStatusMonitor::running: fShutDownDlg = TRUE; strMsg.LoadString(IDS_UNKNOWN_ERROR); } if (!strMsg.IsEmpty()) { CString strTitle; strTitle.LoadString(IDS_TITLE_ERROR); MessageBox(strMsg, strTitle, MB_OK | MB_ICONINFORMATION); } if (fShutDownDlg) { PostMessage(WM_CLOSE, 0, 0); } } ///////////////////////////////////////////////////////////////////////////// // COptionsDlg dialog COptionsDlg::COptionsDlg(CWnd* pParent /*=NULL*/) : CDialog(COptionsDlg::IDD, pParent) { BOOL fSound = FALSE; BOOL fDlg = FALSE; switch(((CSCStatusApp*)AfxGetApp())->m_dwAlertOption) { case k_AlertOption_IconSound: fSound = TRUE; break; case k_AlertOption_IconSoundMsg: fSound = TRUE; case k_AlertOption_IconMsg: fDlg = TRUE; break; } //{{AFX_DATA_INIT(COptionsDlg) m_fDlg = fDlg; m_fSound = fSound; //}}AFX_DATA_INIT } void COptionsDlg::DoDataExchange(CDataExchange* pDX) { CDialog::DoDataExchange(pDX); //{{AFX_DATA_MAP(COptionsDlg) DDX_Check(pDX, IDC_DIALOG, m_fDlg); DDX_Check(pDX, IDC_SOUND, m_fSound); //}}AFX_DATA_MAP } BEGIN_MESSAGE_MAP(COptionsDlg, CDialog) //{{AFX_MSG_MAP(COptionsDlg) //}}AFX_MSG_MAP END_MESSAGE_MAP() ///////////////////////////////////////////////////////////////////////////// // COptionsDlg message handlers void COptionsDlg::OnOK() { // use status of check boxes to set alert options state for app UpdateData(TRUE); if (TRUE == m_fSound) { if (TRUE == m_fDlg) { ((CSCStatusApp*)AfxGetApp())->m_dwAlertOption = k_AlertOption_IconSoundMsg; } else { ((CSCStatusApp*)AfxGetApp())->m_dwAlertOption = k_AlertOption_IconSound; } } else if (TRUE == m_fDlg) { ((CSCStatusApp*)AfxGetApp())->m_dwAlertOption = k_AlertOption_IconMsg; } else { ((CSCStatusApp*)AfxGetApp())->m_dwAlertOption = k_AlertOption_IconOnly; } CDialog::OnOK(); }