Advertisement
Not a member of Pastebin yet?
Sign Up,
it unlocks many cool features!
- import std.stdio;
- import core.thread;
- // Steamworks SDK: https://partner.steamgames.com/doc/sdk
- // Download link: https://partner.steamgames.com/downloads/steamworks_sdk.zip
- // A file named "steam_appid.txt" must be present in the working directory, containing the number 480 (ID for Steamworks public developer test application)
- // See SDK steam_api_flat.h, steam_api.h, steam_api_internal.h
- pragma(lib, "steam_api_omf");
- // stdout autoflush fix for IDE compatibility, optional
- void write(T...)(lazy T t) { stdout.write(t); stdout.flush(); }
- void writef(T...)(lazy T t) { stdout.writef(t); stdout.flush(); }
- void writeln(T...)(lazy T t) { stdout.writeln(t); stdout.flush(); }
- void writefln(T...)(lazy T t) { stdout.writefln(t); stdout.flush(); }
- alias int HSteamPipe;
- alias int HSteamUser;
- alias ulong SteamAPICall_t;
- alias byte int8;
- alias ubyte uint8;
- alias short int16;
- alias ushort uint16;
- alias int int32;
- alias uint uint32;
- alias long int64;
- alias ulong uint64;
- enum {
- STEAMCLIENT_INTERFACE_VERSION = "SteamClient017",
- STEAMUTILS_INTERFACE_VERSION = "SteamUtils009",
- STEAMUSER_INTERFACE_VERSION = "SteamUser019",
- STEAMFRIENDS_INTERFACE_VERSION = "SteamFriends015",
- STEAMUSERSTATS_INTERFACE_VERSION = "STEAMUSERSTATS_INTERFACE_VERSION011",
- STEAMREMOTESTORAGE_INTERFACE_VERSION = "STEAMREMOTESTORAGE_INTERFACE_VERSION014",
- }
- enum {
- k_iSteamUserStatsCallbacks = 1100,
- }
- enum ESteamAPICallFailure {
- None = -1, // no failure
- SteamGone = 0, // the local Steam process has gone away
- NetworkFailure = 1, // the network connection to Steam has been broken, or was already broken
- // SteamServersDisconnected_t callback will be sent around the same time
- // SteamServersConnected_t will be sent when the client is able to talk to the Steam servers again
- InvalidHandle = 2, // the SteamAPICall_t handle passed in no longer exists
- MismatchedCallback = 3,// GetAPICallResult() was called with the wrong callback type for this API call
- }
- extern(C) {
- const SteamAPICall_t k_uAPICallInvalid = 0x0;
- class ISteamClient {}
- class ISteamUtils {}
- class ISteamUser {}
- class ISteamUserStats {}
- class ISteamFriends {}
- class ISteamRemoteStorage {}
- bool SteamAPI_Init();
- void SteamAPI_Shutdown();
- // Interfaces
- ISteamClient SteamClient();
- ISteamUtils SteamAPI_ISteamClient_GetISteamUtils(ISteamClient instancePtr, HSteamPipe hSteamPipe, const char* pchVersion);
- ISteamUser SteamAPI_ISteamClient_GetISteamUser(ISteamClient instancePtr, HSteamUser hSteamUser, HSteamPipe hSteamPipe, const char* pchVersion);
- ISteamUserStats SteamAPI_ISteamClient_GetISteamUserStats(ISteamClient instancePtr, HSteamUser hSteamUser, HSteamPipe hSteamPipe, const char* pchVersion);
- // Handles
- HSteamPipe SteamAPI_ISteamClient_CreateSteamPipe(ISteamClient instancePtr);
- HSteamUser SteamAPI_ISteamClient_ConnectToGlobalUser(ISteamClient instancePtr, HSteamPipe hSteamPipe);
- bool SteamAPI_ISteamClient_BReleaseSteamPipe(ISteamClient instancePtr, HSteamPipe hSteamPipe);
- void SteamAPI_ISteamClient_ReleaseUser(ISteamClient instancePtr, HSteamPipe hSteamPipe, HSteamUser hUser);
- // Misc
- ulong SteamAPI_ISteamUser_GetSteamID(ISteamUser instancePtr);
- bool SteamAPI_ISteamUser_BLoggedOn(ISteamUser instancePtr);
- // Callbacks/Call Results
- void SteamAPI_RegisterCallResult(CCallbackBase pCallback, SteamAPICall_t hAPICall);
- void SteamAPI_UnregisterCallResult(CCallbackBase pCallback, SteamAPICall_t hAPICall);
- void SteamAPI_RunCallbacks();
- bool SteamAPI_ISteamUtils_IsAPICallCompleted(ISteamUtils instancePtr, SteamAPICall_t hSteamAPICall, bool* pbFailed);
- ESteamAPICallFailure SteamAPI_ISteamUtils_GetAPICallFailureReason(ISteamUtils instancePtr, SteamAPICall_t hSteamAPICall);
- bool SteamAPI_ISteamUtils_GetAPICallResult(ISteamUtils instancePtr, SteamAPICall_t hSteamAPICall, void* pCallback, int cubCallback, int iCallbackExpected, bool* pbFailed);
- // Async Requests
- SteamAPICall_t SteamAPI_ISteamUserStats_GetNumberOfCurrentPlayers(ISteamUserStats instancePtr);
- struct NumberOfCurrentPlayers_t {
- enum k_iCallback = k_iSteamUserStatsCallbacks + 7;
- uint8 m_bSuccess; // 1 if the call was successful
- int32 m_cPlayers; // Number of players currently playing
- }
- }
- extern(C++) {
- class CallHandler {}
- abstract class CCallbackBase {
- this() { m_nCallbackFlags = 0; m_iCallback = 0; }
- void Run( void *pvParam );
- void Run( void *pvParam, bool bIOFailure, SteamAPICall_t hSteamAPICall );
- int GetICallback() { return m_iCallback; }
- int GetCallbackSizeBytes();
- enum { k_ECallbackFlagsRegistered = 0x01, k_ECallbackFlagsGameServer = 0x02 }
- uint8 m_nCallbackFlags;
- int m_iCallback;
- //friend class CCallbackMgr;
- //CCallbackBase( const CCallbackBase& );
- //CCallbackBase& operator=( const CCallbackBase& );
- }
- class CallResult(T, P) : CCallbackBase {
- // T: A C++ class whose member function is called m_Func is to be called
- // P: The struct type to cast the result pointer to
- //typedef void (T::*func_t)( P*, bool );
- alias func_t = void function(P*, bool);
- this() {
- m_hAPICall = k_uAPICallInvalid;
- m_pObj = null;
- m_Func = null;
- m_iCallback = P.k_iCallback;
- }
- ~this() {}
- void Set(SteamAPICall_t hAPICall, T p, func_t func) {
- /+if (m_hAPICall)
- SteamAPI_UnregisterCallResult(this, m_hAPICall);+/
- m_hAPICall = hAPICall;
- m_pObj = p;
- m_Func = func;
- /+if (hAPICall)
- SteamAPI_RegisterCallResult(this, hAPICall);+/
- }
- bool IsActive() {
- return (m_hAPICall != k_uAPICallInvalid);
- };
- void Cancel() {
- if (m_hAPICall != k_uAPICallInvalid) {
- /+SteamAPI_UnregisterCallResult(this, m_hAPICall);+/
- m_hAPICall = k_uAPICallInvalid;
- }
- }
- void SetGameserverFlag() { m_nCallbackFlags |= k_ECallbackFlagsGameServer; }
- final override void Run( void *pvParam ) {
- if (pvParam !is null) {
- P result = *(cast(P*) pvParam);
- writeln("Call Result returned data: %s", result);
- } else {
- writeln("Call Result returned no data.");
- }
- }
- final override void Run( void *pvParam, bool bIOFailure, SteamAPICall_t hSteamAPICall ) {
- if (pvParam !is null) {
- P result = *(cast(P*) pvParam);
- writeln("Call Result(%s) returned data: %s", hSteamAPICall, result);
- } else {
- writeln("Call Result(%s) returned no data.", hSteamAPICall);
- }
- }
- final override int GetCallbackSizeBytes() { return P.sizeof; }
- SteamAPICall_t m_hAPICall;
- T m_pObj; // Object whose member function should be called to finalize callback (not used here)
- func_t m_Func; // Member function of the object above to run
- }
- }
- void main() {
- writefln("Initializing.");
- bool initialized = SteamAPI_Init();
- assert(initialized, "Unable to initialize SteamAPI, ensure Steam client is running");
- auto client = SteamClient();
- assert(client !is null, "Unable to retrieve SteamClient interface");
- HSteamPipe pipe = SteamAPI_ISteamClient_CreateSteamPipe(client);
- HSteamUser userPipe = SteamAPI_ISteamClient_ConnectToGlobalUser(client, pipe);
- scope(exit) {
- if (initialized) {
- if (userPipe)
- SteamAPI_ISteamClient_ReleaseUser(client, pipe, userPipe);
- if (pipe)
- SteamAPI_ISteamClient_BReleaseSteamPipe(client, pipe);
- SteamAPI_Shutdown();
- }
- writefln("Terminating.");
- }
- auto utils = SteamAPI_ISteamClient_GetISteamUtils(client, pipe, STEAMUTILS_INTERFACE_VERSION);
- auto user = SteamAPI_ISteamClient_GetISteamUser(client, userPipe, pipe, STEAMUSER_INTERFACE_VERSION);
- auto userStats = SteamAPI_ISteamClient_GetISteamUserStats(client, userPipe, pipe, STEAMUSERSTATS_INTERFACE_VERSION);
- ulong userid = SteamAPI_ISteamUser_GetSteamID(user);
- bool loggedOn = SteamAPI_ISteamUser_BLoggedOn(user);
- writefln("User logged on: %s", loggedOn);
- writefln("Starting request.");
- alias NumberOfCurrentPlayers_t RESULT;
- auto cbk = new CallResult!(CallHandler, RESULT)();
- auto hid = SteamAPI_ISteamUserStats_GetNumberOfCurrentPlayers(userStats);
- writefln("hid: %s", hid);
- cbk.m_hAPICall = hid;
- cbk.m_iCallback = NumberOfCurrentPlayers_t.k_iCallback;
- // Register CallResult here, should cause some method to fire when SteamAPI_RunCallbacks is executed?
- SteamAPI_RegisterCallResult(cbk, hid);
- int attempts = 10;
- bool failed;
- bool finished;
- while (attempts-- > 0) {
- if (failed)
- write("?");
- else if (finished)
- write("!");
- else
- write(".");
- SteamAPI_RunCallbacks();
- // Check request status manually
- finished = SteamAPI_ISteamUtils_IsAPICallCompleted(utils, hid, &failed);
- Thread.sleep(msecs(500));
- }
- writeln();
- // Display results of manually checking call completion status
- if (failed) {
- auto failReason = SteamAPI_ISteamUtils_GetAPICallFailureReason(utils, hid);
- writefln("Request failed: %s", failReason);
- } else if (finished) {
- RESULT result;
- auto b = SteamAPI_ISteamUtils_GetAPICallResult(utils, hid, &result, result.sizeof, RESULT.k_iCallback, &failed);
- writefln("Request completed: %s", result);
- } else {
- writeln("No response from request.");
- }
- }
- /+ +++++++++++++++++++++ from steam_api.h:
- //----------------------------------------------------------------------------------------------------------------------------------------------------------//
- // steam callback and call-result helpers
- //
- // The following macros and classes are used to register your application for
- // callbacks and call-results, which are delivered in a predictable manner.
- //
- // STEAM_CALLBACK macros are meant for use inside of a C++ class definition.
- // They map a Steam notification callback directly to a class member function
- // which is automatically prototyped as "void func( callback_type *pParam )".
- //
- // CCallResult is used with specific Steam APIs that return "result handles".
- // The handle can be passed to a CCallResult object's Set function, along with
- // an object pointer and member-function pointer. The member function will
- // be executed once the results of the Steam API call are available.
- //
- // CCallback and CCallbackManual classes can be used instead of STEAM_CALLBACK
- // macros if you require finer control over registration and unregistration.
- //
- // Callbacks and call-results are queued automatically and are only
- // delivered/executed when your application calls SteamAPI_RunCallbacks().
- //----------------------------------------------------------------------------------------------------------------------------------------------------------//
- // SteamAPI_RunCallbacks is safe to call from multiple threads simultaneously,
- // but if you choose to do this, callback code could be executed on any thread.
- // One alternative is to call SteamAPI_RunCallbacks from the main thread only,
- // and call SteamAPI_ReleaseCurrentThreadMemory regularly on other threads.
- S_API void S_CALLTYPE SteamAPI_RunCallbacks();
- // Declares a callback member function plus a helper member variable which
- // registers the callback on object creation and unregisters on destruction.
- // The optional fourth 'var' param exists only for backwards-compatibility
- // and can be ignored.
- #define STEAM_CALLBACK( thisclass, func, .../*callback_type, [deprecated] var*/ ) \
- _STEAM_CALLBACK_SELECT( ( __VA_ARGS__, 4, 3 ), ( /**/, thisclass, func, __VA_ARGS__ ) )
- // Declares a callback function and a named CCallbackManual variable which
- // has Register and Unregister functions instead of automatic registration.
- #define STEAM_CALLBACK_MANUAL( thisclass, func, callback_type, var ) \
- CCallbackManual< thisclass, callback_type > var; void func( callback_type *pParam )
- // Internal functions used by the utility CCallback objects to receive callbacks
- S_API void S_CALLTYPE SteamAPI_RegisterCallback( class CCallbackBase *pCallback, int iCallback );
- S_API void S_CALLTYPE SteamAPI_UnregisterCallback( class CCallbackBase *pCallback );
- // Internal functions used by the utility CCallResult objects to receive async call results
- S_API void S_CALLTYPE SteamAPI_RegisterCallResult( class CCallbackBase *pCallback, SteamAPICall_t hAPICall );
- S_API void S_CALLTYPE SteamAPI_UnregisterCallResult( class CCallbackBase *pCallback, SteamAPICall_t hAPICall );
- //-----------------------------------------------------------------------------
- // Purpose: base for callbacks and call results - internal implementation detail
- //-----------------------------------------------------------------------------
- class CCallbackBase
- {
- public:
- CCallbackBase() { m_nCallbackFlags = 0; m_iCallback = 0; }
- // don't add a virtual destructor because we export this binary interface across dll's
- virtual void Run( void *pvParam ) = 0;
- virtual void Run( void *pvParam, bool bIOFailure, SteamAPICall_t hSteamAPICall ) = 0;
- int GetICallback() { return m_iCallback; }
- virtual int GetCallbackSizeBytes() = 0;
- protected:
- enum { k_ECallbackFlagsRegistered = 0x01, k_ECallbackFlagsGameServer = 0x02 };
- uint8 m_nCallbackFlags;
- int m_iCallback;
- friend class CCallbackMgr;
- private:
- CCallbackBase( const CCallbackBase& );
- CCallbackBase& operator=( const CCallbackBase& );
- };
- //-----------------------------------------------------------------------------
- // Purpose: templated base for callbacks - internal implementation detail
- //-----------------------------------------------------------------------------
- template< int sizeof_P >
- class CCallbackImpl : protected CCallbackBase
- {
- public:
- ~CCallbackImpl() { if ( m_nCallbackFlags & k_ECallbackFlagsRegistered ) SteamAPI_UnregisterCallback( this ); }
- void SetGameserverFlag() { m_nCallbackFlags |= k_ECallbackFlagsGameServer; }
- protected:
- virtual void Run( void *pvParam ) = 0;
- virtual void Run( void *pvParam, bool /*bIOFailure*/, SteamAPICall_t /*hSteamAPICall*/ ) { Run( pvParam ); }
- virtual int GetCallbackSizeBytes() { return sizeof_P; }
- };
- //-----------------------------------------------------------------------------
- // Purpose: maps a steam async call result to a class member function
- // template params: T = local class, P = parameter struct
- //-----------------------------------------------------------------------------
- template< class T, class P >
- class CCallResult : private CCallbackBase
- {
- public:
- typedef void (T::*func_t)( P*, bool );
- CCallResult();
- ~CCallResult();
- void Set( SteamAPICall_t hAPICall, T *p, func_t func );
- bool IsActive() const;
- void Cancel();
- void SetGameserverFlag() { m_nCallbackFlags |= k_ECallbackFlagsGameServer; }
- private:
- virtual void Run( void *pvParam );
- virtual void Run( void *pvParam, bool bIOFailure, SteamAPICall_t hSteamAPICall );
- virtual int GetCallbackSizeBytes() { return sizeof( P ); }
- SteamAPICall_t m_hAPICall;
- T *m_pObj;
- func_t m_Func;
- };
- //-----------------------------------------------------------------------------
- // Purpose: maps a steam callback to a class member function
- // template params: T = local class, P = parameter struct,
- // bGameserver = listen for gameserver callbacks instead of client callbacks
- //-----------------------------------------------------------------------------
- template< class T, class P, bool bGameserver = false >
- class CCallback : public CCallbackImpl< sizeof( P ) >
- {
- public:
- typedef void (T::*func_t)(P*);
- // NOTE: If you can't provide the correct parameters at construction time, you should
- // use the CCallbackManual callback object (STEAM_CALLBACK_MANUAL macro) instead.
- CCallback( T *pObj, func_t func );
- void Register( T *pObj, func_t func );
- void Unregister();
- protected:
- virtual void Run( void *pvParam );
- T *m_pObj;
- func_t m_Func;
- };
- //-----------------------------------------------------------------------------
- // Purpose: subclass of CCallback which allows default-construction in
- // an unregistered state; you must call Register manually
- //-----------------------------------------------------------------------------
- template< class T, class P, bool bGameServer = false >
- class CCallbackManual : public CCallback< T, P, bGameServer >
- {
- public:
- CCallbackManual() : CCallback< T, P, bGameServer >( NULL, NULL ) {}
- // Inherits public Register and Unregister functions from base class
- };
- #ifdef _WIN32
- // disable this warning; this pattern need for steam callback registration
- #pragma warning( disable: 4355 ) // 'this' : used in base member initializer list
- #endif
- //----------------------------------------------------------------------------------------------------------------------------------------------------------//
- // steamclient.dll private wrapper functions
- //
- // The following functions are part of abstracting API access to the steamclient.dll, but should only be used in very specific cases
- //----------------------------------------------------------------------------------------------------------------------------------------------------------//
- // SteamAPI_IsSteamRunning() returns true if Steam is currently running
- S_API bool S_CALLTYPE SteamAPI_IsSteamRunning();
- // Pumps out all the steam messages, calling registered callbacks.
- // NOT THREADSAFE - do not call from multiple threads simultaneously.
- S_API void Steam_RunCallbacks( HSteamPipe hSteamPipe, bool bGameServerCallbacks );
- // register the callback funcs to use to interact with the steam dll
- S_API void Steam_RegisterInterfaceFuncs( void *hModule );
- // returns the HSteamUser of the last user to dispatch a callback
- S_API HSteamUser Steam_GetHSteamUserCurrent();
- // returns the filename path of the current running Steam process, used if you need to load an explicit steam dll by name.
- // DEPRECATED - implementation is Windows only, and the path returned is a UTF-8 string which must be converted to UTF-16 for use with Win32 APIs
- S_API const char *SteamAPI_GetSteamInstallPath();
- // returns the pipe we are communicating to Steam with
- S_API HSteamPipe SteamAPI_GetHSteamPipe();
- // sets whether or not Steam_RunCallbacks() should do a try {} catch (...) {} around calls to issuing callbacks
- S_API void SteamAPI_SetTryCatchCallbacks( bool bTryCatchCallbacks );
- // backwards compat export, passes through to SteamAPI_ variants
- S_API HSteamPipe GetHSteamPipe();
- S_API HSteamUser GetHSteamUser();
- +/
- /+ +++++++++++++++++++++ from steam_api_internal.h:
- //-----------------------------------------------------------------------------
- // The following macros are implementation details, not intended for public use
- //-----------------------------------------------------------------------------
- #define _STEAM_CALLBACK_AUTO_HOOK( thisclass, func, param )
- #define _STEAM_CALLBACK_HELPER( _1, _2, SELECTED, ... ) _STEAM_CALLBACK_##SELECTED
- #define _STEAM_CALLBACK_SELECT( X, Y ) _STEAM_CALLBACK_HELPER X Y
- #define _STEAM_CALLBACK_3( extra_code, thisclass, func, param ) \
- struct CCallbackInternal_ ## func : private CCallbackImpl< sizeof( param ) > { \
- CCallbackInternal_ ## func () { extra_code SteamAPI_RegisterCallback( this, param::k_iCallback ); } \
- CCallbackInternal_ ## func ( const CCallbackInternal_ ## func & ) { extra_code SteamAPI_RegisterCallback( this, param::k_iCallback ); } \
- CCallbackInternal_ ## func & operator=( const CCallbackInternal_ ## func & ) { return *this; } \
- private: virtual void Run( void *pvParam ) { _STEAM_CALLBACK_AUTO_HOOK( thisclass, func, param ) \
- thisclass *pOuter = reinterpret_cast<thisclass*>( reinterpret_cast<char*>(this) - offsetof( thisclass, m_steamcallback_ ## func ) ); \
- pOuter->func( reinterpret_cast<param*>( pvParam ) ); \
- } \
- } m_steamcallback_ ## func ; void func( param *pParam )
- #define _STEAM_CALLBACK_4( _, thisclass, func, param, var ) \
- CCallback< thisclass, param > var; void func( param *pParam )
- //-----------------------------------------------------------------------------
- // Purpose: maps a steam async call result to a class member function
- // template params: T = local class, P = parameter struct
- //-----------------------------------------------------------------------------
- template< class T, class P >
- inline CCallResult<T, P>::CCallResult()
- {
- m_hAPICall = k_uAPICallInvalid;
- m_pObj = NULL;
- m_Func = NULL;
- m_iCallback = P::k_iCallback;
- }
- template< class T, class P >
- inline void CCallResult<T, P>::Set( SteamAPICall_t hAPICall, T *p, func_t func )
- {
- if ( m_hAPICall )
- SteamAPI_UnregisterCallResult( this, m_hAPICall );
- m_hAPICall = hAPICall;
- m_pObj = p;
- m_Func = func;
- if ( hAPICall )
- SteamAPI_RegisterCallResult( this, hAPICall );
- }
- template< class T, class P >
- inline bool CCallResult<T, P>::IsActive() const
- {
- return (m_hAPICall != k_uAPICallInvalid);
- }
- template< class T, class P >
- inline void CCallResult<T, P>::Cancel()
- {
- if ( m_hAPICall != k_uAPICallInvalid )
- {
- SteamAPI_UnregisterCallResult( this, m_hAPICall );
- m_hAPICall = k_uAPICallInvalid;
- }
- }
- template< class T, class P >
- inline CCallResult<T, P>::~CCallResult()
- {
- Cancel();
- }
- template< class T, class P >
- inline void CCallResult<T, P>::Run( void *pvParam )
- {
- m_hAPICall = k_uAPICallInvalid; // caller unregisters for us
- (m_pObj->*m_Func)((P *)pvParam, false);
- }
- template< class T, class P >
- inline void CCallResult<T, P>::Run( void *pvParam, bool bIOFailure, SteamAPICall_t hSteamAPICall )
- {
- if ( hSteamAPICall == m_hAPICall )
- {
- m_hAPICall = k_uAPICallInvalid; // caller unregisters for us
- (m_pObj->*m_Func)((P *)pvParam, bIOFailure);
- }
- }
- //-----------------------------------------------------------------------------
- // Purpose: maps a steam callback to a class member function
- // template params: T = local class, P = parameter struct,
- // bGameserver = listen for gameserver callbacks instead of client callbacks
- //-----------------------------------------------------------------------------
- template< class T, class P, bool bGameserver >
- inline CCallback< T, P, bGameserver >::CCallback( T *pObj, func_t func )
- : m_pObj( NULL ), m_Func( NULL )
- {
- if ( bGameserver )
- {
- this->SetGameserverFlag();
- }
- Register( pObj, func );
- }
- template< class T, class P, bool bGameserver >
- inline void CCallback< T, P, bGameserver >::Register( T *pObj, func_t func )
- {
- if ( !pObj || !func )
- return;
- if ( this->m_nCallbackFlags & CCallbackBase::k_ECallbackFlagsRegistered )
- Unregister();
- m_pObj = pObj;
- m_Func = func;
- // SteamAPI_RegisterCallback sets k_ECallbackFlagsRegistered
- SteamAPI_RegisterCallback( this, P::k_iCallback );
- }
- template< class T, class P, bool bGameserver >
- inline void CCallback< T, P, bGameserver >::Unregister()
- {
- // SteamAPI_UnregisterCallback removes k_ECallbackFlagsRegistered
- SteamAPI_UnregisterCallback( this );
- }
- template< class T, class P, bool bGameserver >
- inline void CCallback< T, P, bGameserver >::Run( void *pvParam )
- {
- (m_pObj->*m_Func)((P *)pvParam);
- }
- +/
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement