Reputation: 95
I'm targeting .Net Framework 3.5 (4.0+ is sadly not an option for this project) on 64-bit Windows 8. I originally thought the problem was that the memory mapped file made by ProcessA was not findable by ProcessB, but not even ProcessA can find the file it just made, even though the handle is good and can be used to write and read the file. In the code example I call OpenFileMapping right after calling CreateFileMapping, but it fails even after writing data to the file. I've played with the file mapping attributes in CreateFileMapping, making it long and passing in 0, making it a SECURITY_ATTRIBUTES struct and passing in IntPtr.Zero for the lpSecurityDescriptor, all with no joy. I've also tried FileMapAccess ReadWrite and AllAccess with no joy. I've also tried making memoryfilename not constant. I'm not seeing why the mapped file cannot be found, even by the process that created it. Here are the bare bones of the code involved:
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);
Upvotes: 1
Views: 1867
Reputation: 613372
[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
);
The DllImport
attribute uses CharSet.Auto
which means that the wide character version of the function will be used. You then pass an ANSI encoded string because you used UnmanagedType.LPStr
. Which, as Hans says, means that your name will be mangled when the system interprets the ANSI encoded text you supplied as though it was UTF-16 encoded.
[DllImport("kernel32.dll", SetLastError = true)]
static extern IntPtr OpenFileMapping(
FileMapAccess dwDesiredAccess,
Int32 bInheritHandle,
[MarshalAs(UnmanagedType.LPStr)]
string lpName
);
This time you omit CharSet.Auto
and so the default of ``CharSet.Ansiis used. And so the ANSI version of the function is used, which matches
UnmanagedType.LPStr` this time. Hence the intended name is passed.
All this explains why the system reports ERROR_FILE_NOT_FOUND
.
Fix the p/invoke declarations and all will be well.
[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
);
Upvotes: 1