Delphi-PRAXiS

Delphi-PRAXiS (https://www.delphipraxis.net/forum.php)
-   Sonstige Fragen zu Delphi (https://www.delphipraxis.net/19-sonstige-fragen-zu-delphi/)
-   -   Delphi Fehler bei Aufruf eines TForms mit TWebbrowser aus DLL (https://www.delphipraxis.net/37472-fehler-bei-aufruf-eines-tforms-mit-twebbrowser-aus-dll.html)

MaBuSE 6. Jan 2005 11:05


Fehler bei Aufruf eines TForms mit TWebbrowser aus DLL
 
Hallo,

wenn ich eine Unit1.pas mit einem TWebBrowser (Standard Komponente aus Internetpallette) aus einer Applikation erzeuge klappt das ohne Probleme, aus einer DLL nicht.

Unit1.pas:
Delphi-Quellcode:
unit Unit1;

interface

uses
  Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms,
  Dialogs, OleCtrls, SHDocVw, StdCtrls;

type
  TForm1 = class(TForm)
    WebBrowser1: TWebBrowser;
  private
    { Private-Deklarationen }
  public
    { Public-Deklarationen }
  end;

var
  Form1: TForm1;

implementation

{$R *.dfm}

end.
Aus einer Unit2.pas (Hauptformular) kann das Form ohne Probleme erzeugt werden.
Delphi-Quellcode:
procedure TForm2.Button1Click(Sender: TObject);
begin
  Form1 := TForm1.Create(Application);
  try
    Form1.ShowModal;
  finally
    Form1.Free;
  end;
end;
Das klappt super !!!

Wenn ich nun eine DLL erzeuge:

Project1.dpr:
Delphi-Quellcode:
library Project1;

uses
  Forms,
  SysUtils,
  Classes,
  Unit1 in 'Unit1.pas' {Form1};

{$R *.res}

procedure showPdf;
begin
  Form1 := TForm1.Create(Application);
  try
    Form1.ShowModal;
  finally
    Form1.Free;
  end;
end;

procedure showPdfWithApp(App: TApplication);
var
  dllApp : TApplication;
begin
  dllApp := Application;
  Application := App;
  Form1 := TForm1.Create(App);
  try
    Form1.ShowModal;
  finally
    Form1.Free;
  end;
  Application := dllApp;
end;

exports
  showPdf, showPdfWithApp;

begin
end.
und dann in einem Projekt2.exe die Funktion aufrufe gibts einen Fehler:

Unit2.pas vom Project2.dpr:
Delphi-Quellcode:
unit Unit2;

interface

uses
  Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms,
  Dialogs, StdCtrls;

type
  TForm2 = class(TForm)
    Button1: TButton;
    Button2: TButton;
    procedure Button1Click(Sender: TObject);
    procedure Button2Click(Sender: TObject);
  private
    { Private-Deklarationen }
  public
    { Public-Deklarationen }
  end;

var
  Form2: TForm2;

implementation

{$R *.dfm}

procedure showPdf; external 'Project1.dll';
procedure showPdfWithApp(app: TApplication); external 'Project1.dll';

procedure TForm2.Button1Click(Sender: TObject);
begin
  showPdf;
end;

procedure TForm2.Button2Click(Sender: TObject);
begin
  showPdfWithApp(Application);
end;

end.
Die TWebBrowser Komponente wirft einen EOleSysError mit Meldung :
Zitat:

CoInitialize wurde nicht aufgerufen
Was ist zu tun.

Ich hatte erst den Verdacht, er will die Application der Anwendung haben, aber das half nichts.
(Bei MDI Fenstern aus der DLL war das so)

mirage228 6. Jan 2005 11:09

Re: Fehler bei Aufruf eines TForms mit TWebbrowser aus DLL
 
Hi,

dann ruf doch in der DLL einfach CoInitialize auf! ;)

(Das wird sonst im Application.Initialize erledigt, soweit ich weiss)

mfG
mirage228

MaBuSE 6. Jan 2005 13:07

Re: Fehler bei Aufruf eines TForms mit TWebbrowser aus DLL
 
Zitat:

Zitat von mirage228
dann ruf doch in der DLL einfach CoInitialize auf! ;)
(Das wird sonst im Application.Initialize erledigt, soweit ich weiss)

Das man auf die einfachen Dinge nicht selbst kommt :stupid:

Das ist zwar nicht die "ganze" Lösung, hat mich aber schon weiter gebracht.
Wenn's fertig ist, werde ich hier die Lösung posten.

Danke noch mal

MaBuSE 10. Jan 2005 10:23

Re: Fehler bei Aufruf eines TForms mit TWebbrowser aus DLL
 
Zitat:

Zitat von MaBuSE
Wenn's fertig ist, werde ich hier die Lösung posten.

Es funktioniert nun.

Die Komponente TWebBrowser verwendet eine Unit, die den InitProc-Pointer auf eine eigene Procedure setzt. Application.Initialize prüft ob der Zeiger gesetzt ist und ruft dann diese Procedure auf.
Delphi-Quellcode:
procedure TApplication.Initialize;
begin
  if InitProc <> nil then TProcedure(InitProc);
end;
Da in einer DLL dieser Zeiger nicht gesetzt wird, kommt es zu diesem Fehler.
Delphi-Quellcode:
if not IsLibrary then
begin
  SaveInitProc := InitProc;
  InitProc := @InitComObj;
end;
Dummerweise ist die Procedur InitComObj nur im implementation Teil der Unit definiert.
Sie lässt sich also nicht direkt aufrufen. Deshalb habe ich meiner Unit folgenden initialization Abschnitt hinzugefügt. (Sollte nur ein mal im Programmstehen.)


Folgenden Quelltext habe ich in die Unit1.pas aufgenommen:
Delphi-Quellcode:
...
// In ComObj wird der InitProc verbogen, aber nur wenn keine DLL :-(
// : if not IsLibrary then
// : begin
// :  SaveInitProc := InitProc;
// :  InitProc := @InitComObj;
// : end;
// Leider ist InitComObj nur lokal in der implementation definiert,
// deswegen hier dieses manuelle Init
var
  NeedToUninitialize: Boolean;

initialization
  //InitComObj;
  if (CoInitFlags <> -1) and Assigned(ComObj.CoInitializeEx) then
  begin
    NeedToUninitialize := Succeeded(ComObj.CoInitializeEx(nil, CoInitFlags));
    IsMultiThread := IsMultiThread or
      ((CoInitFlags and COINIT_APARTMENTTHREADED) <> 0) or
      (CoInitFlags = COINIT_MULTITHREADED); // this flag has value zero
  end
  else
    NeedToUninitialize := Succeeded(CoInitialize(nil));
  //--InitComObj

finalization
  if NeedToUninitialize then CoUninitialize;

end.


Alle Zeitangaben in WEZ +1. Es ist jetzt 21:40 Uhr.

Powered by vBulletin® Copyright ©2000 - 2024, Jelsoft Enterprises Ltd.
LinkBacks Enabled by vBSEO © 2011, Crawlability, Inc.
Delphi-PRAXiS (c) 2002 - 2023 by Daniel R. Wolf, 2024 by Thomas Breitkreuz