Reputation: 12403
I'm writing a bot for a game, which has a C++ API interface (ie. methods in a Cpp dll get called by the game when events occur, the dll can call back methods in the game to trigger actions).
I don't really want to write my bot in C++, I'm a fairly experienced C# programmer but I have no C++ experience at all. So, the obvious solution is to use ipc to send event to a C# program, and send actions back to the C++ one, that way all I need to write in C++ is a basic framework for calling methods and sending events.
What would be the best way to do this? Sample code would be greatly appreciated as I no have particular desire to learn C++ at this point!
Upvotes: 10
Views: 24165
Reputation: 15
I've already written a blocking version using pipes. But none of the methods the game calls are allowed to block
This issue is solved by running the blocking pipe functions in a separate thread. I found this issue looking for a better solution, but here is the basic idea of what I currently have:
#include <mutex>
// #include ...
HANDLE pipe;
char* pipeBuffer;
int pipeSize;
bool pipeHasData = false;
std::mutex m;
std::condition_variable cv;
void named_pipe()
{
// optional
int pid = _getpid();
std::wstring pipe_name = L"\\\\.\\pipe\\Game-" + std::to_wstring(pid);
// (very) shortened loop to show mutex lock
// add your own error checking and retrying
hPipe = init_named_pipe(pipe_name);
while (true)
{
if (PeekNamedPipe(hPipe, NULL, 0, NULL, &bytesAvailable, NULL) == FALSE)
{
break;
}
pipeBuffer = buffer;
pipeSize = dwRead;
pipeHasData = true;
{
std::unique_lock<std::mutex> lock(m);
cv.wait(lock);
}
}
}
void (__fastcall* oGame_Tick)(float deltaTime);
void __fastcall hkGame_Tick(float deltaTime)
{
oGame_Tick(deltaTime);
if (pipeHasData)
{
// parse the packet received in pipeBuffer and call your game actions
// respond by writing back to pipe
ProcessPipe(pipe, pipeBuffer, pipeSize);
{
m.lock();
pipeHasData = false;
pipeBuffer = nullptr;
pipeSize = NULL;
m.unlock();
cv.notify_all();
}
}
}
// called once on dll attach
void __cdecl init()
{
// hook gameloop tick function here
// start loop in new thread
std::thread t1(named_pipe);
t1.detach();
}
Things to note:
Upvotes: 1
Reputation: 32669
One solution is to create a managed C++ class library with regular __declspec(dllexport)
functions which call managed methods in a referenced C# class library.
Example - C++ code file in managed C++ project:
#include "stdafx.h"
__declspec(dllexport) int Foo(int bar)
{
csharpmodule::CSharpModule mod;
return mod.Foo(bar);
}
C# Module (separate project in solution):
namespace csharpmodule
{
public class CSharpModule
{
public int Foo(int bar)
{
MessageBox.Show("Foo(" + bar + ")");
return bar;
}
}
}
Note that I am demonstrating that this is an actual .NET call by using a System.Windows.Forms.MessageBox.Show
call.
Sample basic (non-CLR) Win32 console application:
__declspec(dllimport) int Foo(int bar);
int _tmain(int argc, _TCHAR* argv[])
{
std::cout << Foo(5) << std::endl;
return 0;
}
Remember to link the Win32 console application with the .lib
file resulting from the build of the managed C++ project.
Upvotes: 6
Reputation: 1195
In such occasion, I would like to see a C++/CLI party and a C# one using the .NET Framework's named pipes.
Upvotes: 3
Reputation: 12630
There are lots of different ways of doing IPC in Windows. For C# to C++, I'd be tempted to use Sockets as the API under both C++ (WinSock is OK once you get your head around it) and C# is pretty easy.
Named Pipes might be better though if you don't want to use sockets, and were designed specifically for IPC. The API under C++ seems pretty simple, example here.
Upvotes: 9