Delphi XE5 で Canon ケーブルIDプリンター MK2500 を使う
一応プリンターなので、Delphi からでも使えます。が、あまり使い勝手が良いとは言えません。
本体の編集文字や設定とはまったく別に動くことが、何かのメリットになるのかも。(^^;
(製品に同梱されているツールの使い勝手も、お世辞にも良いとは言えません)
MK2500 本体の編集窓部分に、文字列を転送するのではなく、プリンターとしてラベル、チューブ... に描画する使い方になります。
フォントは、MK2500 のフォントではなく、Windows のフォントになります。
※プリンタ情報の取得、設定については、Mr.Xray さんのサイトを参考にさせていただきました。m(_"_)m
エクセルからのコピーペーストを想定して、一行の文字列中にタブがあれば、2行で印字するようにしています。
今のところ、連番には未対応 ... です。

カット長(用紙長)の設定がサポートされていないようなので、プロパティウィンドウを表示させて、その部分を別スレッドから無理やり書き換えています。
なので、一瞬、プロパティウィンドウが表示されます。

unit mk2500Unit2;
interface
uses
Winapi.Windows, Winapi.Messages, System.SysUtils, System.Variants, System.Classes, Vcl.Graphics,
Vcl.Controls, Vcl.Forms, Vcl.Dialogs, Printers, Vcl.StdCtrls,WinSpool,
Vcl.ExtCtrls;
type
TForm2 = class(TForm)
Memo1: TMemo;
ComboBox2: TComboBox;
Label1: TLabel;
Edit1: TEdit;
Button3: TButton;
Edit2: TEdit;
Label2: TLabel;
procedure FormCreate(Sender: TObject);
procedure Button3Click(Sender: TObject);
private
{ Private 宣言 }
public
{ Public 宣言 }
end;
var
Form2: TForm2;
implementation
{$R *.dfm}
uses mk2500Unit3;
procedure TabTextToSL(const atext: string; sl: TStrings);
var
n : integer;
s : string;
begin
sl.Clear;
s := atext;
n := Pos(#09, s);
while n > 0 do begin
sl.Add(Copy(s, 1, n - 1));
Delete(s, 1, n);
n := Pos(#09, s);
end;
if Trim(s) <> '' then sl.Add(s);
end;
procedure TForm2.Button3Click(Sender: TObject);
var
ADevice : array [0..255] of Char;
ADriver : array [0..255] of Char;
APort : array [0..255] of Char;
pDevMode : PDeviceModeW;
PaperLength : SmallInt;
PaperSize : SmallInt;
ADeviceMode: THandle;
hPrinter : THandle;
Mode : Cardinal;
ret : integer;
i : integer;
ytop, xleft, txtH : integer;
sl : TStringList;
begin
ret := 0;
PaperLength := Trunc(StrToFloatDef(Edit1.Text, 0) * 10);
with ComboBox2 do begin
if ItemIndex >= 0 then
PaperSize := SmallInt(Items.Objects[ItemIndex])
else
PaperSize := 0;
end;
if (PaperLength > 0) and (PaperSize > 0) then begin
// プリンターを MK2500 に
Printer.PrinterIndex := Printer.Printers.IndexOf('MK2500');
hPrinter := 0;
// 現在のプリンタに関する情報を取り出す
Printer.GetPrinter(ADevice, ADriver, APort, ADeviceMode);
// 初期化
Printer.SetPrinter(ADevice, ADriver, APort, 0);
// 対象のプリンタ情報
Printer.GetPrinter(ADevice, ADriver, APort, ADeviceMode);
if (ADeviceMode > 0) then begin
// プリンタ情報のアドレスを取得
pDevMode := GlobalLock(ADeviceMode);
try
// 対象のプリンタのハンドルを取得
if OpenPrinter(ADevice, hPrinter, nil) then begin
try
// カット長の設定のためにスレッド生成
Tmk2500edit.Create(Edit1.Text);
if (pDevMode^.dmFields and DM_PAPERSIZE) <> 0 then
pDevMode^.dmPaperSize := PaperSize;
// ※PAPERLENGTH はサポートされていない
if (pDevMode^.dmFields and DM_PAPERLENGTH) <> 0 then
pDevMode^.dmPaperLength := PaperLength;
if (pDevMode^.dmFields and DM_COPIES) <> 0 then
pDevMode^.dmCopies := 1;
Mode := DM_IN_PROMPT or DM_OUT_BUFFER or DM_IN_BUFFER;
// MK2500 のプロパティダイアログを表示
// 別スレッドから自動で閉じられる
ret := DocumentProperties(Handle, hPrinter, ADevice, pDevMode^, pDevMode^, Mode);
finally
// プリンターを閉じる
ClosePrinter(hPrinter);
end;
end;
finally
// ロック解除
GlobalUnLock(ADeviceMode);
end;
// 設定を反映
Printer.SetPrinter(ADevice, ADriver, APort, ADeviceMode);
end;
if ret = 1 then begin
with Printer do begin
// Canvas.Font.Name := 'MS ゴシック';
Canvas.Font.Size := 10;
txtH := Canvas.TextHeight('A');
sl := TStringList.Create;
try
// 転送開始
BeginDoc;
for i := 0 to Memo1.Lines.Count - 1 do begin
if i > 0 then NewPage;
TabTextToSL(Memo1.Lines[i], sl);
if sl.Count = 1 then begin
// センタリングのための開始 Y 座標
ytop := (PageHeight - txtH) div 2;
// センタリングのための開始 X 座標
xleft := (PageWidth - Canvas.TextWidth(sl[0])) div 2;
if xleft < 0 then xleft := 0;
// 文字列描画
Canvas.TextOut(xleft, ytop, sl[0]);
end
else if sl.Count >= 2 then begin
// 2行印字
ytop := PageHeight div 2 - txtH + 2;
xleft := (PageWidth - Canvas.TextWidth(sl[0])) div 2;
if xleft < 0 then xleft := 0;
Canvas.TextOut(xleft, ytop, sl[0]);
ytop := PageHeight div 2 - 2;
xleft := (PageWidth - Canvas.TextWidth(sl[1])) div 2;
if xleft < 0 then xleft := 0;
Canvas.TextOut(xleft, ytop, sl[1]);
end;
end;
EndDoc;
finally
sl.Free;
end;
end;
end;
end;
end;
procedure TForm2.FormCreate(Sender: TObject);
var
ADevice : array [0..255] of Char;
ADriver : array [0..255] of Char;
APort : array [0..255] of Char;
ADeviceMode : THandle;
Count : Integer;
// 動的配列
PaperNames : array of array [0..63] of Char;
PaperNumbers : array of WORD;
i : integer;
s : string;
begin
// 現在のプリンタを MK2500 にする
Printer.PrinterIndex := Printer.Printers.IndexOf('MK2500');
// 現在のプリンタに関する情報を取り出す
Printer.GetPrinter(ADevice, ADriver, APort, ADeviceMode);
// そのプリンタ 用紙名の数を取得
Count := DeviceCapabilities(ADevice, APort, DC_PAPERNAMES, nil, nil);
// その分だけ用紙名配列の長さと用紙番号の配列の長さを確保
SetLength(PaperNames, Count);
SetLength(PaperNumbers, Count);
// その配列に用紙名と用紙番号を取得
DeviceCapabilities(ADevice, APort, DC_PAPERNAMES, PChar(PaperNames), nil);
DeviceCapabilities(ADevice, APort, DC_PAPERS, Pointer(PaperNumbers), nil);
// 用紙名をコンボボックスに追加
if Count > 0 then begin
for i := 0 to Count - 1 do begin
s := String(PaperNames[i]);
if s <> '' then
//用紙名と用紙番号を格納
ComboBox2.Items.AddObject(s, TObject(PaperNumbers[i]));
end;
ComboBox2.ItemIndex := 1;
end;
end;
end.
// スレッド部分
unit mk2500Unit3;
interface
uses
System.Classes,Winapi.Windows, Winapi.Messages, System.SysUtils;
type
Tmk2500edit = class(TThread)
private
{ Private 宣言 }
sLen : string;
protected
procedure Execute; override;
public
constructor Create(PaperLength : string);
end;
implementation
uses mk2500Unit2;
var
// mk2500 長さ設定のエディットウィンドウ
mkedHwnd: Hwnd;
constructor Tmk2500edit.Create(PaperLength : string);
begin
// カット長
sLen := PaperLength;
// 生成と同時にスレッドを実行
inherited Create(False);
FreeOnTerminate := True;
end;
{ Tmk2500edit }
// プロパティウィンドウの長さ設定の Edit ウィンドウを探す
// 最初に見つかったクラス名'Edit'で終了
function EnumWindowProcEditWin(h: HWND; lp: LPARAM):Bool; stdcall;
var
ClassName : array [0..255] of Char;
begin
Result := True;
//クラス名を取得
GetClassName(h, ClassName, 255);
if Classname = 'Edit' then begin
mkedHwnd := h;
Result := False;
end;
end;
procedure Tmk2500edit.Execute;
var
hmk : HWND;
s : string;
i : integer;
begin
while not Terminated do begin
Sleep(100);
// プロパティ設定ダイアログを探す
hmk := FindWindow(nil, 'MK2500のプロパティ');
if hmk <> 0 then begin
// オーナーが Form2 であれば
if GetWindow(hmk, GW_OWNER) = Form2.Handle then begin
// ウィンドウが完成するまで待つ (必須)
Sleep(100);
// 子ウィンドウを探す
EnumChildWindows(hmk, @EnumWindowProcEditWin, 0);
if IsWindow(mkedHwnd) then begin
s := 'A' + sLen;
//文字の送信
for i := 1 to Length(s) do
//1文字送る
SendMessage(mkedHwnd, WM_CHAR, Word(s[i]), 0);
// アクティブに
SetForegroundWindow(hmk);
// ちらっと見せる
Sleep(100);
//[Enter]キーを離す
keybd_event(VK_RETURN, 0, 0, 0);
//[Enter]キーを離す
keybd_event(VK_RETURN, 0, KEYEVENTF_KEYUP, 0);
// keybd_event(VK_ESCAPE, 0, 0, 0);
// keybd_event(VK_ESCAPE, 0, KEYEVENTF_KEYUP, 0);
end;
// スレッド終了
break;
end;
end;
end;
end;
end.