Поделиться через


Приложение .NET CF вызывает Unadvise в точке подключения COM при потере фокуса формы

В этой статье показано, как обойти проблему, в которой события не получены из объекта "Объектная модель компонента" (COM), когда приложение .NET Compact Framework, создающее COM-объект и подключающееся к исходной точке подключения, теряет фокус.

Исходная версия продукта: Microsoft .NET Compact Framework 3.5
Исходный номер базы знаний: 2300221

Симптом

Приложение .NET Compact Framework создает COM-объект и подключается к исходной точке подключения. Объект .NET теперь успешно получает события, отправляемые com-объектом. Однако, когда приложение .NET Compact Framework теряет фокус, дальнейшие события не получаются от COM-объекта, даже после того, как приложение снова получает фокус.

Причина

Когда приложение теряет фокус, платформа .NET Compact Framework ошибочно вызывает Unadvise метод в интерфейсе COM-объекта IConnectionPoint .

Резолюция

Существует два возможных обходных решения:

  • Эта проблема возникает только в .NET Compact Framework 3.5. Приложения будут продолжать работать должным образом в .NET Compact Framework 2.0. Это возможное обходное решение, если это возможно.
  • Вместо того чтобы полагаться на встроенную поддержку точек COM-соединений в .NET Compact Framework, можно написать код для ручного подключения и отключения к исходному интерфейсу, предоставляемому объектом COM. Ниже приведен пример кода для выполнения этой задачи.

Ниже приведен краткий пример того, как можно вручную подключиться к исходному интерфейсу, предоставляемому com-объектом без использования объекта .NET для этого.

Предположим, что мы импортировали COM-объект с именем EventGeneratorLib. Сначала определите интерфейс, предоставляемый в качестве исходного интерфейса объектом COM. В этом примере интерфейс наследуется от IDispatch одного метода.

[ComImport, Guid("<GUID of COM object's source interface>"), InterfaceType(ComInterfaceType.InterfaceIsIDispatch)]
public interface _ISampleEvents
{
    [DispId(1)]
    void FireEvent();
}

Теперь определите класс для реализации интерфейса.

[ComVisible(true), ClassInterface(ClassInterfaceType.None)]
public class SampleEvents : IDisposable, _ISampleEvents
{
    // COM object
    private EventGeneratorLib.EventGenerator _oEventGenerator;

    private bool _disposed = false;
    private IConnectionPoint _cp = null;
    private int _dwCookie = 0;

    public SampleEvents()
    {
        // Instantiate the COM object
        _oEventGenerator = new EventGeneratorLib.EventGenerator();

        // Set up callback
        if (_oEventGenerator != null)
        {
            // Query the object for an IConnectionPointContainer interface
            IConnectionPointContainer cpc = (IConnectionPointContainer)_oEventGenerator;

            IConnectionPoint cp = null;

            Guid cpGuid = new Guid("<GUID of source interface as defined by COM object>");
            int dwCookie = 0;

            // Find the connection point
            cpc.FindConnectionPoint(ref cpGuid, out cp);

            // Call advise to start receiving events from the COM object
            cp.Advise((_ISampleEvents)this, out dwCookie);

            // Save the cookie and the ConnectionPoint interface pointer
            _dwCookie = dwCookie;
            _cp = cp;
        }
    }

    ~SampleEvents()
    {
    Dispose(false);
    }

    public void Dispose()
    {
        Dispose(true);
        GC.SuppressFinalize(this);
        return;
    }

    private void Dispose(bool disposing)
    {
        // Check to see if Dispose has already been called.
        if (!this._disposed)
        {
            if (disposing)
            {
                // No code required here
            }

            // See if we created the COM object
            if (_oEventGenerator != null)
            {
                // Tear down the connection point
                if (_cp != null)
                {
                    _cp.Unadvise(_dwCookie);
                    _cp = null;
                }
                Marshal.ReleaseComObject(_oEventGenerator);
                 _oEventGenerator = null;
            }
        }
    _disposed = true;
    }

    #region _ISampleEvents Members

    // This is the definition of the interface that the COM object
    // calls back into.
    void _ISampleEvents.FireEvent()
    {
        // Do something here with event from COM object
    }
    #endregion
}

Приведенный выше код предоставляется только в качестве примера. Обработка ошибок была опущена для краткости.