简体   繁体   中英

Implementing Win32 FileWrite

[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.

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.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM