最近は新規Windowsアプリ開発はC#でやるようになった。だけど、「既存のC/C++ライブラリ使い回す代わりに工数減らして」と発注元から要求されたり、サードパーティから購入したC言語DLLの商用ライブラリをリンクしないといけなかったりと、いまだにC/C++との連携は避けられない。
というわけで、C#からC/C++のDLL関数を呼び出す手順を覚え書きとして記しておく。
サンプルコード
以下のような簡単なテスト関数をC++で書いてDLLをビルドした。このDLLの関数をC#のテストアプリから呼び出してみる。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 |
#include "stdafx.h" #include <stdio.h> #include <string.h> #include "CppDLL.h" extern "C" { // No argument CPPDLL_API int func1() { return 11; } // Passes values CPPDLL_API int func2(int a, int b) { return a + b; } // Passes values and receives a value CPPDLL_API int func3(int a, int b, int* c) { *c = a + b; return 33; } // Passes a fixed-length string CPPDLL_API int func4(const char* psz) { printf("%s\n", psz); return 44; } // Receives a string CPPDLL_API int func5(char* psz, int len) { strcpy_s(psz, len, "Oh my goodness!"); return 55; } // Passes a structure CPPDLL_API int func6(Data* data) { data->i3 = data->i1 + data->i2; data->u3 = data->u1 + data->u2; data->c3 = data->c1 + data->c2; strcpy_s(data->sz3, 64, data->sz1); strcat_s(data->sz3, 64, data->sz2); return 66; } } // extern "C" |
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 |
#pragma once extern "C" { #ifdef CPPDLL_EXPORTS #define CPPDLL_API __declspec(dllexport) #else #define CPPDLL_API __declspec(dllimport) #endif CPPDLL_API int func1(); CPPDLL_API int func2(int a, int b); CPPDLL_API int func3(int a, int b, int* c); CPPDLL_API int func4(const char* psz); CPPDLL_API int func5(char* psz, int len); typedef struct _Data { int i1; int i2; int i3; unsigned short u1; unsigned short u2; unsigned short u3; unsigned char c1; unsigned char c2; unsigned char c3; char sz1[32]; char sz2[32]; char sz3[64]; } Data; CPPDLL_API int func6(Data* data); } // extern "C" |
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 |
using System; using System.Collections.Generic; using System.Linq; using System.Text; using System.Threading.Tasks; using System.Runtime.InteropServices; using System.Diagnostics; namespace TestDLLCSharp { class Program { [DllImport("CppDLL.dll", CallingConvention = CallingConvention.Cdecl)] public static extern int func1(); [DllImport("CppDLL.dll", CallingConvention = CallingConvention.Cdecl)] public static extern int func2(int a, int b); [DllImport("CppDLL.dll", CallingConvention = CallingConvention.Cdecl)] public static extern int func3(int a, int b, ref int c); [DllImport("CppDLL.dll", CallingConvention = CallingConvention.Cdecl)] public static extern int func4(string str); [DllImport("CppDLL.dll", CallingConvention = CallingConvention.Cdecl)] public static extern int func5(StringBuilder sb, int len); [StructLayout(LayoutKind.Sequential, Pack = 1)] public struct DATA { public int i1; public int i2; public int i3; public ushort u1; public ushort u2; public ushort u3; public byte c1; public byte c2; public byte c3; [MarshalAs(UnmanagedType.ByValTStr, SizeConst = 32)] public string sz1; [MarshalAs(UnmanagedType.ByValTStr, SizeConst = 32)] public string sz2; [MarshalAs(UnmanagedType.ByValTStr, SizeConst = 64)] public string sz3; } [DllImport("CppDLL.dll", CallingConvention = CallingConvention.Cdecl)] public static extern int func6(ref DATA data); static void Main(string[] args) { int c = func1(); Console.WriteLine("func1 returned {0}", c); c = func2(12, 10); Console.WriteLine("func2 returned {0}", c); int d = 0; c = func3(13, 11, ref d); Console.WriteLine("func3 returned {0} ({1})", c, d); c = func4("Hello World"); Console.WriteLine("func4 returned {0}", c); StringBuilder sb = new StringBuilder(512); c = func5(sb, 512); Console.WriteLine("func5 returned {0} ({1})", c, sb); DATA data = new DATA(); data.i1 = 25; data.i2 = 27; data.i3 = 0; data.u1 = 15; data.u2 = 17; data.u3 = 0; data.c1 = 5; data.c2 = 7; data.c3 = 0; data.sz1 = "HELLO+"; data.sz2 = "WORLD"; data.sz3 = ""; c = func6(ref data); Console.WriteLine("func6 returned {0}", c); Console.WriteLine("data.i3 = {0}", data.i3); Console.WriteLine("data.u3 = {0}", data.u3); Console.WriteLine("data.c3 = {0}", data.c3); Console.WriteLine("data.sz3 = {0}", data.sz3); Console.WriteLine("done!"); } } } /* result func1 returned 11 func2 returned 22 func3 returned 33 (24) Hello World func4 returned 44 func5 returned 55 (Oh my goodness!) func6 returned 66 data.i3 = 52 data.u3 = 32 data.c3 = 12 data.sz3 = HELLO+WORLD */ |
参考サイト
チュートリアル: ダイナミック リンク ライブラリの作成と使用 (C++)
http://msdn.microsoft.com/ja-jp/library/ms235636.aspx
pInvokeStackImbalance MDA
http://msdn.microsoft.com/ja-jp/library/0htdy0k3(v=vs.110).aspx