internal ShellPropertyDescription(PROPERTYKEY propertyKey) { Contract.Requires <ArgumentNullException>(propertyKey != null); this.propertyKey = propertyKey; var guid = new Guid(PropertySystemIID.IPropertyDescription); var hr = PropertySystemNativeMethods.PSGetPropertyDescription(ref this.propertyKey, ref guid, out this.propertyDescriptionNative); if (HRESULT.Failed(hr)) { throw new ShellException( String.Format(ErrorMessages.ShellPropertyDescriptionError, propertyKey), hr); } }
/// <summary> /// Creates a list of stack keys, as specified. If this method is not called, /// by default the folder will not be stacked. /// </summary> /// <param name="canonicalNames">Array of canonical names for properties on which the folder is stacked.</param> /// <exception cref="System.ArgumentException">If one of the given canonical names is invalid.</exception> public void SetStacks(params string[] canonicalNames) { List <PropertyKey> propertyKeyList = new List <PropertyKey>(); foreach (string prop in canonicalNames) { // Get the PropertyKey using the canonicalName passed in PropertyKey propKey; int result = PropertySystemNativeMethods.PSGetPropertyKeyFromName(prop, out propKey); if (!CoreErrorHelper.Succeeded(result)) { throw new ArgumentException("The given CanonicalName is not valid.", "canonicalNames", Marshal.GetExceptionForHR(result)); } propertyKeyList.Add(propKey); } if (propertyKeyList.Count > 0) { SetStacks(propertyKeyList.ToArray()); } }
/// <summary> /// Specifies which properties will be collected in the save dialog. /// </summary> /// <param name="appendDefault">True to show default properties for the currently selected /// filetype in addition to the properties specified by propertyList. False to show only properties /// specified by pList. /// <param name="propertyList">List of properties to collect. This parameter can be null.</param> /// </param> /// <remarks> /// SetCollectedPropertyKeys can be called at any time before the dialog is displayed or while it /// is visible. If different properties are to be collected depending on the chosen filetype, /// then SetCollectedProperties can be called in response to CommonFileDialog::FileTypeChanged event. /// Note: By default, no properties are collected in the save dialog. /// </remarks> public void SetCollectedPropertyKeys(bool appendDefault, params PropertyKey[] propertyList) { string propertyListStr = null; // Loop through all our property keys and create a semicolon-delimited property list string. if (propertyList != null && propertyList.Length > 0 && propertyList[0] != null) { foreach (PropertyKey key in propertyList) { string canonicalName = ShellPropertyDescriptionsCache.Cache.GetPropertyDescription(key).CanonicalName; // The string we pass to PSGetPropertyDescriptionListFromString must // start with "prop:", followed a list of canonical names for each // property that is to collected. // // Add "prop:" at the start of the string if we are starting our for loop. if (propertyListStr == null) { propertyListStr = "prop:"; } // For each property, append the canonical name, followed by a semicolon if (!string.IsNullOrEmpty(canonicalName)) { propertyListStr += canonicalName + ";"; } } } // If the string was created correctly, get IPropertyDescriptionList for it if (!string.IsNullOrEmpty(propertyListStr)) { Guid guid = new Guid(ShellIIDGuid.IPropertyDescriptionList); IPropertyDescriptionList propertyDescriptionList = null; try { int hr = PropertySystemNativeMethods.PSGetPropertyDescriptionListFromString(propertyListStr, ref guid, out propertyDescriptionList); // If we get a IPropertyDescriptionList, setit on the native dialog. if (CoreErrorHelper.Succeeded(hr)) { IFileSaveDialog nativeDialog = null; if (nativeDialog == null) { InitializeNativeFileDialog(); nativeDialog = GetNativeFileDialog() as IFileSaveDialog; } if (nativeDialog != null) { hr = nativeDialog.SetCollectedProperties(propertyDescriptionList, appendDefault); if (!CoreErrorHelper.Succeeded(hr)) { Marshal.ThrowExceptionForHR(hr); } } } } finally { if (propertyDescriptionList != null) { Marshal.ReleaseComObject(propertyDescriptionList); } } } }
static void Explorer() { string explorerFile = ""; try { Guid IPropertyStoreGuid = new Guid("886D8EEB-8CF2-4446-8D02-CDBA1DBDCF99"); PropertySystemNativeMethods.PSGetPropertyKeyFromName("System.Comment", out PropertyKey key); DirectoryInfo di = new DirectoryInfo(targetDirectory); int count = 0; bool done = false; while (!done) { foreach (FileInfo file in di.GetFiles()) { explorerFile = file.Name; count++; HResult hr = (HResult)SHGetPropertyStoreFromParsingName(file.FullName, IntPtr.Zero, GETPROPERTYSTOREFLAGS.GPS_READWRITE, ref IPropertyStoreGuid, out IPropertyStore ps); if (hr == HResult.Ok) { try { PropVariant val = new PropVariant(); hr = ps.GetValue(key, val); if (hr == HResult.Ok) { var sValue = val.ToString(); if (count % 30 == 0) { PropVariant value = new PropVariant("test comment"); hr = ps.SetValue(key, value); if (hr == HResult.Ok) { hr = ps.Commit(); if (hr == HResult.Ok) { LogLine(3, $"Explorer Read '{sValue}' and updated"); } else if ((int)hr > 0) { LogLine(2, $"Commit for {explorerFile} returned {hr:X}"); } else { throw new Exception($"Commit failed with 0x{hr:X}"); } } else { throw new Exception($"SetValue failed with 0x{hr:X}"); } } else { LogLine(3, $"Explorer Read '{sValue}'"); } } else if ((uint)hr == 0x80030021) { LogLine(2, $"GetValue for {explorerFile} failed with STG_E_LOCKVIOLATION"); IncrementExplorerFail(); } else { throw new Exception($"GetValue failed with 0x{hr:X}"); } done = IncrementExplorer(); if (done) { break; } } finally { Marshal.ReleaseComObject(ps); // optional GC preempt } } else if ((uint)hr == 0x80030021) { LogLine(2, $"Explorer Open failed on '{explorerFile}' with lock violation 0x{hr:X}"); IncrementExplorerFail(); } else { throw new Exception($"Open failed with 0x{hr:X}"); } } } } catch (Exception ex) { LogLine(1, $"Explorer terminated for '{explorerFile}': {ex}"); IncrementExplorerTerminated(); } }