GameMaker Studio, Create Async Event from Windows DLL - c++

I'm trying to fire a Social Asynchronous event from a DLL on Windows. There is a tutorial for this here at the bottom.
What I don't understand is the following
When your extension is loaded this callback should fire immediately
and be passed in pointers to the four functions.
I guess I should call the function (RegisterCallbacks) from GML since the callback is defined as dllexport.
Here's the callback function
__declspec (dllexport) void RegisterCallbacks(char *arg1, char *arg2, char *arg3, char *arg4 )
{
void (*CreateAsynEventWithDSMapPtr)(int,int) = (void (*)(int,int))(arg1);
int(*CreateDsMapPtr)(int _num,...) = (int(*)(int _num,...)) (arg2);
CreateAsynEventWithDSMap = CreateAsynEventWithDSMapPtr;
CreateDsMap = CreateDsMapPtr;
bool (*DsMapAddDoublePtr)(int _index,char *_pKey,double value)= (bool(*)(int,char*,double))(arg3);
bool (*DsMapAddStringPtr)(int _index, char *_pKey, char *pVal)= (bool(*)(int,char*,char*))(arg4);
DsMapAddDouble = DsMapAddDoublePtr;
DsMapAddString = DsMapAddStringPtr;
}
But how should I pass a pointer to "CreateAsynEventWithDSMap" from GML? Where do I get those functions?

Old question, but I recently had this problem myself and spent a couple of days scratching my head, so I thought I'd post the answer for the record.
First of all the RegisterCallbacks function in the DLL needs to be __declspec (dllexport) and also extern "C", like any other function exported to GM.
Second, the RegisterCallbacks function should be defined in GM also, not just in the C/C++ file, again just like any other exported function in the extension. The four arguments should be defined as string type. It should look like this: http://i.imgur.com/pppbsWa.png
Now, RegisterCallbacks should fire automatically when you start your game, and the DsMap functions to do async stuff should work. Do not try to call RegisterCallbacks() manually.

Related

Passing std::string with dllexport

I'm trying to make some sort of C++ "bridge" to connect an unmanaged C++ dll on one end (without modifying their code) to a C# Wrapper which uses DllImport for various imports.
I was able to pass a C# string to my bridge using char pointers, but the receiving Dll needs to receive std::string, so I tried with std::string(foo); with no luck, it always gets transformed into weird characters.
The structure is the following :
C# Wrapper
[DllImport(#"Bridge.dll", CallingConvention = CallingConvention.Cdecl)]
public static extern void initDetector(string foo, int something = 0);
C++ Bridge
extern "C" __declspec(dllexport) void initCppClass(char* foo, int something)
{
std::string bar = std::string(foo);
std::cout << bar << std::endl; //Returns "foo"
instance = new CppClass(bar, something);
}
C++ Imported DLL (not allowed to change code here)
CppClass::CppClass(std::string foo, int something)
{
std::cout << foo << std::endl; //Returns garbage
}
Note that this constructor is for demonstration purposes only, as I cannot disclose the original code.
I originally tried passing the char* directly to the constructor but that didn't work either. Is there something I'm missing here ?
I think the problem is different string encoding.
Try adding CharSet = CharSet.Ansi in C#, like this:
[DllImport(#"Bridge.dll", CallingConvention = CallingConvention.Cdecl, CharSet = CharSet.Ansi)]
However, please read the documentation of that C++ dll API. A lot of C++ code, especially if that’s cross-platform code, expect UTF8-encoded strings. If that’s your case, instead change the bridge to
extern "C" __declspec(dllexport) void initCppClass(const wchar_t* foo, int something)
And write code to convert the string from UTF16-encoded C pointer into UTF8-encoded std::string, see this answer for an example.
Update: another possible reason is different STL, or different CRT. When you pass std::string or any other STL objects objects across DLL boundaries, you have to use same compiler & same version of it, same build settings for (e.g. in VC++, std::strings memory layout differs between debug and release builds), and also both DLLs must link to CRT dynamically., e.g. Multi-threaded DLL (/MD)

C++, Casting a function pointer parameter

I was trying to write a C++ program, including a header file, and a cpp file, plus, I am using the SimConnect dll.
Let's say I have a class called MyClass, which contains some functions.
Inside one of my functions, I call this SimConnect function:
SIMCONNECTAPI SimConnect_CallDispatch(HANDLE hSimConnect, DispatchProc pfcnDispatch, void * pContext);
Also, I wrote this function:
void __stdcall MyClass::myDispatchProc(SIMCONNECT_RECV* pData, DWORD cbData, void *pContext)
As far as I understood, I should send this function as the second parameter to the SimConnect function SimConnect_CallDispatch I talked about before.
I read an example which came with the SimConnect SDK which is doing exactly what I am doing, while I get an error, and they don't.
The only thing that's different is that they wrote their whole code in one page, while I tried to split the code into header + body.
When I try to do as I said above, and write
SimConnect_CallDispatch(hSimConnect, myDispatchProc, NULL);
I receive this error (compiler is having trouble in myDispatchProc part):
argument of type "void (__stdcall TransmitData::*)(SIMCONNECT_RECV *pData, DWORD cbData, void *pContext)" is incompatible with parameter of type "DispatchProc"
So clearly, it's a casting-like error.
As I said, this code would've worked if I didn't split my program into two separate files. Why doesn't it work now?
Although this is not a recent question, I'll leave a reference in case anyone else stumbles upon this. Note: This question is specific to the SimConnect SDK used for MS FS2020 (and FSX).
The SimConnect_CallDispatch function requires a reference to a static, callback function with a specific interface, i.e. (SIMCONNECT_RECV* pData, DWORD cbData, void* pContext)
The nature of the static function is that it won't have access to the variables of the instance, so to get around this problem, all of the examples out there don't bother with the complexity of .h and .cpp files and just code everything in one file. This is how I solved this issue,
Define the static callback function in the .h file, e.g.
void static CALLBACK MyDispatchProcRD(SIMCONNECT_RECV *pData, DWORD cbData, void *pContext);
Define a separate instance function to handle the actual processing of the callback in the .h file, e.g.
void DispatchProc(SIMCONNECT_RECV* pData, DWORD cbData);
In the implementation of the static callback (.cpp) cast the context reference to your class and pass it on to the instance method for further processing, e.g.
void CALLBACK MainProcessor::MyDispatchProcRD(SIMCONNECT_RECV* pData, DWORD cbData, void* pContext) {
MainProcessor* procThis = reinterpret_cast<MainProcessor*>(pContext);
procThis->DispatchProc(pData, cbData);
}
Just remember to pass the reference to your instance when calling SimConnect dispatch, i.e.
SimConnect_CallDispatch(hSimConnect, MyDispatchProcRD, this);

C Pass arguments as void-pointer-list to imported function from LoadLibrary()

The problem I have is that I want to create a generic command line application that can be used to load a library DLL and then call a function in the library DLL. The function name is specified on the command line with the arguments also provided on the utility command line.
I can access the external function from a DLL dynamically loaded using the LoadLibrary() function. Once the library is loaded I can obtain a pointer to the function using GetProcAddress() I want to call the function with the arguments specified on the command line.
Can I pass a void-pointer-list to the function-pointer which I got returned by the LoadLibrary() function similar to the example below?
To keep the example code simple, I deleted the error-checking. Is there a way to get something like this working:
//Somewhere in another dll
int DoStuff(int a, int b)
{
return a + b;
}
int main(int argc, char **argv)
{
void *retval;
void *list = argv[3];
HMODULE dll;
void* (*generic_function)(void*);
dll = LoadLibraryA(argv[1]);
//argv[2] = "DoStuff"
generic_function = GetProcAddress(dll, argv[2]);
//argv[3] = 4, argv[4] = 7, argv[5] = NULL
retval = generic_function(list);
}
If I forgot to mention necessary information, please let me know.
Thanks in advance
You need to cast the function pointer returned by LoadLibrary to one with the right argument types before calling it. One way to manage it is to have a number call-adaptor functions that do the right thing for every possible function type you might want to call:
void Call_II(void (*fn_)(), char **args) {
void (*fn)(int, int) = (void (*)(int, int))fn_;
fn(atoi(args[0]), atoi(args[1]));
}
void Call_IS(void (*fn_)(), char **args) {
void (*fn)(int, char *) = (void (*)(int, char *))fn_;
fn(atoi(args[0]), args[1]);
}
...various more functions
Then you take the pointer you got from GetProcAddress and the additional arguments and pass them to the correct Call_X function:
void* (*generic_function)();
dll = LoadLibraryA(argv[1]);
//argv[2] = "DoStuff"
generic_function = GetProcAddress(dll, argv[2]);
//argv[3] = 4, argv[4] = 7, argv[5] = NULL
Call_II(generic_function, &argv[3]);
The problem is that you need to know what the type of the function you're getting the pointer for is and call the appropriate adaptor function. Which generally means making a table of function name/adaptors and doing a lookup in it.
The related problem is that there's no function analogous to GetProcAddress that will tell you the argument types for a function in the library -- that information simply isn't stored anywhere accessable in the dll.
A library DLL contains the object code for the functions that are part of the library along with some additional information to allow the DLL to be usable.
However a library DLL does not contain the actual type information needed to determine the specific argument list and types for the functions contained in the library DLL. The main information in a library DLL is: (1) a list of the functions that the DLL exports along with the address information that will connect a call of a function to the actual function binary code and (2) a list of any required DLLs that the functions in the library DLL use.
You can actually open a library DLL in a text editor, I suggest a small one, and scan through the arcane symbols of the binary code until you reach the section that contains the list of functions in the library DLL as well as other required DLLs.
So a library DLL contains the bare minimum information needed to (1) find a particular function in the library DLL so that it can be invoked and (2) a list of other needed DLLs that the functions in the library DLL depend on.
This is different from a COM object which normally does have type information in order to support the ability to do what is basically reflection and explore the COM object's services and how those services are accessed. You can do this with Visual Studio and other IDEs which generate a list of COM objects installed and allow you to load a COM object and explore it. Visual Studio also has a tool that will generate the source code files that provide the stubs and include file for accessing the services and methods of a COM object.
However a library DLL is different from a COM object and all the additional information provided with a COM object is not available from a library DLL. Instead a library DLL package is normally made up of (1) the library DLL itself, (2) a .lib file that contains the linkage information for the library DLL along with the stubs and functionality to satisfy the linker when building your application which uses the library DLL, and (3) an include file with the function prototypes of the functions in the library DLL.
So you create your application by calling the functions which reside in the library DLL but using the type information from the include file and linking with the stubs of the associated .lib file. This procedure allows Visual Studio to automate much of the work required to use a library DLL.
Or you can hand code the LoadLibrary() and the building of a table of the functions in the library DLL using GetProcAddress(). By doing hand coding all you really need are the function prototypes of the functions in the library DLL which you then can type in yourself and the library DLL itself. You are in effect doing the work by hand that the Visual Studio compiler does for you if you are using the .lib library stubs and include file.
If you know the actual function name and the function prototype of a function in a library DLL then what you could do is to have your command line utility require the following information:
the name of the function to be called as a text string on the command
line
the list of the arguments to be used as a series of text strings on the command line
an additional parameter that describes the function prototype
This is similar to how functions in the C and C++ runtime which accept variable argument lists with unknown parameter types work. For instance the printf() function which prints a list of argument values has a format string followed by the arguments to be printed. The printf() function uses the format string to determine the types of the various arguments, how many arguments to expect, and what kinds of value transformations to do.
So if your utility had a command line something like the following:
dofunc "%s,%d,%s" func1 "name of " 3 " things"
And the library DLL had a function whose prototype looked like:
void func1 (char *s1, int i, int j);
then the utility would dynamically generate the function call by transforming the character strings of the command line into the actual types needed for the function to be called.
This would work for simple functions that take Plain Old Data types however more complicated types such as struct type argument would require more work as you would need some kind of a description of the struct along with some kind of argument description perhaps similar to JSON.
Appendix I: A simple example
The following is the source code for a Visual Studio Windows console application that I ran in the debugger. The command arguments in the Properties was pif.dll PifLogAbort which caused a library DLL from another project, pif.dll, to be loaded and then the function PifLogAbort() in that library to be invoked.
NOTE: The following example depends on a stack based argument passing convention as is used with most x86 32 bit compilers. Most compilers also allow for a calling convention to be specified other than stack based argument passing such as the __fastcall modifier of Visual Studio. Also as pointed out in the comments, the default for x64 and 64 bit Visual Studio is to use the __fastcall convention by default so that function arguments are passed in registers and not on the stack. See Overview of x64 Calling Conventions in the Microsoft MSDN. See as well the comments and discussion in How are variable arguments implemented in gcc?
.
Notice how the argument list to the function PifLogAbort() is built as a structure that contains an array. The argument values are put into the array of a variable of the struct and then the function is called passing the entire struct by value. What this does is to push a copy of the array of parameters onto the stack and then calls the function. The PifLogAbort() function sees the stack based on its argument list and processes the array elements as individual arguments or parameters.
// dllfunctest.cpp : Defines the entry point for the console application.
//
#include "stdafx.h"
typedef struct {
UCHAR *myList[4];
} sarglist;
typedef void ((*libfunc) (sarglist q));
/*
* do a load library to a DLL and then execute a function in it.
*
* dll name.dll "funcname"
*/
int _tmain(int argc, _TCHAR* argv[])
{
HMODULE dll = LoadLibrary(argv[1]);
if (dll == NULL) return 1;
// convert the command line argument for the function name, argv[2] from
// a TCHAR to a standard CHAR string which is what GetProcAddress() requires.
char funcname[256] = {0};
for (int i = 0; i < 255 && argv[2][i]; i++) {
funcname[i] = argv[2][i];
}
libfunc generic_function = (libfunc) GetProcAddress(dll, funcname);
if (generic_function == NULL) return 2;
// build the argument list for the function and then call the function.
// function prototype for PifLogAbort() function exported from the library DLL
// is as follows:
// VOID PIFENTRY PifLogAbort(UCHAR *lpCondition, UCHAR *lpFilename, UCHAR *lpFunctionname, ULONG ulLineNo);
sarglist xx = {{(UCHAR *)"xx1", (UCHAR *)"xx2", (UCHAR *)"xx3", (UCHAR *)1245}};
generic_function(xx);
return 0;
}
This simple example illustrates some of the technical hurdles that must be overcome. You will need to know how to translate the various parameter types into the proper alignment in a memory area which is then pushed onto the stack.
The interface to this example function is remarkably homogeneous in that most of the arguments are unsigned char pointers with the exception of the last which is an int. With a 32 bit executable all four of these variable types have the same length in bytes. With a more varied list of types in the argument list you will need to have an understanding as to how your compiler aligns parameters when it is pushing the arguments onto the stack before doing the call.
Appendix II: Extending the simple example
Another possibility is to have a set of helper functions along with a different version of the struct. The struct provides a memory area to create a copy of the necessary stack and the help functions are used to build the copy.
So the struct and its helper functions may look like the following.
typedef struct {
UCHAR myList[128];
} sarglist2;
typedef struct {
int i;
sarglist2 arglist;
} sarglistlist;
typedef void ((*libfunc2) (sarglist2 q));
void pushInt (sarglistlist *p, int iVal)
{
*(int *)(p->arglist.myList + p->i) = iVal;
p->i += sizeof(int);
}
void pushChar (sarglistlist *p, unsigned char cVal)
{
*(unsigned char *)(p->arglist.myList + p->i) = cVal;
p->i += sizeof(unsigned char);
}
void pushVoidPtr (sarglistlist *p, void * pVal)
{
*(void * *)(p->arglist.myList + p->i) = pVal;
p->i += sizeof(void *);
}
And then the struct and helper functions would be used to build the argument list like the following after which the function from the library DLL is invoked with the copy of the stack provided:
sarglistlist xx2 = {0};
pushVoidPtr (&xx2, "xx1");
pushVoidPtr (&xx2, "xx2");
pushVoidPtr (&xx2, "xx3");
pushInt (&xx2, 12345);
libfunc2 generic_function2 = (libfunc2) GetProcAddress(dll, funcname);
generic_function2(xx2.arglist);

callback functions and static_cast for wrapping class methods

I'm having some trouble making a callback wrapper class method that needs to be used by a third party library; the JackAudio library.
I have been able to make a wrapper for a JackAudio callback function that needs two arguments.
I'm just having trouble creating a callback function for a particular function that needs a const char * as an argument.
So far I have been able to make the JackAudio library jack_set_sample_rate_callback function use a custom class and can be executed like so:
SoundClass Sound;
SoundClass * SoundPointer = &Sound;
jack_set_sample_rate_callback(
client,
SoundClass::SampleRateCallbackWrapper,
SoundPointer
);
And the class looks something like this:
SoundClass
{
int SampleRateCallback( jack_nframes_t nframes )
{
//executes some code when called.
}
static int SampleRateCallbackWrapper( jack_nframes_t nframes, void * arg )
{
return static_cast < SoundClass* > ( arg )->SampleRateCallback( nframes );
}
};
All of the above works well, with no issues.
The problem I'm having now is with the JackAudio callback function jack_set_error_function
This is what I tried:
static void ErrorCallbackWrapper( const char * arg )
{
return static_cast < SoundClass*>( arg )->SomeErrorFunction();
}
But I get error: invalid static_cast from type ‘const char*’ to type ‘SoundClass*’
I get the gist why this is happening, I just have no idea what to do for a solution.
Thanks in advance for any help guys.
Assuming the Jack API is written for the C language, there is a formal problem already with the working callback that you have. Namely that it then needs to be extern "C", and that as a static member function it cannot be. So formally it needs to be a free-standing function.
The documentation that you link to for the jack_set_error_function gives this signature, presumably expressed in C:
void jack_set_error_function( void(*)(const char *) func);
For C++ the callback must be assumed to be extern "C", so,
extern "C" void MyErrorFunction( char const* errorMessage )
{
// Whatever, e.g. post a message to the GUI event queue, or terminate.
}
If you want this function to in turn call a method on an object, then unless the library provides some special mechanism to help you, you will just have to use one of the following techniques:
a namespace scope variable accessed by the callback, or
a dynamically generated callback.
C++ does not as of yet support the second approach, at all, so the first one is strongly indicated – if you want a callback on a method of an object.
EDIT: Sorry, I forgot to mention,
the function declarations in the API documentation are syntactically invalid.
E.g. the documentation’s signature
void jack_set_info_function( void(*)(const char *) func );
simply won’t compile with a standard-conforming compiler. Not as C, and not as C++. It’s syntactically invalid in both languages.
Instead it should be
void jack_set_info_function( void(*func)(const char *) );
Since the documentation apparently is generated by DOxygen, it stands to reason that it's been generated from source code that compiles. If so then this is a bug in DOxygen, and a problem with the quality assurance of the library provider. However it might be a problem that lies solely with the library provider, or, I might be mistaken in the assumption that this is a C library?

How to pass a char* from C to CPP?

A little background:
I've got a library of C code that is part of larger system (all C). For this particular part of the C library a GUI has to be created which allows users to play around with the options. For the GUI I've chosen QT, since cross-platform support is desired.
I'm using Eclipse and MinGW as IDE and compiler (but I think the question is more language than compiler specific?).
With QT I've created a widget that holds a pointer to a struct implemented in C that contains pointers to several functions that perform the logic of the C library.
//QTWidget.cpp
extern "C" {
#include "c-src/CLogic.h"
//extern char* textHelper;
}
QTWidget::QTWidget(QWidget *parent)
{
//rtw is a struct that contains a function pointer to a member of QTWidget
this->rtw.displayText = &QTWidget::displayText;
this->clogic = CLogic_getInstance(&rtw);
}
//Public SLOT, connected to a button's clicked SIGNAL
void QTWidget::buttonClicked()
{
this->clogic->buttonClicked();
}
void QTWidget::displayText(char *text, int position)
{
//I've tried creating a QString from the char*, but this does not work at all.
//ui.textItem->setText(textHelper);
ui.textItem->setText(text);
}
When the user presses a button in the GUI, the method QTWidget::buttonClicked() is called, which tells the C library to do something. Note the the CLogic struct has a reference to the the QTWidget in the form of a struct RefToWidget which holds a function pointer.
//CLogic.c
static CLogic instance;
void CLogic_buttonClicked()
{
//I've tried several variants here, such as making a global
//char* textHelper = "Hello World";
//that is referenced by using the "extern" keyword in the CPP file above.
instance.rtw->displayText("Hello World", 1);
}
CLogic* CLogic_getInstance(RefToWidget *rtw)
{
instance.rtw = rtw;
instance.buttonClicked = &CLogic_buttonClicked();
}
When debugging this program, I find that all the function calls are executed as intended (when I press a button, the QT slot buttonClicked() is called, the CLogic_buttonClicked() is called, which calls the QTWidget::displayText() as planned, but in this last call the parameters are invalid. The char* text points to 0x1 and claims to be pointing to memory out of bounds, while the int position looks like some random number (uninitialized).
How do I pass this data from C to CPP?
EDIT #Luccas Matteis:
#ifdef __cplusplus
#include "QTWidget.h"
extern "C" {
#endif
struct RefToWidget{
#ifdef __cplusplus
void (QTWidget::*displayLine)(char* text, int lineNumber);
#else
void (*displayLine)(char* text, int lineNumber);
#endif
};
typedef struct RefToWidget RefToWidget;
#ifdef __cplusplus
}
#endif
As said above the function calls behave as expected, but the data is not passed "correctly" (even though that when I look at it, the code seems a bit... weird... ;))
Your problem is not passing the char * from C to C++ but calling a C++ function from C. I presume that CLogic.c is compiled as a C library? If not, can you rename it to CLogic.cpp or use a compiler switch to force it to be compiled as C++ even though it has a C file extension?
If you want a C++ GUI on a C library/system, you need to use proper Model-View-Controller logic. Here the C++ code is the View and the Controller while the C code is the Model (as best as I can tell from your description). You need to make it so you set and get data from the model but the model never calls the View or Controller as you are trying to do.
Think about what you are REALLY trying to do. If you just want to display a static string when the button is pressed, why go to the bother of calling into CLogic.c? If you want to display a string that depends upon the state of the CLogic instance then instead do something like:
void QTWidget::buttonClicked()
{
char *display_text = this->clogic->get_button_click_text();
ui.textItem->setText(display_text);
}
I guess the problem is that the structure holds a pointer to a member function. The member function probably expects the first parameter to be 'this' - the object it refers to. So, in fact what you are seeing in debug as text is the second parameter.
A 'solution' would probably be to do something like "instance.rtw->displayText(instance.rtw, "Hello World", 1)", but have no idea if it is portable etc.
Edit: Saying it explicitly: the 'solution' stated above is just to try and check if this is the problem. As the comments are saying this is a horrible hack that might not work even on the same compiler.
I don't think that you should call a C++ method from C. Normally you need to go through a static method that dereferences a pointer argument