{"id":21274178,"url":"https://github.com/endurodave/remotedelegate","last_synced_at":"2025-03-15T12:43:38.192Z","repository":{"id":113549615,"uuid":"246425433","full_name":"endurodave/RemoteDelegate","owner":"endurodave","description":"Invoke remote functions over any communication medium using a C++ delegate library","archived":false,"fork":false,"pushed_at":"2025-02-18T18:19:40.000Z","size":203,"stargazers_count":1,"open_issues_count":0,"forks_count":0,"subscribers_count":1,"default_branch":"master","last_synced_at":"2025-02-18T19:31:02.439Z","etag":null,"topics":["communication","cpp","delegate","remote-call"],"latest_commit_sha":null,"homepage":"","language":"C++","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/endurodave.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null}},"created_at":"2020-03-10T22:55:37.000Z","updated_at":"2025-02-18T18:19:45.000Z","dependencies_parsed_at":null,"dependency_job_id":"494b3aff-e5d1-4194-97c3-d803c0ede7fb","html_url":"https://github.com/endurodave/RemoteDelegate","commit_stats":null,"previous_names":[],"tags_count":0,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/endurodave%2FRemoteDelegate","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/endurodave%2FRemoteDelegate/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/endurodave%2FRemoteDelegate/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/endurodave%2FRemoteDelegate/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/endurodave","download_url":"https://codeload.github.com/endurodave/RemoteDelegate/tar.gz/refs/heads/master","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":243732252,"owners_count":20338831,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["communication","cpp","delegate","remote-call"],"created_at":"2024-11-21T09:19:15.447Z","updated_at":"2025-03-15T12:43:38.183Z","avatar_url":"https://github.com/endurodave.png","language":"C++","readme":"# Remote Procedure Calls using C++ Delegates\nA C++ standards compliant delegate library capable of invoking a callable delegate function on a remote system. \n\nSee CodeProject article at: \u003ca href=\"https://www.codeproject.com/Articles/5262271/Remote-Procedure-Calls-using-Cplusplus-Delegates\"\u003e\u003cstrong\u003eRemote Procedure Calls using C++ Delegates\u003c/strong\u003e\u003c/a\u003e\n\n## ⚠️ Deprecated Repository\n\n\u003e **Warning:** This repository is no longer maintained. Please use the modern delegate library in link below.\n\n## New Repository \n\n[DelegateMQ](https://github.com/endurodave/DelegateMQ) - Invoke any C++ callable function synchronously, asynchronously, or on a remote endpoint.\n\n\u003ch2\u003eIntroduction\u003c/h2\u003e\n\n\u003cp\u003eC++ delegates simplify usage of a publish/subscribe pattern. With delegates, client code anonymously registers a callback function pointer to receive runtime notification. In other languages, delegates are a first class-feature and built into the language. Not so in C++ which leaves developers to create custom libraries to emulate delegates.\u003c/p\u003e\n\n\u003cp\u003eDelegates normally support synchronous executions, that is, when invoked, the bound function is executed within the caller\u0026rsquo;s thread of control. A few years ago, I wrote the article entitled \u0026ldquo;\u003ca href=\"https://www.codeproject.com/Articles/1160934/Asynchronous-Multicast-Delegates-in-Cplusplus\"\u003eAsynchronous Multicast Delegates in C++\u003c/a\u003e\u0026rdquo;. The library offers synchronous and asynchronous function invocations on any callable function. Simply put, the callback function and callback thread is specified during subscriber registration. During notification, the bound callback function is invoked on the subscriber\u0026rsquo;s desired thread of control.\u003c/p\u003e\n\n\u003cp\u003eThis article explains an extension to my original C++ delegate library: remote delegates. A remote delegate invokes a function (with data) on a remote system. A remote system is defined as an application running on a different CPU separated by a communication link or a program executing within a separate process. To a user, the delegate appears local; however the library invokes the remote function with little effort. Think of remote delegates as a C++ standard compliant remote procedure call (RPC) implemented using C++ delegates.\u003c/p\u003e\n\n\u003cp\u003eThe features of the remote delegate library are:\u003c/p\u003e\n\n\u003col\u003e\n\t\u003cli\u003e\u003cstrong\u003eRemote Invocation\u003c/strong\u003e \u0026ndash; remotely invoke any callable function (up to 5 arguments)\u003c/li\u003e\n\t\u003cli\u003e\u003cstrong\u003eAny Protocol\u003c/strong\u003e \u0026ndash; supports any transmission medium: UDP, TCP, serial, named pipes\u003c/li\u003e\n\t\u003cli\u003e\u003cstrong\u003eAny Serialization\u003c/strong\u003e \u0026ndash; support for object any serialization method: binary, JSON, XML\u003c/li\u003e\n\t\u003cli\u003e\u003cstrong\u003eEndianness\u003c/strong\u003e \u0026ndash; handles different CPU architectures\u003c/li\u003e\n\t\u003cli\u003e\u003cstrong\u003eAny Compiler\u003c/strong\u003e \u0026ndash; standard C++ code for any compiler without weird hacks\u003c/li\u003e\n\t\u003cli\u003e\u003cstrong\u003eAny OS\u003c/strong\u003e \u0026ndash; easy porting to any OS. Win32, POSIX and std::thread ports included\u003c/li\u003e\n\t\u003cli\u003e\u003cstrong\u003eAny Function\u003c/strong\u003e \u0026ndash; invoke any callable function: member, static, or free\u003c/li\u003e\n\t\u003cli\u003e\u003cstrong\u003eAny Argument Type\u003c/strong\u003e \u0026ndash; supports any argument type: value, reference, pointer, pointer to pointer\u003c/li\u003e\n\t\u003cli\u003e\u003cstrong\u003eMultiple Arguments\u003c/strong\u003e \u0026ndash; supports multiple function arguments\u003c/li\u003e\n\u003c/ol\u003e\n\n\u003cp\u003eThe remote delegate implementation significantly eases passing data and objects between remote applications. A small amount of platform-specific code is written to tailor the library to a particular OS and communication protocol. After which, the framework handles all of the low-level machinery to safely invoke any function signature on a remote system.\u003c/p\u003e\n\n\u003cp\u003eThe original asynchronous delegate implementation strived to ease inter-thread communication by invoking functions and passing data between threads using C++ delegates. Remote delegates extend the library to include inter-process and inter-processor communications.\u003c/p\u003e\n\n\u003cp\u003eThe original article \u003ca href=\"https://www.codeproject.com/Articles/1160934/Asynchronous-Multicast-Delegates-in-Cplusplus\"\u003eAsynchronous Multicast Delegates in C++\u003c/a\u003e covers all synchronous and asynchronous delegate library features. The focus of this article is the new remote delegate enhancements.\u003c/p\u003e\n\n\u003ch2\u003eDelegates Background\u003c/h2\u003e\n\n\u003cp\u003eIf you\u0026rsquo;re not familiar with a delegate, the concept is quite simple. A delegate can be thought of as a super function pointer. In C++, there\u0026#39;s no pointer type capable of pointing to all the possible function variations: instance member, virtual, const, static, and free (global). A function pointer can\u0026rsquo;t point to instance member functions, and pointers to member functions have all sorts of limitations. However, delegate classes can, in a type-safe way point to any function provided the function signature matches. In short, a delegate points to any function with a matching signature to support anonymous function invocation.\u003c/p\u003e\n\n\u003cp\u003eThis C++ delegate implementation is full featured and allows calling any function, even instance member functions, with any arguments either synchronously or asynchronously. The delegate library makes binding to and invoking any function a snap. The addition of remote delegates extends the delegate paradigm to include invoking functions executing within a separate context.\u003c/p\u003e\n\n\u003ch2\u003eUsing the Code\u003c/h2\u003e\n\n\u003cp\u003eI\u0026rsquo;ll first present how to use the code, and then get into the implementation details.\u003c/p\u003e\n\n\u003cp\u003eThe core delegate library is supported by any C++03 or higher compiler. However, all remote delegate examples are written using some C++11 features. Visual Studio/Win32 and Eclipse/POSIX projects and examples are included.\u0026nbsp;\u003c/p\u003e\n\n\u003cp\u003eThe delegate library is comprised of delegates and delegate containers. A delegate is capable of binding to a single callable function. A multicast delegate container holds one or more delegates in a list to be invoked sequentially. A single cast delegate container holds at most one delegate.\u003c/p\u003e\n\n\u003cp\u003eThe new remote delegate classes are show below, where X is the number of function arguments in the target function signature.\u003c/p\u003e\n\n\u003cul class=\"class\"\u003e\n\t\u003cli\u003e\u003ccode\u003eDelegateRemoteSendX\u0026lt;\u0026gt;\u003c/code\u003e\u003c/li\u003e\n\t\u003cli\u003e\u003ccode\u003eDelegateFreeRemoteRecvX\u0026lt;\u0026gt;\u003c/code\u003e\u003c/li\u003e\n\t\u003cli\u003e\u003ccode\u003eDelegateMemberRemoteRecvX\u0026lt;\u0026gt;\u003c/code\u003e\u003c/li\u003e\n\u003c/ul\u003e\n\n\u003cp\u003e\u003ccode\u003eDelegateRemoteSendX\u0026lt;\u0026gt;\u003c/code\u003e initiates invoking a remote function executing on a remote system. The sending system creates this object.\u003c/p\u003e\n\n\u003cp\u003e\u003ccode\u003eDelegateFreeRemoteRecvX\u0026lt;\u0026gt;\u003c/code\u003e synchronously invokes a local free callback function located on the receiving remote system.\u003c/p\u003e\n\n\u003cp\u003e\u003ccode\u003eDelegateMemberRemoteRecvX\u0026lt;\u0026gt;\u003c/code\u003e synchronously invokes a local member callback function located on the receiving remote system.\u003c/p\u003e\n\n\u003cp\u003eThe remote delegates are capable of being inserted into any existing delegate container.\u003c/p\u003e\n\n\u003cul class=\"class\"\u003e\n\t\u003cli\u003e\u003ccode\u003eSinglecastDelegateX\u0026lt;\u0026gt;\u003c/code\u003e\u003c/li\u003e\n\t\u003cli\u003e\u003ccode\u003eMulticastDelegateX\u0026lt;\u0026gt;\u003c/code\u003e\u003c/li\u003e\n\t\u003cli\u003e\u003ccode\u003eMulticastDelegateSafeX\u0026lt;\u0026gt;\u003c/code\u003e\u003c/li\u003e\n\u003c/ul\u003e\n\n\u003ch3\u003eSend Data Example\u003c/h3\u003e\n\n\u003cp\u003eThe send application shows how to invoke a remote function with a single \u003ccode\u003eRemoteDataPoint\u0026amp;\u003c/code\u003e argument. The key points on the code below are:\u003c/p\u003e\n\n\u003col\u003e\n\t\u003cli\u003e\u003ccode\u003eMakeDelegate()\u003c/code\u003e creates a send remote delegate.\u003c/li\u003e\n\t\u003cli\u003eInvoke the send remote delegate.\u003c/li\u003e\n\u003c/ol\u003e\n\n\u003cpre lang=\"c++\"\u003e\nint main(void)\n{\n    BOOL result = AfxWinInit(GetModuleHandle(NULL), NULL, ::GetCommandLine(), 0);\n    ASSERT_TRUE(result == TRUE);\n\n    result = AfxSocketInit(NULL);\n    ASSERT_TRUE(result == TRUE);\n\n    UdpDelegateSend::GetInstance().Initialize();\n\n    // Create a stream to hold send data\n    stringstream ss(ios::in | ios::out | ios::binary);\n\n    // Create a send remote delegate\n    auto sendDataPointDelegate =\n        MakeDelegate\u0026lt;RemoteDataPoint\u0026amp;\u0026gt;(UdpDelegateSend::GetInstance(), ss, REMOTE_DATA_POINT_ID);\n\n    cout \u0026lt;\u0026lt; \u0026quot;Press any key to exit program.\u0026quot; \u0026lt;\u0026lt; endl;\n\n    int x = 1;\n    int y = 1;\n    while (!_kbhit())\n    {\n        // Send data point to remote system\n        RemoteDataPoint dataPoint(x++, y++);\n        sendDataPointDelegate(dataPoint);\n    }\n\n    return 0;\n}\u003c/pre\u003e\n\n\u003cp\u003e\u003ccode\u003eMakeDelegate()\u003c/code\u003e is an overloaded function that helps create delegate objects. Normally \u003ccode\u003eMakeDelegate()\u003c/code\u003e uses template argument deduction to create the correct instance type based on the arguments. However, a sending delegate doesn\u0026rsquo;t bind to a function; the bound function is on the remote. Therefore, when creating a send delegate the function is called using the template function argument types.\u003c/p\u003e\n\n\u003cpre lang=\"c++\"\u003e\nauto sendDataPointDelegate =\n    MakeDelegate\u0026lt;RemoteDataPoint\u0026amp;\u0026gt;(UdpDelegateSend::GetInstance(), ss, REMOTE_DATA_POINT_ID);\u003c/pre\u003e\n\n\u003cp\u003eThe first argument is the transport object. The second argument is outgoing data byte stream. The last argument is a shared ID between the sender and receiver.\u003c/p\u003e\n\n\u003cp\u003eThe sender invokes the remote delegate using the correct function arguments. The \u003ccode\u003eRemoteDataPoint \u003c/code\u003eobject is serialized and a message sent to the receiver.\u003c/p\u003e\n\n\u003cpre lang=\"c++\"\u003e\nRemoteDataPoint dataPoint(x++, y++);\nsendDataPointDelegate(dataPoint);\u003c/pre\u003e\n\n\u003ch3\u003eReceive Delegate Example\u003c/h3\u003e\n\n\u003cp\u003eThe receive application shows how to register for a remote delegate callback. The key points on the code below:\u003c/p\u003e\n\n\u003col\u003e\n\t\u003cli\u003e\u003ccode\u003eMakeDelegate()\u003c/code\u003e creates a receive remote delegate.\u003c/li\u003e\n\t\u003cli\u003e\u003ccode\u003eRecvDataPointCb()\u003c/code\u003e is called when the sender invokes the delegate.\u003c/li\u003e\n\u003c/ol\u003e\n\n\u003cpre lang=\"c++\"\u003e\nstatic void RecvDataPointCb(RemoteDataPoint\u0026amp; data)\n{\n    cout \u0026lt;\u0026lt; \u0026quot;RemoteDataPoint: \u0026quot; \u0026lt;\u0026lt; data.GetX() \u0026lt;\u0026lt; \u0026quot; \u0026quot; \u0026lt;\u0026lt; data.GetY() \u0026lt;\u0026lt; endl;\n}\n\nint main(void)\n{\n    BOOL result = AfxWinInit(GetModuleHandle(NULL), NULL, ::GetCommandLine(), 0);\n    ASSERT_TRUE(result == TRUE);\n\n    result = AfxSocketInit(NULL);\n    ASSERT_TRUE(result == TRUE);\n\n    UdpDelegateRecv::GetInstance().Initialize();\n\n    // Create a receive remote delegate\n    auto recvDataPointDelegate = MakeDelegate(\u0026amp;RecvDataPointCb, REMOTE_DATA_POINT_ID);\n\n    cout \u0026lt;\u0026lt; \u0026quot;Press any key to exit program.\u0026quot; \u0026lt;\u0026lt; endl;\n\n    while (!_kbhit())\n        Sleep(10);\n\n    return 0;\n}\u003c/pre\u003e\n\n\u003cp\u003eThe receiver creates a delegate using the same ID as the sender.\u003c/p\u003e\n\n\u003cpre lang=\"c++\"\u003e\n// Create a receive remote delegate\nauto recvDataPointDelegate = MakeDelegate(\u0026amp;RecvDataPointCb, REMOTE_DATA_POINT_ID);\u003c/pre\u003e\n\n\u003cp\u003eThe first argument is a pointer to the callback function. The second argument is the shared ID. The delegate library receives the message, deserialized the \u003ccode\u003eReceiveDataPoint\u003c/code\u003e object, and invokes the callback function.\u003c/p\u003e\n\n\u003cp\u003eOf course, the delegate library supports member function callbacks, in addition to multiple arguments and different argument types.\u003c/p\u003e\n\n\u003ch3\u003eSysData Example\u003c/h3\u003e\n\n\u003cp\u003eThe remote delegates can be inserted into a delegate container, just like any other delegate type. The types of delegates are summarized below:\u003c/p\u003e\n\n\u003col\u003e\n\t\u003cli\u003eSynchronous\u003c/li\u003e\n\t\u003cli\u003eAsynchronous\u003c/li\u003e\n\t\u003cli\u003eAsynchronous Blocking\u003c/li\u003e\n\t\u003cli\u003eRemote\u003c/li\u003e\n\u003c/ol\u003e\n\n\u003cp\u003eThis example shows how to register for notification using each delegate type. \u003ccode\u003eSysData \u003c/code\u003eis a simple class that stores the system mode and notifies clients when changed.\u003c/p\u003e\n\n\u003cpre lang=\"c++\"\u003e\n/// @brief SysData stores common data accessible by any system thread. This class\n/// is thread-safe.\nclass SysData\n{\npublic:\n    /// Clients register with MulticastDelegateSafe1 to get callbacks when system mode changes\n    static MulticastDelegateSafe1\u0026lt;const SystemModeChanged\u0026amp;\u0026gt; SystemModeChangedDelegate;\n\n    /// Get singleton instance of this class\n    static SysData\u0026amp; GetInstance();\n\n    /// Sets the system mode and notify registered clients via SystemModeChangedDelegate.\n    /// @param[in] systemMode - the new system mode. \n    void SetSystemMode(SystemMode::Type systemMode);    \n\nprivate:\n    SysData();\n    ~SysData();\n\n    /// The current system mode data\n    SystemMode::Type m_systemMode;\n\n    /// Lock to make the class thread-safe\n    LOCK m_lock;\n};\u003c/pre\u003e\n\n\u003cp\u003eThe \u003ccode\u003eSystemModeChangedDelegate \u003c/code\u003econtainer is used by subscribers to register. The function callback signature is \u003ccode\u003evoid (const SystemModeChanged\u0026amp;)\u003c/code\u003e.\u003c/p\u003e\n\n\u003cpre lang=\"c++\"\u003e\nstatic MulticastDelegateSafe1\u0026lt;const SystemModeChanged\u0026amp;\u0026gt; SystemModeChangedDelegate;\u003c/pre\u003e\n\n\u003cp\u003eThe \u003ccode\u003eSystemModeChanged \u003c/code\u003eobject is the callback argument type.\u003c/p\u003e\n\n\u003cpre lang=\"c++\"\u003e\n/// @brief Structure to hold system mode callback data. \nclass SystemModeChanged\n{\npublic:\n    SystemModeChanged() : \n        PreviousSystemMode(SystemMode::STARTING), \n        CurrentSystemMode(SystemMode::STARTING)\n    {\n    }\n\n    SystemMode::Type PreviousSystemMode;\n    SystemMode::Type CurrentSystemMode;\n\n    friend std::ostream\u0026amp; operator\u0026lt;\u0026lt; (std::ostream \u0026amp;out, const SystemModeChanged\u0026amp; data);\n    friend std::istream\u0026amp; operator\u0026gt;\u0026gt; (std::istream \u0026amp;in, const SystemModeChanged\u0026amp; data);\n};\u003c/pre\u003e\n\n\u003cp\u003eWhen someone calls\u003ccode\u003e SysData::SetSystemMode()\u003c/code\u003e the new mode is saved and all registered subscribers are notified.\u003c/p\u003e\n\n\u003cpre lang=\"c++\"\u003e\nvoid SysData::SetSystemMode(SystemMode::Type systemMode)\n{\n    LockGuard lockGuard(\u0026amp;m_lock);\n\n    // Create the callback data\n    SystemModeChanged callbackData;\n    callbackData.PreviousSystemMode = m_systemMode;\n    callbackData.CurrentSystemMode = systemMode;\n\n    // Update the system mode\n    m_systemMode = systemMode;\n\n    // Callback all registered subscribers\n    if (SystemModeChangedDelegate)\n        SystemModeChangedDelegate(callbackData);\n}\u003c/pre\u003e\n\n\u003cp\u003e\u003ccode\u003eTestSysData()\u003c/code\u003e registers four callbacks with \u003ccode\u003eSysData::SystemModeChangedDelegate\u003c/code\u003e. Each callback represents a different notification type: remote, synchronous, asynchronous and asynchronous blocking.\u003c/p\u003e\n\n\u003cp\u003eNotice that \u003ccode\u003eSysData\u003c/code\u003e just exposes a generic delegate container. Each anonymous client decides on the how to be notified. Also note how the arguments used in calling \u003ccode\u003eMakeDelegate()\u003c/code\u003e dictate the delegate type created.\u003c/p\u003e\n\n\u003cpre lang=\"c++\"\u003e\n// Callback function to receive notifications\nstatic void SystemModeChangedCb(const SystemModeChanged\u0026amp; data)\n{\n    cout \u0026lt;\u0026lt; \u0026quot;SystemModeChangedCb: \u0026quot; \u0026lt;\u0026lt; data.CurrentSystemMode \u0026lt;\u0026lt; \u0026quot; \u0026quot; \u0026lt;\u0026lt; \n             data.PreviousSystemMode \u0026lt;\u0026lt; endl;\n}\n\nvoid TestSysData()\n{\n    sysDataWorkerThread.CreateThread();\n\n    // Binary stream of send data bytes\n    stringstream ss(ios::in | ios::out | ios::binary);\n\n    // Register to send a remote callback\n    SysData::SystemModeChangedDelegate +=\n        MakeDelegate\u0026lt;const SystemModeChanged\u0026amp;\u0026gt;(UdpDelegateSend::GetInstance(), \n                     ss, REMOTE_SYSTEM_MODE_CHANGED_ID);\n\n    // Create a receive delegate to receive remote callback\n    auto recvDataPointDelegate = \n         MakeDelegate(\u0026amp;SystemModeChangedCb, REMOTE_SYSTEM_MODE_CHANGED_ID);\n\n    // Register for synchronous callback\n    SysData::SystemModeChangedDelegate += MakeDelegate(\u0026amp;SystemModeChangedCb);\n\n    // Register for asynchronous callback on a worker thread\n    SysData::SystemModeChangedDelegate += \n             MakeDelegate(\u0026amp;SystemModeChangedCb, \u0026amp;sysDataWorkerThread);\n\n    // Register for asynchronous blocking callback on a worker thread\n    SysData::SystemModeChangedDelegate += \n             MakeDelegate(\u0026amp;SystemModeChangedCb, \u0026amp;sysDataWorkerThread, 5000);\n\n    // Change system mode. All registered subscribers are notified. \n    SysData::GetInstance().SetSystemMode(SystemMode::STARTING);\n    SysData::GetInstance().SetSystemMode(SystemMode::NORMAL);\n\n\u0026nbsp; \u0026nbsp; std::this_thread::sleep_for(std::chrono::seconds(1));\n\n    // Unregister all callbacks\n    SysData::SystemModeChangedDelegate -= MakeDelegate(\u0026amp;SystemModeChangedCb);\n    SysData::SystemModeChangedDelegate -= \n             MakeDelegate(\u0026amp;SystemModeChangedCb, \u0026amp;sysDataWorkerThread);\n    SysData::SystemModeChangedDelegate -= \n             MakeDelegate(\u0026amp;SystemModeChangedCb, \u0026amp;sysDataWorkerThread, 5000);\n    SysData::SystemModeChangedDelegate -=\n        MakeDelegate\u0026lt;const SystemModeChanged\u0026amp;\u0026gt;\n             (UdpDelegateSend::GetInstance(), ss, REMOTE_SYSTEM_MODE_CHANGED_ID);\n\n    sysDataWorkerThread.ExitThread();\n}\u003c/pre\u003e\n\n\u003ch2\u003ePorting Details\u003c/h2\u003e\n\n\u003cp\u003eThe remote delegate library is abstracted from object serialization and the communication protocol. Generic interfaces are used by the library to perform these actions.\u003c/p\u003e\n\n\u003ch3\u003eSerialization\u003c/h3\u003e\n\n\u003cp\u003eEach user-defined data type sent as a remote delegate argument must:\u003c/p\u003e\n\n\u003col\u003e\n\t\u003cli\u003eImplement a default constructor.\u003c/li\u003e\n\t\u003cli\u003eOverload the insertion and extraction operators to serialize the object (i.e., \u003ccode\u003eoperator\u0026lt;\u0026lt;\u003c/code\u003e and \u003ccode\u003eoperator\u0026gt;\u0026gt;\u003c/code\u003e).\u003c/li\u003e\n\u003c/ol\u003e\n\n\u003cp\u003eThe example below binary serializes (i.e., inserts/extracts) a \u003ccode\u003eRemoteDataPoint\u0026amp;\u003c/code\u003e object.\u003c/p\u003e\n\n\u003cpre lang=\"c++\"\u003e\nstruct RemoteDataPoint\n{\npublic:\n    RemoteDataPoint(int x, int y) : m_x(x), m_y(y) {}\n    RemoteDataPoint() : m_x(0), m_y(0) {}\n    int GetX() const { return m_x; }\n    int GetY() const { return m_y; }\n\nprivate:\n    int m_y;\n    int m_x;\n\n    friend std::ostream\u0026amp; operator\u0026lt;\u0026lt; (std::ostream \u0026amp;out, const RemoteDataPoint\u0026amp; data);\n    friend std::istream\u0026amp; operator\u0026gt;\u0026gt; (std::istream \u0026amp;in, RemoteDataPoint\u0026amp; data);\n};\n\nstd::ostream\u0026amp; operator\u0026lt;\u0026lt; (std::ostream \u0026amp;out, const RemoteDataPoint\u0026amp; data)\n{\n\u0026nbsp; \u0026nbsp; out \u0026lt;\u0026lt; data.m_x \u0026lt;\u0026lt; std::endl;\n\u0026nbsp; \u0026nbsp; out \u0026lt;\u0026lt; data.m_y \u0026lt;\u0026lt; std::endl;\n\u0026nbsp; \u0026nbsp; return out;\n}\nstd::istream\u0026amp; operator\u0026gt;\u0026gt; (std::istream \u0026amp;in, RemoteDataPoint\u0026amp; data)\n{\n\u0026nbsp; \u0026nbsp; in \u0026gt;\u0026gt; data.m_x;\n\u0026nbsp; \u0026nbsp; in \u0026gt;\u0026gt; data.m_y;\n\u0026nbsp; \u0026nbsp; return in;\n}\u003c/pre\u003e\n\n\u003cp\u003eA similar \u003ccode\u003eRemoteDataPointJson \u003c/code\u003eobject is serialized with RapidJSON.\u003c/p\u003e\n\n\u003cpre lang=\"c++\"\u003e\nstd::ostream\u0026amp; operator\u0026lt;\u0026lt; (std::ostream \u0026amp;out, const RemoteDataPointJson\u0026amp; data)\n{\n\u0026nbsp; \u0026nbsp; StringBuffer sb;\n\u0026nbsp; \u0026nbsp; PrettyWriter\u0026lt;StringBuffer\u0026gt; writer(sb);\n\n\u0026nbsp; \u0026nbsp; // Serialize object using JSON\n\u0026nbsp; \u0026nbsp; data.Serialize(writer);\n\n\u0026nbsp; \u0026nbsp; // Add JSON length\u0026nbsp;\n\u0026nbsp; \u0026nbsp; out \u0026lt;\u0026lt; sb.GetLength() + 1;\u0026nbsp;\n\n\u0026nbsp; \u0026nbsp; // Add JSON string\n\u0026nbsp; \u0026nbsp; out \u0026lt;\u0026lt; sb.GetString();\n\u0026nbsp; \u0026nbsp; return out;\n}\nstd::istream\u0026amp; operator\u0026gt;\u0026gt; (std::istream \u0026amp;in, RemoteDataPointJson\u0026amp; data)\n{\n\u0026nbsp; \u0026nbsp; // Get JSON length\n\u0026nbsp; \u0026nbsp; size_t bufLen = 0;\n\u0026nbsp; \u0026nbsp; in \u0026gt;\u0026gt; bufLen;\n\n\u0026nbsp; \u0026nbsp; // Allocate storage buffer\n\u0026nbsp; \u0026nbsp; char* buf = (char*)malloc(bufLen);\n\n\u0026nbsp; \u0026nbsp; // Copy JSON into buffer\u0026nbsp;\n\u0026nbsp; \u0026nbsp; in.rdbuf()-\u0026gt;sgetn(buf, bufLen);\n\n\u0026nbsp; \u0026nbsp; // Parse JSON\n\u0026nbsp; \u0026nbsp; Document d;\n\u0026nbsp; \u0026nbsp; d.Parse(buf);\n\n\u0026nbsp; \u0026nbsp; // Get JSON values into object variables\n\u0026nbsp; \u0026nbsp; data.m_x = d[\u0026quot;m_x\u0026quot;].GetInt();\n\u0026nbsp; \u0026nbsp; data.m_y = d[\u0026quot;m_y\u0026quot;].GetInt();\n\n\u0026nbsp; \u0026nbsp; free(buf);\n\u0026nbsp; \u0026nbsp; return in;\n}\u003c/pre\u003e\n\n\u003cp\u003eThe serialization and deserialization method employed is up to you. The only requirement is that an input or output stream is used to hold the serialized object.\u003c/p\u003e\n\n\u003cp\u003eA \u003ccode\u003estd::stringstream\u003c/code\u003e is used in the examples. But any class deriving from \u003ccode\u003estd::iostream\u003c/code\u003e can be utilized.\u003c/p\u003e\n\n\u003ch3\u003eTransport\u003c/h3\u003e\n\n\u003cp\u003eThe remote delegate library uses the \u003ccode\u003eIDelegateTransport\u003c/code\u003e class to send data to the remote.\u003c/p\u003e\n\n\u003cpre lang=\"c++\"\u003e\nclass IDelegateTransport\n{\npublic:\n    /// Dispatch a stream of bytes to a remote system. The implementer is responsible\n    /// for sending the bytes over a communication link. Once the receiver obtains the \n    /// bytes, the DelegateRemoteInvoker::DelegateInvoke() function must be called to \n    /// execute the callback on the remote system. \n    /// @param[in] s - an outgoing stream to send to the remote CPU.\n    virtual void DispatchDelegate(std::iostream\u0026amp; s) = 0;\n};\u003c/pre\u003e\n\n\u003cp\u003eA sender inherits from \u003ccode\u003eIDelegateTransport \u003c/code\u003eand implements \u003ccode\u003eDispatchDelegate()\u003c/code\u003e. The UDP implementation is shown below:\u003c/p\u003e\n\n\u003cpre lang=\"c++\"\u003e\nvoid UdpDelegateSend::DispatchDelegate(std::iostream\u0026amp; s)\n{\n    size_t len = (size_t)s.tellp();\n    char* sendBuf = (char*)malloc(len);\n\n    // Copy char buffer into heap allocated memory\n    s.rdbuf()-\u0026gt;sgetn(sendBuf, len);\n\n    // Send data to remote system using a socket\n    int result = m_sendSocket.Send((void*)sendBuf, len, 0);\n    ASSERT_TRUE(result == len);\n\n    free(sendBuf);\n\n    // Reset stream positions\n    s.seekg(0);\n    s.seekp(0);\n}\u003c/pre\u003e\n\n\u003cp\u003eSimilarly, a Windows named pipe sends remote delegates between processes.\u003c/p\u003e\n\n\u003cpre lang=\"c++\"\u003e\nvoid PipeDelegateSend::DispatchDelegate(std::iostream\u0026amp; s)\n{\n    size_t len = (size_t)s.tellp();\n    char* sendBuf = (char*)malloc(len);\n\n    // Copy char buffer into heap allocated memory\n    s.rdbuf()-\u0026gt;sgetn(sendBuf, len);\n\n    // Send message through named pipe\n    DWORD sentLen = 0;\n    BOOL success = WriteFile(m_hPipe, sendBuf, len, \u0026amp;sentLen, NULL);\n    ASSERT_TRUE(success \u0026amp;\u0026amp; sentLen == len);\n\n    free(sendBuf);\n\n    // Reset stream positions\n    s.seekg(0);\n    s.seekp(0);\n}\u003c/pre\u003e\n\n\u003cp\u003eA receiver thread obtains data from a UDP socket. The only requirement is that \u003ccode\u003eDelegateRemoteInvoker::Invoke()\u003c/code\u003e is called with the incoming stream of data.\u003c/p\u003e\n\n\u003cpre lang=\"c++\"\u003e\nunsigned long UdpDelegateRecv::Process(void* parameter)\n{  \n    MSG msg;\n    const int BUF_SIZE = 1024;\n    char recvBuf[BUF_SIZE];\n\n    SOCKADDR_IN addr;\n    int addrLen = sizeof(addr);\n\n    BOOL success = AfxSocketInit(NULL);\n    ASSERT_TRUE(success == TRUE);\n\n    success = m_recvSocket.Create(514, SOCK_DGRAM, NULL);\n    ASSERT_TRUE(success);\n\n    m_started = true;\n\n    for (;;)\n    {\n        // Check for thread exit message\n        if (PeekMessage(\u0026amp;msg, NULL, WM_USER_BEGIN, WM_USER_END, PM_REMOVE) != 0)\n        {\n            switch (msg.message)\n            {\n            case WM_EXIT_THREAD:\n                m_recvSocket.Close();\n                return 0;\n            }\n        }\n\n        // Check for socket receive message\n        int recvMsgSize = m_recvSocket.Receive(recvBuf, BUF_SIZE, 0);\n        if (recvMsgSize \u0026gt; 0)\n        {\n            // Copy receive data bytes into a stringstream\n            stringstream ss(ios::in | ios::out | ios::binary);\n            ss.write(recvBuf, recvMsgSize);\n\n           // Invoke the remote delegate callback function\n           DelegateRemoteInvoker::Invoke(ss);\n        }\n        else\n        {\n            Sleep(100);\n        }\n    }\n\n    return 0;\n}\u003c/pre\u003e\n\n\u003cp\u003eA named pipe is implemented similarly. Notice the same \u003ccode\u003eDelegateRemoteInvoker::Invoke()\u003c/code\u003e function is called, only in this case the data bytes are obtained from a named pipe and not a UDP socket.\u003c/p\u003e\n\n\u003cpre lang=\"c++\"\u003e\nunsigned long PipeDelegateRecv::Process(void* parameter)\n{  \n    MSG msg;\n    BOOL connected = FALSE;\n    char recvBuf[BUF_SIZE];\n\n    for (;;)\n    {\n        // Check for thread exit message\n        if (PeekMessage(\u0026amp;msg, NULL, WM_USER_BEGIN, WM_USER_END, PM_REMOVE) != 0)\n        {\n            switch (msg.message)\n            {\n            case WM_EXIT_THREAD:\n                CloseHandle(m_hPipe);\n                return 0;\n            }\n        }\n\n        if (!connected)\n        {\n            // Check if client connected\n            connected = ConnectNamedPipe(m_hPipe, NULL) ?\n                TRUE : (GetLastError() == ERROR_PIPE_CONNECTED);\n        }\n        else\n        {\n            DWORD recvMsgSize = 0;\n            BOOL success = ReadFile(m_hPipe, recvBuf, BUF_SIZE, \u0026amp;recvMsgSize, NULL);\n\n            if (success \u0026amp;\u0026amp; recvMsgSize \u0026gt; 0)\n            {\n                // Copy receive data bytes into a stringstream\n                stringstream ss(ios::in | ios::out | ios::binary);\n                ss.write(recvBuf, recvMsgSize);\n\n                // Invoke the remote delegate callback function\n                DelegateRemoteInvoker::Invoke(ss);\n            }\n            else\n            {\n                Sleep(100);\n            }\n        }\n    }\n\n    return 0;\n}\u003c/pre\u003e\n\n\u003cp\u003ePOSIX \u003ccode\u003eUdpDelegateSend\u0026nbsp;\u003c/code\u003eand \u003ccode\u003eUdpDelegateRecv \u003c/code\u003eexamples are available in the attached source code. \u0026nbsp;\u003c/p\u003e\n\n\u003cp\u003eThe \u003ccode\u003eDelegateRemoteInvoker()\u003c/code\u003e library function simply looks up the matching receive delegate instance by ID and calls \u003ccode\u003eDelegateInvoke()\u003c/code\u003e.\u003c/p\u003e\n\n\u003cpre lang=\"c++\"\u003e\nbool DelegateRemoteInvoker::Invoke(std::istream\u0026amp; s)\n{\n\u0026nbsp; \u0026nbsp; // Get id from stream\n\u0026nbsp; \u0026nbsp; DelegateIdType id;\n\u0026nbsp; \u0026nbsp; s \u0026gt;\u0026gt; id;\n\u0026nbsp; \u0026nbsp; s.seekg(0);\n\n\u0026nbsp; \u0026nbsp; // Find invoker instance matching the id\n\u0026nbsp; \u0026nbsp; std::map\u0026lt;DelegateIdType, DelegateRemoteInvoker*\u0026gt;::iterator it;\n\u0026nbsp; \u0026nbsp; {\n\u0026nbsp; \u0026nbsp; \u0026nbsp; \u0026nbsp; LockGuard lockGuard(GetLock());\n\u0026nbsp; \u0026nbsp; \u0026nbsp; \u0026nbsp; it = GetMap().find(id);\n\u0026nbsp; \u0026nbsp; }\n\u0026nbsp; \u0026nbsp; if (it != GetMap().end())\n\u0026nbsp; \u0026nbsp; {\n\u0026nbsp; \u0026nbsp; \u0026nbsp; \u0026nbsp; // Invoke the delegate instance\n\u0026nbsp; \u0026nbsp; \u0026nbsp; \u0026nbsp; (*it).second-\u0026gt;DelegateInvoke(s);\n\u0026nbsp; \u0026nbsp; \u0026nbsp; \u0026nbsp; return true;\n\u0026nbsp; \u0026nbsp; }\n\u0026nbsp; \u0026nbsp; else\n\u0026nbsp; \u0026nbsp; {\n\u0026nbsp; \u0026nbsp; \u0026nbsp; \u0026nbsp; // No delegate found\n\u0026nbsp; \u0026nbsp; \u0026nbsp; \u0026nbsp; return false;\n\u0026nbsp; \u0026nbsp; }\n}\u003c/pre\u003e\n\n\u003cp\u003eThe transport mechanism is completely user defined. Any communication medium is supported using a small amount of platform specific code.\u003c/p\u003e\n\n\u003ch2\u003eRemote Delegate Details\u003c/h2\u003e\n\n\u003cp\u003e\u003ccode\u003eDelegateRemoteSend1\u0026lt;\u0026gt;\u003c/code\u003e implements a single parameter send remote delegate.\u003c/p\u003e\n\n\u003cpre lang=\"c++\"\u003e\n/// @brief Send a delegate to invoke a function on a remote system.\u0026nbsp;\ntemplate \u0026lt;class Param1\u0026gt;\nclass DelegateRemoteSend1 : public Delegate1\u0026lt;Param1\u0026gt; {\npublic:\n\u0026nbsp; \u0026nbsp; DelegateRemoteSend1(IDelegateTransport\u0026amp; transport, std::iostream\u0026amp; stream, DelegateIdType id) :\u0026nbsp;\n\u0026nbsp; \u0026nbsp; \u0026nbsp; \u0026nbsp; m_transport(transport), m_stream(stream), m_id(id) { }\n\n\u0026nbsp;\u0026nbsp; \u0026nbsp;virtual DelegateRemoteSend1* Clone() const { return new DelegateRemoteSend1(*this); }\n\n\u0026nbsp;\u0026nbsp; \u0026nbsp;/// Invoke the bound delegate function.\u0026nbsp;\n\u0026nbsp;\u0026nbsp; \u0026nbsp;virtual void operator()(Param1 p1) {\n\u0026nbsp; \u0026nbsp; \u0026nbsp; \u0026nbsp; m_stream \u0026lt;\u0026lt; m_id \u0026lt;\u0026lt; std::ends;\n\u0026nbsp; \u0026nbsp; \u0026nbsp; \u0026nbsp; m_stream \u0026lt;\u0026lt; p1 \u0026lt;\u0026lt; std::ends;\n\u0026nbsp; \u0026nbsp; \u0026nbsp; \u0026nbsp; m_transport.DispatchDelegate(m_stream);\n\u0026nbsp; \u0026nbsp; }\n\n\u0026nbsp;\u0026nbsp; \u0026nbsp;virtual bool operator==(const DelegateBase\u0026amp; rhs) const {\n\u0026nbsp;\u0026nbsp; \u0026nbsp;\u0026nbsp;\u0026nbsp; \u0026nbsp;const DelegateRemoteSend1\u0026lt;Param1\u0026gt;* derivedRhs = dynamic_cast\u0026lt;const DelegateRemoteSend1\u0026lt;Param1\u0026gt;*\u0026gt;(\u0026amp;rhs);\n\u0026nbsp;\u0026nbsp; \u0026nbsp;\u0026nbsp;\u0026nbsp; \u0026nbsp;return derivedRhs \u0026amp;\u0026amp;\n\u0026nbsp;\u0026nbsp; \u0026nbsp;\u0026nbsp;\u0026nbsp; \u0026nbsp;\u0026nbsp;\u0026nbsp; \u0026nbsp;m_id == derivedRhs-\u0026gt;m_id \u0026amp;\u0026amp;\n\u0026nbsp; \u0026nbsp; \u0026nbsp; \u0026nbsp; \u0026nbsp; \u0026nbsp; \u0026amp;m_transport == \u0026amp;derivedRhs-\u0026gt;m_transport; }\n\nprivate:\n\u0026nbsp;\u0026nbsp; \u0026nbsp;IDelegateTransport\u0026amp; m_transport; \u0026nbsp; \u0026nbsp;// Object sends data to remote\n\u0026nbsp; \u0026nbsp; std::iostream\u0026amp; m_stream; \u0026nbsp; \u0026nbsp; \u0026nbsp; \u0026nbsp; \u0026nbsp; \u0026nbsp;// Storage for remote message\u0026nbsp;\n\u0026nbsp; \u0026nbsp; DelegateIdType m_id; \u0026nbsp; \u0026nbsp; \u0026nbsp; \u0026nbsp; \u0026nbsp; \u0026nbsp; \u0026nbsp; \u0026nbsp;// Remote delegate identifier\n};\u003c/pre\u003e\n\n\u003cp\u003eThe constructor requires a \u003ccode\u003eIDelegateTransport\u0026amp;\u003c/code\u003e, a \u003ccode\u003estd::iostream\u0026amp;\u003c/code\u003e and a \u003ccode\u003eDelegateIdType\u003c/code\u003e.\u003c/p\u003e\n\n\u003cp\u003eThe \u003ccode\u003eoperator()\u003c/code\u003e inserts \u003ccode\u003em_id\u003c/code\u003e into the stream then calls \u003ccode\u003eoperator\u0026lt;\u0026lt;\u003c/code\u003e on each parameter to serialize. After which, \u003ccode\u003eDispatchDelegate()\u003c/code\u003e is called to send the delegate the remote system.\u003c/p\u003e\n\n\u003cp\u003e\u003ccode\u003eDelegateFreeRemoteRecv1\u0026lt;\u0026gt;\u003c/code\u003e implements a single parameter receive remote delegate.\u003c/p\u003e\n\n\u003cpre lang=\"c++\"\u003e\ntemplate \u0026lt;class Param1\u0026gt;\nclass DelegateFreeRemoteRecv1 : public DelegateFree1\u0026lt;Param1\u0026gt;, public DelegateRemoteInvoker {\npublic:\n\u0026nbsp; \u0026nbsp; typedef void(*FreeFunc)(Param1);\n\n\u0026nbsp; \u0026nbsp; // Contructors take a free function and delegete id\u0026nbsp;\n\u0026nbsp; \u0026nbsp; DelegateFreeRemoteRecv1(FreeFunc func, DelegateIdType id) : DelegateRemoteInvoker(id) { Bind(func, id); }\n\n\u0026nbsp; \u0026nbsp; /// Bind a free function to the delegate.\n\u0026nbsp; \u0026nbsp; void Bind(FreeFunc func, DelegateIdType id) {\n\u0026nbsp; \u0026nbsp; \u0026nbsp; \u0026nbsp; m_id = id;\n\u0026nbsp; \u0026nbsp; \u0026nbsp; \u0026nbsp; DelegateFree1\u0026lt;Param1\u0026gt;::Bind(func);\n\u0026nbsp; \u0026nbsp; }\n\n\u0026nbsp; \u0026nbsp; virtual DelegateFreeRemoteRecv1* Clone() const { return new DelegateFreeRemoteRecv1(*this); }\n\n\u0026nbsp; \u0026nbsp; /// Called by the remote system to invoke the delegate function\n\u0026nbsp; \u0026nbsp; virtual void DelegateInvoke(std::istream\u0026amp; stream) {\n\u0026nbsp; \u0026nbsp; \u0026nbsp; \u0026nbsp; RemoteParam\u0026lt;Param1\u0026gt; param1;\n\n\u0026nbsp; \u0026nbsp; \u0026nbsp; \u0026nbsp; Param1 p1 = param1.Get();\n\n\u0026nbsp; \u0026nbsp; \u0026nbsp; \u0026nbsp; stream \u0026gt;\u0026gt; m_id;\n\u0026nbsp; \u0026nbsp; \u0026nbsp; \u0026nbsp; stream.seekg(stream.tellg() + std::streampos(1));\n\u0026nbsp; \u0026nbsp; \u0026nbsp; \u0026nbsp; stream \u0026gt;\u0026gt; p1;\n\u0026nbsp; \u0026nbsp; \u0026nbsp; \u0026nbsp; stream.seekg(stream.tellg() + std::streampos(1));\n\n\u0026nbsp; \u0026nbsp; \u0026nbsp; \u0026nbsp; DelegateFree1\u0026lt;Param1\u0026gt;::operator()(p1);\n\u0026nbsp; \u0026nbsp; }\n\n\u0026nbsp; \u0026nbsp; virtual bool operator==(const DelegateBase\u0026amp; rhs) const {\n\u0026nbsp; \u0026nbsp; \u0026nbsp; \u0026nbsp; const DelegateFreeRemoteRecv1\u0026lt;Param1\u0026gt;* derivedRhs = dynamic_cast\u0026lt;const DelegateFreeRemoteRecv1\u0026lt;Param1\u0026gt;*\u0026gt;(\u0026amp;rhs);\n\u0026nbsp; \u0026nbsp; \u0026nbsp; \u0026nbsp; return derivedRhs \u0026amp;\u0026amp;\n\u0026nbsp; \u0026nbsp; \u0026nbsp; \u0026nbsp; \u0026nbsp; \u0026nbsp; m_id == derivedRhs-\u0026gt;m_id \u0026amp;\u0026amp;\n\u0026nbsp; \u0026nbsp; \u0026nbsp; \u0026nbsp; \u0026nbsp; \u0026nbsp; DelegateFree1\u0026lt;Param1\u0026gt;::operator == (rhs);\n\u0026nbsp; \u0026nbsp; }\n\nprivate:\n\u0026nbsp; \u0026nbsp; DelegateIdType m_id; \u0026nbsp; \u0026nbsp; \u0026nbsp; \u0026nbsp; \u0026nbsp; \u0026nbsp; \u0026nbsp; // Remote delegate identifier\n};\u003c/pre\u003e\n\n\u003cp\u003eThe constructor takes a \u003ccode\u003eFreeFunc\u003c/code\u003e function pointer and a \u003ccode\u003eDelegateIdType\u003c/code\u003e.\u003c/p\u003e\n\n\u003cp\u003e\u003ccode\u003eDelegateRemoteInvoker::Invoke()\u003c/code\u003e calls \u003ccode\u003eDelegateInvoke()\u003c/code\u003e with the incoming data stream. Each function parameter is deserialized using \u003ccode\u003eoperator\u0026lt;\u0026lt;\u003c/code\u003e and the \u003ccode\u003eFreeFunc\u003c/code\u003e target function is called.\u003c/p\u003e\n\n\u003cp\u003eThe member function delegate variants are implemented similarly.\u003c/p\u003e\n\n\u003ch3\u003eAsynchronous Delegate Details\u003c/h3\u003e\n\n\u003cp\u003eAsynchronous delegates are also part of delegate library. The porting details for those features are covered within the \u003ca href=\"https://www.codeproject.com/Articles/1160934/Asynchronous-Multicast-Delegates-in-Cplusplus\"\u003eAsynchronous Multicast Delegates in C++\u003c/a\u003e article.\u003c/p\u003e\n\n\u003ch2\u003eSource Code\u003c/h2\u003e\n\n\u003cp\u003eThe attached source code contains the entire delegate library and numerous examples for Visual Studio\u0026nbsp;and Eclipse.\u003c/p\u003e\n\n\u003ch3\u003eVisual Studio\u003c/h3\u003e\n\n\u003cp\u003eThe Visual Studio/Win32\u0026nbsp;examples have three separate projects:\u003c/p\u003e\n\n\u003col\u003e\n\t\u003cli\u003e\u003cstrong\u003eRemoteDelegate\u003c/strong\u003e \u0026ndash; many samples where the remote sender and receiver are executing within the same application.\u003c/li\u003e\n\t\u003cli\u003e\u003cstrong\u003eRemoteDelegeteSend\u003c/strong\u003e \u0026ndash; a UDP remote delegate sending console application.\u003c/li\u003e\n\t\u003cli\u003e\u003cstrong\u003eRemoteDelegateRecv\u003c/strong\u003e \u0026ndash; a UDP receiving console application that receives from \u003ccode\u003eRemoteDelegateSend\u003c/code\u003e.\u003c/li\u003e\n\u003c/ol\u003e\n\n\u003cp\u003eTo run the JSON examples, you\u0026rsquo;ll need to:\u003c/p\u003e\n\n\u003col\u003e\n\t\u003cli\u003eClone the \u003ccode\u003eRapidJSON\u003c/code\u003e library into a \u003cem\u003erapidjson\u003c/em\u003e directory within your \u003cem\u003eRemoteDelegate\u003c/em\u003e source directory.\u003c/li\u003e\n\t\u003cp\u003e\u003ca href=\"https://github.com/Tencent/rapidjson/\"\u003ehttps://github.com/Tencent/rapidjson/\u003c/a\u003e\u003c/p\u003e\n\t\u003cli\u003eDefine \u003cstrong\u003eRAPID_JSON\u003c/strong\u003e in the \u003cstrong\u003eC/C++ \u0026gt; Preprocessor \u0026gt; Preprocessor Definitions\u003c/strong\u003e within Visual Studio.\u003c/li\u003e\n\u003c/ol\u003e\n\n\u003ch3\u003eEclipse\u003c/h3\u003e\n\n\u003cp\u003eThe Eclipse/POSIX examples are imported into a workspace using \u003cstrong\u003eFile \u0026gt; Import... \u0026gt; Existing Projects into Workspace\u003c/strong\u003e.\u003c/p\u003e\n\n\u003cp\u003eTo run the JSON examples, you\u0026rsquo;ll need to:\u003c/p\u003e\n\n\u003col\u003e\n\t\u003cli\u003eClone the \u003ccode\u003eRapidJSON\u003c/code\u003e library into a \u003cem\u003erapidjson\u003c/em\u003e directory within your \u003cem\u003eRemoteDelegate\u003c/em\u003e source directory.\u003c/li\u003e\n\t\u003cp\u003e\u003ca href=\"https://github.com/Tencent/rapidjson/\"\u003ehttps://github.com/Tencent/rapidjson/\u003c/a\u003e\u003c/p\u003e\n\t\u003cli\u003eDefine \u003cstrong\u003eRAPID_JSON \u003c/strong\u003ein \u003cstrong\u003eProperties \u0026gt; C/C++ General \u0026gt; Paths and Symbols \u0026gt; Symbols\u003c/strong\u003e tab.\u003c/li\u003e\n\u003c/ol\u003e\n\n\u003ch2\u003eConclusion\u003c/h2\u003e\n\n\u003cp\u003eI\u0026rsquo;ve been using the C++ delegate library on a few different projects now. The ease at which functions and data can be moved between threads has really changed how I create multi-threaded applications.\u003c/p\u003e\n\n\u003cp\u003eThe remote delegate enhancements extend library by allowing remote notification. The library eases application development by passing data between remote systems using a simple delegate mechanism.\u003c/p\u003e\n\n\u003ch2\u003eReferences\u003c/h2\u003e\n\n\u003cul\u003e\n\t\u003cli\u003e\u003ca href=\"https://www.codeproject.com/Articles/1160934/Asynchronous-Multicast-Delegates-in-Cplusplus\"\u003eAsynchronous Multicast Delegates in C++\u003c/a\u003e - by David Lafreniere\u003c/li\u003e\n\u003c/ul\u003e\n\n\n\n\n\n","funding_links":[],"categories":[],"sub_categories":[],"project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fendurodave%2Fremotedelegate","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fendurodave%2Fremotedelegate","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fendurodave%2Fremotedelegate/lists"}