0

What is the property or method (if any) that would provide the Win32 HANDLE from a .Net MemoryMappedFile?

I have unmanaged C++ code that reads from and writes to C-style FILEs, such as stdin and stdout. I want to create a MemoryMappedFile using MemoryMappedFile::CreateNew then get a Win32 HANDLE that can be converted to a FILE* for use in the unmanaged C++. I see MemoryMappedViewAccessor::SafeMemoryMappedViewHandle and SafeHandle and other possibilities but I don't find anything stating (or showing by example) that the handle can be used as a Win32 HANDLE in a C/C++ program. I am just not sure what specifically that provides the Win32 HANDLE. There are other possibilities, such as using all Windows API and no .Net but I am asking if this can be done using MemoryMappedFile, I am sure I can do it using all Windows API if it can't be done using MemoryMappedFile.

Update: The following is the code from @MichaelGunter converted to C++. See the comment from Hans Passant, he says this won't work and it does not. The handle returned from safeHandle->DangerousGetHandle() seems valid but when I call _open_osfhandle to convert the handle it fails.

MemoryMappedFile^ mmf = nullptr;
try { mmf = MemoryMappedFile::CreateNew("testmap", 10000, MemoryMappedFileAccess::ReadWrite); }
catch (Object^ ex)
{
    // show error
    return;
}
SafeMemoryMappedFileHandle^ safeHandle = mmf->SafeMemoryMappedFileHandle;
bool success = false;
safeHandle->DangerousAddRef(success);
if (!success)
{
    // show error
    return;
}
IntPtr handle = safeHandle->DangerousGetHandle();
if (safeHandle->IsInvalid)
{
    // show error
    return;
}
pin_ptr<const wchar_t> wchstr = PtrToStringChars(Message);
if (!Put((intptr_t)handle, const_cast<wchar_t*>(wchstr)))
{
    // show error
    return;
}
safeHandle->DangerousRelease();

And this is the "Put" function.

BOOL Put(intptr_t h, wchar_t* Message) {
    int fd = _open_osfhandle(h, 0);
    if (fd < 1)
        return FALSE;
    FILE * fp = _wfdopen(fd, L"w");
    fputws(Message, fp);
    return TRUE;
}

The MemoryMappedFile::SafeMemoryMappedFileHandle Property documentation says that I need security permission so I used the following in a few places.

[SecurityPermissionAttribute(SecurityAction::LinkDemand, UnmanagedCode = true)]
Sam Hobbs
  • 2,594
  • 3
  • 21
  • 32
  • @Dan, yes, thank you. I knew about that. I should have said handle in my question. I apologize for being confused. I will try to update my question to say handle instead of FILE*. – Sam Hobbs Apr 05 '17 at 21:22
  • You cannot convert such a handle to FILE*. XY question. – Hans Passant Apr 06 '17 at 00:54
  • @HansPassant, I know to trust you. Microsoft should say that in the documentation. I know that SafeHandle replaces something else that I forget what it is because it is deprecated but it does state explicitly what you are saying. I was hoping that since the SafeHandle documentation does not indicate the limitation that it does not exist for SafeHandles. I don't know what a XY question is unless you are saying this is a male question based on XY chromosomes. – Sam Hobbs Apr 06 '17 at 01:23
  • See [what is the XY problem](https://meta.stackexchange.com/questions/66377/what-is-the-xy-problem). The fundamental problem has nothing to do with SafeHandle or .NET, it's just that a handle to a memory mapping isn't the same thing as a handle to a file, and the two aren't interchangeable. A handle to a file can be used with functions like ReadFile and WriteFile, a handle to a memory mapping can be used with functions like MapViewOfFile. You can't call ReadFile with a handle to a memory mapping. – Harry Johnston Apr 06 '17 at 03:46
  • 2
    ... specifically, in this case, `_open_osfhandle` requires a file handle. It won't work for any other kind of handle. And I note that the documentation **does** in fact say that. – Harry Johnston Apr 06 '17 at 04:28
  • @HarryJohnston, I see nothing in the [SafeHandle Class](https://msdn.microsoft.com/en-us/library/system.runtime.interopservices.safehandle(v=vs.110).aspx) documentation, [SafeMemoryMappedFileHandle class](https://msdn.microsoft.com/en-us/library/microsoft.win32.safehandles.safememorymappedfilehandle(v=vs.110).aspx) documentation or [SafeHandle.DangerousGetHandle Method](https://msdn.microsoft.com/en-us/library/system.runtime.interopservices.safehandle.dangerousgethandle(v=vs.110).aspx) documentation saying that the handle is not a file handle. SafeMemoryMappedFileHandle implies file handle. – Sam Hobbs Apr 06 '17 at 18:00
  • So why the -1 on the question? As I said, the documentation does not provide the answer. – Sam Hobbs Apr 06 '17 at 18:07
  • I suspect that some people look for any excuse to downvote questions about Windows, but there's no way to tell. The name of the `SafeMemoryMappedFileHandle` function should be parsed as `Safe(MemoryMappedFile)Handle`, i.e., a handle to a memory mapped file object (more properly called a file mapping object) which is not the same thing as a handle to a file object. But yes, the terminology is confusing and documentation isn't as clear as it could be. The .NET documentation in particular tends to assume that you're already familiar with the underlying concepts. – Harry Johnston Apr 06 '17 at 20:51

2 Answers2

1

While you can get a handle to the memory mapped file object (as already described in Michael's answer) you won't be able to pass this handle to __open_osfhandle because a memory mapped file object cannot be used as if it were a file object. That is, you cannot read from or write to the handle; it can only be used to map a view of the file mapping object into memory.

Using the Win32 API directly won't make any difference. File mapping objects simply don't provide the functionality you're looking for.

Instead, you should try using a pipe object. Pipes can be treated as files, provided you don't attempt to move the file pointer. And I believe Microsoft's C runtime can accept a pipe handle in place of a file handle, even though this isn't mentioned in the documentation.

See Pipe Operations in the .NET Framework to get started.

Harry Johnston
  • 35,639
  • 6
  • 68
  • 158
  • pipes use the Win32 API. I am familiar with [Creating a Child Process with Redirected Input and Output](https://msdn.microsoft.com/en-us/library/windows/desktop/ms682499(v=vs.85).aspx). A few years ago I tried to get .Net's implementation of pipes to work and I could not. I think that it is better to use WCF for pipes in .Net. I prefer to use pipes directly through the Windows API if I use pipes. – Sam Hobbs Apr 06 '17 at 21:35
  • 1
    Yes, since you're writing in C++ the Win32 API would probably be my preference too, depending on the context. I had assumed that since you were using .NET's MemoryMappedFile class rather than CreateFileMapping, you'd also prefer the .NET pipe classes, but it doesn't really make any difference in the end. – Harry Johnston Apr 06 '17 at 21:45
0

Given a MemoryMappedFile:

MemoryMappedFile mmf = ...;

Get a "safe" handle. Store this safe handle for as long as the handle is in use.

SafeMemoryMappedFileHandle safeHandle = mmf.SafeMemoryMappedFileHandle;

Add a reference to the handle so that it's not reclaimed:

bool success = false;
safeHandle.DangerousAddRef(ref success);
if (!success)
    throw new InvalidOperationException("Failed to addref handle.");

Get the raw handle:

IntPtr handle = safeHandle.DangerousGetHandle();

When you're done with the raw handle, release the safe handle:

safeHandle.DangerousRelease();
Michael Gunter
  • 12,528
  • 1
  • 24
  • 58