Receive an array of string from a c++ DLL in Delphi 7 - c++

I am creating a DLL in C++, it would be used in a Delphi 7 project.
This question is related to this one, where I present two functions Validate and GetToken only that now they will be done in C++ and the array of strings GetToken produces would be sent back to Delphi.
The problems is I don't know how to create the function in the dll that will return the array of string in c++, and I don't know how it would be stored for further use in Delphi.
The declaration of the function is as follows:
function GetToken(Chain:string):Arrayofstring;

According to your code review, the Delphi code expects the function to have the following signature:
function GetToken(Chain: AnsiString): array of AnsiString;
You cannot write such a function in C++. C++ doesn't know what Delphi strings are, and it doesn't know what Delphi dynamic arrays are, either. Both types need to be allocated from Delphi's memory manager, which your C++ DLL won't have access to. Furthermore, C++ doesn't know how to use Delphi's register calling convention.
The DLL interface was designed poorly. DLLs should never use language-specific types unless it was the designer's intention to exclude all other languages. (And in this case, even later versions of the same language are excluded because the definition of AnsiString changed in Delphi 2009 to include more metadata that Delphi 7 won't handle properly.) The safest calling convention to choose is generally stdcall. It's what everything in the Windows API uses.
A better interface would use types that are common to all languages, and it would dictate the use of memory management that's accessible universally. There are several common ways to do that. For example:
The strings are returned as simple nul-terminated arrays of characters — PAnsiChar in Delphi; char* in C++. The DLL allocates buffers for the strings, and also allocates a buffer for the array of those strings. When the host application is finished using the array and the strings, it calls another function exported by the DLL wherein the DLL frees the memory it allocated. This is the model used by, for example, FormatMessage; when the host program is finished the with message string, it calls LocalFree.
type
PStringArray = ^TStringArray;
TStringArray = array[0..Pred(MaxInt) div SizeOf(PAnsiChar)] of PAnsiChar;
function GetToken(Char: PAnsiChar): PStringArray; stdcall;
procedure FreeStringArray(StringArray: PStringArray); stdcall;
char** __stdcall GetToken(char const* Chain);
void __stdcall FreeStringArray(char** StringArray);
Use COM to return a safearray of BStr objects. It's similar to the previous technique, but the memory management is defined by COM instead of by your DLL, so there's less stuff that needs to be defined by either party of the interface.
Pass a callback function to the DLL, so instead of returning an array of strings, the DLL just calls the function once for each string it identifies. Then you don't have to define what any array looks like, and the lifetime of each string can be just the lifetime of the callback call — if the host application wants a copy, it can do so. The new function signature would look something like this:
type
TTokenCallback = procedure(Token: PAnsiChar); stdcall;
procedure GetToken(Chain: PAnsiChar; ProcessToken: TTokenCallback); stdcall;
typedef void (__stdcall* TokenCallback)(char const* Token);
void __stdcall GetToken(char const* Chain, TokenCallback ProcessToken);
If you're not the one who designed the DLL interface, then you need to lean on the folks who did and get it changed to be more accessible to non-Delphi code. If you can't do that, then the final alternative is to write a DLL in Delphi that wraps your DLL to massage the parameters into something each side understands.

Related

Calling c++ function from delphi

I wrote a DLL in C++ whose functions will be called from a Delphi application.
One of the functions in the DLL takes a Pointer to a buffer where an XML string should be written. But, when I write a string into the buffer, after returning from the function the application crashes with an "Access violation at address 0048B... in module ....exe. Write of address 3030D..." error.
The calling convention of the function declarations are the same, both in the DLL and the application.
I've made a simple application in Delphi to simulate the behavior of the application and it works fine. The biggest problem is that I don't have any information about the application internals: no sources, no documents, not even logs. Just function declarations and parameter descriptions.
Function declaration in delphi:
function functionName(var Buffer: Pointer; var BuffLen: Integer): Integer; stdcall;
Function Declaration in the DLL:
extern "C" int WINAPI functionName(char*, int*);
Does someone know how to solve this?
From my tests, I have a feeling that the problem is in the application, not in the DLL. However, I'm not completely sure about this. Are there any possible tests I can do at the DLL site to either solve the problem or locate the issue?
I'd really appreciate any help in this matter.
As a side note, the DLL is compiled with Visual Studio. Can this cause the problem?
The DLL function you showed is declared wrong in your Delphi code. var Buffer: Pointer is equivilent to void** in C, or void*& in C++, but certainly not to char* like the DLL function is expecting. Using a void**/void*& parameter would be useful if the DLL were allocating memory to return to the application, but from your description that is not the case.
Use this Delphi declaration instead:
function functionName(Buffer: PAnsiChar; var BuffLen: Integer): Integer; stdcall;
PAnsiChar in Delphi is equivalent to char* in C/C++.
You should read the following blog article about the gotchas to watch out for when converting C/C++ declarations to Delphi:
Rudy's Delphi Corner: Pitfalls of converting

“The value of ESP was not properly saved across a function call.”

I have a DLL written in Delphi 7 that I need to use in Visual C++ 2008.
From documentation that came with DLL, I can see that function is declared as (Delphi 7):
function ReadInfo(pCOM, pBuf, pErr: Pointer):boolean;
where pCom is pointer to data structure:
TCOM = record
dwBaudRate: Longword;
nCom,
nErr,
nLang : Byte;
end;
pBuf is pointer to "array of byte" (as it is written in DLL's documentation).
pErr - not used.
So now in c++ (after successfully loading DLL with LoadLibrary), I call:
myFunc = (MY_FUNC_POINTER)GetProcAddress(dllHandle, "ReadInfo");
which also doesn't return any errors.
MY_FUNC_POINTER is defined as:
typedef bool (*MY_FUNC_POINTER)(TCOM*, BYTE*, void*);
where TCOM is:
struct TCOM
{
unsigned long dwBaudRate;
BYTE nComm;
BYTE nError;
BYTE nLanguage;
};
I defined:
TCOM MyCom;
BYTE *myRes;
myRes = new BYTE[1024*1024];
But after calling
myFunc(&MyCom, myRes, NULL)
I get “The value of ESP was not properly saved across a function call.” error.
There would appear to be a calling convention mismatch. On the face of it, the function declares no calling convention in the Delphi, so the default Borland register convention is used. Your C++ code does not declare a calling convention for the import so the default of cdecl is used. But it is plausible that the Delphi code and documentation are not aligned and the Delphi code actually uses a different calling convention. Check the Delphi code, or contact the vendor. No matter what, the error message that you report does indicate a binary mis-match across the boundary between your module and the other module.
If the function really does use the Borland register calling convention (but see below for more), then you cannot readily call the function from languages other than Delphi. In that case you'd need a bridge to adapt that to a standard calling convention such as stdcall. By that I mean a Delphi DLL that can call the original DLL and expose it's functionality a way suited to interop. A better solution would be to fix the root problem and build the DLL again using standard calling conventions.
In fact, I now suspect that all the other commentators are correct. I suspect that the Delphi documentation does not match the Delphi code. I suspect that the function really is stdcall. So you can, probably, solve your problem by changing the function pointer typedef to be as follows:
typedef bool (__stdcall *MY_FUNC_POINTER)(TCOM*, BYTE*, void*);
My reasoning for this is that in stdcall the callee is responsible for cleaning the stack. That's not the case for cdecl, and since all the parameters, and the return value, fit in registers, it's not the case for Delphi register calling convention, for this function. Since there is a stack pointer mis-match, it follows that the most likely explanation is that the Delphi function is stdcall.
All the same, it's not comfortable to be working out calling conventions this way. If you cannot get any help from the DLL vendor then I'd be inclined to dig a little deeper by looking at the DLL function's code under a disassembler.

C++ dll function calling in delphi7

I am using Delphi7 and I am new in it.
I want to use function of Dll(Implemented in C++) in my Delphi Project.
I have a function declaration in C++ like- (given by third party)
Syntax
LPTSTR GetErrorString(LONG lErrorNumber)
Arguments
LONG lErrorNumber Error number
Result
LPTSTR Error string
But when I am passing a value in Delphi7 like
GetErrorString(310);
I am declaring it in my unit-
Function GetErrorString(lErrorNumber : LongInt): String;StdCall;
implementation
Function GetErrorString;external 'Third-Party.DLL';
I am receiving blank string instead of actual Error String. I don't know the exact data type of LPTSTR.
Also tell me the proper steps to use it in my project.
LPTSTR is just a pointer to raw character data. Delphi's equivilent is either PAnsiChar or PWideChar, depending on whether the DLL was compiled for Ansi or Unicode. LPTSTR is always Ansi in Delphi 2007 and earlier (which includes Delphi 7) and always Unicode in Delphi 2009 and later, so you may need to account for that. If the DLL was compiled for Unicode, you would have to ue PWideChar instead of LPTSTR. As such, it is better to use PAnsiChar and PWideChar directly instead of LPTSTR to avoid mismatches between different environments (unless the DLL exports separate versions of the function for both types, like most Win32 API functions do).
Also, depending on the actual calling convention being used by the DLL, the function may be using cdecl or stdcall. In the absence of an explicit calling convention, most C/C++ compilers use cdecl, but they could just as easily be using stdcall and just not document it. So you need to find out, because it makes a BIG difference because cdecl and stdcall have different semantics for stack management and parameter passing.
So, with that said, the correct function declaration will be either:
function GetErrorString(lErrorNumber: Integer): PAnsiChar; cdecl; external 'filename.dll';
Or:
function GetErrorString(lErrorNumber: Integer): PWideChar; cdecl; external 'filename.dll';
Or:
function GetErrorString(lErrorNumber: Integer): PAnsiChar; stdcall; external 'filename.dll';
Or:
function GetErrorString(lErrorNumber: Integer): PWideChar; stdcall; external 'filename.dll';
You will have to do some research to find out whether the DLL is using Ansi or Unicode, and whether it is using cdecl or stdcall, if the documentation does not specifically state that information.
First, a Delphi string is refcounted, and thus something else than a pointer to char (LPTSTR). I suggest you avoid those traps as beginner, and go for straight pointers.
Second LPTSTR is a pointer to a one byte char (LPSTR), or a pointer to a two byte char (LPWSTR) depending on if UNICODE is defined.
So the correct solution is to make the function return pansichar or pwidechar, depending on how UNICODE was defined in your C++ program.
If you start passing character buffers between different languages, make sure they use the same allocator to (de)allocate them, or make sure that each module frees the allocations that it makes.

exporting C++ dll to Delphi program

I have a dll with exporting function
extern "C" __declspec(dllexport) IDriver * __stdcall GetDriver()
There is a programm which is written on Delphi. It can't see the function GetDriver().
It's double awful because I can not get and modify sources of this program.
What may be the reason of successful loading my dll (according log file) and failed call exporting function? Thank you.
Window 7 x64, Visual Studio 2010, C++ project for x86 target
The most likely explanation is that the function will have been exported with a decorated name. I'd expect it to have been exported with the name GetDriver#0. So you could import it like this:
function GetDriver: IDriver; stdcall; external 'DllName.dll' name 'GetDriver#0';
Use a tool like Dependency Walker to check the exact name used to export the function.
If you cannot modify the Delphi code, then you'll need to make your C++ DLL match. Do that by using a .def file which allows you control over the exported name.
The other problem you will face is that Delphi's ABI for return values differs from that used by most other tools on the Windows platform. Specifically a return value is semantically a var parameter. On the other hand, your C++ compiler will regard the return value as an out parameter. My question on Delphi WideString return values covers exactly this issue.
Because of this, I'd expect the function declaration above to lead to access violations. Instead you should declare the return value to be a Pointer and cast it to an interface reference in your Delphi code. You'll need to double check and make sure that the reference counting is handled appropriately.
Again, if you cannot modify the Delphi code, you need to make the C++ code match. A Delphi interface return value is implemented as an additional var parameter following the other parameters. So, to make your C++ function match, declare it like this:
void __stdcall GetDriver(IDriver* &retVal);

Is it possible to pass a reference to a pointer from Excel VBA to C++?

I would like to call my own C++ dll function from excel vba:
void my_cpp_fun ( int& n_size, double*& my_array);
The C++ function creates an array my_array of variable size n_size (this size is computed within my_cpp_fun).
Can I interface this function as is to VBA without using any Excel specific stuff in my C++ code?
So basically what I am looking for is a VBA Declare statement like
Declare Sub my_cpp_fun Lib "my_cpp.dll" (n_size As Long, Ref_to_Ptr_Qualifier my_array As Double)
An additional problem that just occured to me: If I allocate memory inside the c++ dll using new, will that memory be available once the dll function returns control to VB? If that is not the case, the above is pointless...
Short answer: yes, it is possible (and easier than the COM route, in my opinion) to call functions in a DLL from VBA. In my experience, the best way to go is to write wrapper functions with C linkage (to avoid running into various C++ name-mangling schemes) and exposing an interface of pointers rather than references (as the appropriate VBA type to declare a reference argument or result will be rather difficult to predict).
A great guide for how to write appropriate Declare statements (assuming 32-bit Windows) is Chapter 2 of the book "Hardcore Visual Basic", if you can find it.
Note also that any functions exposed to VBA via Declare statements will need to use stdcall (aka WINAPI) calling convention.
TLDR:
I'd do this:
extern 'C' {
void WINAPI my_cpp_fun_wrapper ( int *n_size, double **my_array )
{
my_cpp_fun(*n_size, *my_array);
}
}
and then
Declare Sub my_cpp_fun_wrapper Lib "my_cpp.dll" (ptr_n_size As Long, ptr_ptr_my_array As Long)
and use the various *Ptr functions of VB6/VBA to get the pointers to my data.
You'd need to create a COM object that exposes your function and load it in your VBA using CreateObject