callback c delphi - c++

This is procedure which is defined in C++ application (exe HOST).
typedef struct _ RX_DATA_OBJ {
UINT32 TIME;
UINT32 ID;
UINT8 LEN;
UINT8 DATA[8];
} RX_DATA_OBJ;
static void RX_DATA(UINT16 CNT, RX_DATA_OBJ *p_RX_DTATA_OBJ)
I need to call as callback above function in my DLL file written in Delphi.
I made the following declaration in Delphi for my DLL:
type
TRX_DATA_OBJ = record
time: UINT32;
id: UINT32;
len: UINT8;
data: array [0..7] of UINT8;
end;
PRX_DATA_OBJ = ^TRX_DATA_OBJ;
RX_DATA = procedure(count:UINT16; RX_DATA_OBJ: PRX_DATA_OBJ ) of object;
var
RX_DATA_out: TRX_DATA_OBJ;
In another procedure I get the pointer to the RX_DATA procedure in HOST.
Now I call this callback in my DLL
procedure PUT_DATA;
begin
RX_DATA_out.Time := 100;
RX_DATA_out.id := $500;
RX_DATA_out.len := 4;
RX_DATA_out.data[0] := 1;
RX_DATA_out.data[1] := 2;
RX_DATA_out.data[2] := 3
RX_DATA_out.data[3] := 4;
RX_DATA_out.data[4] := 5;
RX_DATA_out.data[5] := 6;
RX_DATA_out.data[6] := 7;
RX_DATA_out.data[7] := 8;
RX_DATA(1, #RX_DATA_out); // RX_DATA_out is global variable defined.
end;
Callback is called correct but data passed in RX_DATA_out variable are not correct, it looks that pointer to RX_DATA_out variable is not pointing on this variable.
Can anybody say what can be wrong ?

The C++ function type is a plain function, i.e. not a member function. But you have declared your version to be a method of object. That is a mismatch. You must remove of object.
You must also specify the calling convention. Most likely it will be cdecl. In Delphi, if the calling convention is not specified, then the register based Delphi fastcall convention, register is used. That's certainly wrong.
Finally, if the pointer to the struct can never be nil then it is more idiomatic to use a var parameter:
RX_DATA = procedure(count:UINT16; var RX_DATA_OBJ: TRX_DATA_OBJ); cdecl;
And obviously you'd have to change the calling code to match:
RX_DATA(1, RX_DATA_out);

Related

How to call __stdcall function exported from C++ 64-bit DLL [duplicate]

I have, on more than one occasion, advised people to use a return value of type WideString for interop purposes.
Accessing Delphi DLL throwing ocasional exception
ASP.NET web app calling Delphi DLL on IIS webserver, locks up when returning PChar string
Why can Delphi DLLs use WideString without using ShareMem?
The idea is that a WideString is the same as a BSTR. Because a BSTR is allocated on the shared COM heap then it is no problem to allocate in one module and deallocate in a different module. This is because all parties have agreed to use the same heap, the COM heap.
However, it seems that WideString cannot be used as a function return value for interop.
Consider the following Delphi DLL.
library WideStringTest;
uses
ActiveX;
function TestWideString: WideString; stdcall;
begin
Result := 'TestWideString';
end;
function TestBSTR: TBstr; stdcall;
begin
Result := SysAllocString('TestBSTR');
end;
procedure TestWideStringOutParam(out str: WideString); stdcall;
begin
str := 'TestWideStringOutParam';
end;
exports
TestWideString, TestBSTR, TestWideStringOutParam;
begin
end.
and the following C++ code:
typedef BSTR (__stdcall *Func)();
typedef void (__stdcall *OutParam)(BSTR &pstr);
HMODULE lib = LoadLibrary(DLLNAME);
Func TestWideString = (Func) GetProcAddress(lib, "TestWideString");
Func TestBSTR = (Func) GetProcAddress(lib, "TestBSTR");
OutParam TestWideStringOutParam = (OutParam) GetProcAddress(lib,
"TestWideStringOutParam");
BSTR str = TestBSTR();
wprintf(L"%s\n", str);
SysFreeString(str);
str = NULL;
TestWideStringOutParam(str);
wprintf(L"%s\n", str);
SysFreeString(str);
str = NULL;
str = TestWideString();//fails here
wprintf(L"%s\n", str);
SysFreeString(str);
The call to TestWideString fails with this error:
Unhandled exception at 0x772015de in BSTRtest.exe: 0xC0000005: Access violation reading location 0x00000000.
Similarly, if we try to call this from C# with p/invoke, we have a failure:
[DllImport(#"path\to\my\dll")]
[return: MarshalAs(UnmanagedType.BStr)]
static extern string TestWideString();
The error is:
An unhandled exception of type 'System.Runtime.InteropServices.SEHException' occurred in ConsoleApplication10.exe
Additional information: External component has thrown an exception.
Calling TestWideString via p/invoke works as expected.
So, use pass-by-reference with WideString parameters and mapping them onto BSTR appears to work perfectly well. But not for function return values. I have tested this on Delphi 5, 2010 and XE2 and observe the same behaviour on all versions.
Execution enters the Delphi and fails almost immediately. The assignment to Result turns into a call to System._WStrAsg, the first line of which reads:
CMP [EAX],EDX
Now, EAX is $00000000 and naturally there is an access violation.
Can anyone explain this? Am I doing something wrong? Am I unreasonable in expecting WideString function values to be viable BSTRs? Or is it just a Delphi defect?
In regular Delphi functions, the function return is actually a parameter passed by reference, even though syntactically it looks and feels like an 'out' parameter. You can test this out like so (this may be version dependent):
function DoNothing: IInterface;
begin
if Assigned(Result) then
ShowMessage('result assigned before invocation')
else
ShowMessage('result NOT assigned before invocation');
end;
procedure TestParameterPassingMechanismOfFunctions;
var
X: IInterface;
begin
X := TInterfaceObject.Create;
X := DoNothing;
end;
To demonstrate call TestParameterPassingMechanismOfFunctions()
Your code is failing because of a mismatch between Delphi and C++'s understanding of the calling convention in relation to the passing mechanism for function results. In C++ a function return acts like the syntax suggests: an out parameter. But for Delphi it is a var parameter.
To fix, try this:
function TestWideString: WideString; stdcall;
begin
Pointer(Result) := nil;
Result := 'TestWideString';
end;
In C#/C++ you will need to define the Result as out Parameter, in order to maintain binary code compatibility of stdcall calling conventions:
Returning Strings and Interface References From DLL Functions
In the stdcall calling convention, the function’s result is passed via the CPU’s EAX register. However, Visual C++ and Delphi generate different binary code for these routines.
Delphi code stays the same:
function TestWideString: WideString; stdcall;
begin
Result := 'TestWideString';
end;
C# code:
// declaration
[DllImport(#"Test.dll")]
static extern void TestWideString([MarshalAs(UnmanagedType.BStr)] out string Result);
...
string s;
TestWideString(out s);
MessageBox.Show(s);

GoLang Convert C.wchar_t to go string

I am looking to convert a [32]C.wchar_t to a go string.
The array is defined as follows in the dll I am talking to:
typedef struct myStruct {
WCHAR someString[32];
}
I am defining the struct in go as follows:
type myStruct struct {
someString [32]C.wchar_t
}
I have a method in the dll:
DLLINTERFACE HRESULT __stdcall GetMyStruct (myStruct* ptrMyStruct);
This method will populate the someString field of myStruct.
I am calling the method like so (this is working correctly, I think, I have not been able to see the contents of someString):
func getMyStruct() (*myStruct, uintptr) {
var getMyStruct = dll.MustFindProc("GetMyStruct")
var args = new(myStruct)
ret, _, _ := getMyStruct .Call(uintptr(unsafe.Pointer(args)))
fmt.Printf("Return: %d\n", (int)(ret))
return args, ret
}
I need to convert someString to a go string. I have tried using "github.com/GeertJohan/cgo.wchar", but it does not have a method for converting []C.whar_t to go string.
Currently I'm not sure if my go struct is correct. I'm also not sure if I am initializing myStruct correctly before sending it to the dll.
Any help will be greatly appreciated.
On Windows, wchar_t is normally UTF-16 (little-endian). They don't normally start with a BOM (which is present so a decoder can detect if they are stored in big or little endian form).
There is a utf16 package but this only translates individual runes. However, there is an additional unicode text encoding package that can help.
You would probably do something like this:
dec:=unicode.UTF16(unicode.LittleEndian,unicode.UseBOM).NewDecoder()
out,err:= dec.Bytes(([]byte)(unsafe.Pointer(args.someString)))
if err!=nil {
//handle error
}
// Strings are null terminated, only want content up to null byte
i:=bytes.IndexByte(out,0)
if i==-1 {
i = len(out)
}
s:=string(out[:i])
However, I'd be tempted to declare someString as [64]byte which is the amount of bytes that a 32 character (16 bites = 2 bytes per character) would need. This would avoid the unsafe typecasting but otherwise should work as above.
I'm doing this off the top of my head so the code above is meant as an example & may not necessarily work - use at your peril :-)
It seems GeertJohan's library hasn't been updated for the more recent cgo changes, but a fork has, try github.com/vitaminwater/cgo.wchar (godoc) instead.
If the C function writes to a C type, pass a variable of the C type.
A (dodgy) example:
package main
/*
#include <wchar.h>
#include <string.h>
typedef struct myStruct {
wchar_t someString[32];
} myStruct;
wchar_t sample[6] = {0x0048, 0x0069, 0x0020, 0x4e16, 0x754c, 0};
void writeSample(myStruct *m) {
memcpy(m->someString, &sample, sizeof(wchar_t) * 6);
}
*/
import "C"
import (
"fmt"
"log"
"unsafe"
"github.com/vitaminwater/cgo.wchar"
)
func main() {
m := C.myStruct{}
C.writeSample(&m)
s, err := wchar.WcharStringPtrToGoString(unsafe.Pointer(&m.someString))
if err != nil {
log.Fatal(err)
}
fmt.Println(s)
}
This outputs:
Hi 世界

Call Delphi CLASS exported in DLL from C++ code

i have a problem to use delphi class from C++ code. delphi dll demo that export a function that return an object.
my delphi Dll code is as follow:
library DelphiTest;
// uses part....
type
IMyObject = interface
procedure DoThis( n: Integer );
function DoThat : PWideChar;
end;
TMyObject = class(TInterfacedObject,IMyObject)
procedure DoThis( n: Integer );
function DoThat: PChar;
end;
// TMyObject implementation go here ...
procedure TMyObject.DoThis( n: Integer );
begin
showmessage('you are calling the DoThis methode with '+intToStr(n) +'parameter');
end;
function TMyObject.DoThat: PChar;
begin
showmessage('you are calling the DoThat function');
Result := Pchar('Hello im Dothat');
end;
// exporting DLL function :
function CreateMyObject : IMyObject; stdcall;export;
var
txt : TextFile;
begin
AssignFile(txt,'C:\log.log');
Reset(txt);
Writeln(txt,'hello');
Result := TMyObject.Create;
end;
exports CreateMyObject;
in my C++ project i declared the IMyObject interface as follow :
class IMyObject
{
public:
IMyObject();
virtual ~IMyObject();
virtual void DoThis(int n) = 0;
virtual char* DoThat() = 0;
};
and my main function as follow :
typedef IMyObject* (__stdcall *CreateFn)();
int main()
{
HMODULE hLib;
hLib = LoadLibrary(L"DelphiTest.dll");
assert(hLib != NULL); // pass !!
CreateFn pfnCreate;
pfnCreate = (CreateFn)GetProcAddress((HINSTANCE)hLib, "CreateMyObject");
if (pfnCreate == NULL)
{
DWORD errc = GetLastError();
printf("%u\n", errc); // it gets error 127
}
else{
printf("success load\n");
}
IMyObject* objptr = pfnCreate();
objptr->DoThis(5);
FreeLibrary(hLib);
int in;
scanf_s("%i", &in);
return 0;
}
with this example i got an error at run time when i try to access the exported function. the errors is at line :
IMyObject* objptr = pfnCreate();
can you tell me what is wrong about my example.
and if possible any working example to access Delphi class (in DLL) from C++ code.
The first problem is calling convention of the methods. The Delphi interface uses register which is a Delphi specific calling convention. Use stdcall, for example, for the methods of the interface.
The next problem is in the C++. Your C++ interface must derive from IUnknown. Further, it should not declare a constructor or destructor.
Beyond that your Delphi code exports PWideChar which does not map to char*. It maps to wchar_t*.
Looking further ahead, returning a PChar works fine here because your implementation returns a literal. But more serious code will want to use a dynamically allocated string presumably and at that point your design is flawed.
Do note that you need to be an elevate administrator to create a file at the root of the system drive. So that's yet another potential failure point.
I expect there are other mistakes, but that's all I've found so far.

Exception when calling a C++ DLL from Dephi XE

I'm trying to call a C++ DLL function that is defined like this:
int read_record (filep *fptr, int key, char *contents, int *status)
This is a widely used DLL, so I'm pretty certain the problem I'm having is how I'm calling the function.
The DLL docs have this example of how to call it
TFILETYPE *fptr; /* file pointer
char contents[80];
int status = 0;
int single = key;
if (read_record(fptr, key, card, &status)) break;
printf("%s\n", card);
Here's what I think should work, and almost does:
type
TCharArray = Array[1..100] of AnsiChar; // Function returns an array less than 100 char
var
read_record : function( var fptr: TFILETYPE;
Key: Integer;
var Contents: TCharArray; // function fills this in
var Status: Integer): Integer cdecl stdcall;
Procedure Test;
var
Contents: TCharArray;
Status: Integer;
Key: Integer;
begin
#read_record:= GetProcAddress(DLLHandle, 'read_record');
for Key := 1 to 10 do
begin
Contents[1] := #0; // shouldn't be necessary
if (read_record( fptr^, Key, Contents, Status) <> 0) OR (Status <> 0) then
ShowMessage('Error')
else
ShowMessage(Contents); // This shows the expected proper string on all 10 calls
...Other calls at this point to other functions in the DLL result in
an Exception writing to x01a.
end;
Multiple calls from Delphi XE work fine. But after that, when I call different function in the DLL that has always worked in the past, I get an exception writing to x0000001a, which I suspect means I've trashed memory or the stack.
The *fptr pointer datatype I'm using in calls to other functions in the dll, so I don't think that's the problem.
This is the first time I've tried to call a function that returns a string, so I suspect I'm not understanding something with call by reference of string arrays.
Any suggestions on how I should call this function differently to avoid what appears to be trashing of memory?
You have a couple of problems here.
First, the function declaration in Delphi is wrong. First, it's declared as both cdecl and stdcallat the same time. It needs to be one or the other; it can't be both simultaneously.
Also, you have an extra level of dereferencing on the fptr variable.
The declaration indicates it's a pointer:
filep *fptr
You've said in your Delphi declaration that it's a pointer:
var fptr: TFileType
But you're passing a pointer to a pointer:
fptr^
Change your call to the DLL function to
if (read_record( fptr, Key, Contents, Status) <> 0) OR (Status <> 0)
(I think your test of the results should actually be <> 0) AND (Status <> 0), but without the docs I'm not sure.)
If you do in fact need to initialize Contents before passing it to the DLL, you should use FillChar(Contents, SizeOf(Contents), #0) (or ZeroMemory) to do so, BTW.
As an additional suggestion, you can simplify your code somewhat (I've chosen stdcall as the calling convention):
var
read_record : function( var fptr: TFILETYPE;
Key: Integer;
Contents: PAnsiChar; // function fills this in
var Status: Integer): Integer stdcall;
var
Contents: AnsiString;
...
begin
SetLength(Contents, 100);
if (read_record(fptr, Key, PAnsiChar(Contents), Status)...
....
end;

C++ consuming delphi DLL

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);
}
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&);