// Copyright (c) 1995, Microsoft Corporation, all rights reserved // // autodial.c // Remote Access Common Dialog APIs // Autodial APIs, currently private // // 11/19/95 Steve Cobb #include "rasdlgp.h" #include "shlobjp.h" //----------------------------------------------------------------------------- // Local datatypes //----------------------------------------------------------------------------- // Auto-dial query dialog argument block. // typedef struct _AQARGS { WCHAR* pszDestination; WCHAR* pszEntry; WCHAR* pszNewEntry; // points a buffer at least [RAS_MaxEntryName + 1] DWORD dwTimeout; UINT_PTR nIdTimer; //add for bug 336524 gangz } AQARGS; // Auto-dial query dialog context block. // typedef struct _AQINFO { // RAS API arguments. // AQARGS* pArgs; // Handle of this dialog and some of it's controls. // HWND hwndDlg; HWND hwndStText; HWND hwndAqPbNo; HWND hwndAqPbSettings; HWND hwndAqLvConnections; } AQINFO; //----------------------------------------------------------------------------- // External entry points //----------------------------------------------------------------------------- DWORD APIENTRY RasAutodialQueryDlgA( IN HWND hwndOwner, IN LPSTR lpszDestination, IN LPSTR lpszEntry, IN DWORD dwTimeout, OUT LPSTR lpszEntryUserSelected); BOOL APIENTRY RasAutodialDisableDlgA( IN HWND hwndOwner ); DWORD APIENTRY RasUserPrefsDlgAutodial ( HWND hwndParent); //----------------------------------------------------------------------------- // Local prototypes (alphabetically) //----------------------------------------------------------------------------- INT_PTR CALLBACK AqDlgProc( IN HWND hwnd, IN UINT unMsg, IN WPARAM wparam, IN LPARAM lparam ); BOOL AqCommand( IN HWND hwnd, IN WORD wNotification, IN WORD wId, IN HWND hwndCtrl ); BOOL AqInit( IN HWND hwndDlg, IN AQARGS* pArgs ); LVXDRAWINFO* AqLvCallback( IN HWND hwndLv, IN DWORD dwItem ); BOOL AqNotify( HWND hwnd, int idCtrl, LPNMHDR pnmh); VOID AqTerm( IN HWND hwndDlg ); //Add the timer function for bug 336524 // BOOL AqTimer( IN HWND hwndDlg ); INT_PTR CALLBACK DqDlgProc( IN HWND hwnd, IN UINT unMsg, IN WPARAM wparam, IN LPARAM lparam ); BOOL DqCommand( IN HWND hwnd, IN WORD wNotification, IN WORD wId, IN HWND hwndCtrl ); BOOL DqInit( IN HWND hwndDlg ); //----------------------------------------------------------------------------- // Auto-Dial Query dialog Listed alphabetically following API and dialog proc //----------------------------------------------------------------------------- DWORD APIENTRY RasAutodialQueryDlgW( IN HWND hwndOwner, IN LPWSTR lpszDestination, IN LPWSTR lpszEntry, IN DWORD dwTimeout, OUT PWCHAR lpszNewEntry) // Private external entry point to popup the Auto-Dial Query, i.e. the // "Cannot reach 'pszDestination'. Do you want to dial?" dialog. // 'HwndOwner' is the owning window or NULL if none. 'PszDestination' is // the network address that triggered the auto-dial for display. // 'DwTimeout' is the initial seconds on the countdown timer that ends the // dialog with a "do not dial" selection on timeout, or 0 for none. // // Returns true if user chooses to dial, false otherwise. // { INT_PTR nStatus; AQARGS args; DWORD dwErr = NO_ERROR; TRACE1( "RasAutodialQueryDlgW(t=%d)", dwTimeout ); ZeroMemory(&args, sizeof(args)); args.dwTimeout = dwTimeout; args.pszDestination = StrDup( lpszDestination ); args.pszNewEntry = lpszNewEntry; if (lpszEntry) { args.pszEntry = StrDup( lpszEntry ); } if (args.pszDestination == NULL) { Free0(args.pszEntry); return ERROR_NOT_ENOUGH_MEMORY; } nStatus = DialogBoxParam( g_hinstDll, MAKEINTRESOURCE( DID_AQ_AutoDialQuery ), hwndOwner, AqDlgProc, (LPARAM )&args ); Free0( args.pszDestination ); Free0( args.pszEntry ); if (nStatus == -1) { dwErr = GetLastError(); ErrorDlg( hwndOwner, SID_OP_LoadDlg, dwErr, NULL ); nStatus = FALSE; } else { dwErr = (DWORD)nStatus; } return dwErr; } DWORD APIENTRY RasAutodialQueryDlgA( IN HWND hwndOwner, IN LPSTR lpszDestination, IN LPSTR lpszEntry, IN DWORD dwTimeout, OUT LPSTR lpszEntryUserSelected) // Private external entry point to popup the Auto-Dial Query, i.e. the // "Cannot reach 'pszDestination'. Do you want to dial?" dialog. // 'HwndOwner' is the owning window or NULL if none. 'PszDestination' is // the network address that triggered the auto-dial for display. // 'DwTimeout' is the initial seconds on the countdown timer that ends the // dialog with a "do not dial" selection on timeout, or 0 for none. // // Returns true if user chooses to dial, false otherwise. // { WCHAR* pszDestinationW = NULL, *pszEntryW = NULL; WCHAR pszNewEntryW[RAS_MaxEntryName + 1]; BOOL dwErr = ERROR_NOT_ENOUGH_MEMORY; pszNewEntryW[0] = L'\0'; pszDestinationW = StrDupWFromAUsingAnsiEncoding( lpszDestination ); if ( lpszEntry ) { pszEntryW = StrDupWFromAUsingAnsiEncoding ( lpszEntry ); } if (NULL != pszDestinationW) { dwErr = RasAutodialQueryDlgW( hwndOwner, pszDestinationW, pszEntryW, dwTimeout, pszNewEntryW); Free( pszDestinationW ); } Free0( pszEntryW ); StrCpyAFromWUsingAnsiEncoding( lpszEntryUserSelected, pszNewEntryW, sizeof(pszNewEntryW) / sizeof(WCHAR)); return dwErr; } INT_PTR CALLBACK AqDlgProc( IN HWND hwnd, IN UINT unMsg, IN WPARAM wparam, IN LPARAM lparam ) // DialogProc callback for the Auto-Dial Query dialog. Parameters and // return value are as described for standard windows 'DialogProc's. // { if (ListView_OwnerHandler( hwnd, unMsg, wparam, lparam, AqLvCallback )) { return TRUE; } switch (unMsg) { case WM_INITDIALOG: { return AqInit( hwnd, (AQARGS* )lparam ); } case WM_COMMAND: { return AqCommand( hwnd, HIWORD( wparam ), LOWORD( wparam ), (HWND )lparam ); } case WM_NOTIFY: { return AqNotify(hwnd, (int)wparam, (LPNMHDR) lparam); } case WM_TIMER: { return AqTimer( hwnd ); } case WM_DESTROY: { AqTerm( hwnd ); break; } } return FALSE; } BOOL AqCommand( IN HWND hwnd, IN WORD wNotification, IN WORD wId, IN HWND hwndCtrl ) // Called on WM_COMMAND. 'Hwnd' is the dialog window. 'WNotification' is // the notification code of the command. 'wId' is the control/menu // identifier of the command. 'HwndCtrl' is the control window handle of // the command. // // Returns true if processed message, false otherwise. // { DWORD dwErr = NO_ERROR; INT iSelected; AQINFO* pInfo = NULL; TRACE3( "AqCommand(n=%d,i=%d,c=$%x)", (DWORD )wNotification, (DWORD )wId, (ULONG_PTR )hwndCtrl ); pInfo = (AQINFO* )GetWindowLongPtr( hwnd, DWLP_USER ); switch (wId) { case CID_AQ_PB_Settings: { if (pInfo) { //For whistler bug 357164 gangz // Save the "disable current session" checkbox, // { DWORD dwFlag = (DWORD )IsDlgButtonChecked( hwnd, CID_AQ_CB_DisableThisSession ); dwErr = g_pRasSetAutodialParam( RASADP_LoginSessionDisable, &dwFlag, sizeof(dwFlag) ); } //For whistler bug 336524 //Kill the timer ASSERT( pInfo->pArgs ); if( pInfo->pArgs->nIdTimer ) { KillTimer( hwnd, pInfo->pArgs->nIdTimer ); pInfo->pArgs->nIdTimer = 0; } RasUserPrefsDlgAutodial(pInfo->hwndDlg); //For whistler bug 357164 gangz // Initialize the "disable current session" checkbox // { DWORD dwFlag = FALSE, dwErrTmp = NO_ERROR; DWORD cb = sizeof(dwFlag); dwErrTmp = g_pRasGetAutodialParam( RASADP_LoginSessionDisable, &dwFlag, &cb ); // For whistler 522872 if( NO_ERROR != dwErrTmp ) { dwFlag = FALSE; } CheckDlgButton( hwnd, CID_AQ_CB_DisableThisSession, (BOOL )dwFlag ); } } return TRUE; } case CID_AQ_PB_Dial: case CID_AQ_PB_DoNotDial: { TRACE( "(No)Dial pressed" ); if (wId == CID_AQ_PB_Dial && pInfo) { iSelected = ListView_GetSelectionMark(pInfo->hwndAqLvConnections); // If user does not select a connection, then default to the // first one. Alternatively, an error popup could be // raised here but that is annoying. // if (iSelected == -1) { iSelected = 0; } // Get the name of the selected connection // if (pInfo) { ListView_GetItemText( pInfo->hwndAqLvConnections, iSelected, 0, pInfo->pArgs->pszNewEntry, RAS_MaxEntryName + 1); } } //For whistler bug 357164 gangz // Save the "disable current session" checkbox, // { DWORD dwFlag = (DWORD )IsDlgButtonChecked( hwnd, CID_AQ_CB_DisableThisSession ); dwErr = g_pRasSetAutodialParam( RASADP_LoginSessionDisable, &dwFlag, sizeof(dwFlag) ); } EndDialog( hwnd, (wId == CID_AQ_PB_Dial) ? NO_ERROR : ERROR_CANCELLED ); return TRUE; } case IDCANCEL: { TRACE( "Cancel pressed" ); EndDialog( hwnd, ERROR_CANCELLED ); return TRUE; } } return FALSE; } // Fills the list view of connections and selects the appropriate one to // dial // DWORD AqFillListView( IN AQINFO* pInfo) { DWORD dwErr = NO_ERROR, cb, cEntries = 0, i; RASENTRYNAME ren, *pRasEntryNames = NULL; LVITEM lvItem; INT iIndex, iSelect = 0; do { // Enumerate entries across all phonebooks. // cb = ren.dwSize = sizeof(RASENTRYNAME); ASSERT( g_pRasEnumEntries ); dwErr = g_pRasEnumEntries(NULL, NULL, &ren, &cb, &cEntries); // If there are no entries, then we return an error to signal that // there is no point to the dialog. // if ((SUCCESS == dwErr) && (0 == cEntries)) { dwErr = ERROR_CANCELLED; break; } // Allocate a buffer to receive the connections // if( ( (ERROR_BUFFER_TOO_SMALL == dwErr) || (SUCCESS == dwErr)) && (cb >= sizeof(RASENTRYNAME))) { pRasEntryNames = (RASENTRYNAME *) Malloc(cb); if(NULL == pRasEntryNames) { // Nothing else can be done in this case // dwErr = ERROR_NOT_ENOUGH_MEMORY; break; } pRasEntryNames->dwSize = sizeof(RASENTRYNAME); dwErr = g_pRasEnumEntries(NULL, NULL, pRasEntryNames, &cb, &cEntries); if ( NO_ERROR != dwErr ) { break; } } else { break; } // Initialize the list view // if (ListView_GetItemCount( pInfo->hwndAqLvConnections ) == 0) { // Add a single column exactly wide enough to fully display // the widest member of the list. // LV_COLUMN col; ZeroMemory( &col, sizeof(col) ); col.mask = LVCF_FMT; col.fmt = LVCFMT_LEFT; ListView_InsertColumn( pInfo->hwndAqLvConnections, 0, &col ); ListView_SetColumnWidth( pInfo->hwndAqLvConnections, 0, LVSCW_AUTOSIZE_USEHEADER ); } else { ListView_DeleteAllItems( pInfo->hwndAqLvConnections ); } // Fill the list view // for (i = 0; i < cEntries; i++) { ZeroMemory(&lvItem, sizeof(lvItem)); lvItem.mask = LVIF_TEXT; lvItem.pszText = pRasEntryNames[i].szEntryName; lvItem.iItem = i; iIndex = ListView_InsertItem( pInfo->hwndAqLvConnections, &lvItem ); if ((pInfo->pArgs->pszEntry) && (wcsncmp( pInfo->pArgs->pszEntry, pRasEntryNames[i].szEntryName, sizeof(pRasEntryNames[i].szEntryName) / sizeof(WCHAR)) == 0)) { iSelect = (iIndex != -1) ? iIndex : 0; } } }while (FALSE); // Select the appropriate connection // ListView_SetItemState( pInfo->hwndAqLvConnections, iSelect, LVIS_SELECTED | LVIS_FOCUSED, LVIS_SELECTED | LVIS_FOCUSED); // Cleanup { Free0(pRasEntryNames); } return dwErr; } BOOL AqInit( IN HWND hwndDlg, IN AQARGS* pArgs ) // Called on WM_INITDIALOG. 'hwndDlg' is the handle of the owning window. // 'PArgs' is caller's arguments to the RAS API. // // Return false if focus was set, true otherwise, i.e. as defined for // WM_INITDIALOG. // { DWORD dwErr; AQINFO* pInfo; TRACE( "AqInit" ); // Load the Rasapi32Dll so that we can enumerate connections // and set autodial properties // dwErr = LoadRasapi32Dll(); if (dwErr != NO_ERROR) { ErrorDlg( hwndDlg, SID_OP_LoadDlg, dwErr, NULL ); EndDialog( hwndDlg, FALSE); return TRUE; } // Allocate the dialog context block. Initialize minimally for proper // cleanup, then attach to the dialog window. // { pInfo = Malloc( sizeof(*pInfo) ); if (!pInfo) { ErrorDlg( hwndDlg, SID_OP_LoadDlg, ERROR_NOT_ENOUGH_MEMORY, NULL ); EndDialog( hwndDlg, FALSE ); return TRUE; } ZeroMemory( pInfo, sizeof(*pInfo) ); pInfo->pArgs = pArgs; pInfo->hwndDlg = hwndDlg; SetWindowLongPtr( hwndDlg, DWLP_USER, (ULONG_PTR )pInfo ); TRACE( "AQ: Context set" ); } pInfo->hwndStText = GetDlgItem( hwndDlg, CID_AQ_ST_Text ); ASSERT( pInfo->hwndStText ); pInfo->hwndAqPbNo = GetDlgItem( hwndDlg, CID_AQ_PB_DoNotDial ); ASSERT( pInfo->hwndAqPbNo ); pInfo->hwndAqPbSettings = GetDlgItem( hwndDlg, CID_AQ_PB_Settings ); ASSERT( pInfo->hwndAqPbSettings ); pInfo->hwndAqLvConnections = GetDlgItem( hwndDlg, CID_AQ_LV_Connections ); ASSERT( pInfo->hwndAqLvConnections ); // Fill in the listview of connections // dwErr = AqFillListView(pInfo); if (dwErr != NO_ERROR) { EndDialog(hwndDlg, dwErr); return TRUE; } // Fill in the argument in the explanatory text. // { TCHAR* pszTextFormat; TCHAR* pszText; TCHAR* apszArgs[ 1 ]; pszTextFormat = PszFromId( g_hinstDll, SID_AQ_Text ); if (pszTextFormat) { apszArgs[ 0 ] = pArgs->pszDestination; pszText = NULL; FormatMessage( FORMAT_MESSAGE_FROM_STRING | FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_ARGUMENT_ARRAY, pszTextFormat, 0, 0, (LPTSTR )&pszText, 1, (va_list* )apszArgs ); Free( pszTextFormat ); if (pszText) { SetWindowText( pInfo->hwndStText, pszText ); LocalFree( pszText ); } } } // Display the finished window above all other windows. The window // position is set to "topmost" then immediately set to "not topmost" // because we want it on top but not always-on-top. // SetWindowPos( hwndDlg, HWND_TOPMOST, 0, 0, 0, 0, SWP_NOACTIVATE | SWP_NOMOVE | SWP_NOSIZE ); CenterWindow( hwndDlg, GetParent( hwndDlg ) ); ShowWindow( hwndDlg, SW_SHOW ); SetWindowPos( hwndDlg, HWND_NOTOPMOST, 0, 0, 0, 0, SWP_NOACTIVATE | SWP_NOMOVE | SWP_NOSIZE ); // for whistler bug 391195 // Default is to connect, so set the focus on list box and default button // to connect // SetFocus( GetDlgItem( hwndDlg, CID_AQ_LV_Connections) ); //CID_AQ_PB_DoNotDial ) ); //For whistler bug 357164 gangz // Initialize the "disable current session" checkbox // { DWORD dwFlag = FALSE, dwErrTmp = NO_ERROR; DWORD cb = sizeof(dwFlag); dwErrTmp = g_pRasGetAutodialParam( RASADP_LoginSessionDisable, &dwFlag, &cb ); // For whistler 522872 if( NO_ERROR != dwErrTmp) { dwFlag = FALSE; } CheckDlgButton( hwndDlg, CID_AQ_CB_DisableThisSession, (BOOL )dwFlag ); } //Set up the timer for bug 336524 gangz // pInfo->pArgs->nIdTimer = 1; SetTimer( hwndDlg, pInfo->pArgs->nIdTimer, (pInfo->pArgs->dwTimeout) *1000,//in milliseconds NULL); return FALSE; } LVXDRAWINFO* AqLvCallback( IN HWND hwndLv, IN DWORD dwItem ) // Enhanced list view callback to report drawing information. 'HwndLv' is // the handle of the list view control. 'DwItem' is the index of the item // being drawn. // // Returns the address of the draw information. // { // Use "full row select" and other recommended options. // // Fields are 'nCols', 'dxIndent', 'dwFlags', 'adwFlags[]'. // static LVXDRAWINFO info = { 1, 0, 0, { 0, 0 } }; return &info; } BOOL AqNotify( HWND hwnd, int idCtrl, LPNMHDR pnmh) { AQINFO* pInfo = (AQINFO* )GetWindowLongPtr( hwnd, DWLP_USER ); ASSERT(pInfo); ASSERT(pnmh); if(!pnmh || !pInfo) { return FALSE; } switch ( pnmh->code) { case LVN_ITEMACTIVATE: case LVN_KEYDOWN: case LVN_ITEMCHANGED: case LVN_ODSTATECHANGED: case LVN_COLUMNCLICK: case LVN_HOTTRACK: //re-set up the timer // ASSERT( pInfo->pArgs ); if ( pInfo->pArgs->nIdTimer ) { KillTimer( hwnd, pInfo->pArgs->nIdTimer); } break; default: break; } return FALSE; } VOID AqTerm( IN HWND hwndDlg ) // Called on WM_DESTROY. 'HwndDlg' is that handle of the dialog window. // { AQINFO* pInfo = (AQINFO* )GetWindowLongPtr( hwndDlg, DWLP_USER ); TRACE( "AqTerm" ); if (pInfo) { ASSERT(pInfo->pArgs); if( pInfo->pArgs->nIdTimer ) { KillTimer( hwndDlg, pInfo->pArgs->nIdTimer ); } Free( pInfo ); } } //Add the timer function for bug 336524 // BOOL AqTimer( IN HWND hwndDlg ) { AQINFO* pInfo = (AQINFO* )GetWindowLongPtr( hwndDlg, DWLP_USER ); TRACE( "AqTimer" ); pInfo->pArgs->nIdTimer = 0; EndDialog( hwndDlg, ERROR_CANCELLED ); return TRUE; } //---------------------------------------------------------------------------- // Auto-Dial Disable dialog // Listed alphabetically following API and dialog proc //---------------------------------------------------------------------------- BOOL APIENTRY RasAutodialDisableDlgW( IN HWND hwndOwner ) // Private external entry point to popup the Auto-Dial Disable Query, i.e. // the "Attempt failed Do you want to disable auto-dial for this // location?" dialog. 'HwndOwner' is the owning window or NULL if none. // // Returns true if user chose to disable, false otherwise. // { INT_PTR nStatus; TRACE( "RasAutodialDisableDlgA" ); nStatus = (BOOL )DialogBoxParam( g_hinstDll, MAKEINTRESOURCE( DID_DQ_DisableAutoDialQuery ), hwndOwner, DqDlgProc, (LPARAM )0 ); if (nStatus == -1) { ErrorDlg( hwndOwner, SID_OP_LoadDlg, ERROR_UNKNOWN, NULL ); nStatus = FALSE; } return (BOOL )nStatus; } BOOL APIENTRY RasAutodialDisableDlgA( IN HWND hwndOwner ) { return RasAutodialDisableDlgW( hwndOwner ); } INT_PTR CALLBACK DqDlgProc( IN HWND hwnd, IN UINT unMsg, IN WPARAM wparam, IN LPARAM lparam ) // DialogProc callback for the Auto-Dial Query dialog. Parameters and // return value are as described for standard windows 'DialogProc's. // { #if 0 TRACE4( "AqDlgProc(h=$%x,m=$%x,w=$%x,l=$%x)", (DWORD )hwnd, (DWORD )unMsg, (DWORD )wparam, (DWORD )lparam ); #endif switch (unMsg) { case WM_INITDIALOG: { return DqInit( hwnd ); } case WM_COMMAND: { return DqCommand( hwnd, HIWORD( wparam ), LOWORD( wparam ), (HWND )lparam ); } } return FALSE; } BOOL DqCommand( IN HWND hwnd, IN WORD wNotification, IN WORD wId, IN HWND hwndCtrl ) // Called on WM_COMMAND. 'Hwnd' is the dialog window. 'WNotification' is // the notification code of the command. 'wId' is the control/menu // identifier of the command. 'HwndCtrl' is the control window handle of // the command. // // Returns true if processed message, false otherwise. // { DWORD dwErr; TRACE3( "DqCommand(n=%d,i=%d,c=$%x)", (DWORD )wNotification, (DWORD )wId, (ULONG_PTR )hwndCtrl ); switch (wId) { case IDOK: { DWORD dwId; HLINEAPP hlineapp; TRACE( "Yes pressed" ); // User chose to permanently disable auto-dial for the current // TAPI location. // dwErr = LoadRasapi32Dll(); if (dwErr == 0) { hlineapp = 0; dwId = GetCurrentLocation( g_hinstDll, &hlineapp ); ASSERT( g_pRasSetAutodialEnable ); TRACE1( "RasSetAutodialEnable(%d)", dwId ); dwErr = g_pRasSetAutodialEnable( dwId, FALSE ); TRACE1( "RasSetAutodialEnable=%d", dwErr ); TapiShutdown( hlineapp ); } if (dwErr != 0) { ErrorDlg( hwnd, SID_OP_SetADialInfo, dwErr, NULL ); } EndDialog( hwnd, TRUE ); return TRUE; } case IDCANCEL: { TRACE( "No or cancel pressed" ); EndDialog( hwnd, FALSE ); return TRUE; } } return FALSE; } BOOL DqInit( IN HWND hwndDlg ) // Called on WM_INITDIALOG. 'hwndDlg' is the handle of the owning window. // // Return false if focus was set, true otherwise, i.e. as defined for // WM_INITDIALOG. // { TRACE( "DqInit" ); // Display the finished window above all other windows. The window // position is set to "topmost" then immediately set to "not topmost" // because we want it on top but not always-on-top. // SetWindowPos( hwndDlg, HWND_TOPMOST, 0, 0, 0, 0, SWP_NOACTIVATE | SWP_NOMOVE | SWP_NOSIZE ); CenterWindow( hwndDlg, GetParent( hwndDlg ) ); ShowWindow( hwndDlg, SW_SHOW ); SetWindowPos( hwndDlg, HWND_NOTOPMOST, 0, 0, 0, 0, SWP_NOACTIVATE | SWP_NOMOVE | SWP_NOSIZE ); // Default is to not disable auto-dial. // SetFocus( GetDlgItem( hwndDlg, IDCANCEL ) ); return FALSE; }