Реализация Win32 FileWrite - PullRequest
       29

Реализация Win32 FileWrite

0 голосов
/ 02 ноября 2009
[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;
    }
}

Как я узнал, посмотрев на это (использование аналога чтения обсуждается) Мне нужно реализовать цикл while в моем коде, потому что запись / чтение буфера может не пройти в одном идти. Вот где начинается проблема:

Если я хочу сохранить свою сигнатуру метода C # для принятия void *, в отличие от связанного примера Read, где байт * принимается в качестве параметра для буфера.

Это означает, что после одного прохода WriteFile я должен переместить свой void * в начало буфера, который еще не был записан. По-видимому, я не могу сделать это, просто увеличивая void * с помощью uint, которая содержит количество записанных байтов ... Я понимаю, что void * не имеет заранее определенного размера, и поэтому приращение невозможно, но мне интересно, как мне тогда добиться чего Я пытаюсь сделать.

1 Ответ

1 голос
/ 02 ноября 2009

Вы должны иметь возможность привести buffer к byte*, а затем увеличить его. С пустым указателем не связан размер, поэтому, если вы хотите переместить это определенное количество байтов в любом направлении, вы можете привести его к другому типу указателя (любого типа в этом отношении) и затем используйте размер приведенного типа в арифметике указателя, например:

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*, потому что это сделает его более совместимым с другими вызывающими из C #, а byte* больше смысла в этом случае. Вам не нужно беспокоиться о том, чтобы он совпадал с сигнатурой нативного API WriteFile, поскольку при передаче его можно преобразовать 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 # с использованием многих потоковых классов.

...