2014-06-30 20 views
1

我針對.NET Framework 3.5的發現(4.0+可悲的是不是這個項目的一個選項)在64位的Windows 8,我原本以爲問題是,由ProcessA作出的內存映射文件不容易找到的進程B,但即使不ProcessA可以找到剛纔保存的文件,即使手感好,可用於書寫和讀取文件。在代碼示例中,我在調用CreateFileMapping之後立即調用OpenFileMapping,但即使在將數據寫入文件之後它仍然失敗。我已經使用了與文件映射的CreateFileMapping屬性,使其長傳入0,使其成爲一個SECURITY_ATTRIBUTES結構和IntPtr.Zero傳遞的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); 
+0

您的標註聲明非常漂亮。最嚴重的錯誤是在您的CreateFileMapping()聲明中,它會創建一箇中文名稱的MMF。刪除[MarshalAs]。使用pinvoke.net網站以取得進展。 –

+0

@HansPassant這裏就屬於這種情況,正如經常出現的方式,用pinvoke.net讓後面的。 Q中的p/invoke來自那裏!我只是修復它。 pinvoke.net是非常可怕的。也許我們應該找一些專家來整理一個正確的選擇。花時間寫出權威指南來與我聯繫? ;-) –

+0

你說得對,漢斯!不幸的是,CreateFileMapping和OpenFileMapping的pinvoke示例(我使用過)通過免費將字符串封裝爲LPStr而打破了這個例子。謝謝! –

回答

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。正如漢斯所說,這意味着當系統解釋你所提供的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 
); 
+0

謝謝大衛!我很擔心安全問題的可能性,所以我沒有適當注意字符串處理。 –