Solved

Printer API -different with Windows 98 ?

Posted on 1999-01-26
63
273 Views
Last Modified: 2010-04-06
I develop an application under Win NT but with the intention of using it under Win 98 as well. I make use of printer APIs such as

OpenPrinter(PChar(Printer.Printers.Strings[Printer.PrinterIndex]), vPrinterHandle, nil)

This command works well under WinNT and now it returns false under Win 98.

Same thing with

      if EnumJobs(vPrinterHandle, Msg.JobsLeft - 1, 1, 1, vJobInfo, 1000, vNeeded, vReturned) then ...

The values in JobInfo are also wrong.

Again, this code works very well in Win NT. Any suggestions ?




0
Comment
Question by:sharons
[X]
Welcome to Experts Exchange

Add your voice to the tech community where 5M+ people just like you are talking about what matters.

  • Help others & share knowledge
  • Earn cash & points
  • Learn & ask questions
  • 38
  • 12
  • 10
  • +3
63 Comments
 
LVL 20

Expert Comment

by:Madshi
ID: 1363451
Hmm. I'm not using Delphi's Printer object at all. I'm working with pure winAPI in this case and it works well in 95/NT and 98. I can't see any errors in your OpenPrinter statement. Perhaps you should check whether Printer.Printers.Strings[Printer.PrinterIndex] really gives you the exact name of the printer (CompareStr, not CompareText!).
If it does give you the right value and you nevertheless get a false as result, please tell me the GetLastError number.

Regards, Madshi.
0
 

Author Comment

by:sharons
ID: 1363452
Hmm. I'm not using Delphi's Printer object at all. I'm working with pure winAPI in this case and it works well in 95/NT and 98. I can't see any errors in your OpenPrinter statement. Perhaps you should check whether Printer.Printers.Strings[Printer.PrinterIndex] really gives you the exact name of the printer (CompareStr, not CompareText!).
If it does give you the right value and you nevertheless get a false as result, please tell me the GetLastError number.

Regards, Madshi.
0
 
LVL 20

Expert Comment

by:Madshi
ID: 1363453
You are right, it has to do with the value retrieved by Printer.Printers.Strings[Printer.PrinterIndex]. My printer's name is Brother HL-630 but the string in printers is Bother HL-630 on LPT1:.

So that's one problem I have to solve. Then I hardcoded the printer's name and it opens it fine but now I am having problems with the following:

    if OpenPrinter('Brother HL-630', vPrinterHandle, nil) then
//    if OpenPrinter(PChar(Printer.Printers.Strings[Printer.PrinterIndex]), vPrinterHandle, nil) then
    try
      GetMem(vJobInfo, 1000);

      // Get job info.
      if EnumJobs(vPrinterHandle, Msg.JobsLeft - 1, 1, 1, vJobInfo, 1000, vNeeded, vReturned) then
      begin

        // If job is still spooling we have to keep reading the total number
        // of pages since it goes up as the job is spooling.
        while vJobInfo^.Status = JOB_STATUS_SPOOLING do
          EnumJobs(vPrinterHandle, Msg.JobsLeft - 1, 1, 1, vJobInfo, 1000, vNeeded, vReturned);

The last loop gets into an infinite loop. I guess Win98 is very different. Any suggestions ?


0
[Live Webinar] The Cloud Skills Gap

As Cloud technologies come of age, business leaders grapple with the impact it has on their team's skills and the gap associated with the use of a cloud platform.

Join experts from 451 Research and Concerto Cloud Services on July 27th where we will examine fact and fiction.

 
LVL 2

Expert Comment

by:cartti
ID: 1363454
Häh?
0
 
LVL 1

Expert Comment

by:Cooler
ID: 1363455
Testing Testing 1 2 3
0
 
LVL 10

Expert Comment

by:viktornet
ID: 1363456
Cooler's test comment
0
 
LVL 10

Expert Comment

by:viktornet
ID: 1363457
hello sharons... Read your Win32.hlp file and see what it says about those APIs... In my Win32.hlp it says that the funciton is used under Win95 and and WinNT.. Check out yours to see if you can use that under Win98... if not see which is used instead...

-Viktor
--Ivanov
0
 
LVL 10

Expert Comment

by:viktornet
ID: 1363458
What's wrong with this?
0
 
LVL 20

Expert Comment

by:Madshi
ID: 1363459
What's wrong with this thing?
0
 
LVL 20

Expert Comment

by:Madshi
ID: 1363460
Hmmm. Is this question alright again?

Hi Viktor, if the win32.hlp file says, it works under win95, is usually works under win98 as well. There's no API (that I know) that works under win95 and NOT under win98.

Sharons, some hints. First of all, are you sure that Msg.JobsLeft is correct? I mean, what if the number of jobs decreases from 2 to 1. The Msg.JobsLeft variable seems to remain unchanged. So I guess that could be problem.
Another thing: You MUST check the return value of the EnumJobs function. Because if this function fails the Buffer won't be changed and the status will stay forever. So I think your loop doesn't end, because the EnumJobs function fails from the x-th call on.

Regards, Madshi.
0
 
LVL 20

Expert Comment

by:Madshi
ID: 1363461
Dummy comment just to move my "real" comment to the visible area...   :-)
0
 
LVL 20

Expert Comment

by:Madshi
ID: 1363462
dummy
0
 
LVL 20

Expert Comment

by:Madshi
ID: 1363463
sharons, be careful, you have to put 2 dummy comments after your real comment, otherwise your new comment won't be seen...   :-(
0
 
LVL 20

Expert Comment

by:Madshi
ID: 1363464
dummy
0
 
LVL 10

Expert Comment

by:viktornet
ID: 1363465
dummy
0
 
LVL 10

Expert Comment

by:viktornet
ID: 1363466
Madshi, there are plenty of APIs that don't work with Win98 because of the changes made to Win98...

when using WM_CLOSE and you send the message to a Window that is a folder then it won't close as in Win95 it closes alright...

here is what I mean...

SendMessage(FindWindow(nil, 'C:\windows\desktop\myfolder'), WM_CLOSE, 0, 0);

WM_QUIT is not working, and neither is PostMessage()...

There are lots more that I just don't have the time now to explain.. Also who knows how many there are that people have found and I don't know about,,,

-Viktor
--Ivanov
0
 
LVL 10

Expert Comment

by:viktornet
ID: 1363467
dummy
0
 
LVL 20

Expert Comment

by:Madshi
ID: 1363468
dummy
0
 
LVL 20

Expert Comment

by:Madshi
ID: 1363469
You mean WM_QUIT and PostMessage is not working for folder windows, right? Because I'm using both for other things under win98, and they work quite right.
My win32.hlp doesn't say anything about win98 at all. E.g. look at API "CreateWindowEx". According what you say, it doesn't work for win98...   :-)
No, of course win98 behaves differently than win95 in several things, but the APIs (at least the very most) are compatible. I'm quite sure about that, since we're using the same 3 MB program in win98 now without any significant changes - and without any problems!

Regards, Madshi.
0
 
LVL 20

Expert Comment

by:Madshi
ID: 1363470
dummy
0
 
LVL 10

Expert Comment

by:viktornet
ID: 1363471
dummy
0
 
LVL 10

Expert Comment

by:viktornet
ID: 1363472
I've tried using all combinations with SendMessage(), PostMessage() and WM_CLOSE, WM_QUIT and none of them worked on Win98 that I have,, I've no idea why, but that's what happens.. I've also tried other APIs and some of them didn't work...

-Viktor
--Ivanov
0
 
LVL 10

Expert Comment

by:viktornet
ID: 1363473
dummy
0
 
LVL 20

Expert Comment

by:Madshi
ID: 1363474
dummy
0
 
LVL 20

Expert Comment

by:Madshi
ID: 1363475
If you were right, most win32 programs would not work any longer!!! Perhaps you should try to reinstall your win98?    :-(

I'm really using SendMessage/PostMessage/WM_CLOSE/WM_QUIT every day, and it *really* works...

Regards, Madshi.
0
 
LVL 20

Expert Comment

by:Madshi
ID: 1363476
dummy
0
 
LVL 10

Expert Comment

by:viktornet
ID: 1363477
dummy
0
 
LVL 10

Expert Comment

by:viktornet
ID: 1363478
Maybe I should try reinstalling Win98 once again :(

-Viktor
--Ivanov
0
 
LVL 10

Expert Comment

by:viktornet
ID: 1363479
dummy
0
 
LVL 20

Expert Comment

by:Madshi
ID: 1363480
dummy
0
 
LVL 20

Expert Comment

by:Madshi
ID: 1363481
Hmmm. Try the following code snippet. If refreshes your desktop. If it does not work on your computer, you'll probably have to reinstall...   :-(
If it works, you've done something wrong with your SendMessage/Postmessage calls.

procedure RefreshDesktop;
var c1 : cardinal;
begin
  c1:=FindWindowEx(FindWindowEx(FindWindow('Progman','Program Manager'),0,'SHELLDLL_DefView',''),0,'SysListView32','');
  PostMessage(c1,WM_KEYDOWN,VK_F5,0); PostMessage(c1,WM_KEYUP,VK_F5,1 shl 31);
end;

Regards, Madshi.
0
 
LVL 20

Expert Comment

by:Madshi
ID: 1363482
dummy
0
 

Expert Comment

by:earthworm
ID: 1363483
dummy
0
 
LVL 20

Expert Comment

by:Madshi
ID: 1363484
I have written some code like this:

{...}
PrinterName:=Printer.Printers.Strings[Printer.PrinterIndex];
if OpenPrinter(PChar(PrinterName),vPrinterHandle,nil) then
   {...}
else
   {..}
{...}

then i run it
the printername get from Printer.Printers.Strings is 'HP LaserJet 4L on \\Yffwq\hp' (it's a network printer on the other computer) and the OpenPrinter function return FALSE. so i set the printername to 'HP LaserJet 4L' what same as the printer name i can see in the control panel, and now the OpenPrinter function return TRUE.

Now you see? the printername get from Printer.Printers.Strings is not always what the OpenPrinter function needs...  :-)

And so ,i suggest you not to uses the printer through Windows API. Delphi have provided a Printer object which is easy to use.
you can:
(1)Call the BeginDoc method to open the printer...
(2)uses the Canvas property to print text or draw image...
(3)Call the NewPage method to start a new page...
(4)Call the EndDoc method to close the printer...
It's easy to uses and you can do every thing you want.
0
 
LVL 20

Expert Comment

by:Madshi
ID: 1363485
dummy
0
 
LVL 20

Expert Comment

by:Madshi
ID: 1363486
dummy
0
 
LVL 20

Expert Comment

by:Madshi
ID: 1363487
Hey earthworm,

we already found out what you're telling us here...
Please read the comments the next time before you answer a question. Thank you.

sharons,

any progress with EnumJobs?
Hmmm. To be fair, you should reject earthworm's answer, or am I missing something?

Regards, Madshi.
0
 
LVL 20

Expert Comment

by:Madshi
ID: 1363488
dummy
0
 

Author Comment

by:sharons
ID: 1363489
dummy
0
 
LVL 20

Expert Comment

by:Madshi
ID: 1363490
I am now using API to get the name of the default printer and to open it to get the handle. My only problem now is when I print from a richedit with the print procedure jobs seem to be stuck in the status SPOOLING. If I print from other applications such as WordPad it's fine any suggestions? Thank you.
0
 
LVL 20

Expert Comment

by:Madshi
ID: 1363491
dummy
0
 
LVL 20

Expert Comment

by:Madshi
ID: 1363492
dummy
0
 
LVL 20

Expert Comment

by:Madshi
ID: 1363493
Hmmm. Could you show us the code where you print from the richedit component and the OpenPrinter/EnumJobs code, too, please.
Without that code I can't say anything about your problem.

So did my comments solve that EnumJobs problem?

Regards, Madshi.
0
 
LVL 20

Expert Comment

by:Madshi
ID: 1363494
dummy
0
 

Author Comment

by:sharons
ID: 1363495
dummy
0
 
LVL 20

Expert Comment

by:Madshi
ID: 1363496
Hi Madshi,  if you have a minute try the following code. I am running this with Win 98. You might get different results win WinNT.

When printing from the richedit, the status of the job remain SPOOLING causing an infinite loop in the following code. When printing lets say from WordPad while this code is running then it's fine.

Any idea ?  Thank you.

unit Unit1;

interface

uses
  Windows, Messages, SysUtils, Classes, Graphics, Controls, Forms, Dialogs,
  StdCtrls, ComCtrls, Winspool;

type
  TForm1 = class(TForm)
    RichEdit1: TRichEdit;
    Button1: TButton;
    procedure Button1Click(Sender: TObject);
  private
    { Private declarations }
    function GetDefaultPrinter: String;
    procedure WM_SpoolerStatus(var Msg: TWMSPOOLERSTATUS); message WM_SPOOLERSTATUS;
  public
    { Public declarations }
  end;

var
  Form1: TForm1;

implementation

{$R *.DFM}

procedure TForm1.Button1Click(Sender: TObject);
begin
  RichEdit1.Print('test');
end;

procedure TForm1.WM_SpoolerStatus(var Msg: TWMSPOOLERSTATUS);
const
  // This value is used to always know if a job was just added or just removed
  // from the print queue.
  cLastJobsLeft: Integer = 0;
var
  vJobInfo: PJobInfo1;
  vReturned, vNeeded: DWORD;
  LineCur, Port: PChar;
  PrinterInfo: PChar;
  Count, NumInfo: DWORD;
  vPrinterHandle : THandle;
  vDevMode : PDeviceModeA;
  vPrinterName: String;
begin
  // If a job has been added then get the number of pages of newly spooled job.
  if cLastJobsLeft < Msg.JobsLeft then
  begin
    try
      GetMem(vJobInfo, 1000);

      if OpenPrinter(PChar(GetDefaultPrinter), vPrinterHandle, nil) then
      begin
        // Get job info.
        if EnumJobs(vPrinterHandle, Msg.JobsLeft - 1, 1, 1, vJobInfo, 1000, vNeeded, vReturned) then
        begin
          while (vJobInfo^.Status = JOB_STATUS_SPOOLING) do
          begin
            EnumJobs(vPrinterHandle, Msg.JobsLeft - 1, 1, 1, vJobInfo, 1000, vNeeded, vReturned);
            Application.ProcessMessages;
          end;
          showmessage('Finish spooling...');
        end;
      end;
    finally
      FreeMem(vJobInfo, 1000);
    end;
  end;
end;

function TForm1.GetDefaultPrinter: String;
var
  PrinterInfo: PChar;
  Count, NumInfo: DWORD;
begin
  try
    GetMem(PrinterInfo, Count);
    if EnumPrinters(PRINTER_ENUM_DEFAULT, nil, 5, PByte(PrinterInfo), Count, Count, NumInfo) then
      Result := PPrinterInfo5(PrinterInfo)^.pPrinterName;
  finally
    FreeMem(PrinterInfo, Count);
  end;
end;

end.


0
 
LVL 20

Expert Comment

by:Madshi
ID: 1363497
dummy
0
 
LVL 20

Expert Comment

by:Madshi
ID: 1363498
dummy
0
 
LVL 20

Expert Comment

by:Madshi
ID: 1363499
Again: You still DO NOT ask if the EnumJobs API in the loop worked or didn't work and you MUST do that. Since if it did not work, your loop will be infinite.
So please change your loop like this and tell me what ErrorMessage is shown (I'm 98% sure you'll get an error message).

while (vJobInfo^.Status = JOB_STATUS_SPOOLING) do
          begin
            if not EnumJobs(vPrinterHandle, Msg.JobsLeft - 1, 1, 1, vJobInfo, 1000, vNeeded, vReturned) then begin
              MessageBox(0,pchar(intToStr(GetLastError)),'Error in EnumJobs',0);
              break;
            end;
            Application.ProcessMessages;
          end;

If you get no error message, I'll test the code. But I've not so much time. So please test for an error message first. Thank you...

Regards, Madshi.
0
 
LVL 20

Expert Comment

by:Madshi
ID: 1363500
dummy
0
 

Author Comment

by:sharons
ID: 1363501
dummy
0
 

Author Comment

by:sharons
ID: 1363502
The EnumJobs works fine and never reports any error. In fact, when I display the Print manager window that displays the jobs in the queue, this too gets stucked on spooling.

It seems to have something to do with this loop being in the same thread as the printing.  If I start my program and I print from another delphi program with a richedit the print works fine. Thank you.
0
 

Author Comment

by:sharons
ID: 1363503
dummy
0
 
LVL 20

Accepted Solution

by:
Madshi earned 290 total points
ID: 1363504
dummy
0
 
LVL 20

Expert Comment

by:Madshi
ID: 1363505
Ok, I'll test it tomorrow. But I've some ideas right now. Perhaps they help you solve the problem before tomorrow...  :-)

(1) Why do you loop for the job? I mean you get a message if the job STARTS and ENDS. So that's all you need, I think. Or is there a specific reason why you build a loop?

(2) If you really want to do it this way, I think the problem will be this one: Win98 sends this WM_SPOOLERSTATUS to you by using SendMessage. Then Win98 waits for you to return. Afterwards it does the printing. You see the deadlock here? Probably winNT does not wait for the result or prints in another thread. If I'm right with my thoughts here, there are two solutions:
(a) Start a thread that loops for EnumJobs or
(b) try calling "ReplyMessage(0);" in the beginning of the WM_SPOOLERSTATUS message handler. If you do that, Win98 gets the result at once and so doesn't have to wait any longer.

Hmmm. I post this as an answer, before another expert does, since I think, we two will solve this problem together...  :-)

Regards, Madshi.
0
 
LVL 20

Expert Comment

by:Madshi
ID: 1363506
dummy
0
 

Author Comment

by:sharons
ID: 1363507
dummy
0
 

Author Comment

by:sharons
ID: 1363508
Thank you madshi. You are right, a response is expected before the printing starts.  

My goal is to count the number of pages printed for each job. I am also hoping to be able to prevent the printing if the number of pages is more than a specified number.

In my previous code I was just accessing one job when using EnumJobs. I am now trying to look at all of them. pJob is a pointer to an array.  vJobInfo.pDocument gives me the name of the first job. How do I get the others. I thought something like   vJobInfo[1].pDocument but that does not work. Any suggestions ?

Do you know if there is an API to delete a print job other than purging all jobs ?

Thank you.

0
 

Author Comment

by:sharons
ID: 1363509
dummy
0
 
LVL 20

Expert Comment

by:Madshi
ID: 1363510
dummy
0
 

Author Comment

by:sharons
ID: 1363511
Use something like this:

var vJobInfo2: PJobInfo1;
.
  vJobInfo2:=vJobInfo;
  for i1:=1 to vReturned do begin
    // at this place add something to ask "vJobInfo2"
    vJobInfo2:=pointer(cardinal(vJobInfo2)+sizeOf(TJobInfo1));
  end;

To delete a single job use
  SetJob(jobID,...,JOB_CONTROL_CANCEL);

Regards, Madshi.
0
 
LVL 20

Expert Comment

by:Madshi
ID: 1363512
dummy
0
 
LVL 20

Expert Comment

by:Madshi
ID: 1363513
dummy
0

Featured Post

Free Tool: Subnet Calculator

The subnet calculator helps you design networks by taking an IP address and network mask and returning information such as network, broadcast address, and host range.

One of a set of tools we're offering as a way of saying thank you for being a part of the community.

Question has a verified solution.

If you are experiencing a similar issue, please ask a related question

Objective: - This article will help user in how to convert their numeric value become words. How to use 1. You can copy this code in your Unit as function 2. than you can perform your function by type this code The Code   (CODE) The Im…
Introduction I have seen many questions in this Delphi topic area where queries in threads are needed or suggested. I know bumped into a similar need. This article will address some of the concepts when dealing with a multithreaded delphi database…
If you’ve ever visited a web page and noticed a cool font that you really liked the look of, but couldn’t figure out which font it was so that you could use it for your own work, then this video is for you! In this Micro Tutorial, you'll learn yo…
This tutorial will teach you the special effect of super speed similar to the fictional character Wally West aka "The Flash" After Shake : http://www.videocopilot.net/presets/after_shake/ All lightning effects with instructions : http://www.mediaf…
Suggested Courses
Course of the Month8 days, 16 hours left to enroll

617 members asked questions and received personalized solutions in the past 7 days.

Join the community of 500,000 technology professionals and ask your questions.

Join & Ask a Question