//! \file Shell.cs //! \date Tue Aug 02 13:48:55 2011 //! \brief Win32 shell functions. // // Copyright (C) 2011 by poddav // // Permission is hereby granted, free of charge, to any person obtaining a copy // of this software and associated documentation files (the "Software"), to // deal in the Software without restriction, including without limitation the // rights to use, copy, modify, merge, publish, distribute, sublicense, and/or // sell copies of the Software, and to permit persons to whom the Software is // furnished to do so, subject to the following conditions: // // The above copyright notice and this permission notice shall be included in // all copies or substantial portions of the Software. // // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING // FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS // IN THE SOFTWARE. // using System; using System.IO; using System.Text; using System.Collections.Generic; using System.Runtime.InteropServices; namespace GARbro.Shell { /// /// Wrapper around MoveFileEx WINAPI call. /// class File { [DllImport("kernel32.dll", EntryPoint="MoveFileExW", SetLastError=true, CharSet=CharSet.Unicode)] public static extern bool MoveFileEx (string lpExistingFileName, string lpNewFileName, MoveFileFlags dwFlags); [Flags] public enum MoveFileFlags : uint { ReplaceExisting = 0x00000001, CopyAllowed = 0x00000002, DelayUntilReboot = 0x00000004, WriteThrough = 0x00000008, CreateHardlink = 0x00000010, FailIfNotTrackable = 0x00000020 } public static bool Rename (string szFrom, string szTo) { return MoveFileEx (szFrom, szTo, MoveFileFlags.ReplaceExisting); } public static int GetLastError () { return Marshal.GetLastWin32Error(); } /// /// Possible flags for the SHFileOperation method. /// [Flags] public enum FileOperationFlags : ushort { /// /// Do not show a dialog during the process /// FOF_SILENT = 0x0004, /// /// Do not ask the user to confirm selection /// FOF_NOCONFIRMATION = 0x0010, /// /// Delete the file to the recycle bin. (Required flag to send a file to the bin /// FOF_ALLOWUNDO = 0x0040, /// /// Do not show the names of the files or folders that are being recycled. /// FOF_SIMPLEPROGRESS = 0x0100, /// /// Surpress errors, if any occur during the process. /// FOF_NOERRORUI = 0x0400, /// /// Warn if files are too big to fit in the recycle bin and will need /// to be deleted completely. /// FOF_WANTNUKEWARNING = 0x4000, } /// /// File Operation Function Type for SHFileOperation /// public enum FileOperationType : uint { /// /// Move the objects /// FO_MOVE = 0x0001, /// /// Copy the objects /// FO_COPY = 0x0002, /// /// Delete (or recycle) the objects /// FO_DELETE = 0x0003, /// /// Rename the object(s) /// FO_RENAME = 0x0004, } /// /// SHFILEOPSTRUCT for SHFileOperation from COM /// [StructLayout(LayoutKind.Sequential, CharSet = CharSet.Auto, Pack = 1)] private struct SHFILEOPSTRUCT { public IntPtr hwnd; [MarshalAs(UnmanagedType.U4)] public FileOperationType wFunc; public string pFrom; public string pTo; public FileOperationFlags fFlags; [MarshalAs(UnmanagedType.Bool)] public bool fAnyOperationsAborted; public IntPtr hNameMappings; public string lpszProgressTitle; } [DllImport("shell32.dll", CharSet = CharSet.Auto)] private static extern int SHFileOperation (ref SHFILEOPSTRUCT FileOp); /// /// Send file to recycle bin /// /// Location of directory or file to recycle /// FileOperationFlags to add in addition to FOF_ALLOWUNDO public static bool Delete (string path, FileOperationFlags flags) { var fs = new SHFILEOPSTRUCT { wFunc = FileOperationType.FO_DELETE, pFrom = path + '\0' + '\0', fFlags = FileOperationFlags.FOF_ALLOWUNDO | flags }; return 0 == SHFileOperation (ref fs); } public static bool Delete (IEnumerable file_list, FileOperationFlags flags) { var files = new StringBuilder(); foreach (var file in file_list) { files.Append (file); files.Append ('\0'); } if (0 == files.Length) return false; files.Append ('\0'); var fs = new SHFILEOPSTRUCT { wFunc = FileOperationType.FO_DELETE, pFrom = files.ToString(), fFlags = FileOperationFlags.FOF_ALLOWUNDO | flags }; return 0 == SHFileOperation (ref fs); } public static bool Delete (IEnumerable file_list) { return Delete (file_list, FileOperationFlags.FOF_WANTNUKEWARNING); } /// /// Send file to recycle bin. Display dialog, display warning if files are too big to fit (FOF_WANTNUKEWARNING) /// /// Location of directory or file to recycle public static bool Delete (string path) { return Delete (path, FileOperationFlags.FOF_NOCONFIRMATION | FileOperationFlags.FOF_WANTNUKEWARNING); } /// /// Send file silently to recycle bin. Surpress dialog, surpress errors, delete if too large. /// /// Location of directory or file to recycle public static bool MoveToRecycleBin (string path) { return Delete (path, FileOperationFlags.FOF_NOCONFIRMATION | FileOperationFlags.FOF_NOERRORUI | FileOperationFlags.FOF_SILENT); } } public class TemporaryFile : IDisposable { private string m_name; public string Name { get { return m_name; } } public TemporaryFile () { m_name = Path.GetRandomFileName(); } public TemporaryFile (string filename) { m_name = filename; } public TemporaryFile (string path, string filename) { m_name = Path.Combine (path, filename); } #region IDisposable Members bool disposed = false; public void Dispose () { Dispose (true); GC.SuppressFinalize (this); } protected virtual void Dispose (bool disposing) { if (!disposed) { if (disposing) { System.IO.File.Delete (m_name); } disposed = true; } } #endregion }; /// /// Wrapper around SHGetFileInfo WINAPI call. /// class FileInfo { [DllImport("shell32.dll", CharSet=CharSet.Auto)] public static extern IntPtr SHGetFileInfo( string pszPath, Int32 dwFileAttributes, ref SHFILEINFO psfi, int cbFileInfo, int uFlags); [DllImport("User32.dll")] public static extern int DestroyIcon(IntPtr hIcon); [StructLayout(LayoutKind.Sequential, CharSet=CharSet.Auto)] public struct SHFILEINFO { public IntPtr hIcon; public int iIcon; public uint dwAttributes; [MarshalAs(UnmanagedType.ByValTStr, SizeConst = 260)] public string szDisplayName; [MarshalAs(UnmanagedType.ByValTStr, SizeConst = 80)] public string szTypeName; public SHFILEINFO(bool b) { hIcon = IntPtr.Zero; iIcon = 0; dwAttributes = 0; szDisplayName = ""; szTypeName = ""; } }; [Flags] public enum SHGFI : uint { /// get icon Icon = 0x000000100, /// get display name DisplayName = 0x000000200, /// get type name TypeName = 0x000000400, /// get attributes Attributes = 0x000000800, /// get icon location IconLocation = 0x000001000, /// return exe type ExeType = 0x000002000, /// get system icon index SysIconIndex = 0x000004000, /// put a link overlay on icon LinkOverlay = 0x000008000, /// show icon in selected state Selected = 0x000010000, /// get only specified attributes Attr_Specified = 0x000020000, /// get large icon LargeIcon = 0x000000000, /// get small icon SmallIcon = 0x000000001, /// get open icon OpenIcon = 0x000000002, /// get shell size icon ShellIconSize = 0x000000004, /// pszPath is a pidl PIDL = 0x000000008, /// use passed dwFileAttribute UseFileAttributes= 0x000000010, /// apply the appropriate overlays AddOverlays = 0x000000020, /// Get the index of the overlay in the upper 8 bits of the iIcon OverlayIndex = 0x000000040, } public static string GetTypeName (string filename) { SHFILEINFO info = new SHFILEINFO(true); int szInfo = Marshal.SizeOf (info); int result = (int)SHGetFileInfo (filename, 0, ref info, szInfo, (int)SHGFI.TypeName); // If uFlags does not contain SHGFI_EXETYPE or SHGFI_SYSICONINDEX, // the return value is nonzero if successful, or zero otherwise. if (result != 0) return info.szTypeName; else return string.Empty; } public static SHFILEINFO? GetInfo (string filename, SHGFI flags) { SHFILEINFO info = new SHFILEINFO(true); int szInfo = Marshal.SizeOf (info); int result = (int)SHGetFileInfo (filename, 0, ref info, szInfo, (int)flags); return result != 0? new Nullable (info): null; } } }