Step 2: Creating an ActiveX Control with ATL
This step shows how to create an ActiveX control with the Ctrl class defined in Step 1: Preparing the Program. The ActiveX control you will obtain once this step is completed has a minimal interface.
You are going to:
-
Add the initialization and destruction of the display in the DllMain function.
-
Add a new windows message handler to the CDemoATLCtrl class.
Create a new project.
-
In Visual C++, choose New > Project from the File menu and select ATL Project template to create a new project.
-
Type DemoATL in the Project name text field and click OK.
The ATL Project Wizard is displayed.
-
Select the Dynamic Link Library (DLL) option and leave Allow merging of proxy/stub code, Support MFC, and Support of MTS unchecked.
Note These options are not required for this tutorial. But you might have to select them for your own purposes later, depending on what you want to obtain.
-
Click Finish and OK.
Add a new ATL object.
-
Click the ClassView tab of the Project Workspace window to activate it, if necessary, and click the DemoATL classes label with the right mouse button.
-
Select Add > Class from the menu that appears. In the dialog box choose ATL Control.
-
An ATL Control Wizard is displayed.
-
Type DemoATLCtrl in the Short Name text field.
-
The other fields are automatically filled with labels. Leave these as they are.
-
Click the Options tab, select Apartment as Threading model, the Dual Interface, and select Yes in Aggregation. Also check the Support Connection Points option.
-
Click the Appearance tab and select Opaque, Solid Background, NormalizeDC, Insertable and Windowed Only.
-
Leave the other options unchecked. No Stock Properties are declared.
Note
The selected options may be different, depending on what you want to obtain. |
Add files to the project.
-
Add the files ctrl.cpp and ctrl.h to the project.
-
Create the DemoCtrl.h file and add it to the project.
This file should contain the declaration of the DemoCtrl class that follows. This class initializes the control. It also provides an interface between the code generated by the wizard and the Views code and/or the Ctrl class.
class DemoCtrl : public Ctrl
{
public:
DemoCtrl(HWND parent);
~DemoCtrl();
static IlvDisplay* getDisplay()throw() { return _Display; }
static bool InitDisplay(HINSTANCE hInstance) throw();
static void CleanDisplay();
private:
DemoCtrl(const DemoCtrl&); // Not defined to avoid
// default copy constructor.
DemoCtrl(); // Not defined to avoid default constructor.
static IlvDisplay* _Display;
};
-
Create the DemoCtrl.cpp file and add it to the project.
This file defines the member functions of the DemoCtrl class that are not declared inline and the static class variable _Display.
-
The constructor DemoCtrl(HWND parent) calls the corresponding constructor of the Ctrl class:
DemoCtrl::DemoCtrl(HWND hWnd)
: Ctrl(_Display, reinterpret_cast<IlvSystemView>(hWnd))
{
}
-
The static member function InitDisplay creates an instance of IlvDisplay and stores it into _Display.
bool
DemoCtrl::InitDisplay(HINSTANCE hInstance) throw ()
{
try {
_Display = new IlvDisplay(hInstance, "ATL Views Sample");
if (!_Display || _Display->isBad()) {
IlvFatalError("Can’t initialize IlvDisplay.");
if (_Display) {
delete _Display;
_Display = 0;
}
}
}
catch(...) {
CleanDisplay();
}
return _Display ? true : false;
}
-
The static function CleanDisplay releases the instance of IlvDisplay stored in _Display.
void
DemoCtrl::CleanDisplay()
{
if (_Display) {
delete _Display;
_Display = 0;
}
}
-
Add the initialization and destruction of the display in the DllMain function.
Use the static member functions of the DemoCtrl class as follows:
-
Locate the DllMain function and add the following code to its implementation:
switch (dwReason) {
case DLL_PROCESS_ATTACH:
if (!DemoCtrl::InitDisplay(hInstance))
return FALSE;
break;
case DLL_PROCESS_DETACH:
DemoCtrl::CleanDisplay();
break;
default:
break;
}
-
Include the header file DemoCtrl.h.
Add a private member variable for CDemoATLCtrl.
-
Expand DemoATL classes and select CDemoATLCtrl.
-
Press the right mouse button and choose Add > Variable.
-
Enter DemoCtrl* in the Variable Type field.
-
Enter m_Ctrl in Variable Name field and click OK.
Add a new windows message handler to the CDemoATLCtrl class.
-
In the CDemoATLCtrl constructor (file DemoATLCtrl.h) add the following line to make control windowed
m_bWindowOnly = TRUE;
-
Locate the BEGIN_MSG_MAP declaration in DemoATLCtrl.h.
-
In the BEGIN_MSG_MAP declarations, add the following code:
MESSAGE_HANDLER(WM_CREATE, OnCreate)
-
Add the following public function to the CDemoATLCtrl class (file DemoATLCtrl.h):
LRESULT OnCreate (UINT uMsg, WPARAM wParam, LPARAM
lParam, BOOL& bHandled) {
try {
m_Ctrl = new DemoCtrl(m_hWnd);
} catch (...) {
if (m_Ctrl) {
delete m_Ctrl;
m_Ctrl = 0;
}
}
return 0;
}
Modify the DemoATLCtrl.h file generated by the wizard.
Modify the file DemoATLCtrl.h generated by the wizard to create the instance of the class DemoCtrl used by the application as follows:
-
Include the header file DemoCtrl.h in the file DemoATLCtrl.h.
-
Initialize the variable m_Ctrl to 0 in the constructor (file DemoATLCtrl.h):
CDemoATLCtrl()
// Added for Views.
: m_Ctrl(0)
// End Added for Views.
{
m_bWindowOnly = TRUE;
}
Modify the DemoATL.rc file.
Add the following line at the end of the file DemoATL.rc.
#include "viewsdata.rc"
Modify the project settings.
-
Open the project property pages.
-
In the Project Settings dialog box, select the Debug configuration and click the C/C++ tab.
-
Select the General or Preprocessor option in the Category drop-down list and replace the preprocessor definition _DEBUG by NDEBUG.
-
Select All Configurations and click the C/C++ tab if necessary.
-
Select the General or Preprocessor option in the Category drop-down list and add ILVSTD in the “Preprocessor definitions” text field.
-
Select Code Generation in the C/C++ category and select Yes (/EHSC) for Enable C++ Exceptions and select Multi-threaded(/MT) for Runtime Library.
-
Select Language in the C/C++ category drop-down list Enable Run-Time Type Information (RTTI).
-
Select General in the C/C++ category and type the following line in the Additional include directories text field:
".;c:\Perforce\views\include"
Here we assume that Views is installed in C:\Perforce\views\.
-
Select “Precompiled headers” in the Category drop-down list and select the option “Not using precompiled headers” for the files ctrl.cpp and DemoCtrl.cpp.
Because of the initialization mechanism of Views, most of the Views headers cannot be precompiled.
-
In the Linker category, select General in the category and add the path to the Views stat_mta libraries to the "Additional library path" text field:
Ex: c:\Perforce\views\lib\x86_.net2010_10.0\stat_mta
-
Select Input in the Linker category and add the Views libraries (that is, winviews.lib, views.lib, and ilvgadgt.lib) and also the wsock32.lib and imm32.lib libraries in additional dependencies.
-
Select all the Release configurations and remove _ATL_MIN_CRT from the “Preprocessor definitions” text field.
This option must be removed because the standard C++ runtime library is used. However, this option may not be present in your generated ATL project as this option is deprecated since Microsoft Visual Studio 2008 (9.0).
Build the ActiveX control.
Now you can build the ActiveX control and test it. The wizard generates an html file, DemoATLCtrl.htm, that you can use to load the ActiveX control in Internet Explorer.
Since the default size of the ActiveX control is small, you can modify its width and height as follows:
<OBJECT WIDTH=400 HEIGHT=400 ID="DemoATLCtrl" CLASSID="CLSID:3B10417D-3E6C-
11D3-B74F-00C04F68A89D"></OBJECT>
Note
Since the class id is generated, the class id in your file can be different from the one in this example. |