【发布时间】: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/SetCommTimeouts的COMMTIMEOUTS结构中有哪些参数。由于打印机的句柄有效,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