Запрос к IUnknown с использованием Marshal.QueryInterface вызвал ошибку FatalExecutionEngineError и разбился QTAgent32.exe

#c# #.net #visual-studio-2010 #c#-4.0 #interop

#c# #.net #visual-studio-2010 #c #-4.0 #взаимодействие

Вопрос:

У меня есть простой тестовый код, подобный этому —

 public void GetHashCodeTest1()
{
    MyComPointer target = new MyComPointer();
    MyComPointerAccessor privateTarget = new MyComPointerAccessor(target);

    privateTarget._pObject = new IntPtr(1);   
    int i = target.GetHashCode();
}
  

чтобы проверить это —

     public override int GetHashCode()
    {
        if (IsEmpty)
            return 0;

        if (_pIUnknown == IntPtr.Zero)
        {
            Guid iUnknownGuid = new Guid("00000000-0000-0000-C000-000000000046");
            Marshal.QueryInterface(_pObject, ref iUnknownGuid, out _pIUnknown); //<--CRASH HERE
        }
        return (int)_pIUnknown;
    }
  

И он разбился при вызове Marshal.QueryInterface и вызвал ошибку FEEE —

Ошибка FatalExecutionEngineError была обнаружена

Сообщение: Среда выполнения обнаружила неустранимую ошибку. Адрес ошибки был 0x5ba46832 в потоке 0x2354. Код ошибки 0xc0000005. Эта ошибка может быть ошибкой в CLR или в небезопасных или не поддающихся проверке частях пользовательского кода. Распространенные источники этой ошибки включают ошибки маршалинга пользователя для COM-interop или PInvoke, которые могут повредить стек.

Это произошло только при запуске в .NET 4.0. Код отлично работает в .NET 2.0.

Я могу исправить проблему, заменив

 Marshal.QueryInterface(_pObject, ref iUnknownGuid, out _pIUnknown);
  

с

 _pIUnknown = Marshal.GetIUnknownForObject(_pObject);
  

Но я понятия не имею, почему. Кто-нибудь может помочь объяснить это?

Комментарии:

1. Первым аргументом QueryInterface() должен быть указатель на COM-интерфейс. IntPtr(1) не является допустимым указателем. Это никогда не сработает, ни в версии 2.0.

2. Это тестовый код, поэтому IntPtr (1) передается для QI. Я согласен, это может не сработать в реальном коде продукта, но этот тестовый код прошел в .NET 2.0 без сбоев QTAgent32.exe. Тот же код произошел сбой в версии 4.0.

3. Вы хотите сказать, что VS2010 «исправил» это, чтобы оно больше не работало?

4. Что ж, в системе взаимодействия COM в .NET 4, безусловно, произошли изменения. Среда CLR теперь поддерживает несколько экземпляров самой себя в процессе, в частности, для решения проблемы с внедрением COM-версии. Да, не стесняйтесь интерпретировать это как «исправление».