0

TWebBrowser コンポーネントを含むフォームをポップアップする Delphi XE2 で DLL を作成しようとしています。WebBrowser.Navigate2 メソッドが呼び出されると、アプリケーションの終了時にユニット (または任意のユニット) のファイナライズ セクションは呼び出されません。Navigate2 が呼び出されない場合、ファイナライズ セクションは問題なく実行されます。

dll は C++ (現時点では VS 2010 MFC コンソール) から呼び出され、インポート ライブラリでリンクされています。

他にも方法はありますが、すでに書いたコードを再利用したいと思います。

何が起こっているのか誰にも分かりませんか?

ありがとう。

以下は、問題を簡単に再現したものです。

library DisplayPatientAlertsIntf;
exports DisplayPatientAlertsA name 'DisplayPatientAlertsA@4';

begin
end.

unit uAlertWindow;

interface

uses
  Winapi.ActiveX,
  Forms,
  SHDocVw,
  Graphics, Controls;

function DisplayPatientAlertsA(PatientID : PAnsiChar): Integer; export; stdcall;

implementation

var ts : TStringList;

function DisplayPatientAlertsA(PatientID : PAnsiChar): Integer; export; stdcall;
  var Form1 : TForm;
      WebBrowser1 : TWebBrowser;
      DidCoInit : Boolean;
begin
  DidCoInit := Succeeded(CoInitialize(nil));
  try
    Form1 := TForm.Create(nil);
    try
      WebBrowser1 := TWebBrowser.Create(nil);
      try
        WebBrowser1.ParentWindow := Form1.Handle;
        WebBrowser1.Align := alClient;
        WebBrowser1.Navigate2('file://c:\temp.html');
        Form1.ShowModal;
      finally
        WebBrowser1.Free;
      end;
    finally
      Form1.Free;
    end;
  finally
    if DidCoInit then
      CoUninitialize;
  end;
  Result := 0;
end;

initialization
  ts := TStringList.Create;

finalization
  ts.Free;

end.

更新 2013.03.19 別の問題 (dll 内の dbExpress ドライバー) を解決しているときに、インポート ライブラリを使用して静的にリンクされた dll から動的に読み込まれた dll に変更すると、すべてが機能し始めました。

4

3 に答える 3

0

DelphiはプレーンDLLを多用せず、そのサポートは基本的であり、ほとんど文書化されていません

DelphiはEXEファイルに対して適切に機能し、WinMainをインターセプトし、そのセマンティクスをTurbo Pascalスタイルのコンテキストにもたらしますが、DLLの場合は手動で行う必要があります。

DLL-メインのMicrosoftドキュメントとチュートリアルを読むことから始めます。

次に、あなたはあなたのDLL.dprようなものに追加することができます

begin
  DLLProc := @DLLMain;
  DLLMain(DLL_PROCESS_ATTACH);
end.

そして、DLLのいくつかのユニットでは、次のように実装できます。

procedure DLLMain(dwReason: DWORD);
begin
  case dwReason of
  DLL_PROCESS_ATTACH:
    begin
      Application.HelpFile := HelpFileName;
      dmSelVars := TdmSelVars.Create(nil);
    end {= DLL_PROCESS_ATTACH =};

  DLL_PROCESS_DETACH:
    begin
      Application.Handle := 0;
      FreeAndNil(dmSelVars);
      g_pSvRec := nil;
    end {= DLL_PROCESS_DETACH =};
  end {= case =};
end {= DLLMain =};

PS。代わりにDelphiネイティブ(1997年以降)のBPLを使用できるのに、なぜDLLを使用するのですか?それは多くの問題を解決し、はるかに優れたファイナライズサポートを提供します。

  • 手動でロードされたパッケージの場合(LoadPackage(...)呼び出しを介して)、許可されたすべてのユニットに対して呼び出されたファイナライズ
  • (リストを介して)手動でロードされたパッケージのProject Options / Packages / Link with Runtime packages場合、ファイナライズはすべてのユニットに対して呼び出され、ホストEXEの「使用」セクションで参照されます。

PPS。1ページを表示するだけでMSIEを起動する-やり過ぎに見えませんか?多少制限されていても、おそらくネイティブHTMLサポートで十分でしょうか?また、TStreamから、またはString中間の一時ファイルをいじくり回さずにページをロードすることができます。(まあ、MSIEは、いくつかの足場の後でも同様に機能します)。

于 2013-03-19T06:06:57.203 に答える
0

ユニットの 1 つがファイナライズされているときに例外が発生し、他のユニットがファイナライズされないことがあります。

XE2 についてはよくわかりませんが、Delphi の古いバージョンは、ComObj ユニットが使用/初期化で「上位」にあることに非常にうるさい傾向があったため、ファイナライズする最後のユニットの 1 つになりました。
問題は、ComObj のファイナライズが早すぎると、CoUninitialize が早すぎて、COM が初期化されることをまだ期待している他のコードの下から実質的に引き裂かれることでした。

SHDocVw の XE2 バージョンがその実装セクションでまだ ComObj を使用している場合、ComObj は比較的「遅く」初期化されます。それはあなたの問題である可能性が非常に高いです。その場合、ソースの上位に明示的に追加するだけでうまくいくはずです。

于 2013-03-19T17:10:54.187 に答える