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.

1660 lines
40 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, 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. USES_CONVERSION;
  416. TRACE_OUT(("HandleConfSettingsChange, dwSettings=0x%x", dwSettings));
  417. // Tell the user if she changed something that won't take
  418. // effect right away
  419. if (CSETTING_L_REQUIRESRESTARTMASK & dwSettings)
  420. {
  421. ::ConfMsgBox(NULL, (LPCTSTR) IDS_NEED_RESTART);
  422. }
  423. if (CSETTING_L_REQUIRESNEXTCALLMASK & dwSettings)
  424. {
  425. if (::FIsConferenceActive())
  426. {
  427. ::ConfMsgBox(NULL, (LPCTSTR) IDS_NEED_NEXTCALL);
  428. }
  429. }
  430. if (CSETTING_L_BANDWIDTH & dwSettings)
  431. {
  432. if (NULL != g_pNmSysInfo)
  433. {
  434. int nMegahertz=300, nProcFamily=6;
  435. RegEntry re(AUDIO_KEY, HKEY_CURRENT_USER);
  436. UINT uSysPolBandwidth;
  437. UINT uBandwidth;
  438. uBandwidth = re.GetNumber(REGVAL_TYPICALBANDWIDTH, BW_DEFAULT);
  439. #ifdef _M_IX86
  440. GetNormalizedCPUSpeed(&nMegahertz, &nProcFamily);
  441. TRACE_OUT(("Normalized Processor Speed = %d, Processor type = %d\n", nMegahertz, nProcFamily));
  442. #endif
  443. // convert bandwidth ID (1-4) to bits/sec
  444. uBandwidth = GetBandwidthBits(uBandwidth, nMegahertz);
  445. // the existance of a QOS - maximum bandwidth key implies that
  446. // the user's bandwidth is being over-rided (ONLY if his setting is LAN)
  447. uSysPolBandwidth = SysPol::GetMaximumBandwidth();
  448. if ((uSysPolBandwidth > 0) && (uBandwidth >= BW_SLOWLAN_BITS))
  449. {
  450. uBandwidth = max(uSysPolBandwidth, BW_144KBS_BITS);
  451. }
  452. g_pNmSysInfo->SetOption(NM_SYSOPT_BANDWIDTH, uBandwidth);
  453. }
  454. }
  455. if (CSETTING_L_SHOWTASKBAR & dwSettings)
  456. {
  457. // This will remove one if one is already there:
  458. ::RemoveTaskbarIcon(::GetHiddenWindow());
  459. // This will add the icon if the registry switch is on:
  460. ::AddTaskbarIcon(::GetHiddenWindow());
  461. }
  462. if (CSETTING_L_AUDIODEVICE & dwSettings)
  463. {
  464. CConfRoom* pcr = ::GetConfRoom();
  465. if (NULL != pcr)
  466. {
  467. pcr->OnAudioDeviceChanged();
  468. }
  469. }
  470. if (CSETTING_L_AGC & dwSettings)
  471. {
  472. CConfRoom* pcr = ::GetConfRoom();
  473. if (NULL != pcr)
  474. {
  475. pcr->OnAGC_Changed();
  476. }
  477. }
  478. if ((CSETTING_L_AUTOMIC|CSETTING_L_MICSENSITIVITY) & dwSettings)
  479. {
  480. CConfRoom* pcr = ::GetConfRoom();
  481. if (NULL != pcr)
  482. {
  483. pcr->OnSilenceLevelChanged();
  484. }
  485. }
  486. if( CSETTING_L_ULSSETTINGS & dwSettings )
  487. {
  488. if(g_pLDAP)
  489. {
  490. g_pLDAP->OnSettingsChanged();
  491. }
  492. if (NULL != g_pNmSysInfo)
  493. {
  494. RegEntry re(ISAPI_CLIENT_KEY, HKEY_CURRENT_USER);
  495. LPCTSTR pcszName = re.GetString(REGVAL_ULS_NAME);
  496. g_pNmSysInfo->SetProperty(NM_SYSPROP_USER_NAME, CComBSTR(pcszName));
  497. }
  498. }
  499. if (CSETTING_L_FULLDUPLEX & dwSettings)
  500. {
  501. RegEntry re(AUDIO_KEY, HKEY_CURRENT_USER);
  502. BOOL bFullDuplex = FALSE;
  503. UINT uSoundCardCaps = re.GetNumber(REGVAL_SOUNDCARDCAPS,SOUNDCARD_NONE);
  504. if (ISSOUNDCARDFULLDUPLEX(uSoundCardCaps))
  505. {
  506. bFullDuplex = re.GetNumber(REGVAL_FULLDUPLEX,FULLDUPLEX_DISABLED);
  507. }
  508. ASSERT(g_pNmSysInfo);
  509. if (NULL != g_pNmSysInfo)
  510. {
  511. g_pNmSysInfo->SetOption(NM_SYSOPT_FULLDUPLEX, bFullDuplex);
  512. }
  513. }
  514. if (CSETTING_L_CAPTUREDEVICE & dwSettings)
  515. {
  516. if (NULL != g_pNmSysInfo)
  517. {
  518. RegEntry re(VIDEO_KEY, HKEY_CURRENT_USER);
  519. DWORD dwCaptureID = re.GetNumber(REGVAL_CAPTUREDEVICEID, 0);
  520. g_pNmSysInfo->SetOption(NM_SYSOPT_CAPTURE_DEVICE, dwCaptureID);
  521. }
  522. }
  523. if (CSETTING_L_DIRECTSOUND & dwSettings)
  524. {
  525. ASSERT(g_pNmSysInfo);
  526. if (NULL != g_pNmSysInfo)
  527. {
  528. RegEntry re(AUDIO_KEY, HKEY_CURRENT_USER);
  529. DWORD dwDS = re.GetNumber(REGVAL_DIRECTSOUND, DSOUND_USER_DISABLED);
  530. g_pNmSysInfo->SetOption(NM_SYSOPT_DIRECTSOUND, dwDS);
  531. }
  532. }
  533. DebugExitVOID(HandleConfSettingsChange);
  534. }
  535. // DeleteOldRegSettings is called the first time
  536. // this build of NetMeeting is run by the user
  537. // We don't touch UI\Directory as it is populated by the INF file
  538. VOID DeleteOldRegSettings()
  539. {
  540. // "%KEY_CONFERENCING%\UI"
  541. HKEY hKey;
  542. long lRet = ::RegOpenKey(HKEY_CURRENT_USER, UI_KEY, &hKey);
  543. if (NO_ERROR == lRet)
  544. {
  545. ::RegDeleteValue(hKey, REGVAL_MP_WINDOW_X);
  546. ::RegDeleteValue(hKey, REGVAL_MP_WINDOW_Y);
  547. ::RegDeleteValue(hKey, REGVAL_MP_WINDOW_WIDTH);
  548. ::RegDeleteValue(hKey, REGVAL_MP_WINDOW_HEIGHT);
  549. ::RegCloseKey(hKey);
  550. }
  551. }
  552. static HRESULT _ValidatePolicySettings()
  553. {
  554. HRESULT hr = S_OK;
  555. if( g_pNmSysInfo )
  556. {
  557. //
  558. // LAURABU BUGBUG BOGUS:
  559. //
  560. // If security required, and not available, warning
  561. // If security incoming required/outgoing preferred, warning
  562. //
  563. }
  564. else
  565. {
  566. ERROR_OUT(("g_pNmySysInfo should not me NULL"));
  567. hr = E_UNEXPECTED;
  568. }
  569. return hr;
  570. }
  571. HRESULT InitSDK()
  572. {
  573. DBGENTRY(InitSDK);
  574. HRESULT hr = S_OK;
  575. if(FAILED(hr = CSDKWindow::InitSDK())) goto end;
  576. if(FAILED(hr = CNmCallObj::InitSDK())) goto end;
  577. if(FAILED(hr = CNmManagerObj::InitSDK())) goto end;
  578. if(FAILED(hr = CNmConferenceObj::InitSDK())) goto end;
  579. if(FAILED(hr = CNetMeetingObj::InitSDK())) goto end;
  580. if(FAILED(hr = CFt::InitFt())) goto end;
  581. g_pCCallto = new CCallto;
  582. ASSERT( g_pCCallto != NULL );
  583. if( g_pCCallto == NULL )
  584. {
  585. hr = E_FAIL;
  586. }
  587. end:
  588. DBGEXIT_HR(InitSDK,hr);
  589. return hr;
  590. }
  591. void CleanupSDK()
  592. {
  593. DBGENTRY(CleanupSDK);
  594. // Revoke the old filter object
  595. CoRegisterMessageFilter(NULL, NULL);
  596. CNmCallObj::CleanupSDK();
  597. CNmManagerObj::CleanupSDK();
  598. CNmConferenceObj::CleanupSDK();
  599. CSDKWindow::CleanupSDK();
  600. CNetMeetingObj::CleanupSDK();
  601. CFt::CloseFtApplet();
  602. DBGEXIT(CleanupSDK);
  603. }
  604. /* I N I T C O N F E X E */
  605. /*-------------------------------------------------------------------------
  606. %%Function: InitConfExe
  607. -------------------------------------------------------------------------*/
  608. HRESULT InitConfExe(BOOL fShowUI)
  609. {
  610. // Create a message filter object
  611. CComPtr<IMessageFilter> spMsgFilter;
  612. CComPtr<IMessageFilter> spOldMsgFilter;
  613. HRESULT hr = CConfMsgFilter::_CreatorClass::CreateInstance(NULL, IID_IMessageFilter, reinterpret_cast<void**>(&spMsgFilter));
  614. if(FAILED(hr)) return hr;
  615. // Register the message filter object
  616. hr = CoRegisterMessageFilter(spMsgFilter, &spOldMsgFilter);
  617. if(FAILED(hr)) return hr;
  618. // Wipe out default find directory entry... we no longer wish to persist this...
  619. // in some future overhaul / cleanup we should stop using the registry for this...
  620. RegEntry re( DLGCALL_MRU_KEY, HKEY_CURRENT_USER );
  621. re.SetValue( REGVAL_DLGCALL_DEFDIR, TEXT( "" ) );
  622. LPCTSTR lpCmdLine = g_lpCmdLine;
  623. TRACE_OUT(("InitConfExe"));
  624. // Init UI objects (NOTE: we continue if this fails)
  625. CPopupMsg::Init();
  626. CPasswordDlg::Init();
  627. // Allocate dialog list object:
  628. g_pDialogList = new CSimpleArray<ITranslateAccelerator*>;
  629. if (NULL == g_pDialogList)
  630. {
  631. ERROR_OUT(("Could not allocate g_pDialogList!"));
  632. return E_FAIL;
  633. }
  634. //
  635. // Initialize the critical section to protect the dialogList
  636. //
  637. InitializeCriticalSection(&dialogListCriticalSection);
  638. // Determine if we have MORE THAN 256 colors
  639. {
  640. HDC hdc = GetDC(NULL);
  641. if (NULL != hdc)
  642. {
  643. g_fHiColor = 8 < (::GetDeviceCaps(hdc, BITSPIXEL) * ::GetDeviceCaps(hdc, PLANES));
  644. ReleaseDC(NULL, hdc);
  645. }
  646. }
  647. // Get the default dialog (GUI) font for international
  648. // REVIEW: should we check the registry for a localized font?
  649. g_hfontDlg = (HFONT) ::GetStockObject(DEFAULT_GUI_FONT);
  650. if (NULL == g_hfontDlg)
  651. {
  652. return E_FAIL;
  653. }
  654. LoadIconImages();
  655. // On Windows NT, determine if the NetMeeting display driver is
  656. // enabled. Note that this depends on <g_osvi> being initialized.
  657. //
  658. // Since NT 5.0 will support dynamic loading of the display driver,
  659. // we assume that the driver is enabled if the OS major version
  660. // number is greater than 4.
  661. if (::IsWindowsNT())
  662. {
  663. RegEntry re(NM_NT_DISPLAY_DRIVER_KEY, HKEY_LOCAL_MACHINE, FALSE);
  664. g_fNTDisplayDriverEnabled =
  665. 4 < g_osvi.dwMajorVersion ||
  666. NT_DRIVER_START_DISABLED !=
  667. re.GetNumber(
  668. REGVAL_NM_NT_DISPLAY_DRIVER_ENABLED,
  669. NT_DRIVER_START_DISABLED);
  670. }
  671. else
  672. {
  673. ASSERT(FALSE == g_fNTDisplayDriverEnabled);
  674. }
  675. // Check the language layout (UI can be displayed after this point)
  676. CheckLanguageLayout();
  677. // AutoConfiguration
  678. CAutoConf::DoIt();
  679. TRACE_OUT(("Command Line is \"%s\"", lpCmdLine));
  680. // Register hidden window class:
  681. WNDCLASS wcESHidden =
  682. {
  683. 0L,
  684. ESHiddenWndProc,
  685. 0,
  686. 0,
  687. _Module.GetModuleInstance(),
  688. NULL,
  689. NULL,
  690. NULL,
  691. NULL,
  692. g_cszESHiddenWndClassName
  693. };
  694. if (!RegisterClass(&wcESHidden))
  695. {
  696. ERROR_OUT(("Could not register hidden wnd classes"));
  697. return E_FAIL;
  698. }
  699. // Register the "NetMeeting EndSession" message:
  700. g_uEndSessionMsg = ::RegisterWindowMessage(NM_ENDSESSION_MSG_NAME);
  701. // Create a hidden window for event processing:
  702. g_pHiddenWnd = new CHiddenWindow();
  703. if (NULL == g_pHiddenWnd)
  704. {
  705. return(E_FAIL);
  706. }
  707. g_pHiddenWnd->Create();
  708. g_hwndESHidden = ::CreateWindow( g_cszESHiddenWndClassName,
  709. _TEXT(""),
  710. WS_POPUP, // not visible!
  711. 0, 0, 0, 0,
  712. NULL,
  713. NULL,
  714. _Module.GetModuleInstance(),
  715. NULL);
  716. HWND hwndHidden = g_pHiddenWnd->GetWindow();
  717. if ((NULL == hwndHidden) || (NULL == g_hwndESHidden))
  718. {
  719. ERROR_OUT(("Could not create hidden windows"));
  720. return E_FAIL;
  721. }
  722. LONG lSoundCaps = SOUNDCARD_NONE;
  723. // Start the run-once wizard (if needed):
  724. RegEntry reConf(CONFERENCING_KEY, HKEY_CURRENT_USER);
  725. // check to see if the wizard has been run in UI mode for this build
  726. DWORD dwVersion = reConf.GetNumber(REGVAL_WIZARD_VERSION_UI, 0);
  727. BOOL fRanWizardUI = ((VER_PRODUCTVERSION_W & HIWORD(dwVersion)) == VER_PRODUCTVERSION_W);
  728. BOOL fForceWizard = FALSE;
  729. if (!fRanWizardUI)
  730. {
  731. dwVersion = reConf.GetNumber(REGVAL_WIZARD_VERSION_NOUI, 0);
  732. BOOL fRanWizardNoUI = (VER_PRODUCTVERSION_DW == dwVersion);
  733. // wizard has not been run in UI mode
  734. if (!fRanWizardNoUI)
  735. {
  736. // wizard has not been run before, delete old registry settings
  737. DeleteOldRegSettings();
  738. fForceWizard = TRUE;
  739. }
  740. else
  741. {
  742. // wizard has been run in NoUI mode, we only need to run it if we are in UI mode
  743. if(fShowUI)
  744. {
  745. fForceWizard = TRUE;
  746. }
  747. }
  748. if (fForceWizard)
  749. {
  750. WabReadMe();
  751. }
  752. }
  753. hr = ::StartRunOnceWizard(&lSoundCaps, fForceWizard, fShowUI);
  754. if (FAILED(hr))
  755. {
  756. WARNING_OUT(("Did not retrieve necessary info from wizard"));
  757. ConfMsgBox(NULL, MAKEINTRESOURCE(IDS_ERROR_BAD_ADMIN_SETTINGS));
  758. return E_FAIL;
  759. }
  760. else if( S_FALSE == hr )
  761. {
  762. return NM_E_USER_CANCELED_SETUP;
  763. }
  764. if (fForceWizard)
  765. {
  766. reConf.SetValue(fShowUI ? REGVAL_WIZARD_VERSION_UI :
  767. REGVAL_WIZARD_VERSION_NOUI, VER_PRODUCTVERSION_DW);
  768. }
  769. // Start NetMeeting At Page Once
  770. if( fShowUI && fForceWizard )
  771. {
  772. if( ConfPolicies::IsShowFirstTimeUrlEnabled() )
  773. {
  774. CmdLaunchWebPage(ID_HELP_WEB_SUPPORT);
  775. }
  776. }
  777. // The following hack is to fix the don't run wizard twice bug
  778. // the side effect is that the codec ordering is blown away.
  779. // this code restores the key in the event that this wizard is not run.
  780. HKEY hKey;
  781. long lRet = ::RegOpenKey(HKEY_LOCAL_MACHINE,
  782. INTERNET_AUDIO_KEY TEXT("\\") REGVAL_ACMH323ENCODINGS , &hKey);
  783. if (NO_ERROR == lRet)
  784. {
  785. ::RegCloseKey(hKey);
  786. }
  787. else
  788. {
  789. RegEntry reAudio(AUDIO_KEY, HKEY_CURRENT_USER);
  790. UINT uBandwidth = reAudio.GetNumber ( REGVAL_TYPICALBANDWIDTH, BW_DEFAULT );
  791. SaveDefaultCodecSettings(uBandwidth);
  792. }
  793. // Start the Splash screen only after the wizard is complete
  794. if (fShowUI)
  795. {
  796. ::StartSplashScreen(NULL);
  797. }
  798. // Init incoming call log:
  799. g_pInCallLog = new CCallLog(LOG_INCOMING_KEY, TEXT("CallLog"));
  800. // Init capabilities:
  801. g_uMediaCaps = CAPFLAG_DATA;
  802. //
  803. // NOTE: THIS IS WHERE TO CHANGE TO DISABLE H323 CALLS FOR INTEL ET AL.
  804. //
  805. if(!_Module.DidSDKDisableH323())
  806. {
  807. g_uMediaCaps |= CAPFLAG_H323_CC;
  808. if (SOUNDCARD_NONE != lSoundCaps)
  809. {
  810. if (!SysPol::NoAudio())
  811. {
  812. g_uMediaCaps |= CAPFLAGS_AUDIO;
  813. }
  814. }
  815. if (!SysPol::NoVideoReceive())
  816. {
  817. g_uMediaCaps |= CAPFLAG_RECV_VIDEO;
  818. }
  819. if (!SysPol::NoVideoSend())
  820. {
  821. g_uMediaCaps |= CAPFLAG_SEND_VIDEO;
  822. }
  823. }
  824. // Create Manager
  825. hr = CoCreateInstance(CLSID_NmManager2, NULL, CLSCTX_INPROC, IID_INmManager2, (void**)&g_pInternalNmManager);
  826. if (FAILED(hr))
  827. {
  828. ERROR_OUT(("Could not create INmManager"));
  829. return E_FAIL;
  830. }
  831. // Get the INmSysInfo3
  832. CComPtr<INmSysInfo > spSysInfo;
  833. if (SUCCEEDED(g_pInternalNmManager->GetSysInfo(&spSysInfo)))
  834. {
  835. if (FAILED(spSysInfo->QueryInterface(IID_INmSysInfo2, (void **)&g_pNmSysInfo)))
  836. {
  837. ERROR_OUT(("Could not get INmSysInfo2"));
  838. }
  839. else
  840. {
  841. ASSERT( g_pNmSysInfo );
  842. CComPtr<INmSysInfoNotify> spNmSysInfoNotify;
  843. if( SUCCEEDED ( CConfNmSysInfoNotifySink::_CreatorClass::CreateInstance( NULL, IID_INmSysInfoNotify, reinterpret_cast<void**>(&spNmSysInfoNotify))))
  844. {
  845. ASSERT(spNmSysInfoNotify);
  846. ASSERT(0 == g_dwSysInfoNotifyCookie);
  847. NmAdvise(g_pNmSysInfo, spNmSysInfoNotify, IID_INmSysInfoNotify, &g_dwSysInfoNotifyCookie);
  848. }
  849. }
  850. }
  851. _ValidatePolicySettings();
  852. hr = g_pInternalNmManager->Initialize(NULL, &g_uMediaCaps);
  853. if (FAILED(hr))
  854. {
  855. UINT_PTR uErrorID;
  856. switch (hr)
  857. {
  858. case UI_RC_NO_NODE_NAME:
  859. {
  860. // No error in this case - the user probably cancelled from
  861. // the intro wizard.
  862. uErrorID = 0;
  863. break;
  864. }
  865. case UI_RC_BACKLEVEL_LOADED:
  866. {
  867. uErrorID = IDS_BACKLEVEL_LOADED;
  868. break;
  869. }
  870. case UI_RC_T120_ALREADY_INITIALIZED:
  871. {
  872. uErrorID = IDS_T120_ALREADY_INITIALIZED;
  873. break;
  874. }
  875. case UI_RC_T120_FAILURE:
  876. {
  877. WARNING_OUT(("T.120 failed to initialize (winsock problem?)"));
  878. uErrorID = IDS_CANT_START;
  879. break;
  880. }
  881. default:
  882. {
  883. uErrorID = IDS_CANT_START;
  884. break;
  885. }
  886. }
  887. if (0 != uErrorID)
  888. {
  889. ::ConfMsgBox(NULL, (LPCTSTR) uErrorID);
  890. }
  891. return E_FAIL;
  892. }
  893. // force the update of dll settings
  894. HandleConfSettingsChange(CSETTING_L_BANDWIDTH |
  895. CSETTING_L_CAPTUREDEVICE |
  896. CSETTING_L_ULSSETTINGS |
  897. CSETTING_L_DIRECTSOUND|
  898. CSETTING_L_FULLDUPLEX);
  899. if (FALSE == ::ConfRoomInit(_Module.GetModuleInstance()))
  900. {
  901. ::ConfMsgBox(NULL, (LPCTSTR) IDS_CANT_START);
  902. return E_FAIL;
  903. }
  904. // Now perform the check on the machine name and warn if
  905. // it is problematic.
  906. ::CheckMachineNameForExtendedChars();
  907. // Create the main conference manager to make sure
  908. // we can handle incoming calls, even in background mode
  909. if (!CConfMan::FCreate(g_pInternalNmManager))
  910. {
  911. ERROR_OUT(("Unable to create Conference Manager"));
  912. return E_FAIL;
  913. }
  914. // Initialize winsock (for name/address resolution)
  915. {
  916. WSADATA wsaData;
  917. int iErr = WSAStartup(0x0101, &wsaData);
  918. if (0 != iErr)
  919. {
  920. ERROR_OUT(("WSAStartup() failed: %i", iErr));
  921. return E_FAIL;
  922. }
  923. g_WSAStarted = TRUE;
  924. }
  925. // Initialize T.120 Security settings
  926. ::InitT120SecurityFromRegistry();
  927. StopSplashScreen();
  928. CreateConfRoomWindow(fShowUI);
  929. g_pPing = new CPing;
  930. if( ConfPolicies::GetCallingMode() == ConfPolicies::CallingMode_Direct )
  931. {
  932. // Initialize gatewayContext...
  933. RegEntry reConf( CONFERENCING_KEY, HKEY_CURRENT_USER );
  934. if( reConf.GetNumber( REGVAL_USE_H323_GATEWAY ) != 0 )
  935. {
  936. g_pCCallto->SetGatewayName( reConf.GetString( REGVAL_H323_GATEWAY ) );
  937. g_pCCallto->SetGatewayEnabled( true );
  938. }
  939. if(ConfPolicies::LogOntoIlsWhenNetMeetingStartsIfInDirectCallingMode() && !_Module.DidSDKDisableInitialILSLogon())
  940. {
  941. InitNmLdapAndLogon();
  942. }
  943. }
  944. else
  945. {
  946. GkLogon();
  947. }
  948. if(!_Module.InitControlMode())
  949. {
  950. ::AddTaskbarIcon(::GetHiddenWindow());
  951. }
  952. g_bNeedCleanup = true;
  953. CNmManagerObj::NetMeetingLaunched();
  954. return S_OK;
  955. }
  956. VOID CleanUpUi(void)
  957. {
  958. SysPol::CloseKey();
  959. if( 0 != g_dwSysInfoNotifyCookie )
  960. {
  961. NmUnadvise(g_pNmSysInfo, IID_INmSysInfoNotify, g_dwSysInfoNotifyCookie);
  962. g_dwSysInfoNotifyCookie = 0;
  963. }
  964. if (NULL != g_pNmSysInfo)
  965. {
  966. if( IsGatekeeperLoggedOn() )
  967. {
  968. g_pNmSysInfo->GkLogoff();
  969. }
  970. g_pNmSysInfo->Release();
  971. g_pNmSysInfo = NULL;
  972. }
  973. FreeIconImages();
  974. CGenWindow::DeleteStandardPalette();
  975. CGenWindow::DeleteStandardBrush();
  976. CMainUI::CleanUpVideoWindow();
  977. CFindSomeone::Destroy();
  978. }
  979. VOID CleanUp(BOOL fLogoffWindows)
  980. {
  981. FreeCallList();
  982. // Kill the taskbar icon:
  983. if (NULL != g_pHiddenWnd)
  984. {
  985. HWND hwndHidden = g_pHiddenWnd->GetWindow();
  986. TRACE_OUT(("Removing taskbar icon..."));
  987. ::RemoveTaskbarIcon(hwndHidden);
  988. DestroyWindow(hwndHidden);
  989. g_pHiddenWnd->Release();
  990. g_pHiddenWnd = NULL;
  991. }
  992. // NOTE: during WM_ENDSESSION, we want
  993. // to log off after doing all other clean-up, in case it gets stuck
  994. // waiting for the logon thread to complete.
  995. if (FALSE == fLogoffWindows)
  996. {
  997. if(g_pLDAP)
  998. {
  999. g_pLDAP->Logoff();
  1000. delete g_pLDAP;
  1001. g_pLDAP = NULL;
  1002. }
  1003. }
  1004. delete g_pCCallto;
  1005. g_pCCallto = NULL;
  1006. delete g_pPing;
  1007. g_pPing = NULL;
  1008. CleanUpUi();
  1009. // These must happen AFTER all the UI is cleaned up
  1010. if(g_pInternalNmManager)
  1011. {
  1012. g_pInternalNmManager->Release();
  1013. }
  1014. CConfMan::Destroy();
  1015. // destroy incoming call log:
  1016. delete g_pInCallLog;
  1017. g_pInCallLog = NULL;
  1018. CPopupMsg::Cleanup();
  1019. CPasswordDlg::Cleanup();
  1020. // Code to clean up gracefully
  1021. if (FALSE == fLogoffWindows)
  1022. {
  1023. // NOTE: we intentionally leak this list object when shutting down
  1024. // due to logging off windows, because we don't want to put a NULL
  1025. // check in HandleDialogMessage() and there is no WM_QUIT to guarantee that
  1026. // we've stopped receiving messages when shutting down in that code path
  1027. EnterCriticalSection(&dialogListCriticalSection);
  1028. for( int i = 0; i < g_pDialogList->GetSize(); ++i )
  1029. {
  1030. ASSERT( NULL != (*g_pDialogList)[i] );
  1031. RemoveTranslateAccelerator( (*g_pDialogList)[i] );
  1032. }
  1033. LeaveCriticalSection(&dialogListCriticalSection);
  1034. // Delete the dialog list:
  1035. delete g_pDialogList;
  1036. //
  1037. // Delete the critical section
  1038. //
  1039. DeleteCriticalSection(&dialogListCriticalSection);
  1040. g_pDialogList = NULL;
  1041. }
  1042. // Auto-disconnect from MSN:
  1043. ::SendDialmonMessage(WM_APP_EXITING);
  1044. if (g_WSAStarted)
  1045. {
  1046. WSACleanup();
  1047. g_WSAStarted = FALSE;
  1048. }
  1049. delete g_pConfRoom;
  1050. g_pConfRoom = NULL;
  1051. g_bNeedCleanup = false;
  1052. }
  1053. /* S E N D D I A L M O N M E S S A G E */
  1054. /*-------------------------------------------------------------------------
  1055. %%Function: SendDialmonMessage
  1056. Send a message to the dialing monitor.
  1057. Either WINSOCK_ACTIVITY_TIMER or WM_APP_EXITING.
  1058. (The code comes from Internet Explorer)
  1059. -------------------------------------------------------------------------*/
  1060. VOID SendDialmonMessage(UINT uMsg)
  1061. {
  1062. HWND hwndAutodisconnectMonitor = ::FindWindow(_TEXT("MS_AutodialMonitor"), NULL);
  1063. if (NULL != hwndAutodisconnectMonitor)
  1064. {
  1065. ::SendMessage(hwndAutodisconnectMonitor, uMsg, 0, 0);
  1066. }
  1067. }
  1068. // This window procedure exists for the sole purpose of receiving
  1069. // WM_ENDSESSION. Because of bug 2287, we cannot have the regular
  1070. // hidden window handle WM_ENDSESSION. DCL has subclassed our hidden
  1071. // window, and if we unload them inside one of it's messages, then we
  1072. // will fault. It's too bad that we can't find a better fix (such as
  1073. // removing the subclass), but we are under time pressure to fix this
  1074. // bug for v1.0
  1075. LRESULT CALLBACK ESHiddenWndProc( HWND hwnd, UINT uMsg,
  1076. WPARAM wParam, LPARAM lParam)
  1077. {
  1078. if ((WM_ENDSESSION == uMsg) && (TRUE == (BOOL) wParam))
  1079. {
  1080. TRACE_OUT(("Conf received WM_ENDSESSION, fLogoff=%s",
  1081. GetBOOLString((BOOL)lParam)));
  1082. TRACE_OUT(("Conf calling UIEndSession()"));
  1083. CConfRoom::UIEndSession((BOOL) lParam);
  1084. TRACE_OUT(("Conf testing lParam=%d", lParam));
  1085. if ((BOOL) lParam)
  1086. {
  1087. // Logging off:
  1088. TRACE_OUT(("Conf calling CleanUp()"));
  1089. // NOTE: Passing TRUE into CleanUp() because we don't
  1090. // want to logoff ULS / de-init name services until after insuring that DCL
  1091. // has cleaned up properly, because it can take enough time that
  1092. // our task might get killed.
  1093. ::CleanUp(TRUE);
  1094. //
  1095. // Restart the remote control service if we need to.
  1096. //
  1097. RestartRemoteControlService();
  1098. }
  1099. else
  1100. {
  1101. TRACE_OUT(("Conf not cleaning up - Windows shutting down"));
  1102. }
  1103. #if 0 // LONCHANC: it faults 100% on my main dev machine.
  1104. if( g_pLDAP != NULL )
  1105. {
  1106. g_pLDAP->Logoff();
  1107. }
  1108. #endif
  1109. return 0;
  1110. }
  1111. else
  1112. {
  1113. return DefWindowProc(hwnd, uMsg, wParam, lParam);
  1114. }
  1115. }
  1116. /* C M D S H U T D O W N */
  1117. /*-------------------------------------------------------------------------
  1118. %%Function: CmdShutdown
  1119. -------------------------------------------------------------------------*/
  1120. VOID CmdShutdown(void)
  1121. {
  1122. HWND hwndMain = ::GetMainWindow();
  1123. if (NULL != hwndMain)
  1124. {
  1125. // We have UI up, so post a WM_CLOSE with lParam = 1,
  1126. // which indicates a forced "Exit and Stop"
  1127. ::PostMessage(hwndMain, WM_CLOSE, 0, 1);
  1128. }
  1129. else
  1130. {
  1131. ::PostThreadMessage(_Module.m_dwThreadID, WM_QUIT, 0, 0);
  1132. }
  1133. }
  1134. void SignalShutdownStarting(void)
  1135. {
  1136. if (NULL == g_hShutdown)
  1137. {
  1138. g_hShutdown = ::CreateEvent(NULL, TRUE, FALSE, _TEXT("CONF:ShuttingDown"));
  1139. _Module.RevokeClassObjects();
  1140. }
  1141. }
  1142. /* H A N D L E D I A L O G M E S S A G E */
  1143. /*-------------------------------------------------------------------------
  1144. %%Function: HandleDialogMessage
  1145. Global modeless dialog handler
  1146. -------------------------------------------------------------------------*/
  1147. BOOL HandleDialogMessage(LPMSG pMsg)
  1148. {
  1149. if (g_hwndDropDown != NULL)
  1150. {
  1151. switch (pMsg->message)
  1152. {
  1153. case WM_KEYDOWN:
  1154. {
  1155. if ((VK_ESCAPE != pMsg->wParam) && (VK_TAB != pMsg->wParam))
  1156. break;
  1157. if (0 != SendMessage(g_hwndDropDown, WM_CONF_DROP_KEY,
  1158. pMsg->wParam, (LPARAM) pMsg->hwnd))
  1159. {
  1160. return TRUE; // message was handled
  1161. }
  1162. break;
  1163. }
  1164. case WM_LBUTTONDOWN:
  1165. case WM_RBUTTONDOWN:
  1166. case WM_NCLBUTTONDOWN:
  1167. case WM_NCRBUTTONDOWN:
  1168. {
  1169. if (g_hwndDropDown == pMsg->hwnd)
  1170. break; // message is for the window, pass along as normal
  1171. if (0 != SendMessage(g_hwndDropDown, WM_CONF_DROP_CLICK,
  1172. 0, (LPARAM) pMsg->hwnd))
  1173. {
  1174. return TRUE; // message was handled
  1175. }
  1176. break;
  1177. }
  1178. default:
  1179. break;
  1180. } /* switch (pMsg->message) */
  1181. }
  1182. ASSERT(NULL != g_pDialogList);
  1183. EnterCriticalSection(&dialogListCriticalSection);
  1184. for( int i = 0; i < g_pDialogList->GetSize(); ++i )
  1185. {
  1186. ITranslateAccelerator *pTrans = (*g_pDialogList)[i];
  1187. ASSERT( NULL != pTrans );
  1188. if( S_OK == pTrans->TranslateAccelerator(pMsg, 0) )
  1189. {
  1190. LeaveCriticalSection(&dialogListCriticalSection);
  1191. return TRUE;
  1192. }
  1193. }
  1194. LeaveCriticalSection(&dialogListCriticalSection);
  1195. return FALSE;
  1196. }
  1197. //////////////////////////////////////////////////////////////////////////
  1198. /* R E M O T E P A S S W O R D D L G P R O C */
  1199. // Handles the dialog box asking if the user wants to start conf.exe even though the remote control
  1200. // service is in a call.
  1201. INT_PTR CALLBACK ServiceRunningDlgProc(HWND hDlg, UINT iMsg, WPARAM wParam, LPARAM lParam)
  1202. {
  1203. switch (iMsg)
  1204. {
  1205. case WM_INITDIALOG:
  1206. return TRUE;
  1207. break;
  1208. case WM_COMMAND:
  1209. switch (LOWORD(wParam))
  1210. {
  1211. case ID_START_CONF:
  1212. EndDialog(hDlg,1);
  1213. break;
  1214. case ID_EXIT:
  1215. EndDialog(hDlg,0);
  1216. break;
  1217. default:
  1218. break;
  1219. }
  1220. return TRUE;
  1221. break;
  1222. }
  1223. return FALSE;
  1224. }
  1225. BOOL CheckRemoteControlService()
  1226. {
  1227. BOOL fContinue = TRUE;
  1228. // Store OS version info
  1229. g_osvi.dwOSVersionInfoSize = sizeof(g_osvi);
  1230. if (FALSE == ::GetVersionEx(&g_osvi))
  1231. {
  1232. ERROR_OUT(("GetVersionEx() failed!"));
  1233. return FALSE;
  1234. }
  1235. if (::IsWindowsNT()) {
  1236. SC_HANDLE hSCManager = OpenSCManager(NULL, SERVICES_ACTIVE_DATABASE, SC_MANAGER_ALL_ACCESS);
  1237. SC_HANDLE hRemoteControl = NULL;
  1238. SERVICE_STATUS serviceStatus;
  1239. if (hSCManager != NULL) {
  1240. hRemoteControl = OpenService(hSCManager,REMOTE_CONTROL_NAME,SERVICE_ALL_ACCESS);
  1241. DWORD dwError = GetLastError();
  1242. if (hRemoteControl != NULL) {
  1243. // If service is running...
  1244. BOOL fSuccess = QueryServiceStatus(hRemoteControl,&serviceStatus);
  1245. if (fSuccess && serviceStatus.dwCurrentState != SERVICE_STOPPED && serviceStatus.dwCurrentState != SERVICE_PAUSED) {
  1246. if (serviceStatus.dwControlsAccepted & SERVICE_ACCEPT_SHUTDOWN) // Service is in a call
  1247. {
  1248. fContinue = (BOOL)DialogBox(::GetInstanceHandle(),MAKEINTRESOURCE(IDD_SERVICE_RUNNING),GetDesktopWindow(),ServiceRunningDlgProc);
  1249. }
  1250. if (fContinue) {
  1251. ControlService(hRemoteControl,SERVICE_CONTROL_PAUSE,&serviceStatus);
  1252. for (int i = 0; i < MAX_REMOTE_TRIES; i++) {
  1253. fSuccess = QueryServiceStatus(hRemoteControl,&serviceStatus);
  1254. if (serviceStatus.dwCurrentState == SERVICE_PAUSED)
  1255. break;
  1256. TRACE_OUT(("Waiting for srvc - status is %d...",
  1257. serviceStatus.dwCurrentState));
  1258. Sleep(1000);
  1259. }
  1260. if ( MAX_REMOTE_TRIES == i )
  1261. {
  1262. // If we don't manage to shut down the service
  1263. // we shouldn't try to start - it will only fail.
  1264. WARNING_OUT(("TIMED OUT WAITING FOR SRVC!!"));
  1265. fContinue = FALSE;
  1266. }
  1267. }
  1268. }
  1269. CloseServiceHandle(hRemoteControl);
  1270. }
  1271. CloseServiceHandle(hSCManager);
  1272. }
  1273. return fContinue;
  1274. }
  1275. else { // Windows 95
  1276. HANDLE hServiceEvent = OpenEvent(EVENT_ALL_ACCESS, FALSE, SERVICE_PAUSE_EVENT);
  1277. HANDLE hActiveEvent = OpenEvent(EVENT_ALL_ACCESS, FALSE, SERVICE_ACTIVE_EVENT);
  1278. DWORD dwError = GetLastError();
  1279. if (hServiceEvent != NULL && hActiveEvent != NULL) { // Service is running and is active
  1280. CloseHandle(hActiveEvent);
  1281. HANDLE hCallEvent = OpenEvent(EVENT_ALL_ACCESS, FALSE, SERVICE_CALL_EVENT);
  1282. if (hCallEvent != NULL) { // Service is in a call
  1283. fContinue = (BOOL)DialogBox(::GetInstanceHandle(),MAKEINTRESOURCE(IDD_SERVICE_RUNNING),GetDesktopWindow(),ServiceRunningDlgProc);
  1284. CloseHandle(hCallEvent);
  1285. }
  1286. if (fContinue) {
  1287. SetEvent(hServiceEvent);
  1288. CloseHandle(hServiceEvent);
  1289. for (int i = 0; i < MAX_REMOTE_TRIES; i++) {
  1290. hActiveEvent = OpenEvent(EVENT_ALL_ACCESS, FALSE, SERVICE_ACTIVE_EVENT);
  1291. if (NULL == hActiveEvent)
  1292. break;
  1293. TRACE_OUT(("Waiting for srvc"));
  1294. CloseHandle(hActiveEvent);
  1295. Sleep(1000);
  1296. }
  1297. if ( MAX_REMOTE_TRIES == i ) {
  1298. // If we don't manage to shut down the service
  1299. // we shouldn't try to start - it will only fail.
  1300. WARNING_OUT(("TIMED OUT WAITING FOR SRVC!!"));
  1301. fContinue = FALSE;
  1302. }
  1303. }
  1304. }
  1305. return fContinue;
  1306. }
  1307. }
  1308. VOID RestartRemoteControlService()
  1309. {
  1310. RegEntry reLM = RegEntry(REMOTECONTROL_KEY, HKEY_LOCAL_MACHINE);
  1311. if (!reLM.GetNumber(REMOTE_REG_RUNSERVICE,0))
  1312. return;
  1313. if (ConfPolicies::IsRDSDisabled())
  1314. {
  1315. WARNING_OUT(("RDS launch disallowed by policy"));
  1316. return;
  1317. }
  1318. BOOL fActivate = reLM.GetNumber(REMOTE_REG_ACTIVATESERVICE, DEFAULT_REMOTE_ACTIVATESERVICE);
  1319. if (::IsWindowsNT()) {
  1320. SERVICE_STATUS serviceStatus;
  1321. SC_HANDLE hSCManager = OpenSCManager(NULL, SERVICES_ACTIVE_DATABASE, SC_MANAGER_ALL_ACCESS);
  1322. SC_HANDLE hRemoteControl = OpenService(hSCManager,REMOTE_CONTROL_NAME,SERVICE_ALL_ACCESS);
  1323. if (hRemoteControl != NULL) {
  1324. BOOL fSuccess = QueryServiceStatus(hRemoteControl,&serviceStatus);
  1325. if (SERVICE_STOPPED == serviceStatus.dwCurrentState)
  1326. {
  1327. StartService(hRemoteControl,0,NULL);
  1328. }
  1329. else
  1330. {
  1331. if (fActivate)
  1332. {
  1333. ControlService(hRemoteControl, SERVICE_CONTROL_CONTINUE, &serviceStatus);
  1334. }
  1335. }
  1336. }
  1337. else
  1338. {
  1339. WARNING_OUT(("Error starting RDS"));
  1340. }
  1341. }
  1342. else
  1343. {
  1344. if (ConfPolicies::IsRDSDisabledOnWin9x())
  1345. {
  1346. WARNING_OUT(("RDS launch disallowed by policy on Win9x"));
  1347. }
  1348. else
  1349. {
  1350. // Windows 95
  1351. HANDLE hServiceEvent = OpenEvent(EVENT_ALL_ACCESS, FALSE, SERVICE_CONTINUE_EVENT);
  1352. if (hServiceEvent) // Service is running
  1353. {
  1354. if (fActivate)
  1355. {
  1356. SetEvent(hServiceEvent);
  1357. }
  1358. CloseHandle(hServiceEvent);
  1359. }
  1360. else
  1361. {
  1362. WinExec(WIN95_SERVICE_APP_NAME,SW_SHOWNORMAL);
  1363. }
  1364. }
  1365. }
  1366. }