A simple GhostScript PS to PDF C++ DLL wrapper
Updated to work with GPL and AFPL versions for the reg lookup- 3/21/2005
I decided that West Wind Web Connection could use support for GhostScript today as part of its series of supported PDF drivers etc. GhostScript is open source so it's (sort of) free - as with all open source free, doesn't mean really free - commercial use still requires payment. GhostView provides a ton of functionality in dealing with PostScript and PDF manipulation. However, the one I have been interested in is PostScript to PDF conversion which allows you to basically print from any printer to a PostScript File and convert that file into a PDF document.
I have to say I’m always underwhelmed by the documentation of these open source kind of tools. The documentation is always messy and the examples always assume you want to compile the whole source tree, which in most cases is not at all what you want - I suspect most people just want to call into the existing functionality from their own applications. Digging around for a few integration samples turned up all sorts of huge projects that put wrappers for all functionality ontop of GhostScript.
My needs are a bit simpler: I simply want to call the GhostScript DLL – dynamically via a simple DLL interface without having to compile all of GhostScript into my wrapper DLL. I basically want to create a small wrapper DLL function that can be called via Interop from any language – specifically in my case from Visual FoxPro.
To do this I created this simple DLL function that I’ve now added to wwIPStuff.dll which already ships with West Wind Web Connection:
#include <windows.h>
BOOL WINAPI GhostPsToPdf(char *PsFile, char *PdfFile,
char *Resolution, char *PaperSize, char *GsDll )
{
HMODULE hModule = NULL;
char *DllPath;
if (!GsDll)
{
HKEY hReg;
char Path[MAX_PATH] ;
DWORD Size = MAX_PATH;
char RegPath[MAX_PATH] = "SOFTWARE\\AFPL Ghostscript";
if (RegOpenKey(HKEY_LOCAL_MACHINE,RegPath,&hReg) != ERROR_SUCCESS)
{
strcpy(RegPath,"SOFTWARE\\GPL Ghostscript");
if (RegOpenKey(HKEY_LOCAL_MACHINE,RegPath,&hReg) != ERROR_SUCCESS)
return FALSE;
}
// *** Grab the first sub-key
char Version[40]; // just to be safe
DWORD VerSize=9;
if (RegEnumKeyEx(hReg,0,Version,&VerSize,NULL,NULL,NULL,NULL) != ERROR_SUCCESS)
{
RegCloseKey(hReg);
return FALSE;
}
RegCloseKey(hReg);
// *** Add to the main path and open the subkey
strcat(RegPath,"\\");
strcat(RegPath,Version);
if (RegOpenKey(HKEY_LOCAL_MACHINE,RegPath,&hReg) != ERROR_SUCCESS)
return FALSE;
DWORD RegType = REG_SZ;
if (RegQueryValueEx(hReg,"GS_DLL",0,&RegType,(LPBYTE) Path,&Size) != ERROR_SUCCESS)
{
RegCloseKey(hReg);
return FALSE;
}
DllPath = Path;
RegCloseKey(hReg);
}
else
DllPath = GsDll;
hModule = LoadLibrary(DllPath);
if (!hModule)
return FALSE;
if (!Resolution)
{
char cResolution[8] = "150x150";
Resolution = cResolution;
}
char ArgPaperSize[50] = "-sPAPERSIZE=letter";
if (PaperSize)
{
strcpy(ArgPaperSize,"-sPAPERSIZE=");
strcat(ArgPaperSize,PaperSize);
}
// *** Declare all the dynamic typedef function pointers
typedef int (WINAPI *gsapi_new_instance)( char **, int );
gsapi_new_instance lp_gsapi_new_instance ;
lp_gsapi_new_instance = (gsapi_new_instance) GetProcAddress(hModule,"gsapi_new_instance");
typedef int (WINAPI *gsapi_delete_instance) (char *);
gsapi_delete_instance lp_gsapi_delete_instance;
lp_gsapi_delete_instance = (gsapi_delete_instance) GetProcAddress(hModule,"gsapi_delete_instance");
typedef int (WINAPI *gsapi_init_with_args) (char *,int,char *);
gsapi_init_with_args lp_gsapi_init_with_args;
lp_gsapi_init_with_args = (gsapi_init_with_args) GetProcAddress(hModule,"gsapi_init_with_args");
typedef int (WINAPI *gsapi_exit) (char *);
gsapi_exit lp_gsapi_exit;
lp_gsapi_exit = (gsapi_exit) GetProcAddress(hModule,"gsapi_exit");
char ArgResolution[80] = "-r";
strcat(ArgResolution,Resolution);
char ArgOutputFile[MAX_PATH + 16] = "-sOutputFile=";
strcat(ArgOutputFile,PdfFile);
// *** Set up the parameters to the engine
const char * gsargv[11];
int gsargc;
gsargv[0] = "PsToPdf"; /* actual value doesn't matter */
gsargv[1] = "-dNOPAUSE"; // no prompts
gsargv[2] = "-dBATCH"; // exit after processing
gsargv[3] = "-dSAFER"; // Safe mode
gsargv[4] = ArgResolution;
gsargv[5] = ArgPaperSize;
gsargv[6] = "-sDEVICE=pdfwrite";
gsargv[7] = ArgOutputFile;
gsargv[8] = "-c";
gsargv[9] = ".setpdfwrite";
gsargv[10] = "-f";
gsargv[11] = PsFile;
gsargc=12;
// *** Simulate pointer to struct with plain char *
char *Inst = NULL;
int code = 0;
code = (lp_gsapi_new_instance)(&Inst,NULL);
if (code == 0)
{
// Do the conversion
code = (lp_gsapi_init_with_args) (Inst,gsargc,(char *) gsargv );
if (code == 0)
code = (lp_gsapi_exit) (Inst);
// *** Release the handle
(lp_gsapi_delete_instance) (Inst);
}
if (hModule)
FreeLibrary(hModule);
if (code == 0)
return TRUE;
return FALSE;
}
This code is obviously Windows specific since it uses the registry to figure out where the DLL lives. Note also that there’s a parameter to allow you to pass in the DLL name directly just in case the registry is not accessible (it requires Admin rights) or in case the registry entries aren’t there to start with.
Please excuse my sloppy C++ - whenever I do C++ I’m reminded that I’m soooo glad I don’t have to write C++ code and deal with pointers to pointers on a regular basis. Ughhh
Note in order for this to work you need to have GhostScript installed and you probably will want to install a Postscript printer (like the Apple Color LW 12/660 PS ) to print reports or documents to PostScript first.
FWIW, I also found some VFP code that does this all in native Fox code and ironically that’s what ultimately set me on the right path to creating the self-contained DLL code shown here. It's Print2PDF.prg, but heck I can’t find the damn Web link now and there’s no link reference in the source… Here’s an FTP site where you can download the code though - it includes the actual PDF conversion class as well as Ed Rauh's Heap class that deals with managing the parameter structure pointer in the above code.
I ended up not using the pure Fox code because it has some dependencies I didn’t want to pull into West Wind Web Connection and because this functionality is useful for other environments as well.
Hope this helps somebody out.
Other Posts you might also like
- Adding minimal OWIN Identity Authentication to an Existing ASP.NET MVC Application
- Map Physical Paths with an HttpContext.MapPath() Extension Method in ASP.NET
- Getting the Client IP Address in ASP.NET Core
- Resolving Paths To Server Relative Paths in .NET Code
- Preventing iOS Textbox Auto Zooming and ViewPort Sizing
The Voices of Reason
# re: A simple GhostScript PS to PDF C++ DLL wrapper
They work great for web servers or document processing where you need to name pdf files from vfp reports.
Bob Lee
# re: A simple GhostScript PS to PDF C++ DLL wrapper
Bob: Thanks for the link. I wasn't sure exactly who to give credit to because there were so many author notices yet no references to any Web Sites which was odd.
Somewhere I found an article that talked about what the code does. I think it was your's but I just can't find that link again.
# re: A simple GhostScript PS to PDF C++ DLL wrapper
create a .ps file
pass the ps file into ghostscript with the correct parms.. and like magic anything you can make into a ps file, you could convert it to pdf. All Free. No acrobat needed.
That was where I stared.. using VFP to duplicate the orig linux script - or dos batch file..
But, to get it all working with loading dlls, it took more experience than I had.
Since then others have even taken it to convert word docs to pdf using VFP /GhostScript.
I think someone should rewrite it into a report listener function ? with VFP9.
# re: A simple GhostScript PS to PDF C++ DLL wrapper
Malcolm
# re: A simple GhostScript PS to PDF C++ DLL wrapper
# re: A simple GhostScript PS to PDF C++ DLL wrapper
Bob Lee
bobl@1amsoftware.com
# re: A simple GhostScript PS to PDF C++ DLL wrapper
# re: A simple GhostScript PS to PDF C++ DLL wrapper
# I Need Vice-Versa
mohans@exeige.com
# re: A simple GhostScript PS to PDF COM Component
In my project i need to convert PDF file to JPG image, in google i found your DLL will do this process, can you pls help me in this regard.
I need a component where i can covert PDF file to a JPG image file.
Thanks in advance,
Konda.
# re: A simple GhostScript PS to PDF C++ DLL wrapper
I want to know whether can i use this in C#.Net application. I wanted use the feature where in i can convert a .ps file to pdf file or to a .txt file. SO i wanted to know whether is it possible for me to use this.
Govardhan
# re: A simple GhostScript PS to PDF C++ DLL wrapper
# re: A simple GhostScript PS to PDF C++ DLL wrapper
"unable to open initial device, quitting" I have AFPL GhostScript 8.54 installed .Is it caused by that i don't have a Postscript printer installed what should to do instead I want to convert a given Post script file to a pdf file
# re: A simple GhostScript PS to PDF C++ DLL wrapper
Will the updated wwIPstuff.Dll you created for Web Connection be finding its way back to your wwIPstuff product?
I believe the print2pdf website you're looking for might be Bob Lee's
http://1amsoftware.com/Downloads.htm
Note the renamed files (vfp2pdf vs. print2pdf).
Malcolm