http://community.csdn.net/Expert/topic/4390/4390241.xml?temp=.7930719教:在delphi中如何发送打印机控制码?在我的打印机操作面板上有一个功能按钮——换行,执行后打印机向前走纸0.5cm,我想在程序中调用这个换行功能,请高手指点如何实现?windows提供的escape可以给打印机发送控制码,其定义如下:
int Escape(
    HDC hdc, // 打印机的handle  
    int nEscape, // escape 函数 
    int cbInput, // 输入结构的大小 
    LPCSTR lpvInData, // 输入结构的指针 
    LPVOID lpvOutData  // 输出结构的指针 
   );
在这个定义中,第二个参数nEscape,我不清楚要传什么呢?说明文档说提到,这个参数必须是一个预先定义好的,windows下提供了如下的几个定义:ABORTDO;ENDDOC;GETPHYSPAGESIZE;GETPRINTINGOFFSET;GETSCALINGFACTOR;NEWFRAME;NEXTBAND;PASSTHROUGH;SETABORTPROC;STARTDOC;其中好像没有我需要的,用于换行的。在win32api的说明文档中也提到,对于常用的print escape都已经定义对应的方法,如:AbortDoc,EndDoc等,没有对应的用于换行的方法。同时也了解到,如果需要发送一些私有的print escape 需要用到extEscape函数,该函数的定义如下:int ExtEscape(
    HDC hdc, //设备Handle
    int nEscape, // escape function 
    int cbInput, // number of bytes in input structure 
    LPCSTR lpszInData, // pointer to input structure 
    int cbOutput, // number of bytes in output structure 
    LPSTR lpszOutData  // pointer to output structure 
);同样的,在这个函数的定义中,我不知道需要都要传入那些参数呢??
我的环境是delphi7.0/winXP/EPSON LQ-1600KIII请高手们关注。

解决方案 »

  1.   

    打印机的换行命令在EPSON LQ-1600KIII说明书应该就有,然后用写文件方式向LPT1端口写出就应该可以。
      

  2.   

    是的,我查询了 epson的程序员参考手册,其中控制码的 值分别为,27 和 10 ,但我以一下的方式写时,总是会走一页纸,根本达不到换行的效果,
    AssignPrn(textFile);
    Rewrite(textFile);
    WriteLn(textFile,chr(27) + chr(10));以上这些代码应该就是 直接写打印机吧??为什么达不到预期的效果。
      

  3.   

    据说激光打印机不可以部分走纸,可以利用打印机的画布Canvas:
      printer.BeginDoc;
      printer.Canvas.TextOut(100, 20, 'abc');
      printer.Canvas.TextOut(100, 30, '下一行');
      ...
      printer.NewPage;
      ...
      printer.EndDoc;
      

  4.   

    我发现一旦调用 ,
    printer.BeginDoc;
    printer.EndDoc;
    不管他们中间 有没有 语句,都会引起 走一页纸,也就是说,无法达到我只要换行的目的。嗯,我用的是 24针打印机。打印机的面板上有用于换行的按钮,也就是说,他有这个功能,但我现在不知道 如何把控制码 发给他。
      

  5.   

    你想打印什么呢?是预先做好的报表吗?那样可以直接打印的吧.不用换行.如果是canvas打印就不知道了
      

  6.   

    这些票据打印机手册上都会有的,
    这是票据打印一段代码(Epson LQ300K),仅供参考:
    procedure PrintTicket(AStation,Achannel,Auserid,ATicketNo,
            AMoney,APntdate,APnttime:string);stdcall;
    var
      F:TextFile;
      ...
    begin
      ....
      Assignfile(f,'LPT1');   
      rewrite(f);
      {初始化打印机}
      Write(f,chr(27)+'@');  //Chr(27)+'@' 即ESC @ 指令
      {设置汉字显示方式}
      write(f,chr(28)+chr(ord('&')));  //Chr(28) 即 FS
      {设定打印相对水平位置}
      Write(f,chr(27)+chr(ord('\'))+chr($CF)+chr($00));
      //设置高速打印
      //write(f,chr(28)+chr(ord('x'))+chr($01));  Writeln(f,PrintChannel+space(16)+Auserid+space(12)+carType);
      Writeln(f);
      write(f,chr(27)+chr(ord('\'))+chr($CF)+chr($00));
      Write(f, AMoney);
      Writeln(f,Space(26)+PrntTicketno);
      Writeln(f);
      write(f,chr(27)+chr(ord('\'))+chr($CF)+chr($00));
      //Writeln(f);
      Writeln(f,Apntdate+Space(12)+ApntTime);
      //顺时针走纸控制
      Writeln(f,chr(27)+chr(ord('J'))+chr($FF));
      Writeln(f,chr(27)+chr(ord('J'))+chr($20));  flush(f);
      Closefile(f);end;不同的打印机控制码会有所不同,具体参考打印机手册。》怎么让打印机在打印前后退2行,设定纸张的大小
    将打印机纸张类型设为自定义,自定义纸张大小,
    这类代码很多,搜索一下,以上也有给出了一些
    至于,打印前后退2行,先将纸张在打印机装好,控制好
    其装纸位置(可微调打印机),打印后重要的是走纸的控制,
    最好是用控制码控制,实在没办法的话,你也可以用
    writeln(f)
    writeln(f)
    这样的折行控制。>>//顺时针走纸控制
    >>Writeln(f,chr(27)+chr(ord('J'))+chr($FF));
    >>Writeln(f,chr(27)+chr(ord('J'))+chr($20));这个是我根据打印机控制码指令
    执行n/180英寸顺方向走纸 Esc J n    (1<=n<=255)
    以及打印票据纸张的高度,来调整打印连续纸时的走纸长度。
    另外,这里还有一些LQ300K的一些打印位置控制码指令:
    设定高速打印 FS x n (n=0,1)
    设定绝对水平打印位置 Esc ¥ nL nH  (0<=nH<=127
                                       0<=nL<=255)
    设定相对水平打印位置 Esc \ nL nH    (同上)供参考。具体你可以查看你的打印机手册。
      

  7.   

    谢谢,这位大侠了,打印机手册我已经 有了,也已查阅。
    方法就如你所说的,我都试了,和你代码唯一的区别是,你使用 Assignfile(f,'LPT1'); 打开打印机端口,而我使用
     assignprn(f) 来打开打印机端口的,而实际上我的计算机因为是笔记本,所以打印机是通过usb口和打印机联系起来的,所以我想直接的操作 lpt1估计不行吧??
      

  8.   

    优化你好可以告诉钟摆低的QQ号吗?他想和你聊你能告诉他你的QQ号吗?帮忙了大哥
      

  9.   

    另外,我还想问的是:>>Writeln(f,chr(27)+chr(ord('J'))+chr($FF));
    >>Writeln(f,chr(27)+chr(ord('J'))+chr($20));这两句代码中 J,和 $FF或者$20分别代表了什么阿??
    从我的打印机手册中查到 ,换行是两个指令即:ESC + LF,对应的十进制编码也就是 27,10。
    为什么你这里 中间会多一个 值呢??难道是打印机型号不同所致??
    我的是 EPSON LQ-1600KIII
      

  10.   

    楼主:
    用文本的方式打印delphi需要用端口的方式,否则控制命令会没有用。
    下面是小弟的现在用的pos 机的打印部分,供你参考(机型EPSON TM88III);type
      TPrinterInfo = record
        SeverName : PChar;
        PrinterName : PChar;
        ShareName : PChar;
        PortName : PChar;
        DriverName : PChar;
        Comment : PChar;
        Location : PChar;
        DeviceMode : PDeviceModeA;
        SepFile : PChar;
        PrintProcessor : PChar;
        DataType : PChar;
        Parameters : PChar;
        SecurityDescriptor: PSecurityDescriptor;
        Attributes : Cardinal;
        DefaultPriority : Cardinal;
        StartTime : Cardinal;
        UntilTime : Cardinal;
        Status : Cardinal;
        Jobs : Cardinal;
        AveragePPM : Cardinal;
    end;function GetCurrentPrinterInformation: TPrinterInfo;
    var
      hPrinter : THandle;
      pInfo: PPrinterInfo2;
      bytesNeeded: DWORD;
    begin
      hprinter := GetCurrentPrinterHandle;
      try
        Winspool.GetPrinter( hPrinter, 2, Nil, 0, @bytesNeeded );
        pInfo := AllocMem( bytesNeeded );
        try
          Winspool.GetPrinter( hPrinter, 2, pInfo, bytesNeeded, @bytesNeeded );
          Result.SeverName := pInfo^.pServerName;
          Result.PrinterName := pInfo^.pPrinterName;
          Result.ShareName := pInfo^.pShareName;
          Result.PortName := pInfo^.pPortName;
          Result.DriverName := pInfo^.pDriverName;
          Result.Comment := pInfo^.pComment;
          Result.Location := pInfo^.pLocation;
          Result.DeviceMode := pInfo^.pDevMode;
          Result.SepFile := pInfo^.pSepFile;
          Result.PrintProcessor := pInfo^.pPrintProcessor;
          Result.DataType := pInfo^.pDatatype;
          Result.Parameters := pInfo^.pParameters;
          Result.SecurityDescriptor := pInfo^.pSecurityDescriptor;
          Result.Attributes := pInfo^.Attributes;
          Result.DefaultPriority := pInfo^.DefaultPriority;
          Result.StartTime := pInfo^.StartTime;
          Result.UntilTime := pInfo^.UntilTime;
          Result.Status := pInfo^.Status;
          Result.Jobs := pInfo^.cJobs;
          Result.AveragePPM := pInfo^.AveragePPM;
        finally
          FreeMem( pInfo );
        end;
      finally
        ClosePrinter( hPrinter );
      end;
    end;procedure PrintData(PrintList: TStringList; Printname: string; Port: boolean);
    var
      Line: Integer;
      PrintText: TextFile;//System.Text;
      PrinterInfo: TPrinterInfo;
      printport: string;
    begin
      if not Port then
        begin
          printer.PrinterIndex:= printer.printers.IndexOf(Printname);
          PrinterInfo := GetCurrentPrinterInformation;
          printport := PrinterInfo.PortName;
        end
      else
        printport:= Printname;
      AssignFile(PrintText,printport);
      Rewrite(PrintText);
      //Printer.Canvas.Font := Memo1.Font;
      for Line := 0 to PrintList.Count - 1 do
        Write(PrintText,PrintList[Line]);
      CloseFile(PrintText);
    end;
      

  11.   

    谢谢楼上的代码。
    从你的意思来看,是需要用 Assignfile(f,'LPT1');而不是 assignprn(f)
    我当前的打印机是通过usb接口连接到笔记本的,Assignfile(f,'usbidx');是不行的,暂时我没有通过并口直接连接的打印机,所以无法验证是否可以,验证后我再来发表结果。
      

  12.   

    楼主:
    请注意我的代码实现方式。Printname是打印机的名,他会转成printport.代码中考虑到这点了。
      

  13.   

    谢谢大侠,我看明白了,使用打印机的名称 而不是 端口 去关联打印机到文件,我回家试一下先。不过有一点我还是心存疑虑,我使用 assignprn(f),把打印机关联到文件后,写文件内容后,打印机有输出,说明打印机已经被正确的关联了,只是 我发送的 控制码,不被打印机认为是控制码。不知道换上用 打印机名称来关联,是否可以解决问题。试了之后,我回最快来这里 通报 结果的。
      

  14.   

    那是文件打印,通过win的驱动,基本会转成图形打印方式,所以控制命令会不被接受。这是两种打印方式。
    考虑到用到的单元(Printers,winspool)。
    最后,希望楼主不要称我“大侠”。剩下的看楼主自己的了。祝好运。
      

  15.   

    那是由于你没有这个打印机设备。有打印机设备是向打印机打印,没有就向文件写。我本地的打印机和网络打印机都是用过的。Printname: string如果不是端口号是打印机名时 Port: boolean要为false;
      

  16.   

    昨天晚上我回去试了一下,用打印机名称还是没有写向打印机,而是写向了文件,可能是我的系统用USB连接打印机的缘故吧。这件事情,我快没有信心再追问下去了。:(