Почему WriteFile возвращает false с неверным дескриптором? - PullRequest
0 голосов
/ 04 июня 2019

Я случайно сталкиваюсь с методом WriteFile (..), возвращающим false.Когда я вызываю GetLastError (), возвращается значение 6. Кто-нибудь знает, что вызывает эту проблему?Вот часть моего кода:

[DllImport("kernel32.dll", CharSet = CharSet.Ansi, SetLastError = true)]
[return: MarshalAs(UnmanagedType.Bool)]
private static extern bool WriteFile(IntPtr hFile, byte[] lpBuffer,
    uint nNumberOfBytesToWrite, out uint lpNumberOfBytesWritten,
    IntPtr lpOverlapped);

public void Connect()
{
    IntPtr m_WriteHandleToUsbDevice = CreateFile(m_DevicePathName,
        GENERIC_WRITE, FILE_SHARE_READ | FILE_SHARE_WRITE, IntPtr.Zero, OPEN_EXISTING,
        0, IntPtr.Zero).DangerousGetHandle();
}

public void SendCommand()
{
    if (!WriteFile(m_WriteHandleToUsbDevice, command, bytesToWrite, out bytesToWrite, IntPtr.Zero))
    {
        uint lastError = GetLastError(); // lastError = 6
    }
}

Я могу успешно отправить много команд, но в какой-то момент это не удается.Я пробовал много разных сигнатур метода WriteFile, но, похоже, ни одна из них не решает эту проблему (большинство просто меняют последний параметр для структуры System.Threading.NativeOverlapped).Многие подобные проблемы были вызваны тем, что свойство события структуры NativeOverlapped не было инициализировано, но я пробовал это безуспешно.Ниже приведена одна из альтернативных подписей и логики, которые я пробовал:

[DllImport("kernel32.dll", CharSet = CharSet.Ansi, SetLastError = true)]
[return: MarshalAs(UnmanagedType.Bool)]
private static extern bool WriteFile(IntPtr hFile, byte[] lpBuffer,
    uint nNumberOfBytesToWrite, out uint lpNumberOfBytesWritten,
    [In] ref NativeOverlapped lpOverlapped);

public void SendCommand()
{
    var ewh = new EventWaitHandle(false, EventResetMode.AutoReset);
    var unusedOutVariable = new NativeOverlapped {EventHandle = ewh.SafeWaitHandle.DangerousGetHandle()};
    if (!WriteFile(m_WriteHandleToUsbDevice, command, bytesToWrite, out bytesToWrite, IntPtr.Zero))
    {
        uint lastError = GetLastError(); // lastError = 6
    }
}

1 Ответ

0 голосов
/ 04 июня 2019

Использование DangerousGetHandle() не сохраняет файл открытым. Во время следующего прохода сборщика мусора объект SafeHandle будет обнаружен как недоступный, и его финализатор будет запланирован. Финализатор закроет ручку. Тогда ваш другой код начинает давать сбой. Почему вы думаете, что слово Dangerous было в названии функции?

Сохраните экземпляр SafeHandle в данных вашего класса, а не IntPtr.

...