delegat из callback
От: Odi$$ey Россия http://malgarr.blogspot.com/
Дата: 11.04.07 14:50
Оценка:
есть .net компонент с событием:

public delegate void ResultEvent(string msg);
     
public class ManagedClass 
{
   public event ResultEvent OnResult;

      ...
            
}

и C++-dll (/clr) c экспортируемой функцией Func:

typedef void (CALLBACK *Result)(const char* msg);

extern "C" __declspec(dllexport) void Func(Result callback)
{
   ManagedClass^ mc = gcnew ManagedClass();
     
     mc->OnResult+= ???????
}

вопрос — как на С++/CLI подписаться на событие ManagedClass чтоб вызвать функцию callback со строкой msg из параметра события?
... << RSDN@Home 1.2.0 alpha rev. 675>>
Re: delegat из callback
От: TK Лес кывт.рф
Дата: 11.04.07 14:54
Оценка:
Здравствуйте, Odi$$ey, Вы писали:

OE>вопрос — как на С++/CLI подписаться на событие ManagedClass чтоб вызвать функцию callback со строкой msg из параметра события?


Также как и в C# — сделать managed класс с методом который будет подписан на событие и полем в котором будет содержаться адрес каллбека. По факту вызова метода — дергать callback
Если у Вас нет паранойи, то это еще не значит, что они за Вами не следят.
Re[2]: delegat из callback
От: Odi$$ey Россия http://malgarr.blogspot.com/
Дата: 11.04.07 15:14
Оценка:
Здравствуйте, TK, Вы писали:

OE>>вопрос — как на С++/CLI подписаться на событие ManagedClass чтоб вызвать функцию callback со строкой msg из параметра события?


TK>Также как и в C# —


не, там бы анонимный делегат прикрутил и все дела

TK>сделать managed класс с методом который будет подписан на событие и полем в котором будет содержаться адрес каллбека.


а какой должен быть тип поля?
... << RSDN@Home 1.2.0 alpha rev. 675>>
Re: delegat из callback
От: _FRED_ Черногория
Дата: 11.04.07 16:45
Оценка: 26 (1)
Здравствуйте, Odi$$ey, Вы писали:

OE>вопрос — как на С++/CLI подписаться на событие ManagedClass чтоб вызвать функцию callback со строкой msg из параметра события?


Например так. Сначала C# класс:
namespace ClassLibrary1
{
  public delegate void ResultEventHandler(string msg);

  public class ManagedClass
  {
    public event ResultEventHandler Result;

    public void RaiseResult() {
      if(Result != null) {
        System.Console.WriteLine("Event Raised!");
        Result("Aaaaaa!!!");
      }//if
    }
  }
}

Теперь C++/CLI
// TestCpp.cpp : main project file.

#include "stdafx.h"

using namespace System;
using namespace ClassLibrary1;

typedef void (*Result)(const char* msg);

ref class ResultWrapper
{
public:
  ResultWrapper(Result callback) : callback(callback) { }

public:
  void Handler(String^ message) {
    if(callback) {
      Console::WriteLine(L"Handler called!");
      callback("Не знаю как сконвертить String^ в const char*\n");
    }//if
  }

private:
  const Result const callback; // С константами тоже могу наврать
};

extern "C" __declspec(dllexport) void Func(Result callback)
{
  ManagedClass^ mc = gcnew ManagedClass();
  ResultWrapper^ wrapper = gcnew ResultWrapper(callback);
  mc->Result += gcnew ResultEventHandler(wrapper, &ResultWrapper::Handler);
  mc->RaiseResult();
}

void ResultCallback(const char* msg)
{
  Console::WriteLine(L"Callback called!");
}

int main(array<System::String ^> ^args)
{
    Console::WriteLine(L"Hello World");
    Func(ResultCallback);
    return 0;
}


ЗЫ. Прошу больно не бить, это был первый опыт
... << RSDN@Home 1.2.0 alpha rev. 675>>
Now playing: «Тихо в лесу…»
Help will always be given at Hogwarts to those who ask for it.
delegate из callback
От: desco США http://v2matveev.blogspot.com
Дата: 11.04.07 19:33
Оценка: 39 (1)
#Имя: FAQ.dotnet.delegate.from.callback
Здравствуйте, Odi$$ey, Вы писали:

>вопрос — как на С++/CLI подписаться на событие ManagedClass чтоб вызвать функцию callback со строкой msg из параметра события?


можно попробовать что-то такое:
C#

namespace CL1
{
    public delegate void ResultEvent(string msg);

    public class ManagedClass
    {
        public event ResultEvent OnResult;

        public void Run(string message)
        {
            if (OnResult != null)
            {
                OnResult(message);
            }
        }
    }
}

C++

using namespace System;
using namespace System::Runtime::InteropServices;

typedef void (*Result)(const char* msg);

void Callback(const char* msg)
{
    Console::WriteLine(gcnew String(msg));
}

int main(array<System::String ^> ^args)
{
    CL1::ResultEvent^ d =  safe_cast<CL1::ResultEvent^>(Marshal::GetDelegateForFunctionPointer(IntPtr(Callback), CL1::ResultEvent::typeid));
    CL1::ManagedClass c1;
    c1.OnResult += d;

    c1.Run(L"run");
    return 0;
}
Re[3]: delegat из callback
От: TK Лес кывт.рф
Дата: 11.04.07 19:46
Оценка:
Здравствуйте, Odi$$ey, Вы писали:

TK>>Также как и в C# —

OE>не, там бы анонимный делегат прикрутил и все дела

Ну это тоже самое

TK>>сделать managed класс с методом который будет подписан на событие и полем в котором будет содержаться адрес каллбека.

OE>а какой должен быть тип поля?

TK>>сделать managed класс с методом который будет подписан на событие и полем в котором будет содержаться адрес каллбека.

OE>а какой должен быть тип поля?

Все равно. Это же С++. Можно сделать IntPtr который потом кастить к нужному типу и через него дернуть каллбек. или сразу поле нужного типа сделать.

Для ценителей можно через Marshal сделать GetDelegateForFunctionPointer (если сигнатуры подходят) и подписать Invoke на событие. В этом случае даже доп. класс не нужен.
Если у Вас нет паранойи, то это еще не значит, что они за Вами не следят.
Re[2]: delegat из callback
От: Odi$$ey Россия http://malgarr.blogspot.com/
Дата: 12.04.07 06:08
Оценка: +1
Здравствуйте, desco, Вы писали:

D> CL1::ResultEvent^ d = safe_cast<CL1::ResultEvent^>(Marshal::GetDelegateForFunctionPointer(IntPtr(Callback), CL1::ResultEvent::typeid));


работает вроде правильно, правда я не понял, как unicode System.String переданный в делегат из C# компонента правильно преобразовался в не-unicode char* в C++ callback-е

и еще, вот в таком сценарии:

typedef void (CALLBACK *Result)(const char* msg);

extern "C" __declspec(dllexport) void Func(Result result_callback)
{
   ManagedClass^ mc = gcnew ManagedClass();
     
   mc->OnResult+= safe_cast<ResultEvent^>(Marshal::GetDelegateForFunctionPointer(IntPtr(result_callback), ResultEvent::typeid));

   mc->Run(); // асинхронная, сразу возвращает управление, ManagedClass генерует событие через некоторое время.
}

никаких заморочек со временем жизни mc и char* msg, которое GetDelegateForFunctionPointer сделает для result_callback не ожидается? (в тестах вроде все работает)
... << RSDN@Home 1.2.0 alpha rev. 675>>
Re[3]: delegat из callback
От: _FRED_ Черногория
Дата: 12.04.07 08:59
Оценка:
Здравствуйте, Odi$$ey, Вы писали:

D>> CL1::ResultEvent^ d = safe_cast<CL1::ResultEvent^>(Marshal::GetDelegateForFunctionPointer(IntPtr(Callback), CL1::ResultEvent::typeid));


OE>работает вроде правильно, правда я не понял, как unicode System.String переданный в делегат из C# компонента правильно преобразовался в не-unicode char* в C++ callback-е


+1

OE>и еще, вот в таком сценарии:

OE>typedef void (CALLBACK *Result)(const char* msg);

OE>extern "C" __declspec(dllexport) void Func(Result result_callback)
OE>{
OE>   ManagedClass^ mc = gcnew ManagedClass();
     
   mc->>OnResult+= safe_cast<ResultEvent^>(Marshal::GetDelegateForFunctionPointer(IntPtr(result_callback), ResultEvent::typeid));

   mc->>Run(); // асинхронная, сразу возвращает управление, ManagedClass генерует событие через некоторое время.
OE>}
OE>

OE>никаких заморочек со временем жизни mc и char* msg, которое GetDelegateForFunctionPointer сделает для result_callback не ожидается? (в тестах вроде все работает)

Так как ссылка на результат GetDelegateForFunctionPointer хранится в делегате OnResult, то делегат не убьётся и будет жить пока жив ManagedClass^ mc. А в твоём примере он недостижим сразу после выхода из Func.
... << RSDN@Home 1.2.0 alpha rev. 675>>
Now playing: «Тихо в лесу…»
Help will always be given at Hogwarts to those who ask for it.
Re[4]: delegat из callback
От: _FRED_ Черногория
Дата: 12.04.07 09:01
Оценка:
Здравствуйте, _FRED_, Вы писали:

D>>> CL1::ResultEvent^ d = safe_cast<CL1::ResultEvent^>(Marshal::GetDelegateForFunctionPointer(IntPtr(Callback), CL1::ResultEvent::typeid));


OE>>работает вроде правильно, правда я не понял, как unicode System.String переданный в делегат из C# компонента правильно преобразовался в не-unicode char* в C++ callback-е


_FR>+1


Хотя, похоже, тут работает тот же механизм, что и при маршалинге строк.
... << RSDN@Home 1.2.0 alpha rev. 675>>
Now playing: «Тихо в лесу…»
Help will always be given at Hogwarts to those who ask for it.
Re[3]: delegat из callback
От: _Morpheus_  
Дата: 12.04.07 09:09
Оценка:
Здравствуйте, Odi$$ey, Вы писали:

D>> CL1::ResultEvent^ d = safe_cast<CL1::ResultEvent^>(Marshal::GetDelegateForFunctionPointer(IntPtr(Callback), CL1::ResultEvent::typeid));


OE>работает вроде правильно, правда я не понял, как unicode System.String переданный в делегат из C# компонента правильно преобразовался в не-unicode char* в C++ callback-е


а разве char* получается не юникодный?
... << RSDN@Home 1.2.0 alpha rev. 676>>
Re[4]: delegat из callback
От: Odi$$ey Россия http://malgarr.blogspot.com/
Дата: 12.04.07 11:31
Оценка:
Здравствуйте, _Morpheus_, Вы писали:

D>>> CL1::ResultEvent^ d = safe_cast<CL1::ResultEvent^>(Marshal::GetDelegateForFunctionPointer(IntPtr(Callback), CL1::ResultEvent::typeid));

OE>>работает вроде правильно, правда я не понял, как unicode System.String переданный в делегат из C# компонента правильно преобразовался в не-unicode char* в C++ callback-е
_M_>а разве char* получается не юникодный?

русская строка, байт — буква
... << RSDN@Home 1.2.0 alpha rev. 675>>
Re[4]: delegat из callback
От: Odi$$ey Россия http://malgarr.blogspot.com/
Дата: 12.04.07 11:31
Оценка:
Здравствуйте, _FRED_, Вы писали:

_FR>Так как ссылка на результат GetDelegateForFunctionPointer хранится в делегате OnResult, то делегат не убьётся и будет жить пока жив ManagedClass^ mc. А в твоём примере он недостижим сразу после выхода из Func.


в mc->Run(); происходит подписка на SendCompleted локального объекта SmtpClient должен он (mc) дожить до этого события?
... << RSDN@Home 1.2.0 alpha rev. 675>>
Re[5]: delegat из callback
От: _Morpheus_  
Дата: 12.04.07 11:35
Оценка:
Здравствуйте, Odi$$ey, Вы писали:

OE>Здравствуйте, _Morpheus_, Вы писали:


D>>>> CL1::ResultEvent^ d = safe_cast<CL1::ResultEvent^>(Marshal::GetDelegateForFunctionPointer(IntPtr(Callback), CL1::ResultEvent::typeid));

OE>>>работает вроде правильно, правда я не понял, как unicode System.String переданный в делегат из C# компонента правильно преобразовался в не-unicode char* в C++ callback-е
_M_>>а разве char* получается не юникодный?

OE>русская строка, байт — буква


байт или char? char может быть двухбайтовым, зависит от режима компиляции...
... << RSDN@Home 1.2.0 alpha rev. 676>>
Re[6]: delegat из callback
От: Odi$$ey Россия http://malgarr.blogspot.com/
Дата: 12.04.07 11:42
Оценка:
Здравствуйте, _Morpheus_, Вы писали:

_M_>байт или char? char может быть двухбайтовым, зависит от режима компиляции...


С++-проект компилируется без unicode, так что одно и тоже
... << RSDN@Home 1.2.0 alpha rev. 675>>
Re[7]: delegat из callback
От: _FRED_ Черногория
Дата: 12.04.07 12:17
Оценка:
Здравствуйте, Odi$$ey, Вы писали:

_M_>>байт или char? char может быть двухбайтовым, зависит от режима компиляции...


OE>С++-проект компилируется без unicode, так что одно и тоже


А что, если компилить с юникодом, то
char

будет не однобайтовым
... << RSDN@Home 1.2.0 alpha rev. 675>>
Now playing: «Тихо в лесу…»
Help will always be given at Hogwarts to those who ask for it.
Re[8]: delegat из callback
От: Odi$$ey Россия http://malgarr.blogspot.com/
Дата: 12.04.07 14:11
Оценка: :)
Здравствуйте, _FRED_, Вы писали:

_FR>А что, если компилить с юникодом, то

_FR>
_FR>char
_FR>

_FR>будет не однобайтовым

ну, в военное время даже синус может достигать значения 2
... << RSDN@Home 1.2.0 alpha rev. 675>>
Re[5]: delegat из callback
От: VladD2 Российская Империя www.nemerle.org
Дата: 12.04.07 21:53
Оценка:
Здравствуйте, Odi$$ey, Вы писали:

OE>русская строка, байт — буква


Попробуй ради хохмы описание махнуть на юникодное (у сишной фукнции). Если не будет глюка, то это скорее всего чудеса маршалинга строк.
... << RSDN@Home 1.2.0 alpha rev. 637>>
Есть логика намерений и логика обстоятельств, последняя всегда сильнее.
 
Подождите ...
Wait...
Пока на собственное сообщение не было ответов, его можно удалить.