Sunday, August 12, 2007

Adding Custom Paper Size Programmatically

There are times when we need to make a custom report size. Before you can create a custom size, you have to manually add a Printer Form Size (Control Panel -> Printer & Faxes -> File -> Server Properties). Then you can set the Page Setup in your report to use the custom printer form.

The hard part is, when you distribute the application to the client, you must also set the same Custom Form Size for their printer configuration. Of course you don't want to do it one by one manually! So, what you need is create a small procedure to detect whether the custom printer form is already exist. If not then add it.

- Cut * paste the code below into PRG, then run "beautify" to make the code readable
- BinToC() function in this code is an Enhanced function in VFP9. For VFP8 and lower version, use UDF called Long2Str or Num2Str. You can find the function on UT or other VFP forums.

Local hPrinter
Local cPrinterName, cPaperName
Local pPaperName, sPaperSize
Local nResult, nBufLen, nPaperWidth, nPaperHeight

Declare Long GetLastError in Kernel32
Declare Long ClosePrinter in WinSpool.Drv Long hPrinter
Declare Long OpenPrinter in WinSpool.Drv ;
String cPrinterName, Long @O_hPrinter, Long pDefault

Declare Long GetForm in WinSpool.drv as GetPrinterForm ;
Long hPrinter, String pFormName, ;
Long nLevelInfo, String @O_pFormInfo, ;
Long nBufSize, Long @O_nBufNeeded

Declare Long AddForm in WinSpool.drv as AddPrinterForm ;
Long hPrinter, Long nLevelInfo, String @pFormInfo

Declare Long LocalAlloc in Kernel32 Long uFlags, Long dwBytes
Declare Long LocalFree in Kernel32 Long hMem

cPrinterName = set( 'Printer', 2 ) && Get default Windows printer
hPrinter = 0

If (OpenPrinter( cPrinterName, @hPrinter, 0 ) != 0)
cPaperName = 'MyCustom - Half A4'
nBufLen = 32 && FORM_INFO_1_Size
cInfo = replicate( chr(0), 32 )
nResult = GetPrinterForm( hPrinter, cPaperName, 1, ;
@cInfo, nBufLen, @nBufLen )

If (nResult == 0) && Get printer form failed
nResult = GetLastError()

If (nResult == 1902) && ERROR_INVALID_FORM_NAME
** Custom Printer Form not exist, add the new one
nPaperWidth = 210000 / 2 && Paper size is in 1/1000 millimeters
nPaperHeight = 297000 / 2
sPaperSize = BinToC( nPaperWidth, '4rs' ) + BinToC( nPaperHeight, '4rs' )
pPaperName = LocalAlloc( 64, 32 )

If (pPaperName != 0)
sys( 2600, pPaperName, len( cPaperName ), cPaperName )
cInfo = BinToC( 0, '4rs' ) + BinToC( pPaperName, '4rs' ) + ;
sPaperSize + BinToC( 0, '4rs' ) + BinToC( 0, '4rs' ) + sPaperSize

If (AddPrinterForm( hPrinter, 1, cInfo ) != 0)
? 'Custom paper form (' + cPaperName + ') has been added! '
? 'Error:', GetLastError()

LocalFree( pPaperName )

If (nResult == 122) && Insufficient buffer
? 'Error: Custom Paper Form already exist!'
? 'Error: ', nResult
? 'Error: ', nResult
ClosePrinter( hPrinter )


Happy coding! :)


Hendrik said...

wah ... thanks berat
tipnya bagus ... dan sudah saya cari selama ini.

Saya mau buat form untuk invoice tapi setengah halaman ..
Makasih ya pak herman

Herman Tan said...

Terimakasih atas komentarnya pak Hendrik. Mudah-mudahan dapat dipergunakan dengan baik

Sinyonamakoe said...

hihihi...saya salah kamar tadi....maklum lah, wong ndeso ...


Salute ! Bravo ! Chayo !

Saya tunggu tip & trik selanjutnya...

Agooze said...

thanks ya atas functionnya, selama ini saya kira untuk setting server properties harus secara manual, ternyata bisa dilakukan secara coding.
sekali lagi thanks ya

Anonymous said...

Ok this work fine, but which is the id I must use in PAGESIZE clause in EXPR field ind frx file?

Herman Tan said...

I never hack the FRX for this one. Sorry if I can help you for this one.

But, I guess PAGESIZE ID is the ID that comes with the default printer installation. Since we use custom paper I don't think we have an ID. So, you could try to remove the PAGESIZE completely

Anonymous said...

Sorry, I mean PAPERSIZE not PAGESIZE, this is a number that identifies the form that you are defining

Herman Tan said...

Ok I see. Please look in my other tips

Anonymous said...

Pak Herman, sy sudah coba code nya, jalan, dan server propertiesnya udah ke add custom papernya.
Tapi di design report VFP 9, tetap aja ngak nongol custom paper sizenya. Masih sama saja.
Gmn solusinya pak ?

Herman Tan said...

Hi Gary, apakah saat menambahkan Custom Size, Report Designer sedang terbuka? Kalau ya, ditutup dulu, baru dibuka lagi. Anda harus menambahkan Custom Paper Size sebelum membuka Report Designer.

Kalpesh said...


I show your Code. It works fine. if there is Single Printer..

i have five printer in my Printer & Faxes Option..
1. Auto Epson LX-300 on PFIGER3
2. HP LaserJet 1018
3. Microsoft Office Document Image Writer
4. Microsoft XPS Document Writer
5. PrimoPDF

when i want to add in HP Printer but program always add in Epson Printer.

Please Help Me


Herman Tan said...

Hi Kalpesh,

The problem is not about Single or Multiple Printer. AFAIK, The code will only work on Dot Matrix


Anonymous said...

Ma kasih Pak Hendrik atas postingan yang amat membantu ini.