80

C ライブラリがあり、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);
    }
4

5 に答える 5

112

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ファイルにメソッドを次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);
            }
    }
于 2012-07-11T03:54:53.657 に答える
39

更新 - 2019 年 2 月 22 日:この回答はかなりの数の支持を得ているため、C メソッドを呼び出すより良い方法で更新することにしました。以前はunsafeコードを使用することを提案しましたが、安全で正しい方法は、属性を使用して .NETをMarshalAs.NET に変換することです。また、VS2017 には Win32 プロジェクトがなくなりました。おそらく、Visual C++ dll または空のプロジェクトを作成して変更する必要があります。ありがとうございました!stringchar*

P/Invoke を使用して、C# から C 関数を直接呼び出すことができます。
これは、C dll をラップする C# ライブラリの作成に関する簡単なハウツーです。

  1. 新しい C# ライブラリ プロジェクトを作成します (「ラッパー」と呼びます)。
  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)」に変更します。
    • Linker ブランチで、General に移動し、Output File を「$(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 を取得します。
  • C# ラッパー プロジェクトを右クリックし、既存の項目を追加し、CLibrary.dll を追加します。
  • CLibrary.dll をクリックし、プロパティ ペインに移動して、[出力ディレクトリにコピー] を [常にコピー] に設定します。

CLibrary が最初にビルドされるように、Wrapper プロジェクトを CLibrary に依存させることをお勧めします。これを行うには、Wrapper プロジェクトを右クリックし、[Project Dependencies] に移動して [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ます。

結果:
コンソール アプリケーションでのラッパー ライブラリのテスト

于 2012-07-21T15:57:42.747 に答える
4

さて、VS 2010 を開き、[ファイル] -> [新規] -> [プロジェクト] -> [Visual C++] -> [Win32] -> [Win32 プロジェクト] に移動し、名前を付けます (私の場合は HelloWorldDll)。次に、[アプリケーションの種類] の下に表示されるウィンドウで[DLL]を選択します。 'を選択し、[追加オプション] で[空のプロジェクト]を選択します。

通常は VS ウィンドウの右側にある [ソリューション エクスプローラー] タブに移動し、[ソース ファイル] -> [項目の追加] -> [C++ ファイル (.cpp) ] を右クリックして名前を付けます(私の場合は HelloWorld)。

次に、新しいクラスに次のコードを貼り付けます。

#include <stdio.h>

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

プロジェクトをビルドします。プロジェクトのDEBUGフォルダーに移動すると、 HelloWorldDll.dllが見つかります。

次に、dll にアクセスする C# アプリを作成し、[ファイル] -> [新規] -> [プロジェクト] -> [Visual C#] -> [コンソール アプリケーション] に移動し、名前 (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) を取得し、アプリケーションの出力を実行します。

これはC#プログラムです

DLLからこんにちは!

あなたの問題のいくつかが解決されることを願っています。

参考文献

于 2012-07-20T20:46:00.737 に答える