tags:

views:

74

answers:

3

I open a file in C# with FileStream, and I got the file handle number with this line:

IntPtr file_handle = fs.SafeFileHandle.DangerousGetHandle();

Now I want to pass this handle to C++ code and use this handle value to access the file. Is this possible? How to open a file with merely a file handle in C++?

Thanks.

Update

I use C# to P/Invoke into a C++ Win32 DLL(not a COM DLL). I open the file in C# as FileStream, and pass the handle to the C++. Here is some of my code in the C++ DLL:

extern "C" __declspec(dllexport)void read_file(HANDLE file_handle)
{
    char buffer[64];
    ::printf("\nfile = %d\n",file_handle);

    if(::ReadFile(file_handle,buffer,32,NULL,NULL))
    {
        for(int i=0;i<32;i++)
            cout<<buffer[i]<<endl;
    }
    else
        cout<<"error"<<endl;
}

And here is my C# code:

    [DllImport("...",EntryPoint = "read_file", CharSet = CharSet.Auto)]
    public static extern void read_file(IntPtr file_handle_arg);

But I get this error:

Unhandled Exception: System.AccessViolationException: Attempted to read or write
 protected memory. This is often an indication that other memory is corrupt.

Thanks.

+2  A: 

You can use win32 calls, the same way the filestream/file constructors do (via p/invoke).

Cracking it open in .NET Reflector, it looks like it is using this function:

[DllImport("kernel32.dll", CharSet=CharSet.Auto, SetLastError=true)]
private static extern SafeFileHandle CreateFile(
  string lpFileName,
  int dwDesiredAccess,
  FileShare dwShareMode,
  SECURITY_ATTRIBUTES securityAttrs,
  FileMode dwCreationDisposition,
  int dwFlagsAndAttributes,
  IntPtr hTemplateFile);

Here is an official reference:

http://msdn.microsoft.com/en-us/library/aa363858(VS.85).aspx

This is just to open the file, though, as you asked when you said:

How to open a file with merely a file handle in C++

If you want to read an already open file, you might have more trouble. I'm not sure. You might be able to use this function:

[DllImport("kernel32.dll", SetLastError=true)]
internal static extern unsafe int ReadFile(
  SafeFileHandle handle,
  byte* bytes,
  int numBytesToRead,
  IntPtr numBytesRead_mustBeZero,
  NativeOverlapped* overlapped
);

http://msdn.microsoft.com/en-us/library/aa365467(v=VS.85).aspx

Merlyn Morgan-Graham
Thanks Merlyn, but this method requires a file name, while I have only a file handle.
smwikipedia
+1. I don't see where the method requires a file name smwikipedia....
Billy ONeal
@smwikipedia: You may have written your comment while I was still editing my post. Check out the second function, ReadFile
Merlyn Morgan-Graham
got it~~ thanks man~
smwikipedia
+1  A: 

That entirely depends -- but it's unlikely that you will be able to do this. I'm assuming that your C# code and C++ code are running in different processes -- if you're in the same process you should just be able to marshall over the IntPtr over as a HANDLE.

The problem is that file handles are specific to a process -- you won't be able to use that handle in another process.

That said, you're probably better off:

  • Passing the name of the file to the C++ code and opening it there
  • Passing the data actually contained whithin the file to the C++ and dealing with it there.
Billy ONeal
This is probably more accurate than my post, because the file handle is probably process specific. You can try ReadFile, and if that doesn't work, you'll simply have to open the file using C++ functions, as Billy is saying here.
Merlyn Morgan-Graham
A: 

If the C++ code is C++/CLI, then don't bother with the handle at all. Just pass the FileStream object directly to your C++ code.

If the C++ is native code, then you can use the file handle anywhere you'd normally use a Windows HANDLE value for files, such as ReadFile and WriteFile. You wouldn't use the handle to open a file because it's already open. If you want another copy of the handle, or if you want to give the handle to another process, then use DuplicateHandle. If you need to the value with POSIX-like functions like _read and _write, then call _open_osfhandle to get a file descriptor. You can wrap the file descriptor into a C FILE* stream with _fdopen.

Rob Kennedy