StartDocPrinter WinAPI调用在VBA中失败

时间:2014-08-13 13:48:31

标签: vba winapi printing

目标:使用指定的Win API函数从字符串或富文本框打印到任何所需的打印机。

问题:在VBA Access中调用StartDocPrinter始终返回0.

信息:以下代码贯穿始终,不会中断。 OpenPrinter似乎得到了很好的处理。调用StartDocPrinter时,它返回0.

使用以下代码我尝试过,

  • 将不同信息保存到dDocInfo和@David_Heffernan建议,将DOCINFO属性声明为Long并将值设置为0。
    • .pDatatype = vbNullstringGetLastError返回时,
      • StartDocPrinter parameter Level = 1
      • 时出现错误124(无效级别)
      • StarDocPrinter parameter Level = ByVal 1时出现错误6(无效句柄),但hPrinter中显示的是明显有效句柄
    • .pDatatype = "RAW"时,GetLastError无论如何都会返回0。
    • .pDatatype = 'vbNullString和DOCINFO属性设置为字符串时,GetLastError无论如何返回0.
  • 更改WinAPI函数的参数(ByRef DOCINFO
  • 检查访问权限问题。从其他代码看,将最后OpenPrinter参数设置为0应该将对打印机的请求访问权限设置为PRINTER_ACCESS_USE。是否有可能GetLastError没有返回访问拒绝错误?
  • 将多个引用的代码从C ++转换为VBA,但转换或不包括指针令人困惑。我没有正确转换StartDocPrinter(printer, 1, (LPBYTE) &docInfo);吗?

代码:

声明:

Type DOCINFO
 pDocName As String
 pOutputFile As String
 pDatatype As String
End Type

Public Declare Function OpenPrinter Lib "winspool.drv" Alias "OpenPrinterA" (ByVal pPrinterName As String, hPrinter As Long, ByVal pDefault As Long) As Long
Public Declare Function StartDocPrinter Lib "winspool.drv" Alias "StartDocPrinterA" (hPrinter As Long, Level As Long, dDocInfo As DOCINFO) As Long

功能:

Public Function printRawData(sPrinterName As String, lData As String) As Boolean
  Dim bStatus As Boolean, hPrinter As Long, dDocInfo As DOCINFO, lJob As Long, nWritten As Integer

  ' Open a handle to the printer.
  bStatus = OpenPrinter(sPrinterName, hPrinter, 0)
  If bStatus Then
    ' Fill in the structure with info about this "document."
    dDocInfo.pDocName = vbNullString
    dDocInfo.pOutputFile = vbNullString
    dDocInfo.pDatatype = "RAW"

    ' Inform the spooler the document is beginning.
    lJob = StartDocPrinter(hPrinter, 1, dDocInfo) 'Returns 0 :(
    Debug.Print hPrinter, sPrinterName, lJob, GetLastError()

    If lJob > 0 Then
        ' Start a page.
        bStatus = StartPagePrinter(hPrinter)
        If bStatus Then
            ' Send the data to the printer.
            bStatus = WritePrinter(hPrinter, lData, Len(lData), nWritten)
            EndPagePrinter (hPrinter)
        End If
        ' Inform the spooler that the document is ending.
        EndDocPrinter (hPrinter)
    End If
    ' Close the printer handle.
    ClosePrinter (hPrinter)
  End If

  ' Check to see if correct number of bytes were written.
  If Not bStatus Or (nWritten <> Len(lData)) Then
    printRawData = False
  Else
    printRawData = True
  End If
End Function

参考资料/相关问题:
  - http://support.microsoft.com/kb/154078此代码的基础文档。 编辑:找到ByVal在这里的一些声明中遗漏的地方。
  - Send Raw Data to ZPL Printer using Visual Basic (MS Access 2000)这个人似乎有效地使用了几乎相同的代码,为什么我不能呢?这个问题的答案是用C ++编写的   - http://www.cplusplus.com/forum/general/26184/此处的代码也是用C ++编写的,我不确定如何转换   - http://codingdomain.com/visualbasic/win32api/datatypes/我正在使用转换数据类型和指针的指南,我并不完全理解   - StartDocPrinter(hPrinter, 1, di) returns false此处提供了一些代码,但没有答案。这是我有意提供错误的地方。
  - excel bva code to send command to usb printer我尝试过此操作但没有所需的访问权限。我仍然想知道如何正确使用上面的代码,即使这是我最终会做的。

2 个答案:

答案 0 :(得分:0)

使用@ HansPassant链接到MS KB,我在代码中发现了错误。对于ByValhPrinter参数,StartDocPrinter函数的声明缺少Level

Public Declare Function StartDocPrinter Lib "winspool.drv" Alias "StartDocPrinterA" (ByVal hPrinter As Long, ByVal Level As Long, dDocInfo As DOCINFO) As Long

答案 1 :(得分:-1)

您对DOCINFO结构的声明看起来不正确。它应该声明为:

Type DOCINFO
   cbSize As Integer
   lpszDocName As String
   lpszOutput As String
   lpszDatatype As String
   fwType As Integer
End Type

应该将cbSize初始化为结构的大小(以字节为单位),并将fwType设置为0.