Windows-Server-2003/base/pnp/setupapi/dll.c

2329 lines
55 KiB
C

/*++
Copyright (c) Microsoft Corporation. All rights reserved.
Module Name:
dll.c
Abstract:
Initialization/de-initialization of setupapi.dll
Author:
Lonny McMichael (lonnym) 10-May-1995
Revision History:
Jamie Hunter (JamieHun) Apr-25-2002
Security code review
--*/
#include "precomp.h"
#pragma hdrstop
HANDLE MyDllModuleHandle;
OSVERSIONINFOEX OSVersionInfo;
//
// TLS Data
//
DWORD TlsIndex = (DWORD)(-1); // no data
PSETUP_TLS pLastTlsAlloc = NULL; // for cleanup
//
// Static strings we retreive once. Listed in order they are retrieved
//
PCTSTR OsLoaderRelativePath = NULL; // (can be NULL)
PCTSTR OsSystemPartitionRoot = NULL; // eg: \\?\GLOBALROOT\Device\HarddiskVolume1
PCTSTR ProcessFileName = NULL; // Filename of app calling setupapi
PCTSTR WindowsDirectory = NULL; // %windir%, GetSystemWindowsDirectory()
PCTSTR InfDirectory = NULL; // %windir%\INF
PCTSTR System16Directory = NULL; // %windir%\SYSTEM
PCTSTR LastGoodDirectory = NULL; // %windir%\LastGood
PCTSTR SystemDirectory = NULL; // <sys>, %windir%\SYSTEM or %windir%\System32
PCTSTR WindowsBackupDirectory = NULL; // <sys>\ReinstallBackups
PCTSTR ConfigDirectory = NULL; // <sys>\CONFIG
PCTSTR DriversDirectory = NULL; // <sys>\DRIVERS
PCTSTR SystemSourcePath = NULL; // location system installed from
PCTSTR ServicePackSourcePath = NULL; // location service pack installed from (can be NULL)
PCTSTR ServicePackCachePath = NULL; // location service pack files are cached
PCTSTR DriverCacheSourcePath = NULL; // location of driver cache (can be NULL)
BOOL GuiSetupInProgress = FALSE; // set if we determine we're in GUI setup
PCTSTR InfSearchPaths = NULL; // Multi-sz list of fully-qualified directories where INFs are to be searched for.
#ifndef _WIN64
BOOL IsWow64 = FALSE; // set if we're running under WOW64
#endif
CRITICAL_SECTION InitMutex; // for one-time initializations
CRITICAL_SECTION ImageHlpMutex; // for dealing with IMAGEHLP library
CRITICAL_SECTION DelayedComponentMutex; // for any delayed initialization of certain components
CRITICAL_SECTION PlatformPathOverrideCritSect;
CRITICAL_SECTION LogUseCountCs;
CRITICAL_SECTION MruCritSect;
CRITICAL_SECTION NetConnectionListCritSect;
BOOL InInitialization = FALSE;
DWORD DoneInitialization = 0; // bitmask of items we've initialized
DWORD DoneCleanup = 0; // bitmask of items we've cleaned up
DWORD DoneComponentInitialize = 0; // bitmask of components we've done delayed initialization
DWORD FailedComponentInitialize = 0; // bitmask of components we've failed initialization
HANDLE GlobalNoDriverPromptsEventFlag = NULL; // event that acts as a flag during setup
INT DoneCriticalSections = 0;
DWORD Seed;
CRITICAL_SECTION * CriticalSectionList[] = {
&InitMutex,
&ImageHlpMutex,
&DelayedComponentMutex,
&PlatformPathOverrideCritSect,
&LogUseCountCs,
&MruCritSect,
&NetConnectionListCritSect,
NULL
};
#define DONEINIT_TLS (0x0000001)
#define DONEINIT_UTILS (0x0000002)
#define DONEINIT_MEM (0x0000004)
#define DONEINIT_CTRL (0x0000008)
#define DONEINIT_FUSION (0x0000010)
#define DONEINIT_STUBS (0x0000020)
#define DONEINIT_COMMON (0x0000040)
#define DONEINIT_DIAMOND (0x0000080)
#define DONEINIT_LOGGING (0x0000100)
#define DONEINIT_CFGMGR32 (0x0000200)
#define DONEINIT_COMPLETE (0x8000000)
//
// various control flags
//
DWORD GlobalSetupFlags = 0;
DWORD GlobalSetupFlagsOverride = PSPGF_MINIMAL_EMBEDDED | PSPGF_NO_SCE_EMBEDDED; // flags that cannot be modified
//
// Declare a (non-CONST) array of strings that specifies what lines to look for
// in an INF's [ControlFlags] section when determining whether a particular device
// ID should be excluded. These lines are of the form "ExcludeFromSelect[.<suffix>]",
// where <suffix> is determined and filled in during process attach as an optimization.
//
// The max string length (including NULL) is 32, and there can be a maximum of 3
// such strings. E.g.: ExcludeFromSelect, ExcludeFromSelect.NT, ExcludeFromSelect.NTAmd64
//
// WARNING!! Be very careful when mucking with the order/number of these entries. Check
// the assumptions made in devdrv.c!pSetupShouldDevBeExcluded.
//
TCHAR pszExcludeFromSelectList[3][32] = { INFSTR_KEY_EXCLUDEFROMSELECT,
INFSTR_KEY_EXCLUDEFROMSELECT,
INFSTR_KEY_EXCLUDEFROMSELECT
};
DWORD ExcludeFromSelectListUb; // contains the number of strings in the above list (2 or 3).
#ifndef _WIN64
BOOL
GetIsWow64 (
VOID
);
#endif
BOOL
CommonProcessAttach(
IN BOOL Attach
);
PCTSTR
GetDriverCacheSourcePath(
VOID
);
PCTSTR
pSetupGetOsLoaderPath(
VOID
);
PCTSTR
pSetupGetSystemPartitionRoot(
VOID
);
PCTSTR
pSetupGetProcessPath(
VOID
);
BOOL
pGetGuiSetupInProgress(
VOID
);
BOOL
CfgmgrEntry(
PVOID hModule,
ULONG Reason,
PCONTEXT pContext
);
BOOL
ThreadTlsInitialize(
IN BOOL Init
);
VOID
ThreadTlsCleanup(
);
BOOL
IsNoDriverPrompts(
VOID
);
DWORD
GetEmbeddedFlags(
VOID
);
DWORD
GetSeed(
VOID
);
BOOL
ProcessAttach(
IN HANDLE DllHandle,
IN DWORD Reason,
IN LPVOID Reserved
)
/*++
Routine Description:
Handles DLL_PROCESS_ATTACH in a way that can be unwound
Arguments:
Reserved = 'Reserved' value passed into DllMain
Return Value:
TRUE if processed initialized
FALSE if partially/not initialized
--*/
{
BOOL b = FALSE;
if(DoneCleanup) {
//
// if we get here, this means someone lied to us
//
MYASSERT(!DoneCleanup);
DoneInitialization &= ~DoneCleanup;
DoneCleanup = 0;
}
//
// nothing should already be initialized
//
MYASSERT(!DoneInitialization);
try {
MyDllModuleHandle = DllHandle;
//
// initialize TLS before anything else - hence why we use LocalAlloc
//
TlsIndex = TlsAlloc();
if (TlsIndex!=(DWORD)(-1)) {
DoneInitialization |= DONEINIT_TLS;
} else {
leave;
}
//
// always do pSetupInitializeUtils and MemoryInitializeEx first
// (pSetupInitializeUtils sets up memory functions)
//
if(pSetupInitializeUtils()) {
DoneInitialization |= DONEINIT_UTILS;
} else {
leave;
}
if(MemoryInitializeEx(TRUE)) {
DoneInitialization |= DONEINIT_MEM;
} else {
leave;
}
if(spFusionInitialize()) {
DoneInitialization |= DONEINIT_FUSION;
}
//
// Dynamically load proc addresses of NT-specific APIs
// must be before CommonProcessAttach etc
// however memory must be initialized
//
InitializeStubFnPtrs();
DoneInitialization |= DONEINIT_STUBS;
//
// most of the remaining initialization
//
if(CommonProcessAttach(TRUE)) {
DoneInitialization |= DONEINIT_COMMON;
} else {
leave;
}
if(DiamondProcessAttach(TRUE)) {
DoneInitialization |= DONEINIT_DIAMOND;
} else {
leave;
}
if(InitializeContextLogging(TRUE)) {
DoneInitialization |= DONEINIT_LOGGING;
} else {
leave;
}
//
// Since we've incorporated cfgmgr32 into setupapi, we need
// to make sure it gets initialized just like it did when it was
// its own DLL. - must do AFTER everything else
//
if(CfgmgrEntry(DllHandle, Reason, Reserved)) {
DoneInitialization |= DONEINIT_CFGMGR32;
}
DoneInitialization |= DONEINIT_COMPLETE;
b = TRUE;
} except(EXCEPTION_EXECUTE_HANDLER) {
}
return b;
}
void
DestroySetupTlsData(
)
/*++
Routine Description:
Destroy all TLS data from every thread
calling any cleanup routines as required
Arguments:
NONE
Return Value:
NONE
--*/
{
PSETUP_TLS pTLS;
if(pLastTlsAlloc) {
pLastTlsAlloc->Prev->Next = NULL;
while(pLastTlsAlloc) {
pTLS = pLastTlsAlloc;
pLastTlsAlloc = pTLS->Next;
TlsSetValue(TlsIndex,pTLS); // switch specific data into this thread
ThreadTlsCleanup();
LocalFree(pTLS);
}
}
TlsSetValue(TlsIndex,NULL); // don't leave invalid pointer hanging around
}
void
ProcessDetach(
IN HANDLE DllHandle,
IN DWORD Reason,
IN LPVOID Reserved
)
/*++
Routine Description:
Handles DLL_PROCESS_DETACH
Arguments:
Reserved = 'Reserved' value passed into DllMain
Which is actually TRUE for Process Exit, FALSE otherwise
Return Value:
None
--*/
{
DWORD ToCleanup = DoneInitialization & ~ DoneCleanup;
if(!ToCleanup) {
//
// nothing to cleanup
//
return;
}
try {
if (ToCleanup & DONEINIT_COMPLETE) {
DoneCleanup |= DONEINIT_COMPLETE;
}
if(DoneInitialization & DONEINIT_TLS) {
//
// cleanup all remaining Tls data
//
if(!Reserved) {
//
// only do this for FreeLibrary/ failed LoadLibrary
//
DestroySetupTlsData();
}
}
if(ToCleanup & DONEINIT_TLS) {
//
// destroy our allocated TLS index
// do this now so that we don't try allocating
// TLS storage during this cleanup
//
TlsFree(TlsIndex);
TlsIndex = (DWORD)(-1);
DoneCleanup |= DONEINIT_TLS;
}
//
// do things generally in reverse order of ProcessAttach
//
// Since we've incorporated cfgmgr32 into setupapi, we need
// to make sure it gets uninitialized just like it did when it was
// its own DLL. - must do BEFORE anything else
//
if(ToCleanup & DONEINIT_CFGMGR32) {
CfgmgrEntry(DllHandle, Reason, Reserved);
DoneCleanup |= DONEINIT_CFGMGR32;
}
if(ToCleanup & DONEINIT_DIAMOND) {
DiamondProcessAttach(FALSE);
DoneCleanup |= DONEINIT_DIAMOND;
}
#if 0 // see ComponentCleanup at end of file
ComponentCleanup(DoneComponentInitialize);
#endif
if(ToCleanup & DONEINIT_FUSION) {
//
// Fusion cleanup
// only do full if this is FreeLibrary (or failed attach)
//
spFusionUninitialize((Reserved == NULL) ? TRUE : FALSE);
DoneCleanup |= DONEINIT_FUSION;
}
if(ToCleanup & DONEINIT_COMMON) {
//
// Most of remaining cleanup
//
CommonProcessAttach(FALSE);
DoneCleanup |= DONEINIT_COMMON;
}
if(ToCleanup & DONEINIT_STUBS) {
//
// Clean up stub functions
//
CleanUpStubFns();
DoneCleanup |= DONEINIT_STUBS;
}
if(ToCleanup & DONEINIT_LOGGING) {
//
// Clean up context logging
//
InitializeContextLogging(FALSE);
DoneCleanup |= DONEINIT_LOGGING;
}
//
// *THESE MUST ALWAYS BE* very last things, in this order
//
if(ToCleanup & DONEINIT_MEM) {
//
// Clean up context logging
//
MemoryInitializeEx(FALSE);
DoneCleanup |= DONEINIT_MEM;
}
if(ToCleanup & DONEINIT_UTILS) {
//
// Clean up context logging
//
pSetupUninitializeUtils();
DoneCleanup |= DONEINIT_UTILS;
}
} except(EXCEPTION_EXECUTE_HANDLER) {
}
}
//
// Called by CRT when _DllMainCRTStartup is the DLL entry point
//
BOOL
WINAPI
DllMain(
IN HANDLE DllHandle,
IN DWORD Reason,
IN LPVOID Reserved
)
{
BOOL b;
InInitialization = TRUE;
b = TRUE;
switch(Reason) {
case DLL_PROCESS_ATTACH:
b = ProcessAttach(DllHandle,Reason,Reserved);
if(!b) {
ProcessDetach(DllHandle,DLL_THREAD_DETACH,NULL);
}
break;
case DLL_THREAD_ATTACH:
//
// don't do anything here
// any TLS must be done on demand
// via SetupGetTlsData
//
break;
case DLL_PROCESS_DETACH:
//
// any TLS cleanup must be done in ThreadTlsCleanup
//
ProcessDetach(DllHandle,Reason,Reserved);
break;
case DLL_THREAD_DETACH:
ThreadTlsInitialize(FALSE);
break;
}
InInitialization = FALSE;
return(b);
}
PSETUP_TLS
SetupGetTlsData(
)
/*++
Routine Description:
Called to obtain a pointer to TLS data
Arguments:
NONE
Return Value:
Pointer to TLS data, or NULL
--*/
{
PSETUP_TLS pTLS;
if (TlsIndex==(DWORD)(-1)) {
return NULL;
}
pTLS = (PSETUP_TLS)TlsGetValue(TlsIndex);
if (!pTLS) {
ThreadTlsInitialize(TRUE);
pTLS = (PSETUP_TLS)TlsGetValue(TlsIndex);
}
return pTLS;
}
VOID
ThreadTlsCleanup(
)
/*++
Routine Description:
Called to uninitialize some pTLS data
might be a different thread to initialize
but SetupAPI TLS data will have been switched in
Arguments:
pTLS - data to cleanup
Return Value:
NONE.
--*/
{
DiamondTlsInit(FALSE);
ContextLoggingTlsInit(FALSE);
}
BOOL
ThreadTlsUnlink(
IN PSETUP_TLS pTLS
)
{
BOOL b;
try {
EnterCriticalSection(&InitMutex);
if(pTLS->Next == pTLS->Prev) {
pLastTlsAlloc = NULL;
} else {
pTLS->Prev->Next = pTLS->Next;
pTLS->Next->Prev = pTLS->Prev;
pLastTlsAlloc = pTLS->Prev; // anything but pTLS
}
LeaveCriticalSection(&InitMutex);
b = TRUE;
} except(EXCEPTION_EXECUTE_HANDLER) {
b = FALSE;
}
return b;
}
PSETUP_TLS
ThreadTlsCreate(
)
/*++
Routine Description:
Called to create pTLS data for this thread
Arguments:
NONE
Return Value:
per-thread data, or NULL on failure
--*/
{
BOOL b;
PSETUP_TLS pTLS;
if (TlsIndex==(DWORD)(-1)) {
return NULL;
}
pTLS = (PSETUP_TLS)LocalAlloc(LMEM_ZEROINIT,sizeof(SETUP_TLS));
if(!pTLS) {
return NULL;
}
b = TlsSetValue(TlsIndex,pTLS);
if(!b) {
LocalFree(pTLS);
return NULL;
}
try {
EnterCriticalSection(&InitMutex);
if(pLastTlsAlloc) {
pTLS->Prev = pLastTlsAlloc;
pTLS->Next = pTLS->Prev->Next;
pTLS->Prev->Next = pTLS;
pTLS->Next->Prev = pTLS;
} else {
pTLS->Next = pTLS;
pTLS->Prev = pTLS;
}
pLastTlsAlloc = pTLS;
LeaveCriticalSection(&InitMutex);
b = TRUE;
} except(EXCEPTION_EXECUTE_HANDLER) {
b = FALSE;
}
if(!b) {
LocalFree(pTLS);
TlsSetValue(TlsIndex,NULL);
return NULL;
}
//
// TLS data initialized, now specific Init routines
//
b = DiamondTlsInit(TRUE);
if(b) {
b = ContextLoggingTlsInit(TRUE);
if(b) {
//
// all done ok
//
return pTLS;
}
//
// cleanup DiamondTlsInit
//
DiamondTlsInit(FALSE);
}
//
// cleanup memory
//
TlsSetValue(TlsIndex,NULL);
if(ThreadTlsUnlink(pTLS)) {
LocalFree(pTLS);
}
return NULL;
}
BOOL
ThreadTlsInitialize(
IN BOOL Init
)
/*++
Routine Description:
Called with TRUE to initialize TLS, if FALSE, to uninitialize
Arguments:
Init - indicates if we are to initialize vs uninitialize
Return Value:
NONE.
--*/
{
BOOL b = FALSE;
PSETUP_TLS pTLS = NULL;
if (TlsIndex!=(DWORD)(-1)) {
if (Init) {
pTLS = ThreadTlsCreate();
b = pTLS ? TRUE : FALSE;
} else {
pTLS = (PSETUP_TLS)TlsGetValue(TlsIndex);
if(pTLS) {
ThreadTlsCleanup();
TlsSetValue(TlsIndex,NULL);
if(ThreadTlsUnlink(pTLS)) {
LocalFree(pTLS);
}
}
b = TRUE;
}
}
return b;
}
BOOL
IsInteractiveWindowStation(
)
/*++
Routine Description:
Determine if we are running on an interactive station vs non-interactive station (i.e., service)
Arguments:
none
Return Value:
True if interactive
--*/
{
HWINSTA winsta;
USEROBJECTFLAGS flags;
BOOL interactive = TRUE; // true unless we determine otherwise
DWORD lenNeeded;
winsta = GetProcessWindowStation();
if(!winsta) {
return interactive;
}
if(GetUserObjectInformation(winsta,UOI_FLAGS,&flags,sizeof(flags),&lenNeeded)) {
interactive = (flags.dwFlags & WSF_VISIBLE) ? TRUE : FALSE;
}
//
// don't call CLoseWindowStation
//
return interactive;
}
BOOL
CommonProcessAttach(
IN BOOL Attach
)
{
BOOL b;
TCHAR Buffer[MAX_PATH+32];
PTCHAR p;
UINT u;
b = !Attach;
if(Attach) {
try {
//
// (remaining) critical sections
//
while(CriticalSectionList[DoneCriticalSections]) {
InitializeCriticalSection(CriticalSectionList[DoneCriticalSections]);
//
// increment only if we get here (exception can occur)
//
DoneCriticalSections++;
}
#ifndef _WIN64
IsWow64 = GetIsWow64();
#endif
//
// flag indicating we're running in context of GUI setup
//
GuiSetupInProgress = pGetGuiSetupInProgress();
//
// determine if we're interactive or not
//
if(!IsInteractiveWindowStation()) {
GlobalSetupFlagsOverride |= PSPGF_NONINTERACTIVE; // don't allow this to be changed
GlobalSetupFlags |= PSPGF_NONINTERACTIVE; // actual value
}
if(IsNoDriverPrompts()) {
GlobalSetupFlagsOverride |= PSPGF_UNATTENDED_SETUP; // don't allow this to be changed
GlobalSetupFlags |= PSPGF_UNATTENDED_SETUP; // actual value
}
GlobalSetupFlags |= GetEmbeddedFlags();
Seed = GetSeed();
pSetupInitNetConnectionList(TRUE);
pSetupInitPlatformPathOverrideSupport(TRUE);
OsLoaderRelativePath = pSetupGetOsLoaderPath(); // ok to fail
OsSystemPartitionRoot = pSetupGetSystemPartitionRoot(); // ok to fail
//
// Fill in system and windows directories.
//
if ((ProcessFileName = pSetupGetProcessPath()) == NULL) {
goto cleanAll;
}
//
// determine %windir%
//
if(((u = GetSystemWindowsDirectory(Buffer,MAX_PATH)) == 0) || u>MAX_PATH) {
goto cleanAll;
}
p = Buffer + u; // offset past directory to do all the sub-directories
//
// %windir% ==> WindowsDirectory
//
if((WindowsDirectory = DuplicateString(Buffer)) == NULL) {
goto cleanAll;
}
//
// %windir%\INF ==> InfDirectory
//
*p = 0;
if(!pSetupConcatenatePaths(Buffer,TEXT("INF"),MAX_PATH,NULL)
|| ((InfDirectory = DuplicateString(Buffer)) == NULL)) {
goto cleanAll;
}
//
// %windir%\SYSTEM ==> System16Directory
//
*p = 0;
if(!pSetupConcatenatePaths(Buffer,TEXT("SYSTEM"),MAX_PATH,NULL)
|| ((System16Directory = DuplicateString(Buffer))==NULL)) {
goto cleanAll;
}
//
// %windir%\LastGood ==> LastGoodDirectory
//
*p = 0;
if(!pSetupConcatenatePaths(Buffer,SP_LASTGOOD_NAME,MAX_PATH,NULL)
|| ((LastGoodDirectory = DuplicateString(Buffer))==NULL)) {
goto cleanAll;
}
//
// determine system directory
//
if(((u = GetSystemDirectory(Buffer,MAX_PATH)) == 0) || u>MAX_PATH) {
goto cleanAll;
}
p = Buffer + u; // offset past directory to do all the sub-directories
//
// <sys> ==> SystemDirectory (%windir%\System or %windir%\System32)
//
if((SystemDirectory = DuplicateString(Buffer)) == NULL) {
goto cleanAll;
}
//
// <sys>\ReinstallBackups ==> WindowsBackupDirectory
//
*p = 0;
if(!pSetupConcatenatePaths(Buffer,TEXT("ReinstallBackups"),MAX_PATH,NULL)
|| ((WindowsBackupDirectory = DuplicateString(Buffer))==NULL)) {
goto cleanAll;
}
//
// <sys>\CONFIG ==> ConfigDirectory
//
*p = 0;
if(!pSetupConcatenatePaths(Buffer,TEXT("CONFIG"),MAX_PATH,NULL)
|| ((ConfigDirectory = DuplicateString(Buffer))==NULL)) {
goto cleanAll;
}
//
// <sys>\DRIVERS ==> DriversDirectory
//
*p = 0;
if(!pSetupConcatenatePaths(Buffer,TEXT("DRIVERS"),MAX_PATH,NULL)
|| ((DriversDirectory = DuplicateString(Buffer))==NULL)) {
goto cleanAll;
}
//
// location system installed from
//
if((SystemSourcePath = GetSystemSourcePath())==NULL) {
goto cleanAll;
}
//
// location service pack installed from (may be NULL)
//
ServicePackSourcePath = GetServicePackSourcePath();
//
// location of local disk cached files (may be NULL)
// files here have precedence over everything else
//
ServicePackCachePath = GetServicePackCachePath();
//
// location of driver cache (may be NULL)
//
DriverCacheSourcePath = GetDriverCacheSourcePath();
//
// determine driver search path
//
if((InfSearchPaths = AllocAndReturnDriverSearchList(INFINFO_INF_PATH_LIST_SEARCH))==NULL) {
goto cleanAll;
}
//
// note that InitMiniIconList, InitDrvSearchInProgressList, and
// InitDrvSignPolicyList need to be explicitly cleaned up on failure
//
//
// initialize mini icons
//
if(!InitMiniIconList()) {
goto cleanAll;
}
//
// allows aborting of search
//
if(!InitDrvSearchInProgressList()) {
DestroyMiniIconList();
goto cleanAll;
}
//
// global list of device setup classes subject to driver signing policy
//
if(!InitDrvSignPolicyList()) {
DestroyMiniIconList();
DestroyDrvSearchInProgressList();
goto cleanAll;
}
//
// common version initialization
//
ZeroMemory(&OSVersionInfo,sizeof(OSVersionInfo));
OSVersionInfo.dwOSVersionInfoSize = sizeof(OSVersionInfo);
if((!GetVersionEx((LPOSVERSIONINFO)&OSVersionInfo))
|| (OSVersionInfo.dwPlatformId != VER_PLATFORM_WIN32_NT)) {
//
// should never get here
//
MYASSERT(FALSE);
DestroyMiniIconList();
DestroyDrvSearchInProgressList();
DestroyDrvSignPolicyList();
goto cleanAll;
}
//
// Fill in our ExcludeFromSelect string list which
// we pre-compute as an optimization.
//
if(OSVersionInfo.dwPlatformId == VER_PLATFORM_WIN32_NT) {
lstrcat(pszExcludeFromSelectList[1],
pszNtSuffix
);
lstrcat(pszExcludeFromSelectList[2],
pszNtPlatformSuffix
);
ExcludeFromSelectListUb = 3;
} else {
lstrcat(pszExcludeFromSelectList[1],
pszWinSuffix
);
ExcludeFromSelectListUb = 2;
}
//
// Now lower-case all the strings in this list, so that it
// doesn't have to be done at each string table lookup.
//
for(u = 0; u < ExcludeFromSelectListUb; u++) {
CharLower(pszExcludeFromSelectList[u]);
}
b = TRUE;
cleanAll: ;
} except (EXCEPTION_EXECUTE_HANDLER) {
//
// Unexpected exception occurred, drop into cleanup
//
}
if(b) {
//
// succeeded
//
goto Done;
}
} else {
//
// Detach
//
DestroyMiniIconList();
DestroyDrvSearchInProgressList();
DestroyDrvSignPolicyList();
if(GlobalNoDriverPromptsEventFlag) {
CloseHandle(GlobalNoDriverPromptsEventFlag);
}
}
while(DoneCriticalSections--) {
DeleteCriticalSection(CriticalSectionList[DoneCriticalSections]);
}
if (InfSearchPaths) {
MyFree(InfSearchPaths);
InfSearchPaths = NULL;
}
if (DriverCacheSourcePath) {
MyFree(DriverCacheSourcePath);
DriverCacheSourcePath = NULL;
}
if (ServicePackSourcePath) {
MyFree(ServicePackSourcePath);
ServicePackSourcePath = NULL;
}
if (ServicePackCachePath) {
MyFree(ServicePackCachePath);
ServicePackCachePath = NULL;
}
if (SystemSourcePath) {
MyFree(SystemSourcePath);
SystemSourcePath = NULL;
}
if (SystemDirectory) {
MyFree(SystemDirectory);
SystemDirectory = NULL;
if (WindowsBackupDirectory) {
MyFree(WindowsBackupDirectory);
WindowsBackupDirectory = NULL;
}
if (ConfigDirectory) {
MyFree(ConfigDirectory);
ConfigDirectory = NULL;
}
if (DriversDirectory) {
MyFree(DriversDirectory);
DriversDirectory = NULL;
}
}
if (WindowsDirectory) {
MyFree(WindowsDirectory);
WindowsDirectory = NULL;
if (InfDirectory) {
MyFree(InfDirectory);
InfDirectory = NULL;
}
if (System16Directory) {
MyFree(System16Directory);
System16Directory = NULL;
}
if (LastGoodDirectory) {
MyFree(LastGoodDirectory);
} LastGoodDirectory = NULL;
}
if (ProcessFileName) {
MyFree(ProcessFileName);
ProcessFileName = NULL;
}
if (OsLoaderRelativePath) {
MyFree(OsLoaderRelativePath);
OsLoaderRelativePath = NULL;
}
if (OsSystemPartitionRoot) {
MyFree(OsSystemPartitionRoot);
OsSystemPartitionRoot = NULL;
}
pSetupInitNetConnectionList(FALSE);
pSetupInitPlatformPathOverrideSupport(FALSE);
Done:
return(b);
}
#if MEM_DBG
#undef GetSystemSourcePath // defined again below
#endif
PCTSTR
GetSystemSourcePath(
TRACK_ARG_DECLARE
)
/*++
Routine Description:
This routine returns a newly-allocated buffer containing the source path from
which the system was installed, or "A:\" if that value cannot be determined.
This value is retrieved from the following registry location:
\HKLM\Software\Microsoft\Windows\CurrentVersion\Setup
SourcePath : REG_SZ : "\\ntamd64\1300fre.wks" // for example.
Arguments:
None.
Return Value:
If the function succeeds, the return value is a pointer to the path string.
This memory must be freed via MyFree().
If the function fails due to out-of-memory, the return value is NULL.
--*/
{
HKEY hKey;
TCHAR CharBuffer[CSTRLEN(REGSTR_PATH_SETUP) + SIZECHARS(REGSTR_KEY_SETUP)];
DWORD Err, DataType, DataSize;
PTSTR Value;
PCTSTR ReturnVal;
TRACK_PUSH
CopyMemory(CharBuffer,
pszPathSetup,
sizeof(pszPathSetup) - sizeof(TCHAR)
);
CopyMemory((PBYTE)CharBuffer + (sizeof(pszPathSetup) - sizeof(TCHAR)),
pszKeySetup,
sizeof(pszKeySetup)
);
if((Err = RegOpenKeyEx(HKEY_LOCAL_MACHINE,
CharBuffer,
0,
KEY_READ,
&hKey)) == ERROR_SUCCESS) {
//
// Attempt to read the the "SourcePath" value.
//
Err = QueryRegistryValue(hKey, pszSourcePath, &Value, &DataType, &DataSize);
RegCloseKey(hKey);
}
ReturnVal = NULL;
if(Err == NO_ERROR) {
ReturnVal = Value;
}
if(!ReturnVal && Err != ERROR_NOT_ENOUGH_MEMORY) {
//
// We failed to retrieve the SourcePath value, and it wasn't due to an out-of-memory
// condition. Fall back to our default of "A:\".
//
ReturnVal = DuplicateString(pszOemInfDefaultPath);
}
TRACK_POP
return ReturnVal;
}
#if MEM_DBG
#define GetSystemSourcePath() GetSystemSourcePath(TRACK_ARG_CALL)
#endif
#if MEM_DBG
#undef GetServicePackSourcePath // defined again below
#undef GetServicePackCachePath // defined again below
#endif
PCTSTR
GetServicePackSourcePath(
TRACK_ARG_DECLARE
)
/*++
Routine Description:
This routine returns a newly-allocated buffer containing the service pack source path
where we should look for service pack source files, or "CDM" if that value cannot be determined.
This value is retrieved from the following registry location:
\HKLM\Software\Microsoft\Windows\CurrentVersion\Setup
ServicePackSourcePath : REG_SZ : "\\ntamd64\1300fre.wks" // for example.
Arguments:
None.
Return Value:
If the function succeeds, the return value is a pointer to the path string.
This memory must be freed via MyFree().
If the function fails due to out-of-memory, the return value is NULL.
--*/
{
HKEY hKey;
TCHAR CharBuffer[CSTRLEN(REGSTR_PATH_SETUP) + SIZECHARS(REGSTR_KEY_SETUP)];
DWORD Err, DataType, DataSize;
PTSTR Value;
PCTSTR ReturnStr = NULL;
TRACK_PUSH
CopyMemory(CharBuffer,
pszPathSetup,
sizeof(pszPathSetup) - sizeof(TCHAR)
);
CopyMemory((PBYTE)CharBuffer + (sizeof(pszPathSetup) - sizeof(TCHAR)),
pszKeySetup,
sizeof(pszKeySetup)
);
if((Err = RegOpenKeyEx(HKEY_LOCAL_MACHINE,
CharBuffer,
0,
KEY_READ,
&hKey)) == ERROR_SUCCESS) {
//
// Attempt to read the the "ServicePackSourcePath" value.
//
Err = QueryRegistryValue(hKey, pszSvcPackPath, &Value, &DataType, &DataSize);
RegCloseKey(hKey);
}
if(Err == NO_ERROR) {
ReturnStr = Value;
}
if(!ReturnStr && Err != ERROR_NOT_ENOUGH_MEMORY) {
//
// We failed to retrieve the ServicePackSourcePath value, and it wasn't due to an out-of-memory
// condition. Fall back to the SourcePath value in the registry
//
ReturnStr = GetSystemSourcePath();
}
TRACK_POP
return ReturnStr;
}
PCTSTR
GetServicePackCachePath(
TRACK_ARG_DECLARE
)
/*++
Routine Description:
This routine returns a newly-allocated buffer containing the service pack cache path
where we should look for files ahead of anything else
This value is retrieved from the following registry location:
\HKLM\Software\Microsoft\Windows\CurrentVersion\Setup
ServicePackCachePath : REG_SZ : "c:\windows\foo" // for example.
Arguments:
None.
Return Value:
If the function succeeds, the return value is a pointer to the path string.
This memory must be freed via MyFree().
If the function fails due to out-of-memory, the return value is NULL.
--*/
{
HKEY hKey;
TCHAR CharBuffer[CSTRLEN(REGSTR_PATH_SETUP) + SIZECHARS(REGSTR_KEY_SETUP)];
DWORD Err, DataType, DataSize;
PTSTR Value;
PCTSTR ReturnStr = NULL;
TRACK_PUSH
CopyMemory(CharBuffer,
pszPathSetup,
sizeof(pszPathSetup) - sizeof(TCHAR)
);
CopyMemory((PBYTE)CharBuffer + (sizeof(pszPathSetup) - sizeof(TCHAR)),
pszKeySetup,
sizeof(pszKeySetup)
);
if((Err = RegOpenKeyEx(HKEY_LOCAL_MACHINE,
CharBuffer,
0,
KEY_READ,
&hKey)) == ERROR_SUCCESS) {
//
// Attempt to read the the "ServicePackCachePath" value.
//
Err = QueryRegistryValue(hKey, pszSvcPackCachePath, &Value, &DataType, &DataSize);
RegCloseKey(hKey);
}
if(Err == NO_ERROR) {
ReturnStr = Value;
}
TRACK_POP
return ReturnStr;
}
#if MEM_DBG
#define GetServicePackSourcePath() GetServicePackSourcePath(TRACK_ARG_CALL)
#define GetServicePackCachePath() GetServicePackCachePath(TRACK_ARG_CALL)
#endif
PCTSTR
GetDriverCacheSourcePath(
VOID
)
/*++
Routine Description:
This routine returns a newly-allocated buffer containing the source path to the local driver cache
cab-file.
This value is retrieved from the following registry location:
\HKLM\Software\Microsoft\Windows\CurrentVersion\Setup
DriverCachePath : REG_SZ : "\\ntamd64\1300fre.wks" // for example.
Arguments:
None.
Return Value:
If the function succeeds, the return value is a pointer to the path string.
This memory must be freed via MyFree().
If the function fails due to out-of-memory, the return value is NULL.
--*/
{
HKEY hKey;
TCHAR CharBuffer[CSTRLEN(REGSTR_PATH_SETUP) + SIZECHARS(REGSTR_KEY_SETUP)];
DWORD Err, DataType, DataSize;
PTSTR Value;
TCHAR Path[MAX_PATH];
CopyMemory(CharBuffer,
pszPathSetup,
sizeof(pszPathSetup) - sizeof(TCHAR)
);
CopyMemory((PBYTE)CharBuffer + (sizeof(pszPathSetup) - sizeof(TCHAR)),
pszKeySetup,
sizeof(pszKeySetup)
);
if((Err = RegOpenKeyEx(HKEY_LOCAL_MACHINE,
CharBuffer,
0,
KEY_READ,
&hKey)) == ERROR_SUCCESS) {
//
// Attempt to read the the "DriverCachePath" value.
//
Err = QueryRegistryValue(hKey, pszDriverCachePath, &Value, &DataType, &DataSize);
RegCloseKey(hKey);
}
if(Err == NO_ERROR) {
if(Value) {
ExpandEnvironmentStrings(Value,Path,MAX_PATH);
MyFree(Value);
Value = NULL;
if (*Path) {
Value = DuplicateString( Path );
}
return (PCTSTR)Value;
}
} else if(Err == ERROR_NOT_ENOUGH_MEMORY) {
return NULL;
}
return NULL;
}
BOOL
pSetupSetSystemSourcePath(
IN PCTSTR NewSourcePath,
IN PCTSTR NewSvcPackSourcePath
)
/*++
Routine Description:
This routine is used to override the system source path used by setupapi (as
retrieved by GetSystemSourcePath during DLL initialization). This is used by
syssetup.dll to set the system source path appropriately during GUI-mode setup,
so that the device installer APIs will copy files from the correct source location.
We do the same thing for the service pack source path
NOTE: This routine IS NOT thread safe!
Arguments:
NewSourcePath - supplies the new source path to be used.
NewSvcPackSourcePath - supplies the new svcpack source path to be used.
Return Value:
If the function succeeds, the return value is TRUE.
If the function fails (due to out-of-memory), the return value is FALSE.
--*/
{
PCTSTR p,q;
p = (PCTSTR)DuplicateString(NewSourcePath);
q = (PCTSTR)DuplicateString(NewSvcPackSourcePath);
if(p) {
MyFree(SystemSourcePath);
SystemSourcePath = p;
}
if (q) {
MyFree(ServicePackSourcePath);
ServicePackSourcePath = q;
}
if (!p || !q) {
//
// failed due to out of memory!
//
return(FALSE);
}
return TRUE;
}
PCTSTR
pSetupGetOsLoaderPath(
VOID
)
/*++
Routine Description:
This routine returns a newly-allocated buffer containing the path to the OsLoader
(relative to the system partition drive). This value is retrieved from the
following registry location:
HKLM\System\Setup
OsLoaderPath : REG_SZ : <path> // e.g., "\os\winnt40"
Arguments:
None.
Return Value:
If the registry entry is found, the return value is a pointer to the string containing
the path. The caller must free this buffer via MyFree().
If the registry entry is not found, or memory cannot be allocated for the buffer, the
return value is NULL.
--*/
{
HKEY hKey;
PTSTR Value;
DWORD Err, DataType, DataSize;
if(RegOpenKeyEx(HKEY_LOCAL_MACHINE,
TEXT("SYSTEM\\Setup"),
0,
KEY_READ,
&hKey) == ERROR_SUCCESS) {
Err = QueryRegistryValue(hKey, TEXT("OsLoaderPath"), &Value, &DataType, &DataSize);
RegCloseKey(hKey);
return (Err == NO_ERROR) ? (PCTSTR)Value : NULL;
}
return NULL;
}
PCTSTR
pSetupGetSystemPartitionRoot(
VOID
)
/*++
Routine Description:
This routine returns a newly-allocated buffer containing the path to the OsLoader
(relative to the system partition drive). This value is retrieved from the
following registry location:
HKLM\System\Setup
SystemPartition : REG_SZ : <path> // e.g., "\Device\HarddiskVolume1"
Arguments:
None.
Return Value:
If the registry entry is found, the return value is a pointer to the string containing
the path. The caller must free this buffer via MyFree().
If the registry entry is not found, or memory cannot be allocated for the buffer, the
return value is NULL.
--*/
{
#ifdef UNICODE
HKEY hKey;
PTSTR Value;
DWORD Err, DataType, DataSize;
TCHAR Path[MAX_PATH];
if(RegOpenKeyEx(HKEY_LOCAL_MACHINE,
TEXT("SYSTEM\\Setup"),
0,
KEY_READ,
&hKey) == ERROR_SUCCESS) {
Err = QueryRegistryValue(hKey, TEXT("SystemPartition"), &Value, &DataType, &DataSize);
RegCloseKey(hKey);
if(Err == NO_ERROR) {
//
// prepend \\?\GLOBALROOT\
//
lstrcpy(Path,TEXT("\\\\?\\GLOBALROOT\\"));
if(pSetupConcatenatePaths(Path,Value,MAX_PATH,NULL)) {
MyFree(Value);
Value = DuplicateString(Path);
if(!Value) {
Err = ERROR_NOT_ENOUGH_MEMORY;
}
} else {
Err = GetLastError();
MyFree(Value);
}
}
return (Err == NO_ERROR) ? (PCTSTR)Value : NULL;
}
#endif
return NULL;
}
PCTSTR
pSetupGetProcessPath(
VOID
)
/*++
Routine Description:
Get the name of the EXE that we're running in.
Arguments:
NONE.
Return Value:
Pointer to a dynamically allocated string containing the name.
--*/
{
LPTSTR modname;
modname = MyMalloc(MAX_PATH * sizeof(TCHAR));
if(modname != NULL) {
if(GetModuleFileName(NULL, modname, MAX_PATH) > 0) {
LPTSTR modname2;
modname2 = MyRealloc(modname, (lstrlen(modname)+1)*sizeof(TCHAR));
if(modname2) {
modname = modname2;
}
return modname;
} else {
#ifdef PRERELEASE
OutputDebugStringA("GetModuleFileName returned 0\r\n");
DebugBreak();
#endif
MyFree(modname);
}
}
return NULL;
}
#ifdef UNICODE
BOOL
pGetGuiSetupInProgress(
VOID
)
/*++
Routine Description:
This routine determines if we're doing a gui-mode setup.
This value is retrieved from the following registry location:
\HKLM\System\Setup\
SystemSetupInProgress : REG_DWORD : 0x00 (where nonzero means we're doing a gui-setup)
Arguments:
None.
Return Value:
If the function succeeds, the return value is a pointer to the path string.
This memory must be freed via MyFree().
If the function fails due to out-of-memory, the return value is NULL.
--*/
{
HKEY hKey;
TCHAR CharBuffer[CSTRLEN(REGSTR_PATH_SETUP) + SIZECHARS(REGSTR_KEY_SETUP)];
DWORD Err, DataType, DataSize = sizeof(DWORD);
DWORD Value;
if((Err = RegOpenKeyEx(HKEY_LOCAL_MACHINE,
TEXT("System\\Setup"),
0,
KEY_READ,
&hKey)) == ERROR_SUCCESS) {
//
// Attempt to read the the "DriverCachePath" value.
//
Err = RegQueryValueEx(
hKey,
TEXT("SystemSetupInProgress"),
NULL,
&DataType,
(LPBYTE)&Value,
&DataSize);
RegCloseKey(hKey);
}
if(Err == NO_ERROR) {
if(Value) {
return(TRUE);
}
}
return(FALSE);
}
#else
BOOL
pGetGuiSetupInProgress(
VOID
)
{
return FALSE;
}
#endif
VOID pSetupSetGlobalFlags(
IN DWORD Value
)
/*++
exported as a private function
Routine Description:
Sets global flags to change certain setupapi features,
such as "should we call runonce after installing every device" (set if we will manually call it)
or "should we backup every file"
Used to initialize value
Arguments:
Value: combination of:
PSPGF_NO_RUNONCE - set to inhibit runonce calls (e.g., during GUI-
mode setup)
PSPGF_NO_BACKUP - set to inhibit automatic backup (e.g., during
GUI-mode setup)
PSPGF_NONINTERACTIVE - set to inhibit _all_ UI (e.g., for server-side
device installation)
PSPGF_SERVER_SIDE_RUNONCE - batch RunOnce entries for server-side
processing (for use only by umpnpmgr)
PSPGF_NO_VERIFY_INF - set to inhibit verification (digital signature) of
INF files until after the cyrpto DLLs have been registered.
PSPGF_UNATTENDED_SETUP - similar to NONINTERACTIVE - but specific to unattended setup
PSPGF_AUTOFAIL_VERIFIES - automatically fail all calls to crypto
Return Value:
none
--*/
{
pSetupModifyGlobalFlags((DWORD)(-1),Value);
}
VOID
pSetupModifyGlobalFlags(
IN DWORD Flags,
IN DWORD Value
)
/*++
exported as a private function
Routine Description:
Modifies global setup flags
such as "should we call runonce after installing every device" (set if we will manually call it)
or "should we backup every file"
only modifies specified flags to given value
Arguments:
Flags: what actual flags to modify, combination of:
PSPGF_NO_RUNONCE - set to inhibit runonce calls (e.g., during GUI-
mode setup)
PSPGF_NO_BACKUP - set to inhibit automatic backup (e.g., during
GUI-mode setup)
PSPGF_NONINTERACTIVE - set to inhibit _all_ UI (e.g., for server-side
device installation)
PSPGF_SERVER_SIDE_RUNONCE - batch RunOnce entries for server-side
processing (for use only by umpnpmgr)
PSPGF_NO_VERIFY_INF - set to inhibit verification (digital signature) of
INF files until after the cyrpto DLLs have been registered.
PSPGF_UNATTENDED_SETUP - similar to PSPGF_NONINTERACTIVE, but specific to setup
PSPGF_AUTOFAIL_VERIFIES - automatically fail all calls to crypto
Value: new value of bits specified in Flags
Return Value:
none
--*/
{
Flags &= ~GlobalSetupFlagsOverride; // exclusion
#ifdef UNICODE
if((Flags & PSPGF_NO_VERIFY_INF) && !(Value & PSPGF_NO_VERIFY_INF) && (GlobalSetupFlags & PSPGF_NO_VERIFY_INF)) {
Seed = GetSeed();
}
#endif
GlobalSetupFlags = (Value & Flags) | (GlobalSetupFlags & ~Flags);
}
DWORD pSetupGetGlobalFlags(
VOID
)
/*++
exported as a private function, also called internally
Routine Description:
Return flags previously set
Arguments:
none
Return value:
Flags (combination of values described above for pSetupSetGlobalFlags)
--*/
{
return GlobalSetupFlags;
}
BOOL
WINAPI
SetupSetNonInteractiveMode(
IN BOOL NonInteractiveFlag
)
/*++
Global access to the flag PSPGF_NONINTERACTIVE
Routine Description:
Set/Reset the NonInteractiveMode flag, and return previous flag value
(can't clear override)
Arguments:
New flag value
Return value:
Old flag value
--*/
{
BOOL f = (GlobalSetupFlags & PSPGF_NONINTERACTIVE) ? TRUE : FALSE;
if (NonInteractiveFlag) {
pSetupModifyGlobalFlags(PSPGF_NONINTERACTIVE,PSPGF_NONINTERACTIVE);
} else {
pSetupModifyGlobalFlags(PSPGF_NONINTERACTIVE,0);
}
return f;
}
BOOL
WINAPI
SetupGetNonInteractiveMode(
VOID
)
/*++
Global access to the flag PSPGF_NONINTERACTIVE
Routine Description:
Get current flag value
Arguments:
none
Return value:
Current flag value
--*/
{
return (GlobalSetupFlags & PSPGF_NONINTERACTIVE) ? TRUE : FALSE;
}
#ifndef _WIN64
BOOL
GetIsWow64 (
VOID
)
/*++
Routine Description:
Determine if we're running on WOW64 or not (not supported on ANSI builds)
Arguments:
none
Return value:
TRUE if running under WOW64 (and special Wow64 features available)
--*/
{
#ifdef UNICODE
ULONG_PTR ul = 0;
NTSTATUS st;
//
// If this call succeeds and sets ul non-zero
// it's a 32-bit process running on Win64
//
st = NtQueryInformationProcess(NtCurrentProcess(),
ProcessWow64Information,
&ul,
sizeof(ul),
NULL);
if (NT_SUCCESS(st) && (0 != ul)) {
// 32-bit code running on Win64
return TRUE;
}
#endif
return FALSE;
}
#endif // _WIN64
#if 0 // deleted code
//
// this will be useful at somepoint, but not used right now
//
BOOL
InitComponents(
DWORD Components
)
/*++
Routine Description:
Called at a point we want certain components initialized
Arguments:
bitmask of components to initialize
Return value:
TRUE if all initialized ok
--*/
{
BOOL success = FALSE;
PSETUP_TLS pPerThread = SetupGetTlsData();
BOOL locked = FALSE;
if(!pPerThread) {
MYASSERT(pPerThread);
return FALSE;
}
try {
EnterCriticalSection(&DelayedComponentMutex);
locked = TRUE;
Components &= ~ DoneComponentInitialize;
Components &= ~ pPerThread->PerThreadDoneComponent;
if (!Components) {
//
// already done
//
success = TRUE;
leave;
}
if (Components & FailedComponentInitialize) {
//
// previously failed
//
leave;
}
if (Components & pPerThread->PerThreadFailedComponent) {
//
// previously failed
//
leave;
}
MYASSERT(((DoneComponentInitialize | pPerThread->PerThreadDoneComponent) & Components) == Components);
MYASSERT(((FailedComponentInitialize | pPerThread->PerThreadFailedComponent) & Components) == 0);
success = TRUE;
} except (EXCEPTION_EXECUTE_HANDLER) {
MYASSERT(FALSE);
}
if(locked) {
LeaveCriticalSection(&DelayedComponentMutex);
}
return success;
}
VOID
ComponentCleanup(
DWORD Components
)
/*++
Routine Description:
Called to cleanup components
Arguments:
bitmask of components to uninitialize
Return value:
none
--*/
{
PSETUP_TLS pPerThread = SetupGetTlsData();
BOOL locked = FALSE;
try {
EnterCriticalSection(&DelayedComponentMutex);
locked = TRUE;
Components &= (DoneComponentInitialize | (pPerThread? pPerThread->PerThreadDoneComponent : 0));
if (!Components) {
//
// already done
//
leave;
}
} except (EXCEPTION_EXECUTE_HANDLER) {
MYASSERT(FALSE);
}
MYASSERT(((DoneComponentInitialize | (pPerThread ? pPerThread->PerThreadDoneComponent : 0)) & Components) == 0);
if(locked) {
LeaveCriticalSection(&DelayedComponentMutex);
}
}
#endif // deleted code
#ifdef UNICODE
BOOL
pSetupSetNoDriverPrompts(
BOOL Flag
)
/*++
exported as a private function
Routine Description:
Sets system into headless/non-headless mode
Arguments:
Flag - indicating mode
--*/
{
//
//
if(!GuiSetupInProgress) {
return FALSE;
}
if(GlobalNoDriverPromptsEventFlag == NULL) {
GlobalNoDriverPromptsEventFlag = CreateEvent(NULL,TRUE,Flag,SETUP_NODRIVERPROMPTS_MODE);
if(GlobalNoDriverPromptsEventFlag == NULL) {
return FALSE;
}
}
if(Flag) {
//
// force this process's setupapi to be non-interative, and any future setupapi's
//
GlobalSetupFlagsOverride |= PSPGF_UNATTENDED_SETUP; // don't allow this to be changed
GlobalSetupFlags |= PSPGF_UNATTENDED_SETUP; // actual value
SetEvent(GlobalNoDriverPromptsEventFlag);
} else {
//
// can't reset flag for this/existing processes, but can reset it for all future processes
//
ResetEvent(GlobalNoDriverPromptsEventFlag);
}
return TRUE;
}
#endif
BOOL
IsNoDriverPrompts(
VOID
)
/*++
internal
Routine Description:
Obtains headless state
Arguments:
Flag - indicating mode
--*/
{
#ifdef UNICODE
if(!GuiSetupInProgress) {
return FALSE;
}
if(GlobalNoDriverPromptsEventFlag == NULL) {
GlobalNoDriverPromptsEventFlag = OpenEvent(SYNCHRONIZE,FALSE,SETUP_NODRIVERPROMPTS_MODE);
if(GlobalNoDriverPromptsEventFlag == NULL) {
return FALSE;
}
}
//
// poll event, returning TRUE if it's signalled
//
return WaitForSingleObject(GlobalNoDriverPromptsEventFlag,0) == WAIT_OBJECT_0;
#else
return FALSE;
#endif
}
DWORD
GetEmbeddedFlags(
VOID
)
/*++
Routine Description:
This routine determines whether or not we are running on an embedded
product, and if so, whether:
* The "minimize setupapi footprint" option is enabled. This causes us to
modify our default behaviors as follows:
1. Never call any crypto APIs, and just assume everything is signed
2. Never generate PNFs.
* The "disable SCE" option is enabled. This causes us to avoid all use of
the Security Configuration Editor (SCE) routines (as the corresponding
DLLs won't be available on that embedded configuration).
Arguments:
none
Return value:
Combination of the following flags:
PSPGF_MINIMAL_EMBEDDED if we're running in "minimize footprint" mode
PSPGF_NO_SCE_EMBEDDED if we're running in "disable SCE" mode
--*/
{
OSVERSIONINFOEX osvix;
DWORDLONG dwlConditionMask = 0;
HKEY hKey;
TCHAR CharBuffer[CSTRLEN(REGSTR_PATH_SETUP) + SIZECHARS(REGSTR_KEY_SETUP)];
DWORD RegDataType, Data, DataSize;
DWORD Flags;
//
// Are we on the embedded product suite?
//
ZeroMemory(&osvix, sizeof(OSVERSIONINFOEX));
osvix.dwOSVersionInfoSize = sizeof(OSVERSIONINFOEX);
osvix.wSuiteMask = VER_SUITE_EMBEDDEDNT;
VER_SET_CONDITION(dwlConditionMask, VER_SUITENAME, VER_OR);
if(!VerifyVersionInfo(&osvix,
VER_SUITENAME,
dwlConditionMask)) {
return 0;
}
Flags = 0;
//
// OK, we running on embedded. Now we need to find out whether or not we
// should run in "minimal footprint" mode. This is stored in a REG_DWORD
// value entry called "MinimizeFootprint" under
// HKLM\Software\Microsoft\Windows\CurrentVersion\Setup.
//
CopyMemory(CharBuffer,
pszPathSetup,
sizeof(pszPathSetup) - sizeof(TCHAR)
);
CopyMemory((PBYTE)CharBuffer + (sizeof(pszPathSetup) - sizeof(TCHAR)),
pszKeySetup,
sizeof(pszKeySetup)
);
if(ERROR_SUCCESS == RegOpenKeyEx(HKEY_LOCAL_MACHINE,
CharBuffer,
0,
KEY_READ,
&hKey)) {
DataSize = sizeof(Data);
if((ERROR_SUCCESS == RegQueryValueEx(hKey,
pszMinimizeFootprint,
NULL,
&RegDataType,
(LPBYTE)&Data,
&DataSize))
&& (RegDataType == REG_DWORD) && (DataSize == sizeof(Data))) {
Flags |= PSPGF_MINIMAL_EMBEDDED;
}
RegCloseKey(hKey);
}
//
// Now look under HKLM\Software\Microsoft\EmbeddedNT\Security for a
// DisableSCE REG_DWORD value entry, indicating we shouldn't call SCE.
//
if(ERROR_SUCCESS == RegOpenKeyEx(HKEY_LOCAL_MACHINE,
pszEmbeddedNTSecurity,
0,
KEY_READ,
&hKey)) {
DataSize = sizeof(Data);
if((ERROR_SUCCESS == RegQueryValueEx(hKey,
pszDisableSCE,
NULL,
&RegDataType,
(LPBYTE)&Data,
&DataSize))
&& (RegDataType == REG_DWORD) && (DataSize == sizeof(Data))) {
Flags |= PSPGF_NO_SCE_EMBEDDED;
}
RegCloseKey(hKey);
}
return Flags;
}
#ifdef UNICODE
DWORD
GetSeed(
VOID
)
{
HKEY hKey;
DWORD val = 0;
DWORD valsize, valdatatype;
if(GlobalSetupFlags & PSPGF_MINIMAL_EMBEDDED) {
return val;
}
if(ERROR_SUCCESS == RegOpenKeyEx(HKEY_LOCAL_MACHINE,
L"System\\WPA\\PnP",
0,
KEY_READ,
&hKey)) {
valsize = sizeof(val);
if((ERROR_SUCCESS != RegQueryValueEx(hKey,
L"seed",
NULL,
&valdatatype,
(PBYTE)&val,
&valsize))
|| (valdatatype != REG_DWORD) || (valsize != sizeof(val))) {
val = 0;
}
RegCloseKey(hKey);
}
return val;
}
#endif