On Saturday, 9 June 2018 at 03:14:13 UTC, cc wrote:
On Saturday, 9 June 2018 at 03:07:39 UTC, cc wrote:
I've put together a simplified test program here (124KB):
Here is a pastebin of the D source file updated with some
additional comments at the end with the callback class
definitions from the original header files
https://pastebin.com/M8hDXt6L
The proper bare minimum signature for call result callback is
------------------
extern(C++) abstract class CCallbackBase {
abstract void Run( void *pvParam ) { writeln("Run()"); }
abstract void Run( void *pvParam, bool bIOFailure,
SteamAPICall_t hSteamAPICall );
final int GetICallback() { return m_iCallback; } // this is
actually optional
abstract int GetCallbackSizeBytes();
protected:
uint8 m_nCallbackFlags; // probably can be left for some
specific use cases
int m_iCallback;
}
------------------
and the rest templates and stuff is purely for C++ convenience.
Run(void*, bool, SteamAPICall_t) is what actually called for call
result, then CallResult<> template overrides it to call
appropriate pointer member in class with void (T::fun)(Data*,
bool bIOFailure) signature. You can mimic it on D side, or just
ignore and make own.
There is one catch however, for it to be called flags should be
equal 1, and iCallback must match struct enum, like
NumberOfCurrentPlayers_t.k_iCallback for
GetNumberOfCurrentPlayers()
However steam devs decided to shield actual pointer and return
pointer sized integer when C API is used(or they just screw up?).
Anyway, the pointers for subsystems returned by context calls on
C++ API and mirrored C API calls are different, but they also
have some mechanism for filtering this stuff, that way both
integer handle and pointer calls the same underlying
implementation, but C API call again is shielded so setting up
CallResult and CCallback are ignored.
So my solution was just to make simple wrapper around C++ context
calls and pass that real pointer to D side.
------------------- C++ code
// build as static library & link with your project
#ifdef _WIN32
// sorry, I just hardcoded it...
#pragma comment (lib, "steam_api64.lib")
#define _CRT_SECURE_NO_WARNINGS 1
#endif
#include "public/steam/steam_api.h"
#ifdef _WIN32
#define _CRT_SECURE_NO_WARNINGS 1
#endif
extern "C" void* D_GetSteamUserStats()
{
return SteamUserStats();
}
------------------- D code
// yes, I messed up with the signature to avoid casting, this may
or may not be dangerous
extern(C) ISteamUserStats D_GetSteamUserStats();
This of course involves making C++ wrapper, but I don't really
see other ways because they inlined everything ...