none
Сбой при создании объектов класса COM RRS feed

  • Вопрос

  • У меня приложение на C# - cbmon.exe (целевая платформа x86, NetFramework 3.5) и COM компонент на C++ - PI2Disp.dll (целевая платформа x86, NetFramework 3.5). При загрузке Cbmon.exe устанавливается соединение с оборудованием по локальной сети (коммутатором). Для этого используется PI2Disp.dll.  Под WIN32 все работает замечательно. (Win XP, Win Vista, Win 7). Проблема возникает на Win 8.1 SL. Устанавливаю программу. Регистрирую PI2Disp.dll командой:

     C:\Windows\SysWOW64\regsvr32 PI2Disp.dll 

    из командной строки с правами администратора. Регистрация прошла успешно. Запускаю Cbmon.exe с правами администратора. Получаю ошибку:

    Адресат вызова создал исключение.: Сбой при получении производства объектов класса COM для компонента с CLSID {E062D4F8-6083-402F-ABD6-A4EB0F0FFD01} в результате следующей ошибки: 80070005.

    С CLSID {E062D4F8-6083-402F-ABD6-A4EB0F0FFD01} в реестре зарегистрирован класс из COM компонента PI2Disp.dll. В интернете нашла разъяснение к ошибке:

    ASP.NET не имеет права обращаться к запрошенному ресурсу. Рекомендуется предоставить идентификатору запроса ASP.NET права доступа к этому ресурсу. ASP.NET имеет базовый идентификатор процесса (обычно {MACHINE}\ASPNET для IIS > 5 или Network Service на IIS 6), который используется, если приложение не олицетворяется. Если приложение олицетворяется через задание , идентификатором будет служить идентификатор анонимного пользователя (обычно IUSR_MACHINENAME) или идентификатор пользователя запроса > с проверенной подлинностью.

    Для предоставления ASP.NET прав на запись в файл, щелкните на файле правой кнопкой мыши в окне "Проводник", выберите "Свойства", затем вкладку "Безопасность". Выберите "Добавить" для добавления соответствующего пользователя или группы. Выделите учетную запись ASP.NET и установите флажки для требуемых прав доступа.

    Мне странно - приложение не использует ASP.NET, IIS.Это не web служба и не web приложение. Тем не менее я развернула IIS, создала учетную запись ASPNET дала ей администраторские права.  На машине установлен NET Framework 4.0. Прописала в файле config/machine.config строку: 

    <processModel userName="Inna-PC\ASPNET" password="ASPNET" />.

    Однако, это не помогло. Ошибка осталась.

    Объясните, пожалуйста, что еще нужно сделать или что я сделала не так. Большое спасибо.


    5 февраля 2016 г. 10:51

Ответы

  • Запустите Dcomcnfg.exe и проверьте настройки доступа вашего COM объекта:

    https://technet.microsoft.com/en-us/library/cc731901.aspx

    Так же, вы запускайте приложение от имени администратора? 

    В любом случае можно попробовать использовать Standard User Analyzer чтоб посмотреть что именно запрещено:

    https://technet.microsoft.com/en-us/library/dd919180(v=ws.10).aspx


    This posting is provided "AS IS" with no warranties, and confers no rights.

    • Помечено в качестве ответа Bolonat 26 февраля 2016 г. 10:06
    12 февраля 2016 г. 16:44
    Модератор

Все ответы

  • Проблема возникает на Win 8.1 SL.

    Система у Вас 64-разрядная. Следовательно, код приложения на C# компилируется в x64, если в проекте явно не указана целевая архитектура процессора (x86). А 64-разрядное приложение загрузить 32-разрядную DLL (компонент COM) не может.
    в реестре зарегистрирован класс из COM компонента PI2Disp.dll
    В какой ветке реестра? 32-разрядные компоненты должны быть в HKEY_CLASSES_ROOT\Wow6432Node\CLSID.

    Если сообщение помогло Вам, пожалуйста, не забудьте отметить его как ответ данной темы. Удачи в программировании!

    5 февраля 2016 г. 13:28
  • Приложение скомпилировано в 32х разрядной системе. COM компонент тоже. Речь идет об установке готового приложения в 64х разрядную систему. COM компонент успешно зарегистрировался в системе после выполнения команды C:\Windows\SysWOW64\regsvr32 PI2Disp.dll

    [HKEY_LOCAL_MACHINE\SOFTWARE\Classes\Wow6432Node\CLSID\{E062D4F8-6083-402F-ABD6-A4EB0F0FFD01}]

    8 февраля 2016 г. 6:50
  • Приложение скомпилировано в 32х разрядной системе.

    Да хоть в 128-разрядной :) Компилятор C# на выходе создает не машинный код, а код на общем промежуточном языке, который подвергается дополнительной компиляции на целевой системе во время запуска приложения. По умолчанию поведение JIT-компилятора следующее: если целевая система 32-разрядная - получается 32-разрядный код, в противном случае - 64-разрядный.

    В этот процесс можно вмешаться, если в свойствах проекта ЯВНО указать, какой код должен получиться. Т.е. вместо "Any CPU" (по умолчанию) выбрать "x86".


    Если сообщение помогло Вам, пожалуйста, не забудьте отметить его как ответ данной темы. Удачи в программировании!

    8 февраля 2016 г. 8:11
  • В свойствах проекта ЯВНО указано какой код должен получиться, т.е. вместо "Any CPU"  выбрано "x86". Я именно это имела ввиду, когда писала, что целевая платформа x86. Дело в том, что на некоторых форумах пишут, что СОМ не загружается именно потому, что в настройках проекта стоит "Any CPU". Только что попробовала на 64х разрядной Windows 7. Все работает. 
    8 февраля 2016 г. 9:29
  • Возможно не установлено что то что требуется для работы COM. Может быть C++Runtime конкретной версии. А может быть какой нибудь другой компонент/

    Запустите под отладкой и посмотрите.


    This posting is provided "AS IS" with no warranties, and confers no rights.

    8 февраля 2016 г. 16:59
    Модератор
  • В таком случае я бы написал простой клиент на С++ и в отладчике посмотрел, что именно происходит при запросе фабрики класса, а именно на этом этапе и происходит ошибка (судя по диагностике). Клиент С# в данном случае малоинформативен, т.к. многое скрыто в недрах .NET


    Если сообщение помогло Вам, пожалуйста, не забудьте отметить его как ответ данной темы. Удачи в программировании!

    8 февраля 2016 г. 21:09
  • Запустить свой клиент, который на C#, под отладкой на машине с Windows 8.1 не могу, так как  там используется платный компонент Stimulsoft. На старой машине он установлен, а чтобы установить его на новую машину с Windows 8.1 у меня нет дистрибутива. Но я написала  на машине с Windows 8.1 (VS 2008) простой клиент на С++, в котором вызвала метод из моего COM компонента и получила ту же ошибку. Отладчик остановился на создании объекта класса COM (new). В объяснении написано "Убедитесь в наличии необходимых разрешений для доступа к этому ресурсу. Исключение <mshelp:link keywords="T:System.UnauthorizedAccessException" tabindex="0">UnauthorizedAccessException</mshelp:link> генерируется, когда операционная система отказывает в доступе из-за ошибки ввода-вывода или ошибки безопасности." Я создала другой COM компонент на этой же машине и взаимодействие клиента и СОМ сервера прошло успешно. Может нужно откатиться на NET Framework 3.5?


    9 февраля 2016 г. 13:44
  • Может нужно откатиться на NET Framework 3.5?

    Не понимаю, причем здесь версия .NET Framework? Компонент от нее не зависит, т.к. он неуправляемый, не так ли?

    От версии Framework зависит Ваш C#-клиент. Если он собран для 3.5, эта версия должна быть установлена. В Win 8(10) по умолчанию она не установлена. Установить можно через Панель управления (Программы и компоненты - Включение или отключение компонентов Windows).


    Если сообщение помогло Вам, пожалуйста, не забудьте отметить его как ответ данной темы. Удачи в программировании!

    9 февраля 2016 г. 13:57
  • .NET Framework 3.5 установлено. Активировала на Win 8.1 SL  учетную запись супер администратора, вошла в систему, запустила программу и получила ту же ошибку. В документации к VS написано: 

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

    Средство настройки политики управления доступом для кода(Caspol.exe) позволяет пользователям и администраторам изменять политику безопасности на уровне компьютера, пользователя и предприятия.

    Но в Win 8.1 SL это средство напрочь отсутствует! Как и средство для редактирования локальных групповых политик. Попытка его установить и запустить, не увенчалась успехом. Кроме того, я получила кучу обновлений системы безопасности. Честно говоря, меня эта ОС обескураживает.

     

    10 февраля 2016 г. 13:15
  • Этих средства (которые вам скорее всего и не нужны) нет во всех домашних версиях ОС.

    Так же C++ в принципе не может кидать CLR исключения вроде System.UnauthorizedAccessException. Это значит что у вас совсем не C++. Таким образом скорее всего вы копайте совсем не там, соответственно результата не будет.

    Вот что вам надо сделать:

    1. Напишите простейшее приложение на C++ (не C++/CLI как вы видимо сделали думая что это C++) которое создает ваш COM объект. Если не знайте как - спрашивайте.

    2. Запустите его на целевом компьютере под отладкой. При этом ничего устанавливать на нем не следует, используйте удаленную отладку. 

    3. Не повредит так же использовать утилиту depends: http://www.dependencywalker.com/


    This posting is provided "AS IS" with no warranties, and confers no rights.

    10 февраля 2016 г. 17:40
    Модератор
  • Начала с depends. Она показывает отсутствие файлов: 

    API-MS-WIN-CORE-KERNEL32-PRIVATE-L1-1-1.DLL
    API-MS-WIN-CORE-PRIVATEPROFILE-L1-1-1.DLL
    API-MS-WIN-SERVICE-PRIVATE-L1-1-1.DLL
    API-MS-WIN-CORE-SHUTDOWN-L1-1-1.DLL
    EXT-MS-WIN-NTUSER-UICONTEXT-EXT-L1-1-0.DLL
    IESHIMS.DLL

    Первые три лежат в SysWOW64\downlevel. Скачала и установила Visual C++ Redistributable Packages for Visual Studio 2013. Не помогло. Dependency Walker по-прежнему пишет, что файлы не найдены. 

    11 февраля 2016 г. 6:48
  • Она показывает отсутствие файлов: 

    API-MS-WIN-CORE-KERNEL32-PRIVATE-L1-1-1.DLL
    API-MS-WIN-CORE-PRIVATEPROFILE-L1-1-1.DLL
    API-MS-WIN-SERVICE-PRIVATE-L1-1-1.DLL
    API-MS-WIN-CORE-SHUTDOWN-L1-1-1.DLL
    EXT-MS-WIN-NTUSER-UICONTEXT-EXT-L1-1-0.DLL

    На это можете не обращать внимания. Утилита depends, в силу своего преклонного возраста, просто не знает о современной технологии устранения конфликтов между DLL (side-by-side).

    Илья, скорее всего, имел ввиду то, что данная утилита показывает раздел экспорта двоичного файла. У компонента COM обязательно должны экспортироваться четыре стандартные функции (DllRegisterServer, DllUnregisterServer и т.д.).


    Если сообщение помогло Вам, пожалуйста, не забудьте отметить его как ответ данной темы. Удачи в программировании!

    11 февраля 2016 г. 11:45

  • У компонента COM обязательно должны экспортироваться четыре стандартные функции (DllRegisterServer, DllUnregisterServer и т.д.).


           Экспортируются DllCanUnloadNow, DllGetClassObject,DllRegisterServer,DllUnregisterServer. Depends это показывает.

    Попыталась запустить удаленную отладку своего клиента на C# на целевой машине WIN 8.1. На старой машине у меня Windows Vista Home. Поэтому несмотря на то, что что я запускала на целевой машине WIN 8.1 монитор удаленной отладки командой: 

    msvsmon.exe /noauth /nosecuritywarn

    при попытке подключиться к процессу у меня все равно появилось сообщение: "The visual studio remote debugger does not support this edition of windows". Так что, пока с удаленной отладкой не получится. Однако у меня установлена на целевой машине VS2008. Объясните, пожалуйста, как мне правильно создать простейшее приложение на C++. В предыдущем варианте я использовала Windows Forms и по нажатию кнопки вызывала метод из COM. 

     

    11 февраля 2016 г. 12:33
  • Объясните, пожалуйста, как мне правильно создать простейшее приложение на C++.

    Создайте консольное приложение Win32 примерно с таким кодом:

    #import "полный путь к dll-компонента вместе с именем файла" no_namespace named_guids raw_interfaces_only
    
    void main()
    {
        // инициализация библиотеки COM
        CoInitialize(NULL);
    
        // объявляем указатель на требуемый интерфейс
        ISomeInterface *itf;
    
        // создаем экземпляр компонента
        HRESULT hr = CoCreateInstance(...);
    
        if (SUCCEDDED(hr))
        {
            // вызываем методы интерфейса, контролируя возращаемое ими значение HRESULT
            ...
    
            // отпускаем интерфейс
            itf->Release();
        }
    
        // завершение работы с библиотекой COM
        CoUninitialize();
    }
    


    Если сообщение помогло Вам, пожалуйста, не забудьте отметить его как ответ данной темы. Удачи в программировании!

    11 февраля 2016 г. 12:50
  • Если ваш объект требует определенного типа апартмента то вызов CoInitialize() следует заменить на CoInitializeEx() с нужным типом.

    Так же убедитесь что вы создали правильный тип проекта. Например проверьте что в проекте нет раздела "Refrences" и в свойствах проекта пункт "Common Language Runtime Support" установлен в "No Common Language Runtime Support".

    То что не загружается IESHIMS.DLL может быть причиной проблемы. Ваш COM компонент использует IE? Возможно старой версии?


    This posting is provided "AS IS" with no warranties, and confers no rights.

    11 февраля 2016 г. 17:38
    Модератор
  • COM не использует IE. Но на всякий случай я положила IESHIMS.DLL рядом с компонентом. Проблему это не решило. 

    Создала консольное приложение Win32. Запустила пошаговое выполнение. В результате создания экземпляра компонента получаю E_ACCESSDENIED. Смотрите картинку. В  свойствах проекта пункт "Common Language Runtime Support" установлен в "No Common Language Runtime Support".

    12 февраля 2016 г. 9:00
  • Запустите Dcomcnfg.exe и проверьте настройки доступа вашего COM объекта:

    https://technet.microsoft.com/en-us/library/cc731901.aspx

    Так же, вы запускайте приложение от имени администратора? 

    В любом случае можно попробовать использовать Standard User Analyzer чтоб посмотреть что именно запрещено:

    https://technet.microsoft.com/en-us/library/dd919180(v=ws.10).aspx


    This posting is provided "AS IS" with no warranties, and confers no rights.

    • Помечено в качестве ответа Bolonat 26 февраля 2016 г. 10:06
    12 февраля 2016 г. 16:44
    Модератор
  • Не понимаю, причём тут DCOM, компонент, как я понял, локальный. Тем более, в Win7 у человека все получилось без дополнительных "телодвижений". Все дело, похоже, в этой крайне ограниченной в администрировании версии системы.

    To Bolonat. Если есть исходный код компонента, пройдите отладчиком процедуру создания экземпляра и выясните, на какой операции возникает сбой.


    Если сообщение помогло Вам, пожалуйста, не забудьте отметить его как ответ данной темы. Удачи в программировании!

    12 февраля 2016 г. 18:11
  • Я нашла в чем проблема. Программа-инсталлятор создает на диске папку С:\Program Files\Common Files\Shared\PI2Disp и помещает в нее COM компонент и дополнительные dll. Я меняла атрибуты папки, то есть выбирала "не только для чтения", но оказывается после нажатия кнопки OK они не меняются. Я регистрировала компонент на другом диске, но при этом копировала всю папку с системного диска целиком. Соответственно ее атрибуты сохранялись. После того, как я создала ее заново на другом диске и скопировала в нее и зарегистрировала в ней COM - все заработало.  Спасибо, kosuke904 и Ilya Tumanov, что уделили мне время. В свое оправдание могу сказать, что на предыдущих ОС проблем с доступом к папкам ни разу не возникало. 
    12 февраля 2016 г. 18:14
  • Я не знаю как именно работает этот COM. DCOM может быть использован и локально, так что проверить не помешает.

    На Win 7 домашних версий точно такие же ограничения. И они, конечно, совершенно не при чем. 

    Просто в новой версии ОС несколько лучше защита и писать в Program Files кому попало не дают.

    Иными словами проблема в самом COM объекте который зачем то что пишет куда не надо. Решение должно лежать в области устранения данной проблемы, а не переноса папок. 


    This posting is provided "AS IS" with no warranties, and confers no rights.

    12 февраля 2016 г. 18:36
    Модератор
  • Вы, наверно, не совсем меня поняли. Сам COM никуда ничего не пишет. Но может использоваться многими моими приложениями-клиентами. Поэтому он помещается, по крайней мере до сих пор помещался инсталлятором в папку общих файлов Common Files в отдельном каталоге PI2Disp. Конечно, я теперь инсталлятор исправлю. Просто жаль что атрибуты созданной папки неочевидны. Система сама их назначает и не показывает и не запрещает менять, однако изменения не сохраняет. Это вводит в заблуждение.
    12 февраля 2016 г. 18:53
  • Если проблема решается удалением атрибута "только для чтения" то видимо имеется попытка открыть что то на запись.

    Так как в коде тестового приложения на C++ ничего подобного нет, то стало быть это делает сам COM или один из его компонентов. Можно использовать утилиту FileMon чтоб посмотреть что именно открывается и кем, потом устранить это.

    А кем он используется - не важно. Очень многие файлы без проблем используются очень многими приложениями и никаких проблем при этом не возникает вне зависимости от атрибута.


    This posting is provided "AS IS" with no warranties, and confers no rights.

    12 февраля 2016 г. 22:24
    Модератор
  • Ничего "криминального" в установке компонентов в Program Files нет, эта папка именно для этого и предназначена. Другое дело, если эти самые компоненты (либо из зависимости) начинают самостоятельно создавать файлы в папке своего расположения. Вот это уже запрещено. Для служебных файлов выделены папки ProgramData (на общесистемном уровне) и AppData (на уровне конкретного пользователя, от имени которого приложение работает). Существуют функции WinAPI, возвращающие названия этих папок. Ими и следует пользоваться с коде компонента.

    Если сообщение помогло Вам, пожалуйста, не забудьте отметить его как ответ данной темы. Удачи в программировании!

    13 февраля 2016 г. 10:17
  • Проблема никуда не исчезла. Дело в том, что в пятницу вечером я решила попробовать установить программу на совершенно "чистой" своей домашней машине. Она всего месяц как из магазина. На ней тоже W8.1 SL. На ней ничего не установлено кроме некоторых утилит и офисных программ. С первого раза все заработало. Я деинсталлировала программу и для проверки установила снова. Но, чтобы не набирать команду регистрации каждый раз заново, решила создать bat файл и, по глупости или рассеянности,  создала его рядом с компонентом в системной папке. Система, как я понимаю, автоматически меняет атрибуты системной папки при попытке что-то записать в нее. В общем, при следующем запуске программы я получила ошибку 0x80070005. После манипуляций с атрибутами папки, потом ее пересоздания, программа заработала.  Я много раз переустанавливала программу, регистрировала компонент  в системной папке и в не системной папке. И все работает. Но сегодня, на рабочей машине, я попробовала создать папку в другом месте  зарегистрировала в ней компонент, и получаю все ту же ошибку.   

    Вопрос в следующем, может ли система запомнить у себя  компонент как неблагонадежный и просто не давать к нему доступ? Я почистила весь реестр, убрав всякое упоминание о PI2Disp и его идентификаторе, регистрировалась под разными пользователями, но ничего не помогло. 


    • Изменено Bolonat 15 февраля 2016 г. 12:04
    15 февраля 2016 г. 11:18
  • Что мы гадаем на "кофейной гуще"? У Вас есть исходный код компонента? Исследуйте код функции DllGetClassObject, реализацию метода IClassFactory::CreateInstance и конструктор класса компонента (либо его метод FinalConstruct, если использована ATL) на предмет открытия в этом коде файлов на запись.

    Атрибуты папок ни причем. Программа установки работает от имени специального пользователя, которому разрешена запись в Program Files, а приложение (создающее экземпляр компонента) - от имени текущего интерактивного пользователя. Он в системах Win 8(10) прав на запись в Program Files НЕ ИМЕЕТ (даже не смотря на то, что может входить в группу администраторов). Ему не дает это делать контроль учетных записей, отключить который в Win 8(10) довольно проблематично (могут перестать работать приложения Магазина Windows).


    Если сообщение помогло Вам, пожалуйста, не забудьте отметить его как ответ данной темы. Удачи в программировании!

    15 февраля 2016 г. 12:30
  • С отладкой разбираюсь.

    • Изменено Bolonat 20 февраля 2016 г. 8:57
    18 февраля 2016 г. 11:56
  • Простите, что снова отнимаю время, но не могли бы вы проявить еще немного терпения и еще немного помочь мне в данной теме. 

    Я исследую два совершенно одинаковых проекта с одинаковыми свойствами в двух разных ОС (Win Vista и Win 8.1). Я загрузила свой COM компонент под отладкой в Win Vista и могу свободно ходить по шагам. Однако, в Win 8.1 компонент не загружается совсем по все той же причине E_ACCESSDENIED. Я обратила внимание на различие в порядке загрузки библиотек в окне OUTPUT. То есть до определенного момента порядок загрузки одинаковый.  В Win Vista после загрузки oleaut32.dll загружается мой COM - PI2Disp.dll со своими зависимостями. Но в Win 8.1   после загрузки oleaut32.dll загружаются библиотеки cryptsp.dll, rsaenh.dll, bcrypt.dll. После этого больше ничего не загружается. Результат E_ACCESSDENIED как я понимаю, возвращает bcrypt.dll. В инете я нашла, что это криптопровайдер. То есть,  как я предполагаю (в моей программе этого нет), диспетчер управления службами пытается запустить какую-то службу, для этого проверяет данные учетной записи, и его что-то не устраивает. Может вы объясните мне что-нибудь по этому поводу? Как понять, что система делает и зачем? Для наглядности привожу снимки экранов. 

    На WIN Vista Home:

    И на Win 8.1


    • Изменено Bolonat 25 февраля 2016 г. 11:41
    25 февраля 2016 г. 11:28
  • Здравствуйте.

    В Win Vista студия (и, соответственно, приложение под отладкой) запущена от имени администратора:

    а в Win 8.1 нет:

    Возможно, причина в этом?


    Если сообщение помогло Вам, пожалуйста, не забудьте отметить его как ответ данной темы. Удачи в программировании!

    25 февраля 2016 г. 11:47
  • Запустила от имени администратора в Win 8.1

    25 февраля 2016 г. 11:53
  • А если "поиграть" с контекстом исполнения сервера. Например, при вызове CoCreateInstance вместо CLSCTX_ALL указать явно CLSCTX_INPROC_SERVER. Ведь у Вас DLL - "сервер в процессе".

    Если сообщение помогло Вам, пожалуйста, не забудьте отметить его как ответ данной темы. Удачи в программировании!

    25 февраля 2016 г. 12:22
  • Все заработало. В Component Services в папке «COM+ Applications» лежал объект PI2Disp_Connect. Не могу сейчас  объяснить откуда он там взялся и в каких экспериментах участвовал. СОМ не предназначался для работы по сети. После его удаления все заработало.

    Надо было сразу послушать Илью и проверить Службы Компонентов. А обнаружила я это, когда начала экспериментировать с контекстом исполнения сервера по совету kosuke904. В результате получила ошибку 0х80040154 Класс не зарегистрирован. Порывшись в интернете нашла вот это. Зашла в службы компонентов и увидела причину проблемы. Спасибо вам огромное. Без вас я бы не справилась.

    26 февраля 2016 г. 9:58
  • Лучший ответ, я ради плюсика тебе даже зарегался!
    19 октября 2018 г. 14:27