Recipe 11.19 Opening a File Stream with just aFile Handle

Problem

When interoperating with unmanaged code, you encounter a situation where you are provided a file handle and no other information. This file handle must be used to open its corresponding file.

Solution

In order to use an unmanaged file handle to access a file, use the FileStream class. The unmanaged file handle could have been generated using P/Invoke to open a file and get the file handle. The code would then pass it to the WriteToFileHandle managed method for writing data, then flush and close the unmanaged file handle. This setup is illustrated in the following code:

 public void UsingAnUnmanagedFileHandle( ) {     IntPtr hFile = IntPtr.Zero;     // create a file using unmanaged code     hFile = (IntPtr)FileInteropFunctions.CreateFile("data.txt",         FileInteropFunctions.GENERIC_WRITE,         0,         IntPtr.Zero,         FileInteropFunctions.CREATE_ALWAYS,         0,         0);     if(hFile.ToInt64( ) > 0)     {         // write to the file using managed code         WriteToFileHandle(hFile);         // close the file         FileInteropFunctions.CloseHandle(hFile);         // remove the file         File.Delete("data.txt");     } } 

In order to write to the file handle, we wrap it in a FileStream , passing the file handle as the first parameter. Once we have the file stream, we use the capabilities of the FileStream to write to the file handle by getting the bytes from a string in ASCII encoding format and calling Write on the file stream, as shown here:

 public static void WriteToFileHandle(IntPtr hFile) {     // Open a FileStream object using the passed in file handle     // pass false so that the stream doesn't own the handle, if this was true,      // closing the filestream would close the handle     FileStream fileStream = new FileStream(hFile, FileAccess.ReadWrite, false);     // flush before we start to clear any pending unmanaged actions     fileStream.Flush( );         // Operate on file here...     string line = "Managed code wrote this line!";     // write to the file     byte[] bytes = Encoding.ASCII.GetBytes(line);     fileStream.Write(bytes,0,bytes.Length);     // just close the file stream     fileStream.Close( ); } 

In order to perform the unmanaged functions of creating, flushing, and closing the file handle, we have wrapped the unmanaged Win32 API functions for these functions. The DllImport attribute says that these functions are being used from kernel32.dll and the SetLastError attribute is set to true , so that we can see if anything went wrong. A few of the #defines used with file creation have been brought over from unmanaged code for readability:

 class FileInteropFunctions {     public const uint GENERIC_READ = (0x80000000);     public const uint GENERIC_WRITE = (0x40000000);     public const uint GENERIC_EXECUTE = (0x20000000);     public const uint GENERIC_ALL = (0x10000000);     public const uint CREATE_NEW        = 1;     public const uint CREATE_ALWAYS     = 2;     public const uint OPEN_EXISTING     = 3;     public const uint OPEN_ALWAYS       = 4;     public const uint TRUNCATE_EXISTING = 5;     [DllImport("kernel32.dll", SetLastError=true)]     public static extern bool CloseHandle(IntPtr hObject);             [DllImport("kernel32.dll", SetLastError=true)]     public static extern IntPtr CreateFile(         String lpFileName,              // filename         uint dwDesiredAccess,              // access mode         uint dwShareMode,              // share mode         IntPtr attr,                  // Security Descriptor         uint dwCreationDisposition,          // how to create         uint dwFlagsAndAttributes,          // file attributes         uint hTemplateFile);              // handle to template file     [DllImport("kernel32.dll", SetLastError=true)]     public static extern bool FlushFileBuffers(IntPtr hFile); } 

Discussion

You can open a file using one of the overloaded constructors of the FileStream class and passing a file handle into it. When opening a file handle, determine whether this object should be able to close this file's handle. If the unmanaged code creating the file intends to hand off ownership to the managed code, the object should set the ownsHandle parameter to true . The ownsHandle parameter is the third parameter on the constructor used with an existing handle. In many cases, this instance should not be allowed to close this file's handle. Instead, let the code that initially opened the file also close the file. If in doubt, set this parameter to false .

Keep your code short when opening a file using a file handle. Call the FileStream.Close method as soon as possible. The reason for this recommendation is that another object might also have this file open, and operating on that file through both FileStream objects can corrupt the data in the file.

See Also

See the "DllImport Attribute," "File Class," and "FileStream Class" topics in the MSDN documentation.



C# Cookbook
C# 3.0 Cookbook
ISBN: 059651610X
EAN: 2147483647
Year: 2003
Pages: 315

flylib.com © 2008-2017.
If you may any questions please contact us: flylib@qtcs.net