【问题标题】:Can I get a path for a Memory Mapped File? (.NET 4.0)我可以获得内存映射文件的路径吗? (.NET 4.0)
【发布时间】:2009-07-11 22:15:26
【问题描述】:

我希望非 .NET 应用程序访问内存映射文件,但此应用程序不知道内存映射文件的存在,所以我需要文件路径。有可能的?

【问题讨论】:

  • 好问题...不幸的是,答案似乎是否定的。

标签: c# .net .net-4.0 memory-mapped-files


【解决方案1】:

他们有一些样本here

编辑

我认为this 会提供答案。基本上,内存映射文件似乎需要某种内存指针,而不是文件系统路径。

【讨论】:

    【解决方案2】:

    您可以使用GetMappedFileName 函数在映射时获取内存映射文件的路径。这当然要求内存映射文件实际上是由物理文件支持的,但是这个问题使得它的具体情况变得模糊不清。是不是某个第三方库给了你一个 MemoryMappedFile、MemoryMappedViewAccessor 或 MemoryMappedViewStream,但你不知道它是否有物理文件支持?

    这是一个示例,展示了如何从 MemoryMappedFile 中获取文件名:

    using Microsoft.Win32.SafeHandles;
    using System;
    using System.ComponentModel;
    using System.Diagnostics;
    using System.IO.MemoryMappedFiles;
    using System.Runtime.InteropServices;
    using System.Text;
    
    namespace MMFilePathTest
    {
        static class Program
        {
            private static MemoryMappedFile GetMappedPhysicalFile()
            {
                return MemoryMappedFile.CreateFromFile("test.bin", System.IO.FileMode.Create, null, 4096);
            }
    
            private static MemoryMappedFile GetMappedAnonymousMemory()
            {
                /* The documentation errounously claims that mapName must not be null. Actually anonymous
                 * mappings are quite a normal thing on Windows, and is actually both safer and more secure
                 * if you don't have a need for a name for them anyways.
                 * (Reported as https://github.com/dotnet/docs/issues/5404)
                 * Using a name here gives the exact same results (assuming the name isn't already in use). */
                return MemoryMappedFile.CreateNew(null, 4096);
            }
    
            /* This can be changed to kernel32.dll / K32GetMappedFileNameW if compatibility with Windows Server 2008 and
             * earlier is not needed, but it is not clear what the gain of doing so is, see the remarks about
             * PSAPI_VERSION at https://msdn.microsoft.com/en-us/library/windows/desktop/ms683195(v=vs.85).aspx */
            [DllImport("Psapi.dll", EntryPoint = "GetMappedFileNameW", CharSet = CharSet.Unicode, ExactSpelling = true, SetLastError = true)]
            private static extern int GetMappedFileName(
              SafeProcessHandle hProcess,
              SafeMemoryMappedViewHandle lpv,
              [Out] StringBuilder lpFilename,
              int nSize
            );
    
            /* Note that the SafeMemoryMappedViewHandle property of SafeMemoryMappedViewAccess and SafeMemoryMappedViewStream
             * is actually the address where the file is mapped */
            private static string GetPathWithGetMappedFileName(SafeMemoryMappedViewHandle memoryMappedViewHandle)
            {
                // The maximum path length in the NT kernel is 32,767 - memory is cheap nowadays so its not a problem 
                // to just allocate the maximum size of 32KB right away.
                StringBuilder filename = new StringBuilder(short.MaxValue);
                int len;
                len = GetMappedFileName(Process.GetCurrentProcess().SafeHandle, memoryMappedViewHandle, filename, short.MaxValue);
                if (len == 0)
                    throw new Win32Exception(Marshal.GetLastWin32Error());
                filename.Length = len;
                return filename.ToString();
            }
    
            private static void PrintFileName(MemoryMappedFile memoryMappedFile)
            {
                try
                {
                    using (memoryMappedFile)
                    using (MemoryMappedViewAccessor va = memoryMappedFile.CreateViewAccessor())
                    {
                        string filename = GetPathWithGetMappedFileName(va.SafeMemoryMappedViewHandle);
                        Console.WriteLine(filename);
                    }
                }
                catch (Win32Exception e)
                {
                    Console.WriteLine("Error: 0x{0:X08}: {1}", e.NativeErrorCode, e.Message);
                }
            }
    
            static void Main(string[] args)
            {
                PrintFileName(GetMappedPhysicalFile());
                PrintFileName(GetMappedAnonymousMemory());
            }
        }
    }
    

    当我运行它时,我得到了输出:

    \Device\HarddiskVolume5\Users\poizan\Documents\Visual Studio 2017\Projects\MMFilePathTest\MMFilePathTest\bin\Debug\test.bin
    Error: 0x000003EE: The volume for a file has been externally altered so that the opened file is no longer valid
    

    请注意,路径以原生 NT 路径格式返回。如果您需要将其转换为 dos/win32 格式,请参阅此问题:How can I convert a native (NT) pathname into a Win32 path name?

    对于没有关联文件时的错误,错误信息有点奇怪,但错误代码的意思是ERROR_FILE_INVALID,因为没有文件,所以有意义。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2011-01-20
      • 2016-03-25
      • 1970-01-01
      • 2019-11-21
      • 1970-01-01
      • 1970-01-01
      • 2010-09-26
      • 1970-01-01
      相关资源
      最近更新 更多