Click here to Skip to main content
Licence CPOL
First Posted 10 Aug 2004
Views 44,535
Bookmarked 25 times

Using ActiveX controls in MFC more efficiently

By | 10 Aug 2004 | Article
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, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)

About the Author

Antti Keskinen

Software Developer
Cybercom Finland Oy
Finland Finland

Member

I live in the Frozen North, in Finland. Although the opportunities for good jobs or sunny days are scarce here, I still like it here. But at some point I'll move abroad.. Oh, and yes, there ARE polar bears in here Smile | :)
 
I graduated as a B.Sc in Computer Science in 2006, and currently I'm employed by Cybercom Finland Oy, a world-wide software house. I mainly develop Windows Desktop software using Qt and other relevant technologies.
 
When I'm not knee-depth in the code, I play computer games, Go or go to the gym. I love music, in all it's forms, and dancing is close to my heart. Or then I spend time with my friends. I like friends. You can never have enough of them Smile | :)
 
I'm a keen player of games. Simulations and RPG are the key words. Old-time games such as Mega Man are good as well, not forgetting the block-buster hits either.

Sign Up to vote   Poor Excellent
Add a reason or comment to your vote: x
Votes of 3 or less require a comment

Comments and Discussions

 
You must Sign In to use this message board. (secure sign-in)
 
Search this forum  
 FAQ
    Noise  Layout  Per page   
  Refresh
Newshello Pinmemberyangckw15:08 29 Dec '10  
QuestionFile operation & stock event Pinmemberankea16:44 23 Jul '06  
AnswerRe: File operation & stock event PinmemberAntti Keskinen0:07 24 Jul '06  
GeneralDetails for the Very Big Problem Pinmembercharfeddine_ahmed0:32 11 Jul '06  
Thank u very much for your reply..
 
in fact those ActiveX controls are thir party components here's a detailed description hoping you help me if you can :
 
first of all here's my original message i posted :
 
"
i have many resembling activex controls. they are infact controls that controls different types of IP Surveillance Camera. I need to develop an application that is independent of them, ie access them independently, so that when i add new control for a new camera, the application needs not be recompiled. so the code has to be external to the application, more than that the linking should be explicit and at execution time rather at load time.
I tried using a DLL which contains a Cwnd object that embeds the activex control in order to declare the EventSink map there and be able to capture events and then relay them to the application by telling the Dll to link to its caller module.
but i did'nt even succeed to make calls in the direct sense, ie application-->exp Dll functions-->Cwnd member functions-->activex specific members, so to create the object etc, the problem being MFC-class pointer can't pass between app and Dll !!?
So can you give me a way how to encapsulate the different activex components in an abstract one. i tried to see COM, but unsuccessfully: is there a sort of activex control inheritance at least ?
 
"
here's some other details (Note for the ActiveX control, i do'nt know in which language they were written, but i can access them via C++, by building an MFC proxy class ( Create New class-->MFC class from ActiveX ) then integrate that class into a container where i insert the EventSink Map. Well i succeeded 100% in integrating evry control, and capturing its events, etc, but it's just about encapsulation)
 
the detail :
 
"
the activex control i'm talking about are as i understood a sort of COM objects, which are to me classes that can be instantiated at execution time, so the dll needs not an implicit link to the client exe.
i have an application that access different camera on the network through those particular activex control, the code being like this :
 
for example for an axis camera, in the main view window i call
m_Axis.Create(...,this,CRect(..),..); ( m_Axis being here an object of an MFC proxy class to an activeX control (Axis Camera Media Control)).
and of course i handle the onsize member function :
 
so you can see that the activex control is even responsible for rendering the video stream. other members do the connection, allow me to get a handle to the image being displayed, etc.
 
so my problem is that i do'nt want the code to be integrated into my application, in order for the application not to depend on those control. so i want some sort of specification such the application can load and talk independently to those objects.
 

the code would look like :
CcameraControl *_cam[5];
 
and when the user adds a camera to be controled by the application, a dialog prompting for its ip address, and very possibly its type, appears, then i use the type information to localize the control which is then loaded into a case of the table above.
 
so i need to encapsulate, create new controls for evry activex, such that those control have the same functions and can talk to the caller-application using a same mechanism.
 
here's what i tried :
 
i thought i must derive new classes from the activex control, such those classes have the same functions. they need to relay the control from the application to their parent specific services. and capture events back from their parent and relay them to the application, but here i came to the inevitable ad the impossible :
although succeeding in encapsulating the controls into uniform components, there is no WAY for those classes to be loaded at the execution time and behave as true plug-in components. for example for MFC, if there is a wa&y to write a dll that exports some classes dervived from mfc classes, that dll need be implicitly linked to the exe, and this latter wouldn't succeed even to load without her.
 

i thought about COM, i tried to see ATL examples, but in vain.
 
so what i did was to create a simple dll, that can access mfc, then in the CWinApp object i declared a Cwnd object ( acontainer for the specific control) and to there i shifted an activex control data member: when the window is created, it creates the control in its area. i declared the eventsink map in the CWnd so to capture the events. and then you have simple plain exportable functions that enable the caller to create the internal CWnd object and calles its members. but since i need to pass a parent window (originating from the application interface classes) then the problem i talked about comes ( mfc pointer) ( you told me that this problem can be solved)
 

if you think you do better help if you look at the code then i send an application which embeds different activex control for different camera types but which accesses them differently, each according to its interface, then i'll send you the code. (i do'nt have your email )
 

here's also what i am trying now at the time when you sent your reply :
a new MFC ActiveX project, thinking i can apply the containment principle :
an abstract, wrapper Control contains the specific one, relay the evnts in either senses, but it just didn't work, the specific activex control create function fails when the OnCreate container member function is called to load the global control"
 
Thank u in advance.
 
YOURS Ahmed Charfeddine.
GeneralVery Big Problem Pinmembercharfeddine_ahmed2:18 10 Jul '06  

General General    News News    Suggestion Suggestion    Question Question    Bug Bug    Answer Answer    Joke Joke    Rant Rant    Admin Admin   

Use Ctrl+Left/Right to switch messages, Ctrl+Up/Down to switch threads, Ctrl+Shift+Left/Right to switch pages.

Permalink | Advertise | Privacy | Mobile
Web01 | 2.5.120529.1 | Last Updated 11 Aug 2004
Article Copyright 2004 by Antti Keskinen
Everything else Copyright © CodeProject, 1999-2012
Terms of Use
Layout: fixed | fluid