Работа с нативным кодом из .Net Core

251
23 января 2018, 12:16

У Microsoft есть статья, посвященная работе с нативным кодов в .Net Core на различных платформах. Да, они приводят некоторые примеры, но О МНОГОМ не договаривают. Например, тут они вызывают функцию из WinAPI, чтобы вывести сообщение на экран А вот если dll-ка скомпилирована 32 битым компилятором, например стандартным из комплекта поставки Code::Blocks на Windows с MinGW32, то программа улетает с исключением BadImageFormatException Хотелось бы видеть ЖИВОЙ пример работы с нативным кодом на примере доступа к всплывающим уведомлениям на Ubuntu и Windows 10

Answer 1

Ссылку на скачивание ВСЕГО примера я оставил в самом низу ответа на вопрос

Linux

Тут всё просто, на 64 битной системе gcc по умолчанию будет компилировать 64 битные бинарники. Соответственно, задача сводится к написанию простейшей сишной функции, код снизу

#include <stdio.h>
#include <libnotify/notify.h>
int notify(const char *title, const char *description,int timeout)
{
  notify_init("dcnn");
  NotifyNotification* n = notify_notification_new (title, description, 0);
  notify_notification_set_timeout(n, timeout);
  if (!notify_notification_show(n, 0)) 
  {
    printf("Notification fallen");
    return -1;
  }
  printf("Notificated");
  //notify_uninit (void);
  return 1;
}

Ничего сложного. Не вглядывайтесь в содержимое, это просто функция, которая может вернуть значение. main() кстати не нужен, так как далее мы вынесем её в .so, который сам по себе не будет запускаться. Компилируем через gcc со следующими параметрами:

gcc -Wall -shared -o native.so -fPIC native.c `pkg-config --cflags --libs gtk+-2.0 libnotify` -lnotify

Тут важно компилировать одной командой. Да, есть возможность сначала получить объектные модули .o, но компилятор при этом обязательно что нибудь забудет добавить... Рекомендую так же не отходя от кассы попытаться сделать динамичный импорт библиотеки из другой сишной программы, в репозитории в папке ubuntu лежит файл testing.c c её реализацией. Но если можете написать сразу правильно, то можно и пропустить

После сборки получаем файл native.so. Его нужно закинуть в папку со сборкой для .Net Core. По умолчанию у меня сборка появилась в директории

DotnetCoreNativeNotifications/bin/Debug/netcoreapp2.0/

Далее вызывается это дело просто. Всё как в документации MS

public class UbuntuNotify : AbstractNotify
{
    public UbuntuNotify(){}
    [DllImport("native.so")]
    private static extern int notify([MarshalAs(UnmanagedType.LPStr)]string title,[MarshalAs(UnmanagedType.LPStr)]string description, int timeout);
    public override void Notify(string title, string desc, int timeout)
    {
        UbuntuNotify.notify(title,desc,timeout);
    }
}

В Program.cs я проверяю if-ом платформу, создаю экземпляр этого класса и вызываю метод Notify

Windows

Для начала выбираем правильное ПО для прикладного программирования. Не рекомендую пытаться написать dll в Visual Studio. На мой взгляд, она заточена ИМЕННО под C# и процесс написания динамически подключаемой библиотеки в ней затянется на долгое время, так как тупо нет шаблона проекта, собирающего dll

Берем Code::Blocks, http://www.codeblocks.org/

Далее ставим на него 64 битный компилятор. Это важно, без него .Net Core посчитает dll некоректной

Статья как поставить такой тут, https://medium.com/@yzhong.cs/code-blocks-compile-64-bit-under-windows-with-mingw-w64-79101f5bbc02

Создаем проект dll, язык C++

Не забудьте выбрать ПРАВИЛЬНЫЙ компилятор

Далее он сгенерирует достаточно читаемый код. Посмотреть код dll который выводит уведомления на Windows можно тут https://github.com/tripolskypetr/DotnetCoreNativeNotifications/blob/master/windows/native/main.cpp

После того, как закончили написание dll, так же кидаем его в папку со сборкой .Net Core, для обращения я реализовал следующий класс

public class WindowsNotify : AbstractNotify
{
    public WindowsNotify(){}
    [DllImport("native.dll", CallingConvention = CallingConvention.Cdecl)]
    private extern static void NotifyFunc([MarshalAs(UnmanagedType.LPStr)]string title, [MarshalAs(UnmanagedType.LPStr)]string desc);
    public override void Notify(string title, string desc, int timeout)
    {
        WindowsNotify.NotifyFunc(title,desc);
    }
}

В итоге у нас получился проект .Net Core, который и на Ubuntu и на Windows 10 вывел нам уведомление. Чудеса

ВАЖНО: На разных версиях десятки может не работать, так как используется WinAPI и оно тоже меняется... Мой компьютер работает на версии 1703, она достаточно старая. Рекомендую попробовать тот же пример, но в dll на Windows вызывать функцию MessageBoxA как в шаблоне dll среды Code::Blocks, надеюсь мелкомягкие до неё не доберуться. Про linux я спокоен...

void DLL_EXPORT SomeFunction(const LPCSTR sometext)
{
    MessageBoxA(0, sometext, "DLL Message", MB_OK | MB_ICONINFORMATION);
}

Посмотреть полный код данного примера можно тут, https://github.com/tripolskypetr/DotnetCoreNativeNotifications

READ ALSO
Почему вылетает программа после ввода name

Почему вылетает программа после ввода name

Друзья,вылетает программа после ввода поля tabl[i]name; Не могу понять в чём проблема

212
Java, почему не работает код, буфер обмена

Java, почему не работает код, буфер обмена

Помогите, пожалуйста, исправить код моей первой программыОна должна анализировать буфер обмена на наличие в нём 5-ти значного числа начинающегося...

318
Создание AutoCompleteTextView внутри кастомного Menu

Создание AutoCompleteTextView внутри кастомного Menu

Как создать AutoCompleteTextView внутри кастомного меню?

213
В книге Шилда опечатка или нет?

В книге Шилда опечатка или нет?

Читаю книгу Шилда Java 8Ссылки на статические методы

216