Activator.CreateInstance (<guid>) работает внутри VSIDE, но не внешне - PullRequest
6 голосов
/ 03 сентября 2011

У меня есть куча COM-объектов, которые реализуют один и тот же интерфейс, и мне нужно создать один из них, выбранный во время выполнения из списка опций.Поскольку я знаю CLSID для каждого внедряющего COM-сервера, это должно быть легко.Однако для определенного подмножества COM-библиотек я могу выполнить эту работу только в том случае, если я работаю в среде IDE VS2010.

Вот вся программа, которую я использую для тестирования:

using System;

namespace ComTest
{
    class Program
    {
        static void Main(string[] args)
        {
            var clsid = "{E8978DA6-047F-4E3D-9C78-CDBE46041603}";
            var type = Type.GetTypeFromCLSID(new Guid(clsid));
            var obj = Activator.CreateInstance(type, true);
            Console.WriteLine("Obj is {0}", obj);
        }
    }
}

Я могу сделать эту работу для каждого COM CLSID, который я пробовал до сих пор, пока я запускаю VS2010.С подключенным отладчиком или без него, а также с подключенным процессом хостинга или без него, я получаю System.__ComObject обратно от CreateInstance.

Когда я компилирую и запускаю этот код из окна консоли для определенных значений CLSIDВместо этого я получаю:

Unhandled Exception: System.Runtime.InteropServices.COMException: Creating an instance of the COM component with CLSID {E8978DA6-047F-4E3D-9C78-CDBE46041603} from the IClassFactory failed due to the following error: 80004005.
   at System.RuntimeTypeHandle.CreateInstance(RuntimeType type, Boolean publicOnly, Boolean noCheck, Boolean& canBeCached, RuntimeMethodHandleInternal& ctor, Boolean& bNeedSecurityCheck)
   at System.RuntimeType.CreateInstanceSlow(Boolean publicOnly, Boolean skipCheckThis, Boolean fillCache)
   at System.RuntimeType.CreateInstanceDefaultCtor(Boolean publicOnly, Boolean skipVisibilityChecks, Boolean skipCheckThis, Boolean fillCache)
   at System.Activator.CreateInstance(Type type, Boolean nonPublic)
   at ComTest.Program.Main(String[] args) in 

Это происходит только с определенными идентификаторами CLSID - например, "{c1243ca0-bf96-11cd-b579-08002b30bfeb}" (встроенный текст IFilter) работает, но "{E8978DA6-047F-4E3D-9C78-CDBE46041603} "(IFilter Acrobat Reader X's) нет.Что я не могу понять, так это то, что запуск через IDE меняет ситуацию, если вызов COM Interop будет успешным.Любые идеи?

РЕДАКТИРОВАТЬ:

Я не работаю VS2010 в качестве администратора, но у меня есть попытался запустить двоичный файл вывода через консоль Powershell с повышенными правами, и он все еще нене работает.

РЕДАКТИРОВАТЬ 2:

До сих пор единственным COM-сервером, который я использовал для воспроизведения этой "ошибки", является AroRdIf.dll из Acrobat Reader X (предыдущие версии работают нормально).Я больше не беспокоюсь о том, чтобы заставить работать определенный IFilter в Acrobat, но я очень обеспокоен тем, что у меня есть код, который работает в моей IDE, но не за ее пределами.Кроме того, у инструмента Windows SDK FILTDUMP нет проблем с загрузкой этого COM-сервера, поэтому я знаю, что это возможно, я просто не знаю как .

Ответы [ 7 ]

3 голосов
/ 13 января 2012

Этот вопрос старый (и ответил), но я подумал, что добавлю немного информации.

Adobe X (10.1.x) не сможет обеспечить интерфейс IFilter при некоторых условиях. Вызывает QueryInterface, или ClassFactory-> CreateInstance или :: LoadIFilter, или что-то еще не получится с E_FAIL. Условие, о котором я говорю, - это когда запущенный процесс не является частью «Задания».

Т.е., их 10.x IFilter проверяет, находится ли текущий процесс в каком-либо задании. В противном случае это терпит неудачу (для меня по крайней мере) Мой обходной путь похож на следующий псевдо-код:

HANDLE curProc = GetCurrentProcess();
BOOL bResult = FALSE;
int iResult = IsProcessInJob(curProc, NULL, &bResult);
if(iResult != 0 && bResult == FALSE) {
    HANDLE hJob = CreateJobObject(NULL,"whatever");
    AssignProcessToJob(hJob,curProc);
}

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

3 голосов
/ 12 сентября 2011

Так что я потратил некоторое время на тестирование этого, и я смог воспроизвести проблему именно так, как вы описываете. Я воссоздаю ваше точное консольное приложение и вижу то же поведение, но думаю, что могу хотя бы добавить новую информацию.

Сначала я думал так же, как и вы, что это было что-то в визуальной студии, заставляющей работать, но на самом деле это не так. Если вы встроите его в консольный исполняемый файл, а затем запустите его из проводника, он будет работать нормально без участия визуальной студии. Также я добавил Debugger.Launch () в начало, чтобы я мог подключиться к нему при запуске из командной строки, и я получаю сообщение об ошибке даже при полностью подключенном VS и отладке. Все мои результаты показывают, что не VS заставляет его работать, а запускает его из командной строки, которая его ломает.

Я пробовал все виды вещей, чтобы сделать среду одинаковой между запуском командной строки и запуском проводника Windows, но каждый раз получаю одно и то же; отлично работает из проводника и умирает из командной строки.

Копаясь с отражателем, установка проходит все свои испытания и все. Это фактический вызов:

RuntimeTypeHandle.CreateInstance(this, publicOnly, noCheck, ref canBeCached, ref ctor, ref bNeedSecurityCheck);

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

Может быть, кто-то, кто знает больше о внутренностях окон, может рассказать о различиях между выполнением из командной строки и проводником?

3 голосов
/ 03 сентября 2011

Вероятно, это связано с тем, что ваше приложение не поднято за пределы Visual Studio и ему не хватает разрешений для взаимодействия с компонентами COM.

Щелкните правой кнопкой мыши и run as administrator, чтобы увидеть, имеет ли это значение.

1 голос
/ 25 октября 2014

"Технически говоря, Adobe предоставила и правильно зарегистрировала библиотеку DLL фильтра извлечения текста (ACRORDIF.DLL), но ее создание не было бы реализовано какими-либо распространенными средствами, то есть с использованием API-интерфейса LoadIFilter или непосредственного создания COM-объекта после просмотраобъект фильтра CLSID в реестре. Был ли он поврежден? Нет, потому что каким-то образом поиск в Windows мог его использовать !? Некоторые люди утверждали, что фильтр был отброшен в режиме многопоточности STA (как это было в старые дни v6), но это не подтверждаетсяс помощью ThreadingModel библиотеки DLL фильтра. Некоторые говорили о запуске его только через объект Job. Служба поддержки Adobe держала себя в узде и утверждала, что ограничение было для нашей безопасности - хм . "... "Можете ли вы угадать, как работает трюк? Они жестко закодировали имена инструментов MS, таких как FILTDUMP, в фильтре PDF ACRORDIF.DLL !!! Поэтому, когда создается экземпляр объекта PDF IFilter, он проверяетимя вызывающего процесса, и если оно входит в «белый список», оно работает, в противном случае оно подделывает проблему и E_FAIL. Scandalous. Для доказательства переименуйте вашу программу в Filterdump.exe и, как по волшебству, все работает, даже простоLoadIFilter без объектов задания. "

Поддерживает ли программа чтения Adobe PDF извлечение текста или нет?

1 голос
/ 11 сентября 2011

Я не могу воспроизвести проблему, которую вы описываете ... некоторые общие указатели для проверки:

0 голосов
/ 13 сентября 2011

Два предложения.

Использовать атрибут [STAThread].

[STAThread]
static void Main(string[] args)
{...}

Попробуйте позвонить в CoInitialize

[DllImport("ole32.dll")]
static extern int CoInitialize(IntPtr pvRes);
CoInitialize((System.IntPtr)null)
0 голосов
/ 10 сентября 2011

Не уверен, что там происходит, но как обходной путь, мне интересно, не могли бы вы попробовать запустить процесс с чем-то вроде ...

System.Diagnostics.Process.Start("THE_PROCESS.exe");

Тогда, когда процесс запущен, вы можете попытаться получить объект из таблицы запущенных объектов, используя ProgID ...

object appObj = System.Runtime.InteropServices.Marshal.GetActiveObject("THE_PROGID");
...