public T GetObject <T>(string key) { string value = this[key]; if (value == null) { return(default(T)); } else if (typeof(T) == typeof(string)) { // Funny casting because the compiler doesn't know T is string here. return((T)(object)value); } else if (typeof(T) == typeof(CustomActionData)) { // Deserialize nested CustomActionData. return((T)(object)new CustomActionData(value)); } else if (value.Length == 0) { return(default(T)); } else { return(CustomActionData.Deserialize <T>(value)); } }
/// <summary> /// Gets or sets a data value with a specified key. /// </summary> /// <param name="key">Case-sensitive data key.</param> /// <exception cref="ArgumentException">the key does not consist solely of letters, /// numbers, and the period, underscore, and space characters.</exception> public string this[string key] { get { return(this.data[key]); } set { CustomActionData.ValidateKey(key); this.data[key] = value; } }
/// <summary> /// Loads key-value pairs from a string into the data collection. /// </summary> /// <param name="keyValueList">key-value pair list of the form returned by <see cref="ToString"/></param> private void Parse(string keyValueList) { int itemStart = 0; while (itemStart < keyValueList.Length) { // Find the next non-escaped data separator. int semi = itemStart - 2; do { semi = keyValueList.IndexOf(CustomActionData.DataSeparator, semi + 2); }while (semi >= 0 && semi < keyValueList.Length - 1 && keyValueList[semi + 1] == CustomActionData.DataSeparator); if (semi < 0) { semi = keyValueList.Length; } // Find the next non-escaped key-value separator. int equals = itemStart - 2; do { equals = keyValueList.IndexOf(CustomActionData.KeyValueSeparator, equals + 2); }while (equals >= 0 && equals < keyValueList.Length - 1 && keyValueList[equals + 1] == CustomActionData.KeyValueSeparator); if (equals < 0 || equals > semi) { equals = semi; } string key = keyValueList.Substring(itemStart, equals - itemStart); string value = null; // If there's a key-value separator before the next data separator, then the item has a value. if (equals < semi) { value = keyValueList.Substring(equals + 1, semi - (equals + 1)); value = CustomActionData.Unescape(value); } // Add non-duplicate items to the collection. if (key.Length > 0 && !this.data.ContainsKey(key)) { this.data.Add(key, value); } // Move past the data separator to the next item. itemStart = semi + 1; } }
/// <summary> /// Adds a value to the data collection, using XML serialization to persist the object as a string. /// </summary> /// <param name="key">Case-sensitive data key.</param> /// <param name="value">Data value (may be null).</param> /// <exception cref="ArgumentException">the key does not consist solely of letters, /// numbers, and the period, underscore, and space characters.</exception> /// <exception cref="NotSupportedException">The value type does not support XML serialization.</exception> /// <exception cref="InvalidOperationException">The value could not be serialized.</exception> public void AddObject <T>(string key, T value) { if (value == null) { this.Add(key, null); } else if (typeof(T) == typeof(string) || typeof(T) == typeof(CustomActionData)) // Serialize nested CustomActionData { this.Add(key, value.ToString()); } else { string valueString = CustomActionData.Serialize <T>(value); this.Add(key, valueString); } }
/// <summary> /// Executes a built-in action, custom action, or user-interface wizard action. /// </summary> /// <param name="action">Name of the action to execute. Case-sensitive.</param> /// <param name="actionData">Optional data to be passed to a deferred custom action.</param> /// <exception cref="InvalidHandleException">the Session handle is invalid</exception> /// <exception cref="InstallCanceledException">the user exited the installation</exception> /// <remarks><p> /// The DoAction method executes the action that corresponds to the name supplied. If the /// name is not recognized by the installer as a built-in action or as a custom action in /// the CustomAction table, the name is passed to the user-interface handler object, which /// can invoke a function or a dialog box. If a null action name is supplied, the installer /// uses the upper-case value of the ACTION property as the action to perform. If no property /// value is defined, the default action is performed, defined as "INSTALL". /// </p><p> /// Actions that update the system, such as the InstallFiles and WriteRegistryValues /// actions, cannot be run by calling MsiDoAction. The exception to this rule is if DoAction /// is called from a custom action that is scheduled in the InstallExecuteSequence table /// between the InstallInitialize and InstallFinalize actions. Actions that do not update the /// system, such as AppSearch or CostInitialize, can be called. /// </p><p> /// If the called action is a deferred, rollback, or commit custom action, then the supplied /// <paramref name="actionData"/> will be available via the <see cref="CustomActionData"/> /// property of that custom action's session. /// </p><p> /// Win32 MSI API: /// <a href="http://msdn.microsoft.com/library/en-us/msi/setup/msidoaction.asp">MsiDoAction</a> /// </p></remarks> public void DoAction(string action, CustomActionData actionData) { if (String.IsNullOrEmpty(action)) { throw new ArgumentNullException("action"); } this.ValidateSessionAccess(); if (actionData != null) { this[action] = actionData.ToString(); } uint ret = RemotableNativeMethods.MsiDoAction((int)this.Handle, action); if (ret != 0) { throw InstallerException.ExceptionFromReturnCode(ret); } }
/// <summary> /// Gets a string representation of the data suitable for persisting in a property. /// </summary> /// <returns>Data string in the form "Key1=Value1;Key2=Value2"</returns> public override string ToString() { StringBuilder buf = new StringBuilder(); foreach (KeyValuePair <string, string> item in this.data) { if (buf.Length > 0) { buf.Append(CustomActionData.DataSeparator); } buf.Append(item.Key); if (item.Value != null) { buf.Append(CustomActionData.KeyValueSeparator); buf.Append(CustomActionData.Escape(item.Value)); } } return(buf.ToString()); }
/// <summary> /// Adds a key and value to the data collection. /// </summary> /// <param name="key">Case-sensitive data key.</param> /// <param name="value">Data value (may be null).</param> /// <exception cref="ArgumentException">the key does not consist solely of letters, /// numbers, and the period, underscore, and space characters.</exception> public void Add(string key, string value) { CustomActionData.ValidateKey(key); this.data.Add(key, value); }
/// <summary> /// Adds an item with key and value to the data collection. /// </summary> /// <param name="item">Case-sensitive data key, with a data value that may be null.</param> /// <exception cref="ArgumentException">the key does not consist solely of letters, /// numbers, and the period, underscore, and space characters.</exception> public void Add(KeyValuePair <string, string> item) { CustomActionData.ValidateKey(item.Key); this.data.Add(item); }