Visual Programming - MFC-OLE-COM Concepts
Visual Programming - MFC-OLE-COM Concepts
UNIT IV
CHAPTER I
1
1. User presses the left mouse button in the source view window.
2. Mouse button handler calls CRectTracker::HitTest and finds out that the cursor
was inside the tracker rectangle.
3. Handler stores formats in a COleDataSource object.
5. User moves the cursor to the view window of the target application.
6. OLE calls IDropTarget::OnDragEnter and OnDragOver for the COleDropTarget
object, which calls the corresponding virtual functions in the target's view. The
OnDragOver function is passed a COleDataObject pointer for the source object,
which the target tests for a format it can understand.
7. OnDragOver returns a drop effect code, which OLE uses to set the cursor.
2
• An in-place-capable component can run inside the container application's main
window, taking over the container's menu and toolbar,
• An embedded component can run only in its own window, and that window has a
special menu that does not include file commands.
• Embedding relies on two key interfaces, IOleObject and IOleClientSite, which are
used for in-place activation as well.
Excel spreadsheet activated inside a Word document.
2. Examine the generated files. You've got the familiar application, document, main
frame, and view file
4
Set the string's initial value to Initial default text in the document's OnNewDocument
member function.
4. Add a dialog to modify the text. Insert a new dialog template with an edit control,
and then use ClassWizard to generate a CTextDialog class derived from CDialog.
Don't forget to include the dialog class header in ex28aDoc.cpp. Also, use
ClassWizard to add a CString member variable named m_strText for the edit control.
5. Add a new menu command in both the embedded and in-place menus. Add a
Modify menu command in both the IDR_SRVR_EMBEDDED and
IDR_SRVR_INPLACE menus.
To insert this menu command on the IDR_SRVR_EMBEDDED menu, use the
resource editor to add an EX28A-EMBED menu item on the top level, and then add a Modify
option on the submenu for this item.
Next add an EX28A-INPLACE menu item on the top level of the
IDR_SRVR_INPLACE menu and add a Modify option on the EX28A-INPLACE submenu.
To associate both Modify options with one OnModify function, use ID_MODIFY as the ID
for the Modify option of both the IDR_SRVR_EMBEDDED and IDR_SRVR_INPLACE
menus. Then use ClassWizard to map both Modify options to the OnModify function in the
document class. Code the Modify command handler as shown here:
void CEx28aDoc::OnModify()
{ CTextDialog dlg;
dlg.m_strText = m_strText;
if (dlg.DoModal() == IDOK)
{ m_strText = dlg.m_strText;
UpdateAllViews(NULL); // Trigger CEx28aView::OnDraw
UpdateAllItems(NULL); // Trigger
//CEx28aSrvrItem::OnDraw SetModifiedFlag();
}
6. Override the view's OnPrepareDC function. Use ClassWizard to generate the
function, and then replace any existing code with the following line:
pDC->SetMapMode(MM_HIMETRIC);
7. Edit the view's OnDraw function. The following code in ex28aView.cpp draws a
2-cm circle centered in the client rectangle, with the text wordwrapped in the
window:
void CEx28aView::OnDraw(CDC* pDC)
{
CEx28aDoc* pDoc = GetDocument(); ASSERT_VALID(pDoc);
5
CFont font; font.CreateFont(-500, 0, 0, 0, 400, FALSE, FALSE, 0,
ANSI_CHARSET, OUT_DEFAULT_PRECIS,
CLIP_DEFAULT_PRECIS, DEFAULT_QUALITY, DEFAULT_PITCH |
FF_SWISS, "Arial");
CFont* pFont = pDC->SelectObject(&font);
CRect rectClient; GetClientRect(rectClient);
CSize sizeClient = rectClient.Size();
pDC->DPtoHIMETRIC(&sizeClient);
CRect rectEllipse(sizeClient.cx / 2 - 1000, -sizeClient.cy / 2 + 1000, sizeClient.cx / 2 +
1000, -sizeClient.cy / 2 - 1000);
pDC->Ellipse(rectEllipse);
pDC->TextOut(0, 0, pDoc->m_strText);
pDC->SelectObject(pFont);
}
8. Edit the server item's OnDraw function. The following code in the SrvrItem.cpp
file tries to draw the same circle drawn in the view's OnDraw function.
BOOL CEx28aSrvrItem::OnDraw(CDC* pDC, CSize& rSize)
{ // Remove this if you use rSize
UNREFERENCED_PARAMETER(rSize);
CEx28aDoc* pDoc = GetDocument();
ASSERT_VALID(pDoc); // TODO: set mapping mode and extent // (The extent is usually
the same as the size returned from // OnGetExtent)
pDC->SetMapMode(MM_ANISOTROPIC);
pDC->SetWindowOrg(0,0);
pDC->SetWindowExt(3000, -3000);
CFont font; font.CreateFont(-500, 0, 0, 0, 400, FALSE, FALSE, 0, ANSI_CHARSET,
OUT_DEFAULT_PRECIS, CLIP_DEFAULT_PRECIS, DEFAULT_QUALITY,
DEFAULT_PITCH | FF_SWISS, "Arial");
CFont* pFont = pDC->SelectObject(&font);
CRect rectEllipse(CRect(500, -500, 2500, -2500));
pDC->Ellipse(rectEllipse);
pDC->TextOut(0, 0, pDoc->m_strText);
pDC->SelectObject(pFont); return TRUE;
}
6
9. Edit the document's Serialize function. The framework takes care of loading and saving
the document's data from and to an OLE stream named Contents that is attached to the
object's main storage. You simply write normal serialization code, as shown here:
void CEx28aDoc::Serialize(CArchive& ar)
{
if (ar.IsStoring())
{ ar << m_strText; }
else
{ ar >> m_strText; }
}
There is also a CEx28aSrvrItem::Serialize function that delegates to the document Serialize
function.
10. Build and register the EX28A application. You must run the application directly once
to update the Registry.
11. Test the EX28A application. You need a container program that supports in-place
activation. Use Microsoft Excel 97 or a later version if you have it, or build the project in the
MFC DRAWCLI sample. Choose the container's Insert Object menu item. If this option does
not appear on the Insert menu, it might appear on the Edit menu instead. Then select Ex28a
Document from the list.
When you first insert the EX28A object, you'll see a hatched border, which indicates
that the object is in-place active. The bounding rectangle is 3-by-3-cm square, with a 2-cm
circle in the center, as illustrated here.
7
CHAPTER 2
ActiveX Controls
Introduction
Microsoft Visual Basic (VB) was introduced in 1991 and has proven to be a wildly popular
and successful application development system for Microsoft Windows
The 16-bit versions of VB supported Visual Basic controls (VBXs), ready-to-run software
components that VB developers could buy or write themselves.
VBXs became the center of a whole industry, and pretty soon there were hundreds of them.
The VBX standard, which was highly dependent on the 16-bit segment architecture, did not
make it to the 32-bit world.
ActiveX Controls (formerly known as OLE controls, or OCXs) are the industrial-strength
replacement for VBXs based on Microsoft COM technology.
ActiveX controls can be used by application developers in both VB and Visual C++ 6.0.
ActiveX controls can be written in C++ with the help of the MFC library or with the help of
the ActiveX Template Library (ATL).
8
Ordinary Controls—A Frame of Reference
These controls are all child windows that you use most often in dialogs, and they are
represented by MFC classes such as CEdit and CTreeCtrl. The client program is always
responsible for the creation of the control's child window.
Ordinary controls send notification command messages (standard Windows messages), such
as BN_CLICKED, to the dialog.
If you want to perform an action on the control, you call a C++ control class member
function, which sends a Windows message to the control.
The controls are all windows in their own right. All the MFC control classes are derived from
CWnd, so if you want to get the text from an edit control, you call CWnd::GetWindowText.
But even that function works by sending a message to the control.
Windows controls are an integral part of Windows, even though the Windows common
controls are in a separate DLL.
How ActiveX Controls Are Similar to Ordinary Controls
You can consider an ActiveX control to be a child window, just as an ordinary control is.
If you want to include an ActiveX control in a dialog, you use the dialog editor to place it
there, and the identifier for the control turns up in the resource template.
If you're creating an ActiveX control on the fly, you call a Create member function for a
class that represents the control, usually in the WM_CREATE handler for the parent window.
When you want to manipulate an ActiveX control, you call a C++ member function, just as
you do for a Windows control. The window that contains a control is called a container.
ActiveX Controls vs. Ordinary Windows Controls
How ActiveX Controls Are Different from Ordinary Controls—Properties and Methods
The most prominent ActiveX Controls features are properties and methods.
Properties have symbolic names that are matched to integer indexes. For each property, the
control designer assigns a property name, such as BackColor or GridCellEffect, and a
property type, such as string, integer, or double.
The client program can set an individual ActiveX control property by specifying the
property's integer index and its value. The client can get a property by specifying the index
and accepting the appropriate return value.
In certain cases, ClassWizard lets you define data members in your client window class that
are associated with the properties of the controls the client class contains. The generated
Dialog Data Exchange (DDX) code exchanges data between the control properties and the
client class data members.
ActiveX Controls vs. Ordinary Windows Controls
How ActiveX Controls Are Different from Ordinary Controls—Properties and Methods
ActiveX Controls methods are like functions. A method has a symbolic name, a set of
parameters, and a return value. You call a method by calling a C++ member function of
the class that represents the control. A control designer can define any needed methods,
such as PreviousYear, LowerControlRods, and so forth.
9
An ActiveX control doesn't send WM_ notification messages to its container the way
ordinary controls do; instead, it "fires events."
An event has a symbolic name and can have an arbitrary sequence of parameters—it's
really a container function that the control calls.
Like ordinary control notification messages, events don't return a value to the ActiveX
control.
Examples of events are Click, KeyDown, and NewMonth. Events are mapped in your client
class just as control notification messages are.
ActiveX Controls vs. Ordinary Windows Controls
How ActiveX Controls Are Different from Ordinary Controls—Properties and Methods
In the MFC world, ActiveX controls act just like child windows, but there's a significant
layer of code between the container window and the control window.
In fact, the control might not even have a window. When you call Create, the control's
window isn't created directly; instead, the control code is loaded and given the command
for "in-place activation." The ActiveX control then creates its own window, which MFC
lets you access through a CWnd pointer. It's not a good idea for the client to use the
control's hWnd directly, however.
A DLL is used to store one or more ActiveX controls, but the DLL often has an OCX
filename extension instead of a DLL extension.
Your container program loads the DLLs when it needs them, using sophisticated COM
techniques that rely on the Windows Registry.
Once you specify an ActiveX control at design time, it will be loaded for you at runtime.
Obviously, when you ship a program that requires special ActiveX controls, you'll have to
include the OCX files and an appropriate setup program.
Installing ActiveX Controls
Your first step is to copy the ActiveX control's DLL to \Windows\System for Microsoft
Windows 95 or \Winnt\System32 for Microsoft Windows NT. Copy associated files such as
help (HLP) or license (LIC) files to the same directory.
Your next step is to register the control in the Windows Registry. Actually, the ActiveX
control registers itself when a client program calls a special exported function. The Windows
utility Regsvr32 is a client that accepts the control name on the command line.
After you register your ActiveX control, you must install it in each project that uses it. That
doesn't mean that the OCX file gets copied. It means that ClassWizard generates a copy of a
C++ class that's specific to the control, and it means that the control shows up in the dialog
editor control palette for that project.
Installing ActiveX Controls
Choose Add To Project from the Project menu and then choose Components And Controls.
Select Registered ActiveX Controls
10
This gets you the list of all the ActiveX controls currently registered on your system.
11
Properties Methods Events
BackColor AboutBox AfterUpdate
Day NextDay BeforeUpdate
DayFont NextMonth Click
DayFontColor NextWeek DblClick
DayLength NextYear KeyDown
FirstDay PreviousDay KeyPress
GridCellEffect PreviousMonth KeyUp
GridFont PreviousWeek NewMonth
GridFontColor PreviousYear NewYear
GridLinesColor Refresh
Month Today
MonthLength
ShowDateSelectors
12
• Each of the properties, methods, and events has a corresponding integer identifier.
• Information about the names, types, parameter sequences, and integer IDs is stored
inside the control and is accessible to ClassWizard at container design time.
ActiveX Control Container Programming
MFC and ClassWizard support ActiveX controls both in dialogs and as "child windows."
To use ActiveX controls, you must understand how a control grants access to properties, and
you must understand the interactions between your Dialog Data Exchange (DDX) code and
those property values.
Property Access
The ActiveX control developer designates certain properties for access at design time.
Those properties are specified in the property pages that the control displays in the dialog
editor when you right-click on a control and choose Properties.
13
Property Access
When you click on the All tab, you will see a list of all the design- time-accessible properties,
which might include a few properties not found on the Control tab
All the control's properties, including the design-time properties, are accessible at runtime.
Some properties, however, might be designated as read-only.
14
unsigned long CCalendar::GetBackColor()
{
unsigned long result;
InvokeHelper(DISPID_BACKCOLOR, DISPATCH_PROPERTYGET,
VT_I4, (void*)&result, NULL);
return result;
}
void CCalendar::SetBackColor(unsigned long newValue)
{
static BYTE parms[] = VTS_I4;
InvokeHelper(DISPID_BACKCOLOR, DISPATCH_PROPERTYPUT,
VT_EMPTY, NULL, parms, newValue);
}
ClassWizard's C++ Wrapper Classes for ActiveX Controls
short CCalendar::GetDay()
{
short result;
InvokeHelper(0x11, DISPATCH_PROPERTYGET, VT_I2,
(void*)&result, NULL);
return result;
}
void CCalendar::SetDay(short nNewValue)
{
static BYTE parms[] = VTS_I2;
InvokeHelper(0x11, DISPATCH_PROPERTYPUT, VT_EMPTY,NULL, parms,
nNewValue);
}
ClassWizard's C++ Wrapper Classes for ActiveX Controls
COleFont CCalendar::GetDayFont()
{
LPDISPATCH pDispatch;
InvokeHelper(0x1, DISPATCH_PROPERTYGET, VT_DISPATCH,
(void*)&pDispatch, NULL);
15
return COleFont(pDispatch);
}
void CCalendar::SetDayFont(LPDISPATCH newValue)
{
static BYTE parms[] = VTS_DISPATCH;
InvokeHelper(0x1, DISPATCH_PROPERTYPUT, VT_EMPTY, NULL,
parms, newValue);
}
ClassWizard's C++ Wrapper Classes for ActiveX Controls
VARIANT CCalendar::GetValue()
{
VARIANT result;
InvokeHelper(0xc, DISPATCH_PROPERTYGET, VT_VARIANT,
(void*)&result, NULL);
return result;
}
void CCalendar::SetValue(const VARIANT& newValue)
{
static BYTE parms[] = VTS_VARIANT;
InvokeHelper(0xc, DISPATCH_PROPERTYPUT, VT_EMPTY, NULL,
parms, &newValue);
}
ClassWizard's C++ Wrapper Classes for ActiveX Controls
void CCalendar::NextDay()
{
InvokeHelper(0x16, DISPATCH_METHOD, VT_EMPTY, NULL, NULL);
}
void CCalendar::NextMonth()
{
InvokeHelper(0x17, DISPATCH_METHOD, VT_EMPTY, NULL, NULL);
}
16
ClassWizard's C++ Wrapper Classes for ActiveX Controls
The first parameter of each InvokeHelper function match with the dispatch ID for the
corresponding property or method in the Calendar control property list.
Properties always have separate Set and Get functions.
To call a method, simply call the corresponding function.
To call the NextDay method from a dialog class function, you write code such as this:
m_calendar.NextDay();
m_calendar is an object of class CCalendar, the wrapper class for the Calendar control.
18
The ActiveX control remains mapped until your program exits or until you call the
AfxOleUnlockControl function.
Example—An ActiveX Control Dialog Container
Step 1:
Verify that the Calendar control is registered. If the control does not appear in the
Visual C++ Gallery's Registered ActiveX Controls page, copy the files MSCal.ocx,
MSCal.hlp, and MSCal.cnt to your system directory and register the control by running
the REGCOMP program.
Step 2:
Run AppWizard to produce \vcpp32\ex08a\ex08a.
Accept all of the default settings but two: select Single Document and deselect Printing
And Print Preview.
In the AppWizard Step 3 dialog, make sure the ActiveX Controls option is selected, as
shown below.
Step 3: Install the Calendar control in the EX08A project.
Choose Add To Project from Visual C++'s Project menu, and then choose Components And
Controls.
Choose Registered ActiveX Controls, and then choose Calendar Control 8.0.
19
Step 4: Edit the Calendar control class to handle help messages.
Add Calendar.cpp to the following message map code:
BEGIN_MESSAGE_MAP(CCalendar, CWnd) ON_WM_HELPINFO()
END_MESSAGE_MAP()
In the same file, add the OnHelpInfo function:
BOOL CCalendar::OnHelpInfo(HELPINFO* pHelpInfo)
{
// Edit the following string for your system ::WinHelp(GetSafeHwnd(),
"c:\\winnt\\system32\\mscal.hlp", HELP_FINDER, 0);
return FALSE;
}
In Calendar.h, add the function prototype and declare the message map:
protected:
20
afx_msg BOOL OnHelpInfo(HELPINFO* pHelpInfo);
DECLARE_MESSAGE_MAP()
The OnHelpInfo function is called if the user presses the F1 key when the Calendar control
has the input focus.
We have to add the message map code by hand because ClassWizard doesn't modify
generated ActiveX classes.
• Make the Select Date button the default button. Drag the Calendar control from
the control palette.
• Then set an appropriate tab order. Assign control IDs as shown in the following
table.
Control ID
IDC_NEXTWEEK
Next Week button
21
Click on the ClassWizard Message Maps tab, and then add the message handler functions .
To add a message handler function, click on an object ID, click on a message, and click the
Add Function button.
If the Add Member Function dialog box appears, type the function name and click the OK
button.
22
Step 8: Edit the CActiveXDialog class.
Add the m_varValue and m_BackColor data members, and then edit the code for the five
handler functions OnInitDialog, OnNewMonthCalendar1, OnSelectDate, OnNextWeek, and
OnOK.
Step 8.1 : Edit the CActiveXDialog class.
void CActiveXDialog::OnNewMonthCalendar1()
{
AfxMessageBox("EVENT: CActiveXDialog::OnNewMonthCalendar1");
}
void CActiveXDialog::OnSelectDate()
{ CDataExchange dx(this, TRUE);
DDX_Text(&dx, IDC_DAY, m_sDay);
DDX_Text(&dx, IDC_MONTH, m_sMonth);
DDX_Text(&dx, IDC_YEAR, m_sYear);
m_calendar.SetDay(m_sDay);
m_calendar.SetMonth(m_sMonth);
m_calendar.SetYear(m_sYear);
23
}
void CActiveXDialog::OnNextWeek()
{
m_calendar.NextWeek();
}
void CActiveXDialog::OnOK()
{
CDialog::OnOK(); m_varValue = m_calendar.GetValue();
// no DDX for VARIANTs
}
Step 8.2 : Edit the CActiveXDialog class. (3)
The OnSelectDate function is called when the user clicks the Select Date button.
The function gets the day, month, and year values from the three edit controls and transfers
them to the control's properties. ClassWizard can't add DDX code for the BackColor
property, so you must add it by hand.
In addition, there's no DDX code for VARIANT types, so you must add code to the
OnInitDialog and OnOK functions to set and retrieve the date with the control's Value
property.
24
}
The code sets the background color to light yellow and the date to today's date,
displays the modal dialog, and reports the date returned by the Calendar control. You'll
need to include ActiveXDialog.h in ex08aView.cpp.
Step 10: Edit the virtual OnDraw function in the file ex08aView.cpp.
To prompt the user to press the left mouse button, replace the code in the view class
OnDraw function with this single line:
pDC->TextOut(0, 0, "Press the left mouse button here.");
25
CHAPTER 4
Component Object Model
26
Basic COM Concept
27
Identifying an Interface
• Human-readable name
• Globally Unique Identifier (GUID)
• Interface Identifier (IID)
28
COM Classes
• Class identifier (CLSID)
• An object of a specific class supports a certain set of interfaces
• An object’s class identifies a particular implementation of a group of interfaces
COM Library
• The COM library implements a group of functions that supply basic services to
objects and their clients
• The COM library’s services are accessed through ordinary function calls
System Registry
• The classes of all objects that the COM library will be asked to create on this machine
must be registered
• Registry mapping includes
• CLSID
• Kinds of servers
• Pathname for the file containing the server’s DLL or executable, or for where
to find remote server’s executable
Creating a Single Object
29
Reusing COM Objects
• One COM object can’t reuse another’s code through inheritance
• Containment (delegation)
Aggregation
30
Accessing a COM Object in an In-Process Server
31
Steps to Create a COM using VC++
STEP 1
STEP 2
32
STEP 3
STEP 4
33
STEP 5
STEP 6
34
STEP 7
STEP 8
35
STEP 9
• SAVE
• COMPILE by F7
36