Source code of Windows XP (NT5)
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.

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