2010-03-22 71 views
3

我正在使用傳統文件格式。託管.NET等同於WinBase中的CreateFile和WriteFile(kernel32.dll)

該文件是使用非託管C++創建的,該C++利用WinBase.h CreateFile()& WriteFile()函數(可在kernel32.dll中找到)。我一直在以P

/Invoke的互操作來訪問,像這樣這些本機功能:

[DllImport("kernel32.dll")] 
    public static extern bool WriteFile(
     IntPtr hFile, 
     byte[] lpBuffer, 
     uint nNumberOfBytesToWrite, 
     out uint lpNumberOfBytesWritten, 
     [In] ref NativeOverlapped lpOverlapped); 

    [DllImport("kernel32.dll", SetLastError = true)] 
    public static extern bool WriteFileEx(
     IntPtr hFile, 
     byte[] lpBuffer, 
     uint nNumberOfBytesToWrite, 
     [In] ref NativeOverlapped lpOverlapped, 
     WriteFileCompletionDelegate lpCompletionRoutine); 

    [DllImport("kernel32.dll", SetLastError = true)] 
    public static extern IntPtr CreateFile(
     string lpFileName, uint dwDesiredAccess, 
     uint dwShareMode, IntPtr lpSecurityAttributes, 
     uint dwCreationDisposition, 
     uint dwFlagsAndAttributes, IntPtr hTemplateFile); 

    [DllImport("kernel32.dll", SetLastError = true)] 
    public static extern bool CloseHandle(IntPtr hObject); 

    public delegate void WriteFileCompletionDelegate(
     UInt32 dwErrorCode, 
     UInt32 dwNumberOfBytesTransfered, 
     ref NativeOverlapped lpOverlapped); 

與此問題是,當我打電話的WriteFile(),該文件總是由程序調用覆蓋。

優選我想使用一個兼容的.NET等價物,它將允許我生成完全相同的輸出格式。

的C++代碼看起來像這樣:(WORKING)

HANDLE hFile = CreateFile(sFileName, GENERIC_WRITE, FILE_SHARE_WRITE, NULL, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL); 
WriteFile(hFile, &someVar1, sizeof(bool), &dwWritten, NULL); 
WriteFile(hFile, &someVar1, sizeof(long), &dwWritten, NULL); 
WriteFile(hFile, &someVar2, sizeof(bool), &dwWritten, NULL); 
WriteFile(hFile, sStr.GetBuffer(0), dwStrLen*sizeof(TCHAR), &dwWritten, NULL); 
CloseHandle(hFile); 

C#的是如下:(覆蓋以前WRITE即會輸出文件將只包含 'T')

{ 
    var hFile = COMFileOps2.CreateFile(FILE_NAME, (uint) COMFileOps2.FILE_GENERIC_WRITE, 
             COMFileOps2.FILE_SHARE_WRITE, IntPtr.Zero, COMFileOps2.CREATE_ALWAYS, 
             COMFileOps2.FILE_ATTRIBUTE_NORMAL, IntPtr.Zero); 

    var natOverlap = new NativeOverlapped(); 

    COMFileOps2.WriteFileEx(hFile, new byte[] {(byte) 't'}, 1, ref natOverlap, Callback); 
    COMFileOps2.WriteFileEx(hFile, new byte[] { (byte)'e' }, 1, ref natOverlap, Callback); 
    COMFileOps2.WriteFileEx(hFile, new byte[] { (byte)'s' }, 1, ref natOverlap, Callback); 
    COMFileOps2.WriteFileEx(hFile, new byte[] { (byte)'T' }, 1, ref natOverlap, Callback); 

    COMFileOps2.CloseHandle(hFile); 

} 

private static void Callback(uint dwerrorcode, uint dwnumberofbytestransfered, ref NativeOverlapped lpoverlapped) 
{ 
    throw new NotImplementedException(); 
} 

更新:下面的C#代碼將寫出「測試」:

uint written; 
uint position = 0; 

var natOverlap0 = new NativeOverlapped(); 
COMFileOps.WriteFile(hFile, new byte[] {(byte) 'T'}, 1, out written, ref natOverlap0); 

position += written; 
var natOverlap1 = new NativeOverlapped {OffsetLow = (int) position}; 
COMFileOps.WriteFile(hFile, new byte[] { (byte)'e' }, 1, out written, ref natOverlap1); 

position += written; 
var natOverlap2 = new NativeOverlapped { OffsetLow = (int)position }; 
COMFileOps.WriteFile(hFile, new byte[] { (byte)'s' }, 1, out written, ref natOverlap2); 

position += written; 
var natOverlap3 = new NativeOverlapped { OffsetLow = (int)position }; 
COMFileOps.WriteFile(hFile, new byte[] { (byte)'t' }, 1, out written, ref natOverlap3); 

COMFileOps.CloseHandle(hFile); 

謝謝。

回答

3

WriteFileEx只能異步運行,您必須爲每個掛起的調用提供OVERLAPPED的SEPARATE實例,並且您必須設置OVERLAPPED成員,例如作爲文件偏移量,那麼在所有的操作完成之前你不能調用CloseHandle,並且使用一個局部變量來覆蓋範圍,並讓它超出範圍?你的數據被覆蓋的是可能出錯的東西的至少你顯示的代碼是

所以這就是爲什麼你的代碼不起作用,我不知道你爲什麼從WriteFile切換到WriteFileEx,另外,從C#調用Win32 API是非常不方便的,儘管偶爾具完整。但首先看看.NET File API是否能滿足你的需求。由於.NET File API傾向於使用字符串(在textmode中,注意換行符等)或字節數組,因此您需要將其他變量轉換爲byte []。 BitConverter班是你的朋友在這裏。

0

看看System.IO.FileSystem.IO.FileInfo類他們都提供您正在尋找的方法。

3

你沒有解釋你想要處理什麼樣的格式,但不是File.WriteAllText足夠嗎?

File.WriteAllText("someFile.txt", "some format"); 

對於二進制文件,你可以使用File.WriteAllBytes

File.WriteAllText("someFile.bin", new byte[] { 0x1, 0x2, 0x3 }); 
1

沒有什麼特別之處的原始API調用。只需獲得System.IO.FileStream並在其上調用寫入。 (獲取FileStream的一種方法是首先獲取System.IO.File

+5

實際上,原始的API調用I/O比功能強大得多。例如,Win32函數可以與控制檯,命名管道,郵筒,串行端口一起工作(並且可以通過其真實設備名稱打開所述串行端口),真正漫長而奇怪的文件名等。但是這些似乎都不適用於此。 – 2010-03-22 17:54:31