Dynamic creation and placement of ActiveX controls



Environment: VC6 SP4, NT4
- Why do we need the ability of dynamic ActiveX control creation and placement ?
- Create a simple MFC dialog based application
- Dynamic ActiveX Control creation
- Destroying the ActiveX Control
- Resizing the ActiveX Control
- Downloads
Why do we need the ability of dynamic ActiveX control creation and placement ?
Dynamic placement of ActiveX controls throws open the possibility for an application window to acquire different 'look and feel' at run time. You could think of an software application, which would be nothing more than a simple MFC created frame work, capable of loading into itself ActiveX controls written by Visual Basic developers. Such a paradigm offers the scope for customization as well.
Think of an imaginary software that should have the capability of displaying different image files like .jpg, gif, .bmp, etc. Further, individual image viewer ActiveX controls for each of the formats are also made available to us. How should you proceed? A simple approach could be to embed an instance of each of the controls on the main window, and then make visible any one of the control as per file format requirements.
Think of a software design, where in you provide a basic executable that contains a frame work and nothing else. The framework does nothing more than providing a menu, toolbar and some client space. You will let the framework application dynamicaly instantiate and load ActiveX controls into it's client space. The ActiveX controls in this case are the image viewers. While distributing my multi format image viewer product, I would also distribute the individual ActiveX controls, responsible for displaying each of the file formats (.jpg , .gif, .mpg, ..etc.)
Further, my installation package would create a registry list, containing the ActiveX control CLSID/ProgId responsible for each of the file format.
When an user, selects an image file , my product will determine the progid/clsid of the ActiveX control from the registry and instantiate that control within the application frame work, and the display the image file. The requirement from the ActiveX Control's side should be to implement a well published method/property through which I can pass on the file name, that is to be displayed by the ActiveX Control.
In this article I have created a very basic MFC dialog application, that loads an
ActiveX control when supplied with a prog id.
top
Create a simple MFC dialog based application
Create a new MFC Dialog based EXE application. Make sure that the "Enable ActiveX Controls" option is checked.
top
Dynamic ActiveX Control creation
The class CWnd provides a method CreateControl that makes ActiveX control creation very much like a normal window. Add a private member variable (name it m_ControlWrapper), of type CWnd, in the project's main dialog class.
class CYourApplicationDialog { . . . private: CWnd m_ControlWrapper; . . };
The member m_ControlWrapper will be the wrapper for our dynamically instantiated
ActiveX control.Provide a menu bar to the dialog window.
Provide a handler for the "Insert ActiveX control" menu item.
void CYourApplicationDialog::OnFileInsertcontrol() { // TODO: Add your command handler code here // // You may prompt the user for the progid of the // ActiveX control. For the sake of simplicity, I // have hard coded the prog id. The downloadable // source code provides a dialog box to key in the // desired progid CString strControlProgid; strControlProgid="mscal.calendar.7"; //calendar control // // Because we are not a MDI, we make sure to destroy // any earlier instances. // OnDestroycontrol(); // // We will make the ActiveX control occupy the entire // client area // RECT rc; ::GetClientRect(m_hWnd,&rc); // //create the ActiveX control with the given prog id // BOOL bStat=FALSE; bStat= m_ControlWrapper.CreateControl ( strControlProgid, "", WS_VISIBLE, rc, this, 5000, NULL, FALSE, NULL); if (bStat == FALSE) { ::MessageBox (m_hWnd,"Error!!", "Could not place control", MB_OK); return; } ::EnableMenuItem( ::GetMenu(m_hWnd), ID_DESTROYCONTROL, MF_ENABLED | MF_BYCOMMAND); // //display the prog id in the window's title bar // ::SetWindowText (m_hWnd,strControlProgid ); }top
Destroying the ActiveX Control
To safely unload the control we wil have to invoke CWnd::DestroyWindow. The code for control destruction is as follows:
void CYourApplicationDialog::OnDestroycontrol()
{
// TODO: Add your command handler code here
//
//Use the method CWnd::DestroyWindow()
//
m_ControlWrapper.DestroyWindow();
::EnableMenuItem(
::GetMenu(m_hWnd),
ID_DESTROYCONTROL,
MF_GRAYED | MF_DISABLED | MF_BYCOMMAND);
::SetWindowText (m_hWnd,"ActiveX Container");
}
topResizing the ActiveX Control
We will dynamicaly maintain the size of our control equal to that of the client area of the main window. To achieve this, the method IOleObject::SetExtent should be used. But unlike Win32 functions, the dimensions need to be in twips.
We will override the OnSize message handler of the main window. Here we will obtain the new client rectangle extents, convert the dimensions into twips, and then invoke the IOleObject::SetExtent method.
Use the CWnd method GetControlUnknown() to get the IUnknown interface of the ActiveX control COM object. Using the IUnknown, query for the interface IOleObject In this example, I have used the _com_ptr_t smart interface pointer class. VC++ provides such wrappers for all standard OLE interfaces. Given an interface IMyInterface, the following single statement
_COM_SMARTPTR_TYPEDEF(IMyInterface, __uuidof(IMyInterface));
will provide a smart interface pointer wrapper with the name IMyInterfacePtr. Do not forget to include the header file comdef.h .
void CYourApplicationDialog::OnSize(UINT nType, int cx, int cy) { CDialog::OnSize(nType, cx, cy); // TODO: Add your message handler code here // //update the control's dimensions, // // //make sure that we have a valid embedded control // if (m_ControlWrapper.GetControlUnknown() == NULL) return; IOleObjectPtr pOleObj(m_ControlWrapper.GetControlUnknown ()); if (pOleObj != NULL) { RECT rc; ::GetClientRect (m_hWnd, &rc); CSize size(rc.right , rc.bottom ); CClientDC dc(NULL); // //convert from pixel to twips. // dc.DPtoHIMETRIC(&size); pOleObj->SetExtent (1,(SIZEL*)&size;); pOleObj->Update();//this does not seem to be working ::RedrawWindow(m_hWnd,NULL,NULL,RDW_ALLCHILDREN | RDW_UPDATENOW | RDW_INVALIDATE); } }top
Downloads
The following binaries have been provided with this article:- Exe_client.exe:This is the main application, whose screen shots have been provided above
- Sample1.ocx:Sample OCX created using Visual Basic. (progid=CodeGuru.Sample1)
- Sample2.ocx:Sample OCX created using Visual Basic.(progid=CodeGuru.Sample2)
Download demo project - 91 Kb
Download source - 187 Kb
Comments
good job
Posted by Bahar Ali on 09/27/2012 12:09amv useful article, thanks for sharing...
ReplyVB OCX crash problem
Posted by Legacy on 02/27/2003 12:00amOriginally posted by: Bryan Welton
Hi,
Found this article very useful. However, I have hit a problem. If I create an OCX in VB which itself uses mscomctl.ocx, I get a crash occurring when I close the container.
Anyone else observed this?
--
ReplyBryan Welton
Software Engineer
ORIMOS Ltd
Couldn't put ActiveX in a child window from a MFC doc/view app
Posted by Legacy on 02/20/2003 12:00amOriginally posted by: Lucian
Is there any code of .ocx file which will add Gif Images to forms..
Posted by Legacy on 01/30/2003 12:00amOriginally posted by: G. Satyanarayanane
Dear Friends,
I would like to know how to create OCX file which enables us to add the .GIF file to the projects. It should be done in VB-6. Is it possible?? If so and if you R having any examples pls post or send email to me.
Thanks
ReplySatyanarayanane.
What about serialization?
Posted by Legacy on 10/09/2002 12:00amOriginally posted by: Alexei
I have been developing a project with dynamic creation of ActiveX controls. Unfortunately, wrapper class for my ActiveX control doesn't have Serialize(...) member, and CWnd impelemtation does nothing except calling CObect::Serialize(...) method. So the question is how to make serialization with MFC?
Reply
The Easy Way of Eventhandling
Posted by Legacy on 10/02/2002 12:00amOriginally posted by: Markus Schiefele
Thinking about my last comment, I noticed that it might be difficult to get the DISPID of the event you want to handle. So I found a more simple way of event-handling. Before you delete the control from the dialog template and remove the DDX_CONTROL entry from the MESSAGE_MAP, simply let the wizard create event-handling routines for all the events you want to handle. So the wizard will create an EVENT_SINK_MAP and will do nearly all the work for you. The only thing that remains is to change the ID of the control in the ON_EVENT macros. If you want to add more than one control on runtime, you also have to replace the ON_EVENT macros by ON_EVENT_RANGE macros. Please don't forget to add an additional VTS_I4 paramater at the beginning of the parameter list of the ON_EVENT_RANGE macros, and also an ULONG parameter to get the ID in the event-handling routines.
ReplyI think you will never have it more easily.
The Easy Way and Event Handling
Posted by Legacy on 09/30/2002 12:00amOriginally posted by: Markus Schiefele
Did anyone got an answer on how to handle events?
Posted by Legacy on 08/08/2002 12:00amOriginally posted by: Miguel Chavez
Any Ideas on how to handle event or another way of dynamically create ActiveX controls.
Thank you
Miguel
ReplyDynamic creation and placement of ActiveX controls
Posted by Legacy on 05/27/2002 12:00amOriginally posted by: Sunil Gade
This is a wonderful article.
May I take this opportunity to ask you the following questions?
Que 1: How do I handle the events in the client of such an Active x control, if created it dynamically?
Que 2: How do I create one Active X control from another Active X control. How do I make them communicate through events?
Looking forward to get the valuable guidance from you ( if possible, I would appreciate your sending the sample source code)
Yours Sincerely,
ReplySunil Gade
ActiveX vs DLL for dynamic creation
Posted by Legacy on 02/20/2002 12:00amOriginally posted by: Narayan Bhagavatula
I want to dynamically create a control from another ActiveX Control (e.g MSFlexGrid), should I create the other control with a simple DLL or make my own custom ActiveX control which is dynamically created when desired ? Which is more coding, flexible etc. etc. ?
thanks,
Narayan Bhagavatula
ReplyLoading, Please Wait ...