Autor Beitrag
Ares
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starontopic star
Beiträge: 128



BeitragVerfasst: Di 16.12.08 16:32 
Hallo!

ich mache gerade meine ersten Schritte mit COM und bin dabei auf ein paar Probleme gestoßen die ich bis jetzt leider nicht löschen konnte.

Worum geht's:
Ich will ein Programm (Server) durch ein anderes (Client) fernsteuern. Sofern der Server nicht bereits läuft soll der Client diesen starten. Vom Server soll immer höchstens eine Instanz aktiv sein.

Was habe ich gemacht:
Für den Server habe ich zunächst ein neues VCL-Form Projekt erstellt und auf das Form habe ich zwei TEdits gesetzt. Dann habe ich über Datei/Neu/Weitere.../ActiveX/ ein Automatisierungsobjekt (TCOMTester) für das Projekt erstellt. Das Interface enthält Getter und Setter für die Edit Texte und eine Methode mit der eine Nachricht angezeigt werden soll:

ausblenden Delphi-Quelltext
1:
2:
3:
4:
5:
6:
7:
8:
9:
10:
  ICOMTester = interface(IDispatch)
    ['{70419B55-8B32-434A-8023-BA303A150146}']
    function ShowTestMessage(const Text: WideString): WideString; stdcall;
    function Get_Edit1Text: WideString; safecall;
    procedure Set_Edit1Text(const Value: WideString); safecall;
    function Get_Edit2Text: WideString; safecall;
    procedure Set_Edit2Text(const Value: WideString); safecall;
    property Edit1Text: WideString read Get_Edit1Text write Set_Edit1Text;
    property Edit2Text: WideString read Get_Edit2Text write Set_Edit2Text;
  end;


ausblenden volle Höhe Delphi-Quelltext
1:
2:
3:
4:
5:
6:
7:
8:
9:
10:
11:
12:
13:
14:
15:
16:
17:
18:
19:
20:
21:
22:
23:
24:
25:
26:
27:
28:
29:
30:
31:
32:
33:
34:
35:
36:
37:
38:
39:
40:
41:
42:
43:
44:
type
  TCOMTester = class(TAutoObject, ICOMTester)
  protected
    function Get_Edit1Text: WideString; safecall;
    function Get_Edit2Text: WideString; safecall;
    function ShowTestMessage(const Text: WideString): WideString; stdcall;
    procedure Set_Edit1Text(const Value: WideString); safecall;
    procedure Set_Edit2Text(const Value: WideString); safecall;
  end;

implementation

uses ComServ, main {Für den Zugriff auf das Form}, Dialogs;

function TCOMTester.Get_Edit1Text: WideString;
begin
  result := Form1.Edit1.Text;
end;

function TCOMTester.Get_Edit2Text: WideString;
begin
  result := Form1.Edit2.Text;
end;

function TCOMTester.ShowTestMessage(const Text: WideString): WideString;
begin
  ShowMessage(Text);
  result := 'Es wurde eine Nachricht mit folgendem Text angezeigt'+#13#13+Text;
end;

procedure TCOMTester.Set_Edit1Text(const Value: WideString);
begin
  Form1.Edit1.Text := Value;
end;

procedure TCOMTester.Set_Edit2Text(const Value: WideString);
begin
  Form1.Edit2.Text := Value;
end;

initialization
  TAutoObjectFactory.Create(ComServer, TCOMTester, Class_COMTester,
    ciSingleInstance, tmApartment);
end.


Für den Client habe ich dann ebenfalls ein neue VCL-Form Anwendung erstellt und über "Komponente/Komponente improtieren..." einen Wrapper für den Server erstellt:

ausblenden volle Höhe Delphi-Quelltext
1:
2:
3:
4:
5:
6:
7:
8:
9:
10:
11:
12:
13:
14:
15:
16:
17:
18:
19:
20:
21:
22:
23:
24:
25:
26:
27:
28:
29:
30:
31:
32:
{$IFDEF LIVE_SERVER_AT_DESIGN_TIME}
  TCOMTesterProperties= class;
{$ENDIF}
  TCOMTester = class(TOleServer)
  private
    FIntf: ICOMTester;
{$IFDEF LIVE_SERVER_AT_DESIGN_TIME}
    FProps: TCOMTesterProperties;
    function GetServerProperties: TCOMTesterProperties;
{$ENDIF}
    function GetDefaultInterface: ICOMTester;
  protected
    procedure InitServerData; override;
    function Get_Edit1Text: WideString;
    procedure Set_Edit1Text(const Value: WideString);
    function Get_Edit2Text: WideString;
    procedure Set_Edit2Text(const Value: WideString);
  public
    constructor Create(AOwner: TComponent); override;
    destructor  Destroy; override;
    procedure Connect; override;
    procedure ConnectTo(svrIntf: ICOMTester);
    procedure Disconnect; override;
    function ShowTestMessage(const Text: WideString): WideString;
    property DefaultInterface: ICOMTester read GetDefaultInterface;
    property Edit1Text: WideString read Get_Edit1Text write Set_Edit1Text;
    property Edit2Text: WideString read Get_Edit2Text write Set_Edit2Text;
  published
{$IFDEF LIVE_SERVER_AT_DESIGN_TIME}
    property Server: TCOMTesterProperties read GetServerProperties;
{$ENDIF}
  end;


Auf dem Form von dem Client habe ich dann ein Edit, zwei Radio-Buttons und einen Button platziert. Beim Klick auf den Button soll folgendes passieren:

ausblenden Delphi-Quelltext
1:
2:
3:
4:
5:
6:
7:
8:
9:
10:
11:
12:
13:
14:
15:
16:
17:
18:
19:
procedure TForm1.Button1Click(Sender: TObject);
var
  tester: TCOMTester;
  str: string;
begin
  tester := TCOMTester.Create(nil);

  // Der Tester soll eine Nachricht ausgeben
  str := tester.ShowTestMessage('Hallo Welt!');  // <-- Fehler!!
  ShowMessage(str);

  // Je nach Radiobutton im Server einen Edittext ändern
  if Edit1RB.Checked then
    tester.Edit1Text := Edit1.Text
  else
    tester.Edit2Text := Edit1.Text;

  tester.Free;
end;



Hierbei kommt es nun zu folgenden Problemen:
1. Wir "tester.ShowTestMessage(...)" kommt es zu einer Zugriffsverletzung in der rpcrt4.dll. Was hat es damit aufsicht?

2. Bei jedem Klick auf den Button öffnet sich ein Fenster des Servers bei dem dann der Edit Text gesetzt wird. Ich möchte aber erreichen, dass der Text immer im gleichen Server geändert wird. Hierfür habe ich ciSingleInstance verwendet aber das scheint ja nicht die Lösung zu sein. Was mache ich also falsch?

Besten Dank für eure Hilfe!
Ares
jaenicke
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starofftopic star
Beiträge: 19341
Erhaltene Danke: 1752

W11 x64 (Chrome, Edge)
Delphi 12 Pro, C# (VS 2022), JS/HTML, Java (NB), PHP, Lazarus
BeitragVerfasst: Mi 17.12.08 02:27 
An welcher Adresse ist die Zugriffsverletzung? 0 oder eine andere Adresse?

rpcrt4 würde ich spontan mit Remote Procedure Call RunTime übersetzen, insofern vermute ich einen Fehler bei der Verbindung. Ich bin jetzt zu müde dafür, aber ich schau nachher mal nochmal drüber.
Ares Threadstarter
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starontopic star
Beiträge: 128



BeitragVerfasst: Mi 17.12.08 13:53 
Ganz genau sieht die Meldung so aus:
ausblenden Quelltext
1:
Zugriffsverletzung bei Adresse 777C2599 in Modul 'RPCRT4.dll'. Lesen von Adresse FFFFFFF8					
Einloggen, um Attachments anzusehen!


Zuletzt bearbeitet von Ares am Mi 17.12.08 13:58, insgesamt 1-mal bearbeitet
jaenicke
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starofftopic star
Beiträge: 19341
Erhaltene Danke: 1752

W11 x64 (Chrome, Edge)
Delphi 12 Pro, C# (VS 2022), JS/HTML, Java (NB), PHP, Lazarus
BeitragVerfasst: Mi 17.12.08 13:57 
Musst du nicht tester.connect vorher aufrufen?

// EDIT:
Obwohl, dann würde sich der Server ja nicht öffnen.
Ares Threadstarter
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starontopic star
Beiträge: 128



BeitragVerfasst: Mi 17.12.08 14:01 
user profile iconjaenicke hat folgendes geschrieben Zum zitierten Posting springen:
Musst du nicht tester.connect vorher aufrufen?
// EDIT:
Obwohl, dann würde sich der Server ja nicht öffnen.


Ich bin mir da nicht so sicher, wie gesagt bin ich (noch) kein wirklicher Experte im Thema COM. Aber auch mit tester.Connect kommt es zu der gleichen Fehlermeldung. Auch nur der Aufruf von ShowTestMessage führt zum Fehler. Das Setzen der Edit Texte funktioniert fehlerfrei.

Während du deinen Beitrag geschrieben hast habe ich das Testprojekt mal angehängt. Vielleicht kannst du ja mal einen Blick rein werfen :-)