windows-nt/Source/XPSP1/NT/base/ntsetup/ocmanage/common/ochelper.c
2020-09-26 16:20:57 +08:00

1710 lines
40 KiB
C

/*++
Copyright (c) 1996 Microsoft Corporation
Module Name:
ochelper.c
Abstract:
Helper/callback routines, available to plug-in components
when processing interface routine calls.
Author:
Ted Miller (tedm) 13-Sep-1996
Revision History:
--*/
#include "precomp.h"
#pragma hdrstop
#include <stdio.h>
#include <stdarg.h>
//
// Window handle of wizard dialog. Set when the OC Manager client
// calls OcRememberWizardDialogHandle.
//
HWND WizardDialogHandle;
VOID
OcHelperShowHideWizardPage(
IN PVOID OcManagerContext,
IN BOOL bShow
)
{
POC_MANAGER p = ((PHELPER_CONTEXT)OcManagerContext)->OcManager;
if (p->Callbacks.ShowHideWizardPage)
{
// If we have a callback, hide the wizard.
p->Callbacks.ShowHideWizardPage(bShow);
}
}
VOID
OcHelperTickGauge(
IN PVOID OcManagerContext
)
/*++
Routine Description:
Function used while processing the OC_COMPLETE_INSTALLATION Interface function
to step the progress gauge being run by the OC Manager.
Ignored at other times.
Arguments:
OcManagerContext - supplies OC Manager context information the component gets
from the OcManagerContext field of the OCMANAGER_ROUTINES structure.
Return Value:
None.
--*/
{
pOcTickSetupGauge(((PHELPER_CONTEXT)OcManagerContext)->OcManager);
}
VOID
#ifdef UNICODE
OcHelperSetProgressTextW(
#else
OcHelperSetProgressTextA(
#endif
IN PVOID OcManagerContext,
IN LPCTSTR Text
)
/*++
Routine Description:
Function used while processing the OC_COMPLETE_INSTALLATION Interface function
to change the text associated with the progress gauge being run by
the OC Manager. Ignored at other times.
Arguments:
OcManagerContext - supplies OC Manager context information the component gets
from the OcManagerContext field of the OCMANAGER_ROUTINES structure.
Text - Supplies the text for the progress gauge. The component should try to
respect the current language parameters established by OC_SET_LANGUAGE.
The OC Manager will make a copy of the string and truncate it as necessary.
Return Value:
None.
--*/
{
POC_MANAGER p = ((PHELPER_CONTEXT)OcManagerContext)->OcManager;
#ifdef DEBUGPERFTRACE
static DWORD lasttickcount = 0;
static DWORD currenttickcount = 0;
static DWORD diff, lastdiff;
if (!lasttickcount)
lasttickcount = GetTickCount();
lasttickcount = currenttickcount;
currenttickcount = GetTickCount();
lastdiff = diff;
diff = currenttickcount - lasttickcount;
TRACE(( TEXT("SetProgressText at %d (last = %d, diff = %d, last diff = %d)\n"), currenttickcount, lasttickcount, diff, lastdiff ));
if (diff > 1000*3) {
WRN(( TEXT("It's been > 3 seconds since the last tick count update...the user is getting impatient.\n") ));
}
#endif
if(p->ProgressTextWindow) {
SetWindowText(p->ProgressTextWindow,Text);
}
}
#ifdef UNICODE
VOID
OcHelperSetProgressTextA(
IN PVOID OcManagerContext,
IN LPCSTR Text
)
/*++
Routine Description:
ANSI version of OcHelperSetProgressText().
Arguments:
Return Value:
--*/
{
LPCWSTR p;
if(p = pSetupAnsiToUnicode(Text)){
OcHelperSetProgressTextW(OcManagerContext,p);
pSetupFree(p);
}
}
#endif
UINT
_OcHelperSetPrivateData(
IN PVOID OcManagerContext,
IN LPCVOID Name,
IN PVOID Data,
IN UINT Size,
IN UINT Type,
IN BOOL IsNativeCharWidth
)
{
PHELPER_CONTEXT HelperContext;
DWORD rc;
DWORD Disposition;
HKEY hKey;
LONG id;
HelperContext = OcManagerContext;
//
// Fetch the component id. If we're processing an interface routine
// then use the component id of the active component. Otherwise
// resort to the component id stored in the helper context.
//
if(HelperContext->OcManager->CurrentComponentStringId == -1) {
id = HelperContext->ComponentStringId;
} else {
id = HelperContext->OcManager->CurrentComponentStringId;
}
rc = RegCreateKeyEx(
HelperContext->OcManager->hKeyPrivateData,
pSetupStringTableStringFromId(HelperContext->OcManager->ComponentStringTable,id),
0,
NULL,
REG_OPTION_VOLATILE,
KEY_SET_VALUE,
NULL,
&hKey,
&Disposition
);
if(rc == NO_ERROR) {
if(IsNativeCharWidth) {
rc = RegSetValueEx(hKey,Name,0,Type,Data,Size);
} else {
rc = RegSetValueExA(hKey,Name,0,Type,Data,Size);
}
RegCloseKey(hKey);
}
return(rc);
}
UINT
#ifdef UNICODE
OcHelperSetPrivateDataW(
#else
OcHelperSetPrivateDataA(
#endif
IN PVOID OcManagerContext,
IN LPCTSTR Name,
IN PVOID Data,
IN UINT Size,
IN UINT Type
)
/*++
Routine Description:
Function to set a named datum that can then be retrieved later
by the component or by any other component, via the GetPrivateData
helper routine.
This routine can be called at any time.
Arguments:
OcManagerContext - supplies OC Manager context information the component gets
from the OcManagerContext field of the OCMANAGER_ROUTINES structure.
Name - Supplies a name for the datum. If a datum with this name
already exists for the component, it is overwritten.
Data - Supplies the data itself. The OC Manager makes a copy of the data
so the component need not ensure that this buffer remains valid.
Size - Supplies the size in bytes of the data.
Type - Supplies the type of the data. Components should use the standard registry
type names (REG_SZ, REG_BINARY, etc.) to facilitate inter-component
data sharing.
Return Value:
Win32 error code indicating outcome; NO_ERROR means success.
--*/
{
return(_OcHelperSetPrivateData(OcManagerContext,Name,Data,Size,Type,TRUE));
}
#ifdef UNICODE
UINT
OcHelperSetPrivateDataA(
IN PVOID OcManagerContext,
IN LPCSTR Name,
IN PVOID Data,
IN UINT Size,
IN UINT Type
)
/*++
Routine Description:
ANSI version of OcHelperSetPrivateData().
Arguments:
Return Value:
--*/
{
return(_OcHelperSetPrivateData(OcManagerContext,Name,Data,Size,Type,FALSE));
}
#endif
UINT
_OcHelperGetPrivateData(
IN PVOID OcManagerContext,
IN LPCTSTR ComponentId, OPTIONAL
IN LPCVOID Name,
OUT PVOID Data, OPTIONAL
IN OUT PUINT Size,
OUT PUINT Type,
IN BOOL IsNativeCharWidth
)
{
PHELPER_CONTEXT HelperContext;
PCTSTR ComponentName;
DWORD rc;
DWORD Disposition;
HKEY hKey;
LONG id;
HelperContext = OcManagerContext;
//
// Figure out the name of the component that owns the data.
//
if(ComponentId) {
ComponentName = ComponentId;
} else {
if(HelperContext->OcManager->CurrentComponentStringId == -1) {
id = HelperContext->ComponentStringId;
} else {
id = HelperContext->OcManager->CurrentComponentStringId;
}
ComponentName = pSetupStringTableStringFromId(
HelperContext->OcManager->ComponentStringTable,
id
);
if (!ComponentName) {
rc = GetLastError();
goto exit;
}
}
rc = RegCreateKeyEx(
HelperContext->OcManager->hKeyPrivateData,
ComponentName,
0,
NULL,
REG_OPTION_VOLATILE,
KEY_QUERY_VALUE,
NULL,
&hKey,
&Disposition
);
if(rc == NO_ERROR) {
if(IsNativeCharWidth) {
rc = RegQueryValueEx(hKey,Name,0,Type,Data,Size);
} else {
rc = RegQueryValueExA(hKey,Name,0,Type,Data,Size);
}
if(rc == ERROR_MORE_DATA) {
rc = ERROR_INSUFFICIENT_BUFFER;
}
RegCloseKey(hKey);
}
exit:
return(rc);
}
UINT
#ifdef UNICODE
OcHelperGetPrivateDataW(
#else
OcHelperGetPrivateDataA(
#endif
IN PVOID OcManagerContext,
IN LPCTSTR ComponentId, OPTIONAL
IN LPCTSTR Name,
OUT PVOID Data, OPTIONAL
IN OUT PUINT Size,
OUT PUINT Type
)
/*++
Routine Description:
Function to retrieve a named datum that was previously set via
SetPrivateData by the component or by any other component.
This routine can be called at any time.
Arguments:
OcManagerContext - supplies OC Manager context information the component gets
from the OcManagerContext field of the OCMANAGER_ROUTINES structure.
ComponentId - Supplies the short descriptive name of the component
(as specified in OC.INF) that set/owns the datum to be retrieved.
NULL means the current component.
Name - Supplies the name of the datum to be retrieved.
Data - If specified, receives the data. If not specified, the routine puts
the required size in Size and returns NO_ERROR.
Size - On input, supplies the size of the buffer pointed to by Data
(ignored if Data is not specified). On output, receives the size of
the data stored, or the required size if the buffer is not large enough.
Type - Upon successful completion receives the type of the datum.
Return Value:
NO_ERROR: If Data was specified, the requested datum had been placed in
the caller's buffer. If Data was not specified, then the required size
has been placed in the UINT pointed to by Size.
ERROR_INSUFFICIENT_BUFFER: the specified buffer size is too small
to contain the datum. The required size has been placed in the UINT
pointed to by Size.
Other Win32 error codes indicate additional error cases, such as the
datum not being found, etc.
--*/
{
return(_OcHelperGetPrivateData(OcManagerContext,ComponentId,Name,Data,Size,Type,TRUE));
}
#ifdef UNICODE
UINT
OcHelperGetPrivateDataA(
IN PVOID OcManagerContext,
IN LPCSTR ComponentId, OPTIONAL
IN LPCSTR Name,
OUT PVOID Data, OPTIONAL
IN OUT PUINT Size,
OUT PUINT Type
)
/*++
Routine Description:
ANSI version of OcHelperGetPrivateData().
Arguments:
Return Value:
--*/
{
LPCWSTR component;
UINT u;
if(ComponentId) {
component = pSetupAnsiToUnicode(ComponentId);
if(!component) {
u = ERROR_NOT_ENOUGH_MEMORY;
goto c0;
}
} else {
component = NULL;
}
u = _OcHelperGetPrivateData(OcManagerContext,component,Name,Data,Size,Type,FALSE);
if(component) {
pSetupFree(component);
}
c0:
return(u);
}
#endif
UINT
OcHelperSetSetupMode(
IN PVOID OcManagerContext,
IN DWORD SetupMode
)
/*++
Routine Description:
Function that can be used at any time while a component is
processing any Interface function or any of its wizard pages.
It is used to set the current setup mode. It is expected that if a
component supplies a setup mode page, it will use this routine to
inform the OC Manager of the setup mode the user chose.
Arguments:
OcManagerContext - supplies OC Manager context information the component gets
from the OcManagerContext field of the OCMANAGER_ROUTINES structure.
SetupMode - Supplies a numeric value that indicates the setup mode. This may be
any of the 4 standard values (minimal, laptop, custom, or typical).
It can also be any other private value that has meaning to a suite or bundle.
In that case the low 8 bits are interpreted as one of the standard values
so the mode can be meaningful to other components and the OC Manager,
who know nothing about private mode types. The component setting the mode
should attempt to set this as reasonably as possible. The upper 24 bits are
essentially private mode data.
Return Value:
The return value is the previous mode.
--*/
{
POC_MANAGER p = ((PHELPER_CONTEXT)OcManagerContext)->OcManager;
UINT Mode;
Mode = p->SetupMode;
p->SetupMode = SetupMode;
return(Mode);
}
UINT
OcHelperGetSetupMode(
IN PVOID OcManagerContext
)
/*++
Routine Description:
Function that can be used at any time while a component is processing
any Interface function or any of its wizard pages. It is used to query
the current setup mode. Note that this can be a private mode type,
in which case the low 8 bits of the mode value can be interpreted as one of
the standard 4 mode types and the upper 24 bits are private mode data.
The mode can also be unknown. See section 3.2.1 for a list of standard
mode types.
Arguments:
OcManagerContext - supplies OC Manager context information the component gets
from the OcManagerContext field of the OCMANAGER_ROUTINES structure.
Return Value:
The return value is the current mode.
--*/
{
POC_MANAGER p = ((PHELPER_CONTEXT)OcManagerContext)->OcManager;
return(p->SetupMode);
}
BOOL
#ifdef UNICODE
OcHelperQuerySelectionStateW(
#else
OcHelperQuerySelectionStateA(
#endif
IN PVOID OcManagerContext,
IN LPCTSTR SubcomponentId,
IN UINT StateType
)
/*++
Routine Description:
Function that can be used at any time.
It is used determine the selection status of a particular subcomponent.
Arguments:
OcManagerContext - supplies OC Manager context information the component gets
from the OcManagerContext field of the OCMANAGER_ROUTINES structure.
SubcomponentId - Supplies a subidentifier meaningful to the component
being called. The OC Manager imposes no semantics on this subidentifier.
StateType - supplies a constant indicating which state is to be returned
(original or current).
Return Value:
Boolean value indicating whether the subcomponent is selected
for installation. If FALSE, GetLastError() will return something other than
NO_ERROR if an error occurred, such as SubcomponentId being invalid.
--*/
{
POC_MANAGER p = ((PHELPER_CONTEXT)OcManagerContext)->OcManager;
OPTIONAL_COMPONENT Oc;
LONG l;
BOOL b;
l = pSetupStringTableLookUpStringEx(
p->ComponentStringTable,
(LPTSTR)SubcomponentId,
STRTAB_CASE_INSENSITIVE,
&Oc,
sizeof(OPTIONAL_COMPONENT)
);
if(l == -1) {
SetLastError(ERROR_INVALID_NAME);
return(FALSE);
}
switch(StateType) {
case OCSELSTATETYPE_ORIGINAL:
b = (Oc.OriginalSelectionState != SELSTATE_NO);
SetLastError(NO_ERROR);
break;
case OCSELSTATETYPE_CURRENT:
b = (Oc.SelectionState != SELSTATE_NO);
SetLastError(NO_ERROR);
break;
case OCSELSTATETYPE_FINAL:
b = (Oc.SelectionState != SELSTATE_NO);
SetLastError(NO_ERROR);
break;
default:
b = FALSE;
SetLastError(ERROR_INVALID_PARAMETER);
break;
}
return(b);
}
#ifdef UNICODE
OcHelperQuerySelectionStateA(
IN PVOID OcManagerContext,
IN LPCSTR SubcomponentId,
IN UINT StateType
)
{
LPCWSTR id;
DWORD d;
BOOL b;
id = pSetupAnsiToUnicode(SubcomponentId);
if(!id) {
SetLastError(ERROR_NOT_ENOUGH_MEMORY);
return(FALSE);
}
b = OcHelperQuerySelectionStateW(OcManagerContext,id,StateType);
d = GetLastError();
pSetupFree(id);
SetLastError(d);
return(b);
}
#endif
UINT
#ifdef UNICODE
OcHelperCallPrivateFunctionW(
#else
OcHelperCallPrivateFunctionA(
#endif
IN PVOID OcManagerContext,
IN LPCTSTR ComponentId,
IN LPCTSTR SubcomponentId,
IN UINT Function,
IN UINT Param1,
IN OUT PVOID Param2,
OUT PUINT Result
)
/*++
Routine Description:
Function that can be used at any time while a component is
processing any Interface function. It is used to call another component's
interface entry point to perform some private function. This function
cannot be used to call a standard interface function, nor can it be used
to call a function in the DLL of the component making the call.
Arguments:
OcManagerContext - supplies OC Manager context information the component gets
from the OcManagerContext field of the OCMANAGER_ROUTINES structure.
ComponentId - Supplies the short descriptive name of the component
(as specified in OC.INF) to be called. This may not be the name of
the current component.
SubcomponentId - Supplies a subidentifier meaningful to the component
being called. The OC Manager imposes no semantics on this subidentifier.
Function - Supplies a function code meaningful to the component being called.
This may not be one of the standard interface function codes.
Param1, Param2 - Supply values meaningful to the component being called.
The OC Manager imposes no semantics on these values.
Result - If the OC Manager is successful in calling the other component,
then this receives the return value from the other component's
interface routine.
Return Value:
Win32 error code indicating outcome. If NO_ERROR, then the other component
was called and the result is stored in Result. If not NO_ERROR,
then the other component was not called.
ERROR_BAD_ENVIRONMENT - the function was called when the component is not
processing an interface routine, or the caller is attempting to
call a routine in itself.
ERROR_INVALID_FUNCTION - Function is less then OC_PRIVATE_BASE.
ERROR_ACCESS_DENIED - the requested component has no interface entry point.
--*/
{
POC_MANAGER p = ((PHELPER_CONTEXT)OcManagerContext)->OcManager;
BOOL b;
LONG l;
UINT i;
OPTIONAL_COMPONENT OtherOc;
LONG PreviousCurrentComponentStringId;
//
// Validate that we are processing an interface function and
// that the requested function is not a standard function,
// and that the caller wants to call a different component.
//
if(Function < OC_PRIVATE_BASE) {
return(ERROR_INVALID_FUNCTION);
}
l = pSetupStringTableLookUpStringEx(
p->ComponentStringTable,
(PTSTR)ComponentId,
STRTAB_CASE_INSENSITIVE,
&OtherOc,
sizeof(OPTIONAL_COMPONENT)
);
if(l == -1) {
return(ERROR_INVALID_FUNCTION);
}
//
// Make sure the component is top-level.
//
for(b=FALSE,i=0; !b && (i<p->TopLevelOcCount); i++) {
if(p->TopLevelOcStringIds[i] == l) {
b = TRUE;
}
}
if((l == p->CurrentComponentStringId) || (p->CurrentComponentStringId == -1) || !b) {
return(ERROR_BAD_ENVIRONMENT);
}
//
// Make sure the component has an entry point.
//
if(!OtherOc.InstallationRoutine) {
return(ERROR_ACCESS_DENIED);
}
//
// Call the other component.
//
#ifdef UNICODE
//
// If necessary, convert component and subcomponent to ansi
//
if(OtherOc.Flags & OCFLAG_ANSI) {
LPCSTR comp,subcomp;
comp = pSetupUnicodeToAnsi(ComponentId);
if(!comp) {
return(ERROR_NOT_ENOUGH_MEMORY);
}
if(SubcomponentId) {
subcomp = pSetupUnicodeToAnsi(SubcomponentId);
if(!subcomp) {
pSetupFree(comp);
return(ERROR_NOT_ENOUGH_MEMORY);
}
} else {
subcomp = NULL;
}
PreviousCurrentComponentStringId = p->CurrentComponentStringId;
p->CurrentComponentStringId = l;
*Result = CallComponent(p, &OtherOc, comp, subcomp, Function, Param1, Param2);
pSetupFree(comp);
if(subcomp) {
pSetupFree(subcomp);
}
} else
#endif
{
PreviousCurrentComponentStringId = p->CurrentComponentStringId;
p->CurrentComponentStringId = l;
*Result = CallComponent(p, &OtherOc, ComponentId, SubcomponentId, Function, Param1, Param2);
}
p->CurrentComponentStringId = PreviousCurrentComponentStringId;
return(NO_ERROR);
}
#ifdef UNICODE
UINT
OcHelperCallPrivateFunctionA(
IN PVOID OcManagerContext,
IN LPCSTR ComponentId,
IN LPCSTR SubcomponentId,
IN UINT Function,
IN UINT Param1,
IN OUT PVOID Param2,
OUT PUINT Result
)
/*++
Routine Description:
ANSI version of OcHelperCallPrivateFunction().
Arguments:
Return Value:
--*/
{
LPCWSTR comp,subcomp;
UINT u;
comp = pSetupAnsiToUnicode(ComponentId);
if(!comp) {
u = ERROR_NOT_ENOUGH_MEMORY;
goto c0;
}
if(SubcomponentId) {
subcomp = pSetupAnsiToUnicode(SubcomponentId);
if(!subcomp) {
u = ERROR_NOT_ENOUGH_MEMORY;
goto c1;
}
} else {
subcomp = NULL;
}
u = OcHelperCallPrivateFunctionW(
OcManagerContext,
comp,
subcomp,
Function,
Param1,
Param2,
Result
);
if(subcomp) {
pSetupFree(subcomp);
}
c1:
pSetupFree(comp);
c0:
return(u);
}
#endif
BOOL
OcHelperConfirmCancel(
IN HWND ParentWindow
)
/*++
Routine Description:
Ask the user whether he's sure he wants to cancel.
Arguments:
ParentWindow - supplies window handle of parent window for ui
Return Value:
TRUE if user wants to cancel. FALSE if not.
--*/
{
TCHAR Message[1000];
TCHAR Caption[200];
int i;
FormatMessage(
FORMAT_MESSAGE_FROM_HMODULE,
MyModuleHandle,
MSG_QUERY_CANCEL,
0,
Message,
sizeof(Message)/sizeof(TCHAR),
NULL
);
LoadString(MyModuleHandle,IDS_SETUP,Caption,sizeof(Caption)/sizeof(TCHAR));
i = MessageBox(
ParentWindow,
Message,
Caption,
MB_YESNO | MB_ICONQUESTION | MB_DEFBUTTON2 | MB_SETFOREGROUND
);
return(i == IDYES);
}
HWND
OcHelperQueryWizardDialogHandle(
IN PVOID OcManagerContext
)
{
UNREFERENCED_PARAMETER(OcManagerContext);
return(WizardDialogHandle);
}
BOOL
OcHelperSetReboot(
IN PVOID OcManagerContext,
IN BOOL Reserved
)
{
POC_MANAGER p = ((PHELPER_CONTEXT)OcManagerContext)->OcManager;
UNREFERENCED_PARAMETER(Reserved);
p->Callbacks.SetReboot();
return(FALSE);
}
VOID
OcRememberWizardDialogHandle(
IN PVOID OcManagerContext,
IN HWND DialogHandle
)
/*++
Routine Description:
This routine is called by the OC Manager client to inform the
common library of the wizard's dialog handle.
We will also turn around and notify all top-level components
of the wizard dialog handle.
Before doing so, we write the title into the window header.
Arguments:
OcManagerContext - value returned from OcInitialize().
DialogHandle - supplies the dialog handle of the wizard.
Return Value:
None.
--*/
{
UINT i;
POC_MANAGER OcManager;
WizardDialogHandle = DialogHandle;
OcManager = OcManagerContext;
if (*OcManager->WindowTitle) {
SetWindowText(WizardDialogHandle, OcManager->WindowTitle);
}
for(i=0; i<OcManager->TopLevelOcCount; i++) {
OcInterfaceWizardCreated(OcManager,OcManager->TopLevelOcStringIds[i],DialogHandle);
}
}
HINF
OcHelperGetInfHandle(
IN UINT InfIndex,
IN PVOID OcManagerContext
)
/*++
Routine Description:
This routine returns a handle to a well-known inf file that
has been opened by oc manager.
Arguments:
InfIndex - supplies value indicating which inf's handle is desired
OcManagerContext - value returned from OcInitialize().
Return Value:
Handle to INF, NULL if error.
--*/
{
POC_MANAGER OcManager = ((PHELPER_CONTEXT)OcManagerContext)->OcManager;
return((InfIndex == INFINDEX_UNATTENDED) ? OcManager->UnattendedInf : NULL);
}
BOOL
OcHelperClearExternalError (
IN POC_MANAGER OcManager,
IN LONG ComponentId,
IN LONG SubcomponentId OPTIONAL
)
{
LONG l;
DWORD d;
HKEY hKey;
LPCTSTR pValueName;
//
// If Subcomponetid is Zero then use the ComponentId
//
if ( SubcomponentId ) {
pValueName = pSetupStringTableStringFromId(OcManager->ComponentStringTable,SubcomponentId);
} else {
pValueName = pSetupStringTableStringFromId(OcManager->ComponentStringTable,ComponentId);
}
if (!pValueName) {
return ERROR_FILE_NOT_FOUND;
}
//
// Attempt to open the key if successful delete it
//
l = RegOpenKeyEx(
HKEY_LOCAL_MACHINE,
szOcManagerErrors,
0,
KEY_QUERY_VALUE | KEY_SET_VALUE,
&hKey
);
//
// If an errror Key does not exist
//
if(l != NO_ERROR) {
d = l;
goto c1;
}
//
// Delete this Subcomponent Key
//
l = RegDeleteValue( hKey, pValueName);
d = l;
RegCloseKey(hKey);
c1:
SetLastError(d);
return(d == NO_ERROR);
}
BOOL
_OcHelperReportExternalError(
IN PVOID OcManagerContext,
IN LPCTSTR ComponentId,
IN LPCTSTR SubcomponentId, OPTIONAL
IN DWORD_PTR MessageId,
IN DWORD Flags,
IN va_list *arglist,
IN BOOL NativeCharWidth
)
{
POC_MANAGER OcManager = ((PHELPER_CONTEXT)OcManagerContext)->OcManager;
HMODULE Module;
OPTIONAL_COMPONENT Oc;
LONG l;
DWORD d;
DWORD flags;
LPTSTR MessageBuffer=NULL;
LPCTSTR KeyValue;
TCHAR fallback[20];
HKEY hKey;
DWORD Size;
TCHAR *p;
BOOL fmErr = FALSE;
if ( ComponentId == NULL ) {
//
// if Component ID is null use the Suite Inf name
//
KeyValue = OcManager->SuiteName;
//
// if the message isn't preformatted, we have to retreive an error
// from a component dll. But if a component id wasn't specified, then
// we cannot retrieve from a comopnent dll. In that case, assume
// that the message is to be retreived from the main OCM dll.
//
ZeroMemory( &Oc, sizeof(OPTIONAL_COMPONENT));
if ((Flags & ERRFLG_PREFORMATTED) == 0) {
Flags |= ERRFLG_OCM_MESSAGE;
}
} else {
//
// If SubcomponentId was Optional use the ComponentId
//
if ( SubcomponentId ) {
KeyValue = SubcomponentId;
} else {
KeyValue = ComponentId;
}
// Look up the string in the master component table.
// If it's not there, bail now.
//
l = pSetupStringTableLookUpStringEx(
OcManager->ComponentStringTable,
(PTSTR)ComponentId,
STRTAB_CASE_INSENSITIVE,
&Oc,
sizeof(OPTIONAL_COMPONENT)
);
if(l == -1) {
d = ERROR_INVALID_DATA;
goto c0;
}
}
//
// Determine flags for FormatMessage
//
flags = FORMAT_MESSAGE_ALLOCATE_BUFFER;
if(Flags & ERRFLG_SYSTEM_MESSAGE) {
flags |= FORMAT_MESSAGE_FROM_SYSTEM;
} else {
flags |= FORMAT_MESSAGE_FROM_HMODULE;
}
if(Flags & ERRFLG_IGNORE_INSERTS) {
flags |= FORMAT_MESSAGE_IGNORE_INSERTS;
}
if(Flags & ERRFLG_OCM_MESSAGE) {
flags |= FORMAT_MESSAGE_FROM_HMODULE;
}
//
// Format the message.
//
#ifdef UNICODE
if(!NativeCharWidth) {
if (Flags & ERRFLG_PREFORMATTED ) {
MessageBuffer = (LPTSTR) MessageId;
} else {
try {
d = FormatMessageA(
flags,
Flags & ERRFLG_OCM_MESSAGE?MyModuleHandle:Oc.InstallationDll, // ignored if system message
(DWORD)MessageId,
0,
(LPSTR)&MessageBuffer,
0,
arglist
);
} except(EXCEPTION_EXECUTE_HANDLER) {
fmErr = TRUE;
}
if (fmErr) {
d = ERROR_INVALID_DATA;
goto c0;
}
if(d) {
//
// Need to convert resulting message from ansi to unicode
// so we can deal with it below. The LocalAlloc below overallocates
// if some of the ansi chars are double-byte chars, too bad.
//
l = lstrlen(MessageBuffer)+1;
if(p = (PVOID)LocalAlloc(LMEM_FIXED,l*sizeof(WCHAR))) {
d = MultiByteToWideChar(CP_ACP,MB_PRECOMPOSED,(LPSTR)MessageBuffer,-1,p,l);
if ( ! Flags & ERRFLG_PREFORMATTED ) {
LocalFree((HLOCAL)MessageBuffer);
}
if(d) {
MessageBuffer = p;
} else {
LocalFree((HLOCAL)p);
}
} else {
if ( ! Flags & ERRFLG_PREFORMATTED ) {
LocalFree((HLOCAL)MessageBuffer);
}
d = 0;
}
}
}
} else
#endif
{
if (Flags & ERRFLG_PREFORMATTED ) {
MessageBuffer = (LPTSTR) MessageId;
d = 1;
} else {
try {
d = FormatMessage(
flags,
Flags & ERRFLG_OCM_MESSAGE?MyModuleHandle:Oc.InstallationDll, // ignored if system message
(DWORD)MessageId,
0,
(LPTSTR)&MessageBuffer,
0,
arglist
);
} except(EXCEPTION_EXECUTE_HANDLER) {
fmErr = TRUE;
}
if (fmErr) {
d = ERROR_INVALID_DATA;
goto c0;
}
}
if(!d) {
//
// Put *something* in there
//
wsprintf(
fallback,
TEXT("#%s0x%x"),
(Flags & ERRFLG_SYSTEM_MESSAGE) ? TEXT("SYS") : TEXT(""),
MessageId
);
MessageBuffer = fallback;
}
}
l = RegCreateKeyEx(
HKEY_LOCAL_MACHINE,
szOcManagerErrors,
0,
NULL,
REG_OPTION_NON_VOLATILE,
KEY_QUERY_VALUE | KEY_SET_VALUE,
NULL,
&hKey,
&d
);
if(l != NO_ERROR) {
d = l;
goto c1;
}
//
// Figure out how large of a buffer we need to encompass
// the existing key and the string we're going to add to the end.
//
l = RegQueryValueEx(hKey,KeyValue,NULL,NULL,NULL,&Size);
if(l == NO_ERROR) {
if(Size == 0) {
Size = 1; // terminating nul
}
} else {
Size = sizeof(TCHAR); // terminating nul
}
Size += ((lstrlen(MessageBuffer) + 1) * sizeof(TCHAR));
//
// Allocate a buffer, read in the existing entry, and add the string
// to the end.
//
p = (PVOID)LocalAlloc(LMEM_FIXED,Size);
if(!p) {
d = ERROR_NOT_ENOUGH_MEMORY;
goto c2;
}
l = RegQueryValueEx(hKey,KeyValue,NULL,NULL,(BYTE *)p,&Size);
if(l == NO_ERROR) {
Size /= sizeof(TCHAR);
if(Size == 0) {
Size = 1;
}
} else {
Size = 1;
}
lstrcpy(p+(Size-1),MessageBuffer);
Size += lstrlen(MessageBuffer);
p[Size++] = 0;
d = RegSetValueEx(hKey,KeyValue,0,REG_MULTI_SZ,(CONST BYTE *)p,Size*sizeof(TCHAR));
LocalFree((HLOCAL)p);
c2:
RegCloseKey(hKey);
c1:
if(MessageBuffer && MessageBuffer != fallback && MessageBuffer != (LPTSTR)MessageId ) {
LocalFree((HLOCAL)MessageBuffer);
d = 0;
}
c0:
SetLastError(d);
return(d == NO_ERROR);
}
BOOL
pOcHelperReportExternalError(
IN POC_MANAGER OcManager,
IN LONG ComponentId,
IN LONG SubcomponentId, OPTIONAL
IN DWORD_PTR MessageId,
IN DWORD Flags,
...
)
{
BOOL b;
DWORD d;
va_list arglist;
HELPER_CONTEXT OcManagerContext;
OcManagerContext.OcManager = OcManager;
va_start(arglist,Flags);
b = _OcHelperReportExternalError(
&OcManagerContext,
ComponentId ? pSetupStringTableStringFromId(OcManager->ComponentStringTable,ComponentId):NULL,
SubcomponentId ? pSetupStringTableStringFromId(OcManager->ComponentStringTable,SubcomponentId):NULL,
MessageId,
Flags,
&arglist,
TRUE
);
d = GetLastError();
va_end(arglist);
SetLastError(d);
return(b);
}
BOOL
#ifdef UNICODE
OcHelperReportExternalErrorW(
#else
OcHelperReportExternalErrorA(
#endif
IN PVOID OcManagerContext,
IN LPCTSTR ComponentId,
IN LPCTSTR SubcomponentId, OPTIONAL
IN DWORD_PTR MessageId,
IN DWORD Flags,
...
)
{
BOOL b;
DWORD d;
va_list arglist;
va_start(arglist,Flags);
b = _OcHelperReportExternalError(
OcManagerContext,
ComponentId,
SubcomponentId,
MessageId,
Flags,
&arglist,
TRUE
);
d = GetLastError();
va_end(arglist);
SetLastError(d);
return(b);
}
#ifdef UNICODE
BOOL
OcHelperReportExternalErrorA(
IN PVOID OcManagerContext,
IN LPCSTR ComponentId,
IN LPCSTR SubcomponentId, OPTIONAL
IN DWORD_PTR MessageId,
IN DWORD Flags,
...
)
{
LPCWSTR componentId,subcomponentId;
DWORD d;
BOOL b;
va_list arglist;
if (ComponentId) {
componentId = pSetupAnsiToUnicode(ComponentId);
if(!componentId) {
d = ERROR_NOT_ENOUGH_MEMORY;
b = FALSE;
goto e0;
}
} else {
componentId = NULL;
}
if(SubcomponentId) {
subcomponentId = pSetupAnsiToUnicode(SubcomponentId);
if(!subcomponentId) {
d = ERROR_NOT_ENOUGH_MEMORY;
b = FALSE;
goto e1;
}
} else {
subcomponentId = NULL;
}
va_start(arglist,Flags);
b = _OcHelperReportExternalError(
OcManagerContext,
componentId,
subcomponentId,
MessageId,
Flags,
&arglist,
FALSE
);
d = GetLastError();
va_end(arglist);
if(subcomponentId) {
pSetupFree(subcomponentId);
}
e1:
if (componentId) {
pSetupFree(componentId);
}
e0:
SetLastError(d);
return(b);
}
#endif
#if 0
BOOL
#ifdef UNICODE
OcHelperSetSelectionStateW(
#else
OcHelperSetSelectionStateA(
#endif
IN PVOID OcManagerContext,
IN LPCTSTR SubcomponentId,
IN UINT WhichState,
IN UINT NewState
)
/*++
Routine Description:
Function that can be used at any time.
It is used determine the selection status of a particular subcomponent.
Arguments:
OcManagerContext - supplies OC Manager context information the component gets
from the OcManagerContext field of the OCMANAGER_ROUTINES structure.
SubcomponentId - Supplies a subidentifier meaningful to the component
being called. The OC Manager imposes no semantics on this subidentifier.
StateType - supplies a constant indicating which state is to be returned
(original or current).
Return Value:
Boolean value indicating whether the subcomponent is selected
for installation. If FALSE, GetLastError() will return something other than
NO_ERROR if an error occurred, such as SubcomponentId being invalid.
--*/
{
POC_MANAGER p = ((PHELPER_CONTEXT)OcManagerContext)->OcManager;
OPTIONAL_COMPONENT Oc;
LONG l;
BOOL b;
UINT *state;
l = pSetupStringTableLookUpStringEx(
p->ComponentStringTable,
(LPTSTR)SubcomponentId,
STRTAB_CASE_INSENSITIVE,
&Oc,
sizeof(OPTIONAL_COMPONENT)
);
if(l == -1) {
SetLastError(ERROR_INVALID_NAME);
return(FALSE);
}
switch (WhichState) {
case OCSELSTATETYPE_ORIGINAL:
state = &Oc.
break;
case OCSELSTATETYPE_CURRENT:
state = &Oc.
break;
case OCSELSTATETYPE_FINAL:
state = &Oc.
break;
default:
SetLastError(ERROR_INVALID_PARAMETER);
return FALSE;
}
if (NewState != SubcompOn && NewState != SubcompOff) {
SetLastError(ERROR_INVALID_PARAMETER);
return FALSE;
}
*state = NewState;
pOcSetStatesStringWorker(l, NewState, OcPage);
return(b);
}
#endif
BOOL
#ifdef UNICODE
OcLogErrorW(
#else
OcLogErrorA(
#endif
IN PVOID OcManagerContext,
IN DWORD ErrorLevel,
IN LPCTSTR Msg,
...
)
{
TCHAR sz[5000];
va_list arglist;
POC_MANAGER p = ((PHELPER_CONTEXT)OcManagerContext)->OcManager;
va_start(arglist, Msg);
_vstprintf(sz, Msg, arglist);
va_end(arglist);
return p->Callbacks.LogError(ErrorLevel, sz);
}
#ifdef UNICODE
BOOL
OcLogErrorA(
IN PVOID OcManagerContext,
IN DWORD ErrorLevel,
IN LPCSTR Msg,
...
)
{
PWSTR p;
BOOL b;
char sz[5000];
va_list arglist;
va_start(arglist, Msg);
vsprintf(sz, Msg, arglist);
va_end(arglist);
p = pSetupAnsiToUnicode(sz);
if (p) {
b = OcLogErrorW(OcManagerContext, ErrorLevel, p);
pSetupFree(p);
} else {
b = FALSE;
}
return(b);
}
#endif
//
// Now that we've got all the routines defined, we can build a table
// of routines.
//
OCMANAGER_ROUTINESA HelperRoutinesA = { NULL, // Context, filled in later.
OcHelperTickGauge,
OcHelperSetProgressTextA,
OcHelperSetPrivateDataA,
OcHelperGetPrivateDataA,
OcHelperSetSetupMode,
OcHelperGetSetupMode,
OcHelperQuerySelectionStateA,
OcHelperCallPrivateFunctionA,
OcHelperConfirmCancel,
OcHelperQueryWizardDialogHandle,
OcHelperSetReboot,
OcHelperGetInfHandle,
OcHelperReportExternalErrorA,
OcHelperShowHideWizardPage
};
#ifdef UNICODE
OCMANAGER_ROUTINESW HelperRoutinesW = { NULL, // Context, filled in later.
OcHelperTickGauge,
OcHelperSetProgressTextW,
OcHelperSetPrivateDataW,
OcHelperGetPrivateDataW,
OcHelperSetSetupMode,
OcHelperGetSetupMode,
OcHelperQuerySelectionStateW,
OcHelperCallPrivateFunctionW,
OcHelperConfirmCancel,
OcHelperQueryWizardDialogHandle,
OcHelperSetReboot,
OcHelperGetInfHandle,
OcHelperReportExternalErrorW,
OcHelperShowHideWizardPage
};
#endif
EXTRA_ROUTINESA ExtraRoutinesA = { sizeof(EXTRA_ROUTINESA),
OcLogErrorA
};
#ifdef UNICODE
EXTRA_ROUTINESW ExtraRoutinesW = { sizeof(EXTRA_ROUTINESW),
OcLogErrorW
};
#endif