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.

1635 lines
41 KiB

  1. // File: conf.cpp
  2. #include "precomp.h"
  3. #include <mixer.h>
  4. #include <EndSesn.h>
  5. #include "NmLdap.h"
  6. #include "conf.h"
  7. #include "confwnd.h"
  8. #include "taskbar.h"
  9. #include <CR.h>
  10. #include <tsecctrl.h>
  11. #include "iapplet.h"
  12. #include "inodecnt.h"
  13. #include "ConfCpl.h"
  14. #include "confroom.h"
  15. #include "rtoolbar.h"
  16. #include "GenWindow.h"
  17. #include "cmd.h"
  18. #include "confman.h"
  19. #include "splash.h"
  20. #include "calllog.h"
  21. #include "call.h" // for FreeCallList
  22. #include "popupmsg.h"
  23. #include "floatbar.h"
  24. #include "confman.h"
  25. #include <version.h>
  26. #include <nmremote.h>
  27. #include "wininet.h"
  28. #include "setupapi.h"
  29. #include "autoconf.h"
  30. #include "ConfNmSysInfoNotify.h"
  31. #include "ConfPolicies.h"
  32. #include "DShowDlg.h"
  33. #include "Callto.h"
  34. #include "passdlg.h"
  35. // SDK includes
  36. #include "NetMeeting.h"
  37. #include "NmApp.h"
  38. #include "NmManager.h"
  39. #include "NmCall.h"
  40. #include "NmConference.h"
  41. #include "SDKWindow.h"
  42. #include "confapi.h"
  43. #include "FtHook.h"
  44. #include "t120app.h"
  45. #include "certui.h"
  46. #include "dlgcall2.h"
  47. #include "ConfMsgFilter.h"
  48. BEGIN_OBJECT_MAP(ObjectMap)
  49. OBJECT_ENTRY(CLSID_NetMeeting, CNetMeetingObj)
  50. OBJECT_ENTRY(CLSID_NmManager, CNmManagerObj)
  51. OBJECT_ENTRY(CLSID_NmApplet, CNmAppletObj)
  52. END_OBJECT_MAP()
  53. extern VOID SaveDefaultCodecSettings(UINT uBandWidth);
  54. extern int WabReadMe(void);
  55. HRESULT InitSDK();
  56. void CleanupSDK();
  57. ///////////////////////////////////////////////////////////////////////////
  58. // Global Variables
  59. LPTSTR g_lpCmdLine = NULL;
  60. CCallLog * g_pInCallLog = NULL; // The incoming call log object
  61. CSimpleArray<ITranslateAccelerator*> *g_pDialogList = NULL; // Global list of modeless dialogs
  62. CRITICAL_SECTION dialogListCriticalSection; // This is to avoid multiple access to the dialogList
  63. INmSysInfo2 * g_pNmSysInfo = NULL; // Interface to SysInfo
  64. INmManager2* g_pInternalNmManager = NULL;
  65. DWORD g_dwSysInfoNotifyCookie = 0;
  66. bool g_bNeedCleanup = false;
  67. bool g_bEmbedding = FALSE; // Started with the embedding flag
  68. UINT g_uEndSessionMsg; // The "NetMeeting EndSession" message
  69. BOOL g_fHiColor = FALSE; // TRUE if we have more than 256 colors
  70. HWND g_hwndDropDown = NULL; //
  71. BOOL g_WSAStarted = FALSE; // WSAStartup
  72. CCallto * g_pCCallto = NULL;
  73. // The flag to indicate if the NetMeeting's NT display driver is enabled.
  74. BOOL g_fNTDisplayDriverEnabled = FALSE;
  75. OSVERSIONINFO g_osvi; // The os version info structure global
  76. ///////////////////////////////////////////////////////////////////////////
  77. // IPC-related globals:
  78. HANDLE g_hInitialized = NULL;
  79. HANDLE g_hShutdown = NULL;
  80. ///////////////////////////////////////////////////////////////////////////
  81. // Hidden window-related globals:
  82. CHiddenWindow * g_pHiddenWnd = NULL;
  83. HWND g_hwndESHidden = NULL;
  84. const TCHAR g_cszESHiddenWndClassName[] = _TEXT("ConfESHiddenWindow");
  85. LRESULT CALLBACK ESHiddenWndProc(HWND, UINT, WPARAM, LPARAM);
  86. ///////////////////////////////////////////////////////////////////////////
  87. // Remote control service related declarations
  88. INT_PTR CALLBACK ServiceRunningDlgProc(HWND hDlg, UINT iMsg, WPARAM wParam, LPARAM lParam);
  89. VOID RestartRemoteControlService();
  90. const int MAX_REMOTE_TRIES = 30; // number of seconds to wait for service to shut down
  91. const int SERVICE_IN_CALL = 1001;
  92. ///////////////////////////////////////////////////////////////////////////
  93. // Media Caps
  94. ULONG g_uMediaCaps = 0;
  95. BOOL FIsAudioAllowed()
  96. {
  97. return g_uMediaCaps & CAPFLAGS_AUDIO;
  98. }
  99. BOOL FIsReceiveVideoAllowed()
  100. {
  101. return g_uMediaCaps & CAPFLAG_RECV_VIDEO;
  102. }
  103. BOOL FIsSendVideoAllowed()
  104. {
  105. return g_uMediaCaps & CAPFLAG_SEND_VIDEO;
  106. }
  107. BOOL FIsAVCapable()
  108. {
  109. return (FIsAudioAllowed() || FIsReceiveVideoAllowed() || FIsSendVideoAllowed());
  110. }
  111. extern BOOL SetProcessDefaultLayout(int iLayout);
  112. typedef BOOL (WINAPI* PFNSPDL)(int);
  113. #define LAYOUT_LTR 0
  114. int g_iLayout = LAYOUT_LTR;
  115. DWORD g_wsLayout = 0;
  116. VOID CheckLanguageLayout(void)
  117. {
  118. TCHAR szLayout[CCHMAXUINT];
  119. if (!FLoadString(IDS_DEFAULT_LAYOUT, szLayout, CCHMAX(szLayout)))
  120. return;
  121. g_iLayout = (int) DecimalStringToUINT(szLayout);
  122. if (0 == g_iLayout)
  123. {
  124. #ifdef DEBUG
  125. RegEntry re(DEBUG_KEY, HKEY_LOCAL_MACHINE);
  126. g_iLayout = re.GetNumber(REGVAL_DBG_RTL, DEFAULT_DBG_RTL);
  127. if (0 == g_iLayout)
  128. #endif /* DEBUG */
  129. return;
  130. }
  131. HMODULE hmod = GetModuleHandle(TEXT("USER32"));
  132. if (NULL == hmod)
  133. return;
  134. PFNSPDL pfn = (PFNSPDL) GetProcAddress(hmod, "SetProcessDefaultLayout");
  135. if (NULL == pfn)
  136. return;
  137. BOOL fResult = pfn(g_iLayout);
  138. if (fResult)
  139. {
  140. g_wsLayout = WS_EX_NOINHERIT_LAYOUT;
  141. }
  142. else
  143. {
  144. ERROR_OUT(("Problem with SetProcessDefaultLayout"));
  145. }
  146. }
  147. ///////////////////////////////////////////////////////////////////////////
  148. // External Function Prototypes
  149. // from dbgmenu.cpp
  150. BOOL InitDebugMemoryOptions(void);
  151. ///////////////////////////////////////////////////////////////////////////
  152. // Local Function Prototypes
  153. BOOL HandleDialogMessage(LPMSG pMsg);
  154. // This is for command line parsing...
  155. LPCTSTR FindOneOf(LPCTSTR p1, LPCTSTR p2)
  156. {
  157. while (p1 != NULL && *p1 != NULL)
  158. {
  159. LPCTSTR p = p2;
  160. while (p != NULL && *p != NULL)
  161. {
  162. if (*p1 == *p)
  163. return CharNext(p1);
  164. p = CharNext(p);
  165. }
  166. p1 = CharNext(p1);
  167. }
  168. return NULL;
  169. }
  170. // This launches a rundll32.exe which loads msconf.dll which will then wait for
  171. // us to terminate and make sure that the mnmdd display driver was properly deactivated.
  172. BOOL CreateWatcherProcess()
  173. {
  174. BOOL bRet = FALSE;
  175. HANDLE hProcess;
  176. // open a handle to ourselves that the watcher process can inherit
  177. hProcess = OpenProcess(SYNCHRONIZE,
  178. TRUE,
  179. GetCurrentProcessId());
  180. if (hProcess)
  181. {
  182. TCHAR szWindir[MAX_PATH];
  183. if (GetSystemDirectory(szWindir, sizeof(szWindir)/sizeof(szWindir[0])))
  184. {
  185. TCHAR szCmdLine[MAX_PATH * 2];
  186. PROCESS_INFORMATION pi = {0};
  187. STARTUPINFO si = {0};
  188. si.cb = sizeof(si);
  189. wsprintf(szCmdLine, "\"%s\\rundll32.exe\" msconf.dll,CleanupNetMeetingDispDriver %ld", szWindir, HandleToLong(hProcess));
  190. if (CreateProcess(NULL,
  191. szCmdLine,
  192. NULL,
  193. NULL,
  194. TRUE, // we want the watcher to inherit hProcess, so we must set bInheritHandles = TRUE
  195. 0,
  196. NULL,
  197. NULL,
  198. &si,
  199. &pi))
  200. {
  201. bRet = TRUE;
  202. CloseHandle(pi.hThread);
  203. CloseHandle(pi.hProcess);
  204. }
  205. }
  206. CloseHandle(hProcess);
  207. }
  208. return bRet;
  209. }
  210. ///////////////////////////////////////////////////////////////////////////
  211. int WINAPI _tWinMain(HINSTANCE hInstance, HINSTANCE hInstPrev, LPTSTR lpCmdLine, int nCmdShow)
  212. {
  213. // if there is another instance of NetMeeting shutting down
  214. // get out of here. Ideally we should display a message and/or wait for shutdown.
  215. HANDLE hEvent = OpenEvent(EVENT_ALL_ACCESS, FALSE, _TEXT("CONF:ShuttingDown"));
  216. if (NULL != hEvent)
  217. {
  218. DWORD dwResult = WaitForSingleObject(hEvent, INFINITE);
  219. CloseHandle(hEvent);
  220. if (WAIT_TIMEOUT == dwResult)
  221. {
  222. return TRUE;
  223. }
  224. }
  225. // Init debug output as soon as possible
  226. ASSERT(::InitDebugMemoryOptions());
  227. ASSERT(::InitDebugModule(TEXT("CONF")));
  228. ASSERT(::InitDebugZones());
  229. g_lpCmdLine = lpCmdLine;
  230. int nRet = TRUE;
  231. BOOL fRestartService = FALSE;
  232. HRESULT hr = ::CoInitializeEx(NULL, COINIT_APARTMENTTHREADED);
  233. if( SUCCEEDED( hr ) )
  234. {
  235. // Init CComModule
  236. _Module.Init(ObjectMap, hInstance, &LIBID_NetMeetingLib);
  237. _Module.m_dwThreadID = GetCurrentThreadId();
  238. _Module.m_hResourceModule = hInstance;
  239. TCHAR szCommandLineSeps[] = _T("-/");
  240. // Check to see if this is a reg/unreg request or background...
  241. BOOL fShowUI = TRUE;
  242. BOOL bRun = TRUE;
  243. LPCTSTR lpszToken = FindOneOf(lpCmdLine, szCommandLineSeps);
  244. while (lpszToken != NULL)
  245. {
  246. if (lstrcmpi(lpszToken, _T("Embedding"))==0)
  247. {
  248. TRACE_OUT(("We are started with the -Embedding flag"));
  249. g_bEmbedding = TRUE;
  250. }
  251. if (lstrcmpi(lpszToken, _T("UnregServer"))==0)
  252. {
  253. _Module.UpdateRegistryFromResource(IDR_NETMEETING, FALSE);
  254. nRet = _Module.UnregisterServer(TRUE);
  255. // These will fail without complaints
  256. DeleteShortcut(CSIDL_DESKTOP, g_szEmpty);
  257. DeleteShortcut(CSIDL_APPDATA, QUICK_LAUNCH_SUBDIR);
  258. bRun = FALSE;
  259. break;
  260. }
  261. if (lstrcmpi(lpszToken, _T("RegServer"))==0)
  262. {
  263. _Module.UpdateRegistryFromResource(IDR_NETMEETING, TRUE);
  264. nRet = _Module.RegisterServer(TRUE);
  265. bRun = FALSE;
  266. break;
  267. }
  268. if (lstrcmpi(lpszToken, g_cszBackgroundSwitch)==0)
  269. {
  270. fShowUI = FALSE;
  271. }
  272. lpszToken = FindOneOf(lpszToken, szCommandLineSeps);
  273. }
  274. if (bRun)
  275. {
  276. // Setup and RDS rely on the following event to determine whether NetMeeting is Running
  277. // this event creation should not be removed and the name should not be changed
  278. g_hInitialized = ::CreateEvent(NULL, TRUE, FALSE, _TEXT("CONF:Init"));
  279. if (NULL != g_hInitialized)
  280. {
  281. if (ERROR_ALREADY_EXISTS == ::GetLastError())
  282. {
  283. // CreateEvent returned a valid handle, but we don't want initialization to
  284. // succeed if we are running another copy of this exe, so we cleanup and exit
  285. WARNING_OUT(("Detected another conf.exe - sending a message"));
  286. IInternalConfExe * pInternalConfExe;
  287. hr = CoCreateInstance( CLSID_NmManager, NULL, CLSCTX_ALL,
  288. IID_IInternalConfExe, (LPVOID *) &pInternalConfExe );
  289. if (SUCCEEDED(hr))
  290. {
  291. if(FAILED(pInternalConfExe->Launch()))
  292. {
  293. // If we are in INIT_CONTROL mode, then we can't launch NetMeeting or applets
  294. ::ConfMsgBox(NULL, (LPCTSTR) IDS_CANT_START_NM_BECAUSE_SDK_APP_OWNS_NM);
  295. }
  296. pInternalConfExe->Release();
  297. }
  298. }
  299. else if(SUCCEEDED(InitHtmlHelpMarshaler(_Module.GetModuleInstance())))
  300. {
  301. // We create a seperate watcher process that will cleanup the mnmdd display driver
  302. // if we terminate unexpectedly. This is necessary since if we do not disable the
  303. // mirrored driver, all DX games will fail to run
  304. CreateWatcherProcess();
  305. //initialize ATL control contaiment code
  306. AtlAxWinInit();
  307. hr = _Module.RegisterClassObjects(CLSCTX_LOCAL_SERVER, REGCLS_MULTIPLEUSE);
  308. if( SUCCEEDED( hr ) )
  309. {
  310. BOOL fContinue = TRUE;
  311. if( FAILED(InitSDK()) )
  312. {
  313. fContinue = FALSE;
  314. }
  315. if(!g_bEmbedding)
  316. {
  317. // Before doing anything else, take care of the remote control service.
  318. fContinue = CheckRemoteControlService();
  319. fRestartService = fContinue;
  320. if(fContinue)
  321. {
  322. fContinue = SUCCEEDED(InitConfExe(fShowUI));
  323. }
  324. }
  325. if(fContinue)
  326. {
  327. TRACE_OUT(("Entering event loop..."));
  328. MSG msg;
  329. while (::GetMessage(&msg, NULL, 0, 0))
  330. {
  331. BOOL bHandled = FALSE;
  332. if(g_pPing) // This is TRUE if InitConfExe has been called...
  333. {
  334. bHandled = ::HandleDialogMessage(&msg);
  335. }
  336. if(!bHandled)
  337. {
  338. ::TranslateMessage(&msg);
  339. ::DispatchMessage(&msg);
  340. }
  341. }
  342. TRACE_OUT(("Conf received WM_QUIT"));
  343. }
  344. if(g_bNeedCleanup)
  345. {
  346. CleanUp();
  347. }
  348. CleanupSDK();
  349. _Module.RevokeClassObjects();
  350. }
  351. }
  352. ::CloseHandle(g_hInitialized);
  353. if (g_hShutdown)
  354. {
  355. SetEvent(g_hShutdown);
  356. ::CloseHandle(g_hShutdown);
  357. }
  358. }
  359. else
  360. {
  361. ERROR_OUT(("CreateEvent (init) failed!"));
  362. hr = E_FAIL;
  363. }
  364. _Module.Term();
  365. }
  366. ::CoUninitialize();
  367. //
  368. // Restart the remote control service if we need to.
  369. //
  370. if (fRestartService)
  371. RestartRemoteControlService();
  372. }
  373. #ifdef DEBUG
  374. ::ExitDebugModule();
  375. TRACE_OUT(("returned from ExitDebugModule"));
  376. ::DeinitDebugZones();
  377. TRACE_OUT(("returned from DeinitDebugZones"));
  378. #endif //DEBUG
  379. return nRet;
  380. }
  381. VOID CheckMachineNameForExtendedChars ( VOID )
  382. {
  383. DBGENTRY(CheckMachineNameForExtendedChars);
  384. // First we have to get the computer name
  385. TCHAR szMachineName[MAX_COMPUTERNAME_LENGTH + 1];
  386. DWORD cchMachineName = CCHMAX(szMachineName);
  387. // Next we check to see if the computer nami is invalid
  388. if (GetComputerName(szMachineName, &cchMachineName))
  389. {
  390. for ( LPTSTR p = szMachineName; *p != _T('\0'); p++ )
  391. {
  392. if ( (WORD)(*p) & 0xFF80 )
  393. {
  394. // The machine name is invalid because it contains an invalid character
  395. CDontShowDlg MachineNameWarningDlg( IDS_MACHINENAMEWARNING,
  396. REGVAL_DS_MACHINE_NAME_WARNING,
  397. DSD_ALWAYSONTOP | MB_SETFOREGROUND | MB_OK
  398. );
  399. MachineNameWarningDlg.DoModal(NULL);
  400. goto end;
  401. }
  402. }
  403. }
  404. else
  405. {
  406. ERROR_OUT(("GetComputerName() failed, err=%lu", GetLastError()));
  407. *szMachineName = TEXT('\0');
  408. }
  409. end:
  410. DBGEXIT(CheckMachineNameForExtendedChars);
  411. }
  412. VOID HandleConfSettingsChange(DWORD dwSettings)
  413. {
  414. DebugEntry(HandleConfSettingsChange);
  415. TRACE_OUT(("HandleConfSettingsChange, dwSettings=0x%x", dwSettings));
  416. // Tell the user if she changed something that won't take
  417. // effect right away
  418. if (CSETTING_L_REQUIRESRESTARTMASK & dwSettings)
  419. {
  420. ::ConfMsgBox(NULL, (LPCTSTR) IDS_NEED_RESTART);
  421. }
  422. if (CSETTING_L_REQUIRESNEXTCALLMASK & dwSettings)
  423. {
  424. if (::FIsConferenceActive())
  425. {
  426. ::ConfMsgBox(NULL, (LPCTSTR) IDS_NEED_NEXTCALL);
  427. }
  428. }
  429. if (CSETTING_L_BANDWIDTH & dwSettings)
  430. {
  431. if (NULL != g_pNmSysInfo)
  432. {
  433. int nMegahertz=300, nProcFamily=6;
  434. RegEntry re(AUDIO_KEY, HKEY_CURRENT_USER);
  435. UINT uSysPolBandwidth;
  436. UINT uBandwidth;
  437. uBandwidth = re.GetNumber(REGVAL_TYPICALBANDWIDTH, BW_DEFAULT);
  438. #ifdef _M_IX86
  439. GetNormalizedCPUSpeed(&nMegahertz, &nProcFamily);
  440. TRACE_OUT(("Normalized Processor Speed = %d, Processor type = %d\n", nMegahertz, nProcFamily));
  441. #endif
  442. // convert bandwidth ID (1-4) to bits/sec
  443. uBandwidth = GetBandwidthBits(uBandwidth, nMegahertz);
  444. // the existance of a QOS - maximum bandwidth key implies that
  445. // the user's bandwidth is being over-rided (ONLY if his setting is LAN)
  446. uSysPolBandwidth = SysPol::GetMaximumBandwidth();
  447. if ((uSysPolBandwidth > 0) && (uBandwidth >= BW_SLOWLAN_BITS))
  448. {
  449. uBandwidth = max(uSysPolBandwidth, BW_144KBS_BITS);
  450. }
  451. g_pNmSysInfo->SetOption(NM_SYSOPT_BANDWIDTH, uBandwidth);
  452. }
  453. }
  454. if (CSETTING_L_SHOWTASKBAR & dwSettings)
  455. {
  456. // This will remove one if one is already there:
  457. ::RemoveTaskbarIcon(::GetHiddenWindow());
  458. // This will add the icon if the registry switch is on:
  459. ::AddTaskbarIcon(::GetHiddenWindow());
  460. }
  461. if (CSETTING_L_AUDIODEVICE & dwSettings)
  462. {
  463. CConfRoom* pcr = ::GetConfRoom();
  464. if (NULL != pcr)
  465. {
  466. pcr->OnAudioDeviceChanged();
  467. }
  468. }
  469. if (CSETTING_L_AGC & dwSettings)
  470. {
  471. CConfRoom* pcr = ::GetConfRoom();
  472. if (NULL != pcr)
  473. {
  474. pcr->OnAGC_Changed();
  475. }
  476. }
  477. if ((CSETTING_L_AUTOMIC|CSETTING_L_MICSENSITIVITY) & dwSettings)
  478. {
  479. CConfRoom* pcr = ::GetConfRoom();
  480. if (NULL != pcr)
  481. {
  482. pcr->OnSilenceLevelChanged();
  483. }
  484. }
  485. if( CSETTING_L_ULSSETTINGS & dwSettings )
  486. {
  487. if(g_pLDAP)
  488. {
  489. g_pLDAP->OnSettingsChanged();
  490. }
  491. if (NULL != g_pNmSysInfo)
  492. {
  493. RegEntry re(ISAPI_CLIENT_KEY, HKEY_CURRENT_USER);
  494. LPCTSTR pcszName = re.GetString(REGVAL_ULS_NAME);
  495. g_pNmSysInfo->SetProperty(NM_SYSPROP_USER_NAME, CComBSTR(pcszName));
  496. }
  497. }
  498. if (CSETTING_L_FULLDUPLEX & dwSettings)
  499. {
  500. RegEntry re(AUDIO_KEY, HKEY_CURRENT_USER);
  501. BOOL bFullDuplex = FALSE;
  502. UINT uSoundCardCaps = re.GetNumber(REGVAL_SOUNDCARDCAPS,SOUNDCARD_NONE);
  503. if (ISSOUNDCARDFULLDUPLEX(uSoundCardCaps))
  504. {
  505. bFullDuplex = re.GetNumber(REGVAL_FULLDUPLEX,FULLDUPLEX_DISABLED);
  506. }
  507. ASSERT(g_pNmSysInfo);
  508. if (NULL != g_pNmSysInfo)
  509. {
  510. g_pNmSysInfo->SetOption(NM_SYSOPT_FULLDUPLEX, bFullDuplex);
  511. }
  512. }
  513. if (CSETTING_L_CAPTUREDEVICE & dwSettings)
  514. {
  515. if (NULL != g_pNmSysInfo)
  516. {
  517. RegEntry re(VIDEO_KEY, HKEY_CURRENT_USER);
  518. DWORD dwCaptureID = re.GetNumber(REGVAL_CAPTUREDEVICEID, 0);
  519. g_pNmSysInfo->SetOption(NM_SYSOPT_CAPTURE_DEVICE, dwCaptureID);
  520. }
  521. }
  522. if (CSETTING_L_DIRECTSOUND & dwSettings)
  523. {
  524. ASSERT(g_pNmSysInfo);
  525. if (NULL != g_pNmSysInfo)
  526. {
  527. RegEntry re(AUDIO_KEY, HKEY_CURRENT_USER);
  528. DWORD dwDS = re.GetNumber(REGVAL_DIRECTSOUND, DSOUND_USER_DISABLED);
  529. g_pNmSysInfo->SetOption(NM_SYSOPT_DIRECTSOUND, dwDS);
  530. }
  531. }
  532. DebugExitVOID(HandleConfSettingsChange);
  533. }
  534. // DeleteOldRegSettings is called the first time
  535. // this build of NetMeeting is run by the user
  536. // We don't touch UI\Directory as it is populated by the INF file
  537. VOID DeleteOldRegSettings()
  538. {
  539. // "%KEY_CONFERENCING%\UI"
  540. HKEY hKey;
  541. long lRet = ::RegOpenKey(HKEY_CURRENT_USER, UI_KEY, &hKey);
  542. if (NO_ERROR == lRet)
  543. {
  544. ::RegDeleteValue(hKey, REGVAL_MP_WINDOW_X);
  545. ::RegDeleteValue(hKey, REGVAL_MP_WINDOW_Y);
  546. ::RegDeleteValue(hKey, REGVAL_MP_WINDOW_WIDTH);
  547. ::RegDeleteValue(hKey, REGVAL_MP_WINDOW_HEIGHT);
  548. ::RegCloseKey(hKey);
  549. }
  550. }
  551. static HRESULT _ValidatePolicySettings()
  552. {
  553. HRESULT hr = S_OK;
  554. if( g_pNmSysInfo )
  555. {
  556. //
  557. // LAURABU BUGBUG BOGUS:
  558. //
  559. // If security required, and not available, warning
  560. // If security incoming required/outgoing preferred, warning
  561. //
  562. }
  563. else
  564. {
  565. ERROR_OUT(("g_pNmySysInfo should not me NULL"));
  566. hr = E_UNEXPECTED;
  567. }
  568. return hr;
  569. }
  570. HRESULT InitSDK()
  571. {
  572. DBGENTRY(InitSDK);
  573. HRESULT hr = S_OK;
  574. if(FAILED(hr = CSDKWindow::InitSDK())) goto end;
  575. if(FAILED(hr = CNmCallObj::InitSDK())) goto end;
  576. if(FAILED(hr = CNmManagerObj::InitSDK())) goto end;
  577. if(FAILED(hr = CNmConferenceObj::InitSDK())) goto end;
  578. if(FAILED(hr = CNetMeetingObj::InitSDK())) goto end;
  579. if(FAILED(hr = CFt::InitFt())) goto end;
  580. g_pCCallto = new CCallto;
  581. ASSERT( g_pCCallto != NULL );
  582. if( g_pCCallto == NULL )
  583. {
  584. hr = E_FAIL;
  585. }
  586. end:
  587. DBGEXIT_HR(InitSDK,hr);
  588. return hr;
  589. }
  590. void CleanupSDK()
  591. {
  592. DBGENTRY(CleanupSDK);
  593. // Revoke the old filter object
  594. CoRegisterMessageFilter(NULL, NULL);
  595. CNmCallObj::CleanupSDK();
  596. CNmManagerObj::CleanupSDK();
  597. CNmConferenceObj::CleanupSDK();
  598. CSDKWindow::CleanupSDK();
  599. CNetMeetingObj::CleanupSDK();
  600. CFt::CloseFtApplet();
  601. DBGEXIT(CleanupSDK);
  602. }
  603. /* I N I T C O N F E X E */
  604. /*-------------------------------------------------------------------------
  605. %%Function: InitConfExe
  606. -------------------------------------------------------------------------*/
  607. HRESULT InitConfExe(BOOL fShowUI)
  608. {
  609. // Create a message filter object
  610. CComPtr<IMessageFilter> spMsgFilter;
  611. CComPtr<IMessageFilter> spOldMsgFilter;
  612. HRESULT hr = CConfMsgFilter::_CreatorClass::CreateInstance(NULL, IID_IMessageFilter, reinterpret_cast<void**>(&spMsgFilter));
  613. if(FAILED(hr)) return hr;
  614. // Register the message filter object
  615. hr = CoRegisterMessageFilter(spMsgFilter, &spOldMsgFilter);
  616. if(FAILED(hr)) return hr;
  617. // Wipe out default find directory entry... we no longer wish to persist this...
  618. // in some future overhaul / cleanup we should stop using the registry for this...
  619. RegEntry re( DLGCALL_MRU_KEY, HKEY_CURRENT_USER );
  620. re.SetValue( REGVAL_DLGCALL_DEFDIR, TEXT( "" ) );
  621. LPCTSTR lpCmdLine = g_lpCmdLine;
  622. TRACE_OUT(("InitConfExe"));
  623. // Init UI objects (NOTE: we continue if this fails)
  624. CPopupMsg::Init();
  625. CPasswordDlg::Init();
  626. // Allocate dialog list object:
  627. g_pDialogList = new CSimpleArray<ITranslateAccelerator*>;
  628. if (NULL == g_pDialogList)
  629. {
  630. ERROR_OUT(("Could not allocate g_pDialogList!"));
  631. return E_FAIL;
  632. }
  633. //
  634. // Initialize the critical section to protect the dialogList
  635. //
  636. InitializeCriticalSection(&dialogListCriticalSection);
  637. // Determine if we have MORE THAN 256 colors
  638. {
  639. HDC hdc = GetDC(NULL);
  640. if (NULL != hdc)
  641. {
  642. g_fHiColor = 8 < (::GetDeviceCaps(hdc, BITSPIXEL) * ::GetDeviceCaps(hdc, PLANES));
  643. ReleaseDC(NULL, hdc);
  644. }
  645. }
  646. // Get the default dialog (GUI) font for international
  647. // REVIEW: should we check the registry for a localized font?
  648. g_hfontDlg = (HFONT) ::GetStockObject(DEFAULT_GUI_FONT);
  649. if (NULL == g_hfontDlg)
  650. {
  651. return E_FAIL;
  652. }
  653. LoadIconImages();
  654. // On Windows NT, determine if the NetMeeting display driver is
  655. // enabled. Note that this depends on <g_osvi> being initialized.
  656. //
  657. // Since NT 5.0 will support dynamic loading of the display driver,
  658. // we assume that the driver is enabled if the OS major version
  659. // number is greater than 4.
  660. if (::IsWindowsNT())
  661. {
  662. RegEntry re1(NM_NT_DISPLAY_DRIVER_KEY, HKEY_LOCAL_MACHINE, FALSE);
  663. g_fNTDisplayDriverEnabled =
  664. 4 < g_osvi.dwMajorVersion ||
  665. NT_DRIVER_START_DISABLED !=
  666. re1.GetNumber(
  667. REGVAL_NM_NT_DISPLAY_DRIVER_ENABLED,
  668. NT_DRIVER_START_DISABLED);
  669. }
  670. else
  671. {
  672. ASSERT(FALSE == g_fNTDisplayDriverEnabled);
  673. }
  674. // Check the language layout (UI can be displayed after this point)
  675. CheckLanguageLayout();
  676. // AutoConfiguration
  677. CAutoConf::DoIt();
  678. TRACE_OUT(("Command Line is \"%s\"", lpCmdLine));
  679. // Register hidden window class:
  680. WNDCLASS wcESHidden =
  681. {
  682. 0L,
  683. ESHiddenWndProc,
  684. 0,
  685. 0,
  686. _Module.GetModuleInstance(),
  687. NULL,
  688. NULL,
  689. NULL,
  690. NULL,
  691. g_cszESHiddenWndClassName
  692. };
  693. if (!RegisterClass(&wcESHidden))
  694. {
  695. ERROR_OUT(("Could not register hidden wnd classes"));
  696. return E_FAIL;
  697. }
  698. // Register the "NetMeeting EndSession" message:
  699. g_uEndSessionMsg = ::RegisterWindowMessage(NM_ENDSESSION_MSG_NAME);
  700. // Create a hidden window for event processing:
  701. g_pHiddenWnd = new CHiddenWindow();
  702. if (NULL == g_pHiddenWnd)
  703. {
  704. return(E_FAIL);
  705. }
  706. g_pHiddenWnd->Create();
  707. g_hwndESHidden = ::CreateWindow( g_cszESHiddenWndClassName,
  708. _TEXT(""),
  709. WS_POPUP, // not visible!
  710. 0, 0, 0, 0,
  711. NULL,
  712. NULL,
  713. _Module.GetModuleInstance(),
  714. NULL);
  715. HWND hwndHidden = g_pHiddenWnd->GetWindow();
  716. if ((NULL == hwndHidden) || (NULL == g_hwndESHidden))
  717. {
  718. ERROR_OUT(("Could not create hidden windows"));
  719. return E_FAIL;
  720. }
  721. LONG lSoundCaps = SOUNDCARD_NONE;
  722. // Start the run-once wizard (if needed):
  723. RegEntry reConf(CONFERENCING_KEY, HKEY_CURRENT_USER);
  724. // check to see if the wizard has been run in UI mode for this build
  725. DWORD dwVersion = reConf.GetNumber(REGVAL_WIZARD_VERSION_UI, 0);
  726. BOOL fRanWizardUI = ((VER_PRODUCTVERSION_W & HIWORD(dwVersion)) == VER_PRODUCTVERSION_W);
  727. BOOL fForceWizard = FALSE;
  728. if (!fRanWizardUI)
  729. {
  730. dwVersion = reConf.GetNumber(REGVAL_WIZARD_VERSION_NOUI, 0);
  731. BOOL fRanWizardNoUI = (VER_PRODUCTVERSION_DW == dwVersion);
  732. // wizard has not been run in UI mode
  733. if (!fRanWizardNoUI)
  734. {
  735. // wizard has not been run before, delete old registry settings
  736. DeleteOldRegSettings();
  737. fForceWizard = TRUE;
  738. }
  739. else
  740. {
  741. // wizard has been run in NoUI mode, we only need to run it if we are in UI mode
  742. if(fShowUI)
  743. {
  744. fForceWizard = TRUE;
  745. }
  746. }
  747. if (fForceWizard)
  748. {
  749. WabReadMe();
  750. }
  751. }
  752. hr = ::StartRunOnceWizard(&lSoundCaps, fForceWizard, fShowUI);
  753. if (FAILED(hr))
  754. {
  755. WARNING_OUT(("Did not retrieve necessary info from wizard"));
  756. ConfMsgBox(NULL, MAKEINTRESOURCE(IDS_ERROR_BAD_ADMIN_SETTINGS));
  757. return E_FAIL;
  758. }
  759. else if( S_FALSE == hr )
  760. {
  761. return NM_E_USER_CANCELED_SETUP;
  762. }
  763. if (fForceWizard)
  764. {
  765. reConf.SetValue(fShowUI ? REGVAL_WIZARD_VERSION_UI :
  766. REGVAL_WIZARD_VERSION_NOUI, VER_PRODUCTVERSION_DW);
  767. }
  768. // Start NetMeeting At Page Once
  769. if( fShowUI && fForceWizard )
  770. {
  771. if( ConfPolicies::IsShowFirstTimeUrlEnabled() )
  772. {
  773. CmdLaunchWebPage(ID_HELP_WEB_SUPPORT);
  774. }
  775. }
  776. // The following hack is to fix the don't run wizard twice bug
  777. // the side effect is that the codec ordering is blown away.
  778. // this code restores the key in the event that this wizard is not run.
  779. HKEY hKey;
  780. long lRet = ::RegOpenKey(HKEY_LOCAL_MACHINE,
  781. INTERNET_AUDIO_KEY TEXT("\\") REGVAL_ACMH323ENCODINGS , &hKey);
  782. if (NO_ERROR == lRet)
  783. {
  784. ::RegCloseKey(hKey);
  785. }
  786. else
  787. {
  788. RegEntry reAudio(AUDIO_KEY, HKEY_CURRENT_USER);
  789. UINT uBandwidth = reAudio.GetNumber ( REGVAL_TYPICALBANDWIDTH, BW_DEFAULT );
  790. SaveDefaultCodecSettings(uBandwidth);
  791. }
  792. // Start the Splash screen only after the wizard is complete
  793. if (fShowUI)
  794. {
  795. ::StartSplashScreen(NULL);
  796. }
  797. // Init incoming call log:
  798. g_pInCallLog = new CCallLog(LOG_INCOMING_KEY, TEXT("CallLog"));
  799. // Init capabilities:
  800. g_uMediaCaps = CAPFLAG_DATA;
  801. //
  802. // NOTE: THIS IS WHERE TO CHANGE TO DISABLE H323 CALLS FOR INTEL ET AL.
  803. //
  804. if(!_Module.DidSDKDisableH323())
  805. {
  806. g_uMediaCaps |= CAPFLAG_H323_CC;
  807. if (SOUNDCARD_NONE != lSoundCaps)
  808. {
  809. if (!SysPol::NoAudio())
  810. {
  811. g_uMediaCaps |= CAPFLAGS_AUDIO;
  812. }
  813. }
  814. if (!SysPol::NoVideoReceive())
  815. {
  816. g_uMediaCaps |= CAPFLAG_RECV_VIDEO;
  817. }
  818. if (!SysPol::NoVideoSend())
  819. {
  820. g_uMediaCaps |= CAPFLAG_SEND_VIDEO;
  821. }
  822. }
  823. // Create Manager
  824. hr = CoCreateInstance(CLSID_NmManager2, NULL, CLSCTX_INPROC, IID_INmManager2, (void**)&g_pInternalNmManager);
  825. if (FAILED(hr))
  826. {
  827. ERROR_OUT(("Could not create INmManager"));
  828. return E_FAIL;
  829. }
  830. // Get the INmSysInfo3
  831. CComPtr<INmSysInfo > spSysInfo;
  832. if (SUCCEEDED(g_pInternalNmManager->GetSysInfo(&spSysInfo)))
  833. {
  834. if (FAILED(spSysInfo->QueryInterface(IID_INmSysInfo2, (void **)&g_pNmSysInfo)))
  835. {
  836. ERROR_OUT(("Could not get INmSysInfo2"));
  837. }
  838. else
  839. {
  840. ASSERT( g_pNmSysInfo );
  841. CComPtr<INmSysInfoNotify> spNmSysInfoNotify;
  842. if( SUCCEEDED ( CConfNmSysInfoNotifySink::_CreatorClass::CreateInstance( NULL, IID_INmSysInfoNotify, reinterpret_cast<void**>(&spNmSysInfoNotify))))
  843. {
  844. ASSERT(spNmSysInfoNotify);
  845. ASSERT(0 == g_dwSysInfoNotifyCookie);
  846. NmAdvise(g_pNmSysInfo, spNmSysInfoNotify, IID_INmSysInfoNotify, &g_dwSysInfoNotifyCookie);
  847. }
  848. }
  849. }
  850. _ValidatePolicySettings();
  851. hr = g_pInternalNmManager->Initialize(NULL, &g_uMediaCaps);
  852. if (FAILED(hr))
  853. {
  854. UINT_PTR uErrorID;
  855. switch (hr)
  856. {
  857. case UI_RC_NO_NODE_NAME:
  858. {
  859. // No error in this case - the user probably cancelled from
  860. // the intro wizard.
  861. uErrorID = 0;
  862. break;
  863. }
  864. case UI_RC_BACKLEVEL_LOADED:
  865. {
  866. uErrorID = IDS_BACKLEVEL_LOADED;
  867. break;
  868. }
  869. case UI_RC_T120_ALREADY_INITIALIZED:
  870. {
  871. uErrorID = IDS_T120_ALREADY_INITIALIZED;
  872. break;
  873. }
  874. case UI_RC_T120_FAILURE:
  875. {
  876. WARNING_OUT(("T.120 failed to initialize (winsock problem?)"));
  877. uErrorID = IDS_CANT_START;
  878. break;
  879. }
  880. default:
  881. {
  882. uErrorID = IDS_CANT_START;
  883. break;
  884. }
  885. }
  886. if (0 != uErrorID)
  887. {
  888. ::ConfMsgBox(NULL, (LPCTSTR) uErrorID);
  889. }
  890. return E_FAIL;
  891. }
  892. // force the update of dll settings
  893. HandleConfSettingsChange(CSETTING_L_BANDWIDTH |
  894. CSETTING_L_CAPTUREDEVICE |
  895. CSETTING_L_ULSSETTINGS |
  896. CSETTING_L_DIRECTSOUND|
  897. CSETTING_L_FULLDUPLEX);
  898. if (FALSE == ::ConfRoomInit(_Module.GetModuleInstance()))
  899. {
  900. ::ConfMsgBox(NULL, (LPCTSTR) IDS_CANT_START);
  901. return E_FAIL;
  902. }
  903. // Now perform the check on the machine name and warn if
  904. // it is problematic.
  905. ::CheckMachineNameForExtendedChars();
  906. // Create the main conference manager to make sure
  907. // we can handle incoming calls, even in background mode
  908. if (!CConfMan::FCreate(g_pInternalNmManager))
  909. {
  910. ERROR_OUT(("Unable to create Conference Manager"));
  911. return E_FAIL;
  912. }
  913. // Initialize winsock (for name/address resolution)
  914. {
  915. WSADATA wsaData;
  916. int iErr = WSAStartup(0x0101, &wsaData);
  917. if (0 != iErr)
  918. {
  919. ERROR_OUT(("WSAStartup() failed: %i", iErr));
  920. return E_FAIL;
  921. }
  922. g_WSAStarted = TRUE;
  923. }
  924. // Initialize T.120 Security settings
  925. ::InitT120SecurityFromRegistry();
  926. StopSplashScreen();
  927. CreateConfRoomWindow(fShowUI);
  928. g_pPing = new CPing;
  929. if( ConfPolicies::GetCallingMode() == ConfPolicies::CallingMode_Direct )
  930. {
  931. // Initialize gatewayContext...
  932. RegEntry reConf1( CONFERENCING_KEY, HKEY_CURRENT_USER );
  933. if( reConf1.GetNumber( REGVAL_USE_H323_GATEWAY ) != 0 )
  934. {
  935. g_pCCallto->SetGatewayName( reConf1.GetString( REGVAL_H323_GATEWAY ) );
  936. g_pCCallto->SetGatewayEnabled( true );
  937. }
  938. if(ConfPolicies::LogOntoIlsWhenNetMeetingStartsIfInDirectCallingMode() && !_Module.DidSDKDisableInitialILSLogon())
  939. {
  940. InitNmLdapAndLogon();
  941. }
  942. }
  943. else
  944. {
  945. GkLogon();
  946. }
  947. if(!_Module.InitControlMode())
  948. {
  949. ::AddTaskbarIcon(::GetHiddenWindow());
  950. }
  951. g_bNeedCleanup = true;
  952. CNmManagerObj::NetMeetingLaunched();
  953. return S_OK;
  954. }
  955. VOID CleanUpUi(void)
  956. {
  957. SysPol::CloseKey();
  958. if( 0 != g_dwSysInfoNotifyCookie )
  959. {
  960. NmUnadvise(g_pNmSysInfo, IID_INmSysInfoNotify, g_dwSysInfoNotifyCookie);
  961. g_dwSysInfoNotifyCookie = 0;
  962. }
  963. if (NULL != g_pNmSysInfo)
  964. {
  965. if( IsGatekeeperLoggedOn() )
  966. {
  967. g_pNmSysInfo->GkLogoff();
  968. }
  969. g_pNmSysInfo->Release();
  970. g_pNmSysInfo = NULL;
  971. }
  972. FreeIconImages();
  973. CGenWindow::DeleteStandardPalette();
  974. CGenWindow::DeleteStandardBrush();
  975. CMainUI::CleanUpVideoWindow();
  976. CFindSomeone::Destroy();
  977. }
  978. VOID CleanUp(BOOL fLogoffWindows)
  979. {
  980. FreeCallList();
  981. // Kill the taskbar icon:
  982. if (NULL != g_pHiddenWnd)
  983. {
  984. HWND hwndHidden = g_pHiddenWnd->GetWindow();
  985. TRACE_OUT(("Removing taskbar icon..."));
  986. ::RemoveTaskbarIcon(hwndHidden);
  987. DestroyWindow(hwndHidden);
  988. g_pHiddenWnd->Release();
  989. g_pHiddenWnd = NULL;
  990. }
  991. // NOTE: during WM_ENDSESSION, we want
  992. // to log off after doing all other clean-up, in case it gets stuck
  993. // waiting for the logon thread to complete.
  994. if (FALSE == fLogoffWindows)
  995. {
  996. if(g_pLDAP)
  997. {
  998. g_pLDAP->Logoff();
  999. delete g_pLDAP;
  1000. g_pLDAP = NULL;
  1001. }
  1002. }
  1003. delete g_pCCallto;
  1004. g_pCCallto = NULL;
  1005. delete g_pPing;
  1006. g_pPing = NULL;
  1007. CleanUpUi();
  1008. // These must happen AFTER all the UI is cleaned up
  1009. if(g_pInternalNmManager)
  1010. {
  1011. g_pInternalNmManager->Release();
  1012. }
  1013. CConfMan::Destroy();
  1014. // destroy incoming call log:
  1015. delete g_pInCallLog;
  1016. g_pInCallLog = NULL;
  1017. CPopupMsg::Cleanup();
  1018. CPasswordDlg::Cleanup();
  1019. // Code to clean up gracefully
  1020. if (FALSE == fLogoffWindows)
  1021. {
  1022. // NOTE: we intentionally leak this list object when shutting down
  1023. // due to logging off windows, because we don't want to put a NULL
  1024. // check in HandleDialogMessage() and there is no WM_QUIT to guarantee that
  1025. // we've stopped receiving messages when shutting down in that code path
  1026. EnterCriticalSection(&dialogListCriticalSection);
  1027. for( int i = 0; i < g_pDialogList->GetSize(); ++i )
  1028. {
  1029. ASSERT( NULL != (*g_pDialogList)[i] );
  1030. RemoveTranslateAccelerator( (*g_pDialogList)[i] );
  1031. }
  1032. LeaveCriticalSection(&dialogListCriticalSection);
  1033. // Delete the dialog list:
  1034. delete g_pDialogList;
  1035. //
  1036. // Delete the critical section
  1037. //
  1038. DeleteCriticalSection(&dialogListCriticalSection);
  1039. g_pDialogList = NULL;
  1040. }
  1041. // Auto-disconnect from MSN:
  1042. ::SendDialmonMessage(WM_APP_EXITING);
  1043. if (g_WSAStarted)
  1044. {
  1045. WSACleanup();
  1046. g_WSAStarted = FALSE;
  1047. }
  1048. delete g_pConfRoom;
  1049. g_pConfRoom = NULL;
  1050. g_bNeedCleanup = false;
  1051. }
  1052. /* S E N D D I A L M O N M E S S A G E */
  1053. /*-------------------------------------------------------------------------
  1054. %%Function: SendDialmonMessage
  1055. Send a message to the dialing monitor.
  1056. Either WINSOCK_ACTIVITY_TIMER or WM_APP_EXITING.
  1057. (The code comes from Internet Explorer)
  1058. -------------------------------------------------------------------------*/
  1059. VOID SendDialmonMessage(UINT uMsg)
  1060. {
  1061. HWND hwndAutodisconnectMonitor = ::FindWindow(_TEXT("MS_AutodialMonitor"), NULL);
  1062. if (NULL != hwndAutodisconnectMonitor)
  1063. {
  1064. ::SendMessage(hwndAutodisconnectMonitor, uMsg, 0, 0);
  1065. }
  1066. }
  1067. // This window procedure exists for the sole purpose of receiving
  1068. // WM_ENDSESSION. Because of bug 2287, we cannot have the regular
  1069. // hidden window handle WM_ENDSESSION. DCL has subclassed our hidden
  1070. // window, and if we unload them inside one of it's messages, then we
  1071. // will fault. It's too bad that we can't find a better fix (such as
  1072. // removing the subclass), but we are under time pressure to fix this
  1073. // bug for v1.0
  1074. LRESULT CALLBACK ESHiddenWndProc( HWND hwnd, UINT uMsg,
  1075. WPARAM wParam, LPARAM lParam)
  1076. {
  1077. if ((WM_ENDSESSION == uMsg) && (TRUE == (BOOL) wParam))
  1078. {
  1079. TRACE_OUT(("Conf received WM_ENDSESSION, fLogoff=%s",
  1080. GetBOOLString((BOOL)lParam)));
  1081. TRACE_OUT(("Conf calling UIEndSession()"));
  1082. CConfRoom::UIEndSession((BOOL) lParam);
  1083. TRACE_OUT(("Conf testing lParam=%d", lParam));
  1084. if ((BOOL) lParam)
  1085. {
  1086. // Logging off:
  1087. TRACE_OUT(("Conf calling CleanUp()"));
  1088. // NOTE: Passing TRUE into CleanUp() because we don't
  1089. // want to logoff ULS / de-init name services until after insuring that DCL
  1090. // has cleaned up properly, because it can take enough time that
  1091. // our task might get killed.
  1092. ::CleanUp(TRUE);
  1093. //
  1094. // Restart the remote control service if we need to.
  1095. //
  1096. RestartRemoteControlService();
  1097. }
  1098. else
  1099. {
  1100. TRACE_OUT(("Conf not cleaning up - Windows shutting down"));
  1101. }
  1102. #if 0 // LONCHANC: it faults 100% on my main dev machine.
  1103. if( g_pLDAP != NULL )
  1104. {
  1105. g_pLDAP->Logoff();
  1106. }
  1107. #endif
  1108. return 0;
  1109. }
  1110. else
  1111. {
  1112. return DefWindowProc(hwnd, uMsg, wParam, lParam);
  1113. }
  1114. }
  1115. /* C M D S H U T D O W N */
  1116. /*-------------------------------------------------------------------------
  1117. %%Function: CmdShutdown
  1118. -------------------------------------------------------------------------*/
  1119. VOID CmdShutdown(void)
  1120. {
  1121. HWND hwndMain = ::GetMainWindow();
  1122. if (NULL != hwndMain)
  1123. {
  1124. // We have UI up, so post a WM_CLOSE with lParam = 1,
  1125. // which indicates a forced "Exit and Stop"
  1126. ::PostMessage(hwndMain, WM_CLOSE, 0, 1);
  1127. }
  1128. else
  1129. {
  1130. ::PostThreadMessage(_Module.m_dwThreadID, WM_QUIT, 0, 0);
  1131. }
  1132. }
  1133. void SignalShutdownStarting(void)
  1134. {
  1135. if (NULL == g_hShutdown)
  1136. {
  1137. g_hShutdown = ::CreateEvent(NULL, TRUE, FALSE, _TEXT("CONF:ShuttingDown"));
  1138. _Module.RevokeClassObjects();
  1139. }
  1140. }
  1141. /* H A N D L E D I A L O G M E S S A G E */
  1142. /*-------------------------------------------------------------------------
  1143. %%Function: HandleDialogMessage
  1144. Global modeless dialog handler
  1145. -------------------------------------------------------------------------*/
  1146. BOOL HandleDialogMessage(LPMSG pMsg)
  1147. {
  1148. if (g_hwndDropDown != NULL)
  1149. {
  1150. switch (pMsg->message)
  1151. {
  1152. case WM_KEYDOWN:
  1153. {
  1154. if ((VK_ESCAPE != pMsg->wParam) && (VK_TAB != pMsg->wParam))
  1155. break;
  1156. if (0 != SendMessage(g_hwndDropDown, WM_CONF_DROP_KEY,
  1157. pMsg->wParam, (LPARAM) pMsg->hwnd))
  1158. {
  1159. return TRUE; // message was handled
  1160. }
  1161. break;
  1162. }
  1163. case WM_LBUTTONDOWN:
  1164. case WM_RBUTTONDOWN:
  1165. case WM_NCLBUTTONDOWN:
  1166. case WM_NCRBUTTONDOWN:
  1167. {
  1168. if (g_hwndDropDown == pMsg->hwnd)
  1169. break; // message is for the window, pass along as normal
  1170. if (0 != SendMessage(g_hwndDropDown, WM_CONF_DROP_CLICK,
  1171. 0, (LPARAM) pMsg->hwnd))
  1172. {
  1173. return TRUE; // message was handled
  1174. }
  1175. break;
  1176. }
  1177. default:
  1178. break;
  1179. } /* switch (pMsg->message) */
  1180. }
  1181. ASSERT(NULL != g_pDialogList);
  1182. EnterCriticalSection(&dialogListCriticalSection);
  1183. for( int i = 0; i < g_pDialogList->GetSize(); ++i )
  1184. {
  1185. ITranslateAccelerator *pTrans = (*g_pDialogList)[i];
  1186. ASSERT( NULL != pTrans );
  1187. if( S_OK == pTrans->TranslateAccelerator(pMsg, 0) )
  1188. {
  1189. LeaveCriticalSection(&dialogListCriticalSection);
  1190. return TRUE;
  1191. }
  1192. }
  1193. LeaveCriticalSection(&dialogListCriticalSection);
  1194. return FALSE;
  1195. }
  1196. //////////////////////////////////////////////////////////////////////////
  1197. /* R E M O T E P A S S W O R D D L G P R O C */
  1198. // Handles the dialog box asking if the user wants to start conf.exe even though the remote control
  1199. // service is in a call.
  1200. INT_PTR CALLBACK ServiceRunningDlgProc(HWND hDlg, UINT iMsg, WPARAM wParam, LPARAM lParam)
  1201. {
  1202. switch (iMsg)
  1203. {
  1204. case WM_INITDIALOG:
  1205. return TRUE;
  1206. break;
  1207. case WM_COMMAND:
  1208. switch (LOWORD(wParam))
  1209. {
  1210. case ID_START_CONF:
  1211. EndDialog(hDlg,1);
  1212. break;
  1213. case ID_EXIT:
  1214. EndDialog(hDlg,0);
  1215. break;
  1216. default:
  1217. break;
  1218. }
  1219. return TRUE;
  1220. break;
  1221. }
  1222. return FALSE;
  1223. }
  1224. BOOL CheckRemoteControlService()
  1225. {
  1226. BOOL fContinue = TRUE;
  1227. // Store OS version info
  1228. g_osvi.dwOSVersionInfoSize = sizeof(g_osvi);
  1229. if (FALSE == ::GetVersionEx(&g_osvi))
  1230. {
  1231. ERROR_OUT(("GetVersionEx() failed!"));
  1232. return FALSE;
  1233. }
  1234. if (::IsWindowsNT()) {
  1235. SC_HANDLE hSCManager = OpenSCManager(NULL, SERVICES_ACTIVE_DATABASE, SC_MANAGER_ALL_ACCESS);
  1236. SC_HANDLE hRemoteControl = NULL;
  1237. SERVICE_STATUS serviceStatus;
  1238. if (hSCManager != NULL) {
  1239. hRemoteControl = OpenService(hSCManager,REMOTE_CONTROL_NAME,SERVICE_ALL_ACCESS);
  1240. DWORD dwError = GetLastError();
  1241. if (hRemoteControl != NULL) {
  1242. // If service is running...
  1243. BOOL fSuccess = QueryServiceStatus(hRemoteControl,&serviceStatus);
  1244. if (fSuccess && serviceStatus.dwCurrentState != SERVICE_STOPPED && serviceStatus.dwCurrentState != SERVICE_PAUSED) {
  1245. if (serviceStatus.dwControlsAccepted & SERVICE_ACCEPT_SHUTDOWN) // Service is in a call
  1246. {
  1247. fContinue = (BOOL)DialogBox(::GetInstanceHandle(),MAKEINTRESOURCE(IDD_SERVICE_RUNNING),GetDesktopWindow(),ServiceRunningDlgProc);
  1248. }
  1249. if (fContinue) {
  1250. ControlService(hRemoteControl,SERVICE_CONTROL_PAUSE,&serviceStatus);
  1251. for (int i = 0; i < MAX_REMOTE_TRIES; i++) {
  1252. fSuccess = QueryServiceStatus(hRemoteControl,&serviceStatus);
  1253. if (serviceStatus.dwCurrentState == SERVICE_PAUSED)
  1254. break;
  1255. TRACE_OUT(("Waiting for srvc - status is %d...",
  1256. serviceStatus.dwCurrentState));
  1257. Sleep(1000);
  1258. }
  1259. if ( MAX_REMOTE_TRIES == i )
  1260. {
  1261. // If we don't manage to shut down the service
  1262. // we shouldn't try to start - it will only fail.
  1263. WARNING_OUT(("TIMED OUT WAITING FOR SRVC!!"));
  1264. fContinue = FALSE;
  1265. }
  1266. }
  1267. }
  1268. CloseServiceHandle(hRemoteControl);
  1269. }
  1270. CloseServiceHandle(hSCManager);
  1271. }
  1272. return fContinue;
  1273. }
  1274. else { // Windows 95
  1275. HANDLE hServiceEvent = OpenEvent(EVENT_ALL_ACCESS, FALSE, SERVICE_PAUSE_EVENT);
  1276. HANDLE hActiveEvent = OpenEvent(EVENT_ALL_ACCESS, FALSE, SERVICE_ACTIVE_EVENT);
  1277. DWORD dwError = GetLastError();
  1278. if (hServiceEvent != NULL && hActiveEvent != NULL) { // Service is running and is active
  1279. CloseHandle(hActiveEvent);
  1280. HANDLE hCallEvent = OpenEvent(EVENT_ALL_ACCESS, FALSE, SERVICE_CALL_EVENT);
  1281. if (hCallEvent != NULL) { // Service is in a call
  1282. fContinue = (BOOL)DialogBox(::GetInstanceHandle(),MAKEINTRESOURCE(IDD_SERVICE_RUNNING),GetDesktopWindow(),ServiceRunningDlgProc);
  1283. CloseHandle(hCallEvent);
  1284. }
  1285. if (fContinue) {
  1286. SetEvent(hServiceEvent);
  1287. CloseHandle(hServiceEvent);
  1288. for (int i = 0; i < MAX_REMOTE_TRIES; i++) {
  1289. hActiveEvent = OpenEvent(EVENT_ALL_ACCESS, FALSE, SERVICE_ACTIVE_EVENT);
  1290. if (NULL == hActiveEvent)
  1291. break;
  1292. TRACE_OUT(("Waiting for srvc"));
  1293. CloseHandle(hActiveEvent);
  1294. Sleep(1000);
  1295. }
  1296. if ( MAX_REMOTE_TRIES == i ) {
  1297. // If we don't manage to shut down the service
  1298. // we shouldn't try to start - it will only fail.
  1299. WARNING_OUT(("TIMED OUT WAITING FOR SRVC!!"));
  1300. fContinue = FALSE;
  1301. }
  1302. }
  1303. }
  1304. return fContinue;
  1305. }
  1306. }
  1307. VOID RestartRemoteControlService()
  1308. {
  1309. RegEntry reLM = RegEntry(REMOTECONTROL_KEY, HKEY_LOCAL_MACHINE);
  1310. if (!reLM.GetNumber(REMOTE_REG_RUNSERVICE,0))
  1311. return;
  1312. if (ConfPolicies::IsRDSDisabled())
  1313. {
  1314. WARNING_OUT(("RDS launch disallowed by policy"));
  1315. return;
  1316. }
  1317. BOOL fActivate = reLM.GetNumber(REMOTE_REG_ACTIVATESERVICE, DEFAULT_REMOTE_ACTIVATESERVICE);
  1318. if (::IsWindowsNT()) {
  1319. SERVICE_STATUS serviceStatus;
  1320. SC_HANDLE hSCManager = OpenSCManager(NULL, SERVICES_ACTIVE_DATABASE, SC_MANAGER_ALL_ACCESS);
  1321. SC_HANDLE hRemoteControl = OpenService(hSCManager,REMOTE_CONTROL_NAME,SERVICE_ALL_ACCESS);
  1322. if (hRemoteControl != NULL) {
  1323. BOOL fSuccess = QueryServiceStatus(hRemoteControl,&serviceStatus);
  1324. if (SERVICE_STOPPED == serviceStatus.dwCurrentState)
  1325. {
  1326. StartService(hRemoteControl,0,NULL);
  1327. }
  1328. else
  1329. {
  1330. if (fActivate)
  1331. {
  1332. ControlService(hRemoteControl, SERVICE_CONTROL_CONTINUE, &serviceStatus);
  1333. }
  1334. }
  1335. }
  1336. else
  1337. {
  1338. WARNING_OUT(("Error starting RDS"));
  1339. }
  1340. }
  1341. }