如何将函数传递给匿名管道WinAPI?

时间:2012-12-14 11:51:21

标签: c++ winapi pipe

我需要写一些像double (*fun)(double)这样的匿名管道,但是WriteFile(pipe, fun, 4, written_bytes, 0)会导致管道接收器出错ReadFile(read_pipe, fun, 4, written_bytes, 0)。有没有办法做到这一点?

我有个主意。我可以使用相同类型的字段创建结构:

struct Foo
{
    double (*f)(double);
};

然后我写了WriteFile(hWritePipe_StdIN, &to_process, sizeof(Foo), &bytes, 0); 但我有问题,管道接收器永远不会结束读取数据: ReadFile(hReadPipe, &to_process, sizeof(Foo), &bytes, 0);

5 个答案:

答案 0 :(得分:2)

它有一些问题:

首先,你应该知道函数的大小。 如果您这样做,只需致电WriteFile(pipe, funcPtr, funcSize, ...)即可将其转移。

其次,该功能应仅包含position-independent code,并且不会处理任何数据。 例如。像这样的功能不会起作用:

double fun(double x)
{
    int arr[10000]; // implicit function call (alloca or something like this)
    printf("some");
    static int some = 1;
    return globalVal + (++some);
}

因为函数printf将具有不同的地址,并且在另一个进程中将没有静态变量和字符串 (好吧,也许您也可以传输数据,但是您无法生成PI代码。)

所以,有了这些限制,你可以发送一个函数:

__declspec(naked) double fun(double x) { __asm ret }

const auto funcSize = 1;
WriteFile(pipe, &fun, funcSize, ...);

答案 1 :(得分:2)

在本机代码中,您不能发送函数(代码)本身,也不能发送相同或不同的进程。 (您可以像@Abyx建议的那样尝试低级别的黑客行为,但它严重限制了代码可以执行的功能,并且可能会让您诉诸于手动编写汇编程序。)

您也无法将函数的地址发送到另一个进程,因为每个进程都有自己独立的地址空间;在另一个过程中,该地址将包含不同的数据。

解决方案是创建一个共享库(最好是动态的),它将包含可能以这种方式发送的所有函数。为每个函数分配一些标记(例如数字或名称),让DLL维护标记和地址之间的映射。然后发送标签。

答案 2 :(得分:1)

你想要实现的目标是什么?你真的想写功能吗?为什么?这不是你在C ++中可以轻易做到的事情,例如因为函数的大小没有明确定义。

您应该编写数据,即fun()返回的数字:

const double value = fun(input);
DWORD numberOfBytesWritten;
WriteFile(pipe, &value, sizeof value, &numberOfBytesWritten, NULL);

您当然应该添加代码来检查输出。请注意,写这样的二进制数据可能很脆弱。

答案 3 :(得分:1)

由于您使用的是WinAPI,因此发送函数的本机方式是通过COM。特别是,将该函数公开为COM对象上的方法,获取COM名字对象,并发送名字对象。可以序列化Monikers并通过管道发送。另一方可以对名字对象进行反序列化并访问您的对象。

在水下,通过查找COM 运行对象表

中的对象来工作

答案 4 :(得分:0)

看看这在C ++中是如何过于复杂和容易出错的(并且只适用于非常有限的一组功能),我建议你使用脚本语言。除了已经提到过的内容之外,指令缓存和DEP是你必须考虑的另外两件事。

真。将函数作为脚本传输,并在另一端运行它。救你自己的痛苦。

Angelscript看起来和感觉几乎都像C ++,所以这可能是一个可能的候选人。

现在,如果你反对这一点,因为你需要一些脚本无法做到的事情,那么知道:在这种情况下,C ++也无法做到这一点。

除了上面提到的PIC代码问题(@Abyx)以及你无法安全或可移植地知道函数大小的事实之外,你可以想象通过管道发送并以有意义的方式执行的唯一C ++函数是严格的const功能。这里,const是例如GCC的__attribute__((const)),而不是C ++ const关键字。

也就是说,任何这样的函数可能不会检查除其参数之外的任何值,并且除了返回值之外没有任何效果。原因很明显:不同的进程存在于不同的地址空间中,因此您引用的任何内容都是无意义的。你改变的一切都是毫无意义的 现在,这正是脚本可以安全,直接,可靠地完成的工作。考虑到你已经通过管道发送代码,开销是可以忽略不计的。