Recent

Author Topic: MS C++ ThisCall  (Read 1089 times)

SonnyBoyXXl

  • Jr. Member
  • **
  • Posts: 57
MS C++ ThisCall
« on: March 21, 2023, 09:22:56 pm »
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  :P

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][+][-]
  1. if (side=callerside) then
  2.         begin
  3.             paraloc:=hp.paraloc[side].add_location;
  4.             paraloc^.size:=OS_ADDR;
  5.                             paraloc^.def:=methodpointertype;
  6.                             paraloc^.loc:=LOC_REGISTER;
  7.                             paraloc^.register:=newreg(R_INTREGISTER,parasupregs[parareg],cgsize2subreg(R_INTREGISTER,paracgsize));
  8.                             inc(parareg);
  9.         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, :o

So some help would be wonderful  :)

Thaddy

  • Hero Member
  • *****
  • Posts: 14382
  • Sensorship about opinions does not belong here.
Re: MS C++ ThisCall
« Reply #1 on: March 21, 2023, 09:29:25 pm »
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.
« Last Edit: March 21, 2023, 09:42:52 pm by Thaddy »
Object Pascal programmers should get rid of their "component fetish" especially with the non-visuals.

SonnyBoyXXl

  • Jr. Member
  • **
  • Posts: 57
Re: MS C++ ThisCall
« Reply #2 on: March 21, 2023, 09:49:28 pm »
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  ;)



« Last Edit: March 22, 2023, 01:50:28 am by SonnyBoyXXl »

SonnyBoyXXl

  • Jr. Member
  • **
  • Posts: 57
Re: MS C++ ThisCall
« Reply #3 on: March 20, 2024, 01:33:41 am »
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][+][-]
  1. unit ASIO.ASIOStdCall;
  2.  
  3. {$mode delphi}{$H+}
  4.  
  5. interface
  6.  
  7. uses
  8.     Windows, Classes, SysUtils, ASIO.ASIODef,
  9.     ActiveX;
  10.  
  11. const
  12.     cASIO4AllCLSID: TGUID = '{232685C6-6548-49D8-846D-4141A3EF7560}';
  13.  
  14. type
  15.     // Attention: this inteface is in calling convention ThisCall
  16.     // not supported by Free Pascal yet
  17.     IASIO = interface(IUnknown)
  18.         function Init(SysHandle: HWND): TASIOBool;
  19.         procedure GetDriverName(Name: pansichar);
  20.         function GetDriverVersion(): longint;
  21.         procedure GetErrorMessage(Errstring: pansichar);
  22.         function Start(): TASIOError;
  23.         function Stop(): TASIOError;
  24.         function GetChannels(out NumInputChannels, NumOutputChannels: longint): TASIOError;
  25.         function GetLatencies(out InputLatency, OutputLatency: longint): TASIOError;
  26.         function GetBufferSize(MinSize, MaxSize, PreferredSize, Granularity: Plongint): TASIOError;
  27.         function CanSampleRate(SampleRate: TASIOSampleRate): TASIOError;
  28.         function GetSampleRate(out SampleRate: TASIOSampleRate): TASIOError;
  29.         function SetSampleRate(SampleRate: TASIOSampleRate): TASIOError;
  30.         function GetClockSources(Clocks: PASIOClockSource; out NumSources: longint): TASIOError;
  31.         function SetClockSource(Reference: longint): TASIOError;
  32.         function GetSamplePosition(sPos: PASIOSamples; tStamp: PASIOTimeStamp): TASIOError;
  33.         function GetChannelInfo(Info: PASIOChannelInfo): TASIOError;
  34.         function CreateBuffers(BufferInfos: PASIOBufferInfo; NumChannels: longint; BufferSize: longint; callbacks: PASIOCallbacks): TASIOError;
  35.         function DisposeBuffers(): TASIOError;
  36.         function ControlPanel(): TASIOError;
  37.         function Future(Selector: longint; opt: pointer): TASIOError;
  38.         function OutputReady(): TASIOError;
  39.     end;
  40.  
  41.     PASIO = ^IASIO;
  42.  
  43.     { TASIO }
  44.  
  45.     TASIO = class(TObject)
  46.     protected
  47.         FASIODriverThisCall: IASIO;
  48.     public
  49.         constructor Create(ClassID: TGUID);
  50.         destructor Destroy; override;
  51.     public
  52.         function Init(SysHandle: HWND): TASIOBool; stdcall;
  53.         procedure GetDriverName(Name: pansichar); stdcall;
  54.         function GetDriverVersion(): longint; stdcall;
  55.         procedure GetErrorMessage(Errstring: pansichar); stdcall;
  56.         function Start(): TASIOError; stdcall;
  57.         function Stop(): TASIOError; stdcall;
  58.         function GetChannels(out NumInputChannels, NumOutputChannels: longint): TASIOError; stdcall;
  59.         function GetLatencies(out InputLatency, OutputLatency: longint): TASIOError; stdcall;
  60.         function GetBufferSize(MinSize, MaxSize, PreferredSize, Granularity: Plongint): TASIOError; stdcall;
  61.         function CanSampleRate(SampleRate: TASIOSampleRate): TASIOError; stdcall;
  62.         function GetSampleRate(out SampleRate: TASIOSampleRate): TASIOError; stdcall;
  63.         function SetSampleRate(SampleRate: TASIOSampleRate): TASIOError; stdcall;
  64.         function GetClockSources(Clocks: PASIOClockSource; out NumSources: longint): TASIOError; stdcall;
  65.         function SetClockSource(Reference: longint): TASIOError; stdcall;
  66.         function GetSamplePosition(sPos: PASIOSamples; tStamp: PASIOTimeStamp): TASIOError; stdcall;
  67.         function GetChannelInfo(Info: PASIOChannelInfo): TASIOError; stdcall;
  68.         function CreateBuffers(BufferInfos: PASIOBufferInfo; NumChannels: longint; BufferSize: longint;
  69.             callbacks: PASIOCallbacks): TASIOError; stdcall;
  70.         function DisposeBuffers(): TASIOError; stdcall;
  71.         function ControlPanel(): TASIOError; stdcall;
  72.         function Future(Selector: longint; opt: pointer): TASIOError; stdcall;
  73.         function OutputReady(): TASIOError; stdcall;
  74.     end;
  75.  
  76. implementation
  77.  
  78. { TASIO }
  79.  
  80. constructor TASIO.Create(ClassID: TGUID);
  81. var
  82.     hr: HResult;
  83. begin
  84.     hr := CoInitialize(nil);    // initialize COM
  85.     hr := CoCreateInstance(ClassID, nil, CLSCTX_INPROC_SERVER, ClassID, FASIODriverThisCall);
  86. end;
  87.  
  88. destructor TASIO.Destroy;
  89. begin
  90.     FASIODriverThisCall:=nil;
  91.     inherited Destroy;
  92. end;
  93.  
  94.  
  95. {$asmMode  intel}
  96.  
  97. function TASIO.Init(SysHandle: HWND): TASIOBool; stdcall;
  98. var
  99.     x: IASIO;
  100. begin
  101.     x := FASIODriverThisCall;
  102.     asm
  103.                MOV     ECX, x
  104.                PUSH    DWORD PTR SysHandle
  105.                MOV     EAX, DWORD PTR [ECX]
  106.                CALL    [EAX+12]
  107.                MOV     [result],EAX
  108.  
  109.     end;
  110. end;
  111.  
  112. procedure TASIO.GetDriverName(Name: pansichar); stdcall;
  113. var
  114.     x: IASIO;
  115. begin
  116.     x := FASIODriverThisCall;
  117.     asm
  118.                MOV     ECX, x
  119.                PUSH    DWORD PTR Name
  120.                MOV     EAX, DWORD PTR [ECX]
  121.                CALL    [EAX+16]
  122.     end;
  123. end;
  124.  
  125. function TASIO.GetDriverVersion(): longint; stdcall;
  126. var
  127.     x: IASIO;
  128. begin
  129.     x := FASIODriverThisCall;
  130.     asm
  131.                MOV     ECX, x
  132.                MOV     EAX, DWORD PTR [ECX]
  133.                CALL    [EAX+20]
  134.                MOV     [result],EAX
  135.     end;
  136. end;
  137.  
  138. procedure TASIO.GetErrorMessage(Errstring: pansichar); stdcall;
  139. var
  140.     x: IASIO;
  141. begin
  142.     x := FASIODriverThisCall;
  143.     asm
  144.                MOV     ECX, x
  145.                PUSH    DWORD PTR Errstring
  146.                MOV     EAX, DWORD PTR [ECX]
  147.                CALL    [EAX+24]
  148.     end;
  149. end;
  150.  
  151. function TASIO.Start(): TASIOError; stdcall;
  152. var
  153.     x: IASIO;
  154. begin
  155.     x := FASIODriverThisCall;
  156.     asm
  157.                MOV     ECX, x
  158.                MOV     EAX, DWORD PTR [ECX]
  159.                CALL    [EAX+28]
  160.                MOV     [result],EAX
  161.     end;
  162. end;
  163.  
  164. function TASIO.Stop(): TASIOError; stdcall;
  165. var
  166.     x: IASIO;
  167. begin
  168.     x := FASIODriverThisCall;
  169.     asm
  170.                MOV     ECX, x
  171.                MOV     EAX, DWORD PTR [ECX]
  172.                CALL    [EAX+32]
  173.                MOV     [result],EAX
  174.     end;
  175. end;
  176.  
  177. function TASIO.GetChannels(out NumInputChannels, NumOutputChannels: longint): TASIOError; stdcall;
  178. var
  179.     x: IASIO;
  180. begin
  181.     x := FASIODriverThisCall;
  182.     asm
  183.                MOV     ECX, x
  184.                PUSH    DWORD PTR NumOutputChannels
  185.                PUSH    DWORD PTR NumInputChannels
  186.                MOV     EAX, DWORD PTR [ECX]
  187.                CALL    [EAX+36]
  188.                MOV     [result],EAX
  189.     end;
  190. end;
  191.  
  192. function TASIO.GetLatencies(out InputLatency, OutputLatency: longint): TASIOError; stdcall;
  193. var
  194.     x: IASIO;
  195. begin
  196.     x := FASIODriverThisCall;
  197.     asm
  198.                MOV     ECX, x
  199.                PUSH    DWORD PTR OutputLatency
  200.                PUSH    DWORD PTR InputLatency
  201.                MOV     EAX, DWORD PTR [ECX]
  202.                CALL    [EAX+40]
  203.                MOV     [result],EAX
  204.     end;
  205. end;
  206.  
  207. function TASIO.GetBufferSize(MinSize, MaxSize, PreferredSize, Granularity: Plongint): TASIOError; stdcall;
  208. var
  209.     x: IASIO;
  210. begin
  211.     x := FASIODriverThisCall;
  212.     asm
  213.                MOV     ECX, x
  214.                PUSH    DWORD PTR Granularity
  215.                PUSH    DWORD PTR PreferredSize
  216.                PUSH    DWORD PTR MaxSize
  217.                PUSH    DWORD PTR MinSize
  218.                MOV     EAX, DWORD PTR [ECX]
  219.                CALL    [EAX+44]
  220.                MOV     [result],EAX
  221.     end;
  222. end;
  223.  
  224. function TASIO.CanSampleRate(SampleRate: TASIOSampleRate): TASIOError; stdcall;
  225. var
  226.     x: IASIO;
  227. begin
  228.     x := FASIODriverThisCall;
  229.     asm
  230.                MOV     ECX, x
  231.                PUSH    DWORD PTR SampleRate
  232.                PUSH    DWORD PTR SampleRate
  233.                MOV     EAX, DWORD PTR [ECX]
  234.                CALL    [EAX+48]
  235.                MOV     [result],EAX
  236.     end;
  237. end;
  238.  
  239. function TASIO.GetSampleRate(out SampleRate: TASIOSampleRate): TASIOError; stdcall;
  240. var
  241.     x: IASIO;
  242. begin
  243.     x := FASIODriverThisCall;
  244.     asm
  245.                MOV     ECX, x
  246.                PUSH    DWORD PTR SampleRate
  247.                MOV     EAX, DWORD PTR [ECX]
  248.                CALL    [EAX+52]
  249.                MOV     [result],EAX
  250.     end;
  251. end;
  252.  
  253. function TASIO.SetSampleRate(SampleRate: TASIOSampleRate): TASIOError; stdcall;
  254. var
  255.     x: IASIO;
  256. begin
  257.     x := FASIODriverThisCall;
  258.     asm
  259.                MOV     ECX, x
  260.                PUSH    DWORD PTR SampleRate
  261.                PUSH    DWORD PTR SampleRate
  262.                MOV     EAX, DWORD PTR [ECX]
  263.                CALL    [EAX+56]
  264.                MOV     [result],EAX
  265.     end;
  266. end;
  267.  
  268. function TASIO.GetClockSources(Clocks: PASIOClockSource; out NumSources: longint): TASIOError; stdcall;
  269. var
  270.     x: IASIO;
  271. begin
  272.     x := FASIODriverThisCall;
  273.     asm
  274.                MOV     ECX, x
  275.                PUSH    DWORD PTR NumSources
  276.                PUSH    DWORD PTR Clocks
  277.                MOV     EAX, DWORD PTR [ECX]
  278.                CALL    [EAX+60]
  279.                MOV     [result],EAX
  280.     end;
  281. end;
  282.  
  283. function TASIO.SetClockSource(Reference: longint): TASIOError; stdcall;
  284. var
  285.     x: IASIO;
  286. begin
  287.     x := FASIODriverThisCall;
  288.     asm
  289.                MOV     ECX, x
  290.                PUSH    DWORD PTR Reference
  291.                MOV     EAX, DWORD PTR [ECX]
  292.                CALL    [EAX+64]
  293.                MOV     [result],EAX
  294.     end;
  295.  
  296. end;
  297.  
  298. function TASIO.GetSamplePosition(sPos: PASIOSamples; tStamp: PASIOTimeStamp): TASIOError; stdcall;
  299. var
  300.     x: IASIO;
  301. begin
  302.     x := FASIODriverThisCall;
  303.     asm
  304.                MOV     ECX, x
  305.                PUSH    DWORD PTR tStamp
  306.                PUSH    DWORD PTR sPos
  307.                MOV     EAX, DWORD PTR [ECX]
  308.                CALL    [EAX+68]
  309.                MOV     [result],EAX
  310.     end;
  311. end;
  312.  
  313. function TASIO.GetChannelInfo(Info: PASIOChannelInfo): TASIOError; stdcall;
  314. var
  315.     x: IASIO;
  316. begin
  317.     x := FASIODriverThisCall;
  318.     asm
  319.                MOV     ECX, x
  320.                PUSH    DWORD PTR Info
  321.                MOV     EAX, DWORD PTR [ECX]
  322.                CALL    [EAX+72]
  323.                MOV     [result],EAX
  324.     end;
  325. end;
  326.  
  327. function TASIO.CreateBuffers(BufferInfos: PASIOBufferInfo; NumChannels: longint; BufferSize: longint;
  328.     callbacks: PASIOCallbacks): TASIOError; stdcall;
  329. var
  330.     x: IASIO;
  331. begin
  332.     x := FASIODriverThisCall;
  333.     asm
  334.                MOV     ECX, x
  335.                PUSH    DWORD PTR callbacks
  336.                PUSH    DWORD PTR BufferSize
  337.                PUSH    DWORD PTR NumChannels
  338.                PUSH    DWORD PTR BufferInfos
  339.                MOV     EAX, DWORD PTR [ECX]
  340.                CALL    [EAX+76]
  341.                MOV     [result],EAX
  342.     end;
  343. end;
  344.  
  345. function TASIO.DisposeBuffers(): TASIOError; stdcall;
  346. var
  347.     x: IASIO;
  348. begin
  349.     x := FASIODriverThisCall;
  350.     asm
  351.                MOV     ECX, x
  352.                MOV     EAX, DWORD PTR [ECX]
  353.                CALL    [EAX+80]
  354.                MOV     [result],EAX
  355.     end;
  356. end;
  357.  
  358. function TASIO.ControlPanel(): TASIOError; stdcall;
  359. var
  360.     x: IASIO;
  361. begin
  362.     x := FASIODriverThisCall;
  363.     asm
  364.                MOV     ECX, x
  365.                MOV     EAX, DWORD PTR [ECX]
  366.                CALL    [EAX+84]
  367.                MOV     [result],EAX
  368.     end;
  369. end;
  370.  
  371. function TASIO.Future(Selector: longint; opt: pointer): TASIOError; stdcall;
  372. var
  373.     x: IASIO;
  374. begin
  375.     x := FASIODriverThisCall;
  376.     asm
  377.                MOV     ECX, x
  378.                PUSH    DWORD PTR opt
  379.                PUSH    DWORD PTR Selector
  380.                MOV     EAX, DWORD PTR [ECX]
  381.                CALL    [EAX+88]
  382.                MOV     [result],EAX
  383.     end;
  384. end;
  385.  
  386. function TASIO.OutputReady(): TASIOError; stdcall;
  387. var
  388.     x: IASIO;
  389. begin
  390.     x := FASIODriverThisCall;
  391.     asm
  392.                MOV     ECX, x
  393.                MOV     EAX, DWORD PTR [ECX]
  394.                CALL    [EAX+92]
  395.                MOV     [result],EAX
  396.     end;
  397. end;
  398.  
  399. end.        

Have fun

nanobit

  • Full Member
  • ***
  • Posts: 160
Re: MS C++ ThisCall
« Reply #4 on: March 22, 2024, 07:03:40 am »
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

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.

 

TinyPortal © 2005-2018