VB6 StrPtr 函数到 VB.NET

VB6 StrPtr Function to VB.NET

正在尝试将 VB6 代码行转换为 VB.net。如果打印机关闭或打开,代码将用作标识 谢谢

"PRINTERFOUND = OpenPrinterW(StrPtr(PrinterName), hPrinter)" 特定的 StrPtr 函数...

无法让 OpenPrinter 工作 - 尝试打印 我只是想知道打印机是关闭还是打开

换行到

PRINTERFOUND = OpenPrinterW(PrinterName.Normalize(),hPrinter,无)

不行,谢谢

尝试按照之前的建议将 VB6 声明转换为 VB.net,但仍然出现相同的错误,无法将字符串转换为整数,请参见下文

'Private Declare Function GetPrinterApi Lib "winspool.drv" Alias "GetPrinterA" (ByVal hPrinter As Long, ByVal Level As Long, ByRef BUFFER As  Long, ByVal pbSize As Long, ByRef pbSizeNeeded As Long) As Long     
 <DllImport("winspool.Drv", EntryPoint:="GetPrinterA", SetLastError:=True, CharSet:=CharSet.Ansi, ExactSpelling:=True, CallingConvention:=CallingConvention.StdCall)> _
Public Function GetPrinterApi(<MarshalAs(UnmanagedType.LPStr)> ByVal hPrinter As String, ByVal Level As IntPtr, ByVal BUFFER As IntPtr, ByVal pbSize As IntPtr, ByRef pbSizeNeeded As IntPtr) As Boolean
End Function

'Private Declare Function OpenPrinterW Lib "winspool.drv" (ByVal pPrinterName As Long, ByRef phPrinter As Long, Optional ByVal pDefault As Long = 0) As Long  
 <DllImport("winspool.Drv", SetLastError:=True, CharSet:=CharSet.Ansi, ExactSpelling:=True, CallingConvention:=CallingConvention.StdCall)> _
Public Function OpenPrinterW(ByVal pPrinterName As IntPtr, ByVal phPrinter As Int32, <[In](), MarshalAs(UnmanagedType.LPStruct)> ByVal pDefault As IntPtr) As Boolean
End Function

'Private Declare Function ClosePrinter Lib "winspool.drv" (ByVal hPrinter As Long) As Long
 <DllImport("winspool.Drv", EntryPoint:="ClosePrinter", SetLastError:=True, ExactSpelling:=True, CallingConvention:=CallingConvention.StdCall)> _
Public Function ClosePrinter(ByVal hPrinter As IntPtr) As Boolean
End Function

'Private Declare Sub CopyMemory Lib "kernel32" Alias "RtlMoveMemory" (ByRef Destination As Long, ByRef Source As Long, ByVal Length As Long)  
 <DllImport("kernel32.dll", SetLastError:=True, EntryPoint:="RtlMoveMemory")> _
Public Function CopyMemory(ByRef Destination As Long, ByVal Source As IntPtr, ByVal Length As String) As IntPtr
End Function

完整代码如下

'Acknowledgements : This program has been written making extensive use of the
'Merrion article http://www.merrioncomputing.com/Programming/PrintStatus.htm
'It has also benefited from the contributors to VBForums thread # 733849
'http://www.vbforums.com/showthread.php?t=733849&goto=newpost - especially the code
'suggested by "Bonnie West"

'Program written 14 Sept. 2013 by C.A. Moore

Option Explicit

Dim PRINTERFOUND As Long
Dim GETPRINTER As Long
Dim BUFFER() As Long
Dim pbSizeNeeded As Long
Dim PRINTERINFO As PRINTER_INFO_2
Dim N As Integer
Dim M As Integer
Dim CHAR As String
Dim prnPrinter As Printer
Dim BUF13BINARY As String

' Note : PRINTERREADY as an Integer variable is Dim'd
'"Public PRINTERREADY As Integer" at Form1 Option Explicit

Private Type PRINTER_INFO_2
    pServerName As String
    pPrinterName As String
    pShareName As String
    pPortName As String
    pDriverName As String
    pComment As String
    pLocation As String
    pDevMode As Long
    pSepFile As String
    pPrintProcessor As String
    pDatatype As String
    pParameters As String
    pSecurityDescriptor As Long
    Attributes As Long
    Priority As Long
    DefaultPriority As Long
    StartTime As Long
    UntilTime As Long
    Status As Long
    JobsCount As Long
    AveragePPM As Long
End Type

Private Declare Function GetPrinterApi Lib "winspool.drv" Alias "GetPrinterA" (ByVal hPrinter As Long, ByVal Level As Long, BUFFER As Long, ByVal pbSize As Long, pbSizeNeeded As Long) As Long
Private Declare Function OpenPrinterW Lib "winspool.drv" (ByVal pPrinterName As Long, ByRef phPrinter As Long, Optional ByVal pDefault As Long) As Long
Private Declare Function ClosePrinter Lib "winspool.drv" (ByVal hPrinter As Long) As Long
Private Declare Sub CopyMemory Lib "kernel32" Alias "RtlMoveMemory" (Destination As Any, Source As Any, ByVal Length As Long)

Public Function StringFromPointer(lpString As Long, lMaxLength As Long) As String
    'this service function extracts a string (sRet) when fed with a pointer (lpstring)
    'from a buffer
    Dim sRet As String
    Dim lret As Long

    If lpString = 0 Then
        StringFromPointer = ""
        Exit Function
    End If

    '\ Pre-initialise the return string...
    sRet = Space$(lMaxLength)
    CopyMemory ByVal sRet, ByVal lpString, ByVal Len(sRet)
    If Err.LastDllError = 0 Then
        If InStr(sRet, Chr$(0)) > 0 Then
            sRet = Left$(sRet, InStr(sRet, Chr$(0)) - 1)
        End If
    End If

    StringFromPointer = sRet
End Function

Public Function IsPrinterReady(ByRef PrinterName As String)
    Form1.PRINTERREADY = 0

    'first select the named printer and check if it is installed
    For Each prnPrinter In Printers
        CHAR = prnPrinter.DeviceName
        If CHAR = PrinterName Then
            Set Printer = prnPrinter   'sets this as printer
            Form1.PRINTERREADY = 1
        End If
    Next

    If Form1.PRINTERREADY = 0 Then GoTo Line1000     'exit. printer not installed
        Dim hPrinter As Long
        Dim PI6 As PRINTER_INFO_2

        PRINTERFOUND = 0
        Form1.PRINTERREADY = 0
        PRINTERFOUND = OpenPrinterW(StrPtr(PrinterName), hPrinter)
        '(OpenPrinterW(ByVal pPrinterName As Long, ByRef phPrinter As Long) As Long)

        If PRINTERFOUND = 0 Then                'ie. printer not found
            Form1.PRINTERREADY = 0
            Debug.Assert ClosePrinter(hPrinter)
            GoTo Line100
        End If

        'If we get here named printer was found and accessed and its hPrinter handle is
        'known
         'Dim BUFFER() As Long
         'Dim pbSizeNeeded As Long

         ReDim Preserve BUFFER(0 To 1) As Long
         GETPRINTER = GetPrinterApi(hPrinter, 2&, BUFFER(0), UBound(BUFFER), pbSizeNeeded)
         ReDim Preserve BUFFER(0 To (pbSizeNeeded / 4) + 3) As Long
         GETPRINTER = GetPrinterApi(hPrinter, 2&, BUFFER(0), UBound(BUFFER) * 4, pbSizeNeeded)
         If GETPRINTER = 0 Then              'ie. some problem with printer access
             Form1.PRINTERREADY = 0
             GoTo Line100
         End If

         'If we get here then GETPRINTER = 1, ie. printer found and accessed OK
         With PRINTERINFO '\ This variable is of type PRINTER_INFO_2
            'These quantities are defined here because the Merrion article
            'so specifies. However they are not used by this program, and most
            'have been found to be void

            .pServerName = StringFromPointer(BUFFER(0), 1024)
            .pPrinterName = StringFromPointer(BUFFER(1), 1024)
            .pShareName = StringFromPointer(BUFFER(2), 1024)
            .pPortName = StringFromPointer(BUFFER(3), 1024)
            .pDriverName = StringFromPointer(BUFFER(4), 1024)
            .pComment = StringFromPointer(BUFFER(5), 1024)
            .pLocation = StringFromPointer(BUFFER(6), 1024)
            .pDevMode = BUFFER(7)
            .pSepFile = StringFromPointer(BUFFER(8), 1024)
            .pPrintProcessor = StringFromPointer(BUFFER(9), 1024)
            .pDatatype = StringFromPointer(BUFFER(10), 1024)
            .pParameters = StringFromPointer(BUFFER(11), 1024)
            .pSecurityDescriptor = BUFFER(12)
            .Attributes = BUFFER(13)
            .Priority = BUFFER(14)
            .DefaultPriority = BUFFER(15)
            .StartTime = BUFFER(16)
            .UntilTime = BUFFER(17)
            .Status = BUFFER(18)
            .JobsCount = BUFFER(19)
            .AveragePPM = BUFFER(20)
        End With



        'This next code is for interest and program development only.
        'It writes into List1 the value of each buffer 1 - 20
        'To by-pass it, add a "Go To Line15" statement at this point.

        Form1.List1.Clear
        N = 0
Line5:
        On Error GoTo Line15
        Form1.List1.AddItem "Buffer No. " & N & "  Buffer Value " & BUFFER(N)
        N = (N + 1)
        If N = 21 Then GoTo Line15
        GoTo Line5

        'Now to convert the decimal value of Buffer(13) into a binary
        'bit pattern and store this in BUF13BINARY
Line15: 'and to show Buffer(13) as a binary bit pattern at Form1.Label1

        N = BUFFER(13)
        BUF13BINARY = ""
        M = 4196
Line16:
        If N < M Then
            BUF13BINARY = BUF13BINARY & "0"
            GoTo Line20
        End If

        BUF13BINARY = BUF13BINARY & "1"
        N = (N - M)
Line20:
        If M = 1 Then GoTo Line10
            M = M / 2
            GoTo Line16

Line10: 'BUF13BINARY is now the 13 bit binary value of Buffer(13)
        'eg. 0011000100010

        Form1.Label1.Caption = BUF13BINARY  'display this binary value at form 1

        'we now examine the value of the third binary bit in BUF13BINARY
        If Mid$(BUF13BINARY, 3, 1) = "0" Then Form1.PRINTERREADY = 1
        If Mid$(BUF13BINARY, 3, 1) = "1" Then Form1.PRINTERREADY = 0
Line100:
        ClosePrinter (hPrinter)
Line1000:
End Function

Option Explicit
Public PRINTERREADY As Integer

Private Sub Command1_Click()
    IsPrinterReady ("Brother QL-500")
    'IsPrinterReady ("EPSON Stylus CX5400")
    MsgBox PRINTERREADY                     '0 = Not Ready   1 = Ready
End Sub

您不能转换 VarPtr、StrPtr 或 ObjPtr,因为在 .NET 中您不直接控制内存。这些函数用于从实例、变量或 Unicode 字符串中提取指针。但在 .NET 中,对象在内存中的位置由垃圾收集器管理,GC 可以随时在内存中移动对象。

考虑以下代码,但不要使用它!我把它放在这里只是为了解释为什么.NET 中不存在这些功能。

Private Function VarPtr(ByVal obj As Object) As Integer
    ' Obtain a pinned handle to the object
    Dim handle As GCHandle = GCHandle.Alloc(obj, GCHandleType.Pinned)
    Dim pointer As Integer = handle.AddrOfPinnedObject.ToInt32

    ' Free the allocated handle. At this point the GC can move the object in memory, this is 
    ' why this function does not exist in .NET. If you were to use this pointer as a destination 
    ' for memcopy for example, you could overwrite unintended memory, which would crash the 
    ' application or cause unexpected behavior. For this function to work you would need to
    ' maintain the handle until after you are finished using it.
    handle.Free()

    Return pointer
End Function

编辑:

获取打印机状态的正确方法是通过它的托管接口,在本例中是通过 WMI:

Imports System.Management

Public Class Form1

    Private Enum PrinterStatus As Integer
        Other = 1
        Unknown = 2
        Idle = 3
        Printing = 4
        Warmup = 5
        Stopped = 6
        Offline = 7
    End Enum

    Private Sub Form1_Load(sender As Object, e As EventArgs) Handles MyBase.Load
        Dim mos = New ManagementObjectSearcher("SELECT * FROM Win32_Printer")

        For Each p In mos.Get()
            Debug.Print(p.Properties("Name").Value.ToString() & " : " & CType(CInt(p.Properties("PrinterStatus").Value), PrinterStatus).ToString())
        Next
    End Sub

End Class

您可以在此处获取有关 Win32_Printer class 的更多信息:https://msdn.microsoft.com/en-us/library/aa394363(v=vs.85).aspx

特别注意这一点:

Note If you are retrieving PrinterStatus = 3 or PrinterState = 0, the printer driver may not be feeding accurate information into WMI. WMI retrieves the printer information from the spoolsv.exe process. It is possible the printer driver does not report its status to the spooler. In this case, Win32_Printer reports the printer as Idle.

从那里您可以获得有关任何连接的外围设备的信息并进行管理。只需找出合适的 WMI classes 并阅读文档即可。

感谢大家,尤其是醉码猴提供的所有信息,我看完https://msdn.microsoft.com/en-us/library/aa394363(v=vs.85).aspx figured need to is boolean WorkOffline; Pew... made it more simple then VB6 language even using that feels kinda hmm old. Also lucky me found codes that did the same thing as I wanted here is link to VB.NET "https://bytes.com/topic/visual-basic-net/answers/524957-detecting-if-printer-connected-pc后终于实现了我想要的”以及我对下面这段代码的修改

Imports System.Management
Public Class Form1
Public Class CheckPrinterStatus
    Public Function PrinterIsOnline(ByVal sPrinterName As String) As Boolean
        '// Set management scope
        Dim scope As ManagementScope = New ManagementScope("\root\cimv2")
        scope.Connect()

        '// Select Printers from WMI Object Collections
        Dim searcher As ManagementObjectSearcher = New ManagementObjectSearcher("SELECT * FROM Win32_Printer")

        Dim printerName As String = String.Empty
        For Each printer As ManagementObject In searcher.Get()
            printerName = printer("Name").ToString() '.ToLower()
            If (printerName.Equals(sPrinterName)) Then
                MsgBox(printerName)
                If (printer("WorkOffline").ToString().ToLower().Equals("true")) Then

                    MsgBox("Offline")
                    ' Printer is offline by user
                    Return False
                Else
                    ' Printer is not offline
                    MsgBox("Online")
                    Return True
                End If
            End If
        Next
        Return False
    End Function ' PrinterIsOnline
End Class
Private Sub Button1_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles Button1.Click
    Dim PrinterSatus As New CheckPrinterStatus
    PrinterSatus.PrinterIsOnline("Brother QL-500") 'Name of The printer HERE
End Sub
End Class