.net C#与C++的进程间通信

0ve6wy6x  于 2022-11-19  发布在  .NET
关注(0)|答案(4)|浏览(244)

我正在为一个游戏编写一个bot,它有一个C++ API接口(即,当事件发生时,游戏调用Cpp dll中的方法,dll可以回调游戏中的方法以触发动作)。
我并不想用C编写我的机器人程序,我是一个相当有经验的C#程序员,但我完全没有C的经验。所以,显而易见的解决方案是使用ipc将事件发送到C#程序,并将操作发送回C程序,这样我只需要用C编写一个调用方法和发送事件的基本框架。
什么是最好的方法来做到这一点?样本代码将非常感谢,因为我没有特别的愿望学习C++在这一点上!

0aydgbwb

0aydgbwb1#

lots of different ways of doing IPC in Windows。对于C#到C++,我很想在C++(WinSock是可以的,一旦你了解它)和C#下使用套接字作为API,这是相当容易的。
Named Pipes可能更好,如果你不想使用套接字,并且是专门为IPC设计的。C++下的API看起来很简单,例如here

4xrmg8kj

4xrmg8kj2#

一种解决方案是使用常规__declspec(dllexport)函数创建托管C类库,这些函数调用引用的C#类库中的托管方法。
示例-托管C
项目中的C++代码文件:

#include "stdafx.h"

__declspec(dllexport) int Foo(int bar) 
{
    csharpmodule::CSharpModule mod;
    return mod.Foo(bar);
}

C#模块(方案中的个别项目):

namespace csharpmodule
{
    public class CSharpModule
    {
        public int Foo(int bar)
        {
            MessageBox.Show("Foo(" + bar + ")");
            return bar;
        }
    }
}

请注意,我是通过使用System.Windows.Forms.MessageBox.Show调用来演示这是一个实际的.NET调用。
基本(非CLR)Win32主控台应用程序范例:

__declspec(dllimport) int Foo(int bar);

int _tmain(int argc, _TCHAR* argv[])
{
    std::cout << Foo(5) << std::endl;
    return 0;
}

请记得将Win32主控台应用程序与Managed C++项目建置所产生的.lib档案链接。

wecizke3

wecizke33#

在这种情况下,我希望看到一个C++/CLI方和一个C#方使用.NET框架的命名管道。

v7pvogib

v7pvogib4#

我已经写了一个使用管道的阻塞版本。但是游戏调用的方法都不允许阻塞
这个问题是通过在一个单独的线程中运行阻塞管道函数来解决的。我发现这个问题正在寻找一个更好的解决方案,但这里是我目前所拥有的基本想法:

#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();
}

注意事项:

  • 这段代码每帧只处理一个数据包,并且会一直阻塞直到有响应发送。相反,你可以使用队列系统,在这里通过管道发送的数据包从你的管道循环中排队,然后在主游戏线程中处理(这正是游戏本身所做的!)
  • 受帧速率限制
  • 有些游戏动作每帧只能调用一次,否则会使客户端崩溃。我在虚幻引擎游戏中遇到过这个问题(特别是在一次勾选中切换UI相关内容两次时)

相关问题