fisadmaster Ответов: 2

Асинхронная связь между C++ и C#


У меня есть консольное приложение на C++, которое при загрузке загружает библиотеку на C#, которая, в свою очередь, при загрузке показывает модальную форму с несколькими кнопками.

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

Когда приложение C ++ выполняется, форма не отображается, и приложение заканчивается без ответа через несколько секунд (15 мм).

Если раздел, указанный как оператор функции обратного вызова//, закомментирован (на стороне C#), то приложение выполняется и отображается форма. Это указывает на то, что что-то не объявлено так, как должно быть на стороне C#.

Для меня совершенно ново заставить C++ сходиться с C# во время такой модальной функции, как форма.

Мне нужно знать, как исправить оператор, чтобы функция обратного вызова была распознана.

Что я уже пробовал:

Я исправил код, но когда я запускаю функцию обратного вызова, она выдает мне ошибку безопасности ECall

Я обработал следующий код C++:

int wmain(int argc, _TCHAR* argv[]) {

если (значение == значение s_ok) {
с std::wcout &ЛТ;&ЛТ; returned_thing &ЛТ;&ЛТ; функция std::епси;
возвращает 0;
}
возврат 1;
}


Предыдущее приложение взаимодействует с библиотекой на языке C # с помощью следующего кода C #:
namespace CSharpClass
{
    public class The33Class
    {
        CPPCallBack _CPPCallBack = null;

        public void SetCallBacks(IntPtr cppCallBack)
        {
        }


        public String Getng(String arg) // Make sure this is public
        {
        }

    }
}

Richard MacCutchan

Вы могли бы решить эту проблему некоторое время назад, если бы использовали правильный основной класс C# для взаимодействия с библиотекой.

fisadmaster

Вот почему я спрашиваю, Как настроить код, исходный код не мой, но он был полезен мне до того, как я сделал мосты. Если вы так добры, не могли бы вы показать мне, как исправить эти утверждения?

Richard MacCutchan

Неуправляемый код C++ плохо сочетается с .NET, поэтому я не знаю, как вы могли бы решить эту проблему. Я могу только предложить вам использовать Google, чтобы попытаться найти образец, который кто-то действительно сделал для работы.

Rick York

Если бы я был на вашем месте, у меня была бы очень веская причина так сильно бороться с этим вопросом. До сих пор я не читал ни одного из вас, но это нормально. Тебе не нужно оправдываться передо мной. Я перепишу один из этих двух модулей на том же языке, что и другой, и вся эта сложность будет устранена. Вы, вероятно, могли бы сделать переписывание за то время, которое вы потратили на борьбу с этим, и, судя по всему, будете продолжать тратить.

fisadmaster

Я исправил код, но когда я запускаю функцию обратного вызова, она выдает мне ошибку безопасности ECall

2 Ответов

Рейтинг:
16

0x01AA

Я делал подобные вещи и раньше, несколько лет назад. Очень прагматичный подход (и, возможно, очень грязный).
Имейте в виду, что я отметил здесь то, что помню...

Часть c#

public class CSharpCom
{
   // c++ Callback stuff
   private delegate void CPPCallBack([MarshalAs(UnmanagedType.BStr)] string text);

   CPPCallBack _CPPCallBack= null;

   // To set callback from c++ 
   public void SetCallBacks(IntPtr cppCallBack)
   {
      _CPPCallBack= (CPPCallBack)Marshal.GetDelegateForFunctionPointer(
                     cppCallBack,
                     typeof(CPPCallBack));
   }

   // Using of the callback
   public void LogMsg(string msg)
   {
      try
      {
          _CPPCallBack?.Invoke(msg);
      }
      catch
      {
         // Error handling
      }
   }


   // You other COM stuff
}


Часть c++
static void __stdcall CPPCallBack(BSTR msg)
{
  // Implement callback stuff here
}

int wmain(int argc, char* argv[])
{
	CoInitialize(0); // Init COM

	BSTR thing_to_send = ::SysAllocString(L"10 20");
	BSTR returned_thing;
	CSharpDll::_TheClassPtr obj(__uuidof(CSharpDll::TheClass));

        // Register the callback
        obj->SetCallBacks((INT64)CPPCallBack);

	HRESULT hResult = obj->GetTheThing(thing_to_send, &returned_thing);

	if (hResult == S_OK) {
		std::wcout << returned_thing << std::endl;
		return 0;
	}
	return 1;
}


Я надеюсь, что это поможет

[Редактировать]
код корректируется в соответствии с обратной связью ОП


fisadmaster

Спасибо за код, но часть,
_CPPCallBack = (CPPCallBack) .Маршал.Указатель (
                      cppCallBack,
                      typeof (CPPCallBack));

показывает мне ошибку: CSharpCom.CPPCallBack-это тип, который не является допустимым в данном контексте и CSharpCom.CPPCallBack не содержит определения слова "Маршал"

Я включил ваш код в вопрос, чтобы вы могли видеть реализованную сторону C #
Есть идеи?

0x01AA

Хорошо, не уверен, но, возможно, определение делегата должно быть общедоступным. Попробовать это public delegate void CPPCallBack([MarshalAs(UnmanagedType.BStr)] string text);

fisadmaster

Я тоже пробую это сделать, та же проблема

0x01AA

Хорошо, дайте мне "un rato", я попробую настроить небольшой тестовый проект.

0x01AA

Это была просто маленькая опечатка. Я поправил свой ответ.
a.) void SetCallback // void вместо bool (не было проблемы)
b.) _CPPCallBack= (CPPCallBack)Маршал.Указатель(
cppCallBack,
typeof(CPPCallBack));
вместо
_CPPCallBack= (CPPCallBack).Маршал.

fisadmaster

Проверьте изменения, но ничего не происходит, не возвращайтесь к C++

0x01AA

Но он компилируется?
Что говорит вам отладчик с обеих сторон?

Для меня он работает сейчас очень хорошо.

fisadmaster

при отладке форма C # не отображается, форма отображается при освобождении, но функция обратного вызова не выполняется. Мои настройки для 64 бит

0x01AA

Поймите, но я думаю, что это совсем другое дело. В GetThings вы показываете форму с "ShowForm", которую я не знаю в деталях. Убедитесь, что форма отображается в виде диалога.

fisadmaster

Теперь вы можете увидеть полный код, который я опубликовал для C++ и C#, код кнопки, которая должна отправить сообщение о выпуске::
TheClass myClass = новый TheClass ();
класса MyClass.LogMsg ("Работа !!!");

fisadmaster

Я сделал тест, не показывая форму, и функция работает, обратный вызов отправляет сообщение, но мне нужно отправить несколько сообщений, пока форма отображается

0x01AA

Я думаю, что это хорошая новость. Теперь вы должны показать, как ваш экземпляр Form1 использует обратный вызов.

Кстати: используйте виджет ответа комментария, чтобы ответить. Это делает его более структурированным

fisadmaster

в форме есть кнопка, которая в событии click имеет этот код:

0x01AA

Это как будто никогда не сработает. Имейте в виду, что только BimObjectCSharpClass знает обратный вызов. Либо вы передаете BimObjectCSharpClass в свою форму 1, сохраняете ее в частной переменной, например _BimObjectCSharpClass, а затем вызываете _BimObjectCSharpClass.LogMsg из вашей формы или вы устанавливаете делегат для Form1

fisadmaster

Извините, но я заблудился, BimObjectCSharpClass-это пространство имен, А класс-это класс. на который я ссылался в коде кнопки для доступа к LogMsg, форма имеет то же пространство имен:


0x01AA

Простите, я ошибся.
Я имею в виду, что вам нужно передать класс в вашу форму 1. Имейте в виду, что это не очень хороший способ, но проверить его пока будет нормально. Косметику можно сделать и позже ;)

fisadmaster

Но если я передам класс в форму, то не смогу его увидеть и объявить из C ++?

0x01AA

TheClass и Form1 оба они находятся на стороне c#. Я не вижу в этом проблемы...
Form1 должен иметь доступ к TheClass.LogMsg

fisadmaster

Извините, я думал, что мне нужно было передать весь код класса в код формы, но я не знаю, как передать класс в качестве ссылки на форму?

0x01AA

Вы доводите меня до предела :). Я точно этого не знаю. Пожалуйста, заранее простите мне все мои ошибки ;)

открытый form1(класса класса )
{
_TheClass= класс;
}

После этого вы можете использовать _TheClass.LogMsg....

Как уже упоминалось, это не самый чистый способ, но очень хорошо подходит для первого испытания




fisadmaster

Я сделал чистую компиляцию, переписал весь код, мне показалось что-то странное и теперь библиотека C # не загружается, если я отключу строку: obj - > SetCallBacks ((long) CPPCallBack); форма отображается, если она включена, она входит в цикл без ответа и заканчивается через несколько секунд. Я считаю, что в этом утверждении есть проблема, есть ли идея проблемы?

fisadmaster

Я делаю простое изменение с long на INT64 и передаю класс в качестве ссылки и теперь работаю, спасибо человеку!!!!.
obj->SetCallBacks((INT64)CPPCallBack);

0x01AA

Спасибо, что согласились и проголосовали.

Рейтинг:
0

TheGreatAndPowerfulOz

Есть ли причина, по которой консоль должна быть на C++? Является ли это тупым примером, чтобы вы могли заставить его работать в другом, более сложном контексте, например в устаревшем приложении C++ или COM-объекте?

Если нет, тогда ... ..

1) Почему бы не использовать C++/CLI, который также является управляемым кодом?

или

2) Вы можете написать консольное приложение на языке C#. Так что это может решить проблему для вас.