2012-07-04 2 views
1

Я общаюсь с библиотекой сторонних разработчиков, где мне нужно приобрести и освободить неуправляемый ресурс. После некоторого чтения я пришел к выводу, что лучший и «правильный» способ управления ссылкой ресурса был либо в объекте SafeHandle, либо в CriticalHandle.Маршаллинг без знака для SafeHandle

Моя проблема возникает из-за того, что дескрипторы, возвращенные третьей стороной, представляют собой неподписанные короткие числовые значения, а не указатели. Если я укажу MarshalAsAttribute на возвращаемом дескрипторе, я получаю MarshalDirectiveException (CriticalHandles не должен иметь атрибут MarshalAs и не может использоваться в массивах).

Вот то, что я СУЖДЕНИЕ:

  • Marshal ручками в числовом формате и завернуть их в CriticalHandle через Criticalhandle.SetHandle метод. Это позволяет потенциально утечка дескриптора, если возникает исключение между получением ссылки и ее инкапсулированием.
  • Маршал и хранить ручки в их числовом формате. Имейте оснастку типа CriticalFinalizerObject. Это позволяет потенциально утечка дескриптора, если возникает исключение между получением ссылки и ее инкапсулированием.
  • Маршал обрабатывает маркеры SafeHandle как IntPtr (позволяя заполнять квази-мусором наиболее значимые 2 байта). Внесите DangerousGetHandle назад к короткому (отбрасывая наиболее значительные 2 байта мусора) каждый раз, когда мне нужно вызвать собственный метод с помощью SafeHandle. Это предотвратит любые потенциальные утечки рукоятки, но очень громоздки и имеет вид использования грубой силы, чтобы сделать неправильное решение.

Как обращаться с этими «ручками»?

+1

Вы можете сделать SafeHandle работать, если ваш собственный код 32-бит. Короткий аргумент всегда получает значение int в вызове функции C или C++. IntPtr не будет путать его. –

+0

Это немного успокаивает меня, но это оставляет мне интересно, почему дополнительные данные иногда заполняются в наиболее значимые 2 байта в возвращаемом значении. IE: Иногда верхние 2 байта содержат битовую схему всех 0 и других раз содержат битовую схему 0x0091.Хотя я знаю сценарии, которые приводят к обоим обстоятельствам, я не знаю, что представляют собой дополнительные биты. Возможно, это что-то особенное для моей библиотеки, которое я должен исследовать. Благодарю. –

+0

@ HansPassant Это работало очень хорошо для меня. Можете ли вы опубликовать это как ответ, чтобы я мог принять его? –

ответ

1

Как @HansPassant упоминается в комментарий к моему que stion:

Вы можете сделать SafeHandle работать, если ваш собственный код 32-бит. Короткий аргумент всегда получает повышение до int в вызове функции C или C++. Нельзя путать его. IntPtr. - Ханс Passant 4 июля в 15:10

Поэтому возможно маршал С/С ++ без знака коротких непосредственно в производные SafeHandle.

2

Я думаю, что правильно, что нужно сделать здесь реализовать свою собственную оболочку, подобную SafeHandle (и производной от CriticalFinalizerObject. Затем обернуть вызов вашей P/Invoke метода, который создает дескриптор в constrained execution region для обеспечения управляемой ручки обертка инициализирован

ПРИМЕЧАНИЕ.. Я не должен был использовать CER раньше, поэтому без проверки я могу только надеяться, этот код дает вам отправную точку

[DllImport("blah.dll")] 
private static extern ushort CreateMySpecialHandle(); 

public static SafeSpecial Handle Foo() 
{ 
    SafeSpecialHandle safeHandle = new SafeSpecialHandle(); 
    System.Runtime.CompilerServices.RuntimeHelpers.PrepareConstrainedRegions(); 
    try 
    { 
    } 
    finally 
    { 
     ushort rawHandle = CreateMySpecialHandle(); 
     safeHandle.SetHandle(rawHandle); 
    } 

    if (safeHandle.IsInvalid) 
    { 
     // throw exception here, or other error handling 
    } 

    return safeHandle; 
} 
+0

Я прочитал эту статью, но остался неясным в отношении того, что квалифицируется как исключение вне диапазона. Без этого я не могу определить, существуют ли сценарии, где 'CreateMySpecialhandle()' будет выполнять и получить дескриптор, но не сохранять его в 'SafeHandle'. –

+0

Этот пример, похоже, подкрепляется почти идентичным фрагментом с дополнительной информацией, найденной в MSDN ['RuntimeHelpers.PrepareConstrainedRegions'] (http://msdn.microsoft.com/en-us/library/system.runtime.compilerservices.runtimehelpers .prepareconstrainedregions.aspx). –

Смежные вопросы