/* * SETUPDD.CPP * * The code to install the NM display driver for Windows NT. This was * a standalone application launched by Setup that we are now importing * into NM itself. * * Author: * dannygl, 05 Apr 97 */ #include "precomp.h" #include "conf.h" #include "confwnd.h" #include "resource.h" #include "setupdd.h" // String to identify the DLL and function that we need to call to install // the display driver on SP3. const TCHAR g_pcszDisplayCPLName[] = TEXT("DESK.CPL"); const CHAR g_pcszInstallDriverAPIName[] = "InstallGraphicsDriver"; const WCHAR g_pcwszDefaultModelName[] = L"Microsoft NetMeeting graphics driver"; const WCHAR g_pcwszDefaultINFName[] = L"MNMDD.INF"; // Maxmimum size of the model name string const int NAME_BUFFER_SIZE = 128; // Prototype for the function installed by the Display CPL typedef DWORD (*PFNINSTALLGRAPHICSDRIVER)( HWND hwnd, LPCWSTR pszSourceDirectory, LPCWSTR pszModel, LPCWSTR pszInf ); /* * GetInstallDisplayDriverEntryPoint * * This function loads the DLL containing the display driver installation * code and retrieves the entry point for the installation function. It * is used by the below functions as a utility function. * * It returns TRUE if it is able to load the library and get the entry point, * FALSE if either operation fails. It is returns TRUE, it also returns the * DLL module handle and the function address. */ BOOL GetInstallDisplayDriverEntryPoint( HMODULE *phInstallDDDll, PFNINSTALLGRAPHICSDRIVER *ppfnInstallDDFunction) { HMODULE hDll; PFNINSTALLGRAPHICSDRIVER pfn = NULL; ASSERT(NULL != phInstallDDDll && NULL != ppfnInstallDDFunction); hDll = LoadLibrary(g_pcszDisplayCPLName); if (NULL != hDll) { pfn = (PFNINSTALLGRAPHICSDRIVER) GetProcAddress(hDll, g_pcszInstallDriverAPIName); } // If the entry point exists, we pass it and the DLL handle back to // the caller. Otherwise, we unload the DLL immediately. if (NULL != pfn) { *phInstallDDDll = hDll; *ppfnInstallDDFunction = pfn; return TRUE; } else { if (NULL != hDll) { FreeLibrary(hDll); } return FALSE; } } /* * CanInstallNTDisplayDriver * * This function determines whether the entry point for installing the * NT display driver is availalble (i.e. NT 4.0 SP3 or later). */ BOOL CanInstallNTDisplayDriver(void) { static BOOL fComputed = FALSE; static BOOL fRet = FALSE; ASSERT(::IsWindowsNT()); // We verify that the major version number is exactly 4 and either // the minor version number is greater than 0 or the service pack // number (which is stored in the high byte of the low word of the // CSD version) is 3 or greater. if (! fComputed) { LPOSVERSIONINFO lposvi = GetVersionInfo(); if (4 == lposvi->dwMajorVersion) { if (0 == lposvi->dwMinorVersion) { RegEntry re(NT_WINDOWS_SYSTEM_INFO_KEY, HKEY_LOCAL_MACHINE, FALSE); DWORD dwCSDVersion = re.GetNumber(REGVAL_NT_CSD_VERSION, 0); if (3 <= HIBYTE(LOWORD(dwCSDVersion))) { // This is NT 4.0, SP 3 or later fRet = TRUE; } } else { // We assume that any future version of Windows NT 4.x (x > 0) // will support this. fRet = TRUE; } } fComputed = TRUE; } ASSERT(fComputed); return fRet; } /* * OnEnableAppSharing * * Invoked when the "Enable Application Sharing" menu item is selected. * * This function determines whether the entry point for installing the * NT display driver is available. If so, it prompts the user to confirm * this operation, proceeds with the installation, and then prompts the * user to restart the computer. * * If not, it presents a text dialog with information about how to get * the necessary NT Service Pack(s). */ void OnEnableAppSharing( HWND hWnd) { ASSERT(::IsWindowsNT()); USES_CONVERSION; if (::CanInstallNTDisplayDriver()) { // Confirm the installation with the user if (IDYES == ::ConfMsgBox( hWnd, (LPCTSTR) IDS_ENABLEAPPSHARING_INSTALL_CONFIRM, MB_YESNO | MB_ICONQUESTION)) { BOOL fDriverInstallSucceeded = FALSE; HMODULE hDisplayCPL = NULL; PFNINSTALLGRAPHICSDRIVER pfnInstallGraphicsDriver; TCHAR pszSourcePath[MAX_PATH]; LPWSTR pwszSourcePath = NULL; LPWSTR pwszSourcePathEnd; WCHAR pwszModelNameBuffer[NAME_BUFFER_SIZE]; LPCWSTR pcwszModelName; WCHAR pwszINFNameBuffer[MAX_PATH]; LPCWSTR pcwszINFName; // Get the entry point for display driver installation if (! ::GetInstallDisplayDriverEntryPoint( &hDisplayCPL, &pfnInstallGraphicsDriver)) { ERROR_OUT(("GetInstallDisplayDriverEntryPoint() fails")); goto OEAS_AbortInstall; } // The driver files are located in the NM directory. if (! ::GetInstallDirectory(pszSourcePath)) { ERROR_OUT(("GetInstallDirectory() fails")); goto OEAS_AbortInstall; } // Convert the install directory to Unicode, if necessary pwszSourcePath = T2W(pszSourcePath); if (NULL == pwszSourcePath) { ERROR_OUT(("AnsiToUnicode() fails")); goto OEAS_AbortInstall; } // Strip the trailing backslash that GetInstallDirectory appends pwszSourcePathEnd = pwszSourcePath + lstrlenW(pwszSourcePath); // Handle X:\, just to be safe if (pwszSourcePathEnd - pwszSourcePath > 3) { ASSERT(L'\\' == *(pwszSourcePathEnd - 1)); *--pwszSourcePathEnd = L'\0'; } // Read the model name string from the resource file if (0 < ::LoadStringW(GetInstanceHandle(), IDS_NMDD_DISPLAYNAME, pwszModelNameBuffer, CCHMAX(pwszModelNameBuffer))) { pcwszModelName = pwszModelNameBuffer; } else { ERROR_OUT(("LoadStringW() fails, err=%lu", GetLastError())); pcwszModelName = g_pcwszDefaultModelName; } // Read the INF name string from the resource file if (0 < ::LoadStringW(GetInstanceHandle(), IDS_NMDD_INFNAME, pwszINFNameBuffer, CCHMAX(pwszINFNameBuffer))) { pcwszINFName = pwszINFNameBuffer; } else { ERROR_OUT(("LoadStringW() fails, err=%lu", GetLastError())); pcwszINFName = g_pcwszDefaultINFName; } // Now we're set to call the actual installation function DWORD dwErr; dwErr = (*pfnInstallGraphicsDriver)(hWnd, pwszSourcePath, pcwszModelName, pcwszINFName); if (dwErr) { WARNING_OUT(("InstallGraphicsDriver() fails, err=%lu", dwErr)); } if (ERROR_SUCCESS == dwErr) { fDriverInstallSucceeded = TRUE; g_fNTDisplayDriverEnabled = TRUE; } OEAS_AbortInstall: // If we failed to install the driver, we report an error. // If we succeeded, we prompt the user to restart the system. if (! fDriverInstallSucceeded) { ::ConfMsgBox( hWnd, (LPCTSTR) IDS_ENABLEAPPSHARING_INSTALL_FAILURE, MB_OK | MB_ICONERROR); } else if (IDYES == ::ConfMsgBox( hWnd, (LPCTSTR) IDS_ENABLEAPPSHARING_INSTALL_COMPLETE, MB_YESNO | MB_ICONQUESTION)) { // Initiate a system restart. This involves getting the // necessary privileges first. HANDLE hToken; TOKEN_PRIVILEGES tkp; BOOL fRet; // Get the current process token handle so we can get shutdown // privilege. fRet = OpenProcessToken( GetCurrentProcess(), TOKEN_ADJUST_PRIVILEGES | TOKEN_QUERY, &hToken); // Get the LUID for shutdown privilege. if (fRet) { fRet = LookupPrivilegeValue( NULL, SE_SHUTDOWN_NAME, &tkp.Privileges[0].Luid); } else { hToken = NULL; WARNING_OUT(("OpenProcessToken() fails (error %lu)", GetLastError())); } // Get shutdown privilege for this process. if (fRet) { tkp.PrivilegeCount = 1; tkp.Privileges[0].Attributes = SE_PRIVILEGE_ENABLED; fRet = AdjustTokenPrivileges( hToken, FALSE, &tkp, 0, (PTOKEN_PRIVILEGES) NULL, 0); // Special-case scenario where call succeeds but not all // privileges were set. if (fRet && ERROR_SUCCESS != GetLastError()) { fRet = FALSE; } } else { WARNING_OUT(("LookupPrivilegeValue() fails (error %lu)", GetLastError())); } if (! fRet) { WARNING_OUT(("AdjustTokenPrivileges() fails (error %lu)", GetLastError())); } if (NULL != hToken) { CloseHandle(hToken); } if (! ::ExitWindowsEx(EWX_REBOOT, 0)) { WARNING_OUT(("ExitWindowsEx() fails (error %lu)", GetLastError())); } } if (NULL != hDisplayCPL) { FreeLibrary(hDisplayCPL); } } } else { // Tell the user how to get the SP ::ConfMsgBox( hWnd, (LPCTSTR) IDS_ENABLEAPPSHARING_NEEDNTSP); } return; }