Com + позднее связывание с # 4.0

В моей программе я создаю объекты Com + динамически (позднее связывание), используя

Type comObjectType = Type.GetTypeFromProgID(progId, true); 
object comObject = Activator.CreateInstance(comObjectType); 

А затем вызовите один из методов с помощью отражения

object result = comObjectType.InvokeMember(MethodToActivate, BindingFlags.InvokeMethod, null, comObjec, new object[] {....});

Он отлично работает в .Net 1.1 / 2.0 / 3.5

Теперь я пытаюсь запустить тот же код на том же компьютере (Windows XP), скомпилированный для .Net 4.0, но у меня есть

Exception: Method 'System.__ComObject.{MethodName}' not found. 

У меня есть исключение для большинства объектов Com + (не для всех). Кто-нибудь знает, в чем проблема? Почему я получаю исключение в среде FW 4.0? Что мне делать, чтобы этого избежать?

Большое спасибо, даниэль

После некоторого дополнительного исследования я обнаружил, что некоторые из прокси Com + созданы как System._ComObject (я полагаю, это собственные), а некоторые созданы как System.Runtime.Remoting.Proxies._TransparentProxy (я думаю, что это объекты .Net Com +). Вызов метода отлично работает для тех, которые созданы как System._ComObject, и не работают для System.Runtime.Remoting.Proxies._TransparentProxy. Самым интересным фактом является то, что в .Net 2.0 все объекты создаются одинаково (_ComObject и _TransparentProxy), но вызов метода работает нормально. Еще один интересный факт: я могу увидеть "отсутствующий" метод в отладчике с помощью рефлектона.

((System.EnterpriseServices.RemoteServicedComponentProxy)((((System.Runtime.Remoting.Proxies.__TransparentProxy)(ObjectToActivate)))._rp)).ProxiedType.GetMethods()

В какой-то момент я подумал, что это может быть проблема безопасности, но я запускаю код, когда WindowsService вошел в систему как пользователь с правами администратора.


person Daniel Kabzon    schedule 14.04.2011    source источник
comment
Вы проверяли наличие 32/64-битных проблем? Может быть, ваш процесс 64-битный и поэтому попадает в 64-битный реестр COM (где никто не живет :-)?   -  person Simon Mourier    schedule 27.04.2011
comment
Я не думаю, что это 32/34-битная проблема, моя локальная машина 32-битная, как и удаленный сервер.   -  person Daniel Kabzon    schedule 27.04.2011
comment
нормально для 32/64-бит. Теперь похоже, что ваш COM-сервер не находится в процессе или имеет определенную модель потоков (отсюда и прокси). Вы можете подробнее рассказать об этом? они размещены вне процесса? В компонентных сервисах? А как насчет аргументов Invoke? вы уверены, что нет двусмысленности? А как насчет BindingFlags? вам не нужен Public | Instance?   -  person Simon Mourier    schedule 27.04.2011
comment
Большинство серверов com + фактически расположены на удаленной машине (сервер 2003), но не все. Они работают как серверное приложение со своим выделенным пользователем. Я сосредоточился на том, что является локальным и обращается к строкам как параметрам и возвращаемой строке (очень просто). Привязка falg установлена ​​для BindingFlags.InvokeMethod, я не использовал Public | Instance в других версиях .Net, и это не было проблемой, но я попробую, может быть версия 4.0 имеет больше ограничений времени выполнения, чем предыдущие версии   -  person Daniel Kabzon    schedule 27.04.2011
comment
Разве .NET 4.0 не должна обрабатывать это автоматически? Вместо того, чтобы объявлять comObject как объект, объявите его как динамический. Попробуйте прочитать это msmvps .com / blogs / paulomorgado / archive / 19.04.2010 /   -  person Jon Limjap    schedule 27.04.2011


Ответы (2)


Я обнаружил, что существует разница между .NET FW при создании типа COM, и, насколько я понимаю, разница существует только для .NET COM-объектов. Когда тип COM-объекта создается с помощью

Type comObjectType = Type.GetTypeFromProgID(progId, true);

тип, возвращаемый в .NET 1.1 / 2.0 / 3.5, является фактическим типом .NET объекта, поэтому при вызове его метода проблем нет, но в .NET 4.0 возвращается тип System.__ComObject, поэтому код

result = comObjectType.InvokeMember(
   MethodToActivate, BindingFlags.InvokeMethod, null, ObjectToActivate, InputParams);

завершается ошибкой, если метод не найден, исключение.

Решение, которое я нашел, следующее:

Type comObjectType = Type.GetTypeFromProgID(progId, true);        
object comObject = Activator.CreateInstance(comObjectType);

// here the real object type is returned
Type acctualObjectType = comObject.GetType();
result = acctualObjectType.InvokeMember(
   "MethodToActivate", BindingFlags.InvokeMethod, null, comObject, InputParams);

Этот код отлично работает во всех средах.

person Daniel Kabzon    schedule 27.04.2011
comment
Интересно - я на самом деле опубликовал предыдущий ответ, который, как я подозреваю, помог бы, если бы по иронии судьбы удалил его после прочтения другого вопроса, который убедил меня в том, что я был неправ! - В любом случае, рад, что ты решил проблему. - person Justin; 27.04.2011
comment
В вашем коде решения comObject должно быть таким же, как ObjectToActivate? - person Dave Cousineau; 13.09.2014
comment
Да, это. ObjectToActivate - это свойство, возвращающее comObject. - person Daniel Kabzon; 14.09.2014

Я не уверен, почему ваш ранее запущенный код больше не работает, однако я считаю, что в .Net 4.0 вы можете вызывать методы COM, используя IDispatch / позднее связывание через тип dynamic - см. Поддерживает ли C # .NET позднее связывание IDispatch?.

person Justin    schedule 27.04.2011
comment
Я думал об этом решении, но для меня это неприемлемо, потому что мне нужен один и тот же код, запускаемый для всех версий .Net FW. Это часть основной библиотеки, которая работает в разных средах. - person Daniel Kabzon; 27.04.2011
comment
@Daniel: Независимо от того, удовлетворительно ли это, использование dynamic по-прежнему показывает ошибку? - person Gabe; 27.04.2011
comment
Я пробовал небольшой образец с 'динамическим', он работает (но для меня бесполезен (:) - person Daniel Kabzon; 27.04.2011