C# (シーシャープ) は .NET 環境で動作するオブジェクト指向言語です。型安全で例外処理が充実しており、Java に似た構文を持ちます。P/Invoke (Platform Invocation Services) は .NET アプリケーションから C/C++ などで書かれたネイティブコード (DLL) を呼び出す仕組みです。
このリポジトリの prod/calc.net/ は C ライブラリ(libcalc)を .NET から利用するための実装例です。prod/calc.net/libsrc/CalcLib/Internal/NativeMethods.cs で [DllImport] 属性を使った P/Invoke 定義を行い、CalcLibrary.cs がこれをラップして .NET らしいインターフェース (例外・型安全・CalcResult クラス) を提供します。CalcApp がこのライブラリを使うサンプルアプリです。
C 言語開発者が .NET 連携を理解するには、C# の基礎に加えて P/Invoke の仕組みを習得することが重要です。
P/Invoke 定義 (prod/calc.net/libsrc/CalcLib/Internal/NativeMethods.cs) の概要:
using System.Runtime.InteropServices;
namespace CalcLib.Internal;
internal static class NativeMethods
{
// C 関数: int calcHandler(int kind, int a, int b, int *result)
[DllImport("libcalc", CallingConvention = CallingConvention.Cdecl)]
internal static extern int calcHandler(int kind, int a, int b, out int result);
}C# ラッパー (prod/calc.net/libsrc/CalcLib/CalcLibrary.cs) の概要:
namespace CalcLib;
public class CalcLibrary
{
public CalcResult Calculate(CalcKind kind, int a, int b)
{
int nativeResult;
int status = Internal.NativeMethods.calcHandler((int)kind, a, b, out nativeResult);
if (status != 0)
{
throw new CalcException($"計算エラー: status={status}");
}
return new CalcResult(nativeResult);
}
}ネイティブライブラリのロード設定 (prod/calc.net/src/CalcApp/ModuleInitializer.cs):
using System.Runtime.CompilerServices;
using System.Runtime.InteropServices;
namespace CalcApp;
internal static class ModuleInitializer
{
[ModuleInitializer]
internal static void Initialize()
{
// libcalc の検索パスを設定
NativeLibrary.SetDllImportResolver(
typeof(CalcLib.CalcLibrary).Assembly,
DllImportResolver);
}
// ...
}CalcLib のファイル構成:
prod/calc.net/libsrc/CalcLib/
+-- CalcLibrary.cs # メインライブラリクラス
+-- CalcKind.cs # 計算種別の列挙型
+-- CalcResult.cs # 計算結果クラス
+-- CalcException.cs # カスタム例外クラス
+-- Internal/
+-- NativeMethods.cs # P/Invoke 定義