托管 .NET 相当于 CreateFile &来自 WinBase 的 WriteFile (kernel32.dll)

发布于 2024-08-26 02:54:58 字数 3650 浏览 4 评论 0原文

我正在使用旧文件格式。

该文件是使用非托管 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 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(4

空‖城人不在 2024-09-02 02:54:59

原始 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.

陈年往事 2024-09-02 02:54:58

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.

笑饮青盏花 2024-09-02 02:54:58

您没有解释您尝试处理的格式,但不是 文件。 WriteAllText 足够了吗?

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

对于二进制文件,您可以使用 File.WriteAllBytes

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

You didn't explain what format you are trying to handle but isn't File.WriteAllText sufficient?

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

For binary files you could use File.WriteAllBytes:

File.WriteAllBytes("someFile.bin", new byte[] { 0x1, 0x2, 0x3 });
黑凤梨 2024-09-02 02:54:58

查看 System.IO.File 和 System.IO.FileInfo 类,它们都提供您正在寻找的方法。

Look at the System.IO.File and System.IO.FileInfo classes they both provide the methods you are looking for.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文