// 標頭檔
#define LIBEXPORT_API extern "C" __declspec(dllexport)
// 範例函數
LIBEXPORT_API int MySum(int a, int b) { return a + b; }
LIBEXPORT_API char* MyStrCopy(char* dest, const char* src) { strcpy(dest, src); return dest; }
LIBEXPORT_API int MyAdd(int a, int b, int* result) { *result = a + b; return *result; }
關鍵:extern "C" 禁用 C++ Name Mangling,確保匯出符號為純函數名。
| C++ 宣告 | C# 簽章 | 關鍵點 |
|---|---|---|
int MySum(int, int) | [DllImport] static extern int MySum(int a, int b); | 基本型別直接對應 |
char* MyStrCopy(char* dest, const char* src) | [DllImport(CharSet=CharSet.Ansi)] static extern string MyStrCopy(StringBuilder dest, string src); | CharSet.Ansi 對應 char*;StringBuilder 作為可變輸出緩衝區;避免 ref string (不可變導致編組錯誤) |
int MyAdd(int, int, int* result) | [DllImport] static extern int MyAdd(int a, int b, ref int result); | ref int 對應輸出指標;不可用 out (需初始化) |
void ComplexFunc(MyStruct* p) | [DllImport] static extern void ComplexFunc(ref MyStruct s); | 結構體 [StructLayout(LayoutKind.Sequential, Pack=4)] + ref 傳址 |
CharSet.Ansi 或 Unicode (對應 C++ char*/wchar_t*),不可用 ref stringint* → ref int (需預設值);雙重指標 int** → ref IntPtr + Marshal.AllocHGlobalStdCall (預設);C++ 預設 Cdecl → 明確指定 CallingConvention.CdeclAnsi→FuncA,Unicode→FuncW,Auto→平台相關[StructLayout(LayoutKind.Sequential, Pack=4)] 與 C++ #pragma pack(4) 對應;bool 在 C++ 為 1 位元組,C# 預設 4 位元組 → 需 [MarshalAs(UnmanagedType.U1)]
// C++ 原型: int EncryptData(const char* input, int inLen, char* output, int* outLen);
[DllImport("CryptoLib.dll", CallingConvention = CallingConvention.Cdecl, CharSet = CharSet.Ansi)]
private static extern int EncryptData(string input, int inLen, StringBuilder output, ref int outLen);
public string Encrypt(string plainText)
{
byte[] inputBytes = Encoding.ASCII.GetBytes(plainText);
int maxOut = inputBytes.Length * 2 + 16; // 預估緩衝區
var sb = new StringBuilder(maxOut);
int outLen = maxOut;
int ret = EncryptData(plainText, plainText.Length, sb, ref outLen);
if (ret != 0) throw new Exception($"加密失敗,錯誤碼: {ret}");
return sb.ToString(0, outLen);
}
MarshalUsing 自訂編組