托管 .NET 相当于 CreateFile &来自 WinBase 的 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++ 代码如下所示:(正在运行)
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# 如下:(覆盖先前的写入,即输出文件将仅包含“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# 代码将写出“Test” :
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);
谢谢。
I am working with a legacy file format.
The file is created using unmanaged C++ that utilizes the WinBase.h CreateFile() & WriteFile() functions (found in the kernel32.dll).
I have been using P/Invoke interop to access these native functions like so:
[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);
The issue with this is when I call WriteFile(), the file is always overwritten by the proceeding call.
Preferable I would like to use a compatible .NET equivalent that would allow me to produce the exact same format of output.
The C++ code looks like so: (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);
The C# is as follows: (OVERWRITES PREVIOUS WRITE i.e. will output file will contain only '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();
}
UPDATE: The following C# code will write out "Test":
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);
Thanks.
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(4)
原始 API 调用没有什么特别之处。只需获取 System.IO.FileStream 并调用写在上面。 (获取 FileStream 的一种方法是首先获取 System.IO.File。
There's nothing particularly special about the raw API calls. Just get a System.IO.FileStream and call Write on it. (One way to get the FileStream is to first acquire a System.IO.File first.
WriteFileEx 仅异步运行,您必须为每个挂起的调用提供一个单独的 OVERLAPPED 实例,并且必须设置 OVERLAPPED 成员,例如文件偏移量。然后,在所有操作完成之前,您不能调用 CloseHandle。并使用局部变量 OVERLAPPED 并让它超出范围?您的数据被覆盖是您所显示的代码最少可能出现问题的情况。
这就是你的代码不起作用的原因。我不知道你为什么从 WriteFile 切换到 WriteFileEx。此外,从 C# 调用 Win32 API 非常不方便,尽管有时是必要的。但首先看看 .NET 文件 API 是否满足您的需要。
由于 .NET 文件 API 倾向于使用字符串(在文本模式下,注意换行转换等)或字节数组,因此您需要将其他变量转换为 byte[]。 BitConverter 类是您的朋友。
WriteFileEx only runs asynchronously, you must provide a SEPARATE instance of OVERLAPPED for each pending call, and you must setup the OVERLAPPED members, such as the file offset. Then you can't call CloseHandle until all the operations finish. And using a local variable for OVERLAPPED and letting it go out of scope? Your data getting overwritten is the least of the things that can go wrong with the code you show.
So that's why your code doesn't work. I don't know why you switched from WriteFile to WriteFileEx in the first place. In addition, calling the Win32 API from C# is quite inconvenient, although occasionally necessary. But first see if the .NET File APIs do what you need.
Since .NET File APIs tend to work with either strings (in textmode, watch for newline conversions and such) or arrays of bytes, you need to turn your other variables into byte[]. The BitConverter class is your friend here.
您没有解释您尝试处理的格式,但不是 文件。 WriteAllText 足够了吗?
对于二进制文件,您可以使用 File.WriteAllBytes:
You didn't explain what format you are trying to handle but isn't File.WriteAllText sufficient?
For binary files you could use File.WriteAllBytes:
查看 System.IO.File 和 System.IO.FileInfo 类,它们都提供您正在寻找的方法。
Look at the
System.IO.File
andSystem.IO.FileInfo
classes they both provide the methods you are looking for.