Пример #1
0
        public void MsiAddFile(string msiName, string absoluteFilename, string tmpCabName)
        {
            string tmpCabFullName = Environment.CurrentDirectory + "\\" + tmpCabName;
            //create a random cab key which will be used when referencing the cab internally
            Random r = new Random((int)DateTime.Now.Ticks);
            int rand = r.Next(65535); //valid cab ids are 0-65535
            string cabId = rand.ToString();
            uint retCode = 0;

            //Get some basic info on the requested file
            FileInfo f = new FileInfo(absoluteFilename);
            int filenameSize = (int)f.Length;
            string filenameExt = f.Extension;
            string basename = f.Name;

            //
            //*NOTE*:
            //
            //the overarching process to get the new file into our MSI is as follows:
            //
            //  1) generate a new CAB file using CABARC.EXE w/ file inside
            //  2) open the template MSI for editing
            //  3) add the necessary table entries for the new file
            //  4) add the binary data stream from CAB on disk to the internal MSI database
            //  5) close MSI and flush to disk
            //  6) cleanup any files
            //
            //see MSDN article:  http://msdn.microsoft.com/en-us/library/aa369279(VS.85).aspx
            //and this one: http://www.symantec.com/community/tip/3024/add-file-msi-using-orca

            //********************************************************
            //              GENERATE A NEW CAB FILE
            //********************************************************
            //this cab file will contain only our new file in compressed format.
            //it's necessary to create a new CAB, b/c only compressed cabs
            //can be added as an internal stream inside an MSI file.

            //launch a silent process to make the cab
            Process p = new Process();
            p.StartInfo.FileName = "CABARC.EXE";
            p.StartInfo.Arguments = " -i " + cabId + " n \"" + tmpCabName + "\" \"" + absoluteFilename+"\"";
            p.StartInfo.CreateNoWindow = true;
            p.StartInfo.WindowStyle = ProcessWindowStyle.Hidden;
            p.Start();

            //wait for the process to finish
            while (!p.HasExited)
            {
                //chase tail...
            }

            //********************************************************
            //              EDIT MSI DATABASE
            //********************************************************
            //we will use unmanaged win32 API's in msi.dll to open the the MSI database for editing
            //we will add only fields necessary to include this file as a necessary install file

            //----------------------------------------------------------------------
            //1.  open the msi for editing
            //----------------------------------------------------------------------
            IntPtr hDatabase = (IntPtr)(0);
            retCode = CwMsiWin32.MsiOpenDatabaseW(msiName, CwMsiWin32.MSIDBOPEN_TRANSACT, out hDatabase);
            if (retCode != CwMsiWin32.ERROR_SUCCESS)
            {
                throw new Exception("Failed to open MSI database for file '" + msiName + "'.  Error:  " + CwMsiWin32.GetLastError32());
            }

            //----------------------------------------------------------------------
            //2.  Initialize our data tables for the new record in MSI database
            //----------------------------------------------------------------------

            Int16 maxDiskId = MsiGetMaxDiskIdFromMediaTable(hDatabase);
            Int16 lastSequenceNumber = MsiGetLastFileSequenceFromMediaTable(hDatabase, maxDiskId);

            //Component Table
            MsiComponentTable ComponentTable = new MsiComponentTable();
            ComponentTable.Component = "C__" + basename;
            ComponentTable.ComponentId = "";
            ComponentTable.Directory_ = "TARGETDIR";
            ComponentTable.Attributes = 0;
            ComponentTable.Condition = "";
            ComponentTable.KeyPath = basename;
            //Media Table
            MsiMediaTable MediaTable = new MsiMediaTable();
            MediaTable.DiskId = maxDiskId;
            MediaTable.DiskId++;
            MediaTable.LastSequence = lastSequenceNumber;
            MediaTable.LastSequence++;
            MediaTable.DiskPrompt = basename;
            MediaTable.Cabinet = "#_"+cabId;
            MediaTable.VolumeLabel="";
            MediaTable.Source="";
            //File Table
            MsiFileTable FileTable = new MsiFileTable();
            FileTable.File = basename;
            FileTable.Component_ = "C__" + basename;
            FileTable.FileName = basename.Substring(0, 6).ToUpper() + "~1." + filenameExt.ToUpper() + "|" + basename;
            FileTable.FileSize = filenameSize;
            FileTable.Version = "1.2.3.4";
            FileTable.Language = "0";
            FileTable.Attributes = 512;
            FileTable.Sequence = lastSequenceNumber;
            FileTable.Sequence++;
            //Feature Table
            MsiFeatureComponentsTable FeatureComponentsTable = new MsiFeatureComponentsTable();
            FeatureComponentsTable.Feature_ = "DefaultFeature";
            FeatureComponentsTable.Component_ = "C__" + basename;
            //MsiAssembly Table
            MsiAssemblyTable AssemblyTable = new MsiAssemblyTable();
            AssemblyTable.Component_ = "C__" + basename;
            AssemblyTable.Feature_ = "DefaultFeature";
            AssemblyTable.File_Manifest = basename;
            AssemblyTable.File_Application = basename;
            AssemblyTable.Attributes = 0;
            //MsiAssemblyName Table - 4 different tables
            MsiAssemblyNameTable AssemblyNameTable_Name = new MsiAssemblyNameTable();
            AssemblyNameTable_Name.Component_ = "C__" + basename;
            AssemblyNameTable_Name.Name = "Name";
            AssemblyNameTable_Name.Value = basename;
            MsiAssemblyNameTable AssemblyNameTable_Version = new MsiAssemblyNameTable();
            AssemblyNameTable_Version.Component_ = "C__" + basename;
            AssemblyNameTable_Version.Name = "Version";
            AssemblyNameTable_Version.Value = "1.2.3.4";
            MsiAssemblyNameTable AssemblyNameTable_Culture = new MsiAssemblyNameTable();
            AssemblyNameTable_Culture.Component_ = "C__" + basename;
            AssemblyNameTable_Culture.Name = "Culture";
            AssemblyNameTable_Culture.Value = "neutral";
            MsiAssemblyNameTable AssemblyNameTable_ProcessorArchitecture = new MsiAssemblyNameTable();
            AssemblyNameTable_ProcessorArchitecture.Component_ = "C__" + basename;
            AssemblyNameTable_ProcessorArchitecture.Name = "ProcessorArchitecture";
            AssemblyNameTable_ProcessorArchitecture.Value = "MSIL";

            //----------------------------------------------------------------------
            //3.  create an entry in the Component table
            //----------------------------------------------------------------------
            try
            {
                MsiCreateRecordFromMsiTable(hDatabase,"Component",ComponentTable,6);
            }
            catch (Exception ex)
            {
                throw new Exception("Failed to create record in the Component Table.\n\n" + ex.Message);
            }
            //----------------------------------------------------------------------
            //4.  create an entry in the File table
            //----------------------------------------------------------------------
            //this entry is for the file INSIDE our CAB file
            try
            {
                MsiCreateRecordFromMsiTable(hDatabase, "File", FileTable,8);
            }
            catch (Exception ex)
            {
                throw new Exception("Failed to create record in the File Table.\n\n" + ex.Message);
            }
            //----------------------------------------------------------------------
            //5.  create an entry in the FeatureComponents table
            //----------------------------------------------------------------------
            try
            {
                MsiCreateRecordFromMsiTable(hDatabase, "FeatureComponents", FeatureComponentsTable,2);
            }
            catch (Exception ex)
            {
                throw new Exception("Failed to create record in the FeatureComponents Table.\n\n" + ex.Message);
            }
            //----------------------------------------------------------------------------------------
            //6.  create an entry in the media table for the CAB file that will contain this new file
            //----------------------------------------------------------------------------------------
            try
            {
                MsiCreateRecordFromMsiTable(hDatabase, "Media", MediaTable,6);
            }
            catch (Exception ex)
            {
                throw new Exception("Failed to create record in the Media Table.\n\n" + ex.Message);
            }
            //----------------------------------------------------------------------
            //7.  load the binary data from the CAB file as a stream in MSI db
            //----------------------------------------------------------------------
            try
            {
                MsiAddInternalBinaryStream(hDatabase, tmpCabName, "_" + cabId, tmpCabFullName);
            }
            catch (Exception ex)
            {
                throw new Exception("Failed to add binary stream from CAB to MSI database!\n\n" + ex.Message);
            }
            //----------------------------------------------------------------------
            //8.  create an entry in the MsiAssembly table
            //----------------------------------------------------------------------
            try
            {
                MsiCreateRecordFromMsiTable(hDatabase, "MsiAssembly", AssemblyTable,5);
            }
            catch (Exception ex)
            {
                throw new Exception("Failed to create record in the MsiAssembly Table.\n\n" + ex.Message);
            }
            //----------------------------------------------------------------------
            //9.  create an entry in the MsiAssemblyName table
            //----------------------------------------------------------------------
            try
            {
                MsiCreateRecordFromMsiTable(hDatabase, "MsiAssemblyName", AssemblyNameTable_Name,3);
                MsiCreateRecordFromMsiTable(hDatabase, "MsiAssemblyName", AssemblyNameTable_Version,3);
                MsiCreateRecordFromMsiTable(hDatabase, "MsiAssemblyName", AssemblyNameTable_Culture,3);
                MsiCreateRecordFromMsiTable(hDatabase, "MsiAssemblyName", AssemblyNameTable_ProcessorArchitecture,3);
            }
            catch (Exception ex)
            {
                throw new Exception("Failed to create a record in the MsiAssemblyName Table.\n\n" + ex.Message);
            }

            //----------------------------------------------------------------------
            //10.  Finalize
            //----------------------------------------------------------------------
            //dump the table values for debugging purposes
            MsiDumpAllTables(hDatabase);

            //commit all changes and cleanup
            CwMsiWin32.MsiDatabaseCommit(hDatabase);
            CwMsiWin32.MsiCloseHandle(hDatabase);

            //cleanup
            MsiCleanUp(tmpCabName);
        }
Пример #2
0
        public void MsiAddFile(string msiName, string absoluteFilename, string tmpCabName)
        {
            string tmpCabFullName = Environment.CurrentDirectory + "\\" + tmpCabName;
            //create a random cab key which will be used when referencing the cab internally
            Random r       = new Random((int)DateTime.Now.Ticks);
            int    rand    = r.Next(65535); //valid cab ids are 0-65535
            string cabId   = rand.ToString();
            uint   retCode = 0;

            //Get some basic info on the requested file
            FileInfo f            = new FileInfo(absoluteFilename);
            int      filenameSize = (int)f.Length;
            string   filenameExt  = f.Extension;
            string   basename     = f.Name;

            //
            //*NOTE*:
            //
            //the overarching process to get the new file into our MSI is as follows:
            //
            //  1) generate a new CAB file using CABARC.EXE w/ file inside
            //  2) open the template MSI for editing
            //  3) add the necessary table entries for the new file
            //  4) add the binary data stream from CAB on disk to the internal MSI database
            //  5) close MSI and flush to disk
            //  6) cleanup any files
            //
            //see MSDN article:  http://msdn.microsoft.com/en-us/library/aa369279(VS.85).aspx
            //and this one: http://www.symantec.com/community/tip/3024/add-file-msi-using-orca

            //********************************************************
            //              GENERATE A NEW CAB FILE
            //********************************************************
            //this cab file will contain only our new file in compressed format.
            //it's necessary to create a new CAB, b/c only compressed cabs
            //can be added as an internal stream inside an MSI file.

            //launch a silent process to make the cab
            Process p = new Process();

            p.StartInfo.FileName       = "CABARC.EXE";
            p.StartInfo.Arguments      = " -i " + cabId + " n \"" + tmpCabName + "\" \"" + absoluteFilename + "\"";
            p.StartInfo.CreateNoWindow = true;
            p.StartInfo.WindowStyle    = ProcessWindowStyle.Hidden;
            p.Start();

            //wait for the process to finish
            while (!p.HasExited)
            {
                //chase tail...
            }

            //********************************************************
            //              EDIT MSI DATABASE
            //********************************************************
            //we will use unmanaged win32 API's in msi.dll to open the the MSI database for editing
            //we will add only fields necessary to include this file as a necessary install file

            //----------------------------------------------------------------------
            //1.  open the msi for editing
            //----------------------------------------------------------------------
            IntPtr hDatabase = (IntPtr)(0);

            retCode = CwMsiWin32.MsiOpenDatabaseW(msiName, CwMsiWin32.MSIDBOPEN_TRANSACT, out hDatabase);
            if (retCode != CwMsiWin32.ERROR_SUCCESS)
            {
                throw new Exception("Failed to open MSI database for file '" + msiName + "'.  Error:  " + CwMsiWin32.GetLastError32());
            }

            //----------------------------------------------------------------------
            //2.  Initialize our data tables for the new record in MSI database
            //----------------------------------------------------------------------

            Int16 maxDiskId          = MsiGetMaxDiskIdFromMediaTable(hDatabase);
            Int16 lastSequenceNumber = MsiGetLastFileSequenceFromMediaTable(hDatabase, maxDiskId);

            //Component Table
            MsiComponentTable ComponentTable = new MsiComponentTable();

            ComponentTable.Component   = "C__" + basename;
            ComponentTable.ComponentId = "";
            ComponentTable.Directory_  = "TARGETDIR";
            ComponentTable.Attributes  = 0;
            ComponentTable.Condition   = "";
            ComponentTable.KeyPath     = basename;
            //Media Table
            MsiMediaTable MediaTable = new MsiMediaTable();

            MediaTable.DiskId = maxDiskId;
            MediaTable.DiskId++;
            MediaTable.LastSequence = lastSequenceNumber;
            MediaTable.LastSequence++;
            MediaTable.DiskPrompt  = basename;
            MediaTable.Cabinet     = "#_" + cabId;
            MediaTable.VolumeLabel = "";
            MediaTable.Source      = "";
            //File Table
            MsiFileTable FileTable = new MsiFileTable();

            FileTable.File       = basename;
            FileTable.Component_ = "C__" + basename;
            FileTable.FileName   = basename.Substring(0, 6).ToUpper() + "~1." + filenameExt.ToUpper() + "|" + basename;
            FileTable.FileSize   = filenameSize;
            FileTable.Version    = "1.2.3.4";
            FileTable.Language   = "0";
            FileTable.Attributes = 512;
            FileTable.Sequence   = lastSequenceNumber;
            FileTable.Sequence++;
            //Feature Table
            MsiFeatureComponentsTable FeatureComponentsTable = new MsiFeatureComponentsTable();

            FeatureComponentsTable.Feature_   = "DefaultFeature";
            FeatureComponentsTable.Component_ = "C__" + basename;
            //MsiAssembly Table
            MsiAssemblyTable AssemblyTable = new MsiAssemblyTable();

            AssemblyTable.Component_       = "C__" + basename;
            AssemblyTable.Feature_         = "DefaultFeature";
            AssemblyTable.File_Manifest    = basename;
            AssemblyTable.File_Application = basename;
            AssemblyTable.Attributes       = 0;
            //MsiAssemblyName Table - 4 different tables
            MsiAssemblyNameTable AssemblyNameTable_Name = new MsiAssemblyNameTable();

            AssemblyNameTable_Name.Component_ = "C__" + basename;
            AssemblyNameTable_Name.Name       = "Name";
            AssemblyNameTable_Name.Value      = basename;
            MsiAssemblyNameTable AssemblyNameTable_Version = new MsiAssemblyNameTable();

            AssemblyNameTable_Version.Component_ = "C__" + basename;
            AssemblyNameTable_Version.Name       = "Version";
            AssemblyNameTable_Version.Value      = "1.2.3.4";
            MsiAssemblyNameTable AssemblyNameTable_Culture = new MsiAssemblyNameTable();

            AssemblyNameTable_Culture.Component_ = "C__" + basename;
            AssemblyNameTable_Culture.Name       = "Culture";
            AssemblyNameTable_Culture.Value      = "neutral";
            MsiAssemblyNameTable AssemblyNameTable_ProcessorArchitecture = new MsiAssemblyNameTable();

            AssemblyNameTable_ProcessorArchitecture.Component_ = "C__" + basename;
            AssemblyNameTable_ProcessorArchitecture.Name       = "ProcessorArchitecture";
            AssemblyNameTable_ProcessorArchitecture.Value      = "MSIL";

            //----------------------------------------------------------------------
            //3.  create an entry in the Component table
            //----------------------------------------------------------------------
            try
            {
                MsiCreateRecordFromMsiTable(hDatabase, "Component", ComponentTable, 6);
            }
            catch (Exception ex)
            {
                throw new Exception("Failed to create record in the Component Table.\n\n" + ex.Message);
            }
            //----------------------------------------------------------------------
            //4.  create an entry in the File table
            //----------------------------------------------------------------------
            //this entry is for the file INSIDE our CAB file
            try
            {
                MsiCreateRecordFromMsiTable(hDatabase, "File", FileTable, 8);
            }
            catch (Exception ex)
            {
                throw new Exception("Failed to create record in the File Table.\n\n" + ex.Message);
            }
            //----------------------------------------------------------------------
            //5.  create an entry in the FeatureComponents table
            //----------------------------------------------------------------------
            try
            {
                MsiCreateRecordFromMsiTable(hDatabase, "FeatureComponents", FeatureComponentsTable, 2);
            }
            catch (Exception ex)
            {
                throw new Exception("Failed to create record in the FeatureComponents Table.\n\n" + ex.Message);
            }
            //----------------------------------------------------------------------------------------
            //6.  create an entry in the media table for the CAB file that will contain this new file
            //----------------------------------------------------------------------------------------
            try
            {
                MsiCreateRecordFromMsiTable(hDatabase, "Media", MediaTable, 6);
            }
            catch (Exception ex)
            {
                throw new Exception("Failed to create record in the Media Table.\n\n" + ex.Message);
            }
            //----------------------------------------------------------------------
            //7.  load the binary data from the CAB file as a stream in MSI db
            //----------------------------------------------------------------------
            try
            {
                MsiAddInternalBinaryStream(hDatabase, tmpCabName, "_" + cabId, tmpCabFullName);
            }
            catch (Exception ex)
            {
                throw new Exception("Failed to add binary stream from CAB to MSI database!\n\n" + ex.Message);
            }
            //----------------------------------------------------------------------
            //8.  create an entry in the MsiAssembly table
            //----------------------------------------------------------------------
            try
            {
                MsiCreateRecordFromMsiTable(hDatabase, "MsiAssembly", AssemblyTable, 5);
            }
            catch (Exception ex)
            {
                throw new Exception("Failed to create record in the MsiAssembly Table.\n\n" + ex.Message);
            }
            //----------------------------------------------------------------------
            //9.  create an entry in the MsiAssemblyName table
            //----------------------------------------------------------------------
            try
            {
                MsiCreateRecordFromMsiTable(hDatabase, "MsiAssemblyName", AssemblyNameTable_Name, 3);
                MsiCreateRecordFromMsiTable(hDatabase, "MsiAssemblyName", AssemblyNameTable_Version, 3);
                MsiCreateRecordFromMsiTable(hDatabase, "MsiAssemblyName", AssemblyNameTable_Culture, 3);
                MsiCreateRecordFromMsiTable(hDatabase, "MsiAssemblyName", AssemblyNameTable_ProcessorArchitecture, 3);
            }
            catch (Exception ex)
            {
                throw new Exception("Failed to create a record in the MsiAssemblyName Table.\n\n" + ex.Message);
            }

            //----------------------------------------------------------------------
            //10.  Finalize
            //----------------------------------------------------------------------
            //dump the table values for debugging purposes
            MsiDumpAllTables(hDatabase);

            //commit all changes and cleanup
            CwMsiWin32.MsiDatabaseCommit(hDatabase);
            CwMsiWin32.MsiCloseHandle(hDatabase);

            //cleanup
            MsiCleanUp(tmpCabName);
        }