/*++ Copyright (c) 1996 Microsoft Corporation Module Name: regmigrt.c Abstract: Registry migration routines Author: Ted Miller (tedm) 12-Apr-1996 Revision History: --*/ #include "precomp.h" #pragma hdrstop typedef enum { AddQuotesNone, AddQuotesNormal, AddQuotesOpenNoClose, AddQuotesNoOpenOrClose, } AddQuotesOp; BOOL RetrieveMessageIntoBufferV( IN UINT MessageId, OUT PTSTR Buffer, IN UINT BufferSizeChars, IN va_list *arglist ) { DWORD d; d = FormatMessage( FORMAT_MESSAGE_FROM_HMODULE | FORMAT_MESSAGE_FROM_SYSTEM, hInst, MessageId, 0, Buffer, BufferSizeChars, arglist ); if(!d) { d = FormatMessage( FORMAT_MESSAGE_FROM_HMODULE | FORMAT_MESSAGE_ARGUMENT_ARRAY, hInst, MSG_NOT_FOUND, 0, Buffer, BufferSizeChars, (va_list *)&MessageId ); if(!d) { return FALSE; } } return TRUE; } DWORD WriteText( IN HANDLE FileHandle, IN UINT MessageId, ... ) { TCHAR Message[2048]; CHAR message[4096]; va_list arglist; DWORD Written; BOOL b; va_start(arglist,MessageId); b = RetrieveMessageIntoBufferV( MessageId, Message, sizeof(Message)/sizeof(Message[0]), &arglist ); va_end(arglist); if(!b) return ERROR_INVALID_PARAMETER; #ifdef UNICODE Written = (DWORD)WideCharToMultiByte( CP_ACP, 0, Message, lstrlen(Message), message, sizeof(message), NULL, NULL ); #else lstrcpyn(message,Message,sizeof(message)); Written = lstrlen(message); #endif b = WriteFile(FileHandle,message,Written,&Written,NULL); return(b ? NO_ERROR : GetLastError()); } DWORD FlushGenInfLineBuf( IN OUT PINFFILEGEN Context, IN HANDLE File ) { CHAR TransBuf[INFLINEBUFLEN*2]; DWORD rc; PVOID Buffer; DWORD Size; BOOL b; Buffer = TransBuf; #ifdef UNICODE Size = WideCharToMultiByte( CP_ACP, 0, Context->LineBuf, Context->LineBufUsed, TransBuf, sizeof(TransBuf), NULL, NULL ); #else lstrcpyn(TransBuf,Context->LineBuf,sizeof(TransBuf)); Size = Context->LineBufUsed; #endif if(WriteFile(File,Buffer,Size,&rc,NULL)) { rc = NO_ERROR; Context->LineBufUsed = 0; } else { rc = GetLastError(); } return(rc); } DWORD __inline GenInfWriteChar( IN OUT PINFFILEGEN Context, IN HANDLE File, IN TCHAR Char ) { DWORD rc; PVOID Buffer; Context->LineBuf[Context->LineBufUsed++] = Char; rc = (Context->LineBufUsed == INFLINEBUFLEN) ? FlushGenInfLineBuf(Context,File) : NO_ERROR; return(rc); } DWORD GenInfWriteString( IN OUT PINFFILEGEN Context, IN HANDLE File, IN LPCTSTR String, IN AddQuotesOp AddQuotes ) { DWORD rc; TCHAR CONST *p; if((AddQuotes == AddQuotesNormal) || (AddQuotes == AddQuotesOpenNoClose)) { rc = GenInfWriteChar(Context,File,TEXT('\"')); if(rc != NO_ERROR) { return(rc); } } for(p=String; *p; p++) { rc = GenInfWriteChar(Context,File,*p); if(rc != NO_ERROR) { return(rc); } if((*p == TEXT('\"')) && (AddQuotes != AddQuotesNone)) { rc = GenInfWriteChar(Context,File,TEXT('\"')); if(rc != NO_ERROR) { return(rc); } } } if(AddQuotes == AddQuotesNormal) { rc = GenInfWriteChar(Context,File,TEXT('\"')); if(rc != NO_ERROR) { return(rc); } } return(NO_ERROR); } DWORD CreateAndOpenTempFile( IN LPCTSTR Path, IN LPCTSTR HeaderLine, OPTIONAL OUT HANDLE *Handle, OUT PTSTR Filename ) { HANDLE h; DWORD rc; // // Note that this creates the file. // if(!GetTempFileName(Path,TEXT("$IF"),0,Filename)) { rc = GetLastError(); goto c0; } h = CreateFile( Filename, GENERIC_WRITE, FILE_SHARE_READ, NULL, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL ); if(h == INVALID_HANDLE_VALUE) { rc = GetLastError(); goto c1; } if(HeaderLine) { rc = WriteText(h,MSG_INF_SINGLELINE,HeaderLine); if(rc != NO_ERROR) { goto c2; } } *Handle = h; return(NO_ERROR); c2: CloseHandle(h); c1: DeleteFile(Filename); c0: return(rc); } DWORD InfCreateSection( IN LPCTSTR SectionName, IN OUT PINFFILEGEN *Context ) { PTSTR Buffer; DWORD rc; Buffer = MALLOC( (lstrlen(SectionName) + 3)*sizeof(TCHAR) ); if( !Buffer ) { return ERROR_NOT_ENOUGH_MEMORY; } lstrcpy( Buffer, TEXT("[") ); lstrcat( Buffer, SectionName ); lstrcat( Buffer, TEXT("]") ); rc = WriteText((*Context)->FileHandle,MSG_INF_SINGLELINE,Buffer); FREE( Buffer ); return(rc); } DWORD InfStart( IN LPCTSTR InfName, IN LPCTSTR Directory, OUT PINFFILEGEN *Context ) { TCHAR InfFileName[MAX_PATH]; DWORD d; DWORD rc; PINFFILEGEN context; UCHAR UnicodeMark[2]; PTSTR p; DWORD BytesWritten = 0; // // Allocate some context. // context = MALLOC(sizeof(INFFILEGEN)); if(!context) { rc = ERROR_NOT_ENOUGH_MEMORY; goto c0; } ZeroMemory(context,sizeof(INFFILEGEN)); // // We'll create a unique inf name in the given directory // to use as the output inf. The directory itself will // become the oem file root. // if(!GetFullPathName(Directory,MAX_PATH,context->FileName,&p)) { rc = GetLastError(); goto c1; } ConcatenatePaths(context->FileName,InfName,MAX_PATH); SetFileAttributes(context->FileName, FILE_ATTRIBUTE_NORMAL); DeleteFile(context->FileName); // // Create the output file. // context->FileHandle = CreateFile( context->FileName, GENERIC_WRITE, FILE_SHARE_READ, NULL, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL ); if(context->FileHandle == INVALID_HANDLE_VALUE) { rc = GetLastError(); goto c1; } // // Write out header for inf file. // WriteFile(context->FileHandle, INF_FILE_HEADER, strlen(INF_FILE_HEADER), &BytesWritten, NULL); rc = GetLastError(); if(rc != NO_ERROR) { goto c5; } *Context = context; return(NO_ERROR); c5: CloseHandle(context->FileHandle); DeleteFile(context->FileName); c1: FREE(context); c0: return(rc); } DWORD InfEnd( IN OUT PINFFILEGEN *Context ) { PINFFILEGEN context; DWORD rc; HANDLE h; DWORD Size; context = *Context; *Context = NULL; h = context->FileHandle; rc = NO_ERROR; CloseHandle(h); if(rc != NO_ERROR) { DeleteFile(context->FileName); } FREE(context); return(rc); } DWORD pInfRegLineCommon( IN OUT PINFFILEGEN Context, IN HANDLE OutputFile, IN HKEY Key, IN LPCTSTR Subkey, IN LPCTSTR Value OPTIONAL ) { LPCTSTR RootSpec; LPCTSTR SubkeySpec; DWORD rc; if(Subkey[0] == TEXT('\\')) { Subkey++; } // // Figure out the root key spec. // switch((ULONG_PTR)Key) { case (ULONG_PTR)HKEY_LOCAL_MACHINE: // // Check for HKEY_CLASSES_ROOT // if(_tcsnicmp(Subkey,TEXT("SOFTWARE\\Classes"),16)) { RootSpec = TEXT("HKLM"); SubkeySpec = Subkey; } else { RootSpec = TEXT("HKCR"); SubkeySpec = Subkey+16; if(*SubkeySpec == TEXT('\\')) { SubkeySpec++; } } break; case (ULONG_PTR)HKEY_CURRENT_USER: RootSpec = TEXT("HKCU"); SubkeySpec = Subkey; break; case (ULONG_PTR)HKEY_CLASSES_ROOT: RootSpec = TEXT("HKCR"); SubkeySpec = Subkey; break; default: // // Value we can't express via inf. // Use HKEY_ROOT but also write out a comment incidating // that there's a problem // RootSpec = TEXT("HKR"); SubkeySpec = Subkey; Context->SawBogusOp = TRUE; rc = FlushGenInfLineBuf(Context,OutputFile); if(rc != NO_ERROR) { return(rc); } rc = WriteText(OutputFile,MSG_INF_BAD_REGSPEC_1); if(rc != NO_ERROR) { return(rc); } break; } rc = GenInfWriteString(Context,OutputFile,RootSpec,AddQuotesNone); if(rc == NO_ERROR) { rc = GenInfWriteChar(Context,OutputFile,TEXT(',')); if(rc == NO_ERROR) { rc = GenInfWriteString(Context,OutputFile,SubkeySpec,AddQuotesNormal); if((rc == NO_ERROR) && Value) { rc = GenInfWriteChar(Context,OutputFile,TEXT(',')); if(rc == NO_ERROR) { rc = GenInfWriteString(Context,OutputFile,Value,AddQuotesNormal); } } } } return(rc); } DWORD InfRecordAddReg( IN OUT PINFFILEGEN Context, IN HKEY Key, IN LPCTSTR Subkey, IN LPCTSTR Value, OPTIONAL IN DWORD DataType, IN PVOID Data, IN DWORD DataLength, IN BOOL SetNoClobberFlag ) { DWORD rc; DWORD Flags; PTSTR p; DWORD d; int LineLen; TCHAR NumStr[24]; // // Figure out flags based on data type. // The flags dword is built as two halves depending on whether // data is string or binary in nature. // // We do this before we write out the actual line // since that routine might also write a warning if a bogus root key // is specified. // switch(DataType) { case REG_SZ: Flags = FLG_ADDREG_TYPE_SZ; break; case REG_EXPAND_SZ: Flags = FLG_ADDREG_TYPE_EXPAND_SZ; break; case REG_MULTI_SZ: Flags = FLG_ADDREG_TYPE_MULTI_SZ; break; case REG_DWORD: Flags = FLG_ADDREG_TYPE_DWORD; break; //case REG_NONE: // Flags = FLG_ADDREG_TYPE_NONE; // break; case REG_NONE: Flags = FLG_ADDREG_KEYONLY; break; default: // // Arbitrary binary data. Better hope the data type doesn't overflow // 16 bits. // if(DataType > 0xffff) { Context->SawBogusOp = TRUE; rc = FlushGenInfLineBuf(Context,Context->FileHandle); if(rc != NO_ERROR) { return(rc); } rc = WriteText(Context->FileHandle,MSG_INF_BAD_REGSPEC_2); if(rc != NO_ERROR) { return(rc); } DataType = REG_BINARY; } Flags = FLG_ADDREG_BINVALUETYPE | (DataType << 16); break; } rc = pInfRegLineCommon(Context,Context->FileHandle,Key,Subkey,Value); if(rc != NO_ERROR) { return(rc); } if(Flags == FLG_ADDREG_KEYONLY) { rc = GenInfWriteChar(Context,Context->FileHandle,TEXT(',')); if(rc != NO_ERROR) { return(rc); } } // // _stprintf(NumStr,TEXT(",%0#10lx"),Flags | 0x00000002); // Force NO_CLOBBER // // _stprintf(NumStr,TEXT(",%0#10lx"),Flags); wsprintf(NumStr, TEXT(",%#08lx"), SetNoClobberFlag? (Flags | 0x00000002) : Flags); rc = GenInfWriteString(Context,Context->FileHandle,NumStr,AddQuotesNone); if(rc != NO_ERROR) { return(rc); } // // Now we need to write out the data itself. // How we do this is dependent on the data type. // switch(DataType) { case REG_SZ: case REG_EXPAND_SZ: // // Single string. Ignore data length. // rc = GenInfWriteChar(Context,Context->FileHandle,TEXT(',')); if(rc == NO_ERROR) { rc = GenInfWriteString(Context,Context->FileHandle,Data,AddQuotesNormal); } break; case REG_DWORD: // // Write out as a dword. // wsprintf(NumStr,TEXT(",%u"),*(DWORD UNALIGNED *)Data); rc = GenInfWriteString(Context,Context->FileHandle,NumStr,AddQuotesNone); break; case REG_MULTI_SZ: // // Write out each string. // for(p=Data; (rc==NO_ERROR) && *p; p+=lstrlen(p)+1) { rc = GenInfWriteChar(Context,Context->FileHandle,TEXT(',')); if(rc == NO_ERROR) { rc = GenInfWriteString(Context,Context->FileHandle,p,AddQuotesNormal); } } break; case REG_NONE: // // Don't create a value entry // break; default: // // Treat as binary. If we have any data at all start a new line. // if(DataLength) { rc = GenInfWriteString(Context,Context->FileHandle,TEXT(",\\\r\n "),AddQuotesNone); } LineLen = 0; for(d=0; (rc==NO_ERROR) && (dFileHandle,TEXT(",\\\r\n "),AddQuotesNone); LineLen = 0; } if(rc == NO_ERROR) { if(LineLen) { rc = GenInfWriteChar(Context,Context->FileHandle,TEXT(',')); } if(rc == NO_ERROR) { wsprintf(NumStr,TEXT("%02x"),((PBYTE)Data)[d]); rc = GenInfWriteString(Context,Context->FileHandle,NumStr,AddQuotesNone); LineLen++; } } } break; } if(rc == NO_ERROR) { rc = GenInfWriteString(Context,Context->FileHandle,TEXT("\r\n"),AddQuotesNone); if(rc == NO_ERROR) { rc = FlushGenInfLineBuf(Context,Context->FileHandle); } } return(rc); } #if 0 DWORD InfRecordDelReg( IN OUT PINFFILEGEN Context, IN HKEY Key, IN LPCTSTR Subkey, IN LPCTSTR Value OPTIONAL ) { DWORD rc; rc = pInfRegLineCommon(Context,Context->DelRegFile,Key,Subkey,Value); if(rc == NO_ERROR) { rc = GenInfWriteString(Context,Context->DelRegFile,TEXT("\r\n"),AddQuotesNone); if(rc == NO_ERROR) { rc = FlushGenInfLineBuf(Context,Context->DelRegFile); } } return(rc); } #endif