2

のような匿名パイプに書き込む必要double (*fun)(double)がありますが、次のようにWriteFile(pipe, fun, 4, written_bytes, 0)すると、パイプレシーバー while でエラーが発生します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);

4

5 に答える 5

2

それにはいくつかの問題があります:

まず、関数のサイズを知っておく必要があります。その場合は、電話WriteFile(pipe, funcPtr, funcSize, ...)して転送するだけです。

次に、関数には位置に依存しないコードのみを含める必要があり、データをアドレス指定しないでください。たとえば、次のような関数は機能しません。

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, ...);
于 2012-12-14T12:20:05.083 に答える
2

ネイティブ コードでは、同じプロセスにも別のプロセスにも、関数 (コード) 自体を送信することはできません。(@Abyx が提案するような低レベルのハッキングを試すこともできますが、コードが実行できる機能が大幅に制限され、おそらくアセンブラーですべてを手動で記述することになります。)

また、各プロセスには独自の分離されたアドレス空間があるため、関数のアドレスを別のプロセスに送信することもできません。別のプロセスでは、そのアドレスには異なるデータが含まれます。

解決策は、この方法で送信される可能性のあるすべての関数を含む共有ライブラリ (できれば動的) を作成することです。各関数に何らかのタグ (番号や名前など) を割り当て、DLL がタグとアドレス間のマッピングを維持できるようにします。次に、代わりにタグを送信します。

于 2012-12-14T12:35:56.353 に答える
1

WinAPI を使用しているため、関数を送信するネイティブな方法は COM 経由です。具体的には、関数を COM オブジェクトのメソッドとして公開し、COM モニカーを取得して、モニカーを送信します。モニカーは、シリアル化してパイプ経由で送信できます。反対側は、モニカーを逆シリアル化し、オブジェクトにアクセスできます。

水中で、これは COM Running Object Tableでオブジェクトを検索することによって機能します。

于 2012-12-14T12:35:36.720 に答える
1

ここで何を達成しようとしていますか?あなたは本当に関数自体を書こうとしていますか? なんで?たとえば、関数のサイズが明確に定義されていないため、これは C++ で簡単にできることではありません。

おそらくdata、つまりfun()代わりに によって返される数値を書き込む必要があります。

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

もちろん、出力を確認するコードを追加する必要があります。このようなバイナリ データの書き込みは不安定になる可能性があることに注意してください。

于 2012-12-14T11:56:59.750 に答える
0

これが C++ で行うには非常に複雑でエラーが発生しやすい (そして非常に限られた関数セットでしか機能しない) ことを考えると、これにはスクリプト言語を使用することをお勧めします。命令キャッシュと DEP は、既に述べたものに加えて、考慮しなければならないもう 2 つの事項です。

本当。関数をスクリプトとして送信し、反対側で実行します。その痛みを自分で救ってください。

Angelscript はほとんど C++ に似ているので、これが候補になる可能性があります。

さて、スクリプトでは自明に実行できない何かが必要であるという理由でこれに反対する場合は、このシナリオでは、C++ もそれを実行できないことを知っています。

上記のPICコードの問題(@Abyx)と、関数のサイズを安全に、または移植可能に知ることができないという事実を除けば、パイプを介して送信し、意味のある方法で実行できると考えられる唯一のC++関数は、厳密にconst関数です。ここで、const は__attribute__((const))、C++constキーワードではなく、たとえば GCC の という意味です。

つまり、そのような関数は、その引数以外の値を検査することはできず、戻り値以外には何の効果もありません。理由は明らかです。別のプロセスは別のアドレス空間に存在するため、参照するものはすべて無意味です。何を変えても無意味です。
これが、安全で簡単な方法で、確実にスクリプトが実行できることです。オーバーヘッドは、既にパイプを介してコードを送信していることを考えると、ごくわずかです。

于 2012-12-14T12:30:49.477 に答える