|
|
// File: conf.cpp
#include "precomp.h"
#include <mixer.h>
#include <EndSesn.h>
#include "NmLdap.h"
#include "conf.h"
#include "confwnd.h"
#include "taskbar.h"
#include <CR.h>
#include <tsecctrl.h>
#include "iapplet.h"
#include "inodecnt.h"
#include "ConfCpl.h"
#include "confroom.h"
#include "rtoolbar.h"
#include "GenWindow.h"
#include "cmd.h"
#include "confman.h"
#include "splash.h"
#include "calllog.h"
#include "call.h" // for FreeCallList
#include "popupmsg.h"
#include "floatbar.h"
#include "confman.h"
#include <version.h>
#include <nmremote.h>
#include "wininet.h"
#include "setupapi.h"
#include "autoconf.h"
#include "ConfNmSysInfoNotify.h"
#include "ConfPolicies.h"
#include "DShowDlg.h"
#include "Callto.h"
#include "passdlg.h"
// SDK includes
#include "NetMeeting.h"
#include "NmApp.h"
#include "NmManager.h"
#include "NmCall.h"
#include "NmConference.h"
#include "SDKWindow.h"
#include "confapi.h"
#include "FtHook.h"
#include "t120app.h"
#include "certui.h"
#include "dlgcall2.h"
#include "ConfMsgFilter.h"
BEGIN_OBJECT_MAP(ObjectMap) OBJECT_ENTRY(CLSID_NetMeeting, CNetMeetingObj) OBJECT_ENTRY(CLSID_NmManager, CNmManagerObj) OBJECT_ENTRY(CLSID_NmApplet, CNmAppletObj) END_OBJECT_MAP()
extern VOID SaveDefaultCodecSettings(UINT uBandWidth); extern int WabReadMe(void);
HRESULT InitSDK(); void CleanupSDK();
///////////////////////////////////////////////////////////////////////////
// Global Variables
LPTSTR g_lpCmdLine = NULL; CCallLog * g_pInCallLog = NULL; // The incoming call log object
CSimpleArray<ITranslateAccelerator*> *g_pDialogList = NULL; // Global list of modeless dialogs
CRITICAL_SECTION dialogListCriticalSection; // This is to avoid multiple access to the dialogList
INmSysInfo2 * g_pNmSysInfo = NULL; // Interface to SysInfo
INmManager2* g_pInternalNmManager = NULL; DWORD g_dwSysInfoNotifyCookie = 0; bool g_bNeedCleanup = false;
bool g_bEmbedding = FALSE; // Started with the embedding flag
UINT g_uEndSessionMsg; // The "NetMeeting EndSession" message
BOOL g_fHiColor = FALSE; // TRUE if we have more than 256 colors
HWND g_hwndDropDown = NULL; //
BOOL g_WSAStarted = FALSE; // WSAStartup
CCallto * g_pCCallto = NULL;
// The flag to indicate if the NetMeeting's NT display driver is enabled.
BOOL g_fNTDisplayDriverEnabled = FALSE;
OSVERSIONINFO g_osvi; // The os version info structure global
///////////////////////////////////////////////////////////////////////////
// IPC-related globals:
HANDLE g_hInitialized = NULL; HANDLE g_hShutdown = NULL;
///////////////////////////////////////////////////////////////////////////
// Hidden window-related globals:
CHiddenWindow * g_pHiddenWnd = NULL; HWND g_hwndESHidden = NULL; const TCHAR g_cszESHiddenWndClassName[] = _TEXT("ConfESHiddenWindow"); LRESULT CALLBACK ESHiddenWndProc(HWND, UINT, WPARAM, LPARAM);
///////////////////////////////////////////////////////////////////////////
// Remote control service related declarations
INT_PTR CALLBACK ServiceRunningDlgProc(HWND hDlg, UINT iMsg, WPARAM wParam, LPARAM lParam); VOID RestartRemoteControlService(); const int MAX_REMOTE_TRIES = 30; // number of seconds to wait for service to shut down
const int SERVICE_IN_CALL = 1001;
///////////////////////////////////////////////////////////////////////////
// Media Caps
ULONG g_uMediaCaps = 0;
BOOL FIsAudioAllowed() { return g_uMediaCaps & CAPFLAGS_AUDIO; }
BOOL FIsReceiveVideoAllowed() { return g_uMediaCaps & CAPFLAG_RECV_VIDEO; }
BOOL FIsSendVideoAllowed() { return g_uMediaCaps & CAPFLAG_SEND_VIDEO; }
BOOL FIsAVCapable() { return (FIsAudioAllowed() || FIsReceiveVideoAllowed() || FIsSendVideoAllowed()); }
extern BOOL SetProcessDefaultLayout(int iLayout); typedef BOOL (WINAPI* PFNSPDL)(int); #define LAYOUT_LTR 0
int g_iLayout = LAYOUT_LTR; DWORD g_wsLayout = 0;
VOID CheckLanguageLayout(void) { TCHAR szLayout[CCHMAXUINT]; if (!FLoadString(IDS_DEFAULT_LAYOUT, szLayout, CCHMAX(szLayout))) return;
g_iLayout = (int) DecimalStringToUINT(szLayout); if (0 == g_iLayout) { #ifdef DEBUG
RegEntry re(DEBUG_KEY, HKEY_LOCAL_MACHINE); g_iLayout = re.GetNumber(REGVAL_DBG_RTL, DEFAULT_DBG_RTL); if (0 == g_iLayout) #endif /* DEBUG */
return; }
HMODULE hmod = GetModuleHandle(TEXT("USER32")); if (NULL == hmod) return;
PFNSPDL pfn = (PFNSPDL) GetProcAddress(hmod, "SetProcessDefaultLayout"); if (NULL == pfn) return;
BOOL fResult = pfn(g_iLayout); if (fResult) { g_wsLayout = WS_EX_NOINHERIT_LAYOUT; } else { ERROR_OUT(("Problem with SetProcessDefaultLayout")); } }
///////////////////////////////////////////////////////////////////////////
// External Function Prototypes
// from dbgmenu.cpp
BOOL InitDebugMemoryOptions(void);
///////////////////////////////////////////////////////////////////////////
// Local Function Prototypes
BOOL HandleDialogMessage(LPMSG pMsg);
// This is for command line parsing...
LPCTSTR FindOneOf(LPCTSTR p1, LPCTSTR p2) { while (p1 != NULL && *p1 != NULL) { LPCTSTR p = p2; while (p != NULL && *p != NULL) { if (*p1 == *p) return CharNext(p1); p = CharNext(p); } p1 = CharNext(p1); } return NULL; }
// This launches a rundll32.exe which loads msconf.dll which will then wait for
// us to terminate and make sure that the mnmdd display driver was properly deactivated.
BOOL CreateWatcherProcess() { BOOL bRet = FALSE; HANDLE hProcess;
// open a handle to ourselves that the watcher process can inherit
hProcess = OpenProcess(SYNCHRONIZE, TRUE, GetCurrentProcessId()); if (hProcess) { TCHAR szWindir[MAX_PATH];
if (GetSystemDirectory(szWindir, sizeof(szWindir)/sizeof(szWindir[0]))) { TCHAR szCmdLine[MAX_PATH * 2]; PROCESS_INFORMATION pi = {0}; STARTUPINFO si = {0};
si.cb = sizeof(si); wsprintf(szCmdLine, "\"%s\\rundll32.exe\" msconf.dll,CleanupNetMeetingDispDriver %ld", szWindir, hProcess);
if (CreateProcess(NULL, szCmdLine, NULL, NULL, TRUE, // we want the watcher to inherit hProcess, so we must set bInheritHandles = TRUE
0, NULL, NULL, &si, &pi)) { bRet = TRUE;
CloseHandle(pi.hThread); CloseHandle(pi.hProcess); } }
CloseHandle(hProcess); }
return bRet; }
///////////////////////////////////////////////////////////////////////////
int WINAPI _tWinMain(HINSTANCE hInstance, HINSTANCE hInstPrev, LPTSTR lpCmdLine, int nCmdShow) { // if there is another instance of NetMeeting shutting down
// get out of here. Ideally we should display a message and/or wait for shutdown.
HANDLE hEvent = OpenEvent(EVENT_ALL_ACCESS, FALSE, _TEXT("CONF:ShuttingDown")); if (NULL != hEvent) { DWORD dwResult = WaitForSingleObject(hEvent, INFINITE); CloseHandle(hEvent); if (WAIT_TIMEOUT == dwResult) { return TRUE; } }
// Init debug output as soon as possible
ASSERT(::InitDebugMemoryOptions()); ASSERT(::InitDebugModule(TEXT("CONF"))); ASSERT(::InitDebugZones());
g_lpCmdLine = lpCmdLine;
int nRet = TRUE;
BOOL fRestartService = FALSE;
HRESULT hr = ::CoInitializeEx(NULL, COINIT_APARTMENTTHREADED);
if( SUCCEEDED( hr ) ) { // Init CComModule
_Module.Init(ObjectMap, hInstance, &LIBID_NetMeetingLib); _Module.m_dwThreadID = GetCurrentThreadId(); _Module.m_hResourceModule = hInstance; TCHAR szCommandLineSeps[] = _T("-/");
// Check to see if this is a reg/unreg request or background...
BOOL fShowUI = TRUE; BOOL bRun = TRUE; LPCTSTR lpszToken = FindOneOf(lpCmdLine, szCommandLineSeps); while (lpszToken != NULL) { if (lstrcmpi(lpszToken, _T("Embedding"))==0) { TRACE_OUT(("We are started with the -Embedding flag")); g_bEmbedding = TRUE; } if (lstrcmpi(lpszToken, _T("UnregServer"))==0) { _Module.UpdateRegistryFromResource(IDR_NETMEETING, FALSE); nRet = _Module.UnregisterServer(TRUE);
// These will fail without complaints
DeleteShortcut(CSIDL_DESKTOP, g_szEmpty); DeleteShortcut(CSIDL_APPDATA, QUICK_LAUNCH_SUBDIR);
bRun = FALSE; break; } if (lstrcmpi(lpszToken, _T("RegServer"))==0) { _Module.UpdateRegistryFromResource(IDR_NETMEETING, TRUE); nRet = _Module.RegisterServer(TRUE); bRun = FALSE; break; }
if (lstrcmpi(lpszToken, g_cszBackgroundSwitch)==0) { fShowUI = FALSE; }
lpszToken = FindOneOf(lpszToken, szCommandLineSeps); }
if (bRun) { // Setup and RDS rely on the following event to determine whether NetMeeting is Running
// this event creation should not be removed and the name should not be changed
g_hInitialized = ::CreateEvent(NULL, TRUE, FALSE, _TEXT("CONF:Init")); if (NULL != g_hInitialized) { if (ERROR_ALREADY_EXISTS == ::GetLastError()) { // CreateEvent returned a valid handle, but we don't want initialization to
// succeed if we are running another copy of this exe, so we cleanup and exit
WARNING_OUT(("Detected another conf.exe - sending a message")); IInternalConfExe * pInternalConfExe; hr = CoCreateInstance( CLSID_NmManager, NULL, CLSCTX_ALL, IID_IInternalConfExe, (LPVOID *) &pInternalConfExe ); if (SUCCEEDED(hr)) { if(FAILED(pInternalConfExe->Launch())) { // If we are in INIT_CONTROL mode, then we can't launch NetMeeting or applets
::ConfMsgBox(NULL, (LPCTSTR) IDS_CANT_START_NM_BECAUSE_SDK_APP_OWNS_NM);
} pInternalConfExe->Release(); } } else if(SUCCEEDED(InitHtmlHelpMarshaler(_Module.GetModuleInstance()))) { // We create a seperate watcher process that will cleanup the mnmdd display driver
// if we terminate unexpectedly. This is necessary since if we do not disable the
// mirrored driver, all DX games will fail to run
CreateWatcherProcess();
//initialize ATL control contaiment code
AtlAxWinInit();
hr = _Module.RegisterClassObjects(CLSCTX_LOCAL_SERVER, REGCLS_MULTIPLEUSE);
if( SUCCEEDED( hr ) ) { BOOL fContinue = TRUE;
if( FAILED(InitSDK()) ) { fContinue = FALSE; }
if(!g_bEmbedding) { // Before doing anything else, take care of the remote control service.
fContinue = CheckRemoteControlService(); fRestartService = fContinue;
if(fContinue) { fContinue = SUCCEEDED(InitConfExe(fShowUI)); } }
if(fContinue) { TRACE_OUT(("Entering event loop..."));
MSG msg; while (::GetMessage(&msg, NULL, 0, 0)) { BOOL bHandled = FALSE;
if(g_pPing) // This is TRUE if InitConfExe has been called...
{ bHandled = ::HandleDialogMessage(&msg); } if(!bHandled) { ::TranslateMessage(&msg); ::DispatchMessage(&msg); }
} TRACE_OUT(("Conf received WM_QUIT")); }
if(g_bNeedCleanup) { CleanUp(); }
CleanupSDK();
_Module.RevokeClassObjects(); } } ::CloseHandle(g_hInitialized); if (g_hShutdown) { SetEvent(g_hShutdown); ::CloseHandle(g_hShutdown); } } else { ERROR_OUT(("CreateEvent (init) failed!")); hr = E_FAIL; }
_Module.Term(); } ::CoUninitialize();
//
// Restart the remote control service if we need to.
//
if (fRestartService) RestartRemoteControlService(); }
#ifdef DEBUG
::ExitDebugModule(); TRACE_OUT(("returned from ExitDebugModule")); ::DeinitDebugZones(); TRACE_OUT(("returned from DeinitDebugZones")); #endif //DEBUG
return nRet; }
VOID CheckMachineNameForExtendedChars ( VOID ) {
DBGENTRY(CheckMachineNameForExtendedChars);
// First we have to get the computer name
TCHAR szMachineName[MAX_COMPUTERNAME_LENGTH + 1]; DWORD cchMachineName = CCHMAX(szMachineName);
// Next we check to see if the computer nami is invalid
if (GetComputerName(szMachineName, &cchMachineName)) { for ( LPTSTR p = szMachineName; *p != _T('\0'); p++ ) { if ( (WORD)(*p) & 0xFF80 ) { // The machine name is invalid because it contains an invalid character
CDontShowDlg MachineNameWarningDlg( IDS_MACHINENAMEWARNING, REGVAL_DS_MACHINE_NAME_WARNING, DSD_ALWAYSONTOP | MB_SETFOREGROUND | MB_OK );
MachineNameWarningDlg.DoModal(NULL);
goto end; } } } else { ERROR_OUT(("GetComputerName() failed, err=%lu", GetLastError())); *szMachineName = TEXT('\0'); }
end:
DBGEXIT(CheckMachineNameForExtendedChars); }
VOID HandleConfSettingsChange(DWORD dwSettings) { DebugEntry(HandleConfSettingsChange); USES_CONVERSION;
TRACE_OUT(("HandleConfSettingsChange, dwSettings=0x%x", dwSettings));
// Tell the user if she changed something that won't take
// effect right away
if (CSETTING_L_REQUIRESRESTARTMASK & dwSettings) { ::ConfMsgBox(NULL, (LPCTSTR) IDS_NEED_RESTART); } if (CSETTING_L_REQUIRESNEXTCALLMASK & dwSettings) { if (::FIsConferenceActive()) { ::ConfMsgBox(NULL, (LPCTSTR) IDS_NEED_NEXTCALL); } } if (CSETTING_L_BANDWIDTH & dwSettings) { if (NULL != g_pNmSysInfo) { int nMegahertz=300, nProcFamily=6; RegEntry re(AUDIO_KEY, HKEY_CURRENT_USER); UINT uSysPolBandwidth; UINT uBandwidth; uBandwidth = re.GetNumber(REGVAL_TYPICALBANDWIDTH, BW_DEFAULT);
#ifdef _M_IX86
GetNormalizedCPUSpeed(&nMegahertz, &nProcFamily); TRACE_OUT(("Normalized Processor Speed = %d, Processor type = %d\n", nMegahertz, nProcFamily)); #endif
// convert bandwidth ID (1-4) to bits/sec
uBandwidth = GetBandwidthBits(uBandwidth, nMegahertz);
// the existance of a QOS - maximum bandwidth key implies that
// the user's bandwidth is being over-rided (ONLY if his setting is LAN)
uSysPolBandwidth = SysPol::GetMaximumBandwidth();
if ((uSysPolBandwidth > 0) && (uBandwidth >= BW_SLOWLAN_BITS)) { uBandwidth = max(uSysPolBandwidth, BW_144KBS_BITS); }
g_pNmSysInfo->SetOption(NM_SYSOPT_BANDWIDTH, uBandwidth); } }
if (CSETTING_L_SHOWTASKBAR & dwSettings) { // This will remove one if one is already there:
::RemoveTaskbarIcon(::GetHiddenWindow()); // This will add the icon if the registry switch is on:
::AddTaskbarIcon(::GetHiddenWindow()); }
if (CSETTING_L_AUDIODEVICE & dwSettings) { CConfRoom* pcr = ::GetConfRoom(); if (NULL != pcr) { pcr->OnAudioDeviceChanged(); } }
if (CSETTING_L_AGC & dwSettings) { CConfRoom* pcr = ::GetConfRoom(); if (NULL != pcr) { pcr->OnAGC_Changed(); } }
if ((CSETTING_L_AUTOMIC|CSETTING_L_MICSENSITIVITY) & dwSettings) { CConfRoom* pcr = ::GetConfRoom(); if (NULL != pcr) { pcr->OnSilenceLevelChanged(); } } if( CSETTING_L_ULSSETTINGS & dwSettings ) { if(g_pLDAP) { g_pLDAP->OnSettingsChanged(); }
if (NULL != g_pNmSysInfo) { RegEntry re(ISAPI_CLIENT_KEY, HKEY_CURRENT_USER); LPCTSTR pcszName = re.GetString(REGVAL_ULS_NAME);
g_pNmSysInfo->SetProperty(NM_SYSPROP_USER_NAME, CComBSTR(pcszName)); } } if (CSETTING_L_FULLDUPLEX & dwSettings) { RegEntry re(AUDIO_KEY, HKEY_CURRENT_USER); BOOL bFullDuplex = FALSE; UINT uSoundCardCaps = re.GetNumber(REGVAL_SOUNDCARDCAPS,SOUNDCARD_NONE);
if (ISSOUNDCARDFULLDUPLEX(uSoundCardCaps)) { bFullDuplex = re.GetNumber(REGVAL_FULLDUPLEX,FULLDUPLEX_DISABLED); }
ASSERT(g_pNmSysInfo);
if (NULL != g_pNmSysInfo) { g_pNmSysInfo->SetOption(NM_SYSOPT_FULLDUPLEX, bFullDuplex); } }
if (CSETTING_L_CAPTUREDEVICE & dwSettings) { if (NULL != g_pNmSysInfo) { RegEntry re(VIDEO_KEY, HKEY_CURRENT_USER); DWORD dwCaptureID = re.GetNumber(REGVAL_CAPTUREDEVICEID, 0);
g_pNmSysInfo->SetOption(NM_SYSOPT_CAPTURE_DEVICE, dwCaptureID); } }
if (CSETTING_L_DIRECTSOUND & dwSettings) { ASSERT(g_pNmSysInfo);
if (NULL != g_pNmSysInfo) { RegEntry re(AUDIO_KEY, HKEY_CURRENT_USER); DWORD dwDS = re.GetNumber(REGVAL_DIRECTSOUND, DSOUND_USER_DISABLED); g_pNmSysInfo->SetOption(NM_SYSOPT_DIRECTSOUND, dwDS); } }
DebugExitVOID(HandleConfSettingsChange); }
// DeleteOldRegSettings is called the first time
// this build of NetMeeting is run by the user
// We don't touch UI\Directory as it is populated by the INF file
VOID DeleteOldRegSettings() { // "%KEY_CONFERENCING%\UI"
HKEY hKey; long lRet = ::RegOpenKey(HKEY_CURRENT_USER, UI_KEY, &hKey); if (NO_ERROR == lRet) { ::RegDeleteValue(hKey, REGVAL_MP_WINDOW_X); ::RegDeleteValue(hKey, REGVAL_MP_WINDOW_Y); ::RegDeleteValue(hKey, REGVAL_MP_WINDOW_WIDTH); ::RegDeleteValue(hKey, REGVAL_MP_WINDOW_HEIGHT);
::RegCloseKey(hKey); } }
static HRESULT _ValidatePolicySettings() { HRESULT hr = S_OK;
if( g_pNmSysInfo ) { //
// LAURABU BUGBUG BOGUS:
//
// If security required, and not available, warning
// If security incoming required/outgoing preferred, warning
//
} else { ERROR_OUT(("g_pNmySysInfo should not me NULL")); hr = E_UNEXPECTED; }
return hr; }
HRESULT InitSDK() { DBGENTRY(InitSDK); HRESULT hr = S_OK;
if(FAILED(hr = CSDKWindow::InitSDK())) goto end; if(FAILED(hr = CNmCallObj::InitSDK())) goto end; if(FAILED(hr = CNmManagerObj::InitSDK())) goto end; if(FAILED(hr = CNmConferenceObj::InitSDK())) goto end; if(FAILED(hr = CNetMeetingObj::InitSDK())) goto end; if(FAILED(hr = CFt::InitFt())) goto end;
g_pCCallto = new CCallto;
ASSERT( g_pCCallto != NULL ); if( g_pCCallto == NULL ) { hr = E_FAIL; }
end:
DBGEXIT_HR(InitSDK,hr); return hr; }
void CleanupSDK() { DBGENTRY(CleanupSDK);
// Revoke the old filter object
CoRegisterMessageFilter(NULL, NULL);
CNmCallObj::CleanupSDK(); CNmManagerObj::CleanupSDK(); CNmConferenceObj::CleanupSDK(); CSDKWindow::CleanupSDK(); CNetMeetingObj::CleanupSDK(); CFt::CloseFtApplet();
DBGEXIT(CleanupSDK); }
/* I N I T C O N F E X E */ /*-------------------------------------------------------------------------
%%Function: InitConfExe
-------------------------------------------------------------------------*/ HRESULT InitConfExe(BOOL fShowUI) {
// Create a message filter object
CComPtr<IMessageFilter> spMsgFilter; CComPtr<IMessageFilter> spOldMsgFilter; HRESULT hr = CConfMsgFilter::_CreatorClass::CreateInstance(NULL, IID_IMessageFilter, reinterpret_cast<void**>(&spMsgFilter)); if(FAILED(hr)) return hr;
// Register the message filter object
hr = CoRegisterMessageFilter(spMsgFilter, &spOldMsgFilter); if(FAILED(hr)) return hr;
// Wipe out default find directory entry... we no longer wish to persist this...
// in some future overhaul / cleanup we should stop using the registry for this...
RegEntry re( DLGCALL_MRU_KEY, HKEY_CURRENT_USER );
re.SetValue( REGVAL_DLGCALL_DEFDIR, TEXT( "" ) );
LPCTSTR lpCmdLine = g_lpCmdLine; TRACE_OUT(("InitConfExe"));
// Init UI objects (NOTE: we continue if this fails)
CPopupMsg::Init(); CPasswordDlg::Init();
// Allocate dialog list object:
g_pDialogList = new CSimpleArray<ITranslateAccelerator*>; if (NULL == g_pDialogList) { ERROR_OUT(("Could not allocate g_pDialogList!")); return E_FAIL; }
//
// Initialize the critical section to protect the dialogList
//
InitializeCriticalSection(&dialogListCriticalSection); // Determine if we have MORE THAN 256 colors
{ HDC hdc = GetDC(NULL); if (NULL != hdc) { g_fHiColor = 8 < (::GetDeviceCaps(hdc, BITSPIXEL) * ::GetDeviceCaps(hdc, PLANES)); ReleaseDC(NULL, hdc); } }
// Get the default dialog (GUI) font for international
// REVIEW: should we check the registry for a localized font?
g_hfontDlg = (HFONT) ::GetStockObject(DEFAULT_GUI_FONT); if (NULL == g_hfontDlg) { return E_FAIL; }
LoadIconImages();
// On Windows NT, determine if the NetMeeting display driver is
// enabled. Note that this depends on <g_osvi> being initialized.
//
// Since NT 5.0 will support dynamic loading of the display driver,
// we assume that the driver is enabled if the OS major version
// number is greater than 4.
if (::IsWindowsNT()) { RegEntry re(NM_NT_DISPLAY_DRIVER_KEY, HKEY_LOCAL_MACHINE, FALSE);
g_fNTDisplayDriverEnabled = 4 < g_osvi.dwMajorVersion || NT_DRIVER_START_DISABLED != re.GetNumber( REGVAL_NM_NT_DISPLAY_DRIVER_ENABLED, NT_DRIVER_START_DISABLED); } else { ASSERT(FALSE == g_fNTDisplayDriverEnabled); }
// Check the language layout (UI can be displayed after this point)
CheckLanguageLayout();
// AutoConfiguration
CAutoConf::DoIt();
TRACE_OUT(("Command Line is \"%s\"", lpCmdLine));
// Register hidden window class:
WNDCLASS wcESHidden = { 0L, ESHiddenWndProc, 0, 0, _Module.GetModuleInstance(), NULL, NULL, NULL, NULL, g_cszESHiddenWndClassName }; if (!RegisterClass(&wcESHidden)) { ERROR_OUT(("Could not register hidden wnd classes")); return E_FAIL; }
// Register the "NetMeeting EndSession" message:
g_uEndSessionMsg = ::RegisterWindowMessage(NM_ENDSESSION_MSG_NAME); // Create a hidden window for event processing:
g_pHiddenWnd = new CHiddenWindow(); if (NULL == g_pHiddenWnd) { return(E_FAIL); } g_pHiddenWnd->Create();
g_hwndESHidden = ::CreateWindow( g_cszESHiddenWndClassName, _TEXT(""), WS_POPUP, // not visible!
0, 0, 0, 0, NULL, NULL, _Module.GetModuleInstance(), NULL);
HWND hwndHidden = g_pHiddenWnd->GetWindow();
if ((NULL == hwndHidden) || (NULL == g_hwndESHidden)) { ERROR_OUT(("Could not create hidden windows")); return E_FAIL; }
LONG lSoundCaps = SOUNDCARD_NONE;
// Start the run-once wizard (if needed):
RegEntry reConf(CONFERENCING_KEY, HKEY_CURRENT_USER);
// check to see if the wizard has been run in UI mode for this build
DWORD dwVersion = reConf.GetNumber(REGVAL_WIZARD_VERSION_UI, 0); BOOL fRanWizardUI = ((VER_PRODUCTVERSION_W & HIWORD(dwVersion)) == VER_PRODUCTVERSION_W);
BOOL fForceWizard = FALSE; if (!fRanWizardUI) { dwVersion = reConf.GetNumber(REGVAL_WIZARD_VERSION_NOUI, 0); BOOL fRanWizardNoUI = (VER_PRODUCTVERSION_DW == dwVersion);
// wizard has not been run in UI mode
if (!fRanWizardNoUI) { // wizard has not been run before, delete old registry settings
DeleteOldRegSettings();
fForceWizard = TRUE; } else { // wizard has been run in NoUI mode, we only need to run it if we are in UI mode
if(fShowUI) { fForceWizard = TRUE; } }
if (fForceWizard) { WabReadMe(); } }
hr = ::StartRunOnceWizard(&lSoundCaps, fForceWizard, fShowUI); if (FAILED(hr)) { WARNING_OUT(("Did not retrieve necessary info from wizard")); ConfMsgBox(NULL, MAKEINTRESOURCE(IDS_ERROR_BAD_ADMIN_SETTINGS));
return E_FAIL; } else if( S_FALSE == hr ) { return NM_E_USER_CANCELED_SETUP; }
if (fForceWizard) { reConf.SetValue(fShowUI ? REGVAL_WIZARD_VERSION_UI : REGVAL_WIZARD_VERSION_NOUI, VER_PRODUCTVERSION_DW); }
// Start NetMeeting At Page Once
if( fShowUI && fForceWizard ) { if( ConfPolicies::IsShowFirstTimeUrlEnabled() ) { CmdLaunchWebPage(ID_HELP_WEB_SUPPORT); } }
// The following hack is to fix the don't run wizard twice bug
// the side effect is that the codec ordering is blown away.
// this code restores the key in the event that this wizard is not run.
HKEY hKey; long lRet = ::RegOpenKey(HKEY_LOCAL_MACHINE, INTERNET_AUDIO_KEY TEXT("\\") REGVAL_ACMH323ENCODINGS , &hKey); if (NO_ERROR == lRet) { ::RegCloseKey(hKey); } else { RegEntry reAudio(AUDIO_KEY, HKEY_CURRENT_USER); UINT uBandwidth = reAudio.GetNumber ( REGVAL_TYPICALBANDWIDTH, BW_DEFAULT ); SaveDefaultCodecSettings(uBandwidth); }
// Start the Splash screen only after the wizard is complete
if (fShowUI) { ::StartSplashScreen(NULL); }
// Init incoming call log:
g_pInCallLog = new CCallLog(LOG_INCOMING_KEY, TEXT("CallLog"));
// Init capabilities:
g_uMediaCaps = CAPFLAG_DATA;
//
// NOTE: THIS IS WHERE TO CHANGE TO DISABLE H323 CALLS FOR INTEL ET AL.
//
if(!_Module.DidSDKDisableH323()) { g_uMediaCaps |= CAPFLAG_H323_CC;
if (SOUNDCARD_NONE != lSoundCaps) { if (!SysPol::NoAudio()) { g_uMediaCaps |= CAPFLAGS_AUDIO; } } if (!SysPol::NoVideoReceive()) { g_uMediaCaps |= CAPFLAG_RECV_VIDEO; } if (!SysPol::NoVideoSend()) { g_uMediaCaps |= CAPFLAG_SEND_VIDEO; } }
// Create Manager
hr = CoCreateInstance(CLSID_NmManager2, NULL, CLSCTX_INPROC, IID_INmManager2, (void**)&g_pInternalNmManager); if (FAILED(hr)) { ERROR_OUT(("Could not create INmManager")); return E_FAIL; }
// Get the INmSysInfo3
CComPtr<INmSysInfo > spSysInfo; if (SUCCEEDED(g_pInternalNmManager->GetSysInfo(&spSysInfo))) { if (FAILED(spSysInfo->QueryInterface(IID_INmSysInfo2, (void **)&g_pNmSysInfo))) { ERROR_OUT(("Could not get INmSysInfo2")); } else { ASSERT( g_pNmSysInfo );
CComPtr<INmSysInfoNotify> spNmSysInfoNotify; if( SUCCEEDED ( CConfNmSysInfoNotifySink::_CreatorClass::CreateInstance( NULL, IID_INmSysInfoNotify, reinterpret_cast<void**>(&spNmSysInfoNotify)))) { ASSERT(spNmSysInfoNotify); ASSERT(0 == g_dwSysInfoNotifyCookie);
NmAdvise(g_pNmSysInfo, spNmSysInfoNotify, IID_INmSysInfoNotify, &g_dwSysInfoNotifyCookie); } } }
_ValidatePolicySettings();
hr = g_pInternalNmManager->Initialize(NULL, &g_uMediaCaps); if (FAILED(hr)) { UINT_PTR uErrorID;
switch (hr) { case UI_RC_NO_NODE_NAME: { // No error in this case - the user probably cancelled from
// the intro wizard.
uErrorID = 0; break; } case UI_RC_BACKLEVEL_LOADED: { uErrorID = IDS_BACKLEVEL_LOADED; break; } case UI_RC_T120_ALREADY_INITIALIZED: { uErrorID = IDS_T120_ALREADY_INITIALIZED; break; }
case UI_RC_T120_FAILURE: { WARNING_OUT(("T.120 failed to initialize (winsock problem?)")); uErrorID = IDS_CANT_START; break; }
default: { uErrorID = IDS_CANT_START; break; } } if (0 != uErrorID) { ::ConfMsgBox(NULL, (LPCTSTR) uErrorID); } return E_FAIL; }
// force the update of dll settings
HandleConfSettingsChange(CSETTING_L_BANDWIDTH | CSETTING_L_CAPTUREDEVICE | CSETTING_L_ULSSETTINGS | CSETTING_L_DIRECTSOUND| CSETTING_L_FULLDUPLEX);
if (FALSE == ::ConfRoomInit(_Module.GetModuleInstance())) { ::ConfMsgBox(NULL, (LPCTSTR) IDS_CANT_START); return E_FAIL; }
// Now perform the check on the machine name and warn if
// it is problematic.
::CheckMachineNameForExtendedChars();
// Create the main conference manager to make sure
// we can handle incoming calls, even in background mode
if (!CConfMan::FCreate(g_pInternalNmManager)) { ERROR_OUT(("Unable to create Conference Manager")); return E_FAIL; }
// Initialize winsock (for name/address resolution)
{ WSADATA wsaData; int iErr = WSAStartup(0x0101, &wsaData); if (0 != iErr) { ERROR_OUT(("WSAStartup() failed: %i", iErr)); return E_FAIL; } g_WSAStarted = TRUE; }
// Initialize T.120 Security settings
::InitT120SecurityFromRegistry();
StopSplashScreen();
CreateConfRoomWindow(fShowUI);
g_pPing = new CPing;
if( ConfPolicies::GetCallingMode() == ConfPolicies::CallingMode_Direct ) { // Initialize gatewayContext...
RegEntry reConf( CONFERENCING_KEY, HKEY_CURRENT_USER );
if( reConf.GetNumber( REGVAL_USE_H323_GATEWAY ) != 0 ) { g_pCCallto->SetGatewayName( reConf.GetString( REGVAL_H323_GATEWAY ) ); g_pCCallto->SetGatewayEnabled( true ); }
if(ConfPolicies::LogOntoIlsWhenNetMeetingStartsIfInDirectCallingMode() && !_Module.DidSDKDisableInitialILSLogon()) { InitNmLdapAndLogon(); } } else { GkLogon(); }
if(!_Module.InitControlMode()) { ::AddTaskbarIcon(::GetHiddenWindow()); }
g_bNeedCleanup = true; CNmManagerObj::NetMeetingLaunched(); return S_OK; }
VOID CleanUpUi(void) { SysPol::CloseKey();
if( 0 != g_dwSysInfoNotifyCookie ) { NmUnadvise(g_pNmSysInfo, IID_INmSysInfoNotify, g_dwSysInfoNotifyCookie); g_dwSysInfoNotifyCookie = 0; }
if (NULL != g_pNmSysInfo) { if( IsGatekeeperLoggedOn() ) { g_pNmSysInfo->GkLogoff(); }
g_pNmSysInfo->Release(); g_pNmSysInfo = NULL; }
FreeIconImages();
CGenWindow::DeleteStandardPalette(); CGenWindow::DeleteStandardBrush();
CMainUI::CleanUpVideoWindow();
CFindSomeone::Destroy(); }
VOID CleanUp(BOOL fLogoffWindows) {
FreeCallList();
// Kill the taskbar icon:
if (NULL != g_pHiddenWnd) { HWND hwndHidden = g_pHiddenWnd->GetWindow();
TRACE_OUT(("Removing taskbar icon...")); ::RemoveTaskbarIcon(hwndHidden); DestroyWindow(hwndHidden);
g_pHiddenWnd->Release(); g_pHiddenWnd = NULL; }
// NOTE: during WM_ENDSESSION, we want
// to log off after doing all other clean-up, in case it gets stuck
// waiting for the logon thread to complete.
if (FALSE == fLogoffWindows) { if(g_pLDAP) { g_pLDAP->Logoff();
delete g_pLDAP; g_pLDAP = NULL; } }
delete g_pCCallto; g_pCCallto = NULL;
delete g_pPing; g_pPing = NULL;
CleanUpUi();
// These must happen AFTER all the UI is cleaned up
if(g_pInternalNmManager) { g_pInternalNmManager->Release(); } CConfMan::Destroy();
// destroy incoming call log:
delete g_pInCallLog; g_pInCallLog = NULL;
CPopupMsg::Cleanup(); CPasswordDlg::Cleanup(); // Code to clean up gracefully
if (FALSE == fLogoffWindows) { // NOTE: we intentionally leak this list object when shutting down
// due to logging off windows, because we don't want to put a NULL
// check in HandleDialogMessage() and there is no WM_QUIT to guarantee that
// we've stopped receiving messages when shutting down in that code path
EnterCriticalSection(&dialogListCriticalSection);
for( int i = 0; i < g_pDialogList->GetSize(); ++i ) { ASSERT( NULL != (*g_pDialogList)[i] ); RemoveTranslateAccelerator( (*g_pDialogList)[i] ); }
LeaveCriticalSection(&dialogListCriticalSection); // Delete the dialog list:
delete g_pDialogList;
//
// Delete the critical section
//
DeleteCriticalSection(&dialogListCriticalSection); g_pDialogList = NULL; }
// Auto-disconnect from MSN:
::SendDialmonMessage(WM_APP_EXITING); if (g_WSAStarted) { WSACleanup(); g_WSAStarted = FALSE; }
delete g_pConfRoom; g_pConfRoom = NULL;
g_bNeedCleanup = false; }
/* S E N D D I A L M O N M E S S A G E */ /*-------------------------------------------------------------------------
%%Function: SendDialmonMessage
Send a message to the dialing monitor. Either WINSOCK_ACTIVITY_TIMER or WM_APP_EXITING. (The code comes from Internet Explorer) -------------------------------------------------------------------------*/ VOID SendDialmonMessage(UINT uMsg) { HWND hwndAutodisconnectMonitor = ::FindWindow(_TEXT("MS_AutodialMonitor"), NULL); if (NULL != hwndAutodisconnectMonitor) { ::SendMessage(hwndAutodisconnectMonitor, uMsg, 0, 0); } }
// This window procedure exists for the sole purpose of receiving
// WM_ENDSESSION. Because of bug 2287, we cannot have the regular
// hidden window handle WM_ENDSESSION. DCL has subclassed our hidden
// window, and if we unload them inside one of it's messages, then we
// will fault. It's too bad that we can't find a better fix (such as
// removing the subclass), but we are under time pressure to fix this
// bug for v1.0
LRESULT CALLBACK ESHiddenWndProc( HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam) { if ((WM_ENDSESSION == uMsg) && (TRUE == (BOOL) wParam)) { TRACE_OUT(("Conf received WM_ENDSESSION, fLogoff=%s", GetBOOLString((BOOL)lParam))); TRACE_OUT(("Conf calling UIEndSession()")); CConfRoom::UIEndSession((BOOL) lParam); TRACE_OUT(("Conf testing lParam=%d", lParam)); if ((BOOL) lParam) { // Logging off:
TRACE_OUT(("Conf calling CleanUp()")); // NOTE: Passing TRUE into CleanUp() because we don't
// want to logoff ULS / de-init name services until after insuring that DCL
// has cleaned up properly, because it can take enough time that
// our task might get killed.
::CleanUp(TRUE);
//
// Restart the remote control service if we need to.
//
RestartRemoteControlService(); } else { TRACE_OUT(("Conf not cleaning up - Windows shutting down")); }
#if 0 // LONCHANC: it faults 100% on my main dev machine.
if( g_pLDAP != NULL ) { g_pLDAP->Logoff(); } #endif
return 0; } else { return DefWindowProc(hwnd, uMsg, wParam, lParam); } }
/* C M D S H U T D O W N */ /*-------------------------------------------------------------------------
%%Function: CmdShutdown
-------------------------------------------------------------------------*/ VOID CmdShutdown(void) { HWND hwndMain = ::GetMainWindow(); if (NULL != hwndMain) { // We have UI up, so post a WM_CLOSE with lParam = 1,
// which indicates a forced "Exit and Stop"
::PostMessage(hwndMain, WM_CLOSE, 0, 1); } else { ::PostThreadMessage(_Module.m_dwThreadID, WM_QUIT, 0, 0); } }
void SignalShutdownStarting(void) { if (NULL == g_hShutdown) { g_hShutdown = ::CreateEvent(NULL, TRUE, FALSE, _TEXT("CONF:ShuttingDown")); _Module.RevokeClassObjects(); } }
/* H A N D L E D I A L O G M E S S A G E */ /*-------------------------------------------------------------------------
%%Function: HandleDialogMessage
Global modeless dialog handler -------------------------------------------------------------------------*/ BOOL HandleDialogMessage(LPMSG pMsg) { if (g_hwndDropDown != NULL) { switch (pMsg->message) { case WM_KEYDOWN: { if ((VK_ESCAPE != pMsg->wParam) && (VK_TAB != pMsg->wParam)) break; if (0 != SendMessage(g_hwndDropDown, WM_CONF_DROP_KEY, pMsg->wParam, (LPARAM) pMsg->hwnd)) { return TRUE; // message was handled
} break; } case WM_LBUTTONDOWN: case WM_RBUTTONDOWN: case WM_NCLBUTTONDOWN: case WM_NCRBUTTONDOWN: { if (g_hwndDropDown == pMsg->hwnd) break; // message is for the window, pass along as normal
if (0 != SendMessage(g_hwndDropDown, WM_CONF_DROP_CLICK, 0, (LPARAM) pMsg->hwnd)) { return TRUE; // message was handled
} break; }
default: break; } /* switch (pMsg->message) */ }
ASSERT(NULL != g_pDialogList);
EnterCriticalSection(&dialogListCriticalSection);
for( int i = 0; i < g_pDialogList->GetSize(); ++i ) { ITranslateAccelerator *pTrans = (*g_pDialogList)[i]; ASSERT( NULL != pTrans ); if( S_OK == pTrans->TranslateAccelerator(pMsg, 0) ) { LeaveCriticalSection(&dialogListCriticalSection); return TRUE; } } LeaveCriticalSection(&dialogListCriticalSection);
return FALSE; }
//////////////////////////////////////////////////////////////////////////
/* R E M O T E P A S S W O R D D L G P R O C */ // Handles the dialog box asking if the user wants to start conf.exe even though the remote control
// service is in a call.
INT_PTR CALLBACK ServiceRunningDlgProc(HWND hDlg, UINT iMsg, WPARAM wParam, LPARAM lParam) { switch (iMsg) { case WM_INITDIALOG: return TRUE; break; case WM_COMMAND: switch (LOWORD(wParam)) { case ID_START_CONF: EndDialog(hDlg,1); break; case ID_EXIT: EndDialog(hDlg,0); break; default: break; } return TRUE; break; } return FALSE; }
BOOL CheckRemoteControlService() { BOOL fContinue = TRUE; // Store OS version info
g_osvi.dwOSVersionInfoSize = sizeof(g_osvi); if (FALSE == ::GetVersionEx(&g_osvi)) { ERROR_OUT(("GetVersionEx() failed!")); return FALSE; }
if (::IsWindowsNT()) { SC_HANDLE hSCManager = OpenSCManager(NULL, SERVICES_ACTIVE_DATABASE, SC_MANAGER_ALL_ACCESS); SC_HANDLE hRemoteControl = NULL; SERVICE_STATUS serviceStatus;
if (hSCManager != NULL) { hRemoteControl = OpenService(hSCManager,REMOTE_CONTROL_NAME,SERVICE_ALL_ACCESS); DWORD dwError = GetLastError(); if (hRemoteControl != NULL) { // If service is running...
BOOL fSuccess = QueryServiceStatus(hRemoteControl,&serviceStatus); if (fSuccess && serviceStatus.dwCurrentState != SERVICE_STOPPED && serviceStatus.dwCurrentState != SERVICE_PAUSED) { if (serviceStatus.dwControlsAccepted & SERVICE_ACCEPT_SHUTDOWN) // Service is in a call
{ fContinue = (BOOL)DialogBox(::GetInstanceHandle(),MAKEINTRESOURCE(IDD_SERVICE_RUNNING),GetDesktopWindow(),ServiceRunningDlgProc); } if (fContinue) { ControlService(hRemoteControl,SERVICE_CONTROL_PAUSE,&serviceStatus); for (int i = 0; i < MAX_REMOTE_TRIES; i++) { fSuccess = QueryServiceStatus(hRemoteControl,&serviceStatus); if (serviceStatus.dwCurrentState == SERVICE_PAUSED) break; TRACE_OUT(("Waiting for srvc - status is %d...", serviceStatus.dwCurrentState)); Sleep(1000); } if ( MAX_REMOTE_TRIES == i ) { // If we don't manage to shut down the service
// we shouldn't try to start - it will only fail.
WARNING_OUT(("TIMED OUT WAITING FOR SRVC!!")); fContinue = FALSE; } } } CloseServiceHandle(hRemoteControl); } CloseServiceHandle(hSCManager); }
return fContinue; } else { // Windows 95
HANDLE hServiceEvent = OpenEvent(EVENT_ALL_ACCESS, FALSE, SERVICE_PAUSE_EVENT); HANDLE hActiveEvent = OpenEvent(EVENT_ALL_ACCESS, FALSE, SERVICE_ACTIVE_EVENT); DWORD dwError = GetLastError(); if (hServiceEvent != NULL && hActiveEvent != NULL) { // Service is running and is active
CloseHandle(hActiveEvent); HANDLE hCallEvent = OpenEvent(EVENT_ALL_ACCESS, FALSE, SERVICE_CALL_EVENT); if (hCallEvent != NULL) { // Service is in a call
fContinue = (BOOL)DialogBox(::GetInstanceHandle(),MAKEINTRESOURCE(IDD_SERVICE_RUNNING),GetDesktopWindow(),ServiceRunningDlgProc); CloseHandle(hCallEvent); } if (fContinue) { SetEvent(hServiceEvent); CloseHandle(hServiceEvent); for (int i = 0; i < MAX_REMOTE_TRIES; i++) { hActiveEvent = OpenEvent(EVENT_ALL_ACCESS, FALSE, SERVICE_ACTIVE_EVENT); if (NULL == hActiveEvent) break; TRACE_OUT(("Waiting for srvc")); CloseHandle(hActiveEvent); Sleep(1000); } if ( MAX_REMOTE_TRIES == i ) { // If we don't manage to shut down the service
// we shouldn't try to start - it will only fail.
WARNING_OUT(("TIMED OUT WAITING FOR SRVC!!")); fContinue = FALSE; } } } return fContinue; } }
VOID RestartRemoteControlService() { RegEntry reLM = RegEntry(REMOTECONTROL_KEY, HKEY_LOCAL_MACHINE);
if (!reLM.GetNumber(REMOTE_REG_RUNSERVICE,0)) return;
if (ConfPolicies::IsRDSDisabled()) { WARNING_OUT(("RDS launch disallowed by policy")); return; } BOOL fActivate = reLM.GetNumber(REMOTE_REG_ACTIVATESERVICE, DEFAULT_REMOTE_ACTIVATESERVICE); if (::IsWindowsNT()) { SERVICE_STATUS serviceStatus; SC_HANDLE hSCManager = OpenSCManager(NULL, SERVICES_ACTIVE_DATABASE, SC_MANAGER_ALL_ACCESS); SC_HANDLE hRemoteControl = OpenService(hSCManager,REMOTE_CONTROL_NAME,SERVICE_ALL_ACCESS); if (hRemoteControl != NULL) { BOOL fSuccess = QueryServiceStatus(hRemoteControl,&serviceStatus); if (SERVICE_STOPPED == serviceStatus.dwCurrentState) { StartService(hRemoteControl,0,NULL); } else { if (fActivate) { ControlService(hRemoteControl, SERVICE_CONTROL_CONTINUE, &serviceStatus); } } } else { WARNING_OUT(("Error starting RDS")); } } else { if (ConfPolicies::IsRDSDisabledOnWin9x()) { WARNING_OUT(("RDS launch disallowed by policy on Win9x")); } else { // Windows 95
HANDLE hServiceEvent = OpenEvent(EVENT_ALL_ACCESS, FALSE, SERVICE_CONTINUE_EVENT); if (hServiceEvent) // Service is running
{ if (fActivate) { SetEvent(hServiceEvent); } CloseHandle(hServiceEvent); } else { WinExec(WIN95_SERVICE_APP_NAME,SW_SHOWNORMAL); } } } }
|