实现Win32 FileWrite

时间:2009-11-02 14:15:27

标签: c# winapi void-pointers pointer-arithmetic

[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 (the use of the read counterpart is discussed)所学到的,我需要在我的代码中实现一个while循环,因为缓冲区的写入/读取可能不会一次完成。这就是问题的开始:

如果我想保持我的C#方法签名接受void *,不像链接的Read示例,其中字节*被接受作为缓冲区的参数。

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

1 个答案:

答案 0 :(得分:1)

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

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

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

另一种可能性是将buffer一直视为byte*,只有在将void*传递给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; } }

Write

并且,作为最后一个建议,我会考虑完全更改byte*的签名以使用void*而不是byte*,因为它会使其与C#中的其他来电者更兼容在这种情况下,byte*更有意义。您不必担心使其与WriteFile本机API的签名匹配,因为您可以在传递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; } } 转换为{{1}}。

{{1}}
唉,我必须同意其中一位评论者的意见。你为什么做这个?那里 是使用许多面向流的类在c#中完成文件写入的更好方法。