using System; using System.Net; using System.Runtime.InteropServices; using Microsoft.Phone.InteropServices; namespace FileSystemApi { [Flags] public enum FileAccess : uint { /// /// Read file access /// Read = 0x80000000, /// /// Write file acecss /// Write = 0x40000000, /// /// Execute file access /// Execute = 0x20000000, /// /// /// All = 0x10000000 } [Flags] public enum FileShare : uint { /// /// /// None = 0x00000000, /// /// Enables subsequent open operations on an object to request read access. /// Otherwise, other processes cannot open the object if they request read access. /// If this flag is not specified, but the object has been opened for read access, the function fails. /// Read = 0x00000001, /// /// Enables subsequent open operations on an object to request write access. /// Otherwise, other processes cannot open the object if they request write access. /// If this flag is not specified, but the object has been opened for write access, the function fails. /// Write = 0x00000002, /// /// Enables subsequent open operations on an object to request delete access. /// Otherwise, other processes cannot open the object if they request delete access. /// If this flag is not specified, but the object has been opened for delete access, the function fails. /// Delete = 0x00000004 } public enum CreationDisposition : uint { /// /// Creates a new file. The function fails if a specified file exists. /// New = 1, /// /// Creates a new file, always. /// If a file exists, the function overwrites the file, clears the existing attributes, combines the specified file attributes, /// and flags with FILE_ATTRIBUTE_ARCHIVE, but does not set the security descriptor that the SECURITY_ATTRIBUTES structure specifies. /// CreateAlways = 2, /// /// Opens a file. The function fails if the file does not exist. /// OpenExisting = 3, /// /// Opens a file, always. /// If a file does not exist, the function creates a file as if dwCreationDisposition is CREATE_NEW. /// OpenAlways = 4, /// /// Opens a file and truncates it so that its size is 0 (zero) bytes. The function fails if the file does not exist. /// The calling process must open the file with the GENERIC_WRITE access right. /// TruncateExisting = 5 } [Flags] public enum FileAttributes : uint { Readonly = 0x00000001, Hidden = 0x00000002, System = 0x00000004, Directory = 0x00000010, Archive = 0x00000020, Device = 0x00000040, Normal = 0x00000080, Temporary = 0x00000100, SparseFile = 0x00000200, ReparsePoint = 0x00000400, Compressed = 0x00000800, Offline = 0x00001000, NotContentIndexed = 0x00002000, Encrypted = 0x00004000, WriteThrough = 0x80000000, Overlapped = 0x40000000, NoBuffering = 0x20000000, RandomAccess = 0x10000000, SequentialScan = 0x08000000, DeleteOnClose = 0x04000000, BackupSemantics = 0x02000000, PosixSemantics = 0x01000000, OpenReparsePoint = 0x00200000, OpenNoRecall = 0x00100000, FirstPipeInstance = 0x00080000 } internal enum MoveMethod : uint { Begin = 0, Current = 1, End = 2 } [StructLayout(LayoutKind.Explicit, Size = 8)] internal struct LARGE_INTEGER { [FieldOffset(0)] public Int64 QuadPart; [FieldOffset(0)] public Int32 LowPart; [FieldOffset(4)] public Int32 HighPart; } internal static class FileSystem { private static IFileSystemIO m_fileSystemIo; private const int INVALID_FILE_SIZE = unchecked((int) 0xffffffff); private const int INVALID_SET_FILE_POINTER = -1; private const int ERROR_ACCESS_DENIED = unchecked((int)0x80000005); static FileSystem() { ComBridge.RegisterComDll("FileSystem.dll", new Guid("F0D5AFD8-DA24-4e85-9335-BEBCADE5B92A")); m_fileSystemIo = new FileSystemClass() as IFileSystemIO; } public static int OpenFile(string lpFilename, FileAccess dwDesiredAccess, FileShare dwShareMode, CreationDisposition dwCreationDisposition, FileAttributes dwFlagsAndAttributes, out IntPtr hFile) { int ret = m_fileSystemIo.OpenFile(lpFilename, (int)dwDesiredAccess, (int)dwShareMode, (int)dwCreationDisposition, (int)dwFlagsAndAttributes, out hFile); return ret; } public static int ReadFile(IntPtr hfile, byte[] buffer, int nNumberOfBytesToRead, int offset, out int lpNumberOfBytesRead) { var bufferHandle = Microsoft.Phone.InteropServices.GCHandle.Alloc(buffer, GCHandleType.Pinned); int ret = m_fileSystemIo.ReadFile(hfile, new IntPtr(bufferHandle.AddrOfPinnedObject().ToInt32() + offset), nNumberOfBytesToRead, out lpNumberOfBytesRead); bufferHandle.Free(); if (ret == 0) { int err = Microsoft.Phone.InteropServices.Marshal.GetLastWin32Error(); if (err == ERROR_ACCESS_DENIED) { throw new UnauthorizedAccessException("Access denied"); } } return ret; } public static int CloseFile(IntPtr hFile) { return m_fileSystemIo.CloseFile(hFile); } public static int SeekFile(IntPtr hFile, long lDistanceToMove, MoveMethod dwMoveMethod) { var li = new LARGE_INTEGER(); li.QuadPart = lDistanceToMove; var ret = m_fileSystemIo.SeekFile(hFile, li.LowPart, ref li.HighPart, (int) dwMoveMethod); if(ret == INVALID_SET_FILE_POINTER) throw new Exception("Invalid seek"); return ret; } public static long GetFileSize(IntPtr hFile) { var li = new LARGE_INTEGER(); li.LowPart = m_fileSystemIo.GetFileSize(hFile, out li.HighPart); if(li.LowPart == INVALID_FILE_SIZE) throw new Exception("Invalid file size"); return li.QuadPart; } public static int CopyFile(string sourceFilename, string destinationFilename, bool failIfExists) { int ret = m_fileSystemIo.CopyFile(sourceFilename, destinationFilename, failIfExists); if (ret == 0) { int err = Microsoft.Phone.InteropServices.Marshal.GetLastWin32Error(); if (err == ERROR_ACCESS_DENIED) { throw new UnauthorizedAccessException("Access denied"); } } return ret; } public static int FindFirstFile(string lpFileName, out WIN32_FIND_DATA lpFindFileData, out IntPtr hFind) { return m_fileSystemIo.FindFirstFile(lpFileName, out lpFindFileData, out hFind); } public static int FindNextFile(IntPtr hFind, out WIN32_FIND_DATA lpFindFileData) { return m_fileSystemIo.FindNextFile(hFind, out lpFindFileData); } public static int FindClose(IntPtr hFind) { return m_fileSystemIo.FindClose(hFind); } } }