WinRT 中的文件共享模式
File share mode in WinRT
我有两个进程写入同一个文件。顺便说一句,这是一个日志文件,访问与一个命名的互斥体同步。
如何让 StorageFolder.OpenStreamForWriteAsync 通过 FILE_SHARE_READ | FILE_SHARE_WRITE 到它可能使用的底层 CreateFile2 WinAPI 来自 kernelbase.dll?
那是不可能的。
解决方法 — 使用非托管互操作实现您自己的 FileStream class。比较简单,我的代码不到4页
这是您需要的导入:
static class NativeMethods
{
const string file121 = "api-ms-win-core-file-l1-2-1.dll";
const string handle110 = "api-ms-win-core-handle-l1-1-0.dll";
[DllImport( file121, CharSet = CharSet.Unicode, SetLastError = true )]
public static extern SafeFileHandle CreateFile2( [MarshalAs( UnmanagedType.LPWStr )] string filename,
FileAccess dwDesiredAccess, FileShare dwShareMode, FileMode dwCreationDisposition, IntPtr pCreateExParams );
[DllImport( handle110, SetLastError = true )]
[return: MarshalAs( UnmanagedType.Bool )]
internal static extern bool CloseHandle( IntPtr handle );
[DllImport( file121, SetLastError = true )]
[return: MarshalAs( UnmanagedType.Bool )]
static extern bool GetFileInformationByHandleEx( SafeFileHandle handle, FILE_INFO_BY_HANDLE_CLASS FileInformationClass, out FILE_STANDARD_INFO lpFileInformation, int dwBufferSize );
internal static FILE_STANDARD_INFO GetFileStandardInfo( SafeFileHandle handle )
{
FILE_STANDARD_INFO fsi;
if( !GetFileInformationByHandleEx( handle, FILE_INFO_BY_HANDLE_CLASS.FileStandardInfo, out fsi, Marshal.SizeOf<FILE_STANDARD_INFO>() ) )
throw new COMException( "GetFileInformationByHandleEx failed.", Marshal.GetHRForLastWin32Error() );
return fsi;
}
[DllImport( file121, SetLastError = true )]
[return: MarshalAs( UnmanagedType.Bool )]
internal static extern bool SetFilePointerEx( SafeFileHandle handle, long liDistanceToMove, out long lpNewFilePointer, SeekOrigin dwMoveMethod );
[DllImport( file121, SetLastError = true )]
[return: MarshalAs( UnmanagedType.Bool )]
internal static extern bool SetFilePointerEx( SafeFileHandle handle, long liDistanceToMove, IntPtr lpNewFilePointer, SeekOrigin dwMoveMethod );
[DllImport( file121, SetLastError = true )]
[return: MarshalAs( UnmanagedType.Bool )]
internal static extern bool FlushFileBuffers( SafeFileHandle handle );
[DllImport( file121, SetLastError = true )]
[return: MarshalAs( UnmanagedType.Bool )]
internal static extern unsafe bool ReadFile( SafeFileHandle hFile, byte* lpBuffer, uint nNumberOfBytesToRead, out uint lpNumberOfBytesRead, IntPtr lpOverlapped );
[DllImport( file121, SetLastError = true )]
[return: MarshalAs( UnmanagedType.Bool )]
internal static extern unsafe bool SetEndOfFile( SafeFileHandle hFile );
[ DllImport( file121, SetLastError = true )]
[return: MarshalAs( UnmanagedType.Bool )]
internal static extern unsafe bool WriteFile( SafeFileHandle hFile, byte* lpBuffer, uint nNumberOfBytesToWrite, out uint lpNumberOfBytesWritten, IntPtr lpOverlapped ); }
您还需要 structures/enums/SafeFileHandle,但与导入不同的是,这些很容易复制粘贴,例如来自 CoreFX.
我有两个进程写入同一个文件。顺便说一句,这是一个日志文件,访问与一个命名的互斥体同步。
如何让 StorageFolder.OpenStreamForWriteAsync 通过 FILE_SHARE_READ | FILE_SHARE_WRITE 到它可能使用的底层 CreateFile2 WinAPI 来自 kernelbase.dll?
那是不可能的。
解决方法 — 使用非托管互操作实现您自己的 FileStream class。比较简单,我的代码不到4页
这是您需要的导入:
static class NativeMethods
{
const string file121 = "api-ms-win-core-file-l1-2-1.dll";
const string handle110 = "api-ms-win-core-handle-l1-1-0.dll";
[DllImport( file121, CharSet = CharSet.Unicode, SetLastError = true )]
public static extern SafeFileHandle CreateFile2( [MarshalAs( UnmanagedType.LPWStr )] string filename,
FileAccess dwDesiredAccess, FileShare dwShareMode, FileMode dwCreationDisposition, IntPtr pCreateExParams );
[DllImport( handle110, SetLastError = true )]
[return: MarshalAs( UnmanagedType.Bool )]
internal static extern bool CloseHandle( IntPtr handle );
[DllImport( file121, SetLastError = true )]
[return: MarshalAs( UnmanagedType.Bool )]
static extern bool GetFileInformationByHandleEx( SafeFileHandle handle, FILE_INFO_BY_HANDLE_CLASS FileInformationClass, out FILE_STANDARD_INFO lpFileInformation, int dwBufferSize );
internal static FILE_STANDARD_INFO GetFileStandardInfo( SafeFileHandle handle )
{
FILE_STANDARD_INFO fsi;
if( !GetFileInformationByHandleEx( handle, FILE_INFO_BY_HANDLE_CLASS.FileStandardInfo, out fsi, Marshal.SizeOf<FILE_STANDARD_INFO>() ) )
throw new COMException( "GetFileInformationByHandleEx failed.", Marshal.GetHRForLastWin32Error() );
return fsi;
}
[DllImport( file121, SetLastError = true )]
[return: MarshalAs( UnmanagedType.Bool )]
internal static extern bool SetFilePointerEx( SafeFileHandle handle, long liDistanceToMove, out long lpNewFilePointer, SeekOrigin dwMoveMethod );
[DllImport( file121, SetLastError = true )]
[return: MarshalAs( UnmanagedType.Bool )]
internal static extern bool SetFilePointerEx( SafeFileHandle handle, long liDistanceToMove, IntPtr lpNewFilePointer, SeekOrigin dwMoveMethod );
[DllImport( file121, SetLastError = true )]
[return: MarshalAs( UnmanagedType.Bool )]
internal static extern bool FlushFileBuffers( SafeFileHandle handle );
[DllImport( file121, SetLastError = true )]
[return: MarshalAs( UnmanagedType.Bool )]
internal static extern unsafe bool ReadFile( SafeFileHandle hFile, byte* lpBuffer, uint nNumberOfBytesToRead, out uint lpNumberOfBytesRead, IntPtr lpOverlapped );
[DllImport( file121, SetLastError = true )]
[return: MarshalAs( UnmanagedType.Bool )]
internal static extern unsafe bool SetEndOfFile( SafeFileHandle hFile );
[ DllImport( file121, SetLastError = true )]
[return: MarshalAs( UnmanagedType.Bool )]
internal static extern unsafe bool WriteFile( SafeFileHandle hFile, byte* lpBuffer, uint nNumberOfBytesToWrite, out uint lpNumberOfBytesWritten, IntPtr lpOverlapped ); }
您还需要 structures/enums/SafeFileHandle,但与导入不同的是,这些很容易复制粘贴,例如来自 CoreFX.