Форум программистов, компьютерный форум, киберфорум
C# для начинающих
Войти
Регистрация
Восстановить пароль
Блоги Сообщество Поиск Заказать работу  
 
Рейтинг 4.92/13: Рейтинг темы: голосов - 13, средняя оценка - 4.92
1 / 1 / 1
Регистрация: 06.03.2016
Сообщений: 64

Как в C# импортировать функцию из DLL C++, которая возвращает интерфейсное значение?

05.11.2018, 00:59. Показов 2810. Ответов 6

Студворк — интернет-сервис помощи студентам
Мне нужно получить из библиотеки C++ функцию, возвращающую интерфейс. Однако на стороне шарповского кода возникает ошибка (ниже).

Заголовочные файлы:
C++
1
2
3
4
5
6
7
8
// IMath.h
 
class IMath
{
public:
    virtual INT_PTR __stdcall GetName() = 0;
    virtual double __stdcall Calc(double) = 0;
};
C++
1
2
3
4
5
6
7
8
9
10
// Math.h
 
#include "IMath.h"
 
class Math : public IMath 
{
public:
    INT_PTR __stdcall Math::GetName();
    double __stdcall Math::Calc(double x);
};
Инициализация класса:
C++
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
// Math.cpp
 
#include "stdafx.h"
#include <cmath>
#include "Math.h"
 
INT_PTR __stdcall Math::GetName()
{
    return (INT_PTR)(char*) "sin(x)";
}
 
double __stdcall Math::Calc(double x)
{
    return std::sin(x);
}
Экспортируемая функция:
C++
1
2
3
4
5
6
7
#include "stdafx.h"
#include "Math.h"
 
extern "C" _declspec(dllexport) IMath* __stdcall GetInterface()
{
    return new Math();
}
Код C#:
C#
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
 public interface IMath
    {
        IntPtr GetName();
        double Calc(double x);
    }
 
    [UnmanagedFunctionPointer(CallingConvention.StdCall)]
    public delegate IMath InterfaceReceiver();
 
    // Код
 
    IntPtr func_gn = GetProcAddress(plugin, "_GetInterface@0");
 
    if (func_gn == IntPtr.Zero)
    {
         Console.WriteLine("Missing GetInterface function in the DLL!");
    }
 
    InterfaceReceiver GetInterface =
             (InterfaceReceiver)Marshal.GetDelegateForFunctionPointer(func_gn, typeof(InterfaceReceiver));
 
    IMath iMath = GetInterface();  // <- Ошибка FatalExecutionEngineError
Содержание ошибки:
"В среде выполнения обнаружена критическая ошибка. Ошибка произошла по адресу 0x7056a574 в потоке 0xb08. Код ошибки 0xc0000005. Она может быть вызвана ошибкой в CLR или в небезопасных либо не поддающихся проверке фрагментах пользовательского кода. Обычно источниками таких ошибок бывают ошибки упаковки, допускаемые пользователями при COM-взаимодействии, либо PInvoke, повредивший стек."

Как исправить эту проблему? Или, возможно, есть более правильный способ получить интерфейсное значение?
0
Лучшие ответы (1)
IT_Exp
Эксперт
34794 / 4073 / 2104
Регистрация: 17.06.2006
Сообщений: 32,602
Блог
05.11.2018, 00:59
Ответы с готовыми решениями:

Как импортировать вызываемую из dll функцию, если эта функция возвращает значение типа ppchar
Подскажите, пожалуйста, как в с# импортировать вызываемую из dll функцию, если эта функция возращает значение типа ppchar, или вернее...

Как вызвать функцию которая принимает значение int а возвращает float?
#include &lt;iostream&gt; #include &lt;cstring&gt; #include &lt;windows.h&gt; #include &lt;ctime&gt; #include &lt;istream&gt; using namespace std; void...

Написать функцию Factorial, которая возвращает значение значение факториала целого числа.
Помогите, пожалуйста, написать функцию Factorial, которая возвращает значение значение факториала целого числа. Формула: N!=1*2*3*...*N

6
Эксперт .NET
6691 / 4102 / 1607
Регистрация: 09.05.2015
Сообщений: 9,574
05.11.2018, 03:48
Не знаю как насчет использования интерфейса напрямую, но с помощью структуры вполне себе работает

Вот тут можно почитать как сделать именно с интерфейсом
https://stackoverflow.com/ques... in-c-sharp

C#
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
using System;
using System.Runtime.InteropServices;
 
namespace ConsoleApp7
{
    struct IMath
    {
        [UnmanagedFunctionPointer(CallingConvention.StdCall)]
        public delegate IntPtr GetNameDelegate();
 
        [UnmanagedFunctionPointer(CallingConvention.StdCall)]
        public delegate double CalcDelegate(double x);
 
        public GetNameDelegate GetName;
        public CalcDelegate Calc;
 
        public string Name => Marshal.PtrToStringAnsi(GetName());
    }
 
    class Program
    {
        [DllImport("kernel32", CharSet = CharSet.Ansi, ExactSpelling = true, SetLastError = true)]
        static extern IntPtr GetProcAddress(IntPtr hModule, string procName);
 
        [DllImport("kernel32", SetLastError = true, CharSet = CharSet.Ansi)]
        static extern IntPtr LoadLibrary([MarshalAs(UnmanagedType.LPStr)]string lpFileName);
 
        [UnmanagedFunctionPointer(CallingConvention.StdCall)]
        public delegate IntPtr InterfaceReceiver();
 
        static void Main(string[] args)
        {
            IntPtr plugin = LoadLibrary("CppDll1.dll");
 
            IntPtr func_gn = GetProcAddress(plugin, "GetInterface");
 
            if (func_gn == IntPtr.Zero)
            {
                Console.WriteLine("Missing GetInterface function in the DLL!");
                Console.ReadKey();
                return;
            }
 
            InterfaceReceiver GetInterface = Marshal.GetDelegateForFunctionPointer<InterfaceReceiver>(func_gn);
 
            IntPtr iMathPtr = GetInterface();
 
            IntPtr iMathVtablePtr = Marshal.ReadIntPtr(iMathPtr);
 
            IMath test = Marshal.PtrToStructure<IMath>(iMathVtablePtr);
 
            Console.WriteLine(test.Name);
 
            Console.WriteLine(test.Calc(0.5));
 
            Console.ReadKey();
        }
    }
}
2
Эксперт .NET
6691 / 4102 / 1607
Регистрация: 09.05.2015
Сообщений: 9,574
05.11.2018, 17:36
Лучший ответ Сообщение было отмечено WhiscasH как решение

Решение

Вот так работает напрямую с интерфейсом

C++
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
#pragma once
 
#include "unknwn.h"
#include <cmath>
#include <objbase.h>
#include <initguid.h>
#include <cstdio> // for printf
 
// {D18D54BC-C6CE-486C-A814-D2E2168E18EE}
DEFINE_GUID(IID_IMath, 0xd18d54bc, 0xc6ce, 0x486c, 0xa8, 0x14, 0xd2, 0xe2, 0x16, 0x8e, 0x18, 0xee);
 
class IMath : public IUnknown
{
public:
    virtual const BSTR __stdcall GetName() = 0;
    virtual double __stdcall Calc(double x) = 0;
};
 
class Math : public IMath
{
private:
    ULONG count;
    BSTR name;
public:
    Math()
    {
        printf("Math()\n");
        count = 0;
        name = SysAllocString(L"sin(x)");
    }
 
    ~Math()
    {
        printf("~Math()\n");
        if (name)
        {
            SysFreeString(name);
            name = nullptr;
        }
    }
 
    virtual const BSTR __stdcall GetName()
    {
        printf("GetName\n");
        return name;
    }
 
    virtual double __stdcall Calc(double x)
    {
        printf("Calc\n");
        return std::sin(x);
    }
 
    ULONG __stdcall AddRef()
    {
        printf("AddRef\n");
        return InterlockedIncrement(&count);
    }
 
    ULONG __stdcall Release()
    {
        printf("Release\n");
        return InterlockedDecrement(&count);
    }
 
    HRESULT __stdcall QueryInterface(REFIID riid, void **ppvObject)
    {
        printf("QueryInterface\n");
        if (riid == IID_IUnknown)
        {
            *ppvObject = this;
            AddRef();
            return S_OK;
        }
 
        if (riid == IID_IMath)
        {
            *ppvObject = this;
            AddRef();
            return S_OK;
        }
 
        *ppvObject = nullptr;
        return E_NOINTERFACE;
    }
};
 
static Math* s_math = nullptr;
 
extern "C"
{
    _declspec(dllexport) IMath* __stdcall GetInterface()
    {
        if (s_math == nullptr)
            s_math = new Math();
        return s_math;
    }
 
    _declspec(dllexport) void __stdcall FreeInterface()
    {
        if (s_math != nullptr)
            delete s_math;
        s_math = nullptr;
    }
}
C#
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
using System;
using System.Runtime.InteropServices;
 
namespace ConsoleApp7
{
    [Guid("D18D54BC-C6CE-486C-A814-D2E2168E18EE")]
    [InterfaceType(ComInterfaceType.InterfaceIsIUnknown)]
    public interface IMath
    {
        [PreserveSig]
        string GetName();
 
        [PreserveSig]
        double Calc(double x);
    }
 
    class Program
    {
        [DllImport("kernel32", CharSet = CharSet.Ansi, ExactSpelling = true, SetLastError = true)]
        static extern IntPtr GetProcAddress(IntPtr hModule, string procName);
 
        [DllImport("kernel32", SetLastError = true, CharSet = CharSet.Ansi)]
        static extern IntPtr LoadLibrary([MarshalAs(UnmanagedType.LPStr)]string lpFileName);
 
        [UnmanagedFunctionPointer(CallingConvention.StdCall)]
        public delegate IMath GetInterfaceDelegate();
 
        [UnmanagedFunctionPointer(CallingConvention.StdCall)]
        public delegate void FreeInterfaceDelegate();
 
        static void Main(string[] args)
        {
            IntPtr plugin = LoadLibrary("CppDll1.dll");
 
            IntPtr pGetFunc = GetProcAddress(plugin, "GetInterface");
 
            if (pGetFunc == IntPtr.Zero)
            {
                Console.WriteLine("Missing GetInterface function in the DLL!");
                Console.ReadKey();
                return;
            }
 
            GetInterfaceDelegate GetInterface = Marshal.GetDelegateForFunctionPointer<GetInterfaceDelegate>(pGetFunc);
 
            IMath iMath = GetInterface();
 
            Console.WriteLine(iMath.GetName());
 
            Console.WriteLine(iMath.Calc(0.5));
 
            Marshal.FinalReleaseComObject(iMath);
 
            IntPtr pFreeFunc = GetProcAddress(plugin, "FreeInterface");
 
            if (pFreeFunc == IntPtr.Zero)
            {
                Console.WriteLine("Missing FreeInterface function in the DLL!");
                Console.ReadKey();
                return;
            }
 
            FreeInterfaceDelegate FreeInterface = Marshal.GetDelegateForFunctionPointer<FreeInterfaceDelegate>(pFreeFunc);
 
            FreeInterface();
 
            Console.ReadKey();
        }
    }
}
1
1 / 1 / 1
Регистрация: 06.03.2016
Сообщений: 64
06.11.2018, 12:32  [ТС]
Второй код выдает ошибку:

Вызвано исключение: "System.Runtime.InteropServices.COMExcep tion" в project5.exe
Необработанное исключение типа "System.Runtime.InteropServices.COMExcep tion" в project5.exe
Неопознанная ошибка (Исключение из HRESULT: 0x80004005 (E_FAIL))
в System.StubHelpers.InterfaceMarshaler.Co nvertToManaged(IntPtr pUnk, IntPtr itfMT, IntPtr classMT, Int32 flags)
в строке, где вызывается функция делегата GetInterface().
0
Эксперт .NET
6691 / 4102 / 1607
Регистрация: 09.05.2015
Сообщений: 9,574
06.11.2018, 13:54
Скорее всего что-то не так сделали. У меня ошибок не возникает.
Вложения
Тип файла: zip ConsoleApp7.zip (46.5 Кб, 3 просмотров)
0
1 / 1 / 1
Регистрация: 06.03.2016
Сообщений: 64
06.11.2018, 20:17  [ТС]
Странно, но ваш код на C++ Visual Studio вообще не читает. В частности строчку #include "unknwn.h". Я могу его подключить через #include <Unknwn.h>, но в вашем проекте Intellisense даже не может найти этот модуль. Да и в начале Visual Studio вообще ругался, пришлось скачать .NET Framework 4.7.2, только тогда проект запустился. Однако код c++ так же подчеркивает красным.

Добавлено через 15 минут
Все, я решил проблему. Создал новый проект и в него вставил ваш код, немного изменив имена модулей, и все заработало. Действительно, ошибся, когда под себя подгонял.
0
Эксперт .NET
6691 / 4102 / 1607
Регистрация: 09.05.2015
Сообщений: 9,574
06.11.2018, 20:43
Цитата Сообщение от WhiscasH Посмотреть сообщение
Странно, но ваш код на C++ Visual Studio вообще не читает. В частности строчку #include "unknwn.h". Я могу его подключить через #include <Unknwn.h>, но в вашем проекте Intellisense даже не может найти этот модуль. Да и в начале Visual Studio вообще ругался, пришлось скачать .NET Framework 4.7.2, только тогда проект запустился. Однако код c++ так же подчеркивает красным.
У меня компилит без проблем в том виде в котором я выложил, если поменять "" на <> тоже компилит. VS2017 15.8.9.
0
Надоела реклама? Зарегистрируйтесь и она исчезнет полностью.
BasicMan
Эксперт
29316 / 5623 / 2384
Регистрация: 17.02.2009
Сообщений: 30,364
Блог
06.11.2018, 20:43
Помогаю со студенческими работами здесь

Написать функцию, которая возвращает значение
В файле, путь к которому вводится с экрана, находится массив чисел, образующих неубывающую последовательность. Написать функцию, которая...

Написать функцию, которая по заданному x возвращает значение
Написать функцию, которая по заданному x возвращает значение. y=ln|x^3 - 1|. (Нужно максимально простое решение, для новичков)

Напишите рекурсивную функцию, которая возвращает значение
Напишите рекурсивную функцию, которая возвращает значение.

Написать функцию glasn, которая возвращает значение по условию
подсобите, если не трудно Написать функцию glasn, которая возвращает 1, если символ, полученный функцией в качестве аргумента, является...

Написать функцию, которая возвращает среднее значение элементов одномерного массива
2. Написать функцию, которая возвращает среднее значение элементов одномерного массива.


Искать еще темы с ответами

Или воспользуйтесь поиском по форуму:
7
Ответ Создать тему
Новые блоги и статьи
SDL3 для Web (WebAssembly): Основы отладки веб-приложений на SDL3 по USB и Wi-Fi, запущенных в браузере мобильных устройств
8Observer8 07.02.2026
Содержание блога Браузер Chrome имеет средства для отладки мобильных веб-приложений по USB. В этой пошаговой инструкции ограничимся работой с консолью. Вывод в консоль - это часть процесса. . .
SDL3 для Web (WebAssembly): Обработчик клика мыши в браузере ПК и касания экрана в браузере на мобильном устройстве
8Observer8 02.02.2026
Содержание блога Для начала пошагово создадим рабочий пример для подготовки к экспериментам в браузере ПК и в браузере мобильного устройства. Потом напишем обработчик клика мыши и обработчик. . .
Философия технологии
iceja 01.02.2026
На мой взгляд у человека в технических проектах остается роль генерального директора. Все остальное нейронки делают уже лучше человека. Они не могут нести предпринимательские риски, не могут. . .
SDL3 для Web (WebAssembly): Вывод текста со шрифтом TTF с помощью SDL3_ttf
8Observer8 01.02.2026
Содержание блога В этой пошаговой инструкции создадим с нуля веб-приложение, которое выводит текст в окне браузера. Запустим на Android на локальном сервере. Загрузим Release на бесплатный. . .
SDL3 для Web (WebAssembly): Сборка C/C++ проекта из консоли
8Observer8 30.01.2026
Содержание блога Если вы откроете примеры для начинающих на официальном репозитории SDL3 в папке: examples, то вы увидите, что все примеры используют следующие четыре обязательные функции, а. . .
SDL3 для Web (WebAssembly): Установка Emscripten SDK (emsdk) и CMake для сборки C и C++ приложений в Wasm
8Observer8 30.01.2026
Содержание блога Для того чтобы скачать Emscripten SDK (emsdk) необходимо сначало скачать и уставить Git: Install for Windows. Следуйте стандартной процедуре установки Git через установщик. . . .
SDL3 для Android: Подключение Box2D v3, физика и отрисовка коллайдеров
8Observer8 29.01.2026
Содержание блога Box2D - это библиотека для 2D физики для анимаций и игр. С её помощью можно определять были ли коллизии между конкретными объектами. Версия v3 была полностью переписана на Си, в. . .
Инструменты COM: Сохранение данный из VARIANT в файл и загрузка из файла в VARIANT
bedvit 28.01.2026
Сохранение базовых типов COM и массивов (одномерных или двухмерных) любой вложенности (деревья) в файл, с возможностью выбора алгоритмов сжатия и шифрования. Часть библиотеки BedvitCOM Использованы. . .
КиберФорум - форум программистов, компьютерный форум, программирование
Powered by vBulletin
Copyright ©2000 - 2026, CyberForum.ru