【IT168技术文档】
Option Explicit On Imports System.Runtime.InteropServices Module gsapiModule gsapi Public Declare Sub CopyMemory()Sub CopyMemory Lib "kernel32" Alias "RtlMoveMemory" (ByVal dest As IntPtr, ByVal source As IntPtr, ByVal bytes As Long) '------------------------------------------------ 'UDTs Start '------------------------------------------------ <StructLayout(LayoutKind.Sequential)> Public Structure GS_RevisionStructure GS_Revision Public strProduct As IntPtr Public strCopyright As IntPtr Public intRevision As Integer Public intRevisionDate As Integer End Structure '------------------------------------------------ 'UDTs End '------------------------------------------------ '------------------------------------------------ 'Callback Functions Start '------------------------------------------------ 'These are only required if you use gsapi_set_stdio Public Delegate Function StdioCallBack()Function StdioCallBack(ByVal handle As IntPtr, ByVal strptr As IntPtr, ByVal count As Integer) As Integer Public Function gsdll_stdin()Function gsdll_stdin(ByVal intGSInstanceHandle As IntPtr, ByVal strz As IntPtr, ByVal intBytes As Integer) As Integer ' This is dumb code that reads one byte at a time ' Ghostscript doesn't mind this, it is just very slow If intBytes = 0 Then gsdll_stdin = 0 Else Dim ich As Integer = Console.Read() If ich = -1 Then gsdll_stdin = 0 ' EOF Else Dim bch As Byte = ich Dim gcByte As GCHandle = GCHandle.Alloc(bch, GCHandleType.Pinned) Dim ptrByte As IntPtr = gcByte.AddrOfPinnedObject() CopyMemory(strz, ptrByte, 1) ptrByte = IntPtr.Zero gcByte.Free() gsdll_stdin = 1 End If End If End Function Public Function gsdll_stdout()Function gsdll_stdout(ByVal intGSInstanceHandle As IntPtr, ByVal strz As IntPtr, ByVal intBytes As Integer) As Integer ' If you can think of a more efficient method, please tell me! ' We need to convert from a byte buffer to a string ' First we create a byte array of the appropriate size Dim aByte(intBytes) As Byte ' Then we get the address of the byte array Dim gcByte As GCHandle = GCHandle.Alloc(aByte, GCHandleType.Pinned) Dim ptrByte As IntPtr = gcByte.AddrOfPinnedObject() ' Then we copy the buffer to the byte array CopyMemory(ptrByte, strz, intBytes) ' Release the address locking ptrByte = IntPtr.Zero gcByte.Free() ' Then we copy the byte array to a string, character by character Dim str As String Dim i As Integer For i = 0 To intBytes - 1 str = str + Chr(aByte(i)) Next ' Finally we output the message Console.Write(str) gsdll_stdout = intBytes End Function Public Function gsdll_stderr()Function gsdll_stderr(ByVal intGSInstanceHandle As IntPtr, ByVal strz As IntPtr, ByVal intBytes As Integer) As Integer gsdll_stderr = gsdll_stdout(intGSInstanceHandle, strz, intBytes) End Function '------------------------------------------------ 'Callback Functions End '------------------------------------------------ '------------------------------------------------ 'API Calls Start '------------------------------------------------ 'Win32 API 'GhostScript API ' Public Declare Function gsapi_revision Lib "gsdll32.dll" (ByVal pGSRevisionInfo As IntPtr, ByVal intLen As Integer) As Integer Public Declare Function gsapi_revision()Function gsapi_revision Lib "gsdll32.dll" (ByRef pGSRevisionInfo As GS_Revision, ByVal intLen As Integer) As Integer Public Declare Function gsapi_new_instance()Function gsapi_new_instance Lib "gsdll32.dll" (ByRef lngGSInstance As IntPtr, ByVal lngCallerHandle As IntPtr) As Integer Public Declare Function gsapi_set_stdio()Function gsapi_set_stdio Lib "gsdll32.dll" (ByVal lngGSInstance As IntPtr, ByVal gsdll_stdin As StdioCallBack, ByVal gsdll_stdout As StdioCallBack, ByVal gsdll_stderr As StdioCallBack) As Integer Public Declare Sub gsapi_delete_instance()Sub gsapi_delete_instance Lib "gsdll32.dll" (ByVal lngGSInstance As IntPtr) Public Declare Function gsapi_init_with_args()Function gsapi_init_with_args Lib "gsdll32.dll" (ByVal lngGSInstance As IntPtr, ByVal lngArgumentCount As Integer, ByVal lngArguments As IntPtr) As Integer Public Declare Function gsapi_run_file()Function gsapi_run_file Lib "gsdll32.dll" (ByVal lngGSInstance As IntPtr, ByVal strFileName As String, ByVal intErrors As Integer, ByVal intExitCode As Integer) As Integer Public Declare Function gsapi_exit()Function gsapi_exit Lib "gsdll32.dll" (ByVal lngGSInstance As IntPtr) As Integer '------------------------------------------------ 'API Calls End '------------------------------------------------ '------------------------------------------------ 'User Defined Functions Start '------------------------------------------------ Public Function StringToAnsiZ()Function StringToAnsiZ(ByVal str As String) As Byte() ' Convert a Unicode string to a null terminated Ansi string for Ghostscript. ' The result is stored in a byte array. Later you will need to convert ' this byte array to a pointer with GCHandle.Alloc(XXXX, GCHandleType.Pinned) ' and GSHandle.AddrOfPinnedObject() Dim intElementCount As Integer Dim intCounter As Integer Dim aAnsi() As Byte Dim bChar As Byte intElementCount = Len(str) ReDim aAnsi(intElementCount + 1) For intCounter = 0 To intElementCount - 1 bChar = Asc(Mid(str, intCounter + 1, 1)) aAnsi(intCounter) = bChar Next intCounter aAnsi(intElementCount) = 0 StringToAnsiZ = aAnsi End Function Public Function AnsiZtoString()Function AnsiZtoString(ByVal strz As IntPtr) As String ' We need to convert from a byte buffer to a string Dim byteCh(1) As Byte Dim bOK As Boolean = True Dim gcbyteCh As GCHandle = GCHandle.Alloc(byteCh, GCHandleType.Pinned) Dim ptrByte As IntPtr = gcbyteCh.AddrOfPinnedObject() Dim j As Integer = 0 Dim str As String While bOK ' This is how to do pointer arithmetic! Dim sPtr As New IntPtr(strz.ToInt64() + j) CopyMemory(ptrByte, sPtr, 1) If byteCh(0) = 0 Then bOK = False Else str = str + Chr(byteCh(0)) End If j = j + 1 End While AnsiZtoString = str End Function Public Function CheckRevision()Function CheckRevision(ByVal intRevision As Integer) As Boolean ' Check revision number of Ghostscript Dim intReturn As Integer Dim udtGSRevInfo As GS_Revision Dim gcRevision As GCHandle gcRevision = GCHandle.Alloc(udtGSRevInfo, GCHandleType.Pinned) intReturn = gsapi_revision(udtGSRevInfo, 16) Console.WriteLine("Revision = " & udtGSRevInfo.intRevision) Console.WriteLine("RevisionDate = " & udtGSRevInfo.intRevisionDate) Console.WriteLine("Product = " & AnsiZtoString(udtGSRevInfo.strProduct)) Console.WriteLine("Copyright = " & AnsiZtoString(udtGSRevInfo.strCopyright)) If udtGSRevInfo.intRevision = intRevision Then CheckRevision = True Else CheckRevision = False End If gcRevision.Free() End Function Public Function CallGS()Function CallGS(ByVal astrGSArgs() As String) As Boolean Dim intReturn As Integer Dim intGSInstanceHandle As IntPtr Dim aAnsiArgs() As Object Dim aPtrArgs() As IntPtr Dim aGCHandle() As GCHandle Dim intCounter As Integer Dim intElementCount As Integer Dim iTemp As Integer Dim callerHandle As IntPtr Dim gchandleArgs As GCHandle Dim intptrArgs As IntPtr ' Print out the revision details. ' If we want to insist on a particular version of Ghostscript ' we should check the return value of CheckRevision(). CheckRevision(704) ' Load Ghostscript and get the instance handle intReturn = gsapi_new_instance(intGSInstanceHandle, callerHandle) If (intReturn < 0) Then Return (False) End If ' Capture stdio Dim stdinCallback As StdioCallBack stdinCallback = AddressOf gsdll_stdin Dim stdoutCallback As StdioCallBack stdoutCallback = AddressOf gsdll_stdout Dim stderrCallback As StdioCallBack stderrCallback = AddressOf gsdll_stderr intReturn = gsapi_set_stdio(intGSInstanceHandle, stdinCallback, stdoutCallback, stderrCallback) If (intReturn >= 0) Then ' Convert the Unicode strings to null terminated ANSI byte arrays ' then get pointers to the byte arrays. intElementCount = UBound(astrGSArgs) ReDim aAnsiArgs(intElementCount) ReDim aPtrArgs(intElementCount) ReDim aGCHandle(intElementCount) For intCounter = 0 To intElementCount aAnsiArgs(intCounter) = StringToAnsiZ(astrGSArgs(intCounter)) aGCHandle(intCounter) = GCHandle.Alloc(aAnsiArgs(intCounter), GCHandleType.Pinned) aPtrArgs(intCounter) = aGCHandle(intCounter).AddrOfPinnedObject() Next gchandleArgs = GCHandle.Alloc(aPtrArgs, GCHandleType.Pinned) intptrArgs = gchandleArgs.AddrOfPinnedObject() callerHandle = IntPtr.Zero intReturn = gsapi_init_with_args(intGSInstanceHandle, intElementCount + 1, intptrArgs) ' Release the pinned memory For intCounter = 0 To intElementCount aGCHandle(intCounter).Free() Next gchandleArgs.Free() ' Stop the Ghostscript interpreter gsapi_exit(intGSInstanceHandle) End If ' release the Ghostscript instance handle gsapi_delete_instance(intGSInstanceHandle) If (intReturn >= 0) Then CallGS = True Else CallGS = False End If End Function Private Function ConvertFile()Function ConvertFile() As Boolean Dim astrArgs(10) As String astrArgs(0) = "ps2pdf" 'The First Parameter is Ignored astrArgs(1) = "-dNOPAUSE" astrArgs(2) = "-dBATCH" astrArgs(3) = "-dSAFER" astrArgs(4) = "-r300" astrArgs(5) = "-sDEVICE=pdfwrite" astrArgs(6) = "-sOutputFile=c:\out.pdf" astrArgs(7) = "-c" astrArgs(8) = ".setpdfwrite" astrArgs(9) = "-f" astrArgs(10) = "c:\gs\gs7.04\examples\colorcir.ps" Return CallGS(astrArgs) End Function Private Function InteractiveGS()Function InteractiveGS() As Boolean Dim astrArgs(2) As String astrArgs(0) = "gs" 'The First Parameter is Ignored astrArgs(1) = "-c" astrArgs(2) = "systemdict /start get exec" Return CallGS(astrArgs) End Function '------------------------------------------------ 'User Defined Functions End '------------------------------------------------ Sub Main()Sub Main() ConvertFile() 'InteractiveGS() MsgBox("Done") End Sub End Module