Я пишу это в надежде на то, что Дэвид Heffernan исправит меня и научи меня что-то :-)
Как я уже писал в комментариях:
Мой вопрос состоит в : возможно ли хранить ссылку на управляемый объект в родной DLL (без использования CLI/CLR)
На некотором уровне вы должны сообщить CLR, что вы не хотите, чтобы объект был собран , Вы можете сохранить ссылку в статическом свойстве, вы можете напрямую связать ее с GCHandle
, вы можете использовать COM, но, правда, вам нужно сообщить CLR.
Использование COM-объектов является сложным (по крайней мере, для меня :-)).
Что бы я сделал:
Учитывая MyClass
, с объектом, созданным C# -side с DoSomething
метод, который я хочу использовать как C# и C++ сторону.
public class MyClass
{
public string Name;
public string Surname;
public bool DoSomething(int value1, int value2)
{
return Name.Length == value1 || Surname.Length == value2;
}
}
Я хотел бы создать MyProxyClass
вроде этого:
public class MyProxyClass
{
private delegate void FreeMeDelegate();
[return:MarshalAs(UnmanagedType.I1)]
private delegate bool DoSomethingDelegate(int value1, int value2);
private GCHandle Handle;
private DoSomethingDelegate DoSomething { get; set; }
// You pass this function pointer to C++. Its signature is:
// bool(__stdcall *DoSomething)(int32_t, int32_t)
public IntPtr DoSomethingPtr { get; private set; }
private FreeMeDelegate FreeMe { get; set; }
// You have to pass this function too to C++. C++ code must use it
// to free MyProxyClass. Its signature is:
// void (__stdcall *FreeMe)(void)
public IntPtr FreeMePtr { get; private set; }
public void FreeMeImpl()
{
if (Handle.IsAllocated)
{
Handle.Free();
DoSomething = null;
DoSomethingPtr = IntPtr.Zero;
FreeMe = null;
FreeMePtr = IntPtr.Zero;
}
}
public MyProxyClass(MyClass obj)
{
Handle = GCHandle.Alloc(this, GCHandleType.Normal);
// This will implicitly create a reference to obj. GC can't
// collect MyProxyClass because we have a GCHandle on it,
// and can't collect obj because there is a delegate that
// has a reference on it.
DoSomething = obj.DoSomething;
DoSomethingPtr = Marshal.GetFunctionPointerForDelegate(DoSomething);
FreeMe = FreeMeImpl;
FreeMePtr = Marshal.GetFunctionPointerForDelegate(FreeMe);
}
}
Этот класс при создании автоматически останавливает GC собирать ее. Затем создает делегатов методу DoSomething
и к методу FreeMe
, который должен использовать код C++ для его освобождения.
Теперь, C# -side:
MyClass myclass = ...; // you instance of myclass
var proxy = new MyProxyClass(myclass);
// Now you pass these to C++
//proxy.DoSomethingPtr;
//proxy.FreeMePtr;
COM является чистым способом осуществить это –
* Мой вопрос: можно ли сохранить ссылку на управляемый объект в родной DLL (без использования CLI/CLR) * На некотором уровне вы должны сообщить CLR, что вы не хотите, чтобы объект был собран. Вы можете сохранить ссылку в статическом свойстве, вы можете напрямую связать ее с GCHandle, вы можете использовать COM, но, правда, вам нужно сообщить CLR. – xanatos
Не является ли CLR своего рода расширением C++? Является ли это частью C#? Без CLI/CLR я подразумевал, что хочу использовать стандартный C++, а не расширенный C++ MS. – Virus721