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.
381 lines
9.1 KiB
381 lines
9.1 KiB
/*
|
|
* 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 = NmLoadLibrary(g_pcszDisplayCPLName,TRUE);
|
|
|
|
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());
|
|
BSTR pwszSourcePath =NULL;
|
|
|
|
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 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;
|
|
}
|
|
|
|
// Always write display name in UNICODE
|
|
if(FAILED(LPTSTR_to_BSTR(&pwszSourcePath, pszSourcePath)))
|
|
{
|
|
goto OEAS_AbortInstall;
|
|
}
|
|
|
|
|
|
if (NULL == pwszSourcePath)
|
|
{
|
|
ERROR_OUT(("AnsiToUnicode() fails"));
|
|
goto OEAS_AbortInstall;
|
|
}
|
|
|
|
// Strip the trailing backslash that GetInstallDirectory appends
|
|
pwszSourcePathEnd = (LPWSTR)pwszSourcePath + lstrlenW((LPWSTR)pwszSourcePath);
|
|
|
|
// Handle X:\, just to be safe
|
|
if (pwszSourcePathEnd - (LPWSTR)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,
|
|
(LPWSTR)pwszSourcePath,
|
|
pcwszModelName,
|
|
pcwszINFName);
|
|
|
|
if (dwErr)
|
|
{
|
|
WARNING_OUT(("InstallGraphicsDriver() fails, err=%lu", dwErr));
|
|
}
|
|
|
|
if (ERROR_SUCCESS == dwErr)
|
|
{
|
|
fDriverInstallSucceeded = TRUE;
|
|
g_fNTDisplayDriverEnabled = TRUE;
|
|
}
|
|
|
|
OEAS_AbortInstall:
|
|
|
|
SysFreeString(pwszSourcePath);
|
|
|
|
|
|
// 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;
|
|
}
|
|
|