From dbde9e7104b907bbbaea17e21247d8cafc8b3a4c Mon Sep 17 00:00:00 2001 From: Rob Mensching Date: Sat, 14 Oct 2017 16:12:07 -0700 Subject: Massive refactoring to introduce the concept of IBackend --- src/WixToolset.Core.WindowsInstaller/Msi/View.cs | 189 +++++++++++++++++++++++ 1 file changed, 189 insertions(+) create mode 100644 src/WixToolset.Core.WindowsInstaller/Msi/View.cs (limited to 'src/WixToolset.Core.WindowsInstaller/Msi/View.cs') diff --git a/src/WixToolset.Core.WindowsInstaller/Msi/View.cs b/src/WixToolset.Core.WindowsInstaller/Msi/View.cs new file mode 100644 index 00000000..d6542824 --- /dev/null +++ b/src/WixToolset.Core.WindowsInstaller/Msi/View.cs @@ -0,0 +1,189 @@ +// Copyright (c) .NET Foundation and contributors. All rights reserved. Licensed under the Microsoft Reciprocal License. See LICENSE.TXT file in the project root for full license information. + +namespace WixToolset.Msi +{ + using System; + using System.ComponentModel; + using System.Globalization; + using WixToolset.Core.Native; + + /// + /// Enumeration of different modify modes. + /// + public enum ModifyView + { + /// + /// Writes current data in the cursor to a table row. Updates record if the primary + /// keys match an existing row and inserts if they do not match. Fails with a read-only + /// database. This mode cannot be used with a view containing joins. + /// + Assign = MsiInterop.MSIMODIFYASSIGN, + + /// + /// Remove a row from the table. You must first call the Fetch function with the same + /// record. Fails if the row has been deleted. Works only with read-write records. This + /// mode cannot be used with a view containing joins. + /// + Delete = MsiInterop.MSIMODIFYDELETE, + + /// + /// Inserts a record. Fails if a row with the same primary keys exists. Fails with a read-only + /// database. This mode cannot be used with a view containing joins. + /// + Insert = MsiInterop.MSIMODIFYINSERT, + + /// + /// Inserts a temporary record. The information is not persistent. Fails if a row with the + /// same primary key exists. Works only with read-write records. This mode cannot be + /// used with a view containing joins. + /// + InsertTemporary = MsiInterop.MSIMODIFYINSERTTEMPORARY, + + /// + /// Inserts or validates a record in a table. Inserts if primary keys do not match any row + /// and validates if there is a match. Fails if the record does not match the data in + /// the table. Fails if there is a record with a duplicate key that is not identical. + /// Works only with read-write records. This mode cannot be used with a view containing joins. + /// + Merge = MsiInterop.MSIMODIFYMERGE, + + /// + /// Refreshes the information in the record. Must first call Fetch with the + /// same record. Fails for a deleted row. Works with read-write and read-only records. + /// + Refresh = MsiInterop.MSIMODIFYREFRESH, + + /// + /// Updates or deletes and inserts a record into a table. Must first call Fetch with + /// the same record. Updates record if the primary keys are unchanged. Deletes old row and + /// inserts new if primary keys have changed. Fails with a read-only database. This mode cannot + /// be used with a view containing joins. + /// + Replace = MsiInterop.MSIMODIFYREPLACE, + + /// + /// Refreshes the information in the supplied record without changing the position in the + /// result set and without affecting subsequent fetch operations. The record may then + /// be used for subsequent Update, Delete, and Refresh. All primary key columns of the + /// table must be in the query and the record must have at least as many fields as the + /// query. Seek cannot be used with multi-table queries. This mode cannot be used with + /// a view containing joins. See also the remarks. + /// + Seek = MsiInterop.MSIMODIFYSEEK, + + /// + /// Updates an existing record. Non-primary keys only. Must first call Fetch. Fails with a + /// deleted record. Works only with read-write records. + /// + Update = MsiInterop.MSIMODIFYUPDATE + } + + /// + /// Wrapper class for MSI API views. + /// + internal sealed class View : MsiHandle + { + /// + /// Constructor that creates a view given a database handle and a query. + /// + /// Handle to the database to run the query on. + /// Query to be executed. + public View(Database db, string query) + { + if (null == db) + { + throw new ArgumentNullException("db"); + } + + if (null == query) + { + throw new ArgumentNullException("query"); + } + + uint handle = 0; + + int error = MsiInterop.MsiDatabaseOpenView(db.Handle, query, out handle); + if (0 != error) + { + throw new MsiException(error); + } + + this.Handle = handle; + } + + /// + /// Executes a view with no customizable parameters. + /// + public void Execute() + { + this.Execute(null); + } + + /// + /// Executes a query substituing the values from the records into the customizable parameters + /// in the view. + /// + /// Record containing parameters to be substituded into the view. + public void Execute(Record record) + { + int error = MsiInterop.MsiViewExecute(this.Handle, null == record ? 0 : record.Handle); + if (0 != error) + { + throw new MsiException(error); + } + } + + /// + /// Fetches the next row in the view. + /// + /// Returns the fetched record; otherwise null. + public Record Fetch() + { + uint recordHandle; + + int error = MsiInterop.MsiViewFetch(this.Handle, out recordHandle); + if (259 == error) + { + return null; + } + else if (0 != error) + { + throw new MsiException(error); + } + + return new Record(recordHandle); + } + + /// + /// Updates a fetched record. + /// + /// Type of modification mode. + /// Record to be modified. + public void Modify(ModifyView type, Record record) + { + int error = MsiInterop.MsiViewModify(this.Handle, Convert.ToInt32(type, CultureInfo.InvariantCulture), record.Handle); + if (0 != error) + { + throw new MsiException(error); + } + } + + /// + /// Returns a record containing column names or definitions. + /// + /// Specifies a flag indicating what type of information is needed. Either MSICOLINFO_NAMES or MSICOLINFO_TYPES. + /// The record containing information about the column. + public Record GetColumnInfo(int columnType) + { + uint recordHandle; + + int error = MsiInterop.MsiViewGetColumnInfo(this.Handle, columnType, out recordHandle); + if (0 != error) + { + throw new MsiException(error); + } + + return new Record(recordHandle); + } + } +} -- cgit v1.2.3-55-g6feb