Board index » delphi » Re: Thiscall

Re: Thiscall


2005-05-12 05:05:40 PM
delphi171
Quote
function Thiscall(ClassRef, ProcRef: Pointer;
Params: array of Longword): LongWord;
asm
POP EBP // remove stack frame

POP ECX
MOV [ESP], ECX

MOV ECX, EAX
JMP EDX
end;
This doesn't work if the Params array isn't stored on the stack, which
can be the case if Params is taken from an array that wasn't specified
inline.
 
 

Re: Thiscall

"Nicholas Sherlock" <XXXX@XXXXX.COM>writes news:4282f2be$XXXX@XXXXX.COM...
Quote
Hey all,

I'm trying to write a routine which'll let me call thiscall routines in
a C++ DLL from Delphi tidily.

I'm thinking that my function to call thiscall routines could look like
this:
I have a problem that might refer to thiscall as well:
Given a COM interface written in MSVC++ without an explicit calling convention specified, can I assume it to have the ThisCall Calling convention? (The Steinberg Asio interfaces)
Now we work with Delphi and ASIO by a stub dll that translates it to stdcall.
Is it possible to use such an interface from Delphi w.o. the necessity for the stub dll?
I suspect we need some BASM tricks, that why I post it here.
 

Re: Thiscall

Quote
Given a COM interface written in MSVC++ without an explicit calling convention specified, can I assume it to have the ThisCall Calling convention? (The Steinberg Asio interfaces)
Now we work with Delphi and ASIO by a stub dll that translates it to stdcall.
Is it possible to use such an interface from Delphi w.o. the necessity for the stub dll?
I suspect we need some BASM tricks, that why I post it here.
I made a translation for BCB:
you may change every call ASIO.init(params...) by init(ASIO,params...).
This could be easily translated to delphi.
//---------------------------------------------------------------------------
ASIOBool __fastcall init(IASIO* Driver, void* sysHandle)
{
ASIOBool Result;
__asm {
mov eax, sysHandle
push eax
mov ecx, Driver
mov eax, [ecx]
call [eax+12]
mov Result, eax
};
return Result;
};
//---------------------------------------------------------------------------
void getDriverName(IASIO* Driver, char *name)
{
__asm {
mov eax, name
push eax
mov ecx, Driver
mov eax, [ecx]
call [eax+16]
};
};
//---------------------------------------------------------------------------
long getDriverVersion(IASIO* Driver)
{
long Result;
__asm {
mov ecx, Driver
mov eax, [ecx]
call [eax+20]
mov Result, eax
};
return Result;
};
//---------------------------------------------------------------------------
void getErrorMessage(IASIO* Driver, char *string)
{
__asm {
mov eax, string
push eax
mov ecx, Driver
mov eax, [ecx]
call [eax+24]
};
};
//---------------------------------------------------------------------------
ASIOError start(IASIO* Driver)
{
ASIOError Result;
__asm {
mov ecx, Driver
mov eax, [ecx]
call [eax+28]
mov Result, eax
};
return Result;
};
//---------------------------------------------------------------------------
ASIOError stop(IASIO* Driver)
{
ASIOError Result;
__asm {
mov ecx, Driver
mov eax, [ecx]
call [eax+32]
mov Result, eax
};
return Result;
};
//---------------------------------------------------------------------------
ASIOError __fastcall getChannels(IASIO* Driver, long *numInputChannels,
long *numOutputChannels)
{
ASIOError Result;
__asm {
mov eax, numOutputChannels
push eax
mov eax, numInputChannels
push eax
mov ecx, Driver
mov eax, [ecx]
call [eax+36]
mov Result, eax
};
return Result;
};
//---------------------------------------------------------------------------
ASIOError getLatencies(IASIO* Driver, long *inputLatency, long
*outputLatency)
{
ASIOError Result;
__asm {
mov eax, outputLatency
push eax
mov eax, inputLatency
push eax
mov ecx, Driver
mov eax, [ecx]
call [eax+40]
mov Result, eax
};
return Result;
};
//---------------------------------------------------------------------------
ASIOError getBufferSize(IASIO* Driver, long *minSize, long *maxSize,
long *preferredSize, long *granularity)
{
ASIOError Result;
__asm {
mov eax, granularity
push eax
mov eax, preferredSize
push eax
mov eax, maxSize
push eax
mov eax, minSize
push eax
mov ecx, Driver
mov eax, [ecx]
call [eax+44]
mov Result, eax
};
return Result;
};
//---------------------------------------------------------------------------
ASIOError canSampleRate(IASIO* Driver, ASIOSampleRate sampleRate)
{
ASIOError Result;
void *sampleRate_ (&sampleRate);
__asm {
mov eax, sampleRate_
push [eax+4]
push [eax]
mov ecx, Driver
mov eax, [ecx]
call [eax+48]
mov Result, eax
};
return Result;
};
//---------------------------------------------------------------------------
ASIOError getSampleRate(IASIO* Driver, ASIOSampleRate *sampleRate)
{
ASIOError Result;
__asm {
mov eax, sampleRate
push eax
mov ecx, Driver
mov eax, [ecx]
call [eax+52]
mov Result, eax
};
return Result;
};
//---------------------------------------------------------------------------
ASIOError setSampleRate(IASIO* Driver, ASIOSampleRate sampleRate)
{
ASIOError Result;
void *sampleRate_ (&sampleRate);
__asm {
mov eax, sampleRate_
push [eax+4]
push [eax]
mov ecx, Driver
mov eax, [ecx]
call [eax+56]
mov Result, eax
};
return Result;
};
//---------------------------------------------------------------------------
ASIOError getClockSources(IASIO* Driver, ASIOClockSource *clocks, long
*numSources)
{
ASIOError Result;
__asm {
mov eax, numSources
push eax
mov eax, clocks
push eax
mov ecx, Driver
mov eax, [ecx]
call [eax+60]
mov Result, eax
};
return Result;
};
//---------------------------------------------------------------------------
ASIOError setClockSource(IASIO* Driver, long reference)
{
ASIOError Result;
__asm {
mov eax, reference
push eax
mov ecx, Driver
mov eax, [ecx]
call [eax+64]
mov Result, eax
};
return Result;
};
//---------------------------------------------------------------------------
ASIOError getSamplePosition(IASIO* Driver, ASIOSamples *sPos,
ASIOTimeStamp *tStamp)
{
ASIOError Result;
__asm {
mov eax, tStamp
push eax
mov eax, sPos
push eax
mov ecx, Driver
mov eax, [ecx]
call [eax+68]
mov Result, eax
};
return Result;
};
//---------------------------------------------------------------------------
ASIOError getChannelInfo(IASIO* Driver, ASIOChannelInfo *info)
{
ASIOError Result;
__asm {
mov eax, info
push eax
mov ecx, Driver
mov eax, [ecx]
call [eax+72]
mov Result, eax
};
return Result;
};
//---------------------------------------------------------------------------
ASIOError createBuffers(IASIO* Driver, ASIOBufferInfo *bufferInfos, long
numChannels,
long bufferSize, ASIOCallbacks *callbacks)
{
ASIOError Result;
__asm {
mov eax, callbacks
push eax
mov eax, bufferSize
push eax
mov eax, numChannels
push eax
mov eax, bufferInfos
push eax
mov ecx, Driver
mov eax, [ecx]
call [eax+76]
mov Result, eax
};
return Result;
};
//---------------------------------------------------------------------------
ASIOError disposeBuffers(IASIO* Driver)
{
ASIOError Result;
__asm {
mov ecx, Driver
mov eax, [ecx]
call [eax+80]
mov Result, eax
};
return Result;
};
//---------------------------------------------------------------------------
ASIOError controlPanel(IASIO* Driver)
{
ASIOError Result;
__asm {
mov ecx, Driver
mov eax, [ecx]
call [eax+84]
mov Result, eax
};
return Result;
};
//---------------------------------------------------------------------------
ASIOError future(IASIO* Driver, long selector,void *opt)
{
ASIOError Result;
__asm {
mov eax, opt
push eax
mov eax, selector
push eax
mov ecx, Driver
mov eax, [ecx]
call [eax+88]
mov Result, eax
};
return Result;
};
//---------------------------------------------------------------------------
ASIOError outputReady(IASIO* Driver)
{
ASIOError Result;
__asm {
mov ecx, Driver
mov eax, [ecx]
call [eax+92]
mov Result, eax
};
return Result;
};
 

Re: Thiscall

//---------------------------------------------------------------------------
function init(Driver: IASIO; SysHandle: Pointer): ASIOBool;
asm
push SysHandle
mov ecx, Driver
mov eax, [ecx]
call [eax+12]
end;
//---------------------------------------------------------------------------
procedure GetDriverName(Driver: IASIO; Name: PChar);
asm
push name
mov ecx, Driver
mov eax, [ecx]
call [eax+16]
end;
//---------------------------------------------------------------------------
function GetDriverVersion(Driver: IASIO): Integer;
asm
mov ecx, Driver
mov eax, [ecx]
call [eax+20]
end;
//---------------------------------------------------------------------------
procedure GetErrorMessage(Driver: IASIO; Error: PChar);
asm
push Error
mov ecx, Driver
mov eax, [ecx]
call [eax+24]
end;
//---------------------------------------------------------------------------
function Start(Driver: IASIO): ASIOError;
asm
mov ecx, Driver
mov eax, [ecx]
call [eax+28]
end;
//---------------------------------------------------------------------------
function Stop(Driver: IASIO): ASIOError;
asm
mov ecx, Driver
mov eax, [ecx]
call [eax+32]
end;
//---------------------------------------------------------------------------
function GetChannels(Driver: IASIO; NumInputChannels, NumOutputChannels:
PInteger): ASIOError;
asm
push NumOutputChannels
push NumInputChannels
mov ecx, Driver
mov eax, [ecx]
call [eax+36]
end;
//---------------------------------------------------------------------------
function GetLatencies(Driver: IASIO; InputLatency, OutputLatency:
PInteger): ASIOError;
asm
push OutputLatency
push InputLatency
mov ecx, Driver
mov eax, [ecx]
call [eax+40]
end;
//---------------------------------------------------------------------------
function GetBufferSize(Driver: IASIO; MinSize, MaxSize, PreferredSize,
Granularity: PInteger): ASIOError;
asm
push Granularity
push PreferredSize
push MaxSize
push MinSize
mov ecx, Driver
mov eax, [ecx]
call [eax+44]
end;
//---------------------------------------------------------------------------
function CanSampleRate(Driver: IASIO; SampleRate: ASIOSampleRate):
ASIOError;
asm
push DWORD PTR [SampleRate+4]
push DWORD PTR [SampleRate]
mov ecx, Driver
mov eax, [ecx]
call [eax+48]
end;
//---------------------------------------------------------------------------
function GetSampleRate(Driver: IASIO; SampleRate: PASIOSampleRate):
ASIOError;
asm
push SampleRate
mov ecx, Driver
mov eax, [ecx]
call [eax+52]
end;
//---------------------------------------------------------------------------
function SetSampleRate(Driver: IASIO; SampleRate: ASIOSampleRate):
ASIOError;
asm
push DWORD PTR [SampleRate+4]
push DWORD PTR [SampleRate]
mov ecx, Driver
mov eax, [ecx]
call [eax+56]
end;
//---------------------------------------------------------------------------
function GetClockSources(Driver: IASIO; Clocks: PASIOClockSource;
NumSources: PInteger): ASIOError;
asm
push NumSources
push Clocks
mov ecx, Driver
mov eax, [ecx]
call [eax+60]
end;
//---------------------------------------------------------------------------
function SetClockSource(Driver: IASIO; Reference: Integer): ASIOError;
asm
push Reference
mov ecx, Driver
mov eax, [ecx]
call [eax+64]
end;
//---------------------------------------------------------------------------
function GetSamplePosition(Driver: IASIO; sPos: PASIOSamples; TimeStamp:
PASIOTimeStamp): ASIOError;
asm
push TimeStamp
push sPos
mov ecx, Driver
mov eax, [ecx]
call [eax+68]
end;
//---------------------------------------------------------------------------
function GetChannelInfo(Driver: IASIO; Info: PASIOChannelInfo): ASIOError;
asm
push Info
mov ecx, Driver
mov eax, [ecx]
call [eax+72]
end;
//---------------------------------------------------------------------------
function CreateBuffers(Driver: IASIO; BufferInfos: PASIOBufferInfo;
NumChannels, BufferSize: Integer; CallBacks: PASIOCallBacks): ASIOError;
asm
push Callbacks
push BufferSize
push NumChannels
push BufferInfos
mov ecx, Driver
mov eax, [ecx]
call [eax+76]
end;
//---------------------------------------------------------------------------
function DisposeBuffers(Driver: IASIO): ASIOError;
asm
mov ecx, Driver
mov eax, [ecx]
call [eax+80]
end;
//---------------------------------------------------------------------------
function ControlPanel(Driver: IASIO): ASIOError;
asm
mov ecx, Driver
mov eax, [ecx]
call [eax+84]
end;
//---------------------------------------------------------------------------
function Future(Driver: IASIO; Selector: Integer; Option: Pointer):
ASIOError;
asm
push Option
push Selector
mov ecx, Driver
mov eax, [ecx]
call [eax+88]
end;
//---------------------------------------------------------------------------
function OutputReady(Driver: IASIO): ASIOError;
asm
mov ecx, Driver
mov eax, [ecx]
call [eax+92]
end;
 

Re: Thiscall

Avatar Zondertau writes:
Quote
Indeed it looks like the function is not perofrming a check for that
case.

Try this one:

function Thiscall(ClassRef, ProcRef: Pointer;
Params: array of Longword): LongWord;
asm
PUSH EBX
MOV EBX, [EBP+8]
TEST EBX, EBX
JS @@ParamsDone

LEA ECX, [ECX+EBX*4]
@@ParamLoop:
PUSH DWORD PTR [ECX]
LEA ECX, [ECX-4]
DEC EBX
JNS @@ParamLoop

@@ParamsDone:
MOV ECX, [EBP-8]
CALL EDX
POP EBX
end;
Still having problems. Calling your routine with:
thiscall(classref,procref,[200,200]);
Gives:
exception message : Access violation at address 004F492B in module
'<module name...>'. Write of address 00003D8C.
While the code I have written as a test performs fine:
asm
mov ecx, classref
mov edx, procref
mov eax, 200
push eax
mov eax, 200
push eax
call edx
end;
Cheers,
Nicholas Sherlock
 

Re: Thiscall

Quote
Still having problems. Calling your routine with:

thiscall(classref,procref,[200,200]);

Gives:

exception message : Access violation at address 004F492B in module
'<module name...>'. Write of address 00003D8C.

While the code I have written as a test performs fine:

asm
mov ecx, classref
mov edx, procref
mov eax, 200
push eax
mov eax, 200
push eax
call edx
end;
And like this?
function Thiscall(ClassRef, ProcRef: Pointer;
Params: array of Longword): LongWord;
asm
PUSH EBX
MOV EBX, [EBP+8]
TEST EBX, EBX
JS @@ParamsDone
LEA ECX, [ECX+EBX*4]
@@ParamLoop:
PUSH DWORD PTR [ECX]
LEA ECX, [ECX-4]
DEC EBX
JNS @@ParamLoop
@@ParamsDone:
MOV ECX, EAX
CALL EDX
POP EBX
end;
 

Re: Thiscall

Avatar Zondertau writes:
Quote
And like this?

function Thiscall(ClassRef, ProcRef: Pointer;
Params: array of Longword): LongWord;
asm
...
That works just fine, thanks! :). What was wrong with the old one..?
Cheers,
Nicholas Sherlock
 

Re: Thiscall

Quote
>And like this?
>
>function Thiscall(ClassRef, ProcRef: Pointer; Params: array of
>Longword): LongWord;
>asm

That works just fine, thanks! :). What was wrong with the old one..?
Florent's version pushed EAX on the stack and popped it later on. I
modified that, because it wasn' needed and caused return values not to
be returned, but i forgot to change the line that loads the class
pointer as well, so the class pointer was invalid.