3

非同期コールバック関数

展望: 私はいくつかの VB6 ActiveX アプリケーションを C#.net にアップグレードしています。それらはすべて、参照された VC++.net 実行可能ファイルに登録するコールバック関数を使用して互いに通信します。

次の VB6 機能を C# で複製することはできません。メソッドを含むインスタンス化されたクラスをコールバック関数パラメーターとして VC++ に渡す VB6 の機能。VC++ は非同期通信のコールバック関数として登録します。

アップグレードは、 CallBack 関数という 1 つの問題を除けば非常にうまくいきました ...そして、私は 2 週間もその問題に取り組んでいます。私を助けてください!!!

コールバック関数をデリゲートとして渡す方法を理解しました。これは、C# DynamicInvoke で動作するようになりましたが、VC++ で動作するにはこれが本当に必要です。

VC++ステートメントから取得し続けるエラー メッセージは、「パラメーターの数が無効です」です。 invoke


以下に、非同期コールバックを処理する VB6 および VC++ 機能の概要を説明しました。VB6 ActiveX コンポーネントはそれぞれ、1 つのメソッドを含むクラスをコールバック関数として VC++ 実行可能ファイルに渡します。VC++ 実行可能ファイルは、後で使用するためにコールバックを配列に保存します。これは既存のコードであるため、期待どおりに動作します。

以下は、インスタンス化され、コールバックとして使用されるVB6クラス です。Class1
Attribute Notify.VB_UserMemId = 0

VERSION 1.0 CLASS
BEGIN
 MultiUse = -1       
 Persistable = 0 
 DataBindingBehavior = 0 
 DataSourceBehavior  = 0 
 MTSTransactionMode  = 0 
END
Attribute VB_Name = "Class1"
Attribute VB_GlobalNameSpace = False
Attribute VB_Creatable = True
Attribute VB_PredeclaredId = False
Attribute VB_Exposed = True
 
Sub Notify(ByVal message As Integer, ByVal data As Variant)
Attribute Notify.VB_UserMemId = 0
  MsgBox Str$(message) + "  " + data, vbInformation, Form1.Text2
End Sub

上記のコードは、混乱を避けるために簡略化されています。

以下は、 VC++ 実行可能ファイル ( ) をインスタンス化し、インスタンス化されたものをコールバック パラメータとして渡すVB6コードです。VCCallbackHandlerClass1

Dim VCCallbackHandler New VCCallbackHandler.VCCallbackHandler 
Dim c1 As New Class1

Private Sub Register_Click()
   Dim i as int
   i = VCCallbackHandler.Register(c1, "NameOfApplication")
End Sub

VC++ コードはコールバックを登録し (以下を参照)、後で (非同期で) VC++ は、他のイベントによってプロンプトが表示された場合にコールバックを利用できます (以下の「BroadCast」を参照)。この場合、VC++ exe は、複数の同時実行アプリの中央コールバック ハンドラーとして機能しています。各アプリはコールバックを VC++ コールバック ハンドラーに登録しており、あるアプリが別のイベントを呼び出して VC++ callbackHandler を呼び出すと、すべてのコールバックが呼び出されます。このようにして、コールバック ハンドラは、これらすべての他のアプリケーションが相互に通信できるようにします。

以下は、関連するVC++.Netコールバック コードです。

コールバックの登録:

 #define MAXREG  20

 typedef struct tagRegElement {
    char    name[20];       // Name of registered application
    _Callback   *p_Callback;    // Callback wrapper class
 } REG_ELEMENT;

public:
     REG_ELEMENT Registry[MAXREG];


short CBreqDlgAutoProxy::Register(LPDISPATCH callback, LPCTSTR name) 
{
    for (int i = 0;i<MAXREG;i++){
        if(!(theApp.Registry[i].name[0]))
        {
            RegIndex = i;
            strcpy(theApp.Registry[i].name,name);
            theApp.Registry[i].p_Callback = new _Callback(callback);
            return i;
        }
    }
 
    return -1;
 }

コールバックの呼び出し:

 BOOL CBreqDlgAutoProxy::Broadcast(short message, const VARIANT FAR& data) 
 {
    for (int i = 0;i<MAXREG;i++){
        if(theApp.Registry[i].name[0] && (i != RegIndex)){
            if (!theApp.Registry[i].p_Callback->Notify(message,data,theApp.Registry[i].name))
                DeRegister(i);
        }
    }
    
    return TRUE;
 }

 BOOL _Callback::Notify(short message, VARIANT data, char* RegisteredName)
 {
    static BYTE parms[] = VTS_I2 VTS_VARIANT;
        
    InvokeHelper(0x0, DISPATCH_METHOD, VT_EMPTY, NULL, parms, message, &data);
     
    return TRUE;
 }

ノート。 上記の作品。

考えられる解決策は 2 つあります。

  1. C#: C# でメソッドをパラメーターとして渡す方法。デリゲートを使用してそれを行う方法を見つけましたが、VC++ はデリゲートではなくメソッドを必要としています。
  2. VC++: 呼び出すコールバックとしてメソッドではなくデリゲートを処理するように VC++ を取得する方法。

次のC#コード スニペットのいずれでも成功しませんでした: `

  • Marshal.GetFunctionPointerForDelegate
  • GCHandle
  • KeepAlive

私はそこに誰かがこの問題を抱えていて、行くことができることを願っています... スナップ...簡単です..これを使用してください...交差した指。

4

1 に答える 1

0

いつかこのようなことをしましたが、変数を渡すためにそれを使用しました。

C#: C# でメソッドをパラメーターとして渡す方法。デリゲートを使用してそれを行う方法を見つけましたが、VC++ はデリゲートではなくメソッドを必要としています。

C# コード (マネージド) は VC++ コード (アンマネージド) と直接通信できないため、C++/CLI を使用していました。

したがって、CLI/C++ ラッパーを作成できる場合は、それが役立ちます。

PS。デリゲートを VC++ に渡す方法を知りたいです。コードを投稿できれば、それは素晴らしいことです。

于 2011-05-05T06:03:01.497 に答える