0
votes

i am using Ghostscrip VB.NET wrapper to be able to print PDF files, without need to install GhostScript exe on users' computers nor Adobe.

It works very good. But the problem is that i need to print many files and i cannot stop default printer dialog popping up each time when i send some file to print.

I don't mind printer dialog coming up because i wish that user can select printer to print on but i can't figure out how can i send multiple files to the printing in a single command.

The purpose is to show printer dialog just once for many files. This is my code:

RunGS("-q", "-dNOPAUSE", "-dNoCancel", "-dBATCH", "-dSAFER", "-sDEVICE=mswinpr2", Path)

RunGS - is wrapper function Path is variable with filepath.

3

3 Answers

1
votes

The Ghostscript command line can take multiple input files. It should just work if you modify RunGS to take an optional number of Path arguments and pass them through to the underlying gswin32c.exe command line.

I tested this with the below command, which printed 2 copies of the file:

gswin32c -dBATCH -dNOPAUSE -sDEVICE=mswinpr2 file.pdf file.pdf

I'm not sure what RunGS is but I searched and found a previous post here where someone shared a function that interacts directly with the DLL. If it's the same function, it seems to just pass all the args directly through to Ghostscript. Try adding multiple input files and it should just work if that's the case.

Example that works for me:

GhostscriptDllLib.RunGS("-q", "-dNOPAUSE", "-dNoCancel", "-dBATCH", "-dSAFER", "-sDEVICE=mswinpr2", "C:\testing\Test1.pdf", "C:\testing\Test2.pdf")
0
votes

Thank you for your help. I have tried, but didn't work. I use wrapper that communicated directly to dll. This is the module of the wraper:

Option Explicit On
Imports System.Runtime.InteropServices

'--- Simple VB.Net wrapper for Ghostscript gsdll32.dll

'    (Tested using Visual Studio 2010 and Ghostscript 9.06)

Module GhostscriptDllLib

    Private Declare Function gsapi_new_instance Lib "gsdll32.dll" _
      (ByRef instance As IntPtr, _
      ByVal caller_handle As IntPtr) As Integer

    Private Declare Function gsapi_set_stdio Lib "gsdll32.dll" _
      (ByVal instance As IntPtr, _
      ByVal gsdll_stdin As StdIOCallBack, _
      ByVal gsdll_stdout As StdIOCallBack, _
      ByVal gsdll_stderr As StdIOCallBack) As Integer

    Private Declare Function gsapi_init_with_args Lib "gsdll32.dll" _
      (ByVal instance As IntPtr, _
      ByVal argc As Integer, _
      <MarshalAs(UnmanagedType.LPArray, ArraySubType:=UnmanagedType.LPStr)> _
      ByVal argv() As String) As Integer

    Private Declare Function gsapi_exit Lib "gsdll32.dll" _
      (ByVal instance As IntPtr) As Integer

    Private Declare Sub gsapi_delete_instance Lib "gsdll32.dll" _
      (ByVal instance As IntPtr)

    '--- Run Ghostscript with specified arguments

    Public Function RunGS(ByVal ParamArray Args() As String) As Boolean

        Dim InstanceHndl As IntPtr
        Dim NumArgs As Integer
        Dim StdErrCallback As StdIOCallBack
        Dim StdInCallback As StdIOCallBack
        Dim StdOutCallback As StdIOCallBack

        NumArgs = Args.Count

        StdInCallback = AddressOf InOutErrCallBack
        StdOutCallback = AddressOf InOutErrCallBack
        StdErrCallback = AddressOf InOutErrCallBack

        '--- Shift arguments to begin at index 1 (Ghostscript requirement)

        ReDim Preserve Args(NumArgs)
        System.Array.Copy(Args, 0, Args, 1, NumArgs)

        '--- Start a new Ghostscript instance

        If gsapi_new_instance(InstanceHndl, 0) <> 0 Then
            Return False
            Exit Function
        End If

        '--- Set up dummy callbacks

        gsapi_set_stdio(InstanceHndl, StdInCallback, StdOutCallback, StdErrCallback)

        '--- Run Ghostscript using specified arguments

        gsapi_init_with_args(InstanceHndl, NumArgs + 1, Args)

        '--- Exit Ghostscript

        gsapi_exit(InstanceHndl)

        '--- Delete instance

        gsapi_delete_instance(InstanceHndl)

        Return True

    End Function

    '--- Delegate function for callbacks

    Private Delegate Function StdIOCallBack(ByVal handle As IntPtr, _
      ByVal Strz As IntPtr, ByVal Bytes As Integer) As Integer

    '--- Dummy callback for standard input, standard output, and errors

    Private Function InOutErrCallBack(ByVal handle As IntPtr, _
      ByVal Strz As IntPtr, ByVal Bytes As Integer) As Integer

        Return 0

    End Function

End Module

Then i try to run function GS where arguments are divded with comma.

RunGS("-q", "-dNOPAUSE", "-dNoCancel", "-dBATCH", "-dSAFER", "-sDEVICE=mswinpr2", Path)

If i separate path with comma, nothing happens. If i put path together separating with blank space, either. Printing is not invoked.

0
votes

The other post in this site is Simple VB.Net Wrapper for Ghostscript Dll. It doesn't work for me too.

First, the source code goes to InOutErrCallBack method in this part:

gsapi_init_with_args(InstanceHndl, NumArgs + 1, Args)

When this occurr, the execution freeze. After this occurs, the next calls to RunGS method returns false in this part:

If gsapi_new_instance(InstanceHndl, IntPtr.Zero) <> 0 Then
    Return False
    Exit Function
End If

The return value of gsapi_new_instance is -100: Ghostscript API - Return codes

The gswin32.dll is in C:\Windows\System32 and BIN project folder.

I wrote other wrapper too, and occur something similar:

Option Explicit On 

Imports System.Runtime.InteropServices

'''
''' https://msdn.microsoft.com/en-us/library/aa719104(v=vs.71).aspx
''' http://www.codeproject.com/Articles/32274/How-To-Convert-PDF-to-Image-Using-Ghostscript-API
''' http://www.ghostscript.com/doc/current/API.htm
''' https://stackguides.com/questions/16929383/simple-vb-net-wrapper-for-ghostscript-dll
'''
Public Class GhostscriptDLLWrapper

#Region "GhostScript Import"

    <StructLayout(LayoutKind.Sequential)> _
    Public Structure GSVersion
        Public product As IntPtr
        Public copyright As IntPtr
        Public revision As Integer
        Public revisionDate As Integer
    End Structure

    '''
    ''' <summary>This function returns the revision numbers and strings of the Ghostscript interpreter library; 
    ''' you should call it before any other interpreter library functions to make sure that the 
    ''' correct version of the Ghostscript interpreter has been loaded.</summary>
    '''
    <DllImport("gsdll32.dll", CharSet:=CharSet.Ansi, EntryPoint:="gsapi_revision")> _
    Public Shared Function GsapiRevision(ByRef pVer As GSVersion, ByVal pSize As Integer) As Integer

    End Function

    ''' <summary>Create a new instance of Ghostscript.</summary>
    ''' <param name="pinstance"></param>
    ''' <param name="caller_handle"></param>
    ''' <returns>The instance passed to other GS function</returns>
    <DllImport("gsdll32.dll", CharSet:=CharSet.Ansi, EntryPoint:="gsapi_new_instance")> _
    Public Shared Function GsapiNewInstance( _
        ByRef instance As IntPtr, _
        ByVal caller_handle As IntPtr) As Integer

    End Function

    ''' <summary>This will make the conversion</summary>
    ''' <param name="instance"></param><param name="argc"></param>
    ''' <param name="argv"></param>
    ''' <returns>0 if is ok</returns>
    <DllImport("gsdll32.dll", CharSet:=CharSet.Ansi, EntryPoint:="gsapi_init_with_args")> _
    Public Shared Function GsapiInitWithArgs( _
        ByVal instance As IntPtr, _
        ByVal argc As Integer, _
        <MarshalAs(UnmanagedType.LPArray, ArraySubType:=UnmanagedType.LPStr)> _
        ByVal argv() As String) As Integer

    End Function

    ''' <summary>Exit the interpreter</summary>
    ''' <param name="instance"></param>
    ''' <returns></returns>
    <DllImport("gsdll32.dll", CharSet:=CharSet.Ansi, EntryPoint:="gsapi_exit")> _
    Public Shared Function GsapiExit(ByVal instance As IntPtr) As Integer

    End Function

    ''' <summary>Destroy an instance of Ghostscript.</summary>
    ''' <param name="instance"></param>
    <DllImport("gsdll32.dll", CharSet:=CharSet.Ansi, EntryPoint:="gsapi_delete_instance")> _
    Public Shared Function GsapiDeleteInstance(ByVal instance As IntPtr)

    End Function

#End Region

End Class

I call these methods in this way:

'https://stackguides.com/questions/16929383/simple-vb-net-wrapper-for-ghostscript-dll
'Shift arguments to begin at index 1 (Ghostscript requirement)
'Initialise the interpreter. This calls gs_main_init_with_args() in imainarg.c. See below for return codes. 
'The arguments are the same as the "C" main function: argv[0] is ignored and the user supplied arguments are argv[1] to argv[argc-1].
Dim argsCount As Integer = args.Length
ReDim Preserve args(argsCount)
System.Array.Copy(args, 0, args, 1, argsCount)

SyncLock SyncRoot
    Dim gsInstance As IntPtr
    Dim result As Integer
    result = GhostscriptDLLWrapper.GsapiNewInstance(gsInstance, IntPtr.Zero)
    If (result = 0) Then
        Try
            result = GhostscriptDLLWrapper.GsapiInitWithArgs( _
             gsInstance, _
             args.Length, _
             args _
             )

            If (result < 0) Then
                Throw New InvalidOperationException("Erro ao converter páginas do PDF em imagens PNG")
            End If

            If File.Exists(outputImgPath) Then
                objFileStream = New FileStream(outputImgPath, FileMode.Open)
                Dim length As Int32 = objFileStream.Length
                Dim bytes(length) As Byte
                objFileStream.Read(bytes, 0, length)
                objFileStream.Close()

                objMemoryStream = New MemoryStream(bytes, False)

                objImages.Add(Image.FromStream(objMemoryStream))
            Else
                Throw New InvalidOperationException("Erro ao converter páginas do PDF em imagens PNG")
            End If
        Catch ex As Exception
            Throw New InvalidOperationException("Erro ao converter páginas do PDF em imagens PNG", ex)
        End Try
    End If

    GhostscriptDLLWrapper.GsapiExit(gsInstance)
    GhostscriptDLLWrapper.GsapiDeleteInstance(gsInstance)
End SyncLock

My parameter sequence:

    Dim outputImgPath As String
outputImgPath = "C:\Download\DocumentosV2\Protocolo\Pronunciamento\" + Guid.NewGuid.ToString("N") + ".png"

Dim args() As String = { _
    "-dNOPAUSE", _
    "-dBATCH", _
    "-dSAFER", _
    "-dQUIET", _
    "-sDEVICE=png16m", _
    String.Format("-r{0}", resolucao), _
    "-dTextAlphaBits=2", _
    "-dGraphicsAlphaBits=2", _
    String.Format("-dFirstPage={0}", pageNumber), _
    String.Format("-dLastPage={0}", pageNumber), _
    String.Format("-sOutputFile={0}", outputImgPath), _
    "-f", _
    pdfPath _
    }