VC++ static BYTE udfparmss[] =

The techniques and steps on how to use the ActiveX controls from the MFC class library through C++ programming
Module 18:
Using ActiveX Controls
Program examples compiled using Visual C++ 6.0 (MFC
6.0) compiler on Windows XP Pro machine with Service Pack 2. Topics and sub
topics for this Tutorial are listed below:
Using ActiveX Controls
ActiveX Controls vs. Ordinary
Windows Controls
Ordinary Controls: A Frame of
How ActiveX Controls Are Similar
to Ordinary Controls
How ActiveX Controls Are Different
from Ordinary Controls: Properties and Methods
Installing ActiveX Controls
The Calendar Control
ActiveX Control Container Programming
Property Access
ClassWizard's C++ Wrapper Classes
for ActiveX Controls
AppWizard Support for ActiveX
ClassWizard and the Container
Dialog Class Data Members vs.
Wrapper Class Usage
Mapping ActiveX Control Events
Locking ActiveX Controls in
Using ActiveX Controls
Microsoft Visual Basic (VB) was introduced
in 1991 and has proven to be a wildly popular and successful application
development system for Microsoft Windows. Part of its success is attributable
to its open-ended nature. The 16-bit versions of VB (versions 1 through
3) 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. At
Microsoft, the Microsoft Foundation Class (MFC) team figured out a way
for Microsoft Visual C++ programmers to use VBXs in their programs,
The VBX standard, which was highly dependent
on the 16-bit segment architecture, did not make it to the 32-bit world.
Now ActiveX Controls (formerly
known as Object Linking and Embedding
(OLE) controls or OCXs) are the industrial-strength replacement for
VBXs based on Microsoft Component
Object Model (COM) technology. ActiveX controls can be used
by application developers in both VB and Visual C++ 6.0. While VBXs
were written mostly in plain C, ActiveX controls can be written in C++
with the help of the MFC library or with the help of the
ActiveX Template Library (ATL). This module is not about writing ActiveX
it's about using them in a Visual C++ application. The premise
here is that you can learn to use ActiveX controls without knowing much
about the COM on which they're based. After all, Microsoft doesn't require
that VB programmers be COM experts. To effectively write ActiveX controls,
however, you need to know a bit more, starting with the fundamentals
of COM. Consider picking up a copy of Adam Denning's ActiveX Controls
Inside Out (Microsoft Press, 1997) if you're serious about creating
ActiveX controls. Of course, knowing more ActiveX Control theory won't
hurt when you're using the controls in your programs.
An ActiveX Controls
vs Ordinary Windows Controls
An ActiveX control is a
software module that plugs
into your C++ program the same way a
Windows control does. At least that's the way it seems at first.
It's worthwhile here to analyze the similarities and differences between
ActiveX controls and the controls you already know.
Ordinary Controls:
A Frame of Reference
, you used
ordinary Windows controls
such as the edit control and the list box, and you saw the
Windows common controls that
work in much the same way. These controls are all child windows that
you use most often in dialogs, and they are represented by MFC classes
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
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. Another species
of ordinary control, the so-called custom
control, is a programmer-created control that acts as an ordinary
control in that it sends
WM_COMMAND
notifications to its parent window and receives user-defined messages. You'll
see one of these in
. So many control huh!
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
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.
How ActiveX Controls Are Different
from Ordinary Controls: Properties and Methods
The most prominent ActiveX Controls features are
properties and
methods. Those C++ member functions that you call to manipulate
a control instance all revolve around properties and methods. Properties have
symbolic names that are matched to integer indexes. For each property, the control
designer assigns a property name,
GridCellEffect, and a
property type, such as string, integer,
or double. There's even a picture type for bitmaps and icons. 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
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.
An ActiveX control doesn't send
WM_ notification
messages to its container the way
instead, it &fires events.&
An event has a symbolic name and
can have an arbitrary se 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
KeyDown, and
NewMonth. Events are mapped in your client class just as control
notification messages are. 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
the control's window isn' 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
pointer. It's not a good idea for the client to use the control's
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.
For the time being, simply accept the fact that 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 an ActiveX Controls
Let's assume you've found a nifty ActiveX control
that you want to use in your project. Your first step is to
copy the control's DLL to your hard disk.
You could put it anywhere, but it's easier to track your ActiveX controls if
you put them in one place, such as in the system directory (typically \Windows\System
for Microsoft Windows 95, Xp or \Winnt\System32 for Microsoft Windows NT, 2000).
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.
Regsvr32 is suitable for installation
scripts, but another program, RegComp.
Some controls have licensing requirements, which might involve
extra entries to the Registry. Licensed
controls usually come with setup programs that take care of those details. 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.
To install an ActiveX control in a project, choose
Add To Project from the
Project menu and then choose
Components And Controls. Select
Registered ActiveX Controls, as shown
in the following illustration.
Figure 1: Adding ActiveX controls to a project.
Figure 2: Browsing registered ActiveX controls.
This gets you the list of all the ActiveX controls
currently registered on your system. A typical list is shown here.
Figure 3: A list of all the ActiveX controls currently
registered on the system.
The Calendar Control
The MSCal.ocx
control is a popular Microsoft ActiveX Calendar
control that's probably already installed and registered on your computer. Figure
4 shows the Calendar control inside
a modal dialog.
------------------------------------------------------------------
Figure 4: The
Calendar control in use.
The Calendar
control comes with a help file that lists the control's
properties,
methods, and
events shown here.
Properties
AfterUpdate
BeforeUpdate
DayFontColor
PreviousDay
GridCellEffect
PreviousMonth
PreviousWeek
GridFontColor
PreviousYear
GridLinesColor
MonthLength
ShowDateSelectors
ShowHorizontalGridlines
ShowVerticalGridlines
TitleFontColor
ValueIsNull
Table 1: ActiveX Calendar’s properties,
methods and events.
You'll be using the
BackColor,
Month, Year, and
Value properties in the MYMFC24
example later in this module. BackColor
is an unsigned long, but it is used as an
OLE_COLOR,
which is almost the same as a
Month, and Year are
short integers. Value's type is
the special type
which holds the entire date as a 64-bit value. Each of the properties, methods,
and events listed above 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 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.
The Calendar control's main property
page looks like the one shown next.
Figure 5: Calendar Control properties.
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. The
Calendar control's
All page looks like this.
Figure 6: A list of all the
design- time-accessible Calendar control
properties.
All the control's properties, including the design-time
properties, are accessible at runtime. Some properties, however, might be designated
as read-only.
ClassWizard's C++ Wrapper Classes
for ActiveX Controls
When you insert an ActiveX control into a project,
ClassWizard generates a C++ wrapper class,
derived from
which is tailored to your control's methods and properties. The class has member
functions for all properties and methods, and it has constructors that you can
use to dynamically create an instance of the control. ClassWizard also generates
wrapper classes for objects used by the control. Following are a few typical
member functions from the file Calendar.cpp
that ClassWizard generates for the Calendar
long CCalendar::GetBackColor()
InvokeHelper(DISPID_BACKCOLOR, DISPATCH_PROPERTYGET, VT_I4, (void*)&result,
void CCalendar::SetBackColor(unsigned long newValue)
static BYTE parms[ ] = VTS_I4;
InvokeHelper(DISPID_BACKCOLOR, DISPATCH_PROPERTYPUT, VT_EMPTY, NULL, parms,
newValue);
CCalendar::GetDay()
InvokeHelper(0x11, DISPATCH_PROPERTYGET, VT_I2,
(void*)&result, NULL);
void CCalendar::SetDay(short nNewValue)
static BYTE parms[ ] = VTS_I2;
InvokeHelper(0x11, DISPATCH_PROPERTYPUT, VT_EMPTY, NULL, parms, nNewValue);
CCalendar::GetDayFont()
LPDISPATCH& pD
InvokeHelper(0x1, DISPATCH_PROPERTYGET, VT_DISPATCH, (void*)&pDispatch, NULL);
return COleFont(pDispatch);
void CCalendar::SetDayFont(LPDISPATCH newValue)
static BYTE parms[ ] = VTS_DISPATCH;
InvokeHelper(0x1, DISPATCH_PROPERTYPUT, VT_EMPTY, NULL, parms, newValue);
CCalendar::GetValue()
InvokeHelper(0xc, DISPATCH_PROPERTYGET, VT_VARIANT, (void*)&result, NULL);
void CCalendar::SetValue(const VARIANT& newValue)
static& BYTE& parms[ ] = VTS_VARIANT;
InvokeHelper(0xc, DISPATCH_PROPERTYPUT, VT_EMPTY, NULL, parms, &newValue);
CCalendar::NextDay()
InvokeHelper(0x16, DISPATCH_METHOD, VT_EMPTY, NULL, NULL);
void CCalendar::NextMonth()
InvokeHelper(0x17, DISPATCH_METHOD, VT_EMPTY, NULL, NULL);
You don't have to concern yourself too much with
the code inside these functions, but you can match up the first parameter of
InvokeHelper()
function with the dispatch ID for
the corresponding property or method in the
Calendar control property list. As
you can see, properties always have separate
functions. To call a method, you simply call the corresponding function. For
example, to call the
method from a dialog class function, you write code such as this:
m_calendar.NextDay();
In this case,
m_calendar
is an object of class
CCalendar,
the wrapper class for the Calendar
AppWizard Support for ActiveX
When the AppWizard ActiveX Controls option is checked
(the default), AppWizard inserts the following line in your application class
InitInstance()
member function:
AfxEnableControlContainer();
It also inserts the following line in the project's
StdAfx.h file:
&afxdisp.h&
If you decide to add ActiveX controls to an existing
project that doesn't include the two lines above, you can simply add the lines.
ClassWizard and the Container
Once you've used the dialog editor to generate a
dialog template, you already know that you can use ClassWizard to generate a
C++ class for the dialog window. If your template contains one or more ActiveX
controls, you can use ClassWizard to add data members and event handler functions.
Dialog Class Data Members vs.
Wrapper Class Usage
What kind of data members can you add to the dialog
for an ActiveX control? If you want to set a control property before you call
DoModal() for
the dialog, you can add a dialog data member for that property. If you want
to change properties inside the dialog member functions, you must take another
approach: you add a data member that is an object of the wrapper class for the
ActiveX control.
Now is a good time to review the MFC DDX logic.
Look back at the dialog in
CDialog::OnInitDialog
function calls
CWnd::UpdateData(FALSE)
to read the dialog class data members, and the
CDialog::OnOK
function calls
UpdateData(TRUE)
to write the members. Suppose you added a data member for each ActiveX control
property and you needed to get the Value
property value in a button handler. If you called
UpdateData(FALSE)
in the button handler, it would read all the property values from all the dialog's
controls, clearly a waste of time. It's more effective to avoid using a data
member and to call the wrapper class
function instead. To call that function, you must first tell ClassWizard to
add a wrapper class object data member. Suppose you have a
Calendar wrapper class
and you have an
m_calendar
data member in your dialog class. If you want to get the
Value property, you do it like this:
COleVariant
var = m_calendar.GetValue();
Now consider another case: you want to set the day
to the 5th of the month before the control is displayed. To do this by hand,
add a dialog class data member
that corresponds to the control's short integer
Day property. Then add the following
line to the
DoDataExchange()
DDX_OCShort(pDX,
ID_CALENDAR1, 0x11, m_sCalDay);
The third parameter is the
Day property's integer index (its
which you can find in the
functions generated by ClassWizard for the control. Here's how you construct
and display the dialog:
dlg.m_sCalDay
dlg.DoModal();
The DDX code takes care of setting the property
value from the data member before the control is displayed. No other programming
is needed. As you would expect, the DDX code sets the data member from the property
value when the user clicks the OK button.
Even when ClassWizard correctly detects a control's
properties, it can't always generate data members for all of them. In particular,
no DDX functions exist for
properties like the Calendar's
Value property. You'll have to use the wrapper class for these
properties.
Mapping ActiveX Control Events
ClassWizard lets you map
ActiveX control events the same way
you map Windows messages and command messages from controls. If a dialog
class contains one or more ActiveX controls, ClassWizard adds and maintains
an event sink map that connects mapped events to their handler functions. It
works something like a message map. You can see the code in Listing 4. ActiveX
controls have the annoying habit of firing
events before your program is ready for them. If your event handler
uses windows or pointers to C++ objects, it should verify the validity of those
entities prior to using them.
Locking ActiveX Controls in
Normally, an ActiveX control remains mapped in your
process as long as its parent dialog is active. That means it must be reloaded
each time the user opens a modal dialog. The reloads are usually quicker than
the initial load because of disk caching, but you can lock the control into
memory for better performance. To do so, add the following line in the overridden
OnInitDialog()
function after the base class call:
AfxOleLockControl(m_calendar.GetClsid());
The ActiveX control remains mapped until your program
exits or until you call the
AfxOleUnlockControl()
Continue on next module...part
reading and digging:
- latest version.
and Multibyte character set:OCX控件给一个步骤手动增加了一个参数后调用不起来了 - VC/MFC当前位置:& &&&OCX控件给一个步骤手动增加了一个参数后调用不起来了OCX控件给一个步骤手动增加了一个参数后调用不起来了&&网友分享于:&&浏览:0次OCX控件给一个方法手动增加了一个参数后调用不起来了MyOcx.odl&&&&dispinterface&_DMyOcx&&methods:
MyOcxCtl.h&&&Dispatch&maps
MyOcxCtl.cpp&&&&增加函数参数
就在上面三个源代码相应的地方照猫画虎的改了下,方法就掉不起来了。其实更好的办法是重载需要增加的函数,然后增加一个类成员变量来保存增加的参数。然后在旧的调用函数中使用。
现在这种手动改动代码为什么起不了作用呢。求大神帮忙!
------解决方案--------------------调用应用的地方也要修改
&static&BYTE&parms[]&=&嘻嘻嘻嘻嘻嘻------解决方案--------------------这种手动添加的方式经常会漏掉一些地方的添加的,同时类型要对,你要仔细看看
dispinterface&_DMyOcx
properties:
[id(DISPID_ABOUTBOX)]&void&AboutBox();
[id(1)]&void&Test(BSTR&bstr1,&LONG&lParam);
void&Test(LPCTSTR&bstr1,&long&lParam);
DISP_FUNCTION_ID(CMyOcxCtrl,&"Test",&dispidTest,&Test,&VT_EMPTY,&VTS_BSTR&VTS_I4)
void&CMyOcxCtrl::Test(LPCTSTR&bstr1,&long&lParam)
AFX_MANAGE_STATE(AfxGetStaticModuleState());
//&TODO:&在此添加调度处理程序代码
str.Format(_T("%s:%ld"),&bstr1,&lParam);
AfxMessageBox(str);
12345678910
12345678910
12345678910 上一篇:下一篇:文章评论相关解决方案 12345678910 Copyright & &&版权所有

我要回帖

更多关于 udfparms 的文章

 

随机推荐