Sign in to follow this  
Followers 0
vipergts450

Autoit DllCall and GhostScript issue

7 posts in this topic

Hi all,

I've spent hours poring over the forums to try and find similar examples to mine, but still managed to get stuck at a particular point in the process to invoke the gsdll32.dll functions. I am able to open the DLL, and get a successful response from gsapi_new_instance when passing pointers around there. However, attempting to invoke gsapi_init_with_args has me very frustrated. Here's my code:

Local $aDllArgs[9] = ["gswin32c", _
                                 "-sDEVICE=pdfwrite", _
                                 "-dNOPAUSE", _
                                 "-dBATCH", _
                                 "-dSAFER", _
                                 "-dFirstPage=" & $aParseArgs[3], _
                                 "-dLastPage=" & $aParseArgs[4], _
                                 "-sOutputFile=""" & $sDestName & """", _
                                 """" & $sPDFPath & """"]


            $varList = DllStructCreate("ptr[" & UBound($aDllArgs) & "]")
            $p_varList = DllStructGetPtr($varList)


            For $k=1 to UBound($aDllArgs)
               DllStructSetData( $varList, _
                                 $k, _
                                 DllStructSetData(DllStructCreate("char[255]"), 1, $aDllArgs[$k-1]))
            Next

            consolewrite("varList is located at: " & $p_varList & @CRLF)

            Local $hDll = DllOpen(@ScriptDir & "\gsdll32.dll")

            Local $hInst
            ConsoleWrite("hInst prior to call: " & $hInst & @CRLF)
            Local $dResult = DllCall($hDll, "int", "gsapi_new_instance", "ptr*", Null, "ptr", Null)

            $hInst = $dResult[1]

            ConsoleWrite("created instance. returned: " & $dResult[0] & @CRLF & "$hInst: " & $hInst & @CRLF)
            If $dResult[0] = 0 Then
               ConsoleWrite("trying to print PDF" & @CRLF)
               $dResult = DllCall($hDll, "int", "gsapi_init_with_args", "ptr", $hInst, _
                                 "int", UBound($aDllArgs), _
                                 "ptr", $p_varList)

Since gsapi_init_with_args takes (void *instance, int argc, char **argv), I figured I needed to convert the items in my $aDllArgs array to DllStructs, then pass the pointer to that DllStruct into the function call since AutoIt doesn't have char** types. Unfortunately this just crashes out once the code reaches this line.

However, even when I tried passing the third argument as type "str" or "str*" and $aDllArgs directly:

$dResult = DllCall($hDll, "int", "gsapi_init_with_args", "ptr", $hInst, _
                                 "int", UBound($aDllArgs), _
                                 "str*", $aDllArgs)

it still crashes out.

Not sure where to go from here. Any help would be greatly appreciated.

Thanks.

Share this post


Link to post
Share on other sites



#2 ·  Posted (edited)

Have you checked if $varList contains the proper data? (Hint: You have only one element, which is an array of pointers.)

Edited by LarsJ

Share this post


Link to post
Share on other sites

#3 ·  Posted (edited)

Edit 1. I was Wrong. maybe if you try the C code. then can make it in autoit.

Edit 2:

$dResult = DllCall($hDll, "int", "gsapi_init_with_args", "ptr", $hInst,  "int", UBound($aDllArgs),    "str*", $aDllArgs)

 

last dllcall argument should be a pointer to structure $p_varList.

look:

$dResult = DllCall($hDll, "int", "gsapi_init_with_args", "ptr", $hInst,"int",UBound($aDllArgs), "ptr", $p_varList)

Saludos

 

Edit 3

Your structure of pointers is wrong. Try something like this:

Local $aDllArgs[9] = ["gswin32c", _
                                 "-sDEVICE=pdfwrite", _
                                 "-dNOPAUSE", _
                                 "-dBATCH", _
                                 "-dSAFER", _
                                 "-dFirstPage=" & $aParseArgs[3], _
                                 "-dLastPage=" & $aParseArgs[4], _
                                 "-sOutputFile=""" & $sDestName & """", _
                                 """" & $sPDFPath & """"]
   
   
   
   
   $varList = DllStructCreate("ptr[" & UBound($aDllArgs) & "]")
            $p_varList = DllStructGetPtr($varList)


         Local $tData[UBound($aDllArgs)]

            for $i= 1 to UBound($aDllArgs)
                $tData[$i-1]=DllStructCreate("char[" & StringLen($aDllArgs[$i-1])+1 & "]")
                DllStructSetData($varList,1,DllStructGetPtr($tData[$i-1]),$i)
                ;Debug Pointers
                ConsoleWrite(DllStructGetData($varList,1,$i) & @CRLF)
                DllStructSetData($tData[$i-1],1,$aDllArgs[$i-1])
            next


;Debug Strings
for $i=1 to UBound($aDllArgs)
ConsoleWrite(DllStructGetData(DllStructCreate("char[" & StringLen($aDllArgs[$i-1])+1 & "]",DllStructGetData($varList,1,$i)),1) & @CRLF)
Next

Saludos

Edited by Danyfirex
1 person likes this

 

venezuela.png Would you like to say thank to Danyfirex using a warmy way?  offer me a cup of coffee... coffee.png

autoit_scripter_blue_userbar.png

       AutoIt...

 

 

Share this post


Link to post
Share on other sites

Thanks very much for the help LarsJ and Danyfirex. Danyfirex, your solution worked perfectly... I'm still trying to get the hang of the DllStructs and how they are passed from function to function. I'm finding it tough to follow the data through the process of multiple DllStructGetData and DllStructGetPtr functions concatenated like that.

Thanks again for the explanation.

Share this post


Link to post
Share on other sites

You're welcome.

Saludos


 

venezuela.png Would you like to say thank to Danyfirex using a warmy way?  offer me a cup of coffee... coffee.png

autoit_scripter_blue_userbar.png

       AutoIt...

 

 

Share this post


Link to post
Share on other sites

Sorry for the up, is possible to see a working example? I have always use gswin32c executable but if i can avoid it and use only the DLL is better. Thanks

Share this post


Link to post
Share on other sites

Sorry for the up, is possible to see a working example? I have always use gswin32c executable but if i can avoid it and use only the DLL is better. Thanks

 

Certainly. So the gsdll32.dll is a little quirky because you have to initialize it, then run it, then destroy the instance when you're done.

The code by Danyfirex helps get all the args you usually pass in the command line into the AutoIt equivalent of a char** in C/C++. 

I'll walk through it for beginners so hopefully it can referenced by anyone who needs it in the future. Sorry if it's overly explanatory.

Local $aDllArgs[9] = ["gswin32c", _
                                 "-sDEVICE=pdfwrite", _
                                 "-dNOPAUSE", _
                                 "-dBATCH", _
                                 "-dSAFER", _
                                 "-dFirstPage=" & $aParseArgs[3], _
                                 "-dLastPage=" & $aParseArgs[4], _
                                 "-sOutputFile=" & $sDestName & "", _
                                 "" & $sPDFPath & ""]
   
   
   
   
   $varList = DllStructCreate("ptr[" & UBound($aDllArgs) & "]")
            $p_varList = DllStructGetPtr($varList)


         Local $tData[UBound($aDllArgs)]

            for $k= 1 to UBound($aDllArgs)
                $tData[$i-1]=DllStructCreate("char[" & StringLen($aDllArgs[$k-1])+1 & "]")
                DllStructSetData($varList,1,DllStructGetPtr($tData[$k-1]),$k)
                ;Debug Pointers
                ConsoleWrite(DllStructGetData($varList,1,$k) & @CRLF)
                DllStructSetData($tData[$k-1],1,$aDllArgs[$k-1])
            next


;Debug Strings
for $i=1 to UBound($aDllArgs)
ConsoleWrite(DllStructGetData(DllStructCreate("char[" & StringLen($aDllArgs[$i-1])+1 & "]",DllStructGetData($varList,1,$i)),1) & @CRLF)
Next

$aDllArgs is my string array for the individual arguments, $varList is the DllStruct of an array of pointers with the size of $aDllArgs. $p_varList stores the pointer to this DllStruct. $tData is created as an array of "char[]" DllStructs, each appropriately sized for the respective string in $aDllArgs. This converts the strings into char arrays for use in the C-code DLL. The corresponding $varList index ($k) then gets the pointer to this new char array, and finally $tData[$k-1] is set to the value of the string.

After all this, you can finally call the code to create and work with the instances of gsdll32.dll. The stdout of the DLL appears in the Console window when the script runs. Note: you don't have to pass the paths to the PDF input and output files in quotes - this is different than when you're using the executable. Initially, I had them in quotes and this didn't work, but you'll see in the above code in this post, I've removed the extra quotes.

Local $hDll = DllOpen(@ScriptDir & "\gsdll32.dll") ; Open the DLL

            Local $hInst
            Local $dResult = DllCall($hDll, "int", "gsapi_new_instance", "ptr*", Null, "ptr", Null) ; Create a new instance, will return a memory location to the instance in position 1 of the result array

            $hInst = $dResult[1] ; set $hInst to the pointer returned in gsapi_new_instance

            If $dResult[0] = 0 Then ; If return code was 0, proceed.
               ConsoleWrite("trying to print PDF" & @CRLF) ; Debug: checks where we are
               $dResult = DllCall($hDll, "int", "gsapi_init_with_args", "ptr", $hInst, _
                                 "int", UBound($aDllArgs), _
                                 "ptr", $p_varList) ; pass the pointer to the instance, the number of args, and the pointer to the arg array we made previously

               If @error Then
                  ; Display the error message.
                  MsgBox($MB_SYSTEMMODAL, "", "Error in DllCall (""gsapi_init_with_args""). @error = "  & @error)
                  Exit
               EndIf

               If $dResult[0] = 0 Then ; If the return code was 0, proceed
                  $dResult = DllCall($hDll, "int", "gsapi_exit", "ptr", $hInst) ; close the instance as we're now done

               EndIf

               DllCall($hDll, "none", "gsapi_delete_instance", "ptr", $hInst) ; delete the instance

            EndIf

            If @error Then
               ; Display the error message.
               MsgBox($MB_SYSTEMMODAL, "", "Can't find Ghostscript DLL (gsdll32.dll) in " & @CRLF & @ScriptDir) ; probably not needed at this point
               Exit

            EndIf

            DllClose($hDll) ; close the DLL in AutoIt
            ConsoleWrite("closed DLL" & @CRLF) ; Debug: checks where we are

Share this post


Link to post
Share on other sites

Create an account or sign in to comment

You need to be a member in order to leave a comment

Create an account

Sign up for a new account in our community. It's easy!


Register a new account

Sign in

Already have an account? Sign in here.


Sign In Now
Sign in to follow this  
Followers 0