You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何将LPT1重定向至USB001实现ASC文件原始打印

最优解决方案:DOS程序LPT1打印重定向至USB001端口

问题描述

现有仅支持LPT1端口的DOS程序,需将其打印输出重定向至USB001端口,可通过以下两种方式实现:

  • 直接对路径为C:\vDos\#LPT1.asc的ASC文件进行原始打印
  • 监控C:\Users\Admin\AppData\Local\Temp\vDos路径下的tmp格式临时文件并打印

相关文件路径

ASC文件路径:C:\vDos\#LPT1.asc
临时文件目录:C:\Users\Admin\AppData\Local\Temp\vDos

现有VB.NET代码

Public Class Form1
    Public Const FILE_ATTRIBUTE_NORMAL As Short = &H80
    Public Const INVALID_HANDLE_VALUE As Short = -1
    Public Const GENERIC_READ As UInteger = &H80000000UI
    Public Const GENERIC_WRITE As UInteger = &H40000000
    Public Const CREATE_NEW As UInteger = 1
    Public Const CREATE_ALWAYS As UInteger = 2
    Public Const OPEN_EXISTING As UInteger = 3

    <DllImport("kernel32.dll", SetLastError:=True)>
    Shared Function CreateFile(ByVal lpFileName As String, ByVal dwDesiredAccess As UInteger, ByVal dwShareMode As UInteger, ByVal lpSecurityAttributes As IntPtr, ByVal dwCreationDisposition As UInteger, ByVal dwFlagsAndAttributes As UInteger, ByVal hTemplateFile As IntPtr) As SafeFileHandle
    End Function

    Public Shared Sub sendTextToLPT1(ByVal receiptText As String)
        Using ptr As SafeFileHandle = CreateFile("LPT1", GENERIC_WRITE, 0, IntPtr.Zero, OPEN_EXISTING, 0, IntPtr.Zero)
            ' 检查是否为无效句柄
            If ptr.IsInvalid Then
                ' 将Win32错误码转换为异常抛出
                Marshal.ThrowExceptionForHR(Marshal.GetHRForLastWin32Error())
            Else
                Using lpt As New FileStream(ptr, FileAccess.ReadWrite)
                    Dim buffer(2047) As Byte
                    ' 根据打印机支持选择编码,此处用ASCII
                    buffer = System.Text.Encoding.ASCII.GetBytes(receiptText)
                    lpt.Write(buffer, 0, buffer.Length)
                    lpt.Close()
                End Using
            End If
        End Using
    End Sub

    Private Sub btnPrint_Click_1(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles btnPrint.Click
        Dim s As String = "C:\vDos\#LPT1.ASC"
        Dim p As New PrintDocument()
        AddHandler p.PrintPage, Sub(sender1 As Object, e1 As PrintPageEventArgs)
                                    e1.Graphics.DrawString(s, New Font("Times New Roman", 12), New SolidBrush(Color.Black), New RectangleF(0, 0, p.DefaultPageSettings.PrintableArea.Width, p.DefaultPageSettings.PrintableArea.Height))
                                End Sub
        Try
            p.Print()
        Catch ex As Exception
            Throw New Exception("打印时发生异常", ex)
        End Try
    End Sub
End Class

最优解决方案实现

方案一:直接打印ASC文件到USB打印机(推荐)

此方案直接读取vDos生成的ASC文件,以原始字节形式发送到USB打印机,完整保留DOS程序的原始打印格式(包括控制码)。

步骤1:添加原始打印辅助类

添加RawPrinterHelper类,用于实现绕过GDI的原始打印功能:

Imports System
Imports System.Drawing
Imports System.Drawing.Printing
Imports System.IO
Imports System.Runtime.InteropServices

Public Class RawPrinterHelper
    Structure DOCINFO
        <MarshalAs(UnmanagedType.LPWStr)> Public pDocName As String
        <MarshalAs(UnmanagedType.LPWStr)> Public pOutputFile As String
        <MarshalAs(UnmanagedType.LPWStr)> Public pDataType As String
    End Structure

    <DllImport("winspool.drv", EntryPoint:="OpenPrinterW", SetLastError:=True, CharSet:=CharSet.Unicode, ExactSpelling:=True, CallingConvention:=CallingConvention.StdCall)>
    Public Shared Function OpenPrinter(ByVal szPrinter As String, ByRef hPrinter As IntPtr, ByVal pd As IntPtr) As Boolean
    End Function

    <DllImport("winspool.drv", EntryPoint:="ClosePrinter", SetLastError:=True, ExactSpelling:=True, CallingConvention:=CallingConvention.StdCall)>
    Public Shared Function ClosePrinter(ByVal hPrinter As IntPtr) As Boolean
    End Function

    <DllImport("winspool.drv", EntryPoint:="StartDocPrinterW", SetLastError:=True, CharSet:=CharSet.Unicode, ExactSpelling:=True, CallingConvention:=CallingConvention.StdCall)>
    Public Shared Function StartDocPrinter(ByVal hPrinter As IntPtr, ByVal level As Int32, ByRef pDI As DOCINFO) As Boolean
    End Function

    <DllImport("winspool.drv", EntryPoint:="EndDocPrinter", SetLastError:=True, ExactSpelling:=True, CallingConvention:=CallingConvention.StdCall)>
    Public Shared Function EndDocPrinter(ByVal hPrinter As IntPtr) As Boolean
    End Function

    <DllImport("winspool.drv", EntryPoint:="StartPagePrinter", SetLastError:=True, ExactSpelling:=True, CallingConvention:=CallingConvention.StdCall)>
    Public Shared Function StartPagePrinter(ByVal hPrinter As IntPtr) As Boolean
    End Function

    <DllImport("winspool.drv", EntryPoint:="EndPagePrinter", SetLastError:=True, ExactSpelling:=True, CallingConvention:=CallingConvention.StdCall)>
    Public Shared Function EndPagePrinter(ByVal hPrinter As IntPtr) As Boolean
    End Function

    <DllImport("winspool.drv", EntryPoint:="WritePrinter", SetLastError:=True, ExactSpelling:=True, CallingConvention:=CallingConvention.StdCall)>
    Public Shared Function WritePrinter(ByVal hPrinter As IntPtr, ByVal pBytes As IntPtr, ByVal dwCount As Int32, ByRef dwWritten As Int32) As Boolean
    End Function

    ' 将原始字节发送到打印机
    Public Shared Function SendBytesToPrinter(ByVal szPrinterName As String, ByVal pBytes As IntPtr, ByVal dwCount As Int32) As Boolean
        Dim hPrinter As IntPtr = IntPtr.Zero
        Dim dwError As Int32 = 0
        Dim di As DOCINFO = New DOCINFO()
        Dim dwWritten As Int32 = 0
        Dim bSuccess As Boolean = False

        di.pDocName = "DOS原始打印文档"
        di.pDataType = "RAW"

        If OpenPrinter(szPrinterName, hPrinter, IntPtr.Zero) Then
            If StartDocPrinter(hPrinter, 1, di) Then
                If StartPagePrinter(hPrinter) Then
                    bSuccess = WritePrinter(hPrinter, pBytes, dwCount, dwWritten)
                    EndPagePrinter(hPrinter)
                End If
                EndDocPrinter(hPrinter)
            End If
            ClosePrinter(hPrinter)
        End If

        If Not bSuccess Then
            dwError = Marshal.GetLastWin32Error()
            Throw New Exception($"打印失败,错误码:{dwError}")
        End If
        Return bSuccess
    End Function

    ' 将文件内容发送到打印机
    Public Shared Function SendFileToPrinter(ByVal szPrinterName As String, ByVal szFileName As String) As Boolean
        Dim fs As FileStream = New FileStream(szFileName, FileMode.Open)
        Dim br As BinaryReader = New BinaryReader(fs)
        Dim bytes() As Byte = New Byte(fs.Length - 1) {}
        Dim pUnmanagedBytes As IntPtr = IntPtr.Zero
        Dim nLength As Int32 = 0

        nLength = Convert.ToInt32(fs.Length)
        bytes = br.ReadBytes(nLength)
        pUnmanagedBytes = Marshal.AllocCoTaskMem(nLength)
        Marshal.Copy(bytes, 0, pUnmanagedBytes, nLength)
        SendBytesToPrinter(szPrinterName, pUnmanagedBytes, nLength)
        Marshal.FreeCoTaskMem(pUnmanagedBytes)
        Return True
    End Function
End Class

步骤2:修改打印按钮事件

替换原btnPrint_Click_1方法,实现读取ASC文件并发送到USB打印机:

Private Sub btnPrint_Click_1(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles btnPrint.Click
    Dim ascFilePath As String = "C:\vDos\#LPT1.asc"
    ' 替换为你的USB打印机名称,可在Windows打印机设置中查看
    Dim usbPrinterName As String = "你的USB打印机名称"

    Try
        ' 检查文件是否存在
        If File.Exists(ascFilePath) Then
            RawPrinterHelper.SendFileToPrinter(usbPrinterName, ascFilePath)
            MessageBox.Show("打印成功")
        Else
            MessageBox.Show("ASC文件不存在")
        End If
    Catch ex As Exception
        MessageBox.Show($"打印失败:{ex.Message}")
    End Try
End Sub

方案二:监控临时文件目录自动打印

如果需要实时捕获DOS程序的打印输出,可监控指定临时文件目录,当新的tmp文件生成时自动打印:

实现代码

添加FileSystemWatcher组件到窗体,设置监控参数:

Private watcher As FileSystemWatcher

Private Sub Form1_Load(sender As Object, e As EventArgs) Handles MyBase.Load
    watcher = New FileSystemWatcher()
    watcher.Path = "C:\Users\Admin\AppData\Local\Temp\vDos"
    watcher.Filter = "*.tmp"
    ' 监控文件创建事件
    AddHandler watcher.Created, AddressOf OnTmpFileCreated
    watcher.EnableRaisingEvents = True
End Sub

Private Sub OnTmpFileCreated(source As Object, e As FileSystemEventArgs)
    ' 等待文件写入完成
    Threading.Thread.Sleep(1000)
    Dim usbPrinterName As String = "你的USB打印机名称"
    Try
        RawPrinterHelper.SendFileToPrinter(usbPrinterName, e.FullPath)
        ' 可选:打印后删除临时文件
        File.Delete(e.FullPath)
    Catch ex As Exception
        MessageBox.Show($"临时文件打印失败:{ex.Message}")
    End Try
End Sub

注意事项

  • 确保USB打印机支持原始打印(大部分票据打印机、针式打印机支持)
  • 替换代码中的你的USB打印机名称为实际打印机名称,可通过PrinterSettings.InstalledPrinters枚举获取所有已安装打印机
  • ASC文件包含DOS程序的原始打印控制码,直接发送可保证打印格式与DOS环境完全一致

内容的提问来源于stack exchange,提问作者roy

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.25 13:48:22