GUID explanation - C++ - c++

I use a sample from windows to learn DirectShow, and in a class I have this code in the header file:
struct __declspec(uuid("{71771540-2017-11cf-ae26-0020afd79767}")) CLSID_TextureRenderer;
And this line in the cpp file:
CTextureRenderer::CTextureRenderer(LPUNKNOWN unk, HRESULT *hr): CBaseVideoRenderer(__uuidof(CLSID_TextureRenderer), "Texture Renderer", unk, hr)
Can you explain me how that all things work together?
Thank a lot.

This is Microsoft Visual C++ extension to C++, to aid COM programming. __declspec(uuid()) associates GUID structure with a class, and __uuidof yields GUID value of a given type/expression.

Related

Can't find COM object from C++, although Guid it's registered

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.
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.
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.

Implementing Active Directory with C++ Builder

We want to implement Active Directory using C++ Builder (10.2 Tokyo). I've managed to download the SDK from Microsoft and even used C++ Builder's implib/coff2omf utilities to convert the .Lib files to work with C++ Builder.
I've found some sample code from the Microsoft docs, but now its trying to use a CComBSTR function from Microsoft. As I'm going through this the more I am doubting this is the correct way. Regardless, here's the line:
hr = pCont->Create(CComBSTR("user"), CComBSTR("cn=jeffsmith"), &pDisp );
Is there a better way to approach this?
CComBSTR is a smart wrapper class in the ATL framework for a COM BSTR string. C++Builder officially dropped support for ATL in XE (but you can still use it).
C++Builder's RTL has its own smart wrappers for BSTR (WideString and TOleString), for example:
hr = pCont->Create(WideString("user").c_bstr(), WideString("cn=jeffsmith").c_bstr(), &pDisp );

WRL SystemMediaTransportControls E_NOINTERFACE

I'm trying to use the SystemMediaTransportControls in Visual C++ using WRL (toolkit v140) but I'm having issues with the following:
Microsoft::WRL::ComPtr<ABI::Windows::Media::ISystemMediaTransportControls> controls;
HRESULT hResult = ABI::Windows::Foundation::GetActivationFactory(Microsoft::WRL::Wrappers::HStringReference(RuntimeClass_Windows_Media_SystemMediaTransportControls).Get(), &controls);
The above code is returning E_NOINTERFACE but it's working if I follow the MSDN tutorial and activate a IUriRuntimeClassFactory.
Edit: I have initialized it prior to calling those functions.
ISystemMediaTransportControls is an interface implemented on SystemMediaTransportControls class, not its activation factory. Did you intend the controls variable to be Microsoft::WRL::ComPtr<ABI::Windows::Media:ISystemMediaTransportControlsStatics> instead?

How to load registered COM DLL in C++

I have a C++ COM dll and I have register it with regsvr32. I want tho use the functions and class of the dll Inside my code. Unfortunatly I dont possess any .h and it doesnt come with a .tlb file. I have the documentation how to use the functions and class but there is no information about how to link the dll to my project so I could use it. I am new with using external COM interface so i'm not quite sur where I could find this information.
I have tried #import "example.dll" (dll inserted in the project folder but it looks like it doesn't work I have an unable to load dll error. My program is mixed CLR / unmanaged C++.
Any suggestions?
Thanks in advance
If enough information is provided, you can define the interfaces in a header file yourself. I would recommend using #import to import an existing COM type library and investigate the generated .tlh file for ideas. For a simple interface with functions, for example, the code looks something like this:
struct __declspec(uuid("Interface-Guid-with-Dashes")) IInterfaceName : IUnknown
{
virtual HRESULT __stdcall get_Value (/*[out,retval]*/ long * result) = 0;
virtual HRESULT __stdcall Execute (/*[in]*/ int value) = 0;
};

Why do my C# and C++ dlls exhibit different behavior?

I am working on a project that involves the creation of a dll that honours a certain interface in order to plug into some software in order to add functionality to it. This is done by a dll that calls my dll (I do not have the source code for the dll that does the calling). Originally I was given an interface and a C# implementation that created a COM visible dll. However after using this for a while I found I wanted to make use of some large C++ libraries and as creating wrappers would take a long time I thought about creating a C++ ATL COM dll instead. I did this and the methods of my class appear to be called correctly (I register my dll, run the program and the methods appear to be called in the correct order), however I have found some of the behavior to be different.
I am not sure how to go about explaining this as my code relates to a closed source API but perhaps if I describe an example someone might have some ideas as to where I might want look.
For instance, in the C# dll I attempt to open a file by doing this:
FMANFileControl fileControl = new FMANFileControl();
FMANFile wFile = null;
const string filePath = #"C:\Data\April 4\Data_IDA.wiff";
wFile = fileControl.GetFileObject(filePath, 1);
long numSamples = wFile.GetNumberOfSamples();
I get the correct number of samples.
In my C++ dll I have this (with some of the HRESULT checks removed in order to keep the code shorter):
std::string filePath = "C:\\Data\\April 4\\Data_IDA.wiff";
_bstr_t fileName(filePath.c_str());
IFMANFilePtr ipFMANFile;
IFMANFileControlPtr ipFMANFileControl;
hr = ipFMANFileControl.CreateInstance(__uuidof(FMANFileControl));
hr = ipFMANFile.CreateInstance(__uuidof(FMANFile));
ipFMANFile = ipFMANFileControl->GetFileObject(fileName, 1);
long numSamples = ipFMANFile->GetNumberOfSamples();
but the files does not open correctly, resulting is zero samples.
Using oleview I looked at the typelib and it says this for the function:
[id(0x00000001), helpstring("method GetWiffFileObject")]
IFMANWiffFile* GetWiffFileObject( [in] BSTR WiffFileName, [in] long sample);
The file I get information from is one that is being written to during an experiment and just before it obtains more data it calls my method and I should be able to obtain the newest file. In the C# dll this is possible, but in the C++ dll this is not. While I realize the specifics of this is hidden, I am wondering is anyone has any idea why a C++ COM dll and a C#, comvisible dll that make use of the same interface would exhibit different behavour when being called by the same dll.
I am pretty stumped at this moment so any ideas at all would be appreciated, even if they turn out to be way off base. I can share my source code if anyone thinks they might be able to help.
EDIT:
I tried the solution to answer 1, however I could not compile my code. When reading about this I found this post:
Differences between [in, out] and [out, retval] in COM IDL definitions
that seems to suggest that since the FMANFile pointer is marked [out, retval] that the method becomes:
IFMANFilePtr ExploreData::IFMANFileControl(BSTR filename, long sample);
or am I misinterpreting that article?
EDIT 2:
Got it working though I am not really sure why.
Originally I had the variables declared in the header as private member variables of the class, like this:
class ATL_NO_VTABLE CUserIDA :
public CComObjectRootEx<CComSingleThreadModel>,
public CComCoClass<CUserIDA, &CLSID_UserIDAObject>,
public IUserIDA
{
.
.
.
public:
STDMETHOD(GetSwitchCriteria)(DOUBLE* intensity, DOUBLE* minMass, DOUBLE* maxMass, VARIANT_BOOL *selectIntensity, LONG* numOfDepCycles);
.
.
.
private:
ExploreDataObjects::IFMANWiffFilePtr ipFMANWiffFile;
ExploreDataObjects::IFMANWiffFile2Ptr ipFMANWiffFile2;
};
Just to try it I moved them to the top of the class delcaration like this:
class ATL_NO_VTABLE CUserIDA :
public CComObjectRootEx<CComSingleThreadModel>,
public CComCoClass<CUserIDA, &CLSID_UserIDAObject>,
public IUserIDA
{
ExploreDataObjects::IFMANWiffFilePtr ipFMANWiffFile;
ExploreDataObjects::IFMANWiffFile2Ptr ipFMANWiffFile2;
I thought that by default these would also be private members and the same as before so I am at a loss to explain why this seemed to work. Can someone explain this?
Your C++ code is correct, except for the following line:
hr = ipFMANFile.CreateInstance(__uuidof(FMANFile));
It doesn't make any sens, because ipFMANFile is initialized once again in the next statement.
Unfortunately, this IDL declaration:
IFMANWiffFile* GetWiffFileObject([in] BSTR WiffFileName, [in] long sample);
is limited for debugging purposes since it doesn't support the native COM mechanisme for the exception reporting via HRESULT. The COM compliant declaration would be:
HRESULT GetWiffFileObject([in] BSTR WiffFileName, [in] long sample, [out, retval] IFMANWiffFile** fileInstance);
I believe that you are unable to change the library's code so I suggest you to try some external debugging tools like 'procmon.exe' and 'dbgview.exe' to inspect the application events when you run the CPP test case. Look for all failed actions.
I hope this will help you somehow