Здравствуйте, syomin, Вы писали:
S>А что делать в случае, когда нужна обёртка для неправляемого ресурса, который имеет тип, отличный от IntPtr? К примеру, ulong?
JR>Для "подробней", я думаю, сначала Вам стоит более детально описать ситуацию.
Да запросто. Есть DLL'ка, в ней есть функция вида:
unsigned long create_foo();
Внутри функция создаёт некий ресурс и возвращает его дескриптор. Как только ресурс перестанет быть нужен, он должен быть освобожден с помощью функции:
void destroy_foo(unsigned long foo);
Для хранения дескриптора неуправляемого ресурса в .Net есть класс SafeHandle, который гарантирует корректное освобождение во всяких специфических ситуациях, но он работает только с IntPtr, размерность которого в 2 раза меньше. Можно ли сделать то же самое для ulong и какой ценой?
Здравствуйте, syomin, Вы писали:
S>Для хранения дескриптора неуправляемого ресурса в .Net есть класс SafeHandle, который гарантирует корректное освобождение во всяких специфических ситуациях, но он работает только с IntPtr, размерность которого в 2 раза меньше. Можно ли сделать то же самое для ulong и какой ценой?
Да запросто Написать своего наследника от CriticalFinalizerObject и реализовать в нём вызов destroy_foo, делов-то
Здравствуйте, syomin, Вы писали:
S>А как организовать маршалинг
Маршалинг куда? long и так можно использовать без проблем и в нативном, и в управляемом коде.
S>и подсчёт ссылок наподобие того, как это сделано в SafeHandle?
А какие ссылки Вы собираетесь считать? Ваш ресурс поддерживает подсчет ссылок? Тогда ему и переадресуйте. Нет? Тогда Вам зачем? Впрочем, при желании можно и целиком в управляемом коде сделать, только есть ли смысл?
Здравствуйте, syomin, Вы писали:
JR>>Для "подробней", я думаю, сначала Вам стоит более детально описать ситуацию. S>Да запросто. Есть DLL'ка, в ней есть функция вида:
S>unsigned long create_foo();
S>Внутри функция создаёт некий ресурс и возвращает его дескриптор. Как только ресурс перестанет быть нужен, он должен быть освобожден с помощью функции:
S>void destroy_foo(unsigned long foo);
S>Для хранения дескриптора неуправляемого ресурса в .Net есть класс SafeHandle, который гарантирует корректное освобождение во всяких специфических ситуациях, но он работает только с IntPtr, размерность которого в 2 раза меньше. Можно ли сделать то же самое для ulong и какой ценой?
А размер этого "unsigned long" точно 64 бита? А не прячется ли там на самом деле указёр? Просто не совсем понятно, зачем понадобилось дестроить обычное число
Help will always be given at Hogwarts to those who ask for it.
_FR>А размер этого "unsigned long" точно 64 бита? А не прячется ли там на самом деле указёр? Просто не совсем понятно, зачем понадобилось дестроить обычное число
Сие великая тайна есть. Библиотека сторонняя и посмотреть, что там происходит внутри нет никакой возможности...
Чисто ради расширения кругозора предположим, что действительно не передаются числа бОльшие, чем IntPtr для данной архитектуры. Тогда в управляемом коде можно использовать наследник от SafeHandle, но как правильно сделать маршалинг? С помощью MarshalAs?
Здравствуйте, syomin, Вы писали:
_FR>>А размер этого "unsigned long" точно 64 бита? А не прячется ли там на самом деле указёр? Просто не совсем понятно, зачем понадобилось дестроить обычное число
S>Сие великая тайна есть. Библиотека сторонняя и посмотреть, что там происходит внутри нет никакой возможности...
На счёт указателя понятно, но на счёт размера-то вы обязаны знать! Почему вы говорите, что "он работает только с IntPtr, размерность которого в 2 раза меньше"? Поскольку "размерность" IntPtr на разных платформах разная, смысл этого высказывания совсем не ясен. А библиотека ваша строго 32х-битная или имеется и 64х-битная версия? Проблема имеет место быть только если ваша библиотека возвращает именно 64х-битное (что сомнительно, если судить про прототипу) значение вне зависимости от платформы. В других случаях можно пользоваться SafeHandle.
S>Чисто ради расширения кругозора предположим, что действительно не передаются числа бОльшие, чем IntPtr для данной архитектуры. Тогда в управляемом коде можно использовать наследник от SafeHandle, …
Тогда не нужно "использовать наследник от SafeHandle", …
S>…но как правильно сделать маршалинг? С помощью MarshalAs?
…а надо самому выписать всё необходимое. Вы уверены, что вам необходим подсчёт ссылок, реализованный в SafeHandle?
Help will always be given at Hogwarts to those who ask for it.
_FR>На счёт указателя понятно, но на счёт размера-то вы обязаны знать! Почему вы говорите, что "он работает только с IntPtr, размерность которого в 2 раза меньше"? Поскольку "размерность" IntPtr на разных платформах разная, смысл этого высказывания совсем не ясен. А библиотека ваша строго 32х-битная или имеется и 64х-битная версия? Проблема имеет место быть только если ваша библиотека возвращает именно 64х-битное (что сомнительно, если судить про прототипу) значение вне зависимости от платформы. В других случаях можно пользоваться SafeHandle.
Сейчас платформа 32-битная. Дескриптор возвращается 64-битный, сейчас специально проверил: отличны от 0 как старшие 4 байта, так и младшие.
_FR>…а надо самому выписать всё необходимое. Вы уверены, что вам необходим подсчёт ссылок, реализованный в SafeHandle?
Не уверен. Точнее, мне-то он совсем не нужен, но книжка Рихтера утверждает, что это сделано из соображений безопасности. Правда каких — я так и не понял.
Для простоты предположим, что я просто делаю класс, который является прямым наследником CriticalFinalizerObject. Как сделать так, чтобы внешний (extern) метод create_foo() вместо ulong возвращал экземпляр этого класса?
Здравствуйте, syomin, Вы писали: S>А что делать в случае, когда нужна обёртка для неправляемого ресурса, который имеет тип, отличный от IntPtr? К примеру, ulong?
SafeHandle Class
Represents a wrapper class for operating system handles.
Он использует IntPtr, который 32 бита для 32битной ос и 64 бита для 64битной. А ulong который возвращается из сторонней библиотеки не имеет прямого отношения к operating system handles (МОЕ ИМХО). Конечно возможно, что эта либа косвенно и мапит этот ulong на какой-то OS handle.
А мысль моя, что достаточно обернуть это дело обычным IDisposable объектом. Где в методе Dispose вызывать тот самый библиотечный метод, куда и передавать этот ulong для уничтожения ...
Здравствуйте, syomin, Вы писали:
S>Для простоты предположим, что я просто делаю класс, который является прямым наследником CriticalFinalizerObject. Как сделать так, чтобы внешний (extern) метод create_foo() вместо ulong возвращал экземпляр этого класса?
Боюсь, для этого Вам придётся устроиться в Microsoft и переписать компилятор C# Буду рад ошибиться, но похоже на то, что для типов вроде SafeHandle, StringBuilder в компилятор "вшито" специальное поведение, compile magic.
Но ведь это и не обязательно, верно? Можно ведь в свой потомок CriticalFinalizerObject добавить статический метод-фабрику, который будет вызывать эту самую create_foo(), а её результат "упаковывать" в экземпляр этого класа, который и возвращать. То на то и выйдет.
JR>Но ведь это и не обязательно, верно? Можно ведь в свой потомок CriticalFinalizerObject добавить статический метод-фабрику, который будет вызывать эту самую create_foo(), а её результат "упаковывать" в экземпляр этого класа, который и возвращать. То на то и выйдет.
Не спортивно.
Я так понимаю, что можно сделать свой собственный marshal'ер, он почему-то именно для сreate_foo(), которая на самом деле принимает ещё несколько аргументов, он не работает
Здравствуйте, syomin, Вы писали:
S>Я так понимаю, что можно сделать свой собственный marshal'ер, он почему-то именно для сreate_foo(), которая на самом деле принимает ещё несколько аргументов, он не работает
Покажи как "свой собственный marshal'ер" сделан и как используется.
Help will always be given at Hogwarts to those who ask for it.
Здравствуйте, _FRED_, Вы писали:
_FR>Здравствуйте, syomin, Вы писали:
S>>Я так понимаю, что можно сделать свой собственный marshal'ер, он почему-то именно для сreate_foo(), которая на самом деле принимает ещё несколько аргументов, он не работает
_FR>Покажи как "свой собственный marshal'ер" сделан и как используется.
Здравствуйте, _FRED_, Вы писали:
_FR>Здравствуйте, syomin, Вы писали:
S>>Я так понимаю, что можно сделать свой собственный marshal'ер, он почему-то именно для сreate_foo(), которая на самом деле принимает ещё несколько аргументов, он не работает
_FR>Покажи как "свой собственный marshal'ер" сделан и как используется.
public class HDSchedulerHandle : CriticalFinalizerObject
{
~HDSchedulerHandle()
{
hdUnschedule(_handle);
}
private ulong _handle;
}
public class HDSchedulerHandleMarshaler : ICustomMarshaler
{
public void CleanUpManagedData(object ManagedObj) { }
public void CleanUpNativeData(IntPtr pNativeData) { }
public int GetNativeDataSize()
{
return sizeof(ulong);
}
public IntPtr MarshalManagedToNative(object ManagedObj)
{
return IntPtr.Zero;
}
public object MarshalNativeToManaged(IntPtr pNativeData)
{
return new HDSchedulerHandle();
}
public static ICustomMarshaler GetInstance(string cookie)
{
return _instance;
}
private static HDSchedulerHandleMarshaler _instance =
new HDSchedulerHandleMarshaler();
}
[DllImport("hd.dll")]
[return: MarshalAs(UnmanagedType.CustomMarshaler, MarshalTypeRef = typeof(HDSchedulerHandleMarshaler))]
public static extern HDSchedulerHandleMarshaler
hdScheduleAsynchronous(uint callback,
uint data,
ushort priority);
Я поставил точки останова на всех методах в классе HDSchedulerHandleMarshaler. Метод GetInstance() вызывается, а потом управление передается сразу коду, вызвавшему hdScheduleAsynchronous(), который возвращает null.
internal static class NativeMethods
{
/// <summary>
/// Scheduler's callback handle.
/// </summary>public class HDSchedulerHandle : CriticalFinalizerObject
{
~HDSchedulerHandle()
{
hdUnschedule(_handle);
}
private ulong _handle;
}
public class HDSchedulerHandleMarshaler : ICustomMarshaler
{
public void CleanUpManagedData(object ManagedObj) { }
public void CleanUpNativeData(IntPtr pNativeData) { }
public int GetNativeDataSize()
{
return sizeof(ulong);
}
public IntPtr MarshalManagedToNative(object ManagedObj)
{
return IntPtr.Zero;
}
public object MarshalNativeToManaged(IntPtr pNativeData)
{
return new HDSchedulerHandle();
}
public static ICustomMarshaler GetInstance(string cookie)
{
return _instance;
}
private static HDSchedulerHandleMarshaler _instance =
new HDSchedulerHandleMarshaler();
}
public delegate uint HDSchedulerCallback(IntPtr data);
[DllImport("hd.dll")]
[return: MarshalAs(UnmanagedType.CustomMarshaler,
MarshalTypeRef = typeof(HDSchedulerHandleMarshaler))]
public static extern object
hdScheduleAsynchronous(HDSchedulerCallback callback,
IntPtr data,
ushort priority);
}
А вот так происходит вызов:
var callbackHandle =
NativeMethods.hdScheduleAsynchronous(
DoAll, // Некий метод.
(IntPtr)GCHandle.Alloc(this),
NativeMethods.HD_DEFAULT_SCHEDULER_PRIORITY);
В результате callbackHandle равен 0. Отладчиком установил точки останова на всех методах класса HDSchedulerHandleMarshaler, так отрабатывает только метод GetInstance, а MarshalNativeToManaged() даже не вызывается.