使用Microsoft Visual C# 2010,我最近发现您可以通过ref将对象传递给非托管代码。因此,我尝试编写一些非托管代码,使用回调到托管代码来将C++ char*转换为C#字符串。我进行了两次尝试。
尝试1:调用存储ref参数的非托管函数。然后,在该函数返回到托管代码后,调用另一个非托管函数,该函数调用回调函数将char*转换为托管字符串。
尝试2:将字符串引用传递给不受管理的函数,该函数将字符串引用传递给托管回调函数。
尝试1无效,但尝试2有效。在尝试1中,似乎在非托管代码存储完ref之后立即返回后,该ref就变得无效了。为什么会这样?
鉴于尝试1的结果,我对尝试2的可靠性存在疑虑。因此,在与非托管代码一起使用时,ref在非托管代码方面有多安全?换句话说,当在非托管代码中使用ref时,哪些功能将无法正常工作?
我想知道的内容包括:
当使用ref将对象传递给非托管代码时会发生什么?
它是否保证对象在ref在非托管代码中被使用时会留在其当前内存位置?
在非托管代码中,ref的限制是什么(我不能使用ref做什么)?
尝试1:调用存储ref参数的非托管函数。然后,在该函数返回到托管代码后,调用另一个非托管函数,该函数调用回调函数将char*转换为托管字符串。
C++
typedef void (_stdcall* CallbackFunc)(void* ManagedString, char* UnmanagedString);
CallbackFunc UnmanagedToManaged = 0;
void* ManagedString = 0;
extern "C" __declspec(dllexport) void __stdcall StoreCallback(CallbackFunc X) {
UnmanagedToManaged = X;
}
extern "C" __declspec(dllexport) void __stdcall StoreManagedStringRef(void* X) {
ManagedString = X;
}
extern "C" __declspec(dllexport) void __stdcall CallCallback() {
UnmanagedToManaged(ManagedString, "This is an unmanaged string produced by unmanaged code");
}
C#
[DllImport("Name.dll", CallingConvention = CallingConvention.StdCall)]
public static extern void StoreCallback(CallbackFunc X);
[DllImport("Name.dll", CallingConvention = CallingConvention.StdCall)]
public static extern void StoreManagedStringRef(ref string X);
[DllImport("Name.dll", CallingConvention = CallingConvention.StdCall)]
public static extern void CallCallback();
[UnmanagedFunctionPointer(CallingConvention.StdCall)]
public delegate void CallbackFunc(ref string Managed, IntPtr Native);
static void Main(string[] args) {
string a = "This string should be replaced";
StoreCallback(UnmanagedToManaged);
StoreManagedStringRef(ref a);
CallCallback();
}
static void UnmanagedToManaged(ref string Managed, IntPtr Unmanaged) {
Managed = Marshal.PtrToStringAnsi(Unmanaged);
}
尝试2:将字符串引用传递给不受管理的函数,该函数将字符串引用传递给托管回调函数。
C++
typedef void (_stdcall* CallbackFunc)(void* ManagedString, char* UnmanagedString);
CallbackFunc UnmanagedToManaged = 0;
extern "C" __declspec(dllexport) void __stdcall StoreCallback(CallbackFunc X) {
UnmanagedToManaged = X;
}
extern "C" __declspec(dllexport) void __stdcall DoEverything(void* X) {
UnmanagedToManaged(X, "This is an unmanaged string produced by unmanaged code");
}
C#
[DllImport("Name.dll", CallingConvention = CallingConvention.StdCall)]
public static extern void StoreCallback(CallbackFunc X);
[DllImport("Name.dll", CallingConvention = CallingConvention.StdCall)]
public static extern void DoEverything(ref string X);
[UnmanagedFunctionPointer(CallingConvention.StdCall)]
public delegate void CallbackFunc(ref string Managed, IntPtr Unmanaged);
static void Main(string[] args) {
string a = "This string should be replaced";
StoreCallback(UnmanagedToManaged);
DoEverything(ref a);
}
static void UnmanagedToManaged(ref string Managed, IntPtr Unmanaged) {
Managed = Marshal.PtrToStringAnsi(Unmanaged);
}
尝试1无效,但尝试2有效。在尝试1中,似乎在非托管代码存储完ref之后立即返回后,该ref就变得无效了。为什么会这样?
鉴于尝试1的结果,我对尝试2的可靠性存在疑虑。因此,在与非托管代码一起使用时,ref在非托管代码方面有多安全?换句话说,当在非托管代码中使用ref时,哪些功能将无法正常工作?
我想知道的内容包括:
当使用ref将对象传递给非托管代码时会发生什么?
它是否保证对象在ref在非托管代码中被使用时会留在其当前内存位置?
在非托管代码中,ref的限制是什么(我不能使用ref做什么)?