Here is a sample program from AdaGIDE: Martin C. Carlisle, PhD Associate Professor of Computer Science United States Air Force Academy -----Original Message----- From: EDUARDO HASBUN . [mailto:[log in to unmask]] Sent: Wednesday, September 05, 2001 3:27 PM To: [log in to unmask] Subject: printing I need to be able to set the output to a printer, in other words I want to print something in Ada 95 using my printer. I'm using GNAT 3.13p in Windows. Can someone help me?? --------------------------------------------------------------- -- -- ADA GNAT INTEGRATED DEVELOPMENT ENVIRONMENT (AdaGIDE) -- -- PRINT.ADB -- Description : Prints a command-line specified file -- -- By: Dr. Martin C. Carlisle -- -- -- Original Copyright (C) 1997 Martin C. Carlisle -- This is a derivative work by: -- US Air Force Academy Department of Computer Science -- -- AdaGIDE is free software; you can redistribute it and/or -- modify it under terms of the GNU General Public License -- as published by the Free Software Foundation and modified -- below; either version 2, or (at your option) any later version. -- AdaGIDE is distributed in the hope that it will be useful, -- but WITHOUT ANY WARRANTY; without even the implied warranty -- of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. -- See the GNU General Public License for more details. -- You should have received a copy of the GNU General Public -- License distributed with AdaGIDE; see file COPYING.HTML. If -- not, write to the Free Software Foundation, 59 Temple Place, -- Suite 330, Boston, MA 02111-1307, USA. -- -- The GNU General Public License is modified as follows. -- If you distribute or publish this work (or any work based -- on this work) along with a related program, you must cause -- the related work and any modifications you have made to this -- work to be licensed as a whole at no charge to all third -- parties under the terms of the GNU General Public License. For -- purpose of this modification, a related work is defined as any -- work whose process is started by this work (or any work based -- on this work), whose process starts a process running this work -- (or any work based on this work), or whose process communicates -- with a process running this work (or any work based on this -- work). In particular, this modification includes bundling a -- compiler with this work (or any work based on this work). -- --------------------------------------------------------------- WITH Win32,System,Win32.Winmain; USE TYPE Win32.BOOL,Win32.UINT,Win32.INT,Win32.DWORD; WITH Win32.CommDlg,Win32.WinGDI,Win32.Winbase,Win32.Windef; WITH Win32.WinUser; WITH WinConversions; USE TYPE Win32.WinDef.HWND; WITH Ada.Unchecked_Conversion; WITH Ada.Text_IO; PROCEDURE Print IS pragma Linker_Options("-mwindows"); pragma Linker_Options("-lwin32ada"); pragma Linker_Options("-lcomctl32"); pragma Linker_Options("-lcomdlg32"); pragma Linker_Options("-ladvapi32"); TYPE String_Access IS ACCESS ALL String; TYPE LPPAGESETUPHOOK IS NEW Win32.LPVOID; SUBTYPE LPPAGEPAINTHOOK IS Win32.LPVOID; TYPE PAGESETUPDLG IS RECORD lStructSize : Win32.DWORD; hwndOwner : Win32.Windef.HWND; hDevMode : Win32.Windef.HGLOBAL; hDevNames : Win32.Windef.HGLOBAL; Flags : Win32.DWORD; ptPaperSize : Win32.Windef.POINT; rtMinMargin : Win32.Windef.RECT; rtMargin : Win32.Windef.RECT; hInstance : Win32.Windef.HINSTANCE; lCustData : Win32.LPARAM; lpfnPageSetupHook : LPPAGESETUPHOOK; lpfnPagePaintHook : LPPAGEPAINTHOOK; lpPageSetupTemplateName : Win32.LPCSTR; hPageSetupTemplate : Win32.Windef.HGLOBAL; END RECORD; TYPE LPPAGESETUPDLG IS ACCESS ALL PAGESETUPDLG; PSD_DEFAULTMINMARGINS :CONSTANT := 16#00000000#; -- default (printer's) PSD_INWININIINTLMEASURE :CONSTANT := 16#00000000#; -- 1st of 4 possible PSD_MINMARGINS :CONSTANT := 16#00000001#; -- use caller's PSD_MARGINS :CONSTANT := 16#00000002#; -- use caller's PSD_INTHOUSANDTHSOFINCHES :CONSTANT := 16#00000004#; -- 2nd of 4 possible PSD_INHUNDREDTHSOFMILLIMETERS :CONSTANT := 16#00000008#; -- 3rd of 4 possible PSD_DISABLEMARGINS :CONSTANT := 16#00000010#; PSD_DISABLEPRINTER :CONSTANT := 16#00000020#; PSD_NOWARNING :CONSTANT := 16#00000080#; -- must be same as PD_* PSD_DISABLEORIENTATION :CONSTANT := 16#00000100#; PSD_RETURNDEFAULT :CONSTANT := 16#00000400#; -- must be same as PD_* PSD_DISABLEPAPER :CONSTANT := 16#00000200#; PSD_SHOWHELP :CONSTANT := 16#00000800#; -- must be same as PD_* PSD_ENABLEPAGESETUPHOOK :CONSTANT := 16#00002000#; -- must be same as PD_* PSD_ENABLEPAGESETUPTEMPLATE :CONSTANT := 16#00008000#; -- must be same as PD_* PSD_ENABLEPAGESETUPTEMPLATEHANDLE :CONSTANT := 16#00020000#; -- must be same as PD_* PSD_ENABLEPAGEPAINTHOOK :CONSTANT := 16#00040000#; PSD_DISABLEPAGEPAINTING :CONSTANT := 16#00080000#; PSD_NONETWORKBUTTON :CONSTANT := 16#00200000#; -- must be same as PD_* function PageSetupDlg_func( lppd: LPPAGESETUPDLG) return Win32.BOOL; pragma Import(Stdcall, PageSetupDlg_func, "PageSetupDlgA"); pd : ALIASED Win32.CommDlg.PRINTDLG; psd : ALIASED PAGESETUPDLG; tm : ALIASED Win32.WinGDI.TEXTMETRIC; buffer : ARRAY(0..79) OF ALIASED Win32.CHAR; docinfo : ALIASED Win32.WinGDI.DOCINFO; bUserAbort : Boolean; hDlgPrint : Win32.Windef.HWND; FUNCTION PrintDlgProc(hDlg : Win32.Windef.HWND; Message : Win32.UINT; Wparam : Win32.WPARAM; Lparam : Win32.LPARAM) RETURN Win32.BOOL; PRAGMA Convention(Stdcall,PrintDlgProc); FUNCTION AbortProc(hPrinterDC : Win32.Windef.HDC; nCode : Win32.INT) RETURN Win32.BOOL; PRAGMA Convention(Stdcall,AbortProc); ------------------------------------------------------------------ -- FUNCTION PrintDlgProc -- -- Handles messages to Print Dialog box -- currently unused as PrintDialog isn't working -- -- IF init, grey close on system menu -- IF command, set abort ------------------------------------------------------------------ FUNCTION PrintDlgProc(hDlg : Win32.Windef.HWND; Message : Win32.UINT; Wparam : Win32.WPARAM; Lparam : Win32.LPARAM) RETURN Win32.BOOL IS Bool : Win32.BOOL; BEGIN IF Message = Win32.WinUser.WM_INITDIALOG THEN Bool := Win32.WinUser.EnableMenuItem(Win32.WinUser.GetSystemMenu( hDlg, 0), Win32.WinUser.SC_CLOSE, Win32.WinUser.MF_GRAYED); RETURN 1; ELSIF Message = Win32.WinUser.WM_COMMAND THEN bUserAbort := True; Bool := Win32.WinUser.EnableWindow(Win32.WinUser.GetParent(hDlg),1); Bool := Win32.WinUser.DestroyWindow(hDlg); hDlgPrint := Win32.WinDef.HWND(System.Null_Address); RETURN 1; END IF; RETURN 0; END PrintDlgProc; ------------------------------------------------------------------ -- FUNCTION AbortProc -- -- Handles aborting current print -- currently unused as PrintDialog isn't working -- -- WHILE not Abort AND GetMessage LOOP -- process message -- If abort return 0, else 1 ------------------------------------------------------------------ msg : ALIASED Win32.WinUser.MSG; FUNCTION AbortProc(hPrinterDC : Win32.Windef.HDC; nCode : Win32.INT) RETURN Win32.BOOL IS Bool : Win32.BOOL; IgnoreLong : Win32.LONG; BEGIN WHILE (NOT bUserAbort) AND (Win32.WinUser.PeekMessage(msg'ACCESS, System.Null_Address, 0, 0, Win32.WinUser.PM_REMOVE) /= 0) LOOP IF hDlgPrint = Win32.Windef.HWND(System.Null_Address) OR (Win32.WinUser.IsDialogMessage(hDlgPrint, msg'ACCESS) = 0) THEN Bool := Win32.WinUser.TranslateMessage(msg'Unchecked_ACCESS); IgnoreLong := Win32.WinUser.DispatchMessage(msg'Unchecked_ACCESS); END IF; END LOOP; IF bUserAbort THEN RETURN 0; ELSE RETURN 1; END IF; END AbortProc; ------------------------------------------------------------------ -- FUNCTION GetPrinterDC -- -- gets device context for printer -- used since Dialog Box not working -- -- get profile of printer -- replace "," with ASCII.NUL -- Create and return device context ------------------------------------------------------------------ FUNCTION GetPrinterDC RETURN Win32.Windef.HDC IS IgnoreDWORD : Win32.DWORD; IgnoreInt : Win32.INT; counter : Integer; DriverLoc,OutputLoc : Integer; BEGIN IgnoreDWORD := Win32.Winbase.GetProfileString( WinConversions.ConvertStaticString("windows" & Character'First), WinConversions.ConvertStaticString("device" & Character'First), WinConversions.ConvertStaticString(",,," & Character'First), buffer(0)'Unchecked_ACCESS, 80); counter := 0; WHILE Character(buffer(counter)) /= ',' AND counter < 80 LOOP counter := counter + 1; END LOOP; IF counter < 80 THEN DriverLoc := counter+1; buffer(counter) := Win32.CHAR'First; END IF; WHILE Character(buffer(counter)) /= ',' AND Character(buffer(counter)) /= ' ' AND counter < 80 LOOP counter := counter + 1; END LOOP; IF counter < 80 THEN OutputLoc := counter+1; buffer(counter) := Win32.CHAR'First; RETURN Win32.Wingdi.CreateDC(buffer(DriverLoc)'Unchecked_ACCESS, buffer(0)'Unchecked_ACCESS,buffer(OutputLoc)'Unchecked_ACCESS,NULL); END IF; IgnoreInt := Win32.WinUser.MessageBox(System.Null_Address, WinConversions.ConvertStaticString( "Unable to print file" & Character'First), WinConversions.ConvertStaticString( "No printer found" & Character'First), 0); RETURN Win32.Windef.HDC(System.Null_Address); END GetPrinterDC; ------------------------------------------------------------------ -- PROCEDURE PageSetupChoice -- ------------------------------------------------------------------ PROCEDURE PageSetupChoice IS IgnoreBool : Win32.BOOL; BEGIN psd.lStructSize := Win32.DWORD(PAGESETUPDLG'Size/8); psd.hwndOwner := System.Null_Address; psd.hInstance := System.Null_Address; psd.lCustData := 0; psd.lpfnPagePaintHook := System.Null_Address; IgnoreBool := PageSetupDlg_func(psd'ACCESS); END PageSetupChoice; FUNCTION Get_File_Name RETURN String_Access IS USE TYPE Win32.LPSTR; CommandLPSTR : Win32.LPSTR; IgnoreLPSTR : Win32.LPSTR; CommandLength : Integer; StartFileName : Integer; Result : String_Access; BEGIN CommandLPSTR := Win32.Winbase.GetCommandLine; IF CommandLPSTR = NULL THEN RETURN NULL; END IF; CommandLength := Integer(Win32.Winbase.lstrlen(Win32.LPCSTR( CommandLPSTR))); IF CommandLength > 0 THEN DECLARE CommandString : String(1..CommandLength+1); BEGIN IgnoreLPSTR := Win32.Winbase.lstrcpy( WinConversions.ConvertStaticString(CommandString), Win32.LPCSTR(CommandLPSTR)); StartFileName := 2; WHILE StartFileName < CommandLength AND THEN CommandString(StartFileName) /= ' ' LOOP StartFileName := StartFileName + 1; END LOOP; -- skip over blank space StartFileName := StartFileName + 1; -- only try if we have at least one character filename IF StartFileName < CommandLength-1 THEN Result := new String'( CommandString(StartFileName..CommandLength)); END IF; END; ELSE Result := NULL; END IF; RETURN Result; END Get_File_Name; ------------------------------------------------------------------ -- -- call Common Dialog routine so -- Get number of lines, exit if 0 -- get font resolution (horiz and vert) -- Compute characters per line/page -- Compute number of pages -- Disable window -- start document -- FOR number of pages LOOP -- start page -- FOR min(lines per page, lines this page) LOOP -- print line -- end page -- end document -- enable window -- delete device context ------------------------------------------------------------------ Lines : Integer; yChar,nCharsPerLine : Integer; nLinesPerPage : Integer; LineNum : Integer; IgnoreInt : Win32.INT; Bool : Win32.BOOL; bSuccess : Boolean := True; AllPages : Boolean := True; rect : Win32.Windef.RECT; Int2,Int3 : Win32.INT; HFont : Win32.Windef.HFONT; HGDIOBJ : Win32.Windef.HGDIOBJ; StartLineOffset : Integer := 0; FileName : String_Access; FilePtr : Ada.Text_IO.File_Type; DoDialog : Boolean; Lines_Done_This_Page : Integer; BEGIN FileName := Get_File_Name; IF FileName = NULL THEN RETURN; END IF; IF FileName(FileName'First..FileName'First+1) = "-q" THEN DoDialog := False; FileName := new String'(FileName(FileName'First+3..FileName'Last)); ELSE DoDialog := True; END IF; psd.rtMargin.top := 1000; psd.rtMargin.left := 1000; psd.rtMargin.bottom := 1000; psd.rtMargin.right := 1000; psd.hDevMode := System.Null_Address; psd.HDevNames := System.Null_Address; psd.Flags := Win32.DWORD(PSD_MARGINS + PSD_INTHOUSANDTHSOFINCHES); pd.lStructSize := Win32.DWORD(Win32.CommDlg.PRINTDLG'Size/8); pd.hwndOwner := System.Null_Address; pd.hDevMode := System.Null_Address; pd.HDevNames := System.Null_Address; pd.hDC := System.Null_Address; pd.Flags := Win32.DWORD(Win32.CommDlg.PD_RETURNDC + -- Win32.CommDlg.PD_ALLPAGES + Win32.CommDlg.PD_NOSELECTION + Win32.CommDlg.PD_NOPAGENUMS + Win32.CommDlg.PD_USEDEVMODECOPIES ); pd.nFromPage := 0; pd.nToPage := 0; pd.nMinPage := 0; pd.nMaxPage := 0; pd.nCopies := 1; pd.hInstance := System.Null_Address; pd.lCustData := 0; pd.lpfnPrintHook := NULL; pd.lpfnSetupHook := NULL; pd.lpPrintTemplateName := NULL; pd.lpSetupTemplateName := NULL; pd.hPrintTemplate := System.Null_Address; pd.hSetupTemplate := System.Null_Address; pd.lStructSize := Win32.DWORD(66); -- HACK!! IF DoDialog THEN Bool := Win32.CommDlg.PrintDlg_Func(pd'Unchecked_ACCESS); IF Bool = 0 THEN RETURN; -- user pressed cancel. END IF; ELSE pd.hdc := GetPrinterDC; IF pd.hdc = System.Null_Address THEN RETURN; -- no printer! END IF; END IF; Int2 := Win32.WinGDI.GetDeviceCaps(pd.hdc, Win32.WinGDI.LOGPIXELSY); Int3 := -(Win32.WinBase.MulDiv(Win32.INT(10), Int2, 72)); Hfont := Win32.WinGDI.CreateFont(Int3, 0, 0, 0, Win32.WinGDI.FW_NORMAL, 0, 0, 0, 0, 0, 0, 0, 0, WinConversions.ConvertStaticString( "Courier New" & Character'First)); HGDIOBJ := Win32.WinGDI.SelectObject(pd.hDC, hFont); Bool := Win32.WinGDI.GetTextMetrics(pd.hDC, tm'ACCESS); -- compute drawing rectangle (adopted from Win95 common -- controls bible book 2, p. 66) rect.top := Win32.LONG(Integer(Win32.WinGDI.GetDeviceCaps(pd.hDc, Win32.WinGDI.LOGPIXELSY)) * Integer(psd.rtMargin.top) / 1000 - Integer(Win32.WinGDI.GetDeviceCaps(pd.hDc, Win32.WinGDI.PHYSICALOFFSETY))); rect.left := Win32.LONG(Integer(Win32.WinGDI.GetDeviceCaps(pd.hDc, Win32.WinGDI.LOGPIXELSX)) * Integer(psd.rtMargin.left) / 1000 - Integer(Win32.WinGDI.GetDeviceCaps(pd.hDc, Win32.WinGDI.PHYSICALOFFSETX))); -- really we blow off the right margin rect.right := Win32.LONG( Integer(Win32.WinGDI.GetDeviceCaps(pd.hDc, Win32.WinGDI.HORZRES)) - Integer(Win32.WinGDI.GetDeviceCaps(pd.hDc, Win32.WinGDI.LOGPIXELSX)) * Integer(psd.rtMargin.left) / 1000 - Integer(Win32.WinGDI.GetDeviceCaps(pd.hDc, Win32.WinGDI.PHYSICALOFFSETX))); rect.bottom := Win32.LONG( Integer(Win32.WinGDI.GetDeviceCaps(pd.hDc, Win32.WinGDI.PHYSICALHEIGHT)) - Integer(Win32.WinGDI.GetDeviceCaps(pd.hDc, Win32.WinGDI.LOGPIXELSY)) * Integer(psd.rtMargin.bottom) / 1000 - Integer(Win32.WinGDI.GetDeviceCaps(pd.hDc, Win32.WinGDI.PHYSICALOFFSETY))); yChar := Integer(tm.tmHeight) + Integer(tm.tmExternalLeading); nCharsPerLine := (Integer(rect.right) - Integer(rect.left)) / Integer(tm.tmAveCharWidth); nLinesPerPage := (Integer(rect.bottom) - Integer(rect.top)) / yChar; -- nCharsPerLine := Integer(Win32.WinGDI.GetDeviceCaps( -- pd.hDC, Win32.WinGDI.HORZRES)) / Integer(tm.tmAveCharWidth); -- nLinesPerPage := Integer(Win32.WinGDI.GetDeviceCaps( -- pd.hDC, Win32.WinGDI.VERTRES)) / yChar; Ada.Text_IO.Open(File => FilePtr, Name => FileName.all, Mode => Ada.Text_IO.In_File); Lines := 0; WHILE NOT Ada.Text_IO.End_Of_File(FilePtr) LOOP Lines := Lines + 1; Ada.Text_IO.Skip_Line(FilePtr); END LOOP; Ada.Text_IO.Close(File => FilePtr); bUserAbort := False; -- hDlgPrint := Win32.WinUser.CreateDialog(gbObjects.gbAppInst, -- gbObjects.Convert("PrintDlgBox" & Character'First), -- Window1.form.Handle,PrintDlgProc'ACCESS); -- -- IgnoreInt := Win32.WinGDI.SetAbortProc(pd.hDC, AbortProc'Access); docinfo.cbSize := docinfo'SIZE / 8; docinfo.lpszDocName := NULL; docinfo.lpszOutput := NULL; IF Win32.WinGDI.StartDoc(pd.hDC,docinfo'Unchecked_ACCESS) > 0 THEN Ada.Text_IO.Open(File => FilePtr, Name => FileName.all, Mode => Ada.Text_IO.In_File); LineNum := 0; -- While there are lines left, loop starting a new page WHILE LineNum < Lines LOOP IgnoreInt := Win32.WinGDI.StartPage(pd.hDC); IF IgnoreInt < 0 THEN bSuccess := False; EXIT; END IF; -- While lines on this page is less than max loop -- offset by one, since last line may wrap -- Note that we only allow a line to wrap once -- since it was a lot easier that way. Lines_Done_This_Page := 0; WHILE Lines_Done_This_Page < nLinesPerPage-1 AND THEN LineNum < Lines LOOP DECLARE LineString : String(1..4095); TempChar : Character; Last : Integer; FUNCTION SAtoLPCSTR IS NEW Ada.Unchecked_Conversion( System.Address, Win32.LPCSTR); BEGIN Ada.Text_IO.Get_Line(File => FilePtr, Item => LineString, Last => Last); LineNum := LineNum + 1; -- null terminate the string for Windows LineString(Last+1) := Character'First; IF Last > nCharsPerLine THEN TempChar := LineString(nCharsPerLine); LineString(nCharsPerLine) := Character'First; Bool := Win32.WinGDI.TextOut(pd.hDC, Win32.INT(rect.left), -- x location Win32.INT(yChar * Lines_Done_This_Page + Integer(rect.top)), -- y location Win32.LPCSTR(SAtoLPCSTR(LineString(1)'Address)), Win32.INT(nCharsPerLine-1)); Lines_Done_This_Page := Lines_Done_This_Page + 1; LineString(nCharsPerLine) := TempChar; Bool := Win32.WinGDI.TextOut(pd.hDC, Win32.INT(rect.left), -- x location Win32.INT(yChar * Lines_Done_This_Page + Integer(rect.top)), -- y location Win32.LPCSTR(SAtoLPCSTR(LineString(nCharsPerLine)'Address)), Win32.INT(Last-nCharsPerLine+1)); Lines_Done_This_Page := Lines_Done_This_Page + 1; ELSE Bool := Win32.WinGDI.TextOut(pd.hDC, Win32.INT(rect.left), -- x location Win32.INT(yChar * Lines_Done_This_Page + Integer(rect.top)), -- y location Win32.LPCSTR(SAtoLPCSTR(LineString(1)'Address)), Win32.INT(Last)); Lines_Done_This_Page := Lines_Done_This_Page + 1; END IF; END; -- DECLARE END LOOP; -- End loop on lines/page IgnoreInt := Win32.WinGDI.EndPage(pd.hDC); IF IgnoreInt < 0 THEN bSuccess := False; EXIT; END IF; IF bUserAbort THEN EXIT; END IF; END LOOP; -- on linenum < lines Ada.Text_IO.Close(File => FilePtr); ELSE bSuccess := False; END IF; IF bSuccess THEN IgnoreInt := Win32.WinGDI.EndDoc(pd.hDC); END IF; -- restore to prior state HGDIOBJ := Win32.WinGDI.SelectObject(pd.hDC,HGDIOBJ); Bool := Win32.WinGDI.DeleteDC(pd.hDC); Bool := Win32.WinGDI.DeleteObject(hFont); END Print;