【问题标题】:Correct way to send commands directly to printer!直接向打印机发送命令的正确方法!
【发布时间】:2011-08-21 15:30:14
【问题描述】:

好的,我就是这样做的:

procedure TMainWindow.btnRawPrintClick(Sender: TObject);
begin
  BeginPrint;
  SendStr(#27#69);
  SendStr('MyData');
  SendStr(#10);
  EndPrint;
end;

procedure TMainWindow.SendStr(Text: String);
var
  i: Integer;
  data : Array of Char;
begin
  for i := 1 to Length(Text) do
  begin
    SetLength(data,i);
    data[Pred(i)] := Text[i];
  end;

  if (PrintRawData(printHandle,
                   data,
                   Length(data)) < 0) then begin
    ShowMessage('PrintRawData Failed');
    EndRawPrintPage(printHandle);
    EndRawPrintJob(printHandle);
    exit;
  end;
end;

procedure TMainWindow.BeginPrint;
begin
  printHandle := StartRawPrintJob('EPSON TM-T70 Receipt','ESDPRT001','Test Document');

  if printHandle < 0 then
  begin
    ShowMessage('StartRawPrintJob Failed!');
    exit;
  end;

  if (StartRawPrintPage(printHandle) < 0) then begin
    ShowMessage('StartRawPrintPage Failed!');
    EndRawPrintJob(printHandle);
    exit;
  end;
end;

procedure TMainWindow.EndPrint;
begin
  if (EndRawPrintPage(printHandle) < 0) then begin
    ShowMessage('EndRawPrintPage Failed');
    EndRawPrintJob(printHandle);
    exit;
  end;

  if (EndRawPrintJob(printHandle) < 0) then begin
    ShowMessage('EndRawPrintJob Failed');
    exit;
  end;
end;

我还更改了从here 获取的一些代码:

function PrintRawData(hPrn : THandle;
                      Buffer : pointer;
                      NumBytes : SpoolInt) : integer;
{$IFDEF WIN32}
var
  BytesWritten : DWORD;
 {$ENDIF}
begin
  NumBytes := NumBytes * 2;    //<-- I added this line
  ...

但是,由于某些命令(转义序列)无法按预期工作,因此出现了问题!

【问题讨论】:

  • 如何将代码发送到打印机?直接到 LPT1:还是其他方法?您是否启用了打印机调试模式以查看您发送的十六进制?
  • 您发送什么来代替ESC?对于大多数较旧的 Epson 打印机,它是 ASCII 字符 #27。
  • 是的,我发送 #27 而不是 ESC。我使用win api WritePrinter函数发送命令!

标签: delphi printing epson


【解决方案1】:

您使用了错误的功能。使用Escape,传递PASSTHROUGH 标志作为第二个参数。这会将未处理的原始转义码直接发送到打印机。

Joe Hecht(以前的 Borland)曾多次发布一个单元,使这更容易。我在这里找到了unit PrtRaw。

【讨论】:

  • 感谢您的帖子。我更新了我的帖子,添加了一些代码。但是,我不明白将 PASSTHROUGH 标志作为第二个参数传递。什么函数的第二个参数?你能再解释一下吗?
  • Peacelyk,Ken 指的是Escape Windows API 函数。
  • @Peacelyk:对不起。我忘记在原始答案中提供指向 MSDN 上的 Escape 的链接。我现在已经更新了。
  • 肯,NP。我一定会检查的
【解决方案2】:

由于 Ansi 和 Unicode 字符之间的变化,您当前的代码以错误的格式向打印机发送数据。您使用的打印机显然能够容忍一定数量的错误,这就是您的某些命令有效的原因,但有一个限制。

在您的 Delphi 版本中,Char 等同于 WideChar,因此将您的 Char 代码更改为使用 AnsiChar,这样您就可以发送一个字节的字符,正如打印机所期望的那样。你的 PrintRawData 函数以前很好。你的改变是错误的。打印机不希望收到两字节的 Unicode 字符,但这就是您的更改。

恢复原来的PrintRawData代码后,把你的SendStr函数改成这样:

procedure TMainWindow.SendStr(const Text: string);
var
  data: AnsiString;
begin
  data := Text;

  if (PrintRawData(printHandle,
                   PAnsiChar(data),
                   Length(data)) < 0) then begin
    ShowMessage('PrintRawData Failed');
    EndRawPrintPage(printHandle);
    EndRawPrintJob(printHandle);
  end;
end;

我对代码做了如下修改:

  1. 将Char 数组替换为AnsiString。
  2. 不要使用循环一次增加一个字符的数据数组,而是使用单个赋值语句执行 Unicode 到 Ansi 的转换,并让 RTL 负责转换。
  3. 将数据字符串类型转换为 PAnsiChar 以传递给 PrintRawData。
  4. 除非您需要修改其内容,否则将字符串参数作为 const 传递。
  5. 当函数已经完成时,不需要显式的exit 语句。

【讨论】:

  • 迂腐点:我喜欢评论 line data := Text 说“Unicode 到 ansi 转换发生在这里”,因为它可能是有损转换。
【解决方案3】:
Procedure StrLstYazdir(pYazilacakListe: TStringList; pYazici: String);
var
  hPrn: THandle;
  yazilacakVeri: AnsiString;
  intA: Integer;
begin
  hPrn := StartRawPrintJob(PChar(pYazici), '', 'Varakim');
  if (Integer(hPrn) < 0) then
  Begin
    ShowMessage('StartRawPrintJob Hatalı');
    Exit;
  End;

  if (StartRawPrintPage(hPrn) < 0) then
  Begin
    ShowMessage('StartRawPrintPage Hatalı');
    EndRawPrintJob(hPrn);
    Exit;
  end;

  For intA := 0 to pYazilacakListe.Count - 1 do
  Begin
    yazilacakVeri := pYazilacakListe[intA] + #13 + #10;

    if (PrintRawData(hPrn, PAnsiChar(yazilacakVeri), Length(yazilacakVeri)) < 0)
    then
    begin
      ShowMessage('PrintRawData Hatalı');
      EndRawPrintPage(hPrn);
      EndRawPrintJob(hPrn);
      Exit;
    End;
  End;
  if (EndRawPrintPage(hPrn) < 0) then
  begin
    ShowMessage('EndRawPrintPage Hatalı');
    EndRawPrintJob(hPrn);
    Exit;
  End;

  if (EndRawPrintJob(hPrn) < 0) then
  begin
    ShowMessage('EndRawPrintJob Hatalı');
    Exit;
  End;
End;

用法:

StrLstYazdir(Memo1.Lines ,'Lexmark Forms Printer 2491')

【讨论】:

  • 虽然这段代码可以解决问题,但几句话的解释将对当前和未来的读者有很大帮助。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2019-01-27
  • 2016-04-28
  • 2014-08-15
  • 1970-01-01
  • 2020-04-04
  • 2011-02-19
相关资源
最近更新 更多