?? ch09.htm
字號(hào):
Implementation Member Variables and Functions</H3>
<P><FONT COLOR="#0066FF"><TT>BEGIN_MSG_MAP(CATLControlWin) <BR>
MESSAGE_HANDLER(WM_PAINT, OnPaint) <BR>
MESSAGE_HANDLER(WM_GETDLGCODE, OnGetDlgCode) <BR>
MESSAGE_HANDLER(WM_SETFOCUS, OnSetFocus) <BR>
MESSAGE_HANDLER(WM_KILLFOCUS, OnKillFocus) <BR>
MESSAGE_HANDLER(WM_DESTROY, OnDestroy) <BR>
END_MSG_MAP() <BR>
. . . <BR>
LRESULT OnDestroy(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL & bHandled);
<BR>
. . . </TT></FONT></P>
<P>The next step is to add the <TT>OnDestroy</TT> implementation, which will clean
up the resources if they are still allocated (see Listing 9.17).
<H3><A NAME="Heading23"></A>Listing 9.17<SPACER TYPE="HORIZONTAL" SIZE="10"> ATLCONTROLWIN.CPP--OnDestroy
Implementation of Drawing Resource Cleanup</H3>
<P><FONT COLOR="#0066FF"><TT>LRESULT CATLControlWin::OnDestroy(UINT uMsg, WPARAM
wParam, LPARAM lParam, BOOL<BR>
& bHandled) <BR>
{ <BR>
// if there is an old brush <BR>
if(hOldBrush) <BR>
{ <BR>
// get the DC <BR>
HDC hDC = this->GetDC(); <BR>
// select the old brush back <BR>
::SelectObject(hDC, hOldBrush); <BR>
// release the DC <BR>
this->ReleaseDC(hDC); <BR>
} <BR>
// if we created a brush <BR>
if(hBrush) <BR>
// destroy the brush we created <BR>
::DeleteObject(hBrush); <BR>
return TRUE; <BR>
} </TT></FONT></P>
<P>The last step is to update the <TT>OnDraw</TT> implementation to take advantage
of optimized drawing, if the container supports optimized drawing that is (see Listing
9.18). The only line that you need to add to the code is one that checks the <TT>bOptimize</TT>
member of the <TT>ATL_DRAWINFO</TT> structure to see if it is set to 0 (or <TT>FALSE</TT>),
which indicates that the container does not support optimized drawing. If that is
the case, you then clean up all of your allocated resources and restore any original
values. If the container does support optimized drawing, you ignore the cleanup and
reuse the allocated resources the next time around.
<H3><A NAME="Heading24"></A>Listing 9.18 <SPACER TYPE="HORIZONTAL" SIZE="10">ATLCONTROLWIN.CPP--OnDraw
Function Updated to Support Optimized Drawing</H3>
<P><FONT COLOR="#0066FF"><TT>HRESULT CATLControlWin::OnDraw(ATL_DRAWINFO & di)
<BR>
{ <BR>
. . . <BR>
// The container does not support optimized drawing. <BR>
if(!di.bOptimize) <BR>
{ <BR>
// select the old brush back <BR>
::SelectObject(di.hdcDraw, hOldBrush); <BR>
// destroy the brush we created <BR>
::DeleteObject(hBrush); <BR>
// clear the brush handles <BR>
hBrush = hOldBrush = NULL; <BR>
} <BR>
return S_OK; <BR>
} </TT></FONT></P>
<H2><A NAME="Heading25"></A>Adding Clipboard and Drag and Drop Support</H2>
<P>The basic OLE Clipboard and Drag and Drop interfaces are only partially implemented
within your control implementation. As for the <TT>IPerPropertyBrowsing</TT> interface,
you must implement the remaining required interfaces yourself. As is pointed out
in <A HREF="ch07.htm">Chapter 7</A>, Clipboard and Drag and Drop support can add
much to your control implementation while requiring very little work.
<H3><A NAME="Heading26"></A>Clipboard Support</H3>
<P><I>Clipboard support</I> is based on the <TT>IDataObject</TT> and <TT>IEnumFORMATETC</TT>
interfaces. <TT>IDataObject</TT> is the interface through which the data is retrieved
from your control when it has been placed on the Clipboard, and <TT>IEnumFORMATETC</TT>
is the interface that is used by an application to determine what types of data your
<TT>IDataObject</TT> interface supports. In a basic ATL control project, only the
<TT>IDataObject</TT> Interface is supported. The <TT>IEnumFORMATETC</TT> interface
must be added.</P>
<P>Before adding the specific interfaces required by ActiveX to enable Clipboard
transfers, you must first decide which keystroke combinations will be used to initiate
the cut, copy, or paste operations. Fortunately, the Windows operating system (OS)
already has a number of standards in this area. You use Ctrl+X and Shift+Delete for
Cut, Ctrl+C and Ctrl+Insert for Copy, and Ctrl+V and Shift+Insert for Paste.</P>
<P>To trap the keystroke combinations, you need to implement a message handler for
the <TT>WM_KEYDOWN</TT> message in the form of a method called <TT>OnKeyDown</TT>
(see Listing 9.19).
<H3><A NAME="Heading27"></A>Listing 9.19<SPACER TYPE="HORIZONTAL" SIZE="10"> ATLCONTROLWIN.H--WM_KEYDOWN
and OnKeyDown Message Handler Added to the Class Declaration of the Control</H3>
<P><FONT COLOR="#0066FF"><TT>. . . <BR>
BEGIN_MSG_MAP(CATLControlWin) <BR>
MESSAGE_HANDLER(WM_PAINT, OnPaint) <BR>
MESSAGE_HANDLER(WM_GETDLGCODE, OnGetDlgCode) <BR>
MESSAGE_HANDLER(WM_SETFOCUS, OnSetFocus) <BR>
MESSAGE_HANDLER(WM_KILLFOCUS, OnKillFocus) <BR>
MESSAGE_HANDLER(WM_DESTROY, OnDestroy) <BR>
MESSAGE_HANDLER(WM_KEYDOWN, OnKeyDown) <BR>
END_MSG_MAP() <BR>
. . . <BR>
LRESULT OnDestroy(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL & bHandled);
<BR>
LRESULT OnKeyDown(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL & bHandled);
<BR>
. . . </TT></FONT></P>
<P>The <TT>OnKeyDown</TT> implementation looks for the particular keystroke combinations
listed in the preceding paragraph and upon finding them invokes the proper set of
functions to complete the requested Clipboard operation (see Listing 9.20). Note
that in addition to copying the data to the Clipboard, the Cut operation clears the
control's data.
<H3><A NAME="Heading28"></A>Listing 9.20<SPACER TYPE="HORIZONTAL" SIZE="10"> ATLCONTROLWIN.CPP--OnKeyDown
Implementation</H3>
<P><FONT COLOR="#0066FF"><TT>LRESULT CATLControlWin::OnKeyDown(UINT uMsg, WPARAM
wParam, LPARAM lParam, <BR>
BOOL & bHandled) <BR>
{ <BR>
UINT nChar = wParam; <BR>
UINT nRepCnt = LOWORD(lParam); <BR>
UINT nFlags = HIWORD(lParam); <BR>
// find out if the shift key is being held down <BR>
short sShift = ::GetKeyState(VK_SHIFT); <BR>
// find out if the control key is being held down <BR>
short sControl = ::GetKeyState(VK_CONTROL); <BR>
switch(nChar) <BR>
{ <BR>
// COPY <BR>
case 0x43: // `C' <BR>
case 0x63: // `c' <BR>
case VK_INSERT: <BR>
// if the control key is being held down <BR>
if(sControl & 0x8000) <BR>
{ <BR>
// copy the data to the clipboard <BR>
this->CopyDataToClipboard(); <BR>
// we don't need to pass this key to the base implementation <BR>
bHandled = TRUE; <BR>
} <BR>
break; <BR>
// CUT <BR>
case 0x58: // `X' <BR>
case 0x78: // `x' <BR>
case VK_DELETE: <BR>
// if this is a shift delete OR CTRL-X/x <BR>
if((nChar == VK_DELETE && (sShift & 0x8000)) || <BR>
((nChar == 0x58 || nChar == 0x78) && (sControl & 0x8000))) <BR>
{ <BR>
this->CopyDataToClipboard(); <BR>
// clear the string since this is a CUT operation <BR>
delete [] m_lptstrCaption; <BR>
// NULL terminate the string reference <BR>
m_lptstrCaption = new TCHAR[1]; <BR>
m_lptstrCaption[0] = `\0'; <BR>
// fire the global change event <BR>
this->FireChange(); <BR>
// force the control to repaint itself <BR>
this->FireViewChange(); <BR>
// this->InvalidateControl(); <== MFC Version <BR>
// we don't need to pass this key to the base implementation <BR>
bHandled = TRUE; <BR>
} <BR>
break; <BR>
} <BR>
return TRUE; <BR>
} </TT></FONT></P>
<P>In addition to the code that you added to trap the keystrokes, you need to add
four methods for dealing with the Clipboard transfers. You will examine these four
methods in detail in the next section.</P>
<P><TT>CopyDataToClipboard</TT> will, as the name implies, get the data from the
control and, using the helper function, <TT>PrepareDataForTransfer</TT>, package
the data and put it on the Clipboard.</P>
<P><TT>GetDataFromClipboard</TT> will open the Clipboard and look for data formats
that the control understands. Upon finding a suitable format, <TT>GetDataFromClipboard</TT>
will use the helper function <TT>GetDataFromTransfer</TT> to store the data in the
control.</P>
<P>When you enable the control for Drag and Drop support, you are aided by the fact
that the data transfer functions are separated into two separate methods for each
type of transfer, to and from the Clipboard, and then each type of transfer is further
broken into two separate steps. Because the basic data transfer mechanism is the
same between the Clipboard and Drag and Drop, you are able to rely on a large portion
of shared code for each implementation. <B><BR>
<BR>
Using Built-In Clipboard Formats</B> <SPACER TYPE="HORIZONTAL" SIZE="10">As we point
out in <A HREF="ch07.htm">Chapter 7</A>, the Windows OS supports a number of built-in
formats for transferring data via the Clipboard. Your first implementation is to
transfer the caption of your control by using the <TT>CF_TEXT</TT> format, which
is the built-in format for transferring ANSI text. There are two aspects to using
the Clipboard: being a Clipboard source and being a Clipboard target. Being a Clipboard
source refers to an application's capability to copy data <I>to</I> the Clipboard.
Being a Clipboard target refers to an applications capability to copy data <I>from</I>
the Clipboard. You first look at enabling your control as a Clipboard source. <B><I><BR>
<BR>
Enabling a Control as a Clipboard Source</I></B> <SPACER TYPE="HORIZONTAL" SIZE="10">A
<I>Clipboard source</I> is an application that puts data on the Clipboard for other
applications to copy. An application must support two COM interfaces, <TT>IDataObject</TT>
and <TT>IEnumFORMATETC</TT>, in order to qualify as a valid Clipboard source. When
copying data to the Clipboard, the <TT>OnKeyDown</TT> implementation takes advantage
of several helper functions: <TT>CopyDataToClipboard</TT>,<TT> PrepareDataForTransfer</TT>,
and <TT>CopyStgMedium</TT>. <TT>CopyStgMedium</TT>, <TT>CopyDataToClipboard</TT>,
and <TT>PrepareDataForTransfer</TT> are used to prepare your data structures--the
member variables <TT>sTextFormatEtc</TT> and <TT>sTextStgMedium</TT>--for a potential
paste operation. The member variable <TT>ulFORMATETCElement</TT> is the internal
counter for the <TT>IEnumFORMATETC</TT> interface. First you need to add the two
function prototypes to the <TT>CATLControlWin</TT> class declaration (see Listing
9.21).
<H3><A NAME="Heading29"></A>Listing 9.21<SPACER TYPE="HORIZONTAL" SIZE="10"> ATLCONTROLWIN.H--Helper
Functions and Member Variables for Clipboard Support</H3>
<P><FONT COLOR="#0066FF"><TT>. . . <BR>
void CopyDataToClipboard(void); <BR>
void PrepareDataForTransfer(void); <BR>
void CopyStgMedium(LPSTGMEDIUM lpTargetStgMedium, <BR>
LPSTGMEDIUM lpSourceStgMedium, CLIPFORMAT cfSourceFormat); <BR>
ULONG ulFORMATETCElement; <BR>
private: <BR>
FORMATETC sTextFormatEtc; <BR>
STGMEDIUM sTextStgMedium; <BR>
}; </TT></FONT></P>
<P>When the user initiates a data transfer via the Clipboard, a reference to the
control's <TT>IDataObject</TT> interface is placed on the Clipboard. At the time
the interface is placed on the Clipboard, you have to take a snapshot of the data
that the control contains and place it in a <TT>STGMEDIUM</TT> object. You do this
because the data may not be copied from the Clipboard immediately; the data needs
to reflect the state of the control when the copy operation was initiated rather
than when the paste operation takes place. Once the <TT>IDataObject</TT> interface
is on the Clipboard, you simply wait until someone requests the data. If a supported
data format is requested, you copy the data from your <TT>STGMEDIUM</TT> structure
to the <TT>STGMEDIUM</TT> structure that was passed to you.</P>
<P>The <TT>IDataObject</TT> interface is already included in your control's inheritance
hierarchy. The <TT>IEnumFORMATETC</TT> interface, however, must be added (see Listing
9.22). Since you will be implementing various member functions of the <TT>IDataObject</TT>
and the <TT>IEnumFORMATETC</TT> interfaces, you must add the function prototypes
to the class declaration of your control. Note that you need to add prototypes for
only those functions that you intend to implement; the remainder are left to their
default implementations.
<H3><A NAME="Heading30"></A>Listing 9.22 <SPACER TYPE="HORIZONTAL" SIZE="10">ATLCONTROLWIN.H--IEnumFORMATETC
Interface Added to theClass Inheritance Hierarchy</H3>
<P><FONT COLOR="#0066FF"><TT>. . . <BR>
public IPerPropertyBrowsingImpl<CATLControlWin>, <BR>
public IEnumFORMATETC <BR>
{ <BR>
public: <BR>
. . . <BR>
// IDataObject <BR>
STDMETHOD(GetData)(LPFORMATETC, LPSTGMEDIUM); <BR>
STDMETHOD(EnumFormatEtc)(DWORD, LPENUMFORMATETC*); <BR>
// IEnumFORMATETC <BR>
STDMETHOD(Next)(ULONG celt, FORMATETC __RPC_FAR * rgelt, <BR>
ULONG __RPC_FAR * pceltFetched); <BR>
STDMETHOD(Skip)(ULONG celt); <BR>
STDMETHOD(Reset)(void); <BR>
STDMETHOD(Clone)(IEnumFORMATETC __RPC_FAR *__RPC_FAR * ppenum); <BR>
. . . </TT></FONT></P>
<P>The two member variables, <TT>sTextFormatEtc</TT> and <TT>sTextStgMedium</TT>,
must be initialized in the constructor of your class so that they will not contain
meaningless data the first time that they are used (see Listing 9.23).
<H3><A NAME="Heading31"></A>Listing 9.23 <SPACER TYPE="HORIZONTAL" SIZE="10">ATLCONTROLWIN.H--Member
Initialization in the Class Constructor</H3>
<P><FONT COLOR="#0066FF"><TT>. . . <BR>
// set the initial state of the ReadyState property <BR>
?? 快捷鍵說(shuō)明
復(fù)制代碼
Ctrl + C
搜索代碼
Ctrl + F
全屏模式
F11
切換主題
Ctrl + Shift + D
顯示快捷鍵
?
增大字號(hào)
Ctrl + =
減小字號(hào)
Ctrl + -