?? ch09.htm
字號:
m_lReadyState = READYSTATE_LOADING; <BR>
// set to the first element <BR>
ulFORMATETCElement = 0; <BR>
// clear the storage medium <BR>
sTextStgMedium.hGlobal = NULL; <BR>
} <BR>
. . . </TT></FONT></P>
<P>The next step is to implement the member functions that will actually perform
the data preparation and copy operation to the Clipboard.</P>
<P><TT>CopyDataToClipboard</TT> is the function that is called to initiate the Clipboard
transfer (see Listing 9.24). You first check to see whether you are already the owner
of the Clipboard and set the Boolean variable accordingly. You then prepare your
data for the Clipboard, and finally if you are not the owner of the Clipboard, you
flush whatever data is on the Clipboard and set your <TT>IDataObject</TT> reference
on the Clipboard.
<H3><A NAME="Heading32"></A>Listing 9.24 <SPACER TYPE="HORIZONTAL" SIZE="10">ATLCONTROLWIN.CPP--CopyDataToClipboard
Helper Function Implementation</H3>
<P><FONT COLOR="#0066FF"><TT>void CATLControlWin::CopyDataToClipboard(void) <BR>
{ <BR>
BOOL bHaveClipboard = TRUE; <BR>
// if we don't have an IDataObject on the clipboard? <BR>
if(::OleIsCurrentClipboard((IDataObject *) this) != S_OK) <BR>
// set the flag <BR>
bHaveClipboard = FALSE; <BR>
// put data in the storage <BR>
this->PrepareDataForTransfer(); <BR>
// if we don't have the clipboard <BR>
if(!bHaveClipboard) <BR>
{ <BR>
// clear the clipboard <BR>
::OleFlushClipboard(); <BR>
// put the data on the clipboard <BR>
::OleSetClipboard(reinterpret_cast<IDataObject*> <BR>
(static_cast<IDataObjectImpl<CATLControlWin>*>(this))); <BR>
} <BR>
} </TT></FONT></P>
<P><TT>PrepareDataForTransfer</TT> is the function that you call when you want to
copy the data from your control to the <TT>STGMEDIUM</TT> structure that will represent
your data on the Clipboard (see Listing 9.25). First you need to allocate a block
of global memory that will contain your caption in ANSI format. Then you set up the
<TT>FORMATETC</TT> and <TT>STGMEDIUM</TT> structures to reflect the correct data
type and exit the function.
<H3><A NAME="Heading33"></A>Listing 9.25 <SPACER TYPE="HORIZONTAL" SIZE="10">ATLCONTROLWIN.CPP--PrepareDataForTransfer
Helper Function Implementation</H3>
<P><FONT COLOR="#0066FF"><TT>void CATLControlWin::PrepareDataForTransfer(void) <BR>
{ <BR>
// get the length of the data to copy <BR>
long lLength = lstrlen(m_lptstrCaption) + 1; <BR>
// create a global memory object <BR>
HGLOBAL hGlobal = ::GlobalAlloc(GMEM_MOVEABLE | GMEM_SHARE, <BR>
sizeof(TCHAR) * lLength); <BR>
// lock the memory down <BR>
LPTSTR lpTempBuffer = (LPTSTR) ::GlobalLock(hGlobal); <BR>
// copy the string <BR>
for(long lCount = 0; lCount < lLength - 1; lCount++) <BR>
lpTempBuffer[lCount] = m_lptstrCaption[lCount]; <BR>
// null terminate the string <BR>
lpTempBuffer[lCount] = `\0'; <BR>
// unlock the memory <BR>
::GlobalUnlock(hGlobal); <BR>
// copy all of the members <BR>
sTextFormatEtc.cfFormat = CF_TEXT; <BR>
sTextFormatEtc.ptd = NULL; <BR>
sTextFormatEtc.dwAspect = 0; <BR>
sTextFormatEtc.lindex = -1; <BR>
sTextFormatEtc.tymed = TYMED_HGLOBAL; <BR>
// if we have already allocated the data <BR>
if(sTextStgMedium.hGlobal) <BR>
// release it <BR>
::ReleaseStgMedium(&sTextStgMedium); <BR>
sTextStgMedium.tymed = TYMED_HGLOBAL; <BR>
sTextStgMedium.hGlobal = hGlobal; <BR>
sTextStgMedium.pUnkForRelease = NULL; <BR>
} </TT></FONT></P>
<P><TT>CopyStgMedium</TT> is a general purpose helper function for copying one <TT>STGMEDIUM</TT>
to another <TT>STGMEDIUM</TT> (see Listing 9.26). This implementation is important
because the function allocates a new global data object instead of copying the reference
to the existing object.
<H3><A NAME="Heading34"></A>Listing 9.26<SPACER TYPE="HORIZONTAL" SIZE="10"> ATLCONTROLWIN.CPP--CopyStgMedium
Helper Function Implementation</H3>
<P><FONT COLOR="#0066FF"><TT>void CATLControlWin::CopyStgMedium(LPSTGMEDIUM lpTargetStgMedium,
<BR>
LPSTGMEDIUM lpSourceStgMedium, CLIPFORMAT cfSourceFormat) <BR>
{ <BR>
// copy the stgmedium members <BR>
lpTargetStgMedium->tymed = lpSourceStgMedium->tymed; <BR>
lpTargetStgMedium->pUnkForRelease = lpSourceStgMedium->pUnkForRelease; <BR>
lpTargetStgMedium->hGlobal = ::OleDuplicateData(lpSourceStgMedium->hGlobal,
<BR>
cfSourceFormat, GMEM_MOVEABLE | GMEM_SHARE | GMEM_ZEROINIT); <BR>
} </TT></FONT></P>
<P>The last step is to implement the <TT>IDataObject</TT> and <TT>IEnumFORMATETC</TT>
interfaces.</P>
<P>The <TT>IDataObject</TT> implementation is straightforward and involves only two
functions (see Listing 9.27). The remainder of the <TT>IDataObject</TT> functions
are already implemented by the ATL class <TT>IDataObjectImpl</TT>. <TT>GetData</TT>
will, if the format type matches that of a format that your control understands,
copy the control's current data to the <TT>STGMEDIUM</TT> parameter that is passed
to the control. If the format type is unrecognized, you must defer to the base class
implementation of <TT>GetData</TT>. Doing this is very important since the ATL class
<TT>CComControlBase</TT> does implement the <TT>IDataObject::GetData</TT> function
for copying <TT>metafile</TT> data formats. <TT>EnumFormatEtc</TT> is used to return
an <TT>IEnumFORMATETC</TT> reference to the requesting application so that it can
determine what types of data formats are supported by the control implementation.
Again, you must defer to the base class implementation to ensure that the control
implementation functions correctly; however, in this case, the default ATL implementation
of this function returns <TT>E_NOTIMPL</TT>.
<H3><A NAME="Heading35"></A>Listing 9.27 <SPACER TYPE="HORIZONTAL" SIZE="10">ATLCONTROLWIN.CPP--IDataObject
Interface Implementation</H3>
<P><FONT COLOR="#0066FF"><TT>. . . <BR>
STDMETHODIMP CATLControlWin::GetData(LPFORMATETC lpFormatEtc, <BR>
LPSTGMEDIUM lpStgMedium) <BR>
{ <BR>
// if this is a format that we can deal with <BR>
if(lpFormatEtc->cfFormat == CF_TEXT && lpFormatEtc->tymed & TYMED_HGLOBAL)
<BR>
{ <BR>
// get a copy of the current stgmedium <BR>
this->CopyStgMedium(lpStgMedium, &sTextStgMedium, CF_TEXT); <BR>
return S_OK; <BR>
} <BR>
else <BR>
return IDataObjectImpl<CATLControlWin>::GetData(lpFormatEtc, lpStgMedium);
<BR>
} <BR>
STDMETHODIMP CATLControlWin::EnumFormatEtc(DWORD dwDirection, <BR>
LPENUMFORMATETC* ppenumFormatEtc) <BR>
{ <BR>
// we support "get" operations <BR>
if(dwDirection == DATADIR_GET) <BR>
{ <BR>
// make the assignment <BR>
*ppenumFormatEtc = (IEnumFORMATETC *) this; <BR>
<BR>
// increment the reference count <BR>
(*ppenumFormatEtc)->AddRef(); <BR>
// return success <BR>
return S_OK; <BR>
} <BR>
return IDataObjectImpl<CATLControlWin>::EnumFormatEtc( <BR>
dwDirection, ppenumFormatEtc); <BR>
} <BR>
. . . </TT></FONT></P>
<P>The <TT>IEnumFORMATETC</TT> implementation is also simple (see Listing 9.28).
The one thing to note is that there is no default ATL implementation, so it is not
necessary to defer to the base class implementation in the case where you do not
handle the function. <TT>Next</TT> is used to retrieve the next element in the enumeration;
in this case, you need be concerned with only one element, <TT>CF_TEXT</TT>. After
filling in the <TT>FORMATETC</TT> structure with the appropriate data, you must increment
the counter and exit the function. The <TT>Skip</TT> method increments the counter
and exits the function, and <TT>Reset</TT> sets the counter back to 0.
<H3><A NAME="Heading36"></A>Listing 9.28 <SPACER TYPE="HORIZONTAL" SIZE="10">ATLCONTROLWIN.CPP--IEnumFORMATETC
Interface Implementation</H3>
<P><FONT COLOR="#0066FF"><TT>STDMETHODIMP CATLControlWin::Next(ULONG celt, FORMATETC_RPC_FAR
* rgelt, <BR>
ULONG RPC_FAR * pceltFetched) <BR>
{ <BR>
// if we are at the beginning of the enumeration <BR>
if(ulFORMATETCElement == 0 && celt > 0) <BR>
{ <BR>
// copy all of the members <BR>
rgelt->cfFormat = CF_TEXT; <BR>
rgelt->ptd = NULL; <BR>
rgelt->dwAspect = 0; <BR>
rgelt->lindex = -1; <BR>
rgelt->tymed = TYMED_HGLOBAL; <BR>
<BR>
// if the caller wants to know how many we copied <BR>
if(pceltFetched) <BR>
*pceltFetched = 1; <BR>
// increment the counter <BR>
ulFORMATETCElement++; <BR>
// return success <BR>
return S_OK; <BR>
} <BR>
else <BR>
// return failure <BR>
return S_FALSE; <BR>
} <BR>
STDMETHODIMP CATLControlWin::Skip(ULONG celt) <BR>
{ <BR>
// move the counter by the number of elements supplied <BR>
ulFORMATETCElement += celt; <BR>
<BR>
// return success <BR>
return S_OK; <BR>
} <BR>
STDMETHODIMP CATLControlWin::Reset(void) <BR>
{ <BR>
// reset to the beginning of the enumerator <BR>
ulFORMATETCElement = 0; <BR>
<BR>
// return success <BR>
return S_OK; <BR>
} <BR>
STDMETHODIMP CATLControlWin::Clone( <BR>
IEnumFORMATETC_RPC_FAR *__RPC_FAR * /*ppenum*/) <BR>
{ <BR>
return E_NOTIMPL; <BR>
} </TT></FONT></P>
<P>Now that you know how to copy data to the Clipboard, you look at how to get data
from the Clipboard. <B><BR>
<BR>
Enabling a Control as a Clipboard Target</B> <SPACER TYPE="HORIZONTAL" SIZE="10">The
opposite of being a Clipboard source is being a Clipboard target. First you need
to update the <TT>CATLControlWin</TT> class declaration to include two new helper
functions (see Listing 9.29).
<H3><A NAME="Heading37"></A>Listing 9.29 <SPACER TYPE="HORIZONTAL" SIZE="10">ATLCONTROLWIN.H--Clipboard
Target Support Helper Function Prototypes</H3>
<P><FONT COLOR="#0066FF"><TT>. . . <BR>
void CopyDataToClipboard(void); <BR>
void PrepareDataForTransfer(void); <BR>
void GetDataFromClipboard(void); <BR>
void GetDataFromTransfer(IDataObject * ipDataObj); <BR>
void CopyStgMedium(LPSTGMEDIUM lpTargetStgMedium, <BR>
LPSTGMEDIUM lpSourceStgMedium, CLIPFORMAT cfSourceFormat); <BR>
. . . </TT></FONT></P>
<P>Getting data from the Clipboard is almost as easy as putting the data on the Clipboard
in the first place. The first method is <TT>GetDataFromClipboard</TT>, which, as
the name implies, gets the data from the Clipboard and transfers it to the control.
The function first checks the Clipboard to see whether the control already owns the
Clipboard. If the control does own the Clipboard, it refreshes the control's data
with the data that is stored in the <TT>STGMEDIUM</TT> structure. The implementation
is written this way because the data stored in the control may have changed since
it was pasted to the Clipboard in the first place.</P>
<P>If you don't already own the Clipboard, you get the <TT>IDataObject</TT> reference
of the object that does, and you pass the reference on to the <TT>GetDataFromTransfer</TT>
function (see Listing 9.30).
<H3><A NAME="Heading38"></A>Listing 9.30<SPACER TYPE="HORIZONTAL" SIZE="10"> MFCCONTROLWINCTL.CPP--GetDataFromClipboard
Implementation</H3>
<P><FONT COLOR="#0066FF"><TT>void CATLControlWin::GetDataFromClipboard(void) <BR>
{ <BR>
// get an IDataObject pointer <BR>
IDataObject * ipClipboardDataObj = NULL; <BR>
// do we have an IDataObject on the clipboard? <BR>
if(::OleIsCurrentClipboard((IDataObject *) this) == S_OK) <BR>
{ <BR>
// get the global data for this format and lock down the memory <BR>
LPTSTR lpTempBuffer = (LPTSTR) ::GlobalLock(sTextStgMedium.hGlobal); <BR>
// if we have a string <BR>
if(m_lptstrCaption) <BR>
{ <BR>
// delete the existing string <BR>
delete [] m_lptstrCaption; <BR>
// clear the reference just to be safe <BR>
m_lptstrCaption = NULL; <BR>
} <BR>
// allocate a new string <BR>
m_lptstrCaption = new TCHAR[lstrlen(lpTempBuffer) + 1]; <BR>
// assign the string to our member variable <BR>
lstrcpy(m_lptstrCaption, lpTempBuffer); <BR>
// unlock the m
?? 快捷鍵說明
復制代碼
Ctrl + C
搜索代碼
Ctrl + F
全屏模式
F11
切換主題
Ctrl + Shift + D
顯示快捷鍵
?
增大字號
Ctrl + =
減小字號
Ctrl + -