Sam Hobbs
Sam Hobbs

Reputation: 2881

Get Win32 HANDLE from MemoryMappedFile

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)]

Upvotes: 0

Views: 1060

Answers (2)

Harry Johnston
Harry Johnston

Reputation: 36308

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.

Upvotes: 1

Michael Gunter
Michael Gunter

Reputation: 12811

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();

Upvotes: 0

Related Questions