################################################################################# # # Script: muimsi.pm # # (c) 2000 Microsoft Corporation. All rights reserved. # # Purpose: This script creates the msi package # # Version: 1.00 (06/27/2001) : (lguindon) Created # ################################################################################## # Set Package package muimsi; # Set the script name $ENV{script_name} = 'muimsi.pm'; $cmdPrompt = 0; # Set version $VERSION = '1.00'; # Set required perl version require 5.003; # Use section use lib $ENV{ "RazzleToolPath" }; use lib $ENV{ "RazzleToolPath" } . "\\PostBuildScripts"; 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; use Win32::OLE; use Win32::File; # Require Section require Exporter; # Global variable section %SKUList = (); #list of skus to include files for, populated in DefineConstants() %SKUExList = (); # list of skus to excluse files for and to prevent installation on, populated in DefineConstants() @DeleteTableList = ("AdminUISequence", "AdminExecuteSequence"); # names of MSI tables that we want to delete ################################################################################## # # Main entry point. # ################################################################################## sub Main { # if language is US (or not set), we just return and log a warning. This is # so that we can include the script in prs postbuild so that # we will repack the signed binaries back into the MSI if (($lang=~/usa/i) || (!$lang)) { logmsg("MUI MSI package is not produced for US build."); } else { # Check environment variables if (!&VerifyEnvironment()) { errmsg ("The environment is not correct for MSI Package build."); return 0; } # Get language's LCID and ISO code if (!&GetCodes()) { errmsg ("The language's LCID and ISO code could not be extracted from the CODEFILE."); return 0; } # Define some constants if (!&DefineConstants()) { errmsg ("Constants could not be defined."); return 0; } # Make sure directories exist if (!&CheckDirs()) { errmsg ("The required directorys do not exist."); return 0; } # Search for current build number if (!&LookForBuildNumber()) { errmsg ("No build number information found."); } # Apply XMLVAR to the template if (!&XMLVAR()) { errmsg ("Error with XMLVAR script."); } # Modify the template output generated by XMLVAR to include fusion support if (!&GenFusionAssemblyXML()) { errmsg ("Error with GenFusionAssemblyXML script."); } # Insert Eula content into the template if (!&InsertEula()) { errmsg ("Failed to insert Eula Text into the MSI Template - the EULA dialog will be empty in the build."); } # Insert the reserve cost nodes if (!&InsertReserveCost()) { errmsg ("Failed to insert reserved diskcost nodes for language packs into the MSI Template MSI diskcost will not include langpack disk costs."); } # Insert the skus that we want to merge into the final package if (!&InsertSKUNodes()) { errmsg ("Failed to delete the unused SKU merge module nodes from the MSI Template."); } # Generate file contents files if (!&FileContents()) { errmsg ("File contents couldn't be created."); } # Generate custom action files if (!&CustomAction()) { errmsg ("Error with Custom Action script."); } # Make MSI package if (!&MakeMSI()) { errmsg ("Error making the MSI Package."); } # Delete the unused MSI table generated as part of the WiX Build process if (!&DeleteMSITables()) { errmsg ("Error deleting the unused MSI tables."); } # insert the catalog files back into the FE printer packs if (!&InsertCatFiles()) { errmsg ("Error inserting catalog files into the FE printer MSI packages."); } } } # Main ################################################################################## # # VerifyEnvironment() # # Validates necessary environment variables. # ################################################################################## sub VerifyEnvironment { logmsg ("Validating the environment."); $RAZZLETOOLPATH=$ENV{RazzleToolPath}; $_NTPOSTBLD=$ENV{_NTPOSTBLD}; logmsg("------- RAZZLETOOLPATH is $RAZZLETOOLPATH"); logmsg("------- _NTPOSBLD is $_NTPOSTBLD"); logmsg("------- LANG is $LANG"); 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}; logmsg("------- Build architecture is $_BuildArch"); logmsg("------- LOGS is $LOGS"); 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; } # VerifyEnvironment ################################################################################## # # DefineConstants() # # Defines global constants. # ################################################################################## sub DefineConstants { logmsg ("Definition of global constants."); # Directories $LOCBINDIR = "$_NTPOSTBLD"; $MUIDIR = "$LOCBINDIR\\mui"; $MSIDIR = "$MUIDIR\\MSI"; $CONTROLDIR = "$MUIDIR\\control"; $SOURCEDIR = "$MUIDIR\\$Special_Lang\\$_BuildArch.uncomp"; $INFFILE = "$MUIDIR\\mui.inf"; $CDLAYOUT = GetCDLayOut(); $DESTDIR = "$MUIDIR\\release\\$_BuildArch_release\\$CDLAYOUT"; $TMPBUILD = "$MUIDIR\\$Special_Lang\\tmp"; $TEMPLATE = "$MSIDIR\\muimsi_template.wim"; logmsg("------- LOCBINDIR is $LOCBINDIR"); logmsg("------- MUIDIR is $MUIDIR"); logmsg("------- MSIDIR is $MSIDIR"); logmsg("------- CONTROLDIR is $CONTROLDIR"); logmsg("------- SOURCEDIR is $SOURCEDIR"); logmsg("------- DESTDIR is $DESTDIR"); logmsg("------- TMPBUILD is $TMPBUILD"); logmsg("------- CDLAYOUT is $CDLAYOUT"); # Filenames # kenhsu - some build filenames are different on IA64 if (($ENV{_BuildArch} =~/x86/i)) { $GUIDFILE = "$MSIDIR\\guidlang.txt"; $PLATFORM = "Intel"; $IA64CONDITION = "NOT VersionNT64"; $ISWIN64 = "no"; $SYSFOLDERPROP = "SystemFolder"; } else { $GUIDFILE = "$MSIDIR\\guidlang64.txt"; $PLATFORM = "Intel64"; $IA64CONDITION = "VersionNT64"; $ISWIN64 = "yes"; $SYSFOLDERPROP = "System64Folder"; } logmsg("MSI Package platform is $PLATFORM"); logmsg("MSI Template file used is $TEMPLATE"); logmsg("MSI GUID file used is $GUIDFILE"); $SRCRELNOTE = "$MSIDIR\\msinotes.htm"; $SRCXPBITMAP = "$MSIDIR\\muimsi_hl.bmp"; $SRCMUISETUP = "$MUIDIR\\muisetup.exe"; $SRCMUIMSIDLL = "$MSIDIR\\muimsidll.dll"; $DSTRELNOTE = "$DESTDIR\\msinotes.htm"; $MUIMSIXML = "$TMPBUILD\\$LCID_SHORT.wim"; $MUIMSIXMLTemp = "$TMPBUILD\\Temp$LCID_SHORT.wim"; $MUIMSIWIX = "$TMPBUILD\\$LCID_SHORT.msi"; $MUIMSI = "$DESTDIR\\$LCID_SHORT.msi";; $FILECNT_CORE = "$TMPBUILD\\FileContent_CORE.wxm"; #core files required in every flavour $FILELST_CORE = "$TMPBUILD\\FileContent_CORE.msm"; $FILECNT_PRO = "$TMPBUILD\\FileContent_PRO.wxm"; #professional build of NT $FILELST_PRO = "$TMPBUILD\\FileContent_PRO.msm"; $FILECNT_SRV = "$TMPBUILD\\FileContent_SRV.wxm"; #standard server build of NT $FILELST_SRV = "$TMPBUILD\\FileContent_SRV.msm"; $FILECNT_ADV = "$TMPBUILD\\FileContent_ADV.wxm"; #advanced server build of NT $FILELST_ADV = "$TMPBUILD\\FileContent_ADV.msm"; $FILECNT_DTC = "$TMPBUILD\\FileContent_DTC.wxm"; #datacenter build of NT $FILELST_DTC = "$TMPBUILD\\FileContent_DTC.msm"; $FILECNT_WEB = "$TMPBUILD\\FileContent_WEB.wxm"; #webserver (blade) build of NT $FILELST_WEB = "$TMPBUILD\\FileContent_WEB.msm"; $FILECNT_SBS = "$TMPBUILD\\FileContent_SBS.wxm"; #small business build of NT $FILELST_SBS = "$TMPBUILD\\FileContent_SBS.msm"; $CUSTACTION = "$CONTROLDIR\\Custom_action.wxm"; $CUSTACTIONCOMP = "$CONTROLDIR\\Custom_action.msm"; $WISCHEMA = "$MSIDIR\\WiSchema.xml"; # Applications $INFPARSER = "infparser.exe"; $CANDLE = "CScript.exe $MSIDIR\\candle.wsf"; $LIGHT = "CScript.exe $MSIDIR\\light.wsf"; $XMLVAR = "perl.exe $MSIDIR\\xmlvar.bat"; $COPY = "copy"; # Flavor if($_BuildArch =~ /i386/i) { $FLAVOR = "32"; } elsif ($_BuildArch =~ /ia64/i) { $FLAVOR = "64"; } logmsg("------- FLAVOR is $FLAVOR"); # GUID - read the language guid off the language-guid file, if it's not there # generate one and put it in the file. logmsg ("Get the language's MSI package ID from $GUIDFILE."); my(@langguids, @newcontent); # Search GUIDFILE for $Special_Lang and the associated MSI package guid if(!open(GUIDFILE, "$GUIDFILE")) { errmsg ("Can't open language guid file $GUIDFILE for reading."); return 0; } GUID_LOOP: while () { # add the file content to an array, in case we need to append additional data # push(@newcontent, $_); if (/^$Special_Lang\s+/i) { @langguids = split(/\s+/,$_); $MSIGUID = $langguids[1]; # 2nd field should be the client language guid $PRODUCTGUID = $langguids[2]; # 3rd field should be the product language guid last GUID_LOOP; # exit out of the loop if found } } close(GUIDFILE); $MSIGUID =~ tr/a-z/A-Z/; $PRODUCTGUID =~ tr/a-z/A-Z/; # if the language is not found, add a new guid entry into GUIDFILE if(!@langguids) { logmsg ("$Special_Lang is not found in $GUIDFILE, adding an entry for it."); ($MSIGUID) = `uuidgen`; chomp $MSIGUID; $MSIGUID =~ tr/a-z/A-Z/; } ($REGISTRY1GUID) = `uuidgen`; chomp $REGISTRY1GUID; $REGISTRY1GUID =~ tr/a-z/A-Z/; ($REGISTRY3GUID) = `uuidgen`; chomp $REGISTRY3GUID; $REGISTRY3GUID =~ tr/a-z/A-Z/; logmsg("------- REGISTRY1GUID is $REGISTRY1GUID"); logmsg("------- REGISTRY3GUID is $REGISTRY3GUID"); logmsg("------- MSIGUID is $MSIGUID"); logmsg("------- PRODUCTGUID is $PRODUCTGUID"); # Other GUIDs $UPGRADEGUID = "177146D4-5102-4BD9-98A0-114A3ED39076"; $CONTENTGUID = "1AFE112F-290F-4A94-2000-AB4D3FD8B102"; # MSI version number my ($src, $isdst); ($src, $min, $hour, $mday, $mon, $year, $wday, $yday, $isdst) = localtime; eval $hour; eval $min; eval $yday; eval $wday; $VERSIONNUMBER = 100*(12*($year-101)+$mon+1)+$mday; logmsg("------- VERSIONNUMBER is $VERSIONNUMBER"); # Package name $PACKAGENAME = "muiMSITemplate ($VERSIONNUMBER)"; logmsg("------- PACKAGENAME is $PACKAGENAME"); logmsg ("Success: Definition of global constants."); $BuildChecksum=1; logmsg("-------- Including CORE files."); $SKUList{"Core"} = { InfParserFlag => "c", CntLstFileName => "$FILECNT_CORE", MergModeFileName => "$FILELST_CORE", }; if (defined($prosku)) { logmsg("-------- Including files for Professional SKU."); $SKUList{"Pro"} = { InfParserFlag => "p", CntLstFileName => "$FILECNT_PRO", MergModeFileName => "$FILELST_PRO", }; } else { logmsg("-------- Excluding files for Professional SKU."); $SKUExList{"Pro"} = { Message => "The [ProductName] cannot be installed on Windows XP Professional Edition.", Condition => "MsiNTProductType <> 1", }; } # If this is one of the Client(wks) languages we only want the Core File Content included and Pro Launch Condition if ($FLV =~ /WKS/i) { return 1; } if (defined($srvsku)) { logmsg("-------- Including files for Standard Server SKU."); $SKUList{"Srv"} = { InfParserFlag => "s", CntLstFileName => "$FILECNT_SRV", MergModeFileName => "$FILELST_SRV", }; } else { logmsg("-------- Excluding files for Standard Server SKU."); $SKUExList{"Srv"} = { Message => "The [ProductName] cannot be installed on Windows .NET 2003, Standard Edition.", Condition => "MsiNTProductType<>1 AND NOT MsiNTSuiteDataCenter AND NOT MsiNTSuiteEnterprise AND NOT MsiNTSuiteWebServer AND NOT MsiNTSuiteSmallBusiness AND NOT MsiNTSuiteSmallBusinessRestricted", }; } if (defined($advsku)) { logmsg("-------- Including files for Advanced Server SKU."); $SKUList{"Adv"} = { InfParserFlag => "a", CntLstFileName => "$FILECNT_ADV", MergModeFileName => "$FILELST_ADV", }; } else { logmsg("-------- Excluding files for Advanced Server SKU."); $SKUExList{"Adv"} = { Message => "The [ProductName] cannot be installed on Windows .NET 2003, Enterprise Edition.", Condition => "NOT MsiNTSuiteEnterprise", }; } if (defined($dtcsku)) { logmsg("-------- Including files for Datacenter Server SKU."); $SKUList{"Dtc"} = { InfParserFlag => "d", CntLstFileName => "$FILECNT_DTC", MergModeFileName => "$FILELST_DTC", }; } else { logmsg("-------- Excluding files for Datacenter Server SKU."); $SKUExList{"Dtc"} = { Message => "The [ProductName] cannot be installed on Windows .NET 2003, Datacenter Edition.", Condition => "NOT MsiNTSuiteDataCenter", }; } if (defined($websku)) { logmsg("-------- Including files for Blade Server SKU."); $SKUList{"Web"} = { InfParserFlag => "b", CntLstFileName => "$FILECNT_WEB", MergModeFileName => "$FILELST_WEB", }; } else { logmsg("-------- Excluding files for Web Server SKU."); $SKUExList{"Web"} = { Message => "The [ProductName] cannot be installed on Windows .NET 2003 Web Server.", Condition => "NOT MsiNTSuiteWebServer", }; } if (defined($sbssku)) { logmsg("-------- Including files for Small Business Server SKU."); $SKUList{"Sbs"} = { InfParserFlag => "l", CntLstFileName => "$FILECNT_SBS", MergModeFileName => "$FILELST_SBS", }; } else { logmsg("-------- Excluding files for Small Business Server SKU."); $SKUExList{"Sbs"} = { Message => "The [ProductName] cannot be installed on Windows .NET Server 2003 for Small Business Server.", Condition => "NOT MsiNTSuiteSmallBusiness AND NOT MsiNTSuiteSmallBusinessRestricted", }; } return 1; } # DefineConstants ################################################################################## # # GetCodes # # Gets the language's LCID and ISO language code from CODEFILE. # ################################################################################## sub GetCodes { #set the code file name to read $CODEFILE = "$RAZZLETOOLPATH\\codes.txt"; $DESCFILE = "$_NTPOSTBLD\\mui\\MSI\\langdesc.txt"; logmsg ("Get the language's LCID and ISO language code from $CODEFILE."); my(@data); my(@data2); # 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]; $FLV = $data[6]; #extract the language description - get this from our lang description file if(!open(DESCFILE, "$DESCFILE")) { errmsg ("Can't open lcid description file $DESCFILE for reading."); return 0; } DESC_LOOP: while () { if (/^$LCID_SHORT\s+/i) { @data2 = split(/\s+/,$_); last DESC_LOOP; } } close(DESCFILE); if(!@data2) { logmsg ("Cannot find a language description for $LCID_SHORT."); return 0; } $LANG_NAME = $data2[1]; for ($i = 2; $i <= $#data2; $i++) { $LANG_NAME = "$LANG_NAME $data2[$i]"; } logmsg ("Success: Get the language's LCID and ISO language code frrm $CODEFILE."); logmsg("------- LCID is $LCID"); logmsg("------- LCID_SHORT is $LCID_SHORT"); logmsg("------- LANG_ISO is $LANG_ISO"); logmsg("------- GUID is $GUID"); logmsg("------- LANG_NAME is $LANG_NAME"); logmsg("------- FLV is $FLV"); 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,$SOURCEDIR,$MSIDIR) { if(! -e $_) { logmsg ("$0: ERROR: $_ does not exist"); return 0; } } # Make sure destination directories exist foreach ($DESTDIR,$TMPBUILD) { if(! -e $_) { $status = system("md $_"); if($status) { logmsg ("$0: ERROR: cannot create $_"); return 0; } } } logmsg ("del /q /f $TMPBUILD\\*.*"); $returnStatus = system("del /q /f $TMPBUILD\\*.*"); if ($returnStatus) { logmsg ("INFO: script did not find previously generated MSI build files."); } logmsg ("Success: Make sure the necessary directories exist."); return 1; } # CheckDirs ################################################################################## # # LookForBuildNumber # # Scan build log for the build number. # ################################################################################## sub LookForBuildNumber { logmsg ("Update mui.inf with the current build number."); # 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 ("Errorin LookForBuildNumber: BLDNO is $BLDNO"); return 0; } chomp($BLDNO); logmsg("------- BLDNO is $BLDNO"); logmsg ("Success: Update mui.inf with the current build number."); return 1; } # LookForBuildNumber ################################################################################## # # FileContents() # # Generate different flavor of filecontents.wxm. # ################################################################################## sub FileContents { logmsg ("Generate MSI file contents."); for $skuitem (keys %SKUList) { $infparserParam = "/P:$CDLAYOUT /i:$LOCBINDIR /b:$FLAVOR /l:$Special_Lang /f:$SKUList{$skuitem}{InfParserFlag} /s:$MUIDIR /o:$SKUList{$skuitem}{CntLstFileName}"; $compileParam = "-c $SKUList{$skuitem}{MergModeFileName} $SKUList{$skuitem}{CntLstFileName}"; $linkParam = $SKUList{$skuitem}{MergModeFileName}; logmsg ("Generate MSI $skuitem content."); logmsg ("$INFPARSER $infparserParam"); $returnResult = system("$INFPARSER $infparserParam"); if ($returnResult) { logmsg("ERROR: unable to generate MSI $skuitem content! "); return 0; } # Compile core file content logmsg ("Compile MSI $skuitem content."); logmsg ("$CANDLE $compileParam"); $returnResult = system("$CANDLE $compileParam"); if ($returnResult) { logmsg("ERROR: unable to compile MSI $skuitem content! "); return 0; } # Link core file content logmsg ("Link MSI $skuitem contents."); logmsg ("$LIGHT $linkParam"); $returnResult = system("$LIGHT $linkParam"); if ($returnResult) { logmsg("ERROR: unable to link MSI $skuitem content! "); return 0; } } logmsg ("Success: Generate MSI file contents."); return 1; } #FileContents ################################################################################## # # CustomAction() # # Generate file associated with custom action if needed. # ################################################################################## sub CustomAction { logmsg ("Generate MSI file contents."); # Do something logmsg ("Success: Generate MSI file contents."); return 1; } #CustomAction ################################################################################## # # XMLVAR() # # Generate a language specific msi template. # ################################################################################## sub XMLVAR { my ($xmlvarParam); logmsg ("Generate language specific msi template."); $xmlvarParam = " srcmuiinf=\"$INFFILE\""; $xmlvarParam .= " regkey1guid=\"$REGISTRY1GUID\""; $xmlvarParam .= " regkey3guid=\"$REGISTRY3GUID\""; $xmlvarParam .= " IA64CONDITION=\"$IA64CONDITION\""; $xmlvarParam .= " PLATFORM=\"$PLATFORM\""; $xmlvarParam .= " LANG=\"$Special_Lang\""; $xmlvarParam .= " srcmuimsidll=\"$SRCMUIMSIDLL\""; $xmlvarParam .= " srcmuisetup=\"$SRCMUISETUP\""; $xmlvarParam .= " srcxpbitmap=\"$SRCXPBITMAP\""; $xmlvarParam .= " msiguid=\"$MSIGUID\""; $xmlvarParam .= " productguid=\"$PRODUCTGUID\""; $xmlvarParam .= " namePackage=\"$PACKAGENAME\""; $xmlvarParam .= " ver=\"1.0.$VERSIONNUMBER.0\""; $xmlvarParam .= " guidUpgradeCode=\"$UPGRADEGUID\""; $xmlvarParam .= " debugdir=\"$TMPBUILD\""; $xmlvarParam .= " Language=\"$LANG_NAME\""; $xmlvarParam .= " BLD=\"$BLDNO\""; $xmlvarParam .= " CORESRC=\"$FILELST_CORE\""; $xmlvarParam .= " LCID=\"$LCID_SHORT\""; $xmlvarParam .= " ISWIN64=\"$ISWIN64\""; $xmlvarParam .= " SYSFOLDERPROP=\"$SYSFOLDERPROP\""; $xmlvarParam .= " srcSchema=\"$WISCHEMA\""; $xmlvarParam .= " < $TEMPLATE > $MUIMSIXMLTemp"; # Generate [LCID].WIM based on the template logmsg ("Run XMLVAR on the generic template."); logmsg("$XMLVAR $xmlvarParam"); $returnResult = system("$XMLVAR $xmlvarParam"); if ($returnResult) { logmsg("ERROR: XMLVAR failed!"); return 0; } logmsg ("Success: Generate language specific msi template."); return 1; } #XMLVAR ################################################################################## # # MakeMSI() # # Build the MSI package. # ################################################################################## sub MakeMSI { $MEGEMODDLL = "$RAZZLETOOLPATH\\x86\\mergemod.dll"; logmsg ("Create MSI package."); logmsg ("Registering mergemod.dll"); logmsg ("regsvr32 /s $MEGEMODDLL"); $returnResult = system("regsvr32 /s $MEGEMODDLL"); if ($returnResult) { logmsg("ERROR: failed to register $MEGEMODDLL!"); return 0; } # Compile language specific template logmsg ("Compile the language specific template."); logmsg("$CANDLE -o -e -c $MUIMSIWIX $MUIMSIXML"); $returnResult = system("$CANDLE -o -e -c $MUIMSIWIX $MUIMSIXML"); if ($returnResult) { logmsg("ERROR: failed to compile language specific template"); return 0; } # Link language specific template logmsg ("Link the language specific template."); logmsg ("$LIGHT -r -b $TMPBUILD -o $MUIMSI $MUIMSIWIX"); $returnResult = system("$LIGHT -r -b $TMPBUILD -o $MUIMSI $MUIMSIWIX "); if ($returnResult) { logmsg("ERROR: failed to link $MEGEMODDLL!"); return 0; } # copy the release notes file to the release directory logmsg ("Copying release notes file."); logmsg ("$COPY /y $SRCRELNOTE $DSTRELNOTE"); $returnResult = system("$COPY /y $SRCRELNOTE $DSTRELNOTE"); if ($returnResult) { logmsg("ERROR: failed to copy the MSI release notes file!"); return 0; } logmsg ("Success: Create MSI package."); return 1; } #MakeMSI ################################################################################## # # ValidateParams() # # VAlidate parameters. # ################################################################################## sub ValidateParams { # } ################################################################################## # # Usage() # # Print usage. # ################################################################################## sub Usage { print <TARGETDIR # WindowsFolder # MUI # # # ASMS # 6000 # msft # vcrtlmui # Asms6000Msftvcrtlmui # vcrtlmui.cat.2 # vcrtlmui.man.2 # mfc42.dll.mui.2 # # # # # # # # # # # # Assembly Specification: # # MUIFusionInstall # Asms6000Msftvcrtlmui # MUIFusionAssembly # name # version # ...... etc. # # # # ################################################################################## sub GenFusionAssemblyXML { Win32::OLE::CreateObject("Msxml2.DOMDocument", $AsmManifestDoc) or die "Can't create XMLDOM\n"; Win32::OLE::CreateObject("Msxml2.DOMDocument", $MsiTemplateDoc) or die "Can't create XMLDOM\n"; $MsiTemplateDoc->{async} = 0; $AsmManifestDoc->{async} = 0; my $MsiASMType, $MsiASMName, $MsiASMVersion, $MsiASMSN; $CURRENTDIR = Win32::GetCwd(); $FUSIONROOT = "ASMS\\$Special_Lang"; # root directory where all possible Fusion assemblies are stored under $MUIDIR\\Drop $FUSIONSRC = "$MUIDIR\\Drop\\$FUSIONROOT"; $FileCounter = 2; # this counter is appended to the end of files in each assembly to generate unique file IDs logmsg("------- FUSIONSRC is $FUSIONSRC"); logmsg("------- CURRENTDIR is $CURRENTDIR"); # if we can't find the fusionsrc directory, just exit - there are no fusion component for this mui build if (! -e $FUSIONSRC) { logmsg("Cannot locate fusion source directory $FUSIONSRC, there are no fusion components for this MUI build."); logmsg("copy /Y $MUIMSIXMLTemp $MUIMSIXML"); `copy /Y $MUIMSIXMLTemp $MUIMSIXML`; return 1; } # load the xmlvar'ed template my $loadresult = $MsiTemplateDoc->load($MUIMSIXMLTemp); $docError = $MsiTemplateDoc->{parseError}; if ($docError->{errorCode} != 0) { logmsg("Parse error occurred in manifest file, exiting\n"); logmsg("Line: [$docError->{line}], LinePos: [$docError->{linepos}]\n"); logmsg("Reason: [$docError->{reason}]\n"); return 0; } # find the directory root where we want to insert our assembly components my $MsiCompRoot; $MuiRootDirNode = $MsiTemplateDoc->{documentElement}->selectSingleNode("//Directory[\@Name = \"MUI\"]"); if (defined($MuiRootDirNode)) { logmsg("Found MUI directory node."); $MuiFallbackDirNode = $MuiRootDirNode->selectSingleNode("//Directory[\@Name = \"FALLBACK\"]"); if (defined($MuiFallbackDirNode)) { logmsg("Found MUI/FALLBACK directory node."); $MsiCompRoot = $MuiFallbackDirNode->selectSingleNode("//Directory[\@Name = \"$LCID_SHORT\"]"); } else { logmsg("Cannot find FALLBACK directory node within the MUI Directory Node in the MSI Template!"); } } else { logmsg("Cannot find MUI Directory Node in the MSI Template!"); return 0; } if (!defined($MsiCompRoot)) { logmsg("Cannot find the proper directory node MUI/FALLBACK/$LCID_SHORT for fusion insertion!"); return 0; } else { logmsg("Found MUI/FALLBACK/$LCID_SHORT directory node."); } # find the feature root where we want to insert our assembly feature $MsiFeatureRoot = $MsiTemplateDoc->{documentElement}->selectSingleNode("//Feature[\@Title = \"BasicInstall\"]"); if (!defined($MsiFeatureRoot)) { logmsg("Cannot find the proper feature node BasicInstall for fusion insertion!"); return 0; } $bCreatedFeatureNode = 0; # see if there are fusion components to install if ((-e $FUSIONSRC) && (-d $FUSIONSRC)) { logmsg("------- $FUSIONSRC exists."); opendir(DIRHANDLE1, $FUSIONSRC); @DIRFILES1 = grep { $_ ne '.' and $_ ne '..' } readdir(DIRHANDLE1); # $SUBDIR1 - subdirectory under fusionroot e.g. "6000" for directory i386.uncomp\asms\6000\msft\vcrtlmui foreach $SUBDIR1 (@DIRFILES1) { logmsg("------- SUBDIR1 is $SUBDIR1"); if (-d "$FUSIONSRC\\$SUBDIR1") { opendir(DIRHANDLE2, "$FUSIONSRC\\$SUBDIR1"); @DIRFILES2 = grep { $_ ne '.' and $_ ne '..' } readdir(DIRHANDLE2); $TempDirNode1 = $MsiTemplateDoc->createElement("Directory"); $TempDirNode1->setAttribute("Name", $SUBDIR1); $TempDirNode1->{text} = "_$SUBDIR1.$FileCounter"; # prepending a "_" to conform to MSI ID naming convention # $SUBDIR2 - subdirectory under subdir1 e.g. "msft" for directory i386.uncomp\asms\6000\msft\vcrtlmui foreach $SUBDIR2 (@DIRFILES2) { logmsg("------- SUBDIR2 is $SUBDIR2"); if (-d "$FUSIONSRC\\$SUBDIR1\\$SUBDIR2") { opendir(DIRHANDLE3, "$FUSIONSRC\\$SUBDIR1\\$SUBDIR2\\$SUBDIR3"); @DIRFILES3 = grep { $_ ne '.' and $_ ne '..' } readdir(DIRHANDLE3); $TempDirNode2 = $MsiTemplateDoc->createElement("Directory"); $TempDirNode2->setAttribute("Name", $SUBDIR2); $TempDirNode2->{text} = "_$SUBDIR2.$FileCounter"; # prepending a "_" to conform to MSI ID naming convention $TempDirNode1->appendChild($TempDirNode2); # $SUBDIR3 - subdirectory under subdir2 e.g. "vcrtlmui" for directory i386.uncomp\asms\6000\msft\vcrtlmui foreach $SUBDIR3 (@DIRFILES3) { logmsg("------- SUBDIR3 is $SUBDIR3"); # only continue if we can change to this directory and can find a manifest file if (chdir "$FUSIONSRC\\$SUBDIR1\\$SUBDIR2\\$SUBDIR3") { # if we can't find a .man or .manifest file, skip this component if (!defined ($ASMMANFILE = glob("*.man"))) { if (!defined ($ASMMANFILE = glob("*.manifest"))) { logmsg("Skipping $FUSIONSRC\\$SUBDIR1\\$SUBDIR2\\$SUBDIR3 directory, can't find manifest file."); next; } } logmsg("Found assembly directory - $FUSIONSRC\\$SUBDIR1\\$SUBDIR2\\$SUBDIR3\n"); logmsg("Assembly manifest file is $ASMMANFILE"); $TempDirNode3 = $MsiTemplateDoc->createElement("Directory"); $TempDirNode3->setAttribute("Name", $SUBDIR3); $TempDirNode3->{text} = "_$SUBDIR3.$FileCounter"; # prepending a "_" to conform to MSI ID naming convention $TempDirNode2->appendChild($TempDirNode3); # process manifest file for the assembly my $result = $AsmManifestDoc->load("$FUSIONSRC\\$SUBDIR1\\$SUBDIR2\\$SUBDIR3\\$ASMMANFILE"); $docError = $AsmManifestDoc->{parseError}; $ValidateSuccess = 1; if ($docError->{errorCode} != 0) { logmsg("Parse error occurred in manifest file, skipping this component\n"); logmsg("Line: [$docError->{line}], LinePos: [$docError->{linepos}]\n"); logmsg("Reason: [$docError->{reason}]\n"); $ValidateSuccess = 0; } else { $ASMIDNode = $AsmManifestDoc->{documentElement}->selectSingleNode("assemblyIdentity"); if (defined ($ASMIDNode)) { if (defined ($ASMIDNode->{attributes})) { # create an assembly node for insertion later into our msi template $TempAsmNode = $MsiTemplateDoc->createElement("Assembly"); $TempAsmNode->setAttribute("Manifest", "$ASMMANFILE.$FileCounter"); $TempAsmNode->{text} = "_$SUBDIR3.$FileCounter"; # prepending a "_" to conform to MSI ID naming convention # here, we want to go through the list of attributes on the assembly id node, and create a set of properties for it # in the MsiAssemblyName table, except type, which goes into assembly node as well. for ($i = 0; $i < $ASMIDNode->{attributes}->{length}; $i++) { $AsmIDNodeAttribute = $ASMIDNode->{attributes}->item($i); if ($AsmIDNodeAttribute->{nodeName} =~ /^type$/i) { $TempAsmNode->setAttribute("Type", $AsmIDNodeAttribute->{nodeValue}); } $TempPropNode1 = $MsiTemplateDoc->createElement("Property"); $TempPropNode1->setAttribute("Value", "$AsmIDNodeAttribute->{nodeValue}"); $TempPropNode1->{text} = $AsmIDNodeAttribute->{nodeName}; $TempAsmNode->appendChild($TempPropNode1); logmsg("MsiAssemblyName: Name is $AsmIDNodeAttribute->{nodeName}, Value is $AsmIDNodeAttribute->{nodeValue}"); } } } else { # no assemblyIdentity node found, this manifest is invalid, log it and continue $ValidateSuccess = 0; logmsg("Found manifest file is invalid, it does not contain an assembly identity node."); } } if ($ValidateSuccess) { # generate a GUID for this component ($ASMGUID) = `uuidgen`; chomp $ASMGUID; $ASMGUID =~ tr/a-z/A-Z/; $MsiComponentID = "_$SUBDIR1$SUBDIR2$SUBDIR3"; # prepending a "_" to conform to MSI ID naming convention # add all files in the directory to the msitemplate opendir(DIRHANDLE4, "$FUSIONSRC\\$SUBDIR1\\$SUBDIR2\\$SUBDIR3"); @ASMFILES = grep { $_ ne '.' and $_ ne '..' } readdir(DIRHANDLE4); $TempCompNode = $MsiTemplateDoc->createElement("Component"); $TempCompNode->setAttribute("Id", $ASMGUID); $TempCompNode->setAttribute("Win64", $ISWIN64); $TempCompNode->{text} = $MsiComponentID; $TempDirNode3->appendChild($TempCompNode); foreach $ASMFILE (@ASMFILES) { # when processing the manifest file, we also note down its manifest file ID in the MSI logmsg("This file is $ASMFILE"); $TempFileNode = $MsiTemplateDoc->createElement("File"); $TempFileNode->{text} = "$ASMFILE.$FileCounter"; $TempFileNode->setAttribute("DiskId", "1"); $TempFileNode->setAttribute("Name", Win32::GetShortPathName($ASMFILE)); $TempFileNode->setAttribute("LongName", $ASMFILE); $TempFileNode->setAttribute("src", "$FUSIONSRC\\$SUBDIR1\\$SUBDIR2\\$SUBDIR3\\$ASMFILE"); $TempCompNode->appendChild($TempFileNode); } $MsiCompRoot->appendChild($TempDirNode1); # create the assembly feature root node first if we have not done so if (!$bCreatedFeatureNode) { $TempFeatureRoot = $MsiTemplateDoc->createElement("Feature"); $TempFeatureRoot->setAttribute("Title", "FusionInstall"); $TempFeatureRoot->setAttribute("Display", "hidden"); $TempFeatureRoot->setAttribute("Level", "1"); $TempFeatureRoot->setAttribute("AllowAdvertise", "system"); $TempFeatureRoot->setAttribute("FollowParent", "yes"); $TempFeatureRoot->{text} = "MUIFusionInstall"; $MsiFeatureRoot->appendChild($TempFeatureRoot); $MsiFeatureRoot = $TempFeatureRoot; $bCreatedFeatureNode = 1; } # add the feature component specification for the assembly if (defined($TempAsmNode)) { $TempCompNode = $MsiTemplateDoc->createElement("Component"); $TempCompNode->{text} = $MsiComponentID; $TempCompNode->appendChild($TempAsmNode); $MsiFeatureRoot->appendChild($TempCompNode); } $FileCounter += 1; } closedir(DIRHANDLE3); } } closedir(DIRHANDLE2); } } closedir(DIRHANDLE1); } } } # save the xml file $MsiTemplateDoc->save($MUIMSIXML); chdir $CURRENTDIR; # go back to the old current directory return 1; } ################################################################################## # # InsertEula # # This function will look for a specially marked xml node inside the MSI template # called , and then it will create a sibling xml node to # the found node and insert the EULA text content in the TEXT node. Then it will # delete the MUIEULAText node from the template # ################################################################################## sub InsertEula { Win32::OLE::CreateObject("Msxml2.DOMDocument", $MsiTemplateDoc) or die "Can't create XMLDOM\n"; $MsiTemplateDoc->{async} = 0; $MsiEulaStart = "{\\rtf1\\ansi\\ansicpg1252\\deff0\\deflang1033{\\fonttbl{\\f0\\fnil\\fcharset0 MS Shell Dlg;}}\n"; $MsiEulaFirstLine = "\\viewkind4\\uc1\\pard\\f0\\fs17"; $MsiEulaEnd = "}"; $MsiEulaLinePrefix = "\\par"; $EulaLineCounter = 0; $EulaContent = ""; $EULASRC = "$MUIDIR\\eula.txt"; # load the xmlvar'ed template my $loadresult = $MsiTemplateDoc->load($MUIMSIXML); $docError = $MsiTemplateDoc->{parseError}; if ($docError->{errorCode} != 0) { logmsg("Parse error occurred in MSI Template file, exiting\n"); logmsg("Line: [$docError->{line}], LinePos: [$docError->{linepos}]\n"); logmsg("Reason: [$docError->{reason}]\n"); return 0; } # find the EULA Text node in the template $MUIEULATextNode = $MsiTemplateDoc->{documentElement}->selectSingleNode("//MUIEULAText"); if (defined($MUIEULATextNode)) { logmsg("Found MUI Eula Text node."); } else { logmsg("Cannot find MUI Eula Text Node in the MSI Template!"); return 0; } # create a node "Text" under MUIEULAText node's parent $TempTextNode = $MsiTemplateDoc->createElement("Text"); $ParentNode = $MUIEULATextNode->{parentNode}; $ParentNode->appendChild($TempTextNode); $ParentNode->removeChild($MUIEULATextNode); # read the EULA text into memory, format it properly for insertion into the text node if(!open(EULASRCFILE, "$EULASRC")) { logmsg("Cannot find MUI Eula Text file at $EULASRC!"); return 0; } $EulaContent = $MsiEulaStart; $EulaLineCounter = 1; while () { if ($EulaLineCounter == 1) { $EulaContent .= "$MsiEulaFirstLine $_"; } else { $EulaContent .= " $MsiEulaLinePrefix $_"; } $EulaLineCounter++; } close(EULASRCFILE); $EulaContent .= $MsiEulaEnd; # rename the node "Text" instead of "MUIEULAText" and add in the new EulaContent # $TempTextNode->{nodeName} = "Text"; $TempTextNode->{text} = $EulaContent; # save the xml file $MsiTemplateDoc->save($MUIMSIXML); logmsg("Successfully inserted EULA text content into the template file."); return 1; } ################################################################################## # # InsertReserveCost # # This function will read the LangpackCost section of the mui.inf file, and # build them into the ReserveCost table inside the MSI template. # ################################################################################## sub InsertReserveCost { my(@langpackcost, $section_name); Win32::OLE::CreateObject("Msxml2.DOMDocument", $MsiTemplateDoc) or die "Can't create XMLDOM\n"; $MsiTemplateDoc->{async} = 0; # load the xmlvar'ed template my $loadresult = $MsiTemplateDoc->load($MUIMSIXML); $docError = $MsiTemplateDoc->{parseError}; if ($docError->{errorCode} != 0) { logmsg("Parse error occurred in MSI Template file, exiting\n"); logmsg("Line: [$docError->{line}], LinePos: [$docError->{linepos}]\n"); logmsg("Reason: [$docError->{reason}]\n"); return 0; } $MuiRootDirNode = $MsiTemplateDoc->{documentElement}->selectSingleNode("//Directory[\@Name = \"SourceDir\"]"); if (defined($MuiRootDirNode)) { logmsg("InsertReserveCost: Found MUI root directory node."); } else { logmsg("InsertReserveCost: Cannot find MUI Directory Node in the MSI Template!"); return 0; } # find the feature root where we want to insert our assembly feature $MsiFeatureRoot = $MsiTemplateDoc->{documentElement}->selectSingleNode("//Feature[\@Title = \"BasicInstall\"]"); if (!defined($MsiFeatureRoot)) { logmsg("InsertReserveCost: Cannot find the proper feature node BasicInstall!"); return 0; } else { logmsg("InsertReserveCost: Found the proper feature node BasicInstall!"); } if ($_BuildArch =~ /ia64/i) { $section_name = "FileSize_LPK_IA64"; } else { $section_name = "FileSize_LPK"; } @langpackcost = `perl $RAZZLETOOLPATH\\PostBuildScripts\\parseinf.pl $INFFILE $section_name`; # for every entry, we write it into the diretory as a component, and also include the component into the # feature table foreach $lpkitem (@langpackcost) { chop($lpkitem); if ($lpkitem =~ /(.*)=(.*)/) { $lpklcid = $1; $lpkcost = $2; logmsg("----- InsertReserveCost: Langpack LCID is $lpklcid, Langpack filesize is $lpkcost"); # basic error checking if (!defined($lpklcid) || !defined($lpkcost) || ($lpklcid == 0) ) { logmsg("InsertReserveCost: error reading langpack file size in mui.inf."); return 0; } $TempDirCompNode = $MsiTemplateDoc->createElement("Component"); $TempFeaCompNode = $MsiTemplateDoc->createElement("Component"); $TempReserveCostNode = $MsiTemplateDoc->createElement("ReserveCost"); $TempConditionNode = $MsiTemplateDoc->createElement("Condition"); if (!defined($TempDirCompNode) || !defined($TempFeaCompNode) || !defined($TempReserveCostNode) || !defined($TempConditionNode)) { logmsg("InsertReserveCost: failed to create xml nodes for insertion into MSI template."); return 0; } ($LPKGUID) = `uuidgen`; chomp $LPKGUID; $LPKGUID =~ tr/a-z/A-Z/; $LPKID = "LANGPACKFileCost$lpklcid"; $TempDirCompNode->setAttribute("Id", $LPKGUID); $TempDirCompNode->setAttribute("Win64", $ISWIN64); $TempDirCompNode->{text} = $LPKID; $TempFeaCompNode->{text} = $LPKID; $TempReserveCostNode->setAttribute("Directory", "SystemFolder"); $TempReserveCostNode->setAttribute("RunLocal", $lpkcost); $TempReserveCostNode->setAttribute("RunFromSource", "0"); $TempReserveCostNode->{text} = "$LPKID.1"; $TempConditionNode->{text} = "MsiRequireLangPack AND MuiLCID=\"$lpklcid\""; $TempDirCompNode->appendChild($TempReserveCostNode); $TempDirCompNode->appendChild($TempConditionNode); $MuiRootDirNode->appendChild($TempDirCompNode); $MsiFeatureRoot->appendChild($TempFeaCompNode); } } # save the xml file $MsiTemplateDoc->save($MUIMSIXML); logmsg("Successfully inserted ReserveCost table rows into the MSI template."); return 1; } ################################################################################## # # InsertSKUNodes # # This function insert the necessary xml nodes that are going to be # included in the MSI template as specified by the caller. # ################################################################################## sub InsertSKUNodes { Win32::OLE::CreateObject("Msxml2.DOMDocument", $MsiTemplateDoc) or die "Can't create XMLDOM\n"; $MsiTemplateDoc->{async} = 0; # load the xmlvar'ed template my $loadresult = $MsiTemplateDoc->load($MUIMSIXML); $docError = $MsiTemplateDoc->{parseError}; if ($docError->{errorCode} != 0) { logmsg("Parse error occurred in MSI Template file, exiting\n"); logmsg("Line: [$docError->{line}], LinePos: [$docError->{linepos}]\n"); logmsg("Reason: [$docError->{reason}]\n"); return 0; } $MuiRootDirNode = $MsiTemplateDoc->{documentElement}->selectSingleNode("//Directory[\@Name = \"SourceDir\"]"); if (defined($MuiRootDirNode)) { logmsg("InsertSKUNodes: Found MUI root directory node."); } else { logmsg("InsertSKUNodes: Cannot find MUI Directory Node in the MSI Template!"); return 0; } # find the feature root where we want to insert our assembly feature $MsiFeatureRoot = $MsiTemplateDoc->{documentElement}->selectSingleNode("//Feature[\@Title = \"BasicInstall\"]"); if (!defined($MsiFeatureRoot)) { logmsg("InsertSKUNodes: Cannot find the proper feature node BasicInstall!"); return 0; } else { logmsg("InsertSKUNodes: Found the proper feature node BasicInstall!"); } for $skuitem (keys %SKUList) { logmsg("InsertSKUNodes: Inserting $skuitem SKU Nodes into Directory and Feature nodelists"); $TempDirModNode = $MsiTemplateDoc->createElement("Module"); $TempFeaModNode = $MsiTemplateDoc->createElement("Module"); $TempDirModNode->setAttribute("DiskId", "1"); $TempDirModNode->setAttribute("src", $SKUList{$skuitem}{MergModeFileName}); $TempDirModNode->{text} = $skuitem; $TempFeaModNode->{text} = $skuitem; $MuiRootDirNode->appendChild($TempDirModNode); $MsiFeatureRoot->appendChild($TempFeaModNode); } # insert an launch condition for each of the SKU not present so that the MSI package can't be run # on that SKU for $skuexitem (keys %SKUExList) { logmsg("InsertSKUNodes: Inserting launch condition exclusion node for $skuexitem SKU into MSI template."); $TempCondNode = $MsiTemplateDoc->createElement("Condition"); $TempCondNode->setAttribute("Message", $SKUExList{$skuexitem}{Message}); $TempCondNode->{text} = $SKUExList{$skuexitem}{Condition}; $TempHeadCondNode = $MsiTemplateDoc->{documentElement}->selectSingleNode("Condition[1]"); if (defined ($TempHeadCondNode)) { $MsiTemplateDoc->{documentElement}->insertBefore($TempCondNode, $TempHeadCondNode); } else { $MsiTemplateDoc->{documentElement}->appendChild($TempCondNode); } } # save the xml file $MsiTemplateDoc->save($MUIMSIXML); logmsg("Successfully inserted SKU merge module XML nodes."); return 1; } ################################################################################## # # DeleteMSITables # # This function is used to remove the unused tables AdminUISequence, # AdminExecuteSequence, AdvUISequence and AdvExecuteSequence tables # ################################################################################## sub DeleteMSITables { my($Installer, $MUIMSIDB, $SqlQuery, $MUIMSIView); Win32::OLE::CreateObject("WindowsInstaller.Installer", $Installer) or die "Can't create Windows Installer Object\n"; # check if the result MSI package exist if (!(-e $MUIMSI)) { errmsg ("DeleteMSITables error: Cannot locate the MSI package $MUIMSI."); return 0; } logmsg("Opening MSI Package $MUIMSI for table deletion."); # if so, open the package $MUIMSIDB = $Installer->OpenDatabase($MUIMSI, 2); # open in direct, no transaction if (!defined($MUIMSIDB)) { errmsg ("DeleteMSITables error: Cannot open the MSI package $MUIMSI."); return 0; } # delete the tables we don't want foreach (@DeleteTableList) { $SqlQuery = "DROP TABLE $_"; $MUIMSIView = $MUIMSIDB->OpenView($SqlQuery); if (!defined($MUIMSIView)) { $MUIMSIDB->Commit(); # flush all the buffers, even though this is a fatal error. errmsg ("DeleteMSITables error: Cannot open a view on the MSI package."); return 0; } $MUIMSIView->Execute(); $MUIMSIView->Close(); logmsg("Deleted MSI table $_"); } # commit the changes to the package $MUIMSIDB->Commit(); logmsg("DeleteMSITables: Successfully deleted unused tables from the MSI package."); return 1; } ################################################################################## # # InsertCatFiles # # This function will reinsert the catalog files back into the asian printer # driver msi packages. We do this for all 4 msi packages regardless of what # language is being built. # ################################################################################## sub InsertCatFiles { $MUI_PRINTER_DRIVER_DIR = "$DESTDIR\\printer"; $MUI_CAT_DIR = "$MUIDIR\\printer"; # we will do this only for cd1 in RC2, will need to change this and muimake for final release if ((uc($CDLAYOUT) eq "CD1" ) && (-e $MUI_PRINTER_DRIVER_DIR) && (-e $MUI_CAT_DIR)) { %PrinterDriver = (); # list of printer driver files msi file names and the catalog file names $PrinterDriver{"chs"} = { MsiFile=> "chsprint.msi", CatFile => "chspack.cat", }; $PrinterDriver{"cht"} = { MsiFile=> "chtprint.msi", CatFile => "chtpack.cat", }; $PrinterDriver{"jpn"} = { MsiFile=> "jpnprint.msi", CatFile => "jpnpack.cat", }; $PrinterDriver{"kor"} = { MsiFile=> "korprint.msi", CatFile => "korpack.cat", }; for $langitem (keys %PrinterDriver) { logmsg("Printer driver MSI file is at $MUI_PRINTER_DRIVER_DIR\\$PrinterDriver{$langitem}{MsiFile}"); logmsg("Printer driver CAT file is at $MUI_CAT_DIR\\$PrinterDriver{$langitem}{CatFile}"); $returnResult = system("msicab.exe -r $MUI_PRINTER_DRIVER_DIR\\$PrinterDriver{$langitem}{MsiFile} $MUI_CAT_DIR\\$PrinterDriver{$langitem}{CatFile}"); if ($returnResult) { logmsg("ERROR: Failed to insert catalog file into the printer MSI file!"); return 0; } # also delete the cat file from the release directory - we don't want those to be there if (-e "$MUI_PRINTER_DRIVER_DIR\\$PrinterDriver{$langitem}{CatFile}") { logmsg("Deleting $MUI_PRINTER_DRIVER_DIR\\$PrinterDriver{$langitem}{CatFile} from the release point."); $returnedResult = system("del /F /Q $MUI_PRINTER_DRIVER_DIR\\$PrinterDriver{$langitem}{CatFile}"); if ($returnedResult) { logmsg("Warning: failed to delete catalog file $PrinterDriver{$langitem}{CatFile}."); } } } } else { logmsg("INFO: InsertCatFiles skipped - CDLayout is $CDLAYOUT, MSI printer directory is $MUI_PRINTER_DRIVER_DIR, Catalog directory is $MUI_CAT_DIR"); } logmsg("InsertCatFiles: Successfully inserted the catalog files into the Asian Printer Driver MSI Packages."); return 1; } ################################################################################## # # Cmd entry point for script. # ################################################################################## if (eval("\$0 =~ /" . __PACKAGE__ . "\\.pm\$/i")) { # Step 1: Parse the command line # &GetParams ('-o', 'l:psadwb', '-p', 'lang prosku srvsku advsku dtcsku websku sbssku', @ARGV); # Include local environment extensions &LocalEnvEx::localenvex('initialize'); # Set lang from the environment $LANG=$ENV{lang}; # $Special_Lang = "JPN"; // commented out, these are set in GetCodes # $LCID_SHORT = "0411"; // commented out, these are set in GetCodes # Validate the option given as parameter. &ValidateParams; # Set flag indicating that we run from command prompt. $cmdPrompt = 1; # Step 4: Call the main function &muimsi::Main(); # End local environment extensions. &LocalEnvEx::localenvex('end'); }