I have a .DLL compiled in Delphi 7 that exports a function. I am trying to call that function from C++.
procedure SystemReload(lpMessage: PAnsiChar; dwIcon: byte; dwColor: byte);
var
dwMessage: cardinal;
procedure SystemReload_Real(lpMessage: PAnsiChar); assembler;
asm
...
end;
begin
dwMessage := $00415B30;
ShowGameMessage_Real(lpMessage);
end;
exports SystemReload name 'SystemReload';
begin
end.
And then the C++ code I am using to call the function:
int ShowGameMessage(char* Message, BYTE Icon, BYTE Color)
{
int ret;
if (exist("SysReload.dll"))
{
HMODULE hLib = LoadLibrary("SysReload.dll");
if (hLib)
{
typedef int(__stdcall *SGMessage)(char*, BYTE, BYTE);
SGMessage ShowGameMessage = (SGMessage)GetProcAddress(hLib, "SystemReload");
ret = (*ShowGameMessage)(Message, Icon, Color);
} else { FreeLibrary(hLib); }
FreeLibrary(hLib);
}
return ret;
}
The C++ code is crashing when calling the exported Delphi function.
How do I do things right without crashing the application?
You are not specifying a calling convention in your Delphi code. The default calling convention in Delphi is register (which is known as __fastcall in C++Builder, and is not supported by any other C++ compiler). Your C++ code is using __stdcall for the imported function (the default calling convention in C++ is usually __cdecl). Mixing calling conventions is undefined behavior, and can lead to all kinds of problems, including crashes. You need to specify the same calling convention in both languages. In this case, you should use stdcall in your Delphi code to match your use of __stdcall in your C++ code:
procedure SystemReload(lpMessage: PAnsiChar; dwIcon: byte; dwColor: byte); stdcall;
Also, your Delphi code is declaring the exported function as a procedure, which means it has no return value. But your C++ code is declaring the imported function as having an int return type. You should change your C++ code to use void to match your use of procedure in your Delphi code:
typedef void (__stdcall *SGMessage)(char*, BYTE, BYTE);
Also, on an unrelated note, your C++ code is calling FreeLibrary() twice if LoadLibrary() fails. You should not be calling FreeLibrary() at all if LoadLibrary() fails. Call it only once if LoadLibrary() succeeds. You should move your call to FreeLibrary() to inside your if (hLib) block:
void ShowGameMessage(char* Message, BYTE Icon, BYTE Color)
{
HMODULE hLib = LoadLibrary("SysReload.dll");
if (hLib)
{
typedef void (__stdcall *SGMessage)(char*, BYTE, BYTE);
SGMessage ShowGameMessage = (SGMessage) GetProcAddress(hLib, "SystemReload");
if (ShowGameMessage)
(*ShowGameMessage)(Message, Icon, Color);
FreeLibrary(hLib);
}
}
Your Delphi export does not look like it is __stdcall.
So either declare it as __fastcall if you are using C++Builder, or as stdcall in the DLL. Since it is a DLL export, stdcall is probably the better option.
If you don't use C++Builder, but another C++, then __fastcall is not an option, because then, your __fastcall is not compatible with Delphi's default register calling convention. Better to declare the DLL function as stdcall (or cdecl, although for DLLs, stdcall is more usual).
FWIW, using the default register calling convention for a DLL export is a no-no for the reasons layed out above.
More info: DLL dos and don'ts -- Calling convention.
Related
This line of Pascal code:
gh := GCanvas.Handle
(where GCanvas is a variable of type TCanvas)
converts to this in assembly language (as viewed in the CPU window):
mov eax,[GCanvas]
call TCanvas.GetHandle
mov [gh],eax
GetHandle is the private function that returns the value of FHandle defined in Graphics.pas
How can I access the TCanvas Handle property inside an asm statement?
I tried the call as above but the compiler returns "Undeclared identifier 'GetHandle'"
So how do you access properties where the value is returned by a function call?
Any help, please?
If the property accessor method is PRIVATE then the simple answer is: You can't. The compiler simply doesn't know that symbol at that point in your code. Even from Pascal, you can't, except by going via RTTI and that is probably too cumbersome to do from assembly.
The way to do it is to provide a "gateway" function that calls on to the property (which in turn calls the private function):
FUNCTION GetHandle(C : TCanvas) : HDC; Register; // Must be a Global function //
BEGIN
Result:=C.Handle
END;
and then from your assembly code:
VAR GCanvas : TCanvas;
VAR gh : THandle;
ASM
MOV EAX,GCanvas
CALL GetHandle
MOV [gh],EAX
END
If you make the GetHandle function a method of a class, you need to pass "Self" (the instance of the class) in EDX to the function as well.
I also found this this morning - if I end the asm statement to go back to Pascal and use the line
GCanvas.Handle;
this calls the GetHandle function and the result is left in eax - then enter a new asm statement and eax can be stored or pushed as needed.
I am doing a C++/CX runtime wrapper, and I need pass C++/CX Object pointer to native C. How do I do it, and convert the native pointer back to C++/CX Object reference type?
void XClassA::do(XClass ^ B)
{
void * ptr = (void*)(B); // how to convert it?
}
And also, C++/CX uses Reference Counting, if I cast the Object reference to native pointer, how do I manage the pointer life cycle?
update (request from #Hans Passant)
Background of the question,
Native C
I am trying to use C++/CX wrap Native C library (not C++) as Windows Runtime Component. Native c has many callback functions which declared as the following,
for example,
//declare in native c
typedef int (GetData*)(void *, char* arg1, size_t arg2);
void * is a pointer to object instance.
and the callback will be executed in native c during runtime.
We expect Application(C#/C++CX ...) to implement the method.
WinRT wrapper (C++/CX)
my idea is the following,
(1) Provide interface to Application
// XRtWrapperNamespace
public interface class XWinRtDataWrapper
{
//declare in base class
void getData(IVector<byte> ^ data);
}
to let Application implement the function. As I cannot export native data type, I provide IVector to get data from Application.
(2) Declare a global callback function to convert IVector<byte>^ to native data type char *, like following,
// when Native C executes callback function,
// it will forward in the method in C++/CX.
// The method calls the implementation method via object pointer.
// (And here is my my question)
void XRtWrapperNamespace::callbackWrapper(void * ptr, char *, int length)
{
// create Vector to save "out" data
auto data = ref new Vector<byte>();
// I expect I could call the implementation from Application.
ptr->getData(data); // bad example.
// convert IVector data to char *
// ...
}
My question is
How do I keep windows object reference to native C?
It looks impossible, but any solution to do it?
Application (example)
//Application
public ref class XAppData: public XWinRtDataWrapper
{
public:
virtual void getData(IVector<byte> ^ data)
{
//implementation here
}
}
You are not on the right track. I'll assume you #include a c header in your component:
extern "C" {
#include "native.h"
}
And this header contains:
typedef int (* GetData)(void* buffer, int buflen);
void initialize(GetData callback);
Where the initialize() function must be called to initialize the C code, setting the callback function pointer. And that you want the client code to directly write into buffer whose allocated size is buflen. Some sort of error indication would be useful, as well as allowing the client code to specify how many bytes it actually wrote into the buffer. Thus the int return value.
The equivalent of function pointers in WinRT are delegates. So you'll want to declare one that matches your C function pointer in functionality. In your .cpp file write:
using namespace Platform;
namespace YourNamespace {
public delegate int GetDataDelegate(WriteOnlyArray<byte>^ buffer);
// More here...
}
There are two basic ways to let the client code use the delegate. You can add a method that lets the client set the delegate, equivalent to way initialize() works. Or you can raise an event, the more WinRT-centric way. I'll use an event. Note that instancing is an issue, their is no decent mapping from having multiple component objects to a single C function pointer. I'll gloss this over by declaring the event static. Writing the ref class declaration:
public ref class MyComponent sealed
{
public:
MyComponent();
static event GetDataDelegate^ GetData;
private:
static int GetDataImpl(void* buffer, int buflen);
};
The class constructor needs to initialize the C code:
MyComponent::MyComponent() {
initialize(GetDataImpl);
}
And we need the little adapter method that makes the C callback raise the event so the client code can fill the buffer:
int MyComponent::GetDataImpl(void* buffer, int buflen) {
return GetData(ArrayReference<byte>((byte*)buffer, buflen));
}
Now I understand that Defining is to Types as Declaring is to Variables. But which one (Declare or Define) do functions/procedures/methods/subroutines fall under? Or do they have their own terminology?
In C and C++ you can declare a function (a function prototype) like this:
int function(int);
And then you can define it later, say, at the end of the file:
int function(int param) {
printf("This is the param: %d", param);
return 0;
}
So you can say that functions in C and C++ can fit into the terminology of both types and variables. It depends on the language you're using too, but this how I learned it.
Have prepared such function, where some WSA functions will be used as callback:
int StartWinSock(int (*WSAStartup)(WORD, LPWSADATA))
{
}
But when in other code, I'm trying to launch it:
StartWinSock(WSAStartup);
I'm getting an error:
'WSClient::StartWinSock' : cannot convert parameter 1 from 'int (__stdcall *)(WORD,LPWSADATA)' to 'int (__cdecl *)(WORD,LPWSADATA)'
Also, I don't know how to pass parameters correctly through callback function like WSAStartup() ( its parameters: WORD ( unsigned short number of version ) && LPWSADATA ( reference to WSAData ) ).
You are missing the __stdcall calling convention on the function pointer type, which comes from the WINAPI macro. The compiler is therefore assuming the default __cdecl calling convention for this pointer. The two calling conventions are not compatible.
Consider creating this typedef:
typedef int WINAPI (*WSAStartupCallback)(WORD, LPWSADATA);
Then declare your function like this:
int StartWinSock(WSAStartupCallback wsaStartup)
{
}
You should then be able to call this function with the external WSAStartup pointer.
The problem involved a JAVA call to a C-function (API) which returned a pointer-to-pointer as an argout argument. I was trying to call the C API from JAVA and I had no way to modify the API.
Using SWIG typemap to pass pointer-to-pointer:
Here is another approach using typemaps. It is targetting Perl, not Java, but the concepts are the same. And I finally managed to get it working using typemaps and no helper functions:
For this function:
typedef void * MyType;
int getblock( int a, int b, MyType *block );
I have 2 typemaps:
%typemap(perl5, in, numinputs=0) void ** data( void * scrap )
{
$1 = &scrap;
}
%typemap(perl5, argout) void ** data
{
SV* tempsv = sv_newmortal();
if ( argvi >= items ) EXTEND(sp,1);
SWIG_MakePtr( tempsv, (void *)*$1, $descriptor(void *), 0);
$result = tempsv;
argvi++;
}
And the function is defined as:
int getblock( int a, int b, void ** data );
In my swig .i file. Now, this passes back an opaque pointer in the argout typemap, becaust that's what useful for this particular situation, however, you could replace the SWIG_MakePtr line with stuff to actually do stuff with the data in the pointer if you wanted to. Also, when I want to pass the pointer into a function, I have a typemap that looks like this:
%typemap(perl5, in) void * data
{
if ( !(SvROK($input)) croak( "Not a reference...\n" );
if ( SWIG_ConvertPtr($input, (void **) &$1, $1_descriptor, 0 ) == -1 )
croak( "Couldn't convert $1 to $1_descriptor\n");
}
And the function is defined as:
int useblock( void * data );
In my swig .i file.
Obviously, this is all perl, but should map pretty directly to Java as far as the typemap architecture goes. Hope it helps...
[Swig] Java: Using C helper function to pass pointer-to-pointer
The problem involved a JAVA call to a C-function (API) which returned a pointer-to-pointer as an argout argument. I was trying to call the C API from JAVA and I had no way to modify the API.
The API.h header file contained:
extern int ReadMessage(HEADER **hdr);
The original C-call looked like:
HEADER *hdr;
int status;
status = ReadMessage(&hdr);
The function of the API was to store data at the memory location specified by the pointer-to-pointer.
I tried to use SWIG to create the appropriate interface file. SWIG.i created the file SWIGTYPE_p_p_header.java from API.h. The problem is the SWIGTYPE_p_p_header constructor initialized swigCPtr to 0.
The JAVA call looked like:
SWIGTYPE_p_p_header hdr = new SWIGTYPE_p_p_header();
status = SWIG.ReadMessage(hdr);
But when I called the API from JAVA the ptr was always 0.
I finally gave up passing the pointer-to-pointer as an input argument. Instead I defined another C-function in SWIG.i to return the pointer-to-pointer in a return value. I thought it was a Kludge ... but it worked!
You may want to try this:
SWIG.i looks like:
// return pointer-to-pointer
%inline %{
HEADER *ReadMessageHelper() {
HEADER *hdr;
int returnValue;
returnValue = ReadMessage(&hdr);
if (returnValue!= 1) hdr = NULL;
return hdr;
}%}
The inline function above could leak memory as Java won't take ownership of the memory created by ReadMessageHelper, since the HEADER instance iscreated on the heap.
The fix for the memory leak is to define ReadMessageHelper as a newobject in order for Java to take control of the memory.
%newobject ReadMessageHelper();
JAVA call now would look like:
HEADER hdr;
hdr = SWIG.ReadMessageHelper();
If you are lucky, as I was, you may have another API available to release the message buffer. In which case, you wouldn’t have to do the previous step.
William Fulton, the SWIG guru, had this to say about the approach above:
“I wouldn't see the helper function as a kludge, more the simplest solution to a tricky problem. Consider what the equivalent pure 100% Java code would be for ReadMessage(). I don't think there is an equivalent as Java classes are passed by reference and there is no such thing as a reference to a reference, or pointer to a pointer in Java. In the C function you have, a HEADER instances is created by ReadMessage and passed back to the caller. I don't see how one can do the equivalent in Java without providing some wrapper class around HEADER and passing the wrapper to the ReadMessage function. At the end of the day, ReadMessage returns a newly created HEADER and the Java way of returning newly created objects is to return it in the return value, not via a parameter.”