windows-nt/Source/XPSP1/NT/base/ntsetup/oobe/common/util.cpp
2020-09-26 16:20:57 +08:00

1024 lines
23 KiB
C++

//*********************************************************************
//* Microsoft Windows **
//* Copyright(c) Microsoft Corp., 1999 **
//*********************************************************************
//
// UTIL.CPP - utilities
//
// HISTORY:
//
// 1/27/99 a-jaswed Created.
//
// Common utilities for printing out messages
#include <nt.h>
#include <ntrtl.h>
#include <nturtl.h>
#include <objbase.h>
#include <stdio.h>
#include <stdlib.h>
#include <stdarg.h>
#include "util.h"
#include "appdefs.h"
#include <shlwapi.h>
#include <shlobj.h>
#include <shfolder.h>
#include <wchar.h>
#include <winsvcp.h> // for SC_OOBE_MACHINE_NAME_DONE
///////////////////////////////////////////////////////////
// Print out the COM/OLE error string for an HRESULT.
//
void ErrorMessage(LPCWSTR message, HRESULT hr)
{
const WCHAR* sz ;
if (message == NULL)
{
sz = L"The following error occured." ;
}
else
{
sz = message ;
}
void* pMsgBuf;
::FormatMessage(
FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM,
NULL,
hr,
MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), // Default language
(LPWSTR) &pMsgBuf,
0,
NULL
);
WCHAR buf[256] ;
wsprintf(buf, L"%s\r\nError: (%x) - %s", sz, hr, (LPWSTR)pMsgBuf) ;
MessageBox(NULL, buf, L"Utility Error Message Box.", MB_OK) ;
// Free the buffer.
LocalFree( pMsgBuf );
}
////////////////////////////////////////////////////////////
// Check to see if both interfaces are on the same component.
//
BOOL InterfacesAreOnSameComponent(IUnknown* p1, IUnknown* p2)
{
HRESULT hr = S_OK ;
// Get the real IUnknown for the first interface.
IUnknown* pReal1 = NULL ;
hr = p1->QueryInterface(IID_IUnknown, (void**)&pReal1) ;
assert(SUCCEEDED(hr)) ;
// Get the real IUnknown for the second interface.
IUnknown* pReal2 = NULL ;
hr = p2->QueryInterface(IID_IUnknown, (void**)&pReal2) ;
assert(SUCCEEDED(hr)) ;
// Compare the IUnknown pointers.
BOOL bReturn = (pReal1 == pReal2) ;
// Cleanup
pReal1->Release() ;
pReal2->Release() ;
// Return the value.
return bReturn;
}
///////////////////////////////////////////////////////////
// IsValidAddress
//
BOOL IsValidAddress(const void* lp, UINT nBytes, BOOL bReadWrite)
{
return (lp != NULL && !::IsBadReadPtr(lp, nBytes) &&
(!bReadWrite || !::IsBadWritePtr((LPVOID)lp, nBytes)));
}
///////////////////////////////////////////////////////////
// MyDebug
//
#if ASSERTS_ON
VOID
AssertFail(
IN PSTR FileName,
IN UINT LineNumber,
IN PSTR Condition
)
{
int i;
CHAR Name[MAX_PATH];
PCHAR p;
CHAR Msg[4096];
//
// Use dll name as caption
//
GetModuleFileNameA(NULL,Name,MAX_PATH);
if(p = strrchr(Name,'\\')) {
p++;
} else {
p = Name;
}
wsprintfA(
Msg,
"Assertion failure at line %u in file %s: %s%s",
LineNumber,
FileName,
Condition,
"\n\nCall DebugBreak()?"
);
i = MessageBoxA(
NULL,
Msg,
p,
MB_YESNO | MB_TASKMODAL | MB_ICONSTOP | MB_SETFOREGROUND
);
if(i == IDYES) {
DebugBreak();
}
}
#endif
///////////////////////////////////////////////////////////
// Trace
//
void __cdecl MyTrace(LPCWSTR lpszFormat, ...)
{
USES_CONVERSION;
va_list args;
va_start(args, lpszFormat);
int nBuf;
WCHAR szBuffer[512];
nBuf = _vsnwprintf(szBuffer, MAX_CHARS_IN_BUFFER(szBuffer), lpszFormat, args);
// was there an error? was the expanded string too long?
assert(nBuf > 0);
#if DBG
DbgPrintEx( DPFLTR_SETUP_ID, DPFLTR_INFO_LEVEL, W2A(szBuffer) );
#endif
va_end(args);
}
//BUGBUG need bettter default
bool GetString(HINSTANCE hInstance, UINT uiID, LPWSTR szString, UINT uiStringLen)
{
// BUGBUG: Should this assume current module if hInstance is NULL??
MYASSERT(NULL != hInstance);
if (NULL != hInstance)
return (0 < LoadString(hInstance, uiID, szString, uiStringLen));
else
return (false);
}
// the goal of this function is to be able to able to get to
// c:\windows dir\system dir\oobe\oobeinfo.ini
// c:\windows dir\system dir\oeminfo.ini
// c:\windows dir\oemaudit.oem
// the canonicalize allows the specification for oemaudit.oem to be ..\oemaudit.oem
bool GetCanonicalizedPath(LPWSTR szCompletePath, LPCWSTR szFileName)
{
if (0 < GetSystemDirectory(szCompletePath, MAX_PATH))
{
lstrcat(szCompletePath, szFileName);
WCHAR szLocal[MAX_PATH];
lstrcpy(szLocal, szCompletePath);
return PathCanonicalize(szCompletePath, (LPCWSTR) szLocal) ? true : false;
}
return false;
}
bool GetOOBEPath(LPWSTR szOOBEPath)
{
if (0 < GetSystemDirectory(szOOBEPath, MAX_PATH))
{
lstrcat(szOOBEPath, L"\\OOBE");
return true;
}
return false;
}
// This returns the path for the localized OOBE files on a system with MUI.
//
bool GetOOBEMUIPath(LPWSTR szOOBEPath)
{
LANGID UILang;
WCHAR szMUIPath[MAX_PATH];
if (GetOOBEPath(szOOBEPath))
{
UILang = GetUserDefaultUILanguage();
if ( UILang != GetSystemDefaultUILanguage() ) {
wsprintf( szMUIPath, L"\\MUI\\%04x", UILang );
lstrcat(szOOBEPath, szMUIPath );
}
return true;
}
return false;
}
HRESULT GetINIKey(HINSTANCE hInstance, LPCWSTR szINIFileName, UINT uiSectionName, UINT uiKeyName, LPVARIANT pvResult)
{
WCHAR szSectionName[MAX_PATH], szKeyName[MAX_PATH];
WCHAR szItem[1024]; //bugbug bad constant
if (GetString(hInstance, uiSectionName, szSectionName) && GetString(hInstance, uiKeyName, szKeyName))
{
WCHAR szINIPath[MAX_PATH];
if (GetCanonicalizedPath(szINIPath, szINIFileName))
{
if (VT_I4 == V_VT(pvResult))
{
V_I4(pvResult) = GetPrivateProfileInt(szSectionName, szKeyName, 0, szINIPath);
return S_OK;
}
else
{
if (GetPrivateProfileString(
szSectionName,
szKeyName,
L"",
szItem,
MAX_CHARS_IN_BUFFER(szItem),
szINIPath))
{
V_BSTR(pvResult) = SysAllocString(szItem);
return S_OK;
}
}
}
}
if (VT_BSTR == V_VT(pvResult))
V_BSTR(pvResult) = SysAllocString(L"\0");
else
V_I4(pvResult) = 0;
return S_OK;
}
HRESULT GetINIKeyBSTR(HINSTANCE hInstance, LPCWSTR szINIFileName, UINT uiSectionName, UINT uiKeyName, LPVARIANT pvResult)
{
VariantInit(pvResult);
V_VT(pvResult) = VT_BSTR;
return (GetINIKey(hInstance, szINIFileName, uiSectionName, uiKeyName, pvResult));
}
HRESULT GetINIKeyUINT(HINSTANCE hInstance, LPCWSTR szINIFileName, UINT uiSectionName, UINT uiKeyName, LPVARIANT pvResult)
{
VariantInit(pvResult);
V_VT(pvResult) = VT_I4;
return (GetINIKey(hInstance, szINIFileName, uiSectionName, uiKeyName, pvResult));
}
HRESULT SetINIKey(HINSTANCE hInstance, LPCWSTR szINIFileName, UINT uiSectionName, UINT uiKeyName, LPVARIANT pvResult)
{
WCHAR szSectionName[MAX_PATH], szKeyName[MAX_PATH];
VariantInit(pvResult);
V_VT(pvResult) = VT_BSTR;
if (GetString(hInstance, uiSectionName, szSectionName) && GetString(hInstance, uiKeyName, szKeyName))
{
if (WritePrivateProfileString(V_BSTR(pvResult), szKeyName,
V_BSTR(pvResult), szINIFileName))
{
return S_OK;
}
}
return E_FAIL;
}
void WINAPI URLEncode(WCHAR* pszUrl, size_t bsize)
{
if (!pszUrl)
return;
WCHAR* pszEncode = NULL;
WCHAR* pszEStart = NULL;
WCHAR* pszEEnd = (WCHAR*)wmemchr( pszUrl, L'\0', bsize );
int iUrlLen = (int)(pszEEnd-pszUrl);
pszEEnd = pszUrl;
WCHAR c;
size_t cch = (iUrlLen+1) * sizeof(WCHAR) * 3;
assert( cch <= bsize );
if (cch <= bsize)
{
pszEncode = (WCHAR*)malloc(BYTES_REQUIRED_BY_CCH(cch));
if(pszEncode)
{
pszEStart = pszEncode;
ZeroMemory(pszEncode, BYTES_REQUIRED_BY_CCH(cch));
for(; c = *(pszUrl); pszUrl++)
{
switch(c)
{
case L' ': //SPACE
memcpy(pszEncode, L"+", 1*sizeof(WCHAR));
pszEncode+=1;
break;
case L'#':
memcpy(pszEncode, L"%23", 3*sizeof(WCHAR));
pszEncode+=3;
break;
case L'&':
memcpy(pszEncode, L"%26", 3*sizeof(WCHAR));
pszEncode+=3;
break;
case L'%':
memcpy(pszEncode, L"%25", 3*sizeof(WCHAR));
pszEncode+=3;
break;
case L'=':
memcpy(pszEncode, L"%3D", 3*sizeof(WCHAR));
pszEncode+=3;
break;
case L'<':
memcpy(pszEncode, L"%3C", 3*sizeof(WCHAR));
pszEncode+=3;
break;
case L'+':
memcpy(pszEncode, L"%2B", 3*sizeof(WCHAR));
pszEncode += 3;
break;
default:
*pszEncode++ = c;
break;
}
}
*pszEncode++ = L'\0';
memcpy(pszEEnd ,pszEStart, (size_t)(pszEncode - pszEStart));
free(pszEStart);
}
}
}
//BUGBUG: Need to turn spaces into "+"
void WINAPI URLAppendQueryPair
(
LPWSTR lpszQuery,
LPWSTR lpszName,
LPWSTR lpszValue OPTIONAL
)
{
// Append the Name
lstrcat(lpszQuery, lpszName);
lstrcat(lpszQuery, cszEquals);
// Append the Value
if ( lpszValue ) {
lstrcat(lpszQuery, lpszValue);
}
// Append an Ampersand if this is NOT the last pair
lstrcat(lpszQuery, cszAmpersand);
}
void GetCmdLineToken(LPWSTR *ppszCmd, LPWSTR pszOut)
{
LPWSTR c;
int i = 0;
BOOL fInQuote = FALSE;
c = *ppszCmd;
pszOut[0] = *c;
if (!*c)
return;
if (*c == L' ')
{
pszOut[1] = L'\0';
*ppszCmd = c+1;
return;
}
else if( L'"' == *c )
{
fInQuote = TRUE;
}
NextChar:
i++;
c++;
if( !*c || (!fInQuote && (*c == L' ')) )
{
pszOut[i] = L'\0';
*ppszCmd = c;
return;
}
else if( fInQuote && (*c == L'"') )
{
fInQuote = FALSE;
pszOut[i] = *c;
i++;
c++;
pszOut[i] = L'\0';
*ppszCmd = c;
return;
}
else
{
pszOut[i] = *c;
goto NextChar;
}
}
BOOL IsOEMDebugMode()
{
HKEY hKey = NULL;
DWORD dwIsDebug = 0;
DWORD dwSize = sizeof(dwIsDebug);
if(RegOpenKeyEx(HKEY_LOCAL_MACHINE,
OOBE_MAIN_REG_KEY,
0,
KEY_QUERY_VALUE,
&hKey) == ERROR_SUCCESS)
{
RegQueryValueEx(hKey,
OOBE_OEMDEBUG_REG_VAL,
0,
NULL,
(LPBYTE)&dwIsDebug,
&dwSize);
RegCloseKey(hKey);
}
#ifdef DEBUG
return (BOOL)1;
#else
return (BOOL)dwIsDebug;
#endif
}
VOID
PumpMessageQueue(
VOID
)
{
MSG msg;
while(PeekMessage(&msg, NULL, 0,0,PM_REMOVE)) {
DispatchMessage(&msg);
}
}
BOOL
IsThreadActive(
HANDLE hThread
)
{
DWORD dwExitCode = 0;
return (NULL != hThread
&& GetExitCodeThread(hThread, &dwExitCode)
&& STILL_ACTIVE == dwExitCode
);
}
void GetDesktopDirectory(WCHAR* pszPath)
{
WCHAR pszFolder[MAX_PATH];
*pszFolder = L'\0';
HRESULT hRet = SHGetFolderPath(NULL, CSIDL_COMMON_DESKTOPDIRECTORY,
NULL, 0, pszFolder
);
if (S_OK != hRet)
{
hRet = SHGetFolderPath(NULL, CSIDL_DESKTOPDIRECTORY,
NULL, 0, pszFolder
);
}
if (S_OK == hRet)
{
lstrcpy(pszPath , pszFolder);
}
}
void RemoveDesktopShortCut
(
LPWSTR lpszShortcutName
)
{
WCHAR szShortcutPath[MAX_PATH] = L"\0";
GetDesktopDirectory(szShortcutPath);
if(szShortcutPath[0] != L'\0')
{
lstrcat(szShortcutPath, L"\\");
lstrcat(szShortcutPath, lpszShortcutName);
lstrcat(szShortcutPath, L".LNK");
DeleteFile(szShortcutPath);
}
}
BOOL
InvokeExternalApplication(
IN PCWSTR ApplicationName, OPTIONAL
IN PCWSTR CommandLine,
IN OUT PDWORD ExitCode OPTIONAL
)
/*++
Routine Description:
Invokes an external program, which is optionally detached.
Arguments:
ApplicationName - supplies app name. May be a partial or full path,
or just a filename, in which case the standard win32 path search
is performed. If not specified then the first element in
CommandLine must specify the binary to execute.
CommandLine - supplies the command line to be passed to the
application.
ExitCode - If specified, the execution is synchronous and this value
receives the exit code of the application. If not specified,
the execution is asynchronous.
Return Value:
Boolean value indicating whether the process was started successfully.
--*/
{
PWSTR FullCommandLine;
BOOL b;
PROCESS_INFORMATION ProcessInfo;
STARTUPINFO StartupInfo;
DWORD d;
b = FALSE;
//
// Form the command line to be passed to CreateProcess.
//
if(ApplicationName) {
FullCommandLine =
(PWSTR) malloc(BYTES_REQUIRED_BY_SZ(ApplicationName)+BYTES_REQUIRED_BY_SZ(CommandLine)+BYTES_REQUIRED_BY_CCH(2));
if(!FullCommandLine) {
goto err0;
}
lstrcpy(FullCommandLine, ApplicationName);
lstrcat(FullCommandLine, L" ");
lstrcat(FullCommandLine, CommandLine);
} else {
FullCommandLine =
(PWSTR) malloc(BYTES_REQUIRED_BY_SZ(CommandLine));
if(!FullCommandLine) {
goto err0;
}
lstrcpy(FullCommandLine, CommandLine);
}
//
// Initialize startup info.
//
ZeroMemory(&StartupInfo, sizeof(STARTUPINFO));
StartupInfo.cb = sizeof(STARTUPINFO);
//
// Create the process.
//
b = CreateProcess(
NULL,
FullCommandLine,
NULL,
NULL,
FALSE,
ExitCode ? 0 : DETACHED_PROCESS,
NULL,
NULL,
&StartupInfo,
&ProcessInfo
);
if(!b) {
goto err1;
}
//
// If execution is asynchronus, we're done.
//
if(!ExitCode) {
goto err2;
}
err2:
CloseHandle(ProcessInfo.hThread);
CloseHandle(ProcessInfo.hProcess);
err1:
free(FullCommandLine);
err0:
return(b);
}
//////////////////////////////////////////////////////////////////////////////
//
// InSafeMode
//
// Determine whether the system is running in safe mode or clean mode.
//
// parameters:
// None.
//
// returns:
// TRUE if the system was booted in safe mode
// FALSE if the system was booted in clean mode
//
//////////////////////////////////////////////////////////////////////////////
BOOL
InSafeMode()
{
if (BOOT_CLEAN != GetSystemMetrics(SM_CLEANBOOT))
{
TRACE(L"Running in SAFEMODE...\n");
return TRUE;
}
return FALSE;
} // InSafeMode
// Signal winlogon that the computer name has been changed. WinLogon waits to
// start services that depend on the computer name until this event is
// signalled.
//
BOOL
SignalComputerNameChangeComplete()
{
BOOL fReturn = TRUE;
// Open event with EVENT_ALL_ACCESS so that synchronization and state
// change can be done.
//
HANDLE hevent = OpenEvent(EVENT_ALL_ACCESS,
FALSE,
SC_OOBE_MACHINE_NAME_DONE
);
// It is not fatal for OpenEvent to fail: this synchronization is only
// required when OOBE will be run in OEM mode.
//
if (NULL != hevent)
{
if (! SetEvent(hevent))
{
// It is fatal to open but not set the event: services.exe will not
// continue until this event is signalled.
//
TRACE2(L"Failed to signal SC_OOBE_MACHINE_NAME_DONE(%s): 0x%08X\n",
SC_OOBE_MACHINE_NAME_DONE, GetLastError());
fReturn = FALSE;
}
MYASSERT(fReturn); // Why did we fail to set an open event??
}
return fReturn;
}
BOOL
IsUserAdmin(
VOID
)
/*++
Routine Description:
This routine returns TRUE if the caller's process is a
member of the Administrators local group.
Caller is NOT expected to be impersonating anyone and IS
expected to be able to open their own process and process
token.
Arguments:
None.
Return Value:
TRUE - Caller has Administrators local group.
FALSE - Caller does not have Administrators local group.
--*/
{
HANDLE Token;
DWORD BytesRequired;
PTOKEN_GROUPS Groups;
BOOL b;
DWORD i;
SID_IDENTIFIER_AUTHORITY NtAuthority = SECURITY_NT_AUTHORITY;
PSID AdministratorsGroup;
//
// Open the process token.
//
if(!OpenProcessToken(GetCurrentProcess(),TOKEN_QUERY,&Token)) {
return(FALSE);
}
b = FALSE;
Groups = NULL;
//
// Get group information.
//
if(!GetTokenInformation(Token,TokenGroups,NULL,0,&BytesRequired)
&& (GetLastError() == ERROR_INSUFFICIENT_BUFFER)
&& (Groups = (PTOKEN_GROUPS)LocalAlloc(LPTR,BytesRequired))
&& GetTokenInformation(Token,TokenGroups,Groups,BytesRequired,&BytesRequired)) {
b = AllocateAndInitializeSid(
&NtAuthority,
2,
SECURITY_BUILTIN_DOMAIN_RID,
DOMAIN_ALIAS_RID_ADMINS,
0, 0, 0, 0, 0, 0,
&AdministratorsGroup
);
if(b) {
//
// See if the user has the administrator group.
//
b = FALSE;
for(i=0; i<Groups->GroupCount; i++) {
if(EqualSid(Groups->Groups[i].Sid,AdministratorsGroup)) {
b = TRUE;
break;
}
}
FreeSid(AdministratorsGroup);
}
}
//
// Clean up and return.
//
if(Groups) {
LocalFree((HLOCAL)Groups);
}
CloseHandle(Token);
return(b);
}
#define MyMalloc(s) GlobalAlloc(GPTR, s)
#define MyFree(p) GlobalFree(p)
static LPTSTR
pDuplicateString(
LPCTSTR szText
)
{
int cchText;
LPTSTR szOutText;
if (szText == NULL)
{
return NULL;
}
cchText = lstrlen(szText);
szOutText = (LPTSTR) MyMalloc(sizeof(TCHAR) * (cchText + 1));
if (szOutText)
{
lstrcpyn(szOutText, szText, cchText + 1);
}
return szOutText;
}
PSTRINGLIST
CreateStringCell (
IN PCTSTR String
)
{
PSTRINGLIST p = (PSTRINGLIST) MyMalloc (sizeof (STRINGLIST));
if (p) {
ZeroMemory (p, sizeof (STRINGLIST));
if (String) {
p->String = pDuplicateString (String);
if (!p->String) {
MyFree (p);
p = NULL;
}
} else {
p->String = NULL;
}
}
return p;
}
VOID
DeleteStringCell (
IN PSTRINGLIST Cell
)
{
if (Cell) {
MyFree (Cell->String);
MyFree (Cell);
}
}
BOOL
InsertList (
IN OUT PSTRINGLIST* List,
IN PSTRINGLIST NewList
)
{
PSTRINGLIST p;
if (!NewList) {
return FALSE;
}
if (*List) {
for (p = *List; p->Next; p = p->Next) ;
p->Next = NewList;
} else {
*List = NewList;
}
return TRUE;
}
VOID
DestroyList (
IN PSTRINGLIST List
)
{
PSTRINGLIST p, q;
for (p = List; p; p = q) {
q = p->Next;
DeleteStringCell (p);
}
}
BOOL
RemoveListI(
IN OUT PSTRINGLIST* List,
IN PCTSTR String
)
{
PSTRINGLIST p = *List;
BOOL b = FALSE;
if (p)
{
if (!lstrcmpi(p->String, String))
{
*List = p->Next;
DeleteStringCell(p);
b = TRUE;
}
else
{
PSTRINGLIST q;
for (q = p->Next; q; p = q, q = q->Next)
{
if (!lstrcmpi(q->String, String))
{
p->Next = q->Next;
DeleteStringCell(q);
b = TRUE;
break;
}
}
}
}
return b;
}
BOOL
ExistInListI(
IN PSTRINGLIST List,
IN PCTSTR String
)
{
PSTRINGLIST p;
for (p = List; p; p = p->Next)
{
if (!lstrcmpi(p->String, String))
{
break;
}
}
return (p != NULL);
}
BOOL IsDriveNTFS(IN TCHAR Drive)
{
TCHAR DriveName[4];
TCHAR Filesystem[256];
TCHAR VolumeName[MAX_PATH];
DWORD SerialNumber;
DWORD MaxComponent;
DWORD Flags;
BOOL bIsNTFS = FALSE;
DriveName[0] = Drive;
DriveName[1] = TEXT(':');
DriveName[2] = TEXT('\\');
DriveName[3] = 0;
if (GetVolumeInformation(
DriveName,
VolumeName,MAX_PATH,
&SerialNumber,
&MaxComponent,
&Flags,
Filesystem,
sizeof(Filesystem)/sizeof(TCHAR)
))
{
bIsNTFS = (lstrcmpi(Filesystem,TEXT("NTFS")) == 0);
}
return bIsNTFS;
}
BOOL
HasTablet()
{
TCHAR szPath[MAX_PATH+1];
ZeroMemory(szPath, sizeof(szPath));
if (FAILED(SHGetFolderPath(
NULL,
CSIDL_PROGRAM_FILES_COMMON,
NULL,
SHGFP_TYPE_DEFAULT,
szPath)))
{
return FALSE;
}
StrCatBuff(szPath, TEXT("\\Microsoft Shared\\Ink\\tabtip.exe"), MAX_PATH+1);
return PathFileExists(szPath);
}