Управляемый .NET, эквивалентный CreateFile и WriteFile из WinBase (kernel32.dll) - PullRequest
4 голосов
/ 22 марта 2010

Я работаю с устаревшим форматом файла.

Файл создается с использованием неуправляемого 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);

Спасибо.

Ответы [ 4 ]

4 голосов
/ 22 марта 2010

WriteFileEx работает только асинхронно, вы должны предоставить экземпляр SEPARATE OVERLAPPED для каждого ожидающего вызова, и вы должны настроить элементы OVERLAPPED, такие как смещение файла. Тогда вы не сможете вызвать CloseHandle, пока все операции не завершатся. И используя локальную переменную для OVERLAPPED и позволяя ей выйти из области видимости? Ваши данные перезаписываются - это минимум вещей, которые могут пойти не так с кодом, который вы показываете.

Так вот почему ваш код не работает. Я не знаю, почему вы переключились с WriteFile на WriteFileEx. Кроме того, вызывать Win32 API из C # довольно неудобно, хотя иногда необходимо. Но сначала посмотрите, делают ли .NET File API то, что вам нужно.

Поскольку файловые API .NET, как правило, работают либо со строками (в текстовом режиме, следите за преобразованиями строк и т. Д.), Либо с массивами байтов, вам необходимо преобразовать другие переменные в байт []. Класс BitConverter является вашим другом здесь.

4 голосов
/ 22 марта 2010

Вы не объяснили, в каком формате вы пытаетесь обрабатывать, но не достаточно File.WriteAllText ?

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

Для двоичных файлов вы можете использовать File.WriteAllBytes :

File.WriteAllBytes("someFile.bin", new byte[] { 0x1, 0x2, 0x3 });
1 голос
/ 22 марта 2010

Нет ничего особенного в необработанных вызовах API. Просто получите System.IO.FileStream и позвоните в него. (Один из способов получить FileStream - сначала получить System.IO.File.

1 голос
/ 22 марта 2010

Посмотрите на классы System.IO.File и System.IO.FileInfo, которые оба предоставляют методы, которые вы ищете.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...