private void LoadStreams() { using (var stg = new OleStorageFile(new LessIO.Path(SelectedMsiFile.FullName))) { var streamViews = stg.GetStreams().Select(s => StreamInfoView.FromStream(s)); View.SetStreamSelectorSource(streamViews); } }
/// <summary> /// Called by the view to notify of a change in the selection of the SelectedStreamInfo. /// </summary> public void OnSelectedStreamChanged() { if (View.SelectedStreamInfo != null && this.SelectedMsiFile != null) { // 1: find the right stream containing the cab bits: using (var oleFile = new OleStorageFile(new LessIO.Path(this.SelectedMsiFile.FullName))) { var foundStream = oleFile.GetStreams().FirstOrDefault(s => string.Equals(View.SelectedStreamInfo.Name, s.Name, StringComparison.InvariantCulture)); if (foundStream == null) { View.ShowUserError("Could not find stream for CAB '{0}'", View.SelectedStreamInfo.Name); return; } // if the file is a cab, we'll list the files in it (if it isn't clear the view): IEnumerable <CabContainedFileView> streamFiles = new CabContainedFileView[] {}; if (View.SelectedStreamInfo.IsCabStream) { var tempFileName = System.IO.Path.GetTempFileName(); using (var cabBits = foundStream.GetStream(FileMode.Open, FileAccess.Read)) using (var writer = new BinaryWriter(File.Create(tempFileName))) { var buffer = new byte[1024 * 1024]; int bytesRead; do { bytesRead = cabBits.Read(buffer, 0, buffer.Length); writer.Write(buffer, 0, bytesRead); } while (bytesRead > 0); } // 2: enumerate files in the cab and set them to the view's using (var cab = new LibMSPackN.MSCabinet(tempFileName)) { // ToList to force it to enumerate now. streamFiles = cab.GetFiles().Select(f => new CabContainedFileView(f.Filename)).ToList(); } Debug.Assert(streamFiles != null && streamFiles.Any()); } View.SetCabContainedFileListSource(streamFiles); } } }
public static void ExtractCabFromPackage(Path destCabPath, string cabName, Database inputDatabase, LessIO.Path msiPath) { //NOTE: checking inputDatabase.TableExists("_Streams") here is not accurate. It reports that it doesn't exist at times when it is perfectly queryable. So we actually try it and look for a specific exception: //NOTE: we do want to tryStreams. It is more reliable when available and AFAICT it always /should/ be there according to the docs but isn't. const bool tryStreams = true; if (tryStreams) { try { ExtractCabFromPackageTraditionalWay(destCabPath, cabName, inputDatabase); // as long as TraditionalWay didn't throw, we'll leave it at that... return; } catch (Exception e) { Debug.WriteLine("ExtractCabFromPackageTraditionalWay Exception: {0}", e); // According to issue #78 (https://github.com/activescott/lessmsi/issues/78), WIX installers sometimes (always?) // don't have _Streams table yet they still install. Since it appears that msi files generally (BUT NOT ALWAYS - see X86 Debuggers And Tools-x86_en-us.msi) will have only one cab file, we'll try to just find it in the sterams and use it instead: Trace.WriteLine("MSI File has no _Streams table. Attempting alternate cab file extraction process..."); } } using (var stg = new OleStorageFile(msiPath)) { // MSIs do exist with >1. If we use the ExtractCabFromPackageTraditionalWay (via _Streams table) then it handles that. If we are using this fallback approach, multiple cabs is a bad sign! Debug.Assert(CountCabs(stg) == 1, string.Format("Expected 1 cab, but found {0}.", CountCabs(stg))); foreach (var strm in stg.GetStreams()) { using (var bits = strm.GetStream(FileMode.Open, FileAccess.Read)) { if (OleStorageFile.IsCabStream(bits)) { Trace.WriteLine(String.Format("Found CAB bits in stream. Assuming it is for cab {0}.", destCabPath)); Func <byte[], int> streamReader = destBuffer => bits.Read(destBuffer, 0, destBuffer.Length); CopyStreamToFile(streamReader, destCabPath); } } } } }
private static int CountCabs(OleStorageFile stg) { return(stg.GetStreams().Count(strm => OleStorageFile.IsCabStream((StreamInfo)strm))); }