从MemoryMappedFile获取Win32 HANDLE

时间:2017-04-05 21:04:09

标签: .net winapi c++-cli

从.Net MemoryMappedFile提供Win32 HANDLE的属性或方法(如果有的话)是什么?

我有非托管C ++代码,可以读取和写入C风格的文件,例如stdin和stdout。我想使用MemoryMappedFile :: CreateNew创建一个MemoryMappedFile,然后获得一个Win32 HANDLE,可以将其转换为FILE *,以便在非托管C ++中使用。我看到MemoryMappedViewAccessor :: SafeMemoryMappedViewHandle和SafeHandle以及其他可能性,但我没有发现任何说明(或通过示例显示)该句柄可以用作C / C ++程序中的Win32 HANDLE。我只是不确定具体提供Win32 HANDLE。还有其他的可能性,例如使用所有Windows API而不使用.Net,但我问这是否可以使用MemoryMappedFile完成,我确信如果无法使用MemoryMappedFile,我可以使用所有Windows API。

更新:以下是@MichaelGunter转换为C ++的代码。看看Hans Passant的评论,他说这不起作用,但事实并非如此。从safeHandle-> DangerousGetHandle()返回的句柄似乎有效但是当我调用_open_osfhandle来转换句柄时它失败了。

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

这就是“Put”功能。

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;
}

MemoryMappedFile::SafeMemoryMappedFileHandle Property 文档说我需要安全许可,所以我在几个地方使用了以下内容。

[SecurityPermissionAttribute(SecurityAction::LinkDemand, UnmanagedCode = true)]

2 个答案:

答案 0 :(得分:0)

给定MemoryMappedFile:

public class PerformanceCounterDisplay : MonoBehaviour
{
    private PerformanceCounter _cpuCounter;
    private PerformanceCounter _ramCounter;

    [SerializeField]
    private Text _cpuCounterText;

    [SerializeField]
    private Text _ramCounterText;

    void Start()
    {
        _cpuCounter = new PerformanceCounter("Process", "% Processor Time", "_Total");
        _ramCounter = new PerformanceCounter("Memory", "Available MBytes", "_Total");
        _cpuCounterText.text = GetCpuUsage();
        _ramCounterText.text = GetRamUsage();
    }

    void Update()
    {
        _cpuCounterText.text = GetCpuUsage();
        _ramCounterText.text = GetRamUsage();
    }

    public string GetCpuUsage()
    {
        try
        {
            return "CPU: " + _cpuCounter.NextValue() + "%";
        }
        catch (Exception eh)
        {
            Debug.LogError("Cannot get infomation about this PC's CPU");
        }
        return "";
    }

    public string GetRamUsage()
    {
        try
        {
            return "RAM: " + _ramCounter.NextValue() + "MB";
        }
        catch (Exception eh)
        {
            Debug.LogError("Cannot get infomation about this PC's RAM");
        }
        return "";
    }
}

获得“安全”手柄。只要手柄处于使用状态,请存放此安全手柄。

MemoryMappedFile mmf = ...;

添加对句柄的引用,使其不被回收:

SafeMemoryMappedFileHandle safeHandle = mmf.SafeMemoryMappedFileHandle;

获取原始句柄:

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

完成原始手柄后,释放安全手柄:

IntPtr handle = safeHandle.DangerousGetHandle();

答案 1 :(得分:0)

虽然您可以获取内存映射文件对象的句柄(如Michael的回答中所述),但您将无法将此句柄传递给__open_osfhandle,因为无法使用内存映射文件对象,就好像它是一个文件对象。也就是说,你无法读取或写入句柄;它只能 用于将文件映射对象的视图映射到内存中。

直接使用Win32 API不会有任何区别。文件映射对象根本不提供您正在寻找的功能。

相反,您应该尝试使用管道对象。如果您不尝试移动文件指针,则管道可以被视为文件。我相信Microsoft的C运行时可以接受管道句柄来代替文件句柄,即使文档中没有提到这一点。

请参阅Pipe Operations in the .NET Framework开始使用。