5

まず第一に、私のプログラミングスキルはかなり限られていることを認めなければなりません。私は(本当に小さな)既存のC ++ OOPプロジェクトを引き継いで、自分のものを押し込もうとしました。残念ながら、私は自分の知識を超えた問題を経験しています。ここで助けを見つけたいと思います。私はカメラから画像を取得するためにサードパーティのライブラリ(変更できません)を使用しており、ここではいくつかのプレースホルダー名を使用します。

サードパーティのライブラリには、継続的なライブグラブを開始する関数「ThirdPartyGrab」があり、新しいフレームが到着するたびに呼び出される関数へのポインタを取得します。したがって、通常のCアプリケーションでは、次のようになります。

ThirdPartyGrab (HookFunction);

「HookFunction」は次のように宣言する必要があります。

long _stdcall HookFunction (long, long, void*);

または、次のように宣言されている「BUF_HOOK_FUNCTION_PTR」

typedef long (_stdcall *HOOK_FUNCTION_PTR) (long, long, void*);

これで、C++アプリケーションとクラス「MyFrameGrabber」ができました。これは私が行うすべてのことをカプセル化する必要があります。だから私は次のようなプライベートメンバーとしてフック関数を入れました:

long _stdcall HookFunction (long, long, void*);

また、私のクラスには、Grabを開始するパブリックvoid関数「StartGrab」があります。内部で私は電話しようとします:

ThirdPartyGrab (..., HookFunction, ...);

これは(当然のことながら)失敗します。MyFrameGrabber :: HookFunctionの関数呼び出しで引数リストが欠落しているため、代わりに&MyFrameGrabber::HookFunctionを使用してポインターを作成する必要があると表示されます。ただし、代わりに「&MyFrameGrabber :: HookFunction」を渡すと、これをBUF_HOOK_FUNCTION_PTRに変換できないという別のエラーが発生します。

C ++ FAQ関数ポインタを読んだ後、私は問題を理解していると思いますが、解決策を作ることができません。フック関数を静的にしようとしましたが、これも変換エラーになります。フック関数をクラスの外に置くことも考えましたが、フック関数の中にクラス関数を使用する必要があります。別の方法はありますか、それともコンセプト全体を変更する必要がありますか?

編集14.01.08:サードパーティのライブラリを変更できず、voidポインターはフック関数内で使用されるデータ専用であるため、シングルトンの回避策をテストしました。残念ながら、思ったようにそのままでは機能しませんでした。静的関数を別のクラスに入れる必要があるかどうかわからないので、「MyFrameGrabber」クラスに入れました。

static MyFrameGrabber& instance()
{
        static MyFrameGrabber _instance;
        return _instance;
}
long Hook(long, long, void*); // Implementation is in a separate cpp file

私のcppファイルには、call_hook関数があります。

long MFTYPE call_hook(long x, MIL_ID y, void MPTYPE *z)
{
    return MyFrameGrabber::instance().Hook(x,y,z);
}
void
MyFrameGrabber::grab ()
{
    ThirdPartyGrab(..., call_hook, ...);
}

しかし、これにより、static MatroxFrameGrabber _instance;一致する標準コンストラクターが見つからないというエラーが発生します。MyFrameGrabberコンストラクターは次のようになっているので、これは正しいです。

MyFrameGrabber (void* x,
                const std::string &y, int z,
                std::string &zz);

空のコンストラクターを入れようとしましたMyFrameGrabber();が、リンカーエラーが発生します。シングルトンでMyFrameGrabberコンストラクターに空のパラメーターを渡す必要がありますか?または、別のフッククラスが必要ですか?はいの場合、MyFrameGrabber関数にアクセスするにはどうすればよいですか?前もって感謝します。

2番目の編集15.01.08:変更を適用すると、コンパイルとリンクが行われます。残念ながら、これはDLLであり、Debug Caller Exeがまだなく、初期化中などに他の問題があるため、実行時にまだテストできません。これが正しい方法であると確信しているため、投稿を回答としてマークします。

4

2 に答える 2

7

プライベート メンバー メソッドには、this最初の引数として暗黙的なポインターがあります。それを書き出すと、関数のシグネチャが一致しないことは明らかです。

コールバック関数としてライブラリに渡すことができる静的メンバー関数を作成する必要があります。への最後の引数HookFunctionavoid*は、自分のポインターを渡すことができるクッキーのように見えます。

したがって、全体として、次のようになります。

クラス MyClass {
  long MyCallback(long, long) {
    // ここにコールバック コードを実装します
  }

  static long __stdcall ThirdPartyGrabCallback(long a, long b, void* self) {
    return reinterpret_cast<MyClass*>(self)->MyCallback(a, b);
  }
公衆:
  ボイド StartGrab() {
    ThirdPartyGrab(..., &MyClass::ThirdPartyGrabCallback, ..., これ, ...);
  }
};

もちろん、これは、void*引数が私が言ったことを実行している場合にのみ機能します。パラメーター名を含む完全な関数シグネチャがあればthis、呼び出し内のの位置を簡単に見つけることができます。ThirdPartyGrab()

于 2009-01-13T16:11:55.460 に答える
2

"&MyFrameGrabber::HookFunction" を BUF_HOOK_FUNCTION_PTR に変換できない理由は、クラスのメンバーであるため、暗黙的に最初のパラメーターとして "this" ポインターを持っているため、メンバー関数を非メンバー関数に変換できないためです。 2 つの署名は同じように見えますが、実際には異なります。

インターフェイスを宣言し、呼び出す関数を定義し、クラスにそれを実装させ、コールバックの代わりにオブジェクト自体を渡します (インターフェイスは、関数ポインターのオブジェクト指向の置き換えと考えることができます)。

class IHookInterface{
public:
    virtual long HookFunction(long, long, void*) = 0;
};
 class HookClass : public IHookInterface{
public:
    virtual long Hook(long, long, void*) {
        // your code here... 
    }
};

// 新しい定義: ThirdPartyGrab (..., IHookInterface, ...);

編集 - ライブラリを変更できない場合の他の可能な解決策: 静的関数ではなくシングルトンを使用します。

class HookClass{
public:
    static HookClass& instance(){
        static HookClass _instance;
        return _instance;
    }
    long Hook(long, long, void*) {
        // your code here... 
    }
};

long call_hook(long x,long y,void * z){
    return HookClass::instance().Hook(x,y,z);
}

2番目の編集:初期化メソッドを使用してシングルトンクラスをわずかに変更して、適切なパラメーターでコンストラクターを呼び出すことができますが、次のソリューションよりも単純である可能性があります。

class HookClass{
public:

    HookClass(string x,string y...){
    }

    long Hook(long, long, void*) {
        // your code here... 
    }
};

static HookClass * hook_instance = 0;

long call_hook(long x,long y,void * z){
    if (0 != hook_instance){
        return hook_instance->Hook(x,y,z);
    }
}

int main(){
    hook_instance = new HookClass("x","y");
    ThirdPartyGrab(..., call_hook, ...);
}
于 2009-01-13T16:10:15.243 に答える