BorlandTalk.com Forum Index BorlandTalk.com
Borland discussion newsgroups
 
Archives   FAQFAQ   SearchSearch   MemberlistMemberlist   UsergroupsUsergroups   RegisterRegister 
 ProfileProfile   Log in to check your private messagesLog in to check your private messages   Log inLog in 

Printer notification

 
Post new topic   Reply to topic    BorlandTalk.com Forum Index -> C++ Builder (Native API)
View previous topic :: View next topic  
Author Message
Bogdan
Guest





PostPosted: Fri Feb 10, 2006 7:03 pm    Post subject: Printer notification Reply with quote



I'm trying to monitor the printer and log each succesfully printed job, but
I
cannot make a difference between a job that is deleted before printing
because
the user chose to abort the print operation, and the job that is deleted
from
the spooler because it finished printing.
Is there a way to differentiate between the two situations?
I'm using the following piece of code :

void __fastcall TPrinterMonitor::Execute()
{
while(!Terminated)
{
WaitForSingleObject(Notifier,INFINITE);
Changes = 0x00000000;
if(FindNextPrinterChangeNotification(Notifier,&Changes,NULL,NULL))
{

if(Changes & PRINTER_CHANGE_ADD_JOB)
{
Line = "Job added";
Synchronize(Update);
};

if(Changes & PRINTER_CHANGE_DELETE_JOB)
{
Line = "Job deleted";
Synchronize(Update);
};

if(Changes & PRINTER_CHANGE_SET_JOB)
{
Line = "Job set";
Synchronize(Update);
};

if(Changes & PRINTER_CHANGE_WRITE_JOB)
{
Line = "Job write";
Synchronize(Update);
};

};
};
FindClosePrinterChangeNotification(Notifier);
};

Bogdan
Back to top
Remy Lebeau (TeamB)
Guest





PostPosted: Fri Feb 10, 2006 9:03 pm    Post subject: Re: Printer notification Reply with quote



"Bogdan" <boprea (AT) xnet (DOT) ro> wrote in message
news:43ecd5bb (AT) newsgroups (DOT) borland.com...

Quote:
I cannot make a difference between a job that is deleted before
printing because the user chose to abort the print operation, and
the job that is deleted from the spooler because it finished printing.

You have to keep track of the job information. Currently, you are
completely ignoring the pPrinterNotifyOptions and ppPrinterNotifyInfo
parameters of FindNextPrinterChangeNotification(). The ppPrinterNotifyInfo
parameter provides detailed information about each notification. For
example, you can use it to detect JOB_NOTIFY_FIELD_STATUS,
JOB_NOTIFY_FIELD_PAGES_PRINTED, and/or JOB_NOTIFY_FIELD_BYTES_PRINTED
changes. Also, you should be keeping track of the active jobs as well.
When a job is added, add its information to a list somewhere. When the job
is deleted, remove the job from your list. When the job is written to the
printer, keep track of its printing status. When the job is deleted, you
can check the last known status to know what the job was doing.

Quote:
while(!Terminated)
{
WaitForSingleObject(Notifier,INFINITE);

By doing that, you won't be able to terminate the thread while it is waiting
for a notification. You should use CreateEvent() to create a second event
and then use WaitForMultipleObjects() instead. This way, when the
application wants to shut down the thread, it can signal the event.

Quote:
Changes = 0x00000000;
if(FindNextPrinterChangeNotification(Notifier,&Changes,NULL,NULL))
{

Where are you calling FindFirstPrinterChangeNotification()? Which
notifications are you asking it for?


Gambit
Back to top
Bogdan
Guest





PostPosted: Fri Feb 10, 2006 9:03 pm    Post subject: Re: Printer notification Reply with quote



Quote:
Where are you calling FindFirstPrinterChangeNotification()? Which
notifications are you asking it for?

Missed some lines when copy-pasted Smile.

Flags = PRINTER_CHANGE_ALL;
Notifier = FindFirstPrinterChangeNotification(printer,Flags,0,NULL);

But the thread still terminates cleanly, even with :
while(!Terminated)
{
WaitForSingleObject(Notifier,INFINITE);
....
}

I've tried using the pPrinterNotifyOptions and ppPrinterNotifyInfo options
in the following code
to look for the number of pages printerd so far, but i'm not sure I'm using
them corectly...
shouldn't a notification be sent when one of the monitored parameters
changes?

void __fastcall TPrinterMonitor::Execute()
{
PRINTER_NOTIFY_OPTIONS pno;
PRINTER_NOTIFY_OPTIONS_TYPE pnot;
PRINTER_NOTIFY_INFO *pni = NULL;
WORD Field = JOB_NOTIFY_FIELD_PAGES_PRINTED;

pno.Version = 2;
pno.Flags = PRINTER_NOTIFY_OPTIONS_REFRESH;
pno.Count = 1;
pno.pTypes = &pnot;

pnot.Type = JOB_NOTIFY_TYPE;
pnot.Reserved0 = 0;
pnot.Reserved1 = 0;
pnot.Reserved2 = 0;
pnot.Count = 1;
pnot.pFields = &Field;

PPRINTER_NOTIFY_INFO ppni;

Notifier = FindFirstPrinterChangeNotification(printer,MonitorFlags,0,&pno);

while(!Terminated)
{
WaitForSingleObject(Notifier,INFINITE);
Changes = 0x00000000;
if(FindNextPrinterChangeNotification(Notifier,&Changes,&pno,(void**)&pni))
{
if(Changes & PRINTER_CHANGE_ADD_JOB)
{
Line = "Job added";
Synchronize(Update);
//Sleep(100);
//Synchronize(ListJobs);
}
else if(Changes & PRINTER_CHANGE_DELETE_JOB)
{
Line = "Job deleted";
Synchronize(Update);
}
else if(Changes & PRINTER_CHANGE_SET_JOB)
{
Line = "Job set";
Synchronize(Update);
}
else if(Changes & PRINTER_CHANGE_WRITE_JOB)
{
Line = "Job write";
Synchronize(Update);
}
else
{
Line = "some other change";
Synchronize(Update);
};
};
};

FindClosePrinterChangeNotification(Notifier);
}

Bogdan
Back to top
Remy Lebeau (TeamB)
Guest





PostPosted: Sat Feb 11, 2006 12:03 am    Post subject: Re: Printer notification Reply with quote

"Bogdan" <boprea (AT) xnet (DOT) ro> wrote in message
news:43ecfc34$1 (AT) newsgroups (DOT) borland.com...

Quote:
But the thread still terminates cleanly, even with :
while(!Terminated)
{
WaitForSingleObject(Notifier,INFINITE);
....
}

If there are no pending printer notifications, then your thread is blocked
indefinately. The application will not be able to shut the thread down
until another notification arrives, because the thread will not be able to
check its Terminated property. If you don't want to use a second event
object, then you should not be using an INFINITE timeout on
WaitForSingleObject(). Give it a smaller timeout value instead so that the
thread can properly check its Terminated property periodically.

Quote:
I've tried using the pPrinterNotifyOptions and ppPrinterNotifyInfo
options in the following code to look for the number of pages printerd
so far, but i'm not sure I'm using them corectly...

Try the following code (untested):

#include <map>

struct JobInfo
{
DWORD Status;
DWORD NumPages;
DWORD PagesPrinted;
DWORD NumBytes;
DWORD BytesPrinted;

JobInfo()
{
Status = 0;
NumPages = 0;
PagesPrinted = 0;
NumBytes = 0;
BytesPrinted = 0;
}
};

class TPrinterMonitor : public TThread
{
private:
typedef std::map<DWORD, JobInfo> JobMap;
typedef JobMap::iterator JobMapIter;

HANDLE Printer;
HANDLE Notifier
JobMap Jobs;

void __fastcall ProcessPrinterNotifyInfo(PPRINTER_NOTIFY_INFO pni);
void __fastcall Update();

protected
virtual void __fastcall Execute();
virtual void __fastcall DoTerminate();

public:
__fastcall TPrinterMonitor(HANDLE hPrinter);
};

__fastcall TPrinterMonitor::TPrinterMonitor(HANDLE hPrinter)
: TThread(true)
{
Printer = hPrinter;
Notifier = INVALID_HANDLE_VALUE;
Resume();
}

void __fastcall TPrinterMonitor::Execute()
{
DWORD Changes;

PRINTER_NOTIFY_OPTIONS pno = {0};
pno.Version = 2;
pno.Flags = PRINTER_NOTIFY_OPTIONS_REFRESH;

PPRINTER_NOTIFY_INFO pni;

Notifier = FindFirstPrinterChangeNotification(Printer,
PRINTER_CHANGE_JOB, 0, NULL);
if( Notifier == INVALID_HANDLE_VALUE )
return;

while( !Terminated )
{
if( WaitForSingleObject(Notifier, 1000) == WAIT_OBJECT_0 )
{
Changes = 0;
if( FindNextPrinterChangeNotification(Notifier, &Changes,
&pno, (void**)&pni) )
{
ProcessPrinterNotifyInfo(pni);
FreePrinterNotifyInfo(pni);
}
}
}

void __fastcall TPrinterMonitor::DoTerminate()
{
if( Notifier != INVALID_HANDLE_VALUE )
FindClosePrinterChangeNotification(Notifier);
}

void __fastcall
TPrinterMonitor::ProcessPrinterNotifyInfo(PPRINTER_NOTIFY_INFO pni)
{
for(DWORD x = 0; x < pni->Count; ++x)
{
PRINTER_NOTIFY_INFO_DATA &Data = pni->nData[x];
if( Data.Type == JOB_NOTIFY_TYPE )
{
switch( Data.Field )
{
case JOB_NOTIFY_FIELD_STATUS:
if( (Data.adwData[0] == JOB_STATUS_DELETED )
Jobs.erase(Data.Id);
else
Jobs[Data.Id].Status = Data.adwData[0];
break;

case JOB_NOTIFY_FIELD_PAGES_PRINTED:
Jobs[Data.Id].PagesPrinted = Data.adwData[0];
break;

case JOB_NOTIFY_FIELD_TOTAL_BYTES:
Jobs[Data.Id].Info.NumBytes = Data.adwData[0];
break;

case JOB_NOTIFY_FIELD_BYTES_PRINTED:
Jobs[Data.Id].Info.BytesPrinted = Data.adwData[0];
break;
}
}
}

Synchronize(Update);
}

void __fastcall TPrinterMonitor::Update()
{
// update the UI with the info of the current Jobs as needed ...
}


Gambit
Back to top
Bogdan
Guest





PostPosted: Sat Feb 11, 2006 7:03 pm    Post subject: Re: Printer notification Reply with quote

Thanks for the sample code.It worked, but with some little modifications.
You have to specify in an array which printer job fields you want to
monitor for changes :

WORD Types[4] = {JOB_NOTIFY_FIELD_PAGES_PRINTED,
JOB_NOTIFY_FIELD_STATUS,
JOB_NOTIFY_FIELD_TOTAL_BYTES,
JOB_NOTIFY_FIELD_BYTES_PRINTED};

PRINTER_NOTIFY_OPTIONS_TYPE pnot;
pnot.Type = JOB_NOTIFY_TYPE;
pnot.Count = 4;
pnot.pFields = &Types[0];

PRINTER_NOTIFY_OPTIONS pno;
pno.Version = 2;
pno.Flags = PRINTER_NOTIFY_OPTIONS_REFRESH;
pno.Count = 1;
pno.pTypes = &pnot;

PPRINTER_NOTIFY_INFO pni;

Notifier =
FindFirstPrinterChangeNotification(printer,PRINTER_CHANGE_JOB,0,&pno);
.. . .
if(FindNextPrinterChangeNotification(Notifier,&Changes,&pno,(void**)&pni))
.. . .

However, now I have another big problem.Windows sends the job to the
printer, and reports only
JOB_STATUS_SPOOLING and JOB_STATUS_PRINTING.All of the other errors
(like paper out or printer disconnected) are handled by the printer driver,
without any notification
to the spooler.

Bogdan
Back to top
Remy Lebeau (TeamB)
Guest





PostPosted: Mon Feb 13, 2006 8:03 am    Post subject: Re: Printer notification Reply with quote

"Bogdan" <boprea (AT) xnet (DOT) ro> wrote in message
news:43ee2762 (AT) newsgroups (DOT) borland.com...

Quote:
You have to specify in an array which printer job fields
you want to monitor for changes :

According to the documentation, if you specify NULL for the
pPrinterNotifyOptions parameter, then the fdwFlags parameter specifies what
to monitor. In the code I gave you, I do pass NULL in the
pPrinterNotifyOptions parameter, and the fdwFlags parameter is set to
monitor all job-related changes.


Gambit
Back to top
Display posts from previous:   
Post new topic   Reply to topic    BorlandTalk.com Forum Index -> C++ Builder (Native API) All times are GMT
Page 1 of 1

 
Jump to:  
You cannot post new topics in this forum
You cannot reply to topics in this forum
You cannot edit your posts in this forum
You cannot delete your posts in this forum
You cannot vote in polls in this forum


Powered by phpBB © 2001, 2006 phpBB Group
SEO toolkit © 2004-2006 webmedic.