实现 Win32 文件写入

发布于 2024-08-09 11:12:53 字数 1217 浏览 1 评论 0原文

[DllImport("kernel32.dll", SetLastError=true)]
    public static extern unsafe bool WriteFile(IntPtr hFile, void* lpBuffer, uint nNumberOfBytesToWrite, out uint lpNumberOfBytesWritten, IntPtr lpOverlapped);

我通过带有签名的 Write(..) 方法来实现这一点:

Write(IntPtr handleFile, void* bufferData, uint length){
    void* buffer = bufferData
    while (length > 0)
    {
      uint wrtn;
      if (!WriteFile(handle, buffer, len, out wrtn, IntPtr.Zero))
      {
         // Do some error handling
      }
      // THIS DOESNT WORK!
      // I want to move along the buffer to be able to write its remainder...
      // I tried many variations of this as well, but it seems even '+' is not valid  for a void*
      buffer += wrtn;
      len -= wrtn;
    }
}

正如我通过查看 this(讨论了读取对应项的使用) 我需要在代码中实现一个 while 循环,因为缓冲区的写入/读取可能不会一次性完成。这就是问题开始的地方:

如果我想保留我的 C# 方法签名以接受 void*,与链接的 Read 示例不同,其中接受 byte* 作为缓冲区的参数。

这意味着在一次 WriteFile 传递之后,我应该将 void* 移动到尚未写入的缓冲区的开头。我显然不能通过仅用保存写入字节数的 uint 递增 void* 来做到这一点...我知道 void* 没有预定的大小,因此递增是不可能的,但我想知道我应该如何实现什么我正在努力做。

[DllImport("kernel32.dll", SetLastError=true)]
    public static extern unsafe bool WriteFile(IntPtr hFile, void* lpBuffer, uint nNumberOfBytesToWrite, out uint lpNumberOfBytesWritten, IntPtr lpOverlapped);

I am implementing this through a Write(..) method with a signature:

Write(IntPtr handleFile, void* bufferData, uint length){
    void* buffer = bufferData
    while (length > 0)
    {
      uint wrtn;
      if (!WriteFile(handle, buffer, len, out wrtn, IntPtr.Zero))
      {
         // Do some error handling
      }
      // THIS DOESNT WORK!
      // I want to move along the buffer to be able to write its remainder...
      // I tried many variations of this as well, but it seems even '+' is not valid  for a void*
      buffer += wrtn;
      len -= wrtn;
    }
}

As I learned by looking at this (the use of the read counterpart is discussed) I need to implement a while loop in my code because the write/read of the buffer might not go through in one go. This is where the problem start:

If I want to keep my C# method signature as to accept a void*, unlike the linked Read example where a byte* is accepted as a parameter for the buffer.

This means that after one pass of the WriteFile, I should move my void* along to the start of the buffer that has not been written yet. I cannot apparently do this by just incrementing void* with the uint that holds the number of bytes written... I understand that void* does not have a predetermined size and that incrementing is therefore not possible but I wonder how I then should achieve what I am trying to do.

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

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

发布评论

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

评论(1

情深已缘浅 2024-08-16 11:12:53

您应该能够将 buffer 转换为 byte*,然后递增它。 void 指针没有与其关联的大小,因此如果您想在任何方向移动它一定数量的字节,您可以将其转换为不同类型的指针(与此相关的任何类型)然后在指针算术中使用转换类型的大小,如下所示:

buffer = (void *)((byte*)buffer + wrtn);

上面的行将 buffer 转换为字节指针,然后将其位置增加 wrtn 字节数,然后将新指针强制转换回 void*。当然,如果您想要执行任意指针算术,则转换为 byte* 是显而易见的选择。

另一种可能性是始终将 buffer 视为 byte*,并且仅在将其传递给 WriteFile< 时将其强制转换为 void* /code>

Write(IntPtr handleFile, void* bufferData, uint length)
{
    byte* buffer = (byte*)bufferData;
    while (length > 0)
    {
      uint wrtn;
      if (!WriteFile(handle, (void*)buffer, len, out wrtn, IntPtr.Zero))
      {
         // Do some error handling
      }
      buffer += wrtn;
      len -= wrtn;
    }
}

并且,作为最后一个建议,我会考虑完全更改 Write 的签名以使用 byte* 而不是 void* 因为它会使其与 C# 中的其他调用者更加兼容,并且在这种情况下 byte* 更有意义。您不必担心使其与 WriteFile 本机 API 的签名相匹配,因为您可以在传入时将上面所示的 byte* 转换为 void*

Write(IntPtr handleFile, byte* bufferData, uint length)
{
    while (length > 0)
    {
      uint wrtn;
      if (!WriteFile(handle, (void*)bufferData, len, out wrtn, IntPtr.Zero))
      {
         // Do some error handling
      }
      bufferData+= wrtn;
      len -= wrtn;
    }
}

,我不得不同意一位评论者的观点。你为什么要这样做?那里
是使用许多面向流的类在 C# 中完成文件写入的更好方法。

You should be able to cast buffer to a byte* and then increment it. A void pointer doesn't have size associated with it so if you want to move it a certain number of bytes in any direction you can cast it to a different type of pointer (any type for that matter) and then use the casted type's size in the pointer arithmetic, like so:

buffer = (void *)((byte*)buffer + wrtn);

The line above casts buffer to a byte pointer, then increments its position by wrtn number of bytes and then casts the new pointer back to a void*. Of course, casting to a byte* is the obvious choice if you are wanting to perform arbitrary pointer arithmetic.

Another possibility is to treat buffer as a byte* all along and only cast it to void* when you pass it to WriteFile

Write(IntPtr handleFile, void* bufferData, uint length)
{
    byte* buffer = (byte*)bufferData;
    while (length > 0)
    {
      uint wrtn;
      if (!WriteFile(handle, (void*)buffer, len, out wrtn, IntPtr.Zero))
      {
         // Do some error handling
      }
      buffer += wrtn;
      len -= wrtn;
    }
}

And, as a last suggestion, I would consider changing the signature of Write altogether to use a byte* instead of void* because it would make it more compatible with other callers from C# and a byte* makes more sense in that case. You shouldn't have to worry about making it match the signature of the WriteFile native API since you can cast the byte* as shown above to a void* when passing it in.

Write(IntPtr handleFile, byte* bufferData, uint length)
{
    while (length > 0)
    {
      uint wrtn;
      if (!WriteFile(handle, (void*)bufferData, len, out wrtn, IntPtr.Zero))
      {
         // Do some error handling
      }
      bufferData+= wrtn;
      len -= wrtn;
    }
}

Alas, I have to agree with one of the commenters. Why are you doing this? There
are better ways to accomplish a file write in c# using many of the stream oriented classes.

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