錯誤地址:0x66fab3fc,線程:0x31b8,錯誤代碼:0xc0000005
此錯誤可能是 CLR 中的 bug,或者是用戶代碼的不安全部分中的 bug。
常見來源:COM-interop 或 PInvoke 的封送處理錯誤,可能損壞堆棧。
// C++ 聲明
int __stdcall Dcrf_ReadCard(char *S); // 讀卡
// C# 錯誤聲明
[DllImport("LsdDcrf.dll", CallingConvention = CallingConvention.StdCall)]
public extern static int Dcrf_ReadCard(ref String Str);
// 調用代碼
String str = "";
CardRead.Dcrf_ReadCard(ref str);
lab.Text = str.ToString();
C# String 是不可變的引用類型,默認封送為 LPWStr(雙字節寬字符指針),而 C++ 期望的是 char*(單字節 ANSI 指針)。
當使用 ref String 時:
由於編碼不匹配(ANSI vs Unicode)且非托管代碼可能寫入超出預期長度,導致堆棧損壞,觸發 0xc0000005 訪問違規。
[DllImport("LsdDcrf.dll", CallingConvention = CallingConvention.StdCall, CharSet = CharSet.Ansi)]
public static extern int Dcrf_ReadCard(StringBuilder sb);
// 調用
StringBuilder sb = new StringBuilder(256); // 預分配足夠緩衝區
int result = Dcrf_ReadCard(sb);
lab.Text = sb.ToString();
[DllImport("LsdDcrf.dll", CallingConvention = CallingConvention.StdCall)]
public static extern int Dcrf_ReadCard(byte[] buffer, int bufferSize);
// 調用
byte[] buffer = new byte[256];
int result = Dcrf_ReadCard(buffer, buffer.Length);
string str = System.Text.Encoding.Default.GetString(buffer).TrimEnd('\0');
lab.Text = str;
[DllImport("LsdDcrf.dll", CallingConvention = CallingConvention.StdCall, CharSet = CharSet.Ansi)]
public static extern int Dcrf_ReadCard([Out] StringBuilder sb);
// 或
[DllImport("LsdDcrf.dll", CallingConvention = CallingConvention.StdCall, CharSet = CharSet.Ansi)]
public static extern int Dcrf_ReadCard(out string str); // 需 C++ 端配合 CoTaskMemAlloc
| 屬性 | 作用 |
|---|---|
CharSet = CharSet.Ansi | 指定封送為單字節 ANSI,匹配 C++ char* |
[Out] | 標記為輸出參數,CLR 只在返回時封送回托管端 |
StringBuilder | 可變緩衝區,安全接收非托管寫入 |
Marshal.PtrToStringAnsi 手動轉換 IntPtr 驗證數據永遠不要用 `ref string` 接收非托管輸出字符串。改用 StringBuilder + CharSet.Ansi 是最穩健、最符合 .NET 互操作規範的做法。