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

📄 ch03.htm

📁 用VC开发activeX控件的电子书,很不错的
💻 HTM
📖 第 1 页 / 共 5 页
字号:
if(::SafeArrayGetElement(varOutputArray->parray, &lArrayCount, &bstrTemp)
== S_OK) <BR>
{ <BR>
// output the data <BR>
fprintf(m_fileLog, _T(&quot;%s(%10ld)-%s%ls\n&quot;), (LPCTSTR) oTimeStamp.Format(&quot;%H:%M:%S&quot;),
m_lHiResTime - m_lLastHiResTime, (LPCTSTR) cstrIndent, bstrTemp); <BR>
// store the last timer value <BR>
m_lLastHiResTime = m_lHiResTime; <BR>
// free the bstr <BR>
::SysFreeString(bstrTemp); <BR>
} <BR>
} <BR>
} <BR>
else <BR>
bResult = VARIANT_FALSE; <BR>
} <BR>
else <BR>
bResult = VARIANT_FALSE; <BR>
// unlock the array we don't need it anymore <BR>
::SafeArrayUnlock(varOutputArray-&gt;parray); <BR>
} <BR>
else <BR>
bResult = VARIANT_FALSE; <BR>
} <BR>
else <BR>
bResult = VARIANT_FALSE; <BR>
// return the result <BR>
return bResult; <BR>
<BR>
} </TT></FONT></P>
<P>It is worthwhile to review the documentation in the VC++ books online on ODL,
Automation, and <TT>VARIANT</TT> data types to see what kind of flexibility you have
when defining methods and parameters. See <A HREF="ch06.htm">Chapters 6</A> through
11 on developing ActiveX controls for descriptions of more options and features when
creating methods.</P>
<P>Now that you have added a method, you are ready to implement its counterpart,
the property.
<H2><A NAME="Heading18"></A>Adding Properties</H2>
<P>A <I>property</I> can be thought of as an exposed variable that is defined in
the Automation Server. Properties are useful for setting and retrieving information
about the state of the server.</P>
<P>Properties are implemented as a pair of methods: one to get the value, and the
other to set the value. The <TT>m_lIndent</TT> member variable that you added to
the class definition is a perfect candidate to be exposed as a property.</P>
<P>As with methods, properties are also added via the ClassWizard in MFC. From the
<U>V</U>iew menu, select the Class<U>W</U>izard menu item. In the MFC ClassWizard
dialog, select the Automation tab, and click the Add P<U>r</U>operty button. In the
Add Property dialog, enter the <U>E</U>xternal name of the property as Indent and
select the type as <TT>long</TT> (see fig. 3.6). Set the Implementation to Get/Set
<U>m</U>ethods, and click OK to add the property to the server. Click the <U>E</U>dit
Code button to close the MFC ClassWizard dialog and open the source file for editing.
<B><BR>
<BR>
</B><A HREF="Art/03/cfig6r.jpg"><B>FIG. 3.6</B></A> <I><BR>
Add the <TT>Indent</TT> property with the ClassWizard.</I></P>
<P>The actual implementation of the <TT>Indent</TT> property is very easy (see Listing
3.10). <TT>GetIndent</TT> returns the value currently stored in the member variable,
and <TT>SetIndent</TT> stores the new value, after a little bit of error checking,
in the member variable.
<H3><A NAME="Heading19"></A>Listing 3.10 TRACKER.CPP--Indent Property Implementation</H3>
<P><FONT COLOR="#0066FF"><TT>long CTracker::GetIndent() <BR>
{ <BR>
// return the member variable <BR>
return m_lIndent; <BR>
} <BR>
void CTracker::SetIndent(long nNewValue) <BR>
{ <BR>
// if the new value is a least 0 <BR>
if(nNewValue &gt;= 0) <BR>
// assign the value to our member variable <BR>
m_lIndent = nNewValue; <BR>
<BR>
} </TT></FONT></P>
<P>Properties, like methods, also have a wide variety of implementation options,
including parameterized and enumerated values. See <A HREF="ch06.htm">Chapters 6</A>
through 11 on developing ActiveX controls for descriptions of more options and features
when creating properties.</P>
<P>You've added methods and properties to the server but haven't really dealt with
the issue of error handling in their implementation. In some cases, simply returning
success or failure is not enough information for the developer to understand that
an error occurred and what caused it. You will communicate more error information
through the use of OLE exceptions.
<H2><A NAME="Heading20"></A>Generating OLE Exceptions</H2>
<P>While executing a method call or some other action, at times it is necessary to
terminate the process due to some critical error that has occurred or is about to
occur. For example, a method is called to write data to a file, but the method cannot
open the file because there is not enough room on the hard disk to do so. It is necessary
to halt further processing until the error can be resolved. An error of this kind
is known as an <I>exception. </I>Any type of error can be treated as an exception;
it depends on the requirements of your application and how you choose to deal with
the errors that may result.</P>
<P>You must become familiar with two forms of exceptions when creating ActiveX components.
The first is a C++ exception. A <I>C++ exception </I>is a language mechanism used
to create critical errors of the type described earlier and is confined to the application
in which they are defined. The second is an OLE exception. <I>OLE exceptions </I>are
used to communicate the same kinds of errors externally to applications that are
using a component. The difference between the two is that C++ exceptions are used
internal to an application's implementation, and OLE exceptions are used externally
to communicate errors to other applications.</P>
<P>The <TT>IDispatch</TT> interface contains specific parameters in its functions
for dealing with exceptions and passing them to the controller application. The MFC
implementation of the <TT>CCmdTarget</TT> class handles the details of generating
OLE exceptions by trapping any C++ exceptions that it receives and translates them
to the proper <TT>IDispatch</TT> error information. You need only create a C++ exception
of type <TT>COleDispatchException</TT> and throw it. MFC does all of the work for
you. When creating dual-interface servers, exceptions are handled in a different
way, which you will see later in this chapter.</P>
<P>The first step is to add an enumeration of the types of errors that the server
can generate to the ODL file (see Listing 3.11). Adding the enumeration to the ODL
has the effect of publishing the error constants to the applications developer that
is using the server. You add the constants in the form of an include file so that
you can use the same error constants file in the C++ source code implementation.
You also add a <TT>UUID</TT> to the <TT>typedef</TT> so that it can be identified
in the type library that is generated with the GUIDGEN.EXE program.
<H3><A NAME="Heading21"></A>Listing 3.11 MFCSERVER.ODL--Error Enumeration</H3>
<P><FONT COLOR="#0066FF"><TT>. . . <BR>
[ uuid(11C82947-4EDD-11D0-BED8-00400538977D) ] <BR>
coclass TRACKER <BR>
{ <BR>
[default] dispinterface ITracker; <BR>
}; <BR>
typedef [uuid(11C82948-4EDD-11D0-BED8-00400538977D), helpstring(&quot;Tracker Error
Constants&quot;)] <BR>
#include &quot;trackererror.h&quot; <BR>
//{{AFX_APPEND_ODL}} <BR>
<BR>
}; </TT></FONT></P>
<P>TrackerError.h contains a standard C/C++ enumeration of the errors that the application
supports (see Listing 3.12). The starting value of the errors falls into the range
of valid user-defined errors. Be careful when assigning error numbers since most
tools will first look up the system-defined error message before using the message
defined in the exception.
<H3><A NAME="Heading22"></A>Listing 3.12 TRACKERERROR.H--Tracker Error Constants</H3>
<P><FONT COLOR="#0066FF"><TT>// Error enumeration <BR>
enum tagTrackerError <BR>
{ <BR>
MFCSERVER_E_NO_UBOUND = 46080, <BR>
MFCSERVER_E_NO_LBOUND = 46081, <BR>
MFCSERVER_E_NO_ARRAYLOCK = 46082,<BR>
MFCSERVER_E_NO_FILE = 46083,<BR>
MFCSERVER_E_BAD_ARRAY_PARAMETER = 46084,<BR>
MFCSERVER_E_INVALID_VALUE = 46085<BR>
}TRACKERERROR;</TT></FONT></P>
<P>The next step is to add the code that will generate the exceptions to all of the
appropriate locations in the server code (see Listing 3.13). As you can see, instead
of returning <TT>VARIANT_FALSE</TT> or ignoring an error condition, you now generate
meaningful errors and messages instructing the developer as to the source of the
problem. The exception-generating code is fairly straightforward. First you create
a <TT>COleDispacthException</TT> and set the appropriate members with the data that
is necessary for the error that was generated (for information about other types
of exceptions, see the VC++ documentation). For your implementation, you set the
error code, the name of the file that generated the error, and the error message.
You could also supply a help filename and a help ID to further describe the error.
Note the use of the <TT>MAKE_SCODE</TT> macro to generate a valid <TT>SCODE</TT>
error number for the exception.
<H3><A NAME="Heading23"></A>Listing 3.13 TRACKER.CPP--Exception Handling Code Added
to the Source Files</H3>
<P><FONT COLOR="#0066FF"><TT>/////////////////////////////////////////////////////////////////////////////
<BR>
// CTracker message handlers <BR>
BOOL CTracker::OutputLines(VARIANT FAR* varOutputArray, const VARIANT FAR&amp; varIndent)
<BR>
{ <BR>
BOOL bResult = VARIANT_TRUE; <BR>
// if we have a file a if the variant contains a string array <BR>
if(m_fileLog &amp;&amp; varOutputArray-&gt;vt == (VT_ARRAY | VT_BSTR)) <BR>
{ <BR>
// lock the array so we can use it <BR>
if(::SafeArrayLock(varOutputArray-&gt;parray) == S_OK) <BR>
{ <BR>
LONG lLBound; <BR>
// get the lower bound of the array <BR>
if(::SafeArrayGetLBound(varOutputArray-&gt;parray, 1, &amp;lLBound) == S_OK) <BR>
{ <BR>
LONG lUBound; <BR>
// get the number of elements in the array <BR>
if(::SafeArrayGetUBound(varOutputArray-&gt;parray, 1, &amp;lUBound) == S_OK) <BR>
{ <BR>
CString cstrIndent; <BR>
CTime oTimeStamp; <BR>
BSTR bstrTemp; <BR>
// if we have an indent parameter <BR>
if(varIndent.vt != VT_I4) <BR>
{ <BR>
// get a variant that we can use for conversion purposes <BR>
VARIANT varConvertedValue; <BR>
// initialize the variant <BR>
::VariantInit(&amp;varConvertedValue); <BR>
// see if we can convert the data type to something useful - VariantChangeTypeEx()
could also be used <BR>
if(S_OK == ::VariantChangeType(&amp;varConvertedValue, (VARIANT *) &amp;varIndent,
0, VT_I4)) <BR>
// assign the value to our member variable <BR>
m_lIndent = varConvertedValue.lVal; <BR>
} <BR>
else <BR>
// assign the value to our member variable <BR>
m_lIndent = varIndent.lVal; <BR>
// if we have to indent the text <BR>
for(long lIndentCount = 0; lIndentCount &lt; m_lIndent; lIndentCount++) <BR>
// add a tab to the string <BR>
cstrIndent += _T(&quot;\t&quot;); <BR>
// for each of the elements in the array <BR>
for(long lArrayCount = lLBound; lArrayCount &lt; (lUBound + lLBound); lArrayCount++)
<BR>
{ <BR>
// update the time <BR>
oTimeStamp = CTime::GetCurrentTime(); <BR>
m_lHiResTime = timeGetTime(); <BR>
// get the data from the array <BR>
if(::SafeArrayGetElement(varOutputArray-&gt;parray, &amp;lArrayCount, &amp;bstrTemp)
== S_OK) <BR>
{ <BR>
// output the data <BR>
fprintf(m_fileLog, _T(&quot;%s(%10ld)-%s%ls\n&quot;), (LPCTSTR) oTimeStamp.Format(&quot;%H:%M:%S&quot;),
m_lHiResTime - m_lLastHiResTime, (LPCTSTR) cstrIndent, bstrTemp); <BR>
// store the last timer value <BR>
m_lLastHiResTime = m_lHiResTime; <BR>
// free the bstr <BR>
::SysFreeString(bstrTemp); <BR>
} <BR>
} <BR>
} <BR>
else <BR>
{ <BR>
bResult = VARIANT_FALSE; <BR>
// unable to get a record based on the sql statement - throw an exception <BR>
COleDispatchException * pOleDispExcep = new COleDispatchException(_T(&quot;&quot;),
NULL, 0); <BR>
// format the error code <BR>
pOleDispExcep-&gt;m_scError = MAKE_SCODE(SEVERITY_ERROR, FACILITY_ITF, MFCSERVER_E_NO_UBOUND);
<BR>
// set the source file <BR>
pOleDispExcep-&gt;m_strSource = __FILE__; <BR>
// format the error description <BR>
pOleDispExcep-&gt;m_strDescription = _T(&quot;Unable to retrieve the upper bound
dimension of the array.&quot;); <BR>
// the function call failed cause an ole exception <BR>
throw(pOleDispExcep); <BR>
} <BR>
} <BR>
else <BR>
{ <BR>
bResult = VARIANT_FALSE; <BR>
// unable to get a record based on the sql statement - throw an exception <BR>
COleDispatchException * pOleDispExcep = new COleDispatchException(_T(&quot;&quot;),
NULL, 0); <BR>
// format the error code <BR>
pOleDispExcep-&gt;m_scError = MAKE_SCODE(SEVERITY_ERROR, FACILITY_ITF, MFCSERVER_E_NO_LBOUND);

⌨️ 快捷键说明

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