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.

374 lines
8.6 KiB

  1. /*
  2. * SETUPDD.CPP
  3. *
  4. * The code to install the NM display driver for Windows NT. This was
  5. * a standalone application launched by Setup that we are now importing
  6. * into NM itself.
  7. *
  8. * Author:
  9. * dannygl, 05 Apr 97
  10. */
  11. #include "precomp.h"
  12. #include "conf.h"
  13. #include "confwnd.h"
  14. #include "resource.h"
  15. #include "setupdd.h"
  16. // String to identify the DLL and function that we need to call to install
  17. // the display driver on SP3.
  18. const TCHAR g_pcszDisplayCPLName[] = TEXT("DESK.CPL");
  19. const CHAR g_pcszInstallDriverAPIName[] = "InstallGraphicsDriver";
  20. const WCHAR g_pcwszDefaultModelName[] = L"Microsoft NetMeeting graphics driver";
  21. const WCHAR g_pcwszDefaultINFName[] = L"MNMDD.INF";
  22. // Maxmimum size of the model name string
  23. const int NAME_BUFFER_SIZE = 128;
  24. // Prototype for the function installed by the Display CPL
  25. typedef DWORD (*PFNINSTALLGRAPHICSDRIVER)(
  26. HWND hwnd,
  27. LPCWSTR pszSourceDirectory,
  28. LPCWSTR pszModel,
  29. LPCWSTR pszInf
  30. );
  31. /*
  32. * GetInstallDisplayDriverEntryPoint
  33. *
  34. * This function loads the DLL containing the display driver installation
  35. * code and retrieves the entry point for the installation function. It
  36. * is used by the below functions as a utility function.
  37. *
  38. * It returns TRUE if it is able to load the library and get the entry point,
  39. * FALSE if either operation fails. It is returns TRUE, it also returns the
  40. * DLL module handle and the function address.
  41. */
  42. BOOL
  43. GetInstallDisplayDriverEntryPoint(
  44. HMODULE *phInstallDDDll,
  45. PFNINSTALLGRAPHICSDRIVER *ppfnInstallDDFunction)
  46. {
  47. HMODULE hDll;
  48. PFNINSTALLGRAPHICSDRIVER pfn = NULL;
  49. ASSERT(NULL != phInstallDDDll
  50. && NULL != ppfnInstallDDFunction);
  51. hDll = LoadLibrary(g_pcszDisplayCPLName);
  52. if (NULL != hDll)
  53. {
  54. pfn = (PFNINSTALLGRAPHICSDRIVER)
  55. GetProcAddress(hDll,
  56. g_pcszInstallDriverAPIName);
  57. }
  58. // If the entry point exists, we pass it and the DLL handle back to
  59. // the caller. Otherwise, we unload the DLL immediately.
  60. if (NULL != pfn)
  61. {
  62. *phInstallDDDll = hDll;
  63. *ppfnInstallDDFunction = pfn;
  64. return TRUE;
  65. }
  66. else
  67. {
  68. if (NULL != hDll)
  69. {
  70. FreeLibrary(hDll);
  71. }
  72. return FALSE;
  73. }
  74. }
  75. /*
  76. * CanInstallNTDisplayDriver
  77. *
  78. * This function determines whether the entry point for installing the
  79. * NT display driver is availalble (i.e. NT 4.0 SP3 or later).
  80. */
  81. BOOL
  82. CanInstallNTDisplayDriver(void)
  83. {
  84. static BOOL fComputed = FALSE;
  85. static BOOL fRet = FALSE;
  86. ASSERT(::IsWindowsNT());
  87. // We verify that the major version number is exactly 4 and either
  88. // the minor version number is greater than 0 or the service pack
  89. // number (which is stored in the high byte of the low word of the
  90. // CSD version) is 3 or greater.
  91. if (! fComputed)
  92. {
  93. LPOSVERSIONINFO lposvi = GetVersionInfo();
  94. if (4 == lposvi->dwMajorVersion)
  95. {
  96. if (0 == lposvi->dwMinorVersion)
  97. {
  98. RegEntry re(NT_WINDOWS_SYSTEM_INFO_KEY, HKEY_LOCAL_MACHINE, FALSE);
  99. DWORD dwCSDVersion =
  100. re.GetNumber(REGVAL_NT_CSD_VERSION, 0);
  101. if (3 <= HIBYTE(LOWORD(dwCSDVersion)))
  102. {
  103. // This is NT 4.0, SP 3 or later
  104. fRet = TRUE;
  105. }
  106. }
  107. else
  108. {
  109. // We assume that any future version of Windows NT 4.x (x > 0)
  110. // will support this.
  111. fRet = TRUE;
  112. }
  113. }
  114. fComputed = TRUE;
  115. }
  116. ASSERT(fComputed);
  117. return fRet;
  118. }
  119. /*
  120. * OnEnableAppSharing
  121. *
  122. * Invoked when the "Enable Application Sharing" menu item is selected.
  123. *
  124. * This function determines whether the entry point for installing the
  125. * NT display driver is available. If so, it prompts the user to confirm
  126. * this operation, proceeds with the installation, and then prompts the
  127. * user to restart the computer.
  128. *
  129. * If not, it presents a text dialog with information about how to get
  130. * the necessary NT Service Pack(s).
  131. */
  132. void
  133. OnEnableAppSharing(
  134. HWND hWnd)
  135. {
  136. ASSERT(::IsWindowsNT());
  137. USES_CONVERSION;
  138. if (::CanInstallNTDisplayDriver())
  139. {
  140. // Confirm the installation with the user
  141. if (IDYES == ::ConfMsgBox(
  142. hWnd,
  143. (LPCTSTR) IDS_ENABLEAPPSHARING_INSTALL_CONFIRM,
  144. MB_YESNO | MB_ICONQUESTION))
  145. {
  146. BOOL fDriverInstallSucceeded = FALSE;
  147. HMODULE hDisplayCPL = NULL;
  148. PFNINSTALLGRAPHICSDRIVER pfnInstallGraphicsDriver;
  149. TCHAR pszSourcePath[MAX_PATH];
  150. LPWSTR pwszSourcePath = NULL;
  151. LPWSTR pwszSourcePathEnd;
  152. WCHAR pwszModelNameBuffer[NAME_BUFFER_SIZE];
  153. LPCWSTR pcwszModelName;
  154. WCHAR pwszINFNameBuffer[MAX_PATH];
  155. LPCWSTR pcwszINFName;
  156. // Get the entry point for display driver installation
  157. if (! ::GetInstallDisplayDriverEntryPoint(
  158. &hDisplayCPL,
  159. &pfnInstallGraphicsDriver))
  160. {
  161. ERROR_OUT(("GetInstallDisplayDriverEntryPoint() fails"));
  162. goto OEAS_AbortInstall;
  163. }
  164. // The driver files are located in the NM directory.
  165. if (! ::GetInstallDirectory(pszSourcePath))
  166. {
  167. ERROR_OUT(("GetInstallDirectory() fails"));
  168. goto OEAS_AbortInstall;
  169. }
  170. // Convert the install directory to Unicode, if necessary
  171. pwszSourcePath = T2W(pszSourcePath);
  172. if (NULL == pwszSourcePath)
  173. {
  174. ERROR_OUT(("AnsiToUnicode() fails"));
  175. goto OEAS_AbortInstall;
  176. }
  177. // Strip the trailing backslash that GetInstallDirectory appends
  178. pwszSourcePathEnd = pwszSourcePath + lstrlenW(pwszSourcePath);
  179. // Handle X:\, just to be safe
  180. if (pwszSourcePathEnd - pwszSourcePath > 3)
  181. {
  182. ASSERT(L'\\' == *(pwszSourcePathEnd - 1));
  183. *--pwszSourcePathEnd = L'\0';
  184. }
  185. // Read the model name string from the resource file
  186. if (0 < ::LoadStringW(GetInstanceHandle(),
  187. IDS_NMDD_DISPLAYNAME,
  188. pwszModelNameBuffer,
  189. CCHMAX(pwszModelNameBuffer)))
  190. {
  191. pcwszModelName = pwszModelNameBuffer;
  192. }
  193. else
  194. {
  195. ERROR_OUT(("LoadStringW() fails, err=%lu", GetLastError()));
  196. pcwszModelName = g_pcwszDefaultModelName;
  197. }
  198. // Read the INF name string from the resource file
  199. if (0 < ::LoadStringW(GetInstanceHandle(),
  200. IDS_NMDD_INFNAME,
  201. pwszINFNameBuffer,
  202. CCHMAX(pwszINFNameBuffer)))
  203. {
  204. pcwszINFName = pwszINFNameBuffer;
  205. }
  206. else
  207. {
  208. ERROR_OUT(("LoadStringW() fails, err=%lu", GetLastError()));
  209. pcwszINFName = g_pcwszDefaultINFName;
  210. }
  211. // Now we're set to call the actual installation function
  212. DWORD dwErr;
  213. dwErr = (*pfnInstallGraphicsDriver)(hWnd,
  214. pwszSourcePath,
  215. pcwszModelName,
  216. pcwszINFName);
  217. if (dwErr)
  218. {
  219. WARNING_OUT(("InstallGraphicsDriver() fails, err=%lu", dwErr));
  220. }
  221. if (ERROR_SUCCESS == dwErr)
  222. {
  223. fDriverInstallSucceeded = TRUE;
  224. g_fNTDisplayDriverEnabled = TRUE;
  225. }
  226. OEAS_AbortInstall:
  227. // If we failed to install the driver, we report an error.
  228. // If we succeeded, we prompt the user to restart the system.
  229. if (! fDriverInstallSucceeded)
  230. {
  231. ::ConfMsgBox(
  232. hWnd,
  233. (LPCTSTR) IDS_ENABLEAPPSHARING_INSTALL_FAILURE,
  234. MB_OK | MB_ICONERROR);
  235. }
  236. else if (IDYES == ::ConfMsgBox(
  237. hWnd,
  238. (LPCTSTR) IDS_ENABLEAPPSHARING_INSTALL_COMPLETE,
  239. MB_YESNO | MB_ICONQUESTION))
  240. {
  241. // Initiate a system restart. This involves getting the
  242. // necessary privileges first.
  243. HANDLE hToken;
  244. TOKEN_PRIVILEGES tkp;
  245. BOOL fRet;
  246. // Get the current process token handle so we can get shutdown
  247. // privilege.
  248. fRet = OpenProcessToken(
  249. GetCurrentProcess(),
  250. TOKEN_ADJUST_PRIVILEGES | TOKEN_QUERY,
  251. &hToken);
  252. // Get the LUID for shutdown privilege.
  253. if (fRet)
  254. {
  255. fRet = LookupPrivilegeValue(
  256. NULL,
  257. SE_SHUTDOWN_NAME,
  258. &tkp.Privileges[0].Luid);
  259. }
  260. else
  261. {
  262. hToken = NULL;
  263. WARNING_OUT(("OpenProcessToken() fails (error %lu)", GetLastError()));
  264. }
  265. // Get shutdown privilege for this process.
  266. if (fRet)
  267. {
  268. tkp.PrivilegeCount = 1;
  269. tkp.Privileges[0].Attributes = SE_PRIVILEGE_ENABLED;
  270. fRet = AdjustTokenPrivileges(
  271. hToken,
  272. FALSE,
  273. &tkp,
  274. 0,
  275. (PTOKEN_PRIVILEGES) NULL,
  276. 0);
  277. // Special-case scenario where call succeeds but not all
  278. // privileges were set.
  279. if (fRet && ERROR_SUCCESS != GetLastError())
  280. {
  281. fRet = FALSE;
  282. }
  283. }
  284. else
  285. {
  286. WARNING_OUT(("LookupPrivilegeValue() fails (error %lu)", GetLastError()));
  287. }
  288. if (! fRet)
  289. {
  290. WARNING_OUT(("AdjustTokenPrivileges() fails (error %lu)", GetLastError()));
  291. }
  292. if (NULL != hToken)
  293. {
  294. CloseHandle(hToken);
  295. }
  296. if (! ::ExitWindowsEx(EWX_REBOOT, 0))
  297. {
  298. WARNING_OUT(("ExitWindowsEx() fails (error %lu)", GetLastError()));
  299. }
  300. }
  301. if (NULL != hDisplayCPL)
  302. {
  303. FreeLibrary(hDisplayCPL);
  304. }
  305. }
  306. }
  307. else
  308. {
  309. // Tell the user how to get the SP
  310. ::ConfMsgBox(
  311. hWnd,
  312. (LPCTSTR) IDS_ENABLEAPPSHARING_NEEDNTSP);
  313. }
  314. return;
  315. }