|
|
#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); } } }
|