//+------------------------------------------------------------------------- // // Microsoft Windows // // Copyright (C) Microsoft Corporation, 1998 - 1999 // // File: ScInsDlg.cpp // //-------------------------------------------------------------------------- // ScInsDlg.cpp : implementation file // #include "stdafx.h" #include #include "resource.h" #include "scdlg.h" #include "ScSearch.h" #include "ScInsDlg.h" #include "statmon.h" #include "scHlpArr.h" #ifdef _DEBUG #define new DEBUG_NEW #undef THIS_FILE static char THIS_FILE[] = __FILE__; #endif ///////////////////////////////////////////////////////////////////////////// // CScInsertDlg dialog CScInsertDlg::CScInsertDlg(CWnd* pParent/*=NULL*/) : CDialog(CScInsertDlg::IDD, pParent) { // Member Initialization m_lLastError = SCARD_S_SUCCESS; m_ParentHwnd = pParent; m_pOCNW = NULL; m_pOCNA = NULL; m_pSelectedReader = NULL; m_pSubDlg = NULL; m_strTitle.Empty(); m_strPrompt.Empty(); m_mstrAllCards = ""; //{{AFX_DATA_INIT(CScInsertDlg) // NOTE: the ClassWizard will add member initialization here //}}AFX_DATA_INIT } CScInsertDlg::~CScInsertDlg() { // Stop status monitor m_monitor.Stop(); // Clean up status list! if (0 != m_aReaderState.GetSize()) { for (int i = (int)m_aReaderState.GetUpperBound(); i>=0; i--) { delete m_aReaderState[i]; } m_aReaderState.RemoveAll(); } } void CScInsertDlg::DoDataExchange(CDataExchange* pDX) { CDialog::DoDataExchange(pDX); //{{AFX_DATA_MAP(CScInsertDlg) DDX_Control(pDX, IDC_DETAILS, m_btnDetails); //}}AFX_DATA_MAP } BEGIN_MESSAGE_MAP(CScInsertDlg, CDialog) //{{AFX_MSG_MAP(CScInsertDlg) ON_MESSAGE( WM_READERSTATUSCHANGE, OnReaderStatusChange ) ON_BN_CLICKED(IDC_DETAILS, OnDetails) ON_WM_HELPINFO() ON_WM_CONTEXTMENU() //}}AFX_MSG_MAP END_MESSAGE_MAP() ///////////////////////////////////////////////////////////////////////////// // CScInsertDlg data methods /*++ LONG Initialize: Stores the open card name pointer in the proper internal struct. Determines whether to show the dialog in details or brief mode. Arguments: pOCN(x) - pointer to an open card name ex struct Return Value: A LONG value indicating the status of the requested action. Please see the Smartcard header files for additional information. Author: Amanda Matlosz 07/09/1998 --*/ // ANSI LONG CScInsertDlg::Initialize(LPOPENCARDNAMEA_EX pOCNA, DWORD dwNumOKCards, LPCSTR mszOKCards) { _ASSERTE(NULL != pOCNA); if (NULL == pOCNA) { return SCARD_F_UNKNOWN_ERROR; } m_pOCNA = pOCNA; m_strTitle = m_pOCNA->lpstrTitle; m_strPrompt = m_pOCNA->lpstrSearchDesc; m_mstrAllCards = mszOKCards; m_hIcon = pOCNA->hIcon; // hide details if no suitable cards available, else show details m_fDetailsShown = (0==dwNumOKCards) ? FALSE : TRUE; // prepare critical section for UI routines m_pCritSec = new CCriticalSection(); if (NULL == m_pCritSec) { return ERROR_OUTOFMEMORY; // TODO: is another errorcode more appropriate? } // put dialog on top SetForegroundWindow(); return SCARD_S_SUCCESS; } //UNICODE HRESULT CScInsertDlg::Initialize(LPOPENCARDNAMEW_EX pOCNW, DWORD dwNumOKCards, LPCWSTR mszOKCards) { _ASSERTE(NULL != pOCNW); if (NULL == pOCNW) { return SCARD_F_UNKNOWN_ERROR; } m_pOCNW = pOCNW; m_strTitle = m_pOCNW->lpstrTitle; m_strPrompt = m_pOCNW->lpstrSearchDesc; m_mstrAllCards = mszOKCards; m_hIcon = pOCNW->hIcon; // hide details if no suitable cards available, else show details m_fDetailsShown = (0==dwNumOKCards) ? FALSE : TRUE; // prepare critical section for UI routines m_pCritSec = new CCriticalSection(); if (NULL == m_pCritSec) { return ERROR_OUTOFMEMORY; // TODO: is another errorcode more appropriate? } // put dialog on top SetForegroundWindow(); return SCARD_S_SUCCESS; } void CScInsertDlg::EnableOK(BOOL fEnabled) { CButton* pBtn = (CButton*)GetDlgItem(IDOK); _ASSERTE(NULL != pBtn); pBtn->EnableWindow(fEnabled); // // Change prompt text accordingly and set the OK button // to be default if it's enabled // CString strPrompt; if (fEnabled) { strPrompt.LoadString(IDS_SC_FOUND); // set default, remove default pBtn->SetButtonStyle(BS_DEFPUSHBUTTON); pBtn = (CButton*)GetDlgItem(IDCANCEL); _ASSERTE(NULL != pBtn); pBtn->SetButtonStyle(BS_PUSHBUTTON); pBtn = (CButton*)GetDlgItem(IDC_DETAILS); // details can sometimes get set to default _ASSERTE(NULL != pBtn); pBtn->SetButtonStyle(BS_PUSHBUTTON); } else { _ASSERTE(!m_strPrompt.IsEmpty()); strPrompt = m_strPrompt; // remove default, set default pBtn->SetButtonStyle(BS_PUSHBUTTON); pBtn = (CButton*)GetDlgItem(IDCANCEL); _ASSERTE(NULL != pBtn); pBtn->SetButtonStyle(BS_DEFPUSHBUTTON); pBtn = (CButton*)GetDlgItem(IDC_DETAILS); // details can sometimes get set to default _ASSERTE(NULL != pBtn); pBtn->SetButtonStyle(BS_PUSHBUTTON); } CWnd* pDlgItem = GetDlgItem(IDC_PROMPT); _ASSERTE(NULL != pDlgItem); pDlgItem->SetWindowText(strPrompt); } void CScInsertDlg::DisplayError(UINT uiErrorMsg) { CString strTitle, strMsg; strTitle.LoadString(IDS_SC_TITLE_ERROR); strMsg.LoadString(uiErrorMsg); MessageBox(strMsg, strTitle, MB_OK | MB_ICONEXCLAMATION); } void CScInsertDlg::SetSelection(CSCardReaderState* pRdrSt) { m_pSelectedReader = pRdrSt; EnableOK(IsSelectionOK()); } BOOL CScInsertDlg::SameCard(CSCardReaderState* p1, CSCardReaderState* p2) { _ASSERTE(NULL != p1); _ASSERTE(NULL != p2); if ((NULL == p1) && (NULL == p2)) { return TRUE; } if ((NULL == p1) || (NULL == p2)) { return FALSE; } // same reader & card? if ((0 == p1->strReader.Compare(p2->strReader)) && (0 == p1->strCard.Compare(p2->strCard))) { // no drastic state change? if(p1->dwState == p2->dwState) { return TRUE; } if(((p1->dwState == SC_SATATUS_AVAILABLE) || (p1->dwState == SC_STATUS_SHARED) || (p1->dwState == SC_STATUS_EXCLUSIVE)) && ((p2->dwState == SC_SATATUS_AVAILABLE) || (p2->dwState == SC_STATUS_SHARED) || (p2->dwState == SC_STATUS_EXCLUSIVE)) ) { return TRUE; } } return FALSE; } ///////////////////////////////////////////////////////////////////////////// // CScInsertDlg message handlers /*++ void ShowHelp: Helper function for OnHelpInfo and OnContextMenu. BOOL OnHelpInfo: Called by the MFC framework when the user hits F1. void OnContextMenu Called by the MFC framework when the user right-clicks. Author: Amanda Matlosz 03/04/1999 Note: These three functions work together to provide context-sensitive help for the insertdlg. Similar functions are declared for CScInsertBar --*/ void CScInsertDlg::ShowHelp(HWND hWnd, UINT nCommand) { ::WinHelp(hWnd, _T("SCardDlg.hlp"), nCommand, (DWORD_PTR)(PVOID)g_aHelpIDs_IDD_SCARDDLG1); } afx_msg BOOL CScInsertDlg::OnHelpInfo(LPHELPINFO lpHelpInfo) { _ASSERTE(NULL != lpHelpInfo); ShowHelp((HWND)lpHelpInfo->hItemHandle, HELP_WM_HELP); return TRUE; } afx_msg void CScInsertDlg::OnContextMenu(CWnd* pWnd, CPoint pt) { _ASSERTE(NULL != pWnd); ShowHelp(pWnd->m_hWnd, HELP_CONTEXTMENU); } /*++ void OnReaderStatusChange: This message handler is called by the status thread when smartcard status has changed. Arguments: None. Return Value: IGNORED BY CALLER. Long indicating status of ResMgr calls. Author: Amanda Matlosz 07/09/1998 Note: No formal parameters are declared. These are not used and will stop compiler warnings from being generated. The long param takes the result of no_service or stopped --*/ LONG CScInsertDlg::OnReaderStatusChange(UINT uint, LONG lParam) { // Is monitor still alive? CScStatusMonitor::status status = m_monitor.GetStatus(); if (CScStatusMonitor::running != status) { m_pSubDlg->EnableStatusList(FALSE); SetSelection(NULL); // JIC // display appropriate error & set m_lLastError switch(status) { case CScStatusMonitor::no_service: case CScStatusMonitor::stopped: m_lLastError = lParam; DisplayError(IDS_SC_RM_ERR); break; case CScStatusMonitor::no_readers: m_lLastError = SCARD_E_NO_READERS_AVAILABLE; DisplayError(IDS_SC_NO_READERS); break; default: m_lLastError = SCARD_F_UNKNOWN_ERROR; DisplayError(IDS_UNKNOWN_ERROR); break; } } else { // crit section around member reader/card status array _ASSERTE(m_pCritSec); if (m_pCritSec) { m_pCritSec->Lock(); } // make local copy of recent reader state array, // so we know which cards have already been checked CSCardReaderStateArray aPreviousReaderState; aPreviousReaderState.RemoveAll(); for (int nCopy = (int)m_aReaderState.GetUpperBound(); nCopy>=0; nCopy--) { CSCardReaderState* pReader = NULL; pReader = new CSCardReaderState(m_aReaderState[nCopy]); if (NULL != pReader) { aPreviousReaderState.Add(pReader); } } // udpate array from CStatusMonitor // check cards that have not been previously checked, // & update UI m_monitor.GetReaderStatus(m_aReaderState); for (int n = (int)m_aReaderState.GetUpperBound(); n>=0; n--) { CSCardReaderState* pReader = m_aReaderState[n]; BOOL fAlreadyChecked = FALSE; // have we checked this card before? for (int nPrev = (int)aPreviousReaderState.GetUpperBound(); (nPrev>=0 && !fAlreadyChecked); nPrev--) { if (SameCard(pReader, aPreviousReaderState[nPrev])) { pReader->fOK = (aPreviousReaderState[nPrev])->fOK; fAlreadyChecked = TRUE; } } // if this is a new card, or if the card's status has changed // drastically since we last looked at it, check it again if (!fAlreadyChecked) { if (NULL != m_pOCNW) { m_aReaderState[n]->fOK = CheckCardAll( m_aReaderState[n], m_pOCNW, (LPCWSTR)m_mstrAllCards); } else { _ASSERTE(NULL != m_pOCNA); m_aReaderState[n]->fOK = CheckCardAll( m_aReaderState[n], m_pOCNA, (LPCWSTR)m_mstrAllCards); } } } // the subdialog will handle automatic reader selection m_pSubDlg->UpdateStatusList(&m_aReaderState); // clean up for (int nX = (int)aPreviousReaderState.GetUpperBound(); nX>=0; nX--) { delete aPreviousReaderState[nX]; } aPreviousReaderState.RemoveAll(); // end crit section if (m_pCritSec) { m_pCritSec->Unlock(); } } return (long)SCARD_S_SUCCESS; // there's no one to receive this. } void CScInsertDlg::OnDetails() { // // If the details are currently shown, hide them... // otherwise, show them. // CRect rectWin; GetWindowRect(&rectWin); CRect rectButtonBottom; CString strDetailsCaption; // // Determine the new height of the dialog & resize // int nNewHeight = 0; if (m_fDetailsShown) { nNewHeight = m_SmallHeight; strDetailsCaption.LoadString(IDS_DETAILS_SHOW); } else { nNewHeight = m_BigHeight; strDetailsCaption.LoadString(IDS_DETAILS_HIDE); } ScreenToClient(&rectButtonBottom); rectWin.bottom = rectWin.top + nNewHeight; SetWindowPos(NULL, rectWin.left, rectWin.top, rectWin.Width(), rectWin.Height(), SWP_NOMOVE | SWP_NOZORDER); // // change captions, move buttons, show or hide the details section // m_btnDetails.SetWindowText(strDetailsCaption); MoveButton(IDC_DETAILS, nNewHeight - m_yMargin); MoveButton(IDOK, nNewHeight - m_yMargin); MoveButton(IDCANCEL, nNewHeight - m_yMargin); ToggleSubDialog(); // // remember our new state // m_fDetailsShown = !m_fDetailsShown; } BOOL CScInsertDlg::OnInitDialog() { CDialog::OnInitDialog(); // // Initialize bits to query RM; if these fail, there's no point to go on // but the user should see an error message. // // kick off CSCStatusMonitor m_lLastError = m_monitor.Start(m_hWnd, WM_READERSTATUSCHANGE); // if not running or no readers available CScStatusMonitor::status status = m_monitor.GetStatus(); if (SCARD_S_SUCCESS != m_lLastError) { switch(status) { case CScStatusMonitor::no_service: DisplayError(IDS_SC_RM_ERR); break; case CScStatusMonitor::no_readers: // DisplayError(IDS_SC_NO_READERS); // Bug 15742 -> will die quietly (no UI) break; case CScStatusMonitor::running: _ASSERTE(FALSE); // How can this be running if an error was returned?????? // no break; go ahead an report an 'unknown error' default: DisplayError(IDS_UNKNOWN_ERROR); break; } PostMessage(WM_CLOSE, 0, 0); return TRUE; } _ASSERTE(status == CScStatusMonitor::running); // // Determine constant offsets for resizing window (on details) // CRect rectWin, rectDlgItem; GetWindowRect(&rectWin); m_SmallHeight = rectWin.Height(); CWnd* pDlgItem = GetDlgItem(IDOK); _ASSERTE(NULL != pDlgItem); pDlgItem->GetWindowRect(&rectDlgItem); ScreenToClient(rectDlgItem); m_yMargin = m_SmallHeight - rectDlgItem.bottom; pDlgItem = GetDlgItem(IDC_BUTTON_BOTTOM); _ASSERTE(NULL != pDlgItem); pDlgItem->GetWindowRect(&rectDlgItem); ScreenToClient(rectDlgItem); m_BigHeight = rectDlgItem.bottom + m_yMargin; // // Add user-provided or ReaderLoaded icon // if (NULL == m_hIcon) { m_hIcon = AfxGetApp()->LoadIcon(IDI_SC_READERLOADED_V2); } _ASSERTE(NULL != m_hIcon); pDlgItem = GetDlgItem(IDC_USERICON); _ASSERTE(NULL != pDlgItem); pDlgItem->SetIcon(m_hIcon, TRUE); // TRUE: 32x32 icon // // Add other User-Customization bits // if (!m_strTitle.IsEmpty()) { SetWindowText(m_strTitle); } if (m_strPrompt.IsEmpty()) { // Use the default prompt text. m_strPrompt.LoadString(IDS_SC_PROMPT_ANYCARD); } pDlgItem = GetDlgItem(IDC_PROMPT); _ASSERTE(NULL != pDlgItem); pDlgItem->SetWindowText(m_strPrompt); // by default, is not enabled (subdlg's OnInitDlg might change that) EnableOK(FALSE); // // Set HELP ID(s) for context help // pDlgItem = GetDlgItem(IDC_DETAILS); _ASSERTE(NULL != pDlgItem); pDlgItem->SetWindowContextHelpId(IDH_DLG1_DETAILS_BTN); // // Add CScInsertBar (actually, a CDialog-derivative) to our dialog // pDlgItem = GetDlgItem(IDC_DLGBAR); _ASSERTE(NULL != pDlgItem); pDlgItem->GetWindowRect(&rectDlgItem); ScreenToClient(rectDlgItem); m_pSubDlg = new CScInsertBar(this); _ASSERTE(NULL != m_pSubDlg); if (NULL == m_pSubDlg) { m_lLastError = ERROR_OUTOFMEMORY; PostMessage(WM_CLOSE, 0, 0); return TRUE; } m_pSubDlg->Create(IDD_SCARDDLG_BAR, this); m_pSubDlg->SetWindowPos(NULL, rectDlgItem.left, rectDlgItem.top, 0, 0, SWP_NOSIZE | SWP_NOACTIVATE); // TODO: SWP_NOZORDER ?? // // Set the dialog to alter itself to match how it was called // m_fDetailsShown = !m_fDetailsShown; OnDetails(); if (m_fDetailsShown) { return FALSE; // focus should be set to list control } return TRUE; // return TRUE unless you set the focus to a control // EXCEPTION: OCX Property Pages should return FALSE } void CScInsertDlg::MoveButton(UINT nID, int newBottom) { CWnd* pBtn = GetDlgItem(nID); _ASSERTE(NULL != pBtn); CRect rect; pBtn->GetWindowRect(&rect); ScreenToClient(&rect); rect.top = newBottom - rect.Height(); pBtn->SetWindowPos(NULL, rect.left, rect.top, 0, 0, SWP_NOZORDER | SWP_NOSIZE | SWP_NOACTIVATE); } void CScInsertDlg::ToggleSubDialog() { // // All you need to do to toggle the sub dialog's accessibility // is to hide&disable or show&enable the window. // if (m_fDetailsShown) { m_pSubDlg->ShowWindow(SW_HIDE); m_pSubDlg->EnableWindow(FALSE); } else { m_pSubDlg->ShowWindow(SW_SHOW); m_pSubDlg->EnableWindow(TRUE); } } BOOL CScInsertDlg::DestroyWindow() { if (NULL != m_pSubDlg) { m_pSubDlg->DestroyWindow(); delete m_pSubDlg; } return CDialog::DestroyWindow(); } /*++ void OnOK: Handle user's , error if can't complete Arguments: None. Return Value: None Author: Amanda Matlosz 4/28/98 --*/ void CScInsertDlg::OnOK() { USES_CONVERSION; // Must have something selected to exit if (NULL == m_pSelectedReader || m_pSelectedReader->strCard.IsEmpty()) { DisplayError(IDS_SC_SELECT); return; } // Must have selected something we're looking for... if (!(m_pSelectedReader->fOK)) { DisplayError(IDS_SC_NOMATCH); return; } // Call the correct method to set the *real* card selection if(NULL != m_pOCNA) { LPSTR szCard = W2A(m_pSelectedReader->strCard); LPSTR szReader = W2A(m_pSelectedReader->strReader); m_lLastError = SetFinalCardSelection(szReader, szCard, m_pOCNA); } else { _ASSERTE(NULL != m_pOCNW); LPWSTR szCard = m_pSelectedReader->strCard.GetBuffer(1); LPWSTR szReader = m_pSelectedReader->strReader.GetBuffer(1); m_lLastError = SetFinalCardSelection(szReader, szCard, m_pOCNW); m_pSelectedReader->strCard.ReleaseBuffer(); m_pSelectedReader->strReader.ReleaseBuffer(); } if (SCARD_S_SUCCESS != m_lLastError) { DisplayError(IDS_SC_CONNECT_FAILED); // Either connect failed or out of memory - close enough. return; } CDialog::OnOK(); }