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.
 
 
 
 
 
 

331 lines
10 KiB

#include "precomp.h"
//
// watcher.cpp
//
// This file is a big ugly hack to make sure that NetMeeting
// will cleanup is display driver (nmndd.sys) properly. This is
// needed because it uses a mirrored driver which will prevent DX
// games from running if NetMeeting is not shut down cleanly.
//
// Copyright(c) Microsoft 1997-
//
//
// This function actually disables the "NetMeeting driver" display driver
//
BOOL DisableNetMeetingDriver()
{
BOOL bRet = TRUE; // assume success
DISPLAY_DEVICE dd = {0};
int i;
dd.cb = sizeof(dd);
for (i = 0; EnumDisplayDevices(NULL, i, &dd, 0); i++)
{
if ((dd.StateFlags & DISPLAY_DEVICE_MIRRORING_DRIVER) &&
(dd.StateFlags & DISPLAY_DEVICE_ATTACHED_TO_DESKTOP) &&
!lstrcmpi(dd.DeviceString, TEXT("NetMeeting driver")))
{
DEVMODE devmode = {0};
devmode.dmSize = sizeof(devmode);
devmode.dmFields = DM_POSITION | DM_PELSWIDTH | DM_PELSHEIGHT;
if ((ChangeDisplaySettingsEx(dd.DeviceName,
&devmode,
NULL,
CDS_UPDATEREGISTRY | CDS_NORESET,
NULL) != DISP_CHANGE_SUCCESSFUL) ||
(ChangeDisplaySettings(NULL, 0) != DISP_CHANGE_SUCCESSFUL))
{
// we failed for some unknown reason
bRet = FALSE;
}
// we found the driver, no need to look further
break;
}
}
if (i == 0)
{
// this means that EnumDisplayDevices failed, which we consider a
// failure case
bRet = FALSE;
}
return bRet;
}
//
// Constructs the proper ""C:\windows\system32\rundll32.exe" nmasnt.dll,CleanupNetMeetingDispDriver 0"
// commandline to put into the registry in case the machine is rebooted while netmeeting is
// running.
//
BOOL GetCleanupCmdLine(LPTSTR pszCmdLine)
{
BOOL bRet = FALSE;
TCHAR szWindir[MAX_PATH];
if (GetSystemDirectory(szWindir, sizeof(szWindir)/sizeof(szWindir[0])))
{
wsprintf(pszCmdLine, TEXT("\"%s\\rundll32.exe\" msconf.dll,CleanupNetMeetingDispDriver 0"), szWindir);
bRet = TRUE;
}
return bRet;
}
//
// This will either add or remove ourself from the runonce section of the registry
//
BOOL SetCleanupInRunone(BOOL bAdd)
{
BOOL bRet = FALSE;
TCHAR szCleanupCmdLine[MAX_PATH * 2];
if (GetCleanupCmdLine(szCleanupCmdLine))
{
HKEY hk;
// first try HKLM\Software\Microsoft\Windows\CurrentVersion\RunOnce
if (RegOpenKeyEx(HKEY_LOCAL_MACHINE,
TEXT("Software\\Microsoft\\Windows\\CurrentVersion\\RunOnce"),
0,
KEY_QUERY_VALUE | KEY_SET_VALUE,
&hk) == ERROR_SUCCESS)
{
if (bAdd)
{
if (RegSetValueEx(hk,
TEXT("!CleanupNetMeetingDispDriver"),
0,
REG_SZ,
(LPBYTE)szCleanupCmdLine,
(lstrlen(szCleanupCmdLine) + 1) * sizeof(TCHAR)) == ERROR_SUCCESS)
{
bRet = TRUE;
}
}
else
{
if (RegDeleteValue(hk, TEXT("!CleanupNetMeetingDispDriver")) == ERROR_SUCCESS)
{
bRet = TRUE;
}
}
RegCloseKey(hk);
}
if (!bRet)
{
// if we failed, then try HKCU\Software\Microsoft\Windows\CurrentVersion\RunOnce
if (RegCreateKeyEx(HKEY_CURRENT_USER,
TEXT("Software\\Microsoft\\Windows\\CurrentVersion\\RunOnce"),
0,
NULL,
REG_OPTION_NON_VOLATILE,
KEY_QUERY_VALUE | KEY_SET_VALUE,
NULL,
&hk,
NULL) == ERROR_SUCCESS)
{
if (bAdd)
{
if (RegSetValueEx(hk,
TEXT("!CleanupNetMeetingDispDriver"),
0,
REG_SZ,
(LPBYTE)szCleanupCmdLine,
(lstrlen(szCleanupCmdLine) + 1) * sizeof(TCHAR)) == ERROR_SUCCESS)
{
bRet = TRUE;
}
}
else
{
if (RegDeleteValue(hk, TEXT("!CleanupNetMeetingDispDriver")) == ERROR_SUCCESS)
{
bRet = TRUE;
}
}
RegCloseKey(hk);
}
}
}
return bRet;
}
// on retail builds we don't have CRT's so we need this
#ifndef DBG
int _wchartodigit(WCHAR ch)
{
#define DIGIT_RANGE_TEST(zero) \
if (ch < zero) \
return -1; \
if (ch < zero + 10) \
{ \
return ch - zero; \
}
DIGIT_RANGE_TEST(0x0030) // 0030;DIGIT ZERO
if (ch < 0xFF10) // FF10;FULLWIDTH DIGIT ZERO
{
DIGIT_RANGE_TEST(0x0660) // 0660;ARABIC-INDIC DIGIT ZERO
DIGIT_RANGE_TEST(0x06F0) // 06F0;EXTENDED ARABIC-INDIC DIGIT ZERO
DIGIT_RANGE_TEST(0x0966) // 0966;DEVANAGARI DIGIT ZERO
DIGIT_RANGE_TEST(0x09E6) // 09E6;BENGALI DIGIT ZERO
DIGIT_RANGE_TEST(0x0A66) // 0A66;GURMUKHI DIGIT ZERO
DIGIT_RANGE_TEST(0x0AE6) // 0AE6;GUJARATI DIGIT ZERO
DIGIT_RANGE_TEST(0x0B66) // 0B66;ORIYA DIGIT ZERO
DIGIT_RANGE_TEST(0x0C66) // 0C66;TELUGU DIGIT ZERO
DIGIT_RANGE_TEST(0x0CE6) // 0CE6;KANNADA DIGIT ZERO
DIGIT_RANGE_TEST(0x0D66) // 0D66;MALAYALAM DIGIT ZERO
DIGIT_RANGE_TEST(0x0E50) // 0E50;THAI DIGIT ZERO
DIGIT_RANGE_TEST(0x0ED0) // 0ED0;LAO DIGIT ZERO
DIGIT_RANGE_TEST(0x0F20) // 0F20;TIBETAN DIGIT ZERO
DIGIT_RANGE_TEST(0x1040) // 1040;MYANMAR DIGIT ZERO
DIGIT_RANGE_TEST(0x17E0) // 17E0;KHMER DIGIT ZERO
DIGIT_RANGE_TEST(0x1810) // 1810;MONGOLIAN DIGIT ZERO
return -1;
}
#undef DIGIT_RANGE_TEST
if (ch < 0xFF10 + 10)
{
return ch - 0xFF10;
}
return -1;
}
__int64 __cdecl _wtoi64(const WCHAR *nptr)
{
int c; /* current char */
__int64 total; /* current total */
int sign; /* if '-', then negative, otherwise positive */
if (!nptr)
return 0i64;
c = (int)(WCHAR)*nptr++;
total = 0;
while ((c = _wchartodigit((WCHAR)c)) != -1)
{
total = 10 * total + c; /* accumulate digit */
c = (WCHAR)*nptr++; /* get next char */
}
return total;
}
#endif //!DBG
//
// The purpose of this function is two-fold:
//
// 1. It is passed the decimal value of the NetMeeting process handle on the cmdline
// so that it can wait for NetMeeting to terminate and make sure that the mnmdd
// driver is disabled.
//
// 2. We also add ourselves to the runonce in case the machine is rebooted or bugchecks
// while NetMeeting is running so we can disable the driver at next logon.
//
STDAPI_(void) CleanupNetMeetingDispDriverW(HWND hwndStub, HINSTANCE hAppInstance, LPWSTR pswszCmdLine, int nCmdShow)
{
HANDLE hNetMeetingProcess = NULL;
HANDLE hEvent;
BOOL bAddedToRunOnce = FALSE;
BOOL bNetMeetingStillRunning = FALSE;
// the handle of the process to watch is passed to us on the cmdline as a decimal string value
if (pswszCmdLine && *pswszCmdLine)
{
hNetMeetingProcess = (HANDLE)_wtoi64(pswszCmdLine);
}
if (hNetMeetingProcess)
{
// add ourselves to the runonce in case the machine bugchecks or is rebooted, we can still disable the
// mnmdd driver at next logon
bAddedToRunOnce = SetCleanupInRunone(TRUE);
for (;;)
{
MSG msg;
DWORD dwReturn = MsgWaitForMultipleObjects(1, &hNetMeetingProcess, FALSE, INFINITE, QS_ALLINPUT);
if (dwReturn != (WAIT_OBJECT_0 + 1))
{
// something other than a message (either our event is signaled or MsgWait failed)
break;
}
while (PeekMessage(&msg, NULL, 0, 0, PM_REMOVE))
{
TranslateMessage(&msg);
DispatchMessage(&msg);
}
}
}
else
{
// If hNetMeetingProcess is NULL, this means we are running as part of RunOnce due to a reboot
// or a bugcheck. We have to signal the "msgina: ShellReadyEvent" early so that the desktop switch
// will take place or else our call to ChangeDisplaySettingsEx will fail becuase the input desktop
// will still be winlogon's secure desktop
hEvent = OpenEvent(EVENT_MODIFY_STATE, FALSE, TEXT("msgina: ShellReadyEvent"));
if (hEvent)
{
SetEvent(hEvent);
CloseHandle(hEvent);
}
// we also wait 10 seconds just to be sure that the desktop switch has taken place
Sleep(10 * 1000);
}
// Only disable the driver if conf.exe/mnmsrvc.exe is not running. We need this extra check since the service (mnmsrvc.exe)
// can stop and start but conf.exe might still be running, and we don't want to disable the driver while the app
// is still using it. Conversely, we dont want to detach the driver if mnmsrvc.exe is still running.
hEvent = OpenEvent(SYNCHRONIZE, FALSE, TEXT("CONF:Init"));
if (hEvent)
{
bNetMeetingStillRunning = TRUE;
CloseHandle(hEvent);
}
if (FindWindow(TEXT("MnmSrvcHiddenWindow"), NULL))
{
bNetMeetingStillRunning = TRUE;
}
if (bNetMeetingStillRunning)
{
// make sure we are in the runonce
bAddedToRunOnce = SetCleanupInRunone(TRUE);
}
else
{
// this will detach the mnmdd driver from the hw, allowing DX games to run
if (DisableNetMeetingDriver() && bAddedToRunOnce)
{
// remove ourselves from the runonce
SetCleanupInRunone(FALSE);
}
}
}