I am writing a program using Delphi 2006 and storing data in XML files and a Firebird database. I create reports using either FastReports, Excel or QuickPDF. I allow my users to package several reports together and be directed to a destination of their choice, whether it is a PDF file, a printer, the screen, or email.
I want my users to be able to configure their printer choices for the reports they send to printers. To do this, I will use the printer dialog to choose a printer and set the properties of that printer. I want to be able to capture those properties and store them so that when they run their package of reports, they will all go to the correct printer using the configurations they have chosen.
I know different printers have different configuration possibilities. For example, one that I use will allow me to choose to print booklet style so you can produce a 5 1/2 X 8 1/2 booklet from a report. It's possible that a user might choose an option like that when they are configuring a report in their package and expect that report to print in that manner. There are probably lots of possibilities that I am not aware of but would like to allow if that is possible. I just don't know how to capture that configuration from the printer dialog, store it in a database and then use that information to configure the printer when it's time to print the report.
How can I translate the information stored in the printer dialog into something I can store (even in a blob) in a database and then use that information to configure the printer?
Thank you for your help.
AFAIK, that isn't possible. The printer setup dialog is standard, but quite often is replaced (or modified) to include additional printer specific setup information (eg., the booklet information you mentioned). Since there's no way for anyone other than the printer driver publisher to know what's there, there's no way to reliably get the information in a generic fashion.
The GetPrinterDataEx() API function Jeroen mentioned won't work, either, as it requires you to know ahead of time the name of the registry key that was used to store information via the SetPrinterDataEx() procedure, and that may or may not have been used by the printer driver. If it was used, you'd have to manually look at the registry to see where the driver publisher decided to store the info; I'd suspect that varies between printer manufacturers as well.
FOLLOWUP: I just ran a quick check and I'm pretty sure the above is correct. If I use the Printer Setup dialog from a Delphi app to access printer settings (for example, the duplex setting before running a report), no changes are written to the registry. However, if I go into the Control Panel Printer applet and change settings there, the registry is updated. This seems to confirm that per-report setting selections made on the fly by the user would be hard to save, as they're probably not accessible anywhere except to the printer driver. Permanent type settings (those made in the control panel applet) are made by the user and the user opts to make them permanent on a system-wide basis, and therefore they're saved to the registry. This seems to preclude saving those types of options on a per-report basis, at least from the printer setup dialog changes.
This is all possible, but for a specific printer on a specific computer. Basically, you ask the printer driver for its custom config data, and store that exactly as is. You can then pass it back later to print with.
Check out the following Windows API functions. If you want C code for this, ask in a comment. Actually, I'll copy a chunk here of the code I use, sorry it isn't translated to Delphi! This is from real working code though, hard fought over. Hopefully it will give you some clues.
bGood = OpenPrinter(pcDeviceName, &hPrinter, NULL);
int sBuffSize = DocumentProperties(hDlg, hPrinter, pcDeviceName, NULL, NULL, 0);
PDEVMODE pxDevMode = (PDEVMODE)malloc(sBuffSize);
gl_memset(pxDevMode, '\0', sBuffSize);
pxDevMode->dmSize = sBuffSize;
DocumentProperties(hDlg, hPrinter, pcDeviceName, pxDevMode, pxDevMode, DM_PROMPT | DM_COPY);
DocumentProperties(hDlg, hPrinter, pcDeviceName, pxDevMode, NULL, DM_COPY);
DocumentProperties(hDlg, hPrinter, pcDeviceName, pxDevMode, pxDevMode, DM_PROMPT | DM_COPY);
DocumentProperties(hDlg, hPrinter, pcDeviceName, pxDevMode, pxDevMode, DM_UPDATE | DM_MODIFY);
ClosePrinter(hPrinter);
I know this should be possible with GetPrinterDataEx, but I could not find information about people having this used.
--jeroen
The documentation for the Windows API PRINTDLGEX Structure might contain some hints. In particular I think the hDevMode handle gives you the bits that are specific to a printer driver, even though they're undocumented. I don't know how you would use this information from Delphi.
It appears that a similar question was answered with information that may solve my problem for me. Thanks for your responses.
Related
I need to assign a printer for each of three different printing functions, labels, receipts and "standard" (e.g. A4). I have identified all of the printers available using listbox1.assign(printer.printers) but there doesn't appear to be a way to use this to establish the printer's PrinterIndex. I want to store the printername and index value in a file so that I can use printer.printerindex to assign a printer to each type of print job without asking the user to choose a printer using a dialog.
Am I going about this the wrong way, and if so, could someone please tell me the right way to do it, please? I've not had to use the printers unit directly before.
Save the printer name in the file, not the index.
When you restart the program and read back the printer name. Then loop thru all printers to find which one has the saved name (It could have been removed or renamed) and use that printer.
Working with a Konica Minolta, I am sending PostScript commands to it. Most of the time everything works correctly and I am able to switch trays using the MediaPosition command. The printer has 4 trays and the Paper Tray Settings from the printer display are set to "Letterhead", "Letterhead", "Letterhead" and "Plain".
I am successfully switching between trays using this:
<</ManualFeed false /MediaPosition 0>> setpagedevice
One of the ps files creates a job which prints from the from the third tray, the forth tray and then tries print from the first tray. However, at this point the printer freezes and asks you to put "Plain" paper in Tray 1. I am assuming this happens because the last print came from a "Plain" paper tray but I am just guessing. Going from 3 to 4 works but then to 1 does not.
I have tried to use /MediaType (letterhead) but it seems that this command is ignored as it comes along with some settings of Duplex which are incompatible with it:
<</Duplex true /Tumble false>> setpagedevice
Any idea what is actually causing this problem and even more so, how to fix it so the printer continues without freezing and asking to change the tray paper setting?
I cannot see what this has to do with Ghostscript, where is Ghostscript used in the described process ?
Page device parameters are, to some extent, device dependent and are usually treated as requests. For example you can set /Duplex, and the device will generally ignore it if it does not have a duplexer. (ie the request is ignored).
However, certain page device requests can have other effects, these are documented in Section 6.2.7 Unsatisfied Parameter Requests of the 3rd Edition PostScript Language Reference Manual (p446 in my copy).
The interpreter can respond to such an unsatisfied parameter request in a variety
of ways, such as by ignoring it, raising a PostScript error, or displaying a message
on the front panel of the device requesting intervention by the human operator.
Without seeing the exact PostScript program, it's not possible to tell exactly what's going on, but I would guess that the interpreter thinks, for whatever reason, that it cannot satisfy the request for tray 1 because it's MediaType does not match (it wants Plain and you have defined it as Letterhead). It's likely that switching tray the way you are doing changes the current MediaType (or possibly some other parameter but MediaType makes sense). I imagine that initially the MediaType is not present in the dictionary, so you can change to any other tray. When you change the tray, because you've defined the media type on the control panel, it picks up the new MediaType. When you try to switch back the current MediaType doesn't match the MediaType of the tray you are trying to switch to.
Most likely the reason that adding /MediaType (letterhead) doesn't work is because you say you've defined the tray as containing Letterhead. PostScript is case-sensitive so letterhead is not the same as Letterhead.
Or it could be that the paper tray setting simply isn't the same as the MediaType. I'm afraid that this sort of device-dependency is highly specific to each manufacturer, the only people who can probably tell you what you need to send for certain are the printer manufacturers' own engineers.
I need to print documents in a specific order.
To do that,i use shellExecute api to print documents.
Some documents may be quicker to print , so i have to wait for the document to be in the spooler before calling another shellExecute.
For that, i use FindFirstPrinterChangeNotification, waitForSingleObject and FindNextPrinterChangeNotification.
It works fine.
But if the application started by shellExecute is already open, it's possible that it prints on another printer that the windows default printer. (if default printer has been changed )
I could watch all printers, but, i'd prefer to know wich printer uses the started process and watch this printer.
With shellExecuteEx, i can get a handle to the process started by this api.
So, is there a way to know the printer used by default by a process ?
So, is there a way to know the printer used by default by a process?
No there is not. Programs are entitled to use whatever logic they choose to determine their default printer. So in general, you've no way to ask a process which printer it will use, without having more specific knowledge of the process in question.
I know how to force forms to appear on the same monitor as the running application, but I do not see how to ask the Help or the Printer Setup dialogs to display on the same monitor. The Help displays where it displayed last time, but we want it to show up on the application monitor. The Printer Setup dialog always seems to appear on the primary monitor
Passing the parent form's Handle to TPrinterSetupDialog.Execute seems to do the trick.
if PrinterSetupDialog1.Execute(Self.Handle) then
//
Using Delphi 7 (where the TPrinterSetupDialog.Execute does not accept a parameter), you have two choices.
The easiest would be to create your own descendant of TPrinterSetupDialog. Execute is virtual in TCommonDialog, the ancestor of TPrinterSetupDialog, where it is overridden. You could override it in your own descendant, use the code in the TPrinterSetupDialog as a basis for your own Execute override, adding overload as well. Your overloaded Execute would accept a ParentHandle: HWND parameter, and set the PrintDlgRec.hWndOwner to that provided window handle.
I thought about trying to write this for you (or at least get it started), but there are additional things you'd have to copy from the Dialogs unit (functions that are defined in the implementation section that wrap some API calls, and the callback function that's used for the dialog's message loop), and I don't have D7 available where I'm at to even try to compile it.
The other alternative (as David Heffernan mentioned in his comment below) would be to call the Windows API PrintDlgEx directly yourself. This is discussed in MSDN, in the Print Dialog Box (Windows) topic. Once again, I don't have D7 available, so I can't really give you an example of using it from Delphi. (I checked, and don't have one tucked away anywhere.)
I'm not sure you can set the help window's position; I think that's done automatically by Windows based on the user's prior use. (I haven't been able to so so, anyway.)
sorry for this little bit strange title, didn't found a better one..
I've got the following situation:
I have a PC with an RFID reader connected via USB.
I now need a program which pops up when ab transponder was scanned the the RFID reader and shows the scanned value. (The reader just simulates keystrokes)
Problem: the value of the transponder is something like 0001230431, and I can't change it. (To prefix a hotkey combination or so)
So I have thought about using a global keyboard hook, check if three zeros where typed in, capture rest of data and when the 10 digits are complete, call the application through an automation object and show the number.
But I'm not very exalted about using a global keyboard hook. Many AV programs don't like them very much, they are not so easy to handle with Delphi and I guess that's not very resource-friendly for such a little task...
So I'm looking for an alternative solution...maybe somebody has an idea?
Big thx!
ben, you can use the RegisterRawInputDevices and GetRawInputData functions.
first you must use the RegisterRawInputDevices function to register the input device to monitor and then you can retrieves the data from the input device using the GetRawInputData function.
Check theses functions too
GetRawInputDeviceList retrieves the list of input devices attached to the system.
GetRawInputDeviceInfo retrieves information on a device.
Why not make sure the Delphi app with a text edit control has focus before the scan is done? Then the keystrokes will go straight into your Delphi app.