Для связи с принтерами мы используем методы и дескрипторы WinApi. Наше решение правильно работало на Windows 7 (32- и 64-разрядные версии). В настоящее время мы переходим на Windows 10, и есть проблема с сетевыми принтерами.
Проблема в том, что когда мы пытаемся вызвать GetCommTimeouts
, обновим их до того, что нам нужно, и вернем их обратно. С кодом ниже, если я использую прямой доступ к параллельному порту (пример пути - \\.\LPT1
), я могу подключиться к принтеру. Однако на сетевом принтере (путь \\PcName\PrintersName
) приведенный ниже код завершается ошибкой на GetCommTimeouts
. (В данном примере это не SetCommTimeouts
, но он ведет себя так же, как и GetCommTimeouts
).
Сбой с кодом ошибки 87 «Параметр неверен». Но структура должна быть действительной и дескриптор установлен. Дескриптор правильный, потому что, если я пропущу функции Get / SetCommTimeouts, принтер напечатает правильно. (не входит в код)
Private Const INVALID_HANDLE_VALUE As Integer = -1
Private Const GENERIC_READ = &H80000000L
Private Const GENERIC_WRITE = &H40000000
Private Const FILE_SHARE_READ = &H1
Private Const FILE_SHARE_WRITE = &H2
Private Const OPEN_ALWAYS = 4
Private Const FILE_FLAG_SEQUENTIAL_SCAN = &H8000000
Sub Main()
Dim handle = CreateFile("\\PcName\PrintersSharedName",
GENERIC_READ Or GENERIC_WRITE,
FILE_SHARE_READ Or FILE_SHARE_WRITE,
0,
OPEN_ALWAYS,
FILE_FLAG_SEQUENTIAL_SCAN,
0)
If Not handle <> INVALID_HANDLE_VALUE Then
Console.WriteLine("OpenDeviceHandle_Error")
Console.ReadLine()
Return
End If
Try
Dim commTimeouts As New COMMTIMEOUTS
Dim result = GetCommTimeouts(handle, commTimeouts)
If result = 0 Then
Dim exception As New Win32Exception
If exception.NativeErrorCode = 1 Then
Console.WriteLine("GetCommTimeouts_Correct")
Else
Console.WriteLine($"GetCommTimeouts_Error {exception.NativeErrorCode}")
End If
End If
Finally
CloseHandle(handle)
End Try
Console.ReadLine()
End Sub
<DllImport("Kernel32.dll", SetLastError:=True)>
Private Function CreateFile(lpFileName As String,
dwDesiredAccess As UInteger,
dwShareMode As UInteger,
lpSecurityAttributes As IntPtr,
dwCreationDisposition As UInteger,
dwFlagsAndAttributes As UInteger,
hTemplateFile As IntPtr) As Integer
End Function
<DllImport("Kernel32.dll", SetLastError:=True)>
Private Function GetCommTimeouts(iHandle As Integer, ByRef oCommTimeouts As COMMTIMEOUTS) As Integer
End Function
<DllImport("Kernel32.dll", SetLastError:=True)>
Private Function CloseHandle(hObject As IntPtr) As Integer
End Function
<StructLayout(LayoutKind.Sequential)>
Private Structure COMMTIMEOUTS
Dim ReadIntervalTimeout As UInteger ' Maximum time between read chars
Dim ReadTotalTimeoutMultiplier As UInteger ' Multiplier of characters
Dim ReadTotalTimeoutConstant As UInteger ' Constant in milliseconds
Dim WriteTotalTimeoutMultiplier As UInteger ' Multiplier of characters
Dim WriteTotalTimeoutConstant As UInteger ' Constant in milliseconds
End Structure
Этот же код работает правильно на компьютере с Windows 7, и даже этот компьютер может подключаться к общему принтеру, который подключен на компьютере с Windows 10. В Windows 10 я не могу подключиться к общему принтеру на том же компьютере через общий ресурс.
В чем я не уверен, если он не работает, потому что Win10 нужно что-то другое для локальных / общих принтеров, если это что-то, связанное с Windows 10, или если в самом коде есть какая-то ошибка. Я пробовал разные настройки параметров, несколько раз проверял интерфейсы и структуры WinApi, проверял, совпадают ли права доступа к принтеру с Win 7. Все выглядит правильно для меня.