Функции обратного вызова: передача обратных вызовов из приложения winform на C # в VC ++ Exe, на который есть ссылка - PullRequest
3 голосов
/ 05 мая 2011

Функции асинхронного обратного вызова

Перспектива: я обновляю несколько приложений VB6 ActiveX до C # .net, которые все общаются друг с другом с помощью функций обратного вызова, которые они регистрируют с помощью исполняемого файла VC ++. Net.

Я не могу воспроизвести следующие функции VB6 в C #: Способность VB6 передавать VC ++, экземплярный класс, содержащий метод, в качестве параметра функции обратного вызова, который VC ++ затем регистрирует в качестве функции обратного вызова для асинхронного взаимодействия.

Обновление прошло очень хорошо, кроме одной этой проблемы: Функции CallBack ... и я застрял на нем уже две недели. Пожалуйста, помогите мне !!!

Я выяснил, как передать функцию обратного вызова в качестве делегата, что мне удалось получить с помощью C # DynamicInvoke, однако мне действительно нужно это для работы в VC ++.

Сообщение об ошибке Я получаю от оператора VC ++ invoke «Неверное количество параметров» .


НИЖЕ, я обрисовал в общих чертах функциональность VB6 и VC ++, которая обрабатывает асинхронные обратные вызовы. Каждый компонент ActiveX VB6 передает класс, содержащий один метод, в качестве функции обратного вызова в исполняемый файл 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

Приведенный выше код был упрощен во избежание путаницы.

Ниже приведен код VB6 , который создает исполняемый файл VC ++ (VCCallbackHandler) и передает ему экземпляр Class1 в качестве параметра обратного вызова

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 ++, вызывая другое событие, все обратные вызовы вызываются. Таким образом, обработчик обратного вызова позволяет всем этим другим приложениям связываться друг с другом.

Ниже приведен соответствующий код обратного вызова 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;
 }

Примечание. ВЫШЕ РАБОТАЕТ.

Существует два возможных решения:

  1. C #: как заставить C # передать метод в качестве параметра. Я понял, как это сделать с помощью делегата, но VC ++ хочет, чтобы метод не был делегатом.
  2. VC ++: Как заставить VC ++ обрабатывать делегат вместо метода в качестве обратного вызова для вызова.

У меня не было успеха ни с одним из следующих c # фрагментов кода: `

  • Marshal.GetFunctionPointerForDelegate
  • GCHandle
  • KeepAlive

Я надеюсь, что кто-то там имел эту проблему, и может пойти ... SNAP ... это легко ... использовать это ... Скрещенные пальцы.

1 Ответ

0 голосов
/ 05 мая 2011

Некоторое время назад я делал что-то подобное, но я использовал это для передачи переменных.

C #: как заставить C # передать метод в качестве параметра.Я понял, как это сделать с помощью делегата, но VC ++ хочет, чтобы метод не был делегатом.

Я использовал C ++ / CLI, поскольку код C # (управляемый) не может напрямую взаимодействовать с кодом VC ++ (неуправляемый).

Так что, если вы можете написать оболочку CLI / C ++, это поможет.

PS.Я хотел бы знать, как передать делегат VC ++.Если вы можете опубликовать код, это было бы здорово.

...