0

First of all happy new year to everyone, hope you're doing well!

I'm working on a C++ project in which I need to call a C# DLL I created following the first answer of this post. Once I have the DLL, I need to call it from Qt, so by using dumpcpp and the .tlb file generated by regasm, I managed to get the .cpp and .h files to use my classes. Just as a reference, the namespace of the classes is Wrapper, and the main class is Device with guid {DD4A4896-C105-4C60-839B-B18C99C8FE15}.

Once I have the generated files to use the DLL, if I try to create a Wrapper:: Device instance on Qt, I get the following error:

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

It doesn't give any more information, so I tried to check if the guid was stored on the system registry (I used the regasm command explained on the previously quoted post, and It said that it was successful, but you never know). Opening Registry editor and searching for the Guid revealed that it's present at: Computer\HKEY_CLASSES_ROOT\WOW6432Node\CLSID\{DD4A4896-C105-4C60-839B-B18C99C8FE15}, which, as far as I know, is the right route for these guids, and it points to the right DLL.

I though It may be due to some kind ActiveQt problem, and as the previously quoted post explained how to use that DLL from VS C++, I decided to give it a try, using this as an another reference. I've finished with this code, which is supposed to create an instance of my Device object

#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";
}

However, this doesn't work either, the createInstance method throws an exception of Class not registered and HR=80040154. Again, according to Registry editor, the class is registered, so I don't understand the error. I've also tried with devPtr.CreateInstance("Wrapper.Device"), devPtr.CreateInstance("Wrapper::Device") or `devPtr.CreateInstance("Wrapper::CLSID_Device") as the links I posted suggest, but in those cases I get another exception with HR=800401f3 and message Invalid class string.

It doesn't matter whether VS or Qt Creator are opened as administrator or not, I get the exact same error. I have run out of ideas, and I really need to be able to use that DLL from Qt using the files generated by dumpcpp.

Does any one know what could be happening? It feels quite strange to me.

eyllanesc
  • 235,170
  • 19
  • 170
  • 241
Javierd98
  • 708
  • 9
  • 27
  • 2
    Could be 32/64 bit mismatch – David Heffernan Dec 31 '20 at 13:53
  • Please see this answer: https://stackoverflow.com/questions/9711079/class-not-registered-error-for-instantiation-of-c-sharp-object-via-com-from-vc/9711510#9711510 – Joseph Willcoxson Dec 31 '20 at 15:19
  • Thanks for help! Un fortunately, both the DLL and the executable tests I'm using are built on 32 bits (the first one with MinGW4.4.0 32bits, and the second one setting the Win32 as the platform on the VS project properties). I've checked them, and both are 32 bits. Also, I'm using .NET 4.0 version of RegAsm as commented on @JosephWillcoxson's post – Javierd98 Jan 01 '21 at 10:02

2 Answers2

0

If your C++ application is 64-bit, that's the answer right there, because your C# component is 32-bit (or MSIL but registered to the 32-bit hive). In situations like these, a simple test using VBScript is always useful.

Write a simple VB Script (test.vbs)

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

Now, run this macro 2 ways: with 32-bit and 64-bit versions of VBScript:

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

This is assuming your C# component is dispatch compatible. If it's not, then it will still give you differing results that you can use to debug.

Assuming automation/IDispatch compatible, one will work and one won't if you have registered your component correctly.

Have you registered correctly? When I use regasm, I always use the the switches /tlb /codebase when registering the C# component for COM.

Joseph Willcoxson
  • 5,853
  • 1
  • 15
  • 29
  • Thanks a lot Joseph. As I answered to your previous comment, both the DLL and the executable I'm using are 32 bits, so there should be no problem there. What surprised me after testing your VB Script is that, when using c:\windows\SysWow64\cscript.exe (the 32 bit version according to you) it fails with an invalid pointer, but when using the 64 bit version (c:\windows\system32\cscript.exe test.vbs) it returns `Microsoft VBScript runtime error: ActiveX component can't create object: 'Wrapper.Device'` How is that possible? I'm using both swithches /tlb and /codebase on RegAsm. – Javierd98 Jan 01 '21 at 10:12
  • By the way, I don't think my component is IDispatch compatible or Automation compatible, as I don't know what does it mean, and I have just added the Guid, ComVisible and ClassInterface/InterfaceType attributes to the exposed classes. Should I add that compatibility? Why is it necessary? – Javierd98 Jan 01 '21 at 10:14
  • Well, the error messages seem to be consistent with your configuration. The 64-bit outrightly says it can't create the object. That's fine and expected for a 64-bit client. It might see the ProgID, but then can't create the object. The 32-bit says "Invalid pointer". IDK what that might mean. It could be that it can't query for IDispatch or something else. I would normally think it's an E_POINTER error. IDK. I'm not used to the Qt or Ming libraries or how they might work. If it was me, I'd use ProcMon to see what registry locations are being read and what files are being loaded. – Joseph Willcoxson Jan 01 '21 at 19:43
0

Ok, in case someone find the same error, I'll explain the solution I found. The problem was that in my case, the C# class I developed depended on another 32 bits dll which was not registered on my PC. Once I registered the other dll, everything worked fine.

I don't know why VS kept telling me that the class was not registered when my class itselft was registered, it was one of its dependencies that wasn't registered.

Anyway, I discovered this thanks to Joseph's comments, so thanks a lot for your help.

Javierd98
  • 708
  • 9
  • 27