InvalidCastException при использовании IClassFactory в C # - PullRequest
3 голосов
/ 30 января 2012

Я пытаюсь создать экземпляр элемента управления ActiveX без регистрации в проекте C #.Я делаю следующее:

Guid guid = new Guid("(guid of my control here)");

var classFactory = ComHelper.GetClassFactoryFromDll("mycontrol.ocx", guid);
if (classFactory != null)
{
    object obj;
    classFactory.CreateInstance(null, ref guid, out obj); // getting the exception here
    if (obj != null) ocx = (obj as IMyControl);
}

Код ComHelper в основном основан на этой статье и, кажется, отлично работает с примером IFilter.

Этомой код взаимодействия для IClassFactory:

    [ComVisible(false)]
    [ComImport, InterfaceType(ComInterfaceType.InterfaceIsIUnknown), Guid("00000001-0000-0000-C000-000000000046")]
    public interface IClassFactory
    {
        void CreateInstance([MarshalAs(UnmanagedType.Interface)] object pUnkOuter, ref Guid refiid,
                            [MarshalAs(UnmanagedType.Interface)] out object ppunk);

        void LockServer(bool fLock);
    }

Интерфейс IMyControl - это интерфейс, сгенерированный aximp.exe /source.Я хочу избежать использования сателлитных сборок, потому что не могу заставить их использовать безрегулярный COM, а наше развертывание требует этогоЧто бросает исключение?Я использую тот же гид, что и для традиционного спутникового монтажа.Правильно ли направлен гид?Как я могу заставить это работать?


Ради полноты: мне удалось это сделать.Мой метод состоял в том, чтобы просмотреть исходный код AxHost (использовал ILSpy) и посмотреть, что он делает при создании экземпляра:

private object GetOcxCreate()
{
    if (this.instance == null)
    {
        this.CreateInstance();
        this.RealizeStyles();
        this.AttachInterfaces();
        this.oleSite.OnOcxCreate();
    }
    return this.instance;
}

Затем я создаю экземпляр сгенерированного класса AxMyControl и заменил instance privateполе через отражение.Это поле изначально получает значение, вызывая CoCreateInstance из CreateInstance.Затем я вызвал другие методы для исправления других соединений (все они являются частными, так что, опять же, рефлексия).Если класс не зарегистрирован, в конструкторе выдается исключение (CoCreateInstance завершается ошибкой), поэтому я выполняю эту обработку в блоке finally.

Пока что вроде нормально работает.

1 Ответ

2 голосов
/ 30 января 2012

Вы неправильно поняли Гид.Вызов CreateInstance требует, чтобы вы передавали IID интерфейса, а не CLSID кокласса.Вместо этого используйте typeof (IMyControl) .GUID.

Следующий большой возможный режим сбоя - состояние квартиры потока, лучше, чтобы STA или COM собирались найти прокси, который, вероятно, не существует.Вы обходите средства безопасности, которые есть в CLR, и, если необходимо, маршалируете указатель интерфейса. Никогда не использовать объект из неправильного потока.Не уверен, что это стоит риска.

...