File: n_cst_ghostscript.sru
Size: 13233
Date: Sat, 27 Jan 2024 01:57:04 +0100
$PBExportHeader$n_cst_ghostscript.sru
forward
global type n_cst_ghostscript from nonvisualobject
end type
type process_information from structure within n_cst_ghostscript
end type
type startupinfo from structure within n_cst_ghostscript
end type
type filetime from structure within n_cst_ghostscript
end type
type win32_find_data from structure within n_cst_ghostscript
end type
end forward

type process_information from structure
   longptr     hprocess
   longptr     hthread
   unsignedlong      dwprocessid
   unsignedlong      dwthreadid
end type

type startupinfo from structure
   unsignedlong      cb
   string      lpreserved
   string      lpdesktop
   string      lptitle
   unsignedlong      dwx
   unsignedlong      dwy
   unsignedlong      dwxsize
   unsignedlong      dwysize
   unsignedlong      dwxcountchars
   unsignedlong      dwycountchars
   unsignedlong      dwfillattribute
   unsignedlong      dwflags
   unsignedinteger      wshowwindow
   unsignedinteger      cbreserved2
   longptr     lpreserved2
   longptr     hstdinput
   longptr     hstdoutput
   longptr     hstderror
end type

type filetime from structure
   unsignedlong      dwlowdatetime
   unsignedlong      dwhighdatetime
end type

type win32_find_data from structure
   unsignedlong      dwfileattributes
   filetime    ftcreationtime
   filetime    ftlastaccesstime
   filetime    ftlastwritetime
   unsignedlong      nfilesizehigh
   unsignedlong      nfilesizelow
   unsignedlong      dwreserved0
   unsignedlong      dwreserved1
   character      cfilename[260]
   character      calternatefilename[14]
end type

global type n_cst_ghostscript from nonvisualobject autoinstantiate
end type

type prototypes
Function ULong GetTempPath ( &
   ULong nBufferLength, &
   Ref String lpBuffer &
   ) Library "kernel32.dll" Alias For "GetTempPathW"

Function ULong GetTempFileName ( &
   String lpPathName, &
   String lpPrefixString, &
   ULong uUnique, &
   Ref String lpTempFileName &
   ) Library "kernel32.dll"  Alias For "GetTempFileNameW"

Function Boolean CreateProcess ( &
   LongPtr lpApplicationName, &
   String lpCommandLine, &
   LongPtr lpProcessAttributes, &
   LongPtr lpThreadAttributes, &
   Boolean bInheritHandles, &
   ULong dwCreationFlags, &
   LongPtr lpEnvironment, &
   LongPtr lpCurrentDirectory, &
   STARTUPINFO lpStartupInfo, &
   Ref PROCESS_INFORMATION lpProcessInformation &
   ) Library "kernel32.dll" Alias For "CreateProcessW"

Function ULong WaitForSingleObject ( &
   LongPtr hHandle, &
   ULong dwMilliseconds &
   ) Library "kernel32.dll"

Function Boolean CloseHandle ( &
   LongPtr hObject &
   ) Library "kernel32.dll"

Function Boolean GetExitCodeProcess ( &
   LongPtr hProcess, &
   Ref ULong lpExitCode &
   ) Library "kernel32.dll"

Function LongPtr FindFirstFile ( &
   String lpFileName, &
   Ref WIN32_FIND_DATA lpFindFileData &
   ) Library "kernel32.dll" Alias For "FindFirstFileW"

Function Boolean FindNextFile ( &
   LongPtr hFindFile, &
   Ref WIN32_FIND_DATA lpFindFileData &
   ) Library "kernel32.dll" Alias For "FindNextFileW"

Function Boolean FindClose ( &
   LongPtr hFindFile &
   ) Library "kernel32.dll" Alias For "FindClose"

Function Long ShellExecute ( &
   LongPtr hwnd, &
   String lpOperation, &
   String lpFile, &
   LongPtr lpParameters, &
   LongPtr lpDirectory, &
   Long nShowCmd &
   ) Library "Shell32.dll" Alias For "ShellExecuteW"

end prototypes

type variables
Private:

Constant Long    llNull = 0
Constant LongPtr lpNULL = 0
Constant ULong   ulNULL = 0

Constant ULong STARTF_USESHOWWINDOW  = 1
Constant ULong CREATE_NEW_CONSOLE    = 16
Constant ULong NORMAL_PRIORITY_CLASS = 32
Constant ULong INFINITE = 4294967295   // 0xFFFFFFFF
Constant ULong MAX_PATH = 260

Constant String SybasePDF = "Sybase DataWindow PS"

Public:

// nShowCmd options
Constant UInt SW_HIDE            = 0
Constant UInt SW_SHOWNORMAL      = 1
Constant UInt SW_SHOWMINIMIZED   = 2
Constant UInt SW_SHOWMAXIMIZED   = 3

end variables

forward prototypes
private function boolean of_checkbit (long al_number, unsignedinteger ai_bit)
private function integer of_findfolders (readonly string as_filespec, ref string as_filename[])
private function string of_findghostscript ()
private function string of_getpsfilename ()
private function boolean of_ghostscript (readonly string as_filename, readonly string as_psnames[])
private function boolean of_postscriptprint (readonly datastore ads_datastore, readonly string as_filename)
private function boolean of_postscriptprint (readonly datawindow adw_datawindow, readonly string as_filename)
private function unsignedlong of_runandwait (readonly string as_cmdline)
public function boolean of_saveaspdf (readonly datastore ads_datastore[], readonly string as_filename)
public function boolean of_saveaspdf (readonly datastore ads_datastore, readonly string as_filename)
public function boolean of_saveaspdf (readonly datawindow adw_datawindow[], readonly string as_filename)
public function boolean of_saveaspdf (readonly datawindow adw_datawindow, readonly string as_filename)
public function boolean of_shellrun (readonly string as_filename, readonly string as_shellverb, unsignedinteger aui_showcmd)
end prototypes

private function boolean of_checkbit (long al_number, unsignedinteger ai_bit);// Check to see if the bit is on or off

If Int(Mod(al_number / (2 ^(ai_bit - 1)), 2)) > 0 Then
   Return True
End If

Return False

end function

private function integer of_findfolders (readonly string as_filespec, ref string as_filename[]);// return a list of folders

WIN32_FIND_DATA lstr_fd
Boolean lb_Found, lb_Subdir
Integer li_count
LongPtr lp_handle
String ls_empty[], ls_filespec, ls_folder, ls_filename

// append filename pattern
If Right(as_filespec, 1) = "\" Then
   ls_filespec = as_filespec + "*.*"
   ls_folder = as_filespec
Else
   ls_filespec = as_filespec + "\*.*"
   ls_folder = as_filespec + "\"
End If

// initialize output array
as_filename = ls_empty

// find first file
lp_handle = FindFirstFile(ls_filespec, lstr_fd)
If lp_handle < 1 Then Return -1

// loop through each file
Do
   // add file to array
   ls_filename = String(lstr_fd.cFilename)
   If ls_filename = "." Or ls_filename = ".." Then
   Else
      lb_Subdir = of_checkbit(lstr_fd.dwFileAttributes, 5)
      If lb_Subdir Then
         li_count ++
         as_filename[li_count] = ls_folder + ls_filename
      End If
   End If
   // find next file
   lb_Found = FindNextFile(lp_handle, lstr_fd)
Loop Until Not lb_Found

// close find handle
FindClose(lp_handle)

Return li_count

end function

private function string of_findghostscript ();// return the name of the Ghostscript exe

Integer li_count
String ls_FileNames[], ls_Folder, ls_FileName

li_count = of_FindFolders("C:\Program Files\gs", ls_FileNames)
If li_count > 0 Then
   ls_Folder = ls_FileNames[li_count] + "\bin"
   ls_FileName = ls_Folder + "\gswin64c.exe"
   If FileExists(ls_FileName) Then
      Return ls_FileName
   End If
End If

li_count = of_FindFolders("C:\Program Files (x86)\gs", ls_FileNames)
If li_count > 0 Then
   ls_Folder = ls_FileNames[li_count] + "\bin"
   ls_FileName = ls_Folder + "\gswin32c.exe"
   If FileExists(ls_FileName) Then
      Return ls_FileName
   End If
End If

Return ""

end function

private function string of_getpsfilename ();// returns an unique temp file name for the PostScript file

String ls_TempPath, ls_TempFile
ULong lul_Return

ls_TempPath = Space(MAX_PATH + 1)

lul_Return = GetTempPath(MAX_PATH, ls_TempPath)
If (lul_Return > MAX_PATH) Or (lul_Return = 0) Then
   PopulateError(999, "Failed to determine the temp path")
   SetNull(ls_TempFile)
   Return ls_TempFile
End If

ls_TempFile = Space(MAX_PATH + 1)

lul_Return = GetTempFileName(ls_TempPath, "ps", 0, ls_TempFile)
If lul_Return = 0 Then
   PopulateError(999, "Failed to generate a temp file name")
   SetNull(ls_TempFile)
   Return ls_TempFile
End If

Return ls_TempFile

end function

private function boolean of_ghostscript (readonly string as_filename, readonly string as_psnames[]);// runs Ghostscript against the PostScript files

Long ll_idx, ll_max
String ls_GhostExe, ls_psnames, ls_cmdline
ULong lul_RtnCode

// get the filename for GhostScript
ls_GhostExe = of_FindGhostScript()
If ls_GhostExe = "" Then
   PopulateError(999, "Failed to find the GhostScript program.")
   Return False
End If

// build the command line
ll_max = UpperBound(as_psnames)
For ll_idx = 1 To ll_max
   ls_psnames += ' "' + as_psnames[ll_idx] + '"'
Next
ls_cmdline =   ls_GhostExe + ' -q -dNOPAUSE -dBATCH -dSAFER -sDEVICE=pdfwrite ' + &
               '-sOutputFile="' + as_filename + '" -c -f' + ls_psnames

// run Ghostscript and wait for it to finish
lul_RtnCode = of_RunAndWait(ls_CmdLine)

// delete the PostScript files
For ll_idx = 1 To ll_max
   FileDelete(as_psnames[ll_idx])
Next

If lul_RtnCode < 0 Then
   PopulateError(999, "The GhostScript program returned error code " + String(lul_RtnCode) + ".")
   Return False
End If

Return True

end function

private function boolean of_postscriptprint (readonly datastore ads_datastore, readonly string as_filename);// print the DataStore to a PostScript file

Long ll_RtnCode

ads_datastore.Object.DataWindow.Print.PrinterName = SybasePDF
ads_datastore.Object.DataWindow.Print.FileName    = as_filename

ll_RtnCode = ads_datastore.Print(False, False)
If ll_RtnCode < 0 Then
   PopulateError(999, "DataStore failed to print")
   Return False
End If

Return True

end function

private function boolean of_postscriptprint (readonly datawindow adw_datawindow, readonly string as_filename);// print the DataWindow to a PostScript file

Long ll_RtnCode

adw_datawindow.Object.DataWindow.Print.PrinterName = SybasePDF
adw_datawindow.Object.DataWindow.Print.FileName    = as_filename

ll_RtnCode = adw_datawindow.Print(False, False)
If ll_RtnCode < 0 Then
   PopulateError(999, "DataWindow failed to print")
   Return False
End If

Return True

end function

private function unsignedlong of_runandwait (readonly string as_cmdline);// run a program and wait for it to finish

STARTUPINFO lstr_si
PROCESS_INFORMATION lstr_pi
Environment le_env
ULong lul_CreationFlags, lul_Return, lul_ExitCode

GetEnvironment(le_env)

// initialize arguments
If le_env.ProcessBitness = 64 Then
   lstr_si.cb = 104
Else
   lstr_si.cb = 68
End If
lstr_si.dwFlags = STARTF_USESHOWWINDOW
lstr_si.wShowWindow = SW_HIDE
lul_CreationFlags = CREATE_NEW_CONSOLE + NORMAL_PRIORITY_CLASS

// create process/thread and execute the passed program
If CreateProcess(ulNULL, as_cmdline, lpNULL, &
         lpNULL, False, lul_CreationFlags, lpNULL, &
         lpNULL, lstr_si, lstr_pi) Then
   // wait until process ends or timeout period expires
   lul_Return = WaitForSingleObject(lstr_pi.hProcess, INFINITE)
   // check for exit code
   GetExitCodeProcess(lstr_pi.hProcess, lul_ExitCode)
   // close process and thread handles
   CloseHandle(lstr_pi.hProcess)
   CloseHandle(lstr_pi.hThread)
Else
   // return failure
   lul_ExitCode = -1
End If

Return lul_ExitCode

end function

public function boolean of_saveaspdf (readonly datastore ads_datastore[], readonly string as_filename);// save one or more DataStore objects to a single PDF

Long ll_idx, ll_max
String ls_PSfiles[]

ll_max = UpperBound(ads_datastore)
For ll_idx = 1 To ll_max
   ls_PSfiles[ll_idx] = of_GetPSFilename()
   If Not of_PostScriptPrint(ads_datastore[ll_idx], ls_PSfiles[ll_idx]) Then
      Return False
   End If
Next

Return of_GhostScript(as_filename, ls_PSfiles)

end function

public function boolean of_saveaspdf (readonly datastore ads_datastore, readonly string as_filename);// save one DataStore object to a PDF

String ls_PSfiles[]

ls_PSfiles[1] = of_GetPSFilename()
If Not of_PostScriptPrint(ads_datastore, ls_PSfiles[1]) Then
   Return False
End If

Return of_GhostScript(as_filename, ls_PSfiles)

end function

public function boolean of_saveaspdf (readonly datawindow adw_datawindow[], readonly string as_filename);// save one or more DataWindow objects to a single PDF

Long ll_idx, ll_max
String ls_PSfiles[]

ll_max = UpperBound(adw_datawindow)
For ll_idx = 1 To ll_max
   ls_PSfiles[ll_idx] = of_GetPSFilename()
   If Not of_PostScriptPrint(adw_datawindow[ll_idx], ls_PSfiles[ll_idx]) Then
      Return False
   End If
Next

Return of_GhostScript(as_filename, ls_PSfiles)

end function

public function boolean of_saveaspdf (readonly datawindow adw_datawindow, readonly string as_filename);// save one DataWindow object to a PDF

String ls_PSfiles[]

ls_PSfiles[1] = of_GetPSFilename()
If Not of_PostScriptPrint(adw_datawindow, ls_PSfiles[1]) Then
   Return False
End If

Return of_GhostScript(as_filename, ls_PSfiles)

end function

public function boolean of_shellrun (readonly string as_filename, readonly string as_shellverb, unsignedinteger aui_showcmd);// open a file in the assigned program

Long ll_return

ll_return = ShellExecute(Handle(this), as_shellverb, &
               as_filename, llNull, llNull, aui_showcmd)
If ll_return <= 32 Then
   Return False
End If

Return True

end function

on n_cst_ghostscript.create
call super::create
TriggerEvent( this, "constructor" )
end on

on n_cst_ghostscript.destroy
TriggerEvent( this, "destructor" )
call super::destroy
end on