Writing a simple ActiveX control for IE that has one method - c++

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.

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

Handling HRESULTs in a Direct2D application

In Kenny Kerr's msdn magazine articles on imaging and Direct2D he frequently uses HR() macro.
In his Windows Imaging Component article - http://msdn.microsoft.com/en-gb/magazine/cc500647.aspx
he writes -
Finally, the WIC API makes use of HRESULTs to describe errors. The samples in this article use the HR macro to clearly identify where methods return an HRESULT that needs to be checked. You can replace this with your own error-handling strategy—whether that is throwing an exception or returning the HRESULT yourself.
HR(decoder.CoCreateInstance(CLSID_WICTiffDecoder));
However Kenny doesn't show his definition of HR(). I am a C++ beginner and am trying to discover and understand the details of the code. I would like to know what his implementation of HR() is so that I can consider how best to handle the HRESULT in my program. I have searched to find a definition but there doesn't appear to be source code for these particular articles.
Whilst learning about macros I have come across these more recent documents that propose the use of inline functions instead of macros -
http://msdn.microsoft.com/en-us/library/vstudio/ttsbh614.aspx
http://msdn.microsoft.com/en-us/library/vstudio/z8y1yy88.aspx
Can anybody tell me how Kenny defines his HR() macro? And what it actually does?
How should my Direct2D program handle HRESULTs? What is the way to make proper use of HRESULTs so that the program is reliable and resilient?
I am not sure about Kenny's macros, however I suppose that you absolutely need to know the following: error codes have most significant bit set and render the whole value negative. "Standard" macros SUCCEEDED and FAILED test codes exactly for this.
HRESULT nValue = ...
if(SUCCEEDED(nValue)) {
// Not Error
}
Then for code brevity and readability you will want a macro that does both things together: tests for success/failure and either returns on error, or throws an exception. I suppose HR macro in question does one of the two.
If you are going to use ATL, there are predefined macros of this kind already: ATLENSURE_SUCCEEDED, ATLENSURE_THROW etc. Microsoft decided to not document them though (I am not aware of a MSDN link to provide here).
Your HR could be something like (depending on desired action - to throw or exit on error):
inline VOID HR(HRESULT nValue) { if(FAILED(nValue)) AtlThrow(nValue); }
or
#define HR(x) { HRESULT nValue = (x); if(FAILED(nValue)) return nValue; }
Also, to conveniently decode WIC and D2D HRESULTs you might want to use this system tray helper app.
This MSDN article from Kenny may assist others understanding possible approaches for error handling, including throwing exceptions: MSDN - C++ and the Windows API July 2012

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

Given a COM DLL, extract all classes CLSID and corresponding interface name

My question is similar to Getting CLSID for a DLL file?, I think.
I have a directory with some DLLs, each one implementing one or more COM interfaces. I would like to get:
1) Each interface name
2) The CLSID of the class implementing the interface
For each DLL. It's important that everything can be done programatically (So I can't use some sort of COM browser and manually look up for that information).
Later I will lookup the CLSID given the interface name and call some methods using IDispatch.
One alternative seems to be scanning the registry trying to match the type, interface and class GUID and the .dll filename. But that seems to be slow and not robust.
Does someone has a clear solution to this problem?
EDIT:
With the response of Ben Voigt, I came with the following code which suit my needs:
ITypeLib *typelib;
ITypeInfo *typeinfo;
LoadTypeLibEx(_T("c:\\mydir\\mycom1"), REGKIND_NONE, &typelib);
for (UINT i = 0;i < typelib->GetTypeInfoCount();++i) {
TYPEKIND typekind;
typelib->GetTypeInfoType(i, &typekind);
if (typekind == TKIND_COCLASS) {
// class!
CComBSTR className;
TYPEATTR *typeattr;
typelib->GetTypeInfo(i, &typeinfo);
typeinfo->GetDocumentation(MEMBERID_NIL, &className, NULL, NULL, NULL);
typeinfo->GetTypeAttr(&typeattr);
GUID classGUID = typeattr->guid;
for (UINT j = 0;j < typeattr->cImplTypes;++j) {
// interface!
CComBSTR interfaceName;
HREFTYPE hreftype;
ITypeInfo *classtypeinfo;
typeinfo->GetRefTypeOfImplType(j, &hreftype);
typeinfo->GetRefTypeInfo(hreftype, &classtypeinfo);
classtypeinfo->GetDocumentation(MEMBERID_NIL, &interfaceName, NULL, NULL, NULL);
// associate interfaceName with classGUID here
}
}
}
You can't get that from the COM DLL, but you can get it from the typelib. I'm pretty sure the MIDL compiler has a switch to decompile a typelib, but parsing IDL wouldn't be as easy as using the TypeLib API.
To complicate matters, the typelib is often stored as a resource inside the DLL. So you'd extract the resource, and open it with the TypeLib API.
Start with LoadTypeLibEx which will return you an ITypeLib* interface pointer (you knew you were going to need COM in order to get information about COM libraries, right?). This will actually do the resource extraction step for you.
Then, call ITypeLib::GetTypeInfoCount to find out how many types there are. Call ITypeLib::GetTypeInfoType for each one to find the interfaces and coclasses. And call ITypeLib::GetTypeInfo followed by ITypeInfo::GetDocumentation to get the name.
It looks like you have all of this so far. Next you need the GUID of the type, which is gotten with ITypeInfo::GetTypeAttr (not ITypeLib::GetLibAttr). That gives you a TYPEATTR structure, which has a guid field.
From the same TYPEATTR structure, you'll need the cImplTypes field. That together with ITypeInfo::GetRefTypeOfImplType will let you match up each coclass to the interfaces it implements.
Note that there's not guaranteed to be a 1:1 relationship between interfaces and implementation coclasses. And the interface can be in a different library from the coclass.
Few caveats to Ben Voigt's answer: not every COM DLL has a typelib. In your case, it seems, it does; but that's not a requirement. The only rock-solid requirement is that the DLL exports the function DllGetClassObject(), where you pass a CLSID and get back an object factory.
You could load the library and call DllGetClassObject for every registered CLSID on the system (scan the registry under HKCR\CLSID for the list of those). The ones where you get a valid object back are the ones that the DLL supports. Now, in theory, it's not even a requirement that the CLSIDs the DLL supports are registered; I can envision a DLL that implements private object classes that only the intended client knows about and no one else should. But this is a very, very exotic scenario; for one thing, the regular COM mechanism of looking up the DLL path by the CLSID will break for those. The client would have to load the DLL directly.
You could also scan the registry for the CLSID's where the DLL under consideration is registered as InprocServer32; this, again, will break in case of private classes. You can do a registry search in regedit, search in data. Also, you'd have to deal with filename case issues, short vs. long names, hardlinks, environment variable substitution and so on. So I would not recommend it.
EDIT: just thought of another way. Download Regmon, run it, and call regsvr32 on the DLL. Then watch what CLSID's are touched.
You might want to look at the source code in WiX's heat utility, which does the same thing:
http://wix.sourceforge.net/manual-wix3/heat.htm