source: trunk/eraser/Eraser.Util/Shell.cs @ 2057

Revision 2057, 8.0 KB checked in by lowjoel, 4 years ago (diff)

Implemented drag & drop from shell virtual folders (mainly the Recycle Bin)

  • Property svn:eol-style set to native
  • Property svn:keywords set to Id
Line 
1/*
2 * $Id$
3 * Copyright 2008-2010 The Eraser Project
4 * Original Author: Joel Low <lowjoel@users.sourceforge.net>
5 * Modified By:
6 *
7 * This file is part of Eraser.
8 *
9 * Eraser is free software: you can redistribute it and/or modify it under the
10 * terms of the GNU General Public License as published by the Free Software
11 * Foundation, either version 3 of the License, or (at your option) any later
12 * version.
13 *
14 * Eraser is distributed in the hope that it will be useful, but WITHOUT ANY
15 * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR
16 * A PARTICULAR PURPOSE. See the GNU General Public License for more details.
17 *
18 * A copy of the GNU General Public License can be found at
19 * <http://www.gnu.org/licenses/>.
20 */
21
22using System;
23using System.Collections.Generic;
24using System.Linq;
25using System.Text;
26
27using System.Runtime.InteropServices;
28using Microsoft.Win32;
29
30namespace Eraser.Util
31{
32    public static class Shell
33    {
34        /// <summary>
35        /// Gets or sets whether low disk space notifications are enabled for the
36        /// current user.
37        /// </summary>
38        public static bool LowDiskSpaceNotificationsEnabled
39        {
40            get
41            {
42                using (RegistryKey key = Registry.CurrentUser.OpenSubKey(
43                    "Software\\Microsoft\\Windows\\CurrentVersion\\Policies\\Explorer"))
44                {
45                    if (key == null)
46                        return true;
47                    return !Convert.ToBoolean(key.GetValue("NoLowDiskSpaceChecks", false));
48                }
49            }
50            set
51            {
52                RegistryKey key = null;
53                try
54                {
55                    key = Registry.CurrentUser.OpenSubKey(
56                        "Software\\Microsoft\\Windows\\CurrentVersion\\Policies\\Explorer", true);
57                    if (key == null)
58                        key = Registry.CurrentUser.CreateSubKey(
59                            "Software\\Microsoft\\Windows\\CurrentVersion\\Policies\\Explorer");
60                    key.SetValue("NoLowDiskSpaceChecks", !value);
61                }
62                finally
63                {
64                    if (key != null)
65                        key.Close();
66                }
67            }
68        }
69
70        /// <summary>
71        /// Parses the provided command line into its constituent arguments.
72        /// </summary>
73        /// <param name="commandLine">The command line to parse.</param>
74        /// <returns>The arguments specified in the command line</returns>
75        public static string[] ParseCommandLine(string commandLine)
76        {
77            int argc = 0;
78            IntPtr argv = NativeMethods.CommandLineToArgvW(commandLine, out argc);
79            string[] result = new string[argc];
80
81            //Get the pointers to the arguments, then read the string.
82            for (int i = 0; i < argc; ++i)
83                result[i] = Marshal.PtrToStringUni(Marshal.ReadIntPtr(argv, i * IntPtr.Size));
84
85            //Free the memory
86            NativeMethods.LocalFree(argv);
87
88            return result;
89        }
90
91        /// <summary>
92        /// A List of known folder IDs in the shell namespace.
93        /// </summary>
94        public static class KnownFolderIDs
95        {
96            /// <summary>
97            /// The Known Folder ID of the Recycle Bin
98            /// </summary>
99            public static readonly Guid RecycleBin = 
100                new Guid(0xB7534046, 0x3ECB, 0x4C18, 0xBE, 0x4E, 0x64, 0xCD, 0x4C, 0xB7, 0xD6, 0xAC);
101
102            /// <summary>
103            /// Gets the PIDL for the given Known folder ID.
104            /// </summary>
105            /// <param name="folderId">The known folder ID to query.</param>
106            /// <returns>The PIDL for the given folder.</returns>
107            public static ShellItemIDList GetShellItemIdList(Guid folderId)
108            {
109                Guid guid = folderId;
110                IntPtr pidl = IntPtr.Zero;
111                NativeMethods.SHGetKnownFolderIDList(ref guid, 0, IntPtr.Zero, out pidl);
112
113                try
114                {
115                    return new ShellItemIDList(pidl);
116                }
117                finally
118                {
119                    NativeMethods.ILFree(pidl);
120                }
121            }
122        }
123    }
124
125    /// <summary>
126    /// Retrieves the path of a known folder as an ITEMIDLIST structure.
127    /// </summary>
128    public class ShellCIDA
129    {
130        /// <summary>
131        /// Parses the given buffer for CIDA elements
132        /// </summary>
133        /// <param name="buffer"></param>
134        public ShellCIDA(byte[] buffer)
135        {
136            int offset = 0;
137            cidl = BitConverter.ToUInt32(buffer, offset);
138            aoffset = new ShellItemIDList[cidl + 1];
139
140            for (int i = 0; i < aoffset.Length; ++i)
141            {
142                int pidlOffset = BitConverter.ToInt32(buffer, offset += sizeof(int));
143
144                //Read the size of the IDL
145                aoffset[i] = new ShellItemIDList(buffer.Skip(pidlOffset).ToArray());
146            }
147        }
148
149        /// <summary>
150        /// The number of PIDLs that are being transferred, not including the parent folder.
151        /// </summary>
152        public uint cidl
153        {
154            get;
155            private set;
156        }
157
158        /// <summary>
159        /// The first element of aoffset contains the fully-qualified PIDL of a parent folder.
160        /// If this PIDL is empty, the parent folder is the desktop. Each of the remaining
161        /// elements of the array contains an offset to one of the PIDLs to be transferred.
162        /// All of these PIDLs are relative to the PIDL of the parent folder.
163        /// </summary>
164        public ShellItemIDList[] aoffset
165        {
166            get;
167            private set;
168        }
169    }
170
171    /// <summary>
172    /// Contains a list of item identifiers.
173    /// </summary>
174    public class ShellItemIDList
175    {
176        public ShellItemIDList(byte[] buffer)
177        {
178            mkid = new ShellItemID(buffer);
179        }
180
181        public ShellItemIDList(IntPtr buffer)
182        {
183            mkid = new ShellItemID(buffer);
184        }
185
186        public ShellItemID mkid
187        {
188            get;
189            private set;
190        }
191
192        /// <summary>
193        /// The physical path to the object referenced by this IDL.
194        /// </summary>
195        /// <remarks>If this IDL references a virtual object, this will return
196        /// null.</remarks>
197        public string Path
198        {
199            get
200            {
201                IntPtr mkid = this.mkid.ToSHITEMID();
202                try
203                {
204                    StringBuilder result = new StringBuilder(NativeMethods.MaxPath);
205                    if (NativeMethods.SHGetPathFromIDList(mkid, result))
206                        return result.ToString();
207                }
208                finally
209                {
210                    Marshal.FreeHGlobal(mkid);
211                }
212
213                return null;
214            }
215        }
216
217        /// <summary>
218        /// The GUID of the virtual folder referenced by this IDL.
219        /// </summary>
220        /// <remarks>If this IDL references a physical object, this will return
221        /// <see cref="Guid.Empty"/></remarks>
222        public Guid Guid
223        {
224            get
225            {
226                Guid[] guids = new Guid[] {
227                    Shell.KnownFolderIDs.RecycleBin
228                };
229
230                foreach (Guid guid in guids)
231                {
232                    if (Shell.KnownFolderIDs.GetShellItemIdList(guid) == this)
233                        return guid;
234                }
235
236                return Guid.Empty;
237            }
238        }
239
240        public static bool operator==(ShellItemIDList lhs, ShellItemIDList rhs)
241        {
242            return lhs.mkid == rhs.mkid;
243        }
244
245        public static bool operator!=(ShellItemIDList lhs, ShellItemIDList rhs)
246        {
247            return lhs.mkid != rhs.mkid;
248        }
249
250        public override bool Equals(object obj)
251        {
252            if (obj is ShellItemIDList)
253                return this == (ShellItemIDList)obj;
254            return this.Equals(obj);
255        }
256
257        public override int GetHashCode()
258        {
259            return base.GetHashCode();
260        }
261    }
262
263    /// <summary>
264    /// Defines an item identifier. (native type: SHITEMID)
265    /// </summary>
266    public class ShellItemID
267    {
268        public ShellItemID(byte[] buffer)
269        {
270            short cb = BitConverter.ToInt16(buffer, 0);
271            abID = new byte[cb];
272            if (cb > 0)
273                Buffer.BlockCopy(buffer, sizeof(short), abID, 0, cb - sizeof(short));
274        }
275
276        public ShellItemID(IntPtr buffer)
277        {
278            short cb = Marshal.ReadInt16(buffer);
279            abID = new byte[cb];
280            if (cb > 0)
281                Marshal.Copy(new IntPtr(buffer.ToInt64() + sizeof(short)), abID, 0, cb - sizeof(short));
282        }
283
284        byte[] abID;
285
286        /// <summary>
287        /// Converts this ShellItemID to the native SHITEMID.
288        /// </summary>
289        /// <returns>A Pointer to an unmanaged block of memory which should be
290        /// freed by Marshal.FreeHGlobal upon completion.</returns>
291        internal IntPtr ToSHITEMID()
292        {
293            //Allocate the buffer
294            IntPtr result = Marshal.AllocHGlobal(abID.Length + (abID.Length == 0 ? 0 : sizeof(short)));
295
296            //Write the size of the identifier
297            Marshal.WriteInt16(result, (short)abID.Length);
298
299            //Then copy the block of memory
300            Marshal.Copy(abID, 0, new IntPtr(result.ToInt64() + 2), abID.Length);
301            return result;
302        }
303
304        public static bool operator==(ShellItemID lhs, ShellItemID rhs)
305        {
306            return lhs.abID.SequenceEqual(rhs.abID);
307        }
308
309        public static bool operator!=(ShellItemID lhs, ShellItemID rhs)
310        {
311            return !lhs.abID.SequenceEqual(rhs.abID);
312        }
313
314        public override bool Equals(object obj)
315        {
316            if (obj is ShellItemID)
317                return this == (ShellItemID)obj;
318            return this.Equals(obj);
319        }
320
321        public override int GetHashCode()
322        {
323            return base.GetHashCode();
324        }
325    }
326}
Note: See TracBrowser for help on using the repository browser.