2

I'm not able to use the function of a dll developed in delphi. I'm having some difficulties with the conversions of types.

This is the function I want to call the DLL:

function rData(ID: Cardinal; queue: WideString): WideString; stdcall;

My code in C++ was so:

typedef string (*ReturnDataSPL)(DWORD, string);

string result;
HMODULE hLib;
hLib = LoadLibrary("delphi.dll");
pReturnDataSPL = (ReturnDataSPL)GetProcAddress(hLib,"rData");
if (NULL != pReturnDataSPL)
   result = pReturnDataSPL(JobID,printerName);

The problem I'm not able to make it work. I do not know which type is compatible with Delphi WideString and Cardinal.

Someone help me

EDIT:

This is the function I want to call the DLL:

procedure rData(ID: Cardinal; queue: WideString; var Result: WideString); stdcall;

After changing the code looked like this:

typedef void (__stdcall *ReturnDataSPL)(DWORD, BSTR, BSTR&);

HMODULE hLib;
BSTR result = NULL;
hLib = LoadLibrary("delphi.dll");

pReturnDataSPL = (ReturnDataSPL)GetProcAddress(hLib,"rData");
if (NULL != pReturnDataSPL)
{
   pReturnDataSPL(JobID,(BSTR)"Lexmark X656de (MS) (Copiar 2)",result);
}
msantiago
  • 346
  • 2
  • 4
  • 14

1 Answers1

11

You've got very little chance of calling that function.

For a start your current code can't hope to succeed since I presume string is std::string. That's a C++ data type which Delphi code cannot either provide or consume. To match up against Delphi's WideString you need to use the COM BSTR data type.

Another problem with your code as it stands is that it uses cdecl in the C++ side, and stdcall on the Delphi side. You'll need to align the calling conventions.

However, that will also fail because of a difference between Delphi's ABI for return values, and the platform standard. That topic was covered in detail here: Why can a WideString not be used as a function return value for interop?

Your best bet is to stop using WideString as a return value and convert it into a C++ reference parameter. You'll want to convert the Delphi to match.

You are looking at something like this:

Delphi

procedure rData(ID: Cardinal; queue: WideString; var Result: WideString); stdcall;

C++

typedef void (__stdcall *ReturnDataSPL)(DWORD, BSTR, BSTR&);
Community
  • 1
  • 1
David Heffernan
  • 601,492
  • 42
  • 1,072
  • 1,490
  • I changed the code as above: But when the function is executed I get an exception: 'Unhandled exception at 0x772b15ee in CallbackSample.exe: 0xC0000005: Access violation reading location 0x00000000.' what can it be? Thank you – msantiago Apr 02 '13 at 16:19
  • 2
    Your C++ code doesn't match mine. Third parameter must be passed by reference. Compare the difference between your code and mine. Also, you can't just cast a BSTR into existence. You've got to make a real BSTR! – David Heffernan Apr 02 '13 at 16:23
  • SysAllocString to make a BSTR. Or use one of the BSTR convenience wrappers. – David Heffernan Apr 02 '13 at 16:36
  • Good. Remember to free your BSTRs. – David Heffernan Apr 02 '13 at 17:28
  • I would make use of the `WideString` class in the C++ code to manage the BSTR memory. For the second parameter, you can use `WideString::c_bstr()` to pass a BSTR value to the function. For the third parameter, I would change its declaration to `BSTR*` and then use `WideString`'s overridden `&` operator to pass a `BSTR*` to the function, eg: `typedef void (__stdcall *ReturnDataSPL)(DWORD, BSTR, BSTR*); WideString result; pReturnDataSPL(JobID, WideString("Lexmark X656de (MS) (Copiar 2)").c_bstr(), &result);` – Remy Lebeau Apr 02 '13 at 21:25
  • @Remy WideString is not available in most C++ compilers. Only in the very rarely seen Embarcadero compiler. Until stated otherwise I'm assuming the common compilers, MSVC or GNU. – David Heffernan Apr 03 '13 at 05:58
  • @DavidHeffernan: Other compilers have similar classes available, like `_bstr_t` or `CComBSTR`. – Remy Lebeau Apr 03 '13 at 16:09
  • @remy yep, that's what I meant in an earlier comment – David Heffernan Apr 03 '13 at 16:38