【问题标题】:Memory-Mapped file can't be found by the process that just created it刚刚创建它的进程找不到内存映射文件
【发布时间】:2014-06-30 14:19:34
【问题描述】:

我的目标是 64 位 Windows 8 上的 .Net Framework 3.5(遗憾的是,4.0+ 不是这个项目的选项)。我最初认为问题是 ProcessA 生成的内存映射文件无法被 ProcessB 找到,但即使是 ProcessA 也找不到它刚刚创建的文件,即使句柄很好并且可以用来写入和读取文件。在代码示例中,我在调用 CreateFileMapping 后立即调用 OpenFileMapping,但即使在将数据写入文件后它也会失败。我已经在 CreateFileMapping 中使用了文件映射属性,使其变长并传入 0,使其成为 SECURITY_ATTRIBUTES 结构并为 lpSecurityDescriptor 传入 IntPtr.Zero,所有这些都没有任何乐趣。我也毫无乐趣地尝试了 FileMapAccess ReadWrite 和 AllAccess。我也试过让 memoryfilename 不恒定。我看不到为什么找不到映射文件,即使是创建它的进程也是如此。以下是所涉及代码的基本内容:

private IntPtr hHandle;
private IntPtr INVALID_HANDLE_VALUE = new IntPtr(-1);
public const Int64 FILESIZE = 1024 * 1024;
private const string memoryfilename = "myfilename";

//CreateFileMapping
[DllImport("kernel32.dll", SetLastError = true, CharSet = CharSet.Auto)]
static extern IntPtr CreateFileMapping(
IntPtr hFile,
IntPtr lpFileMappingAttributes,
FileMapProtection flProtect,
uint dwMaximumSizeHigh,
uint dwMaximumSizeLow,
[MarshalAs(UnmanagedType.LPStr)] string lpName);

//OpenFileMapping
[DllImport("kernel32.dll", SetLastError = true)]
static extern IntPtr OpenFileMapping(
FileMapAccess dwDesiredAccess,
Int32 bInheritHandle, 
[MarshalAs(UnmanagedType.LPStr)] string lpName);

[Flags]
public enum FileMapAccess : uint
{
  FileMapCopy = 0x0001,
  FileMapWrite = 0x0002,
  FileMapRead = 0x0004,
  FileMapReadWrite = 0x0006,
  FileMapAllAccess = 0x001f,
  FileMapExecute = 0x0020,
}

[Flags]
enum FileMapProtection : uint
{
  PageReadonly = 0x02,
  PageReadWrite = 0x04,
  PageWriteCopy = 0x08,
  PageExecuteRead = 0x20,
  PageExecuteReadWrite = 0x40,
  SectionCommit = 0x8000000,
  SectionImage = 0x1000000,
  SectionNoCache = 0x10000000,
  SectionReserve = 0x4000000,
}

//hHandle becomes non-zero
hHandle= CreateFileMapping(
INVALID_HANDLE_VALUE, IntPtr.Zero, FileMapProtection.PageReadWrite,
(uint)0, (uint)FILESIZE, memoryfilename);

//hHandle2 stays zero
IntPtr hHandle2 = OpenFileMapping(FileMapAccess.FileMapWrite, 0, memoryfilename);

//myerror is 2 ERROR_FILE_NOT_FOUND
uint myerror = GetLastError();

//this works and I can read/write the file through UnmanagedMemoryStream
pBuffer = MapViewOfFile(hHandle, FileMapAccess.FileMapWrite, 0, 0, (uint)FILESIZE);

【问题讨论】:

  • 您的 pinvoke 声明非常糟糕。最严重的错误是在您的 CreateFileMapping() 声明中,它创建了一个带有中文名称的 MMF。删除 [MarshalAs]。使用 pinvoke.net 网站取得成功。
  • @HansPassant 这是一个使用 pinvoke.net 落后的案例,通常是这样。 Q 中的 p/invoke 来自那里!我刚刚修好了。 pinvoke.net 真的很可怕。也许我们应该找一些专家来制定一个正确的替代方案。想和我一起写一本权威指南吗?!! ;-)
  • 你是对的,汉斯!不幸的是,我打破了 CreateFileMapping 和 OpenFileMapping 的 pinvoke 示例(我使用的),无偿地将字符串编组为 LPStr。谢谢!

标签: c# winapi pinvoke


【解决方案1】:
[DllImport("kernel32.dll", SetLastError = true, CharSet = CharSet.Auto)]
static extern IntPtr CreateFileMapping(
    IntPtr hFile,
    IntPtr lpFileMappingAttributes,
    FileMapProtection flProtect,
    uint dwMaximumSizeHigh,
    uint dwMaximumSizeLow,
    [MarshalAs(UnmanagedType.LPStr)] 
    string lpName
);

DllImport 属性使用CharSet.Auto,这意味着将使用函数的宽字符版本。然后传递一个 ANSI 编码的字符串,因为您使用了UnmanagedType.LPStr。正如 Hans 所说,这意味着当系统将您提供的 ANSI 编码文本解释为 UTF-16 编码时,您的姓名将被破坏。

[DllImport("kernel32.dll", SetLastError = true)]
static extern IntPtr OpenFileMapping(
    FileMapAccess dwDesiredAccess,
    Int32 bInheritHandle, 
    [MarshalAs(UnmanagedType.LPStr)] 
    string lpName
);

这次你省略了CharSet.Auto,所以这次默认的`CharSet.Ansiis used. And so the ANSI version of the function is used, which matchesUnmanagedType.LPStr`。因此,预期的名称被传递。

这一切都解释了为什么系统会报告ERROR_FILE_NOT_FOUND

修复 p/invoke 声明,一切都会好起来的。

[DllImport("kernel32.dll", SetLastError = true, CharSet = CharSet.Unicode)]
static extern IntPtr CreateFileMapping(
    IntPtr hFile,
    IntPtr lpFileMappingAttributes,
    FileMapProtection flProtect,
    uint dwMaximumSizeHigh,
    uint dwMaximumSizeLow,
    string lpName
);

[DllImport("kernel32.dll", SetLastError = true, CharSet = CharSet.Unicode)]
static extern IntPtr OpenFileMapping(
    FileMapAccess dwDesiredAccess,
    bool bInheritHandle, 
    string lpName
);

【讨论】:

  • 谢谢你,大卫!我非常关注安全问题的可能性,以至于我没有适当注意字符串处理。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2020-07-29
  • 2023-03-04
  • 2018-03-09
  • 2013-05-03
  • 2021-12-10
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多