/*++ 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 #include // // 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 && (iTopLevelOcCount); 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; iTopLevelOcCount; 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