Создание сильной ссылки на COM-объект в ROT с C#
Мне нужно привязать к работающему экземпляру COM (может быть много экземпляров того, что я ищу, поэтому мне нужно выяснить, какой из них правильный, изучив таблицу запущенных объектов) Используя CoClassCreate или new
Оператор с классом не вариант для меня.
Код, который у меня есть, почти работает, за исключением того, что он не является безопасным исключением
Есть ли способ избежать автоматического Revoke
что происходит за кулисами, если исключение выдается, как в коде ниже? Как только приложение заканчивается, COM-объект удаляется из ROT, пока приложение, которое зарегистрировало его, все еще работает. Я уверен, что Release() вызывается автоматически, и, поскольку это был последний объект, ссылающийся на COM, запись ROT исчезает.
Я хотел бы получить сильную ссылку на объект в ROT атомарным и исключительным способом.
Все мои попытки использовать моникер в сочетании с методом BindToObject
были неудачными. Есть ли проблема с реализацией в.NET 4.0? Первый вызов, кажется, работает, но все последующие вызовы терпят неудачу с исключением Argument или invalidCast, даже при использовании Guid of IUnknown. Насколько мне известно, это всегда должно быть успехом или я что-то упускаю?
Вот лучший рабочий код, который я мог сделать до сих пор. Я просто скучаю по безопасности исключений. Программа предназначена для запуска сама по себе и может быть прервана (может быть выдано исключение для прерывания шага в любое время). Выход из этого незаконченного бизнеса наверняка вызовет у меня некоторые проблемы, если я не смогу решить его чисто.
[DllImport("ole32.dll")]
static extern int CreateBindCtx(uint reserved, out IBindCtx ppbc);
// Returns the contents of the Running Object Table (ROT), where
// open Microsoft applications and their documents are registered.
private IEnumerable<T> GetRunningObjects<T>()
{
// Get the table.
IBindCtx bc;
if (CreateBindCtx(0, out bc) != 0 || bc == null)
throw new ApplicationException("Can't create COM binding context in GetRunningObjects<T>");
IRunningObjectTable runningObjectTable;
bc.GetRunningObjectTable(out runningObjectTable);
IEnumMoniker monikerEnumerator;
runningObjectTable.EnumRunning(out monikerEnumerator);
monikerEnumerator.Reset();
// Enumerate and fill our nice dictionary.
IMoniker[] monikers = new IMoniker[1];
IntPtr numFetched = IntPtr.Zero;
while (monikerEnumerator.Next(1, monikers, numFetched) == 0)
{
object o = null;
if (runningObjectTable.GetObject(monikers[0], out o) == 0 && o != null)
{
if (o is T)
{
// TODO: If an exception is thrown here, then COM object gets revoked from ROT...
throw new Exception("Test");
// monikers[0].BindToObject does not work...
// there seems to be a weakness here.
// if found, create a strong reference to avoid auto-revokation in the ROT
IntPtr ptr = Marshal.GetIUnknownForObject(o);
Marshal.AddRef(ptr);
yield return (T)o;
}
}
}
Marshal.ReleaseComObject(bc);
}
Дополнительное примечание: это, вероятно, происходит, когда сервер OutProc регистрирует активный объект только как слабую ссылку. Я не имею никакого влияния на это, я не являюсь автором серверной части... Мне нужно привязать к работающему объекту, не рискуя отозвать объект из Таблицы запущенных объектов.