0

First things first -- I'm talking about the x64 environment.

I need to call the following function in Delphi code:

Function Foo : WideString; StdCall; External 'Callee.dll' Delayed;

This function is exported from the C++ library named "Callee.dll" like this:

extern "C" __declspec(dllexport) BSTR __stdcall Foo()
{
    return SysAllocString(L"Foo");
}

The function is actually called (I've set and hit a breakpoint on C++ side) but the return value on Delphi side is an empty string.

If I change the calling convention of this function from __stdcall to __safecall like this

// Delphi
Function Foo : WideString; SafeCall; External 'Callee.dll' Delayed;

// C++
extern "C" __declspec(dllexport) HRESULT __stdcall Foo(BSTR* desc)
{
    *desc = SysAllocString(L"Foo");
    return S_OK;
}

everything works as expected.

But the thing is I can't change the calling convention as it is an already-existing contract (that is, I can NOT change anything on the Delphi side).

I think that this has something to do with the following statement from MSDN:

On ARM and x64 processors, __stdcall is accepted and ignored by the compiler; on ARM and x64 architectures, by convention, arguments are passed in registers when possible, and subsequent arguments are passed on the stack

https://learn.microsoft.com/en-us/cpp/cpp/stdcall?view=vs-2019

What can I do in this situation? Thanks.

FrozenHeart
  • 19,844
  • 33
  • 126
  • 242
  • [Why can a WideString not be used as a function return value for interop?](https://stackoverflow.com/q/9349530/327083) – J... May 07 '20 at 16:58
  • @J... thanks for the link, changing the C++ side to `void __stdcall Foo(BSTR* desc)` works as expected. But I've just noticed that if I change `BSTR` / `WideString` to `int` / `Integer` in the original code everything works as expected even without switching to the out parameter. Why? – FrozenHeart May 07 '20 at 17:31
  • Because `BSTR` / `WideString` is complex and varies in length, needing more than 32bit. And `int` / `Integer` is always and only 32bit. – AmigoJack May 07 '20 at 18:27
  • @FrozenHeart Another way to handle this is to leave the C++ side as `BSTR __stdcall Foo()` and change the Delphi side to `Function Foo : TBStr; StdCall;` or `Function Foo : PWideChar; StdCall;` to match it, and then typecast the returned pointer to `WideString` when calling the function, eg: `var W: WideString; Pointer(W) = Foo; ...` – Remy Lebeau May 07 '20 at 19:32

0 Answers0