喫茶XRAYトップページ

[スレッド全体
]

[12120] Re6:PDFの表示終了時のエラー返信 削除
2018/8/4 (土) 12:21:27 福士
ちなみにフォームのOnCreateではなくOnShowで処理をしても同じですか?
COM/ActiveXの類いやシェルコントロールはOnCreateだとタイミング的に
早すぎて問題があった気がするので…

[12121] Re7:PDFの表示終了時のエラー返信 削除
2018/8/4 (土) 15:14:54 mountain079
▼ 福士さん
> ちなみにフォームのOnCreateではなくOnShowで処理をしても同じですか?
> COM/ActiveXの類いやシェルコントロールはOnCreateだとタイミング的に
> 早すぎて問題があった気がするので…


私の説明が間違っておりまして、正しくはFormShowでした。

新規VCLフォームアプリケーションを作成し、
1つのフォームのOnShowにソースを書いています。

OnClose等他のソースは1行も書いておらず、、、

色々と探し回った結果、Excel VBAでもsrc以外のプロパティを変更すると、異常終了するそうです。。

Adobeに振り回されてばかり笑

すくなくともAdobeReader\までは使用できていたので、とりあえずtWebBrowserでしのげればなぁと・

ただし、tWebBrowserはやはり遅いですが。。

[12122] Re8:PDFの表示終了時のエラー返信 削除
2018/8/5 (日) 01:00:23 taka
OnCloseQueryイベントでプロパティを変更して接続を断てばいいのでは?

試してないので知りませんけどね

[12123] Re9:PDFの表示終了時のエラー返信 削除
2018/8/5 (日) 11:41:31 Mr.XRAY
> OnCloseQueryイベントでプロパティを変更して接続を断てばいいのでは?

プロパティの内容にもよるかも知れませんが,確認はできそうな..

福士さんが OnShow のことを書いていたので,もしかしたら,
と思ったら OnShow イベントだったんですね (^^);

アプリはバージョン UP で機能が増え,その分他のプログラムからの操作
は面倒になってきているようです.
Excel の VBA でも同様の現象が発生するのもそういったことかも知れません.

他のアプリを操作する場合,そのアプリの操作対象のオブジェクトの生成完了を
確実に検出してから操作しないと,いろいろトラブルの元になりますね.
この生成完了を検出するのは結構難しいです.
例えば Delphi の IDE なんかは 450 以上のウィンドウを生成しますが,
その生成順序は必ずしも同じではありません.
Excel も CBT フックをしてウィンドウの生成を観察するとやはり生成順序は
常に同じではないです.

ともかく,他のアプリの操作は難しいです.ハイ.
Windows XP あたりまではそこそこ操作ができたようですが.


[12124] Re10:PDFの表示終了時のエラー返信 削除
2018/8/5 (日) 11:56:20 Mr.XRAY
> ともかく,他のアプリの操作は難しいです.ハイ.

最終的な手段はフックかも知れません.
相手が他のアプリなのでローカルフックでは補足できる可能性は低いです.

[03_位置とサイズを指定してアプリを起動 - WH_CBT フック使用]
http://mrxray.on.coocan.jp/Delphi/plSamples/266_App_CreateOpen.htm#03

グローバルフック,これもまた難しい ... (^^;


[12127] Re11:PDFの表示終了時のエラー返信 削除
2018/8/7 (火) 23:30:28 taka
▼ Mr.XRAYさん
> > ともかく,他のアプリの操作は難しいです.ハイ.
>
> 最終的な手段はフックかも知れません.
> 相手が他のアプリなのでローカルフックでは補足できる可能性は低いです.
>
> [03_位置とサイズを指定してアプリを起動 - WH_CBT フック使用]
> http://mrxray.on.coocan.jp/Delphi/plSamples/266_App_CreateOpen.htm#03
>
> グローバルフック,これもまた難しい ... (^^;


http://mrxray.on.coocan.jp/Delphi/plSamples/720_Acrobat.htm
を参考にしてインポート後 試してみました。

なにか呼び出して、AcroPDF1の接続が確立してから
アプリを終了すると終了時にアクセス違反が発生するようです。

procedure TForm1.Button1Click(Sender: TObject);
  var info : string;
begin
  info := AcroPDF1.GetVersions();
  MessageBox(Handle, PWideChar(info), '情報', 0);
end;

を実行後にアプリを終了しても アクセス違反になります

一度違反が発生したら、2回目はないようなので
終了前に手動でコンポーネントを破棄してしまえばいいのかもしれないです。
// try except でエラーを破棄する

procedure TForm1.FormCloseQuery(Sender: TObject; var CanClose: Boolean);
begin
  CanClose := True;
  if Assigned(AcroPDF1) then
  try
    FreeAndNil(AcroPDF1);
  except
    AcroPDF1 := nil;
  end;
end;

 ---------------------------------------------

デバッガで実行して、このコードで故意に落とすと
procedure TForm1.ButtonDebugClick(Sender: TObject);
begin
  if Not Assigned(AcroPDF1) then
    Exit;
  AcroPDF1.GetVersions();
  FreeAndNil(AcroPDF1); // ここにブレークポイントを設置する
  // Buttonをクリックし、停止したらトレース実行する
  // system::_IntfClear で落ちる
end;

system: _IntfClear
の IInterface._Releaseの次の行で落ちているのがわかりました。
内容は、PUREPASCALの部分のコードなんでしょうけど
アセンブラで書かれているのでわかりません。

落ちている前後を
Delphi10.2とDelphi2005と比べるとコードはほぼ同じですので、
気が向いたら Delphi2005で同じエラーが発生するか確認してみようと思います


[12128] Re12:PDFの表示終了時のエラー返信 削除
2018/8/8 (水) 06:27:53 Mr.XRAY
▼ takaさん,お手数おかけします.スミマセン.
やっと重い腰を上げました (^^;

Windows 7 U64(SP1) + Delphi XE(UP1) Pro + Adobe Reader DC
でテストしました.
テストしたのは以下のサンプルです.
IDE でコンパイルして実行.PDF 文書を表示するだけでフォームを閉じると
EXE 終了時に例外が発生しました.
PDF 文書を表示しなければ例外は発生しませんでした.

[02_PDF 文書のフォームへの表示]
http://mrxray.on.coocan.jp/Delphi/plSamples/720_Acrobat.htm#02

taka さんの OnloseQuery コードを追加して実行してみました.
例外は発生しなくなりましたが,メモリリークが発生しました.
で,Delphi XE5(UP2) Pro で同じように実行してみました.
今度は例外も発生しました.

ん ? AcroPDF1.free が操作できない ? メモリリーク ?

  TAcroPDF = class(TOleControl)
  TOleControl = class(TWinControl, IUnknown, IOleClientSite,....

となっています.ああぁ〜 ! もしかして...
で思い出しました.昔同じ様な現象を経験したことがあります.
以下のサンプルです.参照カウンタです.

[コンポーネント TplExplorerFolderView のソースコード]
http://mrxray.on.coocan.jp/Delphi/plSamples/947_ExplorerBrowser.htm#list5

てなわけで以下のようにしてみてください.

procedure TForm1.FormCloseQuery(Sender: TObject; var CanClose: Boolean);
begin
  //TAcroPDF の参照カウンタがインクリメントされていないようなので
  //解放破棄操作される前に AddRef しておく
  AcroPDF1.ControlInterface._AddRef;
end;



[12129] Re13:PDFの表示終了時のエラー返信 削除
2018/8/8 (水) 06:28:19 Mr.XRAY
>てなわけで以下のようにしてみてください.
>
>procedure TForm1.FormCloseQuery(Sender: TObject; var CanClose: Boolean);
>begin
>  AcroPDF1.ControlInterface._AddRef;
>end;


これをいちいち書くのは面倒なので,修正した AcroPDFLib_TLB.pas を UP しました.
EXE も再生成しました.
mountain079 さんが OnShow で操作しているというので確認しました.
一応動作確認コードを掲載しておきます.
Windows 7 U64(SP1) + Delphi XE5(UP2) Pro + Adobe Reader DC です.

procedure TForm1.FormCreate(Sender: TObject);
var
  LPdfFilePath : string;
begin
  LPdfFilePath := ExpandFileName('..\TestAcro.pdf');
  AcroPDF1.src := LPdfFilePath;
end;

procedure TForm1.FormShow(Sender: TObject);
begin
  AcroPDF1.setView('fitv');
end;


[12131] Re13:PDFの表示終了時のエラー返信 削除
2018/8/8 (水) 06:56:33 Mr.XRAY
> procedure TForm1.FormCloseQuery(Sender: TObject; var CanClose: Boolean);
> begin
>   //TAcroPDF の参照カウンタがインクリメントされていないようなので
>   //解放破棄操作される前に AddRef しておく
>   AcroPDF1.ControlInterface._AddRef;
> end;


これ本当はマズイですね.
参照カウンタを確認しないと.えっと,どうするんでしたっけ.
DEKO さんとこに記事があったような...


[12132] Re13:PDFの表示終了時のエラー返信 削除
2018/8/8 (水) 12:07:47 Mr.XRAY
> テストしたのは以下のサンプルです.
> IDE でコンパイルして実行.PDF 文書を表示するだけでフォームを閉じると
> EXE 終了時に例外が発生しました.
> PDF 文書を表示しなければ例外は発生しませんでした.


こういう質問だったらすぐ取り掛かったんですけどね (笑)
掲載しているサンプルコードを参考にしていろいろやっているということでしたので,
その「いろいろ」な部分が問題なのかな ? と思っていましたから.

過去の経験から,
「掲載しているサンプルではそういう現象は発生しませんでした」
とレスすると,
「他にコードを追加したり変更しています..」
となってしまうことが多いので.

まっ,言い訳ですけど (^^;
taka さんのテストがなければ放置だったかも知れません.
問題点をテストしてくださった taka さんに感謝です.


[12133] Re14:PDFの表示終了時のエラー返信 削除
2018/8/8 (水) 12:23:57 taka
▼ Mr.XRAYさん
> > テストしたのは以下のサンプルです.
> > IDE でコンパイルして実行.PDF 文書を表示するだけでフォームを閉じると
> > EXE 終了時に例外が発生しました.
> > PDF 文書を表示しなければ例外は発生しませんでした.
>
> こういう質問だったらすぐ取り掛かったんですけどね (笑)
> 掲載しているサンプルコードを参考にしていろいろやっているということでしたので,
> その「いろいろ」な部分が問題なのかな ? と思っていましたから.
>
> 過去の経験から,
> 「掲載しているサンプルではそういう現象は発生しませんでした」
> とレスすると,
> 「他にコードを追加したり変更しています..」
> となってしまうことが多いので.
>
> まっ,言い訳ですけど (^^;
> taka さんのテストがなければ放置だったかも知れません.
> 問題点をテストしてくださった taka さんに感謝です.

やっぱり参照カウンタの不具合でしたか。
Delphi2005でも再現しました。

修正コードみました。
Delphiのインポートツールのバグなんですね。

[12134] Re15:PDFの表示終了時のエラー返信 削除
2018/8/8 (水) 22:58:49 Mr.XRAY
▼ takaさん,どうもです.

taka さんの

procedure TForm1.FormCloseQuery(Sender: TObject; var CanClose: Boolean);
begin
  CanClose := True;
  if Assigned(AcroPDF1) then
  try
    FreeAndNil(AcroPDF1);
  except
    AcroPDF1 := nil;
  end;
end;

のコードがなかったら気が付かなかったでしょうね.
やはりプログラムというのはコードを書いて,それが実行されるわけですから,
具体的なコードがあるというのは強力です.
コードがなければ抽象的な話になってしまいますから.

> 修正コードみました。
> Delphiのインポートツールのバグなんですね。


ある意味ではやむを得ないということもあるかも知れません.
操作対象の COM オブジェクトはパーションによって機能が変わってきますから.
で,修正コードについて書いていませんでした.AcroPDFLib_TLB.pas にある

  TAcroPDF = class(TOleControl)
  private
    FIntf: IAcroAXDocShim;
    function  GetControlInterface: IAcroAXDocShim;

の FIntf が TAcroPDF のコンテナの実体ですので,destructor を override
して以下のように強制的に nil にしました.
この nil も AcroPDF1 := nil; がヒントです (^^;

destructor TAcroPDF.Destroy;
begin
  FIntf := nil;
  inherited;
end;


[12153] Re16:PDFの表示終了時のエラー返信 削除
2018/8/16 (木) 11:25:32 mountain079
▼ Mr.XRAYさん▼ takaさん

返信遅れて申し訳ございません。


色々と試していただき、誠にありがとうございます。

今回は急ぎの対応でしたので、tWebBrowserでしのぎましたが、
原因も追究していただけたようで、今後は再度AcroPDFでの作成を行っていきたいと思います。


私も皆様のお役に立てるよう、日々勉強に励みます。

本当にお世話になりました。

[▼次のスレッド]
INCM/CMT
Cyclamen v3.82