Printers.pasのBeginDoc関数を変更したい

解決


zzdel5w301  2012-12-22 02:15:30  No: 43521

こんにちは

TPrinterのBeginDoc関数のDocInfoなのですが、
ここにlpszOutputを指定したく次のように修正したPrinters.pasを
アプリのソースフォルダに保存しました。

procedure TPrinter.BeginDocEx(APath: String);

  with DocInfo do
  begin
    cbSize := SizeOf(DocInfo);
    lpszDocName := PChar(Title);
    lpszOutput  := PChar(APath);  // ここはオリジナルソースには無い
  end;

この状態でコンパイルすると「Formsは異なるバージョンによりコンパイルされています」
というコンパイルエラーが発生します。

これは他のコンポーネントがPrinters.pasを参照している為に発生するのでしょうか?

この場合、Program Files\Borland\Delphi5\Lib  内のdcuを全削除して再構築すればよいのでしょうか?
dcuの削除は不安なので試していません。

できることならPrinters.pasを直接修正するような事は避けたいので
他にDocInfo.lpszOutputをセットする方法があるなら教えていただけないでしょうか?

よろしくお願いいたします。


Mr.XRAY  2012-12-22 04:48:35  No: 43522

こんにちは,

>できることならPrinters.pasを直接修正するような事は避けたいので

これは,一般論ですが,Delphi では,あるクラスに機能を追加したり,変更するには,
そのクラスを継承したクラス (コンポーネント) を作成します.
そのために,「継承」という概念があるとも言えます.

  TMyMemo = class(TMemo)
  end;
  
というのは,TMemo というクラスを継承したクラスです.
Delphi では,慣習的に,クラス名の先頭には T を付けているようです.
同じ名前のクラス名は,原則的に,同時使用はできません.  

また,レコード型 (構造体) も同じです.
既にあるレコード型に,勝手にメンバーを追加することはできません.
(比較的新しい Delphi では,少し意味は違いますが,方法があります)

解決策ということではありませんが,参考になれば.


Mr.XRAY  2012-12-22 04:57:20  No: 43523

>既にあるレコード型に,勝手にメンバーを追加することはできません.

そのレコード型を,別のクラス,プログラム等で使用していたとすると,
問題が発生する可能性があります.


KHE00221  2012-12-22 10:47:37  No: 43524

Printers.pas の名前を変えてしまえ


Mr.XRAY  2012-12-22 11:00:06  No: 43525

>LPrinters.pas の名前を変えてしまえ

おおっ !! グッドアイディア !


zzdel5w301  2012-12-22 14:03:55  No: 43526

Mr.XRAYさん、KHE00221さん、ありがとうございます。

実は、当初はPrintersEx.pasとして作成していました。

その状態で印刷処理自体は正常に動いていましたが
TPrinterDialogもPrinters.pasを参照しているようで
プリンタ設定が正しく行えませんでした。


おかぽん  2012-12-22 17:32:16  No: 43527

TPrinterから継承してTPrinterExを作成
TPrinterEx=class(TPrinter)
  procedure BeginDocEx(APath: String);
end;

自分でTPrinterExのインスタンスを作成し、SetPrinter関数(Printers.pas)により、
ユニットで保持するインスタンスの差し替え。
SetPrinterの結果は、Create済みのTPrinterインスタンスが返ってくるので
nil でなければFreeする。

あとは、TPrinterEx(Printer)のようにキャストするだけで使える・・・
と、思ったりしますが、いかがなものでしょう?


KHE00221  2012-12-22 19:59:22  No: 43528

var
    SavePrinter: TPrinter;
begin
    SavePrinter := Vcl.Printers.SetPrinter(TPrinter(PrintersEx.Printer));
    PrintersEx.Printer.Copies := 20;  //確認用
    if PrintDialog1.Execute = True then
    begin

    end;
    Vcl.Printers.SetPrinter(SavePrinter);

Freeにすると終了後にプロセス残って RunTimeError が起こる

Win7 XE2 だけど


zzdel5w301  2012-12-25 17:49:03  No: 43529

おかぽんさん、KHE00221さん

教えていただいた方法で試してみます。

ありがとうございました。


zzdel5w301  2013-01-08 19:11:59  No: 43530

こんにちは

KHE00221 さんに教えていただいたコードでテストを進めていたのですが
思うように動作しないので再度質問させてください。

プリンタダイアログで変更した内容がPrinters.Printerには反映されるのですが
PrintersEx.Printerから参照するとに反映されていない状態になります。

具体的には、ダイアログでCopiesを10に変更して
PrintersEx.Printer.Copiesを確認すると20のままで
Printers.Printer.Copiesを確認すると10になっていました。

Setprinterが正しく行えていないのかと思いPrintersEx.Printerと
Printers.Printerのアドレスを確認しましたが同じものを指していました。

PrintersEx.pasはPrinters.pasをリネームし、usesにPrintersを追加して
  TPrinterEx = class(TPrinter)
としています。TPrinterExの作成方法が問題なのでしょうか?

よろしくお願いいたします。


KHE00221  2013-01-08 19:56:12  No: 43531

uses
  Winapi.Windows, Winapi.Messages, System.SysUtils, System.Variants, System.Classes, Vcl.Graphics,
  Vcl.Controls, Vcl.Forms,   PrintersEx, Printers, Vcl.StdCtrls, Vcl.Dialogs;

procedure TForm1.Button1Click(Sender: TObject);
var
    SavePrinter: TPrinter;
begin
    SavePrinter := Vcl.Printers.SetPrinter(TPrinter(PrintersEx.Printer));
    PrintersEx.Printer.Copies := 20;  //確認用
    if PrintDialog1.Execute = True then
    begin

    end;
    Memo1.Lines.Add(IntToStr(Printer.Copies));                 //変更した数になる
    Memo1.Lines.Add(IntToStr(PrintersEx.Printer.Copies));      //変更した数になる
    Vcl.Printers.SetPrinter(SavePrinter);
    Memo1.Lines.Add(IntToStr(Printer.Copies));                 //1のまま
    Memo1.Lines.Add(IntToStr(PrintersEx.Printer.Copies));      //変更した数になる
end;


zzdel5w301  2013-01-08 23:12:04  No: 43532

KHE00221 さん、ありがとうございます。

プリンタダイアログでCopiesを10に変更した結果
--------------
10
20
1
20
--------------
となり、PrintersEx.Printerには反映されません。
ソースもコピペさせていただいたので全く同じはずなのですが・・・
異なる可能性があるのは、PrintersEx.pasでしょうか。

DelphiはDelphi5を使用しています。
他にDelphi7とDelphi2007がありますので、Delphi2007でテストしてみます。


KHE00221  2013-01-09 10:09:29  No: 43533

var
    SavePrinter: Printers.TPrinter;
begin
    SavePrinter := Printers.SetPrinter(Printers.TPrinter(PrintersEx.Printer));
    PrintersEx.Printer.Copies := 20;  //確認用
    if Pointer(Printers.Printer) = Pointer(PrintersEx.Printer) then Memo1.Lines.Add('同じ1');
    if PrintDialog1.Execute = True then
    begin

    end;
    if Pointer(Printers.Printer) = Pointer(PrintersEx.Printer) then Memo1.Lines.Add('同じ2');
    Memo1.Lines.Add(IntToStr(Printers.Printer.Copies));        //変更した数になる
    Memo1.Lines.Add(IntToStr(PrintersEx.Printer.Copies));      //変更した数になる
    Printers.SetPrinter(SavePrinter);
    Memo1.Lines.Add(IntToStr(Printers.Printer.Copies));        //1のまま
    Memo1.Lines.Add(IntToStr(PrintersEx.Printer.Copies));      //変更した数になる

同じ1
同じ2

表示される?


zzdel5w301  2013-01-09 21:25:45  No: 43534

>表示される?

はい、表示されます。

プリンタダイアログでCopiesを10に変更した結果
---------------
同じ1
同じ2
10
20
1
20
---------------

アドレスが異なっていればわかるのですが、
同じアドレスなのに値が異なるという状態です。

環境はVistaにDelphi2007です。
関係ないとは思いますが、Delphi20xxとXExでは動作が違う可能性も?
XE3体験版をインストールしてテストしてみます。


zzdel5w301  2013-01-17 01:47:54  No: 43535

報告が遅くなり申し訳ありません。

XE3体験版をインストールしてみましたが、
DCUしか付属しておらずテストすることができませんでした。

その後、いろいろ試してみましたがうまくいかず
最終的には次のような処理となりました。

BeginDocExが必要な場合のみPrintersExを使用し、
その際にPrinters.Printerの内容をPrintersEx.Printerへ複写する。

力技っぽい結果となりましたが、いろいろ勉強になりました。
ありがとうございました。


※返信する前に利用規約をご確認ください。

※Google reCAPTCHA認証からCloudflare Turnstile認証へ変更しました。






  このエントリーをはてなブックマークに追加