1799 lines
64 KiB
Perl
1799 lines
64 KiB
Perl
#################################################################################
|
|
#
|
|
# 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 (<GUIDFILE>)
|
|
{
|
|
# 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 (<CODEFILE>)
|
|
{
|
|
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 (<DESCFILE>)
|
|
{
|
|
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 (<BUILDNAME>)
|
|
{
|
|
$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
|
|
{
|
|
#<Add your code for validating the parameters here>
|
|
}
|
|
|
|
|
|
##################################################################################
|
|
#
|
|
# Usage()
|
|
#
|
|
# Print usage.
|
|
#
|
|
##################################################################################
|
|
sub Usage
|
|
{
|
|
print <<USAGE;
|
|
|
|
muimsi.pm is used to create the MUI MSI package for the specified language.
|
|
|
|
Usage: $0 [-l lang] [-p] [-s] [-a] [-d] [-w] [-b]
|
|
-l Language
|
|
-p include Professional SKU MUI files
|
|
-s include Standard Server SKU MUI files
|
|
-a include Advanced Server SKU MUI files
|
|
-d include Datacenter server SKU MUI files
|
|
-w include Blade server SKU MUI files
|
|
-b include Small Business Server MUI files
|
|
-? Displays usage
|
|
|
|
Example:
|
|
$0 -l jpn
|
|
Generate MUI MSI package for Japanese language, include only core files.
|
|
|
|
$0 -l jpn -p -s
|
|
Generate MUI MSI package for Japanese language, include core, professional and standard server files.
|
|
USAGE
|
|
}
|
|
|
|
|
|
##################################################################################
|
|
#
|
|
# GetParams()
|
|
#
|
|
# Get language parameter.
|
|
#
|
|
##################################################################################
|
|
sub GetParams
|
|
{
|
|
# Step 1: Call pm getparams with specified arguments
|
|
&GetParams::getparams(@_);
|
|
|
|
# Step 2: Call the usage if specified by /?
|
|
if ($HELP)
|
|
{
|
|
&Usage();
|
|
exit 1;
|
|
}
|
|
|
|
# Step 3: Set the language into the enviroment
|
|
$ENV{lang}=$lang;
|
|
|
|
logmsg("-------- lang parameter passed in is $lang");
|
|
|
|
}
|
|
|
|
|
|
##################################################################################
|
|
#
|
|
# GetCDLayOut
|
|
#
|
|
# Get CD layout from MUI.INF
|
|
#
|
|
##################################################################################
|
|
sub GetCDLayOut
|
|
{
|
|
my(@cd_layout, @lang_map, $muilang, $lang_id);
|
|
|
|
# Map lang
|
|
logmsg("------ INFFILE is $INFFILE");
|
|
@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");
|
|
}
|
|
|
|
|
|
##################################################################################
|
|
#
|
|
# GenFusionAssemblyXML
|
|
#
|
|
# This function will walk the MUI postbuild directory, find the fusion assembly files, locate the manifest and generate the
|
|
# required xml and put it in a variable for insertion into the WiX template using XMLVAR. Below is an example of the required
|
|
# generated xml snippet
|
|
#
|
|
# Component Specification:
|
|
#
|
|
# <Directory Name='SourceDir'>TARGETDIR
|
|
# <Directory Name='Windows'>WindowsFolder
|
|
# <Directory Name='MUI'>MUI
|
|
# <Directory Name='FALLBACK'>
|
|
# <Directory Name='0411'>
|
|
# <Directory Name="ASMS" LongName="ASMS">ASMS
|
|
# <Directory Name="6000" LongName="6000">6000
|
|
# <Directory Name="msft" LongName="msft">msft
|
|
# <Directory Name="vcrtlmui" LongName="vcrtlmui">vcrtlmui
|
|
# <Component Id='1D56E371-0202-4BD7-A050-69415A59007B'>Asms6000Msftvcrtlmui
|
|
# <File DiskId='1' Name="vcrtlmui.cat" LongName="vcrtlmui.cat" src="c:\nt.relbins.x86fre\jpn\mui\jpn\i386.uncomp\asms\6000\msft\vcrtlmui\vcrtlmui.cat">vcrtlmui.cat.2</File>
|
|
# <File DiskId='1' Name="vcrtlmui.man" LongName="vcrtlmui.man" src="c:\nt.relbins.x86fre\jpn\mui\jpn\i386.uncomp\asms\6000\msft\vcrtlmui\vcrtlmui.man">vcrtlmui.man.2</File>
|
|
# <File DiskId='1' Name="MFC42D~1.mui" LongName="mfc42.dll.mui" src="c:\nt.relbins.x86fre\jpn\mui\jpn\i386.uncomp\asms\6000\msft\vcrtlmui\mfc42.dll.mui">mfc42.dll.mui.2</File>
|
|
# </Component>
|
|
# </Directory>
|
|
# </Directory>
|
|
# </Directory>
|
|
# </Directory>
|
|
# </Directory>
|
|
# </Directory>
|
|
# </Directory>
|
|
# </Directory>
|
|
# </Directory>
|
|
#
|
|
# Assembly Specification:
|
|
#
|
|
# <Feature Title='FusionInstall' Display='hidden' Level='1' AllowAdvertise='system' FollowParent='yes'>MUIFusionInstall
|
|
# <Component>Asms6000Msftvcrtlmui
|
|
# <Assembly Manifest='vcrtlmui.man.2' Type='win32'>MUIFusionAssembly
|
|
# <Property Value='Microsoft.Tools.VisualCPlusPlus.Runtime-Libraries.mui'>name</Property>
|
|
# <Property Value='6.0.0.0'>version</Property>
|
|
# ...... etc.
|
|
# </Assembly>
|
|
# </Component>
|
|
# </Feature>
|
|
#
|
|
##################################################################################
|
|
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 <MUIEULAText>, and then it will create a <TEXT> 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 (<EULASRCFILE>)
|
|
{
|
|
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
|
|
# <run perl.exe GetParams.pm /? to get the complete usage for GetParams.pm>
|
|
&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');
|
|
}
|
|
|
|
|
|
|