我搜索了 SO 并发现了各种相关问题,其中一些问题的回答基本上是“不要那样做”。
我想调用一些访问各种现有 C++ 代码的非托管 C++ 代码。现有代码可能有各种我想映射到 C# 异常中的错误条件。从在 Java 和 JNI 中做类似的事情来看,似乎有可能有一个委托函数来引发定义的异常,然后可以直接从非托管代码中调用。然后调用看起来像 (csharp)->(unmanaged)->(csharp delegate,throw/set pending exception) 然后返回。
下面的代码似乎工作正常(vs2010,单声道)。我的问题是这种方法有什么问题 - 例如,规范说,在调用非托管代码或线程问题等之后,不能保证异常仍然是“未决”的......
// unmanaged.cpp
#include <cstdio>
#define EXPORT __declspec(dllexport)
#define STDCALL __stdcall
typedef void (STDCALL* raiseExcpFn_t)(const char *);
extern "C" {
// STRUCT ADDED TO TEST CLEANUP
struct Allocated {
int x;
Allocated(int a): x(a) {}
~Allocated() {
printf("--- Deleted allocated stack '%d' ---\n", x);
fflush(stdout);
}
};
static raiseExcpFn_t exceptionRaiser = 0;
EXPORT void STDCALL registerRaiseExcpFn(raiseExcpFn_t fun) {
exceptionRaiser = fun;
}
EXPORT void STDCALL hello(const char * x) {
Allocated a0(0);
try {
Allocated a1(1);
printf("1 --- '%s' ---\n", x); fflush(stdout);
(*exceptionRaiser)("Something bad happened!");
printf("2 --- '%s' ---\n", x); fflush(stdout);
} catch (...) {
printf("3 --- '%s' ---\n", x); fflush(stdout);
throw;
}
printf("4 --- '%s' ---\n", x); fflush(stdout);
}
}
// Program.cs
using System;
using System.Runtime.InteropServices;
class Program {
[DllImport("unmanaged.dll")]
public static extern void registerRaiseExcpFn(RaiseException method);
[DllImport("unmanaged.dll")]
public static extern void hello([MarshalAs(UnmanagedType.LPStr)] string m);
public delegate void RaiseException(string s);
public static RaiseException excpfnDelegate =
new RaiseException(RaiseExceptionMessage);
// Static constructor (initializer)
static Program() {
registerRaiseExcpFn(excpfnDelegate);
}
static void RaiseExceptionMessage(String msg) {
throw new ApplicationException(msg);
}
public static void Main(string[] args) {
try {
hello("Hello World!");
} catch (Exception e) {
Console.WriteLine("Exception: " + e.GetType() + ":" + e.Message);
}
}
}
更新:更正了测试和输出,显示单声道和 Windows(带有 /EHsc)泄漏
// Observed output // with Release builds /EHa, VS2010, .Net 3.5 target
//cstest.exe
// --- Deleted allocated stack '0' ---
// --- Deleted allocated stack '1' ---
// 1 --- 'Hello World!' ---
// 3 --- 'Hello World!' ---
// Exception: System.ApplicationException:Something bad happened!
// Observed LEAKING output // with Release builds /EHsc, VS2010, .Net 3.5 target
// cstest.exe
// 1 --- 'Hello World!' ---
// Exception: System.ApplicationException:Something bad happened!
// LEAKING output DYLD_LIBRARY_PATH=`pwd` mono program.exe
// 1 --- 'Hello World!' ---
// Exception: System.ApplicationException:Something bad happened!