⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 ch11.htm

📁 本书详述了VC++环境下网络化多媒体对象技术编程
💻 HTM
📖 第 1 页 / 共 5 页
字号:
<BR>
{<BR>
<BR>
// get the DC<BR>
<BR>
HDC hDC = this-&gt;OcxGetDC(); <BR>
// select the old brush back<BR>
<BR>
::SelectObject(hDC, hOldBrush); <BR>
// release the DC<BR>
<BR>
this-&gt;OcxReleaseDC(hDC);<BR>
<BR>
} <BR>
// if we created a brush<BR>
<BR>
if(hBrush)<BR>
<BR>
// destroy the brush we created<BR>
<BR>
::DeleteObject(hBrush); <BR>
}<BR>
</TT></FONT></P>
<P>The fact is the user will not care how great your code is written or how many
whiz-bang features it supports if it doesn't draw well. You'll be wise to spend some
time on your drawing implementation and get it right.
<H2><A NAME="Heading22"></A>Adding Clipboard and Drag and Drop Support</H2>
<P>The basic OLE Clipboard and Drag and Drop interfaces are not implemented within
the BaseCtl framework. As with the <TT>IPerPropertyBrowsing</TT> interface (see the
section &quot;Dynamic Property Enumeration&quot;), you must implement the required
interfaces yourself. As is pointed out in <A HREF="ch07.htm">Chapters 7</A> and <A
HREF="ch09.htm">9</A>, Clipboard and Drag and Drop support can add much to your control
implementation, while requiring very little work.
<H3><A NAME="Heading23"></A>Clipboard Support</H3>
<P>Clipboard support 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 object 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. <B><BR>
<BR>
Using Built-In Clipboard Formats </B><SPACER TYPE="HORIZONTAL" SIZE="10">As is pointed
out in <A HREF="ch07.htm">Chapter 7</A>, the Windows operating system (OS) supports
a number of built-in formats for transferring data via the Clipboard. Your first
implementation will be to transfer your caption using the <TT>CF_TEXT</TT><B> </B>format,
which is the built-in format for transferring <TT>ANSI</TT> text. There are two aspects
to using the Clipboard: being a Clipboard source and being a Clipboard target. You
will 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
Clipboard source is an application that puts data on the Clipboard for other applications
to copy. You need to support two interfaces to enable your control as a Clipboard
source: <TT>IDataObject</TT><B><I> </I></B>and<B><I> </I></B><TT>IEnumFORMATETC</TT>.
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 must take a snapshot of the data that the control
contains and place it in a <TT>STGMEDIUM</TT> object. You have to do this because
the data may not be copied from the Clipboard immediately and 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>First you need to declare your COM interfaces for supporting the <TT>IDataObject</TT>
and <TT>IEnumFORMATETC</TT> interfaces (see Listings 11.16 and 11.17).
<H3><A NAME="Heading24"></A>Listing 11.16 <SPACER TYPE="HORIZONTAL" SIZE="10">IDATAOBJECT.H--IDataObject
Interface Macro</H3>
<P><FONT COLOR="#0066FF"><TT>#define DECLARE_STANDARD_DATAOBJECT() \<BR>
STDMETHOD(GetData)(LPFORMATETC, LPSTGMEDIUM); \<BR>
STDMETHOD(GetDataHere)(LPFORMATETC, LPSTGMEDIUM); \<BR>
STDMETHOD(QueryGetData)(LPFORMATETC); \<BR>
STDMETHOD(GetCanonicalFormatEtc)(LPFORMATETC, LPFORMATETC); \<BR>
STDMETHOD(SetData)(LPFORMATETC, LPSTGMEDIUM, BOOL); \<BR>
STDMETHOD(EnumFormatEtc)(DWORD, LPENUMFORMATETC*); \<BR>
STDMETHOD(DAdvise)(LPFORMATETC, DWORD, LPADVISESINK, LPDWORD); \<BR>
STDMETHOD(DUnadvise)(DWORD); \ <BR>
STDMETHOD(EnumDAdvise)(LPENUMSTATDATA*);<BR>
</TT></FONT></P>
<H3><A NAME="Heading25"></A>Listing 11.17<SPACER TYPE="HORIZONTAL" SIZE="10"> IENUMFORMATETC--IEnumFORMATETC
Interface Macro</H3>
<P><FONT COLOR="#0066FF"><TT>#define DECLARE_STANDARD_ENUMFORMATETC() \<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>You need to include the header files of your new interface macros, add the <TT>IDataObject</TT>
and <TT>IEnumFORMATETC</TT> interfaces to your inheritance structure, and add the
interface macros to your control declaration. You also need to add some functions
and member variables to aid in your Clipboard support implementation (see Listing
11.18).</P>

<P>You use the functions <TT>CopyStgMedium</TT>, <TT>CopyDataToClipboard</TT>, and
<TT>PrepareDataForTransfer</TT> 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>FORMATETC</TT>
enumerator interface, and <TT>OnKeyDown</TT> is where all of your Clipboard operations
are initiated.
<H3><A NAME="Heading26"></A>Listing 11.18<SPACER TYPE="HORIZONTAL" SIZE="10"> BCFCONTROLCTL.H--Clipboard
Support Implementation--Header File</H3>
<P><FONT COLOR="#0066FF"><TT>. . . <BR>
#include &quot;IPerPropertyBrowsing.h&quot;<BR>
#include &quot;IDataObject.h&quot;<BR>
#include &quot;IEnumFORMATETC.h&quot; <BR>
#include &quot;alignmentenums.h&quot; <BR>
typedef enum<BR>
{<BR>
BCFControlEvent_Change = 0,<BR>
} BCFCONTROLEVENTS; <BR>
. . . <BR>
//<BR>
class CBCFControlControl : public CInternetControl, public IBCFControl,<BR>
public ISupportErrorInfo, public IPerPropertyBrowsing, public IDataObject,<BR>
public IEnumFORMATETC<BR>
{<BR>
public: <BR>
. . . // ISupportErrorInfo methods<BR>
//<BR>
<BR>
DECLARE_STANDARD_SUPPORTERRORINFO(); <BR>
// IPerPropertyBrowsing methods<BR>
<BR>
//<BR>
<BR>
DECLARE_STANDARD_PERPROPERTYBROWSING(); <BR>
// IDataObject methods<BR>
<BR>
//<BR>
<BR>
DECLARE_STANDARD_DATAOBJECT(); <BR>
// IEnumFORMATETC methods<BR>
<BR>
//<BR>
<BR>
DECLARE_STANDARD_ENUMFORMATETC(); <BR>
// IBCFControl methods<BR>
<BR>
//<BR>
<BR>
STDMETHOD(get_Alignment)(THIS_ long FAR* lRetValue);<BR>
<BR>
STDMETHOD(put_Alignment)(THIS_ long lNewValue);<BR>
<BR>
STDMETHOD(get_BackColor)(THIS_ OLE_COLOR FAR* ocRetValue); <BR>
. . . <BR>
void GetTextExtent(HDC hDC, LPCTSTR lpctstrString, int &amp; cx, int &amp; cy);<BR>
<BR>
BOOL bRetrievedDimensions;<BR>
<BR>
int iCharWidthArray[256];<BR>
<BR>
int iCharacterSpacing, iCharacterHeight;<BR>
<BR>
void CopyStgMedium(LPSTGMEDIUM lpTargetStgMedium, LPSTGMEDIUM lpSourceStgMedium,
<BR>
<BR>
CLIPFORMAT cfSourceFormat);<BR>
<BR>
void CopyDataToClipboard(void);<BR>
<BR>
void PrepareDataForTransfer(void);<BR>
<BR>
ULONG ulFORMATETCElement;<BR>
<BR>
void OnKeyDown(UINT nChar, UINT nRepCnt, UINT nFlags); <BR>
private:<BR>
<BR>
FORMATETC sTextFormatEtc;<BR>
<BR>
STGMEDIUM sTextStgMedium; <BR>
};<BR>
</TT></FONT></P>

<P>You need to update the constructor to initialize your enumerator to the beginning
of the enumeration (see Listing 11.19).
<H3><A NAME="Heading27"></A>Listing 11.19 <SPACER TYPE="HORIZONTAL" SIZE="10">BCFCONTROLCTL.CPP--Constructor
Member Initialization</H3>
<P><FONT COLOR="#0066FF"><TT>. . . <BR>
hOldBrush = hBrush = NULL; <BR>
// clear the flag<BR>
<BR>
bRetrievedDimensions = FALSE; <BR>
// set to the first element<BR>
<BR>
ulFORMATETCElement = 0; <BR>
// clear the storage medium<BR>
<BR>
sTextStgMedium.hGlobal = NULL;<BR>
<BR>
} <BR>
#pragma warning(default:4355) // using `this' in constructor<BR>
</TT></FONT></P>
<P>Since you have added two additional COM interfaces to your control, you also need
to update your <TT>QueryInterface</TT> implementation (see Listing 11.20).
<H3><A NAME="Heading28"></A>Listing 11.20<SPACER TYPE="HORIZONTAL" SIZE="10"> BCFCONTROLCTL.CPP--QueryInterface
Update</H3>
<P><FONT COLOR="#0066FF"><TT>HRESULT CBCFControlControl::InternalQueryInterface(REFIID
riid, void **ppvObjOut)<BR>
<BR>
{<BR>
<BR>
IUnknown *pUnk; <BR>
*ppvObjOut = NULL; <BR>
// TODO: if you want to support any additional interfaces, then you should<BR>
<BR>
// indicate that here. never forget to call COleControl's version in the<BR>
<BR>
// case where you don't support the given interface.<BR>
<BR>
//<BR>
<BR>
if(DO_GUIDS_MATCH(riid, IID_IBCFControl))<BR>
<BR>
pUnk = (IUnknown *)(IBCFControl *)this;<BR>
<BR>
else if(DO_GUIDS_MATCH(riid, IID_IPerPropertyBrowsing))<BR>
<BR>
pUnk = (IUnknown *)(IPerPropertyBrowsing *)this;<BR>
<BR>
else if(DO_GUIDS_MATCH(riid, IID_IDataObject))<BR>
<BR>
pUnk = (IUnknown *)(IDataObject *)this;<BR>
<BR>
else if(DO_GUIDS_MATCH(riid, IID_IEnumFORMATETC))<BR>
<BR>
pUnk = (IUnknown *)(IEnumFORMATETC *)this;<BR>
<BR>
else<BR>
<BR>
return COleControl::InternalQueryInterface(riid, ppvObjOut); <BR>
pUnk-&gt;AddRef();<BR>
<BR>
*ppvObjOut = (void *)pUnk;<BR>
<BR>
return S_OK; <BR>
}<BR>
</TT></FONT></P>
<P>You also need to update your <TT>WindowProc</TT> function to look for the <TT>WM_KEYDOWN</TT>
message so that you can process the keystrokes that will initiate your Clipboard
data transfer (see Listing 11.21). <BR>
<BR>
<IMG SRC="bar.gif" WIDTH="480" HEIGHT="6" ALIGN="BOTTOM" BORDER="0"></P>


<BLOCKQUOTE>
	<P><B>NOTE:</B> Listing 11.21 contains a <TT>switch</TT> statement that is used to
	route Windows messages to the proper message handler. The default handler will call
	the method <TT>OcxDefWindowProc</TT>. Whenever you want to use the default implementation
	for a message, you call <TT>OcxDefWindowProc</TT>. <TT>OcxDefWindowProc</TT> is designed
	to deal with the cases when the control does not have a window handle, because the
	control may have been created as windowless. Remember that the control will not have
	its own window handle when it is created windowless, so you should never use the
	handle directly. Always allow the default BaseCtl implementation to handle the windowless
	processing of messages.

</BLOCKQUOTE>

<P><IMG SRC="bar.gif" WIDTH="480" HEIGHT="6" ALIGN="BOTTOM" BORDER="0">
<H3><A NAME="Heading29"></A>Listing 11.21<SPACER TYPE="HORIZONTAL" SIZE="10"> BCFCONTROLCTL.CPP--WM_KEYDOWN
Message Handler</H3>
<P><FONT COLOR="#0066FF"><TT>LRESULT CBCFControlControl::WindowProc<BR>
<BR>
(<BR>
<BR>
UINT msg,<BR>
<BR>
WPARAM wParam,<BR>
<BR>
LPARAM lParam<BR>
<BR>
)<BR>
<BR>
{<BR>
<BR>
// TODO: handle any messages here, like in a normal window<BR>
<BR>
// proc. note that for special keys, you'll want to override and<BR>
<BR>
// implement OnSpecialKey.<BR>
<BR>
// if you're a windowed OCX, you should be able to use any of the<BR>
<BR>
// win32 API routines except for SetFocus. you should always use<BR>
<BR>
// OcxSetFocus()<BR>
<BR>
// <BR>
LRESULT lRetVal = FALSE; <BR>
switch(msg)<BR>
<BR>
{<BR>
<BR>
case WM_KEYDOWN:<BR>
<BR>
this-&gt;OnKeyDown(wParam, LOWORD(lParam), HIWORD(lParam));<BR>
<BR>
break;<BR>
<BR>
default:<BR>
<BR>
lRetVal = OcxDefWindowProc(msg, wParam, lParam);<BR>
<BR>
break;<BR>
<BR>
} <BR>
return lRetVal; <BR>
}<BR>
</TT></FONT></P>
<P>Finally you need to add all of the code for the methods that you declared in your
header file. Take a look at all of the methods in detail.</P>
<P>The <TT>CopyDataToClipboard</TT> is function called to initiate a Clipboard transfer
(see Listing 11.22). You first check to see whether you are the owner of the Clipboard
and set the Boolean variable accordingly. You then prepare your data for the Clipboard,
and if you are not the owner of the Clipboard, you flush the data on it and set your
<TT>IDataObject</TT> reference on the Clipboard.
<H3><A NAME="Heading30"></A>Listing 11.22 <SPACER TYPE="HORIZONTAL" SIZE="10">BCFCONTROLCTL.CPP--CopyDataToClipboard
Implementation</H3>
<P><FONT COLOR="#0066FF"><TT>void CBCFControlControl::CopyDataToClipboard(void)<BR>
<BR>
{<BR>
<BR>
BOOL bHaveClipboard = TRUE; <BR>
// if we don't have an IDataObject on the clipboard?<BR>
<BR>
if(::OleIsCurrentClipboard((IDataObject *) this) != S_OK)<BR>
<BR>
// set the flag<BR>
<BR>
bHaveClipboard = FALSE; <BR>
// put data in the storage<BR>
<BR>
this-&gt;PrepareDataForTransfer(); <BR>
// if we don't have the clipboard<BR>
<BR>
if(!bHaveClipboard)<BR>
<BR>
{<BR>
<BR>
// clear the clipboard<BR>
<BR>
::OleFlushClipboard(); <BR>
// put the data on the clipboard<BR>
<BR>
::OleSetClipboard((IDataObject *) this);<BR>
<BR>
} <BR>
}<BR>
</TT></FONT></P>
<P><TT>PrepareDataForTransfer</TT> (see Listing 11.23) is the function 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. First you allocate a block of global memory
that will contain your caption in <TT>ANSI</TT> format. Then you set up your <TT>FORMATETC</TT>
and <TT>STGMEDIUM</TT> structures to reflect the correct data type.
<H3><A NAME="Heading31"></A>Listing 11.23<SPACER TYPE="HORIZONTAL" SIZE="10"> BCFCONTROLCTL.CPP--PrepareDataForTransfer
Implementation</H3>
<P><FONT COLOR="#0066FF"><TT>void CBCFControlControl::PrepareDataForTransfer(void)<BR>
<BR>
{<BR>
<BR>
// get the length of the data to copy<BR>
<BR>

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -