Leaked source code of windows server 2003
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

1674 lines
49 KiB

  1. //*********************************************************************
  2. //* Microsoft Windows **
  3. //* Copyright(c) Microsoft Corp., 1995 **
  4. //*********************************************************************
  5. //
  6. // DIALMON.C - Window proc for dial monitor app
  7. //
  8. // HISTORY:
  9. //
  10. // 4/18/95 jeremys Created.
  11. //
  12. #include "private.h"
  13. #include <mluisupp.h>
  14. #define TF_THISMODULE TF_DIALMON
  15. //
  16. // Registry keys we use to get autodial information
  17. //
  18. // Internet connection goes in remote access key
  19. const TCHAR c_szRASKey[] = TEXT("RemoteAccess");
  20. // Key name
  21. const TCHAR c_szProfile[] = TEXT("InternetProfile");
  22. const TCHAR c_szEnable[] = TEXT("EnableUnattended");
  23. // registry keys of interest
  24. const TCHAR c_szRegPathInternetSettings[] = REGSTR_PATH_INTERNET_SETTINGS;
  25. static const TCHAR szRegValEnableAutoDisconnect[] = REGSTR_VAL_ENABLEAUTODISCONNECT;
  26. static const TCHAR szRegValDisconnectIdleTime[] = REGSTR_VAL_DISCONNECTIDLETIME;
  27. static const TCHAR szRegValExitDisconnect[] = REGSTR_VAL_ENABLEEXITDISCONNECT;
  28. static const TCHAR szEllipsis[] = TEXT("...");
  29. static const CHAR szDashes[] = "----";
  30. static const TCHAR szAutodialMonitorClass[] = REGSTR_VAL_AUTODIAL_MONITORCLASSNAME;
  31. static const TCHAR c_szDialmonClass[] = TEXT("MS_WebcheckMonitor");
  32. // Dialmon globals
  33. UINT_PTR g_uDialmonSecTimerID = 0;
  34. CDialMon * g_pDialMon = NULL;
  35. // Function prototypes for dialog handling functions
  36. INT_PTR CALLBACK DisconnectPromptDlgProc(HWND hDlg, UINT uMsg, WPARAM wParam,
  37. LPARAM lParam);
  38. BOOL DisconnectDlgInit(HWND hDlg,DISCONNECTDLGINFO * pDisconnectDlgInfo);
  39. VOID DisconnectDlgCancel(HWND hDlg);
  40. VOID DisconnectDlgTimerProc(HWND hDlg);
  41. VOID DisconnectDlgDisableAutodisconnect(HWND hDlg);
  42. VOID DisconnectDlgShowCountdown(HWND hDlg,DWORD dwSecsRemaining);
  43. VOID EnableDisconnectDlgCtrls(HWND hDlg,BOOL fEnable);
  44. BOOL CenterWindow (HWND hwndChild, HWND hwndParent);
  45. ////////////////////////////////////////////////////////////////////////
  46. // RAS delay load helpers
  47. //
  48. typedef DWORD (WINAPI* _RASSETAUTODIALPARAM) (
  49. DWORD, LPVOID, DWORD
  50. );
  51. typedef DWORD (WINAPI* _RASENUMCONNECTIONSA) (
  52. LPRASCONNA, LPDWORD, LPDWORD
  53. );
  54. typedef DWORD (WINAPI* _RASENUMCONNECTIONSW) (
  55. LPRASCONNW, LPDWORD, LPDWORD
  56. );
  57. typedef DWORD (WINAPI* _RASHANGUP) (
  58. HRASCONN
  59. );
  60. typedef struct _tagAPIMAPENTRY {
  61. FARPROC* pfn;
  62. LPSTR pszProc;
  63. } APIMAPENTRY;
  64. static _RASSETAUTODIALPARAM pfnRasSetAutodialParam = NULL;
  65. static _RASENUMCONNECTIONSA pfnRasEnumConnectionsA = NULL;
  66. static _RASENUMCONNECTIONSW pfnRasEnumConnectionsW = NULL;
  67. static _RASHANGUP pfnRasHangUp = NULL;
  68. static HINSTANCE g_hRasLib = NULL;
  69. static long g_lRasRefCnt = 0;
  70. APIMAPENTRY rgRasApiMap[] = {
  71. { (FARPROC*) &pfnRasSetAutodialParam, "RasSetAutodialParamA" },
  72. { (FARPROC*) &pfnRasEnumConnectionsA, "RasEnumConnectionsA" },
  73. { (FARPROC*) &pfnRasEnumConnectionsW, "RasEnumConnectionsW" },
  74. { (FARPROC*) &pfnRasHangUp, "RasHangUpA" },
  75. { NULL, NULL },
  76. };
  77. /////////////////////////////////////////////////////////////////////////////
  78. //
  79. // RasEnumHelp
  80. //
  81. // Abstract grusome details of getting a correct enumeration of connections
  82. // from RAS. Works on all 9x and NT platforms correctly, maintaining unicode
  83. // whenever possible.
  84. //
  85. /////////////////////////////////////////////////////////////////////////////
  86. class RasEnumHelp
  87. {
  88. private:
  89. //
  90. // Possible ways we got info from RAS
  91. //
  92. typedef enum {
  93. ENUM_MULTIBYTE, // Win9x
  94. ENUM_UNICODE, // NT
  95. } ENUM_TYPE;
  96. //
  97. // How we got the info
  98. //
  99. ENUM_TYPE _EnumType;
  100. //
  101. // Any error we got during enumeration
  102. //
  103. DWORD _dwLastError;
  104. //
  105. // Number of entries we got
  106. //
  107. DWORD _dwEntries;
  108. //
  109. // Pointer to info retrieved from RAS
  110. //
  111. RASCONNW * _rcList;
  112. //
  113. // Last entry returned as multibyte or unicode when conversion required
  114. //
  115. RASCONNW _rcCurrentEntryW;
  116. public:
  117. RasEnumHelp();
  118. ~RasEnumHelp();
  119. DWORD GetError();
  120. DWORD GetEntryCount();
  121. LPRASCONNW GetEntryW(DWORD dwEntry);
  122. };
  123. RasEnumHelp::RasEnumHelp()
  124. {
  125. DWORD dwBufSize, dwStructSize;
  126. // init
  127. _dwEntries = 0;
  128. _dwLastError = 0;
  129. // figure out which kind of enumeration we're doing - start with multibyte
  130. _EnumType = ENUM_MULTIBYTE;
  131. dwStructSize = sizeof(RASCONNA);
  132. if (g_fIsWinNT)
  133. {
  134. _EnumType = ENUM_UNICODE;
  135. dwStructSize = sizeof(RASCONNW);
  136. }
  137. // allocate space for 16 entries
  138. dwBufSize = 16 * dwStructSize;
  139. _rcList = (LPRASCONNW)LocalAlloc(LMEM_FIXED, dwBufSize);
  140. if(_rcList)
  141. {
  142. do
  143. {
  144. // set up list
  145. _rcList[0].dwSize = dwStructSize;
  146. // call ras to enumerate
  147. _dwLastError = ERROR_UNKNOWN;
  148. if(ENUM_MULTIBYTE == _EnumType)
  149. {
  150. if(pfnRasEnumConnectionsA)
  151. {
  152. _dwLastError = pfnRasEnumConnectionsA(
  153. (LPRASCONNA)_rcList,
  154. &dwBufSize,
  155. &_dwEntries
  156. );
  157. }
  158. }
  159. else
  160. {
  161. if(pfnRasEnumConnectionsW)
  162. {
  163. _dwLastError = pfnRasEnumConnectionsW(
  164. _rcList,
  165. &dwBufSize,
  166. &_dwEntries
  167. );
  168. }
  169. }
  170. // reallocate buffer if necessary
  171. if(ERROR_BUFFER_TOO_SMALL == _dwLastError)
  172. {
  173. LocalFree(_rcList);
  174. _rcList = (LPRASCONNW)LocalAlloc(LMEM_FIXED, dwBufSize);
  175. if(NULL == _rcList)
  176. {
  177. _dwLastError = ERROR_NOT_ENOUGH_MEMORY;
  178. break;
  179. }
  180. }
  181. else
  182. {
  183. break;
  184. }
  185. } while(TRUE);
  186. }
  187. else
  188. {
  189. _dwLastError = ERROR_NOT_ENOUGH_MEMORY;
  190. }
  191. if(_rcList && (ERROR_SUCCESS != _dwLastError))
  192. {
  193. LocalFree(_rcList);
  194. _rcList = NULL;
  195. _dwEntries = 0;
  196. }
  197. return;
  198. }
  199. RasEnumHelp::~RasEnumHelp()
  200. {
  201. if(_rcList)
  202. {
  203. LocalFree(_rcList);
  204. }
  205. }
  206. DWORD
  207. RasEnumHelp::GetError()
  208. {
  209. return _dwLastError;
  210. }
  211. DWORD
  212. RasEnumHelp::GetEntryCount()
  213. {
  214. return _dwEntries;
  215. }
  216. LPRASCONNW
  217. RasEnumHelp::GetEntryW(DWORD dwEntryNum)
  218. {
  219. LPRASCONNW prc = NULL;
  220. if(dwEntryNum < _dwEntries)
  221. {
  222. _rcCurrentEntryW.hrasconn = _rcList[dwEntryNum].hrasconn;
  223. switch(_EnumType)
  224. {
  225. case ENUM_MULTIBYTE:
  226. {
  227. MultiByteToWideChar(CP_ACP, 0,
  228. ((LPRASCONNA)_rcList)[dwEntryNum].szEntryName,
  229. -1, _rcCurrentEntryW.szEntryName,
  230. ARRAYSIZE(_rcCurrentEntryW.szEntryName));
  231. }
  232. break;
  233. case ENUM_UNICODE:
  234. {
  235. StrCpyNW(_rcCurrentEntryW.szEntryName,
  236. _rcList[dwEntryNum].szEntryName,
  237. ARRAYSIZE(_rcCurrentEntryW.szEntryName));
  238. }
  239. break;
  240. }
  241. prc = &_rcCurrentEntryW;
  242. }
  243. return prc;
  244. }
  245. //
  246. // Functions we can call once ras is loaded
  247. //
  248. DWORD _RasEnumConnections(LPRASCONNW lpRasConn, LPDWORD lpdwSize, LPDWORD lpdwConn)
  249. {
  250. RasEnumHelp reh;
  251. DWORD dwRet = reh.GetError();
  252. if (ERROR_SUCCESS == dwRet)
  253. {
  254. DWORD cItems = reh.GetEntryCount();
  255. DWORD cbNeeded = cItems * sizeof(RASCONNW);
  256. *lpdwConn = 0;
  257. if (*lpdwSize >= cbNeeded)
  258. {
  259. *lpdwConn = cItems;
  260. DWORD dw;
  261. for (dw = 0; dw < cItems; dw++)
  262. {
  263. LPRASCONNW prc = reh.GetEntryW(dw);
  264. ASSERT(prc != NULL);
  265. lpRasConn[dw].hrasconn = prc->hrasconn;
  266. StrCpyNW(lpRasConn[dw].szEntryName,
  267. prc->szEntryName,
  268. ARRAYSIZE(lpRasConn[dw].szEntryName));
  269. }
  270. }
  271. else
  272. {
  273. dwRet = ERROR_BUFFER_TOO_SMALL;
  274. }
  275. *lpdwSize = cbNeeded;
  276. }
  277. return dwRet;
  278. }
  279. DWORD _RasHangUp(HRASCONN hRasConn)
  280. {
  281. if (pfnRasHangUp == NULL)
  282. return ERROR_UNKNOWN;
  283. return (*pfnRasHangUp)(hRasConn);
  284. }
  285. BOOL
  286. LoadRasDll(void)
  287. {
  288. if(NULL == g_hRasLib) {
  289. g_hRasLib = LoadLibrary(TEXT("RASAPI32.DLL"));
  290. if(NULL == g_hRasLib)
  291. return FALSE;
  292. int nIndex = 0;
  293. while (rgRasApiMap[nIndex].pszProc != NULL) {
  294. *rgRasApiMap[nIndex].pfn =
  295. GetProcAddress(g_hRasLib, rgRasApiMap[nIndex].pszProc);
  296. // GetProcAddress will fail on Win95 for a couple of NT only apis.
  297. // ASSERT(*rgRasApiMap[nIndex].pfn != NULL);
  298. nIndex++;
  299. }
  300. }
  301. if(g_hRasLib) {
  302. return TRUE;
  303. }
  304. return FALSE;
  305. }
  306. void
  307. UnloadRasDll(void)
  308. {
  309. if(g_hRasLib) {
  310. FreeLibrary(g_hRasLib);
  311. g_hRasLib = NULL;
  312. int nIndex = 0;
  313. while (rgRasApiMap[nIndex].pszProc != NULL) {
  314. *rgRasApiMap[nIndex].pfn = NULL;
  315. nIndex++;
  316. }
  317. }
  318. }
  319. ///////////////////////////////////////////////////////////////////////////
  320. ///////////////////////////////////////////////////////////////////////////
  321. //
  322. // CDialmonClients
  323. //
  324. // Class to maintain a list of application Windows using Dialmon.
  325. // Used for auto-timeout for all these applications.
  326. // This class supports
  327. // adding hooks to incoming applications,
  328. // removing hooks for exiting applications,
  329. // some aggregate operations on all clients.
  330. //
  331. // This is a singleton class, and needs to support only serialized access
  332. // because all access is thru Dialmon which has a serialized message queue.
  333. ///////////////////////////////////////////////////////////////////////////
  334. ///////////////////////////////////////////////////////////////////////////
  335. class CDialmonClients
  336. {
  337. private:
  338. HWND pHwndArray[MAX_DIALMON_HANDLES];
  339. int cCount;
  340. static CDialmonClients* pSingleton;
  341. public:
  342. CDialmonClients();
  343. ~CDialmonClients(){}
  344. static CDialmonClients* getSingleton()
  345. {
  346. if( NULL == pSingleton )
  347. return ( pSingleton = new CDialmonClients() );
  348. else
  349. return pSingleton;
  350. }
  351. static void Shutdown()
  352. {
  353. if( pSingleton )
  354. delete pSingleton;
  355. }
  356. void ClearAll(void);
  357. BOOL AddHook( HWND hWnd );
  358. BOOL RemoveHook( HWND hWnd );
  359. BOOL HasEntries() { return (cCount != 0); };
  360. friend void BroadcastCanHangup( int iTimeoutMins );
  361. friend void BroadcastHangingUp( void );
  362. friend void OnConfirmHangup( HWND hWnd );
  363. friend void OnDenyHangup( HWND hWnd, CDialMon* pDialMon );
  364. friend BOOL CanHangup( void ); //doesn't have to be a friend - just bunched it together for now.
  365. void DebugPrint( void );
  366. };
  367. CDialmonClients* CDialmonClients::pSingleton;
  368. CDialmonClients::CDialmonClients():cCount(0)
  369. {
  370. for( int i=0; i<MAX_DIALMON_HANDLES; i++ )
  371. pHwndArray[i] = NULL;
  372. }
  373. void CDialmonClients::ClearAll(void)
  374. {
  375. for( int i=0; i<MAX_DIALMON_HANDLES; i++ )
  376. pHwndArray[i] = NULL;
  377. }
  378. // client app. passes a handle to its messaging window when it starts up.
  379. BOOL CDialmonClients::AddHook( HWND hWnd )
  380. {
  381. DebugMsg( DM_TRACE, TEXT("\tCDIALMONCLIENTS: Add Hook\n") );
  382. if( cCount >= MAX_DIALMON_HANDLES )
  383. return false; /* BAD! */
  384. pHwndArray[cCount++] = hWnd;
  385. #ifdef DEBUG
  386. DebugPrint();
  387. #endif
  388. return true;
  389. }
  390. // client app. unhooks the handle from the CDialmonClients.
  391. //IMPL: cCount always points to the next empty entry in the array.
  392. // so when we delete a handle, we move all the entries beyond that
  393. // handle up one place and decrement cCount.
  394. BOOL CDialmonClients::RemoveHook( HWND hWnd )
  395. {
  396. DebugMsg( DM_TRACE, TEXT("\tCDIALMONCLIENTS: Remove Hook\n") );
  397. boolean found = false;
  398. int i;
  399. for( i=0; i<cCount; i++ )
  400. {
  401. if( hWnd == pHwndArray[i] )
  402. {
  403. pHwndArray[i] = NULL;
  404. --cCount;
  405. found = true;
  406. break;
  407. }
  408. }
  409. // move everything beyong cCount up by 1
  410. // so that cCount represents next free index to
  411. // insert into.
  412. if( found )
  413. {
  414. for( ; i<cCount; i++ )
  415. pHwndArray[i] = pHwndArray[i+1];
  416. pHwndArray[cCount] = NULL;
  417. }
  418. #ifdef DEBUG
  419. DebugPrint();
  420. #endif
  421. return found;
  422. }
  423. void CDialmonClients::DebugPrint(void)
  424. {
  425. DebugMsg( DM_TRACE, TEXT("\tCDIALMONCLIENTS: ClientList->\n") );
  426. for( int i=0; i<cCount; i++ )
  427. {
  428. if( pHwndArray[i] )
  429. {
  430. DebugMsg( DM_TRACE, TEXT("\t\t%d: %x\n"), i, pHwndArray[i] );
  431. }
  432. }
  433. }
  434. ///////////////////////////////////////////////////////////////////////////
  435. ///////////////////////////////////////////////////////////////////////////
  436. //
  437. // Start up and Shutdown CDialmonClients
  438. //
  439. ///////////////////////////////////////////////////////////////////////////
  440. ///////////////////////////////////////////////////////////////////////////
  441. CDialmonClients* g_pDialmonClients;
  442. static void DialmonClientsInit(void)
  443. {
  444. g_pDialmonClients = new CDialmonClients();
  445. }
  446. static void DialmonClientsShutdown(void)
  447. {
  448. delete g_pDialmonClients;
  449. }
  450. //#define USE_CONFIRM_ARRAY 1
  451. // We don't need to use the pConfirmHangupArray.
  452. // The option is to simply wait for some preset time, and if no registered
  453. // client refuses the hangup option, to go ahead and simply hangup.
  454. // This array lets us hangup a little earlier just in case all clients reply
  455. // immdly.
  456. #ifdef USE_CONFIRM_ARRAY
  457. static BOOL pConfirmHangupArray[MAX_DIALMON_HANDLES];
  458. #endif
  459. static int cOutstandingReplies = 0;
  460. // Broadcast to all registered client a query of can_hang_up?
  461. void BroadcastCanHangup( int iTimeoutMins )
  462. {
  463. DebugMsg( DM_TRACE, TEXT("\tCDIALMONCLIENTS: Broadcasting WM_CANHANGUP?") );
  464. int i;
  465. cOutstandingReplies=0;
  466. for( i=0; i<g_pDialmonClients->cCount; i++ )
  467. {
  468. if(PostMessage( g_pDialmonClients->pHwndArray[i], WM_CANHANGUP,
  469. 0, (LPARAM)iTimeoutMins ))
  470. ++cOutstandingReplies;
  471. }
  472. // if we are using a confirm boolean array, then set ALL
  473. // entries to false.. this is to take care of any clients that come
  474. // in AFTER we broadcast can hangup and BEFORE all the existing clients
  475. // have finished confirming.
  476. #ifdef USE_CONFIRM_ARRAY
  477. for( i=0; i<MAX_DIALMON_HANDLES; i++ )
  478. {
  479. pConfirmHangupArray[i] = false;
  480. }
  481. #endif
  482. }
  483. // This is a broadcast AFTER hangingup to all registered clients.
  484. void BroadcastHangingUp(void)
  485. {
  486. DebugMsg( DM_TRACE, TEXT("\tCDIALMONCLIENTS: Broadcasting WM_HANGING_UP") );
  487. for( int i=0; i<g_pDialmonClients->cCount; i++ )
  488. PostMessage( g_pDialmonClients->pHwndArray[i], WM_HANGING_UP, 0,0 );
  489. }
  490. // Record that this particular client would like to hangup.
  491. void OnConfirmHangup( HWND hWnd )
  492. {
  493. #ifdef USE_CONFIRM_ARRAY
  494. for( int i=0; i<g_pDialmonClients->cCount; i++ )
  495. if( hWnd == g_pDialmonClients->pHwndArray[i] )
  496. {
  497. pConfirmHangupArray[i] = true;
  498. break;
  499. }
  500. #endif
  501. --cOutstandingReplies;
  502. }
  503. // Checks if all clients have replied positively.
  504. // Returns false if any client has not yet replied.
  505. BOOL CanHangup( void )
  506. {
  507. #ifdef USE_CONFIRM_ARRAY
  508. for( int i=0; i<g_pDialmonClients->cCount; i++ )
  509. if( false == pConfirmHangupArray[i] )
  510. return false;
  511. return true;
  512. #else
  513. return (cOutstandingReplies==0);
  514. #endif
  515. }
  516. // take action to abort hangup, ( set CDialmon::_dwElapsedTicks to 0 ).
  517. // The effect of this would be that after another timeout period, dialmon
  518. // would again query all the clients.
  519. // However, the client does not have to bring up a dialog again if the user
  520. // indicates that he is not interested in the feature.. the client can
  521. // negate the hangup without interrupting the user.
  522. // ( see the auto-disconnect feature in dialmon ).
  523. void OnDenyHangup( HWND hWnd, CDialMon* pDialMon )
  524. {
  525. #ifdef USE_CONFIRM_ARRAY
  526. for( int i=0; i<g_pDialmonClients->cCount; i++ )
  527. if( hWnd == g_pDialmonClients->pHwndArray[i] )
  528. {
  529. pConfirmHangupArray[i] = false;
  530. break;
  531. }
  532. #endif
  533. pDialMon->ResetElapsedTicks();
  534. cOutstandingReplies=0;
  535. }
  536. ///////////////////////////////////////////////////////////////////////////
  537. ///////////////////////////////////////////////////////////////////////////
  538. //
  539. // Helper to tell dialmon something is going on
  540. //
  541. ///////////////////////////////////////////////////////////////////////////
  542. ///////////////////////////////////////////////////////////////////////////
  543. void IndicateDialmonActivity(void)
  544. {
  545. static HWND hwndDialmon = NULL;
  546. HWND hwndMonitor;
  547. // this one is dynamic - have to find window every time
  548. hwndMonitor = FindWindow(szAutodialMonitorClass, NULL);
  549. if(hwndMonitor)
  550. PostMessage(hwndMonitor, WM_WINSOCK_ACTIVITY, 0, 0);
  551. // dialmon lives forever - find it once and we're set
  552. if(NULL == hwndDialmon)
  553. hwndDialmon = FindWindow(c_szDialmonClass, NULL);
  554. if(hwndDialmon)
  555. PostMessage(hwndDialmon, WM_WINSOCK_ACTIVITY, 0, 0);
  556. }
  557. ///////////////////////////////////////////////////////////////////////////
  558. ///////////////////////////////////////////////////////////////////////////
  559. //
  560. // Dialmon startup and shutdown
  561. //
  562. ///////////////////////////////////////////////////////////////////////////
  563. ///////////////////////////////////////////////////////////////////////////
  564. BOOL DialmonInit(void)
  565. {
  566. g_pDialMon = new CDialMon;
  567. DialmonClientsInit();
  568. if(g_pDialMon)
  569. return TRUE;
  570. return FALSE;
  571. }
  572. void DialmonShutdown(void)
  573. {
  574. DialmonClientsShutdown();
  575. SAFEDELETE(g_pDialMon);
  576. }
  577. ///////////////////////////////////////////////////////////////////////////
  578. ///////////////////////////////////////////////////////////////////////////
  579. //
  580. // Dialmon window functions
  581. //
  582. ///////////////////////////////////////////////////////////////////////////
  583. ///////////////////////////////////////////////////////////////////////////
  584. // this cwebcheck instance is in iwebck.cpp
  585. extern CWebCheck *g_pwc;
  586. #ifdef DEBUG_KV
  587. // DEBUG_KV is set to 1 if you need to test hangup logic
  588. // without actually having a dailup connection.
  589. static bool kvhack = true;
  590. #endif
  591. LRESULT CALLBACK Dialmon_WndProc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
  592. {
  593. CDialMon *pDialMon = (CDialMon*) GetWindowLongPtr(hwnd, GWLP_USERDATA);
  594. switch (uMsg)
  595. {
  596. case WM_CREATE:
  597. {
  598. // snag our class pointer and save in window data
  599. CREATESTRUCT *pcs;
  600. pcs = (CREATESTRUCT *)lParam;
  601. SetWindowLongPtr(hwnd, GWLP_USERDATA, (LONG_PTR) pcs->lpCreateParams);
  602. break;
  603. }
  604. // DialMon messages (starting at WM_USER+100)
  605. case WM_SET_CONNECTOID_NAME:
  606. if(pDialMon)
  607. pDialMon->OnSetConnectoid(wParam!=0);
  608. break;
  609. case WM_WINSOCK_ACTIVITY:
  610. if(pDialMon)
  611. pDialMon->OnActivity();
  612. break;
  613. case WM_IEXPLORER_EXITING:
  614. if(pDialMon)
  615. pDialMon->OnExplorerExit();
  616. break;
  617. case WM_DIALMON_HOOK:
  618. DebugMsg( DM_TRACE, TEXT("\tCDIALMONCLIENTS: WM_HOOK recd. from Window 0x%x"), lParam );
  619. BOOL fRetval;
  620. fRetval = g_pDialmonClients->AddHook( (HWND)lParam );
  621. ASSERT( fRetval == TRUE );
  622. #ifdef DEBUG_KV
  623. if( kvhack == true )
  624. {
  625. pDialMon->kvStartMonitoring();
  626. kvhack = false;
  627. }
  628. #endif
  629. break;
  630. case WM_DIALMON_UNHOOK:
  631. DebugMsg( DM_TRACE, TEXT("\tCDIALMONCLIENTS: WM_UNHOOK recd. from Window 0x%x"), lParam );
  632. g_pDialmonClients->RemoveHook( (HWND)lParam );
  633. break;
  634. case WM_CONFIRM_HANGUP:
  635. DebugMsg( DM_TRACE, TEXT("\tCDIALMONCLIENTS: WM_CONFIRM_HANGUP recd. from Window 0x%x"), lParam );
  636. OnConfirmHangup( (HWND)lParam );
  637. break;
  638. case WM_DENY_HANGUP:
  639. DebugMsg( DM_TRACE, TEXT("\tCDIALMONCLIENTS: WM_DENY_HANGUP recd. from Window 0x%x"), lParam );
  640. OnDenyHangup( (HWND)lParam, pDialMon );
  641. break;
  642. case WM_TIMER:
  643. if(pDialMon)
  644. pDialMon->OnTimer(wParam);
  645. break;
  646. case WM_LOAD_SENSLCE:
  647. DBG("Dialmon_WndProc - got WM_LOAD_SENSLCE");
  648. if(g_pwc)
  649. {
  650. g_pwc->LoadExternals();
  651. }
  652. break;
  653. case WM_IS_SENSLCE_LOADED:
  654. if(g_pwc)
  655. {
  656. return g_pwc->AreExternalsLoaded();
  657. }
  658. else
  659. {
  660. return FALSE;
  661. }
  662. break;
  663. case WM_WININICHANGE:
  664. if (lParam && !StrCmpI((LPCTSTR)lParam, TEXT("policy")))
  665. {
  666. ProcessInfodeliveryPolicies();
  667. }
  668. // FEATURE: This should be done on Policy and another filter, not for
  669. // all changes. (The other filter hasn't been defined yet.)
  670. // TODO: handle this in the new architecture!
  671. //SetNotificationMgrRestrictions(NULL);
  672. break;
  673. }
  674. return DefWindowProc(hwnd, uMsg, wParam, lParam);
  675. }
  676. ///////////////////////////////////////////////////////////////////////////
  677. ///////////////////////////////////////////////////////////////////////////
  678. //
  679. // CDialMon class implementation
  680. //
  681. ///////////////////////////////////////////////////////////////////////////
  682. ///////////////////////////////////////////////////////////////////////////
  683. //
  684. // Constructor / Destructor
  685. //
  686. CDialMon::CDialMon()
  687. {
  688. WNDCLASS wc;
  689. // register dialmon window class
  690. memset(&wc, 0, sizeof(wc));
  691. wc.lpfnWndProc = Dialmon_WndProc;
  692. wc.hInstance = g_hInst;
  693. wc.lpszClassName = c_szDialmonClass;
  694. RegisterClass(&wc);
  695. // create dialmon window
  696. _hwndDialmon = CreateWindow(c_szDialmonClass,
  697. c_szDialmonClass,
  698. WS_OVERLAPPEDWINDOW,
  699. CW_USEDEFAULT,
  700. CW_USEDEFAULT,
  701. CW_USEDEFAULT,
  702. CW_USEDEFAULT,
  703. NULL,
  704. NULL,
  705. g_hInst,
  706. (LPVOID)this);
  707. }
  708. CDialMon::~CDialMon()
  709. {
  710. if(_hwndDialmon)
  711. DestroyWindow(_hwndDialmon);
  712. // unload ras if it's still around
  713. UnloadRasDll();
  714. }
  715. ///////////////////////////////////////////////////////////////////////////
  716. //
  717. // Start/StopMonitoring
  718. //
  719. ///////////////////////////////////////////////////////////////////////////
  720. BOOL CDialMon::StartMonitoring(void)
  721. {
  722. DBG("CDialMon::StartMonitoring");
  723. // read timeout settings from registry
  724. RefreshTimeoutSettings();
  725. // set a one-minute timer
  726. StopIdleTimer();
  727. if(!StartIdleTimer())
  728. return FALSE;
  729. _dwElapsedTicks = 0;
  730. return TRUE;
  731. }
  732. void CDialMon::StopMonitoring(void)
  733. {
  734. DBG("CDialMon::StopMonitoring");
  735. // don't ever hang up now but keep an eye on ras connection
  736. _dwTimeoutMins = 0;
  737. _fDisconnectOnExit = FALSE;
  738. }
  739. ///////////////////////////////////////////////////////////////////////////
  740. //
  741. // Start/StopIdleTimer, OnTimer
  742. //
  743. ///////////////////////////////////////////////////////////////////////////
  744. INT_PTR CDialMon::StartIdleTimer(void)
  745. {
  746. if(0 == _uIdleTimerID)
  747. _uIdleTimerID = SetTimer(_hwndDialmon, TIMER_ID_DIALMON_IDLE, 30000, NULL);
  748. ASSERT(_uIdleTimerID);
  749. return _uIdleTimerID;
  750. }
  751. void CDialMon::StopIdleTimer(void)
  752. {
  753. if(_uIdleTimerID) {
  754. KillTimer(_hwndDialmon, _uIdleTimerID);
  755. _uIdleTimerID = 0;
  756. }
  757. }
  758. void CDialMon::OnTimer(UINT_PTR uTimerID)
  759. {
  760. DBG("CDialMon::OnMonitorTimer");
  761. // if we're on Millennium, just bail out. The system handles idle disconnect.
  762. if(g_fIsMillennium)
  763. {
  764. return;
  765. }
  766. // if it's not our timer, ignore it
  767. if(uTimerID != _uIdleTimerID)
  768. return;
  769. // prevent re-entrancy of timer proc (we can stay in here indefinitely
  770. // since we may bring up a dialog box)
  771. if (_fInDisconnectFunction) {
  772. // disconnect dialog already launched, ignore timer ticks while
  773. // it's present
  774. return;
  775. }
  776. _fInDisconnectFunction = TRUE;
  777. CheckForDisconnect(TRUE);
  778. _fInDisconnectFunction = FALSE;
  779. #ifdef DEBUG_KV
  780. /* Don't stop idle timer */
  781. #else
  782. if(FALSE == _fConnected) {
  783. StopIdleTimer();
  784. }
  785. #endif
  786. }
  787. ///////////////////////////////////////////////////////////////////////////
  788. //
  789. // OnSetConnectoid/OnActivity/OnExplorerExit
  790. //
  791. ///////////////////////////////////////////////////////////////////////////
  792. void CDialMon::OnSetConnectoid(BOOL fNoTimeout)
  793. {
  794. RASCONN RasCon[MAX_CONNECTION];
  795. DWORD dwBytes, dwRes, dwConnections;
  796. // save no timeout setting
  797. _fNoTimeout = fNoTimeout;
  798. // Ask ras which connectoid is connected and watch that one
  799. LoadRasDll();
  800. RasCon[0].dwSize = sizeof(RasCon[0]);
  801. dwBytes = MAX_CONNECTION * sizeof(RasCon[0]);
  802. dwRes = _RasEnumConnections(RasCon, &dwBytes, &dwConnections);
  803. // No connections? bail.
  804. if(0 == dwConnections) {
  805. *_pszConnectoidName = TEXT('\0');
  806. _fConnected = FALSE;
  807. return;
  808. }
  809. // Monitor first connectoid
  810. StrCpyN(_pszConnectoidName, RasCon[0].szEntryName, ARRAYSIZE(_pszConnectoidName));
  811. // send ras connect notification if we weren't previously connected
  812. if(FALSE == _fConnected) {
  813. _fConnected = TRUE;
  814. }
  815. // start watching it
  816. StartMonitoring();
  817. }
  818. void CDialMon::OnActivity(void)
  819. {
  820. DBG("CDialMon::OnActivity");
  821. // reset idle tick count
  822. _dwElapsedTicks = 0;
  823. // if the disconnect dialog is present and winsock activity
  824. // resumes, then dismiss the dialog
  825. if(_hDisconnectDlg) {
  826. SendMessage(_hDisconnectDlg, WM_QUIT_DISCONNECT_DLG, 0, 0);
  827. _hDisconnectDlg = NULL;
  828. }
  829. }
  830. void CDialMon::OnExplorerExit()
  831. {
  832. DBG("CDialMon::OnIExplorerExit");
  833. if(FALSE == _fDisconnectOnExit && FALSE == _fNoTimeout) {
  834. // no exit disconnection so bail
  835. DBG("CDialMon::OnIExplorerExit - exit hangup not enabled");
  836. return;
  837. }
  838. // prevent re-entrancy of this function (we can stay in here indefinitely
  839. // since we may bring up a dialog box)
  840. if (_fInDisconnectFunction) {
  841. // some UI already launched
  842. return;
  843. }
  844. _fInDisconnectFunction = TRUE;
  845. CheckForDisconnect(FALSE);
  846. _fInDisconnectFunction = FALSE;
  847. if(FALSE == _fConnected) {
  848. StopIdleTimer();
  849. }
  850. }
  851. ///////////////////////////////////////////////////////////////////////////
  852. //
  853. // RefreshTimeoutSettings
  854. //
  855. ///////////////////////////////////////////////////////////////////////////
  856. BOOL CDialMon::RefreshTimeoutSettings(void)
  857. {
  858. HKEY hKey;
  859. BOOL fSuccess = FALSE;
  860. TCHAR szKey[MAX_PATH];
  861. DWORD dwRes, dwData, dwSize, dwDisp;
  862. // assume disconnect monitoring is off
  863. _dwTimeoutMins = 0;
  864. _fDisconnectOnExit = FALSE;
  865. // figure out appropriate key
  866. wnsprintf(szKey, ARRAYSIZE(szKey), TEXT("%s\\Profile\\%s"),
  867. REGSTR_PATH_REMOTEACCESS, _pszConnectoidName);
  868. // open a regstry key to the internet settings section
  869. dwRes = RegCreateKeyEx(HKEY_CURRENT_USER, szKey, 0, TEXT(""), 0,
  870. KEY_QUERY_VALUE | KEY_SET_VALUE, NULL, &hKey, &dwDisp);
  871. if(ERROR_SUCCESS == dwRes)
  872. {
  873. //
  874. // is autodisconnect enabled?
  875. //
  876. dwSize = sizeof(dwData);
  877. if (RegQueryValueEx(hKey,szRegValEnableAutoDisconnect,NULL,NULL,
  878. (LPBYTE) &dwData, &dwSize) == ERROR_SUCCESS)
  879. {
  880. if(dwData)
  881. {
  882. // what's the timeout?
  883. dwSize = sizeof(dwData);
  884. if (RegQueryValueEx(hKey,szRegValDisconnectIdleTime,NULL,NULL,
  885. (LPBYTE) &dwData, &dwSize) == ERROR_SUCCESS && dwData)
  886. {
  887. _dwTimeoutMins = dwData;
  888. fSuccess = TRUE;
  889. }
  890. }
  891. // is disconnect on exit enabled?
  892. dwSize = sizeof(dwData);
  893. if (RegQueryValueEx(hKey,szRegValExitDisconnect,NULL,NULL,
  894. (LPBYTE) &dwData, &dwSize) == ERROR_SUCCESS && dwData)
  895. {
  896. _fDisconnectOnExit = TRUE;
  897. fSuccess = TRUE;
  898. }
  899. }
  900. else
  901. {
  902. //
  903. // couldn't find enable autodisconnect key. Set all disconnect
  904. // settings to their defaults
  905. //
  906. // set class members to default values
  907. _dwTimeoutMins = 20;
  908. _fDisconnectOnExit = TRUE;
  909. fSuccess = TRUE;
  910. // enable idle disconnect and exit disconnect
  911. dwData = 1;
  912. RegSetValueEx(hKey, szRegValEnableAutoDisconnect, 0, REG_DWORD,
  913. (LPBYTE)&dwData, sizeof(DWORD));
  914. RegSetValueEx(hKey, szRegValExitDisconnect, 0, REG_DWORD,
  915. (LPBYTE)&dwData, sizeof(DWORD));
  916. // Save idle minutes
  917. RegSetValueEx(hKey, szRegValDisconnectIdleTime, 0, REG_DWORD,
  918. (LPBYTE)&_dwTimeoutMins, sizeof(DWORD));
  919. }
  920. RegCloseKey(hKey);
  921. }
  922. return fSuccess;
  923. }
  924. ///////////////////////////////////////////////////////////////////////////
  925. //
  926. // Disconnection handling
  927. //
  928. ///////////////////////////////////////////////////////////////////////////
  929. void CDialMon::CheckForDisconnect(BOOL fTimer)
  930. {
  931. BOOL fPromptForDisconnect = TRUE; // assume we should prompt for disconnect
  932. BOOL fDisconnectDisabled = FALSE;
  933. BOOL fConnectoidAlive = FALSE;
  934. RASCONN RasCon[MAX_CONNECTION];
  935. DWORD dwBytes, dwRes, dwConnections = 0, i;
  936. HRASCONN hConnection = NULL;
  937. // variables for auto-hangup for other client apps. (MARS)
  938. static int dwElapsedTicksSincePoll = 0;
  939. static BOOL fPolledForHangup = false;
  940. BOOL fClientsOkHangup = false;
  941. #define MAX_MINS_CLIENT_RESPONSE 1
  942. #ifdef DEBUG_KV
  943. // skip all the connection code..
  944. goto KVHACK;
  945. #endif
  946. // Verify we still have a connection
  947. RasCon[0].dwSize = sizeof(RasCon[0]);
  948. dwBytes = MAX_CONNECTION * sizeof(RasCon[0]);
  949. dwRes = _RasEnumConnections(RasCon, &dwBytes, &dwConnections);
  950. // If ras is connected at all, stay alive to monitor it
  951. if(0 == dwConnections)
  952. _fConnected = FALSE;
  953. // Find connectoid we're supposed to watch
  954. if(TEXT('\0') == *_pszConnectoidName) {
  955. DBG_WARN("DisconnectHandler: No designated connection to monitor");
  956. return;
  957. }
  958. for(i=0; i<dwConnections; i++) {
  959. if(!StrCmp(RasCon[i].szEntryName, _pszConnectoidName)) {
  960. fConnectoidAlive = TRUE;
  961. hConnection = RasCon[i].hrasconn;
  962. }
  963. }
  964. // if we're not connected to out monitor connectoid, ditch our hangup
  965. // dialog if we have one and bail out
  966. if(FALSE == fConnectoidAlive) {
  967. if(_hDisconnectDlg) {
  968. SendMessage(_hDisconnectDlg, WM_QUIT_DISCONNECT_DLG, 0, 0);
  969. _hDisconnectDlg = NULL;
  970. }
  971. // Also make sure that if we were waiting for client (MARS) reponses for auto-hangup,
  972. // we also clean up state information..
  973. if( fPolledForHangup )
  974. {
  975. dwElapsedTicksSincePoll = 0;
  976. fPolledForHangup = false;
  977. }
  978. return;
  979. }
  980. #ifdef DEBUG_KV
  981. // label to jump to after skipping connection code..
  982. // also need to set _dwTimeoutMins since without connection
  983. KVHACK:_dwTimeoutMins = 2;
  984. #endif
  985. // Check timeout if we got a timer tick
  986. if(fTimer) {
  987. // increment tick count
  988. _dwElapsedTicks ++;
  989. // Haven't exceeded idle threshold or not watching for idle
  990. if (0 == _dwTimeoutMins || _dwElapsedTicks < _dwTimeoutMins * 2)
  991. fPromptForDisconnect = FALSE;
  992. }
  993. // THIS is a good place to message out to other clients (ie Mars ) and
  994. // see if everybody wants to hang up ( this is the point where if
  995. // fPromptForDisconnect is true, then the earlier behavior would have
  996. // prompted for disconnect.
  997. // If this is a disconnect because of IExplorer exiting, we
  998. // probably don't want to hangup if there are other clients using dialmon.
  999. if( !fTimer && g_pDialmonClients->HasEntries() )
  1000. return;
  1001. if( g_pDialmonClients->HasEntries() && fPromptForDisconnect )
  1002. {
  1003. if( fPolledForHangup )
  1004. {
  1005. // WM_CANHANGUP messages have been sent
  1006. // we can hangup if either all clients have replied yes,
  1007. // or if there are no refusals so far, and time has run out.
  1008. if( CanHangup() ||
  1009. ( dwElapsedTicksSincePoll >= 2*MAX_MINS_CLIENT_RESPONSE ) )
  1010. {
  1011. //can hangup!
  1012. dwElapsedTicksSincePoll = 0;
  1013. fPolledForHangup = false;
  1014. fClientsOkHangup = true;
  1015. }
  1016. else
  1017. {
  1018. dwElapsedTicksSincePoll++;
  1019. //ensure that hangup doesn't occur on THIS particular timer message.
  1020. fPromptForDisconnect = false;
  1021. }
  1022. }
  1023. else
  1024. {
  1025. // WM_CANHANGUP queries may be sent out now..
  1026. BroadcastCanHangup( _dwTimeoutMins );
  1027. dwElapsedTicksSincePoll = 0;
  1028. fPolledForHangup = true;
  1029. //ensure that hangup doesn't occur now
  1030. fPromptForDisconnect = false;
  1031. }
  1032. }
  1033. else if( fPolledForHangup )
  1034. {
  1035. // activity restarted while waiting for client responses.
  1036. // do clean up of state information.
  1037. dwElapsedTicksSincePoll = 0;
  1038. fPolledForHangup = false;
  1039. }
  1040. if(FALSE == fPromptForDisconnect) {
  1041. return;
  1042. }
  1043. // prompt user to see if they want to hang up
  1044. if(fClientsOkHangup || PromptForDisconnect(fTimer, &fDisconnectDisabled)) {
  1045. // hang it up
  1046. ASSERT(hConnection);
  1047. if(hConnection)
  1048. _RasHangUp(hConnection);
  1049. // broadcast WM_HANGING_UP to remaining clients - REQUIRED??
  1050. if( g_pDialmonClients->HasEntries() )
  1051. BroadcastHangingUp();
  1052. _fConnected = FALSE;
  1053. }
  1054. if (fDisconnectDisabled) {
  1055. StopMonitoring();
  1056. }
  1057. _dwElapsedTicks = 0;
  1058. }
  1059. BOOL CDialMon::PromptForDisconnect(BOOL fTimer, BOOL *pfDisconnectDisabled)
  1060. {
  1061. ASSERT(_pszConnectoidName);
  1062. ASSERT(pfDisconnectDisabled);
  1063. // fill out struct to pass to dialog
  1064. DISCONNECTDLGINFO DisconnectDlgInfo;
  1065. memset(&DisconnectDlgInfo,0,sizeof(DisconnectDlgInfo));
  1066. DisconnectDlgInfo.pszConnectoidName = _pszConnectoidName;
  1067. DisconnectDlgInfo.fTimer = fTimer;
  1068. DisconnectDlgInfo.dwTimeout = _dwTimeoutMins;
  1069. DisconnectDlgInfo.pDialMon = this;
  1070. // choose the appropriate dialog depending on if this a "timeout" dialog
  1071. // or "app exiting" dialog
  1072. UINT uDlgTemplateID = fTimer ? IDD_DISCONNECT_PROMPT:IDD_APP_EXIT_PROMPT;
  1073. // run the dialog
  1074. BOOL fRet = (BOOL)DialogBoxParam(MLGetHinst(),MAKEINTRESOURCE(uDlgTemplateID),
  1075. NULL, DisconnectPromptDlgProc,(LPARAM) &DisconnectDlgInfo);
  1076. // dialog box stores its window handle in our class so we can send
  1077. // messages to it, clear the global handle now that it's dismissed
  1078. _hDisconnectDlg = NULL;
  1079. *pfDisconnectDisabled = FALSE;
  1080. if (!fRet && DisconnectDlgInfo.fDisconnectDisabled) {
  1081. *pfDisconnectDisabled=TRUE;
  1082. // turn off reg keys for this connection
  1083. TCHAR szKey[128];
  1084. DWORD dwRes, dwValue = 0;
  1085. HKEY hKey;
  1086. wnsprintf(szKey, ARRAYSIZE(szKey), TEXT("%s\\Profile\\%s"),
  1087. REGSTR_PATH_REMOTEACCESS, _pszConnectoidName);
  1088. dwRes = RegOpenKeyEx(HKEY_CURRENT_USER, szKey, 0, KEY_WRITE, &hKey);
  1089. if(ERROR_SUCCESS == dwRes) {
  1090. // Turn off idle disconnect
  1091. RegSetValueEx(hKey, szRegValEnableAutoDisconnect, 0, REG_DWORD,
  1092. (LPBYTE)&dwValue, sizeof(DWORD));
  1093. // Turn off exit disconnect
  1094. RegSetValueEx(hKey, szRegValExitDisconnect, 0, REG_DWORD,
  1095. (LPBYTE)&dwValue, sizeof(DWORD));
  1096. RegCloseKey(hKey);
  1097. }
  1098. }
  1099. return fRet;
  1100. }
  1101. ///////////////////////////////////////////////////////////////////////////
  1102. ///////////////////////////////////////////////////////////////////////////
  1103. //
  1104. // Disconnect dialog implementation
  1105. //
  1106. ///////////////////////////////////////////////////////////////////////////
  1107. ///////////////////////////////////////////////////////////////////////////
  1108. INT_PTR CALLBACK DisconnectPromptDlgProc(HWND hDlg, UINT uMsg, WPARAM wParam,
  1109. LPARAM lParam)
  1110. {
  1111. switch (uMsg) {
  1112. case WM_INITDIALOG:
  1113. // lParam points to data struct, store a pointer to it in window data
  1114. SetWindowLongPtr(hDlg, DWLP_USER,lParam);
  1115. return DisconnectDlgInit(hDlg,(DISCONNECTDLGINFO *) lParam);
  1116. break;
  1117. case WM_COMMAND:
  1118. switch (wParam) {
  1119. case IDOK:
  1120. EndDialog(hDlg,TRUE);
  1121. break;
  1122. case IDCANCEL:
  1123. DisconnectDlgCancel(hDlg);
  1124. EndDialog(hDlg,FALSE);
  1125. break;
  1126. case IDC_DISABLE_AUTODISCONNECT:
  1127. DisconnectDlgDisableAutodisconnect(hDlg);
  1128. break;
  1129. }
  1130. break;
  1131. case WM_QUIT_DISCONNECT_DLG:
  1132. // parent window wants to terminate us
  1133. EndDialog(hDlg,FALSE);
  1134. break;
  1135. case WM_TIMER:
  1136. DisconnectDlgTimerProc(hDlg);
  1137. break;
  1138. }
  1139. return FALSE;
  1140. }
  1141. BOOL __cdecl _FormatMessage(LPCWSTR szTemplate, LPWSTR szBuf, UINT cchBuf, ...)
  1142. {
  1143. BOOL fRet;
  1144. va_list ArgList;
  1145. va_start(ArgList, cchBuf);
  1146. fRet = FormatMessageWrapW(FORMAT_MESSAGE_FROM_STRING, szTemplate, 0, 0, szBuf, cchBuf, &ArgList);
  1147. va_end(ArgList);
  1148. return fRet;
  1149. }
  1150. BOOL DisconnectDlgInit(HWND hDlg,DISCONNECTDLGINFO * pDisconnectDlgInfo)
  1151. {
  1152. ASSERT(pDisconnectDlgInfo);
  1153. if (!pDisconnectDlgInfo)
  1154. return FALSE;
  1155. // allocate buffers to build text for dialog
  1156. BUFFER BufText(MAX_RES_LEN + MAX_CONNECTOID_DISPLAY_LEN + 1);
  1157. BUFFER BufFmt(MAX_RES_LEN),BufConnectoidName(MAX_CONNECTOID_DISPLAY_LEN+4);
  1158. ASSERT(BufText && BufFmt && BufConnectoidName);
  1159. if (!BufText || !BufFmt || !BufConnectoidName)
  1160. return FALSE;
  1161. UINT uStringID;
  1162. // choose the appropriate text string for dialog
  1163. if (pDisconnectDlgInfo->fTimer) {
  1164. uStringID = IDS_DISCONNECT_DLG_TEXT;
  1165. } else {
  1166. uStringID = IDS_APP_EXIT_TEXT;
  1167. }
  1168. // load the format string from resource
  1169. MLLoadString(uStringID,BufFmt.QueryPtr(),BufFmt.QuerySize());
  1170. // copy the connectoid name into buffer, and truncate it if it's really
  1171. // long
  1172. StrCpyN(BufConnectoidName.QueryPtr(),pDisconnectDlgInfo->pszConnectoidName,
  1173. BufConnectoidName.QuerySize());
  1174. if (lstrlen(pDisconnectDlgInfo->pszConnectoidName) > MAX_CONNECTOID_DISPLAY_LEN) {
  1175. StrCpyN(((TCHAR *) BufConnectoidName.QueryPtr()) + MAX_CONNECTOID_DISPLAY_LEN,
  1176. szEllipsis, BufConnectoidName.QuerySize());
  1177. }
  1178. if (pDisconnectDlgInfo->fTimer)
  1179. {
  1180. _FormatMessage(BufFmt.QueryPtr(),
  1181. BufText.QueryPtr(),
  1182. BufText.QuerySize(),
  1183. BufConnectoidName.QueryPtr(),
  1184. pDisconnectDlgInfo->dwTimeout);
  1185. }
  1186. else
  1187. {
  1188. _FormatMessage(BufFmt.QueryPtr(),
  1189. BufText.QueryPtr(),
  1190. BufText.QuerySize(),
  1191. BufConnectoidName.QueryPtr());
  1192. }
  1193. // set text in dialog
  1194. SetDlgItemText(hDlg,IDC_TX1,BufText.QueryPtr());
  1195. // if this timeout dialog (which counts down), initialize countdown timer
  1196. if (pDisconnectDlgInfo->fTimer) {
  1197. pDisconnectDlgInfo->dwCountdownVal = DISCONNECT_DLG_COUNTDOWN;
  1198. DisconnectDlgShowCountdown(hDlg,pDisconnectDlgInfo->dwCountdownVal);
  1199. // set a one-second timer
  1200. g_uDialmonSecTimerID = SetTimer(hDlg,TIMER_ID_DIALMON_SEC,1000,NULL);
  1201. ASSERT(g_uDialmonSecTimerID);
  1202. if (!g_uDialmonSecTimerID) {
  1203. // it's very unlikely that setting the timer will fail... but if it
  1204. // does, then we'll act just like a normal dialog and won't have
  1205. // a countdown. Hide the countdown-related windows...
  1206. ShowWindow(GetDlgItem(hDlg,IDC_TX2),SW_HIDE);
  1207. ShowWindow(GetDlgItem(hDlg,IDC_GRP),SW_HIDE);
  1208. ShowWindow(GetDlgItem(hDlg,IDC_TIME_REMAINING),SW_HIDE);
  1209. ShowWindow(GetDlgItem(hDlg,IDC_TX3),SW_HIDE);
  1210. }
  1211. // beep to alert user
  1212. MessageBeep(MB_ICONEXCLAMATION);
  1213. }
  1214. // center this dialog on the screen
  1215. CenterWindow(hDlg,GetDesktopWindow());
  1216. // default: assume user does not disable auto disconnect, change
  1217. // this later if they do (this field is output to dialog invoker)
  1218. pDisconnectDlgInfo->fDisconnectDisabled = FALSE;
  1219. // Save dialog handle so we can get quit messages
  1220. pDisconnectDlgInfo->pDialMon->_hDisconnectDlg = hDlg;
  1221. return TRUE;
  1222. }
  1223. VOID DisconnectDlgCancel(HWND hDlg)
  1224. {
  1225. // get pointer to data struct out of window data
  1226. DISCONNECTDLGINFO * pDisconnectDlgInfo = (DISCONNECTDLGINFO *)
  1227. GetWindowLongPtr(hDlg, DWLP_USER);
  1228. ASSERT(pDisconnectDlgInfo);
  1229. // check to see if user checked 'disable autodisconnect' checkbox
  1230. if(IsDlgButtonChecked(hDlg,IDC_DISABLE_AUTODISCONNECT))
  1231. {
  1232. // set the output field to indicate that user wanted to disable
  1233. // auto disconnect
  1234. pDisconnectDlgInfo->fDisconnectDisabled = TRUE;
  1235. }
  1236. }
  1237. VOID DisconnectDlgTimerProc(HWND hDlg)
  1238. {
  1239. // ignore timer ticks (e.g. hold countdown) if "disable autodisconnect"
  1240. // checkbox is checked
  1241. if (IsDlgButtonChecked(hDlg,IDC_DISABLE_AUTODISCONNECT))
  1242. return;
  1243. // get pointer to data struct out of window data
  1244. DISCONNECTDLGINFO * pDisconnectDlgInfo =
  1245. (DISCONNECTDLGINFO *) GetWindowLongPtr(hDlg, DWLP_USER);
  1246. ASSERT(pDisconnectDlgInfo);
  1247. if (!pDisconnectDlgInfo)
  1248. return;
  1249. if (pDisconnectDlgInfo->dwCountdownVal) {
  1250. // decrement countdown value
  1251. pDisconnectDlgInfo->dwCountdownVal --;
  1252. // update the dialog with the new value
  1253. if (pDisconnectDlgInfo->dwCountdownVal) {
  1254. DisconnectDlgShowCountdown(hDlg,pDisconnectDlgInfo->dwCountdownVal);
  1255. return;
  1256. }
  1257. }
  1258. // countdown has run out!
  1259. // kill the timer
  1260. KillTimer(hDlg,g_uDialmonSecTimerID);
  1261. g_uDialmonSecTimerID = 0;
  1262. // send a 'OK' message to the dialog to dismiss it
  1263. SendMessage(hDlg,WM_COMMAND,IDOK,0);
  1264. }
  1265. VOID DisconnectDlgShowCountdown(HWND hDlg,DWORD dwSecsRemaining)
  1266. {
  1267. // build a string showing the number of seconds left
  1268. CHAR szSecs[10];
  1269. if (dwSecsRemaining == (DWORD) -1) {
  1270. StrCpyNA(szSecs, szDashes, ARRAYSIZE(szSecs));
  1271. } else {
  1272. wnsprintfA(szSecs, ARRAYSIZE(szSecs), "%lu", dwSecsRemaining);
  1273. }
  1274. // set string in text control
  1275. SetDlgItemTextA(hDlg, IDC_TIME_REMAINING, szSecs);
  1276. }
  1277. VOID DisconnectDlgDisableAutodisconnect(HWND hDlg)
  1278. {
  1279. // get pointer to data struct out of window data
  1280. DISCONNECTDLGINFO * pDisconnectDlgInfo = (DISCONNECTDLGINFO *)
  1281. GetWindowLongPtr(hDlg, DWLP_USER);
  1282. ASSERT(pDisconnectDlgInfo);
  1283. // find out if disable autodisconnect checkbox is checked
  1284. BOOL fDisabled = IsDlgButtonChecked(hDlg,IDC_DISABLE_AUTODISCONNECT);
  1285. // enable or disable controls appropriately
  1286. EnableDisconnectDlgCtrls(hDlg,!fDisabled);
  1287. if (!fDisabled) {
  1288. // reset timer if we're re-enabling autodisconnect
  1289. pDisconnectDlgInfo->dwCountdownVal = DISCONNECT_DLG_COUNTDOWN;
  1290. // show timer value
  1291. DisconnectDlgShowCountdown(hDlg,pDisconnectDlgInfo->dwCountdownVal);
  1292. } else {
  1293. // show "--" in countdown value
  1294. DisconnectDlgShowCountdown(hDlg,(DWORD) -1);
  1295. }
  1296. }
  1297. VOID EnableDisconnectDlgCtrls(HWND hDlg,BOOL fEnable)
  1298. {
  1299. EnableWindow(GetDlgItem(hDlg,IDC_TX1),fEnable);
  1300. EnableWindow(GetDlgItem(hDlg,IDC_TX2),fEnable);
  1301. EnableWindow(GetDlgItem(hDlg,IDC_TX3),fEnable);
  1302. EnableWindow(GetDlgItem(hDlg,IDC_TIME_REMAINING),fEnable);
  1303. EnableWindow(GetDlgItem(hDlg,IDOK),fEnable);
  1304. }
  1305. BOOL CenterWindow (HWND hwndChild, HWND hwndParent)
  1306. {
  1307. RECT rChild, rParent;
  1308. int wChild, hChild, wParent, hParent;
  1309. int wScreen, hScreen, xNew, yNew;
  1310. HDC hdc;
  1311. // Get the Height and Width of the child window
  1312. GetWindowRect (hwndChild, &rChild);
  1313. wChild = rChild.right - rChild.left;
  1314. hChild = rChild.bottom - rChild.top;
  1315. // Get the Height and Width of the parent window
  1316. GetWindowRect (hwndParent, &rParent);
  1317. wParent = rParent.right - rParent.left;
  1318. hParent = rParent.bottom - rParent.top;
  1319. // Get the display limits
  1320. hdc = GetDC (hwndChild);
  1321. wScreen = GetDeviceCaps (hdc, HORZRES);
  1322. hScreen = GetDeviceCaps (hdc, VERTRES);
  1323. ReleaseDC (hwndChild, hdc);
  1324. // Calculate new X position, then adjust for screen
  1325. xNew = rParent.left + ((wParent - wChild) /2);
  1326. if (xNew < 0) {
  1327. xNew = 0;
  1328. } else if ((xNew+wChild) > wScreen) {
  1329. xNew = wScreen - wChild;
  1330. }
  1331. // Calculate new Y position, then adjust for screen
  1332. yNew = rParent.top + ((hParent - hChild) /2);
  1333. if (yNew < 0) {
  1334. yNew = 0;
  1335. } else if ((yNew+hChild) > hScreen) {
  1336. yNew = hScreen - hChild;
  1337. }
  1338. // Set it, and return
  1339. return SetWindowPos (hwndChild, NULL, xNew, yNew, 0, 0,
  1340. SWP_NOSIZE | SWP_NOZORDER);
  1341. }
  1342. ///////////////////////////////////////////////////////////////////////////
  1343. ///////////////////////////////////////////////////////////////////////////
  1344. //
  1345. // BUFFER class implementation
  1346. //
  1347. ///////////////////////////////////////////////////////////////////////////
  1348. ///////////////////////////////////////////////////////////////////////////
  1349. BOOL BUFFER::Alloc( UINT cchBuffer )
  1350. {
  1351. _lpBuffer = (LPTSTR)::MemAlloc(LPTR,cchBuffer*sizeof(TCHAR));
  1352. if (_lpBuffer != NULL) {
  1353. _cch = cchBuffer;
  1354. return TRUE;
  1355. }
  1356. return FALSE;
  1357. }
  1358. BOOL BUFFER::Realloc( UINT cchNew )
  1359. {
  1360. LPVOID lpNew = ::MemReAlloc((HLOCAL)_lpBuffer, cchNew*sizeof(TCHAR),
  1361. LMEM_MOVEABLE | LMEM_ZEROINIT);
  1362. if (lpNew == NULL)
  1363. return FALSE;
  1364. _lpBuffer = (LPTSTR)lpNew;
  1365. _cch = cchNew;
  1366. return TRUE;
  1367. }
  1368. BUFFER::BUFFER( UINT cchInitial /* =0 */ )
  1369. : BUFFER_BASE(),
  1370. _lpBuffer( NULL )
  1371. {
  1372. if (cchInitial)
  1373. Alloc( cchInitial );
  1374. }
  1375. BUFFER::~BUFFER()
  1376. {
  1377. if (_lpBuffer != NULL) {
  1378. MemFree((HLOCAL) _lpBuffer);
  1379. _lpBuffer = NULL;
  1380. }
  1381. }
  1382. BOOL BUFFER::Resize( UINT cchNew )
  1383. {
  1384. BOOL fSuccess;
  1385. if (QuerySize() == 0)
  1386. fSuccess = Alloc( cchNew*sizeof(TCHAR) );
  1387. else {
  1388. fSuccess = Realloc( cchNew*sizeof(TCHAR) );
  1389. }
  1390. if (fSuccess)
  1391. _cch = cchNew;
  1392. return fSuccess;
  1393. }