# --------------------------------------------------------------------------- # Script: muimake.pm # # (c) 2000 Microsoft Corporation. All rights reserved. # # Purpose: This script creates the mui satallite dlls # # Version: 1.00 (09/2/2000) : (dmiura) Inital port from win2k #--------------------------------------------------------------------- # Set Package package muimake; # Set the script name $ENV{script_name} = 'muimake.pm'; # Set version $VERSION = '1.00'; # Set required perl version require 5.003; # Use section use File::Basename; use IO::File; use lib $ENV{ "RazzleToolPath" }; use lib $ENV{ "RazzleToolPath" } . "\\PostBuildScripts"; use ParseArgs; use GetParams; use LocalEnvEx; use Logmsg; use strict; no strict 'vars'; use HashText; use ParseTable; use File::Copy; use File::Find; use Cwd; use DirHandle; # Require section require Exporter; # Global variable section sub Main { # /\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\ # Begin Main code section # /\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\ # Return when you want to exit on error # # Make sure that text written to STDOUT and STDERR is displayed in correct order # $| = 1; # Check environment variables if (!&CheckEnv()) { wrnmsg ("The environment is not correct for MUI build."); return 1; } # Define some constants if (!&DefineConstants()) { errmsg ("The constants could not be defined."); return 0; } # Get language's LCID and ISO code if (!&GetCodes()) { errmsg ("The language's LCID and ISO code could note be extracted from the CODEFILE."); return 0; } # Make sure directories exist if (!&CheckDirs()) { errmsg ("The required directorys do not exist."); return 0; } # Update mui.inf with the current build number if (!&UpdateMuiinf()) { errmsg ("mui.inf could not be updated with the correct build number."); } # # Note: We also extract US binaries for the purpose of adding resource checksum # Extract files listed in extracts.txt if (!&ExtractCabFiles()) { errmsg ("The files listed in extracts.txt could not be extracted."); } # #Add *.MSI to extracted #Note: We also extract US binaries for the purpose of adding resource checksum # if (!&ExtractMSIFiles()) { errmsg("The files listed in extmsi.txt could not be extracted."); } # Get (filtered) contents of source directory if (!&MakeSourceFileList()) { errmsg ("Could not get the filtered contents of the source directory."); } # Generate resource dlls from the files in the source file list if (!&GenResDlls()) { errmsg (""); } # Rename the files listed in renfile.txt if (!&RenameRenfiles()) { errmsg (""); } # # Copy over the files listed in copyfile.txt # We also add resource checksum to the files # if (!&CopyCopyfiles()) { errmsg (""); } # # Copy over the files from \mui\drop # if (!&CopyDroppedfiles()) { errmsg (""); } # # Copy over the updated server files # if (!&CopyServerFiles()) { errmsg (""); } # Delete the files listed in delfile.txt if (!&DeleteDelfiles()) { errmsg (""); } # # BUG BUG: this is a temporary hack to get past the fact that uddi mui package has a file bullet.gif # that exists both under locbin and where uddi files are supposed to be picked up, we make a copy of this file # and rename it to bulletuddi.gif and will rename it back to bullet.gif during mui installation (uddimui.inf) # if (!&CopyRenameUDDIFile()) { errmsg (""); } # # Note: We also extract US binaries for the purpose of adding resource checksum # Copy over components' files to a separate directory # if (!&CopyComponentfiles()) { errmsg (""); } # # BUG BUG: delete the file we just renamed for uddi # if (!&DeleteRenameUDDIFile()) { errmsg (""); } # Compress the resource dlls (& CHM/CHQ/CNT files) if (!&CompressResDlls()) { errmsg (""); } # Fusion team has changed its MUI manifest implementation # Copy fusion files # if (!&CopyFusionFiles ("$_NTPOSTBLD\\asms", "$TARGETDIR\\asms") || # !&CopyFusionFiles ("$_NTPOSTBLD\\asms", "$COMPDIR\\asms")) { # errmsg(""); # } # Copy MUI tools to release share if (!&CopyMUIRootFiles()) { errmsg(""); } # /\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\ # End Main code section # /\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\ } # sub muimake { &Main(); logmsg("This is a muimake test message"); return 0; } sub CopyRenameUDDIFile { logmsg ("Renaming and copying $UDDIORIGFILE --> $UDDIRENAMEFILE."); $status = system("copy /Y $UDDIORIGFILE $UDDIRENAMEFILE"); if($status) { logmsg ("WARNING: Copy/Rename $UDDIORIGFILE --> $UDDIRENAMEFILE failed!"); } return 1; } sub DeleteRenameUDDIFile { logmsg ("Deleting $UDDIRENAMEFILE file."); $status = system("del /F /Q $UDDIRENAMEFILE"); if($status) { logmsg ("WARNING: cannot find $UDDIRENAMEFILE to delete!"); } return 1; } #----------------------------------------------------------------------------- # CheckEnv - validates necessary environment variables #----------------------------------------------------------------------------- sub CheckEnv { logmsg ("Validating the environment."); $RAZZLETOOLPATH=$ENV{RazzleToolPath}; $_NTTREE=$ENV{_NTTREE}; $_NTPOSTBLD=$ENV{_NTPOSTBLD}; # if ($LANG=~/psu/i || $LANG=~/gb/i || $LANG=~/ca/i) # { # $_NTPOSTBLD="$ENV{_NTPostBld_Bak}\\psu"; # } # logmsg ("Reset _NTPostBld for PSU to $_NTPOSTBLD"); if ($LANG=~/psu_(.*)/i) { $Special_Lang=$1; } elsif ($LANG=~/psu/i || $LANG=~/mir/i || $LANG=~/FE/i) { if (defined( $ENV{"LANG_MUI"} ) ) { $Special_Lang=$ENV{"LANG_MUI"}; } elsif ($LANG=~/psu/i) { $Special_Lang="ro"; } elsif ($LANG=~/FE/i) { $Special_Lang="jpn"; } else { $Special_Lang="ara"; } } else { $Special_Lang=$LANG; } logmsg ("------- special lang is $Special_Lang"); $PROCESSOR=$ENV{PROCESSOR}; if ($ENV{_BuildArch}=~/x86/i) { $_BuildArch="i386"; } else { $_BuildArch=$ENV{_BuildArch}; } $_BuildArch_Release=$ENV{_BuildArch}; $LOGS=$ENV{temp}; if ($ENV{_BuildType} =~ /^chk$/i) { wrnmsg ("This does not run on chk machines"); return 0; } if(defined($SAFEMODE=$ENV{SAFEMODE})) { logmsg ("SAFEMODE is ON"); } logmsg ("Success: Validating the environment."); return 1; } # CheckEnv #----------------------------------------------------------------------------- # DefineConstants - defines global constants #----------------------------------------------------------------------------- sub DefineConstants { my ($layout); logmsg ("Definition of global constants."); # Directories $LOCBINDIR = "$_NTPOSTBLD"; $USBINDIR = "$_NTTREE"; $MUIDIR = "$_NTPOSTBLD\\mui"; $MUI_VALUEADD_DIR = "valueadd"; $MUI_PRINTER_DRIVER_DIR = "printer"; $MUI_NETFX_DIR = "netfx"; # .net framework folder name $MUI_RELEASE_DIR = "$MUIDIR\\release\\$_BuildArch_Release\\Temp"; # changing this to hide the classic muisetup packages $MUI_RELEASE_DIR2 = "$MUIDIR\\release\\$_BuildArch_Release"; $CONTROLDIR = "$MUIDIR\\control"; $TMPDIR = "$MUIDIR\\$Special_Lang\\tmp"; $MSIDIR = "$MUIDIR\\msi"; $RESDIR = "$MUIDIR\\$Special_Lang\\res"; $TARGETDIR = "$MUIDIR\\$Special_Lang\\$_BuildArch.uncomp"; #$COMPDIR = "$MUIDIR\\$Special_Lang\\$_BuildArch"; $IE5DIR = "$MUIDIR\\drop\\ie5"; # Filenames $CODEFILE = "$RAZZLETOOLPATH\\codes.txt"; $INFFILE = "$MUIDIR\\mui.inf"; $COPYFILE = "$CONTROLDIR\\copyfile.txt"; $DELFILE = "$CONTROLDIR\\delfile.txt"; $EXTFILE= "$CONTROLDIR\\extracts.txt"; $EXTMSIFILE="$CONTROLDIR\\extmsi.txt"; $RENFILE = "$CONTROLDIR\\renfile.txt"; $COMPEXCLUDEFILE = "$CONTROLDIR\\compexclude.txt"; $UDDIORIGFILE = "$LOCBINDIR\\uddi\\webroot\\help\\default\\images\\bullet.gif"; $UDDIRENAMEFILE = "$LOCBINDIR\\uddi\\webroot\\help\\default\\images\\bulletuddi.gif"; $layout = GetCDLayOut(); $COMPDIR = "$MUI_RELEASE_DIR\\$layout\\$Special_Lang\.mui\\$_BuildArch"; # Other Constants if($_BuildArch =~ /i386/i) { $MACHINE = "IX86"; } elsif ($_BuildArch =~ /ia64/i) { $MACHINE = "IA64"; } if ($LANG =~ /^(ARA|HEB)$/i) { $RESOURCE_TYPES = "2 3 4 5 6 9 10 11 14 16 HTML MOFDATA 23 240 1024 2110"; } else { $RESOURCE_TYPES = "4 5 6 9 10 11 16 HTML MOFDATA 23 240 1024 2110"; } logmsg ("Success: Definition of global constants."); $BuildChecksum=1; if ($BuildChecksum) { if (! -d $USBINDIR) { logmsg("Build Resource Checksum is enabled but $USBINDIR doesn't exist"); $BuildChecksum=0; } } $UnlocalizedFilesDir="$_NTPOSTBLD\\mui\\$Special_Lang\\cabtemp"; $WorkTempFolder ="$_NTPOSTBLD\\mui\\$Special_Lang\\RCCheckSumFiles"; $MSITemp ="$_NTPOSTBLD\\mui\\$Special_Lang\\msitemp"; # # Read renfile.txt into hash so that we may access in muibld() quickly # %Global_RenFiles={}; ParseTable::parse_table_file($RENFILE, \%Global_RenFiles); return 1; } # DefineConstants #----------------------------------------------------------------------------- # GetCodes - gets the language's LCID and ISO language code from CODEFILE #----------------------------------------------------------------------------- sub GetCodes { logmsg ("Get the language's LCID and ISO language code form CODEFILE."); my(@data); # Don't allow nec_98 or CHT to be processed! if($Special_Lang =~ /^(NEC_98|CHT)$/i) { logmsg ("No MUI available for $Special_Lang"); exit 0; } # Search CODEFILE for $Special_Lang, $LCID, $LANG_ISO, etc. if(!open(CODEFILE, "$CODEFILE")) { errmsg ("Can't open lcid file $CODEFILE for reading."); return 0; } CODES_LOOP: while () { if (/^$Special_Lang\s+/i) { @data = split(/\s+/,$_); last CODES_LOOP; } } close(CODEFILE); if(!@data) { logmsg ("$Special_Lang is an unknown language"); &Usage; return 0; } $LCID = $data[2]; $LCID_SHORT = $LCID; $LCID_SHORT =~ s/^0x//; $LANG_ISO = $data[8]; $GUID = $data[11]; $LANG_NAME = $data[$#data]; # The comments are the last column logmsg ("Success: Get the language's LCID and ISO language code form CODEFILE."); return 1; } # GetCodes #----------------------------------------------------------------------------- # CheckDirs - makes sure that the necessary directories exist #----------------------------------------------------------------------------- sub CheckDirs { logmsg ("Make sure the necessary directories exist."); my($status); # Make sure the source directories exist foreach ($LOCBINDIR,$MUIDIR,$CONTROLDIR) { if(! -e $_) { logmsg ("$0: ERROR: $_ does not exist"); return 0; } } # Make sure destination directories exist foreach ($IE5DIR,$TMPDIR,$RESDIR,$TARGETDIR,$COMPDIR) { if(! -e $_) { $status = system("md $_"); if($status) { logmsg ("$0: ERROR: cannot create $_"); return 0; } } } logmsg ("Success: Make sure the necessary directories exist."); return 1; } # CheckDirs #----------------------------------------------------------------------------- # UpdateMuiinf - updates mui.inf with current build number, and insert the filelayout from layout.inx #----------------------------------------------------------------------------- sub UpdateMuiinf { logmsg ("Update mui.inf with the current build number."); my(@inf_contents, $build_section, $build_line_found, @new_contents); my($filelayout_section, $bInFileLayoutSection, $tempFile, $genfilelayoutCmd, @newFileLayout); # Get current build number $LOGS="$_NTPOSTBLD\\build_logs"; my $filename="$LOGS\\buildname.txt"; open (BUILDNAME, "< $filename") or die "Can't open $filename for reading: $!\n"; while () { $BLDNO = $_; $BLDNO =~ s/\.[\w\W]*//i; } close BUILDNAME; if ($BLDNO =~ /(^\d+)-*\d*$/) { $BLDNO = $1; } else { errmsg ("$BLDNO"); return 0; } chomp($BLDNO); # Read $INFFILE if(!open(INFFILE, $INFFILE)) { errmsg ("Cannot open $INFFILE for reading."); return 0; } @inf_contents = ; close(INFFILE); # Modify contents in memory $build_section = 0; $build_line_found = 0; $filelayout_section = "[File_Layout]"; $bInFileLayoutSection = 0; foreach (@inf_contents) { # update the flag if we have exited the filelayout inf section if ($bInFileLayoutSection) { # if we encounter a new section, we know that we have exited the filelayout section if (/^\[\w+\]$/) { $bInFileLayoutSection = 0; logmsg("Finished reading existing [File_Layout] section."); } } # If we find [Buildnumber] we're in the build_section. if(/^\[Buildnumber\]$/ && !$build_section) { $build_section = 1; } # If we find =1 within the build section, replace # with $BLDNO and mark the end of the build section. elsif($build_section && /^(.*)=1$/) { s/^.*=1$/$BLDNO=1/; $build_line_found = 1; $build_section = 0; } # flag it if we are entering file layout section if (/^\[File_Layout\]$/) { logmsg("mui.inf contains a [File_Layout] section, deleting this section and generating a new one dynamically."); $bInFileLayoutSection = 1; } # we don't copy the current filelayout section contents, we will # generate it later dynamically if (!$bInFileLayoutSection) { push(@new_contents, $_); } } $tempFile = "$MSIDIR\\flayout.txt"; $infDir = "$ENV{SDXROOT}\\MergedComponents\\SetupInfs"; $layoutinxFile = "$infDir\\layout.inx"; $layouttxtFile = "$infDir\\usa\\layout.txt"; # call genfilelayout.pl to generate a new filelayoutsection if(-e "$ENV{RazzleToolPath}\\PostBuildScripts\\genfilelayout.pm") { logmsg ("perl $ENV{RazzleToolPath}\\PostBuildScripts\\GenFileLayout.pm $layoutinxFile $layouttxtFile $USBINDIR > $tempFile"); $returnResult = system ("perl $ENV{RazzleToolPath}\\PostBuildScripts\\GenFileLayout.pm $layoutinxFile $layouttxtFile $USBINDIR > $tempFile"); if ($returnResult) { logmsg("GenFileLayout.pm ERROR: unable to generate a new [File_Layout] section for mui.inf!"); return 0; } } else { errmsg("Cannot find genfilelayout.pm script! cannot update mui.inf filelayout section!"); return 0; } # copy the generated file_layout section into the new mui.inf content array if(!open(INFFILE, $tempFile)) { errmsg ("Cannot open $tempFile for reading."); return 0; } @newFileLayout = ; close(INFFILE); push(@new_contents, "\n"); push(@new_contents, "$filelayout_section\n"); foreach (@newFileLayout) { push(@new_contents, $_); } # If no build line was found, the format is wrong - error msg and exit if(!$build_line_found) { errmsg ("$INFFILE doesnt have the expected format."); logmsg ("Looking for:"); logmsg ("[Buildnumber]"); logmsg ("=1"); return 0; } # Overwrite $INFFILE (mui.inf) always - we need to do this to update the filelayout section if(!open(INFFILE, ">$INFFILE")) { errmsg ("Cannot open $INFFILE for writing."); return 0; } print INFFILE @new_contents; close(INFFILE); # Confirm the update logmsg ("$INFFILE successfully updated with Build Number = $BLDNO"); logmsg ("$INFFILE successfully updated with the generated [File_Layout] section in $tempFile."); return 1; } # UpdateMuiinf #----------------------------------------------------------------------------- # Ie5Mui - creates a language-specific version of ie5ui.inf #----------------------------------------------------------------------------- sub Ie5Mui { logmsg ("Create a language-specific version of ie5ui.inf"); my(@new_inf, $input_file, $output_file); $input_file = "$IE5FILE"; $output_file = "$IE5DIR\\ie5ui.inf"; # Check existence of input file if(!-e $input_file) { errmsg ("Can't find $input_file."); logmsg ("$output_file not created."); return 0; } # If the output file already exists and is newer than # the input file, return. (Unless the FORCE option has been set) if(-e $output_file) { if($VERBOSE) { logmsg ("$output_file already exists."); } if(&ModAge($output_file) <= &ModAge($input_file)) { if($VERBOSE) { logmsg ("$output_file is newer than $input_file"); } if(!$FORCE) { if($VERBOSE) { logmsg ("$output_file will not be overwritten."); } logmsg ("Success: Create a language-specific version of ie5ui.inf"); return 1; } else { if($VERBOSE) { logmsg ("FORCE option is ON - overwriting anyway."); } } } } if(!open(INPUTFILE, "$input_file")) { errmsg ("Cannot open $input_file for reading."); logmsg ("$output_file not created."); return 0; } while () { # Replace the human readable language names s/#LANGUAGE#/$LANG_NAME/g; # Replace the GUIDs s/#GUID#/$GUID/g; # Replace the iso language IDs s/#ISO#/$LANG_ISO/g; # Replace the LCIDS s/#LCID#/$LCID_SHORT/g; # Remove the SourceDiskName s/"Internet Explorer UI Satellite Kit"//g; push(@new_inf, $_); } close INPUTFILE; # Special case for Japanese if($LANG_ISO eq "JA") { push(@new_inf, "\n\[Run.MSGotUpd\]\n"); push(@new_inf, "%49501%\\MUI\\0411\\msgotupd.exe \/q\n"); } # Display and log any errors # (if @new_inf has 2 lines or less, it's probably an error) if(scalar(@new_inf) <= 2) { errmsg ("Error from $CONTROLDIR\\ie5mui.pl"); foreach (@new_inf) { logmsg ($_); } logmsg ("$output_file not created"); return 0; } # Write the output of ie5mui.pl to ie5ui.inf if(!open(OUTFILE,">$output_file")) { errmsg ("Can't open $output_file for writing."); logmsg ("$output_file not created."); return 0; } print OUTFILE @new_inf; close(OUTFILE); logmsg ("$output_file successfully created."); logmsg ("Success: Create a language-specific version of ie5ui.inf"); return 1; } # Ie5Mui #----------------------------------------------------------------------------- # ExtractCabFiles - extracts files listed in extracts.txt from their cabfiles. #----------------------------------------------------------------------------- sub ExtractCabFiles { logmsg ("Extract files listed in extracts.txt from their cabfiles."); my($files_extracted, $file_errors, $total_extracts); # Initial messages logmsg ("--------------------------------------------------------"); logmsg ("MUI Cab File Extraction"); logmsg ("--------------------------------------------------------"); # Extract files from their cabfiles ($files_extracted, $file_errors, $total_extracts) = &ExtractFiles("$_NTPOSTBLD", "$_NTPOSTBLD\\mui\\$Special_Lang", $EXTFILE, 0); # Final messages if ($file_errors=~/0/i) { logmsg ("RESULTS: Process Succeeded"); } else { logmsg ("RESULTS: Process Failed!"); } logmsg ("Total number of files listed in:....................($total_extracts)"); logmsg (" $EXTFILE"); logmsg ("Number of files extracted to:.......................($files_extracted)"); logmsg (" $TARGETDIR"); logmsg ("Number of errors:...................................($file_errors)"); return 1; } # ExtractFiles #----------------------------------------------------------------------------- # ExtractMSIFiles - extracts msi files listed in extmsi.txt from their cabfiles. #----------------------------------------------------------------------------- sub ExtractMSIFiles { logmsg ("Extract files listed in extracts.txt from their cabfiles."); my($files_extracted, $file_errors, $total_extracts); # Initial messages logmsg ("--------------------------------------------------------"); logmsg ("MUI .MSI File Extraction"); logmsg ("--------------------------------------------------------"); # Extract files from their msifiles ($files_extracted, $file_errors, $total_extracts) = &ExtractMSICabFiles("$_NTPOSTBLD", "$_NTPOSTBLD\\mui\\$Special_Lang", $EXTMSIFILE, 0); # Final messages if ($file_errors=~/0/i) { logmsg ("RESULTS: Process Succeeded"); } else { logmsg ("RESULTS: Process Failed!"); } logmsg ("Total number of files listed in:....................($total_extracts)"); logmsg (" $EXTMSIFILE"); logmsg ("Number of files extracted to:.......................($files_extracted)"); logmsg (" $TARGETDIR"); logmsg ("Number of errors:...................................($file_errors)"); return 1; } # ExtractMSIFiles #----------------------------------------------------------------------------- # MakeSourceFileList - gets list of appropriate files to process #----------------------------------------------------------------------------- sub MakeSourceFileList { logmsg ("Get list of appropriate files to process."); my(@files,@files2,@Fusion_filelist,$filename); # Initial messages logmsg ("--------------------------------------------------------"); logmsg ("MUI Resource-only dll Generation"); logmsg ("--------------------------------------------------------"); # Get contents of source directory if(!opendir(LOCBINDIR, $LOCBINDIR)) { errmsg ("Can't open $LOCBINDIR"); return 0; } @files = grep !/\.(gpd|icm|ppd|bmp|txt|cab|cat|hlp|chm|chq|cnt|mfl)$/i, readdir LOCBINDIR; close(LOCBINDIR); if(!opendir(TMPDIR, $TMPDIR)) { errmsg ("Can't open $TMPDIR"); return 0; } @files2 = grep !/\.(gpd|icm|ppd|bmp|txt|cab|cat|hlp|chm|chq|cnt|mfl)$/i, readdir TMPDIR; close(TMPDIR); # Filter out non-binaries, store in global @FILE_LIST # (muibld.exe gives errors on text files, and produces annoying # pop-up dialogs for directories) @FILE_LIST = (); foreach (@files) { if(-B "$LOCBINDIR\\$_") { push(@FILE_LIST, "$LOCBINDIR\\$_"); } } foreach (@files2) { if(-B "$TMPDIR\\$_") { push(@FILE_LIST, "$TMPDIR\\$_"); } } # Append fusion files # @Fusion_filelist = `dir /s /b $_NTPOSTBLD\\asms\\*.dll $_NTPOSTBLD\\asms\\*.exe`; # foreach $filename (@Fusion_filelist) # { # chomp ($filename); # push(@FILE_LIST, $filename); # } logmsg ("Success: Get list of appropriate files to process."); return 1; } # MakeSourceFileList #----------------------------------------------------------------------------- # GenResDlls - loops over the file list, performs muibld, and logs output #----------------------------------------------------------------------------- sub GenResDlls { logmsg ("Loop over the file list, perform muibld, and log output"); my($error, $resdlls_created, @resdlls, $total_resdlls); # Process each (binary) file in the source directory $resdlls_created = 0; foreach $_ (@FILE_LIST) { $error = &MuiBld($_); if(!$error) { $resdlls_created++; } } # Get total number of resource-only dlls in destination directory if(!opendir(TARGETDIR, $TARGETDIR)) { wrnmsg ("WARNING: Can't open $TARGETDIR"); } @resdlls = grep /\.mui$/, readdir TARGETDIR; close(TARGETDIR); $total_resdlls = scalar(@resdlls); # Final messages logmsg ("RESULTS: Process Succeeded"); logmsg ("Number of resource-only dlls created in:...........($resdlls_created)"); logmsg (" $TARGETDIR"); logmsg ("Total number of resource-only dlls in:.............($total_resdlls)"); logmsg (" $TARGETDIR"); return 1; } sub FindOriginalFile { my ($filename); my ($original_file); ($filename) = @_; # # If the US file exists and checksum feature is enabled, add the -c to muibld to embed the checksum. # The original file is the US English version of the file that $source file is localized against. # $original_file = "$USBINDIR\\$filename"; if (-e $original_file) { return $original_file; } # # We also extract nonlocalized files to $original_file_Unl (.cab , .msi) # else { # # Check if the original file exists in %_NTTREE%\\ # $original_file = "$USBINDIR\\$LANG\\$filename"; if (-e $original_file) { return $original_file; } else { # # Check if the original file exists in %_NTTREE%\lang\\ # $original_file = $USBINDIR . "\\lang\\$LANG\\$filename"; if (-e $original_file) { return $original_file; } } } return ""; } sub ExecuteProgram { $Last_Command = shift; @Last_Output = `$Last_Command`; chomp $_ foreach ( @Last_Output ); return $Last_Output[0]; } #----------------------------------------------------------------------------- # MuiBld - creates a resource dll for the input file, using muibld.exe # and link (but not if the corresponding resource dll already exists and is # newer than the input file). #----------------------------------------------------------------------------- sub MuiBld { # logmsg ("MUI build creates the resource dll's"); my ($filename, $source, $resource, $resdll, $status, @stat, $resdll_time, $source_time, $muibld_command, $link_command, @trash); my ($original_file, $file_ver_string, $machine_flag, $MyFilenName); $source = shift; # Make sure target folder exist before calling MUIBLD and LINK if ($source =~ /\Q$LOCBINDIR\E\\(.*)/) { $filename = $1; $resource = "$RESDIR\\$1.res"; $resdll = "$TARGETDIR\\$1.mui"; if($resource =~ /(^\S+)\\([^\\]+)$/) { mkdir($1, 0777); } if($resdll =~ /(^\S+)\\([^\\]+)$/) { mkdir($1, 0777); } } else { errmsg ("$source: invalid file"); return 0; } # If the source doesn't exist, return. if(! -e $source) { logmsg ("warning: $source not found"); return 1; } # If the corresponding resource dll already exists and is newer than # the input file, return. (Unless the FORCE option has been set) if( -e $resdll && !$FORCE) { if(&ModAge($resdll) <= &ModAge($source)) { if($VERBOSE) { logmsg ("$source: $resdll already exists and is newer; conversion not performed."); } return 0; } } # Construct muibld command $muibld_command = "muibld.exe -l $LCID -i $RESOURCE_TYPES $source $resource 2>&1"; if ($BuildChecksum) { # # Important: Check if this file is listed in renfile.txt. If it's the case, we should use renamed file name as key # to find original file(unlocalized file) # $MyFilenName=$filename.".mui"; if (&IsWin32File($filename) && defined ($Global_RenFiles{ $MyFilenName}) ) { $MyFileName = $Global_RenFiles{$MyFilenName}{DestFile}; if ($MyFileName =~ /(.*)\.mu_/i ||$MyFileName =~ /(.*)\.mui/i ) { $MyFileName = $1; } $original_file = &FindOriginalFile($MyFileName); } else { $original_file = &FindOriginalFile($filename); } if ($original_file =~ /\w+/) { $muibld_command = "muibld.exe -c $original_file -l $LCID -i $RESOURCE_TYPES $source $resource 2>&1"; logmsg($muibld_command); } else { logmsg($muibld_command); wrnmsg ("$source: muibld.exe: The US version of this file ($original_file) is not found. Resource checksum is not included."); } } else { logmsg($muibld_command); } # If SAFEMODE is on, just print muibld command if($SAFEMODE) { print "$muibld_command\n"; $status = 0; } # Execute muibld.exe for the appropriate language, localized binary, and # resource file. else { # Execute command @trash = `$muibld_command`; $status = $?/256; # Display warnings from muibld.exe if($VERBOSE) { SWITCH: { if($status >= 100) { wrnmsg ("$source: muibld.exe: SYSTEM ERROR $status"); last SWITCH; } if($status >= 7) { wrnmsg ("$source: muibld.exe: TOO FEW ARGUMENTS"); last SWITCH; } if($status == 6) { wrnmsg ("$source: muibld.exe: NO LANGUAGE_SPECIFIED"); last SWITCH; } if($status == 5) { wrnmsg ("$source: muibld.exe: NO TARGET"); last SWITCH; } if($status == 4) { wrnmsg ("$source: muibld.exe: NO SOURCE"); last SWITCH; } if($status == 3) { wrnmsg ("$source: muibld.exe: LANGUAGE NOT IN SOURCE"); last SWITCH; } if($status == 2) { wrnmsg ("$source: muibld.exe: NO RESOURCES"); last SWITCH; } if($status == 1) { wrnmsg ("$source: muibld.exe: ONLY VERSION STAMP"); last SWITCH; } } } } # Construct link command $machine_flag = $MACHINE; if ($MACHINE =~ /IA64/i && $original_file =~ /\w+/i) { $file_ver_string = &ExecuteProgram("filever $original_file"); if ($file_ver_string =~ /i64/i) { $machine_flag = "IA64"; } else { $machine_flag = "IX86"; } } $link_command = "link /noentry /dll /nologo /nodefaultlib /machine:$machine_flag /out:$resdll $resource"; # If SAFEMODE is on, just print link command if($SAFEMODE) { print "$link_command\n"; } # If muibld.exe command failed, then the $status is non-zero. # Return $status to parent routine. if($status) { return $status; } # If the muibld.exe command was successful, execute link.exe for # the appropriate resource file and resource-only-dll. elsif( !$status ) { $? = 0; # Reset system error variable logmsg($link_command); # Execute command $message = `$link_command`; # Display error messages from link.exe if($message =~ /^LINK : (.*:.*)$/) { if($VERBOSE) { wrnmsg ("$source: link.exe: $1"); } wrnmsg ("$source: link.exe: $1"); return 0; } elsif($?) { $status = $?/256; if($status) { if($VERBOSE) { wrnmsg ("$source: link.exe: SYSTEM_ERROR $status"); } wrnmsg ("$source: link.exe: SYSTEM_ERROR $status"); return 0; } } elsif(! -e $resdll) { if($VERBOSE) { wrnmsg ("$source: link.exe: $resdll was not created"); } wrnmsg ("$source: link.exe: $resdll was not created"); return 0; } else { logmsg ("$source: created $resdll"); return 0; } } return 1; } # MuiBld #----------------------------------------------------------------------------- # DeleteDelfiles - deletes files listed in delfile.txt #----------------------------------------------------------------------------- sub DeleteDelfiles { my($files_deleted, $file_errors, $total_delfiles); # Initial messages logmsg ("--------------------------------------------------------"); logmsg ("BEGIN delfile.txt file deletes"); logmsg ("--------------------------------------------------------"); # Delete each of the files listed in delfile.txt ($files_deleted, $file_errors, $total_delfiles) = &DeleteFiles("$_NTPOSTBLD\\mui\\$Special_Lang", $DELFILE, 0); # Final messages if ($file_errors=~/0/i) { logmsg ("RESULTS: Process Succeeded"); } else { logmsg ("RESULTS: Process Failed!"); } logmsg ("Total number of files listed in:....................($total_delfiles)"); logmsg (" $DELFILE"); logmsg ("Number of delfile.txt files deleted from:...........($files_deleted)"); logmsg (" $TARGETDIR"); logmsg ("Number of errors:...................................($file_errors)"); return 1; } # DeleteDelfiles #----------------------------------------------------------------------------- # RenameRenfiles - renames files listed in renfile.txt #----------------------------------------------------------------------------- sub RenameRenfiles { my($files_renamed, $file_errors, $total_renfiles); # Initial messages logmsg ("--------------------------------------------------------"); logmsg ("BEGIN renfile.txt file rename"); logmsg ("--------------------------------------------------------"); # Rename files listed in renfile.txt ($files_renamed, $file_errors, $total_renfiles) = &RenameFiles("$_NTPOSTBLD\\mui\\$Special_Lang", "$_NTPOSTBLD\\mui\\$Special_Lang", $RENFILE, 0); # Final messages if ($file_errors=~/0/i) { logmsg ("RESULTS: Process Succeeded"); } else { logmsg ("RESULTS: Process Failed!"); } logmsg ("Total number of files listed in:.....................($total_renfiles)"); # logmsg (" $RENFILE"); logmsg ("Number of renfile.txt files renamed:.................($files_renamed)"); logmsg ("Number of errors:....................................($file_errors)"); return 1; } # RenameRenfiles #----------------------------------------------------------------------------- # CompressResDlls - compresses the resource dlls (& hlp|chm files) #----------------------------------------------------------------------------- sub CompressResDlls { my(@messages, $status, $exclude, $tmp_compressdir); # Initial messages logmsg ("--------------------------------------------------------"); logmsg ("BEGIN compression"); logmsg ("--------------------------------------------------------"); #Create a hash-hash from the control file table ParseTable::parse_table_file($COMPEXCLUDEFILE, \%CompExFiles); # Compress the resource dlls, using compress.exe @filelist = `dir /a-d/s/b $TARGETDIR\\*.*`; foreach $file (@filelist) { chomp $file; $exclude = "no"; $filename = $file; $filename =~/(\w*\.\w+)$/; $filename = $1; chomp $filename; if ($file !~ /\w*/) { next; } #Loop through all control file entries foreach $CompExFile (keys %CompExFiles) { if ($CompExFiles{$CompExFile}{FileType} =~ /^folder/i && $file =~ /\\$CompExFile\\/i) { if ($file =~ /\Q$TARGETDIR\E(\S*)\\[^\\]*/) { $tmp_compressdir = "$COMPDIR$1"; mkdir($tmp_compressdir, 0777); logmsg ("No compression for:$filename"); logmsg ("Copying $file -> $tmp_compressdir\\$filename"); unless (copy($file, $tmp_compressdir)) { logmsg("$!"); } } $exclude = "yes"; last; } elsif ($filename eq $CompExFile) { logmsg ("No compression for:$filename"); logmsg ("Copying $file -> $COMPDIR\\$filename"); unless (copy($file, $COMPDIR)) { logmsg("$!"); } $exclude = "yes"; last; } } # If not excluded from compression if ($exclude eq "no") { $tmp_compressdir = $COMPDIR; foreach $ComponentFolder (@ComponentFolders) { # Skip blank if ($ComponentFolder eq "") { next; } # If component folder is in the file path if ($file =~ /\\\Q$ComponentFolder\E\\/i) { # Filter out component directory if ($file =~ /\Q$TARGETDIR\E(\S*)\\[^\\]*/) { # create the directory if needed by appending it part by part # Append component dir to the compress dir @dir_parts = split(/\\/, $1); foreach $subdir (@dir_parts) { $tmp_compressdir = "$tmp_compressdir\\$subdir"; if (!-e $tmp_compressdir) { logmsg("CompressResDlls: Component Directory to create is $tmp_compressdir"); mkdir($tmp_compressdir, 0777); } } # Don't compress component's inf files if ($file =~ /.*\.inf/i && $file !~ /.*\.mui/i) { logmsg ("No compression for:$file"); logmsg ("Copying $file -> $tmp_compressdir\\$file"); copy($file, $tmp_compressdir); $exclude = "yes"; } # if we encountered a '\' we keep searching for a component directory that matches the everything but the filename if (scalar(@dir_parts) > 0) { last; } } } } # Starts compression if ($exclude eq "no") { $result = `compress.exe -d -zx21 -s -r $file $tmp_compressdir`; if($?) { $status = $?/256; errmsg ("error in compress.exe: $status"); } # Print the output of compress.exe chomp $result; logmsg ($result); } # Print the output of compress.exe chomp $result; logmsg ($result); } } logmsg ("Success: Compress the files"); return 1; } # CompressResDlls #----------------------------------------------------------------------------- # CopyCopyfiles - copies files listed in copyfile.txt #----------------------------------------------------------------------------- sub CopyCopyfiles { my($files_copied, $file_errors, $total_copyfiles); # Initial messages logmsg ("--------------------------------------------------------"); logmsg ("BEGIN copyfile.txt file copy"); logmsg ("--------------------------------------------------------"); # Copy files listed in copyfile.txt to $COMPDIR # ($files_copied, $file_errors, $total_copyfiles) = &CopyFiles("$_NTPOSTBLD", "$_NTPOSTBLD\\mui\\$Special_Lang", $COPYFILE, 0); # workaround bug of Xcopy.exe $src_temp ="$_NTPOSTBLD\.mui.tmp"; $dest_final="$_NTPOSTBLD\\mui\\$Special_Lang"; if ( -e $src_temp) { system "rmdir /S /Q $src_temp"; } mkdir($src_temp, 0777); if (-e $src_temp) { ($files_copied, $file_errors, $total_copyfiles) = &CopyFiles("$_NTPOSTBLD", "$src_temp", $COPYFILE, 0); unless (system "xcopy /evcirfy $src_temp $dest_final") { } system "rmdir /S /Q $src_temp"; } else { logmsg ("Error: Create temp. folder for work around failed: $src_temp"); ($files_copied, $file_errors, $total_copyfiles) = &CopyFiles("$_NTPOSTBLD", "$_NTPOSTBLD\\mui\\$Special_Lang", $COPYFILE, 0); } # Final messages if ($file_errors=~/0/i) { logmsg ("RESULTS: Process Succeeded"); } else { logmsg ("RESULTS: Process Failed!"); } logmsg ("Total number of files listed in:....................($total_copyfiles)"); logmsg (" $COPYFILE"); logmsg ("Number of copyfile.txt files copied to:.............($files_copied)"); logmsg (" $COMPDIR"); logmsg ("Number of errors:...................................($file_errors)"); return 1; } # CopyCopyfiles #----------------------------------------------------------------------------- # CopyDroppedfiles - copies dropped files from \mui\drop #----------------------------------------------------------------------------- sub CopyDroppedfiles { my($files_copied, $file_errors, $total_copyfiles); # Initial messages logmsg ("--------------------------------------------------------"); logmsg ("BEGIN \mui\drop file copy"); logmsg ("--------------------------------------------------------"); # Copy files from \mui\drop $COMPDIR ($files_copied, $file_errors, $total_copyfiles) = &CopyDropFiles("$_NTPOSTBLD\\mui\\drop", "$TARGETDIR", 0); # Final messages if ($file_errors=~/0/i) { logmsg ("RESULTS: Process Succeeded"); } else { logmsg ("RESULTS: Process Failed!"); } logmsg ("Total number of files listed in \mui\drop:............($total_copyfiles)"); logmsg ("Number of \mui\drop files copied to:..................($files_copied)"); logmsg (" $COMPDIR"); logmsg ("Number of errors:...................................($file_errors)"); return 1; } # CopyCopyfiles #----------------------------------------------------------------------------- # CopyServerFiles - copies dropped files from \mui\drop #----------------------------------------------------------------------------- sub CopyServerFiles { my($srvinfpath, $destdir); $srvinfpath = "$LOCBINDIR\\srvinf"; $destdir = "$TARGETDIR"; # Initial messages logmsg ("------------------------------------------------------------------"); logmsg ("BEGIN Copying .hlp and .chm files from $srvinfpath to $destdir"); logmsg ("------------------------------------------------------------------"); #Copy the files recursivly if (-e "$srvinfpath") { if (system("copy /Y $srvinfpath\\*.hlp $destdir")) { logmsg("WARNING: CopyServerFiles - copy hlp files failed."); } if (system("copy /Y $srvinfpath\\*.chm $destdir")) { logmsg("WARNING: CopyServerFiles - copy chm files failed."); } } else { logmsg ("WARNING: CopyServerFiles - $srvinfpath does not exist!"); logmsg ("WARNING: CopyServerFiles - Updated server help files may be missing from the MUI build!"); } return 1; } # CopyServerFiles #----------------------------------------------------------------------------- # Build the hash for the string in [Strings] sections of a INF file #----------------------------------------------------------------------------- sub BuildUpStringSection { my ($INFPath, $pTheStringSection) = @_; my (@Items, @StringItems, $Section, $Line, $Counter, $Start_idx,$End_idx); $Section='Strings'; $Counter=0; %$pTheStringSection={}; unless (open(INFILE,$INFPath)) { return $Counter; } @Items=; close(INFILE); if ( !&GetTheSection($Section,\@Items,\@StringItems,\$Start_idx,\$End_idx)) { return $Counter; } ; foreach $Line (@StringItems) { chomp($Line); if (length($Line) == 0) { next; } if ($Line !~ /\w/) { next; } if (substr($Line,0,1) eq ";") { next; } if ( $Line =~ /\s*(\S+)\s*=\s*(\S*)/ ) { $$pTheStringSection {$1} = $2; $Counter++; } } return $Counter; } sub GetTheSection { my ($SectioName, $pItems, $pSectionContent, $Start_Idx, $End_Idx) = @_; my ($Idx, $Limit, $InSection, $LeadingChar, $Line, $Pattern, $Result); $Idx=0; $InSection=0; $Limit=scalar(@$pItems); $Pattern='^\[' . $SectioName . '\]$'; $$Start_Idx = -1; $$End_Idx = -1; $Result=0; for ($Idx=0; $Idx < $Limit; $Idx++) { #chomp($$pItems[$Idx]); $Line=$$pItems[$Idx]; $LeadingChar=substr($Line,0,1); if ($LeadingChar ne ";") { if ($LeadingChar eq "[") { if ( $Line =~ /$Pattern/i ) { if ( ! $InSection) { $InSection = 1; } } else { if ($InSection) { $$End_Idx=$Idx-1; $InSection=0; } } next; } if ($InSection) { if ($$Start_Idx == -1) { $$Start_Idx=$Idx; } push(@$pSectionContent,$Line); } } } if ($InSection && ($$End_Idx== -1 )) { $$End_Idx=$Idx-1; } if (($$Start_Idx != -1) && ($$End_Idx != -1)) { $Result=1; } return $Result; } # /\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\ # # IsFusionResource --- Check if the binary contains fusion resource (#24) # # /\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\ sub IsFusionResource { my ($FileName) = @_; my (@Rsrc_Record,@Qualified,$Num, $Result, $Rsrc_Temp); $Result = 0; if (! -e $FileName) { return $Result; } $Rsrc_Temp = $FileName."rsrc.out"; # # Call RSRC to check # system("rsrc.exe $FileName >$Rsrc_Temp 2>nul"); unless (open(RSRCFILE, $Rsrc_Temp)) { errmsg("Can't open RSRC for $FileName"); return $Result; } @Rsrc_Record=; close (RSRCFILE); # # Scan the output of rsrc.exe. # @Qualified=grep /^\s{3}18/ , @Rsrc_Record; $Num=scalar(@Qualified); if ($Num > 0 ) { $Result = 1; } if (-e $Rsrc_Temp) { system("del $Rsrc_Temp"); } return $Result; } # /\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\ # # DoMUIizedForFiles --- Do MUI'ization for a localized file # # /\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\ sub DoMUIizedForFiles { my ($LocalizedFile,$original_file) = @_; my ($Result, $Checksum, $muibld_command, $resource, $resdll, @trash, $status); my ($machine_flag, $file_ver_string, $link_command, $message); $Result = 0; $Checksum=0; if (! -e $LocalizedFile) { return $Result; } if ( ($BuildChecksum) && ($original_file =~ /\w+/) && (-e $original_file)) { $Checksum=1; } $resource = "$LocalizedFile.res"; $resdll = "$LocalizedFile.muitmp"; if ($Checksum) { $muibld_command = "muibld.exe -c $original_file -l $LCID -i $RESOURCE_TYPES $LocalizedFile $resource 2>&1"; } else { $muibld_command = "muibld.exe -l $LCID -i $RESOURCE_TYPES $LocalizedFile $resource 2>&1"; } @trash = `$muibld_command`; $status = $?/256; # Display warnings from muibld.exe if($VERBOSE) { SWITCH: { if($status >= 100) { wrnmsg ("$LocalizedFile: muibld.exe: SYSTEM ERROR $status"); last SWITCH; } if($status >= 7) { wrnmsg ("$LocalizedFile: muibld.exe: TOO FEW ARGUMENTS"); last SWITCH; } if($status == 6) { wrnmsg ("$LocalizedFile: muibld.exe: NO LANGUAGE_SPECIFIED"); last SWITCH; } if($status == 5) { wrnmsg ("$LocalizedFile: muibld.exe: NO TARGET"); last SWITCH; } if($status == 4) { wrnmsg ("$LocalizedFile: muibld.exe: NO SOURCE"); last SWITCH; } if($status == 3) { wrnmsg ("$LocalizedFile: muibld.exe: LANGUAGE NOT IN SOURCE"); last SWITCH; } if($status == 2) { wrnmsg ("$LocalizedFile: muibld.exe: NO RESOURCES"); last SWITCH; } if($status == 1) { wrnmsg ("$LocalizedFile: muibld.exe: ONLY VERSION STAMP"); last SWITCH; } } } if($status) { if (-e $resource) { system("del $resource"); } return $Result; } $machine_flag = $MACHINE; if ( ($MACHINE =~ /IA64/i) && ($original_file =~ /\w+/i) && (-e $original_file)) { $file_ver_string = &ExecuteProgram("filever $original_file"); if ($file_ver_string =~ /i64/i) { $machine_flag = "IA64"; } else { $machine_flag = "IX86"; } } $link_command = "link /noentry /dll /nologo /nodefaultlib /machine:$machine_flag /out:$resdll $resource"; if($SAFEMODE) { print "$link_command\n"; } $? = 0; # Reset system error variable logmsg($link_command); # Execute command $message = `$link_command`; $Result = 1; # Display error messages from link.exe if($message =~ /^LINK : (.*:.*)$/) { wrnmsg ("$LocalizedFile: link.exe: $1"); $Result = 0; } elsif($?) { $status = $?/256; if($status) { wrnmsg ("$LocalizedFile: link.exe: SYSTEM_ERROR $status"); $Result = 0; } } elsif(! -e $resdll) { wrnmsg ("$LocalizedFile: link.exe: $resdll was not created"); $Result = 0; } else { logmsg ("$LocalizedFile: created $resdll"); } if (-e $resource) { system("del $resource"); } if ($Result) { if (system("move/y $resdll $LocalizedFile") != 0) { wrnmsg ("$LocalizedFile: can't move $resdll to $LocalizedFile"); } } else { if (-e $resdll) { system("del $resdll"); } } return $Result; } #----------------------------------------------------------------------------- # CopyIE5files - copies ie5 files over to a separate directory #----------------------------------------------------------------------------- sub CopyIE5files { my($ie5_files_copied, $ie5_file_errors, $total_ie5files, $web_files_copied, $web_file_errors, $total_webfiles, $total_files_in_dir, @files); my(%TheStringSection); # Initial messages logmsg ("--------------------------------------------------------"); logmsg ("BEGIN ie5 file copy"); logmsg ("--------------------------------------------------------"); logmsg ("Copy files listed in the [Satellite.files.install] section of ie5ui.inf"); $listfile = "$IE5DIR\\ie5ui.inf"; if (-e $listfile) { $section = "Satellite.files.install"; @filelist = `perl $RAZZLETOOLPATH\\PostBuildScripts\\parseinf.pl $listfile $section`; &BuildUpStringSection($listfile,\%TheStringSection); ($ie5_files_copied, $ie5_file_errors, $total_ie5files) = &CopyFileList ("$_NTPOSTBLD", "$_NTPOSTBLD\\mui\\$Special_Lang\\$_BuildArch\\ie5", \%TheStringSection,@filelist); # BUGBUG - For RTM, ARA/HEB get different *HTT for MUI than for loc build if($Special_Lang =~ /^(ara|heb)$/i) { $HTTDIR = "$_NTBINDIR\\loc\\mui\\$Special_Lang\\web"; @messages=`xcopy /vy $HTTDIR\\* $IE5DIR\\ 2>&1`; logmsg (@messages); } } # Final messages logmsg ("RESULTS: Process Succeeded"); logmsg ("Total number of ie5 files listed in:..................($total_ie5files)"); logmsg (" $IE5FILE"); logmsg ("Number of ie5 files copied to:........................($ie5_files_copied)"); logmsg (" $IE5DIR"); logmsg ("Number of ie5 file errors:............................($ie5_file_errors)"); logmsg ("Total number of web files listed in:..................($total_webfiles)"); logmsg (" $IE5FILE"); logmsg ("Number of web files copied to:........................($web_files_copied)"); logmsg (" $IE5DIR"); logmsg ("Number of web file errors:............................($web_file_errors)"); logmsg (" $IE5DIR"); return 1; } # CopyIE5files #----------------------------------------------------------------------------- # CopyComponentfiles - copies compoents' files over to a separate directory # # note that this function is changed to now also handle SKU specific components #----------------------------------------------------------------------------- sub CopyComponentfiles { my($files_copied, $file_errors, $total_files, $total_components, @sku_dirs); my(%TheStringSection, @OutputMsgs, $INFName, $DupINF); @sku_dirs = ("", "blainf", "dtcinf", "entinf", "sbsinf", "srvinf"); # we ignore personal builds "perinf" directory # Initial messages logmsg ("--------------------------------------------------------"); logmsg ("BEGIN component file copy"); logmsg ("--------------------------------------------------------"); logmsg ("Copy files listed in the installation section of component INF file."); if ($_BuildArch =~ /ia64/i) { if (-e "$_NTPOSTBLD\\build_logs\\cplocation.txt") { system "del /f $_NTPOSTBLD\\build_logs\\cplocation.txt"; } system "$RAZZLETOOLPATH\\PostBuildScripts\\cplocation.cmd /l:$LANG"; } if (-e $INFFILE) { # Get component list from MUI.INF @filelist = `perl $RAZZLETOOLPATH\\PostBuildScripts\\parseinf.pl $INFFILE "Components"`; $total_components = 0; foreach $Component (@filelist) { # Format: CompnentName=ComponentDirectory,ComponentINF_FileName,InstallationSection,UninstallationSection # $1 ComponentName # $2 ComponentDirectory # $3 ComponentINF_FileName # $4 InstallationSection if ($Component !~ /\w/) { next; } if ($Component =~ /^\s*;/i) { next; } if ($Component =~ /([^\=]*)=([^\,]*),([^\,]*),([^\,]*),(.*)/) { foreach $Sku (@sku_dirs) { logmsg ("Process component : $Component, SKU is $Sku"); # All external components inf files have to be binplaced to mui\drop\[component dir] # note that there may now be SKU specific sub folders, we will look for them and check $ComponentName = $1; if ($Sku eq "") { $ComponentDir = $2; $INFName=$3; $ComponentInf = "$MUIDIR\\drop\\$2\\$3"; } else { $ComponentInf = "$MUIDIR\\drop\\$2\\$Sku\\$3"; $ComponentDir = "$2\\$Sku"; $INFName=$3; } logmsg("ComponentDir is $ComponentDir, ComponentInf is $ComponentInf"); $ComponentInstallSection = $4; if (-e $ComponentInf) { $total_components++; $ComponentFolders[$total_components] = $ComponentDir; # # Comment out those file don't exist # $DupINF="$TARGETDIR\\$ComponentDir\\$INFName"; @OutputMsgs=`$RAZZLETOOLPATH\\PostBuildScripts\\comminf.cmd -o:yes -m:$ComponentInf -s:$ComponentInstallSection -d:$DupINF -p:$_NTPOSTBLD`; logmsg(@OutputMsgs); # # Get INF file default file install section @ComponentFileInstall = `perl $RAZZLETOOLPATH\\PostBuildScripts\\parseinf.pl $ComponentInf $ComponentInstallSection`; &BuildUpStringSection($ComponentInf,\%TheStringSection); logmsg ("Installing $ComponentInf $ComponentInstallSection"); foreach $ComponentInstall (@ComponentFileInstall) { logmsg ($ComponentInstall); #Parse CopyFiles list if ($ComponentInstall =~ /.*CopyFiles.*=(.*)/i) { $ComponentFileCopySections = $1; #Loop through all sections while ($ComponentFileCopySections ne "") { if ($ComponentFileCopySections =~ /([^\,]*),(.*)/i) { $ComponentFileCopySections = $2; $CopyFileSectionName = $1; } else { $CopyFileSectionName = $ComponentFileCopySections; $ComponentFileCopySections = ""; } # Get copy file list @ComponentFileList = `perl $RAZZLETOOLPATH\\PostBuildScripts\\parseinf.pl $ComponentInf $CopyFileSectionName`; if($ComponentDir =~ /oemhelp/i) { ($files_copied, $file_errors, $total_files) = &CopyFileList ("$_NTPOSTBLD\\oem\\help", "$TARGETDIR\\$ComponentDir", \%TheStringSection,@ComponentFileList); } else { ($files_copied, $file_errors, $total_files) = &CopyFileList ("$_NTPOSTBLD", "$TARGETDIR\\$ComponentDir", \%TheStringSection,@ComponentFileList); } # BUGBUG - For RTM, ARA/HEB get different *HTT for MUI than for loc build if(($ComponentName =~ /ie5/i) && ($Special_Lang =~ /^(ara|heb)$/i && $1)) { $HTTDIR = "$_NTBINDIR\\loc\\mui\\$Special_Lang\\web"; $IE5DIR = "$MUIDIR\\drop\\ie5"; @messages=`xcopy /vy $HTTDIR\\* $IE5DIR\\ 2>&1`; logmsg (@messages); } # Final messages logmsg ("RESULTS: Process Succeeded"); logmsg ("Total number of $ComponentName-$CopyFileSectionName files listed in:..................($total_files)"); logmsg ("Number of $ComponentName-$CopyFileSectionName files copied to:........................($files_copied)"); logmsg ("Number of $ComponentName-$CopyFileSectionName file errors:............................($file_errors)"); } } } } } } else { logmsg ("Warning: Invalid INF file, please check $Component"); } } } # Always success return 1; } # CopyComponentfiles # Function to copy dropped external partners files sub CopyDropFiles { my ($SrcDir, $DestDir, $Incremental); my (%CopyFiles, @CopyLangs, $files_copied, $file_errors, $total_files_copied); #Pickup parameters ($SrcDir, $DestDir, $Incremental) = @_; #Set defaults $files_copied = 0; $file_errors = 0; $total_files_copied = 0; #Create the destination dir if it does not exist unless (-e $DestDir) { logmsg("Make dir:$DestDir"); &MakeDir($DestDir); } #Copy the files recursivly system "xcopy /verifky $SrcDir $DestDir"; #Copy fusion manifest files if (-e "$DestDir\\asms") { #Remove previous copied files system "rd /s /q $DestDir\\asms"; if (-e "$SrcDir\\asms\\$Special_Lang") { logmsg("Copy fusion manifest files"); system "xcopy /verifky $SrcDir\\asms\\$Special_Lang $DestDir\\asms"; system "xcopy /verifky $SrcDir\\asms\\$Special_Lang $COMPDIR\\asms"; } else { logmsg("Warning: fusion $SrcDir\\asms\\$Special_Lang not found"); } } return ($files_copied, $file_errors, $total_files_copied); } sub CopyFusionFiles { my ($SrcDir, $DestDir); my ($filename, @Manifest_filelist); #Pickup parameters ($SrcDir, $DestDir) = @_; logmsg("Copying fusion manifest files"); #Search all manifest file. @Manifest_filelist = `dir /s /b $SrcDir\\*.man`; #For each manifest file, verify if the corresponding dll is already #in the destination folder. If not, skip the manifest file copy. foreach $filename (@Manifest_filelist) { chomp $filename; if ($filename =~ /\Q$SrcDir\E(.*).man/i) { if (-e "$DestDir$1.dll" | -e "$DestDir$1.exe" | -e "$DestDir$1.dl_" | -e "$DestDir$1.ex_") { system "xcopy /v /k $filename $DestDir$1.*"; } } } return 1; } #+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ # # Generate Exclude file for xcopy # #+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ sub GenerateExcludeList { my ($ExcludeList,$RootPath,$OutputFile) = @_; my ($Result, @Data, $Line, $TempFile); $Result = 0; unless (open(INFILE,$ExcludeList)) { errmsg("Can't open input for $ExcludeList"); return $Result; } $TempFile=$ENV{temp}; $TempFile="$TempFile\\muiexclude.txt"; unless (open(OUTFILE,">$TempFile")) { errmsg("Can't open output for $TempFile"); close(INFILE); return $Result; } @Data=; close(INFILE); foreach $Line (@Data) { chomp($Line); $NewLine="$RootPath\\$Line"; print(OUTFILE "$NewLine\n"); } close(OUTFILE); $$OutputFile = $TempFile; $Result = 1; return $Result; } # #Function to copy files using a specified control file # We also add Resource Checksum to the files being copied # sub CopyFiles { my ($SrcRootDir, $DestRootDir, $ControlFile, $Incremental); my (%CopyFiles, @CopyLangs, $files_copied, $file_errors, $total_files_copied, $excludefile); my ($SrcCopyFile_US, $MyFileName, $MyPath, $FileCheckSumAdded, $UseModifiedFile,$CopyResult); my ($NewExcludeFile); #Pickup parameters ($SrcRootDir, $DestRootDir, $ControlFile, $Incremental) = @_; # Set defaults $files_copied = 0; $file_errors = 0; $total_files_copied = 0; #Use exclude file for recursive copies $excludefile="$ENV{RazzleToolPath}\\PostBuildScripts\\muiexclude.txt"; #Create a hash-hash from the control file table ParseTable::parse_table_file($ControlFile, \%CopyFiles); #Loop through all control file entries foreach $SrcFile (keys %CopyFiles) { # Create file record hash $CopyFileRecord{SourceFile} = $SrcFile; $CopyFileRecord{SourceDir} = $CopyFiles{$SrcFile}{SourceDir}; $CopyFileRecord{DestFile} = $CopyFiles{$SrcFile}{DestFile}; $CopyFileRecord{DestDir} = $CopyFiles{$SrcFile}{DestDir}; $CopyFileRecord{Recursive} = $CopyFiles{$SrcFile}{Recursive}; $CopyFileRecord{Languages} = $CopyFiles{$SrcFile}{Languages}; #Preprocess file record hash unless ($CopyFileRecord = &PreProcessRecord(\%CopyFileRecord) ) { next; } #Process "-" entry in text file list if ($CopyFileRecord->{SourceDir}=~/^-$/i) { $SrcCopyFileDir="$SrcRootDir"; } else { $SrcCopyFileDir="$SrcRootDir\\$CopyFileRecord->{SourceDir}"; } if ($CopyFileRecord->{DestDir}=~/^-$/i) { $DestCopyFileDir="$DestRootDir"; } else { $DestCopyFileDir="$DestRootDir\\$CopyFileRecord->{DestDir}"; } #Create the destination dir if it does not exist unless (-e $DestCopyFileDir) { &MakeDir($DestCopyFileDir); } $SrcCopyFile = "$SrcCopyFileDir\\$CopyFileRecord->{SourceFile}"; if ($CopyFileRecord->{DestFile}=~/^-$/i) { $DestCopyFile = "$DestCopyFileDir"; } else { $DestCopyFile = "$DestCopyFileDir\\$CopyFileRecord->{DestFile}"; } if ($CopyFileRecord{Recursive}=~/(y|yes|true)/i) { #Copy the files recursivly if ( GenerateExcludeList($excludefile,$SrcRootDir,\$NewExcludeFile) && (-e $SrcCopyFileDir)) { if (system ("xcopy /evcirfy $SrcCopyFile $DestCopyFile /EXCLUDE:$NewExcludeFile") != 0) { errmsg("Fatal: Failed=>xcopy /evcirfy $SrcCopyFile $DestCopyFile /EXCLUDE:$$NewExcludeFile"); } } else { errmsg("Fatal: can't do copy for $SrcCopyFile $DestCopyFile /EXCLUDE:$NewExcludeFile"); } } else { #Copy the file for $SrcSingleCopyFile (glob "$SrcCopyFile") { # Support multiple target files - file names separated by ',' @DestFiles = split /,/, $CopyFileRecord->{DestFile}; foreach $file (@DestFiles) { $UseModifiedFile=0; # # We'll add Resource Checksum # if ($CopyFileRecord->{DestFile}=~/^-$/i) { $DestCopyFile = "$DestCopyFileDir"; ($MyFileName, $MyPath ) = fileparse($SrcSingleCopyFile); } else { $DestCopyFile = "$DestCopyFileDir\\$file"; $MyFileName=$file; } if ($BuildChecksum) { if ($MyFileName =~ /(.*)\.mu_/i ||$MyFileName =~ /(.*)\.mui/i ) { $MyFileName = $1; } $SrcCopyFile_US = &FindOriginalFile($MyFileName); if ( (&IsWin32File($MyFileName)) && (length($SrcCopyFile_US) > 0) ) { # # Copy source file to a temporary location # unless ( -e $WorkTempFolder) { &MakeDir($WorkTempFolder); } $FileCheckSumAdded=$WorkTempFolder."\\$MyFileName.mui"; logmsg("Copying $SrcSingleCopyFile -> $FileCheckSumAdded"); if (system("copy $SrcSingleCopyFile $FileCheckSumAdded") != 0) { logmsg("Can't copy $SrcSingleCopyFile to $FileCheckSumAdded"); $file_errors++; } # # Add resource checksum to the file # else { if ( system("checksum.exe $FileCheckSumAdded") == 0) { logmsg("muirct.exe -c $SrcCopyFile_US -z $FileCheckSumAdded"); system("muirct.exe -c $SrcCopyFile_US -z $FileCheckSumAdded"); } else { logmsg("Resource Checksum already in $FileCheckSumAdded"); } if ( -e $FileCheckSumAdded) { $UseModifiedFile=1; } else { logmsg("Failed:muirct.exe -c $SrcCopyFile_US -z $FileCheckSumAdded"); } } } #if ( (&IsWin32File($MyFileName)) && (length($SrcCopyFile_US) > 0) ) } # if ($BuildChecksum) if ($UseModifiedFile) { logmsg ("Copying $FileCheckSumAdded -> $DestCopyFile"); } else { logmsg ("Copying $SrcSingleCopyFile -> $DestCopyFile"); } $total_files_copied++; if ($UseModifiedFile) { $CopyResult=copy("$FileCheckSumAdded", "$DestCopyFile"); } else { $CopyResult=copy("$SrcSingleCopyFile", "$DestCopyFile"); } if ($CopyResult ) { $files_copied++; } else { logmsg("$!"); $file_errors++; } } } } } return ($files_copied, $file_errors, $total_files_copied); } #Function to validate a comma seperated lang list given a control lang sub IsValidFileForLang { #Declare local variables my ($ValidFileLangs, $lang) = @_; #Copy only for the specified languages in the control file @ValidLangs = split /,/i, $ValidFileLangs; unless (grep /(all|$lang)/i, @ValidLangs) { return; } return 1; } #Function to preprocess a hashref file record list sub PreProcessRecord { #Declare local variables my ($FileRecord) = @_; #Verify arguments; unless (@_ == 1 && ref($FileRecord) eq 'HASH') { print "usage: HASHREF"; return; } #Validate language for file record unless (&IsValidFileForLang($FileRecord->{Languages}, $Special_Lang) ) { return; } #Sub in environment vars foreach $field (keys %$FileRecord) { while ( $FileRecord->{$field}=~/(%\w+%)/i ) { $EnvVar=$1; $CmdVar=$1; $EnvVar=~s/%//ig; $CmdValue=$ENV{$EnvVar}; #Environment value substutions $CmdValue=~s/x86/i386/i; #Substutute the environment values into the file record $FileRecord->{$field}=~s/$CmdVar/$CmdValue/i; } } return ($FileRecord); } sub IsWin32File { my ($FileName) = @_; my %FileTypeTbl = ( ".exe" => 1, ".dll" => 1, ".cpl" => 1, ".ocx" => 1, ".tsp" => 1, ".scr" => 1 ); my ($Result, $TheFileExt); $Result=0; if (length($FileName) > 4) { $TheFileExt=substr($FileName,-4,4); $TheFileExt="\L$TheFileExt"; if (defined ($FileTypeTbl{$TheFileExt}) ) { $Result=1; } } return $Result; } # #Function to copy files using a specified array of files # # We'll also add resource checksum to the files # sub CopyFileList { my ($SrcRootDir, $DestRootDir, $RootMUIFile, $pTheStringSection, @FileList, $Incremental); my ($files_copied, $file_errors, $total_files_copied, $RootMUIFile, $FileCheckSumAdded, $SrcCopyFile_US); my ($IsWin32Res, $TheFileExt, $CopyResult); my ($Replaced, $SrcFileNew, $Doit, $DoCnt, $TheLine); #Pickup parameters ($SrcRootDir, $DestRootDir, $pTheStringSection, @FileList, $Incremental) = @_; # Set defaults $files_copied = 0; $file_errors = 0; $total_files_copied = 0; #Loop through all control file entries foreach $SrcFile (@FileList) { chomp $SrcFile; #Don't process blank line if ($SrcFile !~ /\w/) { next; } if (substr($SrcFile,0,1) eq ";") { next; } $total_files_copied++; #Create the destination dir if it does not exist unless (-e $DestRootDir) { &MakeDir($DestRootDir); } # Source file could be in the format of "[original file], [compressed file]" if ($SrcFile =~ /(.*),\s*(.*)\s*/) { $SrcFile = $2; } #Make sure source file doesn't contain MUI extension if ($SrcFile =~ /(.*)\.mu_/i ||$SrcFile =~ /(.*)\.mui/i ) { $SrcFile = $1; } $Doit=1; $DoCnt=0; $SrcFileNew=$SrcFile; while( ($Doit) && ($SrcFileNew =~ /(.*)%(.*)%(.*)/)) { if ( defined ($$pTheStringSection{$2})) { $Replaced=$$pTheStringSection{$2}; $SrcFileNew=$1.$Replaced.$3; $DoCnt++; } else { logmsg("**** Can't map:$2*"); $SrcFileNew=$SrcFile; $Doit=0; } } if (($Doit) && ($DoCnt)) { logmsg("$SrcFile is mapped to $SrcFileNew"); } $SrcFile=$SrcFileNew; # # Some source file may have form like %Filename%%LCID% which Filename and LCID comes from string section # of INF file. We have to replace these name on the fly # $SrcCopyFile = "$SrcRootDir\\$SrcFile"; $SrcCopyFile_US = "$USBINDIR\\$SrcFile"; #Append .MUI to the file name $DestCopyFile = "$DestRootDir\\$SrcFile.mui"; if (!(-e $SrcCopyFile)) { $SrcCopyFile = "$SrcRootDir\\dump\\$SrcFile"; $SrcCopyFile_US = "$USBINDIR\\dump\\$SrcFile"; } if (!(-e $SrcCopyFile)) { $SrcCopyFile = "$SrcRootDir\\netfx\\$SrcFile"; $SrcCopyFile_US = "$USBINDIR\\netfx\\$SrcFile"; } if (!(-e $SrcCopyFile)) { $SrcCopyFile = "$SrcRootDir\\mui\\drop\\$SrcFile"; $SrcCopyFile_US = "$USBINDIR\\mui\\drop\\$SrcFile"; } if (!(-e $SrcCopyFile)) { $SrcCopyFile = "$SrcRootDir\\uddi\\system32\\$SrcFile"; $SrcCopyFile_US = "$USBINDIR\\uddi\\system32\\$SrcFile"; } if (!(-e $SrcCopyFile)) { $SrcCopyFile = "$SrcRootDir\\uddi\\resources\\$SrcFile"; $SrcCopyFile_US = "$USBINDIR\\uddi\\resources\\$SrcFile"; } if (!(-e $SrcCopyFile)) { $SrcCopyFile = "$SrcRootDir\\uddi\\help\\$SrcFile"; $SrcCopyFile_US = "$USBINDIR\\uddi\\help\\$SrcFile"; } if (!(-e $SrcCopyFile)) { $SrcCopyFile = "$SrcRootDir\\uddi\\webroot\\help\\default\\$SrcFile"; $SrcCopyFile_US = "$USBINDIR\\uddi\\webroot\\help\\default\\$SrcFile"; } if (!(-e $SrcCopyFile)) { $SrcCopyFile = "$SrcRootDir\\uddi\\webroot\\help\\default\\images\\$SrcFile"; $SrcCopyFile_US = "$USBINDIR\\uddi\\webroot\\help\\default\\images\\$SrcFile"; } # For ia64, we need to try some extral step to get external files # from wow64 or i386 release server if (!(-e $SrcCopyFile) && ($_BuildArch =~ /ia64/i)) { if (!(-e $SrcCopyFile)) { $SrcCopyFile = "$SrcRootDir\\wowbins_uncomp\\$SrcFile"; $SrcCopyFile_US = "$USBINDIR\\wowbins_uncomp\\$SrcFile"; } if (!(-e $SrcCopyFile)) { $SrcCopyFile = "$SrcRootDir\\wowbins\\$SrcFile"; $SrcCopyFile_US = "$USBINDIR\\wowbins\\$SrcFile"; } if (-e "$_NTPOSTBLD\\build_logs\\cplocation.txt" && !(-e $SrcCopyFile)) { if (open (X86_BIN, "$_NTPOSTBLD\\build_logs\\cplocation.txt")) { $SrcRootDir = ; chomp ($SrcRootDir); $SrcCopyFile = "$SrcRootDir\\$SrcFile"; $SrcCopyFile_US = "$USBINDIR\\$SrcFile"; if (!(-e $SrcCopyFile)) { $SrcCopyFile = "$SrcRootDir\\dump\\$SrcFile"; $SrcCopyFile_US = "$USBINDIR\\dump\\$SrcFile"; } if (!(-e $SrcCopyFile)) { $SrcCopyFile = "$SrcRootDir\\mui\\drop\\$SrcFile"; $SrcCopyFile_US = "$USBINDIR\\mui\\drop\\$SrcFile"; } logmsg("Copy $SrcCopyFile from i386 release"); close (X86_BIN); } } } $RootMUIFile = "$DestRootDir\\..\\$SrcFile.mui"; if (-e $RootMUIFile) { logmsg ("Copying $RootMUIFile -> $DestCopyFile"); if (copy("$RootMUIFile", "$DestCopyFile") ) { if (unlink $RootMUIFile) { logmsg ("Deleting $RootMUIFile"); } $files_copied++; } else { logmsg("$!"); $file_errors++; } } elsif (-e $SrcCopyFile) { # # We want to add resource checksum to the file before it's added # $IsWin32Res=&IsWin32File($SrcFile); if (($BuildChecksum) && ($IsWin32Res) && (-e $SrcCopyFile_US) ) { unless ( -e $WorkTempFolder) { &MakeDir($WorkTempFolder); } # # Copy source file to a temporary location # $FileCheckSumAdded=$WorkTempFolder."\\$SrcFile.mui"; logmsg("Copying $SrcCopyFile -> $FileCheckSumAdded"); if (system("copy $SrcCopyFile $FileCheckSumAdded") != 0) { logmsg("Can't copy $SrcCopyFile to $FileCheckSumAdded"); $file_errors++; } # # Add resource checksum to the file # else { if (system("checksum.exe $FileCheckSumAdded") == 0) { logmsg("muirct.exe -c $SrcCopyFile_US -z $FileCheckSumAdded"); system("muirct.exe -c $SrcCopyFile_US -z $FileCheckSumAdded"); } else { logmsg("Resource Checksum already in $FileCheckSumAdded"); } if (-e $FileCheckSumAdded) { logmsg("Copying $FileCheckSumAdded -> $DestCopyFile"); $CopyResult=copy("$FileCheckSumAdded", "$DestCopyFile"); } else { logmsg("Failed:muirct.exe -c $SrcCopyFile_US -z $FileCheckSumAdded"); logmsg ("Copying $SrcCopyFile -> $DestCopyFile"); $CopyResult=copy("$SrcCopyFile", "$DestCopyFile"); } if ($CopyResult) { $files_copied++; } else { logmsg("$!"); $file_errors++; } } } else { logmsg ("Copying $SrcCopyFile -> $DestCopyFile"); if (copy("$SrcCopyFile", "$DestCopyFile") ) { $files_copied++; } else { logmsg("$!"); $file_errors++; } } } elsif (!($SrcCopyFile =~ /\.inf/i)) { logmsg("warning: $SrcCopyFile not found"); } } return ($files_copied, $file_errors, $total_files_copied); } #Function to rename files using a specifiec control file sub RenameFiles { my ($SrcRootDir, $DestRootDir, $ControlFile, $Incremental); my (%RenFiles, @RenLangs, $files_renamed, $file_errors, $total_files_renamed); #Pickup parameters ($SrcRootDir, $DestRootDir, $ControlFile, $Incremental) = @_; # Set defaults $files_renamed = 0; $file_errors = 0; $total_files_renamed = 0; #Create a hash-hash from the control file table ParseTable::parse_table_file($ControlFile, \%RenFiles); #Loop through all control file entries foreach $SrcFile (keys %RenFiles) { # Create file record hash $RenFileRecord{SourceFile} = $SrcFile; $RenFileRecord{SourceDir} = $RenFiles{$SrcFile}{SourceDir}; $RenFileRecord{DestFile} = $RenFiles{$SrcFile}{DestFile}; $RenFileRecord{DestDir} = $RenFiles{$SrcFile}{DestDir}; $RenFileRecord{Languages} = $RenFiles{$SrcFile}{Languages}; #Preprocess file record hash unless ($RenFileRecord = &PreProcessRecord(\%RenFileRecord) ) { next; } #Process "-" entry in text file list if ($RenFileRecord->{SourceDir}=~/^-$/i) { $SrcRenFileDir="$SrcRootDir"; } else { $SrcRenFileDir="$SrcRootDir\\$RenFileRecord->{SourceDir}"; } if ($RenFileRecord->{DestDir}=~/^-$/i) { $DestRenFileDir="$DestRootDir"; } else { $DestRenFileDir="$DestRootDir\\$RenFileRecord->{DestDir}"; } #Create the destination dir if it does not exist unless (-e $DestRenFileDir) { &MakeDir($DestRenFileDir); } $SrcRenFile = "$SrcRenFileDir\\$SrcFile"; if ($RenFileRecord->{DestFile}=~/^-$/i) { $DestRenFile = "$DestRenFileDir"; } else { $DestRenFile = "$DestRenFileDir\\$RenFileRecord->{DestFile}"; } #Rename the file for $SrcSingleRenFile (glob "$SrcRenFile") { logmsg ("Rename $SrcSingleRenFile -> $DestRenFile"); $total_files_renamed++; if (rename("$SrcSingleRenFile", "$DestRenFile") ) { $files_renamed++; } else { logmsg("$!"); $file_errors++; } } } return ($files_renamed, $file_errors, $total_files_renamed); } #Function to move files using a specifiec control file sub MoveFiles { my ($SrcRootDir, $DestRootDir, $ControlFile, $Incremental); my (%MoveFiles, @MoveLangs, $files_moved, $file_errors, $total_files_moved); #Pickup parameters ($SrcRootDir, $DestRootDir, $ControlFile, $Incremental) = @_; # Set defaults $files_moved = 0; $file_errors = 0; $total_files_moved = 0; #Create a hash-hash from the control file table ParseTable::parse_table_file($ControlFile, \%MoveFiles); #Loop through all control file entries foreach $SrcFile (keys %MoveFiles) { # Create file record hash $MoveFileRecord{SourceFile} = $SrcFile; $MoveFileRecord{SourceDir} = $MoveFiles{$SrcFile}{SourceDir}; $MoveFileRecord{DestFile} = $MoveFiles{$SrcFile}{DestFile}; $MoveFileRecord{DestDir} = $MoveFiles{$SrcFile}{DestDir}; $MoveFileRecord{Languages} = $MoveFiles{$SrcFile}{Languages}; #Preprocess file record hash unless ($MoveFileRecord = &PreProcessRecord(\%MoveFileRecord) ) { next; } #Process "-" entry in text file list if ($MoveFileRecord->{SourceDir}=~/^-$/i) { $SrcMoveFileDir="$SrcRootDir"; } else { $SrcMoveFileDir="$SrcRootDir\\$MoveFileRecord->{SourceDir}"; } if ($MoveFileRecord->{DestDir}=~/^-$/i) { $DestMoveFileDir="$DestRootDir"; } else { $DestMoveFileDir="$DestRootDir\\$MoveFileRecord->{DestDir}"; } #Create the destination dir if it does not exist unless (-e $DestMoveFileDir) { &MakeDir($DestMoveFileDir); } $SrcMoveFile = "$SrcMoveFileDir\\$MoveFileRecord->{SourceFile}"; if ($MoveFileRecord->{DestFile}=~/^-$/i) { $DestMoveFile = "$DestMoveFileDir"; } else { $DestMoveFile = "$DestMoveFileDir\\$MoveFileRecord->{DestFile}"; } #Move the file for $SrcSingleMoveFile (glob "$SrcMoveFile") { logmsg ("Copying $SrcSingleMoveFile -> $DestMoveFile"); $total_files_moved++; if (move("$SrcSingleMoveFile", "$DestMoveFile") ) { $files_moved++; } else { logmsg("$!"); $file_errors++; } } } return ($files_moved, $file_errors, $total_files_moved); } #Function to delete files using a specifiec control file sub DeleteFiles { my ($SrcRootDir, $DestRootDir, $ControlFile, $Incremental); my (%DelFiles, @ValidLangs, $files_deleted, $file_errors, $total_files_deleted); #Pickup parameters ($SrcRootDir, $ControlFile, $Incremental) = @_; # Set defaults $files_deleted = 0; $file_errors = 0; $total_files_deleted = 0; #Create a hash-hash from the control file table ParseTable::parse_table_file($ControlFile, \%DelFiles); #Loop through all control file entries foreach $SrcFile (keys %DelFiles) { # Create file record hash $DelFileRecord{SourceFile} = $SrcFile; $DelFileRecord{SourceDir} = $DelFiles{$SrcFile}{SourceDir}; $DelFileRecord{Languages} = $DelFiles{$SrcFile}{Languages}; #Preprocess file record hash unless ($DelFileRecord = &PreProcessRecord(\%DelFileRecord) ) { next; } #Process "-" entry in text file list if ($DelFileRecord->{SourceDir}=~/^-$/i) { $SrcDelFileDir="$SrcRootDir"; } else { $SrcDelFileDir="$SrcRootDir\\$DelFileRecord->{SourceDir}"; } $SrcDelFile = "$SrcDelFileDir\\$DelFileRecord->{SourceFile}"; #Delete the file for $SrcSingleDelFile (glob "$SrcDelFile") { logmsg ("Deleting $SrcSingleDelFile"); $total_files_deleted++; if (-e $SrcSingleDelFile) { if (unlink $SrcSingleDelFile) { $files_deleted++; } else { logmsg("$!"); $file_errors++; } } } } return ($files_deleted, $file_errors, $total_files_deleted); } #Function to extract files from a cab file using a specifiec control file # # We also add resource checksum to extracted files sub ExtractFiles { my ($CabRootDir, $ExtractRootDir, $ControlFile, $Incremental); my (%ExtractFiles, @ExtractLangs, $files_extracted, $file_errors, $total_files_extracted,$OriginalCabFile); my ($SourceFile_Localized, $SourceFile_US,$ContainFusionResource); #Pickup parameters ($CabRootDir, $ExtractRootDir, $ControlFile, $Incremental) = @_; # Set defaults $files_extracted = 0; $file_errors = 0; $total_files_extracted = 0; #Create a hash-hash from the control file table ParseTable::parse_table_file($ControlFile, \%ExtractFiles); #Loop through all control file entries foreach $ExtractFile (keys %ExtractFiles) { # Create file record hash $ExtractFileRecord{ExtractFile} = $ExtractFile; $ExtractFileRecord{ExtractDir} = $ExtractFiles{$ExtractFile}{ExtractDir}; $ExtractFileRecord{CabFile} = $ExtractFiles{$ExtractFile}{CabFile}; $ExtractFileRecord{CabDir} = $ExtractFiles{$ExtractFile}{CabDir}; $ExtractFileRecord{Languages} = $ExtractFiles{$ExtractFile}{Languages}; #Preprocess file record hash unless ($ExtractFileRecord = &PreProcessRecord(\%ExtractFileRecord) ) { next; } #Process "-" entry in text file list if ($ExtractFileRecord->{CabDir}=~/^-$/i) { $CabFileDir="$CabRootDir"; } else { $CabFileDir="$CabRootDir\\$ExtractFileRecord->{CabDir}"; } if ($ExtractFileRecord->{ExtractDir}=~/^-$/i) { $ExtractFileDir="$ExtractRootDir"; } else { $ExtractFileDir="$ExtractRootDir\\$ExtractFileRecord->{ExtractDir}"; } #Create the destination dir if it does not exist unless (-e $ExtractFileDir) { &MakeDir($ExtractFileDir); } $CabFile = "$CabFileDir\\$ExtractFileRecord->{CabFile}"; if ($ExtractFileRecord->{ExtractFile}=~/^-$/i) { $ExtractFile = "$ExtractFileDir"; } else { $ExtractFile = "$ExtractFileDir\\$ExtractFileRecord->{ExtractFile}"; } #Extract the file logmsg ("extract.exe /y /l $ExtractFileDir $CabFile $ExtractFileRecord->{ExtractFile}"); $SourceFile_Localized=""; if (-e $CabFile) { if (!system ("extract.exe /y /l $ExtractFileDir $CabFile $ExtractFileRecord->{ExtractFile}") ) { $files_extracted++; if (&IsWin32File($ExtractFileRecord->{ExtractFile})) { rename("$ExtractFileDir\\$ExtractFileRecord->{ExtractFile}", "$ExtractFileDir\\$ExtractFileRecord->{ExtractFile}\.mui"); $SourceFile_Localized ="$ExtractFileDir\\$ExtractFileRecord->{ExtractFile}\.mui"; } $files_extracted++; } } else { logmsg ("Cabinet file:$CabFile not found!"); } # # We have to extract Unlocalized version of the files so that we may add resource checksum to it # if ($BuildChecksum && (length($SourceFile_Localized) > 0) ) { # Get unlocalized Cab file $OriginalCabFile=&FindOriginalFile($ExtractFileRecord->{CabFile}); if (length($OriginalCabFile) == 0) { logmsg("Can't found Original for:$ExtractFileRecord->{CabFile}"); } else { logmsg("Try to get US files for:$ExtractFileRecord->{CabFile}"); } # # We Force Mui'ize every files from Cab # We only apply this process for files contain Fusion resource, but now we apply to # all files from Cab # # $ContainFusionResource=&IsFusionResource($SourceFile_Localized); $ContainFusionResource=1; if (length($OriginalCabFile) > 0) { $ExtractFileDir=$UnlocalizedFilesDir; unless (-e $ExtractFileDir) { &MakeDir($ExtractFileDir); } if ( -e $OriginalCabFile) { logmsg("extract.exe /y /l $ExtractFileDir $OriginalCabFile $ExtractFileRecord->{ExtractFile}"); if (!system ("extract.exe /y /l $ExtractFileDir $OriginalCabFile $ExtractFileRecord->{ExtractFile}") ) { logmsg("Unlocalized file $ExtractFileRecord->{ExtractFile} is extracted from $ExtractFileRecord->{CabFile} successfully"); # # Add Resource Checksum here # $SourceFile_US =$ExtractFileDir."\\$ExtractFileRecord->{ExtractFile}"; if (! $ContainFusionResource) { if (system("checksum.exe $SourceFile_Localized") == 0) { logmsg("muirct.exe -c $SourceFile_US -z $SourceFile_Localized"); system("muirct.exe -c $SourceFile_US -z $SourceFile_Localized"); } else { logmsg("Resource checksum already in $SourceFile_Localized"); } } else # ! $ContainFusionResource { if (! &DoMUIizedForFiles($SourceFile_Localized,$SourceFile_US)) { logmsg("$SourceFile_Localized contains Fusion but Can't be MUIized"); } } } else # !system ("extract.exe { if ($ContainFusionResource) { if (! &DoMUIizedForFiles($SourceFile_Localized,"")) { logmsg("$SourceFile_Localized contains Fusion but Can't be MUIized"); } } } } else # -e $OriginalCabFile { if ($ContainFusionResource) { if (! &DoMUIizedForFiles($SourceFile_Localized,"")) { logmsg("$SourceFile_Localized contains Fusion but Can't be MUIized"); } } } } else # length($OriginalCabFile) > 0 { if ($ContainFusionResource) { if (! &DoMUIizedForFiles($SourceFile_Localized,"")) { logmsg("$SourceFile_Localized contains Fusion but Can't be MUIized"); } } } } # if ($BuildChecksum) } return ($files_extracted, $file_errors, $total_files_extracted); } sub ExtractMSICabFiles { my ($CabRootDir, $ExtractRootDir, $ControlFile, $Incremental); my (%ExtractFiles, @ExtractLangs, $files_extracted, $file_errors, $total_files_extracted,$OriginalCabFile); my($MyTempFolder,$MSICabFolder,@Items, $Line, $MSICabName, $MSICabPath, $ExtractFileDir_US); my($UnlocalizedFile,$LocalizedFile, $LocalizedFolder, $DestFile, $New_LocalizedFile); #Pickup parameters ($CabRootDir, $ExtractRootDir, $ControlFile, $Incremental) = @_; # Set defaults $files_extracted = 0; $file_errors = 0; $total_files_extracted = 0; #Create a hash-hash from the control file table ParseTable::parse_table_file($ControlFile, \%ExtractFiles); #Loop through all control file entries # # $ExtractFileRecord{ExtractFile} : name of MSI table which contains CAB # $ExtractFileRecord{ExtractDir} : Destination Directory # $ExtractFileRecord{CabFile} : name of MSI File # $ExtractFileRecord{CabDir} : Source folder contains MSI file # foreach $ExtractFile (keys %ExtractFiles) { # Create file record hash $ExtractFileRecord{ExtractFile} = $ExtractFiles{$ExtractFile}{ExtractTable}; $ExtractFileRecord{ExtractDir} = $ExtractFiles{$ExtractFile}{ExtractDir}; $ExtractFileRecord{CabFile} = $ExtractFile; $ExtractFileRecord{CabDir} = $ExtractFiles{$ExtractFile}{MSIDir}; $ExtractFileRecord{Languages} = $ExtractFiles{$ExtractFile}{Languages}; logmsg("MSI:$ExtractFileRecord{CabFile} Table:$ExtractFileRecord{ExtractFile}"); #Preprocess file record hash unless ($ExtractFileRecord = &PreProcessRecord(\%ExtractFileRecord) ) { next; } #Process "-" entry in text file list if ($ExtractFileRecord->{CabDir}=~/^-$/i) { $CabFileDir="$CabRootDir"; } else { $CabFileDir="$CabRootDir\\$ExtractFileRecord->{CabDir}"; } if ($ExtractFileRecord->{ExtractDir}=~/^-$/i) { $ExtractFileDir="$ExtractRootDir"; } else { $ExtractFileDir="$ExtractRootDir\\$ExtractFileRecord->{ExtractDir}"; } $total_files_extracted++; #Create the destination dir if it does not exist unless (-e $ExtractFileDir) { &MakeDir($ExtractFileDir); } $CabFile = "$CabFileDir\\$ExtractFileRecord->{CabFile}"; unless (-e $MSITemp) { &MakeDir($MSITemp); } $MyTempFolder=$MSITemp."\\$ExtractFileRecord{CabFile}"; $LocalizedFolder= $MyTempFolder."\\LocalizedFolder"; if ( -e $MyTempFolder) { if ( system("rd /s /q $MyTempFolder") != 0) { errmsg("Can't delete $MyTempFolder for MSI extraction"); $file_errors++; next; } } &MakeDir($MyTempFolder); if (! -e $MyTempFolder) { errmsg("Can't create $MyTempFolder for MSI extraction"); next; } &MakeDir($LocalizedFolder); if (! -e $LocalizedFolder) { errmsg("Can't create $LocalizedFolder for MSI extraction"); next; } # # Let's extract Cab from MSI # if ( ! -e $CabFile) { logmsg("Warning:$CabFile doesn't exist"); next; } logmsg("msidb.exe -d $CabFile -f $MyTempFolder -e $ExtractFileRecord{ExtractFile}"); if ( system("msidb.exe -d $CabFile -f $MyTempFolder -e $ExtractFileRecord{ExtractFile}") != 0) { logmsg("Warning: Can't extract table $ExtractFileRecord{ExtractFile} from $CabFile"); next; } # # There is a subfolder $ExtractFileRecord{ExtractFile} under $MyTempFolder and the cab file live under this folder # $MSICabFolder=$MyTempFolder."\\$ExtractFileRecord{ExtractFile}"; # # Get the name of CAB file # unless (opendir(INDIR,$MSICabFolder)) { errmsg("Can't open MSI cab folder: $MSICabFolder"); $file_errors++; next; } @Items=readdir INDIR; close(INDIR); undef $MSICabName; LINE: foreach $Line (@Items) { if ( ($Line eq "." ) || ($Line eq "..") ) { next; } $MSICabName=$Line; last LINE; } # # Extract the Cab inside *.MSI # if (! defined($MSICabName)) { errmsg("No CAB file inside $ExtractFileRecord{CabFile}"); $file_errors++; next; } $MSICabPath="$MSICabFolder\\$MSICabName"; logmsg("extract /y /L $LocalizedFolder $MSICabPath *.exe *.dll *.cpl *.ocx *.tsp *.scr *.chm *.chq *.hlp *.cnt *.mfl"); if (system("extract /y /L $LocalizedFolder $MSICabPath *.exe *.dll *.cpl *.ocx *.tsp *.scr *.chm *.chq *.hlp *.cnt *.mfl") != 0) { errmsg("extract $MSICabPath failed"); next; } $files_extracted++; # We have to extract Unlocalized version of the files so that we may add resource checksum to it # if ($BuildChecksum) { $CabFile=&FindOriginalFile($ExtractFileRecord->{CabFile}); if (length($CabFile) == 0) { logmsg("Can't found Original for:$ExtractFileRecord->{CabFile}"); } else { logmsg("Try to get US files for:$ExtractFileRecord->{CabFile}"); } if (length($CabFile) > 0) { if ( -e $CabFile) { $MyTempFolder=$MSITemp."\\$ExtractFileRecord{CabFile}.unl"; if ( -e $MyTempFolder) { if ( system("rd /s /q $MyTempFolder") != 0) { logmsg("Can't delete $MyTempFolder for MSI extraction"); $file_errors++; next; } } &MakeDir($MyTempFolder); if (! -e $MyTempFolder) { errmsg("Can't create $MyTempFolder"); next; } $ExtractFileDir_US=$MyTempFolder."\\UnlocalizedFolder"; &MakeDir($ExtractFileDir_US); if (! -e $ExtractFileDir_US) { errmsg("Can't create $ExtractFileDir_US"); next; } # # Let's extract Cab from MSI # logmsg("msidb.exe -d $CabFile -f $MyTempFolder -e $ExtractFileRecord{ExtractFile}"); if ( system("msidb.exe -d $CabFile -f $MyTempFolder -e $ExtractFileRecord{ExtractFile}") != 0) { errmsg("Can't extract table $ExtractFileRecord{ExtractFile} from $CabFile"); $file_errors++; next; } # # There is a subfolder $ExtractFileRecord{ExtractFile} under $MyTempFolder and the cab file live under this folder # $MSICabFolder=$MyTempFolder."\\$ExtractFileRecord{ExtractFile}"; # # Extract the Cab inside *.MSI # $MSICabPath="$MSICabFolder\\$MSICabName"; logmsg("extract /y /L $ExtractFileDir_US $MSICabPath *.exe *.dll *.cpl *.ocx *.tsp *.scr"); if (system("extract /y /L $ExtractFileDir_US $MSICabPath *.exe *.dll *.cpl *.ocx *.tsp *.scr ") != 0) { errmsg("extract $MSICabPath failed"); next; } # # Add Resource Checksum to Files # unless (opendir(INDIR,$ExtractFileDir_US)) { errmsg("Can't open Unlocalized MSI cab folder: $ExtractFileDir_US"); $file_errors++; next; } @Items=readdir INDIR; close(INDIR); foreach $Line (@Items) { if ( ($Line eq "." ) || ($Line eq "..") ) { next; } $UnlocalizedFile=$ExtractFileDir_US."\\$Line"; $LocalizedFile=$LocalizedFolder."\\$Line"; if (system("checksum.exe $LocalizedFile") == 0 ) { logmsg("muirct.exe -c $UnlocalizedFile -z $LocalizedFile"); system("muirct.exe -c $UnlocalizedFile -z $LocalizedFile"); } else { logmsg("Resourcechecksum already in $LocalizedFile"); } } # foreach $Line (@Items) } # if ( -e $CabFile) } # if (length($CabFile) } # if ($BuildChecksum) # # Copy Files to Destination # unless (opendir(INDIR,$LocalizedFolder)) { errmsg("Can't open Unlocalized MSI cab folder: $LocalizedFolder"); $file_errors++; next; } @Items=readdir INDIR; close(INDIR); foreach $Line (@Items) { if ( ($Line eq "." ) || ($Line eq "..") ) { next; } $LocalizedFile=$LocalizedFolder."\\$Line"; $DestFile=$ExtractFileDir."\\$Line"; if ( &IsWin32File($Line)) { $DestFile=$DestFile.".mui"; # # We Force Mui'ize every files from MSI # We only apply this process for files contain Fusion resource, but now we apply to # all files from MSI # # if (&IsFusionResource($LocalizedFile)) # if(1) { $UnlocalizedFile=$ExtractFileDir_US."\\$Line"; if (! -e $UnlocalizedFile) { $UnlocalizedFile=""; } if (! &DoMUIizedForFiles($LocalizedFile,$UnlocalizedFile)) { logmsg("Warning: $LocalizedFile contains Fusion resource but it can't be MUIized"); } } } logmsg("Copying $LocalizedFile -> $DestFile"); if (!copy("$LocalizedFile", "$DestFile")) { logmsg("Failed:Copying $LocalizedFile -> $DestFile"); $file_errors++; } } } return ($files_extracted, $file_errors, $total_files_extracted); } #Function to copy a directory given a filter sub CopyDir { my ($SrcDir, $DestDir, $FileFilter, $Incremental); my (@CopyFiles, $files_copied, $file_errors, $total_files_copied); ($SrcDir, $DestDir, $FileFilter, $Incremental) = @_; #If a file filter is not defined set a file filter of *. if (!defined $FileFilter) {$FileFilter ="*"}; #Create the destination dir if it does not exist unless (-e $DestDir) { &MakeDir($DestDir); } my $LocalDirHandle = DirHandle->new($SrcDir); @CopyFiles = sort grep {-f} map {"$SrcDir\\$_"} grep {!/^\./} grep {/\.$FileFilter$/i} $LocalDirHandle->read(); foreach $SrcCopyFile (@CopyFiles) { #Copy the file logmsg ("Copying $SrcCopyFile -> $DestDir"); if (copy("$SrcCopyFile", "$DestDir") ) { $files_copied++; } else { logmsg("$!"); $file_errors++; } } return; } # Function to create a directory sub MakeDir { my ($fulldir) = @_; my ($drive, $path) = $fulldir =~ /((?:[a-z]:)|(?:\\\\[\w-]+\\[^\\]+))?(.*)/i; logmsg ("Making dir:$fulldir"); my $thisdir = ''; for my $part ($path =~ /(\\[^\\]+)/g) { $thisdir .= "$part"; mkdir( "$drive$thisdir", 0777 ); } if ( ! -d $fulldir ) { errmsg ("Could not mkdir:$fulldir $!"); return 0; } return; } #----------------------------------------------------------------------------- # ModAge - returns (fractional) number of days since file was last modified # NOTE: this script is necessary only because x86 and alpha give different # answers to perl's file age functions: # Alpha: # -C = days since creation # -M = days since last modification # -A = days since last access # X86: # -C = days since last modification # -M = days since last access # -A = ??? #----------------------------------------------------------------------------- sub ModAge { my($file, $mod_age); # Get input arguments ($file) = @_; # i386 uses -C when alpha uses -M if($PROCESSOR =~ /^[iI]386$/) { $mod_age = -C $file; } elsif($PROCESSOR =~ /^(ALPHA|Alpha|alpha)$/) { $mod_age = -M $file; } return $mod_age; } # ModAge sub ValidateParams { # } # sub Usage { print < and populates the %_nt_bindir%\\mui tree Creates language-specific resource only DLLs from localized 32-bit images. These DLLs are used for the Multilingual User Interface (MUI), aka pluggable UI product for NT5. By default, does not create a resource-only-dll if there already is one of the same name and it is newer than the localized binary. Also Creates a language-specific version of ie5ui.inf, and updates mui.inf to contain the current build number. perl $0 [-f] [-v] -f: Force option - overrides the incremental behavior of this script. Overwrites output files (such as resource-only dlls) even if they already exist and are newer than their input files (such as the localized binaries). -v: Verbose option - gives extra messages describing what is happening to each file. By default, the only messages displayed are successes and errors which abort the process. lang: valid 2-letter (Dublin) or 3-letter (Redmond) code for a language (There is no default value for lang) OUTPUT The language-specific resource-only DLLs are placed in: %_NTBINDIR%\\mui\\\\%_BuildArch% The language-specific resource files are placed in: %_NTBINDIR%\\mui\\\\res A logfile is created, named: %_NTBINDIR%\\logs\\muigen..log Safemode: if you want the command echoed to stdout and not run, set safemode=1 (This also turns off the logfile) EXAMPLE perl $0 ger USAGE } sub GetParams { # Step 1: Call pm getparams with specified arguments &GetParams::getparams(@_); # Step 2: Set the language into the enviroment $ENV{lang}=$lang; # Step 3: Call the usage if specified by /? if ($HELP) { &Usage(); exit 1; } } # Cmd entry point for script. if (eval("\$0 =~ /" . __PACKAGE__ . "\\.pm\$/i")) { # Step 1: Parse the command line # &GetParams ('-o', 'fvl:', '-p', 'FORCE VERBOSE lang', @ARGV); # Include local environment extensions &LocalEnvEx::localenvex('initialize'); # Set lang from the environment $LANG=$ENV{lang}; # Validate the option given as parameter. &ValidateParams; # Step 4: Call the main function &muimake::Main(); # End local environment extensions. &LocalEnvEx::localenvex('end'); } # Copy MUI root files sub CopyMUIRootFiles { my ($layout); my ($us_muisetup); $layout = GetCDLayOut(); logmsg("Copy MUI root files"); system "xcopy /vy $MUIDIR\\*.* $MUI_RELEASE_DIR\\$layout\\*.*"; system "xcopy /vy $MUIDIR\\*.* $MUI_RELEASE_DIR2\\$layout\\*.*"; #temp fix to copy it to another dir for msi #copy over valueadd tools to MUI CD1 if (-e "$MUIDIR\\$MUI_VALUEADD_DIR" && uc($layout) eq "CD1" ) { unless (-e "$MUI_RELEASE_DIR\\$layout\\$MUI_VALUEADD_DIR") { &MakeDir("$MUI_RELEASE_DIR\\$layout\\$MUI_VALUEADD_DIR"); } system "xcopy /svy $MUIDIR\\$MUI_VALUEADD_DIR $MUI_RELEASE_DIR\\$layout\\$MUI_VALUEADD_DIR"; unless (-e "$MUI_RELEASE_DIR2\\$layout\\$MUI_VALUEADD_DIR") { &MakeDir("$MUI_RELEASE_DIR2\\$layout\\$MUI_VALUEADD_DIR"); } system "xcopy /svy $MUIDIR\\$MUI_VALUEADD_DIR $MUI_RELEASE_DIR2\\$layout\\$MUI_VALUEADD_DIR"; logmsg("Copy valueadd files"); } # copy the far east printer drivers if (-e "$MUIDIR\\$MUI_PRINTER_DRIVER_DIR" && uc($layout) eq "CD1" ) { unless (-e "$MUI_RELEASE_DIR\\$layout\\$MUI_PRINTER_DRIVER_DIR") { &MakeDir("$MUI_RELEASE_DIR\\$layout\\$MUI_PRINTER_DRIVER_DIR"); } system "xcopy /svy $MUIDIR\\$MUI_PRINTER_DRIVER_DIR $MUI_RELEASE_DIR\\$layout\\$MUI_PRINTER_DRIVER_DIR"; unless (-e "$MUI_RELEASE_DIR2\\$layout\\$MUI_PRINTER_DRIVER_DIR") { &MakeDir("$MUI_RELEASE_DIR2\\$layout\\$MUI_PRINTER_DRIVER_DIR"); } system "xcopy /svy $MUIDIR\\$MUI_PRINTER_DRIVER_DIR $MUI_RELEASE_DIR2\\$layout\\$MUI_PRINTER_DRIVER_DIR"; logmsg("Copy FE printer drivers"); } # copy the .net framework files to the release cd from postbuild bin dir # exclude PSU and client languages (which do not have .net framework files) if ($ENV{_BuildArch}=~/x86/i && !($LANG=~/^(PSU|MIR|FE|ARA|HEB|DA|FI|NO|EL)/i )) { # make the .net framework directory netfx in cd release dir unless (-e "$MUI_RELEASE_DIR\\$layout\\$MUI_NETFX_DIR") { &MakeDir("$MUI_RELEASE_DIR\\$layout\\$MUI_NETFX_DIR"); } unless (-e "$MUI_RELEASE_DIR2\\$layout\\$MUI_NETFX_DIR") { &MakeDir("$MUI_RELEASE_DIR2\\$layout\\$MUI_NETFX_DIR"); } # make the language subfolder under netfx in cd release dir unless (-e "$MUI_RELEASE_DIR\\$layout\\$MUI_NETFX_DIR\\$LANG") { &MakeDir("$MUI_RELEASE_DIR\\$layout\\$MUI_NETFX_DIR\\$LANG"); } unless (-e "$MUI_RELEASE_DIR2\\$layout\\$MUI_NETFX_DIR\\$LANG") { &MakeDir("$MUI_RELEASE_DIR2\\$layout\\$MUI_NETFX_DIR\\$LANG"); } # copy langpack.msi and langpac1.cab to the netfx\lang directory in cd release dir if (-e "$LOCBINDIR\\netfx\\langpack.msi" && -e "$LOCBINDIR\\netfx\\langpac1.cab") { system "copy /vy $LOCBINDIR\\netfx\\langpack.msi $MUI_RELEASE_DIR\\$layout\\$MUI_NETFX_DIR\\$LANG\\langpack.msi"; system "copy /vy $LOCBINDIR\\netfx\\langpac1.cab $MUI_RELEASE_DIR\\$layout\\$MUI_NETFX_DIR\\$LANG\\langpac1.cab"; system "copy /vy $LOCBINDIR\\netfx\\langpack.msi $MUI_RELEASE_DIR2\\$layout\\$MUI_NETFX_DIR\\$LANG\\langpack.msi"; system "copy /vy $LOCBINDIR\\netfx\\langpac1.cab $MUI_RELEASE_DIR2\\$layout\\$MUI_NETFX_DIR\\$LANG\\langpac1.cab"; logmsg("Copied .net framework files."); } else { errmsg("Cannot find .net framework MUI files."); } } else { logmsg("NOTE: Skipping .net framework files for language $LANG and platform $ENV{_BuildArch}"); } # muisetup.exe exists under US binary and it is a signed binary # so we'll grab US version to prevent file protection issues $us_muisetup = &FindOriginalFile("muisetup.exe"); if (-e $us_muisetup) { # system "xcopy /vy $us_muisetup $MUI_RELEASE_DIR\\$layout\\*.*"; system "xcopy /vy $us_muisetup $MUI_RELEASE_DIR2\\$layout\\*.*"; #temp fix to copy it to another dir for msi system "xcopy /vy $us_muisetup $MUIDIR\\*.*"; logmsg ("Copy signed MUISETUP.EXE from $us_muisetup"); } else { logmsg ("WARNING: signed MUISETUP.EXE not found"); } # also copy the old muisetup.exe from the mui\msi postbuild directory for the temp build $us_muisetup = "$MUIDIR\\MSI\\muisetup.exe"; if (-e $us_muisetup) { system "xcopy /vy $us_muisetup $MUI_RELEASE_DIR\\$layout\\*.*"; } else { logmsg("Can't find old version of muisetup.exe for copying."); } return 1; } # Get CD layout from MUI.INF sub GetCDLayOut { my(@cd_layout, @lang_map, $muilang, $lang_id); # Map lang @lang_map = `perl $RAZZLETOOLPATH\\PostBuildScripts\\parseinf.pl $INFFILE Languages`; foreach $muilang (@lang_map) { if ($muilang =~ /(.*)=$LANG\.mui/i) { # Get layout $langid = $1; # Try ia64 section first if we're building ia64 MUI if ($_BuildArch =~ /ia64/i) { @cd_layout = `perl $RAZZLETOOLPATH\\PostBuildScripts\\parseinf.pl $INFFILE CD_LAYOUT_IA64`; foreach $layout (@cd_layout) { chomp($layout); if ($layout =~ /$langid=(\d+)/i) { return uc("cd$1"); } } } @cd_layout = `perl $RAZZLETOOLPATH\\PostBuildScripts\\parseinf.pl $INFFILE CD_LAYOUT`; foreach $layout (@cd_layout) { chomp($layout); if ($layout =~ /$langid=(\d+)/i) { return uc("cd$1"); } } last; } } return lc("psu"); } # ------------------------------------------------------------------------------------------- # Script: template_script.pm # Purpose: Template perl perl script for the NT postbuild environment # SD Location: %sdxroot%\tools\postbuildscripts # # (1) Code section description: # CmdMain - Developer code section. This is where your work gets done. # - Developer subs code section. This is where you write subs. # # (2) Reserved Variables - # $ENV{HELP} - Flag that specifies usage. # $ENV{lang} - The specified language. Defaults to USA. # $ENV{logfile} - The path and filename of the logs file. # $ENV{logfile_bak} - The path and filename of the logfile. # $ENV{errfile} - The path and filename of the error file. # $ENV{tmpfile} - The path and filename of the temp file. # $ENV{errors} - The scripts errorlevel. # $ENV{script_name} - The script name. # $ENV{_NTPostBld} - Abstracts the language from the files path that # postbuild operates on. # $ENV{_NTPostBld_Bak} - Reserved support var. # $ENV{_temp_bak} - Reserved support var. # # (3) Reserved Subs - # Usage - Use this sub to discribe the scripts usage. # ValidateParams - Use this sub to verify the parameters passed to the script. # # (4) Call other executables or command scripts by using: # system "foo.exe"; # Note that the executable/script you're calling with system must return a # non-zero value on errors to make the error checking mechanism work. # # Example # if (system("perl.exe foo.pl -l $lang")){ # errmsg("perl.exe foo.pl -l $lang failed."); # # If you need to terminate function's execution on this error # goto End; # } # # (5) Log non-error information by using: # logmsg ""; # and log error information by using: # errmsg ""; # # (6) Have your changes reviewed by a member of the US build team (ntbusa) and # by a member of the international build team (ntbintl). # # ------------------------------------------------------------------------------------------- =head1 NAME B - What this package for =head1 SYNOPSIS =head1 DESCRIPTION =head1 INSTANCES =head2 =head1 METHODS =head2 =head1 SEE ALSO =head1 AUTHOR > =cut 1;