WRL SystemMediaTransportControls E_NOINTERFACE - c++

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?

Related

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 );

Implementing IServiceProvider in an MFC application

I need to implement the IServiceProvider interface in an open source MFC application; specifically my TTSApp application.
I am attempting to add support for the IAccessibleApplication interface, which is used by screen readers to obtain information about an application's name and version information.
It appears that Google Chrome implements the IServiceProvider interface via the AXPlatformNodeWin class, which is derived from the CComObjectRootEx class and other classes and interface. The problem is that an MFC application does not use the CComObjectRootEx class; it is used by ATL.
I have found the IServiceProviderImpl Class. Unfortunately, I cannot find any information on how it fits in the context of an application. Which class in my class hierarchy needs to be derived from the IServiceProviderImpl Class; my CWinApp derived class, my CDialogEx derived class, or some other class?
I learned a great deal while on my quest in search for an answer to this question. During the quest I fell down the rabbit hole (Alice's Adventures in Wonderland by Charles Lutwidge Dodgson, a.k.a. Lewis Carroll) only to find Cthulhu (The Call of Cthulhu by H. P. Lovecraft) waiting for me.
My initial research led me to the following macros defined in afxwin.h.
DECLARE_INTERFACE_MAP
BEGIN_INTERFACE_MAP
END_INTERFACE_MAP
BEGIN_INTERFACE_PART
END_INTERFACE_PART
The best documentation I could find for these macros is in the TN038: MFC/OLE IUnknown Implementation technical note. A good sample demonstrating the use of these macros and the implementation of the QueryService function is the TstCon sample.
Of course, this led to another question, what window do I need to do this for? To answer this question I looked at the source code of a certain screen reader to see how it uses the IAccessibleApplication interface.
The following function, though not the actual code used, demonstrates the technique (I cannot share the actual code since the screen reader is not open source).
std::wstring GetApplicationNameUsingTheIAccessibleApplicationInterface(
HWND hwnd, long idObject, long idChild)
{
CComPtr<IAccessible> acc;
CComVariant var;
auto hr = AccessibleObjectFromEvent(hwnd, idObject, idChild, &acc, &var);
if (hr != S_OK) return L"";
if (!acc) return L"";
CComQIPtr<IServiceProvider> serviceProvider = acc;
if (!serviceProvider) return L"";
CComQIPtr<IAccessibleApplication> application;
hr = serviceProvider->QueryService(
IID_IAccessible, __uuidof(IAccessibleApplication),
reinterpret_cast<void**>(&application));
if (FAILED(hr)) return L"";
if (!application) return L"";
CComBSTR appName;
hr = application->get_appName(&text);
if (FAILED(hr)) return L"";
return appName.m_str;
}
This function, or something like it, is called from our WinEventProc callback function in response to the EVENT_OBJECT_FOCUS event. This indicates that I need to do this for every window that can gain focus.
Armed with what I thought was the answer to my question, I dove in and implemented the IAccessibleApplication interface and added the necessary code to all of my focus-able windows. Much to my horror, my QueryService function was never called. When I debugged the screen reader to find out why, I discovered that the implicit QueryInterface implied by the following line of code failed.
CComQIPtr<IServiceProvider> serviceProvider = acc;
This led to a long and arduous quest to discover why the call to QueryInterface was failing.
I was working on a personal project at first so I could not call upon resources I have at my employer. Then, entirely by chance, I was assigned a task that required me to provide information on how to implement the IAccessible2 interface in a C++ application to a client who needed the information to help them make their applications more accessible. Hurrah, I was finally able to call upon coworkers for aid!
My coworker guided me down the correct path.
Create a customized version of the IAccessibleProxyImpl class and CAccessibleProxy class using source code obtained from atlacc.h.
Add a COM_INTERFACE_ENTRY for IAccessibleApplication in the COM_MAP (BEGIN_COM_MAP/END_COM_MAP) for my custom IAccessibleProxyImpl class.
Use the BEGIN_SERVICE_MAP, END_SERVICE_MAP, and SERVICE_ENTRY macros to provide an implementation of the IServiceProvider interface.
Provide an override for the CWnd::CreateAccessibleProxy function to cause my windows to use my custom accessible proxy and thus my implementation of the IAccessibleApplication interface.
Now the screen reader uses the application name I provide for the IAccessibleApplication interface for my application.
The application I did this for is open source. It is my TTSApp application. I have also made an example that demonstrates how to use a similar technique to support the IAccessible2 interface available here.
I am sharing this in the hopes that the information will prove to be helpful.

C# COM dll has REGDB_E_CLASSNOTREG error in C++ project

I have a C# dll that I properly have registered for COM Interop, and made COM visible. Using cppbuilder, I imported the type library, which generated the wrapper classes, and I am now attempting to use to create an instance of my C# class. However, I'm getting a REGDB_E_CLASSNOTREG error in my C++ code. I verified the dll is in the registry, and even re-registered it with regasm. No change. What could I be missing?
Here is my C++ code:
_MyClassPtr obj;
HRESULT hr = obj.CreateInstance(__uuidof(MyClass));
//now hr equals REGDB_E_CLASSNOTREG
I've also tried it as such:
IMyClass* obj;
HRESULT hr = CoCreateInstance(__uuidof(MyClass), NULL, CLSCTX_INPROC_SERVER, __uuidof(IMyClass), (void**) &obj);
//same result, hr equals REGDB_E_CLASSNOTREG
I do have one additional dependency in the C# app. I registered it for COM as well with no difference, but did not import it's type library into the C++ project.
UPDATE: based on the comments below, I discovered that CreateInstance is looking up the class guid in the following places in the registry:
HKCU\Software\Classes\Wow6432Node\CLSID\{guid}
HKCR\Wow6432Node\CLSID\{guid}
HKCU\Software\Classes\CLSID\{guid}
HKCR\CLSID\{guid}
But, going through the registry, the only entry under any of the CLSID nodes that is related to my assembly is the guid for the assembly itself, which is, of course, different than the guid for the class, or the interface.
I've manually run regasm under both x86 and x64 mode to try to acheive different results. No differences.
Well, I found out what would work.
IMyClassPtr obj;
HRESULT hr = obj.CreateInstance(CLSID_MyClass);
CLSID_MyCLass was a guid constant in the generated MyClass_TLB.cpp file. Using it instead of __uuidof(...) for the class types enabled everything to start working correctly.

Writing a simple ActiveX control for IE that has one method

I'm learning how to write a scriptable ActiveX control. My goal is to have a tiny control that can check to see if something is installed on the system. What I've done so far is:
Create a MFC ActiveX control project in VS2008
Add some 'safe for scripting' bits that I found here.
Extend the IDL to provide my "IsInstalled" method, which for now returns TRUE unconditionally (but will later read some keys from the registry.)
Build the control and run regsvr32 on it. I verified that it does show up in HKEY_CLASSES_ROOT, and when I instantiate the object, the IE Developer Tools "Locals" pane shows that the object is of type _D[my plugin name]. Not only that, but my IsInstalled() method shows up underneath that object.
However, when I call IsInstalled(), I just can't get it to work:
JScript Debugger - Breaking on JScript runtime error -(n http://img138.imageshack.us/img138/1586/whycomwhy.png
I'm at a loss. I've also tried making IsInstalled a property instead of a method, using VARIANT_BOOL instead of boolean instead of BOOL in the IDL, you name it.
Here's the relevant excerpts of code.
The header:
afx_msg VARIANT_BOOL IsInstalled();
The implementation:
afx_msg VARIANT_BOOL
CMyAXCtrl::IsInstalled()
{
return TRUE;
}
The dispatch map:
BEGIN_DISPATCH_MAP(CMyAXCtrl, COleControl)
DISP_FUNCTION_ID(CMyAXCtrl, "IsInstalled", dispidIsInstalled, IsInstalled, VT_BOOL, VTS_NONE)
END_DISPATCH_MAP()
The dispatch part of the IDL:
[ uuid(6B662202-CF13-4144-AA33-C3FEE9C2C962),
helpstring("Dispatch interface for My Control")]
dispinterface _Daxplugin
{
properties:
methods:
[id(1)] VARIANT_BOOL IsInstalled();
};
If there's any other relevant bits of code I should provide, let me know. But I'm stumped here. Thank you in advance!
You almost certainly have the wrong prototype for a scriptable function. OLE Automation for scripting languages tends to rely on returning a HRESULT then using an out parameter for the actual return code.
So change it to
[id(1)] HRESULT IsInstalled(VARIANT_BOOL* p);
Also TRUE != VARIANT_TRUE, you must return VARIANT_TRUE which is equal to -1 instead of 1.
Hope some of that actually helps, but without the actual error I might be mistaken :)
You could mark your control as save for scripting by implementing IObjectSafety or by marking the Object as save while registering it (as supposed by the link you provided).
Have you run regsvr32 after adding the code to mark it save for scripting?
You can check the registry if your control has the safe for scripting bits set.
If the bits are set you will find the two keys {7DD95802-9882-11CF-9FA9-00AA006C42C4} (Safe for Initialization)
{7DD95801-9882-11CF-9FA9-00AA006C42C4}(Safe For Scripting) as subkeys of ImplementedCategories in your object.
I would suggest to implement IObjectSafety since it doesn't depend on your class to register itself.

Problems accessing uccapi.dll COM interface C++

I'm working on a project involving the Microsoft Unified Communications Client API; uccapi.dll. I'm also using Codegear C++Builder 2010, not Visual Studio. After registering the dll with regsvr32 and importing it as type library into C++Builder 2010, uccapi_tlb- and uccapi_ocx-files were generated. When having imported these into my new project I'm trying to follow the msdn guideline for creating a Office Communicator Client able of signing into the Office Communication server.
In this regard I have two questions:
What is the correct way of accessing the com-interfaces made available through the ocx?
I've so far found several ways of creating access points, such as.
TCOMIUccPlatform plat;
plat = CoUccPlatform::Create();
and
IUccPlatformPtr im;
im = CreateComObject(CLSID_UccPlatform);
and
IUccPlatform* pIUccPlatform;
hr = CoCreateInstance(CLSID_UccPlatform,
NULL,
CLSCTX_INPROC_SERVER,
__uuidof(IUccPlatform),
(void**)&pIUccPlatform);
and
IUccPlatformPtr pIPlat;
pIPlat.CreateInstance(__uuidof(IUccPlatform));
The three first seem to work well. The latter will give me an Assertion failed: intf!=0 error with 0×40000015 exception. Using any of the three top ones I can access methods and initialize the platform interface.
However when trying any of the same tactics to access any other interface, such as IUccContext, IUccUriManager or IUccUri, all of which have a clsid defined in the _tlb.h file, I either get a "class not registered" error in the first two cases, or a hresult failure in the third case. Which brings me to my next question.
Using ole-viewer all interfaces are registered as they should. Why wouldn't all co-creatable classes in the dll be registered when registering the dll? And what could be the reasons why don't they act similarly?
Edit1 from UCCAPILib_tlb.h:
//
// COCLASS DEFAULT INTERFACE CREATOR
// CoClass : UccPlatform
// Interface: TCOMIUccPlatform
//
typedef TCoClassCreatorT<TCOMIUccPlatform, IUccPlatform, &CLSID_UccPlatform, &IID_IUccPlatform> CoUccPlatform;
//
// COCLASS DEFAULT INTERFACE CREATOR
// CoClass : UccUriManager
// Interface: TCOMIUccUriManager
//
typedef TCoClassCreatorT<TCOMIUccUriManager, IUccUriManager, &CLSID_UccUriManager, &IID_IUccUriManager> CoUccUriManager;
This issue is already being discussed in detail in the Embarcadero forums.