source: trunk/eraser/Eraser.Util/NativeMethods/Kernel.cs @ 2549

Revision 2549, 67.1 KB checked in by lowjoel, 3 years ago (diff)

Forward-port from Eraser 6.0: We need to recursively dereference all reparse points before we call GetVolumeNameForVolumeMountPoint?. This prevents a situation where we we get an invalid parameter error from GetVolumeNameForVolumeMountPoint? when we hand it a reparse point but it is not a volume reparse point.

Fixes bug in https://eraser.heidi.ie/forum/viewtopic.php?f=2&t=8684.

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Rev URL
Line 
1/*
2 * $Id$
3 * Copyright 2008-2012 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.Text;
25using System.Runtime.InteropServices;
26
27using System.Security.Permissions;
28using System.Runtime.ConstrainedExecution;
29using Microsoft.Win32.SafeHandles;
30
31namespace Eraser.Util
32{
33    /// <summary>
34    /// Stores Kernel32.dll functions, structs and constants.
35    /// </summary>
36    internal static partial class NativeMethods
37    {
38        /// <summary>
39        /// Copies an existing file to a new file, notifying the application of
40        /// its progress through a callback function.
41        /// </summary>
42        /// <param name="lpExistingFileName">The name of an existing file.
43        ///
44        /// In the ANSI version of this function, the name is limited to MAX_PATH
45        /// characters. To extend this limit to 32,767 wide characters, call the
46        /// ]Unicode version of the function and prepend "\\?\" to the path.
47        /// For more information, see Naming a File.
48        ///
49        /// If lpExistingFileName does not exist, the CopyFileEx function fails,
50        /// and the GetLastError function returns ERROR_FILE_NOT_FOUND.</param>
51        /// <param name="lpNewFileName">The name of the new file.
52        ///
53        /// In the ANSI version of this function, the name is limited to MAX_PATH
54        /// characters. To extend this limit to 32,767 wide characters, call the
55        /// Unicode version of the function and prepend "\\?\" to the path. For
56        /// more information, see Naming a File.</param>
57        /// <param name="lpProgressRoutine">The address of a callback function of
58        /// type <see cref="ExtensionMethods.IO.CopyProgressFunction"/> that is
59        /// called each time another portion of the file has been copied. This
60        /// parameter can be NULL. For more information on the progress callback
61        /// function, see the <see cref="ExtensionMethods.IO.CopyProgressFunction"/>
62        /// function.</param>
63        /// <param name="lpData">The argument to be passed to the callback function.
64        /// This parameter can be NULL.</param>
65        /// <param name="pbCancel">If this flag is set to TRUE during the copy
66        /// operation, the operation is canceled. Otherwise, the copy operation
67        /// will continue to completion.</param>
68        /// <param name="dwCopyFlags">Flags that specify how the file is to be
69        /// copied. This parameter can be a combination of the
70        /// <see cref="CopyFileFlags"/> enumeration.
71        /// </param>
72        /// <returns>If the function succeeds, the return value is nonzero.
73        ///
74        /// If the function fails, the return value is zero. To get extended error information
75        /// call <see cref="Marshal.GetLastWin32Error"/>.
76        ///
77        /// If lpProgressRoutine returns PROGRESS_CANCEL due to the user canceling the
78        /// operation, CopyFileEx will return zero and GetLastError will return
79        /// ERROR_REQUEST_ABORTED. In this case, the partially copied destination file is
80        /// deleted.
81        ///
82        /// If lpProgressRoutine returns PROGRESS_STOP due to the user stopping the
83        /// operation, CopyFileEx will return zero and GetLastError will return
84        /// ERROR_REQUEST_ABORTED. In this case, the partially copied destination file
85        /// is left intact.</returns>
86        [DllImport("Kernel32.dll", SetLastError = true)]
87        public static extern bool CopyFileEx(string lpExistingFileName,
88            string lpNewFileName, CopyProgressFunction lpProgressRoutine,
89            IntPtr lpData, ref bool pbCancel, CopyFileFlags dwCopyFlags);
90
91        /// <summary>
92        /// Flags used with <see cref="CopyFileEx"/>
93        /// </summary>
94        [Flags]
95        public enum CopyFileFlags
96        {
97            /// <summary>
98            /// An attempt to copy an encrypted file will succeed even if the
99            /// destination copy cannot be encrypted.
100            ///
101            /// Windows 2000: This value is not supported.
102            /// </summary>
103            AllowDecryptedDestination = 0x00000008,
104
105            /// <summary>
106            /// If the source file is a symbolic link, the destination file is
107            /// also a symbolic link pointing to the same file that the source
108            /// symbolic link is pointing to.
109            ///
110            /// Windows Server 2003 and Windows XP/2000: This value is not
111            /// supported.
112            /// </summary>
113            CopySymlink = 0x00000800,
114
115            /// <summary>
116            /// The copy operation fails immediately if the target file already
117            /// exists.
118            /// </summary>
119            FailIfExists = 0x00000001,
120
121            /// <summary>
122            /// The copy operation is performed using unbuffered I/O, bypassing
123            /// system I/O cache resources. Recommended for very large file
124            /// transfers.
125            ///
126            /// Windows Server 2003 and Windows XP/2000: This value is not
127            /// supported.
128            /// </summary>
129            NoBuffering = 0x00001000,
130
131            /// <summary>
132            /// The file is copied and the original file is opened for write
133            /// access.
134            /// </summary>
135            OpenSourceForWrite = 0x00000004,
136
137            /// <summary>
138            /// Progress of the copy is tracked in the target file in case the
139            /// copy fails. The failed copy can be restarted at a later time by
140            /// specifying the same values for lpExistingFileName and lpNewFileName
141            /// as those used in the call that failed.
142            /// </summary>
143            Restartable = 0x00000002
144        }
145
146        /// <summary>
147        /// An application-defined callback function used with the CopyFileEx,
148        /// MoveFileTransacted, and MoveFileWithProgress functions. It is called when
149        /// a portion of a copy or move operation is completed. The LPPROGRESS_ROUTINE
150        /// type defines a pointer to this callback function. CopyProgressRoutine is
151        /// a placeholder for the application-defined function name.
152        /// </summary>
153        /// <param name="TotalFileSize">The total size of the file, in bytes.</param>
154        /// <param name="TotalBytesTransferred">The total number of bytes
155        /// transferred from the source file to the destination file since the
156        /// copy operation began.</param>
157        /// <param name="StreamSize">The total size of the current file stream,
158        /// in bytes.</param>
159        /// <param name="StreamBytesTransferred">The total number of bytes in the
160        /// current stream that have been transferred from the source file to the
161        /// destination file since the copy operation began.</param>
162        /// <param name="dwStreamNumber">A handle to the current stream. The
163        /// first time CopyProgressRoutine is called, the stream number is 1.</param>
164        /// <param name="dwCallbackReason">The reason that CopyProgressRoutine was
165        /// called. This parameter can be one of the following values.</param>
166        /// <param name="hSourceFile">A handle to the source file.</param>
167        /// <param name="hDestinationFile">A handle to the destination file.</param>
168        /// <param name="lpData">Argument passed to CopyProgressRoutine by CopyFileEx,
169        /// MoveFileTransacted, or MoveFileWithProgress.</param>
170        /// <returns>The CopyProgressRoutine function should return one of the
171        /// <see cref="CopyProgressFunctionResult"/> values.</returns>
172        public delegate ExtensionMethods.Methods.CopyProgressFunctionResult
173            CopyProgressFunction(long TotalFileSize, long TotalBytesTransferred,
174            long StreamSize, long StreamBytesTransferred, uint dwStreamNumber,
175            CopyProgressFunctionCallbackReasons dwCallbackReason,
176            IntPtr hSourceFile, IntPtr hDestinationFile, IntPtr lpData);
177
178        /// <summary>
179        /// Callback reasons for the <see cref="CopyProgressFunction"/> callbacks.
180        /// </summary>
181        public enum CopyProgressFunctionCallbackReasons
182        {
183            /// <summary>
184            /// Another part of the data file was copied.
185            /// </summary>
186            ChunkFinished = 0x00000000,
187
188            /// <summary>
189            /// Another stream was created and is about to be copied. This is
190            /// the callback reason given when the callback routine is first invoked.
191            /// </summary>
192            StreamSwitch = 0x00000001
193        }
194
195        /// <summary>
196        /// Deletes an existing file.
197        /// </summary>
198        /// <param name="lpFileName">The name of the file to be deleted.
199        ///
200        /// In the ANSI version of this function, the name is limited to MAX_PATH
201        /// characters. To extend this limit to 32,767 wide characters, call
202        /// the Unicode version of the function and prepend "\\?\" to the path.
203        /// For more information, see Naming a File.</param>
204        /// <returns>If the function succeeds, the return value is nonzero.
205        ///
206        /// If the function fails, the return value is zero (0). To get extended
207        /// error information, call Marshal.GetLastWin32Error().</returns>
208        [DllImport("Kernel32.dll", SetLastError = true, CharSet = CharSet.Unicode)]
209        [return: MarshalAs(UnmanagedType.Bool)]
210        public static extern bool DeleteFile(string lpFileName);
211
212        /// <summary>
213        /// Retrieves information about the current system.
214        /// </summary>
215        /// <param name="lpSystemInfo">A pointer to a SYSTEM_INFO structure that
216        /// receives the information.</param>
217        [DllImport("Kernel32.dll")]
218        public static extern void GetSystemInfo(out SYSTEM_INFO lpSystemInfo);
219
220        /// <summary>
221        /// The QueryPerformanceCounter function retrieves the current value of
222        /// the high-resolution performance counter.
223        /// </summary>
224        /// <param name="lpPerformanceCount">[out] Pointer to a variable that receives
225        /// the current performance-counter value, in counts.</param>
226        /// <returns>If the function succeeds, the return value is nonzero.
227        ///
228        /// If the function fails, the return value is zero. To get extended error
229        /// information, call Marshal.GetLastWin32Error. </returns>
230        [DllImport("Kernel32.dll", SetLastError = true)]
231        [return: MarshalAs(UnmanagedType.Bool)]
232        public static extern bool QueryPerformanceCounter(out long lpPerformanceCount);
233
234        /// <summary>
235        /// Contains information about the current computer system. This includes
236        /// the architecture and type of the processor, the number of processors
237        /// in the system, the page size, and other such information.
238        /// </summary>
239        [StructLayout(LayoutKind.Sequential)]
240        internal struct SYSTEM_INFO
241        {
242            /// <summary>
243            /// Represents a list of processor architectures.
244            /// </summary>
245            public enum ProcessorArchitecture : ushort
246            {
247                /// <summary>
248                /// x64 (AMD or Intel).
249                /// </summary>
250                PROCESSOR_ARCHITECTURE_AMD64 = 9,
251
252                /// <summary>
253                /// Intel Itanium Processor Family (IPF).
254                /// </summary>
255                PROCESSOR_ARCHITECTURE_IA64 = 6,
256
257                /// <summary>
258                /// x86.
259                /// </summary>
260                PROCESSOR_ARCHITECTURE_INTEL = 0,
261
262                /// <summary>
263                /// Unknown architecture.
264                /// </summary>
265                PROCESSOR_ARCHITECTURE_UNKNOWN = 0xffff
266            }
267
268            /// <summary>
269            /// The processor architecture of the installed operating system.
270            /// This member can be one of the ProcessorArchitecture values.
271            /// </summary>
272            public ProcessorArchitecture processorArchitecture;
273
274            /// <summary>
275            /// This member is reserved for future use.
276            /// </summary>
277            private const ushort reserved = 0;
278
279            /// <summary>
280            /// The page size and the granularity of page protection and commitment.
281            /// This is the page size used by the VirtualAlloc function.
282            /// </summary>
283            public uint pageSize;
284
285            /// <summary>
286            /// A pointer to the lowest memory address accessible to applications
287            /// and dynamic-link libraries (DLLs).
288            /// </summary>
289            public IntPtr minimumApplicationAddress;
290
291            /// <summary>
292            /// A pointer to the highest memory address accessible to applications
293            /// and DLLs.
294            /// </summary>
295            public IntPtr maximumApplicationAddress;
296
297            /// <summary>
298            /// A mask representing the set of processors configured into the system.
299            /// Bit 0 is processor 0; bit 31 is processor 31.
300            /// </summary>
301            public IntPtr activeProcessorMask;
302
303            /// <summary>
304            /// The number of processors in the system.
305            /// </summary>
306            public uint numberOfProcessors;
307
308            /// <summary>
309            /// An obsolete member that is retained for compatibility. Use the
310            /// wProcessorArchitecture, wProcessorLevel, and wProcessorRevision
311            /// members to determine the type of processor.
312            /// Name                        Value
313            /// PROCESSOR_INTEL_386         386
314            /// PROCESSOR_INTEL_486         486
315            /// PROCESSOR_INTEL_PENTIUM     586
316            /// PROCESSOR_INTEL_IA64        2200
317            /// PROCESSOR_AMD_X8664         8664
318            /// </summary>
319            public uint processorType;
320
321            /// <summary>
322            /// The granularity for the starting address at which virtual memory
323            /// can be allocated. For more information, see VirtualAlloc.
324            /// </summary>
325            public uint allocationGranularity;
326
327            /// <summary>
328            /// The architecture-dependent processor level. It should be used only
329            /// for display purposes. To determine the feature set of a processor,
330            /// use the IsProcessorFeaturePresent function.
331            ///
332            /// If wProcessorArchitecture is PROCESSOR_ARCHITECTURE_INTEL, wProcessorLevel
333            /// is defined by the CPU vendor.
334            /// If wProcessorArchitecture is PROCESSOR_ARCHITECTURE_IA64, wProcessorLevel
335            /// is set to 1.
336            /// </summary>
337            public ushort processorLevel;
338
339            /// <summary>
340            /// The architecture-dependent processor revision. The following table
341            /// shows how the revision value is assembled for each type of
342            /// processor architecture.
343            ///
344            /// Processor                   Value
345            /// Intel Pentium, Cyrix        The high byte is the model and the
346            /// or NextGen 586              low byte is the stepping. For example,
347            ///                             if the value is xxyy, the model number
348            ///                             and stepping can be displayed as follows:
349            ///                             Model xx, Stepping yy
350            /// Intel 80386 or 80486        A value of the form xxyz.
351            ///                             If xx is equal to 0xFF, y - 0xA is the model
352            ///                             number, and z is the stepping identifier.
353            ///
354            ///                             If xx is not equal to 0xFF, xx + 'A'
355            ///                             is the stepping letter and yz is the minor stepping.
356            /// </summary>
357            public ushort processorRevision;
358        }
359
360        [DllImport("Kernel32.dll")]
361        public static extern EXECUTION_STATE SetThreadExecutionState(EXECUTION_STATE esFlags);
362
363        [Flags]
364        public enum EXECUTION_STATE : uint
365        {
366            ES_AWAYMODE_REQUIRED = 0x00000040,
367            ES_CONTINUOUS = 0x80000000,
368            ES_DISPLAY_REQUIRED = 0x00000002,
369            ES_SYSTEM_REQUIRED = 0x00000001,
370            ES_USER_PRESENT = 0x00000004
371        }
372
373        /// <summary>
374        /// Allocates a new console for the calling process.
375        /// </summary>
376        /// <returns>If the function succeeds, the return value is nonzero.
377        ///
378        /// If the function fails, the return value is zero. To get extended error
379        /// information, call Marshal.GetLastWin32Error.</returns>
380        /// <remarks>A process can be associated with only one console, so the AllocConsole
381        /// function fails if the calling process already has a console. A process can
382        /// use the FreeConsole function to detach itself from its current console, then
383        /// it can call AllocConsole to create a new console or AttachConsole to attach
384        /// to another console.
385        ///
386        /// If the calling process creates a child process, the child inherits the
387        /// new console.
388        ///
389        /// AllocConsole initializes standard input, standard output, and standard error
390        /// handles for the new console. The standard input handle is a handle to the
391        /// console's input buffer, and the standard output and standard error handles
392        /// are handles to the console's screen buffer. To retrieve these handles, use
393        /// the GetStdHandle function.
394        ///
395        /// This function is primarily used by graphical user interface (GUI) application
396        /// to create a console window. GUI applications are initialized without a
397        /// console. Console applications are initialized with a console, unless they
398        /// are created as detached processes (by calling the CreateProcess function
399        /// with the DETACHED_PROCESS flag).</remarks>
400        [DllImport("Kernel32.dll", SetLastError = true)]
401        [return: MarshalAs(UnmanagedType.Bool)]
402        public static extern bool AllocConsole();
403
404        /// <summary>
405        /// Detaches the calling process from its console.
406        /// </summary>
407        /// <returns>If the function succeeds, the return value is nonzero.
408        ///
409        /// If the function fails, the return value is zero. To get extended error
410        /// information, call Marshal.GetLastWin32Error.</returns>
411        /// <remarks>A process can be attached to at most one console. If the calling
412        /// process is not already attached to a console, the error code returned is
413        /// ERROR_INVALID_PARAMETER (87).
414        ///
415        /// A process can use the FreeConsole function to detach itself from its
416        /// console. If other processes share the console, the console is not destroyed,
417        /// but the process that called FreeConsole cannot refer to it. A console is
418        /// closed when the last process attached to it terminates or calls FreeConsole.
419        /// After a process calls FreeConsole, it can call the AllocConsole function to
420        /// create a new console or AttachConsole to attach to another console.</remarks>
421        [DllImport("Kernel32.dll", SetLastError = true)]
422        [return: MarshalAs(UnmanagedType.Bool)]
423        public static extern bool FreeConsole();
424
425        /// <summary>
426        /// The CreateFile function creates or opens a file, file stream, directory,
427        /// physical disk, volume, console buffer, tape drive, communications resource,
428        /// mailslot, or named pipe. The function returns a handle that can be used
429        /// to access an object.
430        /// </summary>
431        /// <param name="FileName"></param>
432        /// <param name="DesiredAccess"> access to the object, which can be read,
433        /// write, or both</param>
434        /// <param name="ShareMode">The sharing mode of an object, which can be
435        /// read, write, both, or none</param>
436        /// <param name="SecurityAttributes">A pointer to a SECURITY_ATTRIBUTES
437        /// structure that determines whether or not the returned handle can be
438        /// inherited by child processes. Can be null</param>
439        /// <param name="CreationDisposition">An action to take on files that exist
440        /// and do not exist</param>
441        /// <param name="FlagsAndAttributes">The file attributes and flags.</param>
442        /// <param name="hTemplateFile">A handle to a template file with the
443        /// GENERIC_READ access right. The template file supplies file attributes
444        /// and extended attributes for the file that is being created. This
445        /// parameter can be null</param>
446        /// <returns>If the function succeeds, the return value is an open handle
447        /// to a specified file. If a specified file exists before the function
448        /// all and dwCreationDisposition is CREATE_ALWAYS or OPEN_ALWAYS, a call
449        /// to GetLastError returns ERROR_ALREADY_EXISTS, even when the function
450        /// succeeds. If a file does not exist before the call, GetLastError
451        /// returns 0.
452        ///
453        /// If the function fails, the return value is INVALID_HANDLE_VALUE.
454        /// To get extended error information, call Marshal.GetLastWin32Error().</returns>
455        [DllImport("Kernel32.dll", SetLastError = true, CharSet = CharSet.Unicode)]
456        public static extern SafeFileHandle CreateFile(string lpFileName, uint dwDesiredAccess,
457            uint dwShareMode, IntPtr SecurityAttributes, uint dwCreationDisposition,
458            uint dwFlagsAndAttributes, IntPtr hTemplateFile);
459
460        public const uint FILE_READ_ATTRIBUTES = 0x0080;
461        public const uint FILE_WRITE_ATTRIBUTES = 0x0100;
462        public const uint GENERIC_READ = 0x80000000;
463        public const uint GENERIC_WRITE = 0x40000000;
464        public const uint GENERIC_EXECUTE = 0x20000000;
465        public const uint GENERIC_ALL = 0x10000000;
466
467        public const uint FILE_SHARE_READ = 0x00000001;
468        public const uint FILE_SHARE_WRITE = 0x00000002;
469        public const uint FILE_SHARE_DELETE = 0x00000004;
470
471        public const uint CREATE_NEW = 1;
472        public const uint CREATE_ALWAYS = 2;
473        public const uint OPEN_EXISTING = 3;
474        public const uint OPEN_ALWAYS = 4;
475        public const uint TRUNCATE_EXISTING = 5;
476
477        public const uint FILE_FLAG_WRITE_THROUGH = 0x80000000;
478        public const uint FILE_FLAG_OVERLAPPED = 0x40000000;
479        public const uint FILE_FLAG_NO_BUFFERING = 0x20000000;
480        public const uint FILE_FLAG_RANDOM_ACCESS = 0x10000000;
481        public const uint FILE_FLAG_SEQUENTIAL_SCAN = 0x08000000;
482        public const uint FILE_FLAG_DELETE_ON_CLOSE = 0x04000000;
483        public const uint FILE_FLAG_BACKUP_SEMANTICS = 0x02000000;
484        public const uint FILE_FLAG_POSIX_SEMANTICS = 0x01000000;
485        public const uint FILE_FLAG_OPEN_REPARSE_POINT = 0x00200000;
486        public const uint FILE_FLAG_OPEN_NO_RECALL = 0x00100000;
487        public const uint FILE_FLAG_FIRST_PIPE_INSTANCE = 0x00080000;
488
489        /// <summary>
490        /// Defines, redefines, or deletes MS-DOS device names.
491        /// </summary>
492        /// <param name="dwFlags">The controllable aspects of the DefineDosDevice function. This
493        /// parameter can be one or more of the DosDeviceDefineFlags.</param>
494        /// <param name="lpDeviceName">A pointer to an MS-DOS device name string specifying the
495        /// device the function is defining, redefining, or deleting. The device name string must
496        /// not have a colon as the last character, unless a drive letter is being defined,
497        /// redefined, or deleted. For example, drive C would be the string "C:". In no case is
498        /// a trailing backslash ("\") allowed.</param>
499        /// <param name="lpTargetPath">A pointer to a path string that will implement this
500        /// device. The string is an MS-DOS path string unless the DDD_RAW_TARGET_PATH flag
501        /// is specified, in which case this string is a path string.</param>
502        /// <returns>If the function succeeds, the return value is true.
503        ///
504        /// If the function fails, the return value is zero. To get extended error
505        /// information, call Marshal.GetLastWin32Error.</returns>
506        [DllImport("Kernel32.dll", SetLastError = true)]
507        [return: MarshalAs(UnmanagedType.Bool)]
508        public extern static bool DefineDosDevice(DosDeviceDefineFlags dwFlags,
509            string lpDeviceName, string lpTargetPath);
510
511        [Flags]
512        public enum DosDeviceDefineFlags
513        {
514            /// <summary>
515            /// If this value is specified along with DDD_REMOVE_DEFINITION, the function will
516            /// use an exact match to determine which mapping to remove. Use this value to
517            /// ensure that you do not delete something that you did not define.
518            /// </summary>
519            ExactMatchOnRmove = 0x00000004,
520
521            /// <summary>
522            /// Do not broadcast the WM_SETTINGCHANGE message. By default, this message is
523            /// broadcast to notify the shell and applications of the change.
524            /// </summary>
525            NoBroadcastSystem = 0x00000008,
526
527            /// <summary>
528            /// Uses the lpTargetPath string as is. Otherwise, it is converted from an MS-DOS
529            /// path to a path.
530            /// </summary>
531            RawTargetPath = 0x00000001,
532
533            /// <summary>
534            /// Removes the specified definition for the specified device. To determine which
535            /// definition to remove, the function walks the list of mappings for the device,
536            /// looking for a match of lpTargetPath against a prefix of each mapping associated
537            /// with this device. The first mapping that matches is the one removed, and then
538            /// the function returns.
539            ///
540            /// If lpTargetPath is NULL or a pointer to a NULL string, the function will remove
541            /// the first mapping associated with the device and pop the most recent one pushed.
542            /// If there is nothing left to pop, the device name will be removed.
543            ///
544            /// If this value is not specified, the string pointed to by the lpTargetPath
545            /// parameter will become the new mapping for this device.
546            /// </summary>
547            RemoveDefinition = 0x00000002
548        }
549
550        /// <summary>
551        /// Retrieves information about MS-DOS device names. The function can obtain the
552        /// current mapping for a particular MS-DOS device name. The function can also obtain
553        /// a list of all existing MS-DOS device names.
554        ///
555        /// MS-DOS device names are stored as junctions in the object name space. The code
556        /// that converts an MS-DOS path into a corresponding path uses these junctions to
557        /// map MS-DOS devices and drive letters. The QueryDosDevice function enables an
558        /// application to query the names of the junctions used to implement the MS-DOS
559        /// device namespace as well as the value of each specific junction.
560        /// </summary>
561        /// <param name="lpDeviceName">An MS-DOS device name string specifying the target of
562        /// the query. The device name cannot have a trailing backslash; for example,
563        /// use "C:", not "C:\".
564        ///
565        /// This parameter can be NULL. In that case, the QueryDosDevice function will
566        /// store a list of all existing MS-DOS device names into the buffer pointed to
567        /// by lpTargetPath.</param>
568        /// <param name="lpTargetPath">A pointer to a buffer that will receive the result
569        /// of the query. The function fills this buffer with one or more null-terminated
570        /// strings. The final null-terminated string is followed by an additional NULL.
571        ///
572        /// If lpDeviceName is non-NULL, the function retrieves information about the
573        /// particular MS-DOS device specified by lpDeviceName. The first null-terminated
574        /// string stored into the buffer is the current mapping for the device. The other
575        /// null-terminated strings represent undeleted prior mappings for the device.
576        ///
577        /// If lpDeviceName is NULL, the function retrieves a list of all existing MS-DOS
578        /// device names. Each null-terminated string stored into the buffer is the name
579        /// of an existing MS-DOS device, for example, \Device\HarddiskVolume1 or
580        /// \Device\Floppy0.</param>
581        /// <param name="length">The maximum number of TCHARs that can be stored into
582        /// the buffer pointed to by lpTargetPath.</param>
583        /// <returns>If the function succeeds, the return value is the number of TCHARs
584        /// stored into the buffer pointed to by lpTargetPath.
585        ///
586        /// If the function fails, the return value is zero. To get extended error
587        /// information, call Marshal.GetLastWin32Error.
588        ///
589        /// If the buffer is too small, the function fails and the last error code is
590        /// ERROR_INSUFFICIENT_BUFFER.</returns>
591        [DllImport("Kernel32.dll", SetLastError = true)]
592        private static extern uint QueryDosDevice([Optional] string lpDeviceName,
593            [MarshalAs(UnmanagedType.LPArray, SizeParamIndex = 2)] [Out] char[] lpTargetPath, int length);
594
595        private static string[] QueryDosDeviceInternal(string lpDeviceName)
596        {
597            char[] buffer = new char[32768];
598            for ( ; ; buffer = new char[buffer.Length * 2])
599            {
600                uint written = NativeMethods.QueryDosDevice(lpDeviceName, buffer, buffer.Length);
601
602                //Do we have enough space for all the text
603                if (written != 0)
604                    return ParseNullDelimitedArray(buffer, (int)written);
605                else if (Marshal.GetLastWin32Error() == Win32ErrorCode.InsufficientBuffer)
606                    continue;
607                else
608                    throw Win32ErrorCode.GetExceptionForWin32Error(Marshal.GetLastWin32Error());
609            }
610        }
611
612        public static string QueryDosDevice(string lpDeviceName)
613        {
614            string[] result = QueryDosDeviceInternal(lpDeviceName);
615            return result.Length == 0 ? null : result[0];
616        }
617
618        public static string[] QueryDosDevices()
619        {
620            return QueryDosDeviceInternal(null);
621        }
622
623        [DllImport("Kernel32.dll", SetLastError = true)]
624        [return: MarshalAs(UnmanagedType.Bool)]
625        public extern static bool DeviceIoControl(SafeFileHandle hDevice,
626            uint dwIoControlCode, IntPtr lpInBuffer, uint nInBufferSize,
627            out ushort lpOutBuffer, uint nOutBufferSize, out uint lpBytesReturned,
628            IntPtr lpOverlapped);
629
630        [DllImport("Kernel32.dll", SetLastError = true)]
631        [return: MarshalAs(UnmanagedType.Bool)]
632        public extern static bool DeviceIoControl(SafeFileHandle hDevice,
633            uint dwIoControlCode, ref ushort lpInBuffer, uint nInBufferSize,
634            IntPtr lpOutBuffer, uint nOutBufferSize, out uint lpBytesReturned,
635            IntPtr lpOverlapped);
636
637        public const uint FSCTL_GET_COMPRESSION = 0x9003C;
638        public const uint FSCTL_SET_COMPRESSION = 0x9C040;
639        public const ushort COMPRESSION_FORMAT_NONE = 0x0000;
640        public const ushort COMPRESSION_FORMAT_DEFAULT = 0x0001;
641
642        [DllImport("Kernel32.dll", SetLastError = true)]
643        [return: MarshalAs(UnmanagedType.Bool)]
644        public extern static bool DeviceIoControl(SafeFileHandle hDevice,
645            uint dwIoControlCode, IntPtr lpInBuffer, uint nInBufferSize,
646            IntPtr lpOutBuffer, uint nOutBufferSize, out uint lpBytesReturned,
647            IntPtr lpOverlapped);
648
649        public const uint FSCTL_LOCK_VOLUME = 0x90018;
650        public const uint FSCTL_UNLOCK_VOLUME = 0x9001C;
651
652        [DllImport("Kernel32.dll", CharSet = CharSet.Unicode, SetLastError = true)]
653        [return: MarshalAs(UnmanagedType.Bool)]
654        public extern static bool DeviceIoControl(SafeFileHandle hDevice,
655            uint dwIoControlCode, IntPtr lpInBuffer, uint nInBufferSize,
656            out NTFS_VOLUME_DATA_BUFFER lpOutBuffer, uint nOutBufferSize,
657            out uint lpBytesReturned, IntPtr lpOverlapped);
658
659        /// <summary>
660        /// Retrieves information about the specified NTFS file system volume.
661        /// </summary>
662        public const int FSCTL_GET_NTFS_VOLUME_DATA = (9 << 16) | (25 << 2);
663
664        /// <summary>
665        /// Removes the boot signature from the master boot record, so that the disk will
666        /// be formatted from sector zero to the end of the disk. Partition information
667        /// is no longer stored in sector zero.
668        /// </summary>
669        public const uint IOCTL_DISK_DELETE_DRIVE_LAYOUT =
670            (0x00000007 << 16) | ((0x01 | 0x02) << 14) | (0x0040 << 2);
671
672        [DllImport("Kernel32.dll", SetLastError = true)]
673        [return: MarshalAs(UnmanagedType.Bool)]
674        public extern static bool DeviceIoControl(SafeFileHandle hDevice,
675            uint dwIoControlCode, IntPtr lpInBuffer, uint nInBufferSize,
676            out DiskPerformanceInfoInternal lpOutBuffer, uint nOutBufferSize,
677            out uint lpBytesReturned, IntPtr lpOverlapped);
678
679        public const uint IOCTL_DISK_PERFORMANCE = ((0x00000007) << 16) | ((0x0008) << 2);
680
681        [StructLayout(LayoutKind.Sequential, CharSet = CharSet.Unicode)]
682        public struct DiskPerformanceInfoInternal
683        {
684            public long BytesRead;
685            public long BytesWritten;
686            public long ReadTime;
687            public long WriteTime;
688            public long IdleTime;
689            public uint ReadCount;
690            public uint WriteCount;
691            public uint QueueDepth;
692            public uint SplitCount;
693            public long QueryTime;
694            public uint StorageDeviceNumber;
695
696            [MarshalAs(UnmanagedType.ByValTStr, SizeConst = 8)]
697            public string StorageManagerName;
698        }
699
700        [DllImport("Kernel32.dll", SetLastError = true)]
701        [return: MarshalAs(UnmanagedType.Bool)]
702        public extern static bool DeviceIoControl(SafeFileHandle hDevice,
703            uint dwIoControlCode, IntPtr lpInBuffer, uint nInBufferSize,
704            out long lpOutBuffer, uint nOutBufferSize, out uint lpBytesReturned,
705            IntPtr lpOverlapped);
706
707        /// <summary>
708        /// Retrieves the length of the specified disk, volume, or partition.
709        /// </summary>
710        public const int IOCTL_DISK_GET_LENGTH_INFO =
711            (0x00000007 << 16) | (0x0001 << 14) | (0x0017 << 2);
712
713        /// <summary>
714        /// Retrieves the physical location of a specified volume on one or more disks.
715        /// </summary>
716        public const int IOCTL_VOLUME_GET_VOLUME_DISK_EXTENTS =
717            ((0x00000056) << 16) | ((0) << 14) | ((0) << 2) | (0);
718
719        /// <summary>
720        /// Represents a physical location on a disk.
721        /// </summary>
722        [StructLayout(LayoutKind.Sequential, CharSet = CharSet.Unicode)]
723        public struct VOLUME_DISK_EXTENTS
724        {
725            /// <summary>
726            /// The number of disks in the volume (a volume can span multiple disks).
727            ///
728            /// An extent is a contiguous run of sectors on one disk. When the number
729            /// of extents returned is greater than one (1), the error code
730            /// ERROR_MORE_DATA is returned. You should call DeviceIoControl again,
731            /// allocating enough buffer space based on the value of NumberOfDiskExtents
732            /// after the first DeviceIoControl call.
733            /// </summary>
734            public uint NumberOfDiskExtents;
735
736            /// <summary>
737            /// The first extent in the set. Subsequent extents are found after this
738            /// structure.
739            /// </summary>
740            public DISK_EXTENT Extent;
741        }
742
743        /// <summary>
744        /// Represents a disk extent.
745        /// </summary>
746        [StructLayout(LayoutKind.Sequential, CharSet = CharSet.Unicode)]
747        public struct DISK_EXTENT
748        {
749            /// <summary>
750            /// The number of the disk that contains this extent.
751            ///
752            /// This is the same number that is used to construct the name of the disk,
753            /// for example, the X in PhysicalDriveX or HarddiskX.
754            /// </summary>
755            public uint DiskNumber;
756
757            /// <summary>
758            /// The offset from the beginning of the disk to the extent, in bytes.
759            /// </summary>
760            public long StartingOffset;
761
762            /// <summary>
763            /// The number of bytes in this extent.
764            /// </summary>
765            public long ExtentLength;
766        }
767
768        public const uint FSCTL_GET_REPARSE_POINT = (9 << 16) | (42 << 2);
769
770        /// <summary>
771        /// The REPARSE_DATA_BUFFER structure contains reparse point data for a
772        /// Microsoft reparse point. (Third-party reparse point owners must use
773        /// the REPARSE_GUID_DATA_BUFFER structure instead.)
774        /// </summary>
775        [StructLayout(LayoutKind.Sequential, CharSet = CharSet.Unicode)]
776        public struct REPARSE_DATA_BUFFER
777        {
778            /// <summary>
779            /// Contains the reparse point information for a Symbolic Link.
780            /// </summary>
781            /// <remarks>The PathBuffer member found at the end of the C structure
782            /// declaration is appended at the end of this structure.</remarks>
783            [StructLayout(LayoutKind.Sequential, CharSet = CharSet.Unicode)]
784            public struct SymbolicLinkReparseBuffer
785            {
786                /// <summary>
787                /// Offset, in bytes, of the substitute name string in the PathBuffer
788                /// array. Note that this offset must be divided by sizeof(char) to
789                /// get the array index.
790                /// </summary>
791                public ushort SubstituteNameOffset;
792
793                /// <summary>
794                /// Length, in bytes, of the substitute name string. If this string is
795                /// NULL-terminated, SubstituteNameLength does not include space for
796                /// the UNICODE_NULL character.
797                /// </summary>
798                public ushort SubstituteNameLength;
799
800                /// <summary>
801                /// Offset, in bytes, of the print name string in the PathBuffer array.
802                /// Note that this offset must be divided by sizeof(char) to get the
803                /// array index.
804                /// </summary>
805                public ushort PrintNameOffset;
806
807                /// <summary>
808                /// Length, in bytes, of the print name string. If this string is
809                /// NULL-terminated, PrintNameLength does not include space for the
810                /// UNICODE_NULL character.
811                /// </summary>
812                public ushort PrintNameLength;
813
814                /// <summary>
815                /// Used to indicate if the given symbolic link is an absolute or relative
816                /// symbolic link. If Flags contains SYMLINK_FLAG_RELATIVE, the symbolic
817                /// link contained in the PathBuffer array (at offset SubstitueNameOffset)
818                /// is processed as a relative symbolic link; otherwise, it is processed
819                /// as an absolute symbolic link.
820                /// </summary>
821                public SymbolicLinkFlags Flags;
822            }
823
824            /// <summary>
825            /// Contains the reparse point information for a Directory Junction.
826            /// </summary>
827            /// <remarks>The PathBuffer member found at the end of the C structure
828            /// declaration is appended at the end of this structure.</remarks>
829            [StructLayout(LayoutKind.Sequential, CharSet = CharSet.Unicode)]
830            public struct MountPointReparseBuffer
831            {
832                /// <summary>
833                /// Offset, in bytes, of the substitute name string in the PathBuffer
834                /// array. Note that this offset must be divided by sizeof(char) to
835                /// get the array index.
836                /// </summary>
837                public ushort SubstituteNameOffset;
838
839                /// <summary>
840                /// Length, in bytes, of the substitute name string. If this string is
841                /// NULL-terminated, SubstituteNameLength does not include space for
842                /// the UNICODE_NULL character.
843                /// </summary>
844                public ushort SubstituteNameLength;
845
846                /// <summary>
847                /// Offset, in bytes, of the print name string in the PathBuffer array.
848                /// Note that this offset must be divided by sizeof(char) to get the
849                /// array index.
850                /// </summary>
851                public ushort PrintNameOffset;
852
853                /// <summary>
854                /// Length, in bytes, of the print name string. If this string is
855                /// NULL-terminated, PrintNameLength does not include space for the
856                /// UNICODE_NULL character.
857                /// </summary>
858                public ushort PrintNameLength;
859            }
860
861            [Flags]
862            public enum SymbolicLinkFlags
863            {
864                /// <summary>
865                /// <see cref="SymbolicLinkReparseBuffer.Flags"/>
866                /// </summary>
867                SYMLINK_FLAG_RELATIVE = 0x00000001
868            }
869
870            /// <summary>
871            /// Reparse point tag. Must be a Microsoft reparse point tag. (See the following Remarks section.)
872            /// </summary>
873            public REPARSE_DATA_TAG ReparseTag;
874
875            /// <summary>
876            /// Size, in bytes, of the reparse data in the DataBuffer member.
877            /// </summary>
878            public ushort ReparseDataLength;
879            ushort Reserved;
880        }
881
882        /// <summary>
883        /// See http://msdn.microsoft.com/en-us/library/windows/desktop/aa365511%28v=vs.85%29.aspx.
884        /// </summary>
885        public enum REPARSE_DATA_TAG : uint
886        {
887            IO_REPARSE_TAG_MOUNT_POINT = 0xA0000003,
888            IO_REPARSE_TAG_HSM = 0xC0000004,
889            IO_REPARSE_TAG_HSM2 = 0x80000006,
890            IO_REPARSE_TAG_SIS = 0x80000007,
891            IO_REPARSE_TAG_WIM = 0x80000008,
892            IO_REPARSE_TAG_CSV = 0x80000009,
893            IO_REPARSE_TAG_DFS = 0x8000000A,
894            IO_REPARSE_TAG_SYMLINK = 0xA000000C,
895            IO_REPARSE_TAG_DFSR = 0x80000012
896        }
897
898        /// <summary>
899        /// Retrieves a set of FAT file system attributes for a specified file or
900        /// directory.
901        /// </summary>
902        /// <param name="lpFileName">The name of the file or directory.</param>
903        /// <returns>If the function succeeds, the return value contains the attributes
904        /// of the specified file or directory.
905        ///
906        /// If the function fails, the return value is INVALID_FILE_ATTRIBUTES.
907        /// To get extended error information, call Marshal.GetLastWin32Error.
908        ///
909        /// The attributes can be one or more of the FILE_ATTRIBUTE_* values.</returns>
910        [DllImport("Kernel32.dll", SetLastError = true, CharSet = CharSet.Unicode)]
911        public static extern uint GetFileAttributes(string lpFileName);
912
913        /// <summary>
914        /// Sets the attributes for a file or directory.
915        /// </summary>
916        /// <param name="lpFileName">The name of the file whose attributes are
917        /// to be set.</param>
918        /// <param name="dwFileAttributes">The file attributes to set for the file.
919        /// This parameter can be one or more of the FILE_ATTRIBUTE_* values.
920        /// However, all other values override FILE_ATTRIBUTE_NORMAL.</param>
921        /// <returns>If the function succeeds, the return value is nonzero.
922        ///
923        /// If the function fails, the return value is zero. To get extended error
924        /// information, call Marshal.GetLastWin32Error.</returns>
925        [System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Usage", "CA2205:UseManagedEquivalentsOfWin32Api")]
926        [DllImport("Kernel32.dll", SetLastError = true, CharSet = CharSet.Unicode)]
927        [return: MarshalAs(UnmanagedType.Bool)]
928        public static extern bool SetFileAttributes(string lpFileName,
929            uint dwFileAttributes);
930
931        /// <summary>
932        /// Retrieves the size of the specified file.
933        /// </summary>
934        /// <param name="hFile">A handle to the file. The handle must have been
935        /// created with either the GENERIC_READ or GENERIC_WRITE access right.
936        /// For more information, see File Security and Access Rights.</param>
937        /// <param name="lpFileSize">A reference to a long that receives the file
938        /// size, in bytes.</param>
939        /// <returns>If the function succeeds, the return value is nonzero.
940        ///
941        /// If the function fails, the return value is zero. To get extended error
942        /// information, call Marshal.GetLastWin32Error.</returns>
943        [DllImport("Kernel32.dll", SetLastError = true)]
944        [return: MarshalAs(UnmanagedType.Bool)]
945        public static extern bool GetFileSizeEx(SafeFileHandle hFile, out long lpFileSize);
946
947        /// <summary>
948        /// Retrieves the date and time that a file or directory was created, last
949        /// accessed, and last modified.
950        /// </summary>
951        /// <param name="hFile">A handle to the file or directory for which dates
952        /// and times are to be retrieved. The handle must have been created using
953        /// the CreateFile function with the GENERIC_READ access right. For more
954        /// information, see File Security and Access Rights.</param>
955        /// <param name="lpCreationTime">A pointer to a FILETIME structure to
956        /// receive the date and time the file or directory was created. This
957        /// parameter can be NULL if the application does not require this
958        /// information.</param>
959        /// <param name="lpLastAccessTime">A pointer to a FILETIME structure to
960        /// receive the date and time the file or directory was last accessed. The
961        /// last access time includes the last time the file or directory was
962        /// written to, read from, or, in the case of executable files, run. This
963        /// parameter can be NULL if the application does not require this
964        /// information.</param>
965        /// <param name="lpLastWriteTime">A pointer to a FILETIME structure to
966        /// receive the date and time the file or directory was last written to,
967        /// truncated, or overwritten (for example, with WriteFile or SetEndOfFile).
968        /// This date and time is not updated when file attributes or security
969        /// descriptors are changed. This parameter can be NULL if the application
970        /// does not require this information.</param>
971        /// <returns>If the function succeeds, the return value is nonzero.
972        ///
973        /// If the function fails, the return value is zero. To get extended error
974        /// information, call Marshal.GetLastWin32Error().</returns>
975        [DllImport("Kernel32.dll", SetLastError = true)]
976        [return: MarshalAs(UnmanagedType.Bool)]
977        public static extern bool GetFileTime(SafeFileHandle hFile,
978            out System.Runtime.InteropServices.ComTypes.FILETIME lpCreationTime,
979            out System.Runtime.InteropServices.ComTypes.FILETIME lpLastAccessTime,
980            out System.Runtime.InteropServices.ComTypes.FILETIME lpLastWriteTime);
981
982        /// <summary>
983        /// Sets the date and time that the specified file or directory was created,
984        /// last accessed, or last modified.
985        /// </summary>
986        /// <param name="hFile">A handle to the file or directory. The handle must
987        /// have been created using the CreateFile function with the
988        /// FILE_WRITE_ATTRIBUTES access right. For more information, see File
989        /// Security and Access Rights.</param>
990        /// <param name="lpCreationTime">A pointer to a FILETIME structure that
991        /// contains the new creation date and time for the file or directory.
992        /// This parameter can be NULL if the application does not need to change
993        /// this information.</param>
994        /// <param name="lpLastAccessTime">A pointer to a FILETIME structure that
995        /// contains the new last access date and time for the file or directory.
996        /// The last access time includes the last time the file or directory was
997        /// written to, read from, or (in the case of executable files) run. This
998        /// parameter can be NULL if the application does not need to change this
999        /// information.
1000        ///
1001        /// To preserve the existing last access time for a file even after accessing
1002        /// a file, call SetFileTime immediately after opening the file handle
1003        /// with this parameter's FILETIME structure members initialized to
1004        /// 0xFFFFFFFF.</param>
1005        /// <param name="lpLastWriteTime">A pointer to a FILETIME structure that
1006        /// contains the new last modified date and time for the file or directory.
1007        /// This parameter can be NULL if the application does not need to change
1008        /// this information.</param>
1009        /// <returns>If the function succeeds, the return value is nonzero.
1010        ///
1011        /// If the function fails, the return value is zero. To get extended error
1012        /// information, call GetLastError.</returns>
1013        [DllImport("Kernel32.dll", SetLastError = true)]
1014        [return: MarshalAs(UnmanagedType.Bool)]
1015        public static extern bool SetFileTime(SafeFileHandle hFile,
1016            ref System.Runtime.InteropServices.ComTypes.FILETIME lpCreationTime,
1017            ref System.Runtime.InteropServices.ComTypes.FILETIME lpLastAccessTime,
1018            ref System.Runtime.InteropServices.ComTypes.FILETIME lpLastWriteTime);
1019
1020        /// <summary>
1021        /// Retrieves the name of a volume on a computer. FindFirstVolume is used
1022        /// to begin scanning the volumes of a computer.
1023        /// </summary>
1024        /// <param name="lpszVolumeName">A pointer to a buffer that receives a
1025        /// null-terminated string that specifies the unique volume name of the
1026        /// first volume found.</param>
1027        /// <param name="cchBufferLength">The length of the buffer to receive the
1028        /// name, in TCHARs.</param>
1029        /// <returns>If the function succeeds, the return value is a search handle
1030        /// used in a subsequent call to the FindNextVolume and FindVolumeClose
1031        /// functions.
1032        ///
1033        /// If the function fails to find any volumes, the return value is the
1034        /// INVALID_HANDLE_VALUE error code. To get extended error information,
1035        /// call GetLastError.</returns>
1036        [DllImport("Kernel32.dll", SetLastError = true, CharSet = CharSet.Unicode)]
1037        public static extern SafeFindVolumeHandle FindFirstVolume(
1038            StringBuilder lpszVolumeName, uint cchBufferLength);
1039
1040        /// <summary>
1041        /// Implements a Safe handle for FindFirstVolume.
1042        /// </summary>
1043        [SecurityPermission(SecurityAction.InheritanceDemand, UnmanagedCode = true)]
1044        [SecurityPermission(SecurityAction.Demand, UnmanagedCode = true)]
1045        public class SafeFindVolumeHandle : SafeHandleMinusOneIsInvalid
1046        {
1047            internal SafeFindVolumeHandle()
1048                : base(true)
1049            {
1050            }
1051
1052            [ReliabilityContract(Consistency.WillNotCorruptState, Cer.MayFail)]
1053            protected override bool ReleaseHandle()
1054            {
1055                return FindVolumeClose(handle);
1056            }
1057        }
1058
1059        /// <summary>
1060        /// Continues a volume search started by a call to the FindFirstVolume
1061        /// function. FindNextVolume finds one volume per call.
1062        /// </summary>
1063        /// <param name="hFindVolume">The volume search handle returned by a previous
1064        /// call to the FindFirstVolume function.</param>
1065        /// <param name="lpszVolumeName">A pointer to a string that receives the
1066        /// unique volume name found.</param>
1067        /// <param name="cchBufferLength">The length of the buffer that receives
1068        /// the name, in TCHARs.</param>
1069        /// <returns>If the function succeeds, the return value is nonzero.
1070        ///
1071        /// If the function fails, the return value is zero. To get extended error
1072        /// information, call GetLastError. If no matching files can be found, the
1073        /// GetLastError function returns the ERROR_NO_MORE_FILES error code. In
1074        /// that case, close the search with the FindVolumeClose function.</returns>
1075        [DllImport("Kernel32.dll", SetLastError = true, CharSet = CharSet.Unicode)]
1076        [return: MarshalAs(UnmanagedType.Bool)]
1077        public static extern bool FindNextVolume(SafeFindVolumeHandle hFindVolume,
1078            StringBuilder lpszVolumeName, uint cchBufferLength);
1079
1080        /// <summary>
1081        /// Closes the specified volume search handle. The FindFirstVolume and
1082        /// FindNextVolume functions use this search handle to locate volumes.
1083        /// </summary>
1084        /// <param name="hFindVolume">The volume search handle to be closed. This
1085        /// handle must have been previously opened by the FindFirstVolume function.</param>
1086        /// <returns>If the function succeeds, the return value is nonzero.
1087        ///
1088        /// If the function fails, the return value is zero. To get extended error
1089        /// information, call GetLastError.</returns>
1090        [DllImport("Kernel32.dll", SetLastError = true)]
1091        [return: MarshalAs(UnmanagedType.Bool)]
1092        internal static extern bool FindVolumeClose(IntPtr hFindVolume);
1093
1094        /// <summary>
1095        /// Retrieves the name of a volume mount point on the specified volume.
1096        /// FindFirstVolumeMountPoint is used to begin scanning the volume mount
1097        /// points on a volume.
1098        /// </summary>
1099        /// <param name="lpszRootPathName">The unique volume name of the volume
1100        /// to scan for volume mount points. A trailing backslash is required.</param>
1101        /// <param name="lpszVolumeMountPoint">A pointer to a buffer that receives
1102        /// the name of the first volume mount point found.</param>
1103        /// <param name="cchBufferLength">The length of the buffer that receives
1104        /// the volume mount point name, in TCHARs.</param>
1105        /// <returns>If the function succeeds, the return value is a search handle
1106        /// used in a subsequent call to the FindNextVolumeMountPoint and
1107        /// FindVolumeMountPointClose functions.
1108        ///
1109        /// If the function fails to find a volume mount point on the volume, the
1110        /// return value is the INVALID_HANDLE_VALUE error code. To get extended
1111        /// error information, call GetLastError.</returns>
1112        [DllImport("Kernel32.dll", SetLastError = true, CharSet = CharSet.Unicode)]
1113        public static extern SafeFindVolumeMountPointHandle FindFirstVolumeMountPoint(
1114            string lpszRootPathName, StringBuilder lpszVolumeMountPoint,
1115            uint cchBufferLength);
1116
1117        /// <summary>
1118        /// Implements a Safe handle for FindFirstVolumeMountPoint.
1119        /// </summary>
1120        [SecurityPermission(SecurityAction.InheritanceDemand, UnmanagedCode = true)]
1121        [SecurityPermission(SecurityAction.Demand, UnmanagedCode = true)]
1122        public class SafeFindVolumeMountPointHandle : SafeHandleMinusOneIsInvalid
1123        {
1124            internal SafeFindVolumeMountPointHandle()
1125                : base(true)
1126            {
1127            }
1128
1129            [ReliabilityContract(Consistency.WillNotCorruptState, Cer.MayFail)]
1130            protected override bool ReleaseHandle()
1131            {
1132                return FindVolumeMountPointClose(handle);
1133            }
1134        }
1135
1136        /// <summary>
1137        /// Continues a volume mount point search started by a call to the
1138        /// FindFirstVolumeMountPoint function. FindNextVolumeMountPoint finds one
1139        /// volume mount point per call.
1140        /// </summary>
1141        /// <param name="hFindVolumeMountPoint">A mount-point search handle returned
1142        /// by a previous call to the FindFirstVolumeMountPoint function.</param>
1143        /// <param name="lpszVolumeMountPoint">A pointer to a buffer that receives
1144        /// the name of the volume mount point found.</param>
1145        /// <param name="cchBufferLength">The length of the buffer that receives
1146        /// the names, in TCHARs.</param>
1147        /// <returns>If the function succeeds, the return value is nonzero.
1148        ///
1149        /// If the function fails, the return value is zero. To get extended error
1150        /// information, call GetLastError. If no matching files can be found, the
1151        /// GetLastError function returns the ERROR_NO_MORE_FILES error code. In
1152        /// that case, close the search with the FindVolumeMountPointClose function.</returns>
1153        [DllImport("Kernel32.dll", SetLastError = true, CharSet = CharSet.Unicode)]
1154        [return: MarshalAs(UnmanagedType.Bool)]
1155        public static extern bool FindNextVolumeMountPoint(
1156            SafeFindVolumeMountPointHandle hFindVolumeMountPoint, StringBuilder lpszVolumeMountPoint,
1157            uint cchBufferLength);
1158
1159        /// <summary>
1160        /// Closes the specified mount-point search handle. The FindFirstVolumeMountPoint
1161        /// and FindNextVolumeMountPoint  functions use this search handle to locate
1162        /// volume mount points on a specified volume.
1163        /// </summary>
1164        /// <param name="hFindVolumeMountPoint">The mount-point search handle to
1165        /// be closed. This handle must have been previously opened by the
1166        /// FindFirstVolumeMountPoint function.</param>
1167        /// <returns>If the function succeeds, the return value is nonzero.
1168        ///
1169        /// If the function fails, the return value is zero. To get extended error
1170        /// information, call GetLastError.</returns>
1171        [DllImport("Kernel32.dll", SetLastError = true)]
1172        [return: MarshalAs(UnmanagedType.Bool)]
1173        internal static extern bool FindVolumeMountPointClose(IntPtr hFindVolumeMountPoint);
1174
1175        /// <summary>
1176        /// Retrieves information about the specified disk, including the amount
1177        /// of free space on the disk.
1178        ///
1179        /// The GetDiskFreeSpace function cannot report volume sizes that are
1180        /// greater than 2 gigabytes (GB). To ensure that your application works
1181        /// with large capacity hard drives, use the GetDiskFreeSpaceEx function.
1182        /// </summary>
1183        /// <param name="lpRootPathName">The root directory of the disk for which
1184        /// information is to be returned. If this parameter is NULL, the function
1185        /// uses the root of the current disk. If this parameter is a UNC name,
1186        /// it must include a trailing backslash (for example, \\MyServer\MyShare\).
1187        /// Furthermore, a drive specification must have a trailing backslash
1188        /// (for example, C:\). The calling application must have FILE_LIST_DIRECTORY
1189        /// access rights for this directory.</param>
1190        /// <param name="lpSectorsPerCluster">A pointer to a variable that receives
1191        /// the number of sectors per cluster.</param>
1192        /// <param name="lpBytesPerSector">A pointer to a variable that receives
1193        /// the number of bytes per sector.</param>
1194        /// <param name="lpNumberOfFreeClusters">A pointer to a variable that
1195        /// receives the total number of free clusters on the disk that are
1196        /// available to the user who is associated with the calling thread.
1197        ///
1198        /// If per-user disk quotas are in use, this value may be less than the
1199        /// total number of free clusters on the disk.</param>
1200        /// <param name="lpTotalNumberOfClusters">A pointer to a variable that
1201        /// receives the total number of clusters on the disk that are available
1202        /// to the user who is associated with the calling thread.
1203        ///
1204        /// If per-user disk quotas are in use, this value may be less than the
1205        /// total number of clusters on the disk.</param>
1206        /// <returns>If the function succeeds, the return value is true. To get
1207        /// extended error information, call Marshal.GetLastWin32Error().</returns>
1208        [DllImport("Kernel32.dll", SetLastError = true, CharSet = CharSet.Unicode)]
1209        [return: MarshalAs(UnmanagedType.Bool)]
1210        public static extern bool GetDiskFreeSpace(
1211            string lpRootPathName, out UInt32 lpSectorsPerCluster, out UInt32 lpBytesPerSector,
1212            out UInt32 lpNumberOfFreeClusters, out UInt32 lpTotalNumberOfClusters);
1213
1214
1215        /// <summary>
1216        /// Retrieves information about the amount of space that is available on
1217        /// a disk volume, which is the total amount of space, the total amount
1218        /// of free space, and the total amount of free space available to the
1219        /// user that is associated with the calling thread.
1220        /// </summary>
1221        /// <param name="lpDirectoryName">A directory on the disk.
1222        ///
1223        /// If this parameter is NULL, the function uses the root of the current
1224        /// disk.
1225        ///
1226        /// If this parameter is a UNC name, it must include a trailing backslash,
1227        /// for example, "\\MyServer\MyShare\".
1228        ///
1229        /// This parameter does not have to specify the root directory on a disk.
1230        /// The function accepts any directory on a disk.
1231        ///
1232        /// The calling application must have FILE_LIST_DIRECTORY access rights
1233        /// for this directory.</param>
1234        /// <param name="lpFreeBytesAvailable">A pointer to a variable that receives
1235        /// the total number of free bytes on a disk that are available to the
1236        /// user who is associated with the calling thread.
1237        ///
1238        /// This parameter can be NULL.
1239        ///
1240        /// If per-user quotas are being used, this value may be less than the
1241        /// total number of free bytes on a disk.</param>
1242        /// <param name="lpTotalNumberOfBytes">A pointer to a variable that receives
1243        /// the total number of bytes on a disk that are available to the user who
1244        /// is associated with the calling thread.
1245        ///
1246        /// This parameter can be NULL.
1247        ///
1248        /// If per-user quotas are being used, this value may be less than the
1249        /// total number of bytes on a disk.
1250        ///
1251        /// To determine the total number of bytes on a disk or volume, use
1252        /// IOCTL_DISK_GET_LENGTH_INFO.</param>
1253        /// <param name="lpTotalNumberOfFreeBytes">A pointer to a variable that
1254        /// receives the total number of free bytes on a disk.
1255        ///
1256        /// This parameter can be NULL.</param>
1257        /// <returns>If the function succeeds, the return value is nonzero.
1258        ///
1259        /// If the function fails, the return value is zero (0). To get extended
1260        /// error information, call GetLastError.</returns>
1261        [DllImport("Kernel32.dll", SetLastError = true, CharSet = CharSet.Unicode)]
1262        [return: MarshalAs(UnmanagedType.Bool)]
1263        public static extern bool GetDiskFreeSpaceEx(
1264            string lpDirectoryName,
1265            out UInt64 lpFreeBytesAvailable,
1266            out UInt64 lpTotalNumberOfBytes,
1267            out UInt64 lpTotalNumberOfFreeBytes);
1268
1269        /// <summary>
1270        /// Determines whether a disk drive is a removable, fixed, CD-ROM, RAM disk,
1271        /// or network drive.
1272        /// </summary>
1273        /// <param name="lpRootPathName">The root directory for the drive.
1274        ///
1275        /// A trailing backslash is required. If this parameter is NULL, the function
1276        /// uses the root of the current directory.</param>
1277        /// <returns>The return value specifies the type of drive, which can be
1278        /// one of the DriveInfo.DriveType values.</returns>
1279        [DllImport("Kernel32.dll", SetLastError = true, CharSet = CharSet.Unicode)]
1280        public static extern uint GetDriveType(string lpRootPathName);
1281
1282        /// <summary>
1283        /// Retrieves information about the file system and volume associated with
1284        /// the specified root directory.
1285        ///
1286        /// To specify a handle when retrieving this information, use the
1287        /// GetVolumeInformationByHandleW function.
1288        ///
1289        /// To retrieve the current compression state of a file or directory, use
1290        /// FSCTL_GET_COMPRESSION.
1291        /// </summary>
1292        /// <param name="lpRootPathName">    A pointer to a string that contains
1293        /// the root directory of the volume to be described.
1294        ///
1295        /// If this parameter is NULL, the root of the current directory is used.
1296        /// A trailing backslash is required. For example, you specify
1297        /// \\MyServer\MyShare as "\\MyServer\MyShare\", or the C drive as "C:\".</param>
1298        /// <param name="lpVolumeNameBuffer">A pointer to a buffer that receives
1299        /// the name of a specified volume. The maximum buffer size is MAX_PATH+1.</param>
1300        /// <param name="nVolumeNameSize">The length of a volume name buffer, in
1301        /// TCHARs. The maximum buffer size is MAX_PATH+1.
1302        ///
1303        /// This parameter is ignored if the volume name buffer is not supplied.</param>
1304        /// <param name="lpVolumeSerialNumber">A pointer to a variable that receives
1305        /// the volume serial number.
1306        ///
1307        /// This parameter can be NULL if the serial number is not required.
1308        ///
1309        /// This function returns the volume serial number that the operating system
1310        /// assigns when a hard disk is formatted. To programmatically obtain the
1311        /// hard disk's serial number that the manufacturer assigns, use the
1312        /// Windows Management Instrumentation (WMI) Win32_PhysicalMedia property
1313        /// SerialNumber.</param>
1314        /// <param name="lpMaximumComponentLength">A pointer to a variable that
1315        /// receives the maximum length, in TCHARs, of a file name component that
1316        /// a specified file system supports.
1317        ///
1318        /// A file name component is the portion of a file name between backslashes.
1319        ///
1320        /// The value that is stored in the variable that *lpMaximumComponentLength
1321        /// points to is used to indicate that a specified file system supports
1322        /// long names. For example, for a FAT file system that supports long names,
1323        /// the function stores the value 255, rather than the previous 8.3 indicator.
1324        /// Long names can also be supported on systems that use the NTFS file system.</param>
1325        /// <param name="lpFileSystemFlags">A pointer to a variable that receives
1326        /// flags associated with the specified file system.
1327        ///
1328        /// This parameter can be one or more of the FS_FILE* flags. However,
1329        /// FS_FILE_COMPRESSION and FS_VOL_IS_COMPRESSED are mutually exclusive.</param>
1330        /// <param name="lpFileSystemNameBuffer">A pointer to a buffer that receives
1331        /// the name of the file system, for example, the FAT file system or the
1332        /// NTFS file system. The maximum buffer size is MAX_PATH+1.</param>
1333        /// <param name="nFileSystemNameSize">The length of the file system name
1334        /// buffer, in TCHARs. The maximum buffer size is MAX_PATH+1.
1335        ///
1336        /// This parameter is ignored if the file system name buffer is not supplied.</param>
1337        /// <returns>If all the requested information is retrieved, the return value
1338        /// is nonzero.
1339        ///
1340        ///
1341        /// If not all the requested information is retrieved, the return value is
1342        /// zero (0). To get extended error information, call GetLastError.</returns>
1343        [DllImport("Kernel32.dll", SetLastError = true, CharSet = CharSet.Unicode)]
1344        [return: MarshalAs(UnmanagedType.Bool)]
1345        public static extern bool GetVolumeInformation(
1346            string lpRootPathName,
1347            StringBuilder lpVolumeNameBuffer,
1348            uint nVolumeNameSize,
1349            out uint lpVolumeSerialNumber,
1350            out uint lpMaximumComponentLength,
1351            out uint lpFileSystemFlags,
1352            StringBuilder lpFileSystemNameBuffer,
1353            uint nFileSystemNameSize);
1354
1355        /// <summary>
1356        /// Retrieves the unique volume name for the specified volume mount point or root directory.
1357        /// </summary>
1358        /// <param name="lpszVolumeMountPoint">The path of a volume mount point (with a trailing
1359        /// backslash, "\") or a drive letter indicating a root directory (in the
1360        /// form "D:\").</param>
1361        /// <param name="lpszVolumeName">A pointer to a string that receives the
1362        /// volume name. This name is a unique volume name of the form
1363        /// "\\?\Volume{GUID}\" where GUID is the GUID that identifies the volume.</param>
1364        /// <param name="cchBufferLength">The length of the output buffer, in TCHARs.
1365        /// A reasonable size for the buffer to accommodate the largest possible
1366        /// volume name is 50 characters.</param>
1367        /// <returns>If the function succeeds, the return value is nonzero.
1368        ///
1369        /// If the function fails, the return value is zero. To get extended
1370        /// error information, call GetLastError.</returns>
1371        [DllImport("Kernel32.dll", SetLastError = true, CharSet = CharSet.Unicode)]
1372        [return: MarshalAs(UnmanagedType.Bool)]
1373        public static extern bool GetVolumeNameForVolumeMountPoint(
1374            string lpszVolumeMountPoint, StringBuilder lpszVolumeName,
1375            uint cchBufferLength);
1376
1377        /// <summary>
1378        /// Retrieves a list of path names for the specified volume name.
1379        /// </summary>
1380        /// <param name="lpszVolumeName">The volume name.</param>
1381        /// <param name="lpszVolumePathNames">A pointer to a buffer that receives
1382        /// the list of volume path names. The list is an array of null-terminated
1383        /// strings terminated by an additional NULL character. If the buffer is
1384        /// not large enough to hold the complete list, the buffer holds as much
1385        /// of the list as possible.</param>
1386        /// <param name="cchBufferLength">The length of the lpszVolumePathNames
1387        /// buffer, in TCHARs.</param>
1388        /// <param name="lpcchReturnLength">If the call is successful, this parameter
1389        /// is the number of TCHARs copied to the lpszVolumePathNames buffer. Otherwise,
1390        /// this parameter is the size of the buffer required to hold the complete
1391        /// list, in TCHARs.</param>
1392        /// <returns></returns>
1393        [DllImport("Kernel32.dll", SetLastError = true, CharSet = CharSet.Unicode)]
1394        [return: MarshalAs(UnmanagedType.Bool)]
1395        private static extern bool GetVolumePathNamesForVolumeName(string lpszVolumeName,
1396            [MarshalAs(UnmanagedType.LPArray, SizeParamIndex = 3)] char[] lpszVolumePathNames,
1397            uint cchBufferLength, out uint lpcchReturnLength);
1398
1399        /// <summary>
1400        /// Retrieves a list of path names for the specified volume name.
1401        /// </summary>
1402        /// <param name="lpszVolumeName">The volume name.</param>
1403        public static string[] GetVolumePathNamesForVolumeName(string lpszVolumeName)
1404        {
1405            uint returnLength = 0;
1406            char[] pathNamesBuffer = new char[NativeMethods.MaxPath];
1407            while (!NativeMethods.GetVolumePathNamesForVolumeName(lpszVolumeName,
1408                pathNamesBuffer, (uint)pathNamesBuffer.Length, out returnLength))
1409            {
1410                int errorCode = Marshal.GetLastWin32Error();
1411                switch (errorCode)
1412                {
1413                    case Win32ErrorCode.NotReady:
1414                        //The drive isn't ready yet: just return an empty list.
1415                        return new string[0];
1416                    case Win32ErrorCode.MoreData:
1417                        pathNamesBuffer = new char[pathNamesBuffer.Length * 2];
1418                        break;
1419                    default:
1420                        throw Win32ErrorCode.GetExceptionForWin32Error(errorCode);
1421                }
1422            }
1423
1424            return ParseNullDelimitedArray(pathNamesBuffer, (int)returnLength);
1425        }
1426
1427        public const int MaxPath = 260;
1428        public const int LongPath = 32768;
1429
1430        /// <summary>
1431        /// Retrieves the product type for the operating system on the local computer, and
1432        /// maps the type to the product types supported by the specified operating system.
1433        /// </summary>
1434        /// <param name="dwOSMajorVersion">The major version number of the operating system.
1435        /// The minimum value is 6.
1436        ///
1437        /// The combination of the dwOSMajorVersion, dwOSMinorVersion, dwSpMajorVersion,
1438        /// and dwSpMinorVersion parameters describes the maximum target operating system
1439        /// version for the application. For example, Windows Vista and Windows Server
1440        /// 2008 are version 6.0.0.0 and Windows 7 and Windows Server 2008 R2 are version
1441        /// 6.1.0.0.</param>
1442        /// <param name="dwOSMinorVersion">The minor version number of the operating
1443        /// system. The minimum value is 0.</param>
1444        /// <param name="dwSpMajorVersion">The major version number of the operating
1445        /// system service pack. The minimum value is 0.</param>
1446        /// <param name="dwSpMinorVersion">The minor version number of the operating
1447        /// system service pack. The minimum value is 0.</param>
1448        /// <param name="pdwReturnedProductType">The product type. This parameter
1449        /// cannot be NULL. If the specified operating system is less than the
1450        /// current operating system, this information is mapped to the types
1451        /// supported by the specified operating system. If the specified operating
1452        /// system is greater than the highest supported operating system, this
1453        /// information is mapped to the types supported by the current operating system.
1454        ///
1455        /// If the product has not been activated and is no longer in the grace period,
1456        /// this parameter is set to PRODUCT_UNLICENSED (0xABCDABCD).</param>
1457        /// <returns>If the function succeeds, the return value is a nonzero value.
1458        /// If the software license is invalid or expired, the function succeeds
1459        /// but the pdwReturnedProductType parameter is set to PRODUCT_UNLICENSED.
1460        ///
1461        /// If the function fails, the return value is zero. This function fails if
1462        /// one of the input parameters is invalid.</returns>
1463        [DllImport("Kernel32.dll", CharSet = CharSet.Unicode)]
1464        public static extern bool GetProductInfo(uint dwOSMajorVersion,
1465            uint dwOSMinorVersion, uint dwSpMajorVersion, uint dwSpMinorVersion,
1466            out WindowsEditions pdwReturnedProductType);
1467
1468        /// <summary>
1469        /// Frees the specified local memory object and invalidates its handle.
1470        /// </summary>
1471        /// <param name="hMem">A handle to the local memory object. This handle is
1472        /// returned by either the LocalAlloc or LocalReAlloc function. It is not
1473        /// safe to free memory allocated with GlobalAlloc.</param>
1474        /// <returns>If the function succeeds, the return value is NULL.
1475        ///
1476        /// If the function fails, the return value is equal to a handle to the
1477        /// local memory object. To get extended error information, call
1478        /// GetLastError.</returns>
1479        /// <remarks>If the process tries to examine or modify the memory after
1480        /// it has been freed, heap corruption may occur or an access violation
1481        /// exception (EXCEPTION_ACCESS_VIOLATION) may be generated.
1482        ///
1483        /// If the hMem parameter is NULL, LocalFree ignores the parameter and
1484        /// returns NULL.
1485        ///
1486        /// The LocalFree function will free a locked memory object. A locked
1487        /// memory object has a lock count greater than zero. The LocalLock
1488        /// function locks a local memory object and increments the lock count
1489        /// by one. The LocalUnlock function unlocks it and decrements the lock
1490        /// count by one. To get the lock count of a local memory object, use
1491        /// the LocalFlags function.
1492        ///
1493        /// If an application is running under a debug version of the system,
1494        /// LocalFree will issue a message that tells you that a locked object
1495        /// is being freed. If you are debugging the application, LocalFree will
1496        /// enter a breakpoint just before freeing a locked object. This allows
1497        /// you to verify the intended behavior, then continue execution.</remarks>
1498        [DllImport("Kernel32.dll", SetLastError = true)]
1499        public static extern IntPtr LocalFree(IntPtr hMem);
1500
1501        /// <summary>
1502        /// Parses a null-delimited array into a string array.
1503        /// </summary>
1504        /// <param name="buffer">The buffer to parse.</param>
1505        /// <param name="length">The valid length of the array.</param>
1506        /// <returns>The array found in the buffer</returns>
1507        private static string[] ParseNullDelimitedArray(char[] buffer, int length)
1508        {
1509            List<string> result = new List<string>();
1510            for (int lastIndex = 0, i = 0; i != length; ++i)
1511            {
1512                if (buffer[i] == '\0')
1513                {
1514                    //If the string formed is empty, there are no elements left.
1515                    if (i - lastIndex == 0)
1516                        break;
1517
1518                    result.Add(new string(buffer, lastIndex, i - lastIndex));
1519
1520                    lastIndex = i + 1;
1521                    if (buffer[lastIndex] == '\0')
1522                        break;
1523                }
1524            }
1525
1526            return result.ToArray();
1527        }
1528    }
1529}
Note: See TracBrowser for help on using the repository browser.