Используя Microsoft Visual C# 2010, я недавно заметил, что вы можете передавать объекты по ссылке на неуправляемый код. Поэтому я поставил себе задачу написать некоторый неуправляемый код, который преобразует символ C++ в строку C#, используя обратный вызов управляемого кода. Я сделал две попытки.Насколько безопасен 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: Pass строка исх неуправляемой функции, которая передает строку реф на управляемом обратный вызов.
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) в неуправляемом коде?
Небезопасный код называется «небезопасным» по какой-либо причине ... он небезопасен. :) – Almo