}// WizFinish internal bool CreateMyMSIFile(String sNameOfFileToPackage, String sNameOfMSIFile, PolicyLevelType polType) { int nRet = 0; IntPtr hDatabase = (IntPtr)0; try { // Get the path off of the MSI File to create. int nEndOfDirectory = sNameOfMSIFile.LastIndexOf('\\'); String sDirectory = sNameOfMSIFile.Substring(0, nEndOfDirectory + 1); int nEndOfXMLDirectory = sNameOfFileToPackage.LastIndexOf('\\'); String sFileName = sNameOfFileToPackage.Substring(nEndOfXMLDirectory + 1); // First, create the cab file CreateCab(sNameOfFileToPackage, sDirectory + "SECXML.CAB"); // Ok, now we need to create our MSI file.... ugh IntPtr hView = (IntPtr)0; IntPtr hNewRecord = (IntPtr)0; // Create a GUID unique to this installation package String sMyGuid = "{" + System.Guid.NewGuid().ToString().ToUpper(CultureInfo.InvariantCulture) + "}"; // Copy our template file to the file we want to create byte[] bMSITemplate = null; if (polType == PolicyLevelType.User) { bMSITemplate = CResourceStore.GetMSI("USER_MSI"); } else { bMSITemplate = CResourceStore.GetMSI("MACHINE_MSI"); } // Save this template.... try { FileStream fs = new FileStream(sNameOfMSIFile, FileMode.Create); fs.Write(bMSITemplate, 0, bMSITemplate.Length); fs.Close(); } catch (Exception) { MessageBox(String.Format(CResourceStore.GetString("CCreateDeploymentPackageWizard:ErrorWritingFile"), sNameOfMSIFile), CResourceStore.GetString("CCreateDeploymentPackageWizard:ErrorWritingFileTitle"), MB.ICONEXCLAMATION); return(false); } nRet = MsiOpenDatabase(sNameOfMSIFile, 1, out hDatabase); if (nRet != 0) { throw new Exception("Error opening database file 1"); } //----------------------------------------- // First, add a GUID to this MSI (so we don't need to worry about cached MSIs) //----------------------------------------- IntPtr hSummaryInfo; nRet = MsiGetSummaryInformation(hDatabase, null, 15, out hSummaryInfo); if (nRet != 0) { throw new Exception("MsiGetSummaryInformation failed 2"); } // Place the guid in our table nRet = MsiSummaryInfoSetProperty(hSummaryInfo, PIDSI_REVNUMBER, VT_LPSTR, 0, 0, sMyGuid); if (nRet != 0) { throw new Exception("MsiSummaryInfoSetProperty failed 3"); } // Save this change nRet = MsiSummaryInfoPersist(hSummaryInfo); if (nRet != 0) { throw new Exception("MsiSummaryInfoPersist 4"); } MsiCloseHandle(hSummaryInfo); //----------------------------------------- // Now put this guid in as the product code //----------------------------------------- hNewRecord = MsiCreateRecord(2); nRet = MsiRecordSetString(hNewRecord, 1, "ProductCode"); if (nRet != 0) { throw new Exception("MsiRecordSetString 5"); } nRet = MsiRecordSetString(hNewRecord, 2, sMyGuid); if (nRet != 0) { throw new Exception("MsiRecordSetString 6"); } nRet = MsiDatabaseOpenView(hDatabase, "INSERT INTO Property (Property, Value) VALUES (?, ?)", out hView); if (nRet != 0) { throw new Exception("MsiDatabaseOpenView 7"); } nRet = MsiViewExecute(hView, hNewRecord); if (nRet != 0) { throw new Exception("MsiViewExecute 8"); } MsiCloseHandle(hView); MsiCloseHandle(hNewRecord); //----------------------------------------- // Now put this Product Name in //----------------------------------------- String sProductName; if (polType == PolicyLevelType.User) { sProductName = CResourceStore.GetString("CCreateDeploymentPackageWizard:UserPolicy"); } else if (polType == PolicyLevelType.Machine) { sProductName = CResourceStore.GetString("CCreateDeploymentPackageWizard:MachinePolicy"); } else // an Enterprise level { sProductName = CResourceStore.GetString("CCreateDeploymentPackageWizard:EnterprisePolicy"); } hNewRecord = MsiCreateRecord(2); nRet = MsiRecordSetString(hNewRecord, 1, "ProductName"); if (nRet != 0) { throw new Exception("MsiRecordSetString 5"); } nRet = MsiRecordSetString(hNewRecord, 2, sProductName); if (nRet != 0) { throw new Exception("MsiRecordSetString 6"); } nRet = MsiDatabaseOpenView(hDatabase, "INSERT INTO Property (Property, Value) VALUES (?, ?)", out hView); if (nRet != 0) { throw new Exception("MsiDatabaseOpenView 7"); } nRet = MsiViewExecute(hView, hNewRecord); if (nRet != 0) { throw new Exception("MsiViewExecute 8"); } MsiCloseHandle(hView); MsiCloseHandle(hNewRecord); //----------------------------------------- // Now put in the Version //----------------------------------------- // We'll get the version of mscorlib that we're running with.... // Mscorlib should be providing us with the int type Assembly ast = Assembly.GetAssembly(typeof(object)); // This should give us something like // c:\winnt\complus\v1.x86chk\mscorlib.dll // We need to strip off the version... aka, we're after // v1.x86chk String sBase = ast.Location.Replace('/', '\\'); String[] sPieces = sBase.Split(new char[] { '\\' }); String sVersion = sPieces[sPieces.Length - 2]; hNewRecord = MsiCreateRecord(2); nRet = MsiRecordSetString(hNewRecord, 1, "ProductVersion"); if (nRet != 0) { throw new Exception("MsiRecordSetString 5"); } // The version needs to be a real version, and not something funky, // like v1.x86chk or even v1.2.3.4. Right now, we'll just put in // the version of mscorlib.dll as a hard coded string, and replace it // in RTM when SBS isn't completely screwed up. When everything is working // correctly, we will be able to put in sVersion and we'll be set. nRet = MsiRecordSetString(hNewRecord, 2, "1.0.2411.0"); if (nRet != 0) { throw new Exception("MsiRecordSetString 6"); } nRet = MsiDatabaseOpenView(hDatabase, "INSERT INTO Property (Property, Value) VALUES (?, ?)", out hView); if (nRet != 0) { throw new Exception("MsiDatabaseOpenView 7"); } nRet = MsiViewExecute(hView, hNewRecord); if (nRet != 0) { throw new Exception("MsiViewExecute 8"); } MsiCloseHandle(hView); MsiCloseHandle(hNewRecord); //----------------------------------------- // Now put the file info in.... //----------------------------------------- hNewRecord = MsiCreateRecord(5); // Put in the File "Key" nRet = MsiRecordSetString(hNewRecord, 1, sFileName); if (nRet != 0) { throw new Exception("MsiRecordSetString 9"); } // Put in the Component value nRet = MsiRecordSetString(hNewRecord, 2, "NETSECURITY"); if (nRet != 0) { throw new Exception("MsiRecordSetString 10"); } // Put in the filename nRet = MsiRecordSetString(hNewRecord, 3, sFileName + "|" + sFileName); if (nRet != 0) { throw new Exception("MsiRecordSetString 11"); } // Put in the file length nRet = MsiRecordSetInteger(hNewRecord, 4, (int)(new FileInfo(sNameOfFileToPackage).Length)); if (nRet != 0) { throw new Exception("MsiRecordSetString 12"); } // Put in the sequence number nRet = MsiRecordSetInteger(hNewRecord, 5, 1); if (nRet != 0) { throw new Exception("MsiRecordSetString"); } nRet = MsiDatabaseOpenView(hDatabase, "INSERT INTO File (File, Component_, FileName, FileSize, Sequence) VALUES (?, ?, ?, ?, ?)", out hView); if (nRet != 0) { throw new Exception("MsiDatabaseOpenView 13"); } nRet = MsiViewExecute(hView, hNewRecord); if (nRet != 0) { throw new Exception("MsiViewExecute 14"); } MsiCloseHandle(hView); MsiCloseHandle(hNewRecord); //----------------------------------------- // MSI has this nasty habit in that it won't write // over a pre-existing file if that pre-existing file // is newer than the file that we're trying to install. // We'll get around that by having MSI delete any file // that might exist before we try and install our packaged one //----------------------------------------- hNewRecord = MsiCreateRecord(5); // Put in the FileKey nRet = MsiRecordSetString(hNewRecord, 1, sFileName); if (nRet != 0) { throw new Exception("MsiRecordSetString 9"); } // Put in the Component value nRet = MsiRecordSetString(hNewRecord, 2, "NETSECURITY"); if (nRet != 0) { throw new Exception("MsiRecordSetString 10"); } // Put in the filename nRet = MsiRecordSetString(hNewRecord, 3, sFileName); if (nRet != 0) { throw new Exception("MsiRecordSetString 11"); } // Put in the Directory if (polType == PolicyLevelType.User) { nRet = MsiRecordSetString(hNewRecord, 4, "VERSIONDIRECTORY"); } else { nRet = MsiRecordSetString(hNewRecord, 4, "CONFIGDIRECTORY"); } if (nRet != 0) { throw new Exception("MsiRecordSetString 12"); } // Put in the install mode // We'll put in an install mode of '1'. That means that this // file will only be removed when we are installing a package. nRet = MsiRecordSetInteger(hNewRecord, 5, 1); if (nRet != 0) { throw new Exception("MsiRecordSetString"); } nRet = MsiDatabaseOpenView(hDatabase, "INSERT INTO RemoveFile (FileKey, Component_, FileName, DirProperty, InstallMode) VALUES (?, ?, ?, ?, ?)", out hView); if (nRet != 0) { throw new Exception("MsiDatabaseOpenView 13"); } nRet = MsiViewExecute(hView, hNewRecord); if (nRet != 0) { throw new Exception("MsiViewExecute 14"); } MsiCloseHandle(hView); MsiCloseHandle(hNewRecord); //----------------------------------------- // Now put the directory entry.... //----------------------------------------- hNewRecord = MsiCreateRecord(3); // Put in the Directory "Key" nRet = MsiRecordSetString(hNewRecord, 1, "VERSIONDIRECTORY"); if (nRet != 0) { throw new Exception("MsiRecordSetString 9"); } // Put in the Display Parent value if (polType == PolicyLevelType.User) { nRet = MsiRecordSetString(hNewRecord, 2, "CLRSECURITYCONFIG"); } else { nRet = MsiRecordSetString(hNewRecord, 2, "CLRINSTALLROOT"); } if (nRet != 0) { throw new Exception("MsiRecordSetString 10"); } // Put in the filename nRet = MsiRecordSetString(hNewRecord, 3, sVersion + "|" + sVersion); if (nRet != 0) { throw new Exception("MsiRecordSetString 11"); } nRet = MsiDatabaseOpenView(hDatabase, "INSERT INTO Directory (Directory, Directory_Parent, DefaultDir) VALUES (?, ?, ?)", out hView); if (nRet != 0) { throw new Exception("MsiDatabaseOpenView 13"); } nRet = MsiViewExecute(hView, hNewRecord); if (nRet != 0) { throw new Exception("MsiViewExecute 14"); } MsiCloseHandle(hView); MsiCloseHandle(hNewRecord); //----------------------------------------- // Now add the new cab to the MSI file //----------------------------------------- hNewRecord = MsiCreateRecord(2); if (hNewRecord == (IntPtr)0) { throw new Exception("MsiCreateRecord failed 15"); } nRet = MsiRecordSetString(hNewRecord, 1, "SECXML.CAB"); if (nRet != 0) { throw new Exception("MsiRecordSetString failed 16"); } nRet = MsiRecordSetStream(hNewRecord, 2, sDirectory + "SECXML.CAB"); if (nRet != 0) { throw new Exception("MsiRecordSetStream failed 17"); } nRet = MsiDatabaseOpenView(hDatabase, "INSERT INTO `_Streams` (Name, Data) VALUES (?, ?)", out hView); if (nRet != 0) { throw new Exception("MsiDatabaseOpenView failed 19"); } nRet = MsiViewExecute(hView, hNewRecord); if (nRet != 0) { throw new Exception("MsiViewExecute failed 20"); } MsiCloseHandle(hView); MsiCloseHandle(hNewRecord); //----------------------------------------- // Now put in the error message we'll display // if the .NET framework isn't installed on the machine // the user tries to deploy this package to. But, we'll only // do this if we're dealing with a machine or enterprise policy // deployment //----------------------------------------- if (polType != PolicyLevelType.User) { hNewRecord = MsiCreateRecord(3); if (hNewRecord == (IntPtr)0) { throw new Exception("MsiCreateRecord failed"); } nRet = MsiRecordSetString(hNewRecord, 1, "VERIFYINSTALLROOT"); if (nRet != 0) { throw new Exception("MsiRecordSetString failed"); } nRet = MsiRecordSetInteger(hNewRecord, 2, 19); if (nRet != 0) { throw new Exception("MsiRecordSetInteger"); } nRet = MsiRecordSetString(hNewRecord, 3, CResourceStore.GetString("CCreateDeploymentPackageWizard:FrameworkNotExist")); if (nRet != 0) { throw new Exception("MsiRecordSetString"); } nRet = MsiDatabaseOpenView(hDatabase, "INSERT INTO `CustomAction` (Action, Type, Target) VALUES (?, ?, ?)", out hView); if (nRet != 0) { throw new Exception("MsiDatabaseOpenView failed"); } nRet = MsiViewExecute(hView, hNewRecord); if (nRet != 0) { throw new Exception("MsiViewExecute failed"); } MsiCloseHandle(hView); MsiCloseHandle(hNewRecord); } //----------------------------------------- // Update the LockPermissions table // // We only need to worry about this if we're working with either the // machine policy or the enterprise policy //----------------------------------------- if (polType != PolicyLevelType.User) { nRet = MsiDatabaseOpenView(hDatabase, "SELECT * FROM `LockPermissions`", out hView); if (nRet != 0) { throw new Exception("MsiDatabaseOpenView failed " + nRet.ToString()); } nRet = MsiViewExecute(hView, (IntPtr)0); if (nRet != 0) { throw new Exception("MsiViewExecute failed"); } IntPtr hRecord; nRet = MsiViewFetch(hView, out hRecord); if (nRet != 0) { throw new Exception("MsiViewFetch failed " + nRet.ToString()); } nRet = MsiRecordSetString(hRecord, 1, sFileName); if (nRet != 0) { throw new Exception("MsiRecordSetString failed " + nRet.ToString()); } /*nRet = MsiViewModify(hView, 2, hRecord); * if (nRet != 0) * throw new Exception("MsiRecordSetStream failed"); */ MsiCloseHandle(hView); MsiCloseHandle(hRecord); } //----------------------------------------- // Commit the change to the MSI file //----------------------------------------- MsiDatabaseCommit(hDatabase); MsiCloseHandle(hDatabase); //----------------------------------------- // Now remove the cab file we created on the disk //----------------------------------------- File.Delete(sDirectory + "SECXML.CAB"); return(true); } catch (Exception) { MsiCloseHandle(hDatabase); MessageBox(String.Format(CResourceStore.GetString("CCreateDeploymentPackageWizard:ErrorEditingFile"), sNameOfMSIFile), CResourceStore.GetString("CCreateDeploymentPackageWizard:ErrorEditingFileTitle"), MB.ICONEXCLAMATION); // Try and delete the file we were creating. File.Delete(sNameOfMSIFile); return(false); } }// CreateMyMSIFile