Here an example of code used to listen for UDP trame. As C language is not my programming language my code can be far from best. This code works in 32bit and 64bit (Use VC++ 2012 express - much easier to build DLL for 32bits and 64bits than VC++ 2010) Notes: - This example take the ISI example plugin as code base - In C when a variable is declared, it is not initialized with classical values (so if you do not explicitly set a variable default value in the constructor, a new created variable will have a random value) -> Main source of issue for JAVA, C#, ... developpers - This example use Naming Resolution (to covnert a DNS name into an IP address), and as "gethostbyname" is obsolete, i need to use "getaddrinfo" instead. This method needs to include <WinSock2.h>. But as this version contains structure also declared in the <windows.h> include, you need to specify #include <WinSock2.h> before #include <windows.h> - This example also use WINAPI to read ini files. Here we go: - in the Example.hpp add some variables Code: // socket variables bool environmentAlreadySet; int senderSocket; // socket to data struct sockaddr_in sadSender; char serverHostname[256]; u_short serverPort; char identificationData[22]; Now in the constructor, initialize the variables that need to have defined init values Code: ExampleInternalsPlugin() { environmentAlreadySet = false; senderSocket = 0; } Now in the Example.cpp, add the includes for socket. The #include <WinSock2.h> must be inserted before the #include "Example.hpp" The include part looks like: Code: // socket WinSock2.h must be included before <windows.h> #include <WinSock2.h> #include "Example.hpp" // corresponding header file #include <math.h> // for atan2, sqrt #include <stdio.h> // for sample output #include <limits> #include <string> // std::string // socket #include <ws2tcpip.h> // thread #include <process.h> #pragma comment(lib, "Ws2_32.lib") As i use INI file to configure the plugin and i want the ini file are stored in the <rF2Data>/UserData/<profile> directory and not in the <rF2Code>/plugins directory. To achieve that from inside the plugin, i use the rF2 SetEnvironment API method to retrieve profile path. Code: void ExampleInternalsPlugin::SetEnvironment( const EnvironmentInfoV01 &info ) { // as the SetEnvironment can be called several times at launch if (environmentAlreadySet) { return; } // retrieve the ini filename (full path) std::string str = info.mPath[1]; unsigned found = str.find_last_of("/\\"); str = str.substr(0,found); str.append("\\ExampleInternalsPlugin.ini"); // read ini serverPort = (u_short)GetPrivateProfileInt("Server", "Port", 666, str.c_str()); GetPrivateProfileString("Server", "Address", "localhost", serverHostname, 255, str.c_str()); senderSocket = socket(PF_INET, SOCK_DGRAM, 0); if (senderSocket < 0) { return; } //gethostbyname by getaddrinfo replacement ADDRINFO hints = {sizeof(addrinfo)}; hints.ai_flags = AI_ALL; hints.ai_family = PF_INET; hints.ai_protocol = IPPROTO_IPV4; ADDRINFO* pResult = NULL; int errcode = getaddrinfo(serverHostname, NULL, &hints, &pResult); //if(errcode != 0) // return ERROR; memset(&sadSender, 0, sizeof(sadSender)); sadSender.sin_family = AF_INET; sadSender.sin_addr.S_un.S_addr = *((ULONG*)&(((sockaddr_in*)pResult->ai_addr)->sin_addr)); sadSender.sin_port = htons(serverPort); environmentAlreadySet = true; } Now to send data throw UDP you can use this kind of code Code: // send a trame containing 12 bytes. memcpy(&identificationData[0], &mSession, sizeof(long)); memcpy(&identificationData[4], &mCurrentET, sizeof(double)); sendto(senderSocket, identificationData, 12, 0, (struct sockaddr *) &sadSender, sizeof(struct sockaddr));
Wow, thanks for this tutorial Can you give some code how to listen the data send by plugin in a C++/C# application?
Here an example in C# listening UDP trame comming on port 639 Code: int listeningPort = 639; UdpClient udpServer = new UdpClient(listeningPort); // while thread is alive while (Thread.CurrentThread.IsAlive) { IPEndPoint remoteEP = new IPEndPoint(IPAddress.Any, 0); byte[] data = udpServer.Receive(ref remoteEP); if (data.Length >= 0) { // do something } }