Подтвердить что ты не робот

Можно ли вызвать функцию C из С#.Net

У меня есть C lib и хочу вызвать функцию в этой библиотеке из приложения С#. Я попытался создать оболочку С++/CLI в C lib, добавив файл C lib в качестве вставки компоновщика и добавив исходные файлы в качестве дополнительных зависимостей.

Есть ли лучший способ достичь этого, так как я не уверен, как добавить вывод C в приложение С#.

Мой код C -

__declspec(dllexport) unsigned long ConnectSession(unsigned long handle,
                            unsigned char * publicKey,
                            unsigned char   publicKeyLen);

My CPP Wrapper -

long MyClass::ConnectSessionWrapper(unsigned long handle,
                                unsigned char * publicKey,
                                unsigned char   publicKeyLen)
    {
        return ConnectSession(handle, publicKey, publicKeyLen);
    }
4b9b3361

Ответ 1

Пример для Linux:

1) Создайте файл C, libtest.c с этим контентом:

#include <stdio.h>

void print(const char *message)
{
  printf("%s\\n", message);
}

Это простая псевдо-обертка для printf. Но представляет любую функцию C в библиотеке, которую вы хотите вызвать. Если у вас есть функция C++, не забудьте поставить extern C, чтобы избежать изменения имени.

2) создайте файл C#

using System;

using System.Runtime.InteropServices;

public class Tester
{
        [DllImport("libtest.so", EntryPoint="print")]

        static extern void print(string message);

        public static void Main(string[] args)
        {

                print("Hello World C# => C++");
        }
}

3) Если у вас нет библиотеки libtest.so в стандартном пути библиотеки, например "/usr/lib", вы, вероятно, увидите System.DllNotFoundException, чтобы исправить это, вы можете переместить libtest.so в /usr/lib или еще лучше, просто добавьте свой CWD в путь библиотеки: export LD_LIBRARY_PATH=pwd

кредиты здесь

ИЗМЕНИТЬ

Для Windows это немного отличается. Взяв пример из здесь, вы можете добавить только свой *.cpp файл в свой <<2 > Что-то вроде

extern "C"
{
//Note: must use __declspec(dllexport) to make (export) methods as 'public'
      __declspec(dllexport) void DoSomethingInC(unsigned short int ExampleParam, unsigned char AnotherExampleParam)
      {
            printf("You called method DoSomethingInC(), You passed in %d and %c\n\r", ExampleParam, AnotherExampleParam);
      }
}//End 'extern "C"' to prevent name mangling

затем, скомпилируйте, и в вашем файле С# сделайте

[DllImport("C_DLL_with_Csharp.dll", EntryPoint="DoSomethingInC")]

public static extern void DoSomethingInC(ushort ExampleParam, char AnotherExampleParam);

а затем просто используйте его:

using System;

    using System.Runtime.InteropServices;

    public class Tester
    {
            [DllImport("C_DLL_with_Csharp.dll", EntryPoint="DoSomethingInC")]

    public static extern void DoSomethingInC(ushort ExampleParam, char AnotherExampleParam);

            public static void Main(string[] args)
            {
                    ushort var1 = 2;
                    char var2 = '';  
                    DoSomethingInC(var1, var2);
            }
    }

Ответ 2

ОБНОВЛЕНИЕ - 22 февраля 2019 г.: Поскольку этот ответ получил довольно много откликов, я решил обновить его, чтобы улучшить способ вызова метода C. Ранее я предлагал использовать код unsafe, но безопасный и правильный способ - использовать атрибут MarshalAs для преобразования .NET string в char*. Кроме того, в VS2017 больше нет проекта Win32, вам, вероятно, придется создать Visual C++ dll или пустой проект и изменить его. Спасибо!

Вы можете напрямую вызывать функции C из С#, используя P/Invoke.
Вот краткое руководство по созданию библиотеки С#, которая охватывает C dll.

  1. Создайте новый проект библиотеки С# (я назову его "Wrapper")
  2. Добавьте проект Win32 к решению, установите тип приложения: DLL (я назову его "CLibrary")

    • Вы можете удалить все остальные файлы cpp/h, так как они нам не понадобятся
    • Переименуйте файл CLibrary.cpp в CLibrary.c
    • Добавьте заголовочный файл CLibrary.h
  3. Теперь нам нужно настроить проект CLibrary, щелкнуть его правой кнопкой мыши, перейти к свойствам и выбрать "Конфигурация:" Все конфигурации "

    • В свойствах конфигурации> C/C++> предварительно скомпилированные заголовки установите для предварительно скомпилированных заголовков значение "Не использовать предварительно скомпилированные заголовки"
    • В той же ветке C/C++ перейдите в Advanced, измените Compile As на: "Compile as C code (/TC)"
    • Теперь в ветке компоновщика перейдите в раздел "Общие" и измените файл вывода на "$ (SolutionDir) Wrapper\$ (ProjectName).dll", это скопирует встроенную библиотеку C DLL в корневой каталог проекта С#.

CLibrary.h

__declspec(dllexport) unsigned long ConnectSession(unsigned long   handle,
                                                   unsigned char * publicKey,
                                                   unsigned char   publicKeyLen);

CLibrary.c

#include "CLibrary.h"

unsigned long ConnectSession(unsigned long   handle,
                             unsigned char * publicKey,
                             unsigned char   publicKeyLen)
{
    return 42;
}
  • Щелкните правой кнопкой мыши проект CLibrary, соберите его, чтобы мы получили DLL в каталоге проекта С#
  • Щелкните правой кнопкой мыши по проекту С# Wrapper, добавьте существующий элемент, добавьте CLibrary.dll
  • Нажмите CLibrary.dll, перейдите на панель свойств, установите "Копировать в выходной каталог" на "Копировать всегда"

Хорошей идеей будет сделать проект Wrapper зависимым от CLibrary, чтобы CLibrary создавался первым, вы можете сделать это, щелкнув правой кнопкой мыши проект Wrapper, перейдя в "Зависимости проекта" и выбрав "CLibrary". Теперь для фактического кода оболочки:

ConnectSessionWrapper.cs

using System.Runtime.InteropServices;

namespace Wrapper
{
    public class ConnectSessionWrapper
    {
        [DllImport("CLibrary.dll", CallingConvention = CallingConvention.Cdecl)]
        static extern uint ConnectSession(uint handle,
            [MarshalAs(UnmanagedType.LPStr)] string publicKey,
            char publicKeyLen);

        public uint GetConnectSession(uint handle, 
                                      string publicKey,
                                      char publicKeyLen)
        {
            return ConnectSession(handle, publicKey, publicKeyLen);
        }
    }
}

Теперь просто позвоните GetConnectSession, и он должен вернуть 42.

Результат:
Testing wrapper library in a console application

Ответ 3

Хорошо, Open VS 2010, Goto File → New → Project → Visual С++ → Win32 → Win32 Project и дайте ему имя (HelloWorldDll в моем случае), Затем в окне, которое следует по типу приложения выберите "DLL", а в разделе "Дополнительные параметры" выберите "Пустой проект".

Теперь перейдите на вкладку "Обозреватель решений", как правило, правой стороной окна VS, щелкните правой кнопкой мыши "Исходные файлы" → "Добавить элемент" → файл С++ (.cpp) и дайте ему имя (HelloWorld в моем случае)

Затем в новом классе вставьте этот код:

#include <stdio.h>

extern "C"
{
  __declspec(dllexport) void DisplayHelloFromDLL()
  {
    printf ("Hello from DLL !\n");
  }
}

Теперь создайте проект, после перехода к папке DEBUG, и там вы должны найти: HelloWorldDll.dll.

Теперь давайте создадим наше приложение С#, которое будет обращаться к DLL, Goto File → New → Project → Visual С# → Консольное приложение и присвоить ему имя (CallDllCSharp), теперь скопируйте и вставьте этот код в свой основной

using System;
using System.Runtime.InteropServices;
...
        static void Main(string[] args)
        {
            Console.WriteLine("This is C# program");
            DisplayHelloFromDLL();
            Console.ReadKey();
        }

и создайте программу, теперь, когда у нас есть оба наших приложения, они могут использовать их, получить *.dll и ваш .exe(bin/debug/.exe) в том же каталоге и выполнить вывод приложения должен быть

Это программа С#

Привет из DLL!

Надеюсь, что некоторые из ваших проблем будут устранены.

Ссылки

Ответ 4

ПРИМЕЧАНИЕ. НИЖЕ КОД ДЛЯ НЕСКОЛЬКИХ МЕТОДОВ ИЗ DLL.

[DllImport("MyLibc.so")] public static extern bool MyLib_GetName();
[DllImport("MyLibc.so")] public static extern bool MyLib_SetName(string name);
[DllImport("MyLibc.so")] public static extern bool MyLib_DisplayName(string name);

public static void Main(string[] args)
{
string name = MyLib_GetName();
MyLib_SetName(name);
MyLib_DisplayName(name);
}