Click here to Skip to main content
65,938 articles
CodeProject is changing. Read more.
Articles
(untagged)

Using ActiveX controls in MFC more efficiently

0.00/5 (No votes)
10 Aug 2004 1  
Augmenting the interface access level provided by automatic code generation.

Introduction

Hello people, and welcome to this article. It's been a while since I've written one, so if there are bad spelling or other errors, please do notify me so I can fix them.

Background

There are already several articles here on Code Project that show the basic usage of ActiveX controls in MFC programs. If you are unfamiliar on how to add an ActiveX control to your MFC project, I recommend the article Using ActiveX Controls Example: Insert Internet Explorer into your Dialogs by Hazem Nasereddin.

As for the reasons of this article, we will come back to them soon.

The problem of wrapping ActiveX controls

By following the up-mentioned article, you can easily add a control to your program, and utilize its basic functionality. However, many controls also sport other interfaces that offer advanced functionality or settings. Some of these interfaces may be hidden, or be non-creatable, so basic querying of them won't work.

For a ground up example, let's continue on where Mr. Nasereddin left off. We have the web browser control in our dialog, and it's working well. We also have the member variable in our dialog class, and the IDispatch wrapper class for methods available through IWebBrowser2 and its bases. This interface offers a huge amount of things you can do with the control.

However, after navigating to a certain multi-framed web page, we now have an arbitrary need to find our the names of the frames on this page. There would be two ways to do this: either we use the IWebBrowser2 interface to get the document, and search it through there, or we somehow get access to the ITargetFrame2 interface of the browser.

The problem that arises now is that the wrapper class that was automatically generated for us does not offer a method that could be used for getting the ITargetFrame2 interface. So, how should we proceed?

Getting into the depths of IUnknown

Luckily, the wrapper class is derived from CWnd base class. This class is designed for holding ActiveX controls, and as such, it happens to provide us with a method called CWnd::GetControlUnknown. This method gives us a copy of the pointer to the created ActiveX object's IUnknown interface.

 // Assuming that m_ctrlBrowser is the added member variable

 
 // First, here is the IUnknown pointer

 IUnknown* pUnk;
 
 // Let's get the object's interface

 pUnk = m_ctrlBrowser.GetControlUnknown();

Now, the pointer returned by GetControlUnknown is a copy of a pointer to the IUnknown. This same pointer is constantly being used by the MFC Framework to upkeep the control on your dialog. Needless to say, if you release this interface pointer, MFC ceases to be able to operate on the control, and if it happens to be that it is the last interface pointer on the object, the object will even shut itself down (self-destroy when all interfaces are released).

So, this interface pointer must NOT be released. When you no longer need the pointer, set it to NULL and forget about it.

The way up from the deep

So, what all nifty things can we do with this pointer, then? Easy enough: we now have complete access to every interface the object contains, whether they were creatable or not. We are operating on a level that was opened for us by the MFC Framework, and putting it short, we have complete access to the object.

Let's start by accessing the ITargetFrame2 interface. Following basic COM function calls, this happens by issuing the following:

 // The interface pointer

 ITargetFrame2* pFrame;
 
 // Query for it

 HRESULT hr = pUnk->QueryInterface( __uuidof( ITargetFrame2), (void**) &pFrame );

Hey! What is that __uuidof() call? This nifty function allows you to search all included modules for the GUID of an interface to which you know the name. Most type libraries (or headers generated from type libraries) grant you a short-cut by defining IID_* variables to identify the interface GUIDs. But not all of them. This function is for those 'not this time' -situations.

Final steps, conclusion

Here we are. We have a valid, working interface pointer that can be used to wreak havoc on our web browser control. The choices on what to do now are up to you. You can use the ITargetFrame2 interface pointer, or you can query for another interface on the browser control that you need.

The key issues of this article were to bring out the steps required in accessing the IUnknown interface, and through it, all other interfaces of the object. The biggest advantage of this approach is that the IUnknown pointer returned is not a newly created pointer, but a copy of an existing one. Thus, all interfaces that the object has become available, whether they were creatable or not. Just remember that all other interface pointers you query from the IUnknown one should be released normally.

For an example of accessing non-creatable interfaces, add a Microsoft RDP Client Control into your dialog. This control offers, by default, a very limited access to its interfaces, and by following this approach, all of its interfaces are available for us. Even the difficult process of automatically logging on to a Terminal Services server.

License

This article has no explicit license attached to it but may contain usage terms in the article text or the download files themselves. If in doubt please contact the author via the discussion board below.

A list of licenses authors might use can be found here