/// <summary> /// Release the native and managed objects /// </summary> /// <param name="disposing">Indicates that this is being called from Dispose(), rather than the finalizer.</param> protected virtual void Dispose(bool disposing) { if (disposing) { internalName = null; internalParsingName = null; properties = null; thumbnail = null; parentShellObject = null; } if (internalPIDL != IntPtr.Zero) { ShellNativeMethods.ILFree(internalPIDL); internalPIDL = IntPtr.Zero; } if (nativeShellItem != null) { Marshal.ReleaseComObject(nativeShellItem); nativeShellItem = null; } if (NativePropertyStore != null) { Marshal.ReleaseComObject(NativePropertyStore); NativePropertyStore = null; } }
/// <summary> /// Returns a known folder given its shell namespace parsing name, such as /// <c>::{645FF040-5081-101B-9F08-00AA002F954E}</c> for the Recycle Bin. /// </summary> /// <param name="parsingName">The parsing name (or path) for the requested known folder.</param> /// <returns>A known folder representing the specified name.</returns> /// <exception cref="System.ArgumentException">Thrown if the given parsing name is invalid.</exception> public static IKnownFolder FromParsingName(string parsingName) { if (parsingName == null) { throw new ArgumentNullException(nameof(parsingName)); } IntPtr pidl = IntPtr.Zero; IntPtr pidl2 = IntPtr.Zero; try { pidl = ShellHelper.PidlFromParsingName(parsingName); if (pidl == IntPtr.Zero) { throw new ArgumentException(LocalizedMessages.KnownFolderParsingName, nameof(parsingName)); } // It's probably a special folder, try to get it IKnownFolderNative knownFolderNative = KnownFolderHelper.FromPIDL(pidl); if (knownFolderNative != null) { IKnownFolder kf = KnownFolderHelper.GetKnownFolder(knownFolderNative); if (kf == null) { throw new ArgumentException(LocalizedMessages.KnownFolderParsingName, nameof(parsingName)); } return(kf); } // No physical storage was found for this known folder // We'll try again with a different name // try one more time with a trailing \0 pidl2 = ShellHelper.PidlFromParsingName(parsingName.PadRight(1, '\0')); if (pidl2 == IntPtr.Zero) { throw new ArgumentException(LocalizedMessages.KnownFolderParsingName, nameof(parsingName)); } IKnownFolder kf2 = KnownFolderHelper.GetKnownFolder(KnownFolderHelper.FromPIDL(pidl)); if (kf2 == null) { throw new ArgumentException(LocalizedMessages.KnownFolderParsingName, nameof(parsingName)); } return(kf2); } finally { ShellNativeMethods.ILFree(pidl); ShellNativeMethods.ILFree(pidl2); } }
// This is a work around for the STA thread bug. This will execute the call on a non-sta thread, then return the result private static bool IsVirtualKnownFolder(IShellItem2 nativeShellItem2) { IntPtr pidl = IntPtr.Zero; try { IKnownFolderNative nativeFolder = null; KnownFoldersSafeNativeMethods.NativeFolderDefinition definition = new KnownFoldersSafeNativeMethods.NativeFolderDefinition(); // We found a bug where the enumeration of shell folders was // not reliable when called from a STA thread - it would return // different results the first time vs the other times. // // This is a work around. We call FindFolderFromIDList on a // worker MTA thread instead of the main STA thread. // // Ultimately, it would be a very good idea to replace the 'getting shell object' logic // to get a list of pidl's in 1 step, then look up their information in a 2nd, rather than // looking them up as we get them. This would replace the need for the work around. object padlock = new object(); lock (padlock) { IntPtr unknown = Marshal.GetIUnknownForObject(nativeShellItem2); ThreadPool.QueueUserWorkItem(obj => { lock (padlock) { pidl = ShellHelper.PidlFromUnknown(unknown); new KnownFolderManagerClass().FindFolderFromIDList(pidl, out nativeFolder); if (nativeFolder != null) { nativeFolder.GetFolderDefinition(out definition); } Monitor.Pulse(padlock); } }); Monitor.Wait(padlock); } return(nativeFolder != null && definition.category == FolderCategory.Virtual); } finally { ShellNativeMethods.ILFree(pidl); } }
private static IKnownFolderNative GetNativeKnownFolder(IShellItem nativeShellItem, out bool isVirtual) { IntPtr pidl = IntPtr.Zero; try { // Get the PIDL for the ShellItem pidl = ShellHelper.PidlFromShellItem(nativeShellItem); if (pidl == IntPtr.Zero) { isVirtual = false; return(null); } IKnownFolderNative knownFolderNative = KnownFolderHelper.FromPIDL(pidl); if (knownFolderNative != null) { // If we have a valid IKnownFolder, try to get its category KnownFoldersSafeNativeMethods.NativeFolderDefinition nativeFolderDefinition; knownFolderNative.GetFolderDefinition(out nativeFolderDefinition); // Get the category type and see if it's virtual if (nativeFolderDefinition.category == FolderCategory.Virtual) { isVirtual = true; } else { isVirtual = false; } return(knownFolderNative); } else { // KnownFolderHelper.FromPIDL could not create a valid KnownFolder from the given PIDL. // Return null to indicate the given IShellItem is not a KnownFolder. Also set our out parameter // to default value. isVirtual = false; return(null); } } finally { ShellNativeMethods.ILFree(pidl); } }