寻找有耐心的富翁,帮忙解答一个有很多很多问题的问题(226分)

  • 主题发起人 主题发起人 cypl
  • 开始时间 开始时间
C

cypl

Unregistered / Unconfirmed
GUEST, unregistred user!
初次使用 API 函数,是两个获取与指定作业有关的信息的 API 函数,<br>有很多很多不明白的地方,请指教:<br>第一个:OpenPrinter //说明:打开指定的打印机,并获取打印机的句柄 <br><br>&nbsp; &nbsp; LPTSTR pPrinterName, // 要打开的打印机的名字,但名字从哪能获得呢?<br>&nbsp; &nbsp; LPHANDLE phPrinter, &nbsp;// 用于装载打印机的句柄,我想这要用一个变量装<br>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; // 这个句柄吧,回来好用,但这个变量申请什么类型的?<br>&nbsp; &nbsp; LPPRINTER_DEFAULTS pDefault // 这个结构保存要载入的打印机信息,这个信息用<br>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;//什么保存?要申请一个和它一样的结构吗?<br>取的打印机的句柄后,发现用 GetJob 函数能取得打印任务的信息,我就想取里面的打印<br>任务是否完成的信息。<br>GetJob <br>&nbsp; &nbsp; HANDLE hPrinter, // 打印机句柄,已经获得<br>&nbsp; &nbsp; DWORD JobId, // 作业编号,这有个问题,这个作业编号的变量是 DWORD类型的,<br>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;//但帮助里没找到这个类型,但申请时可以,这是 WORD 类型吗?为<br>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; //什么前面要加 D ?<br>&nbsp; &nbsp; DWORD Level, // 数据类型级别,也是 DWORD<br>&nbsp; &nbsp; LPBYTE pJob, // 包含JOB_INFO_1 或 JOB_INFO_2结构的缓冲区,结构中包含<br>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; //了与打印作业有关的信息,这是关键,但我不知道该怎么做下去,<br>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; //我觉得是不是申请个和这个结构相同的结构,然后取的信息<br><br>&nbsp; &nbsp; DWORD cbBuf, // pJob缓冲区中的字符数量 &nbsp; &nbsp;这是什么意思?<br>&nbsp; &nbsp; LPDWORD pcbNeeded &nbsp;// 指向一个Long型变量的指针,该变量用于保存请求的缓冲区长度,或者 <br>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;//实际读入的字节数量,这个 LPDWORD 又是什么类型的?帮助里面也没有啊<br>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;//还有它说“该变量用于保存请求的缓冲区长度”好象是说上面的那个 cbBuf 那个<br>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; //参数的,但那个参数不有字符数量了吗?这到底是什么意思?<br><br>//那个 pJob 的结构如下:<br>typedef struct _JOB_INFO_1 { &nbsp; &nbsp;// ji1 &nbsp;<br>&nbsp; &nbsp; DWORD &nbsp;JobId; &nbsp;<br>&nbsp; &nbsp; LPTSTR pPrinterName; <br>&nbsp; &nbsp; LPTSTR pMachineName; <br>&nbsp; &nbsp; LPTSTR pUserName; <br>&nbsp; &nbsp; LPTSTR pDocument; <br>&nbsp; &nbsp; LPTSTR pDatatype; <br>&nbsp; &nbsp; LPTSTR pStatus; <br>&nbsp; &nbsp; DWORD &nbsp;Status; //这个里面就装着我要的,在下面<br>&nbsp; &nbsp; DWORD &nbsp;Priority; <br>&nbsp; &nbsp; DWORD &nbsp;Position; <br>&nbsp; &nbsp; DWORD &nbsp;TotalPages; <br>&nbsp; &nbsp; DWORD &nbsp;PagesPrinted; <br>&nbsp; &nbsp; SYSTEMTIME Submitted; <br>} JOB_INFO_1; <br><br>//上面的结构的内容怎样才能取出来呢?我老是弄不明白,还有它这个 LPBYTE 类型,是<br>//什么类型?<br><br>这是其中的 &nbsp;status 里面的值<br>Status<br>JOB_STATUS_DELETING<br>JOB_STATUS_ERROR<br>JOB_STATUS_OFFLINE<br>JOB_STATUS_PAPEROUT<br>JOB_STATUS_PAUSED<br>JOB_STATUS_PRINTED &nbsp;//应该是这个吧,作业状态是:已经打印了<br>JOB_STATUS_PRINTING<br>JOB_STATUS_SPOOLING<br><br>//这个又怎么才能得到呢?<br><br>对这些我简直是一点都不明白,谁好心给我详细说说,我把所有分,都给你,就只有226分了。<br>这个 API 函数为什么这么复杂? &nbsp;DELPHI &nbsp;里面有没有包装这两个函数的函数?
 
你不要用api 在delphi 中已封装了一个tprinter类<br>例:<br>&nbsp; print:tprinter;<br>&nbsp; print:=tprinter.create;<br>&nbsp; print.begindoc &nbsp; &nbsp;//<br>&nbsp; print.canvas.textout('123242');<br>&nbsp; print.enddoc;<br>
 
其实这个函数在Delphi中已经封装了,<br>声明在winspool.pas(D:/Program Files/Borland/Delphi5/Source/Vcl)里面,<br>Delphi把打印相关的东西封装成TPrinter对象,这个对象在printers.pas<br>(D:/Program Files/Borland/Delphi5/Source/Vcl)单元里面。<br>Printers这个单元有很详细的说明,你先看看吧,有什么问题再在这提出来好了。<br><br>至于说耐心,我想在这的每一个人都不会缺这个,唯一缺的可能是时间吧,只要有<br>时间,应该来说都不会有问题的。[:D]
 
chshanghai:<br>&nbsp; print:tprinter;<br>&nbsp; print:=tprinter.create;<br>&nbsp; print.begindoc &nbsp; &nbsp;//<br>&nbsp; print.canvas.textout('123242');<br>&nbsp; print.enddoc;<br>你说的这个不好使啊,print.enddoc 后,那个左下脚就出了打印机的小图标,里面有打印<br>任务,我就想知道那个打印任务打印完成后如何判断啊! enddoc 好象是把打印数据发出后<br>就结束了,不是有没有打印!<br>不过也多谢你!<br><br>xianjun:<br>&nbsp; &nbsp;我找找看看,多谢你,但最好有时间帮忙给我解释一下那个 api 函数,我是第一次用,<br>更想知道怎么用那些奇怪的函数!<br>&nbsp;<br>
 
OpenPrinter<br>&nbsp;获取指定打印机的句柄<br>var<br>&nbsp; hPrinter: THandle; &nbsp;//获得的打印机句柄<br>&nbsp; PrtName: String; &nbsp; //打印机名字<br>OpenPrinter( PChar( PrtName ) , hPrinter , nil );<br><br>GetJob<br>&nbsp;获取打印作业信息<br><br>其实Delphi里已经封装了TPrinter类,你直接uses Printers,就可以调用打印任务了。<br>BeginDoc;<br>.....<br>.....<br>.....<br>EndDoc;<br><br>给你举一个图象打印的例子:<br><br>procedure TForm1.Button1Click(Sender: TObject);<br>var<br>&nbsp; ScaleX, ScaleY: Integer;<br>&nbsp; R: TRect;<br><br>begin<br>&nbsp; Printer.BeginDoc; &nbsp;// **<br>&nbsp; with Printer do<br>&nbsp; try<br>&nbsp; &nbsp; ScaleX := GetDeviceCaps(Handle, logPixelsX) div PixelsPerInch;<br>&nbsp; &nbsp; ScaleY := GetDeviceCaps(Handle, logPixelsY) div PixelsPerInch;<br>&nbsp; &nbsp; R := Rect(0, 0, Image1.Picture.Width * ScaleX,<br>&nbsp; &nbsp; &nbsp; Image1.Picture.Height * ScaleY);<br>&nbsp; &nbsp; Canvas.StretchDraw(R, Image1.Picture.Graphic); &nbsp;// **<br>&nbsp; finally<br>&nbsp; &nbsp; EndDoc; &nbsp;// **<br>&nbsp; end;<br>end;<br><br><br>
 
还是不明白
 
winspool里已经封装了这两个函数,我先按你的要求试写一个例子,晚点给你。
 
你看看那个单元的SetToDefaultPrinter过程就知道了,<br>LPTSTR pPrinterName, 是从系统的打印机列表中用API:EnumPrinters取得的<br>phPrinter就是打印机的Handle, 是OpenPrinter根据你传入的名称返回的<br>LPPRINTER_DEFAULTS pDefault保存了打印机的一些默认设置,你传入nil就行了。<br><br>DWORD JobId: DWORD是WINDOWS的一个数据类型,相当于DELPHI的LongWord,当然<br>DELPHI中也声明了DWORD这个类型,不过是DWORD = LongWord;<br>...<br><br>其实这个真的挺复杂,如果你是用来作打印任务的话,最好别直接用API,用TPrinter<br>对象就可以了,一切都已经为你做好。而且TPrinter还带有详细的帮助。
 
&nbsp;所谓的DWORD就是Double Word的意思,Word你应该知道吧,16位的无符号整数,因此<br>DWORD就是32位的无符号整数了,跟UINT是一样的。对于以LP开头的所有类型,都是指针。<br>Delphi对这些指针一般有如下规定,在作为参数的时候,LPTSTR就是PChar,其余的都是<br>以var的形式传递。对于放在某些结构里(例如你的JOB_INFO_1)的指针,就是用指针。至<br>于是什么类型的指针,看具体类型而言,也可以一律用PChar。<br>&nbsp; 其实,在使用WinAPI的时候,有一个适用于大多数函数的规律,如果MSDN中说某个函数<br>在xxxx.lib中,那么Delphi中如果不在Windows.dcu中声明,就会在xxxx.dcu中声明。<br>会有对应的xxxx.dcu,在uses中添加xxxx即可。函数名是相同的,然后你可以利用Delphi的<br>自动完成提示功能,让它显示所有参数的类型。那个已经翻译成Delphi的类型了。<br>&nbsp; 另外说一些WinAPI的普遍调用规律吧,WinAPI总是将某些返回值放在缓冲区中。正如<br>Delphi中使用了var的参数一样。不过WinAPI需要你自己分配内存,因此你需要告诉它你分<br>配了多少内存。但是某些时候你不知道WinAPI究竟需要多少内存,这时它通常会提供一个指<br>针类型的参数,当你分配的内存不够的时候,它会在这个参数里返回所需要的内存。<br>&nbsp; 你所需要的函数在WinSpool.dcu中有声明,所有要用到的结构也都定义了,不过那些结构<br>的名字和MSDN中不一样。多利用一下Delphi的提示功能,可以免去你很多麻烦。
 
OK,花了俺午休的时间,给你作了一个简单的例子,留下MAIL给你发过去。
 
都是好人啊,多谢多谢,<br>j_shen2000:真是好人中的好人啊,不过信箱坏了,你就贴出来吧!
 
首先,我没有用GETJOB,而是用了ENUMJOBS,不是因为GETJOB不能用而是因为,GETJOB<br>中的JOBID必须是ADDJOB生成的作业句柄,而ENUMJOBS中的JOBID是作业的INDEX,不过功能<br>差不多,后者可能更完善,因为它能捕作所有在打印机管理中的作业目前的运行情况。<br>函数说明你可以看MSDN,测试时,找一个大文件,要不停的按按钮,或者你放到线程或者<br>放个TIMER来扫描,呵,偷了一个懒:)。<br>USE winspool,printers;<br>procedure TForm1.Button2Click(Sender: TObject);<br>var<br>&nbsp; MyPrinter,MyHandle &nbsp; &nbsp; &nbsp; : THandle;<br>&nbsp; MyDevModeOut,MyDevModeIn : pDevmode;<br>&nbsp; MyDevice,MyDriver,MyPort: array [0..255] of Char;<br>&nbsp; jb:job_info_1A;<br>&nbsp; pn,pr:dword;<br>&nbsp; s:string;<br>begin<br>&nbsp; { set Printer index to the default printer }<br>&nbsp; Printer().PrinterIndex := -1;<br>&nbsp; { get our printer properties }<br>&nbsp; Printer().GetPrinter(MyDevice,MyDriver,MyPort,MyHandle);<br>&nbsp; { OpenPrinter WIN32 API call returns hPrinter to us }<br>&nbsp; if OpenPrinter(@MyDevice, MyPrinter, nil) then begin<br>&nbsp; &nbsp; If EnumJobs(myprinter,0,1,1,@Jb,SizeOf(job_info_1A)+128,pn,pr) then<br>&nbsp; &nbsp; //0代表第一个作业(GETJOB中必须是作业句柄),<br>&nbsp; &nbsp; //1代表所要列举的作业总数为1,即只找第一个。<br>&nbsp; &nbsp; //1代表LEVEL为1,对应job_info_1结构。<br>&nbsp; &nbsp; Begin<br>&nbsp; &nbsp; &nbsp; If jb.JobId&gt;0 then<br>&nbsp; &nbsp; &nbsp; Begin<br>&nbsp; &nbsp; &nbsp; case jb.Status of<br>&nbsp; &nbsp; &nbsp; JOB_STATUS_DELETING:showmessage('JOB_STATUS_DELETING');<br>&nbsp; &nbsp; &nbsp; JOB_STATUS_ERROR:showmessage('JOB_STATUS_ERROR');<br>&nbsp; &nbsp; &nbsp; JOB_STATUS_OFFLINE:showmessage('JOB_STATUS_OFFLINE');<br>&nbsp; &nbsp; &nbsp; JOB_STATUS_PAPEROUT:showmessage('JOB_STATUS_PAPEROUT');<br>&nbsp; &nbsp; &nbsp; JOB_STATUS_PAUSED:showmessage('JOB_STATUS_PAUSED');<br>&nbsp; &nbsp; &nbsp; JOB_STATUS_PRINTED:showmessage('JOB_STATUS_PRINTED');<br>&nbsp; &nbsp; &nbsp; JOB_STATUS_PRINTING:showmessage('JOB_STATUS_PRINTING');<br>&nbsp; &nbsp; &nbsp; JOB_STATUS_SPOOLING:showmessage('JOB_STATUS_SPOOLING');<br>&nbsp; &nbsp; &nbsp; else showmessage('print end or no print');<br>&nbsp; &nbsp; &nbsp; end;<br>&nbsp; &nbsp; &nbsp;End;<br>&nbsp; &nbsp; End<br>&nbsp; &nbsp; else<br>&nbsp; &nbsp; &nbsp;ShowMessage(SysErrorMessage(GetLastError));<br>&nbsp; End;<br>end;<br>
 
后退
顶部