Leaked source code of windows server 2003
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

333 lines
11 KiB

  1. #include "precomp.h"
  2. //
  3. // watcher.cpp
  4. //
  5. // This file is a big ugly hack to make sure that NetMeeting
  6. // will cleanup is display driver (nmndd.sys) properly. This is
  7. // needed because it uses a mirrored driver which will prevent DX
  8. // games from running if NetMeeting is not shut down cleanly.
  9. //
  10. // Copyright(c) Microsoft 1997-
  11. //
  12. //
  13. // This function actually disables the "NetMeeting driver" display driver
  14. //
  15. BOOL DisableNetMeetingDriver()
  16. {
  17. BOOL bRet = TRUE; // assume success
  18. DISPLAY_DEVICE dd = {0};
  19. int i;
  20. dd.cb = sizeof(dd);
  21. for (i = 0; EnumDisplayDevices(NULL, i, &dd, 0); i++)
  22. {
  23. if ((dd.StateFlags & DISPLAY_DEVICE_MIRRORING_DRIVER) &&
  24. (dd.StateFlags & DISPLAY_DEVICE_ATTACHED_TO_DESKTOP) &&
  25. !lstrcmpi(dd.DeviceString, TEXT("NetMeeting driver")))
  26. {
  27. DEVMODE devmode = {0};
  28. devmode.dmSize = sizeof(devmode);
  29. devmode.dmFields = DM_POSITION | DM_PELSWIDTH | DM_PELSHEIGHT;
  30. if ((ChangeDisplaySettingsEx(dd.DeviceName,
  31. &devmode,
  32. NULL,
  33. CDS_UPDATEREGISTRY | CDS_NORESET,
  34. NULL) != DISP_CHANGE_SUCCESSFUL) ||
  35. (ChangeDisplaySettings(NULL, 0) != DISP_CHANGE_SUCCESSFUL))
  36. {
  37. // we failed for some unknown reason
  38. bRet = FALSE;
  39. }
  40. // we found the driver, no need to look further
  41. break;
  42. }
  43. }
  44. if (i == 0)
  45. {
  46. // this means that EnumDisplayDevices failed, which we consider a
  47. // failure case
  48. bRet = FALSE;
  49. }
  50. return bRet;
  51. }
  52. //
  53. // Constructs the proper ""C:\windows\system32\rundll32.exe" nmasnt.dll,CleanupNetMeetingDispDriver 0"
  54. // commandline to put into the registry in case the machine is rebooted while netmeeting is
  55. // running.
  56. //
  57. BOOL GetCleanupCmdLine(LPTSTR pszCmdLine)
  58. {
  59. BOOL bRet = FALSE;
  60. TCHAR szWindir[MAX_PATH];
  61. if (GetSystemDirectory(szWindir, sizeof(szWindir)/sizeof(szWindir[0])))
  62. {
  63. wsprintf(pszCmdLine, TEXT("\"%s\\rundll32.exe\" msconf.dll,CleanupNetMeetingDispDriver 0"), szWindir);
  64. bRet = TRUE;
  65. }
  66. return bRet;
  67. }
  68. //
  69. // This will either add or remove ourself from the runonce section of the registry
  70. //
  71. BOOL SetCleanupInRunone(BOOL bAdd)
  72. {
  73. BOOL bRet = FALSE;
  74. TCHAR szCleanupCmdLine[MAX_PATH * 2];
  75. if (GetCleanupCmdLine(szCleanupCmdLine))
  76. {
  77. HKEY hk;
  78. // first try HKLM\Software\Microsoft\Windows\CurrentVersion\RunOnce
  79. if (RegOpenKeyEx(HKEY_LOCAL_MACHINE,
  80. TEXT("Software\\Microsoft\\Windows\\CurrentVersion\\RunOnce"),
  81. 0,
  82. KEY_QUERY_VALUE | KEY_SET_VALUE,
  83. &hk) == ERROR_SUCCESS)
  84. {
  85. if (bAdd)
  86. {
  87. if (RegSetValueEx(hk,
  88. TEXT("!CleanupNetMeetingDispDriver"),
  89. 0,
  90. REG_SZ,
  91. (LPBYTE)szCleanupCmdLine,
  92. (lstrlen(szCleanupCmdLine) + 1) * sizeof(TCHAR)) == ERROR_SUCCESS)
  93. {
  94. bRet = TRUE;
  95. }
  96. }
  97. else
  98. {
  99. if (RegDeleteValue(hk, TEXT("!CleanupNetMeetingDispDriver")) == ERROR_SUCCESS)
  100. {
  101. bRet = TRUE;
  102. }
  103. }
  104. RegCloseKey(hk);
  105. }
  106. if (!bRet)
  107. {
  108. // if we failed, then try HKCU\Software\Microsoft\Windows\CurrentVersion\RunOnce
  109. if (RegCreateKeyEx(HKEY_CURRENT_USER,
  110. TEXT("Software\\Microsoft\\Windows\\CurrentVersion\\RunOnce"),
  111. 0,
  112. NULL,
  113. REG_OPTION_NON_VOLATILE,
  114. KEY_QUERY_VALUE | KEY_SET_VALUE,
  115. NULL,
  116. &hk,
  117. NULL) == ERROR_SUCCESS)
  118. {
  119. if (bAdd)
  120. {
  121. if (RegSetValueEx(hk,
  122. TEXT("!CleanupNetMeetingDispDriver"),
  123. 0,
  124. REG_SZ,
  125. (LPBYTE)szCleanupCmdLine,
  126. (lstrlen(szCleanupCmdLine) + 1) * sizeof(TCHAR)) == ERROR_SUCCESS)
  127. {
  128. bRet = TRUE;
  129. }
  130. }
  131. else
  132. {
  133. if (RegDeleteValue(hk, TEXT("!CleanupNetMeetingDispDriver")) == ERROR_SUCCESS)
  134. {
  135. bRet = TRUE;
  136. }
  137. }
  138. RegCloseKey(hk);
  139. }
  140. }
  141. }
  142. return bRet;
  143. }
  144. // on retail builds we don't have CRT's so we need this
  145. #if 0
  146. #ifndef DBG
  147. int _wchartodigit(WCHAR ch)
  148. {
  149. #define DIGIT_RANGE_TEST(zero) \
  150. if (ch < zero) \
  151. return -1; \
  152. if (ch < zero + 10) \
  153. { \
  154. return ch - zero; \
  155. }
  156. DIGIT_RANGE_TEST(0x0030) // 0030;DIGIT ZERO
  157. if (ch < 0xFF10) // FF10;FULLWIDTH DIGIT ZERO
  158. {
  159. DIGIT_RANGE_TEST(0x0660) // 0660;ARABIC-INDIC DIGIT ZERO
  160. DIGIT_RANGE_TEST(0x06F0) // 06F0;EXTENDED ARABIC-INDIC DIGIT ZERO
  161. DIGIT_RANGE_TEST(0x0966) // 0966;DEVANAGARI DIGIT ZERO
  162. DIGIT_RANGE_TEST(0x09E6) // 09E6;BENGALI DIGIT ZERO
  163. DIGIT_RANGE_TEST(0x0A66) // 0A66;GURMUKHI DIGIT ZERO
  164. DIGIT_RANGE_TEST(0x0AE6) // 0AE6;GUJARATI DIGIT ZERO
  165. DIGIT_RANGE_TEST(0x0B66) // 0B66;ORIYA DIGIT ZERO
  166. DIGIT_RANGE_TEST(0x0C66) // 0C66;TELUGU DIGIT ZERO
  167. DIGIT_RANGE_TEST(0x0CE6) // 0CE6;KANNADA DIGIT ZERO
  168. DIGIT_RANGE_TEST(0x0D66) // 0D66;MALAYALAM DIGIT ZERO
  169. DIGIT_RANGE_TEST(0x0E50) // 0E50;THAI DIGIT ZERO
  170. DIGIT_RANGE_TEST(0x0ED0) // 0ED0;LAO DIGIT ZERO
  171. DIGIT_RANGE_TEST(0x0F20) // 0F20;TIBETAN DIGIT ZERO
  172. DIGIT_RANGE_TEST(0x1040) // 1040;MYANMAR DIGIT ZERO
  173. DIGIT_RANGE_TEST(0x17E0) // 17E0;KHMER DIGIT ZERO
  174. DIGIT_RANGE_TEST(0x1810) // 1810;MONGOLIAN DIGIT ZERO
  175. return -1;
  176. }
  177. #undef DIGIT_RANGE_TEST
  178. if (ch < 0xFF10 + 10)
  179. {
  180. return ch - 0xFF10;
  181. }
  182. return -1;
  183. }
  184. __int64 __cdecl _wtoi64(const WCHAR *nptr)
  185. {
  186. int c; /* current char */
  187. __int64 total; /* current total */
  188. int sign; /* if '-', then negative, otherwise positive */
  189. if (!nptr)
  190. return 0i64;
  191. c = (int)(WCHAR)*nptr++;
  192. total = 0;
  193. while ((c = _wchartodigit((WCHAR)c)) != -1)
  194. {
  195. total = 10 * total + c; /* accumulate digit */
  196. c = (WCHAR)*nptr++; /* get next char */
  197. }
  198. return total;
  199. }
  200. #endif //!DBG
  201. #endif // 0
  202. //
  203. // The purpose of this function is two-fold:
  204. //
  205. // 1. It is passed the decimal value of the NetMeeting process handle on the cmdline
  206. // so that it can wait for NetMeeting to terminate and make sure that the mnmdd
  207. // driver is disabled.
  208. //
  209. // 2. We also add ourselves to the runonce in case the machine is rebooted or bugchecks
  210. // while NetMeeting is running so we can disable the driver at next logon.
  211. //
  212. STDAPI_(void) CleanupNetMeetingDispDriverW(HWND hwndStub, HINSTANCE hAppInstance, LPWSTR pswszCmdLine, int nCmdShow)
  213. {
  214. HANDLE hNetMeetingProcess = NULL;
  215. HANDLE hEvent;
  216. BOOL bAddedToRunOnce = FALSE;
  217. BOOL bNetMeetingStillRunning = FALSE;
  218. // the handle of the process to watch is passed to us on the cmdline as a decimal string value
  219. if (pswszCmdLine && *pswszCmdLine)
  220. {
  221. hNetMeetingProcess = (HANDLE)_wtoi64(pswszCmdLine);
  222. }
  223. if (hNetMeetingProcess)
  224. {
  225. // add ourselves to the runonce in case the machine bugchecks or is rebooted, we can still disable the
  226. // mnmdd driver at next logon
  227. bAddedToRunOnce = SetCleanupInRunone(TRUE);
  228. for (;;)
  229. {
  230. MSG msg;
  231. DWORD dwReturn = MsgWaitForMultipleObjects(1, &hNetMeetingProcess, FALSE, INFINITE, QS_ALLINPUT);
  232. if (dwReturn != (WAIT_OBJECT_0 + 1))
  233. {
  234. // something other than a message (either our event is signaled or MsgWait failed)
  235. break;
  236. }
  237. while (PeekMessage(&msg, NULL, 0, 0, PM_REMOVE))
  238. {
  239. TranslateMessage(&msg);
  240. DispatchMessage(&msg);
  241. }
  242. }
  243. }
  244. else
  245. {
  246. // If hNetMeetingProcess is NULL, this means we are running as part of RunOnce due to a reboot
  247. // or a bugcheck. We have to signal the "msgina: ShellReadyEvent" early so that the desktop switch
  248. // will take place or else our call to ChangeDisplaySettingsEx will fail becuase the input desktop
  249. // will still be winlogon's secure desktop
  250. hEvent = OpenEvent(EVENT_MODIFY_STATE, FALSE, TEXT("msgina: ShellReadyEvent"));
  251. if (hEvent)
  252. {
  253. SetEvent(hEvent);
  254. CloseHandle(hEvent);
  255. }
  256. // we also wait 10 seconds just to be sure that the desktop switch has taken place
  257. Sleep(10 * 1000);
  258. }
  259. // Only disable the driver if conf.exe/mnmsrvc.exe is not running. We need this extra check since the service (mnmsrvc.exe)
  260. // can stop and start but conf.exe might still be running, and we don't want to disable the driver while the app
  261. // is still using it. Conversely, we dont want to detach the driver if mnmsrvc.exe is still running.
  262. hEvent = OpenEvent(SYNCHRONIZE, FALSE, TEXT("CONF:Init"));
  263. if (hEvent)
  264. {
  265. bNetMeetingStillRunning = TRUE;
  266. CloseHandle(hEvent);
  267. }
  268. if (FindWindow(TEXT("MnmSrvcHiddenWindow"), NULL))
  269. {
  270. bNetMeetingStillRunning = TRUE;
  271. }
  272. if (bNetMeetingStillRunning)
  273. {
  274. // make sure we are in the runonce
  275. bAddedToRunOnce = SetCleanupInRunone(TRUE);
  276. }
  277. else
  278. {
  279. // this will detach the mnmdd driver from the hw, allowing DX games to run
  280. if (DisableNetMeetingDriver() && bAddedToRunOnce)
  281. {
  282. // remove ourselves from the runonce
  283. SetCleanupInRunone(FALSE);
  284. }
  285. }
  286. }