Не удается найти COM-объект из C++, хотя в Guid он зарегистрирован

Во-первых, всех с наступающим Новым годом, надеюсь, у вас все хорошо!

Я работаю над проектом C++, в котором мне нужно вызвать DLL C#, созданную после первого ответа этот пост. Когда у меня есть DLL, мне нужно вызвать ее из Qt, поэтому с помощью dumpcpp и файла .tlb, сгенерированного regasm, мне удалось получить файл . cpp и .h, чтобы использовать мои классы. Для справки: пространство имен классов — Wrapper, а основной класс — Device с идентификатором {DD4A4896-C105-4C60-839B-B18C99C8FE15}< /эм>.

Когда у меня есть сгенерированные файлы для использования DLL, при попытке создать экземпляр Wrapper::Device в Qt я получаю следующую ошибку:

QAxBase::setControl: requested control {dd4a4896-c105-4c60-839b-b18c99c8fe15} could not be instantiated
QAxBase::qt_metacall: Object is not initialized, or initialization failed

Это не дает никакой дополнительной информации, поэтому я попытался проверить, хранится ли guid в системном реестре (я использовал команду regasm, описанную в предыдущем сообщении, и она сказала, что это было успешно, но вы никогда не знаете). Открытие редактора реестра и поиск Guid показали, что он присутствует по адресу: Computer\HKEY_CLASSES_ROOT\WOW6432Node\CLSID\{DD4A4896-C105-4C60-839B-B18C99C8FE15}, что, насколько я знаю, является правильным маршрутом для этих guids и указывает на правильную DLL.

Я думаю, что это может быть связано с какой-то проблемой ActiveQt, и, поскольку в ранее процитированном сообщении объяснялось, как использовать эту DLL из VS C++, я решил попробовать, используя это в качестве еще одной ссылки. Я закончил с этим кодом, который должен создать экземпляр моего объекта «Устройство».

#include <iostream>
#include <atlstr.h>
#import "C:\Users\javie\Documents\Wrapper\Wrapper\bin\x86\Release\netstandard2.0\Wrapper.tlb" named_guids raw_interfaces_only

inline void TESTHR(HRESULT x) { if FAILED(x) _com_issue_error(x); };

int main()
{

    try
    {
        TESTHR(CoInitialize(0));
        Wrapper::IDevicePtr devPtr = nullptr;
        TESTHR(devPtr.CreateInstance("{DD4A4896-C105-4c60-839B-B18C99C8FE15}"));
    }
    catch (const _com_error& e)
    {
        CStringW out;
        out.Format(L"Exception occurred. HR = %lx, error = %s", e.Error(), e.ErrorMessage());
        MessageBoxW(NULL, out, L"Error", MB_OK);
    }

    CoUninitialize();// Uninitialize COM

    std::cout << "Hello World!\n";
}

Однако это тоже не работает, метод createInstance выдает исключение Класс не зарегистрирован и HR=80040154. Опять же, по словам редактора реестра, класс зарегистрирован, поэтому я не понимаю ошибки. Я также пытался использовать devPtr.CreateInstance("Wrapper.Device"), devPtr.CreateInstance("Wrapper::Device") или `devPtr.CreateInstance(Wrapper::CLSID_Device) в соответствии с опубликованными ссылками, но в этих случаях я получаю другое исключение с HR=800401f3 и сообщением Недопустимая строка класса.

Неважно, открыты ли VS или Qt Creator от имени администратора или нет, я получаю ту же ошибку. У меня закончились идеи, и мне действительно нужно иметь возможность использовать эту DLL из Qt, используя файлы, сгенерированные dumpcpp.

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


person Javierd98    schedule 31.12.2020    source источник
comment
Возможно несоответствие 32/64 бит   -  person David Heffernan    schedule 31.12.2020
comment
См. этот ответ: stackoverflow.com/questions/9711079/   -  person Joseph Willcoxson    schedule 31.12.2020
comment
Спасибо за помощь! К сожалению, и DLL, и исполняемые тесты, которые я использую, построены на 32 битах (первый с 32-битным MinGW4.4.0, а второй устанавливает Win32 в качестве платформы в свойствах проекта VS). Я проверил их, и оба они 32-битные. Кроме того, я использую версию RegAsm для .NET 4.0, как прокомментировал пост @JosephWillcoxson.   -  person Javierd98    schedule 01.01.2021


Ответы (2)


Если ваше приложение на C++ 64-разрядное, это правильный ответ, потому что ваш компонент C# является 32-разрядным (или MSIL, но зарегистрированным в 32-разрядном кусте). В подобных ситуациях всегда полезен простой тест с использованием VBScript.

Напишите простой скрипт VB (test.vbs)

Dim obj
Set obj = CreateObject("Wrapper.Device") ' or whatever your ProgID is
MsgBox TypeName(obj)

Теперь запустите этот макрос двумя способами: с 32-битной и 64-битной версиями VBScript:

32-bit > c:\windows\SysWow64\cscript.exe test.vbs
64-bit > c:\windows\system32\cscript.exe test.vbs

Это предполагает, что ваш компонент С# совместим с диспетчеризацией. Если это не так, то он все равно даст вам разные результаты, которые вы можете использовать для отладки.

Предполагая совместимость с автоматизацией/IDispatch, один будет работать, а другой нет, если вы правильно зарегистрировали свой компонент.

Вы правильно зарегистрировались? Когда я использую regasm, я всегда использую ключи /tlb/codebase при регистрации компонента C# для COM.

person Joseph Willcoxson    schedule 31.12.2020
comment
Большое спасибо Джозеф. Как я ответил на ваш предыдущий комментарий, и DLL, и исполняемый файл, который я использую, являются 32-битными, поэтому проблем быть не должно. Что меня удивило после тестирования вашего сценария VB, так это то, что при использовании c:\windows\SysWow64\cscript.exe (32-разрядная версия, по вашему мнению) он дает сбой с недопустимым указателем, но при использовании 64-разрядной версии (c:\ windows\system32\cscript.exe test.vbs) возвращает Microsoft VBScript runtime error: ActiveX component can't create object: 'Wrapper.Device' Как это возможно? Я использую ключи /tlb и /codebase на RegAsm. - person Javierd98; 01.01.2021
comment
Кстати, я не думаю, что мой компонент совместим с IDispatch или с автоматизацией, поскольку я не знаю, что это значит, и я только что добавил атрибуты Guid, ComVisible и ClassInterface/InterfaceType к открытым классам. Должен ли я добавить эту совместимость? Почему это необходимо? - person Javierd98; 01.01.2021
comment
Ну, сообщения об ошибках, кажется, соответствуют вашей конфигурации. 64-бит прямо говорит, что не может создать объект. Это нормально и ожидаемо для 64-битного клиента. Он может видеть ProgID, но не может создать объект. 32-битный говорит Неверный указатель. ИДК, что это может означать. Возможно, он не может запросить IDispatch или что-то еще. Обычно я думаю, что это ошибка E_POINTER. Я НЕ ЗНАЮ. Я не привык к библиотекам Qt или Ming или к тому, как они могут работать. Если бы это был я, я бы использовал ProcMon, чтобы увидеть, какие места в реестре читаются и какие файлы загружаются. - person Joseph Willcoxson; 01.01.2021

Хорошо, если кто-то обнаружит ту же ошибку, я объясню решение, которое я нашел. Проблема заключалась в том, что в моем случае класс C#, который я разработал, зависел от другой 32-битной dll, которая не была зарегистрирована на моем ПК. Как только я зарегистрировал другую dll, все заработало нормально.

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

Во всяком случае, я обнаружил это благодаря комментариям Джозефа, так что большое спасибо за вашу помощь.

person Javierd98    schedule 07.01.2021