创建内存映射文件的进程无法找到该文件

本文关键字:文件 进程 内存 映射 创建 | 更新日期: 2023-09-27 18:10:53

我的目标是64位Windows 8上的。net Framework 3.5(遗憾的是4.0+不是这个项目的选项)。我最初认为问题是ProcessA制作的内存映射文件无法被ProcessB找到,但即使ProcessA也不能找到它刚刚制作的文件,即使句柄很好,可以用来写入和读取文件。在代码示例中,我在调用CreateFileMapping后立即调用OpenFileMapping,但即使在将数据写入文件后也会失败。我在CreateFileMapping中玩了文件映射属性,使其长并传入0,使其成为SECURITY_ATTRIBUTES结构体并传入IntPtr。lpSecurityDescriptor为零,一切都不愉快。我也尝试过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);

创建内存映射文件的进程无法找到该文件

[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。Ansi is used. And so the ANSI version of the function is used, which matches UnmanagedType。这次是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
);