Nice programing

C # .Net에서 C 함수를 호출 할 수 있습니까?

nicepro 2021. 1. 6. 20:49
반응형

C # .Net에서 C 함수를 호출 할 수 있습니까?


C lib가 있고 C # 응용 프로그램에서이 라이브러리의 함수를 호출하고 싶습니다. C lib 파일을 링커 입력으로 추가하고 소스 파일을 추가 종속성으로 추가하여 C lib에 C ++ / CLI 래퍼를 만들려고했습니다.

C # 응용 프로그램에 C 출력을 추가하는 방법을 잘 모르기 때문에 이것을 달성하는 더 좋은 방법이 있습니까?

내 C 코드-

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

내 CPP 래퍼-

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

예는 Linux의 경우 다음과 같습니다.

1) 다음 내용으로 C파일을 만듭니다 libtest.c.

#include <stdio.h>

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

이것은 printf에 대한 간단한 의사 래퍼입니다. 그러나 C호출하려는 라이브러리의 모든 함수를 나타냅니다 . C++함수가 있다면 C이름을 엉망으로 만드는 것을 피하기 위해 extern 넣는 것을 잊지 마십시오.

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) "/ usr / lib"와 같은 표준 라이브러리 경로에 libtest.so 라이브러리가없는 경우 System.DllNotFoundException이 표시 될 수 있습니다.이 문제를 해결하려면 libtest.so를 / usr / lib로 이동할 수 있습니다. 더 좋은 방법은 라이브러리 경로에 CWD를 추가하는 것입니다. export LD_LIBRARY_PATH=pwd

여기 에서 크레딧

편집하다

들어 윈도우 , 그것은 크게 다르지 않다. 여기 에서 예를 들어 , 당신은 당신의 *.cpp파일에 당신의 방법을 extern "C"Something like

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);
            }
    }

업데이트-2019 년 2 월 22 일 : 이 답변이 많은 찬성 투표를 받았기 때문에 C 메서드를 호출하는 더 나은 방법으로 업데이트하기로 결정했습니다. 이전에는 unsafe코드 사용을 제안 했지만 안전하고 올바른 방법은 MarshalAs.NET string.NET 으로 변환하는 데 속성 을 사용 하는 것 char*입니다. 또한 VS2017에는 더 이상 Win32 프로젝트가 없으므로 Visual C ++ dll 또는 빈 프로젝트를 만들고 수정해야 할 것입니다. 감사합니다!

P / Invoke를 사용하여 C #에서 직접 C 함수를 호출 할 수 있습니다.
다음은 C dll을 감싸는 C # lbrary를 만드는 방법에 대한 간단한 방법입니다.

  1. 새 C # 라이브러리 프로젝트를 만듭니다 ( "래퍼"라고 함).
  2. 솔루션에 Win32 프로젝트를 추가하고 응용 프로그램 유형을 다음으로 설정합니다. DLL ( "CLibrary"라고 함)

    • 다른 모든 cpp / h 파일은 필요하지 않으므로 제거 할 수 있습니다.
    • CLibrary.cpp 파일의 이름을 CLibrary.c로 바꿉니다.
    • CLibrary.h 헤더 파일 추가
  3. 이제 CLibrary 프로젝트를 구성하고 마우스 오른쪽 단추로 클릭하고 속성으로 이동 한 다음 구성 : "모든 구성"을 선택해야합니다.

    • 구성 속성> C / C ++> 미리 컴파일 된 헤더에서 미리 컴파일 된 헤더를 "미리 컴파일 된 헤더를 사용하지 않음"으로 설정합니다.
    • 동일한 C / C ++ 분기에서 고급으로 이동하여 다음으로 컴파일을 "컴파일로 C 코드 (/ TC)"로 변경하십시오.
    • 이제 링커 분기에서 일반으로 이동하여 출력 파일을 "$ (SolutionDir) Wrapper \ $ (ProjectName) .dll"로 변경하면 빌드 된 C DLL이 C # 프로젝트 루트에 복사됩니다.

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 프로젝트를 마우스 오른쪽 버튼으로 클릭하고 빌드하여 C # 프로젝트 디렉터리에 DLL을 가져옵니다.
  • 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"

It's a good idea to make the Wrapper project dependent on CLibrary so CLibrary gets built first, you can do that by right-clicking the Wrapper project, going to "Project Dependencies" and checking "CLibrary". Now for the actual wrapper code:

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);
        }
    }
}

Now just call GetConnectSession, and it should return 42.

Result:
Testing wrapper library in a console application


Okay well, Open VS 2010, Goto File -> New -> Project -> Visual C++ -> Win32 -> Win32 Project and give it a name (HelloWorldDll in my case), Then in the window that follows under Application Type choose 'DLL' and under Additonal Options choose 'Empty Project'.

Now goto your Solution Explorer tab usually right hand side of VS window, right click Source Files -> Add Item -> C++ file (.cpp) and give it a name (HelloWorld in my case)

Then in the new class paste this code:

#include <stdio.h>

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

Now Build the project, after navigate to your projects DEBUG folder and there you should find: HelloWorldDll.dll.

Now, lets create our C# app which will access the dll, Goto File -> New -> Project -> Visual C# -> Console Application and give it a name (CallDllCSharp), now copy and paste this code to your main:

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

and build the program, now that we have both our apps built lets use them, get your *.dll and your .exe (bin/debug/.exe) in the same directory, and execute the application output should be

This is C# program

Hello from DLL !

Hope that clears some of your issues up.

References:


NOTE : BELOW CODE IS FOR MULTIPLE METHODS FROM 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);
}

ReferenceURL : https://stackoverflow.com/questions/11425202/is-it-possible-to-call-a-c-function-from-c-net

반응형