Вопрос по c#-4.0, c, interop – Можно ли вызвать функцию C из C # .Net

47

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

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

Мой код C -

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

Мой CPP Wrapper -

long MyClass::ConnectSessionWrapper(unsigned long handle,
                                unsigned char * publicKey,
                                unsigned char   publicKeyLen)
    {
        return ConnectSession(handle, publicKey, publicKeyLen);
    }
Пожалуйста, оставьте свой код. Jack
Смотреть вPInvoke Mark Hall
да, это возможно, и есть много примеров, если вы гуглите это, но не представляете, в чем ваша проблема, из ограниченной информации Keith Nicholas
В: Можно ли вызвать функцию C из C # .Net? A: Да, очевидно! Q: Является ли оболочка C ++ / CLI подходящим способом? Лично я считаю C ++ / CLI мерзостью. Но люди используют это в сценариях, как это. Я бы предпочел использовать Interop напрямую (т.е. PInvoke) - все на C #, вплоть до нативного, неуправляемого C / C ++. Есть много учебных пособий, и этоnot сложно. Конечно, не сложнее, чем вызывать C / C ++ из VB6;) ИМХО .. paulsm4
Если вам больно, когда вы делаете X, прекратите делать X. Переименуйте ваш метод-оболочку C ++, чтобы исключить это как источник проблемы. И разместите свой код :-) Eric J.

Ваш Ответ

3   ответа
3

File -> New -> Project -> Visual C++ -> Win32 -> Win32 Project и дать ему имя (HelloWorldDll в моем случае), затем в окне, которое следует подApplication Type выбирать'DLL' и подAdditonal Options выбирать'Empty Project'.

Теперь иди в свойSolution Explorer вкладка обычно справа от окна VS, щелкните правой кнопкой мышиSource Files -> Add Item -> C++ file (.cpp) и дать ему имя (HelloWorld в моем случае)

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

#include <stdio.h>

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

СейчасBuild проект, после перехода к вашим проектамDEBUG папку и там вы должны найти:HelloWorldDll.dll.

Теперь давайте создадим наше приложение на C #, которое получит доступ к DLL, GotoFile -> New -> Project -> Visual C# -> Console Application и дайте ему имя (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) в том же каталоге, и выполнять вывод приложения следует

This is C# program

Hello from DLL !

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

References:

How to create a DLL library in C and then use it with C#
Я не смог скомпилировать программу на C #, потому что мой проект не может найти файл DLL. Поэтому я использовал полный путь в выражении DllImport:[DllImport("C:\\Users\\...full path...\\HelloWorldDll\\Debug\\HelloWorldDll.dll")]
74

Linux:

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

#include <stdio.h>

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

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

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 по стандартному пути библиотеки, например & # x201C; / usr / lib & # x201D ;, вы, скорее всего, увидите исключение System.DllNotFoundException, чтобы исправить это, вы можете переместить ваш libtest.so в / usr / lib или, что еще лучше, просто добавьте CWD в путь к библиотеке:export LD_LIBRARY_PATH=pwd

кредиты отВот

EDIT

ЗаWindowsэто не сильно отличается. Взяв пример изВот, у тебя есть только твое*.cpp подать ваш метод сextern "C" Что-то вроде

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

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

[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);
            }
    }
Может ли кто-нибудь отредактировать ответ? У меня проблемы с включением, не показывает stdio.h
@ paulsm4 спасибо за редактирование !!
Хороший пример! Это очень хороший пример использования Interop. Это, очевидно, Linux (не Windows), но принцип тот же. ЭтоEXACTLY подход, который я рекомендую ФП.
@Chinjoo рассмотреть этоcodeproject.com/Articles/6912/…, Вы изменили свой код C, добавив _declspec (dllexport)? Если этот пример работает для вас, я добавлю его в ответ
думаю, что это должно работать .. но не знаю, как получить выходные данные как .so из vs2010 .. он дает только .lib и .dll, опять же .dll, когда установлен как dllimport при неправильном исключении формата Chinjoo
22

UPDATE - Feb 22 2019: Поскольку этот ответ получил довольно много голосов, я решил обновить его, чтобы лучше вызывать метод Си. Ранее я предлагал использоватьunsafe код, но безопасный и правильный способ заключается в использованииMarshalAs атрибут для преобразования .NETstring кchar*, Кроме того, в VS2017 больше нет проекта Win32, вам, вероятно, придется создать dll или пустой проект Visual C ++ и изменить его. Спасибо!

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

Create a new C# Library project (I'll call it "Wrapper")

Add a Win32 project to the solution, set application type to: DLL (I'll call it "CLibrary")

You can remove all the other cpp/h files since we won't need them Rename the CLibrary.cpp file to CLibrary.c Add a CLibrary.h header file

Now we need to configure the CLibrary project, right-click it and go to properties, and select Configuration: "All Configurations"

In Configuration Properties > C/C++ > Precompiled headers, set Precompiled Headers to: "Not using Precompiled Headers" In the same C/C++ branch, go to Advanced, change Compile As to: "Compile as C code (/TC)" Now in the Linker branch, go to General, and change Output File to: "$(SolutionDir)Wrapper\$(ProjectName).dll", this will copy the built C DLL to the C# project root.

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;
}
Right-click CLibrary project, build it, so we get the DLL in the C# project directory Right-click C# Wrapper project, add existing item, add CLibrary.dll Click on CLibrary.dll, go to the properties pane, set "Copy to output Directory" to "Copy Always"

Хорошей идеей будет сделать проект 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

Это сработало для меня, но мне также пришлось изменить свой проект .NETProperties->Build->Platform Target вx64.

Похожие вопросы