【问题标题】:GetCommTimeouts returns error 87 for network printerGetCommTimeouts 为网络打印机返回错误 87
【发布时间】:2019-10-29 13:31:15
【问题描述】:

为了与打印机通信,我们使用 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 上的相同。一切看起来对我来说都是正确的。

【问题讨论】:

  • 在window 10上,Get/SetCommTimeoutsCOMMTIMEOUTS结构中有哪些参数。由于打印机的句柄有效,win10下Get/SetCommTimeouts函数不起作用,或者返回的参数是异常。
  • 有关更多信息,link 指出 GetCommTimeouts 和 SetCommTimeouts 是特定于串行端口驱动程序的。它们不是可以应用于任何驱动程序的通用功能。您可以通过使用重叠 I/O 然后对 OVERLAPPED 结构中的事件对象执行 WaitForSingleObject 来获得您想要的效果。 WaitForSingleObject 取毫秒超时值。可能是window10上的驱动不支持Get/SetCommTimeouts
  • 您是否在其他 Windows 10 计算机上进行测试?还有On Windows 10, I am not able to connect to shared printer on same computer via the share path是什么意思。是不是权限不够?
  • @StriveSun-MSFT 感谢您的回复。例如,我使用的 COMMTIMEOUTS 的结构,默认值都是 0。返回值与输入相同,来自两个函数。关于串行端口驱动程序规范,它适用于 Windows 7 上的 LPT 端口,因此 Windows 10 可能会禁用此方法。我在 4 台不同的 PC 上测试了这种行为(3 次相同的 OS Pro 版本但不同的硬件,1 次 Enterprise LTSC)。对于最后一条评论 - 我在 PC1 上安装了共享打印机,然后从那台电脑上,我尝试连接到 \\PC1\printersname,即使这样也不起作用。希望这会有所帮助。
  • 它与 Windows 7 上的 LPT 端口一起使用,因此 Windows 10 可能会禁用此方法。对于这种情况,我会咨询相关工程师确认是否是潜在问题。

标签: .net windows vb.net winapi


【解决方案1】:

在与微软相关工程师讨论后,Get/SetCommTimeouts 应该只适用于直接连接到 PC 的打印机,例如串行或 LPT 端口。它也应该适用于蓝牙。它应该不起作用,现在它不起作用,这是预期的行为。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2017-04-21
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2012-05-28
    • 2011-04-13
    • 1970-01-01
    相关资源
    最近更新 更多