Add and delete custom printer forms
By Sergey - Posted on May 12th, 2008
To distribute applications that use reports with custom paper size you have to create custom printer forms on every destination PC that runs Windows 2000 or later. The MS KB article Q157172 explains how it can be done manually. However there's a way to do that programmatically using Windows API.
The code is based on the working code posted by Jim Livermore on UT and work of George Tasker and late Ed Rauh.
| This is sample code. Add error handling and adjust to your requirements as necessary. |
Requires Windows 2000 or later. The WinApiErrMsg function in the code below is from Retrieving Windows system error message. The Windows API support class is used to handle Windows API structures.
lcPrinterName = "Adobe PDF" && All sizes in inches ooo = NEWOBJECT("AddPrinterForm", "AddPrinterForm.fxp") IF NOT ooo.AddForm("MyCustomForm1", 5,7, lcPrinterName) ? ooo.cErrorMessage ? ooo.cApiErrorMessage && Error ENDIF &&!* * Delete just created form &&!* ooo = NEWOBJECT("AddPrinterForm", "AddPrinterForm.fxp") &&!* IF NOT ooo.DeleteForm("MyCustomForm1", lcPrinterName) &&!* ? ooo.cErrorMessage &&!* ? ooo.cApiErrorMessage &&!* * Error &&!* ENDIF && All sizes in cm ooo = NEWOBJECT("AddPrinterForm", "AddPrinterForm.fxp", "", "Metric") IF NOT ooo.AddForm("MyCustomForm2", 15,17, lcPrinterName) && Error ENDIF &&!* * Delete just created form &&!* ooo = NEWOBJECT("AddPrinterForm", "AddPrinterForm.fxp") &&!* IF NOT ooo.DeleteForm("MyCustomForm2", lcPrinterName) &&!* ? ooo.cErrorMessage &&!* ? ooo.cApiErrorMessage &&!* * Error &&!* ENDIF &&------------------------------------------------------------------------------------------- &&AddPrinterForm.prg DEFINE CLASS AddPrinterForm AS Custom HIDDEN cUnit, cPrinterName, nFormHeight, nFormWidth, nLeftMargin, ; nTopMargin, nRightMargin, nBottomMargin, nInch2mm, nCm2mm, nCoefficient, hHeap cUnit = "English" && inches or Metric - cm's cPrinterName = "" nFormHeight = 0 nFormWidth = 0 nLeftMargin = 0 nTopMargin = 0 nRightMargin = 0 nBottomMargin = 0 cApiErrorMessage = "" cErrorMessage = "" nInch2mm = 25.4 nCm2mm = 10 nCoefficient = This.nInch2mm * 1000 hHeap = 0 && Win API support class oWas = NULL PROCEDURE Init(tcUnit) This.oWas = NEWOBJECT("WinApiSupport", "WinApiSupport.fxp") IF PCOUNT() = 1 This.cUnit = PROPER(tcUnit) ENDIF This.LoadApiDlls() This.hHeap = HeapCreate(0, 4096, 0) && Use Windows default printer This.cPrinterName = SET("Printer",2) ENDPROC PROCEDURE cUnit_Assign(tcUnit) IF INLIST(tcUnit, "English", "Metric") This.cUnit = PROPER(tcUnit) ELSE RETURN ENDIF && Calculate conversion coefficient This.nCoefficient = IIF(PROPER(This.cUnit) = "English", ; This.nInch2mm, This.nCm2mm) * 1000 ENDPROC PROCEDURE Destroy IF This.hHeap <> 0 HeapDestroy(This.hHeap) ENDIF ENDPROC PROCEDURE SetFormMargins(tnLeft, tnTop, tnRight, tnBottom) WITH This .nLeftMargin = tnLeft * .nCoefficient .nTopMargin = tnTop * .nCoefficient .nRightMargin = tnRight * .nCoefficient .nBottomMargin = tnBottom * .nCoefficient ENDWITH ENDPROC PROCEDURE AddForm(tcFormName, tnWidth, tnHeight, tcPrinterName) LOCAL lhPrinter, llOK, lcForm This.nFormWidth = tnWidth * This.nCoefficient This.nFormHeight = tnHeight * This.nCoefficient IF PCOUNT() > 3 This.cPrinterName = tcPrinterName ENDIF This.ClearErrors() lhPrinter = 0 IF OpenPrinter(This.cPrinterName, @lhPrinter, 0) = 0 This.cErrorMessage = "Unable to get printer handle for " + This.cPrinterName This.cApiErrorMessage = WinApiErrMsg(GetLastError()) RETURN .F. ENDIF lnFormName = HeapAlloc(This.hHeap, 0, LEN(tcFormName) + 1) = SYS(2600, lnFormName, LEN(tcFormName) + 1, tcFormName + CHR(0)) && Build FORM_INFO_1 structure WITH This.oWas lcForm = .Num2Long(0) + .Num2Long(lnFormName) + ; .Num2Long(This.nFormWidth) + .Num2Long(This.nFormHeight) + ; .Num2Long(This.nLeftMargin) + .Num2Long(This.nTopMargin) + ; .Num2Long(This.nFormWidth - This.nRightMargin) + ; .Num2Long(This.nFormHeight - This.nBottomMargin) ENDWITH && Finally, call the API IF AddForm(lhPrinter, 1, @lcForm) = 0 This.cErrorMessage = "Unable to Add Form " + tcFormName This.cApiErrorMessage = STRTRAN(WinApiErrMsg(GetLastError()), "file", "form", -1, -1, 3) llOK = .F. ELSE llOK = .T. ENDIF = HeapFree(This.hHeap, 0, lnFormName) = ClosePrinter(lhPrinter) RETURN llOK PROCEDURE ClearErrors This.cErrorMessage = "" This.cApiErrorMessage = "" ENDPROC PROCEDURE DeleteForm(tcFormName, tcPrinterName) LOCAL lhPrinter, llOK IF PCOUNT() > 1 This.cPrinterName = tcPrinterName ENDIF This.ClearErrors() lhPrinter = 0 IF OpenPrinter(This.cPrinterName, @lhPrinter, 0) = 0 This.cErrorMessage = "Unable to get printer handle for " + This.cPrinterName + "." This.cApiErrorMessage = WinApiErrMsg(GetLastError()) RETURN .F. ENDIF && Finally, call the API llOK = ( DeleteForm(lhPrinter, tcFormName) <> 0 ) IF NOT llOK This.cErrorMessage = "Unable to delete Form " + tcFormName This.cApiErrorMessage = STRTRAN(WinApiErrMsg(GetLastError()), "file", "form", -1, -1, 3) ENDIF = ClosePrinter(lhPrinter) RETURN llOK HIDDEN PROCEDURE LoadApiDlls DECLARE Long HeapCreate IN WIN32API Long dwOptions, Long dwInitialSize, Long dwMaxSize DECLARE Long HeapAlloc IN WIN32API Long hHeap, Long dwFlags, Long dwBytes DECLARE Long HeapFree IN WIN32API Long hHeap, Long dwFlags, Long lpMem DECLARE HeapDestroy IN WIN32API Long hHeap DECLARE Long GetLastError IN kernel32 ENDPROC ENDDEFINE &&---------------------------------------------------------------------------------------------- FUNCTION OpenPrinter(tcPrinterName, thPrinter, tcDefault) DECLARE Long OpenPrinter IN WinSpool.Drv ; String pPrinterName, Long @ phPrinter, String pDefault RETURN OpenPrinter(tcPrinterName, @thPrinter, tcDefault) FUNCTION ClosePrinter (thPrinter) DECLARE Long ClosePrinter IN WinSpool.Drv Long hPrinter RETURN ClosePrinter(thPrinter) FUNCTION AddForm(thPrinter, tnLevel, tcForm) DECLARE Long AddForm IN winspool.drv Long hPrinter, Long Level, String @pForm RETURN AddForm(thPrinter, tnLevel, tcForm) FUNCTION DeleteForm(thPrinter, tcForm) DECLARE Long DeleteForm IN winspool.drv Long hPrinter, String pFormName RETURN DeleteForm(thPrinter, tcForm)
Recent comments
2 weeks 1 day ago
2 weeks 2 days ago
2 weeks 2 days ago
5 weeks 2 days ago
9 weeks 6 days ago
9 weeks 6 days ago
10 weeks 5 days ago
11 weeks 4 days ago
12 weeks 6 days ago
13 weeks 1 hour ago