How safe is ref when used with unsafe code?

Using Microsoft Visual C # 2010, I recently noticed that you can pass objects by reference to unmanaged code. So I set myself the task of writing some unmanaged code that converts C ++ char * to a C # string using a managed code callback. I made two attempts.

Attempt 1: Call an unmanaged function in which the ref parameter is stored. Then, as soon as this function returns to the managed code, call another unmanaged function that calls the callback function, which converts char * to a managed string.

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);
}

Attempt 2: Passing the ref string to an unmanaged function that passes the ref string to a managed callback.

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) ?

+4
1

, p/invoke, Q & A. :

. p/invoke , , , , .

p/invoke . , . , , .

, . , p/invoke , ref . , p/invoke , - - ref.


:

  • "" . , - , # "" , unsafe. , unsafe.
  • , , . , p/invoke , , -. , p/invoked, , , ( ), . , GC.KeepAlive() , . (, , GC.Collect() StoreCallback() , ).
+1
source

Source: https://habr.com/ru/post/1624374/


All Articles