{gelöst] Generische Methode an Objekt zuweisen

Für Fragen von Einsteigern und Programmieranfängern...
Antworten
Nimral
Beiträge: 390
Registriert: Mi 10. Jun 2015, 11:33

{gelöst] Generische Methode an Objekt zuweisen

Beitrag von Nimral »

Ich habe eine Komponente verwendet (UniqueInstance - stellt sicher dass ein Programm nur einm Mal gestartet werden kann), die über IDE Integration verfügt hat. Ich habe die Komponente in das Hauptforumlar der Applikation eingebaut, und das Erzeugen und das Zweisen der Properties wurde automatisch erledigt. Jetzt brauche ich die Komponente bereits, bevor das Hauptformular gezeigt wird, und muss sie daher selber im Code erzeugen.

Problem: innerhalb der Komponente wird eine Prozedur erwartet die aufgerufen wird, wenn ein (bereits laufendes - also erste Instanz) Programm erkennt, dass jemand versucht hat, noch eine Kopie zu starten. Es geht jetzt nicht um das was mach ich dann, sondern darum, wie ich meine eigene Prozedur zuweisen muss, dich ich bisher einfach als Property in der IDE eingetragen habe. Das ist die Komponente ...

Code: Alles auswählen

type

  TOnOtherInstance = procedure (Sender : TObject; ParamCount: Integer; const Parameters: array of String) of object;

  { TUniqueInstance }

  TUniqueInstance = class(TComponent)
  private
    FIdentifier: String;
    FOnOtherInstance: TOnOtherInstance;
    FUpdateInterval: Cardinal;
    FEnabled: Boolean;
    FPriorInstanceRunning: Boolean;
    procedure ReceiveMessage(Sender: TObject);
    {$ifdef PollIPCMessage}
    procedure CheckMessage(Sender: TObject);
    {$endif}
  protected
    procedure Loaded; override;
  public
    constructor Create(AOwner: TComponent); override;
    property PriorInstanceRunning: Boolean read FPriorInstanceRunning;
  published
    property Enabled: Boolean read FEnabled write FEnabled default False;
    property Identifier: String read FIdentifier write FIdentifier;
    property UpdateInterval: Cardinal read FUpdateInterval write FUpdateInterval default 1000;
    property OnOtherInstance: TOnOtherInstance read FOnOtherInstance write FOnOtherInstance;
  end;
  
Ich habe meine eigene Prozedur mit passender Signatur erstellt ...

Code: Alles auswählen

procedure MyUniqueInstanceOtherInstance(Sender: TObject; ParamCount: integer; Parameters: array of string);

// what to do if a second instance is detected

begin
	...
end;
und kriege nun nicht heraus, wie genau ich diese Routine an die OnOtherInstance Property des Objekts zuweisen muss. Mir käme das logisch vor:

Code: Alles auswählen

  MyUniqueInstance := TUniqueInstance.Create(Application);
  MyUniqueInstance.OnOtherInstance := @MyUniqueInstanceOtherInstance;
 
aber das führt zu einem Compilerfehler:

Code: Alles auswählen

Error: Incompatible types: got "<address of procedure(TObject;LongInt;{Open} Array Of AnsiString);Register>" expected "<procedure variable type of procedure(TObject;LongInt;const {Open} Array Of AnsiString) of object;Register>"
Wie macht man die Deklaration der Prozedur bzw. die Zuweisung richtig?

Thnx, Armin
Zuletzt geändert von Nimral am Do 1. Apr 2021, 07:14, insgesamt 2-mal geändert.

Benutzeravatar
fliegermichl
Lazarusforum e. V.
Beiträge: 1435
Registriert: Do 9. Jun 2011, 09:42
OS, Lazarus, FPC: Lazarus Fixes FPC Stable
CPU-Target: 32/64Bit
Wohnort: Echzell

Re: Generische Prozedur zuweisen

Beitrag von fliegermichl »

Der dritte Parameter wird als const erwartet.
Passt also eigentlich alles soweit. Nur daß du deine Procedur anders deklarieren musst:
Und natürlich als Methode einer Klasse

Code: Alles auswählen

type
 TMyClass = class
  procedure MyUniqueInstanceOtherInstance(Sender: TObject; ParamCount: integer; const Parameters: array of string);
 end;

procedure TMyClass.MyUniqueInstanceOtherInstance(Sender: TObject; ParamCount: integer; const Parameters: array of string);
begin
end;

Benutzeravatar
kupferstecher
Beiträge: 422
Registriert: Do 17. Nov 2016, 11:52

Re: Generische Prozedur zuweisen

Beitrag von kupferstecher »

Hallo Armin,

die Fehlermeldung ist nicht so leicht zu verstehen, aber es kommt ein "of object" darin vor - die zugewiesene Prozedur muss also eine Methode sein. Wenn ich dich richtig verstanden habe gibt es Form1 zum Zeitpunkt des Zuweisens ggf. noch nicht, sonst könntest du die Procedur darin definieren. Ansonsten eine einfache Klasse basteln:

Code: Alles auswählen

Type TInstanceHandlers = class
  Procedure OtherInstanceHandler (Sender : TObject; ParamCount: Integer; const Parameters: array of String);
end;

var
  InstanceHandlers :TInstanceHandlers ;
Und dann:

Code: Alles auswählen

  MyUniqueInstance := TUniqueInstance.Create(Application);
  InstanceHandlers:= TInstanceHandlers.Create;
  MyUniqueInstance.OnOtherInstance := @InstanceHandlers.OtherInstanceHandler ;
EDIT: fliegermichl war schneller...

Benutzeravatar
fliegermichl
Lazarusforum e. V.
Beiträge: 1435
Registriert: Do 9. Jun 2011, 09:42
OS, Lazarus, FPC: Lazarus Fixes FPC Stable
CPU-Target: 32/64Bit
Wohnort: Echzell

Re: Generische Prozedur zuweisen

Beitrag von fliegermichl »

:-) Erster :-)

Nimral
Beiträge: 390
Registriert: Mi 10. Jun 2015, 11:33

Re: Generische Prozedur zuweisen

Beitrag von Nimral »

Tja, was soll ich sagen, eure Erklärung war für mich schlüssig, leider sieht das der Compiler nicht so. Hier der Code aus der lpr Datei (ich habe ihn hier eingebaut weil ich den Check vor dem Aufruf des Hauptformulars brauche, aber ich denke das tut nix zur Sache)

Code: Alles auswählen


{$mode objfpc}{$H+}

uses {$IFDEF UNIX} {$IFDEF UseCThreads}
  cthreads, {$ENDIF} {$ENDIF}
  Interfaces, // this includes the LCL widgetset
  Forms,
  MainFormHandler,
  SysUtils,
  ConfigurationUnit,
  MainUnit,
  LoginFormUnit,UniqueInstance;

{$R *.res}

{...}
const
  PROGGUID = '5d87594a-3d44-401a-b012-b435c6e514f7';

// --------------------------------------------------
// Unique instance
// ensure only one instance of the program is running
// --------------------------------------------------

Type

{ TInstanceHandlers }

TInstanceHandlers = class
  Procedure OtherInstanceHandler (Sender : TObject; ParamCount: Integer; const Parameters: array of String);
end;

procedure TInstanceHandlers.OtherInstanceHandler(Sender: TObject;
  ParamCount: Integer; const Parameters: array of String);

begin
	// Collision handling code goes here ...
end;

var
  InstanceHandlers :TInstanceHandlers;

var MyUniqueInstanceHandler: TUniqueInstance;

// ------------------------------------------
// Main Program entry point
// ------------------------------------------

var
  authenticated: boolean = False;

begin
  // ensure uniqueness
  MyUniqueInstanceHandler := TUniqueInstance.Create(nil);
  MyUniqueInstanceHandler.Identifier:=PROGGUID;
  InstanceHandlers:= TInstanceHandlers.Create;
  MyUniqueInstanceHandler.OnOtherInstance := @InstanceHandlers.OtherInstanceHandler;
{ ...}
  FreeAndNil(InstanceHandlers);
  FreeAndNil(MyUniqueInstanceHandler);
end.
Leider exakt die selbe Fehlermeldung:

Code: Alles auswählen

Error: Incompatible types: got "<procedure variable type of procedure(TObject;LongInt;const {Open} Array Of AnsiString) of object;Register>" expected "<procedure variable type of procedure(TObject;LongInt;{Open} Array Of AnsiString) of object;Register>"
in der Zeile

Code: Alles auswählen

  MyUniqueInstanceHandler.OnOtherInstance := @InstanceHandlers.OtherInstanceHandler;
Hab ich was übersehen?

Armin

Benutzeravatar
kupferstecher
Beiträge: 422
Registriert: Do 17. Nov 2016, 11:52

Re: Generische Prozedur zuweisen

Beitrag von kupferstecher »

Laut Fehlermeldung stimmt was mit dem Array nicht. Versuch mal statt
array of String
einen Typ zu definieren
Type TStringArray = array of String;
und dann
Procedure OtherInstanceHandler (...; const Parameters: TStringArray);

Nimral
Beiträge: 390
Registriert: Mi 10. Jun 2015, 11:33

Re: Generische Prozedur zuweisen

Beitrag von Nimral »

Haut mich tot, das habe ich übersehen. Die Meldungen waren sich so ähnlich dass ich dachte, es ist das selbe Problem. Das const raus ...

Code: Alles auswählen

procedure TInstanceHandlers.OtherInstanceHandler(Sender: TObject; ParamCount: Integer;Parameters: array of String);
... dann passt es nicht nur ungefähr, sondern wortwörtlich zur Definition des Originals, und schon ist der Compiler glücklich.

Jungs, ihr habt mich ein schönes Stück weiter gebracht, vielen Dank!

Armin.

Antworten