/// <summary> /// Reads a record stream field into a file. /// </summary> /// <param name="field">Specifies the field of the Record to get.</param> /// <param name="filePath">Specifies the path to the file to contain the stream.</param> /// <exception cref="ArgumentOutOfRangeException">The field is less than 0 or greater than the /// number of fields in the Record.</exception> /// <exception cref="NotSupportedException">Attempt to extract a storage from a database open /// in read-write mode, or from a database without an associated file path</exception> /// <remarks><p> /// This method is capable of directly extracting substorages. To do so, first select both the /// `Name` and `Data` column of the `_Storages` table, then get the stream of the `Data` field. /// However, substorages may only be extracted from a database that is open in read-only mode. /// </p><p> /// Win32 MSI API: /// <a href="http://msdn.microsoft.com/library/en-us/msi/setup/msirecordreadstream.asp">MsiRecordReadStream</a> /// </p></remarks> public void GetStream(int field, string filePath) { if (string.IsNullOrWhiteSpace(filePath)) { throw new ArgumentNullException("filePath"); } IList <TableInfo> tables = (this.view != null ? this.view.Tables : null); if (tables != null && tables.Count == 1 && tables[0].Name == "_Storages" && field == this.FindColumn("Data")) { if (!this.view.Database.IsReadOnly) { throw new NotSupportedException("Database must be opened read-only to support substorage extraction."); } else if (this.view.Database.FilePath == null) { throw new NotSupportedException("Database must have an associated file path to support substorage extraction."); } else if (this.FindColumn("Name") <= 0) { throw new NotSupportedException("Name column must be part of the Record in order to extract substorage."); } else { Record.ExtractSubStorage(this.view.Database.FilePath, this.GetString("Name"), filePath); } } else { if (!this.IsNull(field)) { Stream readStream = null, writeStream = null; try { readStream = new RecordStream(this, field); writeStream = new FileStream(filePath, FileMode.Create, FileAccess.Write); int count = 512; byte[] buf = new byte[count]; while (count == buf.Length) { if ((count = readStream.Read(buf, 0, buf.Length)) > 0) { writeStream.Write(buf, 0, count); } } } finally { if (readStream != null) { readStream.Close(); } if (writeStream != null) { writeStream.Close(); } } } } }