MS C++ ThisCall lazarus / 64-FPC development ---------------------------------------------------------------------- SonnyBoyXXl · 2023-03-21 20:22 Hi folks, this question was asked sometime ago in this forum: supports FPC the "thiscall" calling convention. And the answer is: no. And normaly nobody needs this, BUT: the ASIO interface from Steinberg uses no calling convention keyword, so therefore the standard calling convention will be used in C++, and this is "thiscall". A workaround with a C++ DLL with stdcall incapsulating the thiscall will be possible, but not beautiful  So I tried to work out a solution. What I've solved already: 1) Lazarus knows the keyword "thiscall" and highlights, etc. 2) FPC can compile thiscall... but not correct at the moment Since "thiscall" is just for the i386 on windows, I've only make changes on the i386 compiler. I've added a tcpuparamanager procedure create_msvcthiscall_paraloc_info for the calling convention "thiscall". Since parameter passing is the sames as stdcall, I used this as a base. for thiscall, in ECX the "this" pointer must be loaded. So here I need to add an Register (ECX) to the parameters. Code: Pascal  [Select][+][-]window.onload = function(){var x1 = document.getElementById("main_content_section"); if (x1) { var x = document.getElementsByClassName("geshi");for (var i = 0; i if (side=callerside) then        begin            paraloc:=hp.paraloc[side].add_location;            paraloc^.size:=OS_ADDR;                            paraloc^.def:=methodpointertype;                            paraloc^.loc:=LOC_REGISTER;                            paraloc^.regist er:=newreg(R_INTREGISTER,parasupregs[parareg],cgsize2subreg(R_INTREGIS TER,paracgsize));                            inc(parareg);        end; The compiler crashes now, with  Fatal: Internal error 200501162 on Pushdata in line 145 of i386/cgcpu.pas. Seems it tries to push the LOC_REGSITER parameter location on the stack, So some help would be wonderful ---------------------------------------------------------------------- Thaddy · 2023-03-21 20:29 Well, google for the AsioVST package that TobyBear and me and later TobyBear and Christian wrote about - more than - 20 years ago.... The ASIO part is largely mine, the VST part largely by Frederic VanMol. Will have a look, but it should be easy to find. If you can't, I probably still have it somewhere. Note that Christian was not very generous is giving credits. That's why I quit the scene. He presented my code as if it was written by him.... Bad idea.... Then again he was very young at the time. Note I left out one person involved that made even static linking possible, but I forgot his name. Will quote him when I find the code. Anyway: it has been done and in a proper way. ---------------------------------------------------------------------- SonnyBoyXXl · 2023-03-21 20:49 Thanks Thaddy, I found the OpenASIO.dll hint in your source. Thx. This will help for my work with ASIO. Edit: the OpenASIO.dll do not work. It's crashing all the time. I now wrote my own (working) warpper-DLL, to refresh my C++ knowledge  Edit2: The OpenASIO DLL seems old. The thiscall was introduced in VS2005. And Im testing with ASIO4All which is uptodate. Maybw before 2005 their is another calling convention used ascdefaulr in c++? But the issue with the compiler remains ---------------------------------------------------------------------- SonnyBoyXXl · 2024-03-20 00:33 Update: got some time and worked on a C++ dll to convert the thiscalls to stdcalls, since the available DLLs are old. But as hating programmin in C/C++, I changed this issue to a assembler session in Pascal, which is even more enjoyable. this is the result: Code: Pascal  [Select][+][-]window.onload = function(){var x1 = document.getElementById("main_content_section"); if (x1) { var x = document.getElementsByClassName("geshi");for (var i = 0; i unit ASIO.ASIOStdCall; {$mode delphi}{$H+} interface uses    Windows, Classes, SysUtils, ASIO.ASIODef,    ActiveX; const    cASIO4AllCLSID: TGUID = '{232685C6-6548-49D8-846D-4141A3EF7560}'; type    // Attention: this inteface is in calling convention ThisCall    // not supported by Free Pascal yet    IASIO = interface(IUnknown)        function Init(SysHandle: HWND): TASIOBool;        procedure GetDriverName(Name: pansichar);        function GetDriverVersion(): longint;        procedure GetErrorMessage(Errstring: pansichar);      function Start(): TASIOError;        function Stop(): TASIOError;      function GetChannels(out NumInputChannels, NumOutputChannels: longint): TASIOError;        function GetLatencies(out InputLatency, OutputLatency: longint): TASIOError;        function GetBufferSize(MinSize, MaxSize, PreferredSize, Granularity: Plongint): TASIOError;        function CanSampleRate(SampleRate: TASIOSampleRate): TASIOError;        function GetSampleRate(out SampleRate: TASIOSampleRate): TASIOError;        function SetSampleRate(SampleRate: TASIOSampleRate): TASIOError;        function GetClockSources(Clocks: PASIOClockSource; out NumSources: longint): TASIOError;        function SetClockSource(Reference: longint): TASIOError;        function GetSamplePosition(sPos: PASIOSamples; tStamp: PASIOTimeStamp): TASIOError;        function GetChannelInfo(Info: PASIOChannelInfo): TASIOError;        function CreateBuffers(BufferInfos: PASIOBufferInfo; NumChannels: longint; BufferSize: longint; callbacks: PASIOCallbacks): TASIOError;        function DisposeBuffers(): TASIOError;        function ControlPanel(): TASIOError;        function Future(Selector: longint; opt: pointer): TASIOError;        function OutputReady(): TASIOError;    end;     PASIO = ^IASIO;     { TASIO }     TASIO = class(TObject)    protected        FASIODriverThisCall: IASIO;    public        constructor Create(ClassID: TGUID);        destructor Destroy; override;    public        function Init(SysHandle: HWND): TASIOBool; stdcall;      procedure GetDriverName(Name: pansichar); stdcall;        function GetDriverVersion(): longint; stdcall;        procedure GetErrorMessage(Errstring: pansichar); stdcall;        function Start(): TASIOError; stdcall;        function Stop(): TASIOError; stdcall;        function GetChannels(out NumInputChannels, NumOutputChannels: longint): TASIOError; stdcall;        function GetLatencies(out InputLatency, OutputLatency: longint): TASIOError; stdcall;        function GetBufferSize(MinSize, MaxSize, PreferredSize, Granularity: Plongint): TASIOError; stdcall;        function CanSampleRate(SampleRate: TASIOSampleRate): TASIOError; stdcall;        function GetSampleRate(out SampleRate: TASIOSampleRate): TASIOError; stdcall;        function SetSampleRate(SampleRate: TASIOSampleRate): TASIOError; stdcall;      function GetClockSources(Clocks: PASIOClockSource; out NumSources: longint): TASIOError; stdcall;        function SetClockSource(Reference: longint): TASIOError; stdcall;        function GetSamplePosition(sPos: PASIOSamples; tStamp: PASIOTimeStamp): TASIOError; stdcall;        function GetChannelInfo(Info: PASIOChannelInfo): TASIOError; stdcall;        function CreateBuffers(BufferInfos: PASIOBufferInfo; NumChannels: longint; BufferSize: longint;            callbacks: PASIOCallbacks): TASIOError; stdcall;        function DisposeBuffers(): TASIOError; stdcall;        function ControlPanel(): TASIOError; stdcall;        function Future(Selector: longint; opt: pointer): TASIOError; stdcall;        function OutputReady(): TASIOError; stdcall;    end; implementation { TASIO } constructor TASIO.Create(ClassID: TGUID);var    hr: HResult;begin    hr := CoInitialize(nil);    // initialize COM    hr := CoCreateInstance(ClassID, nil, CLSCTX_INPROC_SERVER, ClassID, FASIODriverThisCall);end; destructor TASIO.Destroy;begin    FASIODriverThisCall:=nil;    inherited Destroy;end;  {$asmMode  intel} function TASIO.Init(SysHandle: HWND): TASIOBool; stdcall;var    x: IASIO;begin    x := FASIODriverThisCall;    asm               MOV     ECX, x               PUSH    DWORD PTR SysHandle               MOV     EAX, DWORD PTR [ECX]               CALL    [EAX+12]               MOV     [result],EAX     end;end; procedure TASIO.GetDriverName(Name: pansichar); stdcall;var  x: IASIO;begin    x := FASIODriverThisCall;    asm               MOV   ECX, x               PUSH    DWORD PTR Name               MOV     EAX, DWORD PTR [ECX]               CALL    [EAX+16]    end;end; function TASIO.GetDriverVersion(): longint; stdcall;var    x: IASIO;begin    x := FASIODriverThisCall;    asm               MOV     ECX, x               MOV     EAX, DWORD PTR [ECX]               CALL  [EAX+20]               MOV     [result],EAX    end;end; procedure TASIO.GetErrorMessage(Errstring: pansichar); stdcall;var    x: IASIO;begin    x := FASIODriverThisCall;    asm               MOV     ECX, x               PUSH    DWORD PTR Errstring               MOV   EAX, DWORD PTR [ECX]               CALL    [EAX+24]    end;end; function TASIO.Start(): TASIOError; stdcall;var    x: IASIO;begin    x := FASIODriverThisCall;    asm               MOV     ECX, x               MOV     EAX, DWORD PTR [ECX]               CALL  [EAX+28]               MOV     [result],EAX    end;end; function TASIO.Stop(): TASIOError; stdcall;var    x: IASIO;begin    x := FASIODriverThisCall;    asm               MOV     ECX, x               MOV     EAX, DWORD PTR [ECX]               CALL    [EAX+32]             MOV     [result],EAX    end;end; function TASIO.GetChannels(out NumInputChannels, NumOutputChannels: longint): TASIOError; stdcall;var    x: IASIO;begin    x := FASIODriverThisCall;    asm             MOV     ECX, x               PUSH    DWORD PTR NumOutputChannels               PUSH    DWORD PTR NumInputChannels             MOV     EAX, DWORD PTR [ECX]               CALL    [EAX+36]               MOV     [result],EAX    end;end; function TASIO.GetLatencies(out InputLatency, OutputLatency: longint): TASIOError; stdcall;var    x: IASIO;begin    x := FASIODriverThisCall;    asm               MOV     ECX, x               PUSH    DWORD PTR OutputLatency               PUSH    DWORD PTR InputLatency               MOV     EAX, DWORD PTR [ECX]               CALL    [EAX+40]               MOV     [result],EAX    end;end; function TASIO.GetBufferSize(MinSize, MaxSize, PreferredSize, Granularity: Plongint): TASIOError; stdcall;var    x: IASIO;begin    x := FASIODriverThisCall;    asm               MOV     ECX, x             PUSH    DWORD PTR Granularity               PUSH    DWORD PTR PreferredSize               PUSH    DWORD PTR MaxSize               PUSH    DWORD PTR MinSize               MOV     EAX, DWORD PTR [ECX]               CALL    [EAX+44]               MOV     [result],EAX    end;end; function TASIO.CanSampleRate(SampleRate: TASIOSampleRate): TASIOError; stdcall;var    x: IASIO;begin    x := FASIODriverThisCall;    asm               MOV     ECX, x               PUSH    DWORD PTR SampleRate               PUSH    DWORD PTR SampleRate               MOV     EAX, DWORD PTR [ECX]               CALL    [EAX+48]               MOV     [result],EAX    end;end; function TASIO.GetSampleRate(out SampleRate: TASIOSampleRate): TASIOError; stdcall;var    x: IASIO;begin    x := FASIODriverThisCall;    asm               MOV     ECX, x               PUSH    DWORD PTR SampleRate               MOV     EAX, DWORD PTR [ECX]               CALL    [EAX+52]               MOV     [result],EAX    end;end; function TASIO.SetSampleRate(SampleRate: TASIOSampleRate): TASIOError; stdcall;var    x: IASIO;begin    x := FASIODriverThisCall;    asm               MOV     ECX, x               PUSH    DWORD PTR SampleRate               PUSH    DWORD PTR SampleRate               MOV     EAX, DWORD PTR [ECX]               CALL    [EAX+56]               MOV     [result],EAX    end;end; function TASIO.GetClockSources(Clocks: PASIOClockSource; out NumSources: longint): TASIOError; stdcall;var    x: IASIO;begin    x := FASIODriverThisCall;    asm               MOV     ECX, x             PUSH    DWORD PTR NumSources               PUSH    DWORD PTR Clocks               MOV     EAX, DWORD PTR [ECX]               CALL  [EAX+60]               MOV     [result],EAX    end;end; function TASIO.SetClockSource(Reference: longint): TASIOError; stdcall;var    x: IASIO;begin    x := FASIODriverThisCall;    asm               MOV   ECX, x               PUSH    DWORD PTR Reference               MOV   EAX, DWORD PTR [ECX]               CALL    [EAX+64]               MOV     [result],EAX    end; end; function TASIO.GetSamplePosition(sPos: PASIOSamples; tStamp: PASIOTimeStamp): TASIOError; stdcall;var    x: IASIO;begin    x := FASIODriverThisCall;    asm               MOV     ECX, x               PUSH    DWORD PTR tStamp               PUSH    DWORD PTR sPos             MOV     EAX, DWORD PTR [ECX]               CALL    [EAX+68]             MOV     [result],EAX    end;end; function TASIO.GetChannelInfo(Info: PASIOChannelInfo): TASIOError; stdcall;var    x: IASIO;begin    x := FASIODriverThisCall;    asm               MOV     ECX, x               PUSH    DWORD PTR Info               MOV     EAX, DWORD PTR [ECX]               CALL    [EAX+72]               MOV   [result],EAX    end;end; function TASIO.CreateBuffers(BufferInfos: PASIOBufferInfo; NumChannels: longint; BufferSize: longint;    callbacks: PASIOCallbacks): TASIOError; stdcall;var    x: IASIO;begin    x := FASIODriverThisCall;    asm               MOV     ECX, x             PUSH    DWORD PTR callbacks               PUSH    DWORD PTR BufferSize               PUSH    DWORD PTR NumChannels               PUSH    DWORD PTR BufferInfos               MOV     EAX, DWORD PTR [ECX]               CALL    [EAX+76]               MOV     [result],EAX    end;end; function TASIO.DisposeBuffers(): TASIOError; stdcall;var    x: IASIO;begin    x := FASIODriverThisCall;    asm             MOV     ECX, x               MOV     EAX, DWORD PTR [ECX]             CALL    [EAX+80]               MOV     [result],EAX    end;end; function TASIO.ControlPanel(): TASIOError; stdcall;var    x: IASIO;begin    x := FASIODriverThisCall;    asm               MOV     ECX, x               MOV     EAX, DWORD PTR [ECX]               CALL  [EAX+84]               MOV     [result],EAX    end;end; function TASIO.Future(Selector: longint; opt: pointer): TASIOError; stdcall;var    x: IASIO;begin    x := FASIODriverThisCall;    asm             MOV     ECX, x               PUSH    DWORD PTR opt             PUSH    DWORD PTR Selector               MOV     EAX, DWORD PTR [ECX]               CALL    [EAX+88]               MOV     [result],EAX    end;end; function TASIO.OutputReady(): TASIOError; stdcall;var    x: IASIO;begin    x := FASIODriverThisCall;    asm             MOV     ECX, x               MOV     EAX, DWORD PTR [ECX]             CALL    [EAX+92]               MOV     [result],EAX    end;end; end.       Have fun ---------------------------------------------------------------------- nanobit · 2024-03-22 06:03 Quote from: SonnyBoyXXl on March 21, 2023, 09:22:56 pmHi folks, this question was asked sometime ago in this forum: supports FPC the "thiscall" calling convention. And the answer is: no. And normaly nobody needs this I recall, the win32 version of TextServ.h (COM-interfaces for Windows Text Services) also requires thiscall, unfortunately. And Delphi programmers offered stdcall wrappers for this.