Link to home
Start Free TrialLog in
Avatar of nk51
nk51

asked on

How to select a printer without PrintDialog ?

Hello everybody !

Is there someone who knows how to select a printer without using PrintDialog ?
I explain :
I'm using a Delphi 3.0 program to create and print WinWord files.
The user can choice a printer in a combobox which contains the list of available printers of Windows.
I'm using the printer (printers) object to propose this list and to know the printindex and the name of the selected printer.
In my code I send WordBasic orders to WinWord to create the word document.
But before I want to specifie the printer selected by the user to windows.
I know the existence of the OpenPrinter and SetPrinter functions of Windows but I don't know how to use it.
Can you give me some examples ?

Thanks.

Avatar of lortega
lortega

Just add a buttons adn a listbox and try this...


procedure TForm1.FormShow(Sender: TObject);
begin
     ListBox1.Items := Printer.printers;
end;


procedure TForm1.Button1Click(Sender: TObject);
begin
  Printer.PrinterIndex := ListBox1.ItemIndex;
  Printer.BeginDoc;
  Printer.Canvas.TextOut(10,10,'Luis');
  Printer.EndDoc;
end;

Avatar of nk51

ASKER

It's no so simple.
I'm french and perhaps I don't use a good english.
My question was :
How to change the default printer of windows without PrintDialog component?
With your example I only can print canvas.
I want to print a .DOC file on the printer of my choice without using the printdialog component (so, with code).
I want to know how to change the default printer of windows in my code.
Thanks.

Avatar of nk51

ASKER

I think I have to use OpenPrinter, SetPrinter of Windows but I have some pbs to use this functions.
I need some examples.
Thanks.
why not change HKEY_LOCAL_MACHINE\Config\0001\System\CurrentControlSet\Control\Print\Printers
i.e. change the Key "default" = "HP Laserjet 1" into some Printer you want to use.
For that, read the printerNames out by using TPrinter.Printers, that is a TStringList with all available Printers. I didn't try it, but it should work.
The only hard thing about it is, that TPrinter.Printers does show the Printer Name and the Connection. Into the registry-key you should only write the Printer Name. So you would somehow have to extract the printer Name out of TPrinter.Printers.
Good luck !

of course I mean changing the Registry key temporarily by using TRegistry in your code.
Oli
me again...
I did a litlle research and here's some news:
TPrinter.SetPrinter seems to only take action in your program.
If I understood you right, you want to change the default printer for winword.exe.
In this case to me it seems, working with TRegistry is the onliest way.
Oli
Here is what Microsoft have to say about this:


HOWTO: Get and Set the Default Printer in Windows

Last reviewed: March 4, 1998
Article ID: Q135387 The information in this article applies to:

•Microsoft Windows Software Development Kit (SDK) for Windows version 3.1 •Microsoft Win32 Application Programming Interface (API) included with: - Microsoft Windows NT versions 3.5, 3.51 - Microsoft Windows 95







SUMMARY

In all versions of Windows, the appropriate way to get the default printer is to use GetProfileString, and the appropriate way to set the default printer is to use WriteProfileString. This works whether the default printer information is stored in the WIN.INI file or in the registry.





MORE INFORMATION





Notes to Keep in Mind



•The Device value you get or set actually contains three elements separated by commas as follows:



      <printer name>,<driver name>,<port>





For example:





      My Printer,HPPCL5MS,lpt1:



•When setting the default printer, you must specify valid names for these elements. That is, you must specify a valid printer, driver, and port. If not, programs such as Print Manager may set the printer back to the previous valid printer, and other programs may become very confused. You can use the EnumPrinters API to retrieve the printer name, driver name, and port name of all available printers. •Windows 95 and Windows NT map most .INI file references to the registry. Because of this mapping, GetProfileString and WriteProfileString still function as they do under 16-bit Windows (Microsoft Windows and Windows for Workgroups). •After setting the default printer, notify all other applications of the change by broadcasting the WM_WININICHANGE message.





Sample Code



   // This code uses a sample profile string of "My Printer,HPPCL5MS,lpt1:"
   // To get the default printer for Windows 3.1, Windows 3.11,
   // Windows 95, and Windows NT use:
   GetProfileString("windows", "device", ",,,", buffer, sizeof(buffer));

   -----

   // To set the default printer for Windows 3.1 and Windows 3.11 use:
   WriteProfileString("windows", "device", "My Printer,HPPCL5MS,lpt1:");
   SendMessage(HWND_BROADCAST, WM_WININICHANGE, 0, 0L);

   -----

   // To set the default printer for Windows 95 use:
   WriteProfileString("windows", "device", "My Printer,HPPCL5MS,lpt1:");
   SendMessageTimeout(HWND_BROADCAST, WM_WININICHANGE, 0L,
   (LPARAM)(LPCTSTR)"windows", SMTO_NORMAL, 1000, NULL);

   -----

   // To set the default printer for Windows NT use:
   /* Note printer driver is usually WINSPOOL under Windows NT */
   WriteProfileString("windows", "device", "My Printer,WINSPOOL,lpt1:");
  SendMessageTimeout(HWND_BROADCAST, WM_WININICHANGE, 0L, 0L,
  SMTO_NORMAL, 1000, NULL);




There are two circumstances where the code won't work:



1.If the customer leaves out the SendMessage, no other application will recognize the change in the .INI settings.

2.If a different 32-bit application does not handle the WIN.INI change message, then it will appear to that application as if the default printer has not been changed. The user will need to exit and re-enter Windows 95 to have the other application recognize the printer change.



This is the preferred method of changing the printer if the code is to be platform independent; this method will work on Windows 3.1, Windows 95 and Windows NT.



For additional information, please see the following article(s) in the Microsoft Knowledge Base:



   ARTICLE-ID: Q140560
   TITLE     : How to Set the Default Printer Programmatically in Windows
               95






------------------------------------------------------------------------


Additional query words: 3.11
Keywords : GdiPrn kbcode kbprint
Version : WINNT:3.1,3.5,3.51,4.0; WIN95
Platform : Win95 winnt
Issue type : kbhowto




Last reviewed: March 4, 1998
© 1998 Microsoft Corporation. All rights reserved. Terms of Use.
Avatar of nk51

ASKER

All your answers are very interessant but I think I don't have the answer I expected.
I want to select a printer as in the printer dialog box of windows in the list of printers but without the printdialog.
So in my code. I try with the printer object but it seems to work only in the delphi environnement and not the winword environnement.

 
Avatar of nk51

ASKER

Sorry, you (oli2 & philipleighs) had right. The only and best way is to change the registry.
Thanks
The best way is to do what the MS document says. The system.ini file is mirrored into the registry. It doesn't work the other way around.
Also, changing the ini file will update both local machine and current user, and send a WM_INI_CHANGED message.

By using the documented method, you get some assurance that it will work on the listed platforms. This is probably not the case if hack the registry.

Avatar of nk51

ASKER

I can't totally accept Philipleighs' proposed answer because only one part of the answer is correct.
I explain :
(see https://www.experts-exchange.com/Q.10102173)
In my code I make modifications in the registry.
After those modifications I have to notify all others applications of those changes by broadcasting the WM_WININICHANGE message.
Under win95 I have to use the SendMessageTimeOut function.
The SDK give this example :
SendMessageTimeOut(HWND_BROADCAST,WM_WININICHANGE,0,0L,(LPARAM)(LPCTSTR)"windows",SMTO_NORMAL,1000,NULL);
But it doesn't work !
Does anybody know how to use this function ?
If you have some examples, it will be great !
Thanks in advance.
ASKER CERTIFIED SOLUTION
Avatar of philipleighs
philipleighs

Link to home
membership
This solution is only available to members.
To access this solution, you must be a member of Experts Exchange.
Start Free Trial
Whoops, I forgot to mention that dw is declared as a DWORD.

procedure TForm1.Button1Click(Sender: TObject);
var dw: DWORD;
begin
SendMessageTimeout(HWND_BROADCAST, WM_WININICHANGE, Longint(0),
LParam(PChar('windows')), SMTO_NORMAL, 1000, dw);
end;

Avatar of nk51

ASKER

Your last answer is good but the SendMessageTimeout function erase the modification I made in the registry and restore the previous value.
Have you an idea about what's happening ?

Avatar of nk51

ASKER

Your last answer is good the SendMessageTimeout function erase the modification I made in the registry and restore the previous value.
Have you an idea about what's happening ?

Are you changing the registry directly, or are you using WriteProfileString?

If you do it the way it says in the MS doc, it will update the registry for you.
If you write to the registry, then send INI_CHANGE, then Windows will synchronise the registry with WIN.INI. ie, the contents of WIN.INI will be copied into the registry overwriting your changes.

Use WriteProfileString.

Avatar of nk51

ASKER

I use WriteProfileString and it works correctly.
Thanks.