Странные последствия использования ключевого слова ref в C # для взаимодействия с COM - PullRequest
0 голосов
/ 29 июня 2010

Рассмотрим отрывок из кода, который можно найти здесь :

namespace WinSearchFile
{
    public class Parser
    {
        [DllImport("query.dll", CharSet = CharSet.Unicode)] 
        private extern static int LoadIFilter (string pwcsPath, ref IUnknown pUnkOuter, ref IFilter ppIUnk); 

        [ComImport, Guid("00000000-0000-0000-C000-000000000046")] 
        [InterfaceType(ComInterfaceType.InterfaceIsIUnknown)] 
        private interface IUnknown 
        { 
            [PreserveSig] 
            IntPtr QueryInterface( ref Guid riid, out IntPtr pVoid ); 
            [PreserveSig] 
            IntPtr AddRef(); 
            [PreserveSig] 
            IntPtr Release(); 
        } 

        private static IFilter loadIFilter(string filename)
        {
            IUnknown iunk = null; 
            IFilter filter = null;

            // Try to load the corresponding IFilter 
            int resultLoad = LoadIFilter( filename, ref iunk, ref filter ); 
            if (resultLoad != (int)IFilterReturnCodes.S_OK) 
            { 
                return null;
            } 
            return filter;
        }
  }

Parser::loadIFilter(), в этом коде в основном вызывается функция LoadIFilter () .Последний просматривает реестр, находит, какой идентификатор класса соответствует указанному расширению файла, создает экземпляр соответствующего COM-класса (вызывает CoCreateInstance()) и вызывает из него IPersistFile::Load().

Теперь проблема в том, что подписьдля LoadIFilter() следующее:

HRESULT __stdcall LoadIFilter( PCWSTR pwcsPath, __in IUnknown *pUnkOuter, __out void **ppIUnk );

, поэтому вторым параметром является IUnknown* объекта агрегирования.Если класс COM для расширения интереса не поддерживает агрегирование, а переданный IUnknown* не равен нулю CoCreateInstance() возвращает CLASS_E_NOAGGREGATION, и так же LoadIFilter().

Если я удаляю refКлючевое слово из параметра pUnkOuter в объявлении и на сайте вызова LoadIFilter() вызывает функцию с нулевым значением IUnknown*.Если я сохраню ключевое слово ref, функция будет вызываться с ненулевым IUnknown* и возвращает CLASS_E_NOAGGREGATION для классов, которые не поддерживают агрегацию.

Мой вопрос - почему не равен нулю IUnknown* прошло, когда ключевое слово сохраняется?IUnknown iunk Локальная переменная инициализируется в null, так откуда же ненулевое IUnknown* взято из вызванного неуправляемого кода?

Ответы [ 3 ]

3 голосов
/ 29 июня 2010

Когда вы используете ref, вы на самом деле не отправляете null, вы отправляете ссылку, где хранится это null, но когда вы отправляете без ref вы отправляете действительное значение, которое равно null.

Итак:

С ref это ссылка на нулевой указатель.

Без него это простонулевой указатель.

Редактировать: Если я правильно понимаю ваш вопрос, который я не уверен на 100% ...

2 голосов
/ 29 июня 2010

Использовать ref просто неправильно, ваш IUnknown уже передан как указатель, поскольку это интерфейс. Передача ref будет эквивалентна IUnknown **

1 голос
/ 29 июня 2010

Ненулевой бит происходит изнутри метода - он создает экземпляр объекта по предоставленной вами ссылке.Использование ключевого слова ref для ссылочного типа передаст ссылку вызывающим объектам, а не создаст другую ссылку на объект (что происходит, когда вы передаете по ссылке в обычном режиме).Попробуйте это:

static void Main()
{
    object foo = null;
    SetMyObject(ref foo);

    bool test = foo == null;
}

public static void SetMyObject(ref object foo)
{
    foo = new object();
}

Проверка переменной будет ложной.

...