Подключение C++ dll к WPF проекту C# [дубликат]

85
21 ноября 2021, 05:30
На этот вопрос уже даны ответы здесь:
Как добавить в C#-проект dll-файл? (2 ответа)
Закрыт 1 год назад.

Есть WPF проект на C# и С++ dll реализующая некоторые сложные вычисления, возможно ли как то подключить эту библиотеку к С# проекту для создания экземпляров классов С++, и если да, то что для этого требуется? Если не сложно объясните поэтапно, я в этом деле новичок.

Answer 1

Если вы хотите использовать именно классы c++, то вариант решения, примерно такой:

  1. Объявим класс который будет generic классом:
public abstract class CClassBase<TNewDelegate, TDeleteDelegate> :
    IDisposable
    where TNewDelegate    : Delegate
    where TDeleteDelegate : Delegate
{
    protected TNewDelegate    New;
    protected TDeleteDelegate Delete;
    protected IntPtr          ThisPtr;
    protected CClassBase(TNewDelegate newDelegate, TDeleteDelegate deleteDelegate)
    {
        New = newDelegate;
        Delete = deleteDelegate;
    }
    public bool IsDisposed
    {
        get;
        protected set;
    }
    protected abstract void Dispose(bool disposable);
    public void Dispose()
    {
        Dispose(true);
        GC.SuppressFinalize(this);
    }
    ~CClassBase()
    {
        Dispose(false);
    }
}
  1. Наследование от этого класса, базового класса, не generic:
// Делегат конструктора без параметров, вы можете определять свои, и наследоваться от generic класса
[UnmanagedFunctionPointer(CallingConvention.ThisCall)]
public delegate void NewDelegate(ref IntPtr thisPtr);
[UnmanagedFunctionPointer(CallingConvention.ThisCall)]
public delegate void DeleteDelegate(ref IntPtr thisPtr);
public class CClassBase :
    CClassBase<NewDelegate, DeleteDelegate>
{
    protected CClassBase(NewDelegate newDelegate, DeleteDelegate deleteDelegate)
        : base(newDelegate, deleteDelegate)
    {
        New(ref ThisPtr);
    }
    protected override void Dispose(bool disposable)
    {
        if (IsDisposed)
        {
            return;
        }
        Delete(ref ThisPtr);
        if (disposable)
        {
            ThisPtr = IntPtr.Zero;
            New = null;
            Delete = null;
        }
        IsDisposed = true;
    }
}
  1. Описание неуправляемого (экспортируемого класса) класса:

В моем случае неуправляемый класс объявлен как:

struct MI_CORE_API engine : public ::window_container
{
public:
    ::LRESULT on_message(::HWND hwnd, ::UINT msg, ::WPARAM w_param, ::LPARAM l_param) override;
    bool process_messages() override;
    bool initialize(::HINSTANCE app_instance, ::int32_t width, ::int32_t height, wchar_t const* application_name);
};

Соответственно я определил управляемый класс как:

public class Engine :
    CClassBase
{
    [DllImport("mi_core.dll",
        CallingConvention = CallingConvention.ThisCall,
        EntryPoint = "??0engine@@QAE@XZ")]
    private static extern void EngineNew(ref IntPtr thisPtr);
    [DllImport("mi_core.dll",
        CallingConvention = CallingConvention.ThisCall,
        EntryPoint = "??1engine@@UAE@XZ")]
    private static extern void EngineDelete(ref IntPtr ptr);
    [DllImport("mi_core.dll",
        CallingConvention = CallingConvention.ThisCall,
        EntryPoint = "?initialize@engine@@QAE_NPAUHINSTANCE__@@HHPB_W@Z")]
    private static extern bool EngineInitialize(ref IntPtr thisPtr, IntPtr applicationInstance, int width, int height,
        [MarshalAs(UnmanagedType.LPWStr)] string applicationName);
    [DllImport("mi_core.dll",
        CallingConvention = CallingConvention.ThisCall,
        EntryPoint = "?process_messages@engine@@UAE_NXZ")]
    private static extern bool EngineProcessMessages(ref IntPtr thisPtr);
    public Engine() :
        base(EngineNew, EngineDelete)
    {
        GC.KeepAlive(this);
    }
    public bool ProcessMessages()
    {
        return EngineProcessMessages(ref ThisPtr);
    }
    public bool Initialize(int width, int height, string applicationName)
    {
        ProcessModule processModule = Process.GetCurrentProcess().MainModule;
        if (processModule == null)
        {
            return false;
        }
        IntPtr applicationInstance = processModule.BaseAddress;
        return EngineInitialize(ref ThisPtr, applicationInstance, width, height, applicationName);
    }
}

Ну и запуск:

internal static class Program
{
    public static int Main(string[] args)
    {
        using (Engine engine = new Engine())
        {
            if (!engine.Initialize(1280, 720, "Some Application Name"))
            {
                return 1;
            }
            while (engine.ProcessMessages())
            {
            }
        }
        return 0;
    }
}

Результат:

READ ALSO
Angular - как правильно подписаться на ng-model

Angular - как правильно подписаться на ng-model

Почему я не могу так сделать? У меня два селектаПервый солект должен создать вложенный объект у объекта Album

200
Вопрос по методу Instantiate() в Unity

Вопрос по методу Instantiate() в Unity

Необходимо сделать так, что бы при смерти моего главного героя на этом месте появлялся объект - его душаПочему то в данный момент получается...

129
Загрузка System.Runtime.InteropServices.RuntimeInformation

Загрузка System.Runtime.InteropServices.RuntimeInformation

После ошибки "Пакет Shared Web Component не был правильно загружен" удалил Visual Studio Community 17 и установил Visual Studio Community 19

117
Парсер на c#. IndexOf выдает -1 [дубликат]

Парсер на c#. IndexOf выдает -1 [дубликат]

Пытаюсь получить значение после определенного текста в html коде страницыpage

165