4

I have a situation like the following:

interface

type
    IMyInterface = interface
    [GUID]
        procedure MyProcedure; stdcall;
    end;

    TMyOBject = class(TInterfacedObject, IMyInterface)
        procedure MyProcedure; virtual; stdcall; abstract;
    end;

    TDerivedObject = class(TMyOBject)
        procedure MyProcedure; override; stdcall;
        procedure SomeOtherProcedure;
    end;

implementation

uses
    System.Threading;

procedure TDerivedObject.MyProcedure;
begin
    //DoStuff;
end;

procedure TDerivedObject.SomeOtherProcedure;
begin
    TTask.Run(MyProcedure); //Error: Run can't be called with this parameter
end;

The compiler says I can't use a TTask to run MyProcedure. It is an error to try and cast MyProcedure to a TProc. My questions are 1) What type is MyProcedure? 2) How would I go about discovering the type of MyProcedure?

Thanks

David U
  • 943
  • 1
  • 8
  • 22

1 Answers1

6

TProc doesn't use the stdcall calling convention. It is declared an as anonymous method type that uses the default register calling convention instead:

 TProc = reference to procedure;

whereas

 TMyProcedure = procedure of object; stdcall;

Anonymous methods are not compatible with methods declaring calling conventions other than the standard Delphi register convention. Either don't use stdcall, or insert a wrapper method or local anonymous method, ie:

procedure TDerivedObject.SomeOtherProcedure;
begin
  TTask.Run(procedure begin MyProcedure; end); 
end;
Remy Lebeau
  • 555,201
  • 31
  • 458
  • 770
J...
  • 30,968
  • 6
  • 66
  • 143
  • @J Thanks. What do you mean by 30 characters? – David U May 16 '19 at 19:12
  • @J OK, but I can create another method in TDerivedObject, name it 'LocalProc', run MyProcedure from LocalProc, and successfully pass LocalProc to TTask.Run. It seems to me that LocalProc is a 'procedure of object' and not a TProc, but it works. – David U May 16 '19 at 19:23
  • @DavidU Yes, but a normal `procedure of object` is generally assignment compatible with the anonymous `reference to procedure` type (by compiler magic) so long as there is no calling convention override involved. See [this question](https://stackoverflow.com/q/34677505/327083) if you're interested in a bit more detail on that point (and some caveats). – J... May 16 '19 at 19:26
  • @DavidU With that said, for a void method with no arguments, there is no difference between the `register` and `stdcall` conventions - I presume this is boilerplate for something that is going to plug into an external API where there will be arguments and return values? If not, the obvious solution is just not to decorate your class method with `stdcall`. – J... May 16 '19 at 19:31
  • @J Yes, if I understand your question. I'm performing a Facebook login, which gives me a short-term token. I thought I'd try to exchange the short-term token for a long-term one in the background. I don't know if it works yet. – David U May 16 '19 at 19:37