📄 ch11.htm
字号:
long lLength = lstrlen(m_lptstrCaption) + 1; <BR>
// create a global memory object<BR>
<BR>
HGLOBAL hGlobal = ::GlobalAlloc(GMEM_MOVEABLE | GMEM_SHARE,<BR>
<BR>
sizeof(TCHAR) * lLength);<BR>
<BR>
<BR>
<BR>
// lock the memory down<BR>
<BR>
LPTSTR lpTempBuffer = (LPTSTR) ::GlobalLock(hGlobal); <BR>
// copy the string<BR>
<BR>
for(long lCount = 0; lCount < lLength - 1; lCount++)<BR>
<BR>
lpTempBuffer[lCount] = m_lptstrCaption[lCount]; <BR>
// null terminate the string<BR>
<BR>
lpTempBuffer[lCount] = `\0'; <BR>
// unlock the memory<BR>
<BR>
::GlobalUnlock(hGlobal); <BR>
// copy all of the members<BR>
<BR>
sTextFormatEtc.cfFormat = CF_TEXT;<BR>
<BR>
sTextFormatEtc.ptd = NULL;<BR>
<BR>
sTextFormatEtc.dwAspect = 0;<BR>
<BR>
sTextFormatEtc.lindex = -1;<BR>
<BR>
sTextFormatEtc.tymed = TYMED_HGLOBAL; <BR>
// if we have already allocated the data<BR>
<BR>
if(sTextStgMedium.hGlobal)<BR>
<BR>
// release it<BR>
<BR>
::ReleaseStgMedium(&sTextStgMedium); <BR>
sTextStgMedium.tymed = TYMED_HGLOBAL;<BR>
<BR>
sTextStgMedium.hGlobal = hGlobal;<BR>
<BR>
sTextStgMedium.pUnkForRelease = NULL; <BR>
}<BR>
</TT></FONT></P>
<P><TT>CopyStgMedium</TT> (see Listing 11.24) is a simple helper function to copy
one <TT>STGMEDIUM</TT> structure to another. The function relies on the <TT>OleDuplicateData</TT>
function to create a new copy of the global memory stored in the source <TT>STGMEDIUM</TT>.
The copied data is then stored in the target <TT>STGMEDIUM</TT> structure.
<H3><A NAME="Heading32"></A>Listing 11.24 <SPACER TYPE="HORIZONTAL" SIZE="10">BCFCONTROLCTL.CPP--CopyStgMedium
Implementation</H3>
<P><FONT COLOR="#0066FF"><TT>void CBCFControlControl::CopyStgMedium(LPSTGMEDIUM lpTargetStgMedium,
<BR>
<BR>
LPSTGMEDIUM lpSourceStgMedium, CLIPFORMAT cfSourceFormat)<BR>
<BR>
{<BR>
<BR>
// copy the stgmedium members<BR>
<BR>
lpTargetStgMedium->tymed = lpSourceStgMedium->tymed;<BR>
<BR>
lpTargetStgMedium->pUnkForRelease = lpSourceStgMedium->pUnkForRelease;<BR>
<BR>
lpTargetStgMedium->hGlobal = ::OleDuplicateData(lpSourceStgMedium->hGlobal,
<BR>
<BR>
cfSourceFormat, GMEM_MOVEABLE | GMEM_SHARE | GMEM_ZEROINIT); <BR>
}<BR>
</TT></FONT></P>
<P>The next set of functions (see Listing 11.25) are implemented for the <TT>IDataObject</TT>
interface that you declared in your header file. A number of methods are not implemented
and return the value <TT>E_NOTIMPL</TT> because they are not needed for this implementation.</P>
<P><TT>GetData</TT> is the function called when you need to copy the data in your
<TT>STGMEDIUM</TT> structure to the <TT>STGMEDIUM</TT> structure that is supplied.
You first see whether the format that is requested matches the data that you support
and, if so, copy the data using your helper function.</P>
<P><TT>EnumFormatEtc</TT> is the method called when the requesting application wants
to enumerate your supported formats. You support only the <TT>DATADIR_GET</TT> direction,
which means you can support only the <TT>GetData</TT> function and not the <TT>SetData</TT>
function of the <TT>IDataObject</TT> interface.</P>
<P>The remainder of the functions are not implemented and simply return the constant
<TT>E_NOTIMPL</TT>.
<H3><A NAME="Heading33"></A>Listing 11.25 <SPACER TYPE="HORIZONTAL" SIZE="10">BCFCONTROLCTL.CPP--IDataObject
Implementation</H3>
<P><FONT COLOR="#0066FF"><TT>STDMETHODIMP CBCFControlControl::GetData(LPFORMATETC
lpFormatEtc, <BR>
<BR>
LPSTGMEDIUM lpStgMedium)<BR>
<BR>
{<BR>
<BR>
// if this is a format that we can deal with<BR>
<BR>
if(lpFormatEtc->cfFormat == CF_TEXT && lpFormatEtc->tymed & TYMED_HGLOBAL)<BR>
<BR>
{<BR>
<BR>
// get a copy of the current stgmedium<BR>
<BR>
this->CopyStgMedium(lpStgMedium, &sTextStgMedium, CF_TEXT); <BR>
return S_OK;<BR>
<BR>
}<BR>
<BR>
else<BR>
<BR>
return DATA_E_FORMATETC;<BR>
<BR>
} <BR>
STDMETHODIMP CBCFControlControl::GetDataHere(LPFORMATETC /*lpFormatEtc*/, <BR>
<BR>
LPSTGMEDIUM /*lpStgMedium*/)<BR>
<BR>
{<BR>
<BR>
return E_NOTIMPL;<BR>
<BR>
} <BR>
STDMETHODIMP CBCFControlControl::QueryGetData(LPFORMATETC /*lpFormatEtc*/)<BR>
<BR>
{<BR>
<BR>
return E_NOTIMPL;<BR>
<BR>
} <BR>
STDMETHODIMP CBCFControlControl::GetCanonicalFormatEtc(LPFORMATETC /*lpFormatEtcIn*/,<BR>
<BR>
LPFORMATETC /*lpFormatEtcOut*/)<BR>
<BR>
{<BR>
<BR>
return E_NOTIMPL;<BR>
<BR>
} <BR>
STDMETHODIMP CBCFControlControl::SetData(LPFORMATETC /*lpFormatEtc*/,<BR>
<BR>
LPSTGMEDIUM /*lpStgMedium*/,<BR>
<BR>
BOOL /*bRelease*/)<BR>
<BR>
{<BR>
<BR>
return E_NOTIMPL;<BR>
<BR>
} <BR>
STDMETHODIMP CBCFControlControl::EnumFormatEtc(DWORD dwDirection, <BR>
<BR>
LPENUMFORMATETC * ppenumFormatEtc)<BR>
<BR>
{<BR>
<BR>
// we support "get" operations<BR>
<BR>
if(dwDirection == DATADIR_GET)<BR>
<BR>
{<BR>
<BR>
// make the assignment<BR>
<BR>
*ppenumFormatEtc = (IEnumFORMATETC *) this;<BR>
<BR>
<BR>
<BR>
// increment the reference count<BR>
<BR>
(*ppenumFormatEtc)->AddRef(); <BR>
// return success<BR>
<BR>
return S_OK;<BR>
<BR>
} <BR>
return E_NOTIMPL;<BR>
<BR>
} <BR>
STDMETHODIMP CBCFControlControl::DAdvise(FORMATETC * /*pFormatEtc*/, DWORD /*advf*/,<BR>
<BR>
LPADVISESINK /*pAdvSink*/, DWORD * /*pdwConnection*/)<BR>
<BR>
{<BR>
<BR>
return E_NOTIMPL;<BR>
<BR>
} <BR>
STDMETHODIMP CBCFControlControl::DUnadvise(DWORD /*dwConnection*/)<BR>
<BR>
{<BR>
<BR>
return E_NOTIMPL;<BR>
<BR>
} <BR>
STDMETHODIMP CBCFControlControl::EnumDAdvise(LPENUMSTATDATA * /*ppenumAdvise*/)<BR>
<BR>
{<BR>
<BR>
return E_NOTIMPL; <BR>
}<BR>
</TT></FONT></P>
<P>The next set of functions (see Listing 11.26) are implemented for the <TT>IEnumFORMATETC</TT>
interface that you declared in your header file. Cloning is not supported and will
return the value <TT>E_NOTIMPL</TT>.</P>
<P>The <TT>Next</TT> function is used to enumerate through the entire list of supported
formats. You first check to see whether your counter is set to the first element
and that the user asked for at least one entry. If so, you set the <TT>FORMATETC</TT>
structure to your supported format, and if appropriate, you set the number of elements
that you are returning and increment the counter.</P>
<P>The <TT>Skip</TT> function advances the enumerator by the number of elements specified.</P>
<P>The <TT>Reset</TT> function sets the enumerator back to the beginning of the enumeration.
<H3><A NAME="Heading34"></A>Listing 11.26<SPACER TYPE="HORIZONTAL" SIZE="10"> BCFCONTROLCTL.CPP--IEnumFORMATETC
Implementation</H3>
<P><FONT COLOR="#0066FF"><TT>STDMETHODIMP CBCFControlControl::Next(ULONG celt, FORMATETC_RPC_FAR
* rgelt, <BR>
<BR>
ULONG RPC_FAR * pceltFetched)<BR>
<BR>
{<BR>
<BR>
// if we are at the beginning of the enumeration<BR>
<BR>
if(ulFORMATETCElement == 0 && celt > 0)<BR>
<BR>
{<BR>
<BR>
// copy all of the members<BR>
<BR>
rgelt->cfFormat = CF_TEXT;<BR>
<BR>
rgelt->ptd = NULL;<BR>
<BR>
rgelt->dwAspect = 0;<BR>
<BR>
rgelt->lindex = -1;<BR>
<BR>
rgelt->tymed = TYMED_HGLOBAL;<BR>
<BR>
<BR>
<BR>
// if the caller wants to know how many we copied<BR>
<BR>
if(pceltFetched)<BR>
<BR>
*pceltFetched = 1; <BR>
// increment the counter<BR>
<BR>
ulFORMATETCElement++; <BR>
// return success<BR>
<BR>
return S_OK;<BR>
<BR>
}<BR>
<BR>
else<BR>
<BR>
// return failure<BR>
<BR>
return S_FALSE;<BR>
<BR>
} <BR>
STDMETHODIMP CBCFControlControl::Skip(ULONG celt)<BR>
<BR>
{<BR>
<BR>
// move the counter by the number of elements supplied<BR>
<BR>
ulFORMATETCElement += celt;<BR>
<BR>
<BR>
<BR>
// return success<BR>
<BR>
return S_OK;<BR>
<BR>
} <BR>
STDMETHODIMP CBCFControlControl::Reset(void)<BR>
<BR>
{<BR>
<BR>
// reset to the beginning of the enumerator<BR>
<BR>
ulFORMATETCElement = 0;<BR>
<BR>
<BR>
<BR>
// return success<BR>
<BR>
return S_OK;<BR>
<BR>
} <BR>
STDMETHODIMP CBCFControlControl::Clone(IEnumFORMATETC RPC_FAR *__RPC_FAR * /*ppenum*/)<BR>
<BR>
{<BR>
<BR>
return E_NOTIMPL; <BR>
}<BR>
</TT></FONT></P>
<P>Finally you are at the end of your implementation: the <TT>OnKeyDown</TT> function
(see Listing 11.27). The <TT>OnKeyDown</TT> contains all of the code that is necessary
to look for the common keystroke combinations used to initiate Clipboard operations.
<H3><A NAME="Heading35"></A>Listing 11.27 <SPACER TYPE="HORIZONTAL" SIZE="10">BCFCONTROLCTL.CPP--OnKeyDown
Implementation</H3>
<P><FONT COLOR="#0066FF"><TT>void CBCFControlControl::OnKeyDown(UINT nChar, UINT
nRepCnt, UINT nFlags)<BR>
<BR>
{<BR>
<BR>
BOOL bHandled = FALSE; <BR>
// find out if the shift key is being held down<BR>
<BR>
short sShift = ::GetKeyState(VK_SHIFT);<BR>
<BR>
// find out if the control key is being held down<BR>
<BR>
short sControl = ::GetKeyState(VK_CONTROL); <BR>
switch(nChar)<BR>
<BR>
{<BR>
<BR>
// COPY or PASTE<BR>
<BR>
case 0x43: // `C'<BR>
<BR>
case 0x63: // `c' <BR>
<BR>
// if the control key is being held down<BR>
<BR>
if(sControl & 0x8000)<BR>
<BR>
{<BR>
<BR>
// copy the data to the clipboard<BR>
<BR>
this->CopyDataToClipboard(); <BR>
// we don't need to pass this key to the base implementation<BR>
<BR>
bHandled = TRUE;<BR>
<BR>
}<BR>
<BR>
break;<BR>
<BR>
case 0x58: // `X'<BR>
<BR>
case 0x78: // `x'<BR>
<BR>
case VK_DELETE:<BR>
<BR>
// if this is a shift delete OR CTRL-X/x<BR>
<BR>
if((nChar == VK_DELETE && (sShift & 0x8000)) || <BR>
<BR>
((nChar == 0x58 || nChar == 0x78) && (sControl & 0x8000)))<BR>
<BR>
{<BR>
<BR>
this->CopyDataToClipboard(); <BR>
// clear the string since this is a CUT operati
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -