COM provides a rich mechanism for allowing objects to return error information to callers. The following interfaces are used:
IErrorInfo
-- Returns information
from an error object.
ICreateErrorInfo
-- Sets error information.
ISupportErrorInfo()
-- Identifies
this object as supporting the
IErrorInfo()
interface.
Error handling functions.
This chapter covers the error handling interfaces.
To return error information:
Implement the
ISupportErrorInfo()
interface.
To create an instance of the generic error object, call the
CreateErrorInfo()
function.
To set its contents, use the
ICreateErrorInfo
methods.
To associate the error object with the current logical thread,
call the
SetErrorInfo()
function.
The error handling interfaces create and manage an error object, which provides information about the error. The error object is not the same as the object that encountered the error. It is a separate object associated with the current thread of execution.
To retrieve error information:
Check whether the returned value represents an error that the object is prepared to handle.
Call
QueryInterface()
to get a pointer
to the
ISupportErrorInfo
interface.
Then, call
InterfaceSupportsErrorInfo
to verify that the error was raised by
the object that returned it and that the error object pertains to the current
error, and not to a previous call.
To get a pointer to the error object, call the
GetErrorInfo()
function.
To retrieve information from the error object, use the
IErrorInfo
methods.
If the object is not prepared to handle the error, but needs to propagate
the error information further down the call chain, it should simply pass the
return value to its caller.
Because the
GetErrorInfo()
function clears the error information and passes ownership of the error object
to the caller, the function should be called only by the object that handles
the error.
The
IErrorInfo()
interface provides detailed contextual
error information.
Implemented by
|
Used by
|
Header filename |
Import library name |
Oleaut32.dll
(32-bit systems)
Ole2disp.dll
(16-bit systems) |
Applications that receive rich information. | Oleauto.h Dispatch.h |
Oleaut32.lib Oledisp.lib |
- Returns a textual description of the error.
IErrorInfo::GetDescription()
HRESULT GetDescription(
#include <Oaidl.h>
BSTR * pBstrDescription
);
Pointer to a brief string that describes the error.
S_OK
Success
The text is returned in the language specified by the locale identifier
(LCID)
that was passed to
IDispatch::Invoke()
for the method that
encountered the error.
- Returns the globally unique identifier (GUID) of the interface that defined
the error.
IErrorInfo::GetGUID()
HRESULT GetGUID(
#include <Oaidl.h>
GUID * pGUID
);
Pointer to a GUID, or
GUID_NULL
, if the
error was
defined by the operating system.
S_OK
Success.
IErrorInfo::GetGUID
returns the GUID of the interface
that defined the error.
If the error was defined by the system,
IErrorInfo::GetGUID
returns
GUID_NULL
.
This GUID does not necessarily represent the source of the error.
The
source is
the class or application that raised the error.
Using the GUID, an application
can handle errors in an interface, independent of the class that implements
the
interface.
- Returns the Help context identifier (ID) for the error.
IErrorInfo::GetHelpContext()
HRESULT GetHelpContext(
#include <Oaidl.h>
DWORD * pdwHelpContext
);
Pointer to the Help context ID for the error.
S_OK
Success
IErrorInfo::GetHelpContext
returns the Help context
ID for the error.
To find
the Help file to which it applies, use
IErrorInfo::GetHelpFile
.
- Returns the path of the Help file that describes the error.
IErrorInfo::GetHelpFile()
HRESULT GetHelpFile(
#include <Oaidl.h>
BSTR * pBstrHelpFile
);
Pointer to a string that contains the fully qualified path of the Help file.
S_OK
Success
IErrorInfo::GetHelpFile
returns the fully qualified
path of the Help file that
describes the current error.
IErrorInfo::GetHelpContext
should be used
to find the Help context ID for the error in the Help file.
- Returns the language-dependent programmatic ID (ProgID) for the
class or application that raised the error.
IErrorInfo::GetSource()
HRESULT GetSource(
#include <Oaidl.h>
BSTR * pBstrSource
);
Pointer to a string containing a ProgID, in the form progname.objectname.
S_OK
Success
Use IErrorInfo::GetSource
to determine the class
or application that is the
source of the error.
The language for the returned ProgID depends on the locale
ID (LCID) that was passed into the method at the time of invocation.
The
ICreateErrorInfo
interface returns error information.
Implemented by
|
Used by
|
Header filename |
Import library name |
Oleaut32.dll
(32-bit systems)
Oledisp.dll
(16-bit systems) |
Applications that return rich error information. | Oleauto.h Dispatch.h |
Oleaut32.lib Oledisp.lib |
- Sets the textual description of the error.
ICreateErrorInfo::SetDescription()
HRESULT SetDescription(
#include <Oleauto.h>
LPCOLESTR * szDescription
);
A brief, zero-terminated string that describes the error.
S_OK
Success
E_OUTOFMEMORY
Insufficient memory to complete the operation.
The text should be supplied in the language specified by the locale ID (LCID) that was passed to the method raising the error.
hr = CreateErrorInfo(&pcerrinfo); if (m_excepinfo.bstrDescription
) pcerrinfo->SetDescription
(m_excepinfo.bstrDescription
);
- Sets the globally unique identifier (GUID) of the interface that
defined the error.
ICreateErrorInfo::SetGUID()
HRESULT SetGUID(
#include <Oleauto.h>
REFGUID rguid
);
The GUID of the interface that defined the error, or
GUID_NULL
if the error was defined by the operating system.
The return value obtained from the returned
HRESULT
is one of the following:
S_OK
E_OUTOFMEMORY
ICreateErrorInfo
::SetGUID
sets
the GUID of the interface that defined the error.
If the error was defined
by the system, set
ICreateErrorInfo
::SetGUID
to
GUID_NULL
.
This GUID does not necessarily represent the source of the error; however, the source is the class or application that raised the error. Using the GUID, applications can handle errors in an interface, independent of the class that implements the interface.
hr = CreateErrorInfo(&pcerrinfo);
pcerrinfo->SetGUID
(IID_IHello);
- Sets the Help context identifier (ID) for the error.
ICreateErrorInfo::SetHelpContext()
HRESULT SetHelpContext(
#include <Oleauto.h>
DWORD dwHelpContext
);
The Help context ID for the error.
S_OK
Success
E_OUTOFMEMORY
Insufficient memory to complete the operation
ICreateErrorInfo
::SetHelpContext
sets the Help context ID for the error.
To
establish the Help file to which it applies, use
ICreateErrorInfo
::SetHelpFile
.
hr = CreateErrorInfo(&pcerrinfo);
pcerrinfo->SetHelpContext
(dwhelpcontext);
- Sets the path of the Help file that describes the error.
ICreateErrorInfo::SetHelpFile()
HRESULT SetHelpFile(
#include <Oleauto.h>
LPCOLESTR szHelpFile
);
The fully qualified path of the Help file that describes the error.
S_OK
Success
E_OUTOFMEMORY
Insufficient memory to complete the operation
ICreateErrorInfo
::SetHelpFile
sets the fully qualified path of the Help file
that describes the current error.
Use
ICreateErrorInfo
::SetHelpContext
to set the Help context ID for the error in the Help file.
hr = CreateErrorInfo(&pcerrinfo);
pcerrinfo->SetHelpFile
(<``><''>C:\myapp\myapp.hlp<``><''>);
- Sets the language-dependent programmatic identifier (ProgID) for
the
class or application that raised the error.
ICreateErrorInfo::SetSource()
HRESULT SetSource(
#include <Oleauto.h>
LPCOLESTR szSource
);
A ProgID in the form progname.objectname.
S_OK
Success
E_OUTOFMEMORY
Insufficient memory to complete the operation.
ICreateErrorInfo
::SetSource
should
be used to identify the class or application
that is the source of the error.
The language for the returned ProgID depends
on the locale identifier (LCID) that was passed to the method at the time
of
invocation.
hr = CreateErrorInfo(&pcerrinfo); if (m_excepinfo.bstrSource
) pcerrinfo->SetSource
(m_excepinfo.bstrSource
);
The
ISupportErrorInfo()
interface ensures that error
information
can be propagated up the call chain correctly.
Automation objects that use
the error
handling interfaces must implement
ISupportErrorInfo()
.
Implemented by |
Used by |
Header filename |
Applications that return error information. | Applications that retrieve error information. | Oleauto.h
(32-bit systems)
Dispatch.h
(16-bit systems) |
- Indicates whether or not an interface supports
the
ISupportErrorInfo::InterfaceSupportsErrorInfo()
IErrorInfo()
interface.
HRESULT InterfaceSupportsErrorInfo(
#include <Oaidl.h>
REFIID riid
);
Pointer to an interface identifier (IID).
S_OK
Interface supports
IErrorInfo()
S_FALSE
Interface does not support
IErrorInfo()
Objects that support the
IErrorInfo()
interface must
also implement this
interface.
Programs that receive an error return value should call
QueryInterface()
to get a
pointer to the
ISupportErrorInfo()
interface, and then
call
InterfaceSupportsErrorInfo
with the
riid
of the interface that returned
the return value.
If
InterfaceSupportsErrorInfo
returns
S_FALSE
, then the error
object does not represent an error returned from the caller, but from somewhere
else.
In this case, the error object can be considered incorrect and should
be
discarded.
If
ISupportErrorInfo()
returns
S_OK
,
use the
GetErrorInfo()
function to get a pointer to the error object.
The following example implements the
ISupportErrorInfo()
for the Lines sample.
The
IErrorInfo()
implementation also supports the
AddRef()
,
Release()
, and
QueryInterface()
members inherited from the
IUnknown()
interface.
CSupportErrorInfo::CSupportErrorInfo(IUnknown()
FAR* punkObject, REFIID riid)
{
m_punkObject = punkObject;
m_iid = riid;
}
STDMETHODIMP
CSupportErrorInfo::QueryInterface(REFIID iid, void FAR* FAR* ppv)
{
return m_punkObject->QueryInterface(iid, ppv);
}
STDMETHODIMP_(ULONG)
CSupportErrorInfo::AddRef(void)
{
return m_punkObject->AddRef();
}
STDMETHODIMP_(ULONG)
CSupportErrorInfo::Release(void)
{
return m_punkObject->Release();
}
STDMETHODIMP
CSupportErrorInfo::InterfaceSupportsErrorInfo(REFIID riid)
{
return (riid == m_iid) ? NOERROR : ResultFromScode(S_FALSE);
}
- Creates an instance of a generic error object.
CreateErrorInfo()
HRESULT CreateErrorInfo((
#include <oleauto.h>
ICreateErrorInfo ** pperrinfo
);
Pointer to a system-implemented generic error object.
S_OK
Success
E_OUTOFMEMORY
Could not create the error object
This function returns a pointer to a generic error object, which you
can use
with
QueryInterface()
on
ICreateErrorInfo
to set its contents.
You can then pass
the resulting object to
SetErrorInfo()
.
The generic error
object
implements both
ICreateErrorInfo
and
IErrorInfo()
.
ICreateErrorInfo *perrinfo; HRESULT hr; hr = CreateErrorInfo(&pcerrinfo);
- Obtains the error information pointer set by the previous call
to SetErrorInfo_oa96_SetErrorInfo in the current logical thread.
GetErrorInfo()
HRESULT GetErrorInfo((
#include <oleauto.h>
DWORD dwReserved,
IErrorInfo ** pperrinfo
);
Reserved for future use. Must be zero.
Pointer to a pointer to an error object.
S_OK
Success
S_FALSE
There was no error object to return
This function returns a pointer to the most recently set
IErrorInfo()
pointer in
the current logical thread.
It transfers ownership of the error object to
the
caller, and clears the error state for the thread.
- Sets the error information object for the current thread of execution.
SetErrorInfo()
HRESULT SetErrorInfo((
#include <oleauto.h>
DWORD dwReserved,
IErrorInfo * perrinfo
);
Reserved for future use. Must be zero.
Pointer to an error object.
S_OK
Success
This function releases the existing error information object, if one exists, and sets the pointer to perrinfo. Use this function after creating an error object that associates the object with the current thread of execution.
If the property or method that calls
SetErrorInfo()
is called by
DispInvoke()
, then
DispInvoke()
will
fill the
EXCEPINFO
parameter with the
values specified in the error information object.
DispInvoke()
will return
DISP_E_EXCEPTION
when the property or method returns a
failure return value for
DispInvoke()
.
Virtual function table (VTBL) binding controllers that do not use
IDispatch::Invoke()
can get the error information object
by using
GetErrorInfo()
.
This allows an object that supports a dual
interface to
use
SetErrorInfo()
, regardless of whether the client uses
VTBL binding or
IDispatch()
.
ICreateErrorInfo *pcerrinfo; IErrorInfo *perrinfo; HRESULT hr; hr = CreateErrorInfo(&pcerrinfo); hr = pcerrinfo->QueryInterface(IID_IErrorInfo, (LPVOID FAR*) &perrinfo); if (SUCCEEDED(hr)) { SetErrorInfo(0, perrinfo); perrinfo->Release(); } pcerrinfo->Release();
The key type involved in COM error reporting is
HRESULT
.
[Footnote 59]
In addition, the COM Library
provides a
few functions and macros to help applications of any kind deal with error
information.
An
HRESULT
is a simple 32-bit value:
typedef LONG HRESULT;
[Footnote 60]
An
HRESULT
is divided up into an internal structure that
has four fields with the
following format (numbers indicate bit positions):
S
:(1 bit) Severity field:
0 -- Success -- The function was successful; it behaved according to its prescribed semantics.
1 -- Error -- The function failed due to an error condition.
R
:(2 bits) Reserved for future use; must be set to zero by present programs generating HRESULTs; present code should not take action that relies on any particular bits being set or cleared this field.
Facility
:(13 bits) Indicates which group of status codes this belongs
to.
New facilities must be allocated by a central coordinating body since
they
need to be universally unique.
[Footnote 60]
However, the need for new facility codes is very small.
Most cases can and
should use
FACILITY_ITF
.
See Section
Section 12.3.4.1
below.
Code
:(16 bits) Describes what actually took place, error or otherwise.
COM presently defines the following facility codes:
|
Facility Value
|
Description
|
FACILITY_NULL |
0 | Used for broadly applicable common status
codes that have
no specific grouping.
S_OK
belongs to this facility, for
example.
|
FACILITY_ITF |
4 | Used for by far the majority of result codes
that are
returned from an interface member function.
Use of this facility indicates
that the
meaning of the error code is defined solely by the definition of the particular
interface
in question; an
HRESULT
with exactly the same 32-bit value
returned
from another interface might have a different meaning. |
FACILITY_RPC |
1 | Used for errors that result from an underlying remote procedure call implementation. In general, this specification does not explicitly document the RPC errors that can be returned from functions, though they nevertheless can be returned in situations where the interface being used is in fact remoted |
FACILITY_DISPATCH |
2 | Used for
IDispatch -interface-related
status codes.
|
FACILITY_STORAGE |
3 | Used for persistent-storage-related status codes. Status codes whose code (lower 16 bits) value is in the range of DOS error codes (less than 256) have the same meaning as the corresponding DOS error. |
FACILITY_WIN32 |
7 | Used to provide a means of mapping an error
code from a
function in the Win32 API into an
HRESULT .
The semantically
significant
part of a Win32 error is 16 bits large.
|
FACILITY_WINDOWS |
8 | Used for additional error codes from Microsoft-defined interfaces. |
FACILITY_CONTROL |
10 | Used for ActiveX Controls-related error values. |
A particular
HRESULT
value by convention uses the
following naming structure:
<Facility
>_<Sev
>_<Reason
>
where <Facility
>
is either the facility name or
some other
distinguishing identifier, <Sev
>
is a single letter,
one of the
set { S, E } indicating the severity (success or error), and
<Reason
>
is a short identifier that describes the meaning
of the
code.
Status codes from
FACILITY_NULL
omit the <Facility
>_ prefix.
For example, the status code
E_NOMEMORY
is the general
out-of memory error.
All
codes have either
S_
or
E_
in them allowing
quick visual determination if the
code means success or failure.
The general ``success''
HRESULT
is named
S_OK
,
meaning ``everything worked'' as per
the function specification.
The value of this
HRESULT
is
zero.
In addition, as
it is useful to have functions that can succeed but return Boolean results,
the
code
S_FALSE
is defined are success codes intended to mean
``function worked and
the result is false.''
#define S_OK 0 #define S_FALSE 1
From a general interface design perspective, ``success'' status codes
should be
used for circumstances where the consequence of ``what happened'' in a method
invocation is most naturally understood and dealt with by client code by
looking at the out-values returned from the interface function:
NULL
pointers,
etc.
``Error'' status codes should in contrast be used in situations where
the
function has performed in a manner that would naturally require ``out of band''
processing in the client code, logic that is written to deal with situations
in
which the interface implementation truly did not behave in a manner under
which
normal client code can make normal forward progress.
The distinction is an
imprecise and subtle one, and indeed many existing interface definitions do
not
for historical reasons abide by this reasoning.
However, with this approach,
it
becomes feasible to implement automated COM development tools that
appropriately turn the error codes into exceptions as was mentioned above.
Interface functions in general take the form:
HRESULT ISomeInteface::SomeFunction(ARG1_T arg1, ... , ARGN_T argn, RET_T * pret);
Stylistically, what would otherwise be the return value is passed as an out-value through the last argument of the function. COM development tools which map error returns into exceptions might also consider mapping the last argument of such a function containing only one out-parameter into what the programmer sees as the ``return value'' of the method invocation.
The COM remoting infrastructure only supports reporting of RPC-induced
errors
(such as communication failures) through interface member functions that return
HRESULT
s.
For interface member functions of other return
types (e.g.: void),
such errors are silently discarded.
To do otherwise would, to say the least,
significantly complicate local / remote transparency.
The use of
FACILITY_ITF
deserves some special discussion
with respect to
interfaces defined in COM and interfaces that will be defined in the future.
Whereas status codes with other facilities (FACILITY_NULL
,
FACILITY_RPC
, etc.) have universal meaning, status codes
in
FACILITY_ITF
have their meaning completely determined by
the interface member
function (or API function) from which they are returned; the same 32-bit value
in
FACILITY_ITF
returned from two different interface functions
may have
completely different meanings.
The reasoning behind this distinction is as follows.
For reasons of
efficiency,
it is unreasonable to have the primary error code data type (HRESULT
) be larger
than 32 bits in size.
32 bits is not large enough, unfortunately, to enable
COM
to develop an allocation policy for error codes that will universally avoid
conflict between codes allocated by different non-communicating programmers
at
different times in different places (contrast, for instance, with what is
done
with IIDs and CLSIDs).
Therefore, COM structures the use of the 32 bit
SCODE
in
such a way as to allow a central coordinating body
[Footnote 60]
to define
some
universally defined error codes while
at the same
time allowing other programmers to define new error codes without fear of
conflict by
limiting the places in which those field-defined error codes can be used.
Thus:
Status codes in facilities other than
FACILITY_ITF
can only be defined by
the central coordinating body.
Status codes in facility
FACILITY_ITF
are
defined solely by the
definer
of the interface
or API by which said status code is returned.
That is, in
order to avoid conflicting error codes, a human being needs to coordinate
the
assignment of codes in this facility, and we state that he who defines the
interface gets to do the coordination.
COM itself defines a number of interfaces and APIs, and so COM defines
many
status codes in
FACILITY_ITF
.
By design, none of the COM-defined
status codes
in fact have the same value, even if returned by different interfaces, though
it would have been legal for COM to do otherwise.
Likewise, it is possible (though not required) for designers of COM interface suites to coordinate the error codes across the interfaces in that suite so as to avoid duplication. The designers of the COM interface suite, for example, ensured such lack of duplication.
Thus, with regard to which errors can be returned by which interface functions, it is the case that, in the extreme,
It is legal that any COM-defined
error
code may
in fact be returned by
any COM-defined interface member function or API function.
This includes errors
presently defined in
FACILITY_ITF
.
Further, COM may in
the future define new
failure codes (but not
success
codes) that may also be
so ubiquitously
returned.
Designers of interface suites may if they wish choose to provide similar rules across the interfaces in their suites.
Further, any
error
in
FACILITY_RPC
or other
facility, even those errors not presently defined, may be returned.
Clients must treat error codes that are unknown to them as synonymous
with
E_UNEXPECTED
, which in general should be and is presently
a legal error return
value from each and every interface member function in all interfaces;
interface designers and implementors
are responsible to insure
that any
newly defined error codes they should choose to invent or return will be such
that that existing clients with code treating generic cases as synonymous
with
E_UNEXPECTED
this will have reasonable behavior.
In short, if you know the function you invoked, you know as a client how to unambiguously take action on any error code you receive. The interface implementor is responsible for maintaining your ability to do same.
Normally, of course, only a small subset of the COM-defined status codes will be usefully returned by a given interface function or API, but the immediately preceding statements are in fact the actual interoperability rules for the COM-defined interfaces. This specification endeavors to point out which error codes are particularly useful for each function, but code must be written to correctly handle the general rule.
The present document is, however, precise as to which success codes may legally be returned.
Conversely, it is
only
legal to return a status
code from the
implementation of an interface member function which has been sanctioned by
the
designer of that interface as being legally returnable; otherwise, there is
the
possibility of conflict between these returned code values and the codes
in-fact sanctioned by the interface designer.
Pay particular attention to
this
when propagating errors from internally called functions.
Nevertheless, as
noted above, callers of interfaces must to guard themselves from imprecise
interface implementations by treating any otherwise unknown returned error
code
(in contrast with success code) as synonymous with
E_UNEXPECTED
:
experience
shows that programmers are notoriously lax in dealing with error handling.
Further, given the third bullet point above, this coding practice is
required
by clients of the COM-defined interfaces and
APIs.
Pragmatically speaking, however, this is little burden to programmers: normal
practice is to handle a few special error codes specially, but treat the rest
generically.
All the COM-defined
FACILITY_ITF
codes will, in fact,
have a
code
value
which lies in the region 0x0000--0x01FF.
Thus, while it is indeed legal
for
the definer of a new function or interface to make use of any codes in
FACILITY_ITF
that he chooses in any way he sees fit, it
is highly recommended
that only
code
values in the range 0x0200--0xFFFF
be used, as this
will reduce the possibility of accidental confusion with any COM-defined
errors.
It is also highly recommended that designers of new functions and
interfaces consider defining as legal that most if not all of their functions
can return the appropriate status codes defined by COM in facilities other
than
FACILITY_ITF
.
E_UNEXPECTED
is a specific
error code that most if not all
interface definers will wish to make universally legal.
The
IErrorLog()
interface is an abstraction for an
error log that is
used to communicate detailed error information between a client and an object.
The caller of the single interface method,
AddError
, simply
logs an error where
the error is an
EXCEPINFO
structure related to a specific
property.
The implementer
of the interface is responsible for handling the error in whatever way it
desires.
IErrorLog()
is used in the protocol between a client that
implements
IPropertyBag()
and
an object that implements
IPersistPropertyBag()
.
A container implements
IErrorLog()
to provide a control
with a means of
logging errors when the control is loading its properties from the
container-provided property bag.
A control logs calls the single method in this interface to log any errors that occur when it is loading its properties.
IUnknown Methods
|
Description
|
QueryInterface()
|
Returns pointers to supported interfaces. |
AddRef()
|
Increments reference count. |
Release()
|
Decrements reference count. |
|
Description
|
AddError |
Logs an error, an
EXCEPINFO
structure, in the error log during the property load process for a named property.
|
IPersistPropertyBag()
,
IPropertyBag()
- Logs an error, an
IErrorLog::AddError()
EXCEPINFO
structure, in the error log
during the property
load process for a named property.
HRESULT AddError(
#include <ocidl.h>
LPCOLESTR pszPropName,
LPEXCEPINFO pException
);
E_NOTIMPL
is not a valid return code as the method
is the only one in the
entire interface.
[in] Pointer to the name of the property involved with the
error.
Cannot
be
NULL
.
[in] Pointer to the caller-initialized
EXCEPINFO
structure that describes the error to log.
Cannot be
NULL
.
S_OK
The error was logged successfully.
E_FAIL
There was a problem logging the error.
E_OUTOFMEMORY
There was not enough memory to log the error.
E_POINTER
The address in pszPropName or pExceptInfo is not valid (such as NULL). The caller must supply both.