Com Spec
Com Spec
Version 1.0
April 10, 1998
Note: This document is meant to specify and accompany software that is still in
development. Some of the information in this documentation may be inaccurate or m
ay not be an accurate representation of the actual functionality of the software.
When this document and the functionality of the software conflict, The actual f
unctionality of the software represents the correct functionality. Microsoft as
sumes no responsibility for any damages that might occur either directly or indi
rectly from these discrepencies or inaccuracies. Microsoft may have trademarks,
copyrights, patents or pending patent applications, or other intellectual proper
ty rights covering subject matter in this document. The furnishing of this docum
ent does not give you a license to these trademarks, copyrights, patents, or oth
er intellectual property rights.
This document contains the specification to the COM core technologies, an archit
ecture and supporting infrastructure for building, using, and evolving component
software in a robust manner. This specification contains the standard APIs supp
orted by the COM core technology along with the network protocol used by the Com
ponent Object Model (COM) in support of distributed computing.
The COM Core Technology Specification
4.7.3.3 IProvideClassInfo2::GetGUID
Returns a GUID corresponding to the specified dwGuidKind. The dwGuidKind paramet
er has several values defined. See GUIDKIND. Additional flags can be defined at
a later time and will be recognized by an IProvideClassInfo2 implementation.
HRESULT GetGUID(
DWORD dwGuidKind, //Desired GUID
GUID * pGUID //Pointer to the desired GUID
);
Parameters
dwGuidKind
[in] Specifies the GUID desired on return. This parameter takes a value from the
GUIDKIND enumeration.
pGUID
[out] Pointer to the caller s variable in which to store the GUID associated with
dwGuidKind.
Return Values
S_OK
The GUID was successfully returned in *pGUID.
E_POINTER
The address in pGUID is not valid (such as NULL).
E_UNEXPECTED
An unknown error occurred.
E_INVALIDARG
The dwGuidKind value does not correspond to a supported GUID kind.
Remarks
E_NOTIMPL is not a valid return code since it would be pointless to implement th
is interface without implementing this method.
E_INVALIDARG is not valid when dwGuidKind is GUIDKIND_DEFAULT_SOURCE_DISP_IID.
See Also
GUIDKIND
4.8 Objects and Interfaces Enumeration Description
4.8.1 GUIDKIND
The GUIDKIND enumeration values are flags used to specify the kind of informatio
n requested from an object in the IProvideClassInfo2.
typedef enum tagGUIDKIND
{
GUIDKIND_DEFAULT_SOURCE_DISP_IID = 1,
} GUIDKIND;
Elements
GUIDKIND_DEFAULT_SOURCE_DISP_IID
The interface identifier (IID) of the object s outgoing dispinterface, labeled [so
urce, default]. The outgoing interface in question must be derived from IDispatc
h.
See Also
IProvideClassInfo2
5. The COM Library
5.1 COM Application Responsibilities
All applications, that is, running programs that define a task or a process be t
hey client or servers, have specific responsibilities. This chapter examines the
roles and responsibilities of all COM applications and the necessary COM librar
y support functions for those responsibilities.
In short, any application that makes use of COM, client or server, has three spe
cific responsibilities to insure proper operation with other components:
On application startup, initialize the COM Library.
On application shutdown, uninitialize the COM Library to allow it to free resour
ces and perform any cleanup operations as necessary.
Each of these responsibilities requires support from the COM Library itself as d
etailed in the following sections. For convenience, initialization and uninitial
ization are described together. Additional COM Library functions related to init
ialization and memory management are also given in this chapter.
5.2 Library Initialization / Uninitialization
To use basic COM services, all COM threads of execution in clients and out-of-pr
ocess servers must call either the CoInitialize or the CoInitializeEx function b
efore calling any other COM function except memory allocation calls. CoInitializ
eEx replaces the other function, adding a parameter that allows you to specify t
he threading model of the thread either apartment-threaded or free-threaded. A c
all to CoInitialize simply sets the threading model to apartment-threaded. For i
nformation on threading in clients and servers, refer to Processes and Threads.
In-process servers do not call the initialization functions, because they are be
ing loaded into a process that has already done so. As a result, in-process serv
ers must set their threading model in the registry under the InprocServer32 key.
For detailed information on threading issues in in-process servers, refer to In
-Process Server Threading Issues.
It is also important to uninitialize the library. For each call to CoInitialize
or CoInitializeEx, there must be a corresponding call to CoUninitialize.
5.3 Memory Management
As was articulated earlier in this specification, when ownership of allocated me
mory is passed through an interface, COM requires that the memory be allocated w
ith a specific task allocator. Most general purpose access to the task allocator i
s provided through the IMalloc interface instance returned from CoGetMalloc. Sim
ple shortcut allocation and freeing APIs are also provided in the form of CoTask
MemAlloc and CoTaskMemFree.
5.3.1 Memory Allocation Example
An object may need to pass memory between it and the client at some point in the
object s lifetime this applies to in-process as well as out-of-process servers. Whe
n such a situation arises the object must use the task allocator as described in
Chapter 3. That is, the object must allocate memory whose ownership is transfer
red from one party to another through an interface function by using the local t
ask allocator.
CoGetMalloc provides a convenient way for objects to allocate working memory as
well. For example, when the TextRender object (see Chapter 4, Designing and Imple
menting Objects ) under consideration in this document loads text from a file in t
he function IPersistFile::Load (that is, CTextRender::Load) it will want to make
a memory copy of that text. It would use the task allocator for this purpose as
illustrated in the following code (unnecessary details of opening files and rea
ding data are omitted for simplicity):
//Implementation of IPersistFile::Load
HRESULT CTextRender::Load(char *pszFile, DWORD grfMode) {
int hFile;
DWORD cch;
IMalloc * pIMalloc;
HRESULT hr;
/*
* Open the file and seek to the end to set the
* cch variable to the length of the file.
*/
hr=CoGetMalloc(MEMCTX_TASK, &pIMalloc);
if (FAILED(hr))
//Close file and return failure
psz=pIMalloc->Alloc(cch);
pIMalloc->Release();
if (NULL==psz)
//Close file and return failure
//Read text into psz buffer and close file
//Save memory pointer and return success
m_pszText=psz;
return NOERROR;
}
If an object will make many allocations throughout it s lifetime, it makes sense t
o call CoGetMalloc once when the object is created, store the IMalloc pointer in
the object (m_pIMalloc or such), and call IMalloc::Release when the object is d
estroyed. Alternatively, the APIs CoTaskMemAlloc and its friends may be used.
5.4 COM Library Interface Descriptions
5.4.1 IMalloc
Allocates, frees, and manages memory.
5.4.1.1.1 When to Implement
In general, you should not implement IMalloc, instead using the COMOLE implement
ation, which is guaranteed to be thread-safe in managing task memory. You get a
pointer to the COMOLE task allocator object s IMalloc through a call to the CoGetM
alloc function.
5.4.1.1.2 When to Use
Call the methods of IMalloc to allocate and manage memory. The COMOLE libraries
and object handlers also call the IMalloc methods to manage memory. Object handl
ers should call CoGetMalloc to get a pointer to the IMalloc implementation on th
e task allocator object, and use the implementation of those methods to manage t
ask memory.
The IMalloc methods Alloc, Free, and Realloc are similar to the C library functi
ons malloc, free, and realloc. For debugging, refer to the functions CoRegisterM
allocSpy and CoRevokeMallocSpy.
Methods in Vtable Order
IUnknown Methods Description
QueryInterface Returns pointers to supported interfaces.
AddRef Increments the reference count.
Release Decrements the reference count.
IMalloc Methods Description
Alloc Allocates a block of memory.
Realloc Changes the size of a previously allocated block of memory.
Free Frees a previously allocated block of memory.
GetSize Returns the size in bytes of a previously allocated block of memory.
DidAlloc Determines if this instance of IMalloc was used to allocate the
specified block of memory.
HeapMinimize Minimizes the heap by releasing unused memory to the operating s
ystem.
See Also
CoGetMalloc, IMallocSpy, CoRegisterMallocSpy, CoRevokeMallocSpy
5.4.1.2 IMalloc::Alloc
Allocates a block of memory.
void * Alloc(
ULONG cb //Size of the requested memory block in bytes
);
Parameter
cb
[in] Size , in bytes, of the memory block to be allocated.
Return Values
If successful, Alloc returns a pointer to the allocated memory block.
NULL
If insufficient memory is available, Alloc returns NULL.
Remarks
The IMalloc::Alloc method allocates a memory block in essentially the same way t
hat the C Library malloc function does.
The initial contents of the returned memory block are undefined there is no guar
antee that the block has been initialized, so you should initialize it in your c
ode. The allocated block may be larger than cb bytes because of the space requir
ed for alignment and for maintenance information.
If cb is zero, IMalloc::Alloc allocates a zero-length item and returns a valid p
ointer to that item. If there is insufficient memory available, IMalloc::Alloc r
eturns NULL.
Note
Applications should always check the return value from this method, even when re
questing small amounts of memory, because there is no guarantee the memory will
be allocated.
See Also
IMalloc::Free, IMalloc::Realloc, CoTaskMemAlloc
5.4.1.3 IMalloc::DidAlloc
Determines if this allocator was used to allocate the specified block of memory.
int DidAlloc(
void *pv //Pointer to the memory block
);
Parameter
pv
[in] Pointer to the memory block; can be a NULL pointer, in which case, -1 is re
turned.
Return Values
1
The memory block was allocated by this IMalloc instance.
0
The memory block was not allocated by this IMalloc instance.
-1
DidAlloc is unable to determine whether or not it allocated the memory block.
Remarks
Calling IMalloc::DidAlloc is useful if a application is using multiple allocatio
ns, and needs to know whether a previously allocated block of memory was allocat
ed by a particular allocation.
See Also
IMalloc::Alloc, IMalloc::HeapMinimize, IMalloc::Realloc
5.4.1.4 IMalloc::Free
Frees a previously allocated block of memory.
void Free(
void * pv //Pointer to the memory block to be freed
);
Parameter
pv
[in] Pointer to the memory block to be freed.
Remarks
IMalloc:Free frees a block of memory previously allocated through a call to IMal
loc::Alloc or IMalloc::Realloc. The number of bytes freed equals the number of b
ytes that were allocated. After the call, the memory block pointed to by pv is i
nvalid and can no longer be used.
Note
The pv parameter can be NULL. If so, this method has no effect.
See Also
IMalloc::Alloc, IMalloc::Realloc, CoTaskMemFree
5.4.1.5 IMalloc::GetSize
Returns the size (in bytes) of a memory block previously allocated with IMalloc:
:Alloc or IMalloc::Realloc.
ULONG GetSize(
void *pv //Pointer to the memory block for which the size is requested
);
Parameter
pv
[in] Pointer to the memory block for which the size is requested.
Return Value
The size of the allocated memory block in bytes or, if pv is a NULL pointer, -1.
Remarks
To get the size in bytes of a memory block, the block must have been previously
allocated with IMalloc::Alloc or IMalloc::Realloc. The size returned is the actu
al size of the allocation, which may be greater than the size requested when the
allocation was made.
See Also
IMalloc::Alloc, IMalloc::Realloc
5.4.1.6 IMalloc::HeapMinimize
Minimizes the heap as much as possible by releasing unused memory to the operati
ng system, coalescing adjacent free blocks and committing free pages.
void HeapMinimize();
Remarks
Calling IMalloc::HeapMinimize is useful when an application has been running for
some time and the heap may be fragmented.
See Also
IMalloc::Alloc, IMalloc::Free, IMalloc::Realloc
5.4.1.7 IMalloc::Realloc
Changes the size of a previously allocated memory block.
void *Realloc(
void *pv, //Pointer to memory block to be reallocated
ULONG cb //Size of the memory block in bytes
);
Parameters
pv
[in] Pointer to the memory block to be reallocated. The pointer can have a NULL
value, as discussed in the following Remarks section.
cb
[in] Size of the memory block (in bytes) to be reallocated. It can be zero, as d
iscussed in the following remarks.
Return Values
Reallocated memory block
Memory block successfully reallocated.
NULL
Insufficient memory or cb is zero and pv is not NULL.
Remarks
IMalloc::Realloc reallocates a block of memory, but does guarantee that the cont
ents of the returned memory block are initialized. Therefore, the caller is resp
onsible for intializing it in code, subsequent to the reallocation. The allocate
d block may be larger than cb bytes because of the space required for alignment
and for maintenance information.
The pv argument points to the beginning of the memory block. If pv is NULL, IMal
loc::Realloc allocates a new memory block in the same way that IMalloc::Alloc do
es. If pv is not NULL, it should be a pointer returned by a prior call to IMallo
c::Alloc.
The cb argument specifies the size (in bytes) of the new block. The contents of
the block are unchanged up to the shorter of the new and old sizes, although the
new block can be in a different location. Because the new block can be in a dif
ferent memory location, the pointer returned by IMalloc::Realloc is not guarante
ed to be the pointer passed through the pv argument. If pv is not NULL and cb is
zero, then the memory pointed to by pv is freed.
IMalloc::Realloc returns a void pointer to the reallocated (and possibly moved)
memory block. The return value is NULL if the size is zero and the buffer argume
nt is not NULL, or if there is not enough memory available to expand the block t
o the given size. In the first case, the original block is freed; in the second,
the original block is unchanged.
The storage space pointed to by the return value is guaranteed to be suitably al
igned for storage of any type of object. To get a pointer to a type other than v
oid, use a type cast on the return value.
See Also
IMalloc::Alloc, IMalloc::Free5.4.2 IMallocSpy
The IMallocSpy interface is a debugging interface that allows application develo
pers to monitor (spy on) memory allocation, detect memory leaks and simulate mem
ory failure in calls to IMalloc methods.
Caution
The IMallocSpy interface is intended to be used only to debug application code u
nder development. Do not ship this interface to retail customers of your applica
tion, because it causes severe performance degradation and could conflict with u
ser-installed software to produce unpredictable results.
When to Implement
Implement this interface to debug memory allocation during application developme
nt.
When to Use
When an implementation of IMallocSpy is registered with CoRegisterMallocSpy, COM
calls the pair of IMallocSpy methods around the corresponding IMalloc method. Y
ou would not make direct calls to IMallocSpy methods. The COM SDK contains a sam
ple implementation of IMallocSpy. The call to the pre-method through the return
from the corresponding post-method is guaranteed to be thread-safe in multi-thre
aded operations.
Methods in Vtable Order
IUnknown Methods Description
QueryInterface Returns pointers to supported interfaces.
AddRef Increments reference count.
Release Decrements reference count.
IMallocSpy Methods Description
PreAlloc Called before invoking IMalloc::Alloc, and may extend or modify
the allocation to store debug information.
PostAlloc Called after invoking IMalloc::Alloc.
PreFree Called before invoking IMalloc::Free.
PostFree Called after invoking IMalloc::Free.
PreRealloc Called before invoking IMalloc::Realloc.
PostRealloc Called after invoking IMalloc::Realloc.
PreGetSize Called before invoking IMalloc::GetSize.
PostGetSize Called after invoking IMalloc::GetSize.
PreDidAlloc Called before invoking IMalloc::DidAlloc.
PostDidAlloc Called after invoking IMalloc::DidAlloc.
PreHeapMinimize Called before invoking IMalloc::DidAlloc.
PostHeapMinimize Called after invoking IMalloc::HeapMinimize.
See Also
IMalloc, CoGetMalloc, CoRegisterMallocSpy
IMallocSpy::PreAlloc
Called just prior to invoking IMalloc::Alloc.
ULONG PreAlloc(
ULONG cbRequest //Byte count passed to IMalloc::Alloc
);
Parameter
cbRequest
[in] Number of bytes specified in the allocation request the caller is passing t
o IMalloc::Alloc. byte count actually passed to IMalloc::Alloc, which should be
greater than or equal to the value of cbRequest.
Remarks
The IMallocSpy::PreAlloc implementation may extend and/or modify the allocation
to store debug-specific information with the allocation.
PreAlloc can force memory allocation failure by returning 0, allowing testing to
ensure that the application handles allocation failure gracefully in all cases.
In this case, PostAlloc is not called and Alloc returns NULL. Forcing allocatio
n failure is effective only if cbRequest is not equal to 0. If PreAlloc is forci
ng failure by returning NULL, PostAlloc is not called. However, if IMalloc::Allo
c encounters a real memory failure and returns NULL, PostAlloc is called.
The call to PreAlloc through the return from PostAlloc is guaranteed to be threa
d safe.
See Also
IMalloc::Alloc, IMallocSpy::PostAlloc, CoRegisterMallocSpy, CoRevokeMallocSpy
IMallocSpy::PostAlloc
Called just after invoking IMalloc::Alloc, taking as input a pointer to the IMal
loc::Alloc caller's allocation, and returning a pointer to the actual allocation
.
void * PostAlloc(
void * pActual //Pointer to the allocation actually done by
//IMalloc::Alloc
);
Parameter
pActual
[in] Pointer to the allocation done by IMalloc::Alloc.
Return Value
A pointer to the beginning of the memory block actually allocated. This pointer
is also returned to the caller of IMalloc::Alloc. If debug information is writte
n at the front of the caller's allocation, this should be a forward offset from
pActual. The value is the same as pActual if debug information is appended or if
no debug information is attached.
Remarks
When a spy object implementing IMallocSpy is registered with CoRegisterMallocSpy
, COM calls IMallocSpy::PostAlloc after any call to IMalloc::Alloc. It takes as
input a pointer to the allocation done by the call to IMalloc::Alloc, and return
s a pointer to the beginning of the total allocation, which could include a forw
ard offset from the other value if IMallocSpy::Prealloc was implemented to attac
h debug information to the allocation in this way. If not, the same pointer is r
eturned, and also becomes the return value to the caller of IMalloc::Alloc.
See Also
IMalloc::Alloc, IMallocSpy::PreAlloc, CoRegisterMallocSpy, CoRevokeMallocSpy
IMallocSpy::PreDidAlloc
Called by COM just prior to invoking IMalloc::DidAlloc.
void * PreDidAlloc(
void * pRequest,
//Pointer the caller is passing to IMalloc::DidAlloc
BOOL fSpyed //Whether pRequest was allocated while this spy was
//active
);
Parameters
pRequest
[in] Pointer the caller is passing to IMalloc::DidAlloc.
fSpyed
[in] TRUE if the allocation was done while this spy was active.
Return Value
The pointer for which allocation status is determined. This pointer is passed to
PostDidAlloc as the fActual parameter.
Remarks
When a spy object implementing IMallocSpy is registered with CoRegisterMallocSpy
, COM calls this method immediately before any call to IMalloc::DidAlloc. This m
ethod is included for completeness and consistency it is not anticipated that de
velopers will implement significant functionality in this method.
See Also
IMalloc::DidAlloc, IMallocSpy::PostDidAlloc, CoRegisterMallocSpy, CoRevokeMalloc
Spy
IMallocSpy::PostDidAlloc
Called just after invoking IMalloc::DidAlloc.
int PostDidAlloc(
void * pRequest, //Original pointer passed to IMalloc::DidAlloc
BOOL fSpyed, //Whether the allocation was done while this spy
//was active
int fActual //Whether pRequest was actual value used in
//IMalloc call
);
Parameters
pRequest
[in] Pointer specified in the original call to IMalloc::DidAlloc.
fSpyed
[in] TRUE if the allocation was done while this spy was active.
fActual
[in] Actual value returned by IMalloc::DidAlloc.
Return Value
The value returned to the caller of IMalloc::DidAlloc.
Remarks
When a spy object implementing IMallocSpy is registered with CoRegisterMallocSpy
, COM calls this method immediately after any call to IMalloc::DidAlloc. This me
thod is included for completeness and consistency it is not anticipated that dev
elopers will implement significant functionality in this method.
For convenience, pRequest, the original pointer passed in the call to IMalloc::D
idAlloc, is passed to PostDidAlloc. In addition, the parameter fActual is a bool
ean that indicates whether this value was actually passed to IMalloc::DidAlloc.
If not, it would indicate that IMallocSpy::PreDidAlloc was implemented to alter
this pointer for some debugging purpose.
The fSpyed parameter is a boolean that indicates whether the allocation was done
while the current spy object was active.
See Also
IMalloc::DidAlloc, IMallocSpy::PreDidAlloc, CoRegisterMallocSpy, CoRevokeMallocS
py
IMallocSpy::PreFree
Called just before invoking IMalloc::Free to ensure that the pointer passed to I
Malloc::Free points to the beginning of the actual allocation.
void * PreFree(
void * pRequest, //Pointer is passing to IMalloc::Free
BOOL fSpyed //TRUE if this memory was allocated while the
//spy was active
);
Parameters
pRequest
[in] Pointer to the block of memory that the caller is passing to IMalloc::Free.
fSpyed
[in] TRUE if the pRequest parameter of IMallocSpy::PreFree was allocated while t
he spy was installed. This value is also passed to IMallocSpy::PostFree.
Return Value
The actual pointer to pass to IMalloc::Free.
Remarks
If IMallocSpy::PreAlloc modified the original allocation request passed to IMall
oc::Alloc (or IMalloc::Realloc), IMallocSpy::PreFree must supply a pointer to th
e actual allocation, which COM will pass to IMalloc::Free. For example, if the P
reAlloc/PostAlloc pair attached a header used to store debug information to the
beginning of the caller's allocation, PreFree must return a pointer to the begin
ning of this header, so all of the block that was allocated can be freed.
See Also
IMalloc::Free, IMallocSpy::PostFree, CoRegisterMallocSpy, CoRevokeMallocSpy
IMallocSpy::PostFree
Called just after invoking IMalloc::Free.
void PostFree(
BOOL fSpyed //Whether the memory block to be freed was allocated
//while the spy is active
);
Parameter
fSpyed
[in] TRUE if the memory block to be freed was allocated while the current spy wa
s active, otherwise FALSE.
Remarks
When a spy object implementing IMallocSpy is registered with CoRegisterMallocSpy
, COM calls this method immediately after any call to IMalloc::Free. This method
is included for completeness and consistency it is not anticipated that develop
ers will implement significant functionality in this method. On return, the fSpy
ed parameter simply indicates whether the memory was freed while the current spy
was active.
See Also
IMalloc::Free, IMallocSpy::PreFree, CoRegisterMallocSpy, CoRevokeMallocSpy
IMallocSpy::PreGetSize
Called by COM just prior to any call to IMalloc::GetSize.
void * PreGetSize(
void * pRequest,
//Pointer the caller is passing to IMalloc::GetSize
BOOL fSpyed //TRUE if allocation was done while this spy was
//active
);
Parameters
pRequest
[in] Pointer the caller is passing to IMalloc::GetSize.
fSpyed
[in] TRUE if the allocation was done while the spy was active.
Return Value
Pointer to the actual allocation for which the size is to be determined.
Remarks
The PreGetSize method receives as its pRequest parameter the pointer the caller
is passing to IMalloc::GetSize. It must then return a pointer to the actual allo
cation, which may have altered pRequest in the implementation of either the PreA
lloc or PreRealloc methods of IMallocSpy. The pointer to the true allocation is
then passed to IMalloc::GetSize as its pv parameter.
IMalloc::GetSize then returns the size determined, and COM passes this value to
IMallocSpy::PostGetSize in cbActual.
Note
The size determined by IMalloc::GetSize is the value returned by the Win32 funct
ion HeapSize. On Windows NT, this is the size originally requested. On Windows 9
5, memory allocations are done on eight-byte boundaries. For example, a memory a
llocation request of 27 bytes on Windows NT would return an allocation of 32 byt
es and GetSize would return 27. On Windows 95, the same request would return an
allocation of 28 bytes and GetSize would return 28. Implementers of IMallocSpy::
PostGetSize cannot assume, for example, that if cbActual is sizeof(debug_header)
, that the value is the actual size of the user's allocation.
See Also
IMalloc::GetSize, IMallocSpy::PostGetSize, CoRegisterMallocSpy, CoRevokeMallocSp
y
IMallocSpy::PostGetSize
Called just after invoking IMalloc::GetSize.
ULONG PostGetSize(
ULONG cbActual, //Actual size of the allocation
BOOL fSpyed //Whether the allocation was done while a spy was
//active
);
Parameters
cbActual
[in] Actual number of bytes in the allocation, as returned by IMalloc::GetSize.
fSpyed
[in] TRUE if the allocation was done while a spy was active.
Return Values
The same value returned by IMalloc::GetSize, which is the size of the allocated
memory block in bytes.
Remarks
The size determined by IMalloc::GetSize is the value returned by the Win32 funct
ion HeapSize. On Windows NT, this is the size originally requested. On Windows 9
5, memory allocations are done on eight-byte boundaries. For example, a memory a
llocation request of 27 bytes on Windows NT would return an allocation of 32 byt
es and GetSize would return 27. On Windows 95, the same request would return an
allocation of 28 bytes and GetSize would return 28. Implementers of IMallocSpy::
PostGetSize cannot assume, for example, that if cbActual is sizeof(debug_header)
, that the value is the actual size of the user's allocation.
See Also
IMalloc::GetSize, IMallocSpy::PreGetSize, CoRegisterMallocSpy, CoRevokeMallocSpy
IMallocSpy::PreHeapMinimize
Called just prior to invoking IMalloc::HeapMinimize.
void PreHeapMinimize(void);
Remarks
This method is included for completeness; it is not anticipated that developers
will implement significant functionality in this method.
See Also
IMalloc::HeapMinimize, IMallocSpy::PostHeapMinimize, CoRegisterMallocSpy, CoRevo
keMallocSpy
IMallocSpy::PostHeapMinimize
Called just after invoking IMalloc::HeapMinimize.
void PostHeapMinimize(void);
Remarks
When a spy object implementing IMallocSpy is registered with CoRegisterMallocSpy
, COM calls this method immediately after any call to IMalloc::Free. This method
is included for completeness and consistency it is not anticipated that develop
ers will implement significant functionality in this method.
See Also
IMalloc::HeapMinimize, IMallocSpy::PreHeapMinimize, CoRegisterMallocSpy, CoRevok
eMallocSpy
IMallocSpy::PreRealloc
Called just before invoking IMalloc::Alloc.
ULONG PreRealloc(
void * pRequest, //Pointer the caller is passing to
//IMalloc::Realloc
ULONG cbRequest, //Byte count the caller is passing to
//IMalloc::Realloc
void ** ppNewRequest,
//Address of output variable that receives a
//pointer to the requested memory block to be
//reallocated
BOOL fSpyed //Whether the original allocation was "spyed"
);
Parameters
pRequest
[in] Pointer specified in the original call to IMalloc::Realloc, indicating the
the memory block to be reallocated.
cbRequest
[in] Memory block's byte count as specified in the original call to IMalloc::Rea
lloc.
ppNewRequest
[out] Address of pointer variable that receives a pointer to the actual memory b
lock to be reallocated. This may be different from the pointer in pRequest if th
e implementation of IMallocSpy::PreRealloc extends or modifies the reallocation.
This is an out pointer and should always be stored by PreRealloc.
fSpyed
[in] TRUE if the original allocation was done while the spy was active.
Return Value
The actual byte count to be passed to IMalloc::Realloc.
Remarks
The IMallocSpy::PreRealloc implementation may extend and/or modify the allocatio
n to store debug-specific information with the allocation. Thus, the ppNewReques
t parameter may differ from pRequest, a pointer to the request specified in the
original call to IMalloc::Realloc.
PreRealloc can force memory allocation failure by returning 0, allowing testing
to ensure that the application handles allocation failure gracefully in all case
s. In this case, PostRealloc is not called and Realloc returns NULL. However, if
IMalloc::Realloc encounters a real memory failure and returns NULL, PostRealloc
is called. Forcing allocation failure is effective only if cbRequest is not equ
al to 0.
See Also
IMalloc::Realloc, IMallocSpy::PostRealloc, CoRegisterMallocSpy, CoRevokeMallocSp
y
IMallocSpy::PostRealloc
Called after invoking IMalloc::Realloc.
void * PostRealloc(
void * pActual, //Pointer returned by IMalloc::Realloc
BOOL fSpyed //Whether the original allocation was "spyed"
);
Parameters
pActual
[in] Pointer to the memory block reallocated by IMalloc::Realloc.
fSpyed
[in] If TRUE, the original memory allocation was done while the spy was active.
Return Values
A pointer to the beginning of the memory block actually allocated. This pointer
is also returned to the caller of IMalloc::Realloc. If debug information is writ
ten at the front of the caller's allocation, it should be a forward offset from
pActual. The value should be the same as pActual if debug information is appende
d or if no debug information is attached.
See Also
IMalloc::Realloc, IMallocSpy::PreRealloc, CoRegisterMallocSpy, CoRevokeMallocSpy
5.4.3 IOleContainer
The IOleContainer interface is used to enumerate objects in a compound document
or lock a container in the running state. Container and object applications both
implement this interface.
When to Implement
Applications that support links and links to embedded objects implement this int
erface to provide object enumeration, name parsing, and silent updates of link s
ources. Simple, nonlinking containers do not need to implement IOleContainer if
it is useful mainly to support links to embedded objects.
When to Use
Call IOleContainer to enumerate the objects in a compound document or to lock a
container so that silent updates of link sources can be carried out safely.
Many applications inherit the functions of IOleContainer by implementing IOleIte
mContainer, which is used to bind item monikers.
Methods in VTable Order
IUnknown Methods Description
QueryInterface Returns pointers to supported interfaces.
AddRef Increments reference count.
Release Decrements reference count.
IParseDisplayName Method Description
ParseDisplayName Parses object's display name to form moniker.
IOleContainer Methods Description
EnumObjects Enumerates objects in a container.
LockContainer Keeps container running until explicitly released.
See Also
IOleItemContainer, IParseDisplayName
IOleContainer::EnumObjects
Enumerates objects in the current container.
HRESULT EnumObjects(
DWORD grfFlags, //Value specifying what is to be enumerated
IEnumUnknown **ppenum
//Address of output variable that receives the
// IEnumUnknown interface pointer
);
Parameters
grfFlags
[in] Value that specifies which objects in a container are to be enumerated, as
defined in the enumeration OLECONTF.
ppenum
[out] Address of IEnumUnknown* pointer variable that receives the interface poin
ter to the enumerator object. Each time a container receives a successful call t
o EnumObjects, it must increase the reference count on the *ppenum pointer the m
ethod returns. It is the caller's responsibility to call IUnknown::Release when
it is done with the pointer. If an error is returned, the implementation must se
t *ppenum to NULL.
Return Values
This method supports the standard return value E_FAIL, as well as the following:
S_OK
Enumerator successfully returned.
E_NOTIMPL
Object enumeration not supported.
Remarks
A container should implement EnumObjects to enable programmatic clients to find
out what objects it holds. This method, however, is not called in standard linki
ng scenarios.
See Also
IEnumUnknown, IOleItemContainer, OLECONTF
IOleContainer::LockContainer
Keeps an embedded object's container running.
HRESULT LockContainer(
BOOL fLock //Value indicating lock or unlock
);
Parameter
fLock
[in] Value that specifies whether to lock (TRUE) or unlock (FALSE) a container.
Return Values
This method supports the standard return values E_FAIL and E_OUTOFMEMORY, as wel
l as the following:
S_OK
Container was locked successfully.
Remarks
An embedded object calls IOleContainer::LockContainer to keep its container runn
ing when the object has link clients that require an update. If an end user sele
cts File Close from the container's menu, however, the container ignores all out
standing LockContainer locks and closes the document anyway.
Notes to Callers
When an embedded object changes from the loaded to the running state, it should
call IOleContainer::LockContainer with the fLock parameter set to TRUE. When the
embedded object shuts down (transitions from running to loaded), it should call
IOleContainer::LockContainer with the fLock parameter set to FALSE.
Each call to LockContainer with fLock set to TRUE must be balanced by a call to
LockContainer with fLock set to FALSE. Object applications typically need not ca
ll LockContainer; the default handler makes these calls automatically for object
applications implemented as .EXEs as the object makes the transition to and fro
m the running state. Object applications not using the default handler, such as
DLL object applications, must make the calls directly.
An object should have no strong locks on it when it registers in the Running Obj
ect Table, but it should be locked as soon as the first external client connects
to it. Therefore, following registration of the object in the Running Object Ta
ble, object handlers and DLL object applications, as part of their implementatio
n of IRunnableObject::Run, should call IOleContainer::LockContainer(TRUE) to loc
k the object.
Notes to Implementers
The container must keep track of whether and how many calls to LockContainer(TRU
E) have been made. To increment or decrement the reference count, IOleContainer:
:LockContainer calls CoLockObjectExternal with a flag set to match fLock.
See Also
CoLockObjectExternal, IRunnableObject::Run
5.4.4 IPersistMoniker
Objects, especially asynchronous-aware objects, can expose the IPersistMoniker i
nterface to obtain more control over the way they bind to their persistent data.
Existing moniker implementations call QueryInterface on the client objectfor per
sistence interfaces such as IPersistFile, IPersistStream[Init], or IPersistStora
ge as part of their IMoniker::BindToObject implementation when they are instanti
ating and initializing the object. The IPersistMoniker interface allows moniker
implementations and other applications that instantiate objects from persistent
data to give control to the object being instantiated over binding to its persis
tent data. An object could, for example, implement IPersistMoniker::Load by call
ing IMoniker::BindToStorage for the interface it prefers: IStorage, IStream, asy
nchronous binding, etc.
Unlike some other persistent object interfaces, IPersistMoniker does not include
an InitNew method. This means that IPersistMoniker cannot be used to initialize
an object to a freshly initialized state. Clients of IPersistMoniker who wish t
o initialize the object should QueryInterface for a different persistence interf
ace that contains an InitNew method, such as IPersistStreamInit, IPersistMemory,
or IPersistPropertyBag. Then, the client can use the InitNew method found in th
e other persistence interface to initialize the object. The client can still saf
ely used IPersistMoniker to save the persistent state of the object.
The IPersistMoniker contract inherits its definition from the IPersist interface
, and includes the GetClassID method of IPersist.
When to Implement
Implement IPersistMoniker on any object that can be saved persistently to multip
le storage mediums or can take advantage of any of the asynchronous stream, stor
age, or IMoniker::BindToStorage behavior described above.
When to Use
Custom moniker implementations should support IPersistMoniker as the most flexib
le persistence interface in their implementation of IMoniker::BindToObject if th
ey are instantiating an arbitrary class and need to initialize it from persisten
t data. Typically, these monikers should use the published persistence interface
s in the following order: IPersistMoniker, IPersistStream[Init], IPersistStorage
, IPersistFile, and IPersistMemory.
Methods in Vtable Order
IUnknown Methods Description
QueryInterface Returns pointers to supported interfaces.
AddRef Increments the reference count.
Release Decrements the reference count.
IPersist Method Description
GetClassID Returns the class identifier (CLSID) for the object.
IPersistMoniker Methods Description
IsDirty Checks an object for changes since it was last saved.
Load Loads an object using a specified moniker.
Save Saves the object, specifying a destination moniker.
SaveCompleted Notifies the object that the save operation is complete.
GetCurMoniker Gets the current moniker for the object.
IPersistMoniker::GetCurMoniker
Retrieves the moniker that refers to the object's persistent state.
HRESULT GetCurMoniker(
IMoniker **ppmkCur //Address of output variable that receives the
//IMoniker interface pointer
);
Parameter
ppmkCur
[out] Address of IMoniker* pointer variable that receives the interface pointer
to the object's current persistent state.
Return Values
S_OK
A valid absolute path was successfully returned.
E_INVALIDARG
The ppmkCur parameter is invalid.
Remarks
Typically, this method returns the moniker last passed to the object by means of
IPersistMoniker::Load, IPersistMoniker::Save, or IPersistMoniker::SaveCompleted
.
See Also
IPersistMoniker::Load, IPersistMoniker::Save, IPersistMoniker::SaveCompleted
IPersistMoniker::IsDirty
Checks an object for changes since it was last saved.
HRESULT IsDirty(void);
Return Values
S_OK
The object has changed since it was last saved.
S_FALSE
The object has not changed since the last save.
Remarks
IPersistMoniker::IsDirty checks whether an object has changed since it was last
saved so you can avoid losing information in objects that have not yet been save
d.
See Also
IPersistMoniker::Save
IPersistMoniker::Load
Loads the object from its persistent state indicated by a supplied moniker.
HRESULT Load(
BOOL fFullyAvailable,
//Indicates whether the object was already loaded
IMoniker *pmkSrc,
//Pointer to source moniker that references the
//persistent state to be loaded
IBindCtx *pbc, //Pointer to the moniker's bind context
DWORD grfMode //Access mode values taken from the STGM
//enumeration
);
Parameters
fFullyAvailable
[in] If TRUE, then the data referred to by the moniker has already been loaded o
nce, and subsequent binding to the moniker should be synchronous. If FALSE, then
an asynchronous bind operation should be launched.
pmkSrc
[in] Pointer to a moniker that references the persistent state for the object to
be loaded.
pbc
[in] Pointer to the IBindCtx interface for the bind context to be used for any m
oniker binding during this method.
grfMode
[in] A combination of values from the STGM enumeration which indicate the access
mode to use when binding to the persistent state. The IPersistMoniker::Load met
hod can treat this value as a suggestion, adding more restrictive permissions if
necessary. If grfMode is zero, the implementation should bind to the persistent
state using default permissions.
Return Values
S_OK
The object was successfully loaded.
E_INVALIDARG
One or more parameters are invalid.
Remarks
Typically, the object will immediately bind to its persistent state through a ca
ll to the source moniker's IMoniker::BindToStorage method, requesting either the
IStream or IStorage interface.
See Also
IPersistMoniker::Save, IPersistMoniker::SaveCompleted
IPersistMoniker::Save
Requests that the object save itself to the location referred to by pmkDst.
HRESULT Save(
IMoniker *pmkDst, //Pointer to destination moniker
IBindCtx *pbc, //Pointer to the moniker's bind context
BOOL fRemember //Specifies whether the destination moniker is
//to be the current working one
);
Parameters
pmkDst
[in] Pointer to the moniker referencing the location where the object should per
sistently store itself. The object typically binds to the location through a cal
l to pmkDst->BindToStorage, requesting either the IStream or IStorage interface.
This parameter can be NULL, in which case the object should save itself to the
same location referred to by the moniker passed to it in IPersistMoniker::Load.
Using the NULL value, can act as an optimization to prevent the object from bind
ing, since it has typically already bound to the moniker when it was loaded.
pbc
[in] Pointer to IBindCtx for the bind context to be used for any moniker binding
during this method.
fRemember
[in] Indicates whether pmkDst is to be used as the reference to the current pers
istent state after the save. If TRUE, pmkDst becomes the reference to the curren
t persistent state and the object should clear its dirty flag after the save. If
FALSE, this save operation is a "Save A Copy As ..." operation. In this case, t
he reference to the current persistent state is unchanged, and the object should
not clear its dirty flag. If pmkDst is NULL, the implementation should ignore t
he fRemember flag.
Return Values
S_OK
The object was successfully saved.
E_INVALIDARG
One or more parameters are invalid.
See Also
IPersistMoniker::GetCurMoniker, IPersistMoniker::Load, IPersistMoniker::SaveComp
leted
IPersistMoniker::SaveCompleted
Notifies the object that it has been completely saved and points it to its new p
ersisted state.
HRESULT SaveCompleted(
IMoniker *pmkNew, //Pointer to moniker for the object's new
//persistent state
IBindCtx *pbc //Bind context for binding during this method
);
Parameter
pmkNew
[in] Pointer to the moniker for the object's new persistent state. This paramete
r can be NULL if the moniker to the object's new persistent state is the same as
the previous moniker to the object's persistent state. This optimization is all
owed only if there was a prior call to IPersistMoniker::Save with the fRemember
parameter set to TRUE, in which case the object need not rebind to pmkNew.
pbc
[in] Pointer to the bind context to use for any moniker binding during this meth
od.
Return Value
S_OK
The operation was successful.
E_INVALIDARG
One or more parameters are invalid.
Remarks
Typically, the object will immediately bind to its persistent state through a ca
ll to pmkNew->BindToStorage method, requesting either the IStream or IStorage in
terface, as in IPersistMoniker::Load.
See Also
IPersistMoniker::Load, IPersistMoniker::Save
5.4.5 IRunnableObject
The IRunnableObject interface enables a container to control the running of its
embedded objects. In the case of an object implemented with a local server, call
ing IRunnableObject::Run launches the server's .EXE file. In the case of an obje
ct implemented with an in-process server, calling the Run method causes the obje
ct .DLL file to transition into the running state.
When to Implement
Object handlers should implement IRunnableObject to provide their containers wit
h a way to run them and manage their running state. DLL object applications shou
ld implement IRunnableObject to support silent updates of their objects.
When to Use
Containers call IRunnableObject to determine if an embedded object is running, t
o force an object to run, to lock an object into the running state, or to inform
an object handler whether its object is being run as either a simple embedding
or as a link source.
Methods VTable Order
IUnknown Methods Description
QueryInterface Returns pointers to supported interfaces.
AddRef Increments reference count.
Release Decrements reference count.
IRunnableObject::GetRunningClass
Returns the CLSID of a running object.
HRESULT GetRunningClass(
LPCLSID lpClsid //Pointer to an object's CLSID
);
Parameter
lpClsid
[out] Pointer to the object's class identifier.
Return Values
This method supports the standard return values E_INVALIDARG and E_UNEXPECTED, a
s well as the following:
S_OK
CLSID was returned successfully.
Remarks
If an embedded document was created by an application that is not available on t
he user's computer, the document, by a call to CoTreatAsClass, may be able to di
splay itself for editing by emulating a class that is supported on the user's ma
chine. In this case, the CLSID returned by a call to IRunnableObject::GetRunning
Class will be that of the class being emulated, rather than the document's nativ
e class.
See Also
CoTreatAsClass
IRunnableObject::IsRunning
Determines whether an object is currently in the running state.
BOOL IsRunning();
Return Values
TRUE
The object is in the running state.
FALSE
The object is not in the running state.
Remarks
A container application could call IRunnableObject::IsRunning when it needs to k
now if the server is immediately available.
An object handler could call IRunnableObject::IsRunning when it wants to avoid c
onflicts with a running server or when the running server might have more up-to-
date information
OleIsRunning is a helper function that conveniently repackages the functionality
offered by IRunnableObject::IsRunning. With the release of OLE 2.01, the implem
entation of OleIsRunning was changed so that it calls QueryInterface, asks for I
RunnableObject, and then calls IRunnableObject::IsRunning. In other words, you c
an use the interface and the helper function interchangeably.
See Also
OleIsRunning
IRunnableObject::LockRunning
Locks an already running object into its running state or unlocks it from its ru
nning state.
HRESULT LockRunning(
BOOL fLock, //Flag indicating whether object is locked
BOOL fLastUnlockCloses
//Flag indicating whether to close object
);
Parameters
fLock
[in] TRUE locks the object into its running state. FALSE unlocks the object from
its running state.
fLastUnlockCloses
[in] TRUE specifies that if the connection being released is the last external l
ock on the object, the object should close. FALSE specifies that the object shou
ld remain open until closed by the user or another process.
Return Values
This method supports the standard return values E_FAIL, E_INVALIDARG, E_OUTOFMEM
ORY and E_UNEXPECTED, as well as the following:
S_OK
If the value of fLock is TRUE, the object was successfully locked; if the value
of fLock is FALSE, the object was successfully unlocked.
Remarks
Most implementations of IRunnableObject::LockRunning call CoLockObjectExternal.
OleLockRunning is a helper function that conveniently repackages the functionali
ty offered by IRunnableObject::LockRunning. With the release of OLE 2.01, the im
plementation of OleLockRunning was changed to call QueryInterface, ask for IRunn
ableObject, and then call IRunnableObject::LockRunning. In other words, you can
use the interface and the helper function interchangeably.
See Also
CoLockObjectExternal
IRunnableObject::Run
Runs an object.
HRESULT Run(
LPBC lpbc //Pointer to binding context
);
Parameter
lpbc
[in] Pointer to the binding context of the run operation. May be NULL.
Return Values
This method supports the standard return values E_OUTOFMEMORY and E_UNEXPECTED,
as well as the following:
S_OK
The object was successfully placed in the running state.
Remarks
Containers call IRunnableObject::Run to force their objects to enter the running
state. If the object is not already running, calling IRunnableObject::Run can b
e an expensive operation, on the order of many seconds. If the object is already
running, then this method has no effect on the object.
Notes to Callers
When called on a linked object that has been converted to a new class since the
link was last activated, IRunnableObject::Run may return OLE_E_CLASSDIFF.
OleRun is a helper function that conveniently repackages the functionality offer
ed by IRunnableObject::Run. With the release of OLE 2.01, the implementation of
OleRun was changed so that it calls QueryInterface, asks for IRunnableObject, an
d then calls IRunnableObject::Run. In other words, you can use the interface and
the helper function interchangeably.
Notes to Implementers
The object should register in the running object table if it has a moniker assig
ned. The object should not hold any strong locks on itself; instead, it should r
emain in the unstable, unlocked state. The object should be locked when the firs
t external connection is made to the object.
An embedded object must hold a lock on its embedding container while it is in th
e running state. The Default handler provided by OLE 2 takes care of locking the
embedding container on behalf of objects implemented by an EXE object applicati
on.
See Also
OleRun
IRunnableObject::SetContainedObject
Notifies an object that it is embedded in an OLE container, which ensures that r
eference counting is done correctly for containers that support links to embedde
d objects.
HRESULT SetContainedObject(
BOOL fContained //Flag indicating whether object is embedded
);
Parameter
fContained
[in] TRUE specifies that the object is contained in an OLE container. FALSE indi
cates that it is not.
Return Values
This method supports the standard return values E_INVALIDARG, E_OUTOFMEMORY AND
E_UNEXPECTED, as well as the following:
S_OK
Object has been marked as a contained embedding.
Remarks
The IRunnableObject::SetContainedObject method enables a container to inform an
object handler that it is embedded in the container, rather than acting as a lin
k. This call changes the container's reference on the object from strong, the de
fault for external connections, to weak. When the object is running visibly, thi
s method is of little significance because the end user has a lock on the object
. During a silent update of an embedded link source, however, the container shou
ld not be able to hold an object in the running state after the link has been br
oken. For this reason, the container's reference to the object must be weak.
Notes to Callers
A container application must call IRunnableObject::SetContainedObject if it supp
orts linking to embedded objects. It normally makes the call immediately after c
alling OleLoad or OleCreate and never calls the method again, even before it clo
ses. Moreover, a container almost always calls this method with fContained set t
o TRUE. The use of this method with fContained set to FALSE is rare.
Calling IRunnableObject::SetContainedObject is optional only when you know that
the embedded object will not be referenced by any client other than the containe
r. If your container application does not support linking to embedded objects; i
t is preferable, but not necessary, to call IRunnableObject::SetContainedObject.
OleSetContainedObject is a helper function that conveniently repackages the func
tionality offered by IRunnableObject::SetContainedObject. With the release of OL
E 2.01, the implementation of OleSetContainedObject was changed to call QueryInt
erface, ask for IRunnableObject, and then call IRunnableObject::SetContainedObje
ct. In other words, you can use the interface and the helper function interchang
eably.
See Also
OleSetContainedObject, OleNoteObjectVisible, CoLockObjectExternal
5.5.11 CLSIDFromString
Converts a string generated by the StringFromCLSID function back into the origin
al CLSID.
HRESULT CLSIDFromString(
LPOLESTR lpsz, //Pointer to the string representation of the CLSID
LPCLSID pclsid //Pointer to the CLSID
);
Parameters
lpsz
[in] Pointer to the string representation of the CLSID.
pclsid
[out] Pointer to the CLSID on return.
Return Values
This function supports the standard return value E_INVALIDARG, as well as the fo
llowing:
NOERROR
The CLSID was obtained successfully.
CO_E_CLASSTRING
The class string was improperly formatted.
REGDB_E_WRITEREGDB
The CLSID corresponding to the class string was not found in the registry.
Remarks
Because of the restrictions placed on OLE 1 CLSID values, CLSIDFromProgID and CL
SIDFromString are the only two functions that can be used to generate a CLSID fo
r an OLE 1 object.
See Also
CLSIDFromProgID, StringFromCLSID
5.5.12 CoCreateGuid
Creates a GUID, a unique 128-bit integer used for CLSIDs and interface identifie
rs.
HRESULT CoCreateGuid(
GUID *pguid //Pointer to the GUID on return
);
Parameter
pguid
[out] Pointer to the requested GUID on return.
Return Value
S_OK
The GUID was successfully created.
Win32 errors are returned by UuidCreate but wrapped as an HRESULT.
Remarks
The CoCreateGuid function calls the RPC function UuidCreate, which creates a GUI
D, a globally unique 128-bit integer. Use the CoCreateGuid function when you nee
d an absolutely unique number that you will use as a persistent identifier in a
distributed environment.To a very high degree of certainty, this function return
s a unique value no other invocation, on the same or any other system (networked
or not), should return the same value.
See Also
UuidCreate (documented in the RPC Programmer s Guide and Reference)
5.5.13 CoDosDateTimeToFileTime
Converts the MS-DOS representation of the time and date to a FILETIME structure,
which Win32 uses to determine the date and time.
BOOL CoDosDateTimeToFileTime(
WORD nDosDate, //16-bit MS-DOS date
WORD nDosTime, //16-bit MS-DOS time
FILETIME * lpFileTime //Pointer to the structure
);
Parameters
nDosDate
[in] 16-bit MS-DOS date.
nDosTime
[in] 16-bit MS-DOS time.
lpFileTime
[out] Pointer to the FILETIME structure.
Return Values
TRUE
The FILETIME structure was created successfully.
FALSE
The FILETIME structure was not created successfully, probably because of invalid
arguments.
Remarks
The FILETIME structure and the CoDosDateTimeToFileTime and CoFileTimeToDosDateTi
me functions are part of the Win32 API definition. They are provided for compati
bility in all COM implementations, but are redundant on Win32 platforms.
MS-DOS records file dates and times as packed 16-bit values. An MS-DOS date has
the following format:
Bits Contents
0-4 Days of the month (1-31).
5-8 Months (1 = January, 2 = February, and so forth).
9-15 Year offset from 1980 (add 1980 to get actual year).
An MS-DOS time has the following format:
Bits Contents
0-4 Seconds divided by 2.
5-10 Minutes (0-59).
11-15 Hours (0-23 on a 24-hour clock).
See Also
CoFileTimeToDosDateTime, CoFileTimeNow
5.5.14 CoFileTimeNow
Returns the current time as a FILETIME structure.
HRESULT CoFileTimeNow(
FILETIME * lpFileTime //Pointer to return the structure
);
Parameter
lpFileTime
[out] Pointer to return the FILETIME structure.
Return Values
S_OK
The current time was converted to a FILETIME structure.
See Also
CoDosDateTimeToFileTime, CoFileTimeToDosDateTime
5.5.15 CoFileTimeToDosDateTime
Converts a FILETIME into MS-DOS date and time values.
BOOL CoFileTimeToDosDateTime(
FILETIME * lpFileTime, //Pointer to the structure to be converted
LPWORD lpDosDate, //Pointer to the 16-bit MS-DOS date
LPWORD lpDosTime //Pointer to the 16-bit MS-DOS time
);
Parameters
lpFileTime
[in] Pointer to the FILETIME structure to be converted.
lpDosDate
[out] Pointer to the 16-bit MS-DOS date.
lpDosTime
[out] Pointer to the 16-bit MS-DOS time.
Return Values
TRUE
The FILETIME structure was converted successfully.
FALSE
The FILETIME structure was not converted successfully.
Remarks
This is the inverse of the operation provided by the CoDosDateTimeToFileTime fun
ction.
See Also
CoDosDateTimeToFileTime, CoFileTimeNow
5.5.16 CoGetCurrentProcess
Returns a value that is unique to the current thread. It can be used to avoid PR
OCESSID reuse problems.
DWORD CoGetCurrentProcess( );
Return Value
DWORD value
Unique value for the current thread that can be used to avoid PROCESSID reuse pr
oblems.
Remarks
The CoGetCurrentProcess function returns a value that is effectively unique, bec
ause it is not used again until 232 more threads have been created on the curren
t workstation or until the workstation is rebooted.
Using the value returned from a call to CoGetCurrentProcess can help you maintai
n tables that are keyed by threads or in uniquely identifying a thread to other
threads or processes.
Using the value returned by CoGetCurrentProcess is more robust than using the HT
ASK task handle value returned by the Win32 function GetCurrentTask, because Win
dows task handles can be reused relatively quickly when a window s task dies.
5.5.17 IIDFromString
Converts a string generated by the StringFromIID function back into the original
interface identifier (IID).
WINOLEAPI IIDFromString(
LPOLESTR lpsz, //Pointer to the string representation of the IID
LPIID lpiid //Pointer to the requested IID on return
);
Parameters
lpsz
[in] Pointer to the string representation of the IID.
lpiid
[out] Pointer to the requested IID on return.
Return Values
This function supports the standard return values E_INVALIDARG and E_OUTOFMEMORY
, as well as the following:
S_OK
The string was successfully converted.
Remarks
The function converts the interface identifier in a way that guarantees differen
t interface identifiers will always be converted to different strings.
See Also
StringFromIID
5.5.18 IsEqualGUID
Determines whether two GUIDs are equal.
BOOL IsEqualGUID(
REFGUID rguid1, //GUID to compare to rguid2
REFGUID rguid2 //GUID to compare to rguid1
);
Parameters
rguid1
[in] GUID to compare to rguid2.
rguid2
[in] GUID to compare to rguid1.
Return Values
TRUE
The GUIDs are equal.
FALSE
The GUIDs are not equal.
Remarks
IsEqualGUID is used by the IsEqualCLSID and IsEqualIID functions.
See Also
IsEqualCLSID, IsEqualIID
5.5.19 IsEqualCLSID
Determines whether two CLSIDs are equal.
BOOL IsEqualCLSID(
REFCLSID rclsid1, //CLSID to compare to rclsid2
REFCLSID rclsid2 //CLSID to compare to rclsid1
);
Parameters
rclsid1
[in] CLSID to compare to rclsid2.
rclsid2
[in] CLSID to compare to rclsid1.
Return Values
TRUE
The CLSIDs are equal.
FALSE
The CLSIDs are not equal.
See Also
IsEqualGUID, IsEqualIID
5.5.20 IsEqualIID
Determines whether two interface identifiers are equal.
BOOL IsEqualIID(
REFGUID riid1, //Interface identifier to compare to riid2
REFGUID riid2 //Interface identifier to compare to riid1
);
Parameters
riid1
[in] Interface identifier to compare with riid2.
riid2
[in] Interface identifier to compare with riid1.
Return Values
TRUE
The interface identifiers are equal.
FALSE
The interface identifiers are not equal.
See Also
IsEqualGUID, IsEqualCLSID
5.5.21 GetRunningObjectTable
Supplies a pointer to the IRunningObjectTable interface on the local Running Obj
ect Table (ROT).
WINOLEAPI GetRunningObjectTable(
DWORD reserved, //Reserved
LPRUNNINGOBJECTTABLE *pprot //Address of output variable that receives the
// IRunningObjectTable interface pointer
);
Parameters
reserved
[in] Reserved for future use; must be zero.
pprot
[out] Address of IRunningObjectTable* pointer variable that receives the interfa
ce pointer to the local ROT. When the function is successful, the caller is resp
onsible for calling IUnknown::Release on the interface pointer. If an error occu
rs, pprot is undefined.
Return Values
This function supports the standard return value E_UNEXPECTED, as well as the fo
llowing:
S_OK
An IRunningObjectTable pointer was successfully returned.
Remarks
Each workstation has a local ROT that maintains a table of the objects that have
been registered as running on that machine. This function returns an IRunningOb
jectTable interface pointer, which provides access to that table.
Moniker providers, which hand out monikers that identify objects so they are acc
essible to others, should call GetRunningObjectTable. Use the interface pointer
returned by this function to register your objects when they begin running, to r
ecord the times that those objects are modified, and to revoke their registratio
ns when they stop running. See the IRunningObjectTable interface for more inform
ation.
Compound-document link sources are the most common example of moniker providers.
These include server applications that support linking to their documents (or p
ortions of a document) and container applications that support linking to embedd
ings within their documents. Server applications that do not support linking can
also use the ROT to cooperate with container applications that support linking
to embeddings.
If you are implementing the IMoniker interface to write a new moniker class, and
you need an interface pointer to the ROT, call IBindCtx::GetRunningObjectTable
rather than the GetRunningObjectTable function. This allows future implementatio
ns of the IBindCtx interface to modify binding behavior.
See Also
IBindCtx::GetRunningObjectTable, IMoniker, IRunningObjectTable
5.5.22 ProgIDFromCLSID
Retrieves the ProgID for a given CLSID.
WINOLEAPI ProgIDFromCLSID(
REFCLSID clsid, //CLSID for which the ProgID is requested
LPOLESTR * lplpszProgID //Address of output variable that receives a
5.5.23 StringFromCLSID
Converts a CLSID into a string of printable characters. Different CLSIDs always
convert to different strings.
WINOLEAPI StringFromCLSID(
REFCLSID rclsid, //CLSID to be converted
LPOLESTR * ppsz //Address of output variable that receives a
// pointer to the resulting string
);
Parameters
rclsid
[in] CLSID to be converted.
ppsz
[out] Address of LPOLESTR pointer variable that receives a pointer to the result
ing string.
Return Values
This function supports the standard return value E_OUTOFMEMORY; as well as the f
ollowing:
S_OK
Indicates the CLSID was successfully converted and returned.
Remarks
The StringFromCLSID function calls the StringFromGuid2 function to convert a glo
bally unique identifier (GUID) into a string of printable characters.
See Also
CLSIDFromString, StringFromGuid2
5.5.24 StringFromGUID2
Converts a globally unique identifier (GUID) into a string of printable characte
rs.
StringFromGUID2(
REFGUID rguid, //Interface identifier to be converted
LPOLESTR lpsz, //Pointer to the resulting string on return
int cbMax //Maximum size the returned string is expected to be
);
Parameters
rguid
[in] Interface identifier to be converted.
lpsz
[out] Pointer to the resulting string on return.
cbMax
[in] Maximum size the returned string is expected to be.
Return Values
0 (zero)
Buffer is too small for returned string.
Non-zero value
The number of characters in the returned string, including the null terminator.
Remarks
The string that the lpsz parameter receives has a format like that of the follow
ing sample:
{c200e360-38c5-11ce-ae62-08002b2b79ef}
where the successive fields break the GUID into the form DWORD-WORD-WORD-WORD-WO
RD.DWORD covering the 128-bit GUID. The string includes enclosing braces, which
are a COM convention.
See Also
StringFromCLSID
5.5.25 StringFromIID
Converts an interface identifier into a string of printable characters.
WINOLEAPI StringFromIID(
REFIID rclsid, //Interface identifier to be converted
LPOLESTR * lplpsz //Address of output variable that receives a
// pointer to the resulting string
);
Parameters
rclsid
[in] Interface identifier to be converted.
lplpsz
[out] Address of LPOLESTR pointer variable that receives a pointer to the result
ing string.
Return Values
This function supports the standard return value E_OUTOFMEMORY; as well as the f
ollowing:
S_OK
The character string was successfully returned.
Remarks
The string returned by the function is freed in the standard way, using the task
allocator (refer to the CoGetMallocfunction).
See Also
IIDFromString, CoGetMalloc
5.5.26 CoRegisterMessageFilter
Registers with OLE the instance of an EXE application's IMessageFilter interface
, which is to be used for handling concurrency issues. DLL object applications c
annot register a message filter.
HRESULT CoRegisterMessageFilter(
Parameters
lpMessageFilter
[in] Pointer to theIMessageFilter interface on the message filter supplied by th
e application. Can be NULL, indicating that the current IMessageFilter registrat
ion should be revoked.
lplpMessageFilter
[out] Address of IMessageFilter* pointer variable that receives the interface po
inter to the previously registered message filter. If there was no previously re
gistered message filter, the value of *lplpMessageFilter is NULL. The value cont
ained in the output variable is rarely NULL, however, containing instead a point
er to the default message filter.
Return Values
S_OK
The IMessageFilter instance registered or revoked successfully.
S_FALSE
Error registering or revoking IMessageFilter instance.
PENDINGMSG_WAITDEFPROCESS
Because of the increased resources available in 32-bit systems, you are unlikely
to get this return value. It now indicates the same state as PENDINGMSG_WAITNOP
ROCESS.
Keyboard and mouse messages are no longer dispatched, as was done with PENDINGMS
G_WAITDEFPROCESS. However there are some cases where mouse and keyboard messages
could cause the system to deadlock, and in these cases, mouse and keyboard mess
ages are discarded. WM_PAINT messages are dispatched. Task-switching and activat
ion messages are handled as before.
Remarks
COM calls IMessageFilter::MessagePending after an application has made an COM me
thod call and a Windows message occurs before the call has returned. A Windows m
essage is sent, for example, when the user selects a menu command or double-clic
ks an object. Before COM makes the IMessageFilter::MessagePending call, it calcu
lates the elapsed time since the original COM method call was made. COM delivers
the elapsed time in the dwTickCount parameter. In the meantime, COM does not re
move the message from the queue.
Windows messages that appear in the caller s queue should remain in the queue unti
l sufficient time has passed to ensure that the messages are probably not the re
sult of typing ahead, but are, instead, an attempt to get attention. Set the del
ay with the dwTickCount parameter a two- or three-second delay is recommended. I
f that amount of time passes and the call has not been completed, the caller sho
uld flush the messages from the queue, and the COM UI busy dialog box should be
displayed offering the user the choice of retrying the call (continue waiting) o
r switching to the task identified by the threadIDCallee parameter. This ensures
that:
· If calls are completed in a reasonable amount of time, type ahead will be treate
d correctly.
· If the callee does not respond, type ahead is not misinterpreted and the user is
able to act to solve the problem. For example, OLE 1 servers can queue up reque
sts without responding when they are in modal dialog boxes.
Handling input while waiting for an outgoing call to finish can introduce compli
cations. The application should determine whether to process the message without
interrupting the call, continue waiting, or cancel the operation.
When there is no response to the original COM call, the application can cancel t
he call and restore the COM object to a consistent state by calling IStorage::Re
vert on its storage. The object can be released when the container can shut down
. However, canceling a call can create orphaned operations and resource leaks. C
anceling should be used only as a last resort. It is strongly recommended that a
pplications not allow such calls to be canceled.
See Also
IStorage::Revert, IStorage::Revert, OLEUIBUSY, In the WIN32 SDK: GetTickCount
6.6.1.6 IMessageFilter::RetryRejectedCall
A client-based method that gives the application an opportunity to display a dia
log box so the user can retry or cancel the call, or switch to the task identifi
ed by threadIDCallee.
DWORD RetryRejectedCall(
HTASK threadIDCallee, //Server task handle
DWORD dwTickCount, //Elapsed tick count
DWORD dwRejectType //Returned rejection message
);
Parameters
threadIDCallee
[in] Handle of the server task that rejected the call.
dwTickCount
[in] Number of elapsed ticks since the call was made.
dwRejectType
[in] Specifies either SERVERCALL_REJECTED or SERVERCALL_RETRYLATER, as returned
by the object application.
Return Values
-1
The call should be canceled. COM then returns RPC_E_CALL_REJECTED from the origi
nal method call.
Value >= 0 and <100
The call is to be retried immediately.
Value >= 100
COM will wait for this many milliseconds and then retry the call.
Remarks
COM calls RetryRejectedCall on the caller s IMessageFilter immediately after recei
ving SERVERCALL_RETRYLATER or SERVERCALL_REJECTED from the IMessageFilter::Handl
eInComingCall method on the callee s IMessageFilter.
If a called task rejects a call, the application is probably in a state where it
cannot handle such calls, possibly only temporarily. When this occurs, COM retu
rns to the caller and issues IMessageFilter::RetryRejectedCall to determine if i
t should retry the rejected call.
Applications should silently retry calls that have returned with SERVERCALL_RETR
YLATER. If, after a reasonable amount of time has passed, say about 30 seconds,
the application should display the busy dialog box; a standard implementation of
this dialog box is available in the OLEDLG library. The callee may momentarily
be in a state where calls can be handled. The option to wait and retry is provid
ed for special kinds of calling applications, such as background tasks executing
macros or scripts, so that they can retry the calls in a nonintrusive way.
If, after a dialog box is displayed, the user chooses to cancel, RetryRejectedCa
ll returns -1 and the call will appear to fail with RPC_E_CALL_REJECTED.
6.7 Process and Thread Related API Descriptions
6.7.1 CoCreateFreeThreadedMarshaler
Creates an aggregatable object capable of context-dependent marshaling.
HRESULT CoCreateFreeThreadedMarshaler(
LPUNKNOWN punkOuter, //Pointer to object aggregating the marshaler ob
ject
LPUNKNOWN * ppunkMarshaler //Address of output variable that receives the
IUnknown
//interface pointer to the marshaler object
);
Parameters
punkOuter
[in] Pointer to the aggregating object's controlling IUnknown.
ppunkMarshaler
[out] Address of IUnknown* pointer variable that receives the interface pointer
to the aggregatable marshaler.
Return Values
This function supports the standard return value E_OUTOFMEMORY, as well as the f
ollowing:
S_OK
The marshaler was created.
Remarks
The CoCreateFreeThreadedMarshaler function enables an object to efficiently mars
hal interface pointers between threads in the same process. If your objects do n
ot support interthread marshaling, you have no need to call this function. It is
intended for use by free-threaded DLL servers that must be accessed directly by
all threads in a process, even those threads associated with single-threaded ap
artments. It custom-marshals the real memory pointer over into other apartments
as a bogus "proxy" and thereby gives direct access to all callers, even if they
are not free-threaded.
The CoCreateFreeThreadedMarshaler function performs the following tasks:
1. Creates a free-threaded marshaler object.
2. Aggregates this marshaler to the object specified by the punkOut
er parameter. This object is normally the one whose interface pointers are to be
marshaled.
The aggregating object's implementation of IMarshal should delegate QueryInterfa
ce calls for IID_IMarshal to the IUnknown of the free-threaded marshaler. Upon r
eceiving a call, the free-threaded marshaler performs the following tasks:
1. Checks the destination context specified by the CoMarshalInterfa
ce function's dwDestContext parameter.
2. If the destination context is MSHCTX_INPROC, copies the interfac
e pointer into the marshaling stream.
3. If the destination context is any other value, finds or creates
an instance of COM's default (standard) marshaler and delegates marshaling to it
.
Values for dwDestContext come from the MSHCTX enumeration. MSHCTX_INPROC indicat
es that the interface pointer is to be marshaled between different threads in th
e same process. Because both threads have access to the same address space, the
client thread can dereference the pointer directly rather than having to direct
calls to a proxy. In all other cases, a proxy is required, so CoCreateFreeThread
edMarshaler delegates the marshaling job to COM's default implementation.
Great care should be exercised in using the CoCreateFreeThreadedMarshaler functi
on. This is because the performance of objects which aggregate the free-threaded
marshaler is obtained through a calculated violation of the rules of COM, with
the ever-present risk of undefined behavior unless the object operates within ce
rtain restrictions. The most important restrictions are:
A free-threaded marshaler object cannot hold direct pointers to interfaces on an
object that does not aggregate the free-threaded marshaler as part of its state
. If the object were to use direct references to ordinary single-threaded aggreg
ate objects, it may break their single threaded property. If the object were to
use direct references to ordinary multi-threaded aggregate objects, these object
s can behave in ways that show no sensitivity to the needs of direct single-thre
aded aggregate clients. For example, these objects can spin new threads and pass
parameters to the threads that are references to ordinary single-threaded aggre
gate objects.
A free-threaded marshaler object cannot hold references to proxies to objects in
other apartments. Proxies are sensitive to the threading model and can return R
PC_E_WRONG_THREAD if called by the wrong client.
See Also
CoMarshalInterThreadInterfaceInStream, CoGetInterfaceAndReleaseStream
6.7.2 CoGetInterfaceAndReleaseStream
Unmarshals a buffer containing an interface pointer and releases the stream when
an interface pointer has been marshaled from another thread to the calling thre
ad.
HRESULT CoGetInterfaceAndReleaseStream(
LPSTREAM pStm, //Pointer to the stream from which the object is to be m
arshaled
REFIID riid, //Reference to the identifier of the interface
LPVOID * ppv //Address of output variable that receives the
// interface pointer requested in riid
);
Parameters
pStm
[in] Pointer to the IStream interface on the stream to be unmarshaled.
riid
[in] Reference to the identifier of the interface requested from the unmarshaled
object.
ppv
[out] IndirectAddress of pointer variable that receives the interface pointer re
quested in riid. Upon successful return, *ppv contains the requested interface p
ointer to the unmarshaled interface.
Return Values
This function supports the standard return value E_INVALIDARG, as well as the fo
llowing:
S_OK
Indicates the output interface was unmarshaled and the stream was released.
This function can also return any of the values returned by CoUnmarshalInterface
.
Remarks
The CoGetInterfaceAndReleaseStream function performs the following tasks:
1. Calls CoUnmarshalInterface to unmarshal an interface pointer pre
viously passed in a call to CoMarshalInterThreadInterfaceInStream.
2. Releases the stream pointer. Even if the unmarshaling fails, the
stream is still released because there is no effective way to recover from a fa
ilure of this kind.
See Also
CoMarshalInterThreadInterfaceInStream, CoUnmarshalInterface
6.7.3 CoMarshalInterThreadInterfaceInStream
Marshals an interface pointer from one thread to another thread in the same proc
ess.
HRESULT CoMarshalInterThreadInterfaceInStream(
REFIID riid, //Reference to the identifier of the interface
LPUNKNOWN pUnk, //Pointer to the interface to be marshaled
LPSTREAM * ppStm //Address of output variable that receives the
// IStream interface pointer for the marshaled
// interface
);
Parameters
riid
[in] Reference to the identifier of the interface to be marshaled.
pUnk
[in] Pointer to the interface to be marshaled, which must be derived from IUnkno
wn; can be NULL.
ppStm
[out] Address of IStream* pointer variable that receives the interface pointer t
o the stream that contains the marshaled interface.
Return Values
This function supports the standard return value E_OUTOFMEMORY, as well as the f
ollowing:
S_OK
The interface was marshaled successfully.
Remarks
The CoMarshalInterThreadInterfaceInStream function enables an object to easily a
nd reliably marshal an interface pointer to another thread in the same process.
The stream returned in ppStm is guaranteed to behave correctly when a client run
ning in the receiving thread attempts to unmarshal the pointer. The client can t
hen call the CoGetInterfaceAndReleaseStream to unmarshal the interface pointer a
nd release the stream object.
The CoMarshalInterThreadInterfaceInStream function performs the following tasks:
1. Creates a stream object.
2. Passes the stream object s IStream pointer to CoMarshalInterface.
3. Returns the IStream pointer to the caller.
See Also
CoGetInterfaceAndReleaseStream
6.8 Process and Thread Related Structure Descriptions
6.8.1 INTERFACEINFO
The INTERFACEINFO structure contains information about incoming calls. The struc
ture is defined as follows:
typedef struct tagINTERFACEINFO
{
LPUNKNOWN pUnk;
IID iid;
WORD wMethod;
} INTERFACEINFO, * LPINTERFACEINFO;
Members
pUnk
Pointer to the IUnknown interface on the object.
iid
Identifier of the requested interface
wMethod
Interface method.
See Also
IMessageFilter::HandleIncomingCall
6.9 Process and Thread Related Enumeration Descriptions
6.9.1 CALLTYPE
The CALLTYPE enumeration constant specifies the call types used by IMessageFilte
r::HandleInComingCall.
typedef enum tagCALLTYPE
{
CALLTYPE_TOPLEVEL = 1,
CALLTYPE_NESTED = 2,
CALLTYPE_ASYNC = 3,
CALLTYPE_TOPLEVEL_CALLPENDING = 4,
CALLTYPE_ASYNC_CALLPENDING = 5
} CALLTYPE;
Elements
CALLTYPE_TOPLEVEL
A top-level call has arrived and that the object is not currently waiting for a
reply from a previous outgoing call. Calls of this type should always be handled
.
CALLTYPE_NESTED
A call has arrived bearing the same logical thread identifier as that of a previ
ous outgoing call for which the object is still awaiting a reply. Calls of this
type should always handled.
CALLTYPE_ASYNC
An aysnchronous call has arrived. Calls of this type cannot be rejected. COM alw
ays delivers calls of this type.
CALLTYPE_TOPLEVEL_CALLPENDING
A new top-level call has arrived with a new logical thread identifier and that t
he object is currently waiting for a reply from a previous outgoing call. Calls
of this type may be handled or rejected.
CALLTYPE_ASYNC_CALLPENDING
An asynchronous call has arrived with a new logical thread identifier and that t
he object is currently waiting for a reply from a previous outgoing call. Calls
of this type cannot be rejected.
async call - can NOT be rejected
See Also
IMessageFilter::HandleInComingCall, IMessageFilter
6.9.2 PENDINGMESSAGE
The PENDINGMSG enumeration constants are return values of IMessageFilter::Messag
ePending.
Defined in the IMessageFilter interface (msgflt.idl).
typedef enum tagPENDINGMSG
{
PENDINGMSG_CANCELCALL = 0,
PENDINGMSG_WAITNOPROCESS = 1,
PENDINGMSG_WAITDEFPROCESS = 2
} PENDINGMSG;
Elements
PENDINGMSG_CANCELCALL
Cancel the outgoing call.
PENDINGMSG_WAITNOPROCESS
Wait for the return and don't dispatch the message.
PENDINGMSG_WAITDEFPROCESS
Wait and dispatch the message.
See Also
IMessageFilter::MessagePending
6.9.3 PENDINGTYPE
The PENDINGTYPE enumeration constants indicate the level of nesting in the IMess
ageFilter::MessagePending method.
typedef enum tagPENDINGTYPE
{
PENDINGTYPE_TOPLEVEL = 1,
PENDINGTYPE_NESTED = 2
} PENDINGTYPE;
Elements
PENDINGTYPE_TOPLEVEL
Top-level call.
PENDINGTYPE_NESTED
Nested call.
See Also
IMessageFilter::MessagePending
6.9.4 SERVERCALL
The SERVERCALL enumeration constants indicate the status of server call ¾ returned
by IMessageFilter::HandleInComingCall and passed to IMessageFilter::RetryReject
edCall.
Defined in the IMessageFilter interface (msgflt.idl).
typedef enum tagSERVERCALL
{
SERVERCALL_ISHANDLED = 0,
SERVERCALL_REJECTED = 1,
SERVERCALL_RETRYLATER = 2
} SERVERCALL;
Elements
SERVERCALL_ISHANDLED
The object may be able to process the call.
SERVERCALL_REJECTED
The object cannot handle the call due to an unforeseen problem, such as network
unavailability.
SERVERCALL_RETRYLATER
The object cannot handle the call at this time. For example, an application migh
t return this value when it is in a user-controlled modal state.
See Also
IMessageFilter::HandleInComingCall, IMessageFilter::RetryRejectedCall
7. COM Clients
As described in earlier chapters, a COM Client is simply any piece of code that
makes use of another object through that object s interfaces. In this sense, a COM
Client may itself be a COM Server acting in the capacity of a client by virtue
of using (or reusing) some other object.
If the client is an application, that is, an executable program as opposed to a
DLL, then it must follow all the requirements for a COM Application as detailed
in Chapter 5. That aside, clients have a number of ways to actually get at an ob
ject to use as discussed in a previous chapter. The client may call a specific f
unction to create an object, it might ask an existing object to create another,
or it might itself implement an object to which some other code hands yet anothe
r object s interface pointer. Not all of these objects must have CLSID.
This chapter, however, is concerned with those clients that want to create an ob
ject based on a CLSID, because at some point or another, many operations that do
n t directly involve a CLSID do eventually resolve to this process. For example, m
oniker binding internally uses a CLSID but shields clients from that fact. In an
y case, whatever client code uses a CLSID will generally perform the following o
perations in order to make use of an object:
Identify the class of object to use.
Obtain the class factory for the object class and ask it to create an uninitialize
d instance of the object class, returning an interface pointer to it.
Initialize the newly created object by calling an initialization member function
of the initialization interface, that is, one of a generally small set of interfa
ces that have such functions.
Make use of the object which generally includes calling QueryInterface to obtain
additional working interface pointers on the object. The client must be prepare
d for the potential absence of a desired interface.
Release the object when it is no longer needed.
The following sections cover the functions and interfaces involved in each of th
ese steps. In addition, the client may want to more closely manage the loading a
nd unloading of server modules (DLLs or EXEs) for optimization purposes, so this
chapter includes a section of such management.
As far as the client is concerned, the COM Library exists to provide fundamental
implementation locator and object creation services and to handle remote proced
ure calls to local or remote objects (in addition to memory management services,
of course). How a server facilitates these functions is the topic of Chapter 8.
Before examining the details of object creating and manipulation, realize that a
fter the object is created and the client has its first interface pointer to tha
t object, the client cannot distinguish an in-process object from a local object
from a remote object by virtue of examining the interface pointer or any other
interfaces on that object. That is, all objects appear identically to the client
such that after creation, all requests made to the object s services are made by
calling interface member functions. Period. There are not special exceptions tha
t a client must make at run-time based on the distance of the object in question
. The COM Library provides any underlying glue to insure that a call made to a l
ocal or remote object is, in fact, marshaled properly to the other process or th
e other machine, respectively. This operation is transparent to the client, who
always sees any call to an object as a function call to the objects interfaces a
s if that object were in-process. This consistency is a key benefit for COM clie
nts as it can treat all objects identically regardless of their actual execution
context. If you are interested in understanding how this transparency is achiev
ed, please see Chapter 9, Communicating via Interfaces: Remoting for more details.
There you will find that all clients do, in fact, always call an in-process obj
ect first, but in local and remote cases that in-process object is just a proxy
that takes care of generating a remote procedure call.
7.1 Getting a Pointer to an Object
Because COM does not have a strict class model, there are several ways to instan
tiate or to get a pointer to an interface on an object. There are, in fact, four
methods through which a client obtains its first interface pointer to a given o
bject:
Call a COM Library API function that creates an object of a pre-determined type ¾
that is, the function will only return a pointer to one specific interface for a
specific object class.
Call a COM Library API function that can create an object based on a class ident
ifier (CLSID) and that returns any type of interface pointer requested.
Call a method of some interface that creates another object (or connects to an e
xisting one) and returns an interface pointer on that separate object.
Implement an object with an interface through which other objects pass their int
erface pointer to the client directly.
For information on getting pointers to other interfaces on an object once you ha
ve the first one, see QueryInterface: Navigating in an Object.
There are numerous COM functions that return pointers to specific interface impl
ementations, such as CoGetMalloc, which retrieves a pointer to the standard COM
memory allocator. Most of these are helper functions, which retrieve a pointer t
o an COM implementation of an interface on an object, as does CoGetMalloc. Most
of these functions are described in the specific area they are related to, such
as storage or data transfer.
There are several functions that, given a CLSID, a client can call to create an
object instance and get a pointer to it. All of these functions are based on the
function CoGetClassObject, which creates a class object and supplies a pointer
to an interface that allows you to create instances of that class. While there m
ust be information that says which system the server resides on, there is no nee
d for that information to be contained in the client. The client needs to know o
nly the CLSID, and never the absolute path of the server code. For more informat
ion, see Creating an Object through a Class Object.
Among the many interface methods that return a pointer to a separate object are
several that create and return a pointer to an enumerator object, which allows y
ou to determine how many items of a given type an object maintains. COM defines
interfaces for enumerating a wide variety of items, such as strings, several str
uctures important in various COM technologies, monikers, and IUnknown interface
pointers. The typical way to create an enumerator instance and get a pointer to
its interface is to call a method from another interface. For example, the IData
Object interface defines two methods, EnumDAdvise and EnumFormatEtc, that return
pointers to interfaces on two different enumeration objects. There are many oth
er examples in COM of methods that return pointers to objects.
The fourth way to get a pointer to an object is used when two objects, such as a
n OLE Compound Document container and server, need bi-directional communication.
Each implements an object containing an interface method to which other objects
can pass interface pointers. In the case of containers and servers, each object
then passes its pointer to the other object. The implementing object, which is
also the client of the created object, can then call the method and get the poin
ter that was passed.
7.1.1 Creating an Object through a Class Object
With the increasing importance of computer networks, it has become necessary for
clients and servers to interact easily and efficiently, whether they reside on
the same machine or across a network. Crucial to this is the ability of a client
to be able to launch a server, create an instance of the server s object, and hav
e access to the methods of the interfaces on the object.
COM provides extensions to this basic COM process that make it virtually seamles
s across a network. If a client is able to identify the server through its CLSID
, calling a few simple functions permit COM to do all the work of locating and l
aunching the server, and activating the object. New subkeys have been added to t
he registry that allow remote servers to register their location, so the client
does not require that information. For applications that want to take advantage
of networking features, object creation functions are provided that allow more f
lexibility and efficiency.
7.1.2 COM Class Objects and CLSIDs
A COM server is implemented as a COM class. A COM class is an implementation of
a group of interfaces in code executed whenever you interact with a given object
. There is an important distinction between a C++ class and a COM class. In C++,
a class is a type. A COM class is simply a definition of the object, and carrie
s no type, although a C++ programmer might implement it using a C++ class. COM i
s designed to allow a class to be used by different applications, including appl
ications written without knowledge of that particular class s existence. Therefore
, class code for a given type of object exists either in a dynamic linked librar
y (DLL) or in another application (EXE).
Each COM class is identified by a CLSID, a unique 128-bit GUID, which the server
must register. COM uses this CLSID, at the request of a client, to associate sp
ecific data with the DLL or EXE containing the code that implements the class, t
hus creating an instance of the object. For information on registering a server,
see Registering COM Servers, and GUID Creation and Optimizations.
For clients and servers on the same machine, the model previously supported, the
CLSID of the server is all the client ever needs. On each machine, COM maintain
s a database (it makes use of the system registry on Windows and Macintosh platf
orms) of all the CLSIDs for the servers installed on the system. This is a mappi
ng between each CLSID and the location of the DLL or EXE that houses the code fo
r that CLSID. COM consults this database whenever a client wants to create an in
stance of a COM class and use its services, so the client never needs to know th
e absolute location of the code on the machine.
For distributed systems, COM provides registry entries that allow a remote serve
r to register itself for use by a client. While applications need know only a se
rver s CLSID, because they can rely on the registry to locate the server, COM allo
ws clients to override registry entries and to specify server locations, to take
full advantage of the network (see Locating a Remote Object).
The basic way to create an instance of a class is through a COM class object. Th
is is simply an intermediate object that supports functions common to creating n
ew instances of a given class. Most class objects used to create objects from a
CLSID support the IClassFactory interface, an interface that includes the import
ant method CreateInstance. You implement an IClassFactory interface for each cla
ss of object that you offer to be instantiated. For information on implementing
IClassFactory, refer to Implementing IClassFactory.
Note
Servers that support some other custom class factory interface are not required
to support IClassFactory specifically. However, calls to activation functions ot
her than CoGetClassObject (such as CoCreateInstanceEx) require that the server s
upport IClassFactory.
When a client wants to create an instance of the server s object, it uses the desi
red object s CLSID in a call to CoGetClassObject. (This call can either be direct
or implicit, through one of the object creation helper functions.)
COM has just a few API functions on which many of the others are built. The most
important of these is probably CoGetClassObject, which underlies all of the ins
tance creation functions. This function locates the code associated with the CLS
ID, and creates a class object, and supplies a pointer to the interface requeste
d (CoGetClassObject takes a riid param that specifies the client s desired interfa
ce pointer).
With this pointer, the caller can create an instance of the object, and retrieve
a pointer to a requested interface on the object. This is usually an initializa
tion interface, used to activate the object (put it in the running state), so th
e client can do whatever work with the object that it wants to. Using these basi
c functions, the client must also take care to release all object pointers. COM
provides several helper functions that reduce the work of creating object instan
ces. These are described in Instance Creation Helper Functions.
Another mechanism for activating object instances is through the class moniker.
Class monikers bind to the class object of the class for which they are created.
For more information, see Class Monikers.
7.1.3 Locating a Remote Object
COM uses the basic model for object creation described in COM Class Objects and
CLSIDs, and adds more than one way to locate an object that may reside on anothe
r system in a network, without overburdening the client application.
COM has registry keys that permit a server to register the name of the machine o
n which it resides, or the machine where an existing storage is located. Thus, c
lient applications need know only the CLSID of the server.
CoGetClassObject takes a COSERVERINFO structure, which allows a client to specif
y the location of a server. Another important value in this function is the CLSC
TX enumeration, which specifies whether the expected object is to be run in-proc
ess, out-of-process local, or out-of-process remote. Taken together, these two v
alues and the values in the registry determine how and where the object is to be
run. Instance creation calls, when they specify a server location, can override
a registry setting. The algorithm COM uses for doing this is described in the r
eference for the CLSCTX enumeration.
Remote activation depends on the security relationship between client and server
. For more information, see Security in COM.
7.1.4 Instance Creation Helper Functions
In previous releases of COM, the primary mechanism used to create an object inst
ance was the CoCreateInstance function. This function encapsulates the process o
f creating a class object, using that to create a new instance and releasing the
class object.
To smooth the process of instance creation on distributed systems, COM has intro
duced four important new instance creation mechanisms:
· Class Monikers and IClassActivator
· CoCreateInstanceEx
· CoGetInstanceFromFile
· CoGetInstanceFromIStorage
Class monikers are a mechanism that permit you to identify the class of an objec
t, and are typically used with another moniker, like a file moniker, to indicate
the location of the object. This permits you to bind to an object ans specify t
he server that is to be launched for that object. Class monikers may also be com
posed to the right of monikers supporting binding to the IClassActivator interfa
ce. For more information, see Class Monikers.
CoCreateInstanceEx extends CoCreateInstance to make it possible to create a sing
le uninitialized object associated with the given CLSID on a specified remote ma
chine. In addition, rather than requesting a single interface and obtaining a si
ngle pointer to that interface, CoCreateInstanceEx makes it possible to query fo
r multiple interfaces and (if available) receive pointers to them in a single ro
und trip, thus permitting fewer round trips between machines. This can make remo
te object interaction much more efficient. To do this, the function uses an arra
y of MULTI_QI structures.
Creating an object through CoCreateInstanceEx still requires that the object be
initialized through a call to one of the initialization interfaces (such as IPer
sistStorage:::Load). The two helper functions, CoGetInstanceFromFile and CoGetIn
stanceFromIStorage encapsulate both the instance creation power of CoCreateInsta
nceEx and initialization, the former from a file, and the latter from a storage.
7.2 Initializing the Object
After the client has successfully created an object of a given class it must ini
tialize that object. By definition, any new object created using IClassFactory::
CreateInstance (or variant or wrapper thereof) is uninitialized. Initialization
generally happens through a single call to a member function of the initializatio
n interface. This interface is usually the one requested by the client in its cal
l to create the object, but this is not required. Before an object is initialize
d, the only calls that are guaranteed to work on the object (besides the initial
izing functions themselves) are the IUnknown functions (of any interface) unless
otherwise explicitly specified in the definition of an interface. In addition,
QueryInterface is only guaranteed to work for IUnknown and any initialization in
terface, but not guaranteed for a non-initialization interface.
Some objects will not require initialization before they are function through al
l of their interfaces. Those that do require initialization will define, either
explicitly through documentation of the object or implicitly through the scenari
os in which the object is used, which member of which interface can be used for
initialization.
For example, objects that can serialize their persistent data to a file will imp
lement the IPersistFile interface (see Persistent Storage Interfaces for Objects i
n Chapter 14). The function IPersistFile::Load, which instructs the object to lo
ad its data from a file, is the initialization function and IPersistFile is the
initialization interface. Other examples are objects that can serialize to stora
ges or streams, where the objects implement the initialization interfaces IPersi
stStorage or IPersistStream, respectively (again, see Chapter 14). The Load func
tions in these interfaces are initialization functions as is IPersistStorage::In
itNew, which initializes a new object with storage instead of loading a previous
ly saved version.
7.3 Managing the Object
Once an object is initialized, it is entirely up to the client to determine what
it intends to do with that object. It is often the case that the initializing i
nterface is not the working interface through which the client will primarily use
the object. The creation sequence only nets the client a single interface pointe
r that has a limited scope of functionality. If the client wishes to perform an
operation outside that scope, it must call the known interface s QueryInterface fu
nction to ask for another interface on the same object.
For example, say a client has created and initialized an object but now wishes t
o obtain a graphical presentation, say a bitmap, from that object by calling IDa
taObject::GetData (see Chapter 16 for details on this function). The client must
call QueryInterface to obtain an IDataObject pointer before calling the functio
n.
It is important to note that all operations on that object will occur through ca
lls to the member functions of the object s various interfaces. Any additional API
functions that the client might call to affect the object itself are usually wr
apper functions of common sequences of interface function calls. There simply is
no other way to affect the object other than through it s interfaces.
Because a client must ask for an interface before it can possibly ask the object
to perform the actions defined in the interface, the client cannot ask the obje
ct to perform an action the object does not support. This is a primary strength
of the QueryInterface function as described in the early chapters of this docume
nt. Calling QueryInterface for access to an object s functionality is not problema
tic nor inconvenient because the client usually makes the call specifically at t
he point where the client wants to perform some action on the object. That is, c
lients generally do not call QueryInterface for all possible interfaces after th
e object is created so as to have all the pointers on hand instead, the client cal
ls QueryInterface before attempting to perform some action with the object.
In practice this means that the client must be prepared for the failure of a cal
l to QueryInterface. Instead of being a complete pain to implementation, such pr
eparation defines a mechanism through which the client can make dynamic choices
based on the functionality of the object itself on an object-by-object basis.
For example, consider a client application that has created a number of objects
and it now wants to save the application s state, which includes saving the state
of each object. Let s say the client is using structured storage for its native fi
le representation, so its first choice will be to assign an individual storage e
lement in that file for each object. Each object can then store structured infor
mation itself and it indicates its ability to do by implementing the IPersistSto
rage interface. However, some object may not know how to write to a storage but
know how to write to a stream and indicate the capability by implementing IPersi
stStream. Yet others may only know how to write information to a file themselves
and thus implement IPersistFile. Finally, some objects may not know how to seri
alize themselves at all, but can provide a binary memory copy of the their nativ
e data through IDataObject.
In this case the client s strategy will be as follows: if an object supports IPers
istStorage, then give it an IStorage instance and ask it to save its data into i
t by calling IPersistStorage::Save. If that object does not provide such support
, check if it supports IPersistStream, and if so, create a client-controlled str
eam for it (in perhaps a separate client-controlled storage element) and pass th
at IStream pointer to the object through IPersistStream::Save. If the object doe
s not support streams, then check for IPersistFile. If the object supports seria
lization to a file, then have the object write its data into a temporary file by
calling IPersistFile::Save, then make a binary copy of that file in a client-co
ntrolled stream element within a client-controlled storage element. If all else
fails, attempt to retrieve the object s binary data from IDataObject::GetData usin
g the first format the object supports, and write that binary data into a client
-controlled stream in a client-controlled storage.
Reloading these objects would be a similar procedure, but the client would know,
from the structure of its storage and other information it saved about the obje
cts itself, which method to use to reload the object from the storage. The clien
t wants to insure that it uses the same method to load the object that it did fo
r saving it originally, that is, use the same interface instead of querying for
the best one. The reason is that while the data was passively stored on disk, th
e object that wrote that data might have been updated such that where it once on
ly supported IPersistStream, for example, it now supports IPersistStorage. In th
at case the client should ask it to load the data using IPersistStream::Load.
However, when the client goes to save the object again, it will now successfully
find that the object supports IPersistStorage and can now have the object save
into a storage element instead. (The container would also insure that the old cl
ient-controlled stream was deleted as it is no longer in use for that object.) T
his demonstrates how an object can be updated and new interfaces supported witho
ut any recompilation on the part of existing clients while at the same time sudd
enly working with clients on a higher level of integration than before. In order
to remain compatible the object must insure that it supports the older interfac
es (such as IPersistStream) but is free to add new contracts new interfaces such a
s IPersistStorage as it wants to provide new functionality.
The point of this example, which is also true for clients that use any other int
erfaces an object might support in other scenarios, is that the client is empowe
red to make dynamic decisions on a per-object basis through the QueryInterface f
unction. Containers programmed to be dynamic as such allow object to improve ind
ependently while insuring that the container will work as good and generally bette
r as it always has with any given object. All of this is due to the powerful and i
mportant QueryInterface mechanism that for all intents and purposes is the singl
e most important aspect of true system component software.
7.4 Releasing the Object
The final operation required in a COM client when dealing with an object from so
me other server is to free that object when the client no longer needs it. This
is achieved by calling the Release member function of all interfaces obtained du
ring the course of using the object.
Recall that a function that creates or synthesizes a new interface pointer is re
sponsible for calling AddRef through that pointer before returning it to the cal
ler of the function. This applies to the IClassFactory::CreateInstance function
as well as CoCreateInstance (and for that matter, CoGetClassObject, too, which i
s why you must call IClassFactory::Release after creating the object). Therefore
, as far as the client is concerned, the object will have a reference count of o
ne after creation. The object may, in fact, have a higher reference count if it
is also being used from other clients as well, but each client is only responsib
le and cognizant of the reference counts added on its behalf.
The other primary function that creates new interface pointers is QueryInterface
. Every call the client makes to QueryInterface to obtain another interface poin
ter will internally generate another call to AddRef in that object, incrementing
the reference count. Therefore, in addition to calling Release through the inte
rface pointer obtained in the creation sequence, the client must also call Relea
se through any interface pointer obtained from QueryInterface (this is illustrat
ed in the pseudo-code of the previous section).
The bottom line is that the client is responsible for matching any operation tha
t generates a call to AddRef through a given interface pointer with a call to Re
lease through that same interface pointer. It is not necessary to call Release i
n the opposite order of calls to AddRef; it is just necessary to match the pairs
. Failure to do so will cause memory leaks as objects are not freed and servers
are not allowed to shut down properly. This is no different that forgetting to f
ree memory obtained through malloc.
Finally, although the client matches its calls to AddRef and Release, the actual
object may still continue to run and the server may continue to execute as well
without any objects in service. The object will continue if other clients are u
sing that same object and thus have reference counts on it. Only when all client
s have released their references will that object free itself. The server will,
of course, continue to execute as long as there is an object to serve, but the c
lient does have some power over keeping a server running even without objects. T
hat is the purpose of Server Management functions in COM.
7.5 Server Management
As mentioned in previous sections, a client has the ability to manage servers on
the server level to keep them running even when they are not serving any object
s. The client s primary mechanism for this is the IClassFactory::LockServer functi
on described above. By calling this function with the TRUE parameter, the client
places a lock on the server. As long as the server either has objects created or
has one or more locks on it, the server will continue to execute. When the serve
r detects a zero object and zero lock condition, it can unload itself (which dif
fers between DLL and EXE servers, as described in Chapter 8).
A client can place more than one lock on a server by calling IClassFactory::Lock
Server(TRUE) more than once. Each call to LockServer(TRUE) must be matched with
a call to LockServer(FALSE) the server maintains a lock count for the server as it
maintains a reference count for its served objects. But while AddRef and Releas
e affect objects, LockServer affects the server itself.
LockServer affects all servers in-process, local, and remote identically. The client
does have some additional control over in-process objects as it normally would
for other DLLs through the functions CoLoadLibrary, CoFreeUnusedLibraries, and C
oFreeAllLibraries, as described below. Normally only CoFreeUnusedLibraries is ca
lled from a client whereas the others are generally used inside the COM Library
to implement other API functions. In addition, the COM Library supplies one addi
tional function that has meaning in this context, CoIsHandlerConnected, that tel
ls the container if an object handler is currently working in association with a
local server as described in its entry below.
7.6 Client Related Interface Descriptions
7.6.1 ICatInformation
The ICatInformation interface provides methods for obtaining information about t
he categories implemented or required by a certain class, as well as information
about the categories registered on a given machine.
7.6.1.1.1 When to Implement
There is no need to implement this interface. The Component Category Manager, a
system-provided COM object that can be instantiated by using CoCreateInstance, i
mplements ICatInformation.
7.6.1.1.2 When to Use
Call the methods of ICatInformation to obtain a listing of available categories,
enumerate classes that belong to a particular category, and determine if a clas
s belongs to a specific category.
Information on using component categories can be found in Component Categories M
anager Implementation.
Methods in Vtable Order
IUnknown Methods Description
QueryInterface Returns pointers to supported interfaces.
AddRef Increments reference count.
Release Decrements reference count.
ICatInformation Methods Description
EnumCategories Returns an enumerator for the component categories registered on
the system.
GetCategoryDesc Retrieves the localized description string for a specific catego
ry ID.
EnumClassesOfCategories Returns an enumerator over the classes that implement/re
quire a certain set of categories.
IsClassOfCategories Determines if a class implements/requires the specified
categories.
EnumImplCategoriesOfClass Returns an enumerator over the CATIDs implemente
d by the specified class.
EnumReqCategoriesOfClass Returns an enumerator over the CATIDs required b
y the specified class.
See Also
ICatRegister
7.6.1.2 ICatInformation::EnumCategories
Returns an enumerator for the component categories registered on the system.
HRESULT EnumCategories(
LCID lcid, //Requested locale for returned szDescription of enumerated CATE
GORYINFOs
IEnumCATEGORYINFO** ppenumCatInfo //Location in which to return an IEnumCA
TEGORYINFO interface
);
Parameters
lcid
[in] Identifies the requested locale for any return szDescription of the enumera
ted CATEGORYINFOs. Typically, the caller specifies GetUserDefaultLCID for this p
arameter.
ppenumCatInfo
[out] Specifies the location to return an IEnumCATEGORYINFO interface. This can
be used to enumerate the CATIDs and localized description strings of the compone
nt categories registered with the system.
Return Values
S_OK
The function was successful.
E_INVALIDARG
One or more arguments are incorrect.
E_OUTOFMEMORY
Insufficient memory to create and return an enumerator object.
See Also
ICatInformation::EnumClassesOfCategories, ICatInformation::EnumImplCategoriesOfC
lass, ICatInformation::EnumReqCategoriesOfClass, ICatInformation::GetCategoryDes
c, ICatInformation::IsClassOfCategories
7.6.1.3 ICatInformation::EnumClassesOfCategories
Returns an enumerator over the classes that implement one or more of rgcatidImpl
. If a class requires a category not listed in rgcatidReq, it is not included in
the enumeration.
HRESULT EnumClassesOfCategories(
ULONG cImplemented, //Number of category IDs in the rgcatidImpl array
CATID rgcatidImpl, //Array of category identifiers
ULONG cRequired, //Number of category IDs in the rgcatidReq array
7.6.1.4 ICatInformation::EnumImplCategoriesOfClass
Returns an enumerator for the CATIDs implemented by the specified class.
HRESULT EnumImplCategoriesOfClass(
REFCLSID rclsid, //Class ID
IEnumCATID** ppenumCATD //Location in which to return an IEnumCATID inte
rface
);
Parameters
rclsid
[in] Specifies the class ID.
ppenumCATD
[out] Specifies the location to return an IEnumCATID interface. This can be used
to enumerate the CATIDs that are implemented by rclsid.
Return Values
S_OK
The function was successful.
E_INVALIDARG
One or more arguments are incorrect.
E_OUTOFMEMORY
Insufficient memory to create and return an enumerator object.
See Also
ICatInformation::EnumCategories, ICatInformation::EnumClassesOfCategories, ICatI
nformation::EnumReqCategoriesOfClass, ICatInformation::GetCategoryDesc, ICatInfo
rmation::IsClassOfCategories
7.6.1.5 ICatInformation::EnumReqCategoriesOfClass
Returns an enumerator for the CATIDs required by the specified class.
HRESULT EnumReqCategoriesOfClass(
REFCLSID rclsid, //Class ID
IEnumCATID** ppenumCATD //Location in which to return an IEnumCATID inte
rface
);
Parameters
rclsid
[in] Specifies the class ID.
ppenumCATD
[out] Specifies the location to return an IEnumCATID interface. This can be used
to enumerate the CATIDs that are required by rclsid.
Return Values
S_OK
The function was successful.
E_INVALIDARG
One or more arguments are incorrect.
E_OUTOFMEMORY
Insufficient memory to create and return an enumerator object.
See Also
ICatInformation::EnumCategories, ICatInformation::EnumClassesOfCategories, ICatI
nformation::EnumImplCategoriesOfClass, ICatInformation::GetCategoryDesc, ICatInf
ormation::IsClassOfCategories
7.6.1.6 ICatInformation::GetCategoryDesc
Retrieves the localized description string for a specific category ID.
HRESULT GetCategoryDesc(
REFCATID rcatid, //Category for which the string is to be returned
LCID lcid, //Locale in which the resulting string is returned
PWCHAR* ppszDesc //Pointer to the string pointer that contains the descri
ption
);
Parameters
rcatid
[in] Identifies the category for which the description string is to be returned.
lcid
[in] Specifies the locale in which the resulting string is returned.
ppszDesc
[out] A pointer to the string pointer that contains the description. This must b
e released by the caller using CoMemTaskFree.
Return Values
S_OK
The function was successful.
E_INVALIDARG
One or more arguments are incorrect.
E_OUTOFMEMORY
Insufficient memory to create and return an enumerator object.
CAT_E_CATIDNOEXIST
The category ID rcatid is not registered.
CAT_E_NODESCRIPTION
There is no description string for rcatid with the specified locale.
See Also
ICatInformation::EnumCategories, ICatInformation::EnumClassesOfCategories, ICatI
nformation::EnumImplCategoriesOfClass, ICatInformation::EnumReqCategoriesOfClass
, ICatInformation::IsClassOfCategories
7.6.1.7 ICatInformation::IsClassOfCategories
Determines if a class implements one or more categories. If the class requires a
category not listed in rgcatidReq, it is not included in the enumeration.
HRESULT IsClassOfCategories(
REFCLSID rclsid, //Class ID of the class to query
ULONG cImplemented, //Number of category IDs in the rgcatidImpl array
CATID rgcatidImpl, //Array of category identifiers
ULONG cRequired, //Number of category IDs in the rgcatidReq array
CATID rgcatidReq //Array of category identifiers
);
Parameters
rclsid
[in] The class ID of the relevent class to query.
cImplemented
[in] The number of category IDs in the rgcatidImpl array. This value cannot be z
ero. If this value is ((ULONG) -1), the implemented categories are not tested.
rgcatidImpl
[in] An array of category identifiers.
cRequired
[in] The number of category IDs in the rgcatidReq array. This value can be zero.
If this value is ((ULONG) -1), the required categories are not tested.
rgcatidReq
[in] An array of category identifiers.
Return Values
S_OK
rclsid is of category rcatid.
S_FALSE
rclsid is not of category rcatid.
See Also
ICatInformation::EnumCategories, ICatInformation::EnumClassesOfCategories, ICatI
nformation::EnumImplCategoriesOfClass, ICatInformation::EnumReqCategoriesOfClass
, ICatInformation::GetCategoryDesc
7.6.2 IMultiQI
The IMultiQI interface enables a client to query an object proxy, or handler, fo
r multiple interfaces, using a single RPC call. By using this interface, instead
of relying on separate calls to IUnknown::QueryInterface, clients can reduce th
e number of RPC calls that have to cross thread, process, or machine boundaries
and, therefore, the amount of time required to obtain the requeseted interface p
ointers.
7.6.2.1.1 When to Implement
You never have to implement this interface because there is no situation in whic
h it is required. COM server applications that rely on COM s standard remoting sup
port get the interface for free because COM implements it on every object proxy.
The only situation in which you might want to implement this interface yourself
is if you are writing a custom marshaler that handles interface remoting. Even
here, implementing IMultiQI yourself is not recommended, particularly if your ob
ject is aggregatable.
7.6.2.1.2 When to Use
When more than one interface pointer is sought, client applications should Query
Interface for IMultiQI and use it if available.
Methods in VTable Order
IUnknown Methods Description
QueryInterface Returns pointers to supported interfaces.
AddRef Increments reference count.
Release Decrements reference count.
IMultiQI Methods Description
QueryMultipleInterfaces Queries for multiple interfaces.
See Also
IUnknown::QueryInterface
7.6.2.2 IMultiQI::QueryMultipleInterfaces
Fills a caller-provided array of structures with pointers to multiple interfaces
.Calling this method is equivalent to issuing a series of separate QueryInterfac
e calls except that you do not incur the overhead of a corresponding number of R
PC calls. In multithreaded applications and distributed environments, keeping RP
C calls to a minimum is essential for optimal performance.
HRESULT QueryMultipleInterfaces(
ULONG cMQIs, //Number of structures in array
MULTI_QI *pMQIs //Pointer to first structure in array
);
Parameters
cMQIs
[in] Pointer to the number of elements in an array of MULTI_QI structures, each
of which contains the IID of a single interface.
pMQIs
[in, out] Pointer to the first MULTI_QI strucutre in the array.
Return Value
S_OK
Pointers were returned to all requested interfaces.
S_FALSE
Pointers were returned to some, but not all, of the requested interfaces.
E_NOINTERFACE
Pointers were returned to none of the requested interfaces.
Remarks
The QueryMultipleInterfaces method takes as input an array of MULTI_QI structure
s. Each structure specifies an interface IID and contains two additional blank f
ields for receiving an interface pointer and return value.
This method obtains as many requested interface pointers as possible directly fr
om the object proxy. For each interface not implemented on the proxy, the method
calls the server to obtain a pointer. Upon receiving an interface pointer from
the server, the method builds a corresponding interface proxy and returns its po
inter along with pointers to the interfaces it already implements.
Notes to Callers
A caller should begin by querying the object proxy for the IMultiQI interface. I
f the object proxy returns a pointer to this interface, the caller should then c
reate a MULTI_QI structure for each interface it wants to obtain. Each structure
should specify an interface IID and set its pItf member to NULL. Failure to set
the pItf member to NULL will cause the object proxy to ignore the structure.
On return, QueryMultipleInterfaces writes the requested interface pointer and a
return value into each MULTI_QI structure in the client s array. The pItf field re
ceives the pointer; the hr field receives the return value.
If the value returned from a call to QueryMultipleInterfaces is S_OK, then point
ers were returned for all requested interfaces. If the return value is E_NOINTER
FACE, then pointers were returned for none of the requested interfaces. If the r
eturn value is S_FALSE, then pointers to one or more requested interfaces were n
ot returned.In this event, the client should check the hr field of each MULTI_QI
structure to determine which interfaces were acquired and which were not.
If a client knows ahead of time that it will be using several of an object s inter
faces, it can call QueryMultipleInterfaces up front and then, later, if a QueryI
nterface is done for one of the interfaces already acquired through QueryMultipl
eInterfaces, no RPC call will be necessary.
On return, the caller should check the hr field of each MULTI_QI structure to de
termine which interface pointers were and were not returned.
The client is responsible for releasing each of the acquired interfaces by calli
ng IUnknown::Release.
See Also
IUnknown
7.7 Client Related API Descriptions
7.7.1 CoCreateInstance
Creates a single uninitialized object of the class associated with a specified C
LSID. Call CoCreateInstance when you want to create only one object on the local
system. To create a single object on a remote system, call CoCreateInstanceEx.
To create multiple objects based on a single CLSID, refer to the CoGetClassObjec
t function.
STDAPI CoCreateInstance(
REFCLSID rclsid, //Class identifier (CLSID) of the object
LPUNKNOWN pUnkOuter, //Pointer to whether object is or isn t part of an
aggregate
DWORD dwClsContext, //Context for running executable code
REFIID riid, //Reference to the identifier of the interface
LPVOID * ppv //Address of output variable that receives
// the interface pointer requested in riid
);
Parameters
rclsid
[in] CLSID associated with the data and code that will be used to create the obj
ect.
pUnkOuter
[in] If NULL, indicates that the object is not being created as part of an aggre
gate. If non-NULL, pointer to the aggregate object s IUnknown interface (the contr
olling IUnknown).
dwClsContext
[in] Context in which the code that manages the newly created object will run. T
he values are taken from the enumeration CLSCTX.
riid
[in] Reference to the identifier of the interface to be used to communicate with
the object.
ppv
[out] Address of pointer variable that receives the interface pointer requested
in riid. Upon successful return, *ppv contains the requested interface pointer.
Return Values
S_OK
An instance of the specified object class was successfully created.
REGDB_E_CLASSNOTREG
A specified class is not registered in the registration database. Also can indic
ate that the type of server you requested in the CLSCTX enumeration is not regis
tered or the values for the server types in the registry are corrupt.
CLASS_E_NOAGGREGATION
This class cannot be created as part of an aggregate.
Remarks
The CoCreateInstance helper function provides a convenient shortcut by connectin
g to the class object associated with the specified CLSID, creating an uninitial
ized instance, and releasing the class object. As such, it encapsulates the foll
owing functionality:
CoGetClassObject(rclsid, dwClsContext, NULL, IID_IClassFactory, &pCF);
hresult = pCF->CreateInstance(pUnkOuter, riid, ppvObj)
pCF->Release();
It is convenient to use CoCreateInstance when you need to create only a single i
nstance of an object on the local machine. If you are creating an instance on re
mote machine, call CoCreateInstanceEx. When you are creating multiple instances,
it is more efficient to obtain a pointer to the class object s IClassFactory inte
rface and use its methods as needed. In the latter case, you should use the CoGe
tClassObject function.
In the CLSCTX enumeration, you can specify the type of server used to manage the
object. The constants can be CLSCTX_INPROC_SERVER, CLSTCTX_INPROC_HANDLER, CLSC
TX_LOCAL_SERVER, or any combination of these values. The constant CLSCTX_ALL is
defined as the combination of all three. For more information about the use of o
ne or a combination of these constants, refer to CLSCTX.
See Also
CoGetClassObject, IClassFactory::CreateInstance, CoCreateInstanceEx, CLSCTX, Ins
tance Creation Helper Functions
7.7.2 CoCreateInstanceEx
Creates an instance of a specific class on a specific machine.
HRESULT CoCreateInstanceEx(
REFCLSID rclsid, //CLSID of the object to be created
IUnknown * punkOuter, //If part of an aggregate, the controlling IUnkn
own
DWORD dwClsCtx, //CLSCTX values
COSERVERINFO* pServerInfo, //Machine on which the object is to be instantia
ted
ULONG cmq, //Number of MULTI_QI structures in pResults
MULTI_QI pResults //Array of MULTI_QI structures
);
Parameters
rclsid
[in] CLSID of the object to be created.
punkOuter
[in] When non-NULL, indicates the instance is being created as part of an aggreg
ate, and punkOuter is to be used as the new instance s controlling IUnknown. Aggre
gation is currently not supported cross-process or cross-machine. When instantia
ting an object out of process, CLASS_E_NOAGGREGATION will be returned if punkOut
er is non-NULL.
dwClsCtx
[in] Values taken from the CLSCTX enumeration.
pServerInfo
[in] Machine on which to instantiate the object. May be NULL, in which case the
object is instantiated on the current machine or at the machine specified in the
registry under the class s RemoteServerName named-value, according to the interpr
etation of the dwClsCtx parameter. See the CLSCTX documentation for details).
cmq
[in] Number of MULTI_QI structures in pResults. Must be greater than zero.
pResults
Array of MULTI_QI structures. Each structure has three members: the identifier f
or a requested interface (pIID), the location to return the interface pointer (p
Itf) and the return value of the call to QueryInterface (hr).
Return Values
This function supports the standard return value E_INVALIDARG, as well as the fo
llowing:
S_OK
Indicates success.
CO_S_NOTALLINTERFACES
At least one, but not all of the interfaces requested in the pResults array were
successfully retrieved. The hr field of each of the MULTI_QI structures in pRes
ults indicates with S_OK or E_NOINTERFACE whether the specific interface was ret
urned.
E_NOINTERFACE
None of the interfaces requested in the pResults array were successfully retriev
ed.
Remarks
CoCreateInstanceEx creates a single uninitialized object associated with the giv
en CLSID on a specified remote machine. This is an extension of the function CoC
reateInstance, which creates an object on the local machine only. In addition, r
ather than requesting a single interface and obtaining a single pointer to that
interface, CoCreateInstanceEx makes it possible to specify an array of structure
s, each pointing to an interface identifier (IID) on input, and, on return, cont
aining (if available) a pointer to the requested interface and the return value
of the QueryInterface call for that interface. This permits fewer round trips be
tween machines.
The CoCreateInstanceEx helper function encapsulates three calls: first, to CoGet
ClassObject to connect to the class object associated with the specified CLSID,
specifying the machine location of the class; second, to IClassFactory::CreateIn
stance to create an uninitialized instance, and finally, to IClassFactory::Relea
se, to release the class object.
The object so created must still be initialized through a call to one of the ini
tialization interfaces (such as IPersistStorage:::Load). The two helper function
s, CoGetInstanceFromFile and CoGetInstanceFromIStorage encapsulate both the inst
ance creation and initialization from the obvious sources.
See Also
CoGetInstanceFromFile, CoGetInstanceFromIStorage, CLSCTX, COSERVERINFO, Instance
Creation Helper Functions
7.7.3 CoFreeAllLibraries
Frees all the DLLs that have been loaded with the CoLoadLibrary function (called
internally by CoGetClassObject), regardless of whether they are currently in us
e. This function is usually not called directly, because CoUninitialize and OleU
ninitialize call it internally.
void CoFreeAllLibraries( );
Remarks
To unload libraries, CoFreeAllLibraries uses a list of loaded DLLs for each proc
ess that the COM library maintains. The CoUninitialize function calls CoFreeAllL
ibraries internally, so COM applications usually have no need to call this funct
ion directly.
See Also
CoLoadLibrary, CoFreeLibrary, CoFreeUnusedLibraries, CoGetClassObject, CoUniniti
alize
7.7.4 CoFreeLibrary
Frees a library that, when loaded, was specified to be freed explicitly.
void CoFreeLibrary(
HINSTANCE hInst //Handle of the library module to be freed
);
Parameter
hInst
[in] Handle to the library module to be freed, as returned by CoLoadLibrary.
Remarks
The CoFreeLibrary function should be called to free a library that is to be free
d explicitly. This is established when the library is loaded with the bAutoFree
parameter of CoLoadLibrary set to FALSE. It is illegal to free a library explici
tly when the corresponding CoLoadLibrary call specifies that it be freed automat
ically (the bAutoFree parameter is set to TRUE).
See Also
CoFreeAllLibraries, CoFreeUnusedLibraries, CoLoadLibrary
7.7.5 CoFreeUnusedLibraries
Unloads any DLLs that are no longer in use and that, when loaded, were specified
to be freed automatically.
void CoFreeUnusedLibraries( );
Remarks
Applications can call CoFreeUnusedLibraries periodically to free resources. It i
s most efficient to call it either at the top of a message loop or in some idle-
time task. DLLs that are to be freed automatically have been loaded with the bAu
toFree parameter of the CoLoadLibrary function set to TRUE. CoFreeUnusedLibraries
internally calls DllCanUnloadNow for DLLs that implement and export that function
.
See Also
CoFreeLibrary, CoFreeUnusedLibraries, CoLoadLibrary, DLLCanUnloadNow
7.7.6 CoGetClassObject
Provides a pointer to an interface on a class object associated with a specified
CLSID. CoGetClassObject locates, and if necessary, dynamically loads the execut
able code required to do this.
Call CoGetClassObject directly when you want to create multiple objects through
a class object for which there is a CLSID in the system registry. You can also r
etrieve a class object from a specific remote machine. Most class objects implem
ent the IClassFactory interface. You would then call IClassFactory::CreateInstan
ce to create an uninitialized object. It is not always necessary to go through t
his process. To create a single object, call instead the either the CoCreateInst
anceEx function, which allows you to create an instance on a remote machine. Thi
s replaces the CoCreateInstance function, which can still be used to create an i
nstance on a local machine. Both functions encapsulate connecting to the class o
bject, creating the instance, and releasing the class object. Two other function
s, CoGetInstanceFromFile and CoGetInstanceFromIStorage, provide both instance cr
eation on a remote system, and object activation. COM also provides many other w
ays to create an object in the form of numerous helper functions and interface m
ethods whose function is to create objects of a single type and provide a pointe
r to an interface on that object.
STDAPI CoGetClassObject(
REFCLSID rclsid, //CLSID associated with the class object
DWORD dwClsContext, //Context for running executable code
COSERVERINFO * pServerInfo, //Pointer to machine on which the object is to b
e instantiated
REFIID riid, //Reference to the identifier of the interface
LPVOID * ppv //Address of output variable that receives the
// interface pointer requested in riid
);
Parameters
rclsid
[in] CLSID associated with the data and code that you will use to create the obj
ects.
dwClsContext
[in] Context in which the executable code is to be run. To enable a remote activ
ation, CLSCTX_REMOTE_SERVER must be included. For more information on the contex
t values and their use, see the CLSCTX enumeration.
pServerInfo
[in] Pointer to machine on which to instantiate the class object. May be NULL, i
n which case the class object is instantiated on the current machine or at the m
achine specified under the class s RemoteServerName key in the registry, according
to the interpretation of the dwClsCtx parameter (see the CLSCTX documentation f
or details).
riid
[in] Reference to the identifier of the interface, which will be supplied in ppv
on successful return. This interface will be used to communicate with the class
object. Typically this value is IID_IClassFactory, although other values such a
s IID_IClassFactory2 which supports a form of licensing are allowed. All COM-def
ined interface IIDs are defined in the COM header files as IID_interfacename, wh
ere interfacename is the name of the interface.
ppv
[out] On successful return, indirect pointer to the requested interfaceAddress o
f pointer variable that receives the interface pointer requested in riid. Upon s
uccessful return, *ppv contains the requested interface pointer.
Return Values
S_OK
Location and connection to the specified class object was successful.
REGDB_E_CLASSNOTREG
CLSID is not properly registered. Can also indicate that the value you specified
in dwClsContext is not in the registry.
E_NOINTERFACE
Either the object pointed to by ppv does not support the interface identified by
riid, or the QueryInterface operation on the class object returned E_NOINTERFAC
E.
REGDB_E_READREGDB
Error reading the registration database.
CO_E_DLLNOTFOUND
In-process DLL or handler DLL not found (depends on context).
CO_E_APPNOTFOUND
EXE not found (CLSCTX_LOCAL_SERVER only).
E_ACCESSDENIED
General access failure (returned from LoadLib/CreateProcess).
CO_E_ERRORINDLL
EXE has error in image.
CO_E_APPDIDNTREG
EXE was launched, but it didn t register class object (may or may not have shut do
wn).
Remarks
A class object in COM is an intermediate object that supports an interface that
permits operations common to a group of objects. The objects in this group are i
nstances derived from the same object definition represented by a single CLSID.
Usually, the interface implemented on a class object is IClassFactory, through w
hich you can create object instances of a given definition (class).
A call to CoGetClassObject creates, initializes, and gives the caller access (th
rough a pointer to an interface specified with the riid parameter) to the class
object. The class object is the one associated with the CLSID that you specify i
n the rclsid parameter. The details of how the system locates the associated cod
e and data within a given machine are transparent to the caller, as is the dynam
ic loading of any code that is not already loaded.
If the class context is CLSCTX_REMOTE_SERVER, indicating remote activation is re
quired, the COSERVERINFO structure provided in the pServerInfo parameter allows
you to specify the machine on which the server is located. For information on th
e algorithm used to locate a remote server when pServerInfo is NULL, refer to th
e CLSCTX enumeration.
There are two places to find a CLSID for a given class:
· The registry holds an association between CLSIDs and file suffixes, and between
CLSIDs and file signatures for determining the class of an object.
· When an object is saved to persistent storage, its CLSID is stored with its data
.
To create and initialize embedded or linked COM document objects, it is not nece
ssary to call CoGetClassObject directly. Instead, call one of the OleCreateor Ol
eCreateXxx helper functions. These functions encapsulate the entire object insta
ntiation and initialization process, and call, among other functions, CoGetClass
Object.
The riid parameter specifies the interface the client will use to communicate wi
th the class object. In most cases, this interface is IClassFactory. This provid
es access to the IClassFactory::CreateInstance method, through which the caller
can then create an uninitialized object of the kind specified in its implementat
ion. All classes registered in the system with a CLSID must implement IClassFact
ory.
In rare cases, however, you may want to specify some other interface that define
s operations common to a set of objects. For example, in the way COM implements
monikers, the interface on the class object is IParseDisplayName, used to transf
orm the display name of an object into a moniker.
The dwClsContext parameter specifies the execution context, allowing one CLSID t
o be associated with different pieces of code in different execution contexts. T
he CLSCTX enumeration, defined in Compobj.H, specifies the available context fla
gs. CoGetClassObject consults (as appropriate for the context indicated) both th
e registry and the class objects that are currently registered by calling the Co
RegisterClassObject function.
To release a class object, use the class object s Release method. The function CoR
evokeClassObject is to be used only to remove a class object s CLSID from the syst
em registry.
See Also
CoCreateInstanceEx, CoRegisterClassObject, CoRevokeClassObject, CLSCTX, Creating
an Object through a Class Object
7.7.7 CoGetInstanceFromFile
Creates a new object and initializes it from a file using IPersistFile::Load.
HRESULT CoGetInstanceFromFile(
COSERVERINFO * pServerInfo, //Pointer to COSERVERINFO struct indicat
ing remote system
CLSID* pclsid, //Pointer to the class of the object to create
Iunknown * punkOuter, //If part of an aggregate, pointer to the contro
lling IUnknown
DWORD dwClsCtx, //CLSCTX values
OLECHAR* szName, //File to initialize the object with
ULONG cmq, //Number of MULTI_QI structures in rgmqResults
MULTI_QI * rgmqResults //Array of MULTI_QI structures
);
Parameters
pServerInfo
[in] Pointer to a COSERVERINFO structure that specifies the machine on which to
instantiate the object and the authentication setting to be used. May be NULL, i
n which case the object is instantiated (1) on the current machine, (2) at the m
achine specified under the RemoteServerName named-value for the class in the reg
istry, or (3) at the machine where the szName file resides if the ActivateAtStor
age named-value is specified for the class in the registry or there is no local
registry information.
pclsid
[in] Pointer to the class of the object to create. May be NULL, in which case th
ere is a call to GetClassFile, using szName as its parameter to get the class of
the object to be instantiated.
punkOuter
[in] When non-NULL, indicates the instance is being created as part of an aggreg
ate, and punkOuter is to be used as the pointer to the new instance s controlling
IUnknown. Aggregation is currently not supported cross-process or cross-machine.
When instantiating an object out of process, CLASS_E_NOAGGREGATION will be retu
rned if punkOuter is non-NULL.
dwClsCtx
[in] Values taken from the CLSCTX enumeration.
grfMode
[in] Flags specifying how the file is to be opened. Values are taken from the ST
GM enumeration.
szName
[in] File to initialize the object with using IPersistFile::Load. May not be NUL
L.
cmq
[in] Number of MULTI_QI structures in rgmqResults. Must be greater than zero.
rgmqResults
[in] Array of MULTI_QI structures. Each structure has three members: the identif
ier for a requested interface (pIID), the location to return the interface point
er (pItf) and the return value of the call to QueryInterface (hr).
Return Values
This function supports the standard return value E_INVALIDARG, as well as the fo
llowing:
S_OK
Indicates success.
CO_S_NOTALLINTERFACES
At least one, but not all of the interfaces requested in the rgmqResults array w
ere successfully retrieved. The hr field of each of the MULTI_QI structures in r
gmqResults indicates with S_OK or E_NOINTERFACE whether or not the specific inte
rface was returned.
E_NOINTERFACE
None of the interfaces requested in the rgmqResults array were successfully retr
ieved.
Remarks
CoGetInstanceFromFile creates a new object and initializes it from a file using
IPersistFile::Load. The result of this function is similar to creating an instan
ce with a call to CoCreateInstanceEx, followed by an initializing call to IPersi
stFile::Load, with the following important distinctions:
· Fewer network round trips are required by this function when instantiating an ob
ject on a remote machine.
· In the case where dwClsCtx is set to CLSCTX_REMOTE_SERVER and pServerInfo is NUL
L, if the class is registered with the ActivateAtStorage sub-key or has no assoc
iated registry information, this function will instantiate an object on the mach
ine where szName resides, providing the least possible network traffic. For exam
ple, if szName specified \\myserver\users\johndo\file , the object would be instant
iated on the myserver machine, and the object would access the file directly.
See Also
CoCreateInstanceEx, CoGetInstanceFromIStorage, CLSCTX, Instance Creation Helper
Functions
7.7.8 CoGetInstanceFromIStorage
Creates a new object and initializes it from a storage object through an interna
l call to IPersistStorage::Load.
HRESULT CoGetInstanceFromIStorage(
COSERVERINFO * pServerInfo, //Pointer to COSERVERINFO struct indicating remo
te system
CLSID * pclsid, //Pointer to the CLSID of the object to be created
Iunknown * punkOuter, //If part of an aggregate, pointer to the contro
lling IUnknown
DWORD dwClsCtx, //Values taken from the CLSCTX enumeration
Istorage * pstg, //Pointer to storage from which object is to be initiali
zed
ULONG cmq, //Number of MULTI_QI structures in rgmqResults
MULTI_QI * rgmqResults //Array of MULTI_QI structures
);
Parameters
pServerInfo
[in] Pointer to a COSERVERINFO structure that specifies the machine on which to
instantiate the object and the authentication setting to be used. May be NULL, i
n which case the object is either instantiated (1) on the current machine, (2) a
t the machine specified under the RemoteServerName named-value for the class in
the registry, or (3) at the machine where the storage object pointed to by pstg
is located if the class is registered with ActivateAtStorage specified or has no
local registry information.
pclsid
[in] Pointer to the class identifier (CLSID) of the object to be created. May be
NULL, in which case there is a call to IStorage:Stat to find the class of the o
bject.
punkOuter
[in] When non-NULL, indicates the instance is being created as part of an aggreg
ate, and punkOuter is to be used as the pointer to the new instance s controlling
IUnknown. Aggregation is currently not supported cross-process or cross-machine.
When instantiating an object out of process, CLASS_E_NOAGGREGATION will be retu
rned if punkOuter is non-NULL.
dwClsCtx
Values taken from the CLSCTX enumeration.
pstg
Pointer to storage to initialize the object with using IPersistStorage::Load. Ma
y not be NULL.
cmq
Number of MULTI_QI structures in rgmqResults. Must be greater than zero.
rgmqResults
Array of MULTI_QI structures. Each structure has three members: the identifier f
or a requested interface (pIID), the location to return the interface pointer (p
Itf) and the return value of the call to QueryInterface (hr).
Return Values
This function supports the standard return value E_INVALIDARG, as well as the fo
llowing:
S_OK
Indicates success.
CO_S_NOTALLINTERFACES
At least one, but not all of the interfaces requested in the rgmqResults array w
ere successfully retrieved. The hr field of each of the MULTI_QI structures in r
gmqResults indicates with S_OK or E_NOINTERFACE whether the specific interface p
ointer was retrieved.
E_NOINTERFACE
None of the interfaces requested in the rgmqResults array were successfully retr
ieved.
Remarks
CoGetInstanceFromIStorage creates a new object and initializes it from a storage
object through a call to IPersistStorage::Load. This function is similar to cre
ating an instance using CoCreateInstanceEx followed by a call to IPersistStorage
::Load, with the following important distinctions:
· Fewer network round trips are required by thisfunction when instantiating remote
ly.
· In the case where dwClsCtx is set to CLSCTX_REMOTE_SERVER and pServerInfo is NUL
L, if the class is registered with the ActivateAtStorage named value or has no a
ssociated registry information, this function will instantiate an object on the
same machine where the storage object pointed to by pstg resides, providing the
least possible network traffic. For example, if pstg were obtained through a cal
l to StgCreateDocfile, specifying \\myserver\users\johndo\file , the object would b
e instantiated on the myserver machine, and the object would access the storage ob
ject directly.
See Also
CoCreateInstanceEx, CoGetInstanceFromFile, CLSCTX, Instance Creation Helper Func
tions
7.7.9 CoGetTreatAsClass
Returns the CLSID of an object that can emulate the specified object.
HRESULT CoGetTreatAsClass(
ld, //CLSID of object that is being emulated
LPCLSID pclsidNew //Pointer to CLSID for object that can emulate clsidOld
);
Parameters
clsidOld
[in] CLSID of the object that can be emulated (treated as) an object with a diff
erent CLSID.
pclsidNew
[out] Pointer to where the CLSID that can emulate clsidOld objects is retrieved.
This parameter cannot be NULL. If there is no emulation information for clsidOl
d objects, the clsidOld parameter is supplied.
Return Values
S_OK
A new CLSID was successfully returned.
S_FALSE
No emulation information for the clsidOld parameter and that the pclsidNew param
eter is set to clsidOld.
REGDB_E_READREGDB
An error reading the registry.
This function can also return any of the error values returned by the CLSIDFromS
tring function.
Remarks
CoGetTreatAsClass returns the TreatAs entry in the registry for the specified ob
ject. The TreatAs entry, if set, is the CLSID of a registered object (an applica
tion) that can emulate the object in question. The TreatAs entry is set through
a call to the CoTreatAsClass function. Emulation allows an application to open a
nd edit an object of a different format, while retaining the original format of
the object. Objects of the original CLSID are activated and treated as objects o
f the second CLSID. When the object is saved, this may result in loss of edits n
ot supported by the original format. If there is no TreatAs entry for the specfi
ed object, this function returns the CLSID of the original object (clsidOld).
See Also
CoTreatAsClass
7.7.10 CoIsHandlerConnected
Determines whether a remote object is connected to the corresponding in-process
object.
BOOL CoIsHandlerConnected(
LPUNKNOWN pUnk //Pointer to the remote object
);
Parameter
pUnk
[in] Pointer to the controlling IUnknown interface on the remote object.
Return Values
TRUE
The object is not remote or that it is remote and is still connected to its remo
te handler.
FALSE
The object is remote and is invalid (no longer connected to its remote handler).
Remarks
The CoIsHandlerConnected function determines the status of a remote object. You
can use it to determine when to release a remote object. You specify the remote
object by giving the function a pointer to its controlling IUnknown interface (t
he pUnk parameter). A TRUE returned from the function indicates either that the
specified object is not remote, or that it is remote and is still connected to i
ts remote handler. A FALSE returned from the function indicates that the object
is remote but is no longer connected to its remote handler; in this case, the ca
ller should respond by releasing the object.
7.7.11 CoLoadLibrary
Loads a specific DLL into the caller s process. The CoGetClassObject function call
s CoLoadLibrary internally; applications should not call it directly.
HINSTANCE CoLoadLibrary(
LPOLESTR lpszLibName, //Pointer to the name of the library to be loade
d
BOOL bAutoFree //Whether library is automatically freed
);
Parameters
lpszLibName
[in] Pointer to the name of the library to be loaded. The use of this name is th
e same as in the Win32 function LoadLibrary.
bAutoFree
[in] If TRUE, indicates that this library is freed when it is no longer needed,
through a call to either the CoFreeUnusedLibraries or CoUninitialize functions.
If FALSE, the library should be explicitly freed with the CoFreeLibrary function
.
Return Values
Module Handle
Handle of the loaded library.
NULL
Library could not be loaded.
Remarks
The CoLoadLibrary function is called internally by the CoGetClassObject function
when the class context (CLSCTX) indicates a DLL. CoLoadLibrary loads a DLL spec
ified by the lpszLibName parameter into the process that called CoGetClassObject
. Containers should not call CoLoadLibrary directly.
Internally, a reference count is kept on the loaded DLL, by using CoLoadLibrary
to increment the count and the CoFreeLibrary function to decrement it.
See Also
CoFreeAllLibraries, CoFreeLibrary, CoFreeUnusedLibraries, CoGetClassObject
7.7.13 CoTreatAsClass
Establishes or removes an emulation, in which objects of one class are treated a
s objects of a different class.
STDAPI CoTreatAsClass(
REFCLSID clsidOld, //CLSID for the original object to be emulated
REFCLSID clsidNew //CLSID for the new object that emulates the original
);
Parameters
clsidOld
[in] CLSID of the object to be emulated.
clsidNew
[in] CLSID of the object that should emulate the original object. This replaces
any existing emulation for clsidOld. Can be CLSID_NULL, in which case any existi
ng emulation for clsidOld is removed.
Return Values
This function supports the standard return value E_INVALIDARG, as well as the fo
llowing:
S_OK
The emulation was successfully established or removed.
REGDB_E_CLASSNOTREG
The clsidOld parameter is not properly registered in the registration database.
REGDB_E_READREGDB
Error reading from registration database.
REGDB_E_WRITEREGDB
Error writing to registration database.
Remarks
This function sets the TreatAs entry in the registry for the specified object, a
llowing the object to be emulated by another application. Emulation allows an ap
plication to open and edit an object of a different format, while retaining the
original format of the object. After this entry is set, whenever any function li
ke CoGetClassObject specifies the object s original CLSID (clsidOld), it is transp
arently forwarded to the new CLSID (clsidNew), thus launching the application as
sociated with the TreatAs CLSID. When the object is saved, it can be saved in it
s native format, which may result in loss of edits not supported by the original
format.
You would call CoTreatAsClass in two situations if your application supports emu
lation:
· In response to an end-user request (through a conversion dialog box) that a spec
ified object be treated as an object of a different class (an object created und
er one application be run under another application, while retaining the origina
l format information).
· In a setup program, to register that one class of objects be treated as objects
of a different class.
An example of the first case is that an end user might wish to edit a spreadshee
t created by one application using a different application that can read and wri
te the spreadsheet format of the original application. For an application that s
upports emulation, CoTreatAsClass can be called to implement a Treat As option i
n a conversion dialog box.
An example of the use of CoTreatAsClass in a setup program would be in an update
d version of an application. When the application is updated, the objects create
d with the earlier version can be activated and treated as objects of the new ve
rsion, while retaining the previous format information. This would allow you to
give the user the option to convert when they save, or to save it in the previou
s format, possibly losing format information not available in the older version.
To ensure that existing emulation information is removed when you install an app
lication, your setup programs should call CoTreatAsClass, setting the clsidNew p
arameter to CLSID_NULL to remove any existing emulation for the classes they ins
tall.
If there is no CLSID assigned to the AutoTreatAs key in the registry, setting cl
sidNew and clsidOld to the same value removes the TreatAs entry, so there is no
emulation. If there is a CLSID assigned to the AutoTreatAs key, that CLSID is as
signed to the TreatAs key.
The CoTreatAsClass function does not validate whether an appropriate registry en
try for clsidNew currently exists.
See Also
CoGetTreatAsClass
7.8 COM Client Related Structure Definitions
7.8.1 MULTI_QI
To optimize network performance, most remote activation functions take an array
of MULTI_QI structures rather than just a single IID as input and a single point
er to the requested interface on the object as output, as do local machine activ
ation functions. This allows a set of pointers to interfaces to be returned from
the same object in a single round-trip to the server. In network scenarios, req
uesting multiple interfaces at the time of object construction can save consider
able time over using a number of calls to the QueryInterface method for unique i
nterfaces, each of which would require a round-trip to the server.
typedef struct _MULTI_QI {
const IID* pIID;
IUnknown * pItf;
HRESULT hr;
} MULTI_QI;
Members
pIID
[in] Pointer to an interface identifier.
pItf
[out] Pointer to the interface requested in pIID. Must be set to NULL on entry.
hr
[out] Return value of the QueryInterface call made to satisfy the request for th
e interface requested in pIID. Common return values are S_OK and E_NOINTERFACE.
Must be set to zero on entry.
See Also
CoGetInstanceFromFile, CoGetInstanceFromIStorage, CoCreateInstanceEx
7.9 COM Client Related Enumeration Definitions
7.9.1 CLSCTX
Values from the CLSCTX enumeration are used in activation calls to indicate the
execution contexts in which an object is to be run. These values are also used i
n calls to CoRegisterClassObject to indicate the set of execution contexts in wh
ich a class object is to be made available for requests to construct instances.
typedef enum tagCLSCTX
{
CLSCTX_INPROC_SERVER = 1,
CLSCTX_INPROC_HANDLER = 2,
CLSCTX_LOCAL_SERVER = 4
CLSCTX_REMOTE_SERVER = 16
} CLSCTX;
#define CLSCTX_SERVER (CLSCTX_INPROC_SERVER | CLSCTX_LOCAL_SERVER | CLSCTX_RE
MOTE_SERVER)
#define CLSCTX_ALL (CLSCTX_INPROC_HANDLER | CLSCTX_SERVER)
Elements
CLSCTX_INPROC_SERVER
The code that creates and manages objects of this class runs in the same process
as the caller of the function specifying the class context.
CLSCTX_INPROC_HANDLER
The code that manages objects of this class is an in-process handler. This is a
DLL that runs in the client process and implements client-side structures of thi
s class when instances of the class are accessed remotely.
CLSCTX_LOCAL_SERVER
The EXE code that creates and manages objects of this class is loaded in a separ
ate process space (runs on same machine but in a different process).
CLSCTX_REMOTE_SERVER
A remote machine context. The LocalServer32 or LocalService code that creates an
d manages objects of this class is run on a different machine.
Defined Terms
CLSCTX_SERVER
Indicates server code, whether in-process, local, or remote. This definition ORs
CLSCTX_INPROC_SERVER, CLSCTX_LOCAL_SERVER, and CLSCTX_REMOTE_SERVER.
CLSCTX_ALL
Indicates all class contexts. This definition ORs CLSCTX_INPROC_HANDLER and CLSC
TX_SERVER.
Remarks
Values from the CLSCTX enumeration are used in activation calls (CoCreateInstanc
e, CoCreateInstanceEx, CoGetClassObject, etc.) to indicate the preferred executi
on contexts in-process, local, or remote in which an object is to be run. They a
re also used in calls to CoRegisterClassObject to indicate the set of execution
contexts in which a class object is to be made available for requests to constru
ct instances (IClassFactory::CreateInstance).
To indicate that more than one context is acceptable, you can string multiple va
lues together with Boolean ORs. The contexts are tried in the order in which the
y are listed.
The following table shows how other COM functions and methods that call CoGetCla
ssObject use the CLSCTX values:
Function Called Context Flag Used
CoUnMarshalInterface CLSCTX_INPROC_HANDLER
Unmarshaling needs the form of the class designed for remote access.
IMoniker::BindToObject, for a file moniker created through a call to CreateFileM
oniker In this case, uses CLSCTX_SERVER interally to create the instance after
calling GetClassFile to determine the class to be instantiated.
The CLSCTX_REMOTE_SERVER value is added to the CLSCTX enumeration for distribute
d COM. The CLSCTX_SERVER and CLSCTX_ALL constants are further updated to include
the CLSCTX_REMOTE_SERVER value.
Given a set of CLSCTX flags, dwClsCtx, the execution context to be used depends
on the availability of registered class codes and other parameters according to
the following algorithm:
The first part of the processing determines whether CLSCTX_REMOTE SERVER should
be specified as follows:
1. If the call specifies either
a) an explicit COSERVERINFO structure indicating a machine differen
t from the current machine, or
b) there is no explicit COSERVERINFO structure specified, but the s
pecified class is registered with either the RemoteServerName or ActivateAtStora
ge named-value.
then CLSCTX_REMOTE_SERVER is implied and is added to dwClsCtx. The second case a
llows applications written prior to the release of distributed COM to be the con
figuration of classes for remote activation to be used by client applications av
ailable prior to DCOM and the CLSCTX_REMOTE_SERVER flag. The cases in which ther
e would be no explicit COSERVERINFO structure are 1) The value is specified as N
ULL, or 2) It is not one of the function parameters, as would be the case in cal
ls to CoCreateInstance or CoGetClassObject in existing applications.
2. If the explicit COSERVERINFO parameter indicates the current mac
hine, CLSCTX_REMOTE_SERVER is removed (if present) from dwClsCtx.
The rest of the processing proceeds by looking at the value(s) of dwClsCtx in th
e following sequence.
1. If dwClsCtx includes CLSCTX_REMOTE_SERVER and no COSERVERINFO pa
rameter is specified, if the activation request indicates a persistent state fro
m which to initialize the object (with CoGetInstanceFromFile, CoGetInstanceFromI
Storage, or, for a file moniker, in a call to IMoniker::BindToObject) and the cl
ass has an ActivateAtStorage sub-key or no class registry information whatsoever
, the request to activate and initialize is forwarded to the machine where the p
ersistent state resides. (Refer to the remote activation functions listed in the
See Also section for details.)
2. If dwClsCtx includes CLSCTX_INPROC_SERVER, the class code in the
DLL found under the class s InprocServer32 key is used if this key exists. The cl
ass code will run within the same process as the caller.
3. If dwClsCtx includes CLSCTX_INPROC_HANDLER, the class code in th
e DLL found under the class s InprocHandler32 key is used if this key exists. The
class code will run within the same process as the caller.
4. If dwClsCtx includes CLSCTX_LOCAL_SERVER, the class code in the
Win32 service found under the class s LocalService key is used if this key exists.
If no Win32 service is specified, but an EXE is specified under that same key,
the class code associated with that EXE is used. The class code (in either case)
will be run in a separate service process on the same machine as the caller.
5. If dwClsCtx is set to CLSCTX_REMOTE_SERVER and an additional COS
ERVERINFO parameter to the function specifies a particular remote machine, a req
uest to activate is forwarded to this remote machine with dwClsCtx modified to b
e CLSCTX_LOCAL_SERVER. The class code will run in its own process on this specif
ic machine, which must be different from that of the caller.
6. Finally, if dwClsCtx includes CLSCTX_REMOTE_SERVER and no COSERV
ERINFO parameter is specified, if a machine name is given under the class s Remote
ServerName named-value, the request to activate is forwarded to this remote mach
ine with dwClsCtx modified to be CLSCTX_LOCAL_SERVER. The class code will run in
its own process on this specific machine, which must be different from that of
the caller.
See Also
CoCreateInstance, CoGetClassObject, CoRegisterClassObject, CoGetInstanceFromFile
, CoGetInstanceFromIStorage, CoCreateInstanceEx, COSERVERINFO structure, Creatin
g an Object through a Class Object, Registering a Running EXE Server
8. COM Servers
As described in earlier chapters, a COM Server is some module of code, a DLL or
an EXE, that implements one or more object classes (each with their own CLSID).
A COM server structures the object implementations such that COM clients can cre
ate an use objects from the server using the CLSID to identify the object throug
h the processes described in Chapter 7.
In addition, COM servers themselves may be clients of other objects, usually whe
n the server is using those other objects to help implement part of its own obje
cts. This chapter will cover the various methods of using an object as part of a
nother through the mechanisms of containment and aggregation.
Another feature that servers might support is the ability to emulate a different
server of a different CLSID. The COM Library provides a few API functions to su
pport this capability that are covered at the end of this chapter.
8.1 COM Server Responsibilities
One of the most important ways for a client to get a pointer to an object is for
the client to ask that a server be launched, and that an instance of the object
provided by the server be created and activated. It is the responsibility of th
e server to ensure that this happens properly. There are several important parts
to this.
The server must implement code for a class object through an implementation of e
ither the IClassFactory or IClassFactory2 interface.
The server must register its CLSID in the system registry on the machine on whic
h it resides, and further, has the option of publishing its machine location to
other systems on a network to allow clients to call it without requiring the cli
ent to know the server s location.
The server is primarily responsible for security that is, for the most part, the
server determines whether it will provide a pointer to one of its objects to a
client.
In-process servers should implement and export certain functions that allow the
client process to instantiate them.
8.2 Implementing IClassFactory
When a client uses a CLSID to request the creation of an object instance, the fi
rst step is creation of a class object, an intermediate object that contains an
implementation of the methods of the IClassFactory interface. While COM provides
several instance creation functions, the first step in the implementation of th
ese functions is the creation of a class object.
As a result, all servers must implement the methods of the IClassFactory interfa
ce. This interface contains two methods: CreateInstance and LockServer. CreateIn
stance must create an uninitialized instance of the object, and return a pointer
to a requested interface on the object.
The LockServer method just increments the reference count on the class object to
ensure that the server stays in memory, and does not shut down before the clien
t is ready for it to do so.
To enable a server to be responsible for its own licensing, COM defines IClassFa
ctory2, which inherits its definition from IClassFactory. Thus, a server impleme
nting IClassFactory2 must, by definition, implement the methods of IClassFactory
. For more information on IClassFactory2, see Licensing and IClassFactory2.
COM also provides helper functions for implementing out-of-process servers. For
more information, see Out-of-process Server Implementation Helpers.
8.3 Licensing and IClassFactory2
The IClassFactory interface on a class object provides the basic object creation
mechanism of COM. Using IClassFactory, a server can control object creation on
a machine basis. The implementation of the IClassFactory::CreateInstance method
can allow or disallow object creation based the existence of a machine license.
A machine license is a piece of information separate from the application that e
xists on a machine to indicate that the software was installed from a valid sour
ce, such as the vendor s installation disks. If the machine license does not exist
, the server can disallow object creation. Machine licensing prevents piracy in
cases where a user attempts to copy the software from one machine to another; be
cause the license information is not copied with the software, and the machine t
hat receives the copy is not licensed.
However, in a component software industry, vendors need a finer level of control
over licensing. In addition to machine license control, the a vendor needs to a
llow some clients to create a component object while preventing other clients fr
om the same capability. This kind of licensing requires that the client applicat
ion obtain a license key from component while the client application is still un
der development. The client application uses the license key later at run-time t
o create objects on an unlicensed machine.
For example, if a vendor provides a library of controls to developers, the devel
oper who purchases the library will have a full machine license, allowing the ob
jects to be created on the development machine. The developer can then build a c
lient application on the licensed machine incorporating one or more of the contr
ols. When the resulting client application is run on another machine, the contro
ls used in the client application must be created on the other machine even if t
hat machine does not possess a machine license to the controls from the original
vendor.
The IClassFactory2 interface provides this level of control. To allow key-based
licensing for any given component, you implement IClassFactory2 on the class fac
tory object for that component. IClassFactory2 is derived from IClassFactory, so
by implementing IClassFactory2 the class factory object fulfills the basic COM
requirements.
The GetLicInfo method fills a LICINFO structure with information describing the
licensing behavior of the class factory. For example, the class factory can prov
ide license keys for run-time licensing if the fRunTimeKeyAvail member is TRUE.
The RequestLicKey method provides a license key for the component. A machine lic
ense must be available when the client calls this method.
The CreateInstanceLic method creates an instance of the licensed component if th
e license key parameter (BSTR bstrKey) is valid.
In its type information, a component uses the attribute licensed to mark the coc
lass that supports licensing through IClassFactory2.
To incorporate a licensed component into your client application, you use the me
thods in IClassFactory2.
First, you need a separate development tool that is also a client of the license
d component. The purpose of this tool is to obtain the run-time license key and
save it in your client application. This tool runs only on a machine that posses
ses a machine license for the component. The tool calls the GetLicInfo and Reque
stLicKey methods to obtain the run-time license key and then saves the license k
ey in your client application. For example, the development tool could create a
.H file containing the BSTR license key. Then, you would include that .H file in
your client application.
To instantiate the component within your client application, you first try to in
stantiate the object directly with IClassFactory::CreateInstance. If CreateInsta
nce succeeds, then the second machine is itself licensed for the component and o
bjects can be created at will. If CreateInstance fails with the return code CLAS
S_E_NOTLICENSED, the only way to create the object is to pass the run-time key t
o the CreateInstanceLic method. CreateInstanceLic verifies the key and creates t
he object if the key is valid.
In this way an application built with components (such as controls), can run on
a machine that has no other license only the client application containing the run
-time license is allowed to create the component objects in question.
The IClassFactory2 interface supports flexibility in licensing schemes. For exam
ple, the server implementor can encrypt license keys in the component for added
security. Server implementers can also enable or disable levels of functionality
in their objects by providing different license keys for different functions. F
or example, one key might allow a base level of functionality, while another wou
ld allow basic and advanced functionality, and so on. See OLE Controls Inside Ou
t published by MS Press for detailed consideration of these issues.
8.4 Registering COM Servers
After you have defined a class in code (ensuring that it implements IClassFactor
y or IClassFactory2) and assigned it a CLSID, you need to put information in the
registry that will allow COM, on request of a client with the CLSID, to create
instances of its objects. This information tells the system, for a given CLSID,
where the DLL or EXE code for that class is located, and how it is to be launche
d. There is more than one way of registering a class in the registry. In additio
n, there are other ways of registering a class with the system when it is running,
so the system is aware that a running object is currently in the system. These
topics are described in the following sections.
8.4.1 Registering a Class at Installation
If a class is intended to be available to clients at any time, as most applicati
ons are, you usually register it through an installation and setup program. This
means putting information about the application into the registry, including ho
w and where its objects are to be instantiated. This information must be registe
red for all CLSIDs. Other information is optional. Win32 tools, such as Regsvr32
, make it simple to write a setup program that registers servers at installation
.
If you are not relying on system defaults, there are two important keys in the r
egistry: CLSID and AppID. Among the important pieces of information under these
keys is how the object is to be instantiated. Objects can be designated as in-pr
ocess, out-of-process local, or out-of-process remote.
Under the new AppID key, are several named-values that define information specif
ic to that application. Among these are RemoteServerName, and ActivateAtStorage,
both of which can be used to permit a client with no built-in knowledge of the
location of the server, to create an object. For more information on remote inst
antiation, see Locating a Remote Object and Instance Creation Helper Functions.
A server or ROT object that is not a Win32 service or run under a specific user
account can be referred to as an activate as activator server. For these servers,
the security context and the window station/desktop of the client must match the
server s.
When a class is registered as in-process, a call to CoGetClassObject to create i
ts class object is automatically passed by COM to the DllGetClassObject function
, which the class must implement to give the calling object a pointer to its cla
ss object.
Classes implemented in executables can specify that COM should execute their pro
cess and wait for the process to register their class object s IClassFactory throu
gh a call to the CoRegisterClassObject function.
For detailed COM registry information, see Registering Object Applications.
8.4.2 Registering a Running EXE Server
When an executable (EXE) server is launched, it should call CoRegisterClassObjec
t, which registers the CLSID for the server in what is called the class table (t
his is a different table than the running object table). When a server is regist
ered in the class table, it allows the SCM to determine that it is not necessary
to launch the class again; because the server is already running. Only if the s
erver is not listed in the class table will the SCM check the registry for appro
priate values and launch the server associated with the given CLSID.
You pass CoRegisterClassObject the CLSID for the class and a pointer to its IUnk
nown interface. Clients who subsequently call CoGetClassObject with this CLSID w
ill retrieve a pointer to their requested interface, as long as security does no
t forbid it. There are several instance creation and activation functions descri
bed in Instance Creation Helper Functions.
The server for a class object should call CoRevokeClassObject to revoke the clas
s object (remove its registration) when all of the following are true:
There are no existing instances of the object definition
There are no locks on the class object
The application providing services to the class object is not under user control
(not visible to the user on the display).
8.4.3 Registering Objects in the ROT
Typically, when a client asks a server to create an object instance, the server
typically creates moniker for the object, and registers it in the running object
table (ROT) through a call to IRunningObjectTable::Register.
A few additional issues arise when registering ROT objects for use by remote cli
ents. When the server calls CreateFileMoniker to create a file moniker to be reg
istered in the ROT, servers should pass local file names that are drive-based, n
ot in UNC format. This ensures that the moniker comparison data that is generate
d by the ROT register call will match what is used while doing a ROT lookup on t
he part of a remote client. This is because when the distribed COM service recei
ves an activation request for a file local to the server from a remote client, t
he file is converted to a local-drive-based path.
8.5 Self-Registration
As component software continues to grow as a market, there will be more and more
instances where a user obtains a new software component as a single DLL or EXE
module, such as downloading a new component from an on-line service or receiving
one from a friend on a floppy disk. In these cases, it is not practical to requ
ire the user to go through a lengthy installation procedure or setup program. Be
sides the licensing issues, which are handled through IClassFactory2, an install
ation procedure typically creates the necessary registry entries for a component
to run properly in the COM context.
Self-Registration is the standard means through which a server module can packag
e its own registry operations, both registration and unregistration, into the mo
dule itself. When used with licensing handled through IClassFactory2, a server c
an become an entirely self-contained module with no need for external installati
on programs or .REG files.
Any self-registering module, DLL or EXE, should first include a string called Ol
eSelfRegister in the StringFileInfo section of its version information resource:
The existence of this data allows any interested party, such as an application t
hat wishes to integrate this new component, to determine if the server supports
self-registration without having to load the DLL or EXE first.
If the server is packaged in a DLL module, the DLL must export the functions Dll
RegisterServer and DllUnregisterServer. Any application that wishes to instruct
the server to register itself (that is, all its CLSIDs and type library IDs) can
obtain a pointer to DllRegisterServer through the Win32 API function GetProcAdd
ress. Within DllRegisterServer, the DLL creates all its necessary registry entri
es, storing the correct path to the DLL for all InprocServer32 or InprocHandler3
2 entries.
When an application wishes to remove the component from the system, it should un
register that component by calling DllUnregisterServer. Within this call, the se
rver removes exactly those entries it previously created in DllRegisterServer. T
he server should not blindly remove all entries for its classes because other so
ftware may have stored additional entries, such as a TreatAs key.
If the server is packaged in an EXE module, then the application wishing to regi
ster the server launches the EXE server with the command-line argument /RegServe
r or -RegServer (case-insensitive). If the application wishes to unregister the
server, it launches the EXE with the command-line argument /UnregServer or -Unre
gServer. The self-registering EXE detects these command-line arguments and invok
es the same operations as a DLL would within DllRegisterServer and DllUnregister
Server, respectively, registering its module path under LocalServer32 instead of
InprocServer32 or InprocHandler32.
The server must register the full path to the installation location of the DLL o
r EXE module for their respective InprocServer32, InprocHandler32, and LocalServ
er32 keys in the registry. The module path is easily obtained through the Win32
API function GetModuleFileName.
8.6 Out-of-process Server Implementation Helpers
Four helper functions that can be called by out-of-process servers are now avail
able to simplify the job of writing server code. COM clients and COM in-process
servers typically would not call them. These functions are designed to help prev
ent race conditions in server activation when the servers have multiple apartmen
ts or multiple class objects. They can also, however, as easily be used for sing
le-threaded and single class object servers. The functions are as follows:
CoAddRefServerProcess
CoReleaseServerProcess
CoSuspendClassObjects
CoResumeClassObjects
To shut down properly, a COM server must keep track of how many object instances
it has instantiated and how many times its IClassFactory::LockServer method has
been called. Only when both of these counts reach zero, can a server shut down.
In single-threaded COM servers, the decision to shut down was coordinated with
incoming activation requests by the fact that the requests were serialized by th
e message queue. The server, upon receiving a Release on it s final object instanc
e and deciding to shut down, would revoke its class objects before any more acti
vation requests were dispatched. If an activation request did come in after this
point, COM would recognize that the class objects were revoked, and would retur
n an error to the SCM, which would then cause a new instance of the local server
process to be run.
However, in an apartment model server, in which different class objects are regi
stered on different apartments, and in all free-threaded servers, this decision
to shut down must be co-ordinated with activation requests across multiple threa
ds, so one thread of the server does not decide to shut down while another threa
d of the server is busy handing out class objects or object instances. One class
ical but cumbersome approach to solving this is to have the server, after it has
revoked its class objects, recheck its instance count and stay alive until all
instances have been released.
To make it easier for server writers to handle these types of race conditions, C
OM provides two new reference counting functions. CoAddRefServerProcess incremen
ts a global per-process reference count. CoReleaseServerProcess decrements the g
lobal per-process reference count. When the global per-process reference count r
eaches zero, COM automatically does a CoSuspendClassObjects, which prevents any
new activation requests from coming in. The server can then deregister its vario
us class objects from its various threads at leisure without worry that another
activation request may come in. All new activation requests are henceforth handl
ed by the SCM launching a new instance of the local server process.
The simplest way for a local server application to make use of these APIs is to
call CoAddRefServerProcess in the constructor for each of its instance objects,
and in each of its IClassFactory::LockServer methods when the fLock parameter is
TRUE. The server application should also call CoReleaseServerProcess in the des
tructor of each of its instance objects, and in each of its IClassFactory::LockS
erver methods when the fLock parameter is FALSE.
Finally, the server application should pay attention to the return code from CoR
eleaseServerProcess and if it returns 0, the server application should initiate
its cleanup, which, for a server with multiple threads, typically means that it
should signal it s various threads to exit their message loops and call CoRevokeCl
assObject and CoUninitialize. Note that if these functions are used at all, they
must be used in both the object instances and the LockServer method, otherwise,
the server application may be shut down prematurely.
In the latest versions of Windows NT, when a CoGetClassObject request is made, C
OM contacts the server, marshals the IClassFactory interface of the class object
, returns to the client process, unmarshals the IClassFactory interface, and ret
urns this to the client. At this point, clients typically call IClassFactory::Lo
ckServer(TRUE) to prevent the server process from shutting down. However, there
is a window of time between when the class object is marshaled and when the clie
nt calls LockServer, in which another client could connect to the same server, g
et an instance and Release that instance causing the server to shutdown and leav
ing the first client high and dry with a disconnected IClassFactory pointer. To
prevent this race condition, COM adds an implicit IClassFactory::LockServer(TRUE
) to the class object when it marshals the IClassFactory interface, and an impli
cit IClassFactory::LockServer(FALSE) when the client releases the IClassFactory
interface. Because of this change, it is no longer necessary to remote LockServe
r calls back to the server, so the proxy for IClassFactory::LockServer simply re
turns S_OK without actually remoting the call.
There is another activation-related race condition during initialization of an o
ut-of-process server process. A COM server that registers multiple classes typic
ally calls CoRegisterClassObject(....REGCLS_LOCAL_SERVER) for each CLSID it supp
orts. After it has done this for all classes, the server enters it s message loop.
For a single-threaded COM server, all activation requests are blocked until the
server enters the message loop. However, for an apartment model server that reg
isters different class objects in different apartments, and for all free-threade
d servers, activation requests can arrive earlier than this. In the case of apar
tment model servers, activation requests could arrive as soon as any one thread
has entered its message loop. In the case of free-threaded servers, an activatio
n request could arrive as soon as the first class object is registered. Since an
activation can happen this early, it is also possible for the final Release to
occur (and hence cause the server to begin shutting down) before the rest of the
server has had a chance to finish initializing.
To eliminate these race conditions and simplify the job of the server writer, an
y server that wants to register multiple class objects with COM should call CoRe
gisterClassObject(...., REGCLS_LOCAL_SERVER | REGCLS_SUSPENDED) for each differe
nt CLSID the server supports. After all classes have been registered and the ser
ver process is ready to accept incoming activation requests, the server should m
ake one call to CoResumeClassObjects. This API tells COM to inform the SCM about
all the registered classes, and it begins letting activation requests into the
server process. Using these APIs has serveral advantages. First, only one call i
s made to the SCM regardless of how many CLSIDs are registered, thus reducing th
e overall registration time (and hence startup time of the server application).
The second advantage is that if the server has multiple apartments and different
CLSIDs are registered in different apartments, or if the server is a free-threa
ded server, no activation requests will come in until the server calls CoResumeC
lassObjects, giving the server a chance to register all of its CLSIDs and get pr
operly set up before having to deal with activation requests, and possible shut
down requests.
8.7 Object Handlers
As mentioned earlier this specification, object handlers from one perspective ar
e special cases of in-process servers that talk to their local or remote servers
as well as a client. From a second perspective, an object handler is really jus
t a fancy proxy for a local or remote server that does a little more than just f
orward calls through RPC. The latter view is more precise architecturally: a hand
ler is simply the piece of code that runs in the client s space on behalf of a remo
te object; it can be used synonymously with the term proxy object. The handler may
be a trivial one, one that simply forwards all of its calls on to the remote ob
ject, or it may implement some amount of non-trivial client side processing. (In
practice, the term proxy object is most often reserved for use with trivial handl
ers, leaving handler for the more general situation.)
The structure of an object handler is exactly the same as a full-in process serv
er: an object handler implements an object, a class factory, and the two functio
ns DllGetClassObject and DllCanUnloadNow exactly as described above.
The key difference between handlers and full DLL servers (and simple proxy objec
ts, for that matter) is the extent to which they implement their respective obje
cts. Whereas the full DLL server implements the complete object (using other obj
ects internally, if desired), the handler only implements a partial object depen
ding on a local or remote server to complete the implementation. Again, the reas
ons for this is that sometimes a certain interface can only be useful when imple
mented on an in-process object, such as when member functions of that interface
contain parameters that cannot be shared between processes. Thus the object in t
he handler would implement the restricted in-process interface but leave all oth
ers for implementation in the local or remote server.
8.8 Object Reusability
With object-oriented programming it is often true that there already exists some
object that implements some of what you want to implement, and instead of rewri
ting all that code yourself you would like to reuse that other object for your o
wn implementation. Hence we have the desire for object reusability and a number
means to achieve it such as implementation inheritance, which is exploited in C+
+ and other languages. However, as discussed in the Object Reusability section of
Chapter 3, implementation inheritance has some significant drawbacks and problem
s that do not make it a good object reusability mechanism for a system object mo
del.
For that reason COM supports two notions of object reuse, containment and aggreg
ation, that were also described in Chapter 3. In that chapter we saw that contai
nment, the most common and simplest for of object reuse, is where the outer objec
t simply uses other inner objects for their services. The outer object is nothing m
ore than a client of the inner objects. We also saw in Chapter 3 the notion of a
ggregation, where the outer object exposes interfaces from inner objects as if t
he outer object implemented those interfaces itself. We brought up the catch tha
t there has to be some mechanism through which the IUnknown behavior of inner ob
ject interfaces exposed in this manner is appropriate to the outer object. We ar
e now in a position to see exactly how the solution manifests itself.
The following sections treat Containment and Aggregation in more detail using th
e TextRender object as an example. To refresh our memory of this object s purpose,
the following list reiterates the specific features of the TextRender object th
at implements the IPersistFile and IDataObject interfaces:
Read text from a file through IPersistFile::Load
Write text to a file through IPersistFile::Save
Accept a memory copy of the text through IDataObject::SetData
Render a memory copy of the text through IDataObject::GetData
Render metafile and bitmap images of the text also through IDataObject::GetData
8.8.1 Reusability Through Containment
Let s say that when we decide to implement the TextRender object we find that anot
her object exists with CLSID_TextImage that is capable of accepting text through
IDataObject::SetData but can do nothing more than render a metafile or bitmap f
or that text through IDataObject::GetData. This TextImage object cannot render mem
ory copies of the text and has no concept of reading or writing text to a file.
But it does such a good job implementing the graphical rendering that we wish to
use it to help implement our TextRender object.
In this case the TextRender object, when asked for a metafile or bitmap of its c
urrent text in IDataObject::GetData, would delegate the rendering to the TextIma
ge object. TextRender would first call TextImage s IDataObject::SetData to give it
the most recent text (if it has changed since the last call) and then call Text
Image s IDataObject::GetData asking for the metafile or bitmap format. This delega
tion is illustrated in Figure 8-1.
Figure 8-1: An outer object that uses inner objects through
containment is a client of the inner objects.
To create this configuration, the TextRender object would, during its own creati
on, instantiate the TextImage object with the following code, storing the TextIm
age s IDataObject pointer in a TextImage field m_pIDataObjImage:
//TextRender initialization
HRESULT hr;
hr=CoCreateInstance(CLSID_TextImage, CLSCTX_SERVER, NULL, IID_IDataObject, (void
*)&m_pIDataObjImage);
if (FAILED(hr))
//TextImage not available, either fail or disable graphic rendering
//Success: can now make use of TextImage object.
8.8.2 Reusability Through Aggregation
Let s now say that we are planning to revise our TextRender object at a later time
than out initial containment implementation in the previous section. At that ti
me we find that the implementor of the TextImage object at the time the implemen
tor of the TextRender object sat down to work (or perhaps is making a revision o
f his object) that the vendor of the TextImage object has improved TextImage suc
h that it implements everything that TextRender would like to do through its IDa
taObject interface. That is, TextImage still accepts text through SetData but ha
s recently added the ability to make copies of its text and provide those copies
through GetData in addition to metafiles and bitmaps.
In this case, the implementor of TextRender now sees that TextImage s implementati
on of IDataObject is exactly the implementation that TextRender requires. What w
e, as the implementors of TextRender, would like to do now is simply expose Text
Image s IDataObject as our own as shown in Figure 8-2.
Figure 8-2: When an inner object does a complete job implementing an
interface, outer objects may want to expose the interface directly.
The only catch is that we must implement the proper behavior of the IUnknown mem
bers in the inner object s (TextImage) IDataObject interface: AddRef and Release h
ave to affect the reference count on the outer object (TextRender) and not the r
eference count of the inner object. Furthermore, QueryInterface has to be able t
o return the TextRender object s IPersistFile interface. The solution is to inform
the inner object that it is being used in an aggregation such that when it sees
IUnknown calls to its interfaces it can delegate those calls to the outer objec
t.
One other catch remains: the outer object must have a means to control the lifet
ime of the inner object through AddRef and Release as well as have a means to qu
ery for the interfaces that only exist on the inner object. For that reason, the
inner object must implement an isolated version of IUnknown that controls the i
nner object exclusively and never delegates to the outer object. This requires t
hat the inner object separates the IUnknown members of its functional interfaces
from an implementation of IUnknown that strictly controls the inner object itse
lf. In other words, the inner object, to support aggregation, must implement two
sets of IUnknown functions: delegating and non-delegating.
This, then, is the mechanism for making aggregation work:
When creating the inner object, the outer object must pass its own IUnknown to t
he inner object through the pUnkOuter parameter of IClassFactory::CreateInstance
. pUnkOuter in this case is called the controlling unknown.
The inner object must check pUnkOuter in its implementation of CreateInstance. I
f this parameter is non-NULL, then the inner object knows it is being created as
part of an aggregate. If the inner object does not support aggregation, then it
must fail with CLASS_E_NOAGGREGATION. If aggregation is supported, the inner ob
ject saves pUnkOuter for later use, but does not call AddRef on it. The reason i
s that the inner object s lifetime is entirely contained within the outer object s l
ifetime, so there is no need for the call and to do so would create a circular r
eference.
If the inner object detects a non-NULL pUnkOuter in CreateInstance, and the call
requests the interface IUnknown itself (as is almost always the case), the inne
r object must be sure to return its non-delegating IUnknown.
If the inner object itself aggregates other objects (which is unknown to the out
er object) it must pass the same pUnkOuter pointer it receives down to the next
inner object.
When the outer object is queried for an interface it exposes from the inner obje
ct, the outer object calls QueryInterface in the non-delegating IUnknown to obta
in the pointer to return to the client.
The inner object must delegate to the controlling unknown, that is, pUnkOuter, a
ll IUnknown calls occurring in any interface it implements other than the non-de
legating IUnknown.
Through these steps, the inner object is made aware of the outer object, obtains
an IUnknown to which it can delegate calls to insure proper behavior of referen
ce counting and QueryInterface, and provides a way for the outer object to contr
ol the inner object s lifetime separately. The mechanism is illustrated in Figure
8-3.
Figure 8-3: Aggregation requires an explicit implementation of IUnknown on the i
nner
object and delegation of IUnknown function of any other interface to the outer o
bject s
IUnknown functions.
Now let s look at how this mechanism manifests in code. First off, the TextRender
object no longer needs it s own IDataObject implementation and can thus remove it
from it s class, but will need to add a member m_pUnkImage to maintain the TextIma
ge s non-delegating IUnknown:
class CTextRender : public IPersistFile {
private:
ULONG m_cRef; //Reference Count
char * m_pszText; //Pointer to allocated t
ext
ULONG m_cchText; //Number of characters i
n m_pszText
IUnknown * m_pUnkImage; //TextImage IUnknown
//Other internal member functions here
public:
[Constructor, Destructor]
//Outer object IUnknown
HRESULT QueryInterface(REFIID iid, void ** ppv);
ULONG AddRef(void);
ULONG Release(void);
//IPersistFile Member overrides
...
};
In the previous section we saw how the TextRender object would create a TextImag
e object for containment using CoCreateInstance with the pUnkOuter parameter set
to NULL. In aggregation, this parameter will be TextRender s own IUnknown (obtain
ed using a typecast). Furthermore, TextRender must request IUnknown initially fr
om TextImage (storing the pointer in m_pUnkImage):
//TextRender initialization
HRESULT hr;
hr=CoCreateInstance(CLSID_TextImage, CLSCTX_ SERVER, (IUnknown *)this, IID_IUnkn
own, (void *)&m_pUnkImage);
if (FAILED(hr))
//TextImage not available, either fail or disable graphic rendering
//Success: can now make use of TextImage object.
Now, since TextRender does not have it s own IDataObject any longer, its implement
ation of QueryInterface will use m_pUnkImage to obtain interface pointers:
HRESULT CTextRender::QueryInterface(REFIID iid, void ** ppv) {
*ppv=NULL;
//This code assumes an overloaded == operator for GUIDs exists
if (IID_IUnknown==iid)
*ppv=(void *)(IUnknown *)this;
if (IID_IPersitFile==iid)
*ppv=(void *)(IPersistFile *)this;
if (IID_IDataObject==iid)
return m_pUnkImage->QueryInterface(iid, ppv);
if (NULL==*ppv)
return E_NOINTERFACE; //iid not supported.
//Any call to anyone s AddRef is our own.
AddRef();
return NOERROR;
}
Note that delegating QueryInterface to the inner object is done only for those i
nterfaces that the outer object knows it wants to expose. The outer object shoul
d not delegate the query as a default case, for such blind forwarding without an
understanding of the semantic being forwarded will almost assuredly break the o
uter object should the inner one be revised with new functionality.
8.8.2.1 Caching interfaces on the inner object
In order to avoid reference counting cycles, special action is needed if the out
er object wishes to cache pointers to the inner object s interfaces.
Specifically, if the outer object wishes to cache a to an inner object s interface
, once it has obtained the interface from the inner object, the outer object sho
uld invoke Release on the punkOuter that was given to the inner object at its in
stantiation time.
// Obtaining inner object interface pointer
pUnkInner->QueryInterface(IID_IFoo, &pIFoo);
pUnkOuter->Release();
// Releasing inner object interface pointer
pUnkOuter->AddRef();
pIFoo->Release();
It is suggested that to allow inner objects to do better resource management tha
t controlling objects delay the acquisition of cached pointers and release them
when there is no possible use for them.
8.8.2.2 Efficiency at any Depth of Aggregation
Aggregation has one interesting aspect when aggregates are used on more than one
level of an object implementation. Imagine that the TextImage object in the pre
vious example is itself an aggregate object that uses other inner objects. In su
ch a case TextImage will be passing some controlling unknown to those other inne
r objects. If TextImage is not being aggregated by anyone else, then the control
ling unknown is its own; otherwise it passes the pUnkOuter from IClassFactory::C
reateInstance on down the line, and any other inner objects that are aggregates
themselves do the same.
The net result is that any object in an aggregation, no matter how deeply it is
buried in the overall structure, will almost always delegate directly to the con
trolling unknown if it s interface is exposed from that final outer object. Theref
ore performance and efficiency of multiple levels of aggregation is not an issue
. At worst each delegation is a single extra function call.
8.9 Emulating Other Servers
The final topic related to COM Servers for this chapter is what is known as emul
ation: the ability for one server associated with one CLSID to emulate a server
of another CLSID. A server that can emulate another is responsible for providing
compatible behavior for a different class through a different implementation. T
his forms the basis for allowing end-users the choice in which servers are used
for which objects, as long as the behavior is compatible between those servers.
As far as COM is concerned, it only has to provide some way for a server to indi
cate that it wishes to emulate some CLSID. To that end, the COM Library supplies
the function CoTreatAsClass to establish an emulation that remains in effect (p
ersistently) until canceled or changed. In addition it supplies CoGetTreatAsClas
s to allow a caller to determine if a given CLSID is marked for emulation.
8.10 COM Server Related Interface Descriptions
8.10.1 ICatRegister
The ICatRegister interface provides methods for registering and unregistering co
mponent category information in the Registry. This includes both the human-reada
ble names of categories and the categories implemented/required by a given compo
nent or class.
8.10.1.1.1 When to Implement
There is no need to implement this interface. The Component Category Manager, a
system-provided COM object that can be instantiated by using CoCreateInstance, i
mplements ICatRegister.
8.10.1.1.2 When to Use
The owner of a category uses this interface to register or unregister the human-
readable names. The owner of a component uses this interface to add or remove ca
tegories implemented or required by this component.
Methods in Vtable Order
IUnknown Methods Description
QueryInterface Returns pointers to supported interfaces.
AddRef Increments reference count.
Release Decrements reference count.
ICatRegister Methods Description
RegisterCategories Registers one or more component categories.
UnRegisterCategories Removes the registration of one or more component catego
ries.
RegisterClassImplCategories Registers the class as implementing one or more
component categories.
UnRegisterClassImplCategories Removes one or more implemented category identif
iers from a class.
RegisterClassReqCategories Registers the class as requiring one or more com
ponent categories.
UnRegisterClassReqCategories Removes one or more required category identifier
s from a class.
8.10.1.2 ICatRegister::RegisterCategories
Registers one or more component categories. Each component category consists of
a CATID and a list of locale-dependent description strings.
HRESULT RegisterCategories(
8.10.1.3 ICatRegister::RegisterClassImplCategories
Registers the class as implementing one or more component categories.
HRESULT RegisterClassImplCategories(
REFCLSID rclsid, //Class ID of the relevent class
ULONG cCategories, //Number of category CATIDs
CATID* rgcatid //Array of cCategories CATID
);
Parameters
rclsid
[in] The class ID of the relevent class for which category information will be s
et.
cCategories
[in] The number of category CATIDs to associate as category identifiers for the
class.
rgcatid
[in] The array of cCategories CATID to associate as category identifiers for the
class.
Return Values
S_OK
The function was successful.
E_INVALIDARG
One or more arguments are incorrect.
Remarks
In case of an error, this function does not ensure that the Registry is restored
to the state prior to the call. This function can only be called by the owner o
f a class, usually as part of the installation of the component.
See Also
ICatRegister::RegisterCategories, ICatRegister::RegisterClassReqCategories, ICat
Register::UnRegisterCategories, ICatRegister::UnRegisterClassImplCategories, ICa
tRegister::UnRegisterClassReqCategories
8.10.1.4 ICatRegister::RegisterClassReqCategories
Registers the class as requiring one or more component categories.
HRESULT RegisterClassReqCategories(
REFCLSID rclsid, //Class ID of the relevent class
ULONG cCategories, //Number of category CATIDs
CATID* rgcatid //Array of cCategories CATID
);
Parameters
rclsid
[in] The class ID of the relevent class for which category information will be s
et.
cCategories
[in] The number of category CATIDs to associate as category identifiers for the
class.
rgcatid
[in] The array of cCategories CATID to associate as category identifiers for the
class.
Return Values
S_OK
The function was successful.
E_INVALIDARG
One or more arguments are incorrect.
Remarks
In case of an error, this function does not ensure that the Registry is restored
to the state prior to the call. This function can only be called by the owner o
f a class, usually as part of the installation of the component.
See Also
ICatRegister::RegisterCategories, ICatRegister::RegisterClassImplCategories, ICa
tRegister::UnRegisterCategories, ICatRegister::UnRegisterClassImplCategories, IC
atRegister::UnRegisterClassReqCategories
8.10.1.5 ICatRegister::UnRegisterCategories
Removes the registration of one or more component categories. Each component cat
egory consists of a CATID and a list of locale-dependent description strings.
HRESULT UnRegisterCategories(
ULONG cCategories, //Number of cCategories CATIDs to be removed
REFCATID rgcatid //Array of cCategories CATIDs
);
Parameters
cCategories
[in] The number of cCategories CATIDs to be removed.
rgcatid
[in] Identifies the categories to be removed.
Return Values
S_OK
The function was successful.
E_INVALIDARG
One or more arguments are incorrect.
Remarks
This function will be successful even if one or more of the category IDs specifi
ed are not registered. This function can only be called by the owner of a catego
ry, usually as part of the installation or de-installation of the operating syst
em or application.
Note
This method does not remove the component category tags from individual classes.
To do this, use the ICatRegister::UnRegisterClassCategories method.
See Also
ICatRegister::RegisterCategories, ICatRegister::RegisterClassImplCategories, ICa
tRegister::RegisterClassReqCategories, ICatRegister::UnRegisterClassImplCategori
es, ICatRegister::UnRegisterClassReqCategories
8.10.1.6 ICatRegister::UnRegisterClassImplCategories
Removes one or more implemented category identifiers from a class.
HRESULT UnRegisterClassImplCategories(
REFCLSID rclsid, //Class ID of the relevent class
ULONG cCategories, //Number of category CATIDs
CATID* rgcatid //Array of cCategories CATID
);
Parameters
rclsid
[in] The class ID of the relevant class to be manipulated.
cCategories
[in] The number of category CATIDs to remove.
rgcatid
[in] The array of cCategories CATID that are to be removed. Only the category ID
s specified in this array are removed.
Return Values
S_OK
The function was successful.
E_INVALIDARG
One or more arguments are incorrect.
Remarks
In case of an error, this function does not ensure that the Registry is restored
to the state prior to the call. The call will be successful even if one or more
of the category IDs specified are not registered for the class. This function c
an only be called by the owner of a class, usually as part of the de-installatio
n of the component.
See Also
ICatRegister::RegisterCategories, ICatRegister::RegisterClassImplCategories, ICa
tRegister::RegisterClassReqCategories, ICatRegister::UnRegisterCategories, ICatR
egister::UnRegisterClassReqCategories
8.10.1.7 ICatRegister::UnRegisterClassReqCategories
Removes one or more required category identifiers from a class.
HRESULT UnRegisterClassReqCategories(
REFCLSID rclsid, //Class ID of the relevent class
ULONG cCategories, //Number of category CATIDs
CATID* rgcatid* //Array of cCategories CATID
);
Parameters
rclsid
[in] The class ID of the relevent class to be manipulated.
cCategories
[in] The number of category CATIDs to remove.
rgcatid
[in] The array of cCategories CATID that are to be removed. Only the category ID
s specified in this array are removed.
Return Values
S_OK
The function was successful.
E_INVALIDARG
One or more arguments are incorrect.
Remarks
In case of an error, this function does not ensure that the Registry is restored
to the state prior to the call. The call will be successful even if one or more
of the category IDs specified are not registered for the class.
See Also
ICatRegister::RegisterCategories, ICatRegister::RegisterClassImplCategories, ICa
tRegister::UnRegisterCategories, ICatRegister::UnRegisterClassImplCategories, IC
atRegister::RegisterClassReqCategories
8.10.2 IClassFactory
The IClassFactory interface contains two methods intended to deal with an entire
class of objects, and so is implemented on the class object for a specific clas
s of objects (identified by a CLSID). The first method, CreateInstance, creates
an uninitialized object of a specified CLSID, and the second, LockServer, locks
the object s server in memory, allowing new objects to be created more quickly.
8.10.2.1 When to Implement
You must implement this interface for every class that you register in the syste
m registry and to which you assign a CLSID, so objects of that class can be crea
ted.
8.10.2.2 When to Use
After calling the CoGetClassObject function to get an IClassFactory interface po
inter to the class object, call the CreateInstance method of this interface to c
reate a new uninitialized object.
It is not, however, always necessary to go through this process to create an obj
ect. To create a single uninitialized object, you can, instead, just call CoCrea
teInstance. COM also provides numerous helper functions (with names of the form
OleCreateXxx) to create compound document objects.
Call the LockServer method to keep the object server in memory and enhance perfo
rmance only if you intend to create more than one object of the specified class.
Methods in Vtable Order
IUnknown Methods Description
QueryInterface Returns pointers to supported interfaces.
AddRef Increments reference count.
Release Decrements reference count.
IClassFactory Methods Description
CreateInstance Creates an uninitialized object.
LockServer Locks object application open in memory.
See Also
CoGetClassObject, CoCreateInstance
8.10.2.3 IClassFactory::CreateInstance
Creates an uninitialized object.
HRESULT CreateInstance(
IUnknown * pUnkOuter, //Pointer to whether object is or isn t part of an
aggregate
REFIID riid, //Reference to the identifier of the interface
void ** ppvObject //Indirect pointer to the interface
);
Parameters
pUnkOuter
[in] If the object is being created as part of an aggregate, pointer to the cont
rolling IUnknown interface of the aggregate. Otherwise, pUnkOuter must be NULL.
riid
[in] Reference to the identifier of the interface to be used to communicate with
the newly created object. If pUnkOuter is NULL, this parameter is frequently th
e IID of the initializing interface; if pUnkOuter is non-NULL, riid must be IID_
IUnknown (defined in the header as the IID for IUnknown).
ppvObject
[out] Indirect pointer to the requested interface. If the object does not suppor
t the interface specified in riid, ppvObject must be set to NULL.
Return Values
This method supports the standard return values E_UNEXPECTED, E_OUTOFMEMORY, and
E_INVALIDARG, as well as the following:
S_OK
The specified object was created.
CLASS_E_NOAGGREGATION
The pUnkOuter parameter was non-NULL and the object does not support aggregation
.
E_NOINTERFACE
The object that ppvObject points to does not support the interface identified by
riid.
Remarks
The IClassFactory interface is always on a class object. The CreateInstance meth
od creates an uninitialized object of the class identified with the specified CL
SID. When an object is created in this way, the CLSID must be registered in the
system registry with CoRegisterClassObject.
The pUnkOuter parameter indicates whether the object is being created as part of
an aggregate. Object definitions are not required to support aggregation they m
ust be specifically designed and implemented to support it.
The riid parameter specifies the IID (interface identifier) of the interface thr
ough which you will communicate with the new object. If pUnkOuter is non-NULL (i
ndicating aggregation), the value of the riid parameter must be IID_IUnknown. If
the object is not part of an aggregate, riid often specifies the interface thou
gh which the object will be initialized.
For COM embeddings, the initialization interface is IPersistStorage, but in othe
r situations, other interfaces are used. To initialize the object, there must be
a subsequent call to an appropriate method in the initializing interface. Commo
n initialization functions include IPersistStorage::InitNew (for new, blank embe
ddable components), IPersistStorage::Load (for reloaded embeddable components),
IPersistStream::Load, (for objects stored in a stream object) or IPersistFile::L
oad (for objects stored in a file).
In general, if an application supports only one class of objects, and the class
object is registered for single use, only one object can be created. The applica
tion must not create other objects, and a request to do so should return an erro
r from IClassFactory::CreateInstance. The same is true for applications that sup
port multiple classes, each with a class object registered for single use; a Cre
ateInstance for one class followed by a CreateInstance for any of the classes sh
ould return an error.
To avoid returning an error, applications that support multiple classes with sin
gle-use class objects can revoke the registered class object of the first class
by calling CoRevokeClassObject when a request for instantiating a second is rece
ived. For example, suppose there are two classes, A and B. When IClassFactory::C
reateInstance is called for class A, revoke the class object for B. When B is cr
eated, revoke the class object for A. This solution complicates shutdown because
one of the class objects might have already been revoked (and cannot be revoked
twice).
See Also
CoRegisterClassObject, CoRevokeClassObject, CoCreateInstance, CoGetClassObject
8.10.2.4 IClassFactory::LockServer
Called by the client of a class object to keep a server open in memory, allowing
instances to be created more quickly.
HRESULT LockServer(
BOOL fLock //Increments or decrements the lock count
);
Parameter
fLock
[in] If TRUE, increments the lock count; if FALSE, decrements the lock count.
Return Values
This method supports the standard return values E_FAIL, E_OUTOFMEMORY, and E_UNE
XPECTED, as well as the following:
S_OK
The specified object was either locked ( fLock = TRUE) or unlocked from memory (
fLock = FALSE).
Remarks
IClassFactory::LockServer controls whether an object s server is kept in memory. K
eeping the application alive in memory allows instances to be created more quick
ly.
8.10.2.4.1 Notes to Callers
Most clients do not need to call this function. It is provided only for those cl
ients that require special performance in creating multiple instances of their o
bjects.
8.10.2.4.2 Notes to Implementers
If the lock count is zero, there are no more objects in use, and the application
is not under user control, the server can be closed. One way to implement IClas
sFactory::LockServer is to call CoLockObjectExternal.
The process that locks the object application is responsible for unlocking it. O
nce the class object is released, there is no mechanism that guarantees the call
er connection to the same class later (as in the case where a class object is re
gistered as single-use). It is important to count all calls, not just the last o
ne, to IClassFactory::LockServer, because calls must be balanced before attempti
ng to release the pointer to the IClassFactory interface on the class object or
an error results. For every call to LockServer with fLock set to TRUE, there mus
t be a call to LockServer with fLock set to FALSE. When the lock count and the c
lass object reference count are both zero, the class object can be freed.
See Also
CoLockObjectExternal
8.10.3 IClassFactory2
The IClassFactory2 interface enables a class factory object, in any sort of obje
ct server, to control object creation through licensing. This interface is an ex
tension to IClassFactory. This extension enables a class factory executing on a
licensed machine to provide a license key that can be used later to create an ob
ject instance on an unlicensed machine. Such considerations are important for ob
jects like controls that are used to build applications on a licensed machine. S
ubsequently, the application built must be able to run on an unlicensed machine.
The license key gives only that one client application the right to instantiate
objects through IClassFactory2 when a full machine license does not exist.
8.10.3.1.1 When to Implement
Implement this interface on a class factory object if you need to control object
creation through a license. A class that supports licensing should be marked in
an object s type information with the [licensed] attribute on the object s coclass
entry.
The CreateInstance method inherited from IClassFactory is allowed to return CLAS
S_E_NOTLICENSED to indicate that object creation is controlled through licensing
. The caller can create an instance of this object only through IClassFactory2::
CreateInstanceLic if the caller has a license key obtained from IClassFactory2::
RequestLicKey. Otherwise, no object creation is allowed.
8.10.3.1.2 When to Use
Use this interface to create licensed objects or to obtain a license key that ca
n be used in later creations.
Methods in Vtable Order
IUnknown Methods Description
QueryInterface Returns pointers to supported interfaces.
AddRef Increments reference count.
Release Decrements reference count.
IClassFactory Methods Description
CreateInstance Creates an uninitialized object.
LockServer Locks object application open in memory.
IClassFactory2 Methods Description
GetLicInfo Fills a LICINFO structure with information on the licensing capa
bilities of this class factory.
RequestLicKey Creates and returns a license key that the caller can save and u
se later in calls to IClassFactory2::CreateInstanceLic.
CreateInstanceLic Creates an instance of the licensed object given a licen
se key from IClassFactory2::RequestLicKey.
See Also
IClassFactory
8.10.3.2 IClassFactory2::CreateInstanceLic
Creates an instance of the object class supported by this class factory, given a
license key previously obtained from IClassFactory2::RequestLicKey. This method
is the only possible means to create an object on an otherwise unlicensed machi
ne.
HRESULT CreateInstanceLic(
IUnknown* pUnkOuter, //Pointer to controlling unknown of aggregated o
bject
IUnknown* pUnkReserved, //Unused. Must be NULL.
REFIID riid, //Reference to the identifier of the interface
BSTR bstrKey, //License key provided by IClassFactory2::RequestLicKey
void** ppvObject //Indirect pointer to the interface of the type specifie
d in riid
);
Parameters
pUnkOuter
[in] Pointer to the controlling IUnknown interface on the outer unknown if this
object is being created as part of an aggregate. If the object is not part of an
aggregate, this parameter must be NULL.
pUnkReserved
[in] Unused. Must be NULL.
riid
[in] Reference to the identifier of the interface to be used to communicate with
the newly created object.
bstrKey
[in] Run-time license key previously obtained from IClassFactory2::RequestLicKey
that is required to create an object.
ppvObject
[out] Indirect pointer to the interface of the type specified in riid. This para
meter is set to NULL on failure.
Return Values
This method supports the standard return values E_INVALIDARG, E_OUTOFMEMORY, and
E_UNEXPECTED, as well as the following:
S_OK
The license was successfully created.
E_NOTIMPL
This method is not implemented because objects can only be created on fully lice
nsed machines through IClassFactory::CreateInstance.
E_POINTER
The pointers passed in bstrKey or ppvObject are not valid. For example, it may b
e NULL.
E_NOINTERFACE
The object can be created (and the license key is valid) except the object does
not support the interface specified by riid.
CLASS_E_NOAGGREGATION
The pUnkOuter parameter is non-NULL, but this object class does not support aggr
egation.
CLASS_E_NOTLICENSED
The key provided in bstrKey is not a valid license key.
Remarks
8.10.3.2.1 Notes to Implementers
If the class factory does not provide a license key (that is, IClassFactory2::Re
questLicKey returns E_NOTIMPL and the fRuntimeKeyAvail field in LICINFO is set t
o FALSE in IClassFactory2::GetLicInfo), then this method can also return E_NOTIM
PL. In such cases, the class factory is implementing IClassFactory2 simply to sp
ecify whether or not the machine is licensed at all through the fLicVerified fie
ld of LICINFO.
See Also
IClassFactory2::GetLicInfo, IClassFactory2::RequestLicKey, LICINFO
8.10.3.3 IClassFactory2::GetLicInfo
Fills a caller-allocated LICINFO structure with information describing the licen
sing capabilities of this class factory.
HRESULT GetLicInfo(
LICINFO* pLicInfo //Pointer to the structure
);
Parameters
pLicInfo
[out] Pointer to the caller-allocated LICINFO structure to be filled on output.
Return Values
This method supports the standard return value E_UNEXPECTED, as well as the foll
owing:
S_OK
The LICINFO structure was successfully filled in.
E_POINTER
The address in pLicInfo is not valid. For example, it may be NULL.
Remarks
8.10.3.3.1 Notes to Implementers
E_NOTIMPL is not allowed as a return value since this method provides critical i
nformation for the client of a licensed class factory.
See Also
IClassFactory2::CreateInstanceLic, IClassFactory2::RequestLicKey, LICINFO
8.10.3.4 IClassFactory2::RequestLicKey
If the fRuntimeKeyAvail field in LICINFO has been returned as TRUE from IClassFa
ctory2::GetLicInfo, then this method creates and returns a license key. The call
er can save the license key persistently and use it later in calls to IClassFact
ory2::RequestLicKey.
HRESULT RequestLicKey(
DWORD dwReserved , //Unused. Must be zero.
BSTR* pbstrKey //Pointer to the license key
);
Parameters
dwReserved
[in] Unused. Must be zero.
pbstrKey
[out] Pointer to the caller-allocated BSTR variable that receives the callee-all
ocated license key on successful return from this method. This parameter is set
to NULL on any failure.
Return Values
This method supports the standard return values E_INVALIDARG, E_OUTOFMEMORY, and
E_UNEXPECTED, as well as the following:
S_OK
The license key was successfully created.
E_NOTIMPL
This class factory does not support run-time license keys.
E_POINTER
The address in pbstrKey is not valid. For example, it may be NULL.
CLASS_E_NOTLICENSED
This class factory supports run-time licensing, but the current machine itself i
s not licensed. Thus, a run-time key is not available on this machine.
Remarks
The caller can save the license key for subsequent calls to IClassFactory2::Crea
teInstanceLic to create objects on an otherwise unlicensed machine.
8.10.3.4.1 Notes to Callers
The caller must free the BSTR with SysFreeString when the key is no longer neede
d. The value of fRuntimeKeyAvail is returned through a previous call to IClassFa
ctory2::GetLicInfo.
8.10.3.4.2 Notes to Implementers
This method allocates the BSTR key with SysAllocString or SysAllocString[Len], a
nd the caller becomes responsible for this BSTR once this method returns success
fully.
This method need not be implemented when a class factory does not support run-ti
me license keys.
See Also
IClassFactory2::CreateInstanceLic, IClassFactory2::GetLicInfo, LICINFO
8.10.4 IExternalConnection
The IExternalConnection interface enables an embedded object to keep track of ex
ternal locks on it, thereby enabling the safe and orderly shutdown of the object
following silent updates. An object that supports links either to itself or to
some portion of itself (a range of cells in a spreadsheet, for example) should i
mplement this interface to prevent possible loss of data during shutdown.
Such data loss can occur when an object happens to have unsaved changes at a tim
e when its stub manager s count of strong external references has reached zero. Th
is situation would arise, for example, at the end of a silent update, when the f
inal link client breaks its connection to the object. With the severing of this
connection, the stub manager s count of strong external references would reach zer
o, causing it to release its pointers to an interface on the object and initiate
shutdown of the object.
If the object manages its own count of external locks, rather than relying on th
e stub manager to do so, it can save its data before the stub manager has a chan
ce to release its pointers. An object can obtain a count of external connections
by implementing the IExternalConnection interface. The stub manager calls this
interface whenever a new strong external reference is added or deleted. The obje
ct combines this count with its own tally of strong internal references to maint
ain an accurate total of all locks.
8.10.4.1.1 When to Implement
All embeddable compound-document objects that support links to themselves or por
tions of themselves should implement IExternalConnection to prevent possible dat
a loss during shutdown. In addition, an in-place container should call OleLockRu
nning to hold a strong lock on its embedded objects.
8.10.4.1.2 When to Use
An object s stub manager should call IExternalConnection whenever an external conn
ection is added or released.
Methods in VTable Order
IUnknown Methods Description
QueryInterface Returns pointers to supported interfaces.
AddRef Increments reference count.
Release Decrements reference count.
IExternalConnection Methods Description
AddConnection Increments count of external locks.
ReleaseConnection Decrements count of external locks.
8.10.4.2 IExternalConnection::AddConnection
Increments an object s count of its strong external connections (links).
HRESULT AddConnection(
DWORD exconn, //Type of external connection
DWORD dwreserved //Used by COM to pass connection information
);
Parameters
exconn
[in] Type of external connection to the object. The only type of external connec
tion currently supported by this interface is strong, which means that the objec
t must remain alive as long as this external connection exists. Strong external
connections are represented by the value EXTCONN_STRONG = 0x0001, which is defin
ed in the enumeration EXTCONN.
dwreserved
[in] Passes information about the connection. This parameter is reserved for use
by COM. Its value can be zero, but not necessarily. Therefore, implementations
of AddConnection should not contain blocks of code whose execution depends on wh
ether a zero value is returned.
Return Value
DWORD value
The number of reference counts on the object; used for debugging purposes only.
Remarks
An object created by a EXE object server relies on its stub manager to call IExt
ernalConnection::AddConnection whenever a link client activates and therefore cr
eates an external lock on the object. When the link client breaks the connection
, the stub manager calls IExternalConnection::ReleaseConnection to release the l
ock.
Since DLL object applications exist in the same process space as their objects,
they do not use RPC (remote procedure calls) and therefore do not have stub mana
gers to keep track of external connections. Therefore, DLL servers that support
external links to their objects must implement IExternalConnection so link clien
ts can directly call the interface to inform them when connections are added or
released.
The following is a typical implementation for the AddConnection method:
DWORD XX::AddConnection(DWORD extconn, DWORD dwReserved)
{
return extconn&EXTCONN_STRONG ? ++m_cStrong : 0;
}
See Also
IExternalConnection::ReleaseConnection, IRunnableObject::LockRunning
8.10.4.3 IExternalConnection::ReleaseConnection
Decrements an object s count of its strong external connections (references).
HRESULT ReleaseConnection(
DWORD extconn, //Type of external connection
DWORD dwreserved, //Used by COM to pass connection information
BOOL fLastReleaseCloses //Indicates whether connection is last one or no
t
);
Parameters
extconn
[in] Type of external connection to the object. The only type of external connec
tion currently supported by this interface is strong, which means that the objec
t must remain alive as long as this external connection exists. Strong external
connections are represented by the value EXTCONN_STRONG = 0x0001, which is defin
ed in the enumeration EXTCONN.
dwreserved
[in] Passes information about the connection. This parameter is reserved for use
by COM. Its value can be zero, but not necessarily. Therefore, implementations
of ReleaseConnection should not contain blocks of code whose execution depends o
n whether a zero value is returned.
fLastReleaseCloses
[in] TRUE specifies that if the connection being released is the last external l
ock on the object, the object should close. FALSE specifies that the object shou
ld remain open until closed by the user or another process.
Return Value
DWORD value
The number of connections to the object; used for debugging purposes only.
Remarks
If fLastReleaseCloses equals TRUE, calling ReleaseConnection causes the object t
o shut itself down. Calling this method is the only way in which a DLL object, r
unning in the same process space as the container application, will know when to
close following a silent update.
See Also
IExternalConnection::AddConnection
8.11 COM Server Related API Descriptions
8.11.1 CoDisconnectObject
Disconnects all remote process connections being maintained on behalf of all the
interface pointers that point to a specified object. Only the process that actu
ally manages the object should call CoDisconnectObject.
STDAPI CoDisconnectObject(
IUnknown * pUnk, //Pointer to the interface on the object
DWORD dwReserved //Reserved for future use
);
Parameters
pUnk
[in] Pointer to any IUnknown-derived interface on the object to be disconnected.
dwReserved
[in] Reserved for future use; must be zero.
Return Values
S_OK
All connections to remote processes were successfully deleted.
Remarks
The CoDisconnectObject function enables a server to correctly disconnect all ext
ernal clients to the object specified by pUnk.
The CoDisconnectObject function performs the following tasks:
1. Checks to see if the object to be disconnected implements the IM
arshal interface. If so, it gets the pointer to that interface; if not, it gets
a pointer to the standard marshaler s (i.e., COM s) IMarshal implementation.
2. Using whichever IMarshal interface pointer it has acquired, the
function then calls IMarshal::DisconnectObject to disconnect all out-of-process
clients.
An object s client does not call CoDisconnectObject to disconnect itself from the
server (clients should use IUnknown::Release for this purpose). Rather, an COM s
erver calls CoDisconnectObject to forcibly disconnect an object s clients, usually
in response to a user closing the server application.
Similarly, an COM container that supports external links to its embedded objects
can call CoDisconnectObject to destroy those links. Again, this call is normall
y made in response to a user closing the application.
CoDisconnectObject does not necessarily disconnect out-of-process clients immedi
ately. If any marshaled calls are pending on the server object, CoDisconnectObje
ct disconnects the object only when those calls have returned. In the meantime,
CoDisconnectObject sets a flag that causes any new marshaled calls to return CO_
E_OBJECTNOTCONNECTED.
See Also
IMarshal::DisconnectObject
8.11.2 CoLockObjectExternal
Called either to lock an object to ensure that it stays in memory, or to release
such a lock. Call CoLockObjectExternal to place a strong lock on an object to e
nsure that it stays in memory.
STDAPI CoLockObjectExternal(
IUnknown * pUnk, //Pointer to object to be locked or unlocked
BOOL fLock, //TRUE = lock, FALSE = unlock
BOOL fLastUnlockReleases //TRUE = release all pointers to object
);
Parameters
pUnk
[in] Pointer to the IUnknown interface on the object to be locked or unlocked.
fLock
[in] Whether the object is to be locked or released. Specifying TRUE holds a ref
erence to the object (keeping it in memory), locking it independently of externa
l or internal AddRef/Release operations, registrations, or revocations. If fLock
is TRUE, fLastLockReleases is ignored. FALSE releases a lock previously set wit
h a call to this function.
fLastUnlockReleases
[in] Whether a given lock is the last reference that is supposed to keep an obje
ct alive. If it is, TRUE releases all pointers to the object (there may be other
references that are not supposed to keep it alive).
Return Values
This function supports the standard return values E_INVALIDARG, E_OUTOFMEMORY, a
nd E_UNEXPECTED, as well as the following:
S_OK
The object was locked successfully.
Remarks
The CoLockObjectExternal function prevents the reference count of an object from
going to zero, thereby locking it into existence until the lock is released. The
same function (with different parameters) releases the lock. The lock is impleme
nted by having the system call IUnknown::AddRef on the object. The system then w
aits to call IUnknown::Release on the object until a later call to CoLockObjectE
xternal with fLock set to FALSE. This function can be used to maintain a referen
ce count on the object on behalf of the end user, because it acts outside of the
object, as does the user.
The CoLockObjectExternal function must be called in the process in which the obj
ect actually resides (the EXE process, not the process in which handlers may be
loaded).
Calling CoLockObjectExternal sets a strong lock on an object. A strong lock keep
s an object in memory, while a weak lock does not. Strong locks are required, fo
r example, during a silent update to an OLE embedding. The embedded object s conta
iner must remain in memory until the update process is complete. There must also
be a strong lock on an application object to ensure that the application stays
alive until it has finished providing services to its clients. All external refe
rences place a strong reference lock on an object.
The CoLockObjectExternal function is typically called in the following situation
s:
· Object servers should call CoLockObjectExternal with both fLock and fLastLockRel
eases set to TRUE when they become visible. This call creates a strong lock on b
ehalf of the user. When the application is closing, free the lock with a call to
CoLockObjectExternal, setting fLock to FALSE and fLastLockReleases to TRUE.
· A call to CoLockObjectExternal on the server can also be used in the implementat
ion of IOleContainer::LockContainer.
There are several things to be aware of when you use CoLockObjectExternal in the
implementation of IOleContainer::LockContainer. An embedded object would call I
OleContainer::LockContainer on its container to keep it running (to lock it) in
the absence of other reasons to keep it running. When the embedded object become
s visible, the container must weaken its connection to the embedded object with
a call to the OleSetContainedObject function, so other connections can affect th
e object.
Unless an application manages all aspects of its application and document shutdo
wn completely with calls to CoLockObjectExternal, the container must keep a priv
ate lock count in IOleContainer::LockContainer so that it exits when the lock co
unt reaches zero and the container is invisible. Maintaining all aspects of shut
down, and thereby avoiding keeping a private lock count, means that CoLockObject
External should be called whenever one of the following conditions occur:
· A document is created and destroyed or made visible or invisible.
· An application is started and shut down by the user.
· A pseudo-object is created and destroyed.
For debugging purposes, it may be useful to keep a count of the number of extern
al locks (and unlocks) set on the application.
Note
The end user has explicit control over the lifetime of an application, even if t
here are external locks on it. That is, if a user decides to close the applicati
on (File, Exit), it must shut down. In the presence of external locks (such as t
he lock set by CoLockObjectExternal), the application can call the CoDisconnectO
bject function to force these connections to close prior to shutdown.
8.11.3 CoRevokeClassObject
Informs COM that a class object, previously registered with the CoRegisterClassO
bject function, is no longer available for use.
HRESULT CoRevokeClassObject(
DWORD dwRegister //Token on class object
);
Parameter
dwRegister
[in] Token previously returned from the CoRegisterClassObject function.
Return Values
This function supports the standard return values E_INVALIDARG,
E_OUTOFMEMORY, and E_UNEXPECTED, as well as the following:
S_OK
The class object was successfully revoked.
Remarks
A successful call to CoRevokeClassObject means that the class object has been re
moved from the global class object table (although it does not release the class
object). If other clients still have pointers to the class object and have caus
ed the reference count to be incremented by calls to IUnknown::AddRef, the refer
ence count will not be zero. When this occurs, applications may benefit if subse
quent calls (with the obvious exceptions of IUnknown::AddRef and IUnknown::Relea
se) to the class object fail.
An object application must call CoRevokeClassObject to revoke registered class o
bjects before exiting the program. Class object implementers should call CoRevok
eClassObject as part of the release sequence. You must specifically revoke the c
lass object even when you have specified the flags value REGCLS_SINGLEUSE in a c
all to CoRegisterClassObject, indicating that only one application can connect t
o the class object.
See Also
CoGetClassObject, CoRegisterClassObject
8.11.4 CoRegisterClassObject
Registers an EXE class object with COM so other applications can connect to it.
EXE object applications should call CoRegisterClassObject on startup. It can als
o be used to register internal objects for use by the same EXE or other code (su
ch as DLLs) that the EXE uses.
STDAPI CoRegisterClassObject(
REFCLSID rclsid, //Class identifier (CLSID) to be registered
IUnknown * pUnk, //Pointer to the class object
DWORD dwClsContext, //Context for running executable code
DWORD flags, //How to connect to the class object
LPDWORD * lpdwRegister //Pointer to the value returned
);
Parameters
rclsid
[in] CLSID to be registered.
pUnk
[in] Pointer to theIUnknown interface on the class object whose availability is
being published.
dwClsContext
[in] Context in which the executable code is to be run. For information on these
context values, see the CLSCTX enumeration.
flags
[in] How connections are made to the class object. For information on these flag
s, see the REGCLS enumeration.
lpdwRegister
[out] Pointer to a value that identifies the class object registered; later used
by the CoRevokeClassObject function to revoke the registration.
Return Values
This function supports the standard return values E_INVALIDARG, E_OUTOFMEMORY, a
nd E_UNEXPECTED, as well as the following:
S_OK
The class object was registered successfully.
CO_E_OBJISREG
Already registered in the class object table.
Remarks
Only EXE object applications call CoRegisterClassObject. Object handlers or DLL
object applications do not call this function instead, they must implement and e
xport the DllGetClassObject function.
At startup, a multiple-use EXE object application must create a class object (wi
th the IClassFactory interface on it), and call CoRegisterClassObject to registe
r the class object. Object applications that support several different classes (
such as multiple types of embeddable objects) must allocate and register a diffe
rent class object for each.
Multiple registrations of the same class object are independent and do not produ
ce an error. Each subsequent registration yields a unique key in lpdwRegister.
Multiple document interface (MDI) applications must register their class objects
. Single document interface (SDI) applications must register their class objects
only if they can be started by means of the /Embedding switch.
The server for a class object should call CoRevokeClassObject to revoke the clas
s object (remove its registration) when all of the following are true:
· There are no existing instances of the object definition
· There are no locks on the class object
· The application providing services to the class object is not under user control
(not visible to the user on the display).
After the class object is revoked, when its reference count reaches zero, the cl
ass object can be released, allowing the application to exit.
For information on the flags parameter, refer to the REGCLS enumeration.
See Also
CoGetClassObject, CoRevokeClassObject, DllGetClassObject, REGCLS, CLSCTX
8.11.5 DllCanUnloadNow
Determines whether the DLL that implements this function is in use. If not, the
caller can safely unload the DLL from memory.
Note
COM does not provide this function. DLLs that support the Component Object Model
(COM) should implement and export DllCanUnloadNow.
STDAPI DllCanUnloadNow();
Return Values
S_OK
The DLL can be unloaded.
S_FALSE
The DLL cannot be unloaded now.
Remarks
A call to DllCanUnloadNow determines whether the DLL from which it is exported i
s still in use. A DLL is no longer in use when it is not managing any existing o
bjects (the reference count on all of its objects is 0).
8.11.5.1 Notes to Callers
You should not have to call DllCanUnloadNow directly. COM calls it only through
a call to the CoFreeUnusedLibraries function. When it returns S_OK, CoFreeUnused
Libraries safely frees the DLL.
8.11.5.2 Notes to Implementers
You need to implement DllCanUnloadNow in, and export it from, DLLs that are to b
e dynamically loaded through a call to the CoGetClassObject function. (You also
need to implement and export the DllGetClassObject function in the same DLL).
If a DLL loaded through a call to CoGetClassObject fails to export DllCanUnloadN
ow, the DLL will not be unloaded until the application calls the CoUninitialize
function to release the COM libraries.
If the DLL links to another DLL, returning S_OK from DllCanUnloadNow will also c
ause the second, dependent DLL to be unloaded. To eliminate the possibility of a
crash, the primary DLL should call the CoLoadLibrary function, specifying the p
ath to the second DLL as the first parameter, and setting the auto free paramete
r to TRUE. This forces the COM library to reload the second DLL and set it up fo
r a call to CoFreeUnusedLibraries to free it separately when appropriate.
DllCanUnloadNow should return S_FALSE if there are any existing references to ob
jects that the DLL manages.
See Also
DllGetClassObject
8.11.6 DllGetClassObject
Retrieves the class object from a DLL object handler or object application. DllG
etClassObject is called from within the CoGetClassObject function when the class
context is a DLL.
Note
COM does not provide this function. DLLs that support the Component Object Model
(COM) must implement DllGetClassObject in COM object handlers or DLL applicatio
ns.
STDAPI DllGetClassObject(
REFCLSID rclsid, //CLSID for the class object
REFIID riid, //Reference to the identifier of the interface that comm
unicates with the class object
LPVOID * ppv //Address of output variable that receives the
// interface pointer requested in riid
);
Parameters
rclsid
[in] CLSID that will associate the correct data and code.
riid
[in] Reference to the identifier of the interface that the caller is to use to c
ommunicate with the class object. Usually, this is IID_IClassFactory (defined in
the COM headers as the interface identifier for IClassFactory).
ppv
[out] Address of pointer variable that receives the interface pointer requested
in riid. Upon successful return, *ppv contains the requested interface pointer.
If an error occurs, the interface pointer is NULL.
Return Values
This function supports the standard return values E_INVALIDARG, E_OUTOFMEMORY an
d E_UNEXPECTED, as well as the following:
S_OK
The object was retrieved successfully.
CLASS_E_CLASSNOTAVAILABLE
The DLL does not support the class (object definition).
Remarks
If a call to the CoGetClassObject function finds the class object that is to be
loaded in a DLL, CoGetClassObject uses the DLL s exported DllGetClassObject functi
on.
8.11.6.1 Notes to Callers
You should not call DllGetClassObject directly. When an object is defined in a D
LL, CoGetClassObject calls the CoLoadLibrary function to load the DLL, which, in
turn, calls DllGetClassObject.
8.11.6.2 Notes to Implementers
You need to implement DllGetClassObject in (and export it from) DLLs that suppor
t the Component Object Model.
Example
Following is an example (in C++) of an implementation of DllGetClassObject. In t
his example, DllGetClassObject creates a class object and calls its QueryInterfa
ce method to retrieve a pointer to the interface requested in riid. The implemen
tation safely releases the reference it holds to the IClassFactory interface bec
ause it returns a reference-counted pointer to IClassFactory to the caller.
HRESULT_export PASCAL DllGetClassObject
(REFCLSID rclsid, REFIID riid, LPVOID * ppvObj)
{
HRESULT hres = E_OUTOFMEMORY;
*ppvObj = NULL;
CClassFactory *pClassFactory = new CClassFactory(rclsid);
if (pClassFactory != NULL) {
hRes = pClassFactory->QueryInterface(riid, ppvObj);
pClassFactory->Release();
}
return hRes;
}
See Also
CoGetClassObject, DllCanUnloadNow
8.11.7 DllRegisterServer
Instructs an in-process server to create its registry entries for all classes su
pported in this server module. If this function fails, the state of the registry
for all its classes is indeterminate.
STDAPI DllRegisterServer(void);
Return Values
This function supports the standard return values E_OUTOFMEMORY and E_UNEXPECTED
, as well as the following:
S_OK
The registry entries were created successfully.
SELFREG_E_TYPELIB
The server was unable to complete the registration of all the type libraries use
d by its classes.
SELFREG_E_CLASS
The server was unable to complete the registration of all the object classes.
Remarks
E_NOTIMPL is not a valid return code.
See Also
DllUnregisterServer
8.11.8 DllUnregisterServer
Instructs an in-process server to remove only those entries created through DllR
egisterServer.
STDAPI DllUnregisterServer(void);
Return Values
This function supports the standard return values E_OUTOFMEMORY and E_UNEXPECTED
, as well as the following:
S_OK
The registry entries were created successfully.
S_FALSE
Unregistration of this server s known entries was successful, but other entries st
ill exist for this server s classes.
SELFREG_E_TYPELIB
The server was unable to remove the entries of all the type libraries used by it
s classes.
SELFREG_E_CLASS
The server was unable to remove the entries of all the object classes.
Remarks
The server must not disturb any entries that it did not create which currently e
xist for its object classes. For example, between registration and unregistratio
n, the user may have specified a TreatAs relationship between this class and ano
ther. In that case, unregistration can remove all entries except the TreatAs key
and any others that were not explicitly created in DllRegisterServer. The Win32
registry functions specifically disallow the deletion of an entire populated tr
ee in the registry. The server can attempt, as the last step, to remove the CLSI
D key, but if other entries still exist, the key will remain.
See Also
DllRegisterServer
8.11.9 CoAddRefServerProcess
Increments a global per-process reference count.
ULONG CoAddRefServerProcess(void);
Return Values
S_OK
The CLSID was retrieved successfully.
Remarks
Servers can call CoAddRefServerProcess to increment a global per-process referen
ce count. This function is particularly helpful to servers that are implemented
with multiple threads, either multi-apartmented or free-threaded. Servers of the
se types must coordinate the decision to shut down with activation requests acro
ss multiple threads. Calling CoAddRefServerProcess increments a global per-proce
ss reference count, and calling CoReleaseServerProcess decrements that count.
When that count reaches zero, COM automatically calls CoSuspendClassObjects, whi
ch prevents new activation requests from coming in. This permits the server to d
eregister its class objects from its various threads without worry that another
activation request may come in. New activation requests result in launching a ne
w instance of the local server process.
The simplest way for a local server application to make use of these API functio
ns is to call CoAddRefServerProcess in the constructor for each of it s instance o
bjects, and in each of its IClassFactory::LockServer methods when the fLock para
meter is TRUE. The server application should also call CoReleaseServerProcess in
the destruction of each of its instance objects, and in each of its IClassFacto
ry::LockServer methods when the fLock parameter is FALSE. Finally, the server ap
plication should pay attention to the return code from CoReleaseServerProcess an
d if it returns 0, the server application should initiate its cleanup, which, fo
r a server with multiple threads, typically means that it should signal its var
ious threads to exit their message loops and call CoRevokeClassObject and CoUnin
itialize.
If these APIs are used at all, they must be called in both the object instances
and the LockServer method, otherwise the server application may be shut down pre
maturely. In-process servers typically should not call CoAddRefServerProcess or
CoReleaseServerProcess.
See Also
CoReleaseServerProcess, IClassFactory::LockServer, Out-of-process Server Impleme
ntation Helpers
8.11.10 CoReleaseServerProcess
Decrements the global per-process reference count
ULONG CoReleaseServerProcess(void);
Return Values
0
The server application should initiate its cleanup.
Other values
Server application should not yet initiate its cleanup.
Remarks
Servers can call CoReleaseServerProcess to decrement a global per-process refere
nce count incremented through a call to CoAddRefServerProcess
When that count reaches zero, COM automatically calls CoSuspendClassObjects, whi
ch prevents new activation requests from coming in. This permits the server to d
eregister its class objects from its various threads without worry that another
activation request may come in. New activation requests result in launching a ne
w instance of the local server process.
The simplest way for a local server application to make use of these API functio
ns is to call CoAddRefServerProcess in the constructor for each of its instance
objects, and in each of its IClassFactory::LockServer methods when the fLock par
ameter is TRUE. The server application should also call CoReleaseServerProcess i
n the destruction of each of its instance objects, and in each of its IClassFact
ory::LockServer methods when the fLock parameter is FALSE. Finally, the server a
pplication must check the return code from CoReleaseServerProcess; if it returns
0, the server application should initiate its cleanup. This typically means tha
t a server with multiple threads should signal its various threads to exit their
message loops and call CoRevokeClassObject and CoUninitialize.
If these APIs are used at all, they must be called in both the object instances
and the LockServer method, otherwise the server application may be shutdown prem
aturely. In-process Servers typically should not call CoAddRefServerProcess or C
oReleaseServerProcess.
See Also
CoSuspendClassObjects, CoReleaseServerProcess, IClassFactory::LockServer, Out-of
-process Server Implementation Helpers
8.11.11 CoResumeClassObjects
Called by a server that can register multiple class objects to inform the COM SC
M about all registered classes, and permits activation requests for those class
objects.
WINOLEAPI CoResumeClassObjects(void);
Return Values
S_OK
The CLSID was retrieved successfully.
Remarks
Servers that can register multiple class objects call CoResumeClassObjects once,
after having first called CoRegisterClassObject, specifying REGCLS_LOCAL_SERVER
| REGCLS_SUSPENDED for each CLSID the server supports. This function causes COM
to inform the SCM about all the registered classes, and begins letting activati
on requests into the server process.
This reduces the overall registration time, and thus the server application star
tup time, by making a single call to the SCM, no matter how many CLSIDs are regi
stered for the server. Another advantage is that if the server has multiple apar
tments with different CLSIDs registered in different apartments, or is a free-th
readed server, no activation requests will come in until the server calls CoRes
umeClassObjects. This gives the server a chance to register all of its CLSIDs an
d get properly set up before having to deal with activation requests, and possib
ly shutdown requests.
See Also
CoRegisterClassObject, CoSuspendClassObjects, Out-of-process Server Implementati
on Helpers
8.11.12 CoSuspendClassObjects
Prevents any new activation requests from the SCM on all class objects registere
d within the process.
WINOLEAPI CoSuspendClassObjects(void);
Return Values
S_OK
The CLSID was retrieved successfully.
Remarks
CoSuspendClassObjects prevents any new activation requests from the SCM on all c
lass objects registered within the process. Even though a process may call this
API, the process still must call CoRevokeClassObject for each CLSID it has regis
tered, in the apartment it registered in. Applications typically do not need to
call this API, which is generally only called internally by COM when used in con
junction with CoReleaseServerProcess.
See Also
CoRevokeClassObject, CoReleaseServerProcess, Out-of-process Server Implementatio
n Helpers
8.12 COM Server Related Structure Definitions
8.12.1 LICINFO
The LICINFO structure contains parameters that describe the licensing behavior o
f a class factory that supports licensing. The structure is filled during the IC
lassFactory2::GetLicInfo method.
typedef struct tagLICINFO
{
ULONG cbLicInfo;
BOOL fRuntimeKeyAvail;
BOOL fLicVerified;
} LICINFO;
Members
cbLicInfo
Size of the LICINFO structure.
fRuntimeKeyAvail
Whether this class factory allows the creation of its objects on a unlicensed ma
chine through the use of a license key. If TRUE, IClassFactory2::RequestLicKey c
an be called to obtain the key. If FALSE, objects can be created only on a fully
licensed machine.
fLicVerified
Whether a full machine license exists so that calls to IClassFactory::CreateInst
ance and IClassFactory2::RequestLicKey will succeed. If TRUE, the full machine l
icense exists. Thus, objects can be created freely. and a license key is availab
le if fRuntimeKeyAvail is also TRUE. If FALSE, this class factory cannot create
any instances of objects on this machine unless the proper license key is passed
to IClassFactory2::CreateInstanceLic.
See Also
IClassFactory::CreateInstance, IClassFactory2::CreateInstanceLic, IClassFactory2
::GetLicInfo, IClassFactory2::RequestLicKey
8.13 COM Server Related Enumeration Definitions
8.13.1 REGCLS
The REGCLS enumeration defines values used in CoRegisterClassObject to control t
he type of connections to a class object. It is defined as follows:
typedef enum tagREGCLS
{
REGCLS_SINGLEUSE = 0,
REGCLS_MULTIPLEUSE = 1,
REGCLS_MULTI_SEPARATE = 2,
REGCLS_SUSPENDED = 4,
REGCLS_SURROGATE = 8,
} REGCLS;
Elements
REGCLS_SINGLEUSE
Once an application is connected to a class object with CoGetClassObject, the cl
ass object is removed from public view so that no other applications can connect
to it. This value is commonly used for single document interface (SDI) applicat
ions. Specifying this value does not affect the responsibility of the object app
lication to call CoRevokeClassObject; it must always call CoRevokeClassObject wh
en it is finished with an object class.
REGCLS_MULTIPLEUSE
Multiple applications can connect to the class object through calls to CoGetClas
sObject. If both the REGCLS_MULTIPLEUSE and CLSCTX_LOCAL_SERVER are set in a cal
l to CoRegisterClassObject, the class object is also automatically registered as
an in-process server, whether or not CLSCTX_INPROC_SERVER is explicitly set.
REGCLS_MULTI_SEPARATE
Multiple applications can connect to the class object through calls to CoGetClas
sObject. If REGCLS_MULTI_SEPARATE is set, each execution context must be set sep
arately: CoRegisterClassObject does not automatically register an out-of-process
server (for which CLSCTX_LOCAL_SERVER is set) as an in-process server. When a c
lass object is registered with only the REGCLS_MULTI_SEPARATE and CLSCTX_LOCAL_S
ERVER flags set and the server tries to bind to an object with its own CLSID, an
other instance of the server is started.
REGCLS_SUSPENDED
Suspends registration and activation requests for the specified CLSID until ther
e is a call to CoResumeClassObjects. This is used typically to register the CLSI
Ds for servers that can register multiple class objects to reduce the overall re
gistration time, and thus the server application startup time, by making a singl
e call to the SCM, no matter how many CLSIDs are registered for the server.
REGCLS_SURROGATE
The class object is a surrogate process used to run DLL servers. The class facto
ry registered by the surrogate process is not the actual class factory implement
ed by the DLL server, but a generic class factory implemented by the surrogate.
This generic class factory delegates instance creation and marshaling to the cla
ss factory of the DLL server running in the surrogate.
Remarks
In CoRegisterClassObject, members of both the REGCLS and the CLSCTX enumerations
, taken together, determine how the class object is registered.
An EXE surrogate (in which DLL servers are run) calls CoRegisterClassObject to r
egister a class factory using a new REGCLS value, REGCLS_SURROGATE.
The following table summarizes the allowable REGCLS value combinations and the o
bject registrations affected by the combinations.
REGCLS_
SINGLEUSE
REGCLS_
MULTIPLEUSE REGCLS_
MULTI_
SEPARATE
Other
CLSCTX_
INPROC_
SERVER Error In-process In-process Error
CLSCTX_
LOCAL_
SERVER Local In-process/ local Local Error
Both of the above Error In-process/ local In-process/ local
Error
Other Error Error Error Error
All class factories for dll surrogates should be registered with REGCLS_SURROGAT
E set. Do not set REGCLS_SINGLUSE or REGCLS_MULTIPLEUSE when you register a sur
rogate for DLL servers.
See Also
CoGetClassObject, CoRegisterClassObject, CoRevokeClassObject, DllGetClassObject,
9. Interface Remoting and Marshaling
In COM, clients communicate with objects solely through the use of vtable-based
interface instances. The state of the object is manipulated by invoking function
s on those interfaces. For each interface method, the object provides an impleme
ntation that does the appropriate manipulation of the object internals.
Interface remoting provides the infrastructure and mechanisms to allow a method
invocation to return an interface pointer to an object that is in a different pr
ocess, perhaps even on a different machine. The infrastructure that performs the
remoting of interfaces is transparent to both the client and the object server.
Neither the client or object server is necessarily aware that the other party i
s in fact in a different process.
This chapter first explains how interface remoting works giving mention to the i
nterfaces and COM API functions involved. The specifications for the interfaces
and the API functions themselves are given later in this chapter. There is also
a brief discussion about concurrency management at the end of the chapter that i
nvolves an interface called IMessageFilter.
9.1 How Interface Remoting Works
The crux of the problem to be addressed in interface remoting can be stated as f
ollows:
Given an already existing remoted-interface connection between a client process a
nd a server process, how can a method invocation through that connection return
a new interface pointer so as to create a second remoted-interface connection be
tween the two processes?
We state the problem in this way so as to avoid for the moment the issue of how
an initial connection is made between the client and the server process; we will
return to that later.
Let s look at an example. Suppose we have an object in a server process which supp
orts an interface IFoo, and that interface of the object (and IUnknown) has some
time in the past been remoted to a client process through some means not here sp
ecified. In the client process, there is an object proxy which supports the exac
t same interfaces as does the original server object, but whose implementations
of methods in those interfaces are special, in that they forward calls they rece
ive on to calls on the real method implementations back in the server object. We s
ay that the method implementations in the object proxy marshal the data, which i
s then conveyed to the server process, where it is unmarshaled. That is, marshali
ng refers to the packaging up of method arguments for transmission to a remote pr
ocess; unmarshaling refers to the unpackaging of this data at the receiving end. N
otice that in a given call, the method arguments are marshaled and unmarshaled i
n one direction, while the return values are marshaled and unmarshaled in the ot
her direction.
For concreteness, let us suppose that the IFoo interface is defined as follows:
interface IFoo : IUnknown {
HRESULT ReturnABar([out]IBar **ppBar);
};
If the in the client process pFoo->ReturnABar(&pBar) is invoked, then the object
proxy will forward this call on to the IFoo::ReturnABar() method in the server
object, which will do whatever this method is supposed to do in order to come up
with some appropriate IBar*. The server object is then required to return this
IBar* back to the client process. The act of doing this will end up creating a s
econd connection between the two processes:
It is the procedure by which this second connection is established which is the
subject of our discussion here. This process involves two steps:
1. On the server side, the IBar* is packaged or marshaled into a data packe
t.
2. The data packet is conveyed by some means to the client process, where t
he data it contains is unmarshaled to create the new object proxy.
The term marshaling is a general one that is applied in the industry to the packag
ing of any particular data type, not just interface pointers, into a data packet
for transmission through an RPC infrastructure. Each different data type has di
fferent rules for how it is to marshaled: integers are to be stored in a certain
way, strings are to be stored in a certain way, etc. Likewise, marshaled interf
ace pointers are to be stored in a certain way; the Component Object Model funct
ion CoMarshalInterface() contains the knowledge of how this is to be done (note
that we will in this document not mention further any kind of marshaling other t
han marshaling of interface pointers; that subject is well-explored in existing
RPC systems).
The process begins with the code doing the marshaling of the returned IBar* inte
rface. This code has in hand a pointer to an interface that it knows in fact to
be an IBar* and that it wishes to marshal. To do so it calls CoMarshalInterface(
). The first step in CoMarshalInterface() involves finding out whether the objec
t of which this is an interface in fact supports custom object marshaling (often
simply referred to as custom marshaling ). Custom object marshaling is a mechanism
that permits an object to be in control of creation of remote object proxies to
itself. In certain situations, custom object marshaling can be used to create a
more efficient object proxy than would otherwise be the case. Use of custom mar
shaling is completely optional on the object s part; if the object chooses not to
support custom marshaling, then standard interface marshaling is used to marshal
the IBar*. Standard interface marshaling uses a system-provided object proxy im
plementation (called the proxy manager) in the client process. This standard imp
lementation is a generic piece of code, in that it can be used as the object pro
xy for any interface on any object. However, the act of marshaling (and unmarsha
ling) method arguments and return values is inherently interface-specific, since
it is highly sensitive to the semantics and data types used in the particular m
ethods in question. To accommodate this, the standard implementation dynamically
loads in interface-specific pieces of code as needed in order to do the paramet
er marshaling.
We shall discuss in great detail in a moment how standard interface marshaling w
orks. First, however, we shall review custom object marshaling, as this provides
a solid framework in which standard marshaling can be better understood.
9.2 Architecture of Custom Object Marshaling
Imagine that we are presently in a piece of code whose job it is to marshal an i
nterface pointer that it has in hand. For clarity, in what follows we ll refer to
this piece of code as the original marshaling stub. The general case is that the o
riginal marshaling stub does not statically know the particular interface identi
fier (IID) to which the pointer conforms; the IID may be passed to this code as
a second parameter. This is a common paradigm in the Component Object Model. Ext
ant examples of this paradigm include:
IUnknown::QueryInterface(REFIID riid, void** ppvObject);
IOleItemContainer::GetObject(..., REFIID riid, void** ppvObject);
IClassFactory::CreateInstance(..., REFIID riid, void** ppvNewlyCreatedObject);
Let us assume the slightly less general case where the marshaling stub in fact d
oes know a little bit about the IID: that the interface in fact derives from IUn
known. This is a requirement for remoting: it is not possible to remote interfac
es which are not derived from IUnknown.
To find out whether the object to which it has an interface supports custom mars
haling, the original marshaling stub simply does a QueryInterface() for the inte
rface IMarshal. That is, an object signifies that it wishes to do custom marshal
ing simply by implementing the IMarshal interface. IMarshal is defined as follows
:
[
local,
object,
uuid(00000003-0000-0000-C000-000000000046)
]
interface IMarshal : IUnknown {
HRESULT GetUnmarshalClass ( [in] REFIID riid, [in, unique] void *pv,
[in] DWORD dwDestContext, [in, unique] void *pvDestContext,
[in] DWORD mshlflags, [out] CLSID *pCid);
HRESULT GetMarshalSizeMax ([in] REFIID riid, [in, unique] void *pv,
[in] DWORD dwDestContext, [in, unique] void *pvDestContext,
[in] DWORD mshlflags, [out] DWORD *pSize);
HRESULT MarshalInterface ([in, unique] IStream *pStm, [in] REFIID riid,
[in, unique] void *pv,
[in] DWORD dwDestContext, [in, unique] void *pvDestContext, [in]
DWORD mshlflags);
HRESULT UnmarshalInterface ( [in, unique] IStream *pStm, [in] REFIID rii
d, [out] void **ppv);
HRESULT ReleaseMarshalData ( [in, unique] IStream *pStm);
HRESULT DisconnectObject ( [in] DWORD dwReserved);
}
The idea is that if the object says Yes, I do want to do custom marshaling that th
e original marshaling stub will use this interface in order to carry out the tas
k. The sequence of steps that carry this out is:
Using GetUnmarshalClass, the original marshaling stub asks the object which kind
of (i.e.: which class of) proxy object it would like to have created on its beh
alf in the client process.
(optional on the part of the marshaling stub) Using GetMarshalSizeMax, the stub
asks the object how big of a marshaling packet it will need. When asked, the obj
ect will return an upper bound on the amount of space it will need.
The marshaling stub allocates a marshaling packet of appropriate size, then crea
tes an IStream* which points into the buffer. Unless in the previous step the ma
rshaling stub asked the object for an upper bound on the space needed, the IStre
am* must be able to grow its underlying buffer dynamically as IStream::Write cal
ls are made.
The original marshaling stub asks the object to marshal its data using MarshalIn
terface.
We will discuss the methods of this interface in detail later in this chapter.
At this point, the contents of the memory buffer pointed to by the IStream* toge
ther with the class tag returned in step (1) comprises all the information neces
sary in order to be able to create the proxy object in the client process. It is
the nature of remoting and marshaling that original marshaling stubs such as we h
ave been discussing know how to communicate with the client process; recall that
we are assuming that an initial connection between the two processes had alread
y been established. The marshaling stub now communicates to the client process,
by whatever means is appropriate, the class tag and the contents of the memory t
hat contains the marshaled interface pointer. In the client process, the proxy o
bject is created as an instance of the indicated class using the standard COM in
stance creation paradigm. IMarshal is used as the initialization interface; the
initialization method is IMarshal::UnmarshalInterface(). The unmarshaling process lo
oks something like the following:
void ExampleUnmarshal(CLSID& clsidProxyObject, IStream* pstm, IID& iidOriginally
Marshalled, void** ppvReturn)
{
IClassFactory* pcf;
IMarshal* pmsh;
CoGetClassObject(clsidProxyObject, CLSCTX_INPROC_HANDLER, NULL, IID_IClassFacto
ry, (void**)&pcf);
pcf->CreateInstance(NULL, IID_IMarshal, (void**)pmsh);
pmsh->UnmarshalInterface(pstm, iidOriginallyMarshalled, ppvReturn);
pmsh->ReleaseMarshalData(pstm)
pmsh->Release();
pcf->Release();
}
There are several important reasons why an object may choose to do custom marsha
ling.
It permits the server implementation, transparently to the client, to be in comp
lete control of the nature of the invocations that actually transition across th
e network. In designing component architectures, one often runs into a design te
nsion between the interface which for simplicity and elegance one wishes to exhi
bit to client programmers and the interface that is necessary to achieve efficie
nt invocations across the network. The former, for example, might naturally wish
to operate in terms of small-grained simple queries and responses, whereas the
latter might wish to batch requests for efficient retrieval. The client and the
network interfaces are in design tension; custom marshaling is the crucial hook
that allows us to have our cake and eat it too by giving the server implementor
the ability to tune the network interface without affecting the interface seen b
y its client.
When the object does custom marshaling, the client loses any "COM provided" comm
unication to the original object. If the proxy wants to "keep in touch", it has
to connect through some other means (RPC, Named pipe...) to the original object.
Custom Object Marshaling can not be done on a per interface basic, because obje
ct identity is lost! Custom Object Marshaling is a sophisticated way for an obje
ct to pass a copy of an existing instance of itself into another execution conte
xt.
Some objects are of the nature that once they have been created, they are immuta
ble: their internal state does not subsequently change. Many monikers are an exa
mple of such objects. These sorts of objects can be efficiently remoted by makin
g independent copies of themselves in client processes. Custom marshaling is the
mechanism by which they can do that, yet have no other party be the wiser for i
t.
Objects which already are proxy objects can use custom marshaling to avoid creat
ing proxies to proxies; new proxies are instead short-circuited back to the origi
nal server. This is both an important efficiency and an important robustness con
sideration.
Object implementations whose whole state is kept in shared memory can often be r
emoted to other process on the same machine by creating an object in the client
that talks directly to the shared memory rather than back to the original object
. This can be a significant performance improvement, since access to the remoted
object does not result in context switches. The present Microsoft Compound File
implementation is an example of objects using this kind of custom marshaling.
9.3 Architecture of Standard Interface / Object Marshaling
If the object being marshaled chooses not to implement custom object marshaling,
a default or standard object marshaling technique is used. An important part of thi
s standard marshaling technique involves locating and loading the interface-spec
ific pieces of code that are responsible for marshaling and unmarshaling remote
calls to instances of that interface. We call these interface-specific pieces of
code used in standard marshaling and unmarshaling interface proxies and interface
stubs respectively. (It is important not to confuse interface proxies with the ob
ject proxy, which relates to the whole representative in the client process, rat
her than just one interface on that representative. We apologize for the subtlet
ies of the terminology.)
The following figure gives a slightly simplified view of how the standard client
- and server-side structures cooperate.
Simplified conceptual view of client - server remoting structures
When an interface of type IFoo needs to be remoted, a system registry is consult
ed under a key derived from IID_IFoo to locate a class id that implements the in
terface proxy and interface stub for the given interface. Both the interface pro
xies and the interface stubs for a given interface must be implemented by the sa
me class. This class is typically either a system provided class that can provid
e marshaling support for any interface described in a type library or a class ge
nerated by the IDL compiler.
The IDL compiler is a tool whose input is a description of the function signatur
es and semantics of the interface, written in some interface description language
, often known as IDL. However, while highly recommended and encouraged for accuracy s
sake, the use of such a tool is by no means required; interface proxies and stu
bs are merely Component Object Model components which are used by the RPC infras
tructure, and as such, can be written in any manner desired so long as the corre
ct external contracts are upheld. From a logical perspective, it is ultimately t
he programmer who is the designer of a new interface who is responsible for ensu
ring that all interface proxies and stubs that ever exist agree on the represent
ation of their marshaled data. The programmer has the freedom to achieve this by
whatever means he sees fit, but with that freedom comes the responsibility for
ensuring the compatibility.
In the figure, the stub manager is conceptual in the sense that while it useful in t
his documentation to have a term to refer to the pieces of code and state on in
the server-side RPC infrastructure which service the remoting of a given object,
there is no direct requirement that the code and state take any particular well
-specified form. In contrast, on the client side, there is an identifiable piece
of state and associated behavior which appears to the client code to be the one
, whole object. The term proxy manager is used to refer to the COM Library provide
d code that manages the client object identity, etc., and which dynamically load
s in interface proxies as needed (per QueryInterface calls). The proxy manager i
mplementation is intimate with the client-side RPC channel implementation, and the
server-side RPC channel implementation is intimate with the stub manager implement
ation.
Interface proxies are created by the client-side COM Library infrastructure usin
g a code sequence resembling the following:
clsid = LookUpInRegistry(key derived from iid)
CoGetClassObject(clsid, CLSCTX_SERVER, NULL, IID_IPSFactoryBuffer, &pPSFactory))
;
pPSFactory->CreateProxy(pUnkOuter, riid, &pProxy, &piid);
Interface stubs are created by the server-side RPC infrastructure using a code s
equence resembling:
clsid = LookUpInRegistry(key derived from iid)
CoGetClassObject(clsid, CLSCTX_SERVER, NULL, IID_IPSFactoryBuffer, &pPSFactory))
;
pPSFactory->CreateStub(iid, pUnkServer, &pStub);
In particular, notice that the class object is talked-to with IPSFactoryBuffer i
nterface rather than the more common IClassFactory.
The interfaces mentioned here are as follows:
interface IPSFactoryBuffer : IUnknown {
HRESULT CreateProxy(pUnkOuter, iid, ppProxy, ppv);
HRESULT CreateStub(iid, pUnkServer, ppStub);
};
interface IRpcChannelBuffer : IUnknown {
HRESULT GetBuffer(pMessage, riid);
HRESULT SendReceive(pMessage, pStatus);
HRESULT FreeBuffer(pMessage);
HRESULT GetDestCtx(pdwDestCtx, ppvDestCtx);
HRESULT IsConnected();
};
interface IRpcProxyBuffer : IUnknown {
HRESULT Connect(pRpcChannelBuffer);
void Disconnect();
};
interface IRpcStubBuffer : IUnknown {
HRESULT Connect(pUnkServer);
void Disconnect();
HRESULT Invoke(pMessage, pChannel);
IRPCStubBuffer* IsIIDSupported(iid);
ULONG CountRefs();
HRESULT DebugServerQueryInterface(ppv);
void DebugServerRelease(pv);
};
Suppose an interface proxy receives a method invocation on one of it s interfaces
(such as IFoo, IBar, or IBaz in the above figure). The interface proxy s implement
ation of this method first obtains a marshaling packet from its RPC channel usin
g IRpcChannelBuffer::GetBuffer(). The process of marshaling the arguments will c
opy data into the buffer. When marshaling is complete, the interface proxy invok
es IRpcChannelBuffer::SendReceive() to send the method invocation across the wire to
the corresponding interface stub. When IRpcChannelBuffer::SendReceive() returns
, the contents of buffer into which the arguments were marshaled will have been
replaced by the return values marshaled from the interface stub. The interface p
roxy unmarshals the return values, invokes IRpcChannelBuffer::FreeBuffer() to fr
ee the buffer, then returns the return values to the original caller of the meth
od.
It is the implementation of IRpcChannelBuffer::SendReceive() that actually sends
the request over to the server process. It is only the channel who knows or car
es how to identify the server process and object within that process to which th
e request should be sent; this encapsulation allows the architecture we are desc
ribing here to function for a variety of different kinds of channels: intra-mach
ine channels, inter-machine channels (i.e.: across the network), etc. The channe
l implementation knows how to forward the request onto the appropriate stub mana
ger object in the appropriate process. From the perspective of this specificatio
n, the channel and the stub manager are intimate with each other (and intimate w
ith the proxy manager, for that matter). Through this intimacy, eventually the a
ppropriate interface stub receives an IRpcStubBuffer::Invoke() call. The stub un
marshals the arguments from the provided buffer, invokes the indicated method on
the server object, and marshals the return values back into a new buffer, alloc
ated by a call to IRpcChannelBuffer::GetBuffer(). The stub manager and the chann
el then cooperate to ferry the return data packet back to the interface proxy, w
ho is still in the middle of IRpcChannelBuffer::SendReceive(). IRpcChannelBuffer
::SendReceive() returns to the proxy, and we proceed as just described above.
When created, interface proxies are always aggregated into the larger object pro
xy: at interface-proxy-creation time, the proxy is given the IUnknown* to which
it should delegate its QueryInterface(), etc., calls, as per the usual aggregati
on rules. When connected, the interface proxy is also given (with IRpcProxyBuffer:
:Connect()) a pointer to an IRpcChannelBuffer interface instance. It is through th
is pointer that the interface proxy actually sends calls to the server process.
Interface proxies bring a small twist to the normal everyday aggregation scenari
o. In aggregation, each interface supported by an aggregateable object is classi
fied as either external or internal. External interfaces are the norm. They are the
ones whose instances are exposed directly to the clients of the aggregate as who
le. It is always the case that a QueryInterface() that requests an external inte
rface of an aggregated object should be delegated by the object to its controlli
ng unknown (ditto for AddRef() and Release()). Internal interfaces, on the other
hand, are never exposed to outside clients. Instead, they are solely for the us
e of the controlling unknown in manipulating the aggregated object. QueryInterfa
ce() for internal interfaces should never be delegated to the controlling unknow
n (ditto again). In the common uses of aggregation, the IUnknown interface on th
e object is the only internal interface. The twist that interface proxies bring
is that IRpcProxyBuffer is also an internal interface.
Interface stubs, by contrast with interface proxies, are not aggregated, since t
here is no need that they appear to some external client to be part of a larger
whole. When connected, an interface stub is given (with IRpcStubBuffer::Connect(
)) a pointer to the server object to which they should forward invocations that
they receive.
A given interface proxy instance can if it chooses to do so service more than on
e interface. For example, in the above figure, one interface proxy could have ch
osen to service both IFoo and IBar. To accomplish this, in addition to installin
g itself under the appropriate registry entries, the proxy should support QueryIn
terface()ing from one supported interface (and from IUnknown and IRpcProxyBuffer)
to the other interfaces, as usual. When the Proxy Manager in a given object pro
xy finds that it needs the interface proxy for some new interface that it doesn t
already have, before it goes out to the registry to load in the appropriate code
using the code sequence described above, it first does a QueryInterface() for t
he new interface id (IID) on all of its existing interface proxies. If one of th
em supports the interface, then it is used rather than loading a new interface p
roxy.
Interface stub instances, too, can service more than one interface on a server o
bject. However, the extent to which they can do so is quite restricted: a given
interface stub instance may support one or more interfaces only if that set of in
terfaces has in fact a strict single-inheritance relationship. In short, a given
interface stub needs to know how to interpret a given method number that it is a
sked to invoke without at that same time also being told the interface id (IID)
in which that method belongs; the stub must already know the relevant IID. The I
ID which an interface stub is initially created to service is passed as paramete
r to IPSFactoryBuffer::CreateStub(). After creation, the interface stub may from time
to time be asked using IRpcStubBuffer::IsIIDSupported() if it in fact would also lik
e be used to service another IID. If the stub also supports the second IID, then
it should return the appropriate IRpcStubBuffer* for that IID; otherwise, the s
tub buffer should return NULL. This permits the stub manager in certain cases to
optimize the loading of interface stubs.
Both proxies and stubs will at various times have need to allocate or free memor
y. Interface proxies, for example, will need to allocate memory in which to retu
rn out parameters to their caller. In this respect interface proxies and interfa
ce stubs are just normal Component Object Model components, in that they should
use the standard task allocator; see CoGetMalloc(). See also the earlier discuss
ion regarding specific rules for passing in, out, and in out pointers.
On Microsoft Windows platforms, the key derived from IID under which the registry
is consulted to learn the proxy/stub class is as follows:
Interfaces
{IID}
ProxyStubClsid32 = {CLSID}
Here {CLSID} is a shorthand for any class id; the actual value of the unique id
is put between the {}'s; e.g. {DEADBEEF-DEAD-BEEF-C000-000000000046}; all digits
are upper case hex and there can be no spaces. This string format for a unique
id (without the {} s) is the same as the OSF DCE? standard and is the result of t
he StringFromCLSID routine. {IID} is a shorthand for an interface id; this is si
milar to {CLSID}; StringFromIID can be used to produce this string.
9.4 Architecture of Handler Marshaling
Handler marshaling is a third variation on marshaling, one closely related to st
andard marshaling. Colloquially, one can think of it as a middle ground between
raw standard marshaling and full custom marshaling.
In handler marshaling, the object specifies that it would like to have some amou
nt of client-side state; this is designated by the class returned by IStdMarshal
Info::GetClassForHandler. However, this handler class rather than fully taking o
ver the remoting to the object instead aggregates in the default handler, which
carries out the remoting in the standard manner as described above.
9.5 Standards for Marshaled Data Packets
In the architecture described here, nothing has yet to be said about representat
ion or format standards for the data that gets placed in marshaling packets. The
re is a good reason for this. In the Component Object Model architecture, the on
ly two parties that have to agree on what goes into a marshaling packet are the
code that marshals the data into the packet and the code that unmarshals it out
again: the interface proxies and the interface stubs. So long as we are dealing
only with intra-machine procedure calls (i.e.: non-network), then we can reasona
bly assume that pairs of interface proxies and stubs are always installed togethe
r on the machine. In this situation, we have no need to specify a packet format
standard; the packet format can safely be a private matter between the two piece
of code.
However, once a network is involved, relying on the simultaneous installation of
corresponding interface proxies and stubs (on different machines) is no longer
a reasonable thing to do. Thus, when the a method invocation is in fact remoted
over a network, it is strongly recommended that the data marshaled into the pack
et to conform to a published standard (NDR), though, as pointed out above, it is
technically the interface-designer s responsibility to achieve this correspondenc
e by whatever means he sees fit.
9.6 Creating an Initial Connection Between Processes
Earlier we said we would later discuss how an initial remoting connection is est
ablished between two processes. It is now time to have that discussion.
The real truth of the matter is that the initial connection is established by so
me means outside of the architecture that we have been discussing here. The mini
mal that is required is some primitive communication channel between the two proc
esses. As such, we cannot hope to discuss all the possibilities. But we will poi
nt out some common ones.
One common approach is that initial connections are established just like other c
onnections: an interface pointer is marshaled in the server process, the marshal
ed data packet is ferried the client process, and it is unmarshaled. The only tw
ist is that the ferrying is done by some means other than the RPC mechanism whic
h we ve been describing. There are many ways this could be accomplished. The most
important, by far is one where the marshaled data is passed as an out-parameter
from an invocation on a well-known endpoint to a Service Control Manager.
9.7 Interface Remoting and Marshaling Interface Descriptions
Having discussed on a high level how various remoting related interfaces work to
gether, we now present each of them in detail.
9.7.1 IMarshal
The IMarshal interface enables an COM object to define and manage the marshaling
of its interface pointers. The alternative is to use COM s default implementation
, the preferred choice in all but a few special cases (see When to Implement ).
Marshaling is the process of packaging data into packets for transmission to a dif
ferent process or machine. Unmarshaling is the process of recovering that data at
the receiving end. In any given call, method arguments are marshaled and unmarsh
aled in one direction, while return values are marshaled and unmarshaled in the
other.
Although marshaling applies to all data types, interface pointers require specia
l handling. The fundamental problem is how client code running in one address sp
ace can correctly dereference a pointer to an interface on an object residing in
a different address space. COM s solution is for a client application to communic
ate with the original object through a surrogate object, or proxy, which lives i
n the client s process. The proxy holds a reference to an interface on the origina
l object and hands the client a pointer to an interface on itself. When the clie
nt calls an interface method on the original object, its call is actually going
to the proxy. Therefore, from the client s point of view, all calls are in-process
.
On receiving a call, the proxy marshals the method arguments and, through some m
eans of interprocess communication, such as RPC, passes them along to code in th
e server process, which unmarshals the arguments and passes them to the original
object. This same code marshals return values for transmission back to the prox
y, which unmarshals the values and passes them to the client application.
IMarshal provides methods for creating, initializing, and managing a proxy in a
client process; it does not dictate how the proxy should communicate with the or
iginal object. COM s default implementation of IMarshal uses RPC. When you impleme
nt this interface yourself, you are free to choose any method of interprocess co
mmunication you deem to be appropriate for your application shared memory, named
pipe, window handle, RPC in short, whatever works.
9.7.1.1 When to Implement
Implement IMarshal only when you believe that you can realize significant optimi
zations to COM s default implementation. In practice, this will rarely be the case
. However, there are occasions where implementing IMarshal may be preferred:
· The objects you are writing keep their state in shared memory. In this case, bot
h the original process and the client process uses proxies that refer to the sha
red memory. This type of custom marshaling is possible only if the client proces
s is on the same machine as the original process. COM-provided implementations o
f IStorage and IStream are examples of this type of custom marshaling.
· The objects you are writing are immutable, that is, their state does not change
after creation. Instead of forwarding method calls to the original objects, you
simply create copies of those objects in the client process. This technique avoi
ds the cost of switching from one process to another. Some monikers are examples
of immutable objects; if you are implementing your own moniker class, you shoul
d evaluate the costs and benefits of implementing IMarshal on your moniker objec
ts.
· Objects that themselves are proxy objects can use custom marshaling to avoid cre
ating proxies to proxies. Instead, the existing proxy can refer new proxies back
to the original object. This capability is important for the sake of both effic
iency and robustness.
· Your server application wants to manage how calls are made across the network wi
thout affecting the interface exposed to clients. For example, if an end user we
re making changes to a database record, the server might want to cache the chang
es until the user has committed them all, at which time the entire transaction w
ould be forwarded in a single packet. Using a custom proxy would enable the cach
ing and batching of changes in this way.
When you choose to implement IMarshal, you must do so for both your original obj
ect and the proxy you create for it. When implementing the interface on either o
bject or proxy, you simply return E_NOTIMPL for the methods that are not impleme
nted.
COM uses your implementation of IMarshal in the following manner: When it s necess
ary to create a remote interface pointer to your object (that is, when a pointer
to your object is passed as an argument in a remote function call), COM queries
your object for the IMarshal interface. If your object implements it, COM uses
your IMarshal implementation to create the proxy object. If your object does not
implement IMarshal, COM uses its default implementation.
How you choose to structure the proxy is entirely up to you. You can write the p
roxy to use whatever mechanisms you deem appropriate for communicating with the
original object. You can also create the proxy as either a stand-alone object or
as part of a larger aggregation such as a handler. However you choose to struct
ure the proxy, it must implement IMarshal to work at all. You must also generate
a CLSID for the proxy to be returned by your implementation of IMarshal::GetUnm
arshalClass on the original object.
9.7.1.2 When to Use
COM calls this interface as part of system-provided marshaling support. COM s call
s are wrapped in calls to CoMarshalInterface and CoUnmarshalInterface. Your code
typically will not need to call this interface. Special circumstances where you
might choose to do so are discussed in the Notes to Callers section for each meth
od.
Methods in VTable Order
IUnknown Methods Description
QueryInterface Returns pointers to supported interfaces.
AddRef Increments reference count.
Release Decrements reference count.
IMarshal Methods Description
GetUnmarshalClass Returns CLSID of unmarshaling code.
GetMarshalSizeMax Returns size of buffer needed during marshaling.
MarshalInterface Marshals an interface pointer.
UnmarshalInterface Unmarshals an interface pointer.
ReleaseMarshalData Destroys a marshaled data packet.
DisconnectObject Severs all connections.
See Also
IStdMarshalInfo
9.7.1.3 IMarshal::DisconnectObject
Forcibly releases all external connections to an object. The object s server calls
the object s implementation of this method prior to shutting down.
HRESULT DisconnectObject(
DWORD dwReserved //Reserved for future use
);
Parameter
dwReserved
[in] Reserved for future use; must be zero. To ensure compatibility with future
use, DisConnectObject must not check for zero.
Return Values
The method supports the standard return value E_FAIL, as well as the following:
S_OK
The object was disconnected successfully.
Remarks
This method is implemented on the object, not the proxy.
9.7.1.3.1 Notes to Callers
The usual case in which this method is called occurs when an end user forcibly c
loses a COM server that has one or more running objects that implement IMarshal.
Prior to shutting down, the server calls the CoDisconnectObject helper function
to sever external connections to all its running objects. For each object that
implements IMarshal, however, this function calls IMarshal::DisconnectObject, so
that each object that manages its own marshaling can take steps to notify its p
roxy that it is about to shut down.
9.7.1.3.2 Notes to Implementers
As part of its normal shutdown code, a server should call the CoDisconnectObject
function, which in turn calls IMarshal::DisconnectObject, on each of its runnin
g objects that implements IMarshal.
The outcome of any implementation of this method should be to enable a proxy to
respond to all subsequent calls from its client by returning RPC_E_DISCONNECTED
or CO_E_OBJECTNOTCONNECTED rather than attempting to forward the calls on to the
original object. It is up to the client, of course, to destroy the proxy.
If you are implementing this method for an immutable object, such as a moniker,
your implementation doesn t need to do anything because such objects are typically
copied whole into the client s address space. Therefore, they have neither a prox
y nor a connection to the original object. For more information on marshaling im
mutable objects, see IMarshal, When to Implement.
See Also
CoDisconnectObject
9.7.1.4 IMarshal::GetMarshalSizeMax
Returns an upper bound on the number of bytes needed to marshal the specified in
terface pointer on the specified object.
HRESULT GetMarshalSizeMax(
REFIID riid, //Reference to the identifier of the interface to be mar
shaled
void *pv, //Interface pointer to be marshaled
DWORD dwDestContext, //Destination process
void * pvDestContext, //Reserved for future use
DWORD mshlflags, //Reason for marshaling
ULONG * pSize //Pointer to upper-bound value
);
Parameters
riid
[in] Reference to the identifier of the interface to be marshaled.
pv
[in] Interface pointer to be marshaled; can be NULL.
dwDestContext
[in] Destination context where the specified interface is to be unmarshaled. Val
ues for dwDestContext come from the enumeration MSHCTX. Currently, unmarshaling
can occur either in another apartment of the current process (MSHCTX_INPROC) or
in another process on the same computer as the current process (MSHCTX_LOCAL).
pvDestContext
[in] Reserved for future use; must be NULL.
mshlflags
[in] Flag indicating whether the data to be marshaled is to be transmitted back
to the client process the normal case or written to a global table, where it can
be retrieved by multiple clients. Valid values come from the MSHLFLAGS enumerat
ion.
pSize
[out] Pointer to the upper bound on the amount of data to be written to the mars
haling stream.
Return Values
The method supports the standard return value E_FAIL, as well as the following:
S_OK
The maximum size was returned successfully.
E_NOINTERFACE
The specified interface was not supported.
Remarks
This method is called indirectly, in a call to CoGetMarshalSizeMax, by whatever
code in the server process is responsible for marshaling a pointer to an interfa
ce on an object. This marshaling code is usually a stub generated by COM for one
of several interfaces that can marshal a pointer to an interface implemented on
an entirely different object. Examples include the IClassFactory and IOleItemCo
ntainer interfaces. For purposes of discussion, the code responsible for marshal
ing a pointer is here called the marshaling stub.
To create a proxy for an object, COM requires two pieces of information from the
original object: the amount of data to be written to the marshaling stream and
the proxy s CLSID.
The marshaling stub obtains these two pieces of information with successive call
s to CoGetMarshalSizeMax and CoMarshalInterface.
9.7.1.4.1 Note to Callers
The marshaling stub, through a call to CoGetMarshalSizeMax, calls the object s imp
lementation of this method to preallocate the stream buffer that will be passed
to IMarshal::MarshalInterface.
You do not explicitly call this method if you are:
· Implementing existing COM interfaces, or
· Defining your own custom interfaces, using the Microsoft Interface Definition La
nguage (MIDL).
In both cases, the MIDL-generated stub automatically makes the call.
If you are not using MIDL to define your own interface (see Writing a Custom Inte
rface ), your marshaling stub does not have to call GetMarshalSizeMax, though doin
g so is highly recommended. An object knows better than an interface stub what t
he maximum size of a marshaling data packet is likely to be. Therefore, unless y
ou are providing an automatically growing stream that is so efficient that the o
verhead of expanding it is insignificant, you should call this method even when
implementing your own interfaces.
The value returned by this method is only guaranteed to be valid as long as the
internal state of the object being marshaled does not change. Therefore, the act
ual marshaling should be done immediately after this function returns, or the st
ub runs the risk that the object, because of some change in state, might require
more memory to marshal than it originally indicated.
9.7.1.4.2 Notes to Implementers
Your implementation of MarshalInterface will use this buffer to write marshaling
data into the stream. If the buffer is too small, the marshaling operation will
fail. Therefore, the value returned by this method must be a conservative estim
ate of the amount of data that will, in fact, be needed to marshal the interface
. Violation of this requirement should be treated as a catastrophic error.
In a subsequent call to IMarshal::MarshalInterface, your IMarshal implementation
cannot rely on the caller actually having called GetMarshalSizeMax beforehand.
It must still be wary of STG_E_MEDIUMFULL errors returned by the stream and be p
repared to handle them gracefully.
To ensure that your implementation of GetMarshalSizeMax will continue to work pr
operly as new destination contexts are supported in the future, delegate marshal
ing to COM s default implementation for all dwDestContext values that your impleme
ntation does not understand. To delegate marshaling to COM s default implementatio
n, call the CoGetStandardMarshal function.
See Also
CoGetMarshalSizeMax, IMarshal::MarshalInterface
9.7.1.5 IMarshal::GetUnmarshalClass
Returns the CLSID that COM uses to locate the DLL containing the code for the co
rresponding proxy. COM loads this DLL to create an uninitialized instance of the
proxy.
HRESULT GetUnmarshalClass(
REFIID riid, //Reference to the identifier of the interface to be mar
shaled
void * pv, //Interface pointer being marshaled
DWORD dwDestContext, //Destination process
void * pvDestContext, //Reserved for future use
DWORD mshlflags, //Reason for marshaling
CLSID * pCid //Pointer to CLSID of proxy
);
Parameters
riid
[in] Reference to the identifier of the interface to be marshaled.
pv
[in] Pointer to the interface to be marshaled; can be NULL if the caller does no
t have a pointer to the desired interface.
dwDestContext
[in] Destination context where the specified interface is to be unmarshaled. Value
s for dwDestContext come from the enumeration MSHCTX. Currently, unmarshaling ca
n occur either in another apartment of the current process (MSHCTX_INPROC) or in
another process on the same computer as the current process (MSHCTX_LOCAL).
pvDestContext
[in] Reserved for future use; must be NULL.
mshlflags
[in] Whether the data to be marshaled is to be transmitted back to the client pr
ocess the normal case or written to a global table, where it can be retrieved by
multiple clients. Valid values come from the MSHLFLAGS enumeration.
pCid
[out] Pointer to the CLSID to be used to create a proxy in the client process.
Return Value
Returns S_OK if successful; otherwise, S_FALSE.
Remarks
This method is called by whatever code in the server process may be responsible
for marshaling a pointer to an interface on an object. This marshaling code is u
sually a stub generated by COM for one of several interfaces that can marshal a
pointer to an interface implemented on an entirely different object. Examples in
clude the IClassFactory and IOleItemContainer interfaces. For purposes of this d
iscussion, the code responsible for marshaling a pointer is called the marshaling
stub.
To create a proxy for an object, COM requires two pieces of information from the
original object: the amount of data to be written to the marshaling stream and
the proxy s CLSID.
The marshaling stub obtains these two pieces of information with successive call
s to CoGetMarshalSizeMax and CoMarshalInterface.
9.7.1.5.1 Note to Callers
The marshaling stub calls the object s implementation of this method to obtain the
CLSID to be used in creating an instance of the proxy. The client, upon receivi
ng the CLSID, loads the DLL listed for it in the system registry.
You do not explicitly call this method if you are:
· Implementing existing COM interfaces, or
· Defining your own interfaces using the Microsoft Interface Definition Language (
MIDL).
In both cases, the stub automatically makes the call. See Writing a Custom Interf
ace.
If you are not using MIDL to define your own interface, your stub must call this
method, either directly or indirectly, to get the CLSID that the client-side CO
M Library needs to create a proxy for the object implementing the interface.
If the caller has a pointer to the interface to be marshaled, it should, as a ma
tter of efficiency, use the pv parameter to pass that pointer. In this way, an i
mplementation that may use such a pointer to determine the appropriate CLSID for
the proxy does not have to call IUnknown::QueryInterface on itself. If a caller
does not have a pointer to the interface to be marshaled, it can pass NULL.
9.7.1.5.2 Notes to Implementers
COM calls GetUnmarshalClass to obtain the CLSID to be used for creating a proxy
in the client process. The CLSID to be used for a proxy is normally not that of
the original object (see Notes to Implementers for the exception), but one you wil
l have generated (using the GUIDGEN.EXE tool supplied with the Win32 SDK) specif
ically for your proxy object.
Implement this method for each object that provides marshaling for one or more o
f its interfaces. The code responsible for marshaling the object writes the CLSI
D, along with the marshaling data, to a stream; COM extracts the CLSID and data
from the stream on the receiving side.
If your proxy implementation consists simply of copying the entire original obje
ct into the client process, thereby eliminating the need to forward calls to the
original object, the CLSID returned would be the same as that of the original o
bject. This strategy, of course, is advisable only for objects that are not expe
cted to change.
If the pv parameter is NULL and your implementation needs an interface pointer,
it can call IUnknown::QueryInterface on the current object to get it. The pv par
ameter exists merely to improve efficiency.
To ensure that your implementation of GetUnmarshalClass continues to work proper
ly as new destination contexts are supported in the future, delegate marshaling
to COM s default implementation for all dwDestContext values that your implementat
ion does not handle. To delegate marshaling to COM s default implementation, call
the CoGetStandardMarshal function.
9.7.1.6 IMarshal::MarshalInterface
Writes into a stream the data required to initialize a proxy object in some clie
nt process.
HRESULT MarshalInterface(
IStream *pStm, //Pointer to stream used for marshaling
REFIID riid, //Reference to the identifier of the interface to be mar
shaled
void *pv, //Interface pointer to be marshaled
DWORD dwDestContext, //Destination context
void *pvDestContext, //Reserved for future use
DWORD mshlflags //Reason for marshaling
);
Parameters
pStm
[in] Pointer to the stream to be used during marshaling.
riid
[in] Reference to the identifier of the interface to be marshaled. This interfac
e must be derived from the IUnknown interface.
pv
[in] Pointer to the interface pointer to be marshaled; can be NULL if the caller
does not have a pointer to the desired interface.
dwDestContext
[in] Destination context where the specified interface is to be unmarshaled. Val
ues for dwDestContext come from the enumeration MSHCTX. Currently, unmarshaling
can occur either in another apartment of the current process (MSHCTX_INPROC) or
in another process on the same computer as the current process (MSHCTX_LOCAL).
pvDestContext
[in] Reserved for future use; must be zero.
mshlflags
[in] Whether the data to be marshaled is to be transmitted back to the client pr
ocess the normal case or written to a global table, where it can be retrieved by
multiple clients. Valid values come from the MSHLFLAGS enumeration.
Return Values
The method supports the standard return value E_FAIL, as well as the following:
S_OK
The interface pointer was marshaled successfully.
E_NOINTERFACE
The specified interface is not supported.
STG_E_MEDIUMFULL
The stream is full.
Remarks
This method is called indirectly, in a call to CoMarshalInterface, by whatever c
ode in the server process may be responsible for marshaling a pointer to an inte
rface on an object. This marshaling code is usually a stub generated by COM for
one of several interfaces that can marshal a pointer to an interface implemented
on an entirely different object. Examples include the IClassFactory and IOleIte
mContainer interfaces. For purposes of this discussion, the code responsible for
marshaling a pointer is called the marshaling stub.
9.7.1.6.1 Notes to Callers
Normally, rather than calling IMarshal::MarshalInterface directly, your marshali
ng stub instead should call the CoMarshalInterface function, which contains a ca
ll to this method. The stub makes this call to command an object to write its ma
rshaling data into a stream. The stub then either passes the marshaling data bac
k to the client process or writes it to a global table, where it can be unmarsha
led by multiple clients. The stub s call to CoMarshalInterface is normally precede
d by a call to CoGetMarshalSizeMax, to get the maximum size of the stream buffer
into which the marshaling data will be written.
You do not explicitly call this method if you are:
· Implementing existing COM interfaces, or
· Defining your own interfaces using the Microsoft Interface Definition Language (
MIDL).
In both cases, the MIDL-generated stub automatically makes the call.
If you are not using MIDL to define your own interface, your marshaling stub mus
t call this method, either directly or indirectly.Your stub implementation shoul
d call MarshalInterface immediately after its previous call to IMarshal::GetMars
halSizeMax returns. Because the value returned by GetMarshalSizeMax is guarantee
d to be valid only so long as the internal state of the object being marshaled d
oes not change, a delay in calling MarshalInterface runs the risk that the objec
t will require a larger stream buffer than originally indicated.
If the caller has a pointer to the interface to be marshaled, it should, as a ma
tter of efficiency, use the pv parameter to pass that pointer. In this way, an i
mplementation that may use such a pointer to determine the appropriate CLSID for
the proxy does not have to call IUnknown::QueryInterface on itself. If a caller
does not have a pointer to the interface to be marshaled, it can pass NULL.
9.7.1.6.2 Notes to Implementers
Your implementation of IMarshal::MarshalInterface must write to the stream whate
ver data is needed to initialize the proxy on the receiving side. Such data woul
d include a reference to the interface to be marshaled, a MSHLFLAGS value specif
ying whether the data should be returned to the client process or written to a g
lobal table, and whatever is needed to connect to the object, such as a named pi
pe, handle to a window, or pointer to an RPC channel.
Your implementation should not assume that the stream is large enough to hold al
l the data. Rather, it should gracefully handle a STG_E_MEDIUMFULL error. Just b
efore exiting, your implementation should position the seek pointer in the strea
m immediately after the last byte of data written.
If the pv parameter is NULL and your implementation needs an interface pointer,
it can call IUnknown::QueryInterface on the current object to get it. The pv par
ameter exists merely to improve efficiency.
To ensure that your implementation of MarshalInterface continues to work properl
y as new destination contexts are supported in the future, delegate marshaling t
o COM s default implementation for all dwDestContext values that your implementati
on does not handle. To delegate marshaling to COM s default implementation, call t
he CoGetStandardMarshal helper function.
Using the MSHLFLAGS enumeration, callers can specify whether an interface pointe
r is to be marshaled back to a single client or written to a global table, where
it can be unmarshaled by multiple clients. You must make sure that your object
can handle calls from the multiple proxies that might be created from the same i
nitialization data.
See Also
CoGetStandardMarshal, IMarshal::GetMarshalSizeMax, IMarshal::GetUnmarshalClass,
IMarshal::UnmarshalInterface, Writing a Custom Interface
9.7.1.7 IMarshal::ReleaseMarshalData
Destroys a marshaled data packet.
HRESULT ReleaseMarshalData(
IStream * pStm //Pointer to stream used for unmarshaling
);
Parameter
pStm
[in] Pointer to a stream that contains the data packet to be destroyed.
Return Values
The method supports the standard return value E_FAIL, as well as the following:
S_OK
The data packet was released successfully.
IStream errors
This function can also return any of the stream-access error values for the IStr
eam interface.
Remarks
If an object s marshaled data packet does not get unmarshaled in the client proces
s space, and the packet is no longer needed. The client calls ReleaseMarshalData
on the proxy s IMarshal implementation to instruct the object to destroy the data
packet. The call occurs within the CoReleaseMarshalData function. The data pack
et serves as an additional reference on the object, and releasing the data is li
ke releasing an interface pointer by calling IUnknown::Release.
If the marshaled data packet somehow does not arrive in the client process, or R
eleaseMarshalData is not successfully re-created in the proxy, COM can call this
method on the object itself.
9.7.1.7.1 Notes to Callers
You will rarely if ever have occasion to call this method yourself. A possible e
xception would be if you were to implement IMarshal on a class factory for a cla
ss object on which you are also implementing IMarshal. In this case, if you are
marshaling the object to a table, where it can be retrieved by multiple clients,
you might, as part of your unmarshaling routine, call ReleaseMarshalData to rel
ease the data packet for each proxy.
9.7.1.7.2 Notes to Implementers
If your implementation stores state information about marshaled data packets, yo
u can use this method to release the state information associated with the data
packet represented by pStm. Your implementation should also position the seek po
inter in the stream past the last byte of data.
See Also
CoUnMarshalInterface, CoReleaseMarshalData
9.7.1.8 IMarshal::UnmarshalInterface
Initializes a newly created proxy and returns an interface pointer to that proxy
.
HRESULT UnmarshalInterface(
IStream * pStm, //Pointer to the stream to be unmarshaled
REFIID riid, //Reference to the identifier of the interface to be unm
arshaled
void ** ppv //Indirect pointer to interface
);
Parameters
pStm
[in] Pointer to the stream from which the interface pointer is to be unmarshaled
.
riid
[in] Reference to the identifier of the interface to be unmarshaled.
ppv
[out] Indirect pointer to the interface.
Return Values
The method supports the standard return value E_FAIL, as well as the following:
S_OK
The interface pointer was unmarshaled successfully.
E_NOINTERFACE
The specified interface was not supported.
Remarks
The COM library in the process where unmarshaling is to occur calls the proxy s im
plementation of this method.
9.7.1.8.1 Notes to Callers
You do not call this method directly. There are, however, some situations in whi
ch you might call it indirectly through a call to CoUnmarshalInterface. For exam
ple, if you are implementing a stub, your implementation would call CoUnmarshalI
nterface when the stub receives an interface pointer as a parameter in a method
call.
9.7.1.8.2 Notes to Implementers
The proxy s implementation should read the data written to the stream by the origi
nal object s implementation of IMarshal::MarshalInterface and use that data to ini
tialize the proxy object whose CLSID was returned by the marshaling stub s call to
the original object s implementation of IMarshal::GetUnmarshalClass.
To return the appropriate interface pointer, the proxy implementation can simply
call IUnknown::QueryInterface on itself, passing the riid and ppv parameters. H
owever, your implementation of UnmarshalInterface is free to create a different
object and, if necessary, return a pointer to it.
Just before exiting, even if exiting with an error, your implementation should r
eposition the seek pointer in the stream immediately after the last byte of data
read.
See Also
IMarshal::GetUnmarshalClass, IMarshal::MarshalInterface
9.7.1.9 IMarshal - Default Implementation
COM uses its own internal implementation of the IMarshal interface to marshal an
y object that does not provide its own implementation. COM makes this determinat
ion by querying the object for IMarshal. If the interface is missing, COM defaul
ts to its internal implementation.
COM s default implementation of IMarshal uses a generic proxy for each object, and
creates individual stubs and proxies, as they are needed, for each interface im
plemented on the object. This mechanism is necessary because COM cannot know in
advance what particular interfaces a given object may implement. Developers who
do not use COM s default marshaling, electing instead to write their own proxy and
marshaling routines, know at compile time all the interfaces to be found on the
ir objects and therefore understand exactly what marshaling code is required. CO
M, in providing marshaling support for all objects, must do so at run time.
The interface proxy resides in the client process; the interface stub, in the se
rver. Together, each pair handles all marshaling for its interface. The job of e
ach interface proxy is to marshal arguments and unmarshal return values and out
parameters that are passed back and forth in subsequent calls to its interface.
The job of each interface stub is to unmarshal function arguments and pass them
along to the original object, then marshal the return values and out parameters
that the object returns.
Proxy and stub communicate by means of an RPC (remote procedure call) channel, w
hich utilizes the system s RPC infrastructure for interprocess communication. The
RPC channel implements a single interface IRpcChannelBuffer, an internal interfa
ce to which both interface proxies and stubs hold a pointer. The proxy and stub
call the interface to obtain a marshaling packet, send the data to their counter
part, and destroy the packet when they are done. The interface stub also holds a
pointer to the original object.
For any given interface, the proxy and stub are both implemented as instances of
the same class, which is listed for each interface in the system registry under
the label ProxyStubClsid32 (or ProxyStubClsid on 16-bit systems). This entry ma
ps the interface s IID to the CLSID of its proxy and stub objects. When COM needs
to marshal an interface, it looks in the system registry to obtain the appropria
te CLSID. The server identified by this CLSID implements both the interface prox
y and interface stub.
Most often, the class to which this CLSID refers is automatically generated by a
tool whose input is a description of the function signatures and semantics of a
given interface, written in some interface description language. While using su
ch a language is highly recommended and encouraged for accuracy s sake, doing so i
s by no means required. Proxies and stubs are merely Component Object Model comp
onents used by the RPC infrastructure and, as such, can be written in any manner
desired so long as the correct external contracts are upheld. The programmer wh
o designs a new interface is responsible for ensuring that all interface proxies
and stubs that ever exist agree on the representation of their marshaled data.
When created, interface proxies are always aggregated into a larger proxy, which
represents the object as a whole. This object proxy also aggregates COM s generic
proxy object, which is known as the proxy manager. The proxy manager implements
two interfaces: IUnknown and IMarshal. All of the other interfaces that may be
implemented on an object are exposed in its object proxy through the aggregation
of individual interface proxies. A client holding a pointer to the object proxy
believes it holds a pointer to the actual object.
A proxy representing the object as a whole is required in the client process so
that a client can distinguish calls to the same interfaces implemented on entire
ly different objects. Such a requirement does not exist in the server process, h
owever, where the object itself resides, because all interface stubs communicate
only with the objects for which they were created. No other connection is possi
ble.
Interface stubs, by contrast with interface proxies, are not aggregated, because
there is no need that they appear to some external client to be part of a large
r whole. When connected, an interface stub is given a pointer to the server obje
ct to which it should forward method invocations that it receives. Although it i
s useful to refer conceptually to a stub manager, meaning whatever pieces of code
and state in the server-side RPC infrastructure that service the remoting of a g
iven object, there is no direct requirement that the code and state take any par
ticular, well-specified form.
The first time a client requests a pointer to an interface on a particular objec
t, COM loads an IClassFactory stub in the server process and uses it to marshal
the first pointer back to the client. In the client process, COM loads the gener
ic proxy for the class factory object and calls its implementation of IMarshal t
o unmarshal that first pointer. COM then creates the first interface proxy and h
ands it a pointer to the RPC channel. Finally, COM returns the IClassFactory poi
nter to the client, which uses it to call IClassFactory::CreateInstance, passing
it a reference to the interface.
Back in the server process, COM now creates a new instance of the object, along
with a stub for the requested interface. This stub marshals the interface pointe
r back to the client process, where another object proxy is created, this time f
or the object itself. Also created is a proxy for the requested interface, a poi
nter to which is returned to the client. With subsequent calls to other interfac
es on the object, COM will load the appropriate interface stubs and proxies as n
eeded.
When a new interface proxy is created, COM hands it a pointer to the proxy manag
er s implementation of IUnknown, to which it delegates all QueryInterface calls. E
ach interface proxy implements two interfaces of its own: the interface it repre
sents and IRpcProxyBuffer. The interface proxy exposes its own interface directl
y to clients, which can obtain its pointer by calling QueryInterface on the prox
y manager. Only COM, however, can call IRpcProxyBuffer, which it uses to connect
and disconnect the proxy to the RPC channel. A client cannot query an interface
proxy to obtain a pointer to the IRpcProxyBuffer interface.
On the server side, each interface stub implements IRpcStubBuffer, an internal i
nterface. The server code acting as a stub manager calls IRpcStubBuffer::Connect
and passes the interface stub the IUnknown pointer of its object.
When an interface proxy receives a method invocation, it obtains a marshaling pa
cket from its RPC channel through a call to IRpcChannelBuffer::GetBuffer. The pr
ocess of marshaling the arguments will copy data into the buffer. When marshalin
g is complete, the interface proxy invokes IRpcChannelBuffer::SendReceive to sen
d the marshaled packet to the corresponding interface stub. When IRpcChannelBuff
er::SendReceive returns, the buffer into which the arguments were marshaled will
have been replaced by a new buffer containing the return values marshaled from
the interface stub. The interface proxy unmarshals the return values, invokes IR
pcChannelBuffer::FreeBuffer to free the buffer, then returns the return values t
o the original caller of the method.
It is the implementation of IRpcChannelBuffer::SendReceive that actually sends t
he request to the server process and that knows how to identify the server proce
ss and, within that process, the object to which the request should be sent. The
channel implementation also knows how to forward the request on to the appropri
ate stub manager in that process. The interface stub unmarshals the arguments fr
om the provided buffer, invokes the indicated method on the server object, and m
arshals the return values back into a new buffer, allocated by a call to IRpccha
nnelBuffer::GetBuffer. The channel then transmits the return data packet back to
the interface proxy, which is still in the middle of IRpcchannelBuffer::SendRec
eive, which returns to the interface proxy.
A particular instance of an interface proxy can be used to service more than one
interface, so long as two conditions are met. First, the IIDs of the affected i
nterfaces must be mapped to the the appropriate ProxyStubClsid in the system reg
istry. Second, the interface proxy must support calls to QueryInterface from one
supported interface to the other interfaces, as usual, as well as from IUnknown
and IRpcProxyBuffer.
A single instance of an interface stub can also service more than one interface,
but only if that set of interfaces has a strict single-inheritance relationship
. This restriction exists because the stub can direct method invocations to mult
iple interfaces only where it knows in advance which methods are implemented on
which interfaces.
Both proxies and stubs will at various times have need to allocate or free memor
y. Interface proxies, for example, will need to allocate memory in which to retu
rn out parameters to their caller. In this respect, interface proxies and interf
ace stubs are just normal COM components, in that they should use the standard t
ask allocator (see CoGetMalloc).
9.7.1.9.1 When to Use
You should use COM s default implementation of IMarshal except in those very few c
ases where your application has special requirements that COM s default implementa
tion does not address, or where you can achieve optimizations over the marshalin
g code COM has provided. For examples of such special cases, see IMarshal, When t
o Implement.
See Also
IMarshal
9.7.2 IPSFactoryBuffer
IPSFactoryBuffer is the interface through which proxies and stubs are created.
It is used to create proxies and stubs that support IRpcProxyBuffer and IRpcStub
Buffer respectively. Each proxy / stub DLL must support IPSFactory interface on t
he class object accessible through its DllGetClassObject() entry point. As was d
escribed above, the registry is consulted under a key derived from the IID to be
remoted in order to learn the proxy/stub class that handles the remoting of the
indicated interface. The class object for this class is retrieved, asking for t
his interface. A proxy or a stub is then instantiated as appropriate.
interface IPSFactoryBuffer : IUnknown {
HRESULT CreateProxy(pUnkOuter, iid, ppProxy, ppv);
HRESULT CreateStub(iid, pUnkServer, ppStub);
};
9.7.2.1 IPSFactoryBuffer::CreateProxy
HRESULT IPSFactoryBuffer::CreateProxy(pUnkOuter, iid, ppProxy, ppv)
Create a new interface proxy object. This function returns both an IRpcProxy ins
tance and an instance of the interface which the proxy is being created to servi
ce in the first place. The newly created proxy is initially in the unconnected s
tate.
Argument Type Description
pUnkOuter IUnknown * the controlling unknown of the aggregate in whic
h the proxy is being created.
iid REFIID the interface id which the proxy is being created to service, an
d of which an instance should be returned through ppv.
ppProxy IRpcProxyBuffer** on exit, contains the new IRpcProxyBuffer instan
ce.
ppv void ** on exit, contains an interface pointer of type indicated by iid.
return value HRESULT S_OK, E_OUTOFMEMORY, E_NOINTERFACE, E_UNEXPECTED, no oth
ers.
9.7.2.2 IPSFactoryBuffer::CreateStub
HRESULT IPSFactoryBuffer::CreateStub(iid, pUnkServer, ppStub)
Create a new interface stub object. The stub is created in the connected state o
n the object indicated by pUnkServer.
If pUnkServer is non-NULL, then before this function returns the stub must verif
y (by using QueryInterface()) that the server object in fact supports the interfa
ce indicated by iid. If it does not, then this function should fail with the err
or E_NOINTERFACE.
Argument Type Description
iid REFIID the interface that the stub is being created to service
pUnkServer IUnknown* the server object that is being remoted. The stu
b should delegate incoming calls (see IRpcStubBuffer::Invoke()) to the appropria
te interface on this object. pUnkServer may legally be NULL, in which case the c
aller is responsible for later calling IRpcStubBuffer::Connect() before using IR
pcStubBuffer::Invoke().
ppStub IRpcStubBuffer** the place at which the newly create stub is to b
e returned.
return value HRESULT S_OK, E_OUTOFMEMORY, E_NOINTERFACE, E_UNEXPECTED, no oth
ers.
9.7.3 IRpcChannelBuffer
IRpcChannelBuffer is the interface through which interface proxies send calls th
rough to the corresponding interface stub. This interface is implemented by the
RPC infrastructure. The infrastructure provides an instance of this interface to
interface proxies in IRpcProxyBuffer::Connect(). The interface proxies hold on
to this instance and use it each time they receive an incoming call.
interface IRpcChannelBuffer : IUnknown {
HRESULT GetBuffer(pMessage, riid);
HRESULT SendReceive(pMessage, pStatus);
HRESULT FreeBuffer(pMessage);
HRESULT GetDestCtx(pdwDestCtx, ppvDestCtx);
HRESULT IsConnected();
};
9.7.3.1 RPCOLEMESSAGE and related structures
Common to several of the methods in IRpcChannelBuffer is a data structure of typ
e RPCOLEMESSAGE. This structure is defined as is show below. The structure is to
be packed so that there are no holes in its memory layout.
typedef struct RPCOLEMESSAGE {
void * reserved1;
RPCOLEDATAREP dataRepresentation; // in NDR transfer synta
x: info about endianness, etc.
void * pvBuffer;
// memory buffer used for marshalling
ULONG cbBuffer;
// size of the marshalling buffer
ULONG iMethod;
// the method number being invoked
void * reserved2[5];
ULONG rpcFlags;
} on the ultimate destination machine MESSAGE;
The most significant member of this structure is pvBuffer. It is through the mem
ory buffer to which pvBuffer points that marshaled method arguments are transfer
red. cbBuffer is used to indicate the size of the buffer. iMethod is indicates a
particular method number within the interface being invoked. The IID of that in
terface is identified through other means: on the client side as a parameter to
GetBuffer(), and on the server side as part of the internal state of each interf
ace stub.
At all times all reserved values in this structure are to be initialized to zero
by non-RPC-infrastructure parties (i.e.: parties other than the channel / RPC ru
ntime implementor) who allocate RPCOLEMESSAGE structures. However, the RPC channe
l (more generally, the RPC runtime infrastructure) is free to modify these reser
ved fields. Therefore, once initialized, the reserved fields must be ignored by
the initializing code; they cannot be relied on to remain as zero. Further, ther
e are very carefully specified rules as to what values in these structures may or
may not be modified at various times and by which parties. In almost all cases,
aside from actually reading and writing data from the marshaling buffer, which
is done by proxies and stubs, only the channel may change these fields. See the
individual method descriptions for details.
Readers familiar with the connection-oriented DCE protocol may notice that the tr
ansfer syntax used for marshaling the arguments, the particular set of rules and
conventions according to which data is marshaled, is not explicitly called out.
Architecturally speaking, it is only the interface proxy for a given interface an
d its corresponding interface stub that cares at all about what set of marshalin
g rules is in fact used. However, in the general case these interface proxies an
d stubs may be installed on different machines with a network in the middle, be w
ritten by different development organizations on different operating systems, etc
. Accordingly, in cases where the author of an interface proxy for a given IID c
annot guarantee that all copies of the corresponding interface stub are in fact
always revised and updated in synchrony with his interface proxy, a well-defined
convention should be used for the transfer syntax. Indeed, formal transfer synta
x standards exist for this purpose. The one most commonly used is known as Networ
k Data Representation (NDR), originally developed by Apollo Corporation and subse
quently enhanced and adopted by the Open Software Foundation as part of their Dis
tributed Computing Environment (DCE).
When NDR transfer syntax is used (and whether it is in use or not is implicitly
known by the proxy or stub), the member dataRepresentation provides further info
rmation about the rules by which data in the buffer is marshaled. NDR is a multi-
canonical standard, meaning that rather than adopting one standard for things like
byte-order, character set, etc., multiple standards (a fixed set of them) are a
ccommodated. Specifically, this is accommodated by a reader make right policy: the
writer / marshaler of the data is free to write the data in any of the supporte
d variations and the reader / unmarshaler is expected to be able to read any of
them. The particular data type in use is conveyed in an RPCOLEDATAREP structure,
which is defined as follows. Note that this structure, too, is packed; the size
of the entire structure is exactly four bytes. The actual layout of the structur
e in all cases always corresponds to the data representation value as defined in
the DCE standard; the particular structure shown here is equivalent to that layou
t in Microsoft s and other common compilers.
typedef RPCOLEDATAREP {
UINT uCharacterRep : 4; // least signficant nibb
le of first byte
UINT uByteOrder : 4; // most signfica
nt nibble of first byte
BYTE uFloatRep;
BYTE uReserved;
BYTE uReserved2;
} RPCOLEDATAREP;
The values which may legally be found in these fields are as shown in Table . Fu
rther information on the interpretation of this field can be found in the NDR Tr
ansfer Syntax standards documentation.
Field Name Meaning of Field Value in field Interpretation
uCharacterRep determines interpretation of single-byte-character valued and si
ngle-byte-string valued entities 0
1 ASCII
EBCDIC
uByteOrder integer and floating point byte order 0
1 Big-endian (Motorola)
Little-endian (Intel)
uFloatRep representation of floating point numbers 0
1
2
3 IEEE
VAX
Cray
IBM
Table . Interpretation of dataPresentation
9.7.3.2 IRpcChannelBuffer::GetBuffer
HRESULT IRpcChannelBuffer::GetBuffer(pMessage, iid)
This method returns a buffer into which data can be marshaled for subsequent tra
nsmission over the wire. It is used both by interface proxies and by interface s
tubs, the former to marshal the incoming arguments for transmission to the serve
r, and the latter to marshal the return values back to the client.
Upon receipt of an incoming call from the client of the proxy object, interface
proxies use GetBuffer() to get a buffer into which they can marshaling the incom
ing arguments. A new buffer must be obtained for every call operation; old buffe
rs cannot be reused by the interface proxy. The proxy needs to ask for and corre
ctly manage a new buffer even if he himself does not have arguments to marshal (
i.e.: a void argument list). Having marshaled the arguments, the interface proxy
then calls SendReceive() to actually invoke the operation. Upon return from Sen
dReceive(), the buffer no longer contains the marshaled arguments but instead co
ntains the marshaled return values (and out parameter values). The interface pro
xy unmarshals these values, calls FreeBuffer() to free the buffer, then returns
to its calling client.
On the server side (in interface stubs), the sequence is somewhat different. The
server side will not be explored further here; see instead the description of I
RpcStubBuffer::Invoke() for details.
On the client side, the RPCOLEMESSAGE structure argument to GetBuffer() has been
allocated and initialized by the caller (or by some other party on the caller s beh
alf). Interface proxies are to initialize the members of this structure as follow
s.
Member Name Value to initalize to
reserved members as always, reserved values must be initialized to zero /
NULL.
pvBuffer must be NULL.
cbBuffer the size in bytes that the channel should allocate for the buffe
r; that is, the maximum size in bytes needed to marshal the arguments. The inter
face proxy will have determined this information by considering the function sig
nature and the particular argument values passed in.
It is explicitly legal to have this value be zero, indicating that that the call
er does not himself require a memory buffer.
iMethod the zero-based method number in the interface iid which is being invoked
dataRepresentation if NDR transfer syntax is being used, then this indicate
s the byte order, etc., by which the caller will marshal data into the returned
buffer.
rpcFlags ¨ Exact values to be listed here.
If the GetBuffer() function is successful, then upon function exit pvBuffer will
have been changed by the channel to point to a memory buffer of (at least) cbBu
ffer bytes in size into which the method arguments can now be marshaled (if cbBu
ffer was zero, pvBuffer may or may not be NULL). The reserved fields in the RPCO
LEMESSAGE structure may or may not have been changed by the channel. However, ne
ither the cbBuffer nor iMethod fields of RPCOLEMESSAGE will have been changed; t
he channel treats these as read-only. Furthermore, until such time as the now-al
located memory buffer is subsequently freed (see SendReceive() and FreeBuffer())
, no party other than the channel may modify any of the data accessible from pMe
ssage with the lone exceptions of the data pointed to by pvBuffer and the member
cbBuffer, which may be modified only in limited ways; see below.
The arguments to GetBuffer() are as follows:
Argument Type Description
pMessage RPCOLEMESSAGE * a message structure initialized as discussed abo
ve.
iid REFIID the interface identifier of the interface being invoked.
return value HRESULT S_OK, E_OUTOFMEMORY, E_UNEXPECTED
9.7.3.3 IRpcChannelBuffer::SendReceive
HRESULT IRpcChannelBuffer::SendReceive(pMessage, pStatus)
Cause an invocation to be sent across to the server process. The caller will hav
e first obtained access to a transmission packet in which to marshal the argumen
ts by calling IRpcChannelBuffer::GetBuffer(). The same pMessage structure passed
as an argument into that function is passed here to the channel a second time.
In the intervening time period, the method arguments will have been marshaled in
to the buffer pointed to by pMessage->pvBuffer. However, the pvBuffer pointer pa
rameter must on entry to SendReceive() be exactly as it was when returned from G
etBuffer(). That is, it must point to the start of the memory buffer. The caller
should in addition set pMessage->cbBuffer to the number of bytes actually writt
en into the buffer (zero is explicitly a legal value). No other values accessibl
e from pMessage may be different than they were on exit from GetBuffer().
Upon successful exit from SendReceive(), the incoming buffer pointed to by pvBuf
fer will have been freed by the channel. In its place will be found a buffer con
taining the marshaled return values / out parameters from the interface stub: pM
essage->pvBuffer points to the new buffer, and pMessage->cbBuffer indicates the
size thereof. If there are no such return values, then pMessage->cbBuffer is set
to zero, while pMessage?>pvBuffer may or may not be NULL.
On error exit from SendReceive(), the incoming buffer pointed to by pvBuffer may
or may not have been freed. If it has been freed, then on error exit pMessage?>p
vBuffer is set to NULL and pMessage->cbBuffer is set to zero. If in contrast, pM
essage->pvBuffer is on error exit not NULL, then that pointer, the data to which
it points, and the value pMessage->cbBuffer will contain exactly as they did on
entry; that is, the marshaled arguments will not have been touched. Thus, on err
or exit from SendReceive(), in no case are any marshaled return values passed ba
ck; if a marshaling buffer is in fact returned, then it contains the marshaled a
rguments as they were on entry.
The exact cases on error exit when the incoming buffer has or has not been freed
needs careful attention. There are three cases:
1) The channel implementation knows with certainty either that all of the i
ncoming data was successfully unmarshaled or that if any errors occurred during u
nmarshaling that the interface stub correctly cleaned up. In practical terms, thi
s condition is equivalent to the stub manager having actually called IRpcStubBuf
fer::Invoke() on the appropriate interface stub.
In this case, on exit from SendReceive() the incoming arguments will alwa
ys have been freed.
2) The channel implementation knows with certainty the situation in case 1)
has not occurred.
In this case, on exit from SendReceive(), the incoming arguments will ne
ver have been freed.
3) The channel implementation does not know with certainty that either of t
he above two cases has occurred.
In this case, on exit from SendReceive(), the incoming arguments will al
ways have been freed. This is a possible resource leakage (due to, for example,
CoReleaseMarshalData() calls that never get made), but it safely avoids freeing
resources that should not be freed.
If pMessage->pvBuffer is returned as non-NULL, then the caller is responsible fo
r subsequently freeing it; see FreeBuffer(). A returned non-NULL pMessage->pvBuf
fer may in general legally be (and will commonly be, the success case) different
than the (non-NULL) value on entry; i.e.: the buffer may be legally be reallocate
d. Further, between the return from SendReceive() and the subsequent freeing cal
l no data accessible from pMessage may be modified, with the possible exception o
f the data actually in the memory buffer.
Upon successful exit from SendReceive(), the pMessage->dataRepresentation field
will have been modified to contain whatever was returned by the interface stub i
n field of the same name value on exit to IRpcStubBuffer::Invoke(). This is partic
ularly important when NDR transfer syntax is used, as dataRepresentation indicat
es critical things (such as byte order) which apply to the marshaled return / ou
t values. Upon error exit from SendReceive(), pMessage?>dataRepresentation is und
efined.
Argument Type Description
pMessage RPCOLEMESSAGE * message structure containing info to transmit to
server.
pStatus ULONG * may legally be NULL. If non-NULL, then if either 1) an RPC-infras
tructure-detected server-object fault (e.g.: a server object bug caused an except
ion which was caught by the RPC infrastructure) or 2) an RPC communications fail
ure occurs, then at this location a status code is written which describes what
happened. In the two error cases, the errors E_RPCFAULT and E_RPCSTATUS are (res
pectively) returned (and are always returned when these errors occur, irrespecti
ve of the NULL-ness of pStatus).
return value HRESULT S_OK, E_RPCFAULT, E_RPCSTATUS
9.7.3.4 IRpcChannelBuffer::FreeBuffer
HRESULT IRpcChannelBuffer::FreeBuffer(pMessage)
Free a memory buffer in pMessage->pvBuffer that was previously allocated by the
channel.
At various times the RPC channel allocates a memory buffer and returns control o
f same to a calling client. Both GetBuffer() and SendReceive() do so, for exampl
e. FreeBuffer() is the means by which said calling client informs the channel th
at it is done with the buffer.
On function entry, the buffer which is to be freed is pMessage->pvBuffer, which
explicitly may or may not be NULL. If pMessage->pvBuffer is non-NULL, then FreeB
uffer() frees the buffer, NULLs the pointer, and returns NOERROR; if pMessage->p
vBuffer is NULL, then FreeBuffer() simply returns NOERROR (i.e.: passing NULL is
not an error). Thus, on function exit, pMessage->pvBuffer is always NULL. Notic
e that pMessage?>cbBuffer is never looked at or changed.
There are strict rules as to what data accessible from pMessage may have been mo
dified in the intervening time between the time the buffer was allocated and the
call to FreeBuffer(). In short, very little modification is permitted; see abov
e and below for precise details.
Argument Type Description
pMessage RPCOLEMESSAGE * pointer to structure containing pointer to buffe
r to free.
return value HRESULT S_OK, E_UNEXPECTED
9.7.3.5 IRpcChannelBuffer::GetDestCtx
HRESULT IRpcChannelBuffer::GetDestCtx(pdwDestCtx, ppvDestCtx)
Return the destination context for this RPC channel. The destination context her
e is as specified in the description of the IMarshal interface.
Argument Type Description
pdwDestCtx DWORD * the place at which the destination context is to be retu
rned.
ppvDestCtx void ** May be NULL. If non-NULL, then this is the place at whic
h auxiliary information associated with certain destination contexts will be ret
urned. Interface proxies may not hold on to this returned pointer in their inter
nal state; rather, they must assume that a subsequent call to IRpcChannel::Call(
) may in fact invalidate a previously returned destination context.
return value HRESULT S_OK, E_OUTOFMEMORY, E_UNEXPECTED, but no others.
9.7.3.6 IRpcChannelBuffer::IsConnected
HRESULT IRpcChannelBuffer::IsConnected()
Answers as to whether the RPC channel is still connected to the other side. A ne
gative reply is definitive: the connection to server end has definitely been ter
minated. A positive reply is tentative: the server end may or may not be still u
p. Interface proxies can if they wish use this method as an optimization by whic
h they can quickly return an error condition.
Argument Type Description
return value HRESULT S_OK, S_FALSE. No error values may be returned.
9.7.4 IRpcProxyBuffer
IRpcProxyBuffer interface is the interface by which the client-side infrastructu
re (i.e. the proxy manager) talks to the interface proxy instances that it manag
es. When created, proxies are aggregated into some larger object as per the norm
al creation process (where pUnkOuter in IPSFactoryBuffer::CreateProxy() is non-N
ULL). The controlling unknown will then QueryInterface() to the interface that i
t wishes to expose from the interface proxy.
interface IRpcProxyBuffer : IUnknown {
virtual HRESULT Connect(pRpcChannelBuffer) = 0;
virtual void Disconnect() = 0;
};
9.7.4.1 IRpcProxyBuffer::Connect
HRESULT IRpcProxyBuffer::Connect(pRpcChannelBuffer)
Connect the interface proxy to the indicated RPC channel. The proxy should hold
on to the channel, AddRef()ing it as per the usual rules. If the proxy is curren
tly connected, then this call fails (with E_UNEXPECTED); call Disconnect() first i
f in doubt.
Argument Type Description
pRpcChannelBuffer IRpcChannelBuffer* the RPC channel that the interfa
ce proxy is to use to effect invocations to the server object. May not be NULL.
return value HRESULT S_OK, E_OUTOFMEMORY, E_NOINTERFACE, E_UNEXPECTED
9.7.4.2 IRpcProxyBuffer::Disconnect
void IRpcProxyBuffer::Disconnect()
Informs the proxy that it should disconnect itself from any RPC channel that it
may currently be holding on to. This will involve Release()ing the IRpcChannel p
ointer to counteract the AddRef() done in IRpcProxy::Connect().
Notice that this function does not return a value.
9.7.5 IRpcStubBuffer
IRpcStubBuffer is the interface used on the server side by the RPC runtime infra
structure (herein referred to loosely as the channel ) to communicate with interfac
e stubs that it dynamically loads into a server process.
interface IRpcStubBuffer : IUnknown {
virtual HRESULT Connect(pUnkServer) = 0;
virtual void Disconnect() = 0;
virtual HRESULT Invoke(pMessage, pChannel) = 0;
virtual IRpcStubBuffer* IsIIDSupported(iid) = 0;
virtual ULONG CountRefs() = 0;
virtual HRESULT DebugServerQueryInterface(ppv) = 0;
virtual void DebugServerRelease(pv) = 0;
};
9.7.5.1 IRpcStubBuffer::Connect
HRESULT IRpcStubBuffer::Connect(pUnkServer)
Informs the interface stub of server object to which it is now to be connected,
and to which it should forward all subsequent Invoke() operations. The stub will
have to QueryInterface() on pUnkServer to obtain access to appropriate interface
s. The stub will of course follow the normal AddRef() rules when it stores point
ers to the server object in its internal state.
If the stub is currently connected, then this call fails with E_UNEXPECTED.
Argument Type Description
pUnkServer IUnknown * the new server object to which this stub is now
to be connected.
return value HRESULT S_OK, E_OUTOFMEMORY, E_NOINTERFACE, E_UNEXPECTED
9.7.5.2 IRpcStubBuffer::Disconnect
void IRpcStubBuffer::Disconnect()
Informs the stub that it should disconnect itself from any server object that it
may currently be holding on to. Notice that this function does not return a val
ue.
9.7.5.3 IRpcStubBuffer::Invoke
HRESULT IRpcStubBuffer::Invoke(pMessage, pChannel)
Invoke the pMessage->iMethod th method in the server object interface instance to
which this interface stub is currently connected. The RPC runtime infrastructure
(the channel ) calls this method on the appropriate interface stub upon receipt of
an incoming request from some remote client. See the discussion on page regardi
ng how interface stubs implicitly know the IID which they are servicing.
On entry, the members of pMessage are set as follows:
Member Name Value on entry to Invoke()
reserved members indeterminate. These members are neither to be read nor
to be changed by the stub.
pvBuffer points to a buffer which contains the marshaled incoming argumen
ts. In the case that there are no such arguments (i.e.: cbBuffer == 0), pvBuffer
may be NULL, but will not necessarily be so.
cbBuffer the size in bytes of the memory buffer to which pvBuffer points.
If pvBuffer is NULL, then cbBuffer will be zero (but the converse is not necess
arily true, as was mentioned in pvBuffer).
iMethod the zero-based method number in the interface which is being invoked
dataRepresentation if NDR transfer syntax is being used, then this indicate
s the byte order, etc., according to which the data in pvBuffer has been marshal
ed.
rpcFlags indeterminate. Neither to be read nor to be changed by the stub.
The stub is to do the following:
· unmarshal the incoming arguments,
· invoke the designated operation in the server object,
· ask the channel to allocate a new buffer for the return values and out values,
· marshal the return values and out values into the buffer, then
· return successfully (i.e.: NOERROR) from Invoke().
Errors may of course occur at various places in this process. Such errors will c
ause the stub to return an error from Invoke() rather than NOERROR. In cases whe
re such an error code is returned, it is the stub s responsibility to have cleaned
up any data and other resources allocated by the unmarshaling and marshaling pr
ocesses or returned as out values from the server object. However, the stub is n
ot responsible for invoking FreeBuffer() to free the actual marshaling buffer (i
.e.: it is illegal for the stub to do so); rather, on error return from Invoke()
the caller of Invoke() will ignore pvBuffer, and will also free it if non-NULL.
Having made that general statement as to the exit conditions of Invoke(), let us
examine its operation in greater detail.
If the stub cannot deal with the indicated dataRepresentation, it is to return R
PC_E_SERVER_INVALIDDATAREP. If it understands the data representation, the stub is t
o then unmarshal the arguments from the buffer provided in pMessage->pvBuffer, t
he size of which is passed in pMessage->cbBuffer. If the argument data cannot be
completely unmarshaled, the server is to free any partially unmarshaled data, t
hen return RPC_E_SERVER_CANTUNMARSHALDATA from Invoke().
If the data is successfully completely unmarshaled, then the interface stub is t
o invoke the designated method in the designated interface on the server object.
Notice that the incoming pvBuffer memory buffer is at this time still valid, an
d that therefore the stub may if it wishes and if appropriate for the argument a
nd data representations in question pass to the server object pointers which poi
nt directly into this buffer. The memory allocation and data copying that is thu
s avoided can at times be a significant performance optimization.
Once the invocation of the server object returns, the stub is to marshal the ret
urn value and out parameters returned from the server back to the client. It doe
s so irrespective of whether the server object invocation returned an error or s
uccess code; that is, the stub marshals back to the client whatever the server o
bject returned. The stub gets a reply buffer into which to do this marshaling by
calling pChannel->GetBuffer(), passing in the pMessage structure that it receiv
ed in Invoke(). Before calling GetBuffer(), the stub is to set the cbBuffer memb
er to the size that it requires for the to-be-allocated reply buffer. Zero is ex
plicitly a legal value for cbBuffer, and the stub must always call GetBuffer() (
more precisely, to be clear about the error case: the stub must always call GetB
uffer() if the server object method has actually been invoked) to allocate a rep
ly buffer, even if the stub itself does not require one (such as would be the ca
se if for a void-returning function with no out parameters). The stub must also
set dataRepresentation as appropriate for the standard by which it intends to ma
rshal the returning values (or would marshal them if there were some). Aside fro
m cbBuffer, dataRepresentation and possibly the contents of the bytes inside the
memory buffer, on entry to GetBuffer() no other data accessible from pMessage m
ay be different than they were on entry to Invoke().
Before it allocates a reply buffer, the call to GetBuffer() has the side effect
of freeing the memory buffer to which pvBuffer presently points. Thus, the act b
y the interface stub of allocating a reply buffer for the return values necessar
ily terminates access by the stub to the incoming marshaled arguments.
If GetBuffer() successfully allocates a reply buffer (see GetBuffer() for a desc
ription of how the stub determines this), then the stub is to marshal the return
value and returned out parameters into the buffer according to the rules of the
transfer syntax. Once this is complete, the stub is to set the cbBuffer member t
o the number of bytes it actually marshaled (if it marshaled nothing, then it mu
st explicitly set this to zero (but see also GetBuffer())), and then return NOER
ROR from Invoke().
If an error occurs during the unmarshaling of the incoming arguments or the mars
haling of the return values, then the interface stub is responsible for correctl
y freeing any resources consumed by the marshaled data. See in particular CoRele
aseMarshalData(). See also the discussion of this topic in IRpcChannelBuffer::SendRe
cieve().
Argument Type Description
pMessage RPCOLEMESSAGE * channel-allocated message structure.
pChannel IRpcChannelBuffer * the channel to use for buffer management
, etc.
return value HRESULT S_OK, RPC_E_SERVER_INVALIDDATAREP, RPC_E_SERVER_CANTUNMARSH
A, RPC_E_SERVER_CANTMARSHALDATA
9.7.5.4 IRpcStubBuffer::IsIIDSupported
IRpcStubBuffer* IRpcStubBuffer::IsIIDSupported(iid)
Answer whether this stub is designed to handle the unmarshaling of the indicated
interface.
If the stub buffer supports the specified IID, then it should return an appropri
ate IRpcStubBuffer* for that interface. Otherwise, the it should return NULL.
When presented with the need to remote a new IID on a given object, the RPC runt
ime typically calls this function on all the presently-connected interface stubs
in an attempt to locate one that can handle the marshaling for the request befo
re it goes to the trouble of creating a new stub.
As in IPSFactoryBuffer::CreateStub(), if this stub is presently connected to a s
erver object, then not only must this function verify that the stub can handle t
he requested interface id, but it must also verify (using QueryInterface()) that
the connected server object in fact supports the indicated interface (depending
on the IID and previous interface servicing requests, it may have already done s
o).
A common special case is the following: interface stubs which are designed to on
ly support one interface id (as most are designed to do) can simply check if iid
designates the one interface that they handle. If not, return false. Otherwise,
then if connected check that the server object supports the interface. Otherwis
e return true.
Argument Type Description
iid REFIID the interface that the caller wishes to know if the stub can han
dle. iid is never to be IID_IUnknown.
return value IRpcStubBuffer* see above.
9.7.5.5 IRpcStubBuffer::CountRefs
ULONG IRpcStub::CountRefs()
Return the total number of references that this stub interface instance has on t
he server object.
Argument Type Description
return value ULONG the number of such references.
9.7.5.6 IRpcStubBuffer::DebugServerQueryInterface
HRESULT IRpcStubBuffer::DebugServerQueryInterface(ppv)
This function exists in order to facilitate the support of debuggers which wish
to provide transparency when single-stepping, etc., across remote invocations on
objects. As such, the semantics of this function are a little strange in order
to avoid the unnecessarily disturbing the state of the actual server object.
If the stub is not presently connected then set *ppv to NULL (per the usual erro
r-case convention) and return E_UNEXPECTED. If connected but this stub does not s
upport the indicated interface (in the sense expressed in IsIIDSupported()), the
n (set *ppv to NULL and) return E_NOINTERFACE instead.
Otherwise, return the interface pointer on the connected server object which wou
ld be used by an immediate subsequent invocation of Invoke() on this interface s
tub (see the discussion on page regarding how interface stubs implicitly know t
he IID which they are servicing). DebugServerQueryInterface() is analogous to invokin
QueryInterface() on the server itself with the important difference that the ca
ller will later call DebugServerRelease() to indicate that he is done with the p
ointer instead of releasing the returned pointer himself. It is required that De
bugServerRelease() be called before the interface stub itself is destroyed or, i
n fact, before it is disconnected.
In the vast majority of interface stub implementations, DebugServerQueryInterfac
e() can therefore be implemented simply by returning an internal state variable i
nside the interface stub itself without doing an AddRef() on the server or other
wise running any code in the actual server object. In such implementations, DebugS
erverRelease() will be a completely empty no-op. The other rational implementati
on is one where DebugServerQueryInterface() does a QueryInterface() on the server o
bject and DebugServerRelease() does a corresponding Release(), but as this actua
lly runs server code, the former implementation is highly preferred if at all ac
hievable.
Argument Type Description
ppv void** the place at which the interface pointer is to be returned.
return value HRESULT S_OK, E_NOINTERFACE, E_UNEXPECTED
9.7.5.7 IRpcStubBuffer::DebugServerRelease
void IRpcStubBuffer::DebugServerRelease(pv)
Indicate that an interface pointer returned previously from DebugServerQueryInte
rface() is no longer needed by the caller. In most implementations, DebugServerR
elease() is a completely empty no-op; see the description of DebugServerQueryInt
erface() for details.
9.7.6 IStdMarshalInfo
The IStdMarshalInfo interface returns the CLSID identifying the handler to be us
ed in the destination process during standard marshaling.
An object that uses COM s default implementation of IMarshal does not provide its
own proxy but, by implementing IStdMarshalInfo, can nevertheless specify a handl
er to be loaded in the client process. Such a handler would typically handle cer
tain requests in-process and use COM s default marshaling to delegate others back
to the original object.
To create an instance of an object in some client process, COM must first determ
ine whether the object uses default marshaling or its own implementation. If the
object uses default marshaling, COM then queries the object to determine whethe
r it uses a special handler or, simply, COM s default proxy. To get the CLSID of t
he handler to be loaded, COM queries the object for the IStdMarshalInfo interfac
e and then the IPersist interface. If neither interface is supported, a standard
handler is used.
9.7.6.1.1 When to Implement
If you are writing a server application that supports class emulation (that is,
if your server can manipulate objects of another type in response to the Activat
e As option in the Convert dialog box), you must implement the IStdMarshalInfo i
nterface in order to return the CLSID of the handler to be used for the object.
Note that your handler must aggregate the default handler.
9.7.6.1.2 When to Use
You typically don t call this interface yourself. COM queries for this interface w
hen performing standard marshaling.
Methods in VTable Order
IUnknown Methods Description
QueryInterface Returns pointers to supported interfaces.
AddRef Increments reference count.
Release Decrements reference count.
IStdMarshalInfo Method Description
GetClassForHandler Obtains the class identifier of the object handler in th
e destination process.
See Also
IMarshal
9.7.6.2 IStdMarshalInfo::GetClassForHandler
Retrieves the CLSID of the object handler to be used in the destination process
during standard marshaling.
HRESULT GetClassForHandler(
10.3.1.2 IClientSecurity::CopyProxy
Makes a private copy of the specified proxy.
HRESULT CopyProxy(
IUnknown * punkProxy , //IUnknown pointer to the proxy to copy
IUnknown ** ppunkCopy //Indirect IUnknown pointer to the copy
);
Parameter
punkProxy
[in] Points to the IUnknown interface on the proxy to be copied. May not be NULL
.
ppunkCopy
[out] On successful return, points to the location of the IUnknown pointer to th
e copy of the proxy. It may not be NULL.
Return Values
S_OK
Success.
E_INVALIDARG
One or more arguments are invalid.
Remarks
IClientSecurity::CopyProxy makes a private copy of the specified proxy for the c
alling client. Its authentication information may be changed through a call to I
ClientSecurity::SetBlanket without affecting any other clients of the original p
roxy. The copy has the default values for the authentication information. The co
py has one reference and must be released.
The helper function CoCopyProxy encapsulates a QueryInterface call on the proxy
for a pointer to IClientSecurity, and with that pointer calls IClientSecurity::C
opyProxy, and then releases the IClientSecurity pointer.
Local interfaces may not be copied. IUnknown and IClientSecurity are examples of
existing local interfaces.
Copies of the same proxy have a special relationship with respect to QueryInterf
ace. Given a proxy, a, of the IA interface of a remote object, suppose a copy of
a is created, called b. In this case, calling QueryInterface from the b proxy f
or IID_IA will not retrieve the IA interface on b, but the one on a, the origina
l proxy with the default security settings for the IA interface.
See Also
CoCopyProxy
10.3.1.3 IClientSecurity::QueryBlanket
Retrieves authentication information.
HRESULT QueryBlanket(
void* pProxy, //Location for the proxy to query
DWORD* pAuthnSvc, //Location for the current authentication service
DWORD* pAuthzSvc, //Location for the current authorization service
OLECHAR ** pServerPrincName, //Location for the current principal nam
e
DWORD * pAuthnLevel, //Location for the current authentication level
DWORD * pImpLevel, //Location for the current impersonation level
RPC_AUTH_IDENTITY_HANDLE ** ppAuthInfo, //Location for the value passed
to IClientSecurity::SetBlanket
DWORD ** pCapabilities //Location for flags indicating further capabili
ties of the proxy
);
Parameter
pProxy
[in] Pointer to the proxy to query. ????Where does the initial pointer to the prox
y come from, and what interface might it point to????
pAuthnSvc
[out] Pointer to a DWORD value defining the current authentication service. This
will be a single value taken from the list of RPC_C_AUTHN_xxx constants. May be
NULL, in which case the current authentication service is not retrieved.
pAuthzSvc
[out] Pointer to a DWORD value defining the current authorization service. This
will be a single value taken from the list of RPC_C_AUTHZ_xxx constants. May be
NULL, in which case the current authorization service is not retrieved.
pServerPrincName
[out] Pointer to the current principal name. The string will be allocated by the
one called using CoTaskMemAlloc and must be freed by the caller using CoTaskMem
Free when they are done with it. May be NULL, in which case the principal name i
s not retrieved.
pAuthnLevel
[out] Pointer to a DWORD value defining the current authentication level. This w
ill be a single value taken from the list of RPC_C_AUTHN_LEVEL_xxx constants. Ma
y be NULL, in which case the current authentication level is not retrieved.
pImpLevel
[out] Pointer to a DWORD value defining the current impersonation level. This wi
ll be a single value taken from the list of RPC_C_IMP_LEVEL_xxx constants. May b
e NULL, in which case the current authentication level is not retrieved.
ppAuthInfo
[out] Pointer to the pointer value passed to IClientSecurity::SetBlanket indicat
ing the identity of the client. Because this points to the value itself and is n
ot a copy, it should not be manipulated. May be NULL, in which case the informat
ion is not retrieved.
pCapabilities
[out] Pointer to a DWORD of flags indicating further capabilities of the proxy.
Currently, no flags are defined for this parameter and it will only return zero.
May be NULL, in which case the flags indicating further capabilities are not re
trieved.
Return Values
S_OK
Success.
E_INVALIDARG
One or more arguments are invalid.
E_OUTOFMEMORY
Insufficient memory to create the pServerPrincName out-parameter.
Remarks
IClientSecurity::QueryBlanket is called by the client to retrieve the authentica
tion information COM will use on calls made from the specified proxy. With a poi
nter to an interface on the proxy, the client would first call QueryInterface fo
r a pointer to IClientSecurity, then, with this pointer, would call IClientSecur
ity::QueryBlanket, followed by releasing the pointer. This sequence of calls is
encapsulated in the helper function CoQueryProxyBlanket.
In pProxy, you can pass any proxy, such as a proxy you get through a call to CoC
reateInstance, CoUnmarshalInterface, or just passing an interface pointer as a p
arameter. It can be any interface. You cannot pass a pointer to something that i
s not a proxy. Thus you can t pass a pointer to an interface that has the local ke
yword in its interface definition since no proxy is created for such an interfac
e. IUnknown is the exception.
See Also
CoQueryProxyBlanket
10.3.1.4 IClientSecurity::SetBlanket
Sets the authentication information that will be used to make calls on the speci
fied proxy.
HRESULT SetBlanket(
void * pProxy, //Indicates the proxy to set
DWORD dwAuthnSvc, //Authentication service to use
DWORD dwAuthzSvc, //Authorization service to use
WCHAR * pServerPrincName, //The server principal name to use with the auth
entication service
DWORD dwAuthnLevel, //The authentication level to use
DWORD dwImpLevel, //The impersonation level to use
RPC_AUTH_IDENTITY_HANDLE * pAuthInfo, //The identity of the client
DWORD dwCapabilities //Undefined capability flags
);
Parameter
pProxy
[in] Indicates the proxy to set.
dwAuthnSvc
[in] A single DWORD value from the list of RPC_C_AUTHN_xxx constants indicating
the authentication service to use. It may be RPC_C_AUTHN_NONE if no authenticati
on is required.
dwAuthzSvc
[in] A single DWORD value from the list of RPC_C_AUTHZ_xxx constants indicating
the authorization service to use.
pServerPrincName
[in] Pointer to a WCHAR string that indicates the server principal name to use w
ith the authentication service. If you are using RPC_C_AUTHN_WINNT, the principa
l name must be NULL.
dwAuthnLevel
[in] A single DWORD value from the list of RPC_C_AUTHN_LEVEL_xxx constants indic
ating the authentication level to use.
dwImpLevel
[in] A single DWORD value from the list of RPC_C_IMP_LEVEL_xxx constants indicat
ing the impersonation level to use. Currently, only RPC_C_IMP_LEVEL_IMPERSONATE
and RPC_C_IMP_LEVEL_IDENTIFY are supported by NTLMSSP.
pAuthInfo
[in] Pointer to an RPC_AUTH_IDENTITY_HANDLE value that establishes the identity
of the client. It is authentication-service specific. Some authentication servic
es allow the application to pass in a different user name and password. COM keep
s a pointer to the memory passed in until COM is uninitialized or a new value is
set. If NULL is specified COM uses the current identity (the process token ). F
or NTLMSSP the structure is SEC_WINNT_AUTH_IDENTITY_W. The format of this struct
ure depends on the provider of the authentication service.
dwCapabilities
[in] A DWORD defining flags to establish indicating the further capabilities of
this proxy. Currently, no capability flags are defined.
The caller should specify EOAC_NONE. EOAC_MUTUAL_AUTH is defined and may be used
by other security providers, but is not supported by NTLMSSP. Thus, NTLMSSP wil
l accept this flag without generating an error but without providing mutual auth
entication.
Return Values
S_OK
Success, append the headers.
E_INVALIDARG
One or more arguments is invalid.
Remarks
IClientSecurity::SetBlanket sets the authentication information that will be use
d to make calls on the specified proxy. The values specified here override the v
alues chosen by automatic security. Calling this method changes the security val
ues for all other users of the specified proxy. Call IClientSecurity::CopyProxy
to make a private copy of the proxy.
By default, COM will choose the first available authentication service and autho
rization service available on both the client and server machines and the princi
pal name which the server registered for that authentication service. Currently,
COM will not try another authentication service if the first fails.
If pAuthInfo is NULL, it defaults to the current process token. dwAuthnLevel and
dwImpLevel default to the values specified to CoInitializeSecurity. If CoInitia
lizeSecurity is not called, the defaults are taken from the registry. The initia
l value for dwAuthnLevel on a proxy will be the higher of the value set on the c
lient s call to CoInitializeSecurity and the server s call to CoInitializeSecurity .
Security information cannot be set on local interfaces. For example, it is illeg
al to set security on the IClientSecurity interface. However, since that interfa
ce is supported locally, there is no need for security. IUnknown is a special ca
se. There are several cases. First, IUnknown cannot be copied. Thus all users of
an object get the same security. Second, SetBlanket can be used to set the secu
rity used for calls to QueryInterface. However, since QueryInterface is heavily
cached, the server might not see the call. Third, AddRef and Release always use
the security set with CoInitializeSecurity, never the values set with SetBlanket
.
See Also
CoSetProxyBlanket, CoQueryProxyBlanket, RPC_C_AUTHN_xxx, RPC_C_AUTHZ_xxx, RPC_C_
AUTHN_LEVEL_xxx, RPC_C_IMP_LEVEL_xxx
10.3.2 IServerSecurity
Used by a server to help identify the client and to manage impersonation of the
client. IServerSecurity:QueryBlanket and IServerSecurity::ImpersonateClient may
only be called before the ORPC call completes. The interface pointer must be rel
eased when it is no longer needed.
When a client calls a server, the server can call CoGetCallContext until the ser
ver sends the reply back to the client. The pointer to the instance of IServerS
ecurity returned by CoGetCallContext is automaticly deleted when the server send
s the reply back to the client.
When to Implement
The stub managment code in the system provides an implementation of IServerSecur
ity for objects by default as part of each incoming call, so typically you would
not implement this interface.
You may choose to implement IServerSecurity on the custom stubs of objects that
support custom marshaling to maintain a consistent programming model for their o
bjects.
When to Use
The methods of the IServerSecurity interface are called by the server/object to
examine or alter the security level of the connection between the caller and thi
s particular object. Its most common use is for impersonation (IServerSecurity::
ImpersonateClient and ::RevertToSelf), where the server impersonates the client
to test the privilege level of the calling client with an AccessCheck call. The
information obtained through IServerSecurity also allows an object to implement
its own security framework, perhaps not based on the Access Control Lists (ACLs)
that impersonation is geared toward. A different implementation could base its
security framework on the client name or other information available through a c
all to the QueryBlanket method.
Methods in Vtable Order
IUnknown Methods Description
QueryInterface Returns pointers to supported interfaces.
AddRef Increments the reference count.
Release Decrements the reference count.
IServerSecurity Methods Description
QueryBlanket Called by the server to find out about the client that invoked o
ne of its methods.
ImpersonateClient Allows a server to impersonate a client for the duration
of a call.
RevertToSelf Restores the authentication information on a thread to the proce
ss's identity.
IsImpersonating Indicates whether the server is currently impersonating the cli
ent.
See Also
Security in COM
10.3.2.1 IServerSecurity::QueryBlanket
Called by the server to find out about the client that invoked one of its method
s.
HRESULT QueryBlanket(
DWORD* pAuthnSvc, //Pointer to the current authentication service
DWORD* pAuthzSvc, //Pointer to the current authorization service
OLECHAR ** pServerPrincNam, //Pointer to the current principal name
DWORD * pAuthnLevel, //Pointer to the current authentication level
DWORD * pImpLevel, //Must be NULL
RPC_AUTHZ_HANDLE * pPrivs, //Pointer to string identifying client
DWORD ** pCapabilities //Pointer to flags indicating further capabiliti
es of the proxy
);
Parameter
pAuthnSvc
[out] Pointer to the current authentication service. This will be a single value
taken from the list of RPC_C_AUTHN_xxx constants. May be NULL, in which case th
e current authentication service is not returned.
pAuthzSvc
[out] Pointer to the current authorization service. This will be a single value
taken from the list of RPC_C_AUTHZ_xxx constants. May be NULL, in which case the
current authorization service is not returned.
pServerPrincName
[out] Pointer to the current principal name. The string will be allocated by the
callee using CoTaskMemAlloc, and must be freed by the caller using CoTaskMemFre
e when they are done with it. May be NULL, in which case the principal name is n
ot returned.
pAuthnLevel
[out] Pointer to the current authentication level. This will be a single value t
aken from the list of RPC_C_AUTHN_LEVEL_xxx constants. May be NULL, in which cas
e the current authorization level is not returned.
pImpLevel
[out] Must be NULL; the current authentication level is not supplied.
pPrivs
[out] Pointer to a string identifying the client. For NTLMSSP the string is of
the form domain\user. This is not a copy, and so should not be modified or freed
, and is not valid after the ORPC call completes.
pCapabilities
[out] Pointer to return flags indicating further capabilities of the call. Curre
ntly, no flags are defined for this parameter and it will only return EOAC_NONE.
May be NULL, in which case the flags indicating further capabilities are not re
turned.
Return Values
This method supports the standard return values E_INVALIDARG and E_OUTOFMEMORY,
as well as the following:
S_OK
Success.
Remarks
IServerSecurity::QueryBlanket is used by the server to find out about the client
that invoked one of its methods. To get a pointer to IServerSecurity for the cu
rrent call on the current thread, call CoGetCallContext, specifying IID_IServerS
ecurity. This interface pointer may only be used in the same apartment as the ca
ll for the duration of the call.
See Also
CoGetCallContext
10.3.2.2 IServerSecurity::ImpersonateClient
Allows a server to impersonate a client for the duration of a call.
HRESULT ImpersonateClient()
Return Values
This method supports the standard return value E_FAIL, as well as the following:
S_OK
Success.
Remarks
IServerSecurity::ImpersonateClient allows a server to impersonate a client for t
he duration of a call. What the server may do depends on the impersonation level
, specified through one of the RPC_C_IMP_LEVEL_xxx constants. The server may imp
ersonate the client on any secure call at identify, impersonate, or delegate lev
el. At identify level, the server may only find out the client name and perform
ACL checks; it may not access system objects as the client. At delegate level, t
he server may make off-machine calls while impersonating the client. The imperso
nation information only lasts until the end of the current method call. At that
time, IServerSecurity::RevertToSelf will automatically be called if necessary.
Traditionally, impersonation information is not nested - the last call to any Wi
n32 impersonation mechanism overrides any previous impersonation. However, in th
e apartment model, impersonation is maintained during nested calls. Thus if the
server A receives a call from B, impersonates, calls C, receives a call from D,
impersonates, reverts, and receives the reply from C, the impersonation will be
set back to B, not A.
Distributed COM currently does not support dynamic impersonation. The only way t
o change the client token associated with remote COM calls is to use IClientSecu
rity::SetBlanket on the proxy being called. Calling IServerSecurity::Impersonate
Client to impersonate your client and then making a remote call to another serve
r will not affect the token the second server sees when it impersonates on your
call.
See Also
CoImpersonateClient
10.3.2.3 IServerSecurity::RevertToSelf
Restores the authentication information on a thread to the process's identity.
HRESULT RevertToSelf()
Return Values
This method supports the standard return value E_FAIL, as well as the following:
S_OK
Success.
Remarks
IServerSecurity::RevertToSelf restores the authentication information and revert
s an impersonation on a thread to the process's identity. This method will only
revert impersonation changes made by IServerSecurity::ImpersonateClient. If the
thread token is modified by other means (through the SetThreadToken or RpcImpers
onateClient Win32 functions) the result of this function is undefined.
In the apartment model, CoRevertToSelf (IServerSecurity::RevertToSelf) affects o
nly the current method invocation. If there are nested method invocations, they
each may have their own impersonation and COM will correctly restore the imperso
nation before returning to them (regardless of whether or not CoRevertToSelf/ISe
rverSecurity::RevertToSelf was called).
See Also
CoRevertToSelf
10.3.2.4 IServerSecurity::IsImpersonating
Indicates whether IServerSecurity::ImpersonateClient has been called without a m
atching call to IServerSecurity::RevertToSelf.
BOOL IsImpersonating()
Return Values
TRUE
This thread has called IServerSecurity::ImpersonateClient and is currently imper
sonating the client of this call.
FALSE
This thread is not currently impersonating the client of this call.
See Also
IServerSecurity::RevertToSelf.
10.4 Security Related API Descriptions
10.4.1 CoCopyProxy
Makes a private copy of the specified proxy.
HRESULT CoCopyProxy(
IUnknown * punkProxy, //IUnknown pointer to the proxy to copy
IUnknown ** ppunkCopy //Address of output variable that receives
// the IUnknown interface pointer to the
//proxy copy
);
Parameter
punkProxy
[in] Points to the IUnknown interface on the proxy to be copied. May not be NULL
.
ppunkCopy
[out] Address of IUnknown* pointer variable that receives the interface pointer
to the copy of the proxy. It may not be NULL.
Return Values
S_OK
Success.
E_INVALIDARG
One or more arguments are invalid.
Remarks
CoCopyProxy makes a private copy of the specified proxy. Typically, this is call
ed when a client needs to change the authentication information of its proxy thr
ough a call to either CoSetClientBlanket or IClientSecurity::SetBlanket without
changing this information for other clients. CoSetClientBlanket affects all the
users of an instance of a proxy, so creating a private copy of the proxy through
a call to CoCopyProxy eliminates the problem.
This function encapsulates the following sequence of common calls (error handlin
g excluded):
pProxy->QueryInterface(IID_IClientSecurity, (void**)&pcs);
pcs->CopyProxy(punkProxy, ppunkCopy);
pcs->Release();
Local interfaces may not be copied. IUnknown and IClientSecurity are examples of
existing local interfaces.
Copies of the same proxy have a special relationship with respect to QueryInterf
ace. Given a proxy, a, of the IA interface of a remote object, suppose a copy of
a is created, called b. In this case, calling QueryInterface from the b proxy f
or IID_IA will not retrieve the IA interface on b, but the one on a, the origina
l proxy with the default security settings for the IA interface.
See Also
IClientSecurity::CopyProxy, Security in COM
10.4.2 CoGetCallContext
Retrieves the context of the current call on the current thread.
HRESULT CoGetCallContext(
REFIID riid, //Interface identifier
void ** ppv //Address of output variable that receives the
// interface pointer requested in riid
);
Parameters
riid
[in] Interface identifier (IID) of the call context that is being requested. If
you are using the default call context supported by standard marshaling, only II
D_IServerSecurity is available.
ppv
[out] Address of pointer variable that receives the interface pointer requested
in riid. Upon successful return, *ppv contains the requested interface pointer.
Return Values
S_OK
Success.
E_NOINTERFACE
The call context does not support the interface identified by riid.
Remarks
CoGetCallContext retrieves the context of the current call on the current thread
. The riid parameter specifies the interface on the context to be retrieved. Cur
rently, only IServerSecurity is available from the default call context supporte
d by standard marshaling.
This is one of the functions provided to give the server access to any contextua
l information of the caller and to encapsulate common sequences of security chec
king and caller impersonation.
See Also
IServerSecurity, Security in COM
10.4.3 CoImpersonateClient
Allows the server to impersonate the client of the current call for the duration
of the call.
HRESULT CoImpersonateClient( )
Return Values
This function supports the standard return value E_INVALIDARG, as well as the fo
llowing:
S_OK
Indicates success.
Remarks
Allows the server to impersonate the client of the current call for the duration
of the call. If you do not call CoRevertToSelf, COM reverts automatically for y
ou. This function will fail unless the object is being called with RPC_C_AUTHN_L
EVEL_CONNECT or higher authentication in effect (any authentication level except
RPC_C_AUTHN_LEVEL_NONE) This function encapsulates the following sequence of co
mmon calls (error handling excluded):
CoGetCallContext(IID_IServerSecurity, (void**)&pss);
pss->ImpersonateClient();
pss->Release();
This helper function encapsulates the process of getting a pointer to an instanc
e of IServerSecurity that contains data about the current call, calling its Impe
rsonateClient method, and then releasing the pointer.
See Also
IServerSecurity::ImpersonateClient, Security in COM
10.4.4 CoInitializeSecurity
Registers security and sets the default security values for the process. For leg
acy applications, COM automatically calls this function with values from the reg
istry. It is invoked once per process, rather than for each thread in the proces
s. If you set registry values and then call CoInitializeSecurity, the AppID regi
stry values will be ignored, and the CoInitializeSecurity values will be used.
HRESULT CoInitializeSecurity(
PSECURITY_DESCRIPTOR pVoid, //Points to security descriptor
DWORD cAuthSvc, //Count of entries in asAuthSvc
SOLE_AUTHENTICATION_SERVICE * asAuthSvc, //Array of names to register
void * pReserved1, //Reserved for future use
DWORD dwAuthnLevel, //The default authentication level for proxies
DWORD dwImpLevel, //The default impersonation level for proxies
RPC_AUTH_IDENTITY_HANDLE pAuthInfo, //Reserved; must be set to NULL
DWORD dwCapabilities, //Additional client and/or server-side capabilit
ies
void * pvReserved2 //Reserved for future use
);
Parameters
pVoid
[in] Defines the access permissions. If the capability flags (pCapabilities) are
not EOAC_APPID or EOAC_ACCESS_CONTROL, must be a pointer to a Win32 security de
scriptor. If EOAC_APPID is specified, must be a pointer to a GUID that specifies
the AppID of the process. In this case, all other parameters of the call are ig
nored, and registry values are used for security checks. If EOAC_ACCESS_CONTROL
is specified, must be a pointer to an IAccessControl interface, which will be us
ed to check access. See Remarks for more information. If NULL, no ACL checking w
ill be done. If not NULL, COM will check ACLs on new connections. If not NULL, d
wAuthnLevel cannot be RPC_C_AUTHN_LEVEL_NONE.
cAuthSvc
[in] Count of entries in asAuthSvc. Zero means register no services. A value of
-1 tells COM to choose which authentication services to register.
asAuthSvc
[in] Array of authentication/authorization/principal names to register. These va
lues are registered to allow incoming calls. After that they are ignored. The de
fault authentication/authorization/principal for each proxy will be negotiated r
egardless of whether these are set. For example, if the application registers RP
C_C_AUTHN_WINNT and receives and interface from a machine that only supports RPC
_C_AUTHN_DEC_PUBLIC, COM will choose RPC_C_AUTHN_DEC_PUBLIC if this machine supp
orts it.
pReserved1
[in] Reserved for future use; must be NULL.
dwAuthnLevel
[in] The default authentication level for proxies. On the server side, COM will
fail calls that arrive at a lower level. All calls to AddRef and Release are mad
e at this level.
dwImpLevel
[in] The default impersonation level for proxies. This value is not checked on t
he server side. AddRef and Release calls are made with this impersonation level
so even security aware apps should set this carefully. Setting IUnknown security
only affects calls to QueryInterface, not AddRef or Release.
pAuthInfo
[in] Reserved for future use; must be NULL.
dwCapabilities
[in] Additional client and/or server-side capabilitiesThese flags are described
in EOLE_AUTHENTICATION_CAPABILITIES. If EOLE_APPID is specified, pVoid must be a
pointer to a GUID specifying the AppID of the process. If EOLE_ACCESS_CONTROL i
s set, pVoid must be a pointer to the IAccessControl interface on an access cont
rol object. For more information, see the remarks.
pReserved2
[in] Reserved for future use; must be zero.
Return Values
This function supports the standard return value E_INVALIDARG, as well as the fo
llowing:
S_OK
Indicates success.
Remarks
The CoInitializeSecurity layer initializes the security layer and sets the speci
fied values as the security default.
If the application does not call CoInitializeSecurity, COM calls it automaticall
y the first time an interface is marshaled or unmarshaled, registering the syste
m default security. No default security packages will be registered till then.
The first parameter, pVoid, can be one of three types of value, depending on the
value of pCapabilities: a Win32 security descriptor, a pointer to a GUID specif
ying the AppID of the process, or an IAccessControl pointer.
If any capability flags other than EOAC_APPID or EOAC_ACCESS_CONTROL are called,
pVoid must be a pointer to a Win32 SECURITY_DESCRIPTOR. A NULL DACL will allow
calls from anyone. A DACL with no ACEs allows no access. For information on ACLs
and ACEs, refer to the Win32 Programmers Reference section Access Control Model
.
The owner and group of the SECURITY_DESCRIPTOR must be set applications should c
all AccessCheck (not IsValidSecurityDescriptor) to ensure that their security de
scriptor is correctly formed prior to calling CoInitializeSecurity.
If the application passes a NULL security descriptor, COM will construct one tha
t allows calls from the current user and local system. All new connections will
be audited. Distributed COM will copy the security descriptor.
If mutual authentication is enabled all calls will fail unless the server identi
ty is verified to match the principal name set on the proxy. Without mutual auth
entication, security only helps the server; the client has no idea who is handli
ng his call. While CoInitializeSecurity takes principal names as parameters, tha
t does not mean that the server can register any arbitrary name. The security pr
ovider verifies that the server has a right to use the names registered.
Secure references cause DCOM to make extra callbacks to insure that objects are
not released maliciously.
When the EOAC_APPID flag is set, CoInitializeSecurity looks for the authenticati
on level under the AppID. If the authentication level is not found, it looks for
the default authentication level. If the default authentication level is not fo
und, it generates a default authentication level of connect. If the authenticati
on level is not NONE, CoInitializeSecurity looks for the access permission value
under the AppID. If not found, it looks for the default access permission value
. If not found, it generates a default access permission. All the other security
settings are determined the same way as for a legacy application.
When the EOAC_APPID flag is set, all parameters to CoInitializeSecurity except p
Void are ignored. If pVoid is NULL, CoInitializeSecurity will look up the applic
ation .exe name in the registry and use the AppID stored there. Note that this g
ives the same security as if you did not call CoInitializeSecurity.
The IClientSecurity::SetBlanket method and CoSetProxyBlanket function return an
error if you set any of the following flags in the capabilities: EOAC_SECURE_REF
S, EOAC_ACCESS_CONTROL, or EOAC_APPID.
The CoInitializeSecurity function returns an error if both the EOAC_APPID and EO
AC_ACCESS_CONTROL flags are set.
When you set the cloaking capability through the EOAC_CLOAK capability flag, thi
s picks up the token only on the first call to the proxy; dynamic cloaking, in w
hich the token would be picked up on every call, is not supported.
See Also
RPC_C_IMP_LEVEL_xxx, RPC_C_AUTHN_LEVEL_xxx, Security in COM
10.4.5 CoQueryAuthenticationServices
Retrieves a list of the authentication services registered when the process call
ed CoInitializeSecurity.
HRESULT CoQueryAuthenticationServices(
DWORD * pcAuthSvc, //Pointer to the number of entries returned in the array
SOLE_AUTHENTICATION_SERVICE** prgAuthSvc //Pointer to an array of structu
res
);
Parameters
pcAuthSvc
[out] Pointer to return the number of entries returned in the rgAuthSvc array. M
ay not be NULL.
prgAuthSvc
[out] Pointer to an array of SOLE_AUTHENTICATION_SERVICE structures. The list is
allocated through a call to CoTaskMemAlloc. The caller must free the list when
finished with it by calling CoTaskMemFree.
Return Values
This function supports the standard return values E_INVALIDARG and
E_OUTOFMEMORY, as well as the following:
S_OK
Indicates success.
Remarks
CoQueryAuthenticationServices retrieves a list of the authentication services cu
rrently registered. If the process calls CoInitializeSecurity, these are the ser
vices registered through that call. If the application does not call it, CoIniti
alizeSecurity is called automatically by COM, registering the default security p
ackage, the first time an interface is marshaled or unmarshaled.
This function is primarily useful for custom marshalers, to determine which prin
cipal names an application can use.
Different authentication services support different levels of security. For exam
ple, NTLMSSP does not support delegation or mutual authentication while Kerberos
does. The application is responsible only for registering authentication servic
es that provide the features the application needs. This is the way to query whi
ch services have been registered with CoInitializeSecurity.
See Also
CoInitializeSecurity, SOLE_AUTHENTICATION_SERVICE structure, Security in COM
10.4.6 CoQueryClientBlanket
Called by the server to find out about the client that invoked the method execut
ing on the current thread.
HRESULT CoQueryClientBlanket(
DWORD* pAuthnSvc, //Pointer to the current authentication service
DWORD* pAuthzSvc, //Pointer to the current authorization service
OLECHAR ** pServerPrincName, //Pointer to the current principal name
DWORD * pAuthnLevel, //Pointer to the current authentication level
Return Values
S_OK
Success, append the headers.
E_INVALIDARG
One or more arguments is invalid.
Remarks
Sets the authentication information that will be used to make calls on the speci
fied proxy. . The IClientSecurity::SetBlanket method and CoSetProxyBlanket funct
ion return an error if you set any of the following flags in the capabilities: E
OAC_SECURE_REFS, EOAC_ACCESS_CONTROL, or EOAC_APPID. This function encapsulates
the following sequence of common calls (error handling excluded):
pProxy->QueryInterface(IID_IClientSecurity, (void**)&pcs);
pcs->SetBlanket(pProxy, dwAuthnSvc, dwAuthzSvc, pServerPrincName,
dwAuthnLevel, dwImpLevel, pAuthInfo, dwCapabilities);
pcs->Release();
See Also
IClientSecurity::SetBlanket, CoQueryClientBlanket, Security in COM
10.5 Security Related Structure Definitions
10.5.1 COAUTHINFO
Determines the authentication settings used while making a remote activation req
uest from the client scm to the server.
typedef struct _COAUTHINFO
{
DWORD dwAuthnSvc;
DWORD dwAuthzSvc;
[string] WCHAR * pwszServerPrincName;
DWORD dwAuthnLevel;
DWORD dwImpersonationLevel;
AUTH_IDENTITY * pAuthIdentityData;
DWORD dwCapabilities;
} COAUTHINFO;
Members
dwAuthnSvc
[in] A single DWORD value from the list of RPC_C_AUTHN_xxx constants indicating
the authentication service to use. It may be RPC_C_AUTHN_NONE if no authenticati
on is required.
dwAuthzSvc
[in] A single DWORD value from the list of RPC_C_AUTHZ_xxx constants indicating
the authorization service to use.
pwszServerPrincName
Pointer to a WCHAR string that indicates the server principal name to use with t
he authentication service. If you are using RPC_C_AUTHN_WINNT, the principal nam
e must be NULL.
dwAuthnLevel
[in] A single DWORD value from the list of RPC_C_AUTHN_LEVEL_xxx constants indic
ating the authentication level to use.
dwImpersonationLevel
[in] A single DWORD value from the list of RPC_C_IMP_LEVEL_xxx constants indicat
ing the impersonation level to use. Currently, only RPC_C_IMP_LEVEL_IMPERSONATE
and RPC_C_IMP_LEVEL_IDENTIFY are supported.
pAuthIdentityData
Pointer to an AUTH_IDENTITY structure that establishes the identity of the clien
t. It is authentication-service specific, as follows:
typedef struct _AUTH_IDENTITY
{
[size_is(UserLength+1)] USHORT * User;
ULONG UserLength;
[size_is(DomainLength+1)] USHORT * Domain;
ULONG DomainLength;
[size_is(PasswordLength+1)] USHORT * Password;
ULONG PasswordLength;
ULONG Flags;
} AUTH_IDENTITY;
dwCapabilities
[in] A DWORD defining flags to establish indicating the further capabilities of
this proxy. Currently, no capability flags are defined.
Remarks
The values of the COAUTHINFO structure determine the authentication settings use
d while making a remote activation request from the client's scm to the server's
scm. This structure is defined by default for NTLMSSP, and is described only f
or cases that need it to allow DCOM activations to work correctly with security
providers other than NTLMSSP, or to specify additional security information used
during remote activations for interoperability with alternate implementations o
f distributed COM
See Also
COSERVERINFO
10.5.2 COSERVERINFO
Identifies a remote machine resource to the new or enhanced activation functions
. The structure is defined as follows in the Wtypes.h header file:
typedef struct _COSERVERINFO
{
DWORD dwReserved1;
LPWSTR pwszName;
COAUTHINFO *pAuthInfo;
DWORD dwReserved2;
} COSERVERINFO;
Members
dwReserved1
Reserved for future use. Must be 0.
pszName
Pointer to the name of the machine to be used.
pAuthInfo
A non-zero value, which is a pointer to a COAUTHINFO structure, would only be us
ed when a security package other than NTLMSSP is being used.
dwReserved2
Reserved for future use. Must be 0.
Remarks
The COSERVERINFO structure is used primarily to identify a remote system in obje
ct creation functions. Machine resources are named using the naming scheme of th
e network transport. By default, all UNC ( \\server or server ) and DNS names ( server.c
om , www.foo.com , or 135.5.33.19 ) names are allowed.
If you are using the NTLMSSP security package, the default case, the pAuthinfo p
arameter should be set to zero. If you are a vendor supporting another security
package, refer to COAUTHINFO. The mechanism described there is intended to allow
DCOM activations to work correctly with security providers other than NTLMSSP,
or to specify additional security information used during remote activations for
interoperability with alternate implementations of DCOM. If pAuthInfo is set, t
hose values will be used to specify the authentication settings for the remote c
all. These settings will be passed to RpcBindingSetAuthInfoEx.
If the pAuthInfo field is not specified, any values in the AppID section of the
registry will be used to override the following default authentication settings:
dwAuthnSvc RPC_C_AUTHN_WINNT
dwAuthzSvc RPC_C_AUTHZ_NONE
pszServerPrincName NULL
dwAuthnLevel RPC_C_AUTHN_LEVEL_CONNECT
dwImpersonationLevel RPC_C_IMP_LEVEL_IMPERSONATE
pvAuthIdentityData NULL
dwCapabilities RPC_C_QOS_CAPABILITIES_DEFAULT
See Also
CLSCTX, CoGetClassObject, CoGetInstanceFromFile, CoGetInstanceFromIStorage, CoCr
eateInstanceEx, Locating a Remote Object
10.6 Security Related Enumeration Descriptions
10.6.1 RPC_C_AUTHN_XXX
These values, along with the RPC_C_AUTHZ_xxx values, are assigned to the SOLE_AU
THENICATION_SERVICE structure, which is retrieved by the CoQueryAuthenticationSe
rvices function, and passed in to the CoInitializeSecurity function.
Values
RPC_C_AUTHN_NONE
No authentication.
RPC_C_AUTHN_DCE_PRIVATE
DCE private key authentication.
RPC_C_AUTHN_DCE_PUBLIC
DCE public key authentication.
RPC_C_AUTHN_DEC_PUBLIC
DEC public key authentication (reserved for future use).
RPC_C_AUTHN_WINNT
NT LM SSP (NT Security Service).
RPC_C_AUTHN_DEFAULT
The system default authentication service.
See Also
CoInitializeSecurity, CoQueryAuthenticationServices
10.6.2 RPC_C_AUTH_LEVEL_XXX
Used in the security functions and interfaces to specify the authentication leve
l.
Values
RPC_C_AUTHN_LEVEL_NONE
Performs no authentication.
RPC_C_AUTHN_LEVEL_CONNECT
Authenticates only when the client establishes a relationship with the server. D
atagram transports always use RPC_AUTHN_LEVEL_PKT instead.
RPC_C_AUTHN_LEVEL_CALL
Authenticates only at the beginning of each remote procedure call when the serve
r receives the request. Datagram transports use RPC_C_AUTHN_LEVEL_PKT instead.
RPC_C_AUTHN_LEVEL_PKT
Authenticates that all data received is from the expected client.
RPC_C_AUTHN_LEVEL_PKT_INTEGRITY
Authenticates and verifies that none of the data transferred between client and
server has been modified.
RPC_C_AUTHN_LEVEL_PKT_PRIVACY
Authenticates all previous levels and encrypts the argument value of each remote
procedure call.
See Also
IClientSecurity, IServerSecurity
10.6.3 RPC_C_AUTHZ_XXX
These values define what the server authorizes, and are used by methods of the I
ClientSecurity interface. Along with the RPC_C_AUTHN_xxx values, these are the v
alues assigned to the SOLE_AUTHENTICATION_SERVICE structure, which is retrieved
by the CoQueryAuthenticationServices function, and passed in to the CoInitialize
Security function.
Values
RPC_C_AUTHZ_NONE
Server performs no authorization.
RPC_C_AUTHZ_NAME
Server performs authorization based on the client's principal name.
RPC_C_AUTHZ_DCE
Server performs authorization checking using the client's DCE privilege attribut
e certificate (PAC) information, which is sent to the server with each remote pr
ocedure call made using the binding handle. Generally, access is checked against
DCE access control lists (ACLs).
See Also
SOLE_AUTHENTICATION_SERVICE
10.6.4 RPC_C_IMP_LEVEL_XXX
Used in the security functions and interfaces to specify the authentication leve
l.
Values
RPC_C_IMP_LEVEL_ANONYMOUS
(Not supported in this release.) The client is anonymous to the server. The serv
er process cannot obtain identification information about the client and it cann
ot impersonate the client.
RPC_C_IMP_LEVEL_IDENTIFY
The server can obtain the client's identity. The server can impersonate the clie
nt for ACL checking, but cannot access system objects as the client. This inform
ation is obtained when the connection is established, not on every call.
Note GetUserName will fail while impersonating at identify level. The workarou
nd is to impersonate, OpenThreadToken, revert, call GetTokenInformation, and fin
ally, call LookupAccountSid.
RPC_C_IMP_LEVEL_IMPERSONATE
The server process can impersonate the client's security context while acting on
behalf of the client. This information is obtained when the connection is estab
lished, not on every call.
RPC_C_IMP_LEVEL_DELEGATE
(Not supported in this release.) The server process can impersonate the client's
security context while acting on behalf of the client. The server process can a
lso make outgoing calls to other servers while acting on behalf of the client. T
his information is obtained when the connection is established, not on every cal
l.
Comments
See Also
CoInitializeSecurity
11. Error Handling
COM provides a rich mechanism for allowing objects to return error information t
o 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.
11.1 Returning Error Information
To return error information
1. Implement the ISupportErrorInfo interface.
2. To create an instance of the generic error object, call the Crea
teErrorInfo function.
3. To set its contents, use the ICreateErrorInfo methods.
4. To associate the error object with the current logical thread, c
all 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 thre
ad of execution.
11.2 Retrieving Error Information
To retrieve error information
1 Check whether the returned value represents an error that the object is
prepared to handle.
2 Call QueryInterface to get a pointer to the ISupportErrorInfo interface.
Then, call InterfaceSupportsErrorInfo to verify that the error was raised by th
e object that returned it and that the error object pertains to the current erro
r, and not to a previous call.
3 To get a pointer to the error object, call the GetErrorInfo function.
4 To retrieve information from the error object, use the IErrorInfo method
s.
If the object is not prepared to handle the error, but needs to propagate the er
ror information further down the call chain, it should simply pass the return va
lue to its caller. Because the GetErrorInfo function clears the error informatio
n and passes ownership of the error object to the caller, the function should be
called only by the object that handles the error.
11.3 Error Handling API Descriptions
11.3.1 IErrorInfo
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
11.3.1.1 IErrorInfo::GetDescription
HRESULT GetDescription(
BSTR *pBstrDescription
);
Returns a textual description of the error.
Parameter
pBstrDescription
Pointer to a brief string that describes the error.
Return Value
The return value obtained from the returned HRESULT is:
Return value Meaning
S_OK Success.
Comments
The text is returned in the language specified by the locale identifier (LCID) t
hat was passed to IDispatch::Invoke for the method that encountered the error.
11.3.1.2 IErrorInfo::GetGUID
HRESULT GetGUID(
GUID *pGUID
);
Returns the globally unique identifier (GUID) of the interface that defined the
error.
Parameter
pGUID
Pointer to a GUID, or GUID_NULL, if the error was defined by the operating syste
m.
Return Value
The return value obtained from the returned HRESULT is:
Return value Meaning
S_OK Success.
Comments
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 c
an handle errors in an interface, independent of the class that implements the i
nterface.
11.3.1.3 IErrorInfo::GetHelpContext
HRESULT GetHelpContext(
DWORD *pdwHelpContext
);
Returns the Help context identifier (ID) for the error.
Parameter
pdwHelpContext
Pointer to the Help context ID for the error.
Return Value
The return value obtained from the returned HRESULT is:
Return value Meaning
S_OK Success.
Comments
IErrorInfo::GetHelpContext returns the Help context ID for the error. To find th
e Help file to which it applies, use IErrorInfo::GetHelpFile.
11.3.1.4 IErrorInfo::GetHelpFile
HRESULT GetHelpFile(
BSTR *pBstrHelpFile
);
Returns the path of the Help file that describes the error.
Parameter
pBstrHelpFile
Pointer to a string that contains the fully qualified path of the Help file.
Return Value
The return value obtained from the returned HRESULT is:
Return value Meaning
S_OK Success.
Comments
IErrorInfo::GetHelpFile returns the fully qualified path of the Help file that d
escribes the current error. IErrorInfo::GetHelpContext should be used to find th
e Help context ID for the error in the Help file.
11.3.1.5 IErrorInfo::GetSource
HRESULT GetSource(
BSTR *pBstrSource
);
Returns the language-dependent programmatic ID (ProgID) for the class or applica
tion that raised the error.
Parameter
pBstrSource
Pointer to a string containing a ProgID, in the form progname.objectname.
Return Value
The return value obtained from the returned HRESULT is:
Return value Meaning
S_OK Success.
Comments
Use IErrorInfo::GetSource to determine the class or application that is the sour
ce 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.
11.3.2 ICreateErrorInfo
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
11.3.2.1 ICreateErrorInfo::SetDescription
HRESULT SetDescription(
LPCOLESTR *szDescription
);
Sets the textual description of the error.
Parameter
szDescription
A brief, zero-terminated string that describes the error.
Return Value
The return value obtained from the returned HRESULT is one of the following:
Return value Meaning
S_OK Success.
E_OUTOFMEMORY Insufficient memory to complete the operation.
Comments
The text should be supplied in the language specified by the locale ID (LCID) th
at was passed to the method raising the error. For more information, see " LCID Attrib
ute " in Chapter 17, " Type Libraries and the Object Description Language. "
Example
hr = CreateErrorInfo(&pcerrinfo);
if (m_excepinfo.bstrDescription)
pcerrinfo->SetDescription(m_excepinfo.bstrDescription);
11.3.2.2 ICreateErrorInfo::SetGUID
HRESULT SetGUID(
REFGUID rguid
);
Sets the globally unique identifier (GUID) of the interface that defined the err
or.
Parameter
rguid
The GUID of the interface that defined the error, or GUID_NULL if the error was
defined by the operating system.
Return Value
The return value obtained from the returned HRESULT is one of the following:
Return value Meaning
S_OK Success.
E_OUTOFMEMORY Insufficient memory to complete the operation.
Comments
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_N
ULL.
This GUID does not necessarily represent the source of the error; however, the s
ource is the class or application that raised the error. Using the GUID, applica
tions can handle errors in an interface, independent of the class that implement
s the interface.
Example
hr = CreateErrorInfo(&pcerrinfo);
pcerrinfo->SetGUID(IID_IHello);
11.3.2.3 ICreateErrorInfo::SetHelpContext
HRESULT SetHelpContext(
DWORD dwHelpContext
);
Sets the Help context identifier (ID) for the error.
Parameter
dwHelpContext
The Help context ID for the error.
Return Value
The return value obtained from the returned HRESULT is one of the following:
Return value Meaning
S_OK Success.
E_OUTOFMEMORY Insufficient memory to complete the operation.
Comments
ICreateErrorInfo::SetHelpContext sets the Help context ID for the error. To esta
blish the Help file to which it applies, use ICreateErrorInfo::SetHelpFile.
Example
hr = CreateErrorInfo(&pcerrinfo);
pcerrinfo->SetHelpContext(dwhelpcontext);
11.3.2.4 ICreateErrorInfo::SetHelpFile
HRESULT SetHelpFile(
LPCOLESTR szHelpFile
);
Sets the path of the Help file that describes the error.
Parameter
szHelpFile
The fully qualified path of the Help file that describes the error.
Return Value
The return value obtained from the returned HRESULT is one of the following:
Return value Meaning
S_OK Success.
E_OUTOFMEMORY Insufficient memory to complete the operation.
Comments
ICreateErrorInfo::SetHelpFile sets the fully qualified path of the Help file tha
t describes the current error. Use ICreateErrorInfo::SetHelpContext to set the H
elp context ID for the error in the Help file.
Example
hr = CreateErrorInfo(&pcerrinfo);
pcerrinfo->SetHelpFile( " C:\myapp\myapp.hlp " );
11.3.2.5 ICreateErrorInfo::SetSource
HRESULT SetSource(
LPCOLESTR szSource
);
Sets the language-dependent programmatic identifier (ProgID) for the class or ap
plication that raised the error.
Parameter
szSource
A ProgID in the form progname.objectname.
Return Value
The return value obtained from the returned HRESULT is one of the following:
Return value Meaning
S_OK Success.
E_OUTOFMEMORY Insufficient memory to complete the operation.
Comments
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 invoc
ation.
Example
hr = CreateErrorInfo(&pcerrinfo);
if (m_excepinfo.bstrSource)
pcerrinfo->SetSource(m_excepinfo.bstrSource);
11.3.3 ISupportErrorInfo
The ISupportErrorInfo interface ensures that error information can be propagated
up the call chain correctly. Automation objects that use the error handling int
erfaces must implement ISupportErrorInfo.
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);
}
11.3.4 CreateErrorInfo
HRESULT CreateErrorInfo(
ICreateErrorInfo **pperrinfo
);
Creates an instance of a generic error object.
Parameter
pperrinfo
Pointer to a system-implemented generic error object.
Return Value
The return value obtained from the returned HRESULT is one of the following:
Return value Meaning
S_OK Success.
E_OUTOFMEMORY Could not create the error object.
Comments
This function returns a pointer to a generic error object, which you can use wit
h QueryInterface on ICreateErrorInfo to set its contents. You can then pass the
resulting object to SetErrorInfo. The generic error object implements both ICrea
teErrorInfo and IErrorInfo.
Example
ICreateErrorInfo *perrinfo;
HRESULT hr;
hr = CreateErrorInfo(&pcerrinfo);
11.3.5 GetErrorInfo
HRESULT GetErrorInfo(dwReserved, pperrinfo)
DWORD dwReserved,
IErrorInfo **pperrinfo
);
Obtains the error information pointer set by the previous call to SetErrorInfo_o
a96_SetErrorInfo in the current logical thread.
Parameters
dwReserved
Reserved for future use. Must be zero.
pperrinfo
Pointer to a pointer to an error object.
Return Value
The return value obtained from the returned HRESULT is one of the following:
Return value Meaning
S_OK Success.
S_FALSE There was no error object to return.
Comments
This function returns a pointer to the most recently set IErrorInfo pointer in t
he current logical thread. It transfers ownership of the error object to the cal
ler, and clears the error state for the thread.
11.3.6 SetErrorInfo
HRESULT SetErrorInfo(
DWORD dwReserved,
IErrorInfo *perrinfo
);
Sets the error information object for the current thread of execution.
Parameters
dwReserved
Reserved for future use. Must be zero.
perrinfo
Pointer to an error object.
Return Value
The return value obtained from the returned HRESULT is:
Return value Meaning
S_OK Success.
Comments
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 er
ror information object. DispInvoke will return DISP_E_EXCEPTION when the propert
y or method returns a failure return value for DispInvoke.
Virtual function table (VTBL) binding controllers that do not use IDispatch::Inv
oke can get the error information object by using GetErrorInfo. This allows an o
bject that supports a dual interface to use SetErrorInfo, regardless of whether
the client uses VTBL binding or IDispatch.
Example
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();
11.3.7 HRESULT
The key type involved in COM error reporting is HRESULT. In addition, the COM Li
brary 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;
An HRESULT is divided up into an internal structure that has four fields with th
e following format (numbers indicate bit positions):
IErrorLog::AddError
Logs an error, an EXCEPINFO structure, in the error log during the property load
process for a named property.
HRESULT AddError(
LPCOLESTR pszPropName, //Pointer to the name of the property
// involved with the error
LPEXCEPINFO pException //Pointer to the caller-initialized
// EXCEPINFO structure describing the error
);
Parameters
pszPropName
[in] Pointer to the name of the property involved with the error. Cannot be NULL
.
pExcepInfo
[in] Pointer to the caller-initialized EXCEPINFO structure that describes the er
ror to log. Cannot be NULL.
Return Values
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 calle
r must supply both.
Remarks
E_NOTIMPL is not a valid return code as the method is the only one in the entire
interface.
Comments:
E_NOTIMPL is specifically disallowed because outside of type information there w
ould be no other means through which a caller could find the IIDs of the outgoin
g interfaces.
13.1.2.2 IConnectionPointContainer::FindConnectionPoint
HRESULT FindConnectionPoint([in] REFIID riid , [out] IConnectionPoint **ppCP);
Asks the connectable object if it has a connection point for a particular IID, and
if so, returns the IConnectionPoint interface pointer to that connection point.
Upon successful return, the caller must call IConnectionPoint::Release when th
at connection point is no longer needed.
Note that this function is the QueryInterface equivalent for an object s outgoing
interfaces, where the outgoing interface is specified with riid and where the in
terface pointer returned is always that of a connection point.
13.1.4.1 IEnumConnections::Next
HRESULT IEnumConnections::Next([in] ULONG cConnections ,
[out, max_is(cConnections)] CONNECTDATA *rgpcd,
[out] ULONG *pcFetched);
Enumerates the next cConnections elements in the enumerator s list, returning them
in rgpcd along with the actual number of enumerated elements in pcFetched. The
caller is responsible for calling IUnknown::Release through each pUnk pointer r
eturned in the structure elements of rgpcd.
if (cbitUsed == 0)
{
pb++;
}
wc = *++pwc - L A ; //assume uppercase
if (wc > CALPHACHARS)
{
wc += (WCHAR) (L A - L a ) //try lowercase
if (wc > CALPHACHARS)
{
wc += L a - L 0 + CALPHACHARS; //must
be a digit
if (wc > CHARMASK)
{
goto fail; //invalid character
}
}
}
*pb |= (BYTE) (wc << cbitUsed);
cbitStored = min(CBIT_BYTE - cbitUsed,
CBIT_CHARMASK);
//If the translated bits wouldn t fit in the
current byte
if (cbitStored < CBIT_CHARMASK)
{
wc >>= CBIT_BYTE - cbitUsed;
if (cbit + cbitStored == CBIT_GUID)
{
if (wc !+0)
{
goto fail; //extra bits
}
break;
}
pb++;
*pb |= (BYTE) wc;
}
}
Status = NO_ERROR
}
}
fail:
return(Status);
}
When attempting to open an existing property set (in IPropertySetStorage::Open)
the (root) FMTID in hand is converted to a string as depicted above. If an eleme
nt of the IStorage of that name exists, it is used. Otherwise, the open fails.
When creating a new property set, the above mapping determines the string name u
sed.
14.5.8 Storage vs Stream for a Property Set
To provide applications the control they need to fully interoperate through the
IPropertySetStorage interface with the COM property set, the programmer must con
trol whether a property set is stored in a storage or a stream. This is provided
through the presence or absence of the PROPSETFLAG_NONSIMPLE flag in IPropertyS
etStorage::Create.
14.5.9 Setting the CLSID of the Property Set
IPropertyStorage::SetClass, when invoked on a property stored in a compound file
, will set the CLSID of the storage object through a call to IStorage::SetClass
in addition to setting the class tag value stored in the COM property set. This
provides a consistency and uniformity that creates better interaction with some
tools.
14.5.10 Synchronization Points
When property sets are supported on the same object as is IStorage, it is import
ant to be aware of synchronization points between the base storage and the prope
rty storage. The property set storage holds the property set stream in an intern
al buffer until that buffer is commited through the IPropertyStorage::Commit met
hod. This is true whether IPropertyStorage was opened in transacted mode or dire
ct mode.
14.5.11 Code pages: Unicode strings, Macintosh, etc.
Another consideration is how Unicode property names are stored in the property I
D 0 (the property name dictionary), which is not specified per se to use Unicode
strings.
This is straightforward. Unicode officially has a code page value of 1200. To st
ore Unicode values in the property name dictionary, use a code page value of 120
0 for the whole property set (in property ID 1, of course), specified by the abs
ence of the PROPSETFLAG_ANSI flag in IPropertySetStorage::Create. Note that this
has the side effect of storing all string values in the property set in Unicode
. In all code pages, the count found at the start of a VT_LPSTR s a byte count,
not a character count. This is necessary to provide for smooth interoperability
with down-level clients.
The compound file implementation of IPropertySetStorage creates all new property
sets completely either in Unicode (code page 1200) or in the current system ANS
I code page. This is controlled by the absence or presence of the PROPSETFLAG_AN
SI flag in the grfFlags parameter of IPropertySetStorage::Create.
It is recommended that property sets be created or opened as Unicode, by not set
ting the PROPSETFLAG_ANSI flag in the grfFlags parameter of IPropertySetStorage:
:Create. It is also recommended that you avoid using VT_LPSTR values, and use VT
_LPWSTR values instead. When the property set code page is Unicode, VT_LPSTR str
ing values are converted to Unicode when stored, and back to multibyte string va
lues when retrieved. When the code page of the property set is not Unicode, prop
erty names, VT_BSTR strings, and non-simple property values are converted to mul
tibyte strings when stored, and converted back to Unicode when retrieved. If the
property set code page is Unicode, VT_LPSTR string values are converted to Unic
ode when stored, and back to multibyte string values when retrieved.
The setting of the PROPSETFLAG_ANSI flag as reported through a call to IProperty
Storage::Stat simply reflects whether the underlying code page is not Unicode or
is Unicode. Note, though, property ID 1 can be explicitly read to learn the cod
e page.
Property ID 1 is accessible through IPropertyStorage::ReadMultiple. However, it
is read-only, and may not be updated with WriteMultiple. Further, it may not be
deleted with DeleteMultiple.
14.5.12 Dictionary
IPropertyStorage::WritePropertyNames is implemented using the property ID 0 dict
ionary as described above. Property ID 0 is not accessible through IPropertyStor
age::ReadMultiple or ::WriteMultiple.
14.5.13 Extensions
Property set extensions as defined in the original COM property set format have
been removed and are not supported, except for the User Defined Properties secti
on in the Document Summary Information property set, described in more detail in
Appendix C, OLE Serialized Property Set Format.
14.6 Persistent Storage Interface Descriptions
14.6.1 IEnumSTATPROPSETSTG
The IEnumSTATPROPSETSTG interface is used to iterate through an array of STATPRO
PSETSTG structures, which contain statistical information about the property set
s managed by the current instance of IPropertySetStorage. IEnumSTATPROPSETSTG ha
s the same methods as all enumerator interfaces: Next, Skip, Reset, and Clone. F
or general information on these methods, refer to IEnumXXXX.
The implementation defines the order in which the property sets are enumerated.
Property sets that are present when the enumerator is created, and are not remov
ed during the enumeration, will be enumerated only once. Property sets added or
deleted while the enumeration is in progress may or may not be enumerated, but,
if enumerated, will not be enumerated more than once.
For information on how the COM compound document implementation of IEnumSTATPROP
SETSTG:Next supplies members of the STATPROPSETSTG structure, refer to IEnumSTAT
PROPSETSTG--Compound File Implementation.
14.6.1.1.1 When to Implement
IEnumSTATPROPSETSTG is implemented to enumerate the property sets supported by t
he current property set storage object. If you are using the compound file imple
mentation of the storage object, a pointer to which is available through a call
to StgCreateDocfile, IEnumSTATPROPSETSTG is implemented on that object, and a po
inter is returned through a call to IPropertySetStorage::Enum. If you are doing
a custom implementation of IPropertySetStorage, you need to implement IEnumSTATP
ROPSETSTG to fill in a caller-allocated array of STATPROPSETSTG structures, each
of which contains information about the nested elements in the storage object.
14.6.1.1.2 When to Use
Call IPropertySetStorage::Enum to return a pointer to IEnumSTATPROPSETSTG, the m
ethods of which can then be called to enumerate STATPROSETSTG structures so the
application can manage its property sets.
The prototypes of the methods are as follows:
HRESULT Next(
ULONG celt,
STATPROPSETSTG * rgelt,
ULONG * pceltFetched
);
HRESULT Skip(
ULONG celt
);
HRESULT Reset(void)
HRESULT Clone(
IEnumSTATPROPSETSTG ** ppenum
);
See Also
IPropertyStorage::Enum
Note
If you always create a property set using IPropertySetStorage::Create, then, sin
ce a Character GUID is created for the storage name, IEnumSTATPROPSETSTG::Next wil
l return a nonzero, valid format identifier for the property set[STATPROPSETSTG.
fmtid].
· The STATPROPSETSTG.grfFlags member does not necessarily reflect whether the prop
erty set is ANSI or not. If PROPSETFLAG_ANSI is set, the property set is definit
ely ANSI. If PROPSETFLAG_ANSI is clear, the property set could be either Unicode
or non-Unicode, because it is not possible to tell whether it is ANSI without o
pening it.
· The STATPROPSETSTG.grfFlags member does reflect whether the property set is simp
le or not, so the setting of the PROPSETFLAG_NONSIMPLE flag is always valid.
· If IEnumSTATPROPSETSTG::Next cannot provide STATPROPSETSTG.clsid, it is set to a
ll zeroes (CLSID_NULL). In the COM compound file implementation, this occurs whe
n the property set is simple (the PROPSETFLAG_NONSIMPLE flag is not set), or is
non-simple but the CLSID was not explicitly set. For non-simple property sets, t
he CLSID that is received is the one that is maintained by the underlying IStora
ge.
· If IEnumSTATPROPSETSTG::Next cannot provide the time fields [ctime, mtime, atime
], each non-supported time will be set to zeroes. In the COM compound file imple
mentation, getting these values depends on retrieving them from the underlying I
Storage implementation.
IEnumSTATPROPSETSTG::Skip
Skips the number of elements specified in celt. Returns S_OK if the specified nu
mber of elements are skipped, returns S_FALSE if fewer elements than requested a
re skipped. In any other case, returns the appropriate error.
IEnumSTATPROPSETSTG::Reset
Sets the cursor to the beginning of the enumeration. If successful, returns S_OK
, otherwise, returns STG_E_INVALIDHANDLE.
IEnumSTATPROPSETSTG::Clone
Copies the current enumeration state of this enumerator.
14.6.3 IEnumSTATPROPSTG
The IEnumSTATPROPSTG interface is used to iterate through an array of STATPROPST
G structures, which contain statistical information about an open property stora
ge containing a property set. IEnumSTATPROPSTG has the same methods as all enume
rator interfaces: Next, Skip, Reset, and Clone. For general information on these
methods, refer to IEnumXXXX.
The implementation defines the order in which the properties in the set are enum
erated. Properties that are present when the enumerator is created, and are not
removed during the enumeration, will be enumerated only once. Properties added o
r deleted while the enumeration is in progress may or may not be enumerated, but
they will never be enumerated more than once.
Properties with property ID 0 (dictionary), property ID 1 (codepage indicator),
or property ID greater than or equal to 0x80000000 are not enumerated.
Enumeration of a non-simple property does not necessarily indicate that the prop
erty can be read successfully through a call to IPropertyStorage::ReadMultiple.
This is because the performance overhead of checking existence of the indirect s
tream or storage is prohibitive during property enumeration. A client of this in
terface should code accordingly.
14.6.3.1.1 When to Implement
Implement IEnumSTATPROPSTG to enumerate the properties within a property set. If
you are using the compound file implementation of the storage object, a pointer
to which is available through a call to StgCreateDocfile, you can then query fo
r a pointer to IPropertySetStorage. After calling one of its methods either to o
pen or create a property set, you can get a pointer to IEnumSTATPROPSTG through
a call to IPropertyStorage::Enum. If you are doing a custom implementation of IP
ropertyStorage, you also need to implement IEnumSTATPROPSTG to fill in a caller-
allocated array of STATPROPSTG structures. Each STATPROPSTG structure contains i
nformation about a simple property.
14.6.3.1.2 When to Use
Applications that support storage objects and persistent properties within those
objects call IPropertyStorage::Enum to return a pointer to IEnumSTATPROPSTG to
enumerate the properties in the current property set.
The prototypes of the methods are as follows:
HRESULT Next(
ULONG celt,
STATPROPSTG * rgelt,
ULONG * pceltFetched
);
HRESULT Skip(
ULONG celt
);
HRESULT Reset(void)
HRESULT Clone(
IEnumSTATPROPSTG ** ppenum
);
See Also
IPropertyStorage::Enum
14.6.5 IEnumSTATSTG
The IEnumSTATSTG interface is used to enumerate through an array of STATSTG stru
ctures, which contain statistical information about an open storage, stream, or
byte array object. IEnumSTATSTG has the same methods as all enumerator interface
s: Next, Skip, Reset, and Clone. For general information on these methods, refer
to IEnumXXXX.
14.6.5.1.1 When to Implement
IEnumSTATSTG is implemented to enumerate the elements of a storage object. If yo
u are using the compound file implementation of the storage object, a pointer to
which is available through a call to StgCreateDocfile, IEnumSTATSTG is implemen
ted on that object, and a pointer is returned through a call to IStorage::EnumEl
ements. If you are doing a custom implementation of a storage object, you need t
o implement IEnumSTATSTG to fill in a caller-allocated array of STATSTG structur
es, each of which contains information about the nested elements in the storage
object.
14.6.5.1.2 When to Use
Containers call methods that return a pointer to IEnumSTATSTG so the container c
an manage its storage object and the elements within it. Calls to the IStorage::
EnumElements method supplies a pointer to IEnumSTATDATA. The caller allocates an
array of STATSTG structures and the IEnumSTATSTG methods fill in each structure
with the statistics about one of the nested elements in the storage object. If
present, the lpszName member of the STATSTG structure requires additional memory
allocations through the IMalloc interface, and the caller is responsible for fr
eeing this memory, if it is allocated, by calling the IMalloc::Free method. If t
he lpszName member is NULL, no memory is allocated, and, therefore, no memory ne
eds to be freed.
The prototypes of the methods are as follows:
HRESULT Next(
ULONG celt,
STATSTG * rgelt,
ULONG * pceltFetched
);
HRESULT Skip(
ULONG celt
);
HRESULT Reset(void)
HRESULT Clone(
IEnumSTATSTG ** ppenum
);
See Also
CoGetMalloc, IEnumXXXX, IStorage::EnumElements, STATSTG
14.6.6.2 ILockBytes::Flush
Ensures that any internal buffers maintained by the ILockBytes implementation ar
e written out to the underlying physical storage.
HRESULT Flush(void);
Return Values
S_OK
The flush operation was successful.
STG_E_ACCESSDENIED
The caller does not have permission to access the byte array.
STG_E_MEDIUMFULL
The flush operation is not completed because there is no space left on the stora
ge device.
E_FAIL
General failure writing data.
STG_E_TOOMANYFILESOPEN
Under certain circumstances, Flush does a dump-and-close to flush, which can lea
d to a return value of STG_E_TOOMANYFILESOPEN if no file handles are available.
STG_E_INVALIDHANDLE
An underlying file has been prematurely closed, or the correct floppy disk has b
een replaced by an invalid one.
Remarks
ILockBytes::Flush flushes internal buffers to the underlying storage device.
The COM-provided implementation of compound files calls this method during a tra
nsacted commit operation to provide a two-phase commit process that protects aga
inst loss of data.
See Also
IStorage::Commit, ILockBytes¾File-Based Implementation, ILockBytes¾Global Memory Imp
lementation
14.6.6.3 ILockBytes::LockRegion
Restricts access to a specified range of bytes in the byte array.
HRESULT LockRegion(
ULARGE_INTEGER libOffset, //Specifies the byte offset for the beginning of
the range
ULARGE_INTEGER cb, //Specifies the length of the range in bytes
DWORD dwLockType //Specifies the type of restriction on accessing the spe
cified range
);
Parameters
libOffset
[in]Specifies the byte offset for the beginning of the range.
cb
[in]Specifies, in bytes, the length of the range to be restricted.
dwLockType
[in]Specifies the type of restrictions being requested on accessing the range. T
his parameter uses one of the values from the LOCKTYPE enumeration.
Return Values
S_OK
The specified range of bytes was locked.
STG_E_INVALIDFUNCTION
Locking is not supported at all or the specific type of lock requested is not su
pported.
STG_E_ACCESSDENIED
Access denied because the caller has insufficient permission, or another caller
has the file open and locked.
STG_E_LOCKVIOLATION
Access denied because another caller has the file open and locked.
STG_E_INVALIDHANDLE
An underlying file has been prematurely closed, or the correct floppy disk has b
een replaced by an invalid one.
Remarks
ILockBytes::LockRegion restricts access to the specified range of bytes. Once a
region is locked, attempts by others to gain access to the restricted range must
fail with the STG_E_ACCESSDENIED error.
The byte range can extend past the current end of the byte array. Locking beyond
the end of an array is useful as a method of communication between different in
stances of the byte array object without changing data that is actually part of
the byte array. For example, an implementation of ILockBytes for compound files
could rely on locking past the current end of the array as a means of access con
trol, using specific locked regions to indicate permissions currently granted.
The dwLockType parameter specifies one of three types of locking, using values f
rom the LOCKTYPE enumeration. The types are as follows: locking to exclude other
writers, locking to exclude other readers or writers, and locking that allows o
nly one requestor to obtain a lock on the given range. This third type of lockin
g is usually an alias for one of the other two lock types, and permits an Implem
enter to add other behavior as well. A given byte array might support either of
the first two types, or both.
To determine the lock types supported by a particular ILockBytes implementation,
you can examine the grfLocksSupported member of the STATSTG structure returned
by a call to ILockBytes::Stat.
Any region locked with ILockBytes::LockRegion must later be explicitly unlocked
by calling ILockBytes::UnlockRegion with exactly the same values for the libOffs
et, cb, and dwLockType parameters. The region must be unlocked before the stream
is released. Two adjacent regions cannot be locked separately and then unlocked
with a single unlock call.
14.6.6.3.1.1.1 Notes to Callers
Since the type of locking supported is optional and can vary in different implem
entations of ILockBytes, you must provide code to deal with the STG_E_INVALIDFUN
CTION error.
14.6.6.3.1.1.2 Notes to Implementers
Support for this method depends on how the storage object built on top of the IL
ockBytes implementation is used. If you know that only one storage object at any
given time can be opened on the storage device that underlies the byte array, t
hen your ILockBytes implementation does not need to support locking. However, if
multiple simultaneous openings of a storage object are possible, then region lo
cking is needed to coordinate them.
A LockRegion implementation can choose to support all, some, or none of the lock
types. For unsupported lock types, the implementation should return STG_E_INVAL
IDFUNCTION.
See Also
ILockBytes::Stat, ILockBytes::UnlockRegion, IStream::LockRegion, LOCKTYPE, ILock
Bytes File-Based Implementation, ILockBytes Global Memory Implementation
14.6.6.4 ILockBytes::ReadAt
Reads a specified number of bytes starting at a specified offset from the beginn
ing of the byte array object.
HRESULT ReadAt(
ULARGE_INTEGER ulOffset, //Specifies the starting point for reading data
void *pv, //Points to the buffer into which the data is read
ULONG cb, //Specifies the number of bytes to read
ULONG *pcbRead //Pointer to location that contains actual number of byt
es read
);
Parameters
ulOffset
[in]Specifies the starting point from the beginning of the byte array for readin
g data.
pv
[in]Points to the buffer into which the byte array is read.
cb
[in]Specifies the number of bytes of data to attempt to read from the byte array
.
pcbRead
[out]Pointer to a location where this method writes the actual number of bytes r
ead from the byte array. You can set this pointer to NULL to indicate that you a
re not interested in this value. In this case, this method does not provide the
actual number of bytes read.
Return Values
S_OK
Indicates that the specified number of bytes were read, or the maximum number of
bytes were read up to the end of the byte array.
E_FAIL
Data could not be read from the byte array.
E_PENDING
Asynchronous Storage only: Part or all of the data to be read is currently unava
ilable.
STG_E_ACCESSDENIED
The caller does not have permission to access the byte array.
STG_E_READFAULT
The number of bytes to be read does not equal the number of bytes that were acut
ally read.
Remarks
ILockBytes::ReadAt reads bytes from the byte array object. It reports the number
of bytes that were actually read. This value may be less than the number of byt
es requested if an error occurs or if the end of the byte array is reached durin
g the read.
It is not an error to read less than the specified number of bytes if the operat
ion encounters the end of the byte array. Note that this is the same end-of-file
behavior as found in MS-DOS FAT file system files.
See Also
ILockBytes::WriteAt, ILockBytes File-Based Implementation, ILockBytes Global Memory
Implementation
14.6.6.5 ILockBytes::SetSize
Changes the size of the byte array.
HRESULT SetSize(
ULARGE_INTEGER cb //Specifies the new size of the byte array in bytes
);
Parameter
cb
[in]Specifies the new size of the byte array as a number of bytes.
Return Values
S_OK
The size of the byte array was successfully changed.
STG_E_ACCESSDENIED
The caller does not have permission to access the byte array.
STG_E_MEDIUMFULL
The byte array size is not changed because there is no space left on the storage
device.
Remarks
ILockBytes::SetSize changes the size of the byte array. If the cb parameter is l
arger than the current byte array, the byte array is extended to the indicated s
ize by filling the intervening space with bytes of undefined value, as does ILoc
kBytes::WriteAt, if the seek pointer is past the current end-of-stream.
If the cb parameter is smaller than the current byte array, the byte array is tr
uncated to the indicated size.
14.6.6.5.1.1.1 Notes to Callers
Callers cannot rely on STG_E_MEDIUMFULL being returned at the appropriate time b
ecause of cache buffering in the operating system or network. However, callers m
ust be able to deal with this return code because some ILockBytes implementation
s might support it.
See Also
ILockBytes::ReadAt, ILockBytes::WriteAt, ILockBytes File-Based Implementation, ILo
ckBytes Global Memory Implementation
14.6.6.6 ILockBytes::Stat
Retrieves a STATSTG structure containing information for this byte array object.
HRESULT Stat(
STATSTG *pstatstg, //Location for STATSTG structure
DWORD grfStatFlag //Values taken from the STATFLAG enumeration
);
Parameters
pstatstg
[out]Points to a STATSTG structure in which this method places information about
this byte array object. The pointer is NULL if an error occurs.
grfStatFlag
[in]Specifies whether this method should supply the pwcsName member of the STATS
TG structure through values taken from the STATFLAG enumeration. If the STATFLAG
_NONAME is specified, the pwcsName member of STATSTG is not supplied, thus savin
g a memory allocation operation. The other possible value, STATFLAG_DEFAULT, ind
icates that all STATSTG members be supplied.
Return Values
S_OK
The STATSTG structure was successfully returned at the specified location.
E_OUTOFMEMORY
The STATSTG structure was not returned due to a lack of memory for the name fiel
d in the structure.
STG_E_ACCESSDENIED
The STATSTG structure was not returned because the caller did not have access to
the byte array.
STG_E_INSUFFICIENTMEMORY
The STATSTG structure was not returned, due to a lack of memory.
STG_E_INVALIDFLAG
The value for the grfStateFlag parameter is not valid.
STG_E_INVALIDPOINTER
The value for the pStatStg parameter is not valid.
Remarks
ILockBytes::Stat should supply information about the byte array object in a STAT
STG structure.
See Also
STATFLAG, STATSTG, ILockBytes File-Based Implementation, ILockBytes Global Memory Im
plementation
14.6.6.7 ILockBytes::UnlockRegion
Removes the access restriction on a previously locked range of bytes.
HRESULT UnlockRegion(
ULARGE_INTEGER libOffset, //Specifies the byte offset for the beginning of
the range
ULARGE_INTEGER cb, //Specifies the length of the range in bytes
DWORD dwLockType //Specifies the access restriction previously placed on
the range
);
Parameters
libOffset
[in]Specifies the byte offset for the beginning of the range.
cb
[in]Specifies, in bytes, the length of the range that is restricted.
dwLockType
[in]Specifies the type of access restrictions previously placed on the range. Th
is parameter uses a value from the LOCKTYPE enumeration.
Return Values
S_OK
The byte range was unlocked.
STG_E_INVALIDFUNCTION
Locking is not supported at all or the specific type of lock requested is not su
pported.
STG_E_LOCKVIOLATION
The requested unlock cannot be granted.
Remarks
ILockBytes::UnlockRegion unlocks a region previously locked with a call to ILock
Bytes::LockRegion. Each region locked must be explicitly unlocked, using the sam
e values for the libOffset, cb, and dwLockType parameters as in the matching cal
ls to ILockBytes::LockRegion. Two adjacent regions cannot be locked separately a
nd then unlocked with a single unlock call.
See Also
ILockBytes::LockRegion, LOCKTYPE, ILockBytes File-Based Implementation, ILockBytes G
lobal Memory Implementation
14.6.6.8 ILockBytes::WriteAt
Writes the specified number of bytes starting at a specified offset from the beg
inning of the byte array.
HRESULT WriteAt(
ULARGE_INTEGER ulOffset, //Specifies the starting point for writing data
void const *pv, //Points to the buffer containing the data to be written
ULONG cb, //Specifies the number of bytes to write
ULONG *pcbWritten //Pointer to location that contains actual number of byt
es written
);
Parameters
ulOffset
[in]Specifies the starting point from the beginning of the byte array for the da
ta to be written.
pv
[in]Points to the buffer containing the data to be written.
cb
[in]Specifies the number of bytes of data to attempt to write into the byte arra
y.
pcbRead
[out]Pointer to a location where this method specifies the actual number of byte
s written to the byte array. You can set this pointer to NULL to indicate that y
ou are not interested in this value. In this case, this method does not provide
the actual number of bytes written.
Return Values
S_OK
Indicates that the specified number of bytes were written.
E_FAIL
A general failure occurred during the write.
E_PENDING
Asynchronous Storage only: Part or all of the data to be written is currently un
available.
STG_E_ACCESSDENIED
The caller does not have sufficient permissions for writing this byte array.
STG_E_WRITEFAULT
The number of bytes to be written does not equal the number of bytes that were a
cutally written.
STG_E_MEDIUMFULL
The write operation was not completed because there is no space left on the stor
age device. The actual number of bytes written is still returned in pcbWritten.
Remarks
ILockBytes::WriteAt writes the specified data at the specified location in the b
yte array. The number of bytes actually written must always be returned in pcbWr
itten, even if an error is returned. If the byte count is zero bytes, the write
operation has no effect.
If ulOffset is past the end of the byte array and cb is greater than zero, ILock
Bytes::WriteAt increases the size of the byte array. The fill bytes written to t
he byte array are not initialized to any particular value.
See Also
ILockBytes::ReadAt, ILockBytes::SetSize, ILockBytes File-Based Implementation, ILo
ckBytes Global Memory Implementation
14.6.9 IPersist
The IPersist interface defines the single method GetClassID, which is designed t
o supply the CLSID of an object that can be stored persistently in the system. A
call to this method can allow the object to specify which object handler to use
in the client process, as it is used in the COM default implementation of marsh
aling.
IPersist is the base interface for three other interfaces: IPersistStorage, IPer
sistStream, and IPersistFile. Each of these interfaces, therefore, includes the
GetClassID method, and the appropriate one of these three interfaces is implemen
ted on objects that can be serialized to a storage, a stream, or a file. The met
hods of these interfaces allow the state of these objects to be saved for later
instantiations, and load the object using the saved state. Typically, the persis
tence interfaces are implemented by an embedded or linked object, and are called
by the container application or the default object handler
14.6.9.1.1 When to Implement
You must implement the single method of IPersist in implementing any one of the
other persistence interfaces: IPersistStorage, IPersistStream, or IPersistFile.
Typically, for example, you would implement IPersistStorage on an embedded objec
t, IPersistFile on a linked object, and IPersistStream on a new moniker class, a
lthough their uses are not limited to these objects. You could implement IPersis
t in a situation where all that is required is to obtain the CLSID of a persiste
nt object, as it is used in marshaling.
14.6.9.1.2 When to Use
The single method of IPersist is rarely called directly in application code. It
is called by the default object handler to get the CLSID of an embedded object,
or an object to be marshaled. A container application, for example, would probab
ly not call the GetClassID method directly unless it provided object handlers fo
r specific classes of objects.
Methods in Vtable Order
14.6.9.2 IPersist::GetClassID
Retrieves the class identifier (CLSID) of an object. The CLSID is a unique value
that identifies the code that can manipulate the persistent data.
HRESULT GetClassID(
CLSID *pClassID //Pointer to CLSID of object
);
Parameter
pClassID
[out]Points to the location of the CLSID on return. The CLSID is a globally uniq
ue identifier (GUID) that uniquely represents an object class that defines the c
ode that can manipulate the object s data.
Return Values
S_OK
The CLSID was successfully retrieved.
E_FAIL
The CLSID could not be retrieved.
Remarks
The GetClassID method retrieves the class identifier (CLSID) for an object, used
in later operations to load object-specific code into the caller s context.
14.6.9.2.1.1.1 Notes to Callers
A container application might call this method to retrieve the original CLSID of
an object that it is treating as a different class. Such a call would be necess
ary if a user performed an editing operation that required the object to be save
d. If the container were to save it using the treat-as CLSID, the original appli
cation would no longer be able to edit the object. Typically, in this case, the
container calls the OleSave helper function, which performs all the necessary st
eps. For this reason, most container applications have no need to call this meth
od directly.
The exception would be a container that provides an object handler for certain o
bjects. In particular, a container application should not get an object s CLSID an
d then use it to retrieve class specific information from the registry.
14.6.9.2.1.1.2 Notes to Implementers
Typically, implementations of this method simply supply a constant CLSID for an
object. If, however, the object s TreatAs registry key has been set by an applicat
ion that supports emulation (and so is treating the object as one of a different
class), a call to IPersist::GetClassID must supply the CLSID specified in the T
reatAs key. For more information on emulation, refer to CoTreatAsClass.
When an object is in the running state, the default handler calls an implementat
ion of IPersist::GetClassID that delegates the call to the implementation in the
object. When the object is not running, the default handler instead calls the R
eadClassStg function to read the CLSID that is saved in the object s storage.
If you are writing a custom object handler for your object, you might want to si
mply delegate this method to the default handler implementation (see OleCreateDe
faultHandler).
See Also
IPersistStorage, IPersistStream, IPersistFile, ReadClassStg
14.6.10 IPersistFile
The IPersistFile interface provides methods that permit an object to be loaded f
rom or saved to a disk file, rather than a storage object or stream. Because the
information needed to open a file varies greatly from one application to anothe
r, the implementation of IPersistFile::Load on the object must also open its dis
k file.
The IPersistFile interface inherits its definition from IPersist, so all impleme
ntations must also include the GetClassID method of IPersist.
14.6.10.1.1 When to Implement
Implement IPersistFile when you want to read or write information from a separat
e file, which could be of any file format.
This interface should be implemented on any objects that support linking through
a file moniker, including the following:
· Any object that supports links to its files or to pseudo-objects within its file
s
· A container application that supports links to objects within its compound file
Typically, you implement the IPersistFile interface as part of an aggregate obje
ct that includes other interfaces that are appropriate for the type of moniker b
inding that is supported.
For example, in either of the cases mentioned above, the moniker for the linked
object can be a composite moniker. In the first case, a composite moniker identi
fies the pseudo-object contained within the file. In the second case, a composit
e moniker identifies the embedded object contained within the compound file. In
either case of composite monikers, you must implement the IPersistFile interface
as part of the same object on which the IOleItemContainer interface is implemen
ted. Then, when the application for the linked object is run, COM queries for th
e IOleItemContainer interface to locate the embedded object or the pseudo-object
contained in the file.
As another example, if the moniker is a simple file moniker (i.e., the link is t
o the entire file), COM queries for the interface that the initiator of the bind
operation requested. Typically, this is one of the compound document interfaces
, such as IOleObject, IDataObject, or IPersistStorage.
14.6.10.1.2 When to Use
Call methods in the IPersistFile interface to load or save a linked object in a
specified file.
When IPersistFile is implemented on an object that supports linking through a fi
le moniker and the application for the linked object is run, COM calls IPersistF
ile::Load. Once the file is loaded, COM calls IPersistFile::QueryInterface to ge
t another interface pointer to the loaded object. The IPersistFile interface is
typically part of an aggregate object that offers other interfaces.
In this case, the only IPersistFile method that COM calls is the Load method to
load a file linked to a container, running the application associated with the f
ile. It would also be unusual for applications to call other methods in this cas
e, which support saving an object to a file. Generally, it is left to the end us
er and the application for the linked object to decide when to save the object.
This differs from the situation for an embedded object, in which the container a
pplication uses the IPersistStorage interface to provide the storage and to tell
the object when to save itself.
Methods in Vtable Order
IUnknown Methods Description
QueryInterface Returns pointers to supported interfaces.
AddRef Increments the reference count.
Release Decrements the reference count.
IPersist Method Description
GetClassID Returns the class identifier (CLSID) for the component object.
14.6.10.2 IPersistFile::GetCurFile
Retrieves either the absolute path to the object s current working file or, if the
re is no current working file, the object s default filename prompt.
HRESULT GetCurFile(
LPOLESTR *ppszFileName //Pointer to the path for the current file or th
e default save prompt
);
Parameter
ppszFileName
[out]Points to the location of a pointer to a zero-terminated string containing
the path for the current file or the default filename prompt (such as *.txt). If
an error occurs, ppszFileName is set to NULL.
Return Values
S_OK
A valid absolute path was successfully returned.
S_FALSE
The default save prompt was returned.
E_OUTOFMEMORY
The operation failed due to insufficient memory.
E_FAIL
The operation failed due to some reason other than insufficient memory.
Remarks
This method returns the current filename or the default save prompt for the obje
ct.
This method allocates memory for the string returned in the ppszFileName paramet
er using the IMalloc::Alloc method. The caller is responsible for calling the IM
alloc::Free method to free the string. Both the caller and this method use the C
OM task allocator provided by a call to CoGetMalloc.
The LPOLESTR type indicates a wide character string (two bytes per character); o
therwise, the string has one byte per character.
The filename returned in ppszFileName is the name specified in a call to IPersis
tFile::Load when the document was loaded; or in IPersistFile::SaveCompleted if t
he document was saved to a different file.
If the object does not have a current working file, it should supply the default
filename prompt that it would display in a Save As dialog. For example, the defau
lt save prompt for a word processor object could be:
*.txt
14.6.10.2.1.1.1 Notes to Callers
COM does not call the IPersistFile::GetCurFile method. Applications would not ca
ll this method unless they are also calling the save methods of this interface.
In saving the object, you can call this method before calling IPersistFile:Save
to determine whether the object has an associated file. If this method returns S
_OK, you can then call IPersistFile::Save with a NULL filename and a TRUE value
for the fRemember parameter to tell the object to save itself to its current fil
e. If this method returns S_FALSE, you can use the save prompt returned in the p
pszFileName parameter to ask the end user to provide a filename. Then, you can c
all IPersistFile::Save with the filename that the user entered to perform a Save
As operation.
See Also
IPersistFile::Load, IPersistFile::Save, IPersistFile::SaveCompleted
14.6.10.3 IPersistFile::IsDirty
Checks an object for changes since it was last saved to its current file.
HRESULT IsDirty(void);
Return Values
S_OK
The object has changed since it was last saved.
S_FALSE
The object has not changed since the last save.
Remarks
This method checks whether an object has changed since it was last saved. Call i
t to determine whether an object should be saved before closing it. The dirty fl
ag for an object is conditionally cleared in the IPersistFile::Save method.
14.6.10.3.1.1.1 Notes to Callers
COM does not call IPersistFile::IsDirty. Applications would not call it unless t
hey are also saving an object to a file.
You should treat any error return codes as an indication that the object has cha
nged. Unless this method explicitly returns S_FALSE, assume that the object must
be saved.
14.6.10.3.1.1.2 Notes to Implementers
An object with no contained objects simply checks its dirty flag to return the a
ppropriate result.
A container with one or more contained objects must maintain an internal dirty f
lag that is set when any of its contained objects has changed since it was last
saved. To do this, the container should maintain an advise sink by implementing
the IAdviseSink interface. Then, the container can register each link or embeddi
ng for data change notifications with a call to IDataObject::DAdvise. Then, the
container can set its internal dirty flag when it receives an IAdviseSink::OnDat
aChange notification. If the container does not register for data change notific
ations, the IPersistFile::IsDirty implementation would call IPersistStorage::IsD
irty for each of its contained objects to determine whether they have changed.
The container can clear its dirty flag whenever it is saved, as long as the file
to which the object is saved is the current working file after the save. Theref
ore, the dirty flag would be cleared after a successful Save or Save As operation, b
ut not after a Save A Copy As . . . operation.
See Also
IAdviseSink::OnDataChange, IDataObject::DAdvise, IPersistStorage::IsDirty
14.6.10.4 IPersistFile::Load
Opens the specified file and initializes an object from the file contents.
HRESULT Load(
LPCOLESTR pszFileName, //Pointer to absolute path of the file to open
DWORD dwMode //Specifies the access mode from the STGM enumeration
);
Parameters
pszFileName
[in]Points to a zero-terminated string containing the absolute path of the file
to open.
dwMode
[in]Specifies some combination of the values from the STGM enumeration to indica
te the access mode to use when opening the file. IPersistFile::Load can treat th
is value as a suggestion, adding more restrictive permissions if necessary. If d
wMode is zero, the implementation should open the file using whatever default pe
rmissions are used when a user opens the file.
Return Values
S_OK
The object was successfully loaded.
E_OUTOFMEMORY
The object could not be loaded due to a lack of memory.
E_FAIL
The object could not be loaded for some reason other than a lack of memory.
IPersistFile::Load STG_E_* error codes.
Remarks
IPersistFile::Load loads the object from the specified file. This method is for
initialization only and does not show the object to the end user. It is not equi
valent to what occurs when an end user selects the File Open command.
14.6.10.4.1.1.1 Notes to Callers
The BindToObject method in file monikers calls this method to load an object dur
ing a moniker binding operation (when a linked object is run). Typically, applic
ations do not call this method directly.
14.6.10.4.1.1.2 Notes to Implementers
Because the information needed to open a file varies greatly from one applicatio
n to another, the object on which this method is implemented must also open the
file specified by the pszFileName parameter. This differs from the IPersistStora
ge::Load and IPersistStream::Load, in which the caller opens the storage or stre
am and then passes an open storage or stream pointer to the loaded object.
For an application that normally uses COM compound files, your IPersistFile::Loa
d implementation can simply call the StgOpenStorage function to open the storage
object in the specified file. Then, you can proceed with normal initialization.
Applications that do not use storage objects can perform normal file-opening pr
ocedures.
When the object has been loaded, your implementation should register the object
in the Running Object Table (see IRunningObjectTable::Register).
See Also
IRunningObjectTable::Register, StgOpenStorage
14.6.10.5 IPersistFile::Save
Saves a copy of the object into the specified file.
HRESULT Save(
LPCOLESTR pszFileName, //Pointer to absolute path of the file where the
object is saved
BOOL fRemember //Specifies whether the file is to be the current workin
g file or not
);
Parameters
pszFileName
[in]Points to a zero-terminated string containing the absolute path of the file
to which the object should be saved. If pszFileName is NULL, the object should s
ave its data to the current file, if there is one.
fRemember
[in]Indicates whether the pszFileName parameter is to be used as the current wor
king file. If TRUE, pszFileName becomes the current file and the object should c
lear its dirty flag after the save. If FALSE, this save operation is a Save A Cop
y As ... operation. In this case, the current file is unchanged and the object sh
ould not clear its dirty flag. If pszFileName is NULL, the implementation should
ignore the fRemember flag.
Return Values
S_OK
The object was successfully saved.
E_FAIL
The file was not saved.
IPersistFile::Save STG_E_* errors.
Remarks
This method can be called to save an object to the specified file in one of thre
e ways:
Save
Call IPersistFile::GetCurFile first to determine whether the object has an assoc
iated filename. If so, call IPersistFile::Save specifying NULL for the pszFileNa
me parameter in this method to indicate that the object should be saved to its c
urrent file. Then call IPersistFile::SaveCompleted to indicate completion.
Save As
Call IPersistFile::Save specifying TRUE in the fRemember parameter and a non-NUL
L value, indicating the name of the new file the object is to be saved to, for t
he pszFileName parameter . Then call IPersistFile::SaveCompleted to indicate com
pletion.
Save a Copy As
Call IPersistFile::Save specifying FALSE in the fRemember parameter and a non-NU
LL value, indicating the name of the new file the object is to be copied to, for
the pszFileName parameter.
The implementer must detect which type of save operation the caller is requestin
g. If the pszFileName parameter is NULL, a Save is being requested. If the pszFile
Name parameter is not NULL, use the value of the fRemember parameter to distingu
ish between a Save As and a Save a Copy As .
In Save or Save As operations, IPersistFile::Save clears the internal dirty flag aft
er the save and sends IAdviseSink::OnSave notifications to any advisory connecti
ons. Also, in these operations, the object is in NoScribble mode until it receiv
es an IPersistFile::SaveCompleted call. In NoScribble mode, the object must not
write to the file.
In the Save As scenario, the implementation should also send IAdviseSink::OnRename
notifications to any advisory .
In the Save a Copy As scenario, the implementation does not clear the internal dir
ty flag after the save.
14.6.10.5.1.1.1 Notes to Callers
COM does not call IPersistFile::Save. Typically, applications would not call it
unless they are saving an object to a file directly, which is generally left to
the end-user.
See Also
IPersistFile::GetCurFile, IPersistFile::SaveCompleted
14.6.10.6 IPersistFile::SaveCompleted
Notifies the object that it can write to its file. It does this by notifying the
object that it can revert from NoScribble mode (in which it must not write to i
ts file), to Normal mode (in which it can). The component enters NoScribble mode
when it receives an IPersistFile::Save call.
HRESULT SaveCompleted(
LPCOLESTR pszFileName //Pointer to absolute path of the file where the
object was saved
);
Parameter
pszFileName
[in]Points to the absolute path of the file where the object was previously save
d.
Return Value
S_OK
Returned in all cases.
Remarks
IPersistFile::SaveCompleted is called when a call to IPersistFile::Save is compl
eted, and the file that was saved is now the current working file (having been s
aved with Save or Save As operations). The call to Save puts the object into NoScrib
ble mode so it cannot write to its file. When SaveCompleted is called, the objec
t reverts to Normal mode, in which it is free to write to its file.
14.6.10.6.1.1.1 Notes to Callers
COM does not call the IPersistFile::SaveCompleted method. Typically, application
s would not call it unless they are saving objects directly to files, an operati
on which is generally left to the end-user.
See Also
IPersistFile::Save
14.6.11 IPersistMemory
The IPersistMemory interface operates exactly as IPersistStreamInit, except that
it allows the caller to provide a fixed-size memory block (identified with a vo
id *) as opposed to IPersistStreamInit which involves an arbitrarily expandable
IStream.
The cbSize argument to the Load and Save methods indicate the amount of memory a
ccessible through pvMem.
The IsDirty, GetSizeMax, and InitNew methods are semantically and syntactically
identical to those in IPersistStreamInit. Only Load and Save differ.
14.6.11.1.1 When to Implement
An object implements this interface to save itself in memory.
14.6.11.1.2 When to Use
A container calls the methods of this interface to instruct an object to save an
d load itself in memory.
Methods in Vtable Order
IUnknown Methods Description
QueryInterface Returns pointers to supported interfaces.
AddRef Increments reference count.
Release Decrements reference count.
IPersist Method Description
GetClassID Returns the class identifier (CLSID) for the component object.
14.6.11.2 IPersistMemory::GetSizeMax
Returns the size in bytes of the memory block needed to save the object.
HRESULT GetSizeMax(
ULARGE_INTEGER* pcbSize //Pointer to size of memory needed to save objec
t
);
Parameter
pcbSize
[out]Pointer to a 64-bit unsigned integer value indicating the size in bytes of
the memory needed to save this object.
Return Value
S_OK
The size was successfully returned.
Remarks
This method returns the size needed to save an object. You can call this method
to determine the size and set the necessary buffers before calling the IPersistM
emory::Save method.
14.6.11.2.1.1.1 Notes to Implementers
The GetSizeMax implementation must return a conservative estimate of the necessa
ry size because the IPersistMemory::Save method uses a fixed size memory block.
See Also
IPersistMemory::Save
14.6.11.3 IPersistMemory::InitNew
Initializes the object to a default state. This method is called instead of IPer
sistMemory::Load.
HRESULT InitNew(void);
Return Values
S_OK
The object successfully initialized itself.
E_NOTIMPL
The object requires no default initialization. This error code is allowed becaus
e an object may choose to implement IPersistMemory simply for orthogonality or i
n anticipation of a future need for this method.
E_UNEXPECTED
This method was called after the object was already initialized with IPersistMem
ory::Load. Only one initialization is allowed per instance.
E_OUTOFMEMORY
There was not enough memory for the object to initialize itself.
14.6.11.3.1.1.1 Notes to Implementers
If the object has already been initialized with Load, then this method must retu
rn E_UNEXPECTED.
See Also
IPersistMemory::Load
14.6.11.4 IPersistMemory::IsDirty
Checks the object for changes since it was last saved.
HRESULT IsDirty(void);
Return Values
S_OK
The object has changed since it was last saved.
S_FALSE
The object has not changed since the last save.
Remarks
This method checks whether an object has changed since it was last saved so you
can avoid losing information in objects that have not yet been saved. The dirty
flag for an object is conditionally cleared in the IPersistMemory::Save method.
14.6.11.4.1.1.1 Notes to Callers
You should treat any error return codes as an indication that the object has cha
nged. In other words, unless this method explicitly returns S_FALSE, you must as
sume that the object needs to be saved.
See Also
IPersistMemory::Save
14.6.11.5 IPersistMemory::Load
Instructs the object to load its persistent data from the memory pointed to by p
vMem where cbSize indicates the amount of memory at pvMem. The object must not r
ead past the address (BYTE*)((BYTE *)pvMem+cbSize).
HRESULT Load(
void* pvMem, //Pointer to the stream from which the object should be
loaded
ULONG cbSize //Amount of memory from which the object can read its da
ta
);
Parameters
pvMem
[in] Pointer to the address in memory from which the object can read up to cbSiz
e bytes of its data.
cbSize
[in] The amount of memory available at pvMem from which the object can read its
data.
Return Values
S_OK
The object successfully loaded its data.
E_UNEXPECTED
This method was called after the object was already initialized with IPersistMem
ory::Load. Only one initialization is allowed per instance.
E_POINTER
The pointer in pvMem is NULL.
Remarks
Any object that implements IPersistMemory has some information to load persisten
tly, therefore E_NOTIMPL is not a valid return code.
See Also
IPersistMemory::InitNew
14.6.11.6 IPersistMemory::Save
Instructs the object to save its persistent data to the memory pointed to by pvM
em where cbSize indicates the amount of memory available at pvMem. The object mu
st not write past the address (BYTE*)((BYTE *)pvMem+cbSize). The fClearDirty fla
g determines whether the object is to clear its dirty state after the save is co
mplete.
HRESULT Save(
void* pvMem, //Pointer to the stream where the object is to be saved
BOOL fClearDirty, //Specifies whether to clear the dirty flag
ULONG cbSize //Amount of memory to which the object can write its dat
a
);
Parameters
pvMem
[in] Pointer to the memory in which the object should save up to cbSize bytes of
its data.
fClearDirty
[in] A flag indicating whether the object should clear its dirty state on return
from Save or leave that state as-is.
cbSize
[in] The amount of memory available at pvMem to which the object can write its d
ata.
Return Values
S_OK
The object successfully initialized itself.
E_UNEXPECTED
This method was called before the object was initialized with IPersistMemory::In
itNew or IPersistMemory::Load.
E_INVALIDARG
The number of bytes indicated by cbSize is too small to allow the object to save
itself completely.
E_POINTER
The pointer in pvMem is NULL.
Remarks
Any object that implements IPersistMemory has some information to save persisten
tly, therefore E_NOTIMPL is not a valid return code.
The caller should ideally allocate as many bytes as the object returns from IPer
sistMemory::GetSizeMax.
See Also
IPersistMemory::InitNew, IPersistMemory::Load
14.6.12 IPersistPropertyBag
The IPersistPropertyBag interface works in conjunction with IPropertyBag and IEr
rorLog to define an individual property-based persistence mechanism. Whereas a m
echanism like IPersistStream gives an object an IStream in which to store its bi
nary data, IPersistPropertyBag provides an object with an IPropertyBag interface
through which it can save and load individual properties. The implementer of IP
ropertyBag can then save those properties in whatever way it chooses, such as na
me/value pairs in a text file. Errors encountered in the process (on either side
) are recorded in an error log through IErrorLog. This error reporting mechanism
work on a per-property basis instead of an all properties as a whole basis thro
ugh just the return value of IPersist*::Load or IPersist*::Save.
The basic mechanism is that a container tells the object to save or load its pro
perties through IPersistPropertyBag. For each property, the object calls the con
tainer s IPropertyBag interface passed to the IPersistPropertyBag methods. IProper
tyBag::Write saves a property in whatever place the container wants to put it, a
nd IPropertyBag::Read retrieves a property.
This protocol is essentially a means of sequentially communicating individual pr
operty values from the object to the container, which is useful for doing save-a
s-text operations and the like. The object gives the container the choice of the
format in which each property is saved, while retaining itself the decision as
to which properties are saved or loaded.
14.6.12.1.1 When to Implement
An object implements this interface to enable saving its properties persistently
.
14.6.12.1.2 When to Use
A container calls the methods on this interface to instruct an object to load an
d save its properties to the supplied property bag.
Methods in Vtable Order
IUnknown Methods Description
QueryInterface Returns pointers to supported interfaces.
AddRef Increments reference count.
Release Decrements reference count.
14.6.12.2 IPersistPropertyBag::InitNew
Called by the container when the control is initialized to initialize the proper
ty bag.
HRESULT InitNew(void);
Return Values
S_OK
The object successfully initialized itself. This should be returned even if the
object doesn t do anything in the method.
CO_E_ALREADYINITIALISED
The object has already been initialized.
E_OUTOFMEMORY
The storage object was not initialized due to a lack of memory.
E_UNEXPECTED
The storage object was not initialized due to some reason other than a lack of m
emory.
Remarks
This method informs the object that it is being initialized as a newly created o
bject.
E_NOTIMPL should not be returned use S_OK when the object has nothing to do in the
method.
See Also
IPersistPropertyBag::Load
14.6.12.3 IPersistPropertyBag::Load
Called by the container to load the control s properties.
HRESULT Load(
IPropertyBag* pPropBag, //Pointer to caller s property bag
IErrorLog* pErrorLog //Pointer to error log
);
Parameters
pPropBag
[in] Pointer to the caller s IPropertyBag interface bag that the control uses to r
ead its properties. Cannot be NULL.
pErrorLog
[in] Pointer to the caller s IErrorLog interface in which the object stores any er
rors that occur during initialization. Can be NULL in which case the caller is n
ot interested in errors.
Return Values
S_OK
The object successfully initialized itself.
E_UNEXPECTED
This method was called after IPersistPropertyBag::InitNew has already been calle
d. They two initialization methods are mutually exclusive.
E_OUTOFMEMORY
The properties were not loaded due to a lack of memory.
E_POINTER
The address in pPropBag is not valid (such as NULL) and therefore the object can
not initialize itself.
E_FAIL
The object was unable to retrieve a critical property that is necessary for the
object s successful operation. The object was therefore unable to initialize itsel
f completely.
Remarks
This method instructs the object to initialize itself using the properties avail
able in the property bag, notifying the provided error log object when errors oc
cur. All property storage must take place within this method call as the object
cannot hold the IPropertyBag pointer.
E_NOTIMPL is not a valid return code as any object implementing this interface m
ust support the entire functionality of the interface.
See Also
IPersistPropertyBag::InitNew
14.6.12.4 IPersistPropertyBag::Save
Called by the container to save the object s properties.
HRESULT Save(
IPropertyBag* pPropBag, //Pointer to the caller s property bag
BOOL fClearDirty, //Specifies whether to clear the dirty flag
BOOL fSaveAllProperties //Specifies whether to save all properties or ju
st those that have changed
);
Parameters
pPropBag
[in] Pointer to the caller s IPropertyBag interface through which the object can w
rite properties. Cannot be NULL.
fClearDirty
[in] A flag indicating whether the object should clear its dirty flag when savin
g is complete. TRUE means clear the flag, FALSE means leave the flag unaffected.
FALSE is used when the caller wishes to do a Save Copy As type of operation.
fSaveAllProperties
[in] A flag indicating whether the object should save all its properties (TRUE)
or only those that have changed since the last save or initialization (FALSE).
Return Values
S_OK
The object successfully saved the requested properties itself.
E_FAIL
There was a problem saving one of the properties. The object can choose to fail
only if a necessary property could not be saved, meaning that the object can ass
ume default property values if a given property is not seen through IPersistProp
ertyBag::Load at some later time.
E_POINTER
The address in pPropBag is not valid (such as NULL) and therefore the object can
not initialize itself.
STG_E_MEDIUMFULL
The object was not saved because of a lack of space on the disk.
Remarks
This method instructs the object to save its properties to the specified propert
y bag, optionally clearing the object s dirty flag. The caller can request that th
e object save all properties or that the object save only those that are known t
o have changed.
E_NOTIMPL is not a valid return code as any object implementing this interface m
ust support the entire functionality of the interface.
See Also
IPersistPropertyBag::InitNew, IPersistPropertyBag::Load
14.6.13 IPersistStorage
The IPersistStorage interface defines methods that enable a container applicatio
n to pass a storage object to one of its contained objects and to load and save
the storage object. This interface supports the structured storage model, in whi
ch each contained object has its own storage that is nested within the container s
storage.
The IPersistStorage contract inherits its definition from IPersist, so all imple
mentations must also include the GetClassID method of IPersist.
14.6.13.1.1 When to Implement
Any object that can be embedded in a container must implement the IPersistStorag
e interface. This interface is one of the primary interfaces for a compound docu
ment object. Embeddable objects must also implement the IOleObjectand IDataObjec
t interfaces.
The COM default handler for embedded objects provides an implementation of the I
PersistStorage interface that is used when the object is in the loaded state. Si
milarly, the COM default link handler provides an IPersistStorage implementation
that manages storage for a linked object. These default handlers both interact
with the COM default cache implementation, which has its own IPersistStorage imp
lementation.
If you are providing a custom embedding or link handler for your objects, the ha
ndler must include an implementation of IPersistStorage. You can delegate calls
to the default handler so you can take advantage of the default cache implementa
tion.
14.6.13.1.2 When to Use
When an COM container creates a new object, loads an existing object from storag
e, or inserts a new object in a clipboard or a drag-and-drop operation, the cont
ainer uses the IPersistStorage interface to initialize the object and put it in
the loaded or running state. When an object is loaded or running, an COM contain
er calls other IPersistStorage methods to instruct the object to perform various
save operations or to release its storage.
Typically, applications use helper functions such as OleLoad or OleCreate, rathe
r than calling the IPersistStorage::Load or IPersistStorage::InitNew methods dir
ectly. Similarly, applications typically call the OleSave helper function rather
than calling IPersistStorage::Save directly.
Methods in Vtable Order
IUnknown Methods Description
QueryInterface Returns pointers to supported interfaces.
AddRef Increments reference count.
Release Decrements reference count.
IPersist Method Description
GetClassID Returns the class identifier (CLSID) for the object on which it
is implemented.
14.6.13.2 IPersistStorage::HandsOffStorage
Instructs the object to release all storage objects that have been passed to it
by its container and to enter HandsOff mode, in which the object cannot do anyth
ing and the only operation that works is a close operation.
HRESULT HandsOffStorage(void);
Return Value
S_OK
The object has successfully entered HandsOff mode.
Remarks
This method causes an object to release any storage objects that it is holding a
nd to enter the HandsOff mode until a subsequent IPersistStorage::SaveCompleted
call. In HandsOff mode, the object cannot do anything and the only operation tha
t works is a close operation.
A container application typically calls this method during a full save or low-me
mory full save operation to force the object to release all pointers to its curr
ent storage. In these scenarios, the HandsOffStorage call comes after a call to
either OleSave or IPersistStorage::Save, putting the object in HandsOffAfterSave
mode. Calling this method is necessary so the container application can delete
the current file as part of a full save, or so it can call the IRootStorage::Swi
tchToFile method as part of a low-memory save.
A container application also calls this method when an object is in Normal mode
to put the object in HandsOffFromNormal mode.
While the component object is in either HandsOffAfterSave or HandsOffFromNormal
mode, most operations on the object will fail. Thus, the container should restor
e the object to Normal mode as soon as possible. The container application does
this by calling the IPersistStorage::SaveCompleted method, which passes a storag
e pointer back to the component object for the new storage object.
14.6.13.2.1.1.1 Notes to Implementers
This method must release all pointers to the current storage object, including p
ointers to any nested streams and storages. If the object contains nested object
s, the container application must recursively call this method for any nested ob
jects that are loaded or running.
See Also
IPersistStorage::Save, IPersistStorage::SaveCompleted, IRootStorage::SwitchToFil
e
14.6.13.3 IPersistStorage::InitNew
Initializes a new object, providing a pointer to the storage to be used for the
object.
HRESULT InitNew(
IStorage *pStg //Points to the new storage object
);
Parameter
pStg
[in]IStorage pointer to the new storage object to be initialized. The container
creates a nested storage object in its storage object (see IStorage::CreateStora
ge). Then, the container calls the WriteClassStg function to initialize the new
storage object with the object class identifier (CLSID).
Return Values
S_OK
The new storage object was successfully initialized.
CO_E_ALREADYINITIALIZED
The object has already been initialized by a previous call to either the IPersis
tStorage::Load method or the IPersistStorage::InitNew method.
E_OUTOFMEMORY
The storage object was not initialized due to a lack of memory.
E_FAIL
The storage object was not initialized for some reason other than a lack of memo
ry.
Remarks
A container application can call this method when it needs to initialize a new o
bject, for example, with an InsertObject command.
An object that supports the IPersistStorage interface must have access to a vali
d storage object at all times while it is running. This includes the time just a
fter the object has been created but before it has been made persistent. The obj
ect s container must provide the object with a valid IStorage pointer to the stora
ge during this time through the call to IPersistStorage::InitNew. Depending on t
he container s state, a temporary file might have to be created for this purpose.
If the object wants to retain the IStorage instance, it must call IUnknown::AddR
ef to increment its reference count.
After the call to IPersistStorage::InitNew, the object is in either the loaded o
r running state. For example, if the object class has an in-process server, the
object will be in the running state. However, if the object uses the default han
dler, the container s call to InitNew only invokes the handler s implementation whic
h does not run the object. Later if the container runs the object, the handler c
alls the IPersistStorage::InitNew method for the object.
14.6.13.3.1.1.1 Notes to Callers
Rather than calling IPersistStorage::InitNew directly, you typically call the Ol
eCreatehelper function which does the following:
1. Calls the CoCreateInstance function to create an instance of the
object class
2. Queries the new instance for the IPersistStorage interface
3. Calls the IPersistStorage::InitNew method to initialize the obje
ct
The container application should cache the IPersistStorage pointer to the object
for use in later operations on the object.
14.6.13.3.1.1.2 Notes to Implementers
An implementation of IPersistStorage::InitNew should initialize the object to it
s default state, taking the following steps:
1. Pre-open and cache the pointers to any streams or storages that
the object will need to save itself to this storage.
2. Call IPersistStorage::AddRef and cache the storage pointer that
is passed in.
3. Call the WriteFmtUserTypeStg function to write the native clipbo
ard format and user type string for the object to the storage object.
4. Set the dirty flag for the object.
The first two steps are particularly important for ensuring that the object can
save itself in low memory situations. Pre-opening and holding onto pointers to t
he stream and storage interfaces guarantee that a save operation to this storage
will not fail due to insufficient memory.
Your implementation of this method should return the CO_E_ALREADYINITIALIZED err
or code if it receives a call to either the IPersistStorage::InitNew method or t
he IPersistStorage::Load method after it is already initialized.
See Also
IPersistStorage::Load, WriteFmtUserTypeStg
14.6.13.4 IPersistStorage::IsDirty
Indicates whether the object has changed since it was last saved to its current
storage.
HRESULT IsDirty(void);
Return Values
S_OK
The object has changed since it was last saved.
S_FALSE
The object has not changed since the last save.
Remarks
This method checks whether an object has changed since it was last saved so you
can save it before closing it. The dirty flag for an object is conditionally cle
ared in the IPersistStorage::Save method.
For example, you could optimize a File:Save operation by calling the IPersistSto
rage::IsDirty method for each object and then calling the IPersistStorage::Save
method only for those objects that are dirty.
14.6.13.4.1.1.1 Notes to Callers
You should treat any error return codes as an indication that the object has cha
nged. In other words, unless this method explicitly returns S_FALSE, you must as
sume that the object needs to be saved.
14.6.13.4.1.1.2 Notes to Implementers
A container with one or more contained objects must maintain an internal dirty f
lag that is set whenever any of its contained objects are dirty.
See Also
IAdviseSink::OnDataChange, IDataObject::DAdvise, IPersistStorage::Save
14.6.13.5 IPersistStorage::Load
Loads an object from its existing storage.
HRESULT Load(
IStorage *pStg //Pointer to existing storage for the object
);
Parameter
pStg
[in]IStorage pointer to the existing storage from which the object is to be load
ed.
Return Values
S_OK
The object was successfully loaded.
CO_E_ALREADYINITIALIZED
The object has already been initialized by a previous call to the IPersistStorag
e::Load method or the IPersistStorage::InitNew method.
E_OUTOFMEMORY
The object was not loaded due to lack of memory.
E_FAIL
The object was not loaded due to some reason besides a lack of memory.
Remarks
This method initializes an object from an existing storage. The object is placed
in the loaded state if this method is called by the container application. If c
alled by the default handler, this method places the object in the running state
.
Either the default handler or the object itself can hold onto the IStorage point
er while the object is loaded or running.
14.6.13.5.1.1.1 Notes to Callers
Rather than calling IPersistStorage::Load directly, you typically call the OleLo
ad helper function which does the following:
1. Create an uninitialized instance of the object class
2. Query the new instance for the IPersistStorage interface
3. Call IPersistStorage::Load to initialize the object from the exi
sting storage
You also call this method indirectly when you call the OleCreateFromData functio
n or the OleCreateFromFile function to insert an object into a compound file (as
in a drag-and-drop or clipboard paste operation).
The container should cache the IPersistStorage pointer for use in later operatio
ns on the object.
14.6.13.5.1.1.2 Notes to Implementers
Your implementation should perform the following steps to load an object:
1. Open the object s streams in the storage object, and read the nece
ssary data into the object s internal data structures.
2. Clear the object s dirty flag.
3. Call the IPersistStorage::AddRef method and cache the passed in
storage pointer.
4. Keep open and cache the pointers to any streams or storages that
the object will need to save itself to this storage.
5. Perform any other default initialization required for the object
.
Steps 3 and 4 are particularly important for ensuring that the object can save i
tself in low memory situations. Holding onto pointers to the storage and stream
interfaces guarantees that a save operation to this storage will not fail due to
insufficient memory.
Your implementation of this method should return the CO_E_ALREADYINITIALIZED err
or code if it receives a call to either the IPersistStorage::InitNew method or t
he IPersistStorage::Load method after it is already initialized.
See Also
GetConvertStg, IPersistStorage::InitNew, ReadFmtUserTypeStg, SetConvertStg, Writ
eFmtUserTypeStg
14.6.13.6 IPersistStorage::Save
Saves an object, and any nested objects that it contains, into the specified sto
rage. The object is placed in NoScribble mode, and it must not write to the spec
ified storage until it receives a call to its IPersistStorage::SaveCompleted met
hod.
HRESULT Save(
IStorage *pStgSave, //Pointer to storage object
BOOL fSameAsLoad //Indicates whether the specified storage object is the
current one
);
Parameters
pStgSave
[in]IStorage pointer to the storage into which the object is to be saved.
fSameAsLoad
[in]Indicates whether the specified storage is the current one, which was passed
to the object by one of the following calls:
· IPersistStorage::InitNew when it was created.
· IPersistStorage::Load when it was loaded.
· IPersistStorage::SaveCompleted when it was saved to a storage different from its
current storage.
This parameter is set to FALSE when performing a Save As or Save A Copy To opera
tion or when performing a full save. In the latter case, this method saves to a
temporary file, deletes the original file, and renames the temporary file.
This parameter is set to TRUE to perform a full save in a low-memory situation o
r to perform a fast incremental save in which only the dirty components are save
d.
Return Values
S_OK
The object was successfully saved.
STG_E_MEDIUMFULL
The object was not saved because of a lack of space on the disk.
E_FAIL
The object could not be saved due to errors other than a lack of disk space.
Remarks
This method saves an object, and any nested objects it contains, into the specif
ied storage. It also places the object into NoScribble mode. Thus, the object ca
nnot write to its storage until a subsequent call to the IPersistStorage::SaveCo
mpleted method returns the object to Normal mode.
If the storage object is the same as the one it was loaded or created from, the
save operation may be able to write incremental changes to the storage object. O
therwise, a full save must be done.
This method recursively calls the IPersistStorage::Save method, the OleSave func
tion, or the IStorage::CopyTo method to save its nested objects.
This method does not call the IStorage::Commit method. Nor does it write the CLS
ID to the storage object. Both of these tasks are the responsibilities of the ca
ller.
14.6.13.6.1.1.1 Notes to Callers
Rather than calling IPersistStorage::Save directly, you typically call the OleSa
ve helper function which performs the following steps:
1. Call the WriteClassStg function to write the class identifier fo
r the object to the storage.
2. Call the IPersistStorage::Save method.
3. If needed, call the IStorage::Commit method on the storage objec
t.
Then, a container application performs any other operations necessary to complet
e the save and calls the SaveCompleted method for each object.
If an embedded object passes the IPersistStorage::Save method to its nested obje
cts, it must receive a call to its IPersistStorage::SaveCompleted method before
calling this method for its nested objects.
See Also
IPersistStorage::InitNew, IPersistStorage::Load, IPersistStorage::SaveCompleted,
IStorage::Commit, IStorage::CopyTo, WriteClassStg, WriteFmtUserTypeStg
14.6.13.7 IPersistStorage::SaveCompleted
Notifies the object that it can revert from NoScribble or HandsOff mode, in whic
h it must not write to its storage object, to Normal mode, in which it can. The
object enters NoScribble mode when it receives an IPersistStorage::Save call.
HRESULT SaveCompleted(
IStorage *pStgNew //Pointer to the current storage object
);
Parameter
pStgNew
[in]IStorage pointer to the new storage object, if different from the storage ob
ject prior to saving. This pointer can be NULL if the current storage object doe
s not change during the save operation. If the object is in HandsOff mode, this
parameter must be non-NULL.
Return Values
S_OK
The object was successfully returned to Normal mode.
E_OUTOFMEMORY
The object remained in HandsOff mode or NoScribble mode due to a lack of memory.
Typically, this error occurs when the object is not able to open the necessary
streams and storage objects in pStgNew.
E_INVALIDARG
The pStgNew parameter is not valid. Typically, this error occurs if pStgNew is N
ULL when the object is in HandsOff mode.
E_UNEXPECTED
The object is in Normal mode, and there was no previous call to IPersistStorage:
:Save or IPersistStorage::HandsOffStorage.
Remarks
This method notifies an object that it can revert to Normal mode and can once ag
ain write to its storage object. The object exits NoScribble mode or HandsOff mo
de.
If the object is reverting from HandsOff mode, the pStgNew parameter must be non
-NULL. In HandsOffFromNormal mode, this parameter is the new storage object that
replaces the one that was revoked by the IPersistStorage::HandsOffStorage metho
d. The data in the storage object is a copy of the data from the revoked storage
object. In HandsOffAfterSave mode, the data is the same as the data that was mo
st recently saved. It is not the same as the data in the revoked storage object.
If the object is reverting from NoScribble mode, the pStgNew parameter can be NU
LL or non-NULL. If NULL, the object once again has access to its storage object.
If it is not NULL, the component object should simulate receiving a call to its
IPersistStorage::HandsOffStorage method. If the component object cannot simulat
e this call, its container must be prepared to actually call the IPersistStorage
::HandsOffStorage method.
The IPersistStorage::SaveCompleted method must recursively call any nested objec
ts that are loaded or running.
If this method returns an error code, the object is not returned to Normal mode.
Thus, the container object can attempt different save strategies.
See Also
IAdviseSink::OnSave, IPersistStorage::HandsOffStorage, IPersistStorage::Save, IR
ootStorage::SwitchToFile
14.6.14 IPersistStream
The IPersistStream interface provides methods for saving and loading objects tha
t use a simple serial stream for their storage needs. The IPersistStream interfa
ce inherits its definition from the IPersist interface, and so the includes the
GetClassID method of IPersist.
One way in which it is used is to support COM moniker implementations. Each of t
he COM-provided moniker interfaces provides an IPersistStream implementation thr
ough which the moniker saves or loads itself. An instance of the COM generic com
posite moniker class calls the IPersistStream methods of its component monikers
to load or save the components in the proper sequence in a single stream.
COM containers with embedded and linked component objects do not use this interf
ace; they use the IPersistStorage interface instead.
14.6.14.1.1 When to Implement
Implement the IPersistStream interface on objects that are to be saved to a simp
le stream. Some objects of this type are monikers and some COM controls, althoug
h generally, controls use the IPersistStreamInit interface, which has the same m
ethods as IPersistStream, with one added method, IPersistStreamInit::InitNew. Th
e IMoniker interface is derived from the IPersistStream interface, so you must i
mplement the IPersistStream interface if you are implementing a new moniker clas
s.
14.6.14.1.2 When to Use
Call methods of IPersistStream from a container application to save or load obje
cts that are contained in a simple stream. When used to save or load monikers, t
ypical applications do not call the methods directly, but allow the default link
handler to make the calls to save and load the monikers that identify the link
source. These monikers are stored in a stream in the storage for the linked obje
ct. If you are writing a custom link handler for your class of objects, you woul
d call the methods of IPersistStream to implement the link handler.
Methods in Vtable Order
14.6.14.2 IPersistStream::GetSizeMax
Returns the size in bytes of the stream needed to save the object.
HRESULT GetSizeMax(
ULARGE_INTEGER *pcbSize //Pointer to size of stream needed to save objec
t
);
Parameter
pcbSize
[out]Points to a 64-bit unsigned integer value indicating the size in bytes of t
he stream needed to save this object.
Return Value
S_OK
The size was successfully returned.
Remarks
This method returns the size needed to save an object. You can call this method
to determine the size and set the necessary buffers before calling the IPersistS
tream::Save method.
14.6.14.2.1.1.1 Notes to Implementers
The GetSizeMax implementation should return a conservative estimate of the neces
sary size because the caller might call the IPersistStream::Save method with a n
on-growable stream.
See Also
IPersistStream::Save
14.6.14.3 IPersistStream::IsDirty
Checks the object for changes since it was last saved.
HRESULT IsDirty(void);
Return Values
S_OK
The object has changed since it was last saved.
S_FALSE
The object has not changed since the last save.
Remarks
This method checks whether an object has changed since it was last saved so you
can avoid losing information in objects that have not yet been saved. The dirty
flag for an object is conditionally cleared in the IPersistStream::Save method.
14.6.14.3.1.1.1 Notes to Callers
You should treat any error return codes as an indication that the object has cha
nged. In other words, unless this method explicitly returns S_FALSE, you must as
sume that the object needs to be saved.
Note that the COM-provided implementations of the IPersistStream::IsDirty method
in the COM-provided moniker interfaces always return S_FALSE because their inte
rnal state never changes.
See Also
IPersistStream::Save
14.6.14.4 IPersistStream::Load
Initializes an object from the stream where it was previously saved.
HRESULT Load(
IStream *pStm //Pointer to the stream from which the object should be
loaded
);
Parameter
pStm
[in]IStream pointer to the stream from which the object should be loaded.
Return Values
S_OK
The object was successfully loaded.
E_OUTOFMEMORY
The object was not loaded due to a lack of memory.
E_FAIL
The object was not loaded due to some reason other than a lack of memory.
Remarks
This method loads an object from its associated stream. The seek pointer is set
as it was in the most recent IPersistStream::Save method. This method can seek a
nd read from the stream, but cannot write to it.
On exit, the seek pointer must be in the same position it was in on entry, immed
iately past the end of the data.
14.6.14.4.1.1.1 Notes to Callers
Rather than calling IPersistStream::Load directly, you typically call the OleLoa
dFromStream function does the following:
1. Calls the ReadClassStm function to get the class identifier from
the stream.
2. Calls the CoCreateInstance function to create an instance of the
object.
3. Queries the instance for IPersistStream.
4. Calls IPersistStream::Load.
The OleLoadFromStream function assumes that objects are stored in the stream wit
h a class identifier followed by the object data. This storage pattern is used b
y the generic, composite-moniker implementation provided by COM.
If the objects are not stored using this pattern, you must call the methods sepa
rately yourself.
See Also
CoCreateInstance, ReadClassStm
14.6.14.5 IPersistStream::Save
Saves an object to the specified stream.
HRESULT Save(
IStream *pStm, //Pointer to the stream where the object is to be saved
BOOL fClearDirty //Specifies whether to clear the dirty flag
);
Parameters
pStm
[in]IStream pointer to the stream into which the object should be saved.
fClearDirty
[in]Indicates whether to clear the dirty flag after the save is complete. If TRU
E, the flag should be cleared. If FALSE, the flag should be left unchanged.
Return Values
S_OK
The object was successfully saved to the stream.
STG_E_CANTSAVE
The object could not save itself to the stream. This error could indicate, for e
xample, that the object contains another object that is not serializable to a st
ream or that an IStream::Write call returned STG_E_CANTSAVE.
STG_E_MEDIUMFULL
The object could not be saved because there is no space left on the storage devi
ce.
Remarks
IPersistStream::Save saves an object into the specified stream and indicates whe
ther the object should reset its dirty flag.
The seek pointer is positioned at the location in the stream at which the object
should begin writing its data. The object calls the IStream::Write method to wr
ite its data.
On exit, the seek pointer must be positioned immediately past the object data. T
he position of the seek pointer is undefined if an error returns.
14.6.14.5.1.1.1 Notes to Callers
Rather than calling IPersistStream::Save directly, you typically call the OleSav
eToStream helper function which does the following:
1. Calls IPersistStream::GetClassID to get the object s CLSID.
2. Calls the WriteClassStm function to write the object s CLSID to th
e stream.
3. Calls IPersistStream::Save.
If you call these methods directly, you can write other data into the stream aft
er the CLSID before calling IPersistStream::Save.
The COM-provided implementation of IPersistStream follows this same pattern.
14.6.14.5.1.1.2 Notes to Implementers
The IPersistStream::Save method does not write the CLSID to the stream. The call
er is responsible for writing the CLSID.
The IPersistStream::Save method can read from, write to, and seek in the stream;
but it must not seek to a location in the stream before that of the seek pointe
r on entry.
See Also
IPersist::GetClassID, IStream::Write
14.6.15 IPersistStreamInit
The IPersistStreamInit interface is defined as a replacement for IPersistStream
in order to add an initialization method, InitNew. This interface is not derived
from IPersistStream; it is mutually exclusive with IPersistStream. An object ch
ooses to support only one of the two interfaces, based on whether it requires th
e InitNew method. Otherwise, the signatures and semantics of the other methods a
re the same as the corresponding methods of IPersistStream, except as described
below.
14.6.15.1.1 When to Implement
Implement this interface on any object that needs to support initialized stream-
based persistence, regardless of whatever else the object does. The presence of
the InitNew method requires some changes to other methods that are common to IPe
rsistStream, as noted in the method descriptions.
14.6.15.1.2 When to Use
Use this interface to initialize a stream-based object and to save that object t
o a stream.
Methods in Vtable Order
IUnknown Methods Description
QueryInterface Returns pointers to supported interfaces.
AddRef Increments reference count.
Release Decrements reference count.
IPersistStreamInit Methods Description
IsDirty Checks the object for changes since it was last saved.
Load Initializes an object from the stream where it was previously saved.
Save Saves an object into the specified stream and indicates whether the obje
ct should reset its dirty flag.
GetSizeMax Return the size in bytes of the stream needed to save the object
.
InitNew Initializes an object to a default state.
See Also
IPersistStream
14.6.15.2 IPersistStreamInit::GetSizeMax
Same as IPersistStream::GetSizeMax.
HRESULT GetSizeMax(
ULARGE_INTEGER* pcbSize //Receives a pointer to the size of the stream n
eeded to save object
);
14.6.15.3 IPersistStreamInit::InitNew
Initializes the object to a default state. This method is called instead of IPer
sistStreamInit::Load.
HRESULT InitNew(void);
Return Values
This method supports the standard return values E_OUTOFMEMORY and E_UNEXPECTED,
as well as the following:
S_OK
The object successfully initialized itself.
E_NOTIMPL
The object requires no default initialization. This error code is allowed becaus
e an object may choose to implement IPersistStreamInit simply for orthogonality
or in anticipation of a future need for this method.
Remarks
14.6.15.3.1.1.1 Notes to Implementers
If the object has already been initialized with Load, then this method must retu
rn E_UNEXPECTED.
See Also
IPersistStreamInit::Load
14.6.15.4 IPersistStreamInit::IsDirty
Same as IPersistStream::IsDirty.
HRESULT IsDirty(void);
14.6.15.5 IPersistStreamInit::Load
Same as IPersistStream::Load.
HRESULT Load(
LPSTREAM pStm //Pointer to the stream from which the object should be
loaded
);
Remarks
14.6.15.5.1.1.1 Notes to Implementers
If the object has already been initialized with InitNew, then this method must r
eturn E_UNEXPECTED.
14.6.15.6 IPersistStreamInit::Save
Same as IPersistStream::Save.
HRESULT Save(
LPSTREAM pStm , //Pointer to the stream where the object is to be saved
BOOL fClearDirty //Specifies whether to clear the dirty flag
);
14.6.16 IPropertyBag
The IPropertyBag interface provides an object with a property bag in which the o
bject can persistently save its properties.
When a client wishes to have exact control over how individually named propertie
s of an object are saved, it would attempt to use an object s IPersistPropertyBag
interface as a persistence mechanism. In that case the client supplies a propert
y bag to the object in the form of an IPropertyBag interface.
When the object wishes to read a property in IPersistPropertyBag::Load it will c
all IPropertyBag::Read. When the object is saving properties in IPersistProperty
Bag::Save it will call IPropertyBag::Write. Each property is described with a na
me in pszPropName whose value is exchanged in a VARIANT. This information allows
a client to save the property values as text, for instance, which is the primar
y reason why a client might choose to support IPersistPropertyBag.
The client records errors that occur during reading into the supplied error log.
14.6.16.1.1 When to Implement
A container implements this interface to provide its object with a way to store
their properties persistently.
14.6.16.1.2 When to Use
An object calls the methods on this interface to read and write its properties i
nto the container provided property bag.
Methods in Vtable Order
IUnknown Methods Description
QueryInterface Returns pointers to supported interfaces.
AddRef Increments reference count.
Release Decrements reference count.
IPropertyBag Methods Description
Read Called by the control to read a property from the storage provided by th
e container.
Write Called by the control to write each property in turn to the storage prov
ided by the container.
See Also
IErrorLog, IPersistPropertyBag
14.6.16.2 IPropertyBag::Read
Called by the control to read a property from the storage provided by the contai
ner.
HRESULT Read(
LPCOLESTR pszPropName, //Pointer to the property to be read
VARIANT* pVar, //Pointer to the VARIANT to receive the property value
IErrorLog* pErrorLog //Pointer to the caller s error log
);
Parameters
pszPropName
[in] Pointer to the name of the property to read. Cannot be NULL.
pVar
[in, out] Pointer to the caller-initialized VARIANT that is to receive the prope
rty value on output. The method must set both type and value fields in the VARIA
NT before returning. If the caller initialized the pVar->vt field on entry, the
property bag should attempt to coerce the value it knows into this type. If the
caller sets pVar->vt to VT_EMPTY, the property bag can use a convenient type tha
t is consistent with the data. For example, if the property is a string, the pro
perty bag cannot use VT_I4.
pErrorLog
[in] Pointer to the caller s IErrorLog interface in which the property bag stores
any errors that occur during reads. Can be NULL in which case the caller is not
interested in errors.
Return Values
S_OK
The property was read successfully. The caller becomes responsible for any alloc
ations that are contained in the VARIANT in pVar.
E_POINTER
The address in pszPropName is not valid (such as NULL).
E_INVALIDARG
The property named with pszPropName does not exist in the property bag.
E_FAIL
The property bag was unable to read the specified property, such as if the calle
r specified a data type to which the property bag could not coerce the known val
ue. If the caller supplied an error log, a more descriptive error was sent there
.
Remarks
This method asks the property bag to read the property named with pszPropName in
to the caller-initialized VARIANT in pVar. Errors that occur are logged in the e
rror log pointed to by pErrorLog.
When pVar->vt specifies another object pointer (VT_UNKNOWN or VT_DISPATCH) then
the property bag is responsible for creating and initializing the object describ
ed by pszPropName. The action taken by the property bag depends on the value of
pvar->punkVal or pvar->vdispVal. For example, if pvar->punkVal is non-NULL, the
property bag initializes the existing object using the value of the pointer, usu
ally querying for a persistence interface and calling the Load method. However,
if pVar->punkVal is NULL, then the property bag creates a new object and loads i
t as appropriate.
E_NOTIMPL is not a valid return code since any object implementing this interfac
e must support the entire functionality of the interface.
See Also
IPropertyBag::Write
14.6.16.3 IPropertyBag::Write
Called by the control to write each property in turn to the storage provided by
the container.
HRESULT Write(
LPCOLESTR pszPropName, //Points to the property to be written
VARIANT* pVar //Points to the VARIANT containing the property value an
d type
);
Parameters
pszPropName
[in] Pointer to the name of the property to write. Cannot be NULL.
pVar
[in] Pointer to the caller-initialized VARIANT that holds the property value to
save. The caller owns this VARIANT and is responsible for all allocations therei
n. That is, the property bag itself does not attempt to free data in the VARIANT
.
Return Values
S_OK
The property bag successfully saved the requested property.
E_FAIL
There was a problem writing the property. It is possible that the property bag d
oes not understand how to save a particular VARIANT type.
E_POINTER
The address in pszPropName or pVar is not valid (such as NULL). The caller must
supply both.
Remarks
This method asks the property bag to save the property named with pszPropName us
ing the type and value in the caller-initialized VARIANT in pVar. In some cases
the caller may be asking the property bag to save another object, that is, when
pVar->vt is VT_UNKNOWN. In such cases, the property bag queries this object poin
ter for some persistence interface, like IPersistStream or even IPersistProperty
Bag again and has that object save its data as well. Usually, this results in th
e property bag having some byte array for this object which can be saved as enco
ded text (hex string, MIME, etc.). When the property bag is later used to reinit
ialize a control, the client that owns the property bag must recreate the object
when the caller asks for it, initializing that object with the previously saved
bits.
This allows very efficient persistence operations for large BLOB properties like
a picture, where the owner of the property bag itself directly asks the picture
object (managed as a property in the control being saved) to save into a specif
ic location. This avoids potential extra copy operations that would be involved
with other property-based persistence mechanisms.
E_NOTIMPL is not a valid return code as any object implementing this interface m
ust support the entire functionality of the interface.
See Also
IPropertyBag::Read
14.6.17 IPropertySetStorage
Creates, opens, deletes, and enumerates property set storages that support insta
nces of the IPropertyStorage interface. The IPropertyStorage interface manages a
single property set in a property storage subobject; the IPropertySetStorage in
terface manages the storage of groups of such property sets. IPropertySetStorage
can be supported by any file system entity, and is currently implemented in the
COM compound file object.
The IPropertySetStorage and IPropertyStorage interfaces provide a uniform way to
create and manage property sets, whether or not these sets reside in a storage
object that supports IStorage. When called through an object supporting IStorage
(such as structured and compound files and directories) or IStream, the propert
y sets created conform to the COM property set format, described in detail in Ap
pendix C of the COM Programming Guide. Similarly, properties written using IStor
age to the COM property set format are visible through IPropertySetStorage and I
PropertyStorage. IPropertyStorage does not support extensions to the COM seriali
zed property set format or multiple sections, because you can get equivalent fun
ctionality as simply by creating new sets or by adding new properties to existin
g property sets.
IPropertySetStorage methods identify property sets through a GUID called a forma
t identifier (FMTID). The FMTID for a property set identifies the set of propert
y identifiers in the property set, their meaning, and any constraints on the val
ues. The format identifier of a property set should also provide the means to ma
nipulate that property set. Only one instance of a given FMTID may exist at a ti
me within a single property storage.
14.6.17.1.1 When to Implement
Implement IPropertySetStorage to store persistent properties in the file system.
If you are using the COM compound files implementation, you can use the impleme
ntation on the compound file object created through a call to StgCreateDocfile o
r StgOpenStorage. Once you have a pointer to any of the interface implementation
s (such as IStorage) on this object, you can call QueryInterface to get a pointe
r to the IPropertySetStorage interface implementation.
14.6.17.1.2 When to Use
Call IPropertySetStorage methods to create, open, or delete one or more property
sets, or to enumerate the property sets contained in this property set storage.
Methods in Vtable Order
IUnknown Methods Description
QueryInterface Returns pointers to supported interfaces.
AddRef Increments reference count.
Release Decrements reference count.
IPropertySetStorage Methods Description
Create Creates a new property set.
Open Opens a previously created property set.
Delete Deletes an existing property set.
Enum Creates and retrieves a pointer to an object that can be used to enumera
te property sets.
See Also
IPropertyStorage, IEnumSTATPROPSETSTG, STATPROPSETSTG, PROPVARIANT
14.6.17.2 IPropertySetStorage::Create
Creates and opens a new property set in the property set storage object.
HRESULT Create(
REFFMTID fmtid, //Format identifier of the property set to be created
CLSID * pclsid, //Pointer to initial CLSID for this property set
DWORD grfFlags, //PROPSETFLAG values
DWORD grfMode, //Storage mode of new property set
IPropertyStorage** ppPropStg //Indirect pointer to property storage s
ub-object
);
Parameters
fmtid
[in] Format identifier of the property set to be created.
pclsid
[in] Pointer to the initial CLSID for this property set. May be NULL, in which c
ase it is set to all zeroes.
grfFlags
[in] Values from the PROPSETFLAG enumeration.
grfMode
[in] Access mode in which the newly created property set is to be opened, taken
from certain values of the STGM enumeration, as described in the Remarks.
ppPropStg
[out] Indirect pointer to the IPropertyStorage interface on the new property sto
rage sub-object.
Return Values
This method supports the standard return value E_UNEXPECTED, as well as the foll
owing:
S_OK
The property set was created.
STG_E_FILEALREADYEXISTS
A property set of the indicated name already exists, and STGM_CREATE was not spe
cified.
STG_E_ACCESSDENIED
The requested access to the property storage object has been denied.
STG_E_INSUFFICIENTMEMORY
There is not sufficient memory to perform this operation.
STG_E_INVALIDPARAMETER
A parameter is invalid.
Remarks
IPropertySetStorage::Create creates and opens a new property set sub-object (sup
porting the IPropertyStorage interface) contained in this property set storage o
bject. The property set automatically contains code page and locale ID propertie
s. These are set to the current system default, and the current user default, re
spectively.
The grfFlags parameter is a combination of values taken from the enumeration PRO
PSETFLAG.
The grfMode parameter specifies the access mode in which the newly created set i
s to be opened. Values for this parameter are as in the like-named parameter to
IPropertySetStorage::Open, with the addition of the following values:
Value Meaning
STGM_FAILIFTHERE If another property set with the specified fmtid already
exists, the call fails. This is the default action; that is, unless STGM_CREATE
is specified, STGM_FAILIFTHERE is implied.
STGM_CREATE If another property set with the specified fmtid already exists,
it is removed and replaced with this new one.
STGM_DIRECT Open the property set without an additional level of transaction
nesting. This is the default (the behavior if neither STGM_DIRECT nor STGM_TRAN
SACTED is specified).
STGM_TRANSACTED Open the property set with an additional level of transaction ne
sting (beyond the transaction, if any, on this property set storage). This is po
ssible only when you specify PROPSETFLAG_NONSIMPLE in the grfFlags parameter. Ch
anges in the property set must be committed with IPropertyStorage::Commit before
they are visible to the transaction on this property set storage.
STGM_READ Read access is desired on the property set. Read permission is r
equired on the property set storage.
STGM_WRITE Write access is desired on the property set. Write permission is
not required on the property set storage; however, such write permission is req
uired for changes in the storage to be committed.
STGM_READWRITE Read-write access is desired on the property set. Note that this
flag is not the binary OR of the values STGM_READ and STGM_WRITE.
STGM_SHARE_EXCLUSIVE Prevents others from subsequently opening the property s
et either in STGM_READ or STGM_WRITE mode.
Note
The only access mode supported by Create is STGM_SHARE_EXCLUSIVE. To use the res
ulting property set in an access mode other than STGM_SHARE_EXCLUSIVE, the calle
r should close the stream and then re-open it with a call to IPropertySetStorage
::Open.
See Also
IPropertySetStorage::Open
14.6.17.3 IPropertySetStorage::Delete
Deletes one of the property sets contained in the property set storage object.
HRESULT Delete(
14.6.17.4 IPropertySetStorage::Enum
Creates an enumerator object which contains information on the property sets sto
red in this property set storage. On return, this method supplies a pointer to t
he IEnumSTATPROPSETSTG pointer on the enumerator object.
HRESULT Enum(
IEnumSTATPROPSETSTG**ppenum //Indirect pointer to the new enumerator
);
Parameters
ppenum
[out] Indirect pointer to the IEnumSTATPROPSETSTG on the newly created enumerati
on object.
Return Values
S_OK
The enumerator object was successfully created.
STG_E_INSUFFICIENTMEMORY
There is not sufficient memory to perform this operation.
Remarks
IPropertySetStorage::Enum creates an enumerator object that can be used to itera
te through STATPROPSETSTG structures. These sometimes provide information on the
property sets managed by IPropertySetStorage. This method, on return, supplies
a pointer to the IEnumSTATPROPSETSTG interface on this enumerator object on retu
rn.
See Also
IEnumSTATPROPSETSTG, IEnumSTATPROPSETSTG -- Compound File Implementation
14.6.17.5 IPropertySetStorage::Open
Opens a property set contained in the property set storage object.
HRESULT Open(
REFFMTID fmtid, //The format identifier of the property set to be opened
DWORD grfMode, //Storage mode in which property set is to be opened
IPropertyStorage** ppPropStg //Indirect pointer to property storage o
bject
);
Parameters
fmtid
[in] Format identifier of the property set to be opened.
grfMode
[in] Access mode in which the newly created property set is to be opened. These
flags are taken from the STGM enumeration. Flags that may be used and their mean
ings in the context of this method are described in the Remarks.
ppPropStg
[in] Indirect pointer to the IPropertyStorage interface on the requested propert
y storage sub-object.
Return Values
This method supports the standard return value E_UNEXPECTED, as well as the foll
owing:
S_OK
Success.
STG_E_FILENOTFOUND
A property set of the indicated name does not exist.
STG_E_ACCESSDENIED
The requested access to the property storage object has been denied, or the prop
erty set is corrupted.
STG_E_INSUFFICIENTMEMORY
There is not sufficient memory to perform this operation.
STG_E_INVALIDPARAMETER
A parameter is invalid.
Remarks
The mode in which the property set is to be opened is specified in the parameter
grfMode. These flags are taken from the STGM enumeration, but, for this method,
legal values and their meanings are as follows (only certain combinations of th
ese flag values are legal).
Value Meaning
STGM_DIRECT Open the property set without an additional level of transaction
nesting. This is the default (the behavior if neither STGM_DIRECT nor STGM_TRAN
SACTED is specified).
STGM_TRANSACTED Open the property set with an additional level of transaction ne
sting (beyond the transaction, if any, on this property set storage object). Tra
nsacted mode is available only on non-simple property sets, because they use an
IStorage with a contents stream. Changes in the property set must be committed w
ith a call to IPropertyStorage::Commit before they are visible to the transactio
n on this property set storage.
STGM_READ Open the property set with read access. Read permission is requi
red on the property set storage.
STGM_WRITE Open the property set with write access. Write permission is not
required on the IPropertySetStorage; however, such write permission is required
for changes in the storage to be committed.
STGM_READWRITE Open the property set with read-write access. Note that this fla
g is not the binary OR of the values STGM_READ and STGM_WRITE.
STGM_SHARE_DENY_NONE Subsequent openings of the property set are not denied r
ead or write access. Not available in compound file implementation.
STGM_SHARE_DENY_READ Subsequent openings of the property set in are denied re
ad access. Not available in compound file implementation.
STGM_SHARE_DENY_WRITE Subsequent openings of the property set are denied write
access. This value is typically used to prevent making unnecessary copies of an
object opened by multiple users. If this value is not specified, a snapshot is
made, whether there are subsequent openings or not. Thus, you can improve perfor
mance by specifying this value. Not available in compound file implementation.
STGM_SHARE_EXCLUSIVE The combination of STGM_SHARE_DENY_READ and STGM_SHARE_D
ENY_WRITE.
14.6.18 IPropertySetStorage-Compound File Implementation
The COM compound file storage object implementation includes an implementation o
f both IPropertyStorage, the interface that manages a single persistent property
set, and IPropertySetStorage, the interface that manages groups of persistent p
roperty sets.
To get a pointer to the compound file implementation of IPropertySetStorage, fir
st call StgCreateDocfile to create a new compound file object or StgOpenStorage
to open a previously created compound file. Both functions supply a pointer to t
he object s IStorage interface. When you want to deal with persistent property set
s, call IStorage::QueryInterface for the IPropertySetStorage interface, specifyi
ng the header-defined name for the interface identifier IID_IPropertySetStorage.
14.6.18.1.1.1.1 When to Use
Call the methods of IPropertySetStorage to create, open, or delete property sets
in the current compound file property set storage. There is also a method that
supplies a pointer to an enumerator that can be used to enumerate the property s
ets in the storage.
Remarks
IPropertySetStorage::Create
Creates a new property set in the current compound file storage and, on return,
supplies an indirect pointer to the IPropertyStorage compound file implementatio
n. In this implementation, property sets may be transacted only if PROPSETFLAG_N
ONSIMPLE is specified.
IPropertySetStorage::Open
Opens an existing property set in the current property storage. On return, it su
pplies an indirect pointer to the compound file implementation of IPropertyStora
ge.
IPropertySetStorage::Delete
Deletes a property set in this property storage.
IPropertySetStorage::Enum
Creates an object that can be used to enumerate STATPROPSETSTG structures. Each
STATPROPSETSTG structure provides information about a single property set. The i
mplementation calls the constructor for IEnumSTATPROPSETSTG, which, in turn, use
s the pointer to the IStorage interface to create a STATSTG enumerator, which is
then used over the actual storage to get the information about the property set
s.
Note
The DocumentSummaryInformation property set is special, in that it may have two
property set sections. This property set is described in the OLE Programmer s Refe
rence, in the section titled The DocumentSummaryInformation Property Set. The se
cond section is referred to as the User-Defined Properties. Each section is iden
tified with a unique Format ID, for example FMTID_DocumentSummaryInformation and
FMTID_UserDefinedProperties.
When IPropertySetStorage::Create is called to create the User-Defined Property S
et, the first section is created automatically. Thus once FMTID_UserDefinedPrope
rties is created, FMTID_DocumentSummaryInformation need not be created, but can
be opened with a call to IPropertySetStorage::Open. Note that creating the first
section does not automatically create the second section. It is not possible to
open both sections simultaneously.
When IPropertySetStorage::Create is called to create the User-Defined Property S
et, the first section is created automatically. Thus once FMTID_UserDefinedPrope
rties is created, FMTID_DocumentSummaryInformation need not be created, but can
be opened with a call to IPropertySetStorage::Open. Note that creating the first
section does not automatically create the second section. It is not possible to
open both sections simultaneously.
Alternately, when IPropertySetStorage::Delete is called to delete the first sect
ion, both sections are deleted. That is, calling IPropertySetStorage::Delete wit
h FMTID_DocumentSummaryInformation, causes both that section and the FMTID_UserD
efinedProperties section to be deleted. Note that deleting the second section do
es not automatically delete the first section.
Finally, when IPropertySetStorage::Enum is used to enumerate property sets, the
User-Defined Property Set will not be enumerated.
See Also
IPropertyStorage, IPropertySetStorage - Compound File Implementation, STATPROPSE
TSTG structure, PROPSETFLAG enumeration, IStorage::EnumElements
14.6.19 IPropertySetStorage-Standalone Implementation
The system-provided, standalone implementation of IPropertySetStorage includes a
n implementation of both IPropertyStorage, the interface that reads and writes p
roperties in a property set storage, and IPropertySetStorage, the interface that
creates and opens property sets in a storage. The IEnumSTATPROPSTG and IEnumSTA
TPROPSETSTG interfaces are also provided in the standalone implementation.
To use the standalone implementation of IPropertySetStorage, you first obtain a
pointer to the system-provided, standalone implementation and associate the syst
em-provided implementation with your storage object. To get a pointer to the sta
ndalone implementation of IPropertySetStorage, call the StgCreatePropSetStg func
tion and provide the pStorage parameter specifying the storage object that will
contain the property set. This function supplies you with a pointer to the new I
PropertySetStorage interface for the specified storage object.
The standalone implementation of IPropertySetStorage creates property sets on an
y storage or stream object, not just on compound file storages and streams. The
standalone implementation does not depend on compound files and can be used with
any implementation of structured storages. See the section IPropertySetStorage-
Compound File Implementation in the Object Services section of the Platform SDK
for more information on the compound file implementation of this interface.
14.6.19.1.1.1.1 When to Use
Call the methods of IPropertySetStorage to create, open, and delete property set
s in any structured storage. There is also a method that supplies a pointer to t
he IEnumSTATPROPSETSTG enumerator that can be used to enumerate the property set
s in the storage.
The standalone implementation also provides the StgCreatePropStg and the StgOpen
PropStg helper functions in addition to the Create and Open methods to create an
d open property sets. These two functions add support for the PROPSETFLAG_UNBUFF
ERED value so you can directly write changes to the property set instead of buff
ering them in a cache. See the PROPSETFLAG enumeration for more information on u
sing this value.
Remarks
The standalone implementation of IPropertySetStorage supports the following meth
ods:
IPropertySetStorage::Create
Creates a new property set in the storage and returns a pointer to the IProperty
Storage interface on the property set.
If you plan to use the PROPSETFLAG_UNBUFFERED value, use the StgCreatePropStg fu
nction instead to create and open the new property set and to obtain a pointer t
o the standalone implementation for the IPropertyStorage interface on the proper
ty set.
IPropertySetStorage::Open
Opens an existing property set in the storage and returns a pointer to the IProp
ertyStorage interface on the property set.
If you plan to use the PROPSETFLAG_UNBUFFERED value, use the StgOpenPropStg func
tion instead to obtain a pointer to the standalone implementation of IPropertySt
orage on the specified property set.
IPropertySetStorage::Delete
Deletes a property set in this property set storage.
IPropertySetStorage::Enum
Creates an object that can be used to enumerate STATPROPSETSTG structures. Each
STATPROPSETSTG structure provides information about a single property set.
Note
The DocumentSummaryInformation property set is special, in that it may have two
property set sections. This property set is described in the Object Services top
ic of the Platform SDK in the section titled "The DocumentSummaryInformation Pro
perty Set." The second property set is referred to as the User-Defined Propertie
s. Each section is identified with a unique Format ID, for example FMTID_Documen
tSummaryInformation and FMTID_UserDefinedProperties.
When IPropertySetStorage::Create is called to create the User-Defined Property S
et, the first section is created automatically. Thus once FMTID_UserDefinedPrope
rties is created, FMTID_DocumentSummaryInformation need not be created, but can
be opened with a call to IPropertySetStorage::Open. Note that creating the first
section does not automatically create the second section. It is not possible to
open both sections simultaneously.
Alternately, when IPropertySetStorage::Delete is called to delete the first sect
ion, both sections are deleted. That is, calling IPropertySetStorage::Delete wit
h FMTID_DocumentSummaryInformation, causes both that section and the FMTID_UserD
efinedProperties section to be deleted. Note that deleting the second section do
es not automatically delete the first section.
Finally, when IPropertySetStorage::Enum is used to enumerate property sets, the
User-Defined Property Set isl not enumerated.
Programming Information
Unicode Yes
Import Library IPROP.DLL
Header File IPROPIDL.H
See Also
IPropertyStorage, IPropertySetStorage - Compound File Implementation, IPropertyS
torage-Standalone Implementation, STATPROPSETSTG, PROPSETFLAG, IStorage::EnumEle
ments, STGM, StgCreatePropStg, StgOpenPropStg, StgCreatePropSetStg
14.6.20 IPropertyStorage
Manages the persistent properties of a single property set. Persistent propertie
s consist of information that can be stored persistently in a property set, such
as the summary information associated with a file. This contrasts with run-time
properties associated with Controls and Automation, which can be used to affect
system behavior. Use the methods of the IPropertySetStorage interface to create
or open a persistent property set. An IPropertySetStorage instance can manage z
ero or more IPropertyStorage instances.
Each property within a property set is identified by a property identifier, a fo
ur-byte ULONG value unique to that set. You can also assign a string name to a p
roperty through the IPropertyStorage interface.
Property identifiers are different from the dispatch identifiers used in Automat
ion dispid property name tags. One difference is that the general-purpose use of
property identifier values zero and one is prohibited in IPropertyStorage, whil
e no such restriction exists in IDispatch. In addition, while there is significa
nt overlap in the data types for property values that may be used in IPropertySt
orage and IDispatch, the sets are not identical. Persistent property data types
used in IPropertyStorage methods are defined in the PROPVARIANT structure.
14.6.20.1.1.1.1 When to Implement
Implement IPropertyStorage when you want to store properties in the file system.
If you are using the COM compound files implementation, the compound file objec
t created through a call to StgCreateDocfile includes an implementation of IProp
ertySetStorage, which allows access to the implementation of IPropertyStorage. O
nce you have a pointer to any of the interface implementations (such as IStorage
) on this object, you can call QueryInterface to get a pointer to the IPropertyS
etStorage interface implementation, and then call either the Open or Create meth
od, as appropriate to obtain a pointer to the IPropertyStorage interface managin
g the specified property set.
14.6.20.1.1.1.2 When to Use
Use IPropertyStorage to create and manage properties that are stored in a given
property set.
Methods in Vtable Order
IUnknown Methods Description
QueryInterface Returns pointers to supported interfaces.
AddRef Increments reference count.
Release Decrements reference count.
IPropertyStorage Methods Description
ReadMultiple Reads property values in a property set.
WriteMultiple Writes property values in a property set.
DeleteMultiple Deletes properties in a property set.
ReadPropertyNames Gets corresponding string names for given property ident
ifiers.
WritePropertyNames Creates or changes string names corresponding to given p
roperty identifiers.
DeletePropertyNames Deletes string names for given property identifiers.
SetClass Assigns a CLSID to the property set.
Commit As in IStorage::Commit, flushes or commits changes to the property stora
ge object.
Revert When the property storage is opened in transacted mode, discards all cha
nges since the last commit.
Enum Creates and gets a pointer to an enumerator for properties within this s
et.
Stat Receives statistics about this property set.
SetTimes Sets modification, creation, and access times for the property s
et.
See Also
IPropertySetStorage, IEnumSTATPROPSTG, IEnumSTATPROPSETSTG, STATPROPSTG, STATPRO
PSETSTG, PROPVARIANT
14.6.20.2 IPropertyStorage::Commit
Saves any changes made to a property storage object to the parent storage object
.
HRESULT Commit(
14.6.20.3 IPropertyStorage::DeleteMultiple
Deletes as many of the indicated properties as exist in this property set.
HRESULT DeleteMultiple(
ULONG cpspec, //Count of properties to be deleted
PROPSPEC const rgpspec[] //Array of properties to be deleted
);
Parameters
cpspec
[in] Count of properties being deleted. May legally be zero, though this is a no
-op, deleting no properties.
rgpspec[]
[in] Properties to be deleted. A mixture of property identifiers and string-name
d properties is permitted. There may be duplicates, and there is no requirement
that properties be specified in any order.
Return Values
This method supports the standard return value E_UNEXPECTED, as well as the foll
owing:
S_OK
All of the specified properties that exist in the property set have been deleted
.
STG_E_ACCESSDENIED
The requested access to the property storage object has been denied. No properti
es were deleted.
STG_E_INSUFFICIENTMEMORY
There is not sufficient memory to perform this operation. Some properties may no
t have been deleted.
STG_E_INVALIDPARAMETER
At least one of the parameters is invalid, as when one of the PROPSPECs contains
an illegal ulKind value. Some properties may not have been deleted.
STG_E_INVALIDPOINTER
May be returned when at least one of the pointers passed in is invalid. Some pro
perties may not have been written. More frequently, an invalid pointer will inst
ead result in an access violation.
Remarks
IPropertyStorage::DeleteMultiple must delete as many of the indicated properties
as are in the current property set. If a deletion of a stream- or storage-value
d property occurs while that property is open, the deletion will succeed and pla
ce the previously returned IStream or IStorage pointer in the reverted state.
14.6.20.4 IPropertyStorage::DeletePropertyNames
Deletes specified string names from the current property set.
HRESULT DeletePropertyNames(
ULONG cpropid, //Size of the rgpropid array
PROPID const rgpropid[] //Property identifiers for which string names ar
e to be deleted
);
Parameters
cpropid
[in] The size on input of the array rgpropid. If 0, no property names are delete
d.
rgpropid[]
[in] Property identifiers for which string names are to be deleted.
Return Values
This method supports the standard return value E_UNEXPECTED, as well as the foll
owing:
S_OK
Success. The names of all of the indicated properties that exist in this set hav
e been deleted.
STG_E_ACCESSDENIED
The requested access to the property storage object has been denied. No property
names were deleted.
STG_E_INSUFFICIENTMEMORY
There is not sufficient memory to perform this operation. Some property names ma
y not have been deleted.
STG_E_INVALIDPARAMETER
At least one of the parameters is invalid. Some property names may not have been
deleted.
Remarks
For each property identifier in rgpropid, IPropertyStorage::DeletePropertyNames
removes the corresponding name-to-property identifier mapping, if any. An attemp
t to delete the name of a property that either does not exist or does not presen
tly have a string name associated with it is silently ignored. This method has n
o effect on the properties themselves.
Note
All the stored string property names can be deleted by deleting property identif
ier zero, but cpropid must be equal to 1 for this to not be an invalid parameter
error.
See Also
IPropertyStorage::ReadPropertyNames
14.6.20.5 IPropertyStorage::Enum
Creates an enumerator object designed to enumerate data of type STATPROPSTG, whi
ch contains information on the current property set. On return, this method supp
lies a pointer to the IEnumSTATPROPSTG pointer on this object.
HRESULT Enum(
IEnumSTATPROPSTG ** ppenum //Indirect pointer to new enumerator
);
Parameters
ppenum
[out] Indirect pointer to the IEnumSTATPROPSTG interface on the new enumeration
object.
Return Values
This method supports the standard return value E_UNEXPECTED, as well as the foll
owing:
S_OK
A pointer to the enumerator has been retrieved.
STG_E_ACCESSDENIED
The requested access to the property storage object has been denied.
STG_E_INSUFFICIENTMEMORY
There is not sufficient memory to perform this operation.
STG_E_INVALIDPARAMETER
The parameter is invalid.
STG_E_READFAULT
Error reading storage.
Remarks
IPropertyStorage::Enum creates an enumeration object that can be used to iterate
STATPROPSTG structures. On return, this method supplies a pointer to an instanc
e of IEnumSTATPROPSTG interface on this objects whose methods you can call to ob
tain information on the current property set.
See Also
IEnumSTATPROPSTG, IEnumSTATPROPSTG -- Compound File Implementation
14.6.20.6 IPropertyStorage::ReadMultiple
Reads specified properties from the current property set.
HRESULT ReadMultiple(
ULONG cpspec, //Count of properties being read.
PROPSPEC const rgpspec[], //Array of the properties to be read
PROPVARIANT rgvar[] //Array of PROPVARIANTs containing the property values o
n return
);
Parameters
cpspec
[in] Count of properties specified in the rgpspec array. May legally be zero, th
ough this is a no-op, reading no properties.
rgpspec[]
[in] The properties to be read in the PROPSPEC structures. Properties can be spe
cified either by property identifier or by optional string name. It is not neces
sary to specify properties in any particular order in the array. The array can c
ontain duplicate properties, resulting in duplicate property values on return fo
r simple properties. Non-simple properties should return access denied on an att
empt to open them a second time. The array can contain a mixture of property ide
ntifiers and string identifiers.
rgvar[]
[in, out] Caller-allocated array of PROPVARIANTs that, on return, contains the v
alues of the properties specified by rgpspec. The array must be able to receive
at least cpspec PROPVARIANTs. The caller does not need to initialize these PROPV
ARIANTs in any particular way; the implementation must fill in all field members
correctly on return. If there is no other appropriate value, the implementation
must set the vt member of each PROPVARIANT to VT_EMPTY.
Return Values
This method supports the standard return value E_UNEXPECTED, as well as the foll
owing:
S_OK
Success. At least some of the requested properties were retrieved.
S_FALSE
All the property names or identifiers had valid syntax, but none of them exist i
n this property set. Accordingly, no properties were retrieved., and each PROPVA
RIANT structure is set to VT_EMPTY.
STG_E_ACCESSDENIED
The requested access to the property set has been denied, or, when one or more o
f the properties is a stream or storage object, access to that substorage or sub
stream has been denied. (The storage or stream may already be open). No properti
es were retrieved.
STG_E_INSUFFICIENTMEMORY
There is not sufficient memory to perform this operation. No properties were ret
rieved.
STG_E_INVALIDPARAMETER
At least one of the parameters is invalid, such as when one of the PROPSPECs con
tains an illegal ulKind value. No properties were retrieved.
STG_E_INVALIDPOINTER
At least one of the pointers passed in is invalid. No properties were retrieved.
HRESULT_FROM_WIN32(ERROR_NO_UNICODE_TRANSLATION)
There was a failed attempt to translate a Unicode string to or from Ansi.
Remarks
IPropertyStorage::ReadMultiple reads as many of the properties specified in the
rgpspec array as are found in the property set. As long as any of the properties
requested is read, a request to retrieve a property that does not exist is not
an error. Instead, this must cause VT_EMPTY to be written for that property to t
he rgvar[] array on return. When none of the requested properties exist, the met
hod should return S_FALSE, and set VT_EMPTY in each PROPVARIANT. If any other er
ror is returned, no property values are retrieved, and the caller need not worry
about releasing them.
The rgpspec parameter is an array of PROPSPEC structures, which specify for each
property either its property identifier or, if one is assigned, a string identi
fier. You can map a string to a property identifier by calling IPropertyStorage:
:WritePropertyNames. The use of property identifiers is, however, likely to be s
ignificantly more efficient than the use of strings.
Properties that are requested by string name (PRSPEC_LPWSTR) are mapped case-ins
ensitively to property identifiers as they are specified in the current property
set (and according to the current system locale).
All propvariants, except for those that are pointers to streams and storages, ar
e called simple propvariants. These simple propvariants receive data by value, s
o a call to IPropertyStorage::ReadMultiple supplies a copy of the data that the
caller then owns. To create or update these properties, call IPropertyStorage::W
riteMultiple.
In contrast, the variant types VT_STREAM, VT_STREAMEDOBJECT, VT_STORAGE, and VT_
STOREDOBJECT are non-simple properties, because rather than supplying a value, t
he method retrieves a pointer to the indicated interface, from which the data ca
n then be read. These types permit the storage of large amounts of information t
hrough a single property. There are several issues that arise in using non-simpl
e properties.
To create these properties, as for the other properties, call IPropertyStorage::
WriteMultiple. Rather than calling the same method to update, however, it is mor
e efficient to first call IPropertyStorage::ReadMultiple to get the interface po
inter to the stream or storage, then write data using the IStream or IStorage me
thods. A stream or storage opened through a property is always opened in direct
mode, so an additional level of nested transaction is not introduced. There may,
however, still be a transaction on the property set as a whole, depending on ho
w it was opened or created through IPropertySetStorage. Further, the access and
share mode tags specified when the property set is opened or created, are passed
to property-based streams or storages.
The lifetimes of property-based stream or storage pointers, although theoretical
ly independent of their associated IPropertyStorage and IPropertySetStorage poin
ters, in fact, effectively depend on them. The data visible through the stream o
r storage is related to the transaction on the property storage object from whic
h it is retrieved, just as for a storage object (supporting IStorage) with conta
ined stream and storage sub-objects. If the transaction on the parent object is
aborted, existing IStream and IStorage pointers subordinate to that object enter
a zombie state. Because IPropertyStorage is the only interface on the property st
orage object, the useful lifetime of the contained IStream and IStorage pointers
is bounded by the lifetime of the IPropertyStorage interface.
The implementation must also deal with the situation where the same stream- or s
torage-valued property is requested multiple times through the same IPropertySto
rage interface instance. For example, in the COM compound file implementation, t
he open will succeed or fail depending on whether or not the property is already
open.
Another issue is multiple opens in transacted mode. The result depends on the is
olation level that was specified through a call to IPropertySetStorage methods,
(either the Open or Create method, through the STGM flags) at the time that the
property storage was opened .
If the call to open the property set specifies read-write access, IStorage- and
IStream-valued properties are always opened with read-write access. Data can the
n be written through these interfaces, changing the value of the property, which
is the most efficient way to update these properties. The property value itself
does not have an additional level of transaction nesting, so changes are scoped
under the transaction (if any) on the property storage object.
See Also
IPropertySetStorage, IPropertyStorage::WriteMultiple, IPropertyStorage::WritePro
pertyNames
14.6.20.7 IPropertyStorage::ReadPropertyNames
Retrieves any existing string names for the specified property identifiers.
HRESULT ReadPropertyNames(
ULONG cpropid, //Number of elements in rgpropid
PROPID const rgpropid[], //Property identifiers for which names are to be
retrieved.
LPWSTR rglpwstrName[] //Array of returned string names
);
Parameters
cpropid
[in] Number of elements on input of the array rgpropid. May legally be zero, tho
ugh this is a no-op, reading no property names.
rgpropid[]
[in] Array of property identifiers for which names are to be retrieved.
rglpwstrName[]
[in, out] Caller-allocated array of size cpropid of LPWSTRs. On return, the impl
ementation fills in this array. A given entry contains either the corresponding
string name of a property identifier or NULL if the property identifier has no s
tring name.
Each LPWSTR member of the array should be freed using CoTaskMemFree.
Return Values
This method supports the standard return value E_UNEXPECTED, as well as the foll
owing:
S_OK
One or more string names were retrieved and all members of rglpwstrName are vali
d (either NULL or a valid LPWSTR).
S_FALSE
No string names were retrieved because none of the requested property identifier
s have string names presently associated with them in this property storage obje
ct (this result does not address whether the given property identifiers presentl
y exist in the set).
STG_E_INVALIDHEADER
The property name dictionary was not found.
STG_E_READFAULT
Error reading the storage.
STG_E_ACCESSDENIED
The requested access to the property storage object has been denied. No string n
ames were retrieved.
STG_E_INSUFFICIENTMEMORY
There is not sufficient memory to perform this operation. No string names were r
etrieved.
STG_E_INVALIDPARAMETER
A parameter is invalid. No string names were retrieved.
HRESULT_FROM_WIN32(ERROR_NO_UNICODE_TRANSLATION)
There was a failed attempt to translate a Unicode string to or from Ansi.
Remarks
For each property identifier in the list of property identifiers supplied in the
rgpropid array, IPropertyStorage::ReadPropertyNames retrieves the corresponding
string name, if there is one. String names are created either by specifying the
names in calls to IPropertyStorage::WriteMultiple when you are creating the pro
perty, or through a call to IPropertyStorage::WritePropertyNames. In any case, t
he string name is optional; all properties must have a property identifier.
String names mapped to property identifiers must be unique within the set.
See Also
IPropertyStorage::WritePropertyNames, IPropertyStorage::WriteMultiple
14.6.20.8 IPropertyStorage::Revert
Discards all changes to the property set it was opened or changes were last comm
itted. Has no effect on a direct-mode property set.
HRESULT Revert();
Return Values
This method supports the standard return value E_UNEXPECTED, as well as the foll
owing:
S_OK
Success.
Remarks
For transacted-mode property sets, discards all changes that have been made in t
his property set since set was opened or the time it was last committed (dependi
ng on which is later). After this operation, any existing storage- or stream-val
ued properties that have been opened from the property set being reverted are in
valid and can no longer be used. The error STG_E_REVERTED will be returned on al
l calls except Release using these streams or storages.
For direct-mode property sets, this request is ignored and returns S_OK.
See Also
IPropertyStorage::Commit
14.6.20.9 IPropertyStorage::Stat
Retrieves information about the current open property set.
HRESULT Stat(
STATPROPSTG * pstatpsstg //Pointer to a filled-in STATPROPSETSTG structur
e
);
Parameters
pstatpsstg
[out] Pointer to a STATPROPSETSTG structure, which contains statistics about the
current open property set.
Return Values
This method supports the standard return value E_UNEXPECTED, as well as the foll
owing:
S_OK
Statistics were successfully obtained.
STG_E_ACCESSDENIED
The requested access to the property storage object has been denied.
STG_E_INSUFFICIENTMEMORY
There is not sufficient memory to perform this operation.
STG_E_INVALIDPARAMETER
The parameter is invalid.
Remarks
IPropertyStorage::Stat fills in and returns a pointer to a STATPROPSETSTG struct
ure, containing statistics about the current property set. STATPROPSETSTG fields
have the following meanings:
Field Meaning
fmtid The FMTID of this property set, specified when the property set was init
ially created.
clsid The CLSID of this property set, specified when the property set was init
ially created and possibly modified thereafter with IpropertyStorage::SetClass.
If not set, the value will be CLSID_NULL.
grfFlags The flag values this set was created with. For details, see Ipro
pertySetStorage::Create.
mtime The time in UTC (FILETIME) at which this property set was last modified.
Not all IPropertyStorage implementations maintain modification times on propert
y sets; those who do not will return zero for this value.
ctime The time in UTC (FILETIME) at which this property set was created. Not a
ll IPropertyStorage implementations maintain creation times on property sets; th
ose that do not will set this value to 0.
atime The time in UTC (FILETIME) at which this property set was last accessed.
Not all IPropertyStorage implementations maintain last access times on property
sets; those that do not will set this value to 0.
See Also
STATPROPSETSTG structure, IPropertySetStorage::Enum, FILETIME structure
14.6.20.10 IPropertyStorage::SetClass
Assigns a new CLSID to the current property storage object, and persistently sto
res the CLSID with the object.
HRESULT SetClass(
REFCLSID clsid //New CLSID for the property set
);
Parameters
clsid
[in] New CLSID to be associated with the property set.
Return Values
This method supports the standard return value E_UNEXPECTED, as well as the foll
owing:
S_OK
The CLSID has been assigned.
STG_E_ACCESSDENIED
The requested access to the IPropertyStorage interface has been denied. The CLSI
D was not assigned.
STG_E_INSUFFICIENTMEMORY
There is not sufficient memory to perform this operation. The CLSID was not assi
gned.
STG_E_INVALIDPARAMETER
The parameter is invalid. The CLSID was not assigned.
Remarks
Assigns a CLSID to the current property storage object. The CLSID has no relatio
nship to the stored property identifiers. Assigning a CLSID allows a piece of co
de to be associated with a given instance of a property set; such code, for exam
ple, might manage the user interface. Different CLSIDs can be associated with di
fferent property set instances that have the same FMTID.
If the property set is created with NULL specified as the IPropertySetStorage::C
reate pclsid parameter, the CLSID is set to all zeroes.
The current CLSID on a property storage object can be retrieved with a call to I
PropertyStorage::Stat. The initial value for the CLSID can be specified at the t
ime that the storage is created with a call to IPropertySetStorage::Create.
Setting the CLSID on a non-simple property set (one that can legally contain sto
rage- or stream-valued properties, as described in IPropertySetStorage::Create)
also sets the CLSID on the underlying sub-storage.
See Also
IPropertySetStorage::Create, IPropertyStorage::Stat
14.6.20.11 IPropertyStorage::SetTimes
Sets the modification, access, and creation times of this property set, if suppo
rted by the implementation. Not all implementations support all these time value
s.
HRESULT SetTimes(
FILETIME const * pctime, //New creation time for the property set
FILETIME const * patime, //New access time for the property set
FILETIME const * pmtime //New modification time for the property set
);
Parameters
pctime
[in] Pointer to the new creation time for the property set. May be NULL, indicat
ing that this time is not to be modified by this call.
patime
[in] Pointer to the new access time for the property set. May be NULL, indicatin
g that this time is not to be modified by this call.
pmtime
[in] Pointer to the new modification time for the property set. May be NULL, ind
icating that this time is not to be modified by this call.
Return Values
This method supports the standard return value E_UNEXPECTED, as well as the foll
owing:
S_OK
All the requested times have been successfully updated.
STG_E_ACCESSDENIED
The requested access to the property storage object has been denied; no times ha
ve been updated.
STG_E_INSUFFICIENTMEMORY
There is not sufficient memory to perform this operation.
STG_E_INVALIDPARAMETER
The parameter is invalid. This error is returned if an attempt is made to set a
time value which is not supported by this implementation.
Remarks
Sets the modification, access, and creation times of the current open property s
et, if supported by the implementation (not all implementations support all thes
e time values). Unsupported timestamps are always reported as zero, enabling the
caller to test for support. A call to IPropertyStorage::Stat supplies (among ot
her information) timestamp information.
Notice that this functionality is provided as an IPropertyStorage method on a pr
operty storage object that is already open, in contrast to being provided as a m
ethod in IPropertySetStorage. Normally, when the SetTimes method is not explicit
ly called, the access and modification times are updated as a side effect of rea
ding and writing the property set. When SetTimes is used, the latest specified t
imes supersede either default times or time values specified in previous calls t
o SetTimes.
See Also
IPropertyStorage::Stat, FILETIME structure
14.6.20.12 IPropertyStorage::WriteMultiple
Writes a specified group of properties to the current property set. If a propert
y with a specified name already exists, it is replaced, even when the old and ne
w types for the property value are different. If a property of a given name or p
roperty identifier does not exist, it is created.
HRESULT WriteMultiple(
ULONG cpspec, //The number of properties being set.
PROPSPEC const rgpspec[], //Property specifiers
PROPVARIANT const rgvar[], //Array of PROPVARIANT values
PROPID propidNameFirst //Minimum value for property identifiers when th
ey must be allocated
);
Parameters
cpspec
[in] The number of properties being set. May legally be zero, though this is a n
o-op, writing no properties.
rgpspec[]
[in] Array of the specifiers to which properties are to be set. These are in no
particular order, and may legally contain duplicates (the last specified is to t
ake effect). A mixture of property identifiers and string names is permitted.
rgvar[]
[in] An array (of size cpspec) of PROPVARIANTs that contain the property values
to be written. The array must be of the size specified by cpspec.
propidNameFirst
[in] Specifies the minimum value for the property identifiers the method must as
sign if the rgpspec parameter specifies string-named properties for which no pro
perty identifiers currently exist. If all string-named properties specified alre
ady exist in this set, and thus already have property identifiers, this value is
ignored. When not ignored, this value must be at least two (property identifier
s 0and 1 are reserved for special uses) and less than 0x80000000 (property ident
ifier values beyond that are reserved for special use).
HRESULT_FROM_WIN32(ERROR_NO_UNICODE_TRANSLATION)
There was a failed attempt to translate a Unicode string to or from Ansi.
Return Values
This method supports the standard return value E_UNEXPECTED, as well as the foll
owing:
S_OK
All of the indicated properties were successfully written.
STG_E_ACCESSDENIED
The requested access to the property storage object has been denied. No properti
es have been written. The property set was opened in STGM_READ mode.
STG_E_INSUFFICIENTMEMORY
There is not sufficient memory to perform this operation. Some properties may or
may not have been written.
STG_E_INVALIDPARAMETER
At least one of the parameters is invalid. Some properties may not have been wri
tten. This error would be returned in several situations, for example: 1) rgvar
may be NULL; 2) a stream- or storage-valued property is present in rgpspec but t
he property set was created without PROPSETFLAG_NONSIMPLE; 3) one or more proper
ty variant types may be invalid; 4) one of the PROPSPECs contains an illegal ulK
ind value.
STG_E_INVALIDPOINTER
May be returned when at least one of the pointers passed in is invalid. Some pro
perties may or may not have been written. More frequently, an invalid pointer wi
ll instead result in an access violation.
STG_E_WRITEFAULT
Error writing the storage.
STG_E_REVERTED
The property set was reverted. For example, if the property set is deleted while
open (by using IPropertySetStorage::Delete) this status would be returned.
STG_E_MEDIUMFULL
The disk is full. Some properties may or may not have been written.
STG_E_PROPSETMISMATCHED
An attempt was made to write a non-simple (stream- or storage-valued) property t
o a simple property set.
Remarks
If a specified property already exists, it s value is replaced with the new one, e
ven when the old and new types for the property value are different. If you spec
ify a property identifier that does not exist, that property is created. If a st
ring name is supplied for a property which does not exist, the method will alloc
ate a property identifier for that property, and the name will be added to the d
ictionary.
When allocating a property identifier, the implementation can choose any value n
ot currently in use in the property set for a property identifier, as long as it
is not 0 or 1 or greater than 0x80000000, all of which are reserved values. The
propidNameFirst parameter establishes a minimum value for property identifiers
within the set, and must be greater than 1 and less than 0x80000000.
If there is an attempt to write a property that already exists with an invalid p
arameter, the method should return STG_E_INVALIDPARAMETER; if the property does
not exist, it should not be created. This behavior facilitates the use of a Read
Multiple update WriteMultiple sequence to update a group of properties without r
equiring that the calling code ensure that all the requested properties in the c
all to ReadMultiple were retrieved.
It is recommended that property sets be created as Unicode, by not setting the P
ROPSETFLAG_ANSI flag in the grfFlags parameter of IPropertySetStorage::Create. I
t is also recommended that you avoid using VT_LPSTR values, and use VT_LPWSTR va
lues instead. When the property set code page is Unicode, VT_LPSTR string values
are converted to Unicode when stored, and back to multibyte string values when
retrieved. When the code page of the property set is not Unicode, property names
, VT_BSTR strings, and non-simple property values are converted to multibyte str
ings when stored, and converted back to Unicode when retrieved, all using the cu
rrent system ANSI code page.
To create stream or storage object as a property in a nonsimple property set, ca
ll IPropertyStorage::WriteMultiple. While you would also call this method to upd
ate simple properties, it is not an efficient way to update stream and storage o
bjects in a property set. This is because updating one of these properties throu
gh a call to WriteMultiple creates in the property storage object a copy of the
passed-in data, and the IStorage or IStream pointers are not retained beyond the
duration of this call. It is usually more efficient to update stream or storage
objects by first calling IPropertyStorage::ReadMultiple to get the interface po
inter to the stream or storage, then writing data through the IStream or IStorag
e methods.
A stream or storage opened through a property is always opened in direct mode, s
o an additional level of nested transaction is not introduced. There is still li
kely to be a transaction on the property set as a whole. Further, a property-bas
ed stream or storage is opened in read-write mode, if possible, given the mode o
n the property set; otherwise, read mode is used.
When the copy is made, the underlying CopyTo operation on VT_STREAM properties o
perates on the current seek position of the source. The seek position is destroy
ed on failure, but on success it is at EOF.
If a stream or storage property does not exist, passing an IStream or IStorage p
ointer with a value of NULL creates an empty stream or storage property value. I
f a stream or storage property is already open from a call to ReadMultiple, a NU
LL value must cause the WriteMultiple operation to truncate it and return S_OK,
placing the previously returned stream- and storage-valued pointers into the rev
erted state (as happens in the compound file implementation.)
Storage- and stream-valued properties always manifest themselves to downlevel cl
ients as sibling streams or storages to the stream containing the main contents
of the property set¾they are never stored directly in-line in the property set. Th
is allows smooth interoperability and control when down-level clients interact w
ith up-level clients. Thus, from a downlevel perspective, property sets containi
ng IStream or IStorage valued properties are always stored in a storage object,
not a stream. The specific name of the sibling used is completely under the cont
rol of the IPropertyStorage implementation, as long as the name is from the non-
reserved part of the IStorage name space. See Appendix C of the OLE Programmer s G
uide for a discussion of the serialized property set format for further details.
As is described there, the string name is stored in the same format as a VT_BST
R. Refer also to the earlier discussion in this method of multibyte to Unicode c
onversions for property names.
If the WriteMultiple method returns an error when writing stream- or storage-val
ued properties (indirect properties), the amount of data actually written is und
efined. If the caller requires consistency of the property set and its indirect
properties when writing stream- and/or storage-valued properties, use of transac
ted mode is advised.
If an implicit deletion of a stream- or storage-valued property occurs while tha
t property is open, (as, for example, when a VT_I4 is written over a VT_STREAM),
the deletion will succeed and place the previously returned IStream pointer in
the reverted state.
See Also
IPropertySetStorage::Create, IPropertyStorage::ReadMultiple
14.6.20.13 IPropertyStorage::WritePropertyNames
Assigns string names to a specified array of property IDs in the current propert
y set.
HRESULT WritePropertyNames(
ULONG cpropid, //Size on input of the array rgpropid
PROPID const rgpropid[], //Property identifiers for which names are to be
set
LPWSTR const rglpwstrName[] //New names of the corresponding propert
y identifiers
);
Parameters
cpropid
[in] Size on input of the array rgpropid. May legally be zero, though this is a
no-op, writing no property names.
rgpropid[]
[in] Array of the property identifiers for which names are to be set.
rglpwstrName[]
[in] Array of new names to be assigned to the corresponding property identifiers
in the rgpropid array. These names may not exceed 255 characters (not including
the NULL terminator).
Return Values
This method supports the standard return value E_UNEXPECTED, as well as the foll
owing:
S_OK
Success. All of the indicated string names were successfully set.
STG_E_INVALIDNAME
At least one of the indicated property identifier values does not exist in this
property set. No names were set.
STG_E_ACCESSDENIED
The requested access to the property storage object has been denied. No property
names have been changed in the storage.
STG_E_INSUFFICIENTMEMORY
There is not sufficient memory to perform this operation. Some names may not hav
e been set.
STG_E_INVALIDPARAMETER
A parameter is invalid. Some names may not have been set.
HRESULT_FROM_WIN32(ERROR_NO_UNICODE_TRANSLATION)
There was a failed attempt to translate a Unicode string to or from Ansi.
Remarks
IPropertyStorage::WritePropertyNames assigns string names to property identifier
s passed to the method in the rgpropid array. It associates each string name in
the rglpwstrName array with the respective property identifier in rgpropid. It i
s explicitly valid to define a name for a property identifier that is not curren
tly present in the property storage object.
It is also valid to change the mapping for an existing string name (determined b
y a case-insensitive match). That is, you can use the WritePropertyNames method
to map an existing name to a new property identifier, or to map a new name to a
property identifier that already has a name in the dictionary. In either case, t
he original mapping is deleted. Property names must be unique (as are property i
dentifiers) within the property set.
The storage of string property names preserves the case. String property names a
re limited in length to 128 characters. Property names that begin with the binar
y Unicode characters 0x0001 through 0x001F are reserved for future use.
See Also
IPropertyStorage::ReadPropertyNames, IPropertyStorage::ReadMultiple, IPropertySt
orage::WriteMultiple
Unicode Yes
Import Library IPROP.DLL
Header File IPROPIDL.H
See Also
IPropertySetStorage-Standalone Implementation, IPropertyStorage, IStorage::SetEl
ementTimes, StgOpenPropStg, StgCreatePropStg, StgCreatePropSetStg
14.6.23 IRootStorage
The IRootStorage interface contains a single method that switches a storage obje
ct to a different underlying file and saves the storage object to that file. The
save operation occurs even with low memory conditions and uncommitted changes t
o the storage object. A subsequent call to IStorage::Commit is guaranteed to not
consume any additional memory.
14.6.23.1.1 When to Implement
Storage objects that are based on a file should implement IRootStorage in additi
on to the IStorage interface. For storage objects that are not file-based, this
interface is not necessary.
COM provides an implementation of a storage object, including the IRootStorage i
nterface, as part of its compound file implementation.
14.6.23.1.2 When to Use
The primary use for the IRootStorage interface is to save a storage object to a
file during low memory conditions. Typically, the container application calls th
e IRootStorage interface to switch to a new file.
If you have an IStorage pointer to a compound file object, you can call IStorage
::QueryInterface with IID_IRootStorage to obtain a pointer to the IRootStorage i
nterface.
Methods in Vtable Order
IUnknown Methods Description
Unicode Yes
Import Library IPROP.DLL
Header File IPROPIDL.H
See Also
PROPSETFLAG, StgCreatePropStg, StgOpenPropStg
14.7.3 PropVariantClear
Frees all elements that can be freed in a given PROPVARIANT structure.
HRESULT PropVariantClear(
PROPVARIANT* pvarg //Pointer to a PROPVARIANT structure
);
Parameters
pvarg
[in] Pointer to an initialized PROPVARIANT structure for which any deallocatable
elements are to be freed. On return, all zeroes are written to the PROPVARIANT.
Return Values
S_OK
The VT types are recognized and all items that can be freed have been freed.
STG_E_INVALID_PARAMETER
The variant has an unknown VT type.
Remarks
At any level of indirection, a NULL pointer is ignored. For example, in a VT_CF
PROPVARIANT, the pvarg¾pclipdata¾pClipData could be NULL. In this case, the pvarg¾pcli
pdata¾pClipData pointer would be ignored, but the pvarg¾pclipdata pointer would be
freed.
On return, this function writes zeroes to the specified PROPVARIANT, so the VT-t
ype is VT_EMPTY.
Passing NULL as the pvarg parameter produces a return code of S_OK.
See Also
FreePropVariantArray
14.7.4 PropVariantCopy
Copies the contents of a PROPVARIANT structure to another.
HRESULT PropVariantCopy(
PROPVARIANT * pDest //Pointer to uninitialized PROPVARIANT that is filled on
return
PROPVARIANT *pvarg //PROPVARIANT to be copied
);
Parameters
pDest
[in, out] Pointer to an uninitialized PROPVARIANT structure that receives the co
py.
pvarg
[in] Pointer to the PROPVARIANT to be copied.
Return Values
S_OK
The copy was successfully completed.
STG_E_INVALID_PARAMETER
The variant has an unknown type.
Remarks
Copies a PROPVARIANT by value so the original pvarg and new pDest may be freed i
ndependently with calls to PropVariantClear. For non-simple PROPVARIANT types su
ch as VT_STREAM, VT_STORAGE, etc, which require a subobject, the copy is made by
reference. The pointer is copied and AddRef is called on it. It is illegal to p
ass NULL for either pDest or pvarg.
14.7.5 ReadClassStg
Reads the CLSID previously written to a storage object with the WriteClassStg.
WINOLEAPI ReadClassStg(
IStorage * pStg, //Pointer to the storage object containing the CLSID
CLSID * pclsid //Pointer to return the CLSID
);
Parameters
pStg
[in] Pointer to the IStorage interface on the storage object containing the CLSI
D to be retrieved.
pclsid
[out] Pointer to where the CLSID is written. May return CLSID_NULL.
Return Values
This function supports the standard return value E_OUTOFMEMORY, as well as the f
ollowing:
S_OK
The CLSID was returned successfully.
This function also returns any of the error values returned by the IStorage::Sta
t method.
Remarks
This function is simply a helper function that calls the IStorage::Stat method a
nd retrieves the CLSID previously written to the storage object with a call to W
riteClassStg from the STATSTG structure.
See Also
WriteClassStg, IStorage::Stat, STATSTG structure.
14.7.6 ReadClassStm
Reads the CLSID previously written to a stream object with the WriteClassStm met
hod.
WINOLEAPI ReadClassStm(
IStream * pStm, //Pointer to the stream holding the CLSID
CLSID * pclsid //Pointer to where the CLSID is to be written
);
Parameters
pStm
[in] Pointer to the IStream interface on the stream object containing the CLSID
to be read. This CLSID must have been previously written to the stream object us
ing WriteClassStm.
pclsid
[out] Pointer to where the CLSID is to be written.
Return Values
S_OK
The CLSID was successfully retrieved.
STG_E_READFAULT
End of file was reached.
This function also returns any of the error values returned by the IStream::Read
method.
Remarks
Most applications do not call the ReadClassStm method directly. COM calls it bef
ore making a call to an object s IPersistStream::Load implementation.
See Also
WriteClassStm, ReadClassStg, WriteClassStg
14.7.7 ReadFmtUserTypeStg
Returns the clipboard format and user type previously saved with the WriteFmtUse
rTypeStg function.
WINOLEAPI ReadFmtUserTypeStg(
IStorage * pStg, //Pointer to storage object holding the values
CLIPFORMAT * pcf, //Pointer to return the clipboard format
LPWSTR * lplpszUserType //Address of output variable that receives a
// pointer to the requested user type string
);
Parameters
pStg
[in] Pointer to the IStorage interface on the storage object from which the info
rmation is to be read.
pcf
[out] Pointer to where the clipboard format is to be written on return. It can b
e NULL, indicating the format is of no interest to the caller.
lplpszUserType
[out] Address of LPWSTR pointer variable that receives a pointer to the user typ
e string. The caller can specify NULL for this parameter, indicating that the us
er type is of no interest . This function allocates memory for the string. The c
aller is responsible for freeing the memory with CoTaskMemFree.
Return Values
This function supports the standard return values E_FAIL, E_INVALIDARG, and E_OU
TOFMEMORY, as well as the following:
S_OK
The requested information was read successfully.
This function also returns any of the error values returned by the IStream::Read
method.
Remarks
This function returns the clipboard format and the user type string from the spe
cified storage object. The WriteClassStg function must have been called before c
alling the ReadFmtUserTypeStg function.
See Also
CoTaskMemFree, WriteFmtUserTypeStg
14.7.8 SetConvertStg
Sets the convert bit in a storage object to indicate that the object is to be co
nverted to a new class when it is opened. The setting can be retrieved with a ca
ll to the GetConvertStg function.
WINOLEAPI SetConvertStg(
IStorage * pStg, //Points to storage object where the conversion bit is t
o be set
BOOL fConvert //Indicates whether an object is to be converted
);
Parameters
pStg
IStorage pointer to the storage object in which to set the conversion bit.
fConvert
If TRUE, sets the conversion bit for the object to indicate the object is to be
converted when opened. If FALSE, clears the conversion bit.
Return Values
S_OK
Indicates the object s conversion bit was set successfully.
STG_E_ACCESSDENIED
Access denied because the caller has insufficient permission, or another caller
has the file open and locked.
STG_E_LOCKVIOLATION
Access denied because another caller has the file open and locked.
E_OUTOFMEMORY
Indicates the conversion bit was not set due to a lack of memory.
E_INVALIDARG
Indicates one or more arguments are invalid.
E_UNEXPECTED
Indicates an unexpected error occurred.
See the IStorage::CreateStream, IStorage::OpenStreamISequentialStream::Read, and
ISequentialStream::Write methods for possible storage and stream access errors.
Remarks
The SetConvertStg function determines the status of the convert bit in a contain
ed object. It is called by both the container application and the server in the
process of converting an object from one class to another. When a user specifies
through a Convert To dialogue (which the container produces with a call to the
OleUIConvert function) that an object is to be converted, the container must tak
e the following steps:
1. Unload the object if it is currently loaded.
2. Call WriteClassStg to write the new CLSID to the object storage.
3. Call WriteFmtUserTypeStg to write the new user type name and the
existing main format to the storage.
4. Call SetConvertStg with the fConvert parameter set to TRUE to in
dicate that the object has been tagged for conversion to a new class the next ti
me it is loaded.
5. Just before the object is loaded, call OleDoAutoConvert to handl
e any needed object conversion, unless you call OleLoad, which calls it internal
ly.
When an object is initialized from a storage object and the server is the destin
ation of a Convert To operation, the object server should do the following:
1. Call the GetConvertStg function to retrieve the value of the con
version bit.
2. If the bit is set, the server reads the data out of the object a
ccording to the format associated with the new CLSID.
3. When the object is asked to save itself, the object should call
WriteFmtUserType() using the normal native format and user type of the object.
4. The object should then call SetConvertStg with the fConvert para
meter set to FALSE to reset the object s conversion bit.
See Also
GetConvertStg
14.7.9 StgCreateDocfile
Creates a new compound file storage object using the COM-provided compound file
implementation for the IStorage interface.
WINOLEAPI StgCreateDocfile(
const WCHAR * pwcsName, //Points to path of compound file to create
DWORD grfMode, //Specifies the access mode for opening the storage obje
ct
DWORD reserved, //Reserved; must be zero
IStorage ** ppstgOpen //Points to location for returning the new stora
ge object
);
Parameters
pwcsName
[in] Points to the path of the compound file to create. It is passed uninterpret
ed to the file system. This can be a relative name or NULL. If NULL, a temporary
compound file is allocated with a unique name.
grfMode
[in] Specifies the access mode to use when opening the new storage object. For m
ore information, see the STGM enumeration. If the caller specifies transacted mo
de together with STGM_CREATE or STGM_CONVERT, the overwrite or conversion takes
place at the time the storage object is opened and therefore is not revertible.
reserved
[in] Reserved for future use; must be zero.
ppstgOpen
[out] Points to the location of the IStorage pointer to the new storage object.
Return Values
S_OK
Indicates the compound file was successfully created.
STG_E_ACCESSDENIED
Access denied because the caller has insufficient permission, or another caller
has the file open and locked.
STG_E_LOCKVIOLATION
Access denied because another caller has the file open and locked.
STG_E_FILEALREADYEXISTS
Indicates the compound file already exists and grfMode is set to STGM_FAILIFTHER
E.
STG_S_CONVERTED
Indicates the specified file was successfully converted to Storage format.
STG_E_INSUFFICIENTMEMORY
Indicates the compound file was not created due to a lack of memory.
STG_E_INVALIDNAME
Indicates bad name in the pwcsName parameter.
STG_E_INVALIDPOINTER
Indicates bad pointer in the pwcsName parameter or the ppStgOpen parameter.
STG_E_INVALIDFLAG
Indicates bad flag combination in the grfMode pointer.
STG_E_TOOMANYOPENFILES
Indicates the compound file was not created due to a lack of file handles.
STG_E_SHAREVIOLATION
Access denied because another caller has the file open and locked.
See also any file system errors for other error return values.
Remarks
The StgCreateDocfile function creates a new storage object using the COM-provide
d, compound-file implementation for the IStorage interface. The name of the open
compound file can be retrieved by calling the IStorage::Stat method.
StgCreateDocfile creates the file if it does not exist. If it does exist, the us
e of the STGM_CREATE, STGM_CONVERT, and STGM_FAILIFTHERE flags in the grfMode pa
rameter indicate how to proceed. See the STGM enumeration for more information o
n these values.
If the compound file is opened in transacted mode (the grfMode parameter specifi
es STGM_TRANSACTED) and a file with this name already exists, the existing file
is not altered until all outstanding changes are committed. If the calling proce
ss lacks write access to the existing file (because of access control in the fil
e system), the grfMode parameter can only specify STGM_READ and not STGM_WRITE o
r STGM_READWRITE. The resulting new open compound file can still be written to,
but a subsequent commit operation will fail (in transacted mode, write permissio
ns are enforced at commit time).
Specifying STGM_SIMPLE provides a much faster implementation of a compound file
object in a limited, but frequently-used case. This can be used by applications
that require a compound file implementation with multiple streams and no storage
s. The simple mode does not support all of the methods on IStorage. For more inf
ormation, refer to the STGM enumeration.
If the grfMode parameter specifies STGM_TRANSACTED and no file yet exists with t
he name specified by the pwcsName parameter, the file is created immediately. In
an access-controlled file system, the caller must have write permissions in the
file system directory in which the compound file is created. If STGM_TRANSACTED
is not specified, and STGM_CREATE is specified, an existing file with the same
name is destroyed before creating the new file.
StgCreateDocfile can be used to create a temporary compound file by passing a NU
LL value for the pwcsName parameter. However, these files are temporary only in
the sense that they have a system-provided unique name likely one that is meanin
gless to the user. The caller is responsible for deleting the temporary file whe
n finished with it, unless STGM_DELETEONRELEASE was specified for the grfMode pa
rameter.
See Also
StgCreateDocFileOnILockBytes
14.7.10 StgCreateDocfileOnILockBytes
Creates and opens a new compound file storage object on top of a byte array obje
ct provided by the caller. The storage object supports the COM-provided, compoun
d-file implementation for the IStorage interface.
WINOLEAPI StgCreateDocfileOnILockBytes(
ILockBytes * plkbyt, //Points to the ILockBytes interface on the byte
array object
DWORD grfMode, //Specifies the access mode
DWORD reserved, //Reserved; must be zero
IStorage ** ppstgOpen //Points to location for returning the new stora
ge object
);
Parameters
plkbyt
[in] Points to the ILockBytes interface on the underlying byte array object on w
hich to create a compound file.
grfMode
[in] Specifies the access mode to use when opening the new compound file. For mo
re information, see the STGM enumeration.
reserved
[in] Reserved for future use; must be zero.
ppstgOpen
[out] Points to the location of the IStorage pointer on the new storage object.
This function can also return any file system errors or Win32 errors wrapped in
an HRESULT
Return Values
S_OK
Indicates the compound file was successfully created.
STG_E_ACCESSDENIED
Access denied because the caller has insufficient permission, or another caller
has the file open and locked.
STG_E_FILEALREADYEXISTS
Indicates the compound file already exists and the grfMode parameter is set to S
TGM_FAILIFTHERE.
STG_E_INSUFFICIENTMEMORY
Indicates the storage object was not created due to a lack of memory.
STG_E_INVALIDPOINTER
Indicates a bad pointer was in the pLkbyt parameter or the ppStgOpen parameter.
STG_E_INVALIDFLAG
Indicates a bad flag combination was in the grfMode parameter.
STG_E_TOOMANYOPENFILES
Indicates the storage object was not created due to a lack of file handles.
STG_E_LOCKVIOLATION
Access denied because another caller has the file open and locked.
STG_E_SHAREVIOLATION
Access denied because another caller has the file open and locked.
STG_S_CONVERTED
Indicates the compound file was successfully converted. The original byte array
object was successfully converted to IStorage format.
This function can also return any file system errors, or Win32 errors wrapped in
an HRESULT, or ILockBytes interface error return values.
Remarks
The StgCreateDocfileOnILockBytes function creates a storage object on top of a b
yte array object using the COM-provided, compound-file implementation of the ISt
orage interface. StgCreateDocfileOnILockBytes can be used to store a document in
a relational database. The byte array (indicated by the pLkbyt parameter, which
points to the ILockBytes interface on the object) is used for the underlying st
orage in place of a disk file.
Except for specifying a programmer-provided byte-array object, StgCreateDocfileO
nILockBytes is similar to the StgCreateDocfile function. For more information, r
efer to StgCreateDocfile.
The newly created compound file is opened according to the access modes in the g
rfMode parameter. For conversion purposes, the file is always considered to alre
ady exist. As a result, it is not useful to use the STGM_FAILIFTHERE value, beca
use it always causes an error to be returned. However, STGM_CREATE and STGM_CONV
ERT are both still useful.
The ability to build a compound file on top of a byte array object is provided t
o support having the data (underneath an IStorage and IStream tree structure) li
ve in a non-persistent space. Given this capability, there is nothing preventing
a document that is stored in a file from using this facility. For example, a co
ntainer might do this to minimize the impact on its file format caused by adopti
ng COM. However, it is recommended that COM documents adopt the IStorage interfa
ce for their own outer-level storage. This has the following advantages:
· The storage structure of the document is the same as its storage structure when
it is an embedded object, reducing the number of cases the application needs to
handle.
· One can write tools to access the COM embeddings and links within the document w
ithout special knowledge of the document s file format. An example of such a tool
is a copy utility that copies all the documents included in a container containi
ng linked objects. A copy utility like this needs access to the contained links
to determine the extent of files to be copied.
· The IStorage implementation addresses the problem of how to commit the changes t
o the file. An application using the ILockBytes interface must handle these issu
es itself.
· Future file systems will likely implement the IStorage and IStream interfaces as
their native abstractions, rather than layer on top of a byte array as is done
in compound files. Such a file system could be built so documents using the ISto
rage interface as their outer level containment structure would get an automatic
efficiency gain by having the layering flattened when files are saved on the ne
w file system.
See Also
StgCreateDocfile
14.7.11 StgCreatePropSetStg
Creates a property set storage object from a specified storage object. The prope
rty set storage object supplies the system-provided, standalone implementation o
f the IPropertySetStorage interface.
HRESULT StgCreatePropSetStg(
IStorage* pStorage, //Pointer to a storage object
DWORD dwReserved, //Reserved; must be zero
IPropertySetStorage** ppPropSetStg //Address of output variable that receiv
es
// IPropertySetStorage interface pointer
);
Parameter
pStorage
[in] Pointer to the storage object that contains one or more property sets.
dwReserved
Reserved for future use; must be zero.
ppPropSetStg
[out] Address of IPropertySetStorage pointervariable that receives the interface
pointer to the property set storage object.
Return Values
This function supports the standard return value E_INVALIDARG as well as the fol
lowing:
S_OK
The property set storage object was successfully created.
Remarks
StgCreatePropSetStg calls IUnknown::AddRef on the storage object specified by pS
torage. The caller is responsible for releasing the object when it is no longer
needed.
Programming Information
Unicode Yes
Import Library IPROP.DLL
Header File IPROPIDL.H
See Also
IPropertySetStorage-Standalone Implementation
14.7.12 StgCreatePropStg
Creates and opens a property set in a specified storage or stream object. The pr
operty set supplies the system-provided, standalone implementation of the IPrope
rtyStorage interface.
HRESULT StgCreatePropStg(
IUnknown* pUnk, //Interface pointer for object containing the new proper
ty set
REFFMTID fmtid, //Format identifier of the property set to be created
const CLSID* pclsid, //Initial CLSID for the new property set
DWORD grfFlags, //PROPSETFLAG values
DWORD dwReserved, //Reserved; must be zero
IPropertyStorage** ppPropStg //Address of output that receives
// the IPropertyStorage interface pointer
);
Parameters
pUnk
[in] Pointer to the IUnknown interface on the storage or stream object that stor
es the new property set.
fmtid
[in] Format identifier of the property set to be created.
pclsid
[in] Pointer to the initial CLSID for this property set. May be NULL, in which c
ase pclsid is set to all zeroes.
grfFlags
[in] Values from the PROPSETFLAG enumeration that determine how the property set
is created and opened.
dwReserved
[in] Reserved; must be zero.
ppPropStg
[out] Address of theIPropertyStorage pointer variable that receives the interfac
e pointer to the new property set.
Return Values
This function supports the standard return values E_INVALIDARG and E_UNEXPECTED,
as well as the following:
S_OK
The property set was created.
STG_E_ACCESSDENIED
The requested access to the property storage object has been denied.
STG_E_INVALIDHEADER
The property set is corrupted.
STG_E_INSUFFICIENTMEMORY
There is not enough memory to perform this operation.
STG_E_INVALIDFLAG
A flag in the grfMode or grfFlags parameter was invalid.
STG_E_INVALIDPARAMETER
A parameter is invalid.
STG_E_MEDIUMFULL
The storage object could not be increased in size to hold the default property s
et.
Remarks
StgCreatePropStg creates and opens a new property set which supplies the system-
provided, standalone implementation of the IPropertyStorage interface. The new p
roperty set is contained in the storage or stream object specified by pUnk. The
value of the grfFlags parameter indicates whether pUnk specifies a storage or st
ream object. For example, if PROPSETFLAG_NONSIMPLE is set, then pUnk can be quer
ied for an IStorage interface on a storage object.
In either case, this function calls pUnk->AddRef for the storage or stream objec
t containing the property set. It is the responsibility of the caller to release
the object when it is no longer needed.
This function is similar to the IPropertySetStorage::Create method. However, Stg
CreatePropStg adds the pUnk parameter and supports the PROPSETFLAG_UNBUFFERED va
lue for the grfFlags parameter. Use this function instead of the Create method i
f you have an IStorage interface that does not support the IPropertySetStorage i
nterface, or if you want to use the PROPSETFLAG_UNBUFFERED value. See the PROPSE
TFLAG enumeration for more information on using this PROPSETFLAG_UNBUFFERED.
The property set automatically contains code page and locale ID properties. Thes
e are set to the current system default and the current user default, respective
ly.
The grfFlags parameter is a combination of values taken from the enumeration PRO
PSETFLAG. The new enumeration value PROPSETFLAG_UNBUFFERED is supported. See the
PROPSETFLAG enumeration for more information on the use of this value.
Programming Information
Unicode Yes
Import Library IPROP.DLL
Header File IPROPIDL.H
See Also
IPropertySetStorage, IPropertySetStorage-Standalone Implementation, IPropertySto
rage, IPropertyStorage-Standalone Implementation, PROPSETFLAG, StgOpenPropStg, S
tgCreatePropSetStg
14.7.13 StgIsStorageFile
Indicates whether a particular disk file contains a storage object.
WINOLEAPI StgIsStorageFile(
const WCHAR * pwcsName //Points to a pathname of the file to check
);
Parameter
pwcsName
[in] Points to the name of the disk file to be examined. The pwcsName parameter
is passed uninterpreted to the underlying file system.
Return Values
S_OK
Indicates the file contains a storage object.
S_FALSE
Indicates the file does not contain a storage object.
STG_E_INVALIDFILENAME
Indicates a bad filename was passed in the pwcsName parameter.
STG_E_FILENOTFOUND
Indicates the file was not found.
This function can also return any file system errors orWin32 errors wrapped in a
n HRESULT.
Remarks
At the beginning of the disk file underlying a storage object is a signature dis
tinguishing a storage object from other file formats. The StgIsStorageFile funct
ion is useful to applications whose documents use a disk file format that might
or might not use storage objects.
If a root compound file has been created in transacted mode but not yet committe
d, this method still return S_OK.
See Also
StgIsStorageILockBytes
14.7.14 StgIsStorageILockBytes
Indicates whether the specified byte array contains a storage object.
WINOLEAPI StgIsStorageILockBytes(
ILockBytes * plkbyt //ILockBytes pointer to the byte array to be examined
);
Parameter
plkbyt
ILockBytes pointer to the byte array to be examined.
Return Values
S_OK
Indicates the specified byte array contains a storage object.
S_FALSE
Indicates the specified byte array does not contain a storage object.
.This function can also return any file system errors, or Win32 errors wrapped i
n an HRESULT, or .
ILockBytes interface error return values.
Remarks
At the beginning of the byte array underlying a storage object is a signature di
stinguishing a storage object (supporting the IStorage interface) from other fil
e formats. The StgIsStorageILockBytes function is useful to applications whose d
ocuments use a byte array (a bye array object supports the ILockBytes interface)
that might or might not use storage objects.
See Also
StgIsStorageFile, ILockBytes
14.7.15 StgOpenPropStg
Opens a specified property set in a specified storage or stream object. The prop
erty set supplies the system-provided, standalone implementation of the IPropert
yStorage interface.
HRESULT StgOpenPropStg(
IUnknown* pUnk, //Interface pointer for object containing the requested
property set
REFFMTID fmtid, //Format identifier of the property set to be opened
DWORD grfFlags, //PROPSETFLAG values
DWORD dwReserved, //Reserved; must be zero
IPropertyStorage** ppPropStg //Address of output variable that receiv
es the
// IPropertyStorage interface pointer
);
Parameters
pUnk
[in] Interface pointer for IUnknown interface on the storage or stream object th
at contains the requested property set object.
fmtid
[in] Format identifier of the property set to be opened.
grfFlags
[in] Values from the PROPSETFLAG enumeration.
dwReserved
[in] Reserved for future use; must be zero.
ppPropStg
[out] Address of IPropertyStorage pointer variable that receives the interface p
ointer to the requested property set.
Return Values
This function supports the standard return values E_INVALIDARG and E_UNEXPECTED,
as well as the following:
S_OK
The property set was opened.
STG_E_FILENOTFOUND
A property set was not found in the specified object (pUnk).
STG_E_ACCESSDENIED
The requested access to the property storage object has been denied, or the prop
erty set is corrupted.
STG_E_INVALIDHEADER
The property set is corrupted.
STG_E_INSUFFICIENTMEMORY
There is not enough memory to perform this operation.
STG_E_INVALIDFLAG
A flag in the grfMode or grfFlags parameter was invalid.
STG_E_INVALIDPARAMETER
A parameter is invalid.
Remarks
StgOpenPropStg opens the requested property set and supplies the system-provided
, standalone implementation of the IPropertyStorage interface. The requested pro
perty set is contained in the storage or stream object specified by pUnk. The va
lue of the grfFlags parameter indicates whether pUnk specifies a storage or stre
am object. For example, if PROPSETFLAG_NONSIMPLE is set, then pUnk can be querie
d for an IStorage interface on a storage object.
In either case, this function calls pUnk->AddRef for the storage or stream objec
t containing the property set. It is the responsibility of the caller to release
the object when it is no longer needed.
This function is similar to the IPropertySetStorage::Open method. However, StgOp
enPropStg adds the pUnk and grfFlags parameters, including the PROPSETFLAG_UNBUF
FERED value for the grfFlags parameter. Use this function instead of the Open me
thod if you have an IStorage interface that does not support the IPropertySetSto
rage interface, or if you want to use the PROPSETFLAG_UNBUFFERED value. See the
PROPSETFLAG enumeration for more information on using PROPSETFLAG_UNBUFFERED.
The grfFlags parameter is a combination of values taken from the enumeration PRO
PSETFLAG. The new enumeration value PROPSETFLAG_UNBUFFERED is supported. See the
PROPSETFLAG enumeration for more information on the use of this value.
Programming Information
Unicode Yes
Import Library IPROP.DLL
Header File IPROPIDL.H
See Also
IPropertySetStorage, IPropertySetStorage-Standalone Implementation, IPropertySto
rage, IPropertyStorage-Standalone Implementation, PROPSETFLAG, StgCreatePropStg,
StgCreatePropSetStg
14.7.16 StgOpenStorage
Opens an existing root storage object in the file system. You can use this funct
ion to open compound files, but you cannot use it to open directories, files, or
summary catalogs. Nested storage objects can only be opened using their parent'
s IStorage::OpenStorage method.
WINOLEAPI StgOpenStorage(
const WCHAR * pwcsName, //Points to the path of the file containing stor
age object
IStorage * pstgPriority, //Points to a previous opening of a root storage
object
DWORD grfMode, //Specifies the access mode for the object
SNB snbExclude, //Points to an SNB structure specifying elements to be e
xcluded
DWORD reserved, //Reserved; must be zero
IStorage ** ppstgOpen //Address of output variable that receives
// IStorage interface pointer
);
Parameters
pwcsName
[in] Points to the path of the file containing the storage object to open. This
parameter is ignored if the pStgPriority parameter is not NULL.
pstgPriority
[in] Most often NULL. If not NULL, this parameter is used instead of the pwcsNam
e parameter to specify the pointer to the IStorage interface on the storage obje
ct to open. It points to a previous opening of a root storage object, most often
one that was opened in priority mode.
After the StgOpenStorage function returns, the storage object specified in the p
StgPriority parameter on function entry is invalid, and can no longer be used. I
nstead, use the one specified in the ppStgOpen parameter instead.
grfMode
[in] Specifies the access mode to use to open the storage object.
snbExclude
[in] If not NULL, this parameter points to a block of elements in the storage th
at are to be excluded as the storage object is opened. The exclusion occurs inde
pendent of whether a snapshot copy happens on the open. May be NULL.
reserved
[in] Indicates reserved for future use; must be zero.
ppstgOpen
[out] Address of IStorage* pointer variable that receives the interface pointer
to the opened storage.
Return Values
S_OK
Indicates the storage object was successfully opened.
STG_E_FILENOTFOUND
Indicates the specified file does not exist.
STG_E_ACCESSDENIED
Access denied because the caller has insufficient permission, or another caller
has the file open and locked.
STG_E_LOCKVIOLATION
Access denied because another caller has the file open and locked.
STG_E_SHAREVIOLATION
Access denied because another caller has the file open and locked.
STG_E_FILEALREADYEXISTS
Indicates the file exists but is not a storage object.
STG_E_TOOMANYOPENFILES
Indicates the storage object was not opened because there are too many open file
s.
STG_E_INSUFFICIENTMEMORY
Indicates the storage object was not opened due to a lack of memory.
STG_E_INVALIDNAME
Indicates bad name in the pwcsName parameter.
STG_E_INVALIDPOINTER
Indicates bad pointer in one of the parameters: snbExclude, pwcsName, pstgPriori
ty, or ppStgOpen.
STG_E_INVALIDFLAG
Indicates bad flag combination in the grfMode parameter.
STG_E_INVALIDFUNCTION
Indicates STGM_DELETEONRELEASE specified in the grfMode parameter.
STG_E_OLDFORMAT
Indicates the storage object being opened was created by the Beta 1 storage prov
ider. This format is no longer supported.
STG_E_NOTSIMPLEFORMAT
Indicates that the STGM_SIMPLE flag was specified in the grfMode parameter and t
he storage object being opened was not written in simple mode.
STG_E_OLDDLL
Indicates the DLL being used to open this storage object is a version prior to t
he one used to create it.
STG_E_PATHNOTFOUND
Specified path does not exist.
This function can also return any file system errors or Win32 errors wrapped in
an HRESULT.
Remarks
The StgOpenStorage function opens the specified root storage object according to
the access mode in the grfMode parameter, and, if successful, supplies an IStor
age pointer to the opened storage object in the ppstgOpen parameter.
To support the Simple mode for saving a storage object with no substorages, the
StgOpenStorage function accepts the following flag combinations as valid modes i
n the grfMode parameter: STGM_SIMPLE|STGM_READWRITE|STGM_SHARE_EXCLUSIVE and STG
M_SIMPLE|STGM_READ|STGM_SHARE_EXCLUSIVE.
To support the single-writer, multi-reader, direct mode, the following flag comb
inations are valid modes in the grfMode parameter: STGM_READWRITE|STGM_SHARE_DEN
Y_WRITE and STGM_READ|STGM_SHARE_DENY_NONE.
Note
Opening a storage object in read and/or write mode without denying writer permis
sion to others (the grfMode parameter specifies STGM_SHARE_DENY_WRITE) can be a
time-consuming operation since the StgOpenStorage call must make a snapshot of t
he entire storage object.
Applications often try to open storage objects with the following access permiss
ions:
STGM_READ_WRITE | STGM_SHARE_DENY_WRITE
// transacted vs. direct mode omitted for exposition
If the application succeeds, it never needs to do a snapshot copy. If it fails,
the application can revert to using the permissions and make a snapshot copy:
STGM_READ_WRITE
// transacted vs. direct mode omitted for exposition
In this case, the application should prompt the user before doing a time-consumi
ng copy. Alternatively, if the document sharing semantics implied by the access
modes are appropriate, the application could try to open the storage as follows:
STGM_READ | STGM_SHARE_DENY_WRITE
// transacted vs. direct mode omitted for exposition
In this case, if the application succeeds, a snapshot copy will not have been ma
de (because STGM_SHARE_DENY_WRITE was specified, denying others write access).
To reduce the expense of making a snapshot copy, applications can open storage o
bjects in priority mode (grfMode specifies STGM_PRIORITY).
The snbExclude parameter specifies a set of element names in this storage object
that are to be emptied as the storage object is opened: streams are set to a le
ngth of zero; storage objects have all their elements removed. By excluding cert
ain streams, the expense of making a snapshot copy can be significantly reduced.
Almost always, this approach is used after first opening the storage object in
priority mode, then completely reading the now-excluded elements into memory. Th
is earlier priority mode opening of the storage object should be passed through
the pstgPriority parameter to remove the exclusion implied by priority mode. The
calling application is responsible for rewriting the contents of excluded items
before committing. Thus, this technique is most likely only useful to applicati
ons whose documents do not require constant access to their storage objects whil
e they are active.
See Also
IStorage, StgCreateDocfileStgOpenStorageEx
14.7.17 StgOpenStorageOnILockBytes
Opens an existing storage object that does not reside in a disk file, but instea
d has an underlying byte array provided by the caller.
WINOLEAPI StgOpenStorageOnILockBytes(
ILockBytes * plkbyt, //Points to the ILockBytes interface on the unde
rlying byte array
IStorage * pStgPriority, //Points to a previous opening of a root storage
object
DWORD grfMode, //Specifies the access mode for the object
SNB snbExclude, //Points to an SNB structure specifying elements to be e
xcluded
DWORD reserved, //Reserved, must be zero
IStorage ** ppstgOpen //Points to location for returning the storage o
bject
);
Parameters
plkbyt
[in] ILockBytes pointer to the underlying byte array object that contains the st
orage object to be opened.
pStgPriority
[in] Most often NULL. If not NULL, this parameter is used instead of the plkbyt
parameter to specify the storage object to open. In this case, it points to the
IStorage interface on a previously opened root storage object, most often one th
at was opened in priority mode.
After the StgOpenStorageOnILockBytes function returns, the storage object specif
ied in the pStgPriority parameter on function entry is invalid, and can no longe
r be used; use the one specified in the ppStgOpen parameter instead.
grfMode
[in] Specifies the access mode to use to open the storage object.
snbExclude
[in] Can be NULL. If not NULL, this parameter points to a block of elements in t
his storage that are to be excluded as the storage object is opened. This exclus
ion occurs independent of whether a snapshot copy happens on the open. .
reserved
[in] Indicates reserved for future use; must be zero.
ppstgOpen
[out] Points to the location of an IStorage pointer to the opened storage on suc
cessful return.
Return Values
S_OK
The storage object was successfully opened.
STG_E_FILENOTFOUND
The specified byte array does not exist.
STG_E_ACCESSDENIED
Access denied because the caller has insufficient permission, or another caller
has the file open and locked.
STG_E_LOCKVIOLATION
Access denied because another caller has the file open and locked.
STG_E_SHAREVIOLATION
Access denied because another caller has the file open and locked.
STG_E_FILEALREADYEXISTS
The byte array exists but is not a storage object.
STG_E_TOOMANYOPENFILES
The storage object was not opened because there are too many open files.
STG_E_INSUFFICIENTMEMORY
The storage object was not opened due to a lack of memory.
STG_E_INVALIDNAME
Either pwcsName or snbExclude contains an invalid name.
STG_E_INVALIDPOINTER
Either snbExclude, pwcsName, pstgPriority, or ppStgOpen contains an invalid poin
ter.
STG_E_INVALIDFLAG
The grfMode parameter contains a bad flag combination.
STG_E_INVALIDFUNCTION
The access mode STGM_DELETEONRELEASE was specified in the grfMode parameter.
STG_E_OLDDLL
The DLL being used to open this storage object is a version prior to the one use
d to create it.
STG_E_OLDFORMAT
The storage object being opened was created by the Beta 1 storage provider. This
format is no longer supported.
This function can also return any file system errors, or Win32 errors wrapped in
an HRESULT, or ILockBytes interface error return values.
Remarks
StgOpenStorageOnILockBytes opens the specified root storage object. The storage
object is opened according to the access mode in the grfMode parameter; a pointe
r to the IStorage interface on the opened storage object is supplied through the
ppstgOpen parameter.
The storage object must have been previously created by the StgCreateDocfileOnIL
ockBytes function.
Except for specifying a programmer-provided byte-array object, StgOpenStorageOnI
LockBytes is similar to the StgOpenStorage function. For more information, refer
to StgOpenStorage.
See Also
StgOpenStorage, StgCreateDocfileOnILockBytes
14.7.18 StgSetTimes
Sets the creation, access, and modification times of the indicated file, if supp
orted by the underlying file system.
WINOLEAPI StgSetTimes(
WCHAR const * lpszName, //Points to the name of the file to be changed
FILETIME const * pctime, //Points to the new value for the creation time
FILETIME const * patime, //Points to the new value for the access time
FILETIME const * pmtime //Points to the new value for the modification t
ime
);
Parameters
lpszName
[in] Points to the name of the file to be changed.
pctime
[in] Points to the new value for the creation time.
patime
[in] Points to the new value for the access time.
pmtime
[in] Points to the new value for the modification time.
Return Values
S_OK
Indicates time values successfully set.
STG_E_FILENOTFOUND
Indicates element does not exist.
STG_E_INVALIDNAME
Indicates bad name passed in the lpszName parameter, or a file system error.
STG_E_ACCESSDENIED
Access denied because the caller has insufficient permission, or another caller
has the file open and locked.
STG_E_LOCKVIOLATION
Access denied because another caller has the file open and locked.
STG_E_SHAREVIOLATION
Access denied because another caller has the file open and locked.
This function can also return any file system errors or Win32 errors wrapped in
an HRESULT.
Remarks
The StgSetTimes function sets the time values for the specified file. Each of th
e time value parameters can be NULL, indicating no modification should occur.
It is possible that one or more of these time values are not supported by the un
derlying file system. This function sets the times that can be set and ignores t
he rest.
14.7.19 WriteClassStg
Stores the specified CLSID in a storage object.
WINOLEAPI WriteClassStg(
IStorage * pStg, //Points to the IStorage interface on the storage object
REFCLSID rclsid //Specifies the CLSID to be stored in the storage object
);
Parameters
pStg
[in] IStorage pointer to the storage object that gets a new CLSID.
rclsid
[in] Points to the CLSID to be stored with the object.
Return Values
S_OK
Indicates the CLSID was successfully written to the file.
STG_E_MEDIUMFULL
Indicates the CLSID could not be written due to lack of memory.
IStorage::SetClass method error return values.
Remarks
The WriteClassStg function writes a CLSID to the specified storage object so it
can be read by the ReadClassStg function. Container applications typically call
this function before calling the IPersistStorage::Save method.
See Also
ReadClassStg
14.7.20 WriteClassStm
Stores the specified CLSID in the stream.
WINOLEAPI WriteClassStm(
IStream * pStm, //Points to the IStream interface on the stream object
REFCLSID rclsid //Specifies the CLSID to be stored in the stream object
);
Parameters
pStm
[in] IStream pointer to the stream into which the CLSID is to be written.
rclsid
[in] Specifies the CLSID to write to the stream.
Return Values
S_OK
Indicates the CLSID was successfully written.
STG_E_MEDIUMFULL
The CLSID could not be written because there is no space left on device.
IStorage::SetClass method error return values.
Remarks
The WriteClassStm function writes a CLSID to the specified stream object so it c
an be read by the ReadClassStm function. Most applications do not call WriteClas
sStm directly. COM calls it before making a call to an object s IPersistStream::Sa
ve method.
See Also
ReadClassStm, WriteClassStg, ReadClassStg
14.7.21 WriteFmtUserTypeStg
Writes a clipboard format and user type to the storage object.
WINOLEAPI WriteFmtUserTypeStg(
IStorage * pStg, //Points to the IStorage interface on the storage object
CLIPFORMAT cf, //Specifies the clipboard format
LPWSTR * lpszUserType //Points to the current user type
);
Parameters
pStg
[in] IStorage pointer to the storage object where the information is to be writt
en.
cf
[in] Specifies the clipboard format that describes the structure of the native a
rea of the storage object. The format tag includes the policy for the names of s
treams and substorages within this storage object and the rules for interpreting
data within those streams.
lpszUserType
[in] Points to the object s current user type. It cannot be NULL.
Return Values
S_OK
Indicates the information was written successfully.
STG_E_MEDIUMFULL
Indicates information could not be written due to lack of space on the storage m
edium.
IStream::Write method error return values.
Remarks
The WriteFmtUserTypeStg function must be called in an object s implementation of t
he IPersistStorage::Save method. It must also be called by document-level object
s that use structured storage for their persistent representation in their save
sequence.
To read the information saved, applications call the ReadFmtUserTypeStg function
.
See Also
IPersistStorage::Save, ReadFmtUserTypeStg
14.7.22 CreateILockBytesOnHGlobal
Creates a byte array object that allows you use global memory as the physical de
vice underneath a compound file implementation. This object supports an COM impl
ementation of the ILockBytes interface.
WINOLEAPI CreateILockBytesOnHGlobal(
HGLOBAL hGlobal, //Memory handle for the byte array object
BOOL fDeleteOnRelease, //Whether to free memory when the object is rele
ased
ILockBytes ** ppLkbyt //Address of output variable that receives
// the ILockBytes interface pointer
);
Parameters
hGlobal
[in] Memory handle allocated by the GlobalAlloc function. The handle must be all
ocated as moveable and nondiscardable. If the handle is to be shared between pro
cesses, it must also be allocated as shared. New handles should be allocated wit
h a size of zero. If hGlobal is NULL, CreateILockBytesOnHGlobal internally alloc
ates a new shared memory block of size zero.
fDeleteOnRelease
[in] IWhether the underlying handle for this byte array object should be automat
ically freed when the object is released.
ppLkbyt
[out] Address of ILockBytes* pointer variable that receives the interface pointe
r to the new byte array object.
Return Values
This function supports the standard return values E_INVALIDARG and
E_OUTOFMEMORY, as well as the following:
S_OK
The byte array object was created successfully.
Remarks
The CreateILockBytesOnHGlobal function creates a byte array object based on glob
al memory. This object supports an COM implementation of the ILockBytes interfac
e, and is intended to be used as the basis for a compound file. You can then use
the supplied ILockBytes pointer in a call to the StgCreateDocfileOnILockBytes f
unction to build a compound file on top of this byte array object. The ILockByte
s instance calls the GlobalReAlloc function to grow the memory block as needed.
The current contents of the memory block are undisturbed by the creation of the
new byte array object. After creating the ILockBytes instance, you can use the S
tgOpenStorageOnILockBytes function to reopen a previously existing storage objec
t already contained in the memory block. You can also call GetHGlobalFromILockBy
tes to get the global memory handle associated with the byte array object create
d by CreateILockBytesOnHGlobal.
Note
If you free the hGlobal memory handle, the byte array object is no longer valid.
You must call the ILockBytes::Release method before freeing the memory handle.
The value of the hGlobal parameter can be changed by a subsequent call to the Gl
obalReAlloc function; thus, you cannot rely on this value after the byte array o
bject is created.
See Also
StgOpenStorageOnILockBytes, GetHGlobalFromILockBytes, ILockBytes
14.7.23 CreateStreamOnHGlobal
Creates a stream object stored in global memory.
WINOLEAPI CreateStreamOnHGlobal(
HGLOBAL hGlobal, //Memory handle for the stream object
BOOL fDeleteOnRelease, //Whether to free memory when the object is rele
ased
LPSTREAM * ppstm //Address of output variable that
// receives the IStream interface pointer
);
Parameters
hGlobal
[in] Memory handle allocated by the GlobalAlloc function. The handle must be all
ocated as moveable and nondiscardable. If the handle is to be shared between pro
cesses, it must also be allocated as shared. New handles should be allocated wit
h a size of zero. If hGlobal is NULL, the CreateStreamOnHGlobal function interna
lly allocates a new shared memory block of size zero.
fDeleteOnRelease
[in] Whether the underlying handle for this stream object should be automaticall
y freed when the stream object is released.
ppstm
[out] Address of IStream* pointer variable that receives the interface pointer t
o the new stream object. Its value cannot be NULL.
Return Values
This function supports the standard return values E_INVALIDARG and E_OUTOFMEMORY
, as well as the following:
S_OK
The stream object was created successfully.
Remarks
The CreateStreamOnHGlobal function creates a stream object in memory that suppor
ts the COM implementation of the IStream interface. The returned stream object s
upports both reading and writing, is not transacted, and does not support lockin
g.
The initial contents of the stream are the current contents of the memory block
provided in the hGlobal parameter. If the hGlobal paramter is NULL, this functio
n internally allocates memory.
The current contents of the memory block are undisturbed by the creation of the
new stream object. Thus, you can use this function to open an existing stream in
memory.
The initial size of the stream is the size of the memory handle returned by the
Win32 GlobalSize function. Because of rounding, this is not necessarily the same
size that was originally allocated for the handle. If the logical size of the s
tream is important, you should follow the call to this function with a call to t
he IStream::SetSize method.
After you have created the stream object with CreateStreamOnHGlobal, you can cal
l GetHGlobalFromStream to get the global memory handle associated with the strea
m object.
See Also
CreateStreamOnHGlobal, GetHGlobalFromStream, IStream::SetSize,
In the Win32 Programmer s Reference: GlobalSize in Win32
14.7.24 GetClassFile
Supplies the CLSID associated with the given filename.
WINOLEAPI GetClassFile(
LPCWSTR szFileName, //Pointer to filename for which you are requesti
ng a CLSID
CLSID * pclsid //Pointer to location for returning the CLSID
);
Parameters
szFileName
[in] Points to the filename for which you are requesting the associated CLSID.
pclsid
[out] Points to the location where the associated CLSID is written on return.
Return Values
S_OK
Indicates the CLSID was successfully supplied.
MK_E_CANTOPENFILE
Indicates unable to open the specified filename.
MK_E_INVALIDEXTENSION
Indicates the specified extension in the registry is invalid.
Note
This function can also return any file system errors.
Remarks
When given a filename, the GetClassFile function finds the CLSID associated with
that file. Examples of its use are in OleCreateFromFile, which is passed a file
name and requires an associated CLSID, and in the COM implementation of IMonike
r::BindToObject, which, when a link to a file-based document is activated, calls
GetClassFile to locate the object application that can open the file.
GetClassFile uses the following strategies to determine an appropriate CLSID:
1. If the file contains a storage object, as determined by a call t
o the StgIsStorageFile function, GetClassFile returns the CLSID that was written
with the IStorage::SetClass method.
2. If the file is not a storage object, the GetClassFile function a
ttempts to match various bits in the file against a pattern in the registry. A p
attern in the registry can contain a series of entries of the form:
regdb key = offset, cb, mask, value
The value of the offset item is an offset from the beginning or end of the file
and the cb item is a length in bytes. These two values represent a particular by
te range in the file. (A negative value for the offset item is interpreted from
the end of the file). The mask value is a bit mask that is used to perform a log
ical AND operation with the byte range specified by offset and cb. The result of
the logical AND operation is compared with the value item. If the mask is omitt
ed, it is assumed to be all ones.
Each pattern in the registry is compared to the file in the order of the pattern
s in the database. The first pattern where each of the value items matches the r
esult of the AND operation determines the CLSID of the file. For example, the pa
ttern contained in the following entries of the registry requires that the first
four bytes be AB CD 12 34 and that the last four bytes be FE FE FE FE:
HKEY_CLASSES_ROOT
FileType
{12345678-0000-0001-C000-000000000095}
0 = 0, 4, FFFFFFFF, ABCD1234
1 = -4, 4, , FEFEFEFE
If a file contains such a pattern, the CLSID {12345678-0000-0001-C000-0000000000
95} will be associated with this file.
3. If the above strategies fail, the GetClassFile function searches
for the File Extension key in the registry that corresponds to the .ext portion
of the filename. If the database entry contains a valid CLSID, this function re
turns that CLSID.
4. If all strategies fail, the function returns MK_E_INVALIDEXTENSI
ON.
See Also
WriteClassStg
14.7.25 GetConvertStg
Returns the current value of the convert bit for the specified storage object.
WINOLEAPI GetConvertStg(
IStorage * pStg //Points to the IStorage interface on the storage object
);
Parameter
pStg
[in] IStorage pointer to the storage object from which the convert bit is to be
retrieved.
Return Values
S_OK
Indicates the convert bit is set to TRUE.
S_FALSE
Indicates the convert bit is cleared (FALSE).
STG_E_ACCESSDENIED
Access denied because the caller has insufficient permission, or another caller
has the file open and locked.
STG_E_LOCKVIOLATION
Access denied because another caller has the file open and locked.
IStorage::OpenStream, IStorage::OpenStorage, and IStream::Read storage and strea
m access errors.ISequentialStream::Read storage and stream access errors.
Remarks
The GetConvertStg function is called by object servers that support the conversi
on of an object from one format to another. The server must be able to read the
storage object using the format of its previous CLSID and write the object using
the format of its new CLSID to support the object s conversion. For example, a sp
readsheet created by one application can be converted to the format used by a di
fferent application.
The convert bit is set by a call to the SetConvertStg function. A container appl
ication can call this function on the request of an end user, or a setup program
can call it when installing a new version of an application. An end user reques
ts converting an object through the Convert To dialog box. When an object is con
verted, the new CLSID is permanently assigned to the object, so the object is su
bsequently associated with the new CLSID.
Then, when the object is activated, its server calls the GetConvertStg function
to retrieve the value of the convert bit from the storage object. If the bit is
set, the object s CLSID has been changed, and the server must read the old format
and write the new format for the storage object.
After retrieving the bit value, the object application should clear the convert
bit by calling the SetConvertStg function with its fConvert parameter set to FAL
SE.
See Also
SetConvertStg
14.7.26 GetHGlobalFromILockBytes
Retrieves a global memory handle to a byte array object created using the Create
ILockBytesOnHGlobal function.
WINOLEAPI GetHGlobalFromILockBytes(
ILockBytes * pLkbyt, //Points to the byte array object
HGLOBAL * phglobal //Points to the current memory handle for the specified
byte array
);
Parameters
pLkbyt
[in] Points to the ILockBytes interface on the byte array object previously crea
ted by a call to the CreateILockBytesOnHGlobal function.
phglobal
[out] Points to the current memory handle used by the specified byte array objec
t.
Return Values
S_OK
Indicates the handle was returned successfully.
E_INVALIDARG
Indicates invalid value specified for the pLkbyt parameter. It can also indicate
that the byte array object passed in is not one created by the CreateILockBytes
OnHGlobal function.
Remarks
After a call to CreateILockBytesOnHGlobal, which creates a byte array object on
global memory, GetHGlobalFromILockBytes retrieves a pointer to the handle of the
global memory underlying the byte array object. The handle this function return
s might be different from the original handle due to intervening calls to the Gl
obalRealloc function.
The contents of the returned memory handle can be written to a clean disk file,
and then opened as a storage object using the StgOpenStorage function.
This function only works within the same process from which the byte array was c
reated.
See Also
StgOpenStorage, CreateILockBytesOnHGlobal
14.7.27 GetHGlobalFromStream
Retrieves the global memory handle to a stream that was created through a call t
o the CreateStreamOnHGlobal function.
WINOLEAPI GetHGlobalFromStream(
IStream * pstm, //Points to the stream object
HGLOBAL * phglobal //Points to the current memory handle for the specified
stream
);
Parameters
pstm
[in] IStream pointer to the stream object previously created by a call to the Cr
eateStreamOnHGlobal function.
phglobal
[out] Points to the current memory handle used by the specified stream object.
Return Values
S_OK
Indicates the handle was successfully returned.
E_INVALIDARG
Indicates invalid value specified for the pstm parameter. It can also indicate t
hat the stream object passed in is not one created by a call to the CreateStream
OnHGlobal function.
Remarks
The handle this function returns may be different from the original handle due t
o intervening GlobalRealloc calls.
This function can be called only from within the same process from which the byt
e array was created.
14.8 Persistent Storage Structure Descriptions
14.8.1 FILETIME
The FILETIME data structure is a 64-bit value representing the number of 100-nan
osecond intervals since January 1, 1601. It is the means by which Win32 determin
es the date and time. FILETIME is used by the CoDosDateTimeToFileTime, CoFileTim
eToDosDateTime, and CoFileTimeNow functions. It is defined as follows:
typedef struct STRUCT tagFILETIME
{
DWORD dwLowDateTime;
DWORD dwHighDateTime;
} FILETIME;
Members
dwLowDateTime
The low 32 bits of the Win32 date/time value.
dwHighDateTime
The upper 32 bits of the Win32 date/time value.
Remarks
The FILETIME data structure is used in the time conversion functions between DOS
and Win32.
See Also
CoDosDateTimeToFileTime, CoFileTimeNow, CoFileTimeToDosDateTime
14.8.2 RemSNB
The RemSNB structure is used for marshaling the SNB data type.
Defined in the IStorage interface (storag.idl).
typedef struct tagRemSNB {
unsigned long ulCntStr;
unsigned long ulCntChar;
[size_is(ulCntChar)] wchar_t rgString[];
} RemSNB;
typedef [transmit_as(RemSNB)] wchar_t **SNB;
Members
ulCntStr
Number of strings in the rgString buffer.
ulCntChar
Size in bytes of the rgString buffer.
rgString
Pointer to an array of bytes containing the [REVIEW: NULL separated?] stream name s
trings from the SNB.
See Also
IStorage
14.8.4 STATPROPSETSTG
Contains information about a property set. To get this information, call IProper
tyStorage::Stat, which fills in a buffer containing the information describing t
he current property set. To enumerate the STATPROPSETSTG structures for the prop
erty sets in the current property set storage, call IPropertySetStorage::Enum to
get a pointer to an enumerator. You can then call the enumeration methods of th
e IEnumSTATPROPSETSTG interface on the enumerator. The structure is defined as f
ollows:
typedef struct tagSTATPROPSETSTG {
FMTID fmtid;
CLSID clsid;
DWORD grfFlags;
FILETIME mtime;
FILETIME ctime;
FILETIME atime;
} STATPROPSETSTG
Members
fmtid
Format identifier of the current property set.
clsid
The CLSID associated with this property set.
grfFlags
Flag values of the property set, as specified in IPropertySetStorage::Create.
mtime
Time in Universal Coordinated Time (UTC) that the property set was last modified
.
ctime
Time in UTC at which this property set was created.
atime
Time in UCT at which this property set was last accessed.
See Also
IPropertySetStorage::Create, IEnumSTATPROPSETSTG, IPropertyStorage::Stat, FILETI
ME structure
14.8.5 STATPROPSTG
Each STATPROPSTG structure contains information about a single property in a pro
perty set. This information is the property identifier and type tag, and the opt
ional string name that may be associated with the property.
IPropertyStorage::Enum supplies a pointer to the IEnumSTATPROPSTG interface on a
n enumerator object that can be used to enumerate through the STATPROPSTG struct
ures for the properties in the current property set. STATPROPSTG is defined as f
ollows:
typedef struct tagSTATPROPSTG {
LPWSTR lpwstrName;
PROPID propid;
VARTYPE vt;
} STATPROPSTG
Members
lpwstrName
Wide-character string containing the optional string name that can be associated
with the property. May be NULL. This member must be freed using CoTaskMemFree.
propid
A 32-bit identifier that uniquely identifies the property within the property se
t. All properties within property sets must have unique property identifiers.
vt
Type of the property.
See Also
IPropertyStorage::Enum, IEnumSTATPROPSTG
14.8.6 STATSTG
The STATSTG structure contains statistical information about an open storage, st
ream, or byte array object. This structure is used in the IEnumSTATSTG, ILockByt
es, IStorage, and IStream interfaces.
Defined in the IStream interface (stream.idl).
typedef struct tagSTATSTG
{
LPWSTR pwcsName;
DWORD type;
ULARGE_INTEGER cbSize;
FILETIME mtime;
FILETIME ctime;
FILETIME atime;
DWORD grfMode;
DWORD grfLocksSupported;
CLSID clsid;
DWORD grfStateBits;
DWORD reserved;
} STATSTG;
Members
pwcsName
Points to a NULL-terminated string containing the name. Space for this string is
allocated by the method called and freed by the caller (refer to CoTaskMemFree)
. You can specify not to return this member by specifying the STATFLAG_NONAME va
lue when you call a method that returns a STATSTG structure, except for calls to
IEnumSTATSTG::Next, which provides no way to specify this value.
type
Indicates the type of storage object. This is one of the values from the STGTY e
numeration.
cbSize
Specifies the size in bytes of the stream or byte array.
mtime
Indicates the last modification time for this storage, stream, or byte array.
ctime
Indicates the creation time for this storage, stream, or byte array.
atime
Indicates the last access time for this storage, stream or byte array.
grfMode
Indicates the access mode specified when the object was opened. This member is o
nly valid in calls to Stat methods.
grfLocksSupported
Indicates the types of region locking supported by the stream or byte array. See
the LOCKTYPES enumeration for the values available. This member is not used for
storage objects.
clsid
Indicates the class identifier for the storage object; set to CLSID_NULL for new
storage objects. This member is not used for streams or byte arrays.
grfStateBits
Indicates the current state bits of the storage object, that is, the value most
recently set by the IStorage::SetStateBits method. This member is not valid for
streams or byte arrays.
dwStgFmt
Indicates the format of the storage object. This is one of the values from the S
TGFMT enumeration.
See Also
IStorage::SetElementTimes
14.9 Persistent Storage Enumeration Descriptions
14.9.1 LOCKTYPE
The LOCKTYPE enumeration values indicate the type of locking requested for the s
pecified range of bytes. The values are used in the ILockBytes::LockRegion and I
Stream::LockRegion methods.
Defined in the IStream interface (stream.idl).
typedef enum tagLOCKTYPE
{
LOCK_WRITE = 1,
LOCK_EXCLUSIVE = 2,
LOCK_ONLYONCE = 4
} LOCKTYPE;
Elements
LOCK_WRITE
If this lock is granted, the specified range of bytes can be opened and read any
number of times, but writing to the locked range is prohibited except for the o
wner that was granted this lock.
LOCK_EXCLUSIVE
If this lock is granted, writing to the specified range of bytes is prohibited e
xcept for the owner that was granted this lock.
LOCK_ONLYONCE
If this lock is granted, no other LOCK_ONLYONCE lock can be obtained on the rang
e. Usually this lock type is an alias for some other lock type. Thus, specific i
mplementations can have additional behavior associated with this lock type.
14.9.2 PROPSETFLAG
The PROPSETFLAG enumeration values define characteristics of a property set. The
values are used in the grfFlags parameter of IPropertySetStorage methods, the S
tgCreatePropStg function, and the StgOpenPropStg function.
typedef enum PROPSETFLAG {
PROPSETFLAG_DEFAULT = 0,
PROPSETFLAG_NONSIMPLE = 1,
PROPSETFLAG_ANSI = 2,
PROPSETFLAG_UNBUFFERED = 4
} PROPSETFLAG
Elements
PROPSETFLAG_NONSIMPLE
If specified, storage-valued and stream-valued properties are permitted in the n
ewly created set. Otherwise, they are not permitted. In the compound file and st
andalone implementations, property sets may be transacted only if PROPSETFLAG_NO
NSIMPLE is specified.
PROPSETFLAG_ANSI
If specified, all string values in the property set that are not explicitly Unic
ode (those other than VT_LPWSTR) are stored with the current system ANSI code pa
ge (see the Win32 function GetACP). Use of this value is not recommended, as des
cribed in the following Remarks section.
If this value is absent, string values in the new property set are stored in Uni
code. The degree of control afforded by this value is necessary so clients using
the property-related interfaces can interoperate well with standard property se
ts such as the OLE2 summary information, which may exist in the ANSI code page.
PROPSETFLAG_UNBUFFERED
Used only with the StgCreatePropStg and StgOpenPropStg functions, that is, in th
e standalone implementations of property set interfaces. If specified in these f
unctions, changes to the property set are not buffered. Instead, changes are alw
ays written directly to the property set. A property set is changed by calls to
its IPropertyStorage methods. However, by default, changes are buffered in an in
ternal property set cache and are subsequently written to the property set when
the IPropertyStorage::Commit method is called.
Setting PROPSETFLAG_UNBUFFERED reduces performance since the property set's inte
rnal buffer is automatically flushed after every change to the property set. How
ever, writing changes directly prevents coordination problems. For example, supp
ose the storage object is opened in transacted mode, and the property set is buf
fered. Then, if you call the IStorage::Commit method on the storage object, the
property set changes will not be picked up as part of the transaction, since the
y are in a buffer that has not been flushed yet. You must call IPropertyStorage:
:Commit prior to calling IStorage::Commit to flush the property set buffer befor
e committing changes to the storage. As an alternative to making two calls, you
can set PROPSETFLAG_UNBUFFERED so that changes are always written directly to th
e property set and are never buffered in the property set's internal cache. Then
, the changes will be picked up when the transacted storage is committed.
Remarks
These values can be set and checked using bitwise operations that determine how
property sets are created and opened. Property sets are created using the IPrope
rtySetStorage::Create method or the StgCreatePropStg function. They are opened u
sing the IPropertySetStorage::Open method or the StgOpenPropStg function.
It is recommended that property sets be created as Unicode, by not setting the P
ROPSETFLAG_ANSI flag in the grfFlags parameter. It is also recommended that you
avoid using VT_LPSTR values, and use VT_LPWSTR values instead. When the property
set code page is Unicode, VT_LPSTR string values are converted to Unicode when
stored, and converted back to multibyte string values when retrieved. When the c
ode page of the property set is not Unicode, property names, VT_BSTR strings, an
d non-simple property values are converted to multibyte strings when stored, and
converted back to Unicode when retrieved, all using the current system ANSI cod
e page.
Programming Information
Unicode Yes
Import Library IPROP.DLL
Header File IPROPIDL.H
See Also
IPropertySetStorage::Create, IPropertySetStorage::Open, PropStgNameToFmtId, StgC
reatePropSetStg, StgCreatePropStg, StgOpenPropStg
14.9.3 STATSTATE
The STATSTATE enumeration values indicate state information about the storage ob
ject and are used as a mask. The values are used in the IStorage::SetStateBits m
ethod.
<<NOTE TO REVIEWERS: Where is this defined? What file/interface?>>
typedef enum tagSTATSTATE
{
STATSTATE_DOC = 1,
STATSTATE_CONVERT = 2,
STATSTATE_FILESTGSAME = 4
} STATSTATE;
Elements
<<NOTE TO REVIEWERS: More info is needed on these descriptions and in the SetSta
teBits method which says that applications don t use these values. Do apps use the
m? If so, what are they used for?>>
STATSTATE_DOC
<<NOTE TO REVIEWERS: Does this mean compound file? When do nested objects use th
is value?>>
The storage object is a document file. This bit is set on the root storage objec
t as part of a normal File/Save sequence. With nested storage objects, the appli
cation manages the storage objects and sets or clears this bit as appropriate. I
f the nested object is an embedded object, this bit can be ignored. It is cleare
d in a newly created storage object. However, some applications might use this b
it to enable editing an embedded storage object without first copying the object
to the file system. For example, a mail application might set this bit for atta
chments so the attachments can be edited without copying them first to a file.
STATSTATE_CONVERT
<<NOTE TO REVIEWERS: Why would an app want to know if the object was converted??
>>
A convert operation was done on this storage object while it was in a passive st
ate.
STATSTATE_FILESTGSAME
<<NOTE TO REVIEWERS: Does this mean compound file?>>
The embedded object and document representations for the storage object are the
same. Thus, the storage object can be saved in a document file simply by copying
the storage object bits.
See Also
IStorage::SetStateBits
14.9.4 STGC
The STGC enumeration constants specify the conditions for performing the commit
operation in the IStorage::Commit and IStream::Commit methods.
Defined in the IOLETypes pseudo-interface (oletyp.idl).
typedef enum tagSTGC
{
STGC_DEFAULT = 0,
STGC_OVERWRITE = 1,
STGC_ONLYIFCURRENT = 2,
STGC_DANGEROUSLYCOMMITMERELYTODISKCACHE = 4
} STGC;
Elements
STGC_DEFAULT
None of the other values apply. You can specify this condition or some combinati
on of the other three. You would use this value mainly to make your code more re
adable.
STGC_OVERWRITE
The commit operation can overwrite existing data to reduce overall space require
ments. This value is not recommended for typical usage because it is not as robu
st as the default case. In this case, it is possible for the commit to fail afte
r the old data is overwritten but before the new data is completely committed. T
hen, neither the old version nor the new version of the storage object will be i
ntact.
You can use this value in cases where:
· the user has indicated a willingness to risk losing the data
· the low memory save sequence will be used to safely save the storage object to a
smaller file
· a previous commit returned STG_E_MEDIUMFULL but overwriting the existing data wo
uld provide enough space to commit changes to the storage object
Note that the commit operation checks for adequate space before any overwriting
occurs. Thus, even with this value specified, if the commit operation fails due
to space requirements, the old data will remain safe. The case where data loss c
an occur is when the commit operation fails due to some reason other than lack o
f space and the STGC_OVERWRITE value was specified.
STGC_ONLYIFCURRENT
Prevents multiple users of a storage object from overwriting one another s changes
. The commit operation occurs only if there have been no changes to the saved st
orage object since the user most recently opened the storage object. Thus, the s
aved version of the storage object is the same version that the user has been ed
iting. If other users have changed the storage object, the commit operation fail
s and returns the STG_E_NOTCURRENT value. You can override this behavior by call
ing the Commit method again using the STGC_DEFAULT value.
STGC_DANGEROUSLYCOMMITMERELYTODISKCACHE
Commits the changes to a write-behind disk cache, but does not save the cache to
the disk. In a write-behind disk cache, the operation that writes to disk actua
lly writes to a disk cache, thus increasing performance. The cache is eventually
written to the disk, but usually not until after the write operation has alread
y returned. The performance increase comes at the expense of an increased risk o
f losing data if a problem occurs before the cache is saved and the data in the
cache is lost.
If you do not specify this value, then committing changes to root-level storage
objects is robust even if a disk cache is used. The two-phase commit process ens
ures that data is stored on the disk and not just to the disk cache.
Remarks
You can specify STGC_DEFAULT or some combination of the other three values. Typi
cally, you would use STGC_ONLYIFCURRENT to protect the storage object in cases w
here more than one user can edit the object simultaneously.
See Also
IPropertyStorage, IStorage, IStream
14.9.5 STGFMT
This enumeration is defined, but is not used in the COM for UNIX implementation.
typedef enum tagSTGFMT
{
STGFMT_DOCUMENT = 0,
STGFMT_DIRECTORY = 1,
STGFMT_CATALOG = 2,
STGFMT_FILE = 3
} STGFMT;
Elements
STGFMT_DOCUMENT
Indicates a document format.
STGFMT_DIRECTORY
Indicates a directory format.
STGFMT_CATALOG
Indicates a catalog format.
STGFMT_FILE
Indicates a file format.
14.9.6 STGM
The STGM enumeration values are used in the storage and stream interfaces to ind
icate the conditions for creating and deleting the object and access modes for t
he object.
The STGM values are used in the IStorage and IStream interfaces, and in the StgC
reateDocfile and StgCreateDocfileOnILockBytes functions to indicate the conditio
ns for creating and deleting the object and access modes for the object.
STGM values are as follows:
STGM_DIRECT 0x00000000L
STGM_TRANSACTED 0x00010000L
STGM_SIMPLE 0x08000000L
STGM_READ 0x00000000L
STGM_WRITE 0x00000001L
STGM_READWRITE 0x00000002L
STGM_SHARE_DENY_NONE 0x00000040L
STGM_SHARE_DENY_READ 0x00000030L
STGM_SHARE_DENY_WRITE 0x00000020L
STGM_SHARE_EXCLUSIVE 0x00000010L
STGM_PRIORITY 0x00040000L
STGM_DELETEONRELEASE 0x04000000L 001000L
STGM_CONVERT 0x00020000L
STGM_FAILIFTHERE 0x00000000L
STGM_NOSCRATCH 0x00100000L
Elements
14.9.6.1.1.1.1 STGM_DIRECT. STGM_TRANSACTED, STGM_SIMPLE group:
STGM_DIRECT
In direct mode, each change to a storage element is written as it occurs. This i
s the default.
STGM_TRANSACTED
In transacted mode, changes are buffered and are written only if an explicit com
mit operation is called. The changes can be ignored by calling the Revert method
in the IStream or IStorage interfaces. The COM compound file implementation doe
s not support transacted streams, which means that streams can be opened only in
direct mode, and you cannot revert changes to them. Transacted storages are, ho
wever, supported.
STGM_SIMPLE
STGM_SIMPLE is a mode that provides a much faster implementation of a compound f
ile in a limited, but frequently used case. It is described in detail in the fol
lowing Remarks section.
14.9.6.1.1.1.2 STGM_READ, STGM_WRITE, STGM_READWRITE group:
STGM_READ
For stream objects, STGM_READ allows you to call the IStream::Read method. For s
torage objects, you can enumerate the storage elements and open them for reading
.
STGM_WRITE
STGM_WRITE lets you save changes to the object.
STGM_READWRITE
STGM_READWRITE is the combination of STGM_READ and STGM_WRITE.
14.9.6.1.1.1.3 STGM_SHARE_* group:
STGM_SHARE_DENY_NONE
Specifies that subsequent openings of the object are not denied read or write ac
cess.
STGM_SHARE_DENY_READ
Prevents others from subsequently opening the object in STGM_READ mode. It is ty
pically used on a root storage object.
STGM_SHARE_DENY_WRITE
Prevents others from subsequently opening the object in STGM_WRITE mode. This va
lue is typically used to prevent unnecessary copies made of an object opened by
multiple users. If this value is not specified, a snapshot is made, independent
of whether there are subsequent opens or not. Thus, you can improve performance
by specifying this value.
STGM_SHARE_EXCLUSIVE
The combination of STGM_SHARE_DENY_READ and STGM_SHARE_DENY_WRITE.
14.9.6.1.1.1.4 STGM_PRIORITY
STGM_PRIORITY
Opens the storage object with exclusive access to the most recently committed ve
rsion. Thus, other users cannot commit changes to the object while you have it o
pen in priority mode. You gain performance benefits for copy operations, but you
prevent others from committing changes. So, you should limit the time you keep
objects open in priority mode. You must specify STGM_DIRECT and STGM_READ with p
riority mode.
14.9.6.1.1.1.5 STGM_DELETEONRELEASE
STGM_DELETEONRELEASE
Indicates that the underlying file is to be automatically destroyed when the roo
t storage object is released. This capability is most useful for creating tempor
ary files.
14.9.6.1.1.1.6 STGM_CREATE, STGM_CONVERT, STGM_FAILIFTHERE Group
STGM_CREATE
Indicates that an existing storage object or stream should be removed before the
new one replaces it. A new object is created when this flag is specified, only
if the existing object has been successfully removed.
This flag is used in three situations:
· when you are trying to create a storage object on disk but a file of that name a
lready exists
· when you are trying to create a stream inside a storage object but a stream with
the specified name already exists
· when you are creating a byte array object but one with the specified name alread
y exists
STGM_CONVERT
Creates the new object while preserving existing data in a stream named CONTENTS
. In the case of a storage object or a byte array, the old data is flattened to
a stream regardless of whether the existing file or byte array currently contain
s a layered storage object.
STGM_FAILIFTHERE
Causes the create operation to fail if an existing object with the specified nam
e exists. In this case, STG_E_FILEALREADYEXISTS is returned. STGM_FAILIFTHERE ap
plies to both storage objects and streams.
STGM_NOSCRATCH
Not used.
Remarks
You can combine these flags but you can only choose one flag from each group of
related flags. Groups are indicated under the headings in the previous section.
The STGM_SIMPLE flag is applicable only when combined with:
STGM_CREATE | STGM_READWRITE | STGM_SHARE_EXCLUSIVE
Note that direct mode is implied by the absence of STGM_TRANSACTED.
This mode is useful for applications that perform complete save operations. It h
as the following constraints:
1. There is no support for substorages.
2. Access to streams follows a linear pattern. Once a stream is rel
eased, that stream cannot be opened for read/write operations again. The IStorag
e::OpenStream method is not supported in this implementation.
3. The storage and stream objects cannot be marshaled.
4. Each stream is at least 4096 bytes in length. If fewer than 4096
bytes are written into a stream by the time the stream is released, the stream
will be extended to contain 4096 bytes.
5. In this compound file implementation, only a subset of the metho
ds of IStorage and IStream are available.
Specifically, in simple mode, supported IStorage methods are QueryInterface, Add
Ref, Release, CreateStream, Commit, and SetClass. In addition, SetElementTimes i
s supported with a NULL name, allowing applications to set times on a root stora
ge in simple mode.
Supported IStream methods are QueryInterface, AddRef, Release, Write, Seek, SetS
ize, and Read.
All the other methods of IStorage and IStream return STG_E_INVALIDFUNCTION.
See Also
StgCreateDocfile, IStream::Read, IStorage, StgCreateDocfileOnILockBytes, StgOpen
Storage, StgOpenStorageOnILockBytes
14.9.7 STGMOVE
The STGMOVE enumeration values indicate whether a storage element is to be moved
or copied. They are used in the IStorage::MoveElementTo method.
Defined in the IOLETypes pseudo-interface (oletyp.idl).
typedef enum tagSTGMOVE
{
STGMOVE_MOVE = 0,
STGMOVE_COPY = 1
} STGMOVE;
Elements
STGMOVE_MOVE
Indicates the method should move the data from the source to the destination.
STGMOVE_COPY
Indicates the method should copy the data from the source to the destination. A
copy is the same as a move except the source element is not removed after copyin
g the element to the destination. Copying an element on top of itself is undefin
ed.
See Also
IStorage::MoveElementTo
14.9.8 STGTY
The STGTY enumeration values are used in the type member of the STATSTG structur
e to indicate the type of the storage element. A storage element is a storage ob
ject, a stream object, or a byte array object (LOCKBYTES).
Defined in the IStream interface (stream.idl).
typedef enum tagSTGTY
{
STGTY_STORAGE = 1,
STGTY_STREAM = 2,
STGTY_LOCKBYTES = 3,
STGTY_PROPERTY = 4
} STGTY;
Elements
STGTY_STORAGE
Indicates that the storage element is a storage object.
STGTY_STREAM
Indicates that the storage element is a stream object.
STGTY_LOCKBYTES
Indicates that the storage element is a byte array object.
STGTY_PROPERTY
Indicates that the storage element is a property storage object.
See Also
IStream, STATSTG
14.9.9 STREAM_SEEK
The STREAM_SEEK enumeration values specify the origin from which to calculate th
e new seek pointer location. They are used for the dworigin parameter in the ISt
ream::Seek method. The new seek position is calculated using this value and the
dlibMove parameter.
Defined in the IStream interface (stream.idl).
typedef enum tagSTREAM_SEEK
{
STREAM_SEEK_SET = 0,
STREAM_SEEK_CUR = 1,
STREAM_SEEK_END = 2
} STREAM_SEEK;
Elements
STREAM_SEEK_SET
The new seek pointer is an offset relative to the beginning of the stream. In th
is case, the dlibMove parameter is the new seek position relative to the beginni
ng of the stream.
STREAM_SEEK_CUR
The new seek pointer is an offset relative to the current seek pointer location.
In this case, the dlibMove parameter is the signed displacement from the curren
t seek position.
STREAM_SEEK_END
The new seek pointer is an offset relative to the end of the stream. In this cas
e, the dlibMove parameter is the new seek position relative to the end of the st
ream.
See Also
IStream::Seek
See Also
CreateBindCtx, IMoniker, IOleItemContainer, IParseDisplayName
15.2.1.2 IBindCtx::EnumObjectParam
Supplies a pointer to an IEnumString interface on an enumerator that can return
the keys of the bind context s string-keyed table of pointers.
HRESULT EnumObjectParam(
IEnumString **ppenum //Indirect pointer to the enumerator object
);
Parameter
ppenum
[out] Indirect pointer to the IEnumString interface on the enumerator. If an err
or occurs, *ppenum is set to NULL. If *ppenum is non-NULL, the implementation ca
lls IUnknown::AddRef on the parameter; it is the caller s responsibility to call I
Unknown::Release.
Return Values
This method supports the standard return value E_OUTOFMEMORY, as well as the fol
lowing:
S_OK
An enumerator was successfully created and the pointer supplied.
15.2.1.2.1 Remarks
This method provides an IEnumString pointer to an enumerator that can return the
keys of the bind context s string-keyed table of pointers. The keys returned are
the ones previously specified in calls to IBindCtx::RegisterObjectParam.
15.2.1.2.2 Notes to Callers
A bind context maintains a table of interface pointers, each associated with a s
tring key. This enables communication between a moniker implementation and the c
aller that initiated the binding operation. One party can store an interface poi
nter under a string known to both parties so that the other party can later retr
ieve it from the bind context.
See Also
IBindCtx::RegisterObjectParam, IEnumString
15.2.1.3 IBindCtx::GetBindOptions
Returns the binding options stored in this bind context.
HRESULT GetBindOptions(
BIND_OPTS *pbindopts //Pointer to a structure
);
Parameter
pbindopts
[in, out] Pointer to an initialized BIND_OPTS structure on entry that receives t
he current binding parameters on return.
Return Values
This method supports the standard return value E_UNEXPECTED, as well as the foll
owing:
S_OK
The stored binding options were successfully returned.
Remarks
A bind context contains a block of parameters, stored in a BIND_OPTS structure,
that are common to most IMoniker operations and that do not change as the operat
ion moves from piece to piece of a composite moniker.
15.2.1.3.1 Notes to Callers
You typically call this method if you are writing your own moniker class (this r
equires that you implement the IMoniker interface). You call this method to retr
ieve the parameters specified by the moniker client.
You must initialize the BIND_OPTS structure that is filled in by this method. Be
fore calling this method, you must initialize the cbStruct field of the structur
e to the size of the BIND_OPTS structure.
See Also
IBindCtx::SetBindOptions
15.2.1.4 IBindCtx::GetObjectParam
Retrieves the pointer associated with the specified key in the bind context s stri
ng-keyed table of pointers.
HRESULT GetObjectParam(
LPOLESTR pszKey, //Pointer to the key to be used
IUnknown **ppunk //Indirect pointer to the object associated with the key
);
Parameters
pszKey
[in] Pointer to a zero-terminated wide character string (two bytes per character
) containing the key to search for. Key string comparison is case-sensitive.
ppunk
[out] When successful, indirect pointer to the IUnknown interface on the object
associated with pszKey. In this case, the implementation calls IUnknown::AddRef
on the parameter. It is the caller s responsibility to call IUnknown::Release. If
an error occurs, ppunk is set to NULL.
Return Values
This method supports the standard return value E_FAIL, as well as the following:
S_OK
The pointer associated with the specified key was successfully returned.
Remarks
A bind context maintains a table of interface pointers, each associated with a s
tring key. This enables communication between a moniker implementation and the c
aller that initiated the binding operation. One party can store an interface poi
nter under a string known to both parties so that the other party can later retr
ieve it from the bind context.
The pointer this method retrieves must have previously been inserted into the ta
ble using the IBindCtx::RegisterObjectParam method.
15.2.1.4.1 Notes to Callers
Those writing a new moniker class (through an implementation of IMoniker) and so
me moniker clients (objects using a moniker to bind to an object) can call IBind
Ctx::GetObjectParam.
Objects using monikers to locate other objects can call this method when a bindi
ng operation fails to get specific information about the error that occurred. De
pending on the error, it may be possible to correct the situation and retry the
binding operation. See IBindCtx::RegisterObjectParam for more information.
Moniker implementations can call this method to deal with situations where a cal
ler initates a binding operation and requests specific information. By conventio
n, the implementer should use key names that begin with the string form of the C
LSID of a moniker class (see the StringFromCLSID function).
See Also
IBindCtx::RegisterObjectParam, IBindCtx::EnumObjectParam
15.2.1.5 IBindCtx::GetRunningObjectTable
Provides an interface pointer to the Running Object Table (ROT) for the machine
on which this bind context is running.
HRESULT GetRunningObjectTable(
IRunningObjectTable **pprot //Indirect pointer to the Running Object Table
);
Parameter
pprot
[out] When successful, indirect pointer to the IRunningObjectTable interface on
the Running Object Table. If an error occurs, *pprot is set to NULL. If *pprot i
s non-NULL, the implementation calls IUnknown::AddRef on the parameter; it is th
e caller s responsibility to call IUnknown::Release.
Return Values
This method supports the standard return values E_OUTOFMEMORY and E_UNEXPECTED,
as well as the following:
S_OK
A pointer to the ROT was returned successfully.
Remarks
The Running Object Table is a globally accessible table on each machine. It keep
s track of all the objects that are currently running on the machine.
15.2.1.5.1 Notes to Callers
Typically, those implementing a new moniker class (through an implementation of
IMoniker interface) call IBindCtx::GetRunningObjectTable. It is useful to call t
his method in an implementation of IMoniker::BindToObject or IMoniker::IsRunning
to check whether a given object is currently running. You can also call this me
thod in the implementation of IMoniker::GetTimeOfLastChange to learn when a runn
ing object was last modified.
Moniker implementations should call this method instead of using the GetRunningO
bjectTable function. This makes it possible for future implementations of IBindC
tx to modify binding behavior.
See Also
IMoniker, IRunningObjectTable
15.2.1.6 IBindCtx::RegisterObjectBound
Calls IUnknown::AddRef on the specified object to ensure that the object remains
active until the bind context is released. The method stores a pointer to the o
bject in the bind context s internal list of pointers.
HRESULT RegisterObjectBound(
IUnknown *punk //Pointer to the object being registered
);
Parameter
punk
[in] Pointer to the IUnknown interface on the object that is being registered as
bound.
Return Values
This method supports the standard return value E_OUTOFMEMORY, as well as the fol
lowing:
S_OK
The object was successfully registered.
Remarks
15.2.1.6.1 Notes to Callers
Those writing a new moniker class (through an implementation of the IMoniker int
erface), should call this method whenever the implementation activates an object
. This happens most often in the course of binding a moniker, but it can also ha
ppen while retrieving a moniker s display name, parsing a display name into a moni
ker, or retrieving the time that an object was last modified.
IBindCtx::RegisterObjectBound calls IUnknown::AddRef to create an additional ref
erence to the object. You must, however, still release your own copy of the poin
ter. Note that calling this method twice for the same object creates two referen
ces to that object. You can release a reference obtained through a call to this
method by calling IBindCtx::RevokeObjectBound. All references held by the bind c
ontext are released when the bind context itself is released.
Calling IBindCtx::RegisterObjectBound to register an object with a bind context
keeps the object active until the bind context is released. Reusing a bind conte
xt in a subsequent binding operation (either for another piece of the same compo
site moniker, or for a different moniker) can make the subsequent binding operat
ion more efficient because it doesn t have to reload that object. This, however, i
mproves performance only if the subsequent binding operation requires some of th
e same objects as the original one, so you need to balance the possible performa
nce improvement of reusing a bind context against the costs of keeping objects a
ctivated unnecessarily.
IBindCtx does not provide a method to retrieve a pointer to an object registered
using IBindCtx::RegisterObjectBound. Assuming the object has registered itself
with the Running Object Table, moniker implementations can call IRunningObjectTa
ble::GetObject to retrieve a pointer to the object.
See Also
IBindCtx::ReleaseBoundObjects, IBindCtx::RevokeObjectBound, IRunningObjectTable:
:GetObject
15.2.1.7 IBindCtx::RegisterObjectParam
Stores an IUnknown pointer on the specified object under the specified key in th
e bind context s string-keyed table of pointers. The method must call IUnknown::Ad
dRef on the stored pointer.
HRESULT RegisterObjectParam(
LPOLESTR pszKey, //Pointer to the key to be used
IUnknown *punk //Pointer to the object to be associated with the key
);
Parameters
pszKey
[in] Pointer to a zero-terminated wide character string (two bytes per character
) containing the key under which the object is being registered. Key string comp
arison is case-sensitive.
punk
[in] Pointer to the IUnknown interface on the object that is to be registered.
Return Values
This method supports the standard return value E_OUTOFMEMORY, as well as the fol
lowing:
S_OK
The pointer was successfully registered under the specified string.
Remarks
A bind context maintains a table of interface pointers, each associated with a s
tring key. This enables communication between a moniker implementation and the c
aller that initiated the binding operation. One party can store an interface poi
nter under a string known to both parties so that the other party can later retr
ieve it from the bind context.
Binding operations subsequent to the use of this method can use IBindCtx::GetObj
ectParam to retrieve the stored pointer.
15.2.1.7.1 Notes to Callers
IBindCtx::RegisterObjectParam is useful to those implementing a new moniker clas
s (through an implementation of IMoniker) and to moniker clients (those who use
monikers to bind to objects).
In implementing a new moniker class, you call this method when an error occurs d
uring moniker binding to inform the caller of the cause of the error. The key th
at you would obtain with a call to this method would depend on the error conditi
on. The following lists common moniker binding errors, describing for each the k
eys that would be appropriate:
MK_E_EXCEEDEDDEADLINE
If a binding operation exceeds its deadline because a given object is not runnin
g, you should register the object s moniker using the first unused key from the li
st: ExceededDeadline , ExceededDeadline1 , ExceededDeadline2 , etc. If the caller later
inds the moniker in the Running Object Table, the caller can retry the binding o
peration.
MK_E_CONNECTMANUALLY
The ConnectManually key indicates a moniker whose binding requires assistance from
the end user. The caller can retry the binding operation after showing the moni
ker s display name to request that the end user manually connect to the object. Co
mmon reasons for this error are that a password is needed or that a floppy needs
to be mounted.
E_CLASSNOTFOUND
The ClassNotFound key indicates a moniker whose class could not be found (the serv
er for the object identified by this moniker could not be located). If this key
is used for an COM compound-document object, the caller can use IMoniker::BindTo
Storage to bind to the object, and then try to carry out a Treat As... or Conver
t To... operation to associate the object with a different server. If this is su
ccessful, the caller can retry the binding operation.
If you re a moniker client with detailed knowledge of the implementation of the mo
niker you re using, you can also call this method to pass private information to t
hat implementation.
You can define new strings as keys for storing pointers. By convention, you shou
ld use key names that begin with the string form of the CLSID of the moniker cla
ss (see the StringFromCLSID function).
If the pszKey parameter matches the name of an existing key in the bind context s
table, the new object replaces the existing object in the table.
When you register an object using this method, the object is not released until
one of the following occurs:
· It is replaced in the table by another object with the same key.
· It is removed from the table by a call to IBindCtx::RevokeObjectParam.
· The bind context is released. All registered objects are released when the bind
context is released.
See Also
IBindCtx::GetObjectParam, IBindCtx::RevokeObjectParam, IBindCtx::EnumObjectParam
15.2.1.8 IBindCtx::ReleaseBoundObjects
Releases all pointers to all objects that were previously registered by calls to
IBindCtx::RegisterObjectBound.
HRESULT ReleaseBoundObjects(void);
Return Value
S_OK
The objects were released successfully.
Remarks
You rarely call this method directly. The system s IBindCtx implementation calls t
his method when the pointer to the IBindCtx interface on the bind context is rel
eased (the bind context is released). If a bind context is not released, all of
the registered objects remain active.
If the same object has been registered more than once, this method calls the IUn
known::Release method on the object the number of times it was registered.
See Also
IBindCtx::RegisterObjectBound
15.2.1.9 IBindCtx::RevokeObjectBound
Releases the IUnknown pointer to the specified object and removes that pointer f
rom the bind context s internal list of pointers. This undoes a previous call to I
BindCtx::RegisterObjectBound for the same object.
HRESULT RevokeObjectBound(
IUnknown *punk //Pointer to the object whose registration is being revo
ked
);
Parameter
punk
[in] Pointer to the IUnknown interface on the object to be released.
Return Values
S_OK
The object was released successfully.
MK_E_NOTBOUND
Indicates that punk was not previously registered with a call to IBindCtx::Regis
terObjectBound.
Remarks
You rarely call this method. This method is included for completeness.
See Also
IBindCtx::RegisterObjectBound
15.2.1.10 IBindCtx::RevokeObjectParam
Removes the specified key and its associated pointer from the bind context s strin
g-keyed table of objects. The key must have previously been inserted into the ta
ble with a call to IBindCtx::RegisterObjectParam.
HRESULT RevokeObjectParam(
LPOLESTR pszKey //Pointer to the key to be revoked
);
Parameter
pszKey
[in] Pointer to a zero-terminated wide character string (two bytes per character
) containing the key to remove. Key string comparison is case-sensitive.
Return Values
S_OK
The specified key was successfully removed from the table.
S_FALSE
No object has been registered with the specified key.
Remarks
A bind context maintains a table of interface pointers, each associated with a s
tring key. This enables communication between a moniker implementation and the c
aller that initiated the binding operation. One party can store an interface poi
nter under a string known to both parties so that the other party can later retr
ieve it from the bind context.
This method is used to remove an entry from the table. If the specified key is f
ound, the bind context also releases its reference to the object.
See Also
IBindCtx::RegisterObjectParam
15.2.1.11 IBindCtx::SetBindOptions
Specifies new values for the binding parameters stored in the bind context. Subs
equent binding operations can call IBindCtx::GetBindOptions to retrieve the para
meters.
HRESULT SetBindOptions(
15.2.4 IEnumString
IEnumString is defined to enumerate strings. LPWSTR is the type that indicates a
pointer to a zero-terminated string of wide, i.e., Unicode, characters. IEnumSt
ring has the same methods as all enumerator interfaces: Next, Skip, Reset, and C
lone. For general information on these methods, refer to IEnumXXXX.
15.2.4.1.1 When to Implement
It is usually not necessary to implement this interface unless you have use for
a custom string enumerator. A system implementation in the bind context object o
n which is the IBindCtx interface also contains an implementation of IEnumString
. IBindCtx::EnumObjectParam returns a pointer to this IEnumString interface on a
n enumerator that can return the keys of the bind context s string-keyed table of
pointers.
15.2.4.1.2 When to Use
Call the methods of IEnumString to enumerate through a set of strings.
The prototypes of the member functions are as follows:
HRESULT Next(
ULONG celt,
LPOLESTR * rgelt,
ULONG * pceltFetched
);
HRESULT Skip(
ULONG celt
);
HRESULT Reset(void)
HRESULT Clone(
IEnumString ** ppenum
);
15.2.5 IEnumUnknown
This enumerator enumerates objects with the IUnknown interface. It can be used t
o enumerate through the objects in a component containing multiple objects. IEnu
mUnknown has the same methods as all enumerator interfaces: Next, Skip, Reset, a
nd Clone. For general information on these methods, refer to IEnumXXXX.
15.2.5.1.1 When to Implement
You can implement this whenever you want a caller to be able to enumerate the ob
jects contained in another object. You get a pointer to IEnumUnknown through a c
all to IOleContainer::EnumObjects.
15.2.5.1.2 When to Implement
Call the methods of IEnumUnknown to enumerate the objects in a compound document
, when you get a pointer to the interface on the enumerator through a call to IO
leContainer::EnumObjects.
The prototypes of the methods are as follows:
HRESULT Next(
ULONG celt,
IUnknown ** rgelt,
ULONG * pceltFetched
);
HRESULT Skip(
ULONG celt
);
HRESULT Reset(void)
HRESULT Clone(
IEnumUnknown ** ppenum
);
15.2.6 IMoniker
The IMoniker interface contains methods that allow you to use a moniker object,
which contains information that uniquely identifies a COM object. An object that
has a pointer to the moniker object s IMoniker interface can locate, activate, an
d get access to the identified object without having any other specific informat
ion on where the object is actually located in a distributed system.
Like a path to a file in a file system, a moniker contains information that allo
ws a COM object to be located and activated. Monikers can identify any type of C
OM object, from a document object stored in a file to a selection within an embe
dded object. COM provides a set of moniker classes that allow you to create moni
ker objects identifying the objects most commonly found in the system. For examp
le, there might be an object representing a range of cells in a spreadsheet whic
h is itself embedded in a text document stored in a file. In a distributed syste
m, this object s moniker would identify the location of the object s system, the fil
e s physical location on that system, the storage of the embedded object within th
at file, and, finally, the location of the range of cells within the embedded ob
ject.
A moniker object supports the IMoniker interface, which is derived from the IPer
sistStream interface, and uniquely identifies a single object in the system. Onc
e an object providing a moniker has created the moniker object, this information
cannot be changed within that object. If the moniker provider changes the infor
mation, it can only do so by creating a new moniker object, which would then uni
quely identify the object in question.
Monikers have two important capabilites:
· Monikers can be saved to a persistent storage. When a moniker is loaded back int
o memory, it still identifies the same object.
· Monikers support an operation called binding, which is the process of locating th
object named by the moniker, activating it (loading it into memory) if it is no
t already active, and returning a pointer to a requested interface on that objec
t.
Monikers are used as the basis for linking in COM. A linked object contains a mo
niker that identifies its source. When the user activates the linked object to e
dit it, the moniker is bound; this loads the link source into memory.
15.2.6.1.1 When to Implement
Implement IMoniker only if you are writing a new moniker class. This is necessar
y only if you need to identify objects that cannot be identified using one of th
e COM-supplied moniker classes described below.
The COM-supplied moniker classes are sufficient for most situations. Before cons
idering writing your own moniker class, you should make sure that your requireme
nts cannot be satisified by these classes.
If you decide you need to write your own implementation of IMoniker, you must al
so implement the IROTData interface on your moniker class. This interface allows
your monikers to be registered with the Running Object Table (ROT).
15.2.6.1.2 When to Use
Two kinds of objects call the methods of IMoniker:
· A component that contains one or more objects to be identified with a moniker an
d must provide the moniker to other objects
· A client object that must bind to the object identified by the moniker
The component providing a moniker makes it accessible to other objects. It is im
portant to understand the differences between the various system-supplied monike
r classes to know which are appropriate for a given object. COM also provides fu
nctions for creating monikers using the COM-supplied moniker classes.
· File monikers based on a path in the file system. File monikers can be used to i
dentify objects that are saved as files. The associated creation function is Cre
ateFileMoniker.
· Item monikers based on a string that identifies an object in a container. Item m
onikers can be used to identify objects smaller than a file, such as embedded ob
jects in a compound document and pseudo-objects (like a range of cells in a spre
adsheet). The associated creation function is CreateItemMoniker.
· Generic composite monikers consists of two or more monikers of arbitrary type th
at have been composed together. Generic composite monikers allow monikers of dif
ferent classes to be used in combination. The associated creation function is Cr
eateGenericComposite.
· Anti-monikers the inverse of file, item, or pointer monikers. Anti-monikers are u
sed primarily for constructing relative monikers, which are analogous to relativ
e path (such as ..\backup\report.old ), and which specify a location of an object r
elative to the location of another object). The associated creation function is
CreateAntiMoniker.
· Pointer monikers a non-persistent moniker that wraps an interface pointer to an
object loaded in memory. Whereas most monikers identify objects that can be save
d to persistent storage, pointer monikers identify objects that cannot. The asso
ciated creation function is CreatePointerMoniker.
A moniker provider must also implement other interfaces to allow the monikers it
hands out to be bound. COM objects that commonly provide monikers are link sour
ces. These include server applications that support linking and container applic
ations that support linking to their embedded objects.
Binding to an object means that a client uses a moniker to locate the object, ac
tivate it when necessary, and get a pointer to one of the active object s interfac
es. The client of the moniker does not need to be aware of the class of the moni
ker it must just get a pointer to the correct moniker s IMoniker interface. Monike
rs are used most often in this way by container applications that allow their do
cuments to contain linked objects. However, link containers rarely call IMoniker
methods directly
· Class monikers these represent an object class. Class monikers bind to the class
object of the class for which they are created. The associated creation functio
n is CreateClassComposite.
Methods in Vtable Order
IUnknown Methods Description
QueryInterface Returns pointers to supported interfaces.
AddRef Increments reference count.
Release Decrements reference count.
IPersist Methods Description
GetClassID Returns the object s CLSID.
IPersistStream Methods Description
IsDirty Checks whether object has been modified.
Load Loads the object from a stream.
Save Saves the object to a stream.
GetSizeMax Returns the buffer size needed to save the object.
IMoniker Methods Description
BindToObject Binds to the object named by the moniker.
BindToStorage Binds to the object s storage.
Reduce Reduces the moniker to simplest form.
ComposeWith Composes with another moniker.
Enum Enumerates component monikers.
IsEqual Compares with another moniker.
Hash Returns a hash value.
IsRunning Checks whether object is running.
GetTimeOfLastChange Returns time the object was last changed.
Inverse Returns the inverse of the moniker.
CommonPrefixWith Finds the prefix that the moniker has in common with ano
ther moniker.
RelativePathTo Constructs a relative moniker between the moniker and another.
GetDisplayName Returns the display name.
ParseDisplayName Converts a display name into a moniker.
IsSystemMoniker Checks whether moniker is one of the system-supplied types.
See Also
BindMoniker, CreateBindCtx, CreateGenericComposite, CreateFileMoniker, CreateIte
mMoniker, CreateAntiMoniker, CreatePointerMoniker, IPersistStream, IROTData, IMo
niker AntiMoniker Implementation, IMoniker File Moniker Implementation, IMoniker Item
Moniker Implementation, IMoniker Generic Composite Moniker Implementation, IMonike
r Pointer Moniker Implementation
15.2.6.2 IMoniker::BindToObject
Uses the moniker to bind to the object it identifies. The binding process involv
es finding the object, putting it into the running state if necessary, and suppl
ying the caller with a pointer to a specified interface on the identified object
.
HRESULT BindToObject(
IBindCtx *pbc, //Pointer to bind context object to be used
IMoniker *pmkToLeft, //Pointer to moniker that precedes this one in t
he composite
REFIID riidResult, //IID of interface pointer requested
void **ppvResult //Indirect pointer to the specified interface on the obj
ect
);
Parameters
pbc
[in] Pointer to the IBindCtx interface on the bind context object, which is used
in this binding operation. The bind context caches objects bound during the bin
ding process, contains parameters that apply to all operations using the bind co
ntext, and provides the means by which the moniker implementation should retriev
e information about its environment.
pmkToLeft
[in] If the moniker is part of a composite moniker, pointer to the moniker to th
e left of this moniker. This parameter is primarily used by moniker implementers
to enable cooperation between the various components of a composite moniker. Mo
niker clients should pass NULL.
riidResult
[in] IID of the interface the client wishes to use to communicate with the objec
t that the moniker identifies.
ppvResult
[out] When successful, indirect pointer to the interface specified in riidResult
on the object the moniker identifies. In this case, the implementation must cal
l IUnknown::AddRef on this pointer. It is the caller s responsibility to release t
he object with a call to IUnknown::Release. If an error occurs, ppvResult should
return NULL.
Return Values
The method supports the standard return values E_UNEXPECTED and E_OUTOFMEMORY, a
s well as the following:
S_OK
The binding operation was successful.
MK_E_NOOBJECT
The object identified by this moniker, or some object identified by the composit
e moniker of which this moniker is a part, could not be found.
MK_E_EXCEEDEDDEADLINE
The binding operation could not be completed within the time limit specified by
the bind context s BIND_OPTS structure.
MK_E_CONNECTMANUALLY
The binding operation requires assistance from the end user. The most common rea
sons for returning this value are that a password is needed or that a floppy nee
ds to be mounted. When this value is returned, retrieve the moniker that caused
the error with a call to IBindCtx::GetObjectParam with the key ConnectManually . Yo
u can then call IMoniker::GetDisplayName to get the display name, display a dial
og box that communicates the desired information, such as instructions to mount
a floppy or a request for a password, and then retry the binding operation.
MK_E_INTERMEDIATEINTERFACENOTSUPPORTED
An intermediate object was found but it did not support an interface required to
complete the binding operation. For example, an item moniker returns this value
if its container does not support the IOleItemContainer interface.
STG_E_ACCESSDENIED
Unable to access the storage object.
IOleItemContainer::GetObject errors
If the moniker used to bind to an object contains an item moniker, errors associ
ated with this method can be returned.
Remarks
IMoniker::BindToObject implements the primary function of a moniker, which is to
locate the object identified by the moniker and return a pointer to one of its
interfaces.
15.2.6.2.1 Notes to Callers
If you are using a moniker as a persistent connection between two objects, you a
ctivate the connection by calling IMoniker::BindToObject.
You typically call IMoniker::BindToObject during the following process:
1. Create a bind context object with a call to the CreateBindCtx fu
nction.
2. Call IMoniker::BindToObject using the moniker, retrieving a poin
ter to a desired interface on the identified object.
3. Release the bind context.
4. Through the acquired interface pointer, perform the desired oper
ations on the object.
5. When finished with the object, release the object s interface poin
ter.
The following code fragment illustrates these steps:
// pMnk is an IMoniker * that points to a previously acquired moniker
// ICellRange is a custom interface designed for an object that is a
// range of spreadsheet cells
ICellRange *pCellRange;
IBindCtx *pbc;
CreateBindCtx( 0, &pbc );
pMnk->BindToObject( pbc, NULL, IID_ICellRange, &pCellRange );
pbc->Release();
// pCellRange now points to the object; safe to use pCellRange
pCellRange->Release();
You can also use the BindMoniker function when you only intend one binding opera
tion and don t need to retain the bind context object. This helper function encaps
ulates the creation of the bind context, calling IMoniker::BindToObject, and rel
easing the bind context.
COM containers that support links to objects use monikers to locate and get acce
ss to the linked object, but typically do not call IMoniker::BindToObject direct
ly
15.2.6.2.2 Notes to Implementers
What your implementation does depends on whether you expect your moniker to have
a prefix, that is, whether you expect the pmkToLeft parameter to be NULL or not
. For example, an item moniker, which identifies an object within a container, e
xpects that pmkToLeft identifies the container. An item moniker consequently use
s pmkToLeft to request services from that container. If you expect your moniker
to have a prefix, you should use the pmkToLeft parameter (for instance, calling
IMoniker::BindToObject on it) to request services from the object it identifies.
If you expect your moniker to have no prefix, your IMoniker::BindToObject implem
entation should first check the Running Object Table (ROT) to see if the object
is already running. To acquire a pointer to the ROT, your implementation should
call IBindCtx::GetRunningObjectTable on the pbc parameter. You can then call the
IRunningObjectTable::GetObject method to see if the current moniker has been re
gistered in the ROT. If so, you can immediately call IUnknown::QueryInterface to
get a pointer to the interface requested by the caller.
When your IMoniker::BindToObject implementation binds to some object, it should
use the pbc parameter to call IBindCtx::RegisterObjectBound to store a reference
to the bound object in the bind context. This ensures that the bound object rem
ains running until the bind context is released, which can avoid the expense of
having a subsequent binding operation load it again later.
If the bind context s BIND_OPTS structure specifies the BINDFLAGS_JUSTTESTEXISTENC
E flag, your implementation has the option of returning NULL in ppvResult (altho
ugh you can also ignore the flag and perform the complete binding operation).
See Also
BindMoniker, IMoniker::BindToStorage
15.2.6.3 IMoniker::BindToStorage
Retrieves an interface pointer to the storage that contains the object identifie
d by the moniker. Unlike the IMoniker::BindToObject method, this method does not
activate the object identified by the moniker.
HRESULT BindToStorage(
IBindCtx *pbc, //Pointer to bind context to be used
IMoniker *pmkToLeft, //Pointer to moniker to the left of this one in
the composite
REFIID riid, //Reference to the identifier of the storage interface r
equested
void **ppvObj //Indirect pointer to interface on storage object contai
ning the identified object
);
Parameters
pbc
[in] Pointer to the IBindCtx interface on the bind context object to be used dur
ing this binding operation. The bind context caches objects bound during the bin
ding process, contains parameters that apply to all operations using the bind co
ntext, and provides the means by which the moniker implementation should retriev
e information about its environment. For more information, see IBindCtx.
pmkToLeft
[in] If the moniker is part of a composite moniker, pointer to the moniker to th
e left of this moniker. This parameter is primarily used by moniker implementers
to enable cooperation between the various components of a composite moniker. Mo
niker clients should pass NULL.
riid
[in] Reference to the identifier of the storage interface requested, whose point
er will be returned in ppvObj. Storage interfaces commonly requested include ISt
orage, IStream, and ILockBytes.
ppvObj
[out] Pointer to the interface identified by riid on the storage of the object i
dentified by the moniker. If ppvObj is non-NULL, the implementation must call IU
nknown::AddRef on the parameter; it is the caller s responsibility to call IUnknow
n::Release. If an error occurs, ppvObj is set to NULL.
Return Values
The method supports the standard return value E_OUTOFMEMORY, as well as the foll
owing:
S_OK
The binding operation was successful.
MK_E_NOSTORAGE
The object identified by this moniker does not have its own storage.
MK_E_EXCEEDEDDEADLINE
The operation could not be completed within the time limit specified by the bind
context s BIND_OPTS structure.
MK_E_CONNECTMANUALLY
The operation was unable to connect to the storage, possibly because a network d
evice could not be connected to. For more information, see IMoniker::BindToObjec
t.
MK_E_INTERMEDIATEINTERFACENOTSUPPORTED
An intermediate object was found but it did not support an interface required fo
r an operation. For example, an item moniker returns this value if its container
does not support the IOleItemContainer interface.
STG_E_ACCESSDENIED
Unable to access the storage object.
IOleItemContainer::GetObject errors
Binding to a moniker containing an item moniker can return any of the errors ass
ociated with this function.
Remarks
There is an important difference between the IMoniker::BindToObject and IMoniker
::BindToStorage methods. If, for example, you have a moniker that identifies a s
preadsheet object, calling IMoniker::BindToObject provides access to the spreads
heet object itself, while calling IMoniker::BindToStorage provides access to the
storage object in which the spreadsheet resides.
15.2.6.3.1 Notes to Callers
Although none of the COM moniker classes call this method in their binding opera
tions, it might be appropriate to call it in the implementation of a new moniker
class. You could call this method in an implementation of IMoniker::BindToObjec
t that requires information from the object identified by the pmkToLeft paramete
r and can get it from the persistent storage of the object without activation. F
or example, if your monikers are used to identify objects that can be activated
without activating their containers, you may find this method useful.
A client that can read the storage of the object its moniker identifies could al
so call this method.
15.2.6.3.2 Notes to Implementers
Your implementation should locate the persistent storage for the object identifi
ed by the current moniker and return the desired interface pointer. Some types o
f monikers represent pseudo-objects, which are objects that do not have their ow
n persistent storage. Such objects comprise some portion of the internal state o
f its container; as, for example, a range of cells in a spreadsheet. If your mon
iker class identifies this type of object, your implementation of IMoniker::Bind
ToStorage should return the error MK_E_NOSTORAGE.
If the bind context s BIND_OPTS structure specifies the BINDFLAGS_JUSTTESTEXISTENC
E flag, your implementation has the option of returning NULL in ppvObj (although
it can also ignore the flag and perform the complete binding operation).
See Also
IMoniker::BindToObject
15.2.6.4 IMoniker::CommonPrefixWith
Creates a new moniker based on the common prefix that this moniker (the one comp
rising the data of this moniker object) shares with another moniker.
HRESULT CommonPrefixWith(
IMoniker *pmkOther, //Pointer to moniker to be used for comparison
IMoniker **ppmkPrefix //Indirect pointer to the prefix
);
Parameters
pmkOther
[in] Pointer to the IMoniker interface on another moniker to be compared with th
is one to determine whether there is a common prefix.
ppmkPrefix
[out] When successful, points to the IMoniker pointer to the moniker that is the
common prefix of this moniker and pmkOther. In this case, the implementation mu
st call IUnknown::AddRef on the parameter; it is the caller s responsibility to ca
ll IUnknown::Release. If an error occurs or if there is no common prefix, the im
plementation should set ppmkPrefix to NULL.
Return Values
The method supports the standard return value E_OUTOFMEMORY, as well as the foll
owing:
S_OK
A common prefix exists that is neither this moniker nor pmkOther.
MK_S_NOPREFIX
No common prefix exists.
MK_S_HIM
The entire pmkOther moniker is a prefix of this moniker.
MK_S_US
The two monikers are identical.
MK_S_ME
This moniker is a prefix of the pmkOther moniker.
MK_E_NOTBINDABLE
This method was called on a relative moniker. It is not meaningful to take the c
ommon prefix on a relative moniker.
Remarks
IMoniker::CommonPrefixWith creates a new moniker that consists of the common pre
fixes of the moniker on this moniker object and another moniker. If, for example
, one moniker represents the path c:\projects\secret\art\pict1.bmp and another mon
iker represents the path c:\projects\secret\docs\chap1.txt, the common prefix of t
hese two monikers would be a moniker representing the path c:\projects\secret.
15.2.6.4.1 Notes to Callers
The IMoniker::CommonPrefixWith method is primarily called in the implementation
of the IMoniker::RelativePathTo method. Clients using a moniker to locate an obj
ect rarely need to call this method.
Call this method only if pmkOther and this moniker are both absolute monikers. A
n absolute moniker is either a file moniker or a generic composite whose leftmos
t component is a file moniker that represents an absolute path. Do not call this
method on relative monikers, because it would not produce meaningful results.
15.2.6.4.2 Notes to Implementers
Your implementation should first determine whether pmkOther is a moniker of a cl
ass that you recognize and for which you can provide special handling (for examp
le, if it is of the same class as this moniker). If so, your implementation shou
ld determine the common prefix of the two monikers. Otherwise, it should pass bo
th monikers in a call to the MonikerCommonPrefixWith function, which correctly h
andles the generic case.
See Also
IMoniker::RelativePathTo, MonikerCommonPrefixWith
15.2.6.5 IMoniker::ComposeWith
Combines the current moniker with another moniker, creating a new composite moni
ker.
HRESULT ComposeWith(
IMoniker *pmkRight, //Pointer to moniker to be composed onto this one
BOOL fOnlyIfNotGeneric, //Indicates if generic composition permissible
IMoniker **ppmkComposite //Indirect pointer to the composite
);
Parameters
pmkRight
[in] Pointer to the IMoniker interface on the moniker to compose onto the end of
this moniker.
fOnlyIfNotGeneric
[in] If TRUE, the caller requires a non-generic composition, so the operation sh
ould proceed only if pmkRight is a moniker class that this moniker can compose w
ith in some way other than forming a generic composite. If FALSE, the method can
create a generic composite if necessary.
ppmkComposite
[out] When the call is successful, indirect pointer to the location of the resul
ting composite moniker pointer. In this case, the implementation must call IUnkn
own::AddRef on the parameter; it is the caller s responsibility to call IUnknown::
Release. If an error occurs or if the monikers compose to nothing (e.g., composi
ng an anti-moniker with an item moniker or a file moniker), ppmkComposite should
be set to NULL.
Return Values
The method supports the standard return values E_OUTOFMEMORY and E_UNEXPECTED, a
s well as the following:
S_OK
The monikers were successfully combined.
MK_E_NEEDGENERIC
Indicates that fOnlyIfNotGeneric was TRUE, but the monikers could not be compose
d together without creating a generic composite moniker.
Remarks
Joining two monikers together is called composition. Sometimes two monikers of t
he same class can be combined in what is called non-generic composition. For exa
mple, a file moniker representing an incomplete path and another file moniker re
presenting a relative path can be combined to form a single file moniker represe
nting the complete path. Non-generic composition for a given moniker class can b
e handled only in the implementation of IMoniker::ComposeWith for that moniker c
lass.
Combining two monikers of any class is called generic composition, which can be
accomplished through a call to the CreateGenericComposite function.
Composition of monikers is an associative operation. That is, if A, B, and C are
monikers, then, where Comp() represents the composition operation:
Comp( Comp( A, B ), C )
is always equal to
Comp( A, Comp( B, C ) )
15.2.6.5.1 Notes to Callers
To combine two monikers, you should call IMoniker::ComposeWith rather than calli
ng the CreateGenericComposite function to give the first moniker a chance to per
form a non-generic composition.
An object that provides item monkers to identify its objects would call IMoniker
::ComposeWith to provide a moniker that completely identifies the location of th
e object. This would apply, for example, to a server that supports linking to po
rtions of a document, or a container that supports linking to embedded objects w
ithin its documents. In such a situation, you would do the following:
1. Create an item moniker identifying an object.
2. Get a moniker that identifies the object s container.
3. Call IMoniker::ComposeWith on the moniker identifying the contai
ner, passing the item moniker as the pmkRight parameter.
Most callers of IMoniker::ComposeWith should set the fOnlyIfNotGeneric parameter
to FALSE.
15.2.6.5.2 Notes to Implementers
You can use either non-generic or generic composition to compose the current mon
iker with the moniker that pmkRight points to. If the class of the moniker indic
ated by pmkRight is the same as that of the current moniker, it is possible to u
se the contents of pmkRight to perform a more intelligent non-generic compositio
n.
In writing a new moniker class, you must decide if there are any kinds of monike
rs, whether of your own class or another class, to which you want to give specia
l treatment. If so, implement IMoniker::ComposeWith to check whether pmkRight is
a moniker of the type that should have this treatment. To do this, you can call
the moniker s GetClassID method (derived from the IPersist Interface), or, if you
have defined a moniker object that supports a custom interface, you can call IU
nknown::QueryInterface on the moniker for that interface. An example of special
treatment would be the non-generic composition of an absolute file moniker with
a relative file moniker. The most common case of a special moniker is the invers
e for your moniker class (whatever you return from your implementation of IMonik
er::Inverse).
If pmkRight completely negates the receiver so the resulting composite is empty,
you should pass back NULL in ppmkComposite and return the status code S_OK.
If the pmkRight parameter is not of a class to which you give special treatment,
examine fOnlyIfNotGeneric to determine what to do next. If fOnlyIfNotGeneric is
TRUE, pass back NULL through ppmkComposite and return the status code MK_E_NEED
GENERIC. If fOnlyIfNotGeneric is FALSE, call the CreateGenericComposite function
to perform the composition generically.
See Also
CreateGenericComposite, IMoniker::Inverse
15.2.6.6 IMoniker::Enum
Supplies a pointer to an enumerator that can enumerate the components of a compo
site moniker.
HRESULT Enum(
BOOL fForward, //Specifies direction of enumeration
IEnumMoniker **ppenumMoniker //Indirect pointer to the IEnumMoniker p
ointer
);
Parameters
fForward
[in] If TRUE, enumerates the monikers from left to right. If FALSE, enumerates f
rom right to left.
ppenumMoniker
[out] When successful, indirect pointer to an IEnumMoniker enumerator on this mo
niker. In this case, the implementation must call IUnknown::AddRef on the parame
ter. It is the caller s responsibility to call IUnknown::Release. If an error occu
rs or if the moniker has no enumerable components, the implementation sets ppenu
mMoniker to NULL.
Return Values
The method supports the standard return values E_OUTOFMEMORY and E_UNEXPECTED, a
s well as the following:
S_OK
Indicates success. This value is returned even if the moniker does not provide a
n enumerator (if ppenumMoniker equals NULL).
Remarks
IMoniker::Enum must supply an IEnumMoniker pointer to an enumerator that can enu
merate the components of a moniker. For example, the implementation of the IMoni
ker::Enum method for a generic composite moniker creates an enumerator that can
determine the individual monikers that make up the composite, while the IMoniker
::Enum method for a file moniker creates an enumerator that returns monikers rep
resenting each of the components in the path.
15.2.6.6.1 Notes to Callers
Call this method to examine the components that make up a composite moniker.
15.2.6.6.2 Notes to Implementers
If the new moniker class has no discernible internal structure, your implementat
ion of this method can simply return S_OK and set ppenumMoniker to NULL.
See Also
IEnumXXXX
15.2.6.7 IMoniker::GetDisplayName
Gets the display name , which is a user-readable representation of this moniker.
HRESULT GetDisplayName(
IBindCtx *pbc, //Pointer to bind context to be used
IMoniker *pmkToLeft, //Pointer to moniker to the left in the composit
e
LPOLESTR *ppszDisplayName //Indirect pointer to the display name
);
Parameters
pbc
[in] Pointer to the IBindCtx interface on the bind context to be used in this op
eration. The bind context caches objects bound during the binding process, conta
ins parameters that apply to all operations using the bind context, and provides
the means by which the moniker implementation should retrieve information about
its environment. For more information, see IBindCtx.
pmkToLeft
[in] If the moniker is part of a composite moniker, pointer to the moniker to th
e left of this moniker. This parameter is primarily used by moniker implementers
to enable cooperation between the various components of a composite moniker. Mo
niker clients should pass NULL.
ppszDisplayName
[out] When successful, indirect pointer to a zero-terminated wide character stri
ng (two bytes per character) containing the display name of this moniker. The im
plementation must use IMalloc::Alloc to allocate the string returned in ppszDisp
layName, and the caller is responsible for calling IMalloc::Free to free it. Bot
h the caller and and the one called use the COM task allocator returned by CoGet
Malloc. If an error occurs, ppszDisplayName should be set to NULL.
Return Values
The method supports the standard return value E_OUTOFMEMORY
, as well as the following:
S_OK
The display name was successfully supplied.
MK_E_EXCEEDEDDEADLINE
The binding operation could not be completed within the time limit specified by
the bind context s BIND_OPTS structure.
E_NOTIMPL
There is no display name.
Remarks
IMoniker::GetDisplayName provides a string that is a displayable representation
of the moniker. A display name is not a complete representation of a moniker s int
ernal state; it is simply a form that can be read by users. As a result, it is p
ossible (though rare) for two different monikers to have the same display name.
While there is no guarantee that the display name of a moniker can be parsed bac
k into that moniker when calling the MkParseDisplayName function with it, failur
e to do so is rare.
As examples, the file moniker implementation of this method supplies the path th
e moniker represents, and an item moniker s display name is the string identifying
the item that is contained in the moniker.
15.2.6.7.1 Notes to Callers
It is possible that retrieving a moniker s display name may be an expensive operat
ion. For efficiency, you may want to cache the results of the first successful c
all to IMoniker::GetDisplayName, rather than making repeated calls.
15.2.6.7.2 Notes to Implementers
If you are writing a moniker class in which the display name does not change, si
mply cache the display name and supply the cached name when requested. If the di
splay name can change over time, getting the current display name might mean tha
t the moniker has to access the object s storage or bind to the object, either of
which can be expensive operations. If this is the case, your implementation of I
Moniker::GetDisplayName should return MK_E_EXCEEDEDDEADLINE if the name cannot b
e retrieved by the time specified in the bind context s BIND_OPTS structure.
A moniker that is intended to be part of a generic composite moniker should incl
ude any preceding delimiter (such as \ ) as part of its display name. For example,
the display name returned by an item moniker includes the delimiter specified wh
en it was created with the CreateItemMoniker function. The display name for a fi
le moniker does not include a delimiter because file monikers are always expecte
d to be the leftmost component of a composite.
See Also
IMoniker::ParseDisplayName, MkParseDisplayName
15.2.6.8 IMoniker::GetTimeOfLastChange
Provides a number representing the time the object identified by this moniker wa
s last changed. To be precise, the time returned is the earliest time COM can id
entify after which no change has occurred, so this time may be later than the ti
me of the last change to the object.
HRESULT GetTimeOfLastChange(
IBindCtx *pbc, //Bind context to be used
IMoniker *pmkToLeft, //Moniker to the left in the composite
FILETIME *pFileTime //Receives the time of last change
);
Parameters
pbc
[in] Pointer to the bind context to be used in this binding operation. The bind
context caches objects bound during the binding process, contains parameters tha
t apply to all operations using the bind context, and provides the means by whic
h the moniker implementation should retrieve information about its environment.
For more information, see IBindCtx.
pmkToLeft
[in] If the moniker is part of a composite moniker, pointer to the moniker to th
e left of this moniker. This parameter is primarily used by moniker Implementers
to enable cooperation between the various components of a composite moniker. Mo
niker clients should pass NULL.
pFileTime
[out] Pointer to the FILETIME structure receiving the time of last change. A val
ue of {0xFFFFFFFF,0x7FFFFFFF} indicates an error (for example, exceeded time lim
it, information not available).
Return Values
The method supports the standard return value E_UNEXPECTED, as well as the follo
wing:
S_OK
The method successfully returned a time.
MK_E_EXCEEDEDDEADLINE
The binding operation could not be completed within the time limit specified by
the bind context s BIND_OPTS structure.
MK_E_CONNECTMANUALLY
The operation was unable to connect to the storage for this object, possibly bec
ause a network device could not be connected to. For more information, see IMoni
ker::BindToObject.
MK_E_UNAVAILABLE
The time of the change is unavailable, and will not be available no matter what
deadline is used.
Remarks
15.2.6.8.1 Notes to Callers
If you re caching information returned by the object identified by the moniker, yo
u may want to ensure that your information is up-to-date. To do so, you would ca
ll IMoniker::GetTimeOfLastChange and compare the time returned with the time you
last retrieved information from the object.
For the monikers stored within linked objects, IMoniker::GetTimeOfLastChange is
primarily called by the default handler s implementation of IOleObject::IsUpToDate
. Container applications call IOleObject::IsUpToDate to determine if a linked ob
ject (or an embedded object containing linked objects) is up-to-date without act
ually binding to the object. This enables an application to determine quickly wh
ich linked objects require updating when the end user opens a document. The appl
ication can then bind only those linked objects that need updating (after prompt
ing the end user to determine whether they should be updated), instead of bindin
g every linked object in the document.
15.2.6.8.2 Notes to Implementers
It is important to perform this operation quickly because, for linked objects, t
his method is called when a user first opens a compound document. Consequently,
your IMoniker::GetTimeOfLastChange implementation should not bind to any objects
. In addition, your implementation should check the deadline parameter in the bi
nd context and return MK_E_EXCEEDEDDEADLINE if the operation cannot be completed
by the specified time.
There are a number of strategies you can use in your implementations:
· For many types of monikers, the pmkToLeft parameter identifies the container of
the object identified by this moniker. If this is true of your moniker class, yo
u can simply call IMoniker::GetTimeOfLastChange on the pmkToLeft parameter, sinc
e an object cannot have changed at a date later than its container.
· You can get a pointer to the Running Object Table (ROT) by calling IBindCtx::Get
RunningObjectTable on the pbc parameter, and then calling IRunningObjectTable::G
etTimeOfLastChange, since the ROT generally records the time of last change.
· You can get the storage associated with this moniker (or the pmkToLeft moniker)
and return the storage s last modification time with a call to IStorage::Stat.
See Also
IBindCtx::GetRunningObjectTable, IRunningObjectTable::GetTimeOfLastChange
15.2.6.9 IMoniker::Hash
Calculates a 32-bit integer using the internal state of the moniker.
HRESULT Hash(
DWORD *pdwHash //Pointer to hash value
);
Parameter
pdwHash
[out] Pointer to the hash value.
Return Value
S_OK
Successfully received a 32-bit integer hash value.
Remarks
15.2.6.9.1 Notes to Callers
You can use the value returned by this method to maintain a hash table of monike
rs. The hash value determines a hash bucket in the table. To search such a table
for a specified moniker, calculate its hash value and then compare it to the mo
nikers in that hash bucket using IMoniker::IsEqual.
15.2.6.9.2 Notes to Implementers
The hash value must be constant for the lifetime of the moniker. Two monikers th
at compare as equal using IMoniker::IsEqual must hash to the same value.
Marshaling and then unmarshaling a moniker should have no effect on its hash val
ue. Consequently, your implementation of IMoniker::Hash should rely only on the
internal state of the moniker, not on its memory address.
See Also
IMoniker::IsEqual
15.2.6.10 IMoniker::Inverse
Provides a moniker that, when composed to the right of this moniker or one of si
milar structure, will destroy it (the moniker will compose to nothing).
HRESULT Inverse(
IMoniker **ppmk //Indirect pointer to the inverse of the moniker
);
Parameter
ppmk
[out] When successful, indirect pointer to the IMoniker interface on a moniker t
hat is the inverse of this moniker. In this case, the implementation must call I
Unknown::AddRef on the parameter. It is the caller s responsibility to call IUnkno
wn::Release. If an error occurs, the implementation should set ppmk to NULL.
Return Values
The method supports the standard return value E_OUTOFMEMORY, as well as the foll
owing:
S_OK
The inverse moniker has been returned successfully.
MK_E_NOINVERSE
The moniker class does not have an inverse.
Remarks
The inverse of a moniker is analogous to the .. directory in MS-DOS file systems;
the .. directory acts as the inverse to any other directory name, because appendin
g .. to a directory name results in an empty path. In the same way, the inverse of
a moniker typically is also the inverse of all monikers in the same class. Howe
ver, it is not necessarily the inverse of a moniker of a different class.
The inverse of a composite moniker is a composite consisting of the inverses of
the components of the original moniker, arranged in reverse order. For example,
if the inverse of A is Inv( A ) and the composite of A, B, and C is Comp( A, B,
C ), then
Inv( Comp( A, B, C ) )
is equal to
Comp( Inv( C ), Inv( B ), Inv( A ) ).
Not all monikers have inverses. Most monikers that are themselves inverses, such
as anti-monikers, do not have inverses. Monikers that have no inverse cannot ha
ve relative monikers formed from inside the objects they identify to other objec
ts outside.
15.2.6.10.1 Notes to Callers
An object that is using a moniker to locate another object usually does not know
the class of the moniker it is using. To get the inverse of a moniker, you shou
ld always call IMoniker::Inverse rather than the CreateAntiMoniker function, bec
ause you cannot be certain that the moniker you re using considers an anti-moniker
to be its inverse.
The IMoniker::Inverse method is also called by the implementation of the IMonike
r::RelativePathTo method, to assist in constructing a relative moniker.
15.2.6.10.2 Notes to Implementers
If your monikers have no internal structure, you can call the CreateAntiMoniker
function in to get an anti-moniker in your implementation of IMoniker::Inverse.
In your implementation of IMoniker::ComposeWith, you need to check for the inver
se you supply in the implementation of IMoniker::Inverse.
See Also
CreateAntiMoniker, IMoniker::ComposeWith, IMoniker::RelativePathTo
15.2.6.11 IMoniker::IsEqual
Compares this moniker with a specified moniker and indicates whether they are id
entical.
HRESULT IsEqual(
IMoniker *pmkOtherMoniker //Pointer to moniker to be used for comparison
);
Parameter
pmkOtherMoniker
[in] Pointer to the IMoniker interface on the moniker to be used for comparison
with this one (the one from which this method is called).
Return Values
S_OK
The two monikers are identical.
S_FALSE
The two monikers are not identical.
Remarks
Previous implementations of the Running Object Table (ROT) called this method. T
he current implementation of the ROT uses the IROTData interface instead.
15.2.6.11.1 Notes to Callers
Call this method to determine if two monikers are identical or not. Note that th
e reduced form of a moniker is considered different from the unreduced form. You
should call the IMoniker::Reduce method before calling IMoniker::IsEqual, becau
se a reduced moniker is in its most specific form. IMoniker::IsEqual may return
S_FALSE on two monikers before they are reduced, and S_OK after they are reduced
.
15.2.6.11.2 Notes to Implementers
Your implementation should not reduce the current moniker before performing the
comparison. It is the caller s responsibility to call IMoniker::Reduce in order to
compare reduced monikers.
Note that two monikers that compare as equal must hash to the same value using I
Moniker::Hash.
See Also
IMoniker::Reduce, IMoniker::Hash, IROTData
15.2.6.12 IMoniker::IsRunning
Determines whether the object identified by this moniker is currently loaded and
running.
HRESULT IsRunning(
IBindCtx *pbc, //Pointer to bind context to be used
IMoniker *pmkToLeft, //Pointer to moniker to the left in the composit
e
IMoniker *pmkNewlyRunning //Pointer to moniker of a newly running object
);
Parameters
pbc
[in] Pointer to theIBindCtx interface on the bind context to be used in this bin
ding operation. The bind context caches objects bound during the binding process
, contains parameters that apply to all operations using the bind context, and p
rovides the means by which the moniker implementation should retrieve informatio
n about its environment. For more information, see IBindCtx.
pmkToLeft
[in] Pointer to theIMoniker interface on the moniker to the left of this moniker
if this moniker is part of a composite. This parameter is primarily used by mon
iker Implementers to enable cooperation between the various components of a comp
osite moniker; moniker clients can usually pass NULL.
pmkNewlyRunning
[in] Pointer to theIMoniker interface on the moniker most recently added to the
Running Object Table (ROT). This can be NULL. If non-NULL, the implementation ca
n return the results of calling IMoniker::IsEqual on the pmkNewlyRunning paramet
er, passing the current moniker. This parameter is intended to enable IMoniker::
IsRunning implementations that are more efficient than just searching the ROT, b
ut the implementation can choose to ignore pmkNewlyRunning without causing any h
arm.
Return Values
The method supports the standard return value E_UNEXPECTED, as well as the follo
wing:
S_OK
The moniker is running.
S_FALSE
The moniker is not running.
Remarks
15.2.6.12.1 Notes to Callers
If speed is important when you re requesting services from the object identified b
y the moniker, you may want those services only if the object is already running
(because loading an object into the running state may be time-consuming). In su
ch a situation, you d call IMoniker::IsRunning to determine if the object is runni
ng.
For the monikers stored within linked objects, IMoniker::IsRunning is primarily
called by the default handler s implementation of IOleLink::BindIfRunning.
15.2.6.12.2 Notes to Implementers
To get a pointer to the Running Object Table (ROT), your implementation should c
all IBindCtx::GetRunningObjectTable on the pbc parameter. Your implementation ca
n then call IRunningObjectTable::IsRunning to determine whether the object ident
ified by the moniker is running. Note that the object identified by the moniker
must have registered itself with the ROT when it first began running.
See Also
IBindCtx::GetRunningObjectTable, IRunningObjectTable::IsRunning
15.2.6.13 IMoniker::IsSystemMoniker
Indicates whether this moniker is of one of the system-supplied moniker classes.
HRESULT IsSystemMoniker(
DWORD *pdwMksys //Pointer to value from MKSYS enumeration
);
Parameter
pdwMksys
[out] Pointer to an integer that is one of the values from the MKSYS enumeration
, and refers to one of the COM moniker classes. This parameter cannot be NULL.
Return Values
S_OK
The moniker is a system moniker.
S_FALSE
The moniker is not a system moniker.
Remarks
15.2.6.13.1 Notes to Callers
New values of the MKSYS enumeration may be defined in the future; therefore you
should explicitly test for each value you are interested in.
15.2.6.13.2 Notes to Implementers
Your implementation of this method must return MKSYS_NONE. You cannot use this f
unction to identify your own monikers (for example, in your implementation of IM
oniker::ComposeWith). Instead, you should use your moniker s implementation of IPe
rsist::GetClassID or use IUnknown::QueryInterface to test for your own private i
nterface.
See Also
IPersist::GetClassID, MKSYS
15.2.6.14 IMoniker::ParseDisplayName
Reads as many characters of the specified display name as it understands and bui
lds a moniker corresponding to the portion read; this procedure is known as parsi
ng the display name.
HRESULT ParseDisplayName(
IBindCtx *pbc, //Pointer to bind context to be used
IMoniker *pmkToLeft, //Pointer to moniker to the left in the composit
e
LPOLESTR pszDisplayName, //Pointer to display name
ULONG *pchEaten, //Pointer to number of characters consumed
IMoniker **ppmkOut //Indirect pointer to moniker built from display name
);
Parameters
pbc
[in] Pointer to the IBindCtx interface on the bind context to be used in this bi
nding operation. The bind context caches objects bound during the binding proces
s, contains parameters that apply to all operations using the bind context, and
provides the means by which the moniker implementation should retrieve informati
on about its environment. For more information, see IBindCtx.
pmkToLeft
[in] Pointer to the IMoniker interface on the moniker that has been built out of
the display name up to this point.
pszDisplayName
[in] Pointer to a zero-terminated string containing the remaining display name t
o be parsed. For Win32 applications, the LPOLESTR type indicates a wide characte
r string (two bytes per character); otherwise, the string has one byte per chara
cter.
pchEaten
[out] Pointer to the number of characters in pszDisplayName that were consumed i
n this step.
ppmkOut
[out] When successful, indirect pointer to the IMoniker interface on the moniker
that was built from pszDisplayName. In this case, the implementation must call
IUnknown::AddRef on the parameter; it is the caller s responsibility to call IUnkn
own::Release. If an error occurs, the implementation sets ppmkOut to NULL.
Return Values
The method supports the standard return values E_OUTOFMEMORY and E_UNEXPECTED, a
s well as the following:
S_OK
The parsing operation was completed successfully.
MK_E_SYNTAX
An error in the syntax of the input components (pmkToLeft, this moniker, and psz
DisplayName). For example, a file moniker returns this error if pmkToLeft is non
-NULL, and an item moniker returns it if pmkToLeft is NULL.
IMoniker::BindToObject errors
Parsing display names may cause binding. Thus, any error associated with this fu
nction may be returned.
Remarks
15.2.6.14.1 Notes to Callers
Moniker clients do not typically call IMoniker::ParseDisplayName directly. Inste
ad, they call the MkParseDisplayName function when they want to convert a displa
y name into a moniker (for example, in implementing the Links dialog box for a c
ontainer application, or for implementing a macro language that supports referen
ces to objects outside the document). That function first parses the initial por
tion of the display name itself.
[Need to find out how]
It then calls IMoniker::ParseDisplayName on the moniker it has just created, pas
sing the remainder of the display name and getting a new moniker in return; this
step is repeated until the entire display name has been parsed.
15.2.6.14.2 Notes to Implementers
Your implementation may be able to perform this parsing by itself if your monike
r class is designed to designate only certain kinds of objects. Otherwise, you m
ust get an IParseDisplayName interface pointer for the object identified by the
moniker-so-far (i.e., the composition of pmkToLeft and this moniker) and then re
turn the results of calling IParseDisplayName::ParseDisplayName.
There are different strategies for getting an IParseDisplayName pointer:
· You can try to get the object s CLSID (by calling IPersist::GetClassID on the obje
ct), and then call the CoGetClassObject function, requesting the IParseDisplayNa
me interface on the class factory associated with that CLSID.
· You can try to bind to the object itself to get an IParseDisplayName pointer.
· You can try binding to the object identified by pmkToLeft to get an IOleItemCont
ainer pointer, and then call IOleItemContainer::GetObject to get an IParseDispla
yName pointer for the item.
Any objects that are bound should be registered with the bind context (see IBind
Ctx::RegisterObjectBound) to ensure that they remain running for the duration of
the parsing operation.
See Also
IParseDisplayName, MkParseDisplayName
15.2.6.15 IMoniker::Reduce
Returns a reduced moniker; that is, another moniker that refers to the same obje
ct as this moniker but can be bound with equal or greater efficiency.
HRESULT Reduce(
IBindCtx *pbc, //Pointer to bind context to be used
DWORD dwReduceHowFar, //How much reduction should be done
IMoniker **ppmkToLeft, //Indirect pointer to moniker to the left in the
composite
IMoniker **ppmkReduced //Indirect pointer to the reduced moniker
);
Parameters
pbc to the IBindCtx interface on the bind context to be used in this binding ope
ration. The bind context caches objects bound during the binding process, contai
ns parameters that apply to all operations using the bind context, and provides
the means by which the moniker implementation should retrieve information about
its environment. For more information, see IBindCtx.
dwReduceHowFar
[in] DWORD that specifies how far this moniker should be reduced. This parameter
must be one of the values from the MKRREDUCE enumeration.
ppmkToLeft
[in, out] On entry, indirect pointer to the moniker to the left of this moniker,
if this moniker is part of a composite. This parameter is primarily used by mon
iker Implementers to enable cooperation between the various components of a comp
osite moniker; moniker clients can usually pass NULL.
On return, ppmkToLeft is usually set to NULL, indicating no change in the origin
al moniker to the left. In rare situations ppmkToLeft indicates a moniker, indic
ating that the previous moniker to the left should be disregarded and the monike
r returned through ppmkToLeft is the replacement. In such a situation, the imple
mentation must call IUnknown::Release on the passed-in pointer and call IUnknown
::AddRef on the returned moniker; the caller must release it later. If an error
occurs, the implementation can either leave the parameter unchanged or set it to
NULL.
ppmkReduced
[out] Indirect pointer to the IMoniker interface on the reduced form of this mon
iker, which can be NULL if an error occurs or if this moniker is reduced to noth
ing. If this moniker cannot be reduced, ppmkReduced is simply set to this monike
r and the return value is MK_S_REDUCED_TO_SELF. If ppmkReduced is non-NULL, the
implementation must call IUnknown::AddRef on the parameter; it is the caller s res
ponsibility to call IUnknown::Release. (This is true even if ppmkReduced is set
to this moniker.)
Return Values
The method supports the standard return values E_UNEXPECTED and E_OUTOFMEMORY, a
s well as the following:
S_OK
This moniker was reduced.
MK_S_REDUCED_TO_SELF
This moniker could not be reduced any further, so ppmkReduced indicates this mon
iker.
MK_E_EXCEEDEDDEADLINE
The operation could not be completed within the time limit specified by the bind
context s BIND_OPTS structure.
Remarks
IMoniker::Reduce is intended for the following uses:
· It enables the construction of user-defined macros or aliases as new kinds of mo
niker classes. When reduced, the moniker to which the macro evaluates is returne
d.
· It enables the construction of a kind of moniker that tracks data as it moves ab
out. When reduced, the moniker of the data in its current location is returned.
· On file systems that support an identifier-based method of accessing files which
is independent of file names; a file moniker could be reduced to a moniker whic
h contains one of these identifiers.
The intent of the MKRREDUCE flags passed in the dwReduceHowFar parameter is to p
rovide the ability to programmatically reduce a moniker to a form whose display
name is recognizable to the user. For example, paths in the file system, bookmar
ks in word-processing documents, and range names in spreadsheets are all recogni
zable to users. In contrast, a macro or an alias encapsulated in a moniker are n
ot recognizable to users.
15.2.6.15.1 Notes to Callers
The scenarios described above are not currently implemented by the system-suppli
ed moniker classes.
You should call IMoniker::Reduce before comparing two monikers using the IMonike
r::IsEqual method, because a reduced moniker is in its most specific form. IMoni
ker::IsEqual may return S_FALSE on two monikers before they are reduced and retu
rn S_OK after they are reduced.
15.2.6.15.2 Notes to Implementers
If the current moniker can be reduced, your implementation must not reduce the m
oniker in-place. Instead, it must return a new moniker that represents the reduc
ed state of the current one. This way, the caller still has the option of using
the non-reduced moniker (for example, enumerating its components). Your implemen
tation should reduce the moniker at least as far as is requested.
See Also
IMoniker::IsEqual, MKRREDUCE
15.2.6.16 IMoniker::RelativePathTo
Supplies a moniker that, when composed onto the end of this moniker (or one with
a similar structure), yields the specified moniker.
HRESULT RelativePathTo(
IMoniker *pmkOther, //Pointer to moniker to which a relative path should be
taken
IMoniker **ppmkRelPath //Indirect pointer to the relative moniker
);
Parameters
pmkOther
[in] Pointer to the IMoniker interface on the moniker to which a relative path s
hould be taken.
ppmkRelPath
[out] Iindirect pointer to the IMoniker interface on the relative moniker. When
successful, the implementation must call IUnknown::AddRef on the parameter; it i
s the caller s responsibility to call IUnknown::Release. If an error occurs, the i
mplementation sets ppmkRelPath to NULL.
Return Values
The method supports the standard return values E_OUTOFMEMORY and
E_UNEXPECTED, as well as the following:
S_OK
A meaningful relative path has been returned.
MK_S_HIM
No common prefix is shared by the two monikers and the moniker returned in ppmkR
elPath is pmkOther.
MK_E_NOTBINDABLE
This moniker is a relative moniker, such as an item moniker. This moniker must b
e composed with the moniker of its container before a relative path can be deter
mined.
Remarks
A relative moniker is analogous to a relative path (such as ..\backup ). For exampl
e, suppose you have one moniker that represents the path c:\projects\secret\art\p
ict1.bmp and another moniker that represents the path c:\projects\secret\docs\chap
1.txt. Calling IMoniker::RelativePathTo on the first moniker, passing the second
one as the pmkOther parameter, would create a relative moniker representing the
path ..\docs\chap1.txt.
15.2.6.16.1 Notes to Callers
Moniker clients typically do not need to call IMoniker::RelativePathTo. This met
hod is primarily called by the default handler for linked objects. Linked object
s contain both an absolute and a relative moniker to identify the link source (t
his enables link tracking if the user moves a directory tree containing both the
container and source files). The default handler calls this method to create a
relative moniker from the container document to the link source (that is, it cal
ls IMoniker::RelativePathTo on the moniker identifying the container document, p
assing the moniker identifying the link source as the pmkOther parameter).
If you do call IMoniker::RelativePathTo, call it only on absolute monikers; for
example, a file moniker or a composite moniker whose leftmost component is a fil
e moniker, where the file moniker represents an absolute path. Do not call this
method on relative monikers.
15.2.6.16.2 Notes to Implementers
Your implementation of IMoniker::RelativePathTo should first determine whether p
mkOther is a moniker of a class that you recognize and for which you can provide
special handling (for example, if it is of the same class as this moniker). If
so, your implementation should determine the relative path. Otherwise, it should
pass both monikers in a call to the MonikerRelativePathTo function, which corre
ctly handles the generic case.
The first step in determining a relative path is determining the common prefix o
f this moniker and pmkOther. The next step is to break this moniker and pmkOther
into two parts each, say (P, myTail) and (P, otherTail) respectively, where P i
s the common prefix. The correct relative path is then the inverse of myTail com
posed with otherTail:
Comp( Inv( myTail ), otherTail )
Where Comp() represents the composition operation and Inv() represents the inver
se operation.
Note that for certain types of monikers, you cannot use your IMoniker::Inverse m
ethod to construct the inverse of myTail. For example, a file moniker returns an
anti-moniker as an inverse, while its IMoniker::RelativePathTo method must use
one or more file monikers that each represent the path .. to construct the inverse
of myTail.
See Also
IMoniker::Inverse, IMoniker::CommonPrefixWith, MonikerRelativePathTo
15.2.13.2 IOleItemContainer::GetObject
Returns a pointer to the object identified by the specified name.
HRESULT GetObject(
LPOLESTR pszItem, //Pointer to name of the object requested
DWORD dwSpeedNeeded, //Speed requirements on binding
IBindCtx *pbc, //Pointer to bind context object to be used
REFIID riid, //Reference to the identifier of the interface pointer d
esired
void **ppvObject //Indirect pointer to interface
);
Parameters
pszItem
[in] Pointer to a zero-terminated string containing the container s name for the r
equested object. For Win32 applications, the LPOLESTR type indicates a wide char
acter string (two bytes per character); otherwise, the string has one byte per c
haracter.
dwSpeedNeeded
[in] Indicates approximately how long the caller will wait to get the object. Th
e legal values for dwSpeedNeeded are taken from the enumeration BINDSPEED. For i
nformation on the BINDSPEED enumeration, see the Data Structures section.
pbc
[in] Pointer to the IBindCtx interface on the bind context object to be used in
this binding operation. The bind context caches objects bound during the binding
process, contains parameters that apply to all operations using the bind contex
t, and provides the means by which the binding implementation should retrieve in
formation about its environment. For more information, see IBindCtx.
riid
[in] Reference to the identifier of the interface pointer requested.
ppvObject
[out] When successful, indirect pointer to the location of the interface specifi
ed in riid on the object named by pszItem. In this case, the implementation must
call IUnknown::AddRef on the parameter; it is the caller s responsibility to call
IUnknown::Release. If an error occurs, the implementation sets ppvObject to NUL
L.
Return Values
This method supports the standard return value E_OUTOFMEMORY, as well as the fol
lowing:
S_OK
The specified object was successfully returned.
MK_E_EXCEEDEDDEADLINE
The binding operation could not be completed within the time limit specified by
the bind context s BIND_OPTS structure, or with the speed indicated by the dwSpeed
Needed parameter.
MK_E_NOOBJECT
The parameter pszItem does not identify an object in this container.
E_NOINTERFACE
The requested interface was not available.
Remarks
The item moniker implementation of IMoniker::BindToObject calls this method, pas
sing the name stored within the item moniker as the pszItem parameter.
15.2.13.2.1.1.1 Notes to Implementers
Your implementation of IOleItemContainer::GetObject should first determine wheth
er pszItem is a valid name for one of the container s objects. If not, you should
return MK_E_NOOBJECT.
If pszItem names an embedded or linked object, your implementation must check th
e value of the dwSpeedNeeded parameter. If the value is BINDSPEED_IMMEDIATE and
the object is not yet loaded, you should return MK_E_EXCEEDEDDEADLINE. If the ob
ject is loaded, your implementation should determine whether the object is runni
ng (for example, by calling the OleIsRunning function). If it is not running and
the dwSpeedNeeded value is BINDSPEED_MODERATE, your implementation should retur
n MK_E_EXCEEDEDDEADLINE. If the object is not running and dwSpeedNeeded is BINDS
PEED_INDEFINITE, your implementation should call the OleRun function to put the
object in the running state. Then it can query the object for the requested inte
rface. Note that it is important the object be running before you query for the
interface.
If pszItem names a pseudo-object, your implementation can ignore the dwSpeedNeed
ed parameter because a pseudo-object is running whenever its container is runnin
g. In this case, your implementation can simply query for the requested interfac
e.
If you want more specific information about the time limit than is given by dwSp
eedNeeded, you can call IBindCtx::GetBindOptions on the pbc parameter to get the
actual deadline parameter.
See Also
IMoniker::BindToObject, IBindCtx::GetBindOptions
15.2.13.3 IOleItemContainer::GetObjectStorage
Returns a pointer to the storage for the object identified by the specified name
.
HRESULT GetObjectStorage(
LPOLESTR pszItem, //Name of the string containing the name of object whose
storage is requested
IBindCtx *pbc, //Pointer to bind context to be used
REFIID riid, //Reference to the identifier of the interface pointer d
esired
void **ppvStorage //Indirect pointer to object s storage
);
Parameters
pszItem
[in] Pointer to a zero-terminated string containing the compound document s name f
or the object whose storage is requested. For Win32 applications, the LPOLESTR t
ype indicates a wide character string (two bytes per character); otherwise, the
string has one byte per character.
pbc
[in] Pointer to the IBindCtx interface on the bind context to be used in this bi
nding operation. The bind context caches objects bound during the binding proces
s, contains parameters that apply to all operations using the bind context, and
provides the means by which the binding implementation should retrieve informati
on about its environment. For more information, see IBindCtx.
riid
[in] Reference to the identifier of the interface to be used to communicate with
the object, usually IStorage.
ppvStorage
[out] When successful, indirect pointer to the location of the interface specifi
ed in riid, on the storage for the object named by pszItem. In this case, the im
plementation must call IUnknown::AddRef on the parameter; it is the caller s respo
nsibility to call IUnknown::Release. If an error occurs, ppvStorage is set to NU
LL.
Return Values
This method supports the standard return value E_OUTOFMEMORY, as well as the fol
lowing:
S_OK
The storage of the specified object was successfully returned.
MK_E_NOOBJECT
The parameter pszItem does not identify a object in this container.
MK_E_NOSTORAGE
The object does not have its own independent storage.
E_NOINTERFACE
The requested interface is not available.
Remarks
The item moniker implementation of IMoniker::BindToStorage calls this method.
15.2.13.3.1.1.1 Notes to Implementers
If pszItem designates a pseudo-object, your implementation should return MK_E_NO
STORAGE, because pseudo-objects do not have their own independent storage. If ps
zItem designates an embedded object, or a portion of the document that has its o
wn storage, your implementation should return the specified interface pointer on
the appropriate storage object.
See Also
IMoniker - Item Moniker Implementation
15.2.13.4 IOleItemContainer::IsRunning
Indicates whether the object identified by the specified name is running.
HRESULT IsRunning(
LPOLESTR pszItem //Pointer to string containing name of object
);
Parameter
pszItem
[in] Pointer to a zero-terminated wide character string (two bytes per character
) containing the container s name for the object.
Return Values
S_OK
The specified object is running.
S_FALSE
The object is not running.
MK_E_NOOBJECT
The parameter pszItem does not identify an object in this container.
Remarks
The item moniker implementation of IMoniker::IsRunning calls this method.
15.2.13.4.1.1.1 Notes to Implementers
Your implementation of IOleItemContainer::IsRunning should first determine wheth
er pszItem identifies one of the container s objects. If it does not, your impleme
ntation should return MK_E_NOOBJECT. If the object is not loaded, your implement
ation should return S_FALSE. If it is loaded, your implementation can call the O
leIsRunning function to determine whether it is running.
If pszItem names a pseudo-object, your implementation can simply return S_OK bec
ause a pseudo-object is running whenever its container is running.
See Also
IMoniker::IsRunning
15.2.14 IParseDisplayName
The IParseDisplayName interface parses a displayable name string to convert it i
nto a moniker for custom moniker implementations. Display name parsing is necess
ary when the end user inputs a string to identify a component, as in the followi
ng situations:
· A compound document application that supports linked components typically suppor
ts the Edit:Links... dialog box. Through this dialog box, the end user can enter
a display name to specify a new link source for a specified linked component. T
he compound document needs to have this input string converted into a moniker.
· A script language such as the macro language of a spreadsheet can allow textual
references to a component. The language s interpreter needs to have such a referen
ce converted into a moniker in order to execute the macro.
15.2.14.1.1 When to Implement
Compound document applications that support links to embedded components or to p
seudo-objects within their documents must provide an implementation of the IOleI
temContainer interface, which is derived indirectly from IParseDisplayName. In e
ffect, such a compound document is providing a namespace for identifying its int
ernal components; and its IOleItemContainer implementation (which includes the I
ParseDisplayName implementation) is the interface through which another applicat
ion can access this namespace. Alternatively, the compound document application
can implement IParseDisplayName as part of its class object, which is accessible
through the CoGetClassObject function.
Monikers that support their own namespace with custom requirements for parsing n
ames also implement this interface.
15.2.14.1.2 When to Use
If you are implementing your own moniker class, you might need to use this inter
face from your implementation of IMoniker::ParseDisplayName. If you call the MkP
arseDisplayName or the MkParseDisplayNameEx functions, you are indirectly using
IParseDisplayName. These two functions call IParseDisplayName to parse display n
ames for objects that provide custom moniker implementations.
Methods in VTable Order
IUnknown Methods Description
QueryInterface Returns pointers to supported interfaces.
AddRef Increments reference count.
Release Decrements reference count.
IParseDisplayName Method Description
ParseDisplayName Parses the display name returning a moniker correspondin
g to it.
See Also
IMoniker::ParseDisplayName, IOleItemContainer, MkParseDisplayName, MkParseDispla
yNameEx
15.2.14.2 IParseDisplayName::ParseDisplayName
Parses the display name to extract a component of the string that it can convert
into a moniker, using the maximum number of characters from the left side of th
e string.
HRESULT ParseDisplayName(
IBindCtx *pbc, //Pointer to bind context
LPOLESTR pszDisplayName, //Pointer to string containing display name
ULONG *pchEaten, //Pointer to length, in characters, of display name
IMoniker **ppmkOut //Indirect pointer to moniker that results
);
Parameters
pbc
[in] Pointer to the bind context to be used in this binding operation.
pszDisplayName
[in] Pointer to a zero-terminated string containing the display name to be parse
d. For Win32 applications, the LPOLESTR type indicates a wide character string (
two bytes per character); otherwise, the string has one byte per character.
pchEaten
[out Pointer to the number of characters in the display name that correspond to
the ppmkOut moniker.
ppmkOut
[out] Indirect pointer to the resulting moniker. If an error occurs, the impleme
ntation sets *ppmkOut to NULL. If *ppmkOut is non-NULL, the implementation must
call (*ppmkOut)->IUnknown::AddRef; so it is the caller s responsibility to call (*
ppmkOut)->IUnknown::Release.
Return Values
This method supports the standard return values E_OUTOFMEMORY and E_UNEXPECTED,
as well as the following:
S_OK
The parse operation was successful.
MK_E_SYNTAX
Syntax error in the display name. Parsing failed because szDisplayName could onl
y be partially resolved into a moniker. In this case, *pchEaten has the number o
f characters that were successfully parsed into a moniker prefix. The parameter
ppmkOut should be NULL.
MK_E_NOOBJECT
The display name does not identify a component in this namespace.
E_INVALIDARG
One or more parameters are invalid.
Remarks
In general, the maximum prefix of szDisplayName that is syntactically valid and
that represents an object should be consumed by this method and converted to a m
oniker.
Typically, this method is called by MkParseDisplayName[Ex]. In the initial step
of the parsing operation, the MkParseDisplayName[Ex] function can retrieve the I
ParseDisplayName interface directly from an instance of a class identified with
either the @ProgID or ProgID notation. Subsequent parsing steps can query for the in
terface on an intermediate object.
The main loop of MkParseDisplayName[Ex] finds the next moniker piece by calling
the equivalent method in the IMoniker interface, that is, IMoniker::ParseDisplay
Name, on the moniker that it currently holds. In this call to IMoniker::ParseDis
playName, the MkParseDisplayName[Ex] function passes NULL in the pmkToLeft param
eter. If the moniker currently held by MkParseDisplayName[Ex] is a generic compo
site, the call to IMoniker::ParseDisplayName is forwarded by that composite onto
its last piece, passing the prefix of the composite to the left of the piece in
pmkToLeft.
Some moniker classes will be able to handle this parsing internally to themselve
s since they are designed to designate only certain kinds of objects. Others wil
l need to bind to the object that they designate to accomplish the parsing proce
ss. As is usual, these objects should not be released by IMoniker::ParseDisplayN
ame but instead should be transferred to the bind context via IBindCtx::Register
ObjectBound or IBindCtx::GetRunningObjectTable followed by IRunningObjectTable::
Register for release at a later time.
See Also
MkParseDisplayName, MkParseDisplayNameEx IMoniker::ParseDisplayName
15.2.15 IROTData
The IROTData interface is implemented by monikers to enable the Running Object T
able (ROT) to compare monikers against each other.
The ROT uses the IROTData interface to test whether two monikers are equal. The
ROT must do this when, for example, it checks whether a specified moniker is reg
istered as running.
15.2.15.1.1 When to Implement
You must implement IROTData if you are writing your own moniker class (that is,
writing your own implementation of the IMoniker interface), and if your monikers
are meant to be registered in the ROT.
15.2.15.1.2 When to Use
You typically do not need to use this interface. This interface is used by the s
ystem s implementation of the ROT.
Methods in Vtable Order
IUnknown Methods Description
QueryInterface Returns pointers to supported interfaces.
AddRef Increments reference count.
Release Decrements reference count.
IROTData Method Description
GetComparisonData Retrieve data to allow moniker to be compared with anoth
er.
See Also
IMoniker, IRunningObjectTable
15.2.15.2 IROTData::GetComparisonData
Retrieves data from a moniker that can be used to test the moniker for equality
against another moniker.
HRESULT GetComparisonData(
PVOID *ppvData, //Indirect pointer to a buffer that receives the compari
son data
ULONG cbMax, //Length of buffer
PULONG pcbData //Pointer to the length of the comparison data
);
Parameters
ppvData
[out] Indirect pointer to a buffer that receives the comparison data.
cbMax
[in] Length of the buffer specified in ppvData.
pcbData
[out] Pointer to the length of the comparison data.
Return Values
This method supports the standard return value E_OUTOFMEMORY, as well as the fol
lowing:
S_OK
The comparison data was successfully returned.
Remarks
The IROTData::GetComparisonData method is primarily called by the Running Object
Table (ROT). The comparison data returned by the method is tested for binary eq
uality against the comparison data returned by another moniker. The pcbData para
meter enables the ROT to locate the end of the data returned.
15.2.15.2.1.1.1 Notes to Implementers
The comparison data that you return must uniquely identify the moniker, while st
ill being as short as possible. The comparison data should include information a
bout the internal state of the moniker, as well as the moniker s CLSID. For exampl
e, the comparison data for a file moniker would include the path name stored wit
hin the moniker, as well as the CLSID of the file moniker implementation. This m
akes it possible to distinguish two monikers that happen to store similar state
information but are instances of different moniker classes.
The comparison data for a moniker cannot exceed 2048 bytes in length. For compos
ite monikers, the total length of the comparison data for all of its components
cannot exceed 2048 bytes; consequently, if your moniker can be a component withi
n a composite moniker, the comparison data you return must be significantly less
than 2048 bytes.
If your comparison data is longer than the value specified by the cbMax paramete
r, you must return an error. Note that when IROTData::GetComparisionData is call
ed on the components of a composite moniker, the value of cbMax becomes smaller
for each moniker in sequence.
See Also
IMoniker, IRunningObjectTable
15.2.16 IRunningObjectTable
The IRunningObjectTable interface manages access to the Running Object Table (RO
T), a globally accessible look-up table on each workstation. A workstation s ROT k
eeps track of those objects that can be identified by a moniker and that are cur
rently running on the workstation. When a client tries to bind a moniker to an o
bject, the moniker checks the ROT to see if the object is already running; this
allows the moniker to bind to the current instance instead of loading a new one.
The ROT contains entries of the form:
(pmkObjectName, pUnkObject)
The pmkObjectName element is a pointer to the moniker that identifies the runnin
g object. The pUnkObject element is a pointer to the running object itself. Duri
ng the binding process, monikers consult the pmkObjectName entries in the Runnin
g Object Table to see if an object is already running.
Objects that can be named by monikers must be registered with the ROT when they
are loaded and their registration must be revoked when they are no longer runnin
g.
15.2.16.1.1 When to Implement
You do not need to implement this interface. The system provides an implementati
on of the Running Object Table that is suitable for all situations.
15.2.16.1.2 When to Use
You typically use the ROT if you re a moniker provider (that is, you hand out moni
kers identifying your objects to make them accessible to others) or if you re writ
ing your own moniker class (that is, implementing the IMoniker interface).
If you are a moniker provider, you register your objects with the ROT when they
begin running and revoke their registrations when they are no longer running. Th
is enables the monikers that you hand out to be bound to running objects. You sh
ould also use the ROT to record the object s last modification time. You can get a
n IRunningObjectTable interface pointer to the local ROT by calling the GetRunni
ngObjectTable function.
The most common type of moniker provider is a compound-document link source. Thi
s includes server applications that support linking to their documents (or porti
ons of a document) and container applications that support linking to embeddings
within their documents. Server applications that do not support linking can als
o use the ROT to cooperate with container applications that support linking to e
mbeddings.
If you are writing your own moniker class, you use the ROT to determine whether
a object is running and to retrieve the object s last modification time. You can g
et an IRunningObjectTable interface pointer to the local ROT by calling the IBin
dCtx::GetRunningObjectTable method on the bind context for the current binding o
peration. Moniker implementations should always use the bind context to acquire
a pointer to the ROT; this allows future implementations of IBindCtx to modify b
inding behavior. Note that you must also implement the IROTData interface on you
r moniker class in order to allow your monikers to be registered with the ROT.
Methods in VTable Order
IUnknown Methods Description
QueryInterface Returns pointers to supported interfaces.
AddRef Increments reference count.
Release Decrements reference count.
IRunningObjectTable Methods Description
Register Registers an object with the ROT.
Revoke Revokes an object s registration with the ROT.
IsRunning Checks whether an object is running.
GetObject Returns a pointer to an object given its moniker.
NoteChangeTime Notifies the ROT that an object has changed.
GetTimeOfLastChange Returns the time an object was last changed.
EnumRunning Returns an enumerator for the ROT.
See Also
IBindCtx::GetRunningObjectTable, IROTData, GetRunningObjectTable
15.2.16.2 IRunningObjectTable::EnumRunning
Creates and returns a pointer to an enumerator that can list the monikers of all
the objects currently registered in the Running Object Table (ROT).
HRESULT EnumRunning(
IEnumMoniker **ppenumMoniker //Indirect pointer to the enumerator for
ROT
);
Parameter
ppenumMoniker
[out] When successful, indirect pointer to the IEnumMoniker interface on the new
enumerator. In this case, the implementation calls IUnknown::AddRef on the para
meter; it is the caller s responsibility to call IUnknown::Release. If an error oc
curs; the implementation sets ppenumMoniker to NULL.
Return Values
This method supports the standard return value E_OUTOFMEMORY, as well as the fol
lowing:
S_OK
An enumerator was successfully returned.
Remarks
IRunningObjectTable::EnumRunning must create and return a pointer to an IEnumMon
iker interface on an enumerator object. The standard enumerator methods can then
be called to enumerate the monikers currently registered in the registry. The e
numerator cannot be used to enumerate monikers that are registered in the ROT af
ter the enumerator has been created.
The EnumRunning method is intended primarily for the use by the system in implem
enting the Alert Object Table. Note that COM 2 does not include an implementatio
n of the Alert Object Table.
See Also
IEnumXXXX, IEnumMoniker
15.2.16.3 IRunningObjectTable::GetObject
Determines whether the object identified by the specified moniker is running, an
d if it is, retrieves a pointer to that object. This method looks for the monike
r in the Running Object Table (ROT), and retrieves the pointer registered there.
HRESULT GetObject(
IMoniker *pmkObjectName, //Pointer to the moniker on the object
IUnknown **ppunkObject //Indirect pointer to the object
);
Parameters
pmkObjectName
[in] Pointer to the moniker to search for in the Running Object Table.
ppunkObject
[out] When successful. indirect pointer to the IUnknown interface on the running
object. In this case, the implementation calls IUnknown::AddRef on the paramete
r; it is the caller s responsibility to call IUnknown::Release. If the object is n
ot running or if an error occurs, the implementation sets ppunkObject to NULL.
Return Values
S_OK
Indicates that pmkObjectName was found in the ROT and a pointer was returned.
S_FALSE
There is no entry for pmkObjectName in the ROT, or that the object it identifies
is no longer running (in which case, the entry is revoked).
Remarks
This method checks the ROT for the moniker specified by pmkObjectName. If that m
oniker had previously been registered with a call to IRunningObjectTable::Regist
er, this method returns the pointer that was registered at that time.
15.2.16.3.1.1.1 Notes to Callers
Generally, you call the IRunningObjectTable::GetObject method only if you are wr
iting your own moniker class (that is, implementing the IMoniker interface). You
typically call this method from your implementation of IMoniker::BindToObject.
However, note that not all implementations of IMoniker::BindToObject need to cal
l this method. If you expect your moniker to have a prefix (indicated by a non-N
ULL pmkToLeft parameter to IMoniker::BindToObject), you should not check the ROT
. The reason for this is that only complete monikers are registered with the ROT
, and if your moniker has a prefix, your moniker is part of a composite and thus
not complete. Instead, your moniker should request services from the object ide
ntified by the prefix (for example, the container of the object identified by yo
ur moniker).
See Also
IMoniker::BindToObject
15.2.16.4 IRunningObjectTable::GetTimeOfLastChange
Returns the time that an object was last modified. The object must have previous
ly been registered with the Running Object Table (ROT). This method looks for th
e last change time recorded in the ROT.
HRESULT GetTimeOfLastChange(
IMoniker *pmkObjectName, //Pointer to moniker on the object whose status
is desired
FILETIME *pfiletime //Pointer to structure that receives object s last change
time
);
Parameters
pmkObjectName
[in] Pointer to the IMoniker interface on the moniker to search for in the ROT.
pfiletime
[out] Pointer to a FILETIME structure that receives the object s last change time.
Return Values
S_OK
The last change time was successfully retrieved.
S_FALSE
There is no entry for pmkObjectName in the ROT, or that the object it identifies
is no longer running (in which case, the entry is revoked).
Remarks
This method returns the change time that was last reported for this object by a
call to IRunningObjectTable::NoteChangeTime. If IRunningObjectTable::NoteChangeT
ime has not been called previously, the method returns the time that was recorde
d when the object was registered.
This method is provided to enable checking whether a connection between two obje
cts (represented by one object holding a moniker that identifies the other) is u
p-to-date. For example, if one object is holding cached information about the ot
her object, this method can be used to check whether the object has been modifie
d since the cache was last updated. See IMoniker::GetTimeOfLastChange.
15.2.16.4.1.1.1 Notes to Callers
Generally, you call IRunningObjectTable::GetTimeOfLastChange only if you are wri
ting your own moniker class (that is, implementing the IMoniker interface). You
typically call this method from your implementation of IMoniker::GetTimeOfLastCh
ange. However, you should do so only if the pmkToLeft parameter of IMoniker::Get
TimeOfLastChange is NULL. Otherwise, you should call IMoniker::GetTimeOfLastChan
ge on your pmkToLeft parameter instead.
See Also
IMoniker::GetTimeOfLastChange, IRunningObjectTable::NoteChangeTime
15.2.16.5 IRunningObjectTable::IsRunning
Determines whether the object identified by the specified moniker is currently r
unning. This method looks for the moniker in the Running Object Table (ROT).
HRESULT IsRunning(
IMoniker *pmkObjectName //Pointer to the moniker of the object whose sta
tus is desired
);
Parameter
pmkObjectName
[in] Pointer to the IMoniker interface on the moniker to search for in the Runni
ng Object Table.
Return Values
S_OK
The object identified by pmkObjectName is running.
S_FALSE
There is no entry for pmkObjectName in the ROT, or that the object it identifies
is no longer running (in which case, the entry is revoked).
Remarks
This method simply indicates whether a object is running. To retrieve a pointer
to a running object, use the IRunningObjectTable::GetObject method.
15.2.16.5.1.1.1 Notes to Callers
Generally, you call the IRunningObjectTable::IsRunning method only if you are wr
iting your own moniker class (that is, implementing the IMoniker interface). You
typically call this method from your implementation of IMoniker::IsRunning. How
ever, you should do so only if the pmkToLeft parameter of IMoniker::IsRunning is
NULL. Otherwise, you should call IMoniker::IsRunning on your pmkToLeft paramete
r instead.
See Also
IMoniker::IsRunning
15.2.16.6 IRunningObjectTable::NoteChangeTime
Records the time that a running object was last modified. The object must have p
reviously been registered with the Running Object Table (ROT). This method store
s the time of last change in the ROT.
HRESULT NoteChangeTime(
DWORD dwRegister, //Value identifying registration being updated
FILETIME *pfiletime //Pointer to structure containing object s last change tim
e
);
Parameters
dwRegister
[in] Value identifying the ROT entry of the changed object. This value was previ
ously returned by IRunningObjectTable::Register.
pfiletime
[in] Pointer to a FILETIME structure containing the object s last change time.
Return Values
This method supports the standard return value E_INVALIDARG, as well as the foll
owing:
S_OK
The change time was recorded successfully.
Remarks
The time recorded by this method can be retrieved by calling IRunningObjectTable
::GetTimeOfLastChange.
This method is provided to enable a program to check whether a connection betwee
n two objects (represented by one object holding a moniker that identifies the o
ther) is up-to-date. For example, if one object is holding cached information ab
out the other object, this method can be used to check whether the object has be
en modified since the cache was last updated. See IMoniker::GetTimeOfLastChange.
15.2.16.6.1.1.1 Notes to Callers
If you re a moniker provider (that is, you hand out monikers identifying your obje
cts to make them accessible to others), you must call the IRunningObjectTable::N
oteChangeTime method whenever your objects are modified. You must have previousl
y called IRunningObjectTable::Register and stored the identifier returned by tha
t method; you use that identifier when calling IRunningObjectTable::NoteChangeTi
me.
The most common type of moniker provider is a compound-document link source. Thi
s includes server applications that support linking to their documents (or porti
ons of a document) and container applications that support linking to embeddings
within their documents. Server applications that do not support linking can als
o use the ROT to cooperate with container applications that support linking to e
mbeddings.
When an object is first registered in the ROT, the ROT records its last change t
ime as the value returned by calling IMoniker::GetTimeOfLastChange on the monike
r being registered.
See Also
IRunningObjectTable::GetTimeOfLastChange, IMoniker::GetTimeOfLastChange
15.2.16.7 IRunningObjectTable::Register
Registers an object and its identifying moniker in the Running Object Table (ROT
).
HRESULT Register(
DWORD grfFlags, //Specifies a weak or a strong reference
IUnknown *punkObject, //Pointer to the object being registered
IMoniker *pmkObjectName, //Pointer to the moniker of the object being reg
istered
DWORD *pdwRegister //Pointer to the value identifying the registration
);
Parameters
grfFlags
[in] Specifies whether the ROT s reference to punkObject is weak or strong. This v
alue must be either zero, indicating a weak reference that does not call IUnknow
n::AddRef; or ROTFLAGS_REGISTRATIONKEEPSALIVE, indicating a strong reference tha
t calls IUnknown::AddRef and can keep the object running. If a strong reference
is registered, a strong reference is released when the object s registration is re
voked. Most callers specify zero, indicating a weak reference.
punkObject
[in] Pointer to the object that is being registered as running.
pmkObjectName
[in] Pointer to the moniker that identifies punkObject.
pdwRegister
[out] Pointer to a 32-bit value that can be used to identify this ROT entry in s
ubsequent calls to IRunningObjectTable::Revoke or IRunningObjectTable::NoteChang
eTime. The caller cannot specify NULL for this parameter. If an error occurs, *p
dwRegister is set to zero.
Return Values
This method supports the standard return values E_INVALIDARG and E_OUTOFMEMORY,
as well as the following:
S_OK
The object was successfully registered.
MK_S_MONIKERALREADYREGISTERED
The moniker/object pair was successfully registered, but that another object (po
ssibly the same object) has already been registered with the same moniker.
Remarks
This method registers a pointer to an object under a moniker that identifies the
object. The moniker is used as the key when the table is searched with IRunning
ObjectTable::GetObject.
Registering a second object with the same moniker, or re-registering the same ob
ject with the same moniker, creates a second entry in the ROT. In this case, IRu
nningObjectTable::Register returns MK_S_MONIKERALREADYREGISTERED. Each call to I
RunningObjectTable::Register must be matched by a call to IRunningObjectTable::R
evoke because even duplicate entries have different pdwRegister identifiers. A p
roblem with duplicate registrations is that there is no way to determine which o
bject will be returned if the moniker is specified in a subsequent call to IRunn
ingObjectTable::IsRunning.
15.2.16.7.1.1.1 Notes to Callers
If you re a moniker provider (that is, you hand out monikers identifying your obje
cts to make them accessible to others), you must call the IRunningObjectTable::R
egister method to register your objects when they begin running. You must also c
all this method if you rename your objects while they are loaded.
The most common type of moniker provider is a compound-document link source. Thi
s includes server applications that support linking to their documents (or porti
ons of a document) and container applications that support linking to embeddings
within their documents. Server applications that do not support linking can als
o use the ROT to cooperate with container applications that support linking to e
mbeddings.
If you re writing a container application that supports linking to embeddings, you
should register your document with the ROT when it is loaded.
You must cache the identifier returned in pdwRegister, and use it in a call to I
RunningObjectTable::Revoke to revoke the registration when the object is no long
er running or when its moniker changes. This revocation is important because the
re is no way for the system to automatically remove entries from the ROT.
The system s implementation of IRunningObjectTable::Register calls IMoniker::Reduc
e on the pmkObjectName parameter to ensure that the moniker is fully reduced bef
ore registration. If a object is known by more than one fully reduced moniker, t
hen it should be registered under all such monikers.
See Also
IMoniker::Reduce, IRunningObjectTable::IsRunning, IRunningObjectTable::Revoke
15.2.16.8 IRunningObjectTable::Revoke
Removes from the Running Object Table (ROT) an entry that was previously registe
red by a call to IRunningObjectTable::Register.
HRESULT Revoke(
DWORD dwRegister //Value identifying registration to be revoked
);
Parameter
dwRegister
[in] Value identifying the ROT entry to revoke. This value was previously return
ed by IRunningObjectTable::Register.
Return Values
This method supports the standard return value E_INVALIDARG, as well as the foll
owing:
S_OK
The object s registration was successfully revoked.
Remarks
This method undoes the effect of a call to IRunningObjectTable::Register, removi
ng both the moniker and the pointer to the object identified by that moniker.
15.2.16.8.1.1.1 Notes to Callers
If you re a moniker provider (that is, you hand out monikers identifying your obje
cts to make them accessible to others), you must call the IRunningObjectTable::R
evoke method to revoke the registration of your objects when they stop running.
You must have previously called IRunningObjectTable::Register and stored the ide
ntifier returned by that method; you use that identifier when calling IRunningOb
jectTable::Revoke.
The most common type of moniker provider is a compound-document link source. Thi
s includes server applications that support linking to their documents (or porti
ons of a document) and container applications that support linking to embeddings
within their documents. Server applications that do not support linking can als
o use the ROT to cooperate with container applications that support linking to e
mbeddings.
If you re writing a container application, you must revoke a document s registration
when the document is closed. You must also revoke a document s registration befor
e re-registering it when it is renamed.
If you re writing a server application, you must revoke an object s registration whe
n the object is closed. You must also revoke an object s registration before re-re
gistering it when its container document is renamed.
See Also
IRunningObjectTable::Register
15.3.3 MkParseDisplayNameEx
Given a string, this function returns a moniker of the object that the string de
notes.
HRESULT MkParseDisplayNameEx(
IBindCtx*pbc, //Pointer to the bind context
LPWSTR szDisplayName, //Display name to be parsed
ULONG *pcchEaten, //Pointer to the number of characters of the display nam
e successfully parsed
IMoniker ** ppmk //Address of output variable that receives
// IMoniker interface pointer
);
Parameters
pbc
[in] Pointer to the bind context in which to accumulate bound objects.
szDisplayName
[in] Display name to be parsed.
pcchEaten
[out] Pointer to the number of characters of the display name that were successf
ully parsed. Most useful on syntax error, when a non-zero value is often returne
d and therefore a subsequent call to MkParseDisplayNameEx with the same pbc and
a shortened szDisplayName should return a valid moniker.
ppmk
[out] Address of IMoniker* pointer variable that receives the interface pointer
to the resulting moniker.
Return Values
S_OK
The operation was successful.
MK_E_SYNTAX
Parsing failed because szDisplayName could only be partially resolved into a mon
iker. In this case, *pcchEaten has the number of characters that were successful
ly parsed into a moniker prefix.
E_OUTOFMEMORY
The operation ran out of memory.
Remarks
Given a string, this function returns a moniker for the object that the string d
enotes. This operation is known as parsing. A display name is parsed into a moni
ker; it is resolved into its component moniker parts.
If a syntax error occurs, then an indication of how much of the string was succe
ssfully parsed is returned in *pcchEaten and NULL is returned through **ppmk. Ot
herwise, the value returned through *pcchEaten indicates the entire size of the
display name.
This function differs from the original MkParseDisplayName function in that it s
upports Universal Resource Indicator (URI) syntax. See the IETC RFC1630 specific
ation for more information on URIs.
Parsing a display name may in some cases be as expensive as binding to the objec
t that it denotes, since, along the way, the parsing mechanism must connect to v
arious non-trivial name space managers (such as a spreadsheet application that c
an parse into ranges in its sheets). As might be expected, objects are not relea
sed by the parsing operation itself, but are instead handed over to the bind con
text that was passed in through IBindCtx::RegisterObjectBound. Thus, if the moni
ker resulting from the parse is immediately bound using this same bind context,
redundant loading of objects is maximally avoided.
In many other cases, however, parsing a display name may be quite inexpensive si
nce a single name-space manager may quickly return a moniker that will perform f
urther expensive analysis on any acceptable name during IMoniker::BindToObject o
r other methods. An example of such an inexpensive parser is the Win32 implement
ation of a File Moniker. A theoretical example would be a naive URL moniker whic
h parsed from any valid URL strings (i.e., http: , file: ) and only during binding took
time to resolve the string against the Internet, a potentially expensive operati
on.
The parsing process is an inductive one, in that there is an initial step that g
ets the process going, followed by the repeated application of an inductive step
. At any point after the beginning of the parse, a certain prefix of szDisplayNa
me has been parsed into a moniker, and a suffix of the display name remains unre
solved.
The inductive step asks the moniker-so-far using IMoniker::ParseDisplayName to c
onsume as much as it would like of the remaining suffix and return the correspon
ding moniker and the new suffix. The moniker is composed onto the end of the exi
sting moniker, and the process repeats.
Implementations of IMoniker::ParseDisplayName vary in exactly where the knowledg
e of how to carry out the parsing is kept. Some monikers by their nature are onl
y used in particular kinds of containers. It is likely that these monikers thems
elves have the knowledge of the legal display name syntax within the objects tha
t they themselves denote, so they can carry out the processes completely within
IMoniker::ParseDisplayName. The common case, however, is that the moniker is gen
eric in the sense that is not specific to one kind of container, and thus cannot
know the legal syntax for elements within the container. File monikers are an e
xample of these, as are Item Monikers. These monikers in general employ the foll
owing strategy to carry out parsing. First, the moniker connects to the class of
object that it currently denotes, asking for IParseDisplayName interface. If th
at succeeds, then it uses the obtained interface pointer to attempt to carry out
the parse. If the class refuses to handle the parse, then the moniker binds to
the object it denotes, asking again for IParseDisplayName interface. If this fai
ls, then the parse is aborted.
The effect is that ultimately an object always gets to be in control of the synt
ax of elements contained inside of itself. It s just that objects of a certain nat
ure can carry out parsing more efficiently by having a moniker or their class do
the parsing on their behalf.
Notice that since MkParseDisplayNameEx knows nothing of the legal syntax of disp
lay names (with the exception of the initial parsing step; see below). It is of
course beneficial to the user that display names in different contexts not have
gratuitously different syntax. While there some rare situations which call for s
pecial purpose syntax, it is recommended that, unless there are compelling reaso
ns to do otherwise, the syntax for display names should be the same as or simila
r to the native file system syntax. The aim is to build on user familiarity. Mos
t important about this are the characters allowed for the delimiters used to sep
arate the display name of one of the component monikers from the next. Unless th
rough some special circumstances they have very good reason not to, all moniker
implementations should use inter-moniker delimiters from the following character
set:
\ / : ! [
Standardization in delimiters promotes usability. But more importantly, notice t
hat the parsing algorithm has the characteristic that a given container consumes
as much as it can of the string being parsed before passing the remainder on to
the designated object inside themselves. If the delimiter expected of the next-
to-be-generated moniker in fact forms (part of) a valid display name in the cont
ainer, then the container s parse will consume it!
Monikers and objects which have implementations on more than one platform (such
as File Monikers) should always parse according to the syntax of the platform on
which they are currently running. When asked for their display name, monikers s
hould also show delimiters appropriate to the platform on which they are current
ly running, even if they were originally created on a different platform. In tot
al, users will always deal with delimiters appropriate for the host platform.
The initial step of the parsing process is a bit tricky, in that it needs to som
ehow determine the initial moniker. MkParseDisplayNameEx is omniscient with resp
ect to the syntax with which the display name of a moniker may legally begin, an
d it uses this omniscience to choose the initial moniker.
The initial moniker is determined by trying the following strategies in order, u
sing the first to succeed.
1. ProgID: Case: If a prefix of szDisplayName conforms to the legal P
rogID syntax, is more than 1 character long, and is followed by a colon ( : ), the P
rogID is converted to a CLSID with CLSIDFromProgID, An instance of this class is
asked for the IParseDisplayName interface, and IParseDisplayName:ParseDisplayNa
me is called with the entire szDisplayName. This case distinguishes MkParseDispl
ayNameEx from MkParseDisplayName.
2. ROT Case: All prefixes of szDisplayName that consist solely of v
alid file name characters are consulted as file monikers in the Running Object T
able.
3. File-System Case: The file system is consulted to check if a pre
fix of szDisplayName matches an existing file. Said file name may be drive absol
ute, drive relative, working-directory relative, or begin with an explicit netwo
rk share name. This is a common case.
4. @ProgID Case: If the initial character of szDisplayName is @ , then t
he maximal string immediately following the @ which conforms to the legal ProgID s
yntax is determined. This is converted to a CLSID with CLSIDFromProgID. An insta
nce of this class is asked in turn for IParseDisplayName interface; the IParseDi
splayName interface so found is then given the whole string (starting with the @ )
to continue parsing.
See Also
IParseDisplayName
15.3.4 MonikerCommonPrefixWith
Creates a new moniker based on the common prefix that this moniker (the one comp
rising the data of this moniker object) shares with another moniker. This functi
on is intended to be called only in implementations of IMoniker::CommonPrefixWit
h.
WINOLEAPI MonikerCommonPrefixWith(
LPMONIKER pmkThis, //Pointer to the first moniker being compared
LPMONIKER pmkOther, //Pointer to the second moniker being compared
LPMONIKER FAR *ppmkCommon //Address of output variable that receives the
// IMoniker interface pointer
);
Parameters
pmkThis
[in] Pointer to the IMoniker interface on one of the monikers for which a common
prefix is sought; usually the moniker in which this call is used to implement I
Moniker::CommonPrefixWith.
pmkOther
[in] Pointer to the IMoniker interface on the other moniker to compare with the
first moniker.
ppmkCommon
[out] Address of IMoniker* pointer variable that receives the interface pointer
to the moniker based on the common prefix of pmkThis and pmkOther. When successf
ul, the function has called IUnknown::AddRef on the moniker and the caller is re
sponsible for calling IUnknown::Release. If an error occurs, the supplied interf
ace pointer value is NULL.
Return Values
This function supports the standard return values E_OUTOFMEMORY and E_UNEXPECTED
, as well as the following:
S_OK
A common prefix exists that is neither pmkThis nor pmkOther.
MK_S_HIM
The entire pmkOther moniker is a prefix of the pmkThis moniker.
MK_S_ME
The entire pmkThis moniker is a prefix of the pmkOther moniker.
MK_S_US
The pmkThis and pmkOther monikers are equal.
MK_E_NOPREFIX
The monikers have no common prefix.
MK_E_NOTBINDABLE
This function was called on a relative moniker. It is not meaningful to take the
common prefix of relative monikers.
Remarks
Call MonikerCommonPrefixWith only in the implementation of IMoniker::CommonPrefi
xWith for a new moniker class.
Your implementation of IMoniker::CommonPrefixWith should first check whether the
other moniker is of a type that you recognize and handle in a special way. If n
ot, you should call MonikerCommonPrefixWith, passing itself as pmkThis and the o
ther moniker as pmkOther. MonikerCommonPrefixWith correctly handles the cases wh
ere either moniker is a generic composite.
You should call this function only if pmkThis and pmkOther are both absolute mon
ikers (where an absolute moniker is either a file moniker or a generic composite
whose leftmost component is a file moniker, and where the file moniker represen
ts an absolute path). Do not call this function on relative monikers.
See Also
IMoniker::CommonPrefixWith
15.3.5 MonikerRelativePathTo
Provides a moniker that, when composed onto the end of the first specified monik
er (or one with a similar structure), yields the second specified moniker. This
function is intended for use only by IMoniker::RelativePathTo implementations.
WINOLEAPI MonikerRelativePathTo(
LPMONIKER pmkSrc, //Pointer to the source identified by the moniker
15.3.7 CreateBindCtx
Supplies a pointer to an implementation of IBindCtx (a bind context object). Thi
s object stores information about a particular moniker-binding operation. The po
inter this function supplies is required as a parameter in many methods of the I
Moniker interface and in certain functions related to monikers.
WINOLEAPI CreateBindCtx(
DWORD reserved, //Reserved for future use
LPBC FAR* ppbc //Address of output variable that receives the
// IBindCtx interface pointer
);
Parameters
reserved
[in] Reserved for future use; must be zero.
ppbc
[out] onAddress of IBindCtx* pointer variable that receives the interface pointe
r to the new bind context object. When the function is successful, the caller is
responsible for calling IUnknown::Release on the bind context . A NULL value fo
r the bind context indicates that an error occurred.
Return Values
This function supports the standard return value E_OUTOFMEMORY, as well as the f
ollowing:
S_OK
The bind context was allocated and initialized successfully.
Remarks
CreateBindCtx is most commonly used in the process of binding a moniker (locatin
g and getting a pointer to an interface by identifying it through a moniker), as
in the following steps:
1. Get a pointer to a bind context by calling the CreateBindCtx fun
ction.
2. Call the IMoniker::BindToObject method on the moniker, retrievin
g an interface pointer to the object to which the moniker refers.
3. Release the bind context.
4. Use the interface pointer.
5. Release the interface pointer.
The following code fragment illustrates these steps:
// pMnk is an IMoniker * that points to a previously acquired moniker
IFoo *pFoo;
IBindCtx *pbc;
CreateBindCtx( 0, &pbc );
pMnk->BindToObject( pbc, NULL, IID_IFoo, &pFoo );
pbc->Release();
// pFoo now points to the object; safe to use pFoo
pFoo->Release();
Bind contexts are also used in other methods of the IMoniker interface besides I
Moniker::BindToObject and in the MkParseDisplayName function.
A bind context retains references to the objects that are bound during the bindi
ng operation, causing the bound objects to remain active (keeping the object s ser
ver running) until the bind context is released. Reusing a bind context when sub
sequent operations bind to the same object can improve performance. You should,
however, release the bind context as soon as possible, because you could be keep
ing the objects activated unnecessarily.
A bind context contains a BIND_OPTS structure, which contains parameters that ap
ply to all steps in a binding operation. When you create a bind context using Cr
eateBindCtx, the fields of the BIND_OPTS structure are initialized to the follow
ing values:
cbStruct = sizeof(BIND_OPTS)
grfFlags = 0
grfMode = STGM_READWRITE
dwTickCountDeadline = 0.
You can call the IBindCtx::SetBindOptions method to modify these default values.
See Also
BIND_OPTS, IBindCtx, IMoniker, MkParseDisplayName
15.3.8 CreateClassMoniker
Creates a file moniker based on the specified path.
WINOLEAPI CreateClassMoniker(
15.3.10 CreateGenericComposite
Performs a generic composition of two monikers and supplies a pointer to the res
ulting composite moniker.
WINOLEAPI CreateGenericComposite(
LPMONIKER pmkFirst, //Pointer to the first moniker
LPMONIKER pmkRest, //Pointer to the second moniker
LPMONIKER FAR *ppmkComposite //Address of output variable that receiv
es the
// IMoniker interface pointer
);
Parameters
pmkFirst
[in] Pointer to the moniker to be composed to the left of the moniker that pmkRe
st points to. Can point to any kind of moniker, including a generic composite.
pmkRest
[in] Pointer to the moniker to be composed to the right of the moniker that pmkF
irst points to. Can point to any kind of moniker compatible with the type of the
pmkRest moniker, including a generic composite.
ppmkComposite
[out] Address of IMoniker* pointer variable that receives the interface pointer
to the composite moniker object that is the result of composing pmkFirst and pmk
Rest. This object supports the COM composite moniker implementation of IMoniker.
When successful, the function has called IUnknown::AddRef on the moniker and t
he caller is responsible for calling IUnknown::Release. If either pmkFirst or pm
kRest are NULL, the supplied pointer is the one that is non-NULL. If both pmkFir
st and pmkRest are NULL, or if an error occurs, the returned pointer is NULL.
Return Values
This function supports the standard return value E_OUTOFMEMORY, as well as the f
ollowing:
S_OK
The two input monikers were successfully composed.
MK_E_SYNTAX
The two monikers could not be composed due to an error in the syntax of a path (
for example, if both pmkFirst and pmkRest are file monikers based on absolute pa
ths).
Remarks
CreateGenericComposite joins two monikers into one. The moniker classes being jo
ined can be different, subject only to the rules of composition. Call this funct
ion only if you are writing a new moniker class by implementing the IMoniker int
erface, within an implementation of IMoniker::ComposeWith that includes generic
composition capability.
Moniker providers should call IMoniker::ComposeWith to compose two monikers toge
ther. Implementations of ComposeWith should (as do COM implementations) attempt,
when reasonable for the class, to perform non-generic compositions first, in wh
ich two monikers of the same class are combined. If this is not possible, the im
plementation can call CreateGenericComposite to do a generic composition, which
combines two monikers of different classes, within the rules of composition. You
can define new types of non-generic compositions if you write a new moniker cla
ss.
During the process of composing the two monikers, CreateGenericComposite makes a
ll possible simplifications. Consider the example where pmkFirst is the generic
composite moniker, A + B + C, and pmkRest is the generic composite moniker, C -1
+ B -1 + Z (where C -1 is the inverse of C). The function first composes C to C
-1, which composes to nothing. Then it composes B and B -1 to nothing. Finally,
it composes A to Z, and supplies a pointer to the generic composite moniker, A
+ Z.
See Also
IMoniker::ComposeWith, IMoniker - Generic Composite Moniker Implementation
15.3.11 CreateItemMoniker
Creates an item moniker that identifies an object within a containing object (ty
pically a compound document).
WINOLEAPI CreateItemMoniker(
LPCOLESTR lpszDelim, //Pointer to delimiter string
LPCOLESTR lpszItem, //Pointer to item name
LPMONIKER FAR *ppmk //Address of output variable that receives
// the IMoniker interface pointer
);
Parameters
lpszDelim
[in] Pointer to a wide character string (two bytes per character) zero-terminate
d string containing the delimiter (typically ! ) used to separate this item s display
name from the display name of its containing object.
lpszItem
[in] Pointer to a zero-terminated string indicating the containing object s name f
or the object being identified. This name can later be used to retrieve a pointe
r to the object in a call to IOleItemContainer::GetObject.
ppmk
[outAddress of IMoniker* pointer variable that receives the interface pointer to
the the new item moniker. When successful, the function has called IUnknown::Ad
dRef on the item moniker and the caller is responsible for calling IUnknown::Rel
ease. If an error occurs, the supplied interface pointer has a NULL value.
Return Values
This function supports the standard return value E_OUTOFMEMORY, as well as the f
ollowing:
S_OK
The moniker was created successfully.
Remarks
A moniker provider, which hands out monikers to identify its objects so they are
accessible to other parties, would call CreateItemMoniker to identify its objec
ts with item monikers. Item monikers are based on a string, and identify objects
that are contained within another object and can be individually identified usi
ng a string. The containing object must also implement the IOleContainer interfa
ce.
Most moniker providers are COM applications that support linking. Applications t
hat support linking to objects smaller than file-based documents, such as a serv
er application that allows linking to a selection within a document, should use
item monikers to identify the objects. Container applications that allow linking
to embedded objects use item monikers to identify the embedded objects.
The lpszItem parameter is the name used by the document to uniquely identify the
object. For example, if the object being identified is a cell range in a spread
sheet, an appropriate name might be something like A1:E7. An appropriate name when
the object being identified is an embedded object might be something like embedo
bj1. The containing object must provide an implementation of the IOleItemContaine
r interface that can interpret this name and locate the corresponding object. Th
is allows the item moniker to be bound to the object it identifies.
Item monikers are not used in isolation. They must be composed with a moniker th
at identifies the containing object as well. For example, if the object being id
entified is a cell range contained in a file-based document, the item moniker id
entifying that object must be composed with the file moniker identifying that do
cument, resulting in a composite moniker that is the equivalent of C:\work\sales.
xls!A1:E7.
Nested containers are allowed also, as in the case where an object is contained
within an embedded object inside another document. The complete moniker of such
an object would be the equivalent of C:\work\report.doc!embedobj1!A1:E7. In this c
ase, each containing object must call CreateItemMoniker and provide its own impl
ementation of the IOleItemContainer interface.
See Also
IMoniker::ComposeWith, IOleItemContainer, IMoniker - Item Moniker Implementation
15.3.12 CreatePointerMoniker
Creates a pointer moniker based on a pointer to an object.
WINOLEAPI CreatePointerMoniker(
LPUNKNOWN punk, //Pointer to the interface to be used
LPMONIKER FAR *ppmk //Address of output variable that receives
// the IMoniker interface pointer
);
Parameters
punk
[in] Pointer to an IUnknown interface on the object to be identified by the resu
lting moniker.
ppmk
[out] Address of IMoniker* pointer variable that receives the interface pointer
to the new pointer moniker. When successful, the function has called IUnknown::A
ddRef on the moniker and the caller is responsible for calling IUnknown::Release
. When an error occurs, the returned interface pointer has a NULL value.
Return Values
This function supports the standard return values E_OUTOFMEMORY and E_UNEXPECTED
, as well as the following:
S_OK
The pointer moniker was created successfully.
Remarks
A pointer moniker wraps an existing interface pointer in a moniker that can be p
assed to those interfaces that require monikers. Pointer monikers allow an objec
t that has no persistent representation to participate in a moniker-binding oper
ation.
Pointer monikers are not commonly used, so this function is not often called.
See Also
IMoniker - Pointer Moniker Implementation
15.4 Moniker Structure Definitions
15.4.1 BIND_OPTS
Contains parameters used during a moniker-binding operation. The BIND_OPTS2 stru
cture may be used in its place. A BIND_OPTS structure is stored in a bind contex
t; the same bind context is used by each component of a composite moniker during
binding, allowing the same parameters to be passed to all components of a compo
site moniker. See IBindCtx for more information about bind contexts.
If you re a moniker client (that is, you use a moniker to acquire an interface poi
nter to an object), you typically do not need to specify values for the fields o
f this structure. The CreateBindCtx function creates a bind context with the bin
d options set to default values that are suitable for most situations; the BindM
oniker function does the same thing when creating a bind context for use in bind
ing a moniker. If you want to modify the values of these bind options, you can d
o so by passing a BIND_OPTS structure to the IBindCtx::SetBindOptions method. Mo
niker implementers can pass a BIND_OPTS structure to the IBindCtx::GetBindOption
s method to retrieve the values of these bind options.
The BIND_OPTS structure is defined in OBJIDL.IDL
typedef struct tagBIND_OPTS
{
DWORD cbStruct;
DWORD grfFlags;
DWORD grfMode;
DWORD dwTickCountDeadline;
} BIND_OPTS, *LPBIND_OPTS;
Members
cbStruct
Size of this structure in bytes (that is, the size of the BIND_OPTS structure).
grfFlags
Flags that control aspects of moniker binding operations. This value is any comb
ination of the bit flags in the BINDFLAGS enumeration. New values may be defined
in the future, so moniker implementations should ignore any bits in this field
that they do not understand. The CreateBindCtx function initializes this field t
o zero.
grfMode
Flags that should be used when opening the file that contains the object identif
ied by the moniker. The values are taken from the STGM enumeration. The binding
operation uses these flags in the call to IPersistFile::Load when loading the fi
le. If the object is already running, these flags are ignored by the binding ope
ration. The CreateBindCtx function initializes this field to STGM_READWRITE.
dwTickCountDeadline
Clock time (in milliseconds, as returned by the GetTickCount function) by which
the caller would like the binding operation to be completed. This member lets th
e caller limit the execution time of an operation when speed is of primary impor
tance. A value of zero indicates that there is no deadline. Callers most often u
se this capability when calling the IMoniker::GetTimeOfLastChange method, though
it can be usefully applied to other operations as well. The CreateBindCtx funct
ion initializes this field to zero.
Typical deadlines allow for a few hundred milliseconds of execution. This deadli
ne is a recommendation, not a requirement; however, operations that exceed their
deadline by a large amount may cause delays for the end user. Each moniker impl
ementation should try to complete its operation by the deadline, or fail with th
e error MK_E_EXCEEDEDDEADLINE.
If a binding operation exceeds its deadline because one or more objects that it
needs are not running, the moniker implementation should register the objects re
sponsible in the bind context using the IBindCtx::RegisterObjectParam. The objec
ts should be registered under the parameter names ExceededDeadline , ExceededDeadlin
e1 , ExceededDeadline2 , and so on. If the caller later finds the object in the Runni
ng Object Table, the caller can retry the binding operation.
The GetTickCount function indicates the number of milliseconds since system star
tup, and wraps back to zero after 2^31 milliseconds. Consequently, callers shoul
d be careful not to inadvertently pass a zero value (which indicates no deadline
), and moniker implementations should be aware of clock wrapping problems (see t
he GetTickCount function for more information).
See Also
BIND_OPTS2, BIND_FLAGS, CreateBindCtx, IBindCtx::SetBindOptions
15.4.2 BIND_OPTS2
Contains parameters used during a moniker-binding operation. A BIND_OPTS2 struct
ure is stored in a bind context; the same bind context is used by each component
of a composite moniker during binding, allowing the same parameters to be passe
d to all components of a composite moniker. See IBindCtx for more information ab
out bind contexts. BIND_OPTS2 replaces the previously defined BIND_OPTS structur
e, including the previously defined members, and adding four new members.
Moniker clients (those using a moniker to acquire an interface pointer to an obj
ect) typically do not need to specify values for the fields of this structure. T
he CreateBindCtx function creates a bind context with the bind options set to de
fault values that are suitable for most situations. The BindMoniker function doe
s the same thing when creating a bind context for use in binding a moniker. If y
ou want to modify the values of these bind options, you can do so by passing a B
IND_OPTS2 structure to the IBindCtx::SetBindOptions method. Moniker implementers
can pass a BIND_OPTS2 structure to the IBindCtx::GetBindOptions method to retri
eve the values of these bind options.
The BIND_OPTS2 structure is defined in OBJIDL.IDL
typedef struct tagBIND_OPTS2 {
DWORD cbStruct; // sizeof(BIND_OPTS2)
DWORD grfFlags;
DWORD grfMode;
DWORD dwTickCountDeadline;
DWORD dwTrackFlags;
DWORD dwClassContext;
LCID locale;
COSERVERINFO * pServerInfo;
} BIND_OPTS2, * LPBIND_OPTS2;
Members
cbStruct
Size of this structure in bytes (that is, the size of the BIND_OPTS2 structure).
grfFlags
Flags that control aspects of moniker binding operations. This value is any comb
ination of the bit flags in the BINDFLAGS enumeration. New values may be defined
in the future, so moniker implementations should ignore any bits in this field
that they do not understand. The CreateBindCtx function initializes this field t
o zero.
grfMode
Flags that should be used when opening the file that contains the object identif
ied by the moniker. The values are taken from the STGM enumeration. The binding
operation uses these flags in the call to IPersistFile::Load when loading the fi
le. If the object is already running, these flags are ignored by the binding ope
ration. The CreateBindCtx function initializes this field to STGM_READWRITE.
dwTickCountDeadline
Clock time (in milliseconds, as returned by the GetTickCount function) by which
the caller would like the binding operation to be completed. This member lets th
e caller limit the execution time of an operation when speed is of primary impor
tance. A value of zero indicates that there is no deadline. Callers most often u
se this capability when calling the IMoniker::GetTimeOfLastChange method, though
it can be usefully applied to other operations as well. The CreateBindCtx funct
ion initializes this field to zero.
Typical deadlines allow for a few hundred milliseconds of execution. This deadli
ne is a recommendation, not a requirement; however, operations that exceed their
deadline by a large amount may cause delays for the end user. Each moniker impl
ementation should try to complete its operation by the deadline, or fail with th
e error MK_E_EXCEEDEDDEADLINE.
If a binding operation exceeds its deadline because one or more objects that it
needs are not running, the moniker implementation should register the objects re
sponsible in the bind context using the IBindCtx::RegisterObjectParam. The objec
ts should be registered under the parameter names ExceededDeadline , ExceededDeadlin
e1 , ExceededDeadline2 , and so on. If the caller later finds the object in the Runni
ng Object Table, the caller can retry the binding operation.
The GetTickCount function indicates the number of milliseconds since system star
tup, and wraps back to zero after 2^31 milliseconds. Consequently, callers shoul
d be careful not to inadvertently pass a zero value (which indicates no deadline
), and moniker implementations should be aware of clock wrapping problems (see t
he GetTickCount function for more information).
dwTrackFlags
A moniker can use this value during link tracking. If the original persisted dat
a that the moniker is referencing has been moved, the moniker can attempt to ree
stablish the link by searching for the original data though some adequate mechan
ism. dwTrackFlags provides additional information on how the link should be reso
lved. See the documentation of the fFlags parameter in IShellLink::Resolve in th
e Win32 SDK for more details.
COM's file moniker implementation uses the shell link mechanism to reestablish l
inks and passes these flags to IShellLink::Resolve.
dwClassContext
The class context, taken from the CLSCTX enumeration, that is to be used for ins
tantiating the object. Monikers typically pass this value to the dwClsContext pa
rameter of CoCreateInstance.
locale
The LCID value indicating the client s preference for the locale to be used by the
object to which they are binding. A moniker passes this value to IClassActivato
r::GetClassObject.
pServerInfo
Points to a COSERVERINFO structure. This member allows clients calling IMoniker:
:BindToObject to specify server information. Clients may pass a BIND_OPTS2 struc
ture to the IBindCtx::SetBindOptions method. If a server name is specified in th
e COSERVERINFO struct, the moniker bind will be forwarded to the specified machi
ne. SetBindOptions only copies the struct members of BIND_OPTS2, not the COSERVE
RINFO structure and the pointers it contains. Callers may not free any of these
pointers until the bind context is released. COM's new class moniker does not cu
rrently honor the pServerInfo flag.
See Also
BIND_OPTS, BIND_FLAGS, CreateBindCtx, IBindCtx::SetBindOptions
15.5 Moniker Enumeration Definitions
15.5.1 BIND_FLAGS
The BIND_FLAGS enumeration values are used to control aspects of moniker binding
operations. The values are used in the BIND_OPTS structure. Callers of IMoniker
methods can specify values from this enumeration, and implementers of IMoniker
methods can use these values in determining what they should do.
The BIND_FLAGS enumeration is defined in OBJIDL.IDL and in OBJIDL.H]
typedef enum tagBIND_FLAGS
{
BIND_MAYBOTHERUSER = 1,
BIND_JUSTTESTEXISTENCE = 2,
} BIND_FLAGS;
Elements
BIND_MAYBOTHERUSER
If this flag is specified, the moniker implementation can interact with the end
user. If not present, the moniker implementation should not interact with the us
er in any way, such as by asking for a password for a network volume that needs
mounting. If prohibited from interacting with the user when it otherwise would,
a moniker implementation can use a different algorithm that does not require use
r interaction, or it can fail with the error MK_MUSTBOTHERUSER.
BIND_JUSTTESTEXISTENCE
If this flag is specified, the caller is not interested in having the operation
carried out, but only in learning whether the operation could have been carried
out had this flag not been specified. For example, this flag lets the caller ind
icate only an interest in finding out whether an object actually exists by using
this flag in a IMoniker::BindToObject call. Moniker implementations can, howeve
r, ignore this possible optimization and carry out the operation in full. Caller
s must be able to deal with both cases.
See Also
BIND_OPTS, IBindCtx
15.5.2 MKRREDUCE
The MKRREDUCE enumeration constants are used to specify how far the moniker shou
ld be reduced. They are used in the IMoniker::Reduce method. MKRREDUCE is defined
in OBJIDL.IDL and in OBJIDL.H].
typedef enum tagMKRREDUCE
{
MKRREDUCE_ONE = 3<<16,
MKRREDUCE_TOUSER = 2<<16,
MKRREDUCE_THROUGHUSER = 1<<16,
MKRREDUCE_ALL = 0
} MKRREDUCE;
Elements
MKRREDUCE_ONE
Performs only one step of reducing the moniker. In general, the caller must have
specific knowledge about the particular kind of moniker to take advantage of th
is option.
MKRREDUCE_TOUSER
Reduces the moniker to a form that the user identifies as a persistent object. I
f no such point exists, then this option should be treated as MKRREDUCE_ALL.
MKRREDUCE_THROUGHUSER
Reduces the moniker to where any further reduction would reduce it to a form tha
t the user does not identify as a persistent object. Often, this is the same sta
ge as MKRREDUCE_TOUSER.
MKRREDUCE_ALL
Reduces the moniker until it is in its simplest form, that is, reduce it to itse
lf.
See Also
IMoniker::Reduce
15.5.3 MKSYS
The MKSYS enumeration constants indicate the moniker s class. They are returned fr
om the IMoniker::IsSystemMoniker method. MKSYS is defined in Objidl.h.
typedef enum tagMKSYS
{
MKSYS_NONE = 0,
MKSYS_GENERICCOMPOSITE = 1,
MKSYS_FILEMONIKER = 2,
MKSYS_ANTIMONIKER = 3,
MKSYS_ITEMMONIKER = 4,
MKSYS_POINTERMONIKER = 5,
MKSYS_CLASSMONIKER = 7
} MKSYS;
Elements
MKSYS_NONE
Indicates a custom moniker implementation.
MKSYS_GENERICCOMPOSITE
Indicates the system s generic composite moniker class.
MKSYS_FILEMONIKER
Indicates the system s file moniker class.
MKSYS_ANTIMONIKER
Indicates the system s anti-moniker class.
MKSYS_ITEMMONIKER
Indicates the system s item moniker class.
MKSYS_POINTERMONIKER
Indicates the system s pointer moniker class.
MKSYS_CLASSMONIKER
Indicates the system s class moniker class.
See Also
IMoniker::IsSystemMoniker
16. Uniform Data Transfer
COM provides a standard mechanism for transferring data between applications. Th
is mechanism is the data object, which is simply any COM object that implements
the IDataObject interface. Some data objects, such as a piece of text copied to
the clipboard, have IDataObject as their sole interface. Others, such as compoun
d document objects, expose several interfaces, of which IDataObject is simply on
e. Data objects are fundamental to the working of compound documents, although t
hey also have widespread application outside that COM technology.
By exchanging pointers to a data object, providers and consumers of data can man
age data transfers in a uniform manner, regardless of the format of the data, th
e type of medium used to transfer the data, or the target device on which it is
to be rendered. You can include support in your application for basic clipboard
transfers, drag and drop transfers, and COM compound document transfers with a s
ingle implementation of IDataObject. Having done that, the amount of code requir
ed to accommodate the special semantics of each protocol is minimal.
16.1 Data Transfer Interfaces
The IDataObject interface provides consumers of data with methods for getting an
d setting an object s data, determining which formats the object supports, and reg
istering for and receiving notifications when data in the object changes. When o
btaining data, a caller can specify the format in which it wants to render the d
ata. The source of the data, however, determines the storage medium, which it re
turns in an out parameter provided by the caller.
By itself, IDataObject supplies all the tools you need to implement Microsoft® Win
dows® clipboard transfers or compound document transfers in your applications. If
you also want to support drag and drop transfers, you need to implement the IDro
pSource and IDropTarget interfacesalong with IDataObject.
The IDataObject interface combined with COM clipboard APIs provide all the capab
ilities of the Microsoft® Win32® clipboard APIs. Using both the platform s clipboard A
PIs and COM s is usually redundant and unnecessary. Suppliers of data that support
either drag and drop transfers or COM compound documents must implement the IDa
taObject interface. If your application supports only clipboard transfers now, b
ut you intend to add drag and drop or compound documents in later releases, you
may want to implement IDataObject and the COM clipboard APIs now in order to min
imize the amount of time spent recoding and debugging later. You may also want t
o implement IDataObject in order to utilize transfer media other than global mem
ory.
16.2 Data Formats and Transfer Media
Most platforms, including Windows, define a standard protocol for transferring d
ata between applications, based on a set of functions called the clipboard. Appl
ications using these functions can share data even if their native data formats
are wildly different. Generally, these clipboards have two significant shortcomi
ngs that COM has overcome.
First, data descriptions use only a format identifier, such as the single 16-bit
clipboard format identifier on Windows, which means the clipboard can only desc
ribe the structure of its data, that is, the ordering of the bits. It can report
, I have a bitmap or I have some text, but it cannot specify the target devices for
which the data is composed, which views or aspects of itself the data can provid
e, or which storage media are best suited for its transfer. For example, it cann
ot report, I have a string of text that is stored in global memory and formatted
for presentation either on screen or on a printer or I have a thumbnail sketch bit
map rendered for a 100 dpi dot-matrix printer and stored as a disk file.
Second, all data transfers using the clipboard generally occur through global me
mory. Using global memory is reasonably efficient for small amounts of data but
horribly inefficient for large amounts, such as a 20 MB multimedia object. Globa
l memory is slow for a large data object, whose size requires considerable swapp
ing to virtual memory on disk. In cases where the data being exchanged is going
to reside mostly on disk anyway, forcing it through this virtual-memory bottlene
ck is highly inefficient. A better way would skip global memory entirely and sim
ply transfer the data directly to disk.
To alleviate these problems, COM introduces two new data structures: FORMATETC a
nd STGMEDIUM.
16.2.1 The FORMATETC Structure
The FORMATETC structure is a generalized clipboard format, enhanced to encompass
a target device, an aspect or view of the data, and a storage medium. A data co
nsumer, such as an COM container application, passes the FORMATETC structure as
an argument in calls to IDataObject to indicate the type of data it wants from a
data source, such as a compound document object. The source uses the FORMATETC
structure to describe what formats it can provide. FORMATETC can describe virtua
lly any data, including other objects such as monikers. A container can ask one
of its embedded objects to list its data formats by calling IDataObject::EnumFor
matetc, which returns an enumerator object that implements the IEnumFormatEtc in
terface. Instead of replying merely that it has text and a bitmap, the object can
provide a detailed description of the data, including the device (normally scree
n or printer) for which it is rendered, the aspect to be presented to the user (
full contents, thumbnail, icon, or formatted for printing), and the storage medi
um containing the data (global memory, disk file, storage object, or stream). Th
is ability to tightly describe data will, in time, result in higher quality prin
ter and screen output as well as more efficiency in data browsing, where a thumb
nail sketch is much faster to retrieve and display than a fully detailed renderi
ng.
The following table lists fields of the FORMATETC data structure and the informa
tion they specify:
Field Specifies
cfFormat The format in which the data is to be rendered, which can be a s
tandard clipboard format, a proprietary format, or an COM format.
ptd A DVTARGETDEVICE structure, which contains enough information about a Wi
ndows target device, such as a screen or printer, so that a handle to its device
context (hDC) can be created using the Windows CreateDC function.
dwAspect The aspect or view of the data to be rendered; can be the full c
ontents, a thumbnail sketch, an icon, or formatted for printing.
lindex The part of the aspect that is of interest; for the present, the value m
ust be -1, indicating that the entire view is of interest.
tymed The data s storage medium, which can be global memory, disk file, or an in
stance of one of COM s structured-storage interfaces.
16.2.2 The STGMEDIUM Structure
Just as the FORMATETC structure is an enhancement of the Windows clipboard forma
t identifier, so the STGMEDIUM structure is an improvement of the global memory
handle used to transfer the data. The STGMEDIUM structure includes a flag, tymed
, which indicates the medium to be used, and a union comprising pointers and a h
andle for getting whichever medium is specified in tymed.
The STGMEDIUM structure enables both data sources and consumers to choose the mo
st efficient exchange medium on a per-rendering basis. If the data is so big tha
t it should be kept on disk, the data source can indicate a disk-based medium in
its preferred format, only using global memory as a backup if that s the only med
ium the consumer understands. Being able to use the best medium for exchanges as
the default improves overall performance of data exchange between applications.
For example, if some of the data to be transferred is already on disk, the sour
ce application can move or copy it to a new destination, either in the same appl
ication or in some other, without having first to load the data into global memo
ry. At the receiving end, the consumer of the data does not have to write it bac
k to disk.
16.3 Data Notification
Objects that consume data from an external source sometimes need to be informed
when data in that source changes. For example, a stock ticker tape viewer that r
elies on data in some spreadsheet needs to be notified when that data changes so
it can update its display. Similarly, a compound document needs information abo
ut data changes in its embedded objects so that it can update its data caches. I
n cases such as this, where dynamic updating of data is desirable, sources of da
ta require some mechanism of notifying data consumers of changes as they occur w
ithout obligating the consumers to drop everything in order to update their data
. Ideally, having been notified that a change has occurred in the data source, a
consuming object can ask for an updated copy at its leisure.
COM s mechanism for handling asynchronous notifications of this type is an object
called an advise sink, which is simply any COM object that implements an interfa
ce called IAdviseSink. Consumers of data implement the IAdviseSink. They registe
r to receive notifications by handing a pointer to the data object of interest.
The IAdviseSink interfaces exposes the following methods for receiving asynchron
ous notifications:
Method Notifies the Advise Sink that
OnDataChange Calling object s data has changed.
OnViewChange Instructions for drawing the calling object have changed.
OnRename Calling object s moniker has changed.
OnSave Calling object has been saved to persistent storage.
OnClose Calling object has been closed.
As the table indicates, the IAdviseSink interface exposes methods for notifying
the advise sink of events other than changes in the calling object s data. The cal
ling object can also notify the sink when the way in which it draws itself chang
es, or it is renamed, saved, or closed. These other notifications are used mainl
y or entirely in the context of compound documents, although the notification me
chanism is identical. In order to take advantage of the advise sink, a data sour
ce must implement IDataObject::DAdvise, IDataObject::DUnadvise, and IDataObject:
:EnumDAdvise. A data consumer calls the DAdvise mothod to notify a data object t
hat it wishes to be notified when the object s data changes. The consuming object
calls the DUnadvise method to tear down this connection. Any interested party ca
n call the EnumAdvise method to learn the number of objects having an advisory c
onnection with a data object.
When data changes at the source, the data object calls IAdviseSink::OnDataChange
on all data consumers that have registered to receive notifications. To keep tr
ack of advisory connections and manage the dispatch of notifications, data sourc
es rely on an object called a data advise holder. You can create your own data a
dvise holder by implementing the IDataAdviseHolder interface. Or, you can let CO
M do it for you by calling the helper function CreateDataAdviseHolder.
16.4 Uniform Data Transfer Interface Descriptions
IAdviseSink
The IAdviseSink interface enables containers and other objects to receive notifi
cations of data changes, view changes, and compound-document changes occurring i
n objects of interest. Container applications, for example, require such notific
ations to keep cached presentations of their linked and embedded objects up-to-d
ate. Calls to IAdviseSink methods are asynchronous, so the call is sent and then
the next instruction is executed without waiting for the call's return.
For an advisory connection to exist, the object that is to receive notifications
must implement IAdviseSink, and the objects in which it is interested must use
IDataObject::DAdvise.
As shown in the following table, an object that has implemented an advise sink r
egisters its interest in receiving certain types of notifications by calling the
appropriate method:
Call This Method To Register for These Notifications
IDataObject::DAdvise When a document's data changes.
When an event occurs that applies to a registered notification type, the object
application calls the appropriate IAdviseSink method. For example, when an embed
ded object closes, it calls the IAdviseSink::OnClose method to notify its contai
ner. These notifications are asynchronous, occurring after the events that trigg
er them.
When to Implement
Objects, such as container applications and compound documents, implement IAdvis
eSink to receive notification of changes in data, presentation, name, or state o
f their linked and embedded objects. Implementers register for one or more types
of notification, depending on their needs.
Notifications of changes to an embedded object originate in the server and flow
to the container by way of the object handler. If the object is a linked object,
the OLE link object intercepts the notifications from the object handler and no
tifies the container directly. All containers, the object handler, and the OLE l
ink object register for OLE notifications. The typical container also registers
for view notifications. Data notifications are usually sent to the OLE link obje
ct and object handler.
When to Use
Servers call the methods of IAdviseSink to notify objects with which they have a
n advisory connection of changes in an object's data, view, name, or state.
Note
OLE does not permit synchronous calls in the implementation of asynchronous meth
ods, so you cannot make synchronous calls within any of the the IAdviseSink inte
rface's methods. For example, an implementation of IAdviseSink::OnDataChange can
not contain a call to IDataObject::GetData.
Methods in Vtable Order
IUnknown Methods Description
QueryInterface Returns pointers to supported interfaces.
AddRef Increments reference count.
Release Decrements reference count.
IAdviseSink Methods Description
OnDataChange Advises that data has changed.
OnViewChange Advises that view of object has changed.
OnRename Advises that name of object has changed.
OnSave Advises that object has been saved to disk.
OnClose Advises that object has been closed.
See Also
IAdviseSink2, IDataAdviseHolder
IAdviseSink::OnClose
Called by the server to notify all registered advisory sinks that the object has
changed from the running to the loaded state.
Void OnClose();
Remarks
OnClose notification indicates that an object is making the transition from the
running to the loaded state, so its container can take appropriate measures to e
nsure orderly shutdown. For example, an object handler must release its pointer
to the object.
If the object that is closing is the last open object supported by its OLE serve
r application, the application can also shut down.
In the case of a link object, the notification that the object is closing should
always be interpreted to mean that the connection to the link source has broken
.
IAdviseSink::OnDataChange
Called by the server to notify a data object's currently registered advise sinks
that data in the object has changed.
void OnDataChange(
FORMATETC * pFormatetc, //Pointer to format information
STGMEDIUM * pStgmed //Pointer to storage medium
);
Parameters
pFormatetc
[in] Pointer to the FORMATETC structure, which describes the format, target devi
ce, rendering, and storage information of the calling data object.
pStgmed
[in] Pointer to the STGMEDIUM structure, which defines the storage medium (globa
l memory, disk file, storage object, stream object, GDI object, or undefined) an
d ownership of that medium for the calling data object.
Remarks
Object handlers and containers of link objects implement IAdviseSink::OnDataChan
ge to take appropriate steps when notified that data in the object has changed.
They also must call IDataObject::DAdvise to set up advisory connections with the
objects in whose data they are interested. (See IDataObject::DAdvise for more i
nformation on how to specify an advisory connection for data objects.)
Containers that take advantage of OLE's caching support do not need to register
for data-change notifications, because the information necessary to update the c
ontainer's presentation of the object, including any changes in its data, are ma
intained in the object's cache.
Notes to Implementers
If you implement IAdviseSink::OnDataChange for a container, remember that this m
ethod is asynchronous and that making synchronous calls within asynchronous meth
ods is not valid. Therefore, you cannot call IDataObject::GetData to obtain the
data you need to update your object. Instead, you either post an internal messag
e, or invalidate the rectangle for the changed data by calling InvalidateRect an
d waiting for a WM_PAINT message, at which point you are free to get the data an
d update the object.
The data itself, which is valid only for the duration of the call, is passed usi
ng the storage medium pointed to by pStgmed. Since the caller owns the medium, t
he advise sink should not free it. Also, if pStgmed points to an IStorage or ISt
ream interface, the sink must not increment the reference count.
See Also
IDataObject::DAdvise
IAdviseSink::OnRename
Called by the server to notify all registered advisory sinks that the object has
been renamed.
Void OnRename(
IMoniker * pmk //Pointer to the new moniker of the object
);
Parameter
pmk
[in] Pointer to the IMoniker interface on the new full moniker of the object.
Remarks
OLE link objects normally implement IAdviseSink::OnRename to receive notificatio
n of a change in the name of a link source or its container. The object serving
as the link source calls OnRename and passes its new full moniker to the object
handler, which forwards the notification to the link object. In response, the li
nk object must update its moniker. The link object, in turn, forwards the notifi
cation to its own container.
IAdviseSink::OnSave
Called by the server to notify all registered advisory sinks that the object has
been saved.
Void OnSave();
Remarks
Object handlers and link objects normally implement IAdviseSink::OnSave to recei
ve notifications of when an object is saved to disk, either to its original stor
age (through a Save operation) or to new storage (through a Save As operation).
Object Handlers and link objects register to be notified when an object is saved
for the purpose of updating their caches, but then only if the advise flag pass
ed during registration specifies ADVFCACHE_ONSAVE. Object handlers and link obje
cts forward these notifications to their containers.
IAdviseSink::OnViewChange
Notifies an object's registered advise sinks that its view has changed.
Void OnViewChange(
DWORD dwAspect, //Value specifying aspect of object
LONG lindex //Currently must be -1
);
Parameters
dwAspect
[in] The aspect, or view, of the object. Contains a value taken from the enumera
tion, DVASPECT.
lindex
[in] The portion of the view that has changed. Currently only -1 is valid.
Remarks
Even though DVASPECT values are individual flag bits, dwAspect may represent onl
y one value. That is, dwAspect cannot contain the result of an OR operation comb
ining two or more DVASPECT values.
The lindex member represents the part of the aspect that is of interest. The val
ue of lindex depends on the value of dwAspect. If dwAspect is either DVASPECT_TH
UMBNAIL or DVASPECT_ICON, lindex is ignored. If dwAspect is DVASPECT_CONTENT, li
ndex must be -1, which indicates that the entire view is of interest and is the
only value that is currently valid.
16.4.1 IDataAdviseHolder
The IDataAdviseHolder interface contains methods that create and manage advisory
connections between a data object and one or more advise sinks. Its methods are
intended to be used to implement the advisory methods of IDataObject. IDataAdvi
seHolder is implemented on an advise holder object. Its methods establish and de
lete data advisory connections and send notification of change in data from a da
ta object to an object that requires this notification, such as an COM container
, which must contain an advise sink.
Advise sinks are objects that require notification of change in the data the obj
ect contains and implement the IAdviseSink interface. Advise sinks are also usua
lly associated with OLE compound document containers.
16.4.1.1.1.1.1 When to implement
Typically, you use the COM-provided implementation of IDataAdviseHolder to simpl
ify your implementation of the DAdvise, DUnadvise, and EnumDAdvise methods in th
e IDataObject interface, and to send notification of data change as appropriate.
It would be necessary to implement IDataAdviseHolder only in the case where the
re may be a need for a custom data advise holder object, whose methods are to be
used to implement the IDataObject methods in a set of servers.
16.4.1.1.1.1.2 When to use
Your implementation of the advisory methods of IDataObject can call the methods
in IDataAdviseHolder. The first time you receive a call to IDataObject::DAdvise,
call the function CreateDataAdviseHolder to create an instance of the COM-provi
ded advise holder and get a pointer to its IDataAdviseHolder interface. Then, in
implementing the IDataObject interface on the data object, you delegate impleme
ntations of the DAdvise, DUnadvise, and EnumDAdvise methods to the corresponding
methods in IDataAdviseHolder.
When the data of interest to an advise sink actually changes, you call IDataAdvi
seHolder::SendOnDataChange from the data object to carry out the necessary notif
ications.
Methods in VTable Order
IUnknown Methods Description
QueryInterface Returns pointers to supported interfaces.
AddRef Increments reference count.
Release Decrements reference count.
IDataAdviseHolder Methods Description
Advise Creates a connection between an advise sink and a data object so the adv
ise sink can receive notification of change in the data object.
Unadvise Destroys a notification connection previously set up with the Ad
vise method.
EnumAdvise Returns an object that can be used to enumerate the current advi
sory connections.
SendOnDataChange Sends a change notification back to each advise sink tha
t is currently being managed.
See Also
IDataObject, IAdviseSink
16.4.1.2 IDataAdviseHolder::Advise
Creates a connection between an advise sink and a data object for receiving noti
fications.
HRESULT Advise(
IDataObject * pDataObject, //Pointer to the data object for which notificat
ions are requested
FORMATETC * pFormatetc, //Pointer to the description of data to the advi
se sink
DWORD advf, //Flags that specify how the notification takes place
IAdviseSink * pAdvSink, //Pointer to the advise sink requesting notifica
tion
DWORD * pdwConnection //Pointer to the connection token
);
Parameters
pDataObject
[in] Pointer to the IDataObject interface on the data object for which notificat
ions are requested. If data in this object changes, a notification is sent to th
e advise sinks that have requested notification.
pFormatetc
[in] Pointer to the specified format, medium, and target device that is of inter
est to the advise sink requesting notification. For example, one sink may want t
o know only when the bitmap representation of the data in the data object change
s. Another sink may be interested in only the metafile format of the same object
. Each advise sink is notified when the data of interest changes. This data is p
assed back to the advise sink when notification occurs.
advf
[in] Contains a group of flags for controlling the advisory connection. Valid va
lues are from the enumeration ADVF. However, only some of the possible ADVF valu
es are relevant for this method. The following table briefly describes the relev
ant values; a more detailed description can be found in the description of the A
DVF enumeration.
ADVF Value Description
ADVF_NODATA Asks that no data be sent along with the notification.
ADVF_ONLYONCE Causes the advisory connection to be destroyed after the first n
otification is sent. An implicit call to IDataAdviseHolder::Unadvise is made on
behalf of the caller to remove the connection.
ADVF_PRIMEFIRST Causes an initial notification to be sent regardless of whether
or not data has changed from its current state.
ADVF_DATAONSTOP When specified with ADVF_NODATA, this flag causes a last notific
ation with the data included to be sent before the data object is destroyed. Whe
n ADVF_NODATA is not specified, this flag has no effect.
pAdvSink
[in] Pointer to the IAdviseSink interface on the advisory sink that receives the
change notification.
pdwConnection
[out] Pointer to a DWORD token that identifies this connection. The calling obje
ct can later delete the advisory connection by passing this token to IDataAdvise
Holder::Unadvise. If this value is zero, the connection was not established.
Return Values
This method supports the standard return value E_INVALIDARG, as well as the foll
owing:
S_OK
The advisory connection was created.
Remarks
Through the connection established through this method, the advisory sink can re
ceive future notifications in a call to IAdviseSink::OnDataChange.
An object issues a call to IDataObject::DAdvise to request notification on chang
es to the format, medium, or target device of interest. This data is specified i
n the pFormatetc parameter. The DAdvise method is usually implemented to call ID
ataAdviseHolder::Advise to delegate the task of setting up and tracking a connec
tion to the advise holder. When the format, medium, or target device in question
changes, the data object calls IDataAdviseHolder::SendOnDataChange to send the
necessary notifications.
The established connection can be deleted by passing the value in pdwConnection
in a call to IDataAdviseHolder::Unadvise.
See also
ADVF, CreateDataAdviseHolder, FORMATETC, IDataAdviseHolder::Unadvise, IDataObjec
t::DAdvise
16.4.1.3 IDataAdviseHolder::EnumAdvise
Returns a pointer to an IEnumStatdata interface on an enumeration object that ca
n be used to enumerate the current advisory connections.
HRESULT EnumAdvise(
IEnumSTATDATA ** ppenumAdvise //Indirect pointer on the new enumerator
object
);
Parameter
ppenumAdvise
[out] Indirect pointer to the IEnumStatdata interface on the new enumerator obje
ct. If this value is NULL, there are no connections to advise sinks at this time
.
Return Values
This method supports the standard return value E_OUTOFMEMORY, as well as the fol
lowing:
S_OK
The enumerator object is successfully instantiated or there are no connections.
Remarks
This method must supply a pointer to an implementation of the IEnumSTATDATA inte
rface, one of the standard enumerator interfaces that contain the Next, Reset, C
lone, and Skip methods, on an enumerator object. Its methods allow you to enumer
ate the data stored in an array of STATDATA structures. You get a pointer to the
COM implementation of IDataAdviseHolder through a call to CreateDataAdviseHolde
r, and then call IDataAdviseHolder::EnumAdvise to implement IDataObject::EnumDAd
vise.
Adding more advisory connections while the enumerator object is active has an un
defined effect on the enumeration that results from this method.
See Also
IEnumXXXX, IEnumSTATDATA, IDataObject::EnumDAdvise
16.4.1.4 IDataAdviseHolder::SendOnDataChange
Sends notifications to each advise sink for which there is a connection establis
hed by calling the IAdviseSink::OnDataChange method for each advise sink current
ly being handled by this instance of the advise holder object.
HRESULT SendOnDataChange(
IDataObject * pDataObject, //Pointer to the data object that has changed
DWORD dwReserved, //Reserved
DWORD advf //Advise flags
);
Parameters
pDataObject
[in] Pointer to the IDataObject interface on the data object in which the data h
as just changed. This pointer is used in subsequent calls to IAdviseSink::OnData
Change.
dwReserved
[in] Reserved for future use; must be zero.
advf
[in] Container for advise flags that specify how the call to IAdviseSink::OnData
Change is made. These flag values are from the enumeration ADVF. Typically, the
value for advf is NULL. The only exception occurs when the data object is shutti
ng down and must send a final notification that includes the actual data to sink
s that have specified ADVF_DATAONSTOP and ADVF_NODATA in their call to IDataObje
ct::DAdvise. In this case, advf contains ADVF_DATAONSTOP.
Return Values
This method supports the standard return value E_OUTOFMEMORY, as well as the fol
lowing:
S_OK
The call to IAdviseSink::OnDataChange was made.
Remarks
The data object must call this method when it detects a change that would be of
interest to an advise sink that has previously requested notification.
Most notifications include the actual data with them. The only exception is if t
he ADVF_NODATA flag was previously specified when the connection was initially s
et up in the IDataAdviseHolder::Advise method.
Before calling the IAdviseSink::OnDataChange method for each advise sink, this m
ethod obtains the actual data by calling the IDataObject::GetData method through
the pointer specified in the pDataObject parameter.
See Also
ADVF, IAdviseSink::OnDataChange
16.4.1.5 IDataAdviseHolder::Unadvise
Removes a connection between a data object and an advisory sink that was set up
through a previous call to IDataAdviseHolder::Advise. IDataAdviseHolder::Unadvis
e is typically called in the implementation of IDataObject::DUnadvise.
HRESULT Unadvise(
DWORD dwConnection //Connection to remove
);
Parameter
dwConnection
[in] DWORD token that specifies the connection to remove. This value was returne
d by IDataAdviseHolder::Advise when the connection was originally established.
Return Values
S_OK
The specified connection was successfully deleted.
OLE_E_NOCONNECTION
The specified dwConnection is not a valid connection.
See Also
IDataAdviseHolder::Advise, IDataObject::DUnadvise
16.4.2 IDataObject
The IDataObject interface specifies methods that enable data transfer and notifi
cation of changes in data. Data transfer methods specify the format of the trans
ferred data along with the medium through which the data is to be transferred. O
ptionally, the data can be rendered for a specific target device. In addition to
methods for retrieving and storing data, the IDataObject interface specifies me
thods for enumerating available formats and managing connections to advisory sin
ks for handling change notifications.
The term data object is used to mean any object that supports an implementation of
the IDataObject interface. Implementations vary, depending on what the data obj
ect is required to do; in some data objects, the implementation of certain metho
ds not supported by the object could simply be the return of E_NOTIMPL. For exam
ple, some data objects do not allow callers to send them data. Other data object
s do not support advisory connections and change notifications. However, for tho
se data objects that do support change notifications, COM provides an object cal
led a data advise holder. An interface pointer to this holder is available throu
gh a call to the helper function CreateDataAdviseHolder. A data object can have
multiple connections, each with its own set of attributes. The COM data advise h
older simplifies the task of managing these connections and sending the appropri
ate notifications.
16.4.2.1.1.1.1 When to Implement
Implement the IDataObject interface if you are developing a container or server
application that is capable of transferring data. For example, if your applicati
on allows its data to be pasted or dropped into another application, you must im
plement the IDataObject interface. OLE compound document object servers that sup
port objects that can be embedded or linked must implement IDataObject.
COM provides implementations in its default object handler and its cache.
16.4.2.1.1.1.2 When to Use
Any object that can receive data calls the methods in the IDataObject interface.
When you call the data transfer methods in the IDataObject interface, you specif
y a format, a medium, and, optionally, a target device for which the data should
be rendered. Objects, such as containers, that want to be notified through thei
r advise sinks when the data in the data object changes call the IDataObject adv
isory methods to set up an advisory connection through which notifications can b
e sent.
Methods in VTable Order
IUnknown Methods Description
QueryInterface Returns pointers to supported interfaces.
AddRef Increments reference count.
Release Decrements reference count.
IDataObject Methods Description
GetData Renders the data described in a FORMATETC structure and transfers it thr
ough the STGMEDIUM structure.
GetDataHere Renders the data described in a FORMATETC structure and transfer
s it through the STGMEDIUM structure allocated by the caller.
QueryGetData Determines whether the data object is capable of rendering the d
ata described in the FORMATETC structure.
GetCanonicalFormatEtc Provides a potentially different but logically equivalen
t FORMATETC structure.
SetData Provides the source data object with data described by a FORMATETC struc
ture and an STGMEDIUM structure.
EnumFormatEtc Creates and returns a pointer to an object to enumerate the FORM
ATETC supported by the data object.
DAdvise Creates a connection between a data object and an advise sink so the adv
ise sink can receive notifications of changes in the data object.
DUnadvise Destroys a notification previously set up with the DAdvise metho
d.
EnumDAdvise Creates and returns a pointer to an object to enumerate the curr
ent advisory connections.
16.4.2.2 IDataObject::DAdvise
Called by an object supporting an advise sink to create a connection between a d
ata object and the advise sink. This enables the advise sink to be notified of c
hanges in the data of the object.
HRESULT DAdvise(
FORMATETC * pFormatetc, //Pointer to data of interest to the advise sink
DWORD advf, //Flags that specify how the notification takes place
IAdviseSink * pAdvSink, //Pointer to the advise sink
DWORD * pdwConnection //Pointer to a token that identifies this connec
tion
);
Parameters
pFormatetc
[in] Pointer to a FORMATETC structure that defines the format, target device, as
pect, and medium that will be used for future notifications. For example, one si
nk may want to know only when the bitmap representation of the data in the the d
ata object changes. Another sink may be interested in only the metafile format o
f the same object. Each advise sink is notified when the data of interest change
s. This data is passed back to the advise sink when notification occurs.
advf
[in] DWORD that specifies a group of flags for controlling the advisory connecti
on. Valid values are from the enumeration ADVF. However, only some of the possib
le ADVF values are relevant for this method. The following table briefly describ
es the relevant values. Refer to ADVF for a more detailed description.
ADVF Value Description
ADVF_NODATA Asks the data object to avoid sending data with the notification
s. Typically data is sent. This flag is a way to override the default behavior.
When ADVF_NODATA is used, the TYMED member of the STGMEDIUM structure that is pa
ssed to OnDataChange will usually contain TYMED_NULL. The caller can then retrie
ve the data with a subsequent IDataObject::GetData call.
ADVF_ONLYONCE Causes the advisory connection to be destroyed after the first c
hange notification is sent. An implicit call to IDataObject::DUnadvise is made o
n behalf of the caller to remove the connection.
ADVF_PRIMEFIRST Asks for an additional initial notification. The combination of
ADVF_ONLYONCE and ADVF_PRIMEFIRST provides, in effect, an asynchronous IDataObje
ct::GetData call.
ADVF_DATAONSTOP When specified with ADVF_NODATA, this flag causes a last notific
ation with the data included to to be sent before the data object is destroyed.
If used without ADVF_NODATA, IDataObject::DAdvise can be implemented in one of t
he following ways:
· the ADVF_DATAONSTOP can be ignored.
· the object can behave as if ADVF_NODATA was specified.
· a change notification is sent only in the shutdown case. Data changes
prior to shutdown do not cause a notification to be sent.
pAdvSink
[in] Pointer to the IAdviseSink interface on the advisory sink that will receive
the change notification.
pdwConnection
[out] Pointer to a DWORD token that identifies this connection. You can use this
token later to delete the advisory connection (by passing it to IDataObject::DU
nadvise). If this value is zero, the connection was not established.
Return Values
This method supports the standard return values E_INVALIDARG, E_UNEXPECTED, and
E_OUTOFMEMORY, as well as the following:
S_OK
The advisory connection was created.
E_NOTIMPL
This method is not implemented on the data object.
DV_E_LINDEX
Invalid value for lindex; currently, only -1 is supported.
DV_E_FORMATETC
Invalid value for pFormatetc.
OLE_E_ADVISENOTSUPPORTED
The data object does not support change notification.
Remarks
IDataObject::DAdvise creates a change notification connection between a data obj
ect and the caller. The caller provides an advisory sink to which the notificati
ons can be sent when the object s data changes.
Objects used simply for data transfer typically do not support advisory notifica
tions and return OLE_E_ADVISENOTSUPPORTED from IDataObject::DAdvise.
16.4.2.2.1.1.1 Notes to Callers
The object supporting the advise sink calls IDataObject::DAdvise to set up the c
onnection, specifying the format, aspect, medium, and/or target device of intere
st in the FORMATETC structure passed in. If the data object does not support one
or more of the requested attributes or the sending of notifications at all, it
can refuse the connection by returning OLE_E_ADVISENOTSUPPORTED.
Containers of linked objects can set up advisory connections directly with the b
ound link source or indirectly through the standard COM link object that manages
the connection. Connections set up with the bound link source are not automatic
ally deleted. The container must explicitly call IDataObject::DUnAdvise on the b
ound link source to delete an advisory connection. Connections set up through th
e COM link object are destroyed when the link object is deleted.
The COM default link object creates a wildcard advise with the link source so COM
can maintain the time of last change. This advise is specifically used to note t
he time that anything changed. COM ignores all data formats that may have change
d, noting only the time of last change. To allow wildcard advises, set the FORMA
TETC members as follows before calling IDataObject::DAdvise:
cf == 0;
ptd == NULL;
dwAspect ==-1;
lindex == -1
tymed == -1;
The advise flags should also include ADVF_NODATA. Wildcard advises from COM shou
ld always be accepted by applications.
16.4.2.2.1.1.2 Notes to Implementers
To simplify the implementation of DAdvise and the other notification methods in
IDataObject (DUnadvise and EnumAdvise) that supports notification, COM provides
an advise holder object that manages the registration and sending of notificatio
ns. To get a pointer to this object, call the helper function CreateDataAdviseHo
lder on the first invocation of DAdvise. This supplies a pointer to the object s I
DataAdviseHolder interface. Then, delegate the call to the IDataAdviseHolder::Ad
vise method in the data advise holder, which creates, and subsequently manages,
the requested connection.
See Also
ADVF, FORMATETC, CreateDataAdviseHolder , IDataAdviseHolder - OLE implementation , I
AdviseSink::OnDataChange, IDataObject::DUnAdvise
16.4.2.3 IDataObject::DUnadvise
Destroys a notification connection that had been previously set up.
HRESULT DUnadvise(
DWORD dwConnection //Connection to remove
);
Parameter
dwConnection
[in] DWORD token that specifies the connection to remove. Use the value returned
by IDataObject::DAdvise when the connection was originally established.
Return Values
S_OK
The specified connection was successfully deleted.
OLE_E_NOCONNECTION
The specified dwConnection is not a valid connection.
OLE_E_ADVISENOTSUPPORTED
This IDataObject implementation does not support notification.
Remarks
This methods destroys a notification created with a call to the IDataObject::DAd
vise method.
If the advisory connection being deleted was initially set up by delegating the
IDataObject::DAdvise call to IDataAdviseHolder::Advise, you must delegate this c
all to IDataAdviseHolder::Unadvise to delete it.
See Also
IDataObject::DAdvise, IDataAdviseHolder::Unadvise
16.4.2.4 IDataObject::EnumDAdvise
Creates an object that can be used to enumerate the current advisory connections
.
HRESULT EnumDAdvise(
IEnumSTATDATA ** ppenumAdvise //Indirect pointer
);
Parameter
ppenumAdvise
[out] Indirect pointer to the IEnumSTATDATA interface on the new enumerator obje
ct. If the supplied value is NULL, there are no connections to advise sinks at t
his time.
Return Values
This method supports the standard return value E_OUTOFMEMORY, as well as the fol
lowing:
S_OK
The enumerator object is successfully instantiated or there are no connections.
OLE_E_ADVISENOTSUPPORTED
Advisory notifications are not supported by this object.
Remarks
The enumerator object created by this method implements the IEnumSTATDATA interf
ace, one of the standard enumerator interfaces that contain the Next, Reset, Clo
ne, and Skip methods. IEnumSTATDATA permits the enumeration of the data stored i
n an array of STATDATA structures. Each of these structures provides information
on a single advisory connection, and includes FORMATETC and ADVF information, a
s well as the pointer to the advise sink and the token representing the connecti
on.
16.4.2.4.1.1.1 Notes to Callers
After getting a pointer through this method, the data object can call the approp
riate enumeration methods. While the enumeration is in progress, the effect of a
dding more advisory connections on the subsequent enumeration is undefined.
16.4.2.4.1.1.2 Notes to Implementers
It is recommended that you use the COM data advise holder object to handle advis
ory connections. With the pointer obtained through a call to CreateDataAdviseHol
der, implementing IDataObject::EnumDAdvise becomes a simple matter of delegating
the call to IDataAdviseHolder::EnumAdvise. This creates the enumerator and supp
lies the pointer to the COM implementation of IEnumSTATDATA. At that point, you
can call its methods to enumerate the current advisory connections.
See Also
IEnumSTATDATA, IDataAdviseHolder::EnumAdvise
16.4.2.5 IDataObject::EnumFormatEtc
Creates an object for enumerating the FORMATETC structures for a data object. Th
ese structures are used in calls to IDataObject::GetData or IDataObject::SetData
.
HRESULT EnumFormatEtc(
DWORD dwDirection, //Specifies a value from the enumeration DATADIR
IEnumFORMATETC ** ppenumFormatetc //Indirect pointer to the new enumerator
object
);
Parameters
dwDirection
[in] Direction of the data through a value from the enumeration DATADIR.
typedef enum tagDATADIR
{
DATADIR_GET = 1,
DATADIR_SET = 2,
} DATADIR;
The value DATADIR_GET enumerates the formats that can be passed in to a call to
IDataObject::GetData. The value DATADIR_SET enumerates those formats that can be
passed in to a call to IDataObject::SetData.
ppenumFormatetc
[out] Indirect pointer to the IEnumFORMATETC interface on the new enumerator obj
ect.
Return Values
This method supports the standard return values E_INVALIDARG and E_OUTOFMEMORY,
as well as the following:
S_OK
Enumerator object was successfully created.
E_NOTIMPL
The direction specified by dwDirection is not supported.
OLE_S_USEREG
Requests that COM enumerate the formats from the registry.
Remarks
IDataObject::EnumFormatEtc creates an enumerator object that can be used to dete
rmine all of the ways the data object can describe data in a FORMATETC structure
, and supplies a pointer to its IEnumFORMATETC interface. This is one of the sta
ndard enumerator interfaces.
16.4.2.5.1.1.1 Notes to Callers
Having obtained the pointer, the caller can enumerate the FORMATETC structures b
y calling the enumeration methods of IEnumFORMATETC. Because the formats can cha
nge over time, there is no guarantee that an enumerated format is currently supp
orted because the formats can change over time. Accordingly, applications should
treat the enumeration as a hint of the format types that can be passed. The cal
ler is responsible for calling IEnumFormatEtc::Release when it is finished with
the enumeration.
IDataObject::EnumFormatEtc is called when one of the following actions occurs:
· An application calls OleSetClipboard. COM must determine what data to place on t
he Clipboard and whether it is necessary to put COM 1 compatibility formats on t
he Clipboard.
· Data is being pasted from the Clipboard or dropped. An application uses the firs
t acceptable format.
· The Paste Special dialog box is displayed. The target application builds the lis
t of formats from the FORMATETC entries.
16.4.2.5.1.1.2 Notes to Implementers
Formats can be registered statically in the registry or dynamically during objec
t initialization. If an object has an unchanging list of formats and these forma
ts are registered in the registry, COM provides an implementation of a FORMATETC
enumeration object that can enumerate formats registered under a specific CLSID
in the registry. A pointer to its IEnumFORMATETC interface is available through
a call to the helper function OleRegEnumFormatEtc. In this situation, therefore
, you can implement the EnumFormatEtc method simply with a call to this function
.
EXE applications can effectively do the same thing by implementing the method to
return the value OLE_S_USEREG. This return value instructs the default object h
andler to call OleRegEnumFormatEtc. Object applications that are implemented as
DLL object applications cannot return OLE_S_USEREG, so must call OleRegEnumForma
tEtc directly.
Private formats can be enumerated for OLE 1 objects, if they are registered with
the RequestDataFormats or SetDataFormats keys in the registry. Also, private fo
rmats can be enumerated for COM objects (all versions after OLE 1), if they are
registered with the GetDataFormats or SetDataFormats keys.
For OLE 1 objects whose servers do not have RequestDataFormats or SetDataFormats
information registered in the registry, a call to IDataObject::EnumFormatEtc pa
ssing DATADIR_GET only enumerates the Native and Metafile formats, regardless of
whether they support these formats or others. Calling EnumFormatEtc passing DAT
ADIR_SET on such objects only enumerates Native, regardless of whether the objec
t supports being set with other formats.
The FORMATETC structure returned by the enumeration usually indicates a NULL tar
get device (ptd). This is appropriate because, unlike the other members of FORMA
TETC, the target device does not participate in the object s decision as to whethe
r it can accept or provide the data in either a SetData or GetData call.
The TYMED member of FORMATETC often indicates that more than one kind of storage
medium is acceptable. You should always mask and test for this by using a Boole
an OR operator.
See Also
FORMATETC, IEnumFormatEtc, IDataObject::SetData, IDataObject::GetData
16.4.2.6 IDataObject::GetCanonicalFormatEtc
Provides a standard FORMATETC structure that is logically equivalent to one that
is more complex. You use this method to determine whether two different FORMATE
TC structures would return the same data, removing the need for duplicate render
ing.
HRESULT GetCanonicalFormatEtc(
FORMATETC * pFormatetcIn, //Pointer to the FORMATETC structure
FORMATETC * pFormatetcOut //Pointer to the canonical equivalent FORMATETC
structure
);
Parameters
pFormatetcIn
[in] Pointer to the FORMATETC structure that defines the format, medium, and tar
get device that the caller would like to use to retrieve data in a subsequent ca
ll such as IDataObject::GetData. The TYMED member is not significant in this cas
e and should be ignored.
pFormatetcOut
[out] Pointer to a FORMATETC structure that contains the most general informatio
n possible for a specific rendering, making it canonically equivalent to pFormat
etcIn. The caller must allocate this structure and the GetCanonicalFormatEtc met
hod must fill in the data. To retrieve data in a subsequent call like IDataObjec
t::GetData, the caller uses the supplied value of pFormatetcOut, unless the valu
e supplied is NULL. This value is NULL if the method returns DATA_S_SAMEFORMATET
C. The TYMED member is not significant in this case and should be ignored.
Return Values
This method supports the standard return values E_INVALIDARG, E_UNEXPECTED, and
E_OUTOFMEMORY, as well as the following:
S_OK
The returned FORMATETC structure is different from the one that was passed.
DATA_S_SAMEFORMATETC
The FORMATETC structures are the same and NULL is returned in pFormatetcOut.
DV_E_LINDEX
Invalid value for lindex; currently, only -1 is supported.
DV_E_FORMATETC
Invalid value for pFormatetc.
OLE_E_NOTRUNNING
Object application is not running.
Remarks
If a data object can supply exactly the same data for more than one requested FO
RMATETC structure, IDataObject::GetCanonicalFormatEtc can supply a canonical , or s
tandard FORMATETC that gives the same rendering as a set of more complicated FOR
MATETC structures. For example, it is common for the data returned to be insensi
tive to the target device specified in any one of a set of otherwise similar FOR
MATETC structures.
16.4.2.6.1.1.1 Notes to Callers
A call to this method can determine whether two calls to IDataObject::GetData on
a data object, specifying two different FORMATETC structures, would actually pr
oduce the same renderings, thus eliminating the need for the second call and imp
roving performance. If the call to GetCanonicalFormatEtc results in a canonical
format being written to the pFormatetcOut parameter, the caller then uses that s
tructure in a subsequent call to IDataObject::GetData.
16.4.2.6.1.1.2 Notes to Implementers
Conceptually, it is possible to think of FORMATETC structures in groups defined
by a canonical FORMATETC that provides the same results as each of the group mem
bers. In constructing the canonical FORMATETC, you should make sure it contains
the most general information possible that still produces a specific rendering.
For data objects that never provide device-specific renderings, the simplest imp
lementation of this method is to copy the input FORMATETC to the output FORMATET
C, store a NULL in the ptd field of the output FORMATETC, and return DATA_S_SAME
FORMATETC.
See Also
IDataObject::GetData, FORMATETC
16.4.2.7 IDataObject::GetData
Called by a data consumer to obtain data from a source data object. The GetData
method renders the data described in the specified FORMATETC structure and trans
fers it through the specified STGMEDIUM structure. The caller then assumes respo
nsibility for releasing the STGMEDIUM structure.
HRESULT GetData(
FORMATETC * pFormatetc, //Pointer to the FORMATETC structure
STGMEDIUM * pmedium //Pointer to the STGMEDIUM structure
);
Parameters
pFormatetc
[in] Pointer to the FORMATETC structure that defines the format, medium, and tar
get device to use when passing the data. It is possible to specify more than one
medium by using the Boolean OR operator, allowing the method to choose the best
medium among those specified.
pmedium
[out] Pointer to the STGMEDIUMstructure that indicates the storage medium contai
ning the returned data through its tymed member, and the responsibility for rele
asing the medium through the value of its punkOuter member. If punkForRelease is
NULL, the receiver of the medium is responsible for releasing it; otherwise, pu
nkForRelease points to the IUnknown on the appropriate object so its Release met
hod can be called. The medium must be allocated and filled in by IDataObject::Ge
tData.
Return Values
This method supports the standard return values E_INVALIDARG, E_UNEXPECTED, and
E_OUTOFMEMORY, as well as the following:
S_OK
Data was successfully retrieved and placed in the storage medium provided.
DV_E_LINDEX
Invalid value for lindex; currently, only -1 is supported.
DV_E_FORMATETC
Invalid value for pFormatetc.
DV_E_TYMED
Invalid tymed value.
DV_E_DVASPECT
Invalid dwAspect value.
OLE_E_NOTRUNNING
Object application is not running.
STG_E_MEDIUMFULL
An error occurred when allocating the medium.
Remarks
A data consumer calls IDataObject::GetData to retrieve data from a data object,
conveyed through a storage medium (defined through the STGMEDIUM structure).
16.4.2.7.1.1.1 Notes to Callers
You can specify more than one acceptable TYMED medium with the Boolean OR operat
or. IDataObject::GetData must choose from the OR d values the medium that best rep
resents the data, do the allocation, and indicate responsibility for releasing t
he medium.
Data transferred across a stream extends from position zero of the stream pointe
r through to the position immediately before the current stream pointer (that is
, the stream pointer position upon exit).
16.4.2.7.1.1.2 Notes to Implementers
IDataObject::GetData must check all fields in the FORMATETC structure. It is imp
ortant that IDataObject::GetData render the requested aspect and, if possible, u
se the requested medium. If the data object cannot comply with the information s
pecified in the FORMATETC, the method should return DV_E_FORMATETC. If an attemp
t to allocate the medium fails, the method should return STG_E_MEDIUMFULL. It is
important to fill in all of the fields in the STGMEDIUM structure.
Although the caller can specify more than one medium for returning the data, IDa
taObject::GetData can supply only one medium. If the initial transfer fails with
the selected medium, this method can be implemented to try one of the other med
ia specified before returning an error.
See Also
IDataObject::GetDataHere, IDataObject::SetData, FORMATETC, STGMEDIUM
16.4.2.8 IDataObject::GetDataHere
Called by a data consumer to obtain data from a source data object. This method
differs from the GetData method in that the caller must allocate and free the sp
ecified storage medium.
HRESULT GetDataHere(
FORMATETC * pFormatetc, //Pointer to the FORMATETC structure
STGMEDIUM * pmedium //Pointer to the STGMEDIUM structure
);
Parameters
pFormatetc
[in] Pointer to the FORMATETC structure that defines the format, medium, and tar
get device to use when passing the data. Only one medium can be specified in TYM
ED, and only the following TYMED values are valid: TYMED_STORAGE, TYMED_STREAM,
TYMED_HGLOBAL, or TYMED_FILE.
pmedium
[out] Pointer to the STGMEDIUM structure that defines the storage medium contain
ing the data being transferred. The medium must be allocated by the caller and f
illed in by IDataObject::GetDataHere. The caller must also free the medium. The
implementation of this method must always supply a value of NULL for the punkFor
Release member of the STGMEDIUM structure to which this parameter points.
Return Values
This method supports the standard return values E_INVALIDARG, E_UNEXPECTED, and
E_OUTOFMEMORY, as well as the following:
S_OK
Data was successfully retrieved and placed in the storage medium provided.
DV_E_LINDEX
Invalid value for lindex; currently, only -1 is supported.
DV_E_FORMATETC
Invalid value for pFormatetc.
DV_E_TYMED
Invalid tymed value.
DV_E_DVASPECT
Invalid dwAspect value.
OLE_E_NOTRUNNING
Object application is not running.
STG_E_MEDIUMFULL
The medium provided by the caller is not large enough to contain the data.
Remarks
The IDataObject::GetDataHere method is similar to IDataObject::GetData, except t
hat the caller must both allocate and free the medium specified in pmedium. GetD
ataHere renders the data described in a FORMATETC structure and copies the data
into that caller-provided STGMEDIUM structure. For example, if the medium is TYM
ED_HGLOBAL, this method cannot resize the medium or allocate a new hGlobal.
Some media are not appropriate in a call to GetDataHere, including GDI types suc
h as metafiles. The GetDataHere method cannot put data into a caller-provided me
tafile. In general, the only storage media it is necessary to support in this me
thod are TYMED_ISTORAGE, TYMED_ISTREAM, and TYMED_FILE.
When the transfer medium is a stream, COM makes assumptions about where the data
is being returned and the position of the stream s seek pointer. In a GetData cal
l, the data returned is from stream position zero through just before the curren
t seek pointer of the stream (that is, the position on exit). For GetDataHere, t
he data returned is from the stream position on entry through just before the po
sition on exit.
See Also
IDataObject::GetData, FORMATETC, STGMEDIUM
16.4.2.9 IDataObject::QueryGetData
Determines whether the data object is capable of rendering the data described in
the FORMATETC structure. Objects attempting a paste or drop operation can call
this method before calling IDataObject::GetData to get an indication of whether
the operation may be successful.
HRESULT QueryGetData(
FORMATETC * pFormatetc //Pointer to the FORMATETC structure
);
Parameter
pFormatetc
[in] Pointer to the FORMATETC structure defining the format, medium, and target
device to use for the query.
Return Values
This method supports the standard return values E_INVALIDARG, E_UNEXPECTED, and
E_OUTOFMEMORY, as well as the following:
S_OK
Subsequent call to IDataObject::GetData would probably be successful.
DV_E_LINDEX
Invalid value for lindex; currently, only -1 is supported.
DV_E_FORMATETC
Invalid value for pFormatetc.
DV_E_TYMED
Invalid tymed value.
DV_E_DVASPECT
Invalid dwAspect value.
OLE_E_NOTRUNNING
Object application is not running.
Remarks
The client of a data object calls IDataObject::QueryGetData to determine whether
passing the specified FORMATETC structure to a subsequent call to IDataObject::
GetData is likely to be successful. A successful return from this method does no
t necessarily ensure the success of the subsequent paste or drop operation.
See Also
IDataObject::GetData, FORMATETC
16.4.2.10 IDataObject::SetData
Called by an object containing a data source to transfer data to the object that
implements this method.
HRESULT SetData(
FORMATETC * pFormatetc, //Pointer to the FORMATETC structure
STGMEDIUM * pmedium, //Pointer to STGMEDIUM structure
BOOL fRelease //Indicates which object owns the storage medium after t
he call is completed
);
Parameters
pFormatetc
[in] Pointer to the FORMATETC structure defining the format used by the data obj
ect when interpreting the data contained in the storage medium.
pmedium
[in] Pointer to the STGMEDIUM structure defining the storage medium in which the
data is being passed.
fRelease
[in] If TRUE, the data object called, which implements IDataObject::SetData, own
s the storage medium after the call returns. This means it must free the medium
after it has been used by calling the ReleaseStgMedium function. If FALSE, the c
aller retains ownership of the storage medium and the data object called uses th
e storage medium for the duration of the call only.
Return Values
This method supports the standard return values E_FAIL, E_INVALIDARG, E_UNEXPECT
ED, and E_OUTOFMEMORY, as well as the following:
S_OK
Data was successfully transferred.
E_NOTIMPL
This method is not implemented for the data object.
DV_E_LINDEX
Invalid value for lindex; currently, only -1 is supported.
DV_E_FORMATETC
Invalid value for pFormatetc.
DV_E_TYMED
Invalid tymed value.
DV_E_DVASPECT
Invalid dwAspect value.
OLE_E_NOTRUNNING
Object application is not running.
Remarks
IDataObject::SetData allows another object to attempt to send data to the implem
enting data object. A data object implements this method if it supports receivin
g data from another object. If it does not support this, it should be implemente
d to return E_NOTIMPL.
The caller allocates the storage medium indicated by the pmedium, in which the d
ata is passed. The data object called does not take ownership of the data until
it has successfully received it and no error code is returned. The value of the
fRelease parameter indicates the ownership of the medium after the call returns.
FALSE indicates the caller still owns the medium, and the data object only has
the use of it during the call; TRUE indicates that the data object now owns it a
nd must release it when it is no longer needed.
The type of medium (TYMED) specified in the pformatetc and pmedium parameters mu
st be the same. For example, one cannot be an hGlobal (global handle) and the ot
her a stream.
See Also
IDataObject::GetData, FORMATETC, STGMEDIUM
16.4.3 IEnumFORMATETC
The IEnumFORMATETC interface is used to enumerate an array of FORMATETC structur
es. IEnumFORMATETC has the same methods as all enumerator interfaces: Next, Skip
, Reset, and Clone. For general information on these methods, refer to IEnumXXXX
.
16.4.3.1.1.1.1 When to Implement
IEnumFORMATETC must be implemented by all data objects to support calls to IData
Object::EnumFormatEtc, which supplies a pointer to the enumerator s IEnumFORMATETC
interface. If the data object supports a different set of FORMATETC information
depending on the direction of the data (whether a call is intended for the SetD
ata or GetData method of IDataObject), the implementation of IEnumFORMATETC must
be able to operate on both.
The order of formats enumerated through the IEnumFORMATETC object should be the
same as the order that the formats would be in when placed on the clipboard. Typ
ically, this order starts with private data formats and ends with presentation f
ormats such as CF_METAFILEPICT.
16.4.3.1.1.1.2 When to Use
Call the methods of IEnumFORMATETC when you need to enumerate the FORMATETC stru
ctures defining the formats and media supported by a given data object. This is
necessary in most data transfer operations, such as clipboard and drag-and-drop,
so the object on the other end of the data transfer can determine whether the a
ppropriate format and media for the data is supported.
The prototypes of the methods are as follows:
HRESULT Next(
ULONG celt,
FORMATETC * rgelt,
ULONG * pceltFetched
);
HRESULT Skip(
ULONG celt
);
HRESULT Reset(void)
HRESULT Clone(
IEnumFORMATETC ** ppenum
);
See Also
FORMATETC, IEnumXXXX
16.4.4 IEnumSTATDATA
The IEnumSTATDATA interface is used to enumerate through an array of STATDATA st
ructures, which contain advisory connection information for a data object. IEnum
STATDATA has the same methods as all enumerator interfaces: Next, Skip, Reset, a
nd Clone. For general information on these methods, refer to IEnumXXXX.
16.4.4.1.1.1.1 When to Implement
IEnumSTATDATA is implemented to enumerate advisory connections. Most application
s will not implement this directly, but will use the COM-provided implementation
. Pointers to this implementation are available in two ways:
· In a data object, call CreateDataAdviseHolder to get a pointer to the COM data a
dvise holder object, and then, to implement IDataObject::EnumDAdvise, call IData
AdviseHolder::EnumAdvise, which creates the enumeration object and supplies a po
inter to the implementation of IEnumSTATDATA.
· In a compound document object, call CreateOLEAdviseHolder to get a pointer to th
e COM advise holder object.
16.4.4.1.1.1.2 When to Use
Containers usually call methods that return a pointer to IEnumSTATDATA so the co
ntainer can use its methods to enumerate the existing advisory connections, and
use this information to instruct an object to release each of its advisory conne
ctions prior to closing down. IDataObject::EnumDAdvise, IDataAdviseHolder::EnumA
dvise, and methods all supply a pointer to IEnumSTATDATA.
The prototypes of the methods are as follows:
HRESULT Next(
ULONG celt,
STATDATA * rgelt,
ULONG * pceltFetched
);
HRESULT Skip(
ULONG celt
);
HRESULT Reset(void)
HRESULT Clone(
IEnumSTATDATA ** ppenum
);
See Also
STATDATA, IEnumXXXX, IDataObject::EnumDAdvise, IDataAdviseHolder::EnumAdvise
16.5.2 CreateFormatEnumerator
Creates an object that implements IEnumFORMATETC over a static array of FORMATET
C structures.
HRESULT CreateFormatEnumerator(
UINT cfmtetc, //Number of FORMATETC structures in rgfmtetc
FORMATETC *rgfmtetc, //Static array of formats.
IenumFORMATETC **ppenumfmtetc //Address of output variable that receiv
es the
// IEnumFORMATETC interface pointer
);
Parameters
cfmtetc
[in] Number of FORMATETC structures in the static array specified by the rgfmtet
c parameter. The cfmtetc parameter cannot be zero.
rgfmtetc
[in] Pointer to a static array of FORMATETC structures.
ppenumfmtetc
[out] Address of IEnumFORMATETC* pointer variable that receives the interface po
inter to the enumerator object.
Return Values
S_OK
The operation was successful.
E_INVALIDARG
One or more parameters are invalid.
Remarks
The CreateFormatEnumerator function creates an enumerator object that implements
IEnumFORMATETC over a static array of FORMATETC structures. The cfmtetc paramet
er specifies the number of these structures. With the pointer, you can call the
standard enumeration methods to enumerate the structures, as described in the IE
numXXX reference.
16.5.3 ReleaseStgMedium
Frees the specified storage medium.
void ReleaseStgMedium(
STGMEDIUM * pmedium //Pointer to storage medium to be freed
);
Parameter
pmedium
[in] Pointer to the storage medium that is to be freed.
Return Value
None.
Remarks
The ReleaseStgMedium function calls the appropriate method or function to releas
e the specified storage medium. Use this function during data transfer operation
s where storage medium structures are parameters, such as IDataObject::GetData o
r IDataObject::SetData. In addition to identifying the type of the storage mediu
m, this structure specifies the appropriate IUnknown::Release method for releasi
ng the storage medium when it is no longer needed.
It is common to pass a STGMEDIUM from one body of code to another, such as in ID
ataObject::GetData, in which the one called can allocate a medium and return it
to the caller. ReleaseStgMedium permits flexibility in whether the receiving bod
y of code owns the medium, or whether the original provider of the medium still
owns it, in which case the receiving code needs to inform the provider that it c
an free the medium.
When the original provider of the medium is responsible for freeing the medium,
the provider calls ReleaseStgMedium, specifying the medium and the appropriate I
Unknown pointer as the punkForRelease structure member. Depending on the type of
storage medium being freed, one of the following actions is taken, followed by
a call to the Release method on the specified IUnknown pointer:
Medium ReleaseStgMedium Action
TYMED_HGLOBAL None.
TYMED_GDI None.
TYMED_ENHMF None.
TYMED_MFPICT None.
TYMED_FILE Frees the file name string using standard memory management mech
anisms.
TYMED_ISTREAM Calls IStream::Release.
TYMED_ISTORAGE Calls IStorage::Release.
The provider indicates that the receiver of the medium is responsible for freein
g the medium by specifying NULL for the punkForRelease structure member. Then th
e receiver calls ReleaseStgMedium, which makes a call as described in the follow
ing table depending on the type of storage medium being freed:
Medium ReleaseStgMedium Action
TYMED_HGLOBAL Calls the Win32 GlobalFree function on the handle.
TYMED_GDI Calls the Win32 DeleteObject function on the handle.
TYMED_ENHMF Deletes the enhanced metafile.
TYMED_MFPICT The hMF that it contains is deleted with the Win32 DeleteMetaFil
e function; then the handle itself is passed to GlobalFree.
TYMED_FILE Frees the disk file by deleting it. Frees the file name string b
y using the standard memory management paradigm.
TYMED_ISTREAM Calls IStream::Release.
TYMED_ISTORAGE Calls IStorage::Release.
In either case, after the call to ReleaseStgMedium, the specified storage medium
is invalid and can no longer be used.
See Also
STGMEDIUM structure
16.6 Uniform Data Transfer Structure Descriptions
16.6.1 DVASPECTINFO
The DVASPECTINFO structure is used in the IViewObject::Draw method to optimize r
endering of an inactive object by making more efficient use of the GDI. The pvAs
pect parameter in IViewObject::Draw points to this structure. It is defined as f
ollows:
typedef struct STRUCT tagDVASPECTINFO
{
UNIT cb;
DWORD dwFlags;
} DVASPECTINFO;
Members
cb
Size of the structure in bytes. The size includes this member as well as the dwF
lags member.
dwFlags
A value taken from the DVASPECTINFOFLAG enumeration.
See Also
DVASPECTINFOFLAG
16.6.2 DVEXTENTINFO
The DVEXTENTINFO structure is used in IViewObjectEx::GetNaturalExtent.
typedef struct tagDVEXTENTINFO
{
ULONG cb;
DWORD dwExtentMode;
SIZEL sizelProposed;
}DVEXTENTINFO;
Members
cb
Size of the structure in bytes. The size includes this member as well as the dwE
xtentMode and sizelProposed members.
dwExtentMode
Indicates whether the sizing mode is content or integral sizing. See the DVEXTEN
TMODE enumeration for these values.
sizelProposed
Specifies the proposed size in content sizing or the preferred size in integral
sizing.
See Also
DVEXTENTMODE
16.6.3 DVTARGETDEVICE
Use the DVTARGETDEVICE structure to specify information about the target device
for which data is being composed. DVTARGETDEVICE contains enough information abo
ut a Windows target device so a handle to a device context (hDC) can be created
using the Windows CreateDC function.
typedef struct tagDVTARGETDEVICE
{
DWORD tdSize;
WORD tdDriverNameOffset;
WORD tdDeviceNameOffset;
WORD tdPortNameOffset;
WORD tdExtDevmodeOffset;
BYTE tdData[1];
}DVTARGETDEVICE;
Members
tdSize
Size, in bytes, of the DVTARGETDEVICE structure. The initial size is included so
the structure can be copied more easily.
tdDriverNameOffset
Offset, in bytes, from the beginning of the structure to the device driver name,
which is stored as a NULL-terminated string in the tdData buffer.
tdDeviceNameOffset
Offset, in bytes, from the beginning of the structure to the device name, which
is stored as a NULL-terminated string in the tdData buffer. This value can be ze
ro to indicate no device name.
tdPortNameOffset
Offset, in bytes, from the beginning of the structure to the port name, which is
stored as a NULL-terminated string in the tdData buffer. This value can be zero
to indicate no port name.
tdExtDevmodeOffset
Offset, in bytes, from the beginning of the structure to the DEVMODE structure r
etrieved by calling ExtDeviceMode.
tdData
Aray of bytes containing data for the target device. It is not necessary to incl
ude empty strings in tdData (for names where the offset value is zero).
Remarks
Some OLE 1 client applications incorrectly construct target devices by allocatin
g too few bytes in the DEVMODE structure for the OLETARGETDEVICE. They typically
only supply the number of bytes in the DEVMODE.dmSize member. The number of byt
es to be allocated should be the sum of DEVMODE.dmSize + DEVMODE.dmDriverExtra.
When a call is made to the CreateDC function with an incorrect target device, th
e printer driver tries to access the additional bytes and unpredictable results
can occur. To protect against a crash and make the additional bytes available, C
OM pads the size of COM target devices created from OLE 1 target devices.
See Also
FORMATETC, IEnumFORMATETC,
16.6.4 FORMATETC
The FORMATETC structure is a generalized Clipboard format. It is enhanced to enc
ompass a target device, the aspect or view of the data, and a storage medium ind
icator. Where one might expect to find a Clipboard format, COM uses a FORMATETC
data structure instead. This structure is used as a parameter in COM functions a
nd methods that require data format information.
Defined in the IEnumFORMATETC interface.
typedef struct tagFORMATETC
{
CLIPFORMAT cfFormat;
DVTARGETDEVICE *ptd;
DWORD dwAspect;
LONG lindex;
DWORD tymed;
}FORMATETC, *LPFORMATETC;
Members
cfFormat
Particular clipboard format of interest. There are three types of formats recogn
ized by COM:
· Standard interchange formats, such as CF_TEXT.
· Private application formats understood only by the application offering the form
at, or by other applications offering similar features.
· COM formats, which are used to create linked or embedded objects.
ptd
Pointer to a DVTARGETDEVICE structure containing information about the target de
vice for which the data is being composed. A NULL value is used whenever the spe
cified data format is independent of the target device or when the caller doesn t
care what device is used. In the latter case, if the data requires a target devi
ce, the object should pick an appropriate default device (often the display for
visual components). Data obtained from an object with a NULL target device, such
as most metafiles, is independent of the target device. The resulting data is u
sually the same as it would be if the user chose the Save As command from the Fi
le menu and selected an interchange format.
dwAspect
One of the DVASPECT enumeration constants that indicate how much detail should b
e contained in the rendering. A single clipboard format can support multiple asp
ects or views of the object. Most data and presentation transfer and caching met
hods pass aspect information. For example, a caller might request an object s icon
ic picture, using the metafile clipboard format to retrieve it. Note that only o
ne DVASPECT value can be used in dwAspect. That is, dwAspect cannot be the resul
t of a BOOLEAN OR operation on several DVASPECT values.
lindex
Part of the aspect when the data must be split across page boundaries. The most
common value is -1, which identifies all of the data. For the aspects DVASPECT_T
HUMBNAIL and DVASPECT_ICON, lindex is ignored.
tymed
One of the TYMED enumeration constants which indicate the type of storage medium
used to transfer the object s data. Data can be transferred using whatever medium
makes sense for the object. For example, data can be passed using global memory
, a disk file, or structured storage objects. For more information, see the TYME
D enumeration.
Remarks
The FORMATETC structure is used by methods in the data transfer and presentation
interfaces as a parameter specifying the data being transferred. For example, t
he IDataObject::GetData method uses the FORMATETC structure to indicate exactly
what kind of data the caller is requesting.
See Also
DVASPECT, IDataAdviseHolder, IDataObject, IEnumFORMATETC, STATDATA, STGMEDIUM, T
YMED
16.6.5 STATDATA
The STATDATA structure is the data structure used to specify each advisory conne
ction. It is used for enumerating current advisory connections. It holds data re
turned by the IEnumSTATDATA enumerator. This enumerator interface is returned by
IDataObject:DAdvise. Each advisory connection is specified by a unique STATDATA
structure.
Defined in com.h.
typedef struct tagSTATDATA
{
FORMATETC formatetc;
DWORD grfAdvf;
IAdviseSink* pAdvSink;
DWORD dwConnection;
} STATDATA;
Members
formatetc
The FORMATETC structure for the data of interest to the advise sink. The advise
sink receives notification of changes to the data specified by this FORMATETC st
ructure.
grfAdvf
The ADVF enumeration value that determines when the advisory sink is notified of
changes in the data.
pAdvSink
The pointer for the IAdviseSink interface that will receive change notifications
.
dwConnection
The token that uniquely identifies the advisory connection. This token is return
ed by the method that sets up the advisory connection.
See Also
IEnumSTATDATA
16.6.6 STGMEDIUM
The STGMEDIUM structure is a generalized global memory handle used for data tran
sfer operations by the IAdviseSink, and IDataObject.
Defined in the IAdviseSink interface (advsnk.idl).
typedef struct tagSTGMEDIUM
{
DWORD tymed;
[switch_type(DWORD), switch_is((DWORD) tymed)]
union {
[case(TYMED_GDI)] HBITMAP hBitmap;
[case(TYMED_MFPICT)] HMETAFILEPICT hMetafilePict;
[case(TYMED_ENHMF)] HENHMETAFILE hEnhMetaFile;
[case(TYMED_HGLOBAL)] HGLOBAL hGlobal;
[case(TYMED_FILE)] LPWSTR lpszFileName;
[case(TYMED_ISTREAM)] IStream *pstm;
[case(TYMED_ISTORAGE)] IStorage *pstg;
[default] ;
};
[unique] IUnknown *pUnkForRelease;
}STGMEDIUM;
typedef STGMEDIUM *LPSTGMEDIUM;
Members
tymed
Type of storage medium. The marshaling and unmarshaling routines use this value
to determine which union member was used. This value must be one of the elements
of the TYMED enumeration.
union member
Handle, string, or interface pointer that the receiving process can use to acces
s the data being transferred. If tymed is TYMED_NULL, the union member is undefi
ned; otherwise, it is one of the following:
hBitmap
Bitmap handle. The tymed member is TYMED_GDI.
hMetafilePict
Metafile handle. The tymed member is TYMED_MFPICT.
hEnhMetaFile
Enhanced metafile handle. The tymed member is TYMED_ENHMF.
hGlobal
Global memory handle. The tymed member is TYMED_HGLOBAL.
lpszFileName
Pointer to the path of a disk file that contains the data. The tymed member is T
YMED_FILE.
pstm
Pointer to an IStream interface. The tymed member is TYMED_ISTREAM.
pstg
Pointer to an IStorage interface. The tymed member is TYMED_ISTORAGE.
pUnkForRelease
Pointer to an interface instance that allows the sending process to control the
way the storage is released when the receiving process calls the ReleaseStgMediu
m function. If pUnkForRelease is NULL, ReleaseStgMedium uses default procedures
to release the storage; otherwise, ReleaseStgMedium uses the specified IUnknown
interface.
See Also
FORMATETC, IAdviseSink, IDataObject, ReleaseStgMedium
16.7 Uniform Data Transfer Enumeration Descriptions
16.7.1 ADVF
The ADVF enumeration values are flags used by a container object to specify the
requested behavior when setting up an advise sink or a caching connection with a
n object. These values have different meanings, depending on the type of connect
ion in which they are used, and each interface uses its own subset of the flags.
typedef enum tagADVF
{
ADVF_NODATA = 1,
ADVF_ONLYONCE = 2,
ADVF_PRIMEFIRST = 4,
ADVFCACHE_NOHANDLER = 8,
ADVFCACHE_FORCEBUILTIN = 16,
ADVFCACHE_ONSAVE = 32,
ADVF_DATAONSTOP = 64
} ADVF;
Elements
ADVF_NODATA
For data advisory connections (IDataObject::DAdvise or IDataAdviseHolder::Advise
), this flag requests the data object not to send data when it calls IAdviseSink
::OnDataChange. The recipient of the change notification can later request the d
ata by calling IDataObject::GetData. The data object can honor the request by pa
ssing TYMED_NULL in the STGMEDIUM parameter, or it can provide the data anyway.
For example, the data object might have multiple advisory connections, not all o
f which specified ADVF_NODATA, in which case the object might send the same noti
fication to all connections. Regardless of the container s request, its IAdviseSin
k implementation must check the STGMEDIUM parameter because it is responsible fo
r releasing the medium if it is not TYMED_NULL.
ADVF_NODATA is not a valid flag for view advisory connections (IViewObject::SetA
dvise) and it returns E_INVALIDARG.
ADVF_PRIMEFIRST
Requests that the object not wait for the data or view to change before making a
n initial call to IAdviseSink::OnDataChange (for data or view advisory connectio
ns) or updating the cache (for cache connections). Used with ADVF_ONLYONCE, this
parameter provides an asynchronous GetData call.
ADVF_ONLYONCE
Requests that the object make only one change notification or cache update befor
e deleting the connection.
ADVF_ONLYONCE automatically deletes the advisory connection after sending one da
ta or view notification. The advisory sink receives only one IAdviseSink call. A
nonzero connection identifier is returned if the connection is established, so
the caller can use it to delete the connection prior to the first change notific
ation.
For data change notifications, the combination of ADVF_ONLYONCE and ADVF_PRIMEFI
RST provides, in effect, an asynchronous IDataObject::GetData call.
When used with caching, ADVF_ONLYONCE updates the cache one time only, on receip
t of the first OnDataChange notification. After the update is complete, the advi
sory connection between the object and the cache is disconnected. The source obj
ect for the advisory connection calls the IAdviseSink::Release method.
ADVF_DATAONSTOP
For data advisory connections, assures accessibility to data. This flag indicate
s that when the data object is closing, it should call IAdviseSink::OnDataChange
, providing data with the call. Typically, this value is used in combination wit
h ADVF_NODATA. Without this value, by the time an OnDataChange call without data
reaches the sink, the source might have completed its shutdown and the data mig
ht not be accessible. Sinks that specify this value should accept data provided
in OnDataChange if it is being passed, because they may not get another chance t
o retrieve it.
For cache connections, this flag indicates that the object should update the cac
he as part of object closure.
ADVF_DATAONSTOP is not a valid flag for view advisory connections.
ADVFCACHE_NOHANDLER
Synonym for ADVFCACHE_FORCEBUILTIN, which is used more often.
ADVFCACHE_FORCEBUILTIN
This value is used by DLL object applications and object handlers that perform t
he drawing of their objects. ADVFCACHE_FORCEBUILTIN instructs COM to cache prese
ntation data to ensure that there is a presentation in the cache. This value is
not a valid flag for data or view advisory connections. For cache connections, t
his flag caches data that requires only code shipped with COM (or the underlying
operating system) to be present in order to produce it with IDataObject::GetDat
a or IViewObject::Draw. By specifying this value, the container can ensure that
the data can be retrieved even when the object or handler code is not available.
ADVFCACHE_ONSAVE
For cache connections, this flag updates the cached representation only when the
object containing the cache is saved. The cache is also updated when the COM ob
ject transitions from the running state back to the loaded state (because a subs
equent save operation would require rerunning the object). This value is not a v
alid flag for data or view advisory connections.
Remarks
For a data or view advisory connection, the container uses the ADVF constants wh
en setting up a connection between an IAdviseSink instance and and either an IDa
taObject or IViewObject instance. These connections are set up using the IDataOb
ject::DAdvise, IDataAdviseHolder::Advise, or IViewObject::SetAdvisemethods.
These constants are also used in the advf member of the STATDATA structure. This
structure is used by IEnumSTATDATA to describe the enumerated connections, and
the advf member indicates the flags that were specified when the advisory or cac
he connection was established. When STATDATA is used for an IOleObject::EnumAdvi
se enumerator, the advf member is indeterminate.
See Also
IDataAdviseHolder, IDataObject, IEnumSTATDATA,
16.7.2 DATADIR
The DATADIR enumeration values specify the direction of the data flow in the dwD
irection parameter of the IDataObject::EnumFormatEtc method. This determines the
formats that the resulting enumerator can enumerate.
typedef enum tagDATADIR
{
DATADIR_GET = 1,
DATADIR_SET = 2
} DATADIR;
Elements
DATADIR_GET
Requests that IDataObject::EnumFormatEtc supply an enumerator for the formats th
at can be specified in IDataObject::GetData.
DATADIR_SET
Requests that IDataObject::EnumFormatEtc supply an enumerator for the formats th
at can be specified in IDataObject::SetData.
See Also
IDataObject
16.7.3 DVASPECT
The DVASPECT enumeration values specify the desired data or view aspect of the o
bject when drawing or getting data.
typedef enum tagDVASPECT
{
DVASPECT_CONTENT = 1,
DVASPECT_THUMBNAIL = 2,
DVASPECT_ICON = 4,
DVASPECT_DOCPRINT = 8
} DVASPECT;
Elements
DVASPECT_CONTENT
Provides a representation of an object so it can be displayed as an embedded obj
ect inside of a container. This value is typically specified for compound docume
nt objects. The presentation can be provided for the screen or printer.
DVASPECT_THUMBNAIL
Provides a thumbnail representation of an object so it can be displayed in a bro
wsing tool. The thumbnail is approximately a 120 by 120 pixel, 16-color (recomme
nded) device-independent bitmap potentially wrapped in a metafile.
DVASPECT_ICON
Provides an iconic representation of an object.
DVASPECT_DOCPRINT
Provides a representation of the object on the screen as though it were printed
to a printer using the Print command from the File menu. The described data may
represent a sequence of pages.
Remarks
Values of this enumeration are used to define the dwAspect field of the FORMATET
C structure. Only one DVASPECT value can be used to specify a single presentatio
n aspect in a FORMATETC structure. The FORMATETC structure is used in many COM f
unctions and interface methods that require information on data presentation.
See Also
IAdviseSink, IDataObject, FORMATETC
16.7.4 DVASPECT2
The DVASPECT2 enumeration value is used in IViewObject::Draw to specify new draw
ing aspects used to optimize the drawing process.
typedef enum tagDVASPECT2
{
DVASPECT_OPAQUE = 16,
DVASPECT_TRANSPARENT = 32
} DVASPECT2;
Elements
DVASPECT_OPAQUE
Represents the opaque, easy to clip parts of an object. Objects may or may not s
upport this aspect.
DVASPECT_TRANSPARENT
Represents the transparent or irregular parts of on object, typically parts that
are expensive or impossible to clip out. Objects may or may not support this as
pect.
Remarks
To support drawing optimizations to reduce flicker, an object needs to be able t
o draw and return information about three separate aspects of itself:
DVASPECT_CONTENT
Same as before. Specifies the entire content of an object. All objects should su
pport this aspect.
DVASPECT_OPAQUE
Represents the opaque, easy to clip parts of an object. Objects may or may not s
upport this aspect.
DVASPECT_TRANSPARENT
Represents the transparent or irregular parts of on object, typically parts that
are expensive or impossible to clip out. Objects may or may not support this as
pect.
The container can determine which of these drawing aspects an object supports by
calling the new method IViewObjectEx::GetViewStatus. Individual bits return inf
ormation about which aspects are supported. If an object does not support the IV
iewObjectEx interface, it is assumed to support only DVASPECT_CONTENT.
Depending on which aspects are supported, the container can ask the object to dr
aw itself during the front to back pass only, the back to front pass only, or bo
th. The various possible cases are:
· Objects supporting only DVASPECT_CONTENT should be drawn during the back to fron
t pass, with all opaque parts of any overlapping object clipped out. Since all o
bjects should support this aspect, a container not concerned about flickering -
maybe because it is drawing in an offscreen bitmap - can opt to draw all objects
that way and skip the front to back pass.
· Objects supporting DVASPECT_OPAQUE may be asked to draw this aspect during the f
ront to back pass. The container is responsible for clipping out the object s opaq
ue regions (returned by IViewObjectEx::GetRegion) before painting any further o
bject behind it.
· Objects supporting DVASPECT_TRANSPARENT may be asked to draw this aspect during
the back to front pass. The container is responsible for clipping out opaque par
ts of overlapping objects before letting an object draw this aspect.
Even when DVASPECT_OPAQUE and DVASPECT_TRANSPARENT are supported, the container
is free to use these aspects or not. In particular, if it is painting in an offs
creen bitmap and consequently is unconcerned about flicker, the container may us
e DVASPECT_CONTENT and a one-pass drawing only. However, in a two-pass drawing,
if the container uses DVASPECT_OPAQUE during the front to back pass, then it mus
t use DVASPECT_TRANSPARENT during the back to front pass to complete the renderi
ng of the object.
16.7.5 DVASPECTINFOFLAG
The DVASPECTINFOFLAG enumeration value is used in the DVASPECTINFO structure to
indicate whether an object can support optimized drawing of itself.
typedef enum tagDVASPECTINFOFLAG
{
DVASPECTINFOFLAG_CANOPTIMIZE = 1
} DVASPECTINFOFLAG;
Elements
DVASPECTINFOFLAG_CANOPTIMIZE
If TRUE, indicates that the object can support optimized rendering of itself. Si
nce most objects on a form share the same font, background color, and border typ
es, leaving these values in the device context allows the next object to use the
m without having to re-select them. Specifically, the object can leave the font,
brush, and pen selected on return from the IViewObject::Draw method instead of
deselecting these from the device context. The container then must deselect thes
e values at the end of the overall drawing process. The object can also leave ot
her drawing state changes in the device context, such as the background color, t
he text color, raster operation code, the current point, the line drawing, and t
he poly fill mode. The object cannot change state values unless other objects ar
e capable of restoring them. For example, the object cannot leave a changed mode
, transformation value, selected bitmap, clip region, or metafile.
See Also
DVASPECTINFO
16.7.6 STATFLAG
The STATFLAG enumeration values indicate whether the method should try to return
a name in the pwcsName member of the STATSTG structure. The values are used in
the ILockBytes::Stat, IStorage::Stat, and IStream::Stat methods to save memory w
hen the pwcsName member is not needed.
Defined in the IOLETypes pseudo-interface (oletyp.idl).
typedef enum tagSTATFLAG
{
STATFLAG_DEFAULT = 0,
STATFLAG_NONAME = 1
} STATFLAG;
Elements
STATFLAG_DEFAULT
Requests that the statistics include the pwcsName member of the STATSTG structur
e.
STATFLAG_NONAME
Requests that the statistics not include the pwcsName member of the STATSTG stru
cture. If the name is omitted, there is no need for the Stat methods to allocate
and free memory for the string value for the name and the method can save an Al
loc and Free operation.
See Also
ILockBytes::Stat, IStorage::Stat, IStream::Stat
16.7.7 TYMED
The TYMED enumeration values indicate the type of storage medium being used in a
data transfer. They are used in the STGMEDIUM or FORMATETC structures.
typedef [transmit_as(long)] enum tagTYMED
{
TYMED_HGLOBAL = 1,
TYMED_FILE = 2,
TYMED_ISTREAM = 4,
TYMED_ISTORAGE = 8,
TYMED_GDI = 16,
TYMED_MFPICT = 32,
TYMED_ENHMF = 64,
TYMED_NULL = 0
} TYMED;
Elements
TYMED_HGLOBAL
The storage medium is a global memory handle (HGLOBAL). Allocate the global hand
le with the GMEM_SHARE flag. If the STGMEDIUM punkForRelease member is NULL, the
destination process should use GlobalFree to release the memory.
TYMED_FILE
The storage medium is a disk file identified by a path. If the STGMEDIUM punkFor
Release member is NULL, the destination process should use OpenFile to delete th
e file.
TYMED_ISTREAM
The storage medium is a stream object identified by an IStream pointer. Use IStr
eam::Read to read the data. If the STGMEDIUM punkForRelease member is NULL, the
destination process should use IStream::Release to release the stream component.
TYMED_ISTORAGE
The storage medium is a storage component identified by an IStorage pointer. The
data is in the streams and storages contained by this IStorage instance. If the
STGMEDIUM punkForRelease member is NULL, the destination process should use ISt
orage::Release to release the storage component.
TYMED_GDI
The storage medium is a GDI component (HBITMAP). If the STGMEDIUM punkForRelease
member is NULL, the destination process should use DeleteObject to delete the b
itmap.
TYMED_MFPICT
The storage medium is a metafile (HMETAFILEIf the STGMEDIUM punkForRelease membe
r is NULL, the destination process should use DeleteMetaFile to delete the bitma
p.
TYMED_ENHMF
The storage medium is an enhanced metafile. If the STGMEDIUM punkForRelease memb
er is NULL, the destination process should use DeleteEnhMetaFile to delete the b
itmap.
TYMED_NULL
No data is being passed.
Remarks
During data transfer operations, a storage medium is specified. This medium must
be released after the data transfer operation. The provider of the medium indic
ates its choice of ownership scenarios in the value it provides in the STGMEDIUM
structure. A NULL value for the IUNKNOWN field indicates that the receiving bod
y of code owns and can free the medium. A non-NULL pointer specifies that Releas
eStgMedium can always be called to free the medium.
See Also
FORMATETC, IAdviseSink, IDataObject, ReleaseStgMedium, STGMEDIUM
17. Type Libraries
Type libraries and the type description interfaces provide a way to read and bin
d to the descriptions of objects in a type library. These descriptions are used
by COM clients when they browse, create, and manipulate COM objects.
The type description interfaces described in this chapter include:
· ITypeLib Retrieves information about a type library.
· ITypeLib2 Allows ITypeLib to cast to an ITypeLib2 in performance-sensitive cases
.
· ITypeInfo Reads the type information within the type library.
· ITypeInfo2 Allows ITypeInfo to cast to an ITypeInfo2 in performance-sensitive cas
es.
· ITypeComp Creates compilers that use type information.
This chapter also describes functions for loading, registering, and querying typ
e libraries.
17.1 Overview of Type Description Interfaces
A type library is a container for type descriptions of one or more objects, and
is accessed through the ITypeLib interface. The ITypeLib interface provides acce
ss to information about the type description in a type library. The descriptions
of individual objects are accessed through the ITypeInfo interface.
In addition, there are two new interfaces for Automation:
ITypeInfo2::ITypeInfo
ITypeLib2::ITypeLib
Because they inherit from ITypeInfo and ITypeLib, an ITypeInfo can be cast to an
ITypeInfo2 instead of using the calls QueryInterface() and Release().
By adding the new methods described in the following section, QueryInterface can
be called to ITypeInfo2 and ITypeLib2 in the same way as ITypeInfo and ITypeLib
.
The ITypeInfo interface is typically used for reading information about objects.
For example, an object browser tool can use ITypeInfo to extract information ab
out the characteristics and capabilities of objects from type libraries.
Implemented by Used by Header file name
Oleaut32.dll (32-bit systems)
Typelib.dll (16-bit systems) Tools that need to access the descriptions of ob
jects contained in type libraries. Oleauto.h
Dispatch.h
Type information interfaces are intended to describe the parts of the applicatio
n that can be called by outside clients, rather than those that might be used in
ternally to build an application.
The ITypeInfo interface provides access to the following:
· The set of function descriptions associated with the type. For interfaces, this
contains the set of member functions in the interface.
· The set of data member descriptions associated with the type. For structures, th
is contains the set of fields of the type.
· The general attributes of the type, such as whether it describes a structure, an
interface, and so on.
The type description of an IDispatch interface can be used to implement the inte
rface. For more information, see the description of CreateStdDispatch in Chapter
18.
An instance of ITypeInfo provides various information about the type of an objec
t, and is used in different ways. A compiler can use an ITypeInfo to compile ref
erences to members of the type. A type interface browser can use it to find info
rmation about each member of the type. An IDispatch implementor can use it to pr
ovide automatic delegation of IDispatch calls to an interface.
17.1.1 Type Descriptions
The information associated with an object described by ITypeInfo can include a s
et of functions, a set of data members, and various type attributes. It is essen
tially the same as the information described by a C++ class declaration, which c
an be used to define both interfaces and structures, as well as any combination
of functions and data members. In addition to interfaces and structure definitio
ns, the ITypeInfo interface is used to describe other types, including enumerati
ons and aliases. Because the interface to a C file or library is simply a set of
functions and variable declarations, ITypeInfo can also be used to describe the
m.
Type information comprises individual type descriptions. Each type description m
ust have one of the following forms:
Category ODL keyword Description
Return Value
The return value obtained from the returned HRESULT is one of the following:
Return value Meaning
S_OK Success.
E_OUTOFMEMORY Out of memory.
E_INVALIDARG One or more of the arguments is invalid.
TYPE_E_IOERROR The function could not write to the file.
TYPE_E_INVDATAREAD The function could not read from the file.
TYPE_E_UNSUPFORMAT The type library has an older format.
TYPE_E_INVALIDSTATE The type library could not be opened.
TYPE_E_CANTLOADLIBRARY The library or .dll file could not be loaded.
TYPE_E_ELEMENTNOTFOUND The element was not found.
Comments
Passing *pcFound = n indicates that there is enough room in the ppTInfo and rgMe
mId arrays for n (ptinfo, memid) pairs. The function returns MEMBERID_NIL in rgM
emId[i], if the name in szNameBuf is the name of the type information in ppTInfo
[i].
17.2.3.2 ITypeLib::GetDocumentation
HRESULT GetDocumentation(
int index,
BSTR FAR* pBstrName,
BSTR FAR* pBstrDocString,
unsigned long FAR* pdwHelpContext,
BSTR FAR* pBstrHelpFile
);
Retrieves the library ' s documentation string, the complete Help file name and path, a
nd the context identifier for the library Help topic in the Help file.
Parameters
index
Index of the type description whose documentation is to be returned. I If index
is-1, then the documentation for the library itself is returned.
pBstrName
Returns a BSTR that contains the name of the specified item. If the caller does
not need the item name, then pBstrName can be Null.
pBstrDocString
Returns a BSTR that contains the documentation string for the specified item. If
the caller does not need the documentation string, then pBstrDocString can be N
ull.
pdwHelpContext
Returns the Help context identifier (ID) associated with the specified item. If
the caller does not need the Help context ID, then pdwHelpContext can be Null.
pBstrHelpFile
Returns a BSTR that contains the fully qualified name of the Help file. If the c
aller does not need the Help file name, then pBstrHelpFile can be Null.
Return Value
The return value obtained from the returned HRESULT is one of the following:
Return Value
The return value obtained from the returned HRESULT is one of the following:
Return value Meaning
S_OK Success.
TYPE_E_ELEMENTNOTFOUND No type description was found in the library with the sp
ecified GUID.
E_OUTOFMEMORY Out of memory.
E_INVALIDARG One or more of the arguments is invalid.
TYPE_E_IOERROR The function could not write to the file.
TYPE_E_INVDATAREAD The function could not read from the file.
TYPE_E_UNSUPFORMAT The type library has an older format.
TYPE_E_REGISTRYACCESS There was an error accessing the system registration dat
abase.
TYPE_E_INVALIDSTATE The type library could not be opened.
17.2.3.8 ITypeLib::GetTypeInfoType
HRESULT GetTypeInfoType(
unsigned int index,
TYPEKIND FAR* pTKind
);
Retrieves the type of a type description.
Parameters
index
The index of the type description within the type library.
pTKind
A pointer to the TYPEKIND enumeration for the type description.
Return Value
The return value obtained from the returned HRESULT is one of the following:
Return value Meaning
S_OK Success.
TYPE_E_ELEMENTNOTFOUND Index is outside the range of 0 to GetTypeInfoCount() 1.
17.2.3.9 ITypeLib::IsName
HRESULT IsName(
OLECHAR FAR* szNameBuf,
unsigned long lHashVal,
BOOL pfName
);
Indicates whether a passed-in string contains the name of a type or member descr
ibed in the library.
Parameter
szNameBuf
The string to test. If IsName() is successful, szNameBuf is modified to match th
e case (capitalization) found in the type library.
lHashVal
The hash value of szNameBuf.
pfName
On return, set to True if szNameBuf was found in the type library; otherwise Fal
se.
Return Value
The return value obtained from the returned HRESULT is one of the following:
Return value Meaning
S_OK Success.
E_OUTOFMEMORY Out of memory.
E_INVALIDARG One or more of the arguments is invalid.
TYPE_E_IOERROR The function could not read from the file.
TYPE_E_INVDATAREAD Invalid data.
TYPE_E_UNSUPFORMAT The type library has an older format.
TYPE_E_INVALIDSTATE The type library could not be opened.
17.2.3.10 ITypeLib::ReleaseTLibAttr
HRESULT ReleaseTLibAttr(
TLIBATTR FAR* pTLibAttr
);
Releases the TLIBATTR originally obtained from ITypeLib::GetLibAttr.
Parameter
pTLibAttr
Pointer to the TLIBATTR to be freed.
Comments
Releases the specified TLIBATTR. This TLIBATTR was previously obtained with a ca
ll to GetTypeLib::GetLibAttr.
17.2.4 ITypeLib2
The ITypeLib2 interface inherits from the ITypeLib interface. This allows ITypeL
ib to cast to an ITypeLib2 in performance-sensitive cases, rather than perform e
xtra QueryInterface() and Release() calls.
Example
DECLARE_INTERFACE_(ITypeLib2, ITypeLib)
{
17.2.4.1 ITypeLib2::GetCustData
HRESULT GetCustData(
REFGUID guid,
VARIANT *pVarVal
);
Gets the custom data.
Parameter
guid
GUID used to identify the data.
pVarVal
Where to put the retrieved data.
Return Value
The return value obtained from the returned HRESULT is one of the following:
Return value Meaning
S_OK Success.
E_OUTOFMEMORY Out of memory.
E_INVALIDARG One or more of the arguments is invalid.
17.2.4.2 ITypeLib2::GetDocumentation2
HRESULT GetDocumentation2(
[in] int index,
[in] LCID lcid,
[out] BSTR FAR* pbstrHelpString,
[out] unsigned long FAR* pdwHelpStringContext,
BSTR FAR* pbstrHelpStringDll
);
Retrieves the library ' s documentation string, the complete Help file name and path, t
he localization context to use, and the context ID for the library Help topic in
the Help file.
Parameters
index
Index of the type description whose documentation is to be returned; if index is
-1, then the documentation for the library is returned.
lcid
Locale identifier.
pbstrHelpString
Returns a BSTR that contains the name of the specified item. If the caller does
not need the item name, then pbstrHelpString can be Null.
pdwHelpStringContext
Returns the Help localization context. If the caller does not need the Help cont
ext, then it can be Null.
pbstrHelpStringDll
Returns a BSTR that contains the fully qualified name of the file containing the
DLL used for Help file. If the caller does not need the file name, then it can
be Null.
Return Value
The return value obtained from the returned HRESULT is one of the following:
Return value Meaning
S_OK Success.
STG_E_INSUFFICIENTMEMORY Out of memory.
E_INVALIDARG One or more of the arguments is invalid.
TYPE_E_IOERROR The function could not write to the file.
TYPE_E_INVDATAREAD The function could not read from the file.
TYPE_E_UNSUPFORMAT The type library has an older format.
TYPE_E_INVALIDSTATE The type library could not be opened.
TYPE_E_ELEMENTNOTFOUND The element was not found.
Comments
Gets information at the type library level. The caller should free the BSTR para
meters.
This function will call _DLLGetDocumentation in the specified DLL to retrieve th
e desired Help string, if there is a Help string context for this item. If no He
lp string context exists or an error occurs, then it will defer to the GetDocume
ntation method and return the associated documentation string.
17.2.4.3 ITypeLib2::GetLibStatistics
HRESULT GetLibStatistics(
unsigned long* pcUniqueNames,
unsigned long* pcchUniqueNames
);
Returns statistics about a type library that are required for efficient sizing o
f hash tables.
Parameter
pcUniqueNames
Returns a pointer to a count of unique names. If the caller does not need this i
nformation, set to NULL.
pcchUniqueNames
Returns a pointer to a change in the count of unique names.
Return Value
The return value obtained from the returned HRESULT is one of the following:
Return value Meaning
S_OK Success.
E_OUTOFMEMORY Out of memory.
E_INVALIDARG One or more of the arguments is invalid.
Example
ITypeLib2::GetLibStatistics(DWORD *pcUniqueNames, DWORD * pcchUniqueNames)
17.2.4.4 ITypeLib2::GetAllCustData
HRESULT GetAllCustData(
CUSTDATA *pCustData
);
Gets all custom data items for the library.
Parameter
pCustData
Returns a pointer to CUSTDATA (that holds all custom data items).
Return Value
The return value obtained from the returned HRESULT is one of the following:
Return Value
The return value obtained from the returned HRESULT is one of the following:
Return value Meaning
S_OK Success.
E_OUTOFMEMORY Out of memory.
E_INVALIDARG One or more of the arguments is invalid.
E_NOINTERFACE COM could not find an implementation of one or more required int
erfaces.
TYPE_E_ELEMENTNOTFOUND The element was not found.
TYPE_E_IOERROR The function could not read from the file.
TYPE_E_INVDATAREAD Invalid data.
TYPE_E_UNSUPFORMAT The type library has an older format.
TYPE_E_INVALIDSTATE The type library could not be opened.
TYPE_E_WRONGTYPEKIND Type mismatch.
Comments
The caller passes in a member ID, which represents the member function whose ent
ry description is desired. If the function has a DLL entry point, the name of th
e DLL that contains the function, as well as its name or ordinal identifier, are
placed in the passed-in pointers allocated by the caller. If there is no DLL en
try point for the function, an error is returned.
If the type description inherits from another type description, this function is
recursive to the base type description, if necessary, to find the item with the
requested member ID.
The caller should use SysFreeString() to free the BSTRs referenced by pBstrName
and pBstrDllName.
17.2.5.5 ITypeInfo::GetDocumentation
HRESULT GetDocumentation(
MEMBERID memid,
BSTR FAR* pBstrName,
BSTR FAR* pBstrDocString,
unsigned long FAR* pdwHelpContext,
BSTR FAR* pBstrHelpFile
);
Retrieves the documentation string, the complete Help file name and path, and th
e context ID for the Help topic for a specified type description.
Parameters
memid
ID of the member whose documentation is to be returned.
pBstrName
Pointer to a BSTR allocated by the callee into which the name of the specified i
tem is placed. If the caller does not need the item name, pBstrName can be Null.
pBstrDocString
Pointer to a BSTR into which the documentation string for the specified item is
placed. If the caller does not need the documentation string, pBstrDocString can
be Null.
pdwHelpContext
Pointer to the Help context associated with the specified item. If the caller do
es not need the Help context, the pdwHelpContext can be Null.
pBstrHelpFile
Pointer to a BSTR into which the fully qualified name of the Help file is placed
. If the caller does not need the Help file name, pBstrHelpFile can be Null.
Return Value
The return value obtained from the returned HRESULT is one of the following:
Comments
The function GetIDsOfNames maps the name of a member (rgszNames[0]) and its para
meters (rgszNames[1] ...rgszNames[cNames - 1]) to the ID of the member (rgid[0])
, and to the IDs of the specified parameters (rgid[1] ... rgid[cNames - 1]). The
IDs of parameters are 0 for the first parameter in the member function ' s argument li
st, 1 for the second, and so on.
If the type description inherits from another type description, this function is
recursive to the base type description, if necessary, to find the item with the
requested member ID.
17.2.5.8 ITypeInfo::GetImplTypeFlags
HRESULT GetImplTypeFlags(
unsigned int index,
int* pImplTypeFlags
);
Retrieves the IMPLTYPEFLAGS enumeration for one implemented interface or base in
terface in a type description.
Parameters
index
Index of the implemented interface or base interface for which to get the flags.
pImplTypeFlags
On return, pointer to the IMPLTYPEFLAGS enumeration.
Return Value
The return value obtained from the returned HRESULT is one of the following:
Return value Meaning
S_OK Success.
E_OUTOFMEMORY Out of memory.
E_INVALIDARG One or more of the arguments is invalid.
TYPE_E_INVDATAREAD The function could not read from the file.
TYPE_E_UNSUPFORMAT The type library has an older format.
TYPE_E_INVALIDSTATE The type library could not be opened.
TYPE_E_WRONGTYPEKIND Type mismatch.
Comments
The flags are associated with the act of inheritance, and not with the inherited
interface.
17.2.5.9 ITypeInfo::GetMops
HRESULT GetMops(
MEMBERID memid,
BSTR FAR* pBstrMops
);
Retrieves marshaling information.
Parameters
memid
The member ID that indicates which marshaling information is needed.
pBstrMops
On return, contains a pointer to the opcode string used in marshaling the fields
of the structure described by the referenced type description, or returns Null
if there is no information to return.
Return Value
The return value obtained from the returned HRESULT is one of the following:
Return value Meaning
S_OK Success.
E_OUTOFMEMORY Out of memory.
E_INVALIDARG One or more of the arguments is invalid.
TYPE_E_IOERROR The function could not read from the file.
TYPE_E_UNSUPFORMAT The type library has an older format.
TYPE_E_INVALIDSTATE The type library could not be opened.
TYPE_E_ELEMENTNOTFOUND The element was not found.
TYPE_E_WRONGTYPEKIND Type mismatch.
Comments
If the passed-in member ID is MEMBERID_NIL, the function returns the opcode stri
ng for marshaling the fields of the structure described by the type description.
Otherwise, it returns the opcode string for marshaling the function specified b
y the index.
If the type description inherits from another type description, this function re
curses on the base type description, if necessary, to find the item with the req
uested member ID.
17.2.5.10 ITypeInfo::GetNames
HRESULT GetNames(
MEMBERID memid,
BSTR FAR* rgBstrNames,
unsigned int cMaxNames,
unsigned int FAR* pcNames
);
Retrieves the variable with the specified member ID (or the name of the property
or method and its parameters) that correspond to the specified function ID.
Parameters
memid
The ID of the member whose name (or names) is to be returned.
rgBstrNames
Pointer to the caller-allocated array. On return, each of these lpcName elements
is filled in to point to a BSTR that contains the name (or names) associated wi
th the member.
cMaxNames
Length of the passed-in rgBstrNames array.
pcNames
On return, points to the number that represents the number of names in rgBstrNam
es array.
Return Value
The return value obtained from the returned HRESULT is one of the following:
Return value Meaning
S_OK Success.
E_OUTOFMEMORY Out of memory.
E_INVALIDARG One or more of the arguments is invalid.
TYPE_E_IOERROR The function could not read from the file.
TYPE_E_INVDATAREAD Invalid data.
TYPE_E_UNSUPFORMAT The type library has an older format.
TYPE_E_INVALIDSTATE The type library could not be opened.
TYPE_E_WRONGTYPEKIND Type mismatch.
TYPE_E_ELEMENTNOTFOUND The element was not found.
Comments
The caller must release the returned BSTR (Basic string) array.
If the member ID identifies a property that is implemented with property functio
ns, the property name is returned.
For property get functions, the names of the function and its parameters are alw
ays returned.
For property put and put reference functions, the right side of the assignment i
s unnamed. If cMaxNamesis less than is required to return all of the names of th
e parameters of a function, then only the names of the first cMaxNames- 1 parame
ters are returned. The names of the parameters are returned in the array in the
same order that they appear elsewhere in the interface (for example, the same or
der in the parameter array associated with the FUNCDESC enumeration).
If the type description inherits from another type description, this function is
recursive to the base type description, if necessary, to find the item with the
requested member ID.
17.2.5.11 ITypeInfo::GetRefTypeInfo
HRESULT GetRefTypeInfo(
HREFTYPE hRefType,
ITypeInfo FAR* FAR* ppTInfo
);
If a type description references other type descriptions, it retrieves the refer
enced type descriptions.
Parameters
hRefType
Handle to the referenced type description to be returned.
ppTInfo
Points a pointer to a pointer to the referenced type description.
Return Value
The return value obtained from the returned HRESULT is one of the following:
Return value Meaning
S_OK Success.
E_OUTOFMEMORY Out of memory.
E_INVALIDARG One or more of the arguments is invalid.
TYPE_E_IOERROR The function could not read from the file.
TYPE_E_INVDATAREAD Invalid data.
TYPE_E_UNSUPFORMAT The type library has an older format.
TYPE_E_INVALIDSTATE The type library could not be opened.
TYPE_E_WRONGTYPEKIND Type mismatch.
TYPE_E_ELEMENTNOTFOUND The element was not found.
TYPE_E_REGISTRYACCESS There was an error accessing the system registration dat
abase.
TYPE_E_LIBNOTREGISTERED The type library was not found in the system registratio
n database.
Comments
On return, the second parameter contains a pointer to a pointer to a type descri
ption that is referenced by this type description. A type description must have
a reference to each type description that occurs as the type of any of its varia
bles, function parameters, or function return types. For example, if the type of
a data member is a record type, the type description for that data member conta
ins the hRefTypeof a referenced type description. To get a pointer to the type d
escription, the reference is passed to GetRefTypeInfo.
17.2.5.12 ITypeInfo::GetRefTypeOfImplType
HRESULT GetRefTypeOfImplType(
unsigned int index,
HREFTYPE FAR* pRefType
);
If a type description describes a COM class, it retrieves the type description o
f the implemented interface types. For an interface, GetRefTypeOfImplType return
s the type information for inherited interfaces, if any exist.
Parameters
index
Index of the implemented type whose handle is returned. The valid range is 0 to
the cImplTypes field in the TYPEATTR structure.
pRefType
On return, points to a handle for the implemented interface (if any). This handl
e can be passed to ITypeInfo::GetRefTypeInfo to get the type description.
Return Value
The return value obtained from the returned HRESULT is one of the following:
Return value Meaning
S_OK Success.
TYPE_E_ELEMENTNOTFOUND Passed index is outside the range 0 to 1 less than the n
umber of function descriptions.
E_INVALIDARG One or more of the arguments is invalid.
TYPE_E_IOERROR The function could not read from the file.
TYPE_E_INVDATAREAD Invalid data.
TYPE_E_UNSUPFORMAT The type library has an older format.
TYPE_E_INVALIDSTATE The type library could not be opened.
Comments
If the TKIND_DISPATCH type description is for a dual interface, the TKIND_INTERF
ACE type description can be obtained by calling GetRefTypeOfImplType with an ind
ex of 1, and by passing the returned pRefType handle to GetRefTypeInfo to retriev
e the type information.
17.2.5.13 ITypeInfo::GetTypeAttr
HRESULT GetTypeAttr(
TYPEATTR FAR* FAR* ppTypeAttr
);
Retrieves a TYPEATTR structure that contains the attributes of the type descript
ion.
Parameter
ppTypeAttr
On return, points to a pointer to a structure that contains the attributes of th
is type description.
Return Value
The return value obtained from the returned HRESULT is one of the following:
Return value Meaning
S_OK Success.
E_OUTOFMEMORY Out of memory.
E_INVALIDARG One or more of the arguments is invalid.
TYPE_E_IOERROR The function could not write to the file.
TYPE_E_INVDATAREAD The function could not read from the file.
TYPE_E_UNSUPFORMAT The type library has an older format.
TYPE_E_INVALIDSTATE The type library could not be opened.
Comments
To free the TYPEATTR structure, use ITypeInfo::ReleaseTypeAttr.
Example
CHECKRESULT(ptypeinfoCur->GetTypeAttr(&ptypeattrCur));
.
.
.
ptypeinfoCur->ReleaseTypeAttr(ptypeattrCur);
17.2.5.14 ITypeInfo::GetTypeComp
HRESULT GetTypeComp(
ITypeComp FAR* FAR* ppTComp
);
Retrieves the ITypeComp interface for the type description, which enables a clie
nt compiler to bind to the type description ' s members.
Parameter
ppTComp
On return, points to a pointer to the ITypeComp of the containing type library.
Return Value
The return value obtained from the returned HRESULT is one of the following:
Return value Meaning
S_OK Success.
E_OUTOFMEMORY Out of memory.
E_INVALIDARG One or more of the arguments is invalid.
TYPE_E_IOERROR The function could not read from the file.
TYPE_E_INVDATAREAD Invalid data.
TYPE_E_UNSUPFORMAT The type library has an older format.
TYPE_E_INVALIDSTATE The type library could not be opened.
TYPE_E_WRONGTYPEKIND Type mismatch.
Comments
A client compiler can use the ITypeComp interface to bind to members of the type
.
17.2.5.15 ITypeInfo::GetVarDesc
HRESULT GetVarDesc(
unsigned int index,
VARDESC FAR* FAR* ppVarDesc
);
Retrieves a VARDESC structure that describes the specified variable.
Parameters
index
Index of the variable whose description is to be returned. The index should be i
n the range of 0 to 1 less than the number of variables in this type.
ppVarDesc
On return, points to a pointer to a VARDESC that describes the specified variabl
e.
Return Value
The return value obtained from the returned HRESULT is one of the following:
Return value Meaning
S_OK Success.
E_OUTOFMEMORY Out of memory.
E_INVALIDARG One or more of the arguments is invalid.
TYPE_E_IOERROR The function could not read from the file.
TYPE_E_INVDATAREAD Invalid data.
TYPE_E_UNSUPFORMAT The type library has an older format.
TYPE_E_INVALIDSTATE The type library could not be opened.
Comments
To free the VARDESC structure, use ReleaseVarDesc.
Example
CHECKRESULT(ptypeinfo->GetVarDesc(i, &pvardesc));
idMember = pvardesc->memid;
CHECKRESULT(ptypeinfo->GetDocumentation(idMember, &bstrName, NULL, NULL,
NULL));
ptypeinfo->ReleaseVarDesc(pvardesc);
17.2.5.16 ITypeInfo::Invoke
HRESULT Invoke(
VOID FAR* pvInstance,
MEMBERID memid,
unsigned short wFlags,
DISPPARAMS FAR* pDispParams,
VARIANT FAR* pVarResult,
EXCEPINFO FAR* pExcepInfo,
unsigned int FAR* puArgErr
);
Invokes a method, or accesses a property of an object, that implements the inter
face described by the type description.
Parameters
pvInstance
Pointer to an instance of the interface described by this type description.
memid
Identifies the interface member.
wFlags
Flags describing the context of the invoke call, as follows:
Value Description
DISPATCH_METHOD The member is accessed as a method. If there is ambiguity, both
this and the DISPATCH_PROPERTYGET flag can be set.
DISPATCH_PROPERTYGET The member is retrieved as a property or data member.
DISPATCH_PROPERTYPUT The member is changed as a property or data member.
DISPATCH_PROPERTYPUTREF The member is changed by using a reference assignment, r
ather than a value assignment. This value is only valid when the property accept
s a reference to an object.
pDispParams
Points to a structure that contains an array of arguments, an array of DISPIDs f
or named arguments, and counts of the number of elements in each array.
pVarResult
Should be Null if the caller does not expect any result. Otherwise, it should be
a pointer to the location at which the result is to be stored. If wFlags specif
ies DISPATCH_PROPERTYPUT or DISPATCH_PROPERTYPUTREF, pVarResultis ignored.
pExcepInfo
Points to an exception information structure, which is filled in only if DISP_E_
EXCEPTION is returned. If pExcepInfois Null on input, only an HRESULT error will
be returned.
puArgErr
If Invoke returns DISP_E_TYPEMISMATCH, puArgErr indicates the index (within rgva
rg) of the argument with incorrect type. If more than one argument returns an er
ror, puArgErr indicates only the first argument with an error. Arguments in pDis
pParams->rgvarg appear in reverse order, so the first argument is the one having
the highest index in the array. Cannot be Null.
Return Value
The return value obtained from the returned HRESULT is one of the following:
Return value Meaning
S_OK Success.
E_INVALIDARG One or more of the arguments is invalid.
DISP_E_EXCEPTION The member being invoked has returned an error HRESULT.
If the member implements IErrorInfo, details are available in the error object.
Otherwise, the pExcepInfo parameter contains details.
TYPE_E_IOERROR The function could not read from the file.
TYPE_E_INVDATAREAD Invalid data.
TYPE_E_UNSUPFORMAT The type library has an older format.
TYPE_E_REGISTRYACCESS There was an error accessing the system registration dat
abase.
TYPE_E_LIBNOTREGISTERED The type library was not found in the system registratio
n database.
TYPE_E_INVALIDSTATE The type library could not be opened.
TYPE_E_WRONGTYPEKIND Type mismatch.
TYPE_E_ELEMENTNOTFOUND The element was not found.
TYPE_E_BADMODULEKIND The module does not support Invoke.
Other return codes Any of the IDispatch::Invoke errors may also be returned
.
Comments
Use the function ITypeInfo::Invoke to access a member of an object or invoke a m
ethod that implements the interface described by this type description. For obje
cts that support the IDispatch interface, you can use Invoke to implement IDispa
tch::Invoke.
ITypeInfo::Invoke takes a pointer to an instance of the class. Otherwise, its pa
rameters are the same as IDispatch::Invoke, except that ITypeInfo::Invoke omits
the refiid and lcid parameters. When called, ITypeInfo::Invoke performs the acti
ons described by the IDispatch::Invoke parameters on the specified instance.
For VTBL interface members, ITypeInfo::Invoke passes the LCID of the type inform
ation into parameters tagged with the lcid attribute, and the returned value int
o the retval attribute.
If the type description inherits from another type description, this function re
curses on the base type description to find the item with the requested member I
D.
17.2.5.17 ITypeInfo::ReleaseFuncDesc
HRESULT ReleaseFuncDesc(
FUNCDESC FAR* pFuncDesc
);
Releases a FUNCDESC previously returned by GetFuncDesc.
Parameter
pFuncDesc
Pointer to the FUNCDESC to be freed.
Comments
The function ReleaseFuncDesc releases a FUNCDESC that was returned through IType
Info::GetFuncDesc.
Example
ptypeinfoCur->ReleaseFuncDesc(pfuncdesc);
17.2.5.18 ITypeInfo::ReleaseTypeAttr
HRESULT ReleaseTypeAttr(
TYPEATTR FAR* pTypeAttr
);
Releases a TYPEATTR previously returned by GetTypeAttr.
Parameter
pTypeAttr
Pointer to the TYPEATTR to be freed.
Comments
The function ReleaseTypeAttr releases a TYPEATTR that was returned through IType
Info::GetTypeAttr.
17.2.5.19 ITypeInfo::ReleaseVarDesc
HRESULT ReleaseVarDesc(
VARDESC FAR* pVarDesc
);
Releases a VARDESC previously returned by GetVarDesc.
Parameter
pVarDesc
Pointer to the VARDESC to be freed.
Comments
ReleaseVarDesc releases a VARDESC that was returned through ITypeInfo::GetVarDes
c.
Example
VARDESC FAR *pVarDesc;
CHECKRESULT(ptypeinfo->GetVarDesc(i, &pvardesc));
idMember = pvardesc->memid;
CHECKRESULT(ptypeinfo->GetDocumentation(idMember, &bstrName, NULL, NULL,
NULL));
ptypeinfo->ReleaseVarDesc(pvardesc);
17.2.6 ITypeInfo2
An ITypeInfo can be cast to an ITypeInfo2 instead of using the calls QueryInterf
ace() and Release().
17.2.6.1 ITypeInfo2::GetTypeKind
HRESULT GetTypeKind(
TYPEKIND *pTypeKind
);
Returns the TYPEKIND enumeration quickly, without doing any allocations.
Parameter
pTypeKind
Reference to a TYPEKIND enumeration.
Return Value
The return value obtained from the returned HRESULT is one of the following:
Return value Meaning
S_OK Success.
E_OUTOFMEMORY Out of memory.
E_INVALIDARG One or more of the arguments is invalid.
Example
HRESULT ITypeInfo2::GetTypeKind(TYPEKIND * ptypekind)
17.2.6.2 ITypeInfo2::GetTypeFlags
HRESULT GetTypeFlags(
unsigned long *pTypeFlags
);
Returns the type flags without any allocations. This returns a DWORD type flag,
which expands the type flags without growing the TYPEATTR (type attribute).
Parameter
pTypeFlags
The DWORD reference to a TYPEFLAG.
Return Value
The return value obtained from the returned HRESULT is one of the following:
Return value Meaning
S_OK Success.
E_OUTOFMEMORY Out of memory.
E_INVALIDARG One or more of the arguments is invalid.
Example
HRESULT ITypeInfo2::GetTypeFlags(DWORD * pTypeFlags)
17.2.6.3 ITypeInfo2::GetFuncIndexOfMemId
HRESULT GetFuncIndexOfMemId(
MEMBERID memid,
INVOKEKIND invKind,
unsigned int *pFuncIndex
);
Binds to a specific member based on a known DISPID, where the member name is not
known (for example, when binding to a default member).
Parameter
memid
Member identifier.
invKind
Invoke kind.
pFuncIndex
Returns an index into the function.
Return Value
The return value obtained from the returned HRESULT is one of the following:
Return value Meaning
S_OK Success.
E_OUTOFMEMORY Out of memory.
E_INVALIDARG One or more of the arguments is invalid.
Example
ITypeInfo2::GetFuncIndexOfMemId(
MEMID memid,
INVOKEKIND invKind,
UINT * pfuncIndex)
17.2.6.4 ITypeInfo2::GetVarIndexOfMemId
HRESULT GetVarIndexOfMemId(
MEMBERID memid,
unsigned int *pVarIndex
);
Binds to a specific member based on a known DISPID, where the member name is not
known (for example, when binding to a default member).
Parameters
memid
Member identifier.
pVarIndex
Returns the index.
Return Value
The return value obtained from the returned HRESULT is one of the following:
Return value Meaning
S_OK Success.
E_OUTOFMEMORY Out of memory.
E_INVALIDARG One or more of the arguments is invalid.
Example
ITypeInfo2::GetVarIndexOfMemId(MEMID memid, UINT * pvarIndex)
17.2.6.5 ITypeInfo2::GetCustData
HRESULT GetCustData(
REFGUID guid,
VARIANT *pVarVal
);
Gets the custom data.
Parameters
guid
GUID used to identify the data.
pVarVal
Where to put the retrieved data.
Return Value
The return value obtained from the returned HRESULT is one of the following:
Return value Meaning
S_OK Success.
E_OUTOFMEMORY Out of memory.
E_INVALIDARG One or more of the arguments is invalid.
17.2.6.6 ITypeInfo2::GetAllCustData
HRESULT GetAllCustData(
CUSTDATA *pCustData
);
Gets all custom data items for the library.
Parameters
pCustData
Returns a pointer to CUSTDATA (that holds all custom data items).
Return Value
The return value obtained from the returned HRESULT is one of the following:
Return value Meaning
S_OK Success.
E_OUTOFMEMORY Out of memory.
E_INVALIDARG One or more of the arguments is invalid.
Comments
After the call, the caller needs to release memory used to hold the custom data
item by calling ClearCustData().
17.2.6.7 ITypeInfo2::GetAllFuncCustData
HRESULT GetAllFuncCustData(
unsigned int index
CUSTDATA *pCustData
);
Gets all custom data from the specified function.
Parameters
index
The index of the function for which to get the custom data.
pCustData
Returns a pointer to CUSTDATA (that holds all custom data items).
Return Value
The return value obtained from the returned HRESULT is one of the following:
Return value Meaning
S_OK Success.
E_OUTOFMEMORY Out of memory.
E_INVALIDARG One or more of the arguments is invalid.
Comments
After the call, the caller needs to release memory used to hold the custom data
item by calling ClearCustData().
17.2.6.8 ITypeInfo2::GetAllImplTypeCustData
HRESULT GetAllImplTypeCustData(
unsigned int index,
CUSTDATA *pCustData
);
Gets all custom data for the specified implementation type.
Parameters
index
Index of the implementation type for the custom data.
pCustData
Returns a pointer to CUSTDATA (that holds all custom data items).
Return Value
The return value obtained from the returned HRESULT is one of the following:
Return value Meaning
S_OK Success.
E_OUTOFMEMORY Out of memory.
E_INVALIDARG One or more of the arguments is invalid.
17.2.6.9 ITypeInfo2::GetAllParamCustData
HRESULT GetAllParamCustData(
unsigned int indexFunc,
unsigned int indexParam,
CUSTDATA *pCustData
);
Gets all of the custom data for the specified function parameter.
Parameters
indexFunc
Index of the function for which to get the custom data.
IndexParam
Index of the parameter of this function for which to get the custom data.
pCustData
Returns a pointer to CUSTDATA (that holds all custom data items).
Return Value
The return value obtained from the returned HRESULT is one of the following:
Return value Meaning
S_OK Success.
E_OUTOFMEMORY Out of memory.
E_INVALIDARG One or more of the arguments is invalid.
17.2.6.10 ITypeInfo2::GetAllVarCustData
HRESULT GetAllVarCustData(
unsigned int index,
CUSTDATA *pCustData
);
Gets the variable for the custom data.
Parameters
index
Index of the variable for which to get the custom data.
pCustData
Returns a pointer to CUSTDATA (that holds all custom data items).
Return Value
The return value obtained from the returned HRESULT is one of the following:
Return value Meaning
S_OK Success.
E_OUTOFMEMORY Out of memory.
E_INVALIDARG One or more of the arguments is invalid.
17.2.6.11 ITypeInfo2::GetFuncCustData
HRESULT GetFuncCustData(
unsigned int index,
REFGUID guid,
VARIANT *pVarVal
);
Gets the custom data from the specified function.
Parameters
index
The index of the function for which to get the custom data.
guid
The GUID used to identify the data.
pVarVal
Where to put the data.
Return Value
The return value obtained from the returned HRESULT is one of the following:
Return value Meaning
S_OK Success.
E_OUTOFMEMORY Out of memory.
E_INVALIDARG One or more of the arguments is invalid.
17.2.6.12 ITypeInfo2::GetParamCustData
HRESULT GetParamCustData(
unsigned int indexFunc,
unsigned int indexParam,
REFGUID guid,
VARIANT *pVarVal
);
Gets the specified custom data parameter.
Parameters
indexFunc
Index of the function for which to get the custom data.
IndexParam
Index of the parameter of this function for which to get the custom data.
guid
GUID used to identify the data.
pVarVal
Where to put the retrieved data.
Return Value
The return value obtained from the returned HRESULT is one of the following:
Return value Meaning
S_OK Success.
E_OUTOFMEMORY Out of memory.
E_INVALIDARG One or more of the arguments is invalid.
17.2.6.13 ITypeInfo2::GetVarCustData
HRESULT GetVarCustData(
unsigned int index,
REFGUID guid,
VARIANT *pVarVal
);
Gets the variable for the custom data.
Parameters
index
Index of the variable for which to get the custom data.
guid
GUID used to identify the data.
PVarVal
Where to put the retrieved data.
Return Value
The return value obtained from the returned HRESULT is one of the following:
Return value Meaning
S_OK Success.
E_OUTOFMEMORY Out of memory.
E_INVALIDARG One or more of the arguments is invalid.
17.2.6.14 ITypeInfo2::GetImplTypeCustData
HRESULT GetImplTypeCustData(
unsigned int index,
REFGUID guid,
VARIANT *pVarVal
);
Gets the implementation type of the custom data.
Parameters
index
Index of the implementation type for the custom data.
guid
GUID used to identify the data.
pVarVal
Where to put the retrieved data.
Return Value
The return value obtained from the returned HRESULT is one of the following:
Return value Meaning
S_OK Success.
E_OUTOFMEMORY Out of memory.
E_INVALIDARG One or more of the arguments is invalid.
17.2.6.15 ITypeInfo2::GetDocumentation2
HRESULT GetDocumentation2(
[in] MEMID memid,
[in] LCID lcid,
[out] BSTR FAR* pbstrHelpString,
[out] unsigned long FAR* pdwHelpStringContext,
BSTR FAR* pbstrHelpStringDll
);
Retrieves the documentation string, the complete Help file name and path, the lo
calization context to use, and the context ID for the library Help topic in the
Help file.
Parameters
memid
Member identifier for the type description.
lcid
Locale identifier (LCID).
pbstrHelpString
Returns a BSTR that contains the name of the specified item. If the caller does
not need the item name, then pbstrHelpString can be Null.
pdwHelpStringContext
Returns the Help localization context. If the caller does not need the Help cont
ext, it can be Null.
pbstrHelpStringDll
Returns a BSTR that contains the fully qualified name of the file containing the
DLL used for Help file. If the caller does not need the file name, it can be Nu
ll.
Return Value
The return value obtained from the returned HRESULT is one of the following:
Return value Meaning
S_OK Success.
STG_E_INSUFFICIENTMEMORY Out of memory.
E_INVALIDARG One or more of the arguments is invalid.
TYPE_E_IOERROR The function could not write to the file.
TYPE_E_INVDATAREAD The function could not read from the file.
TYPE_E_UNSUPFORMAT The type library has an older format.
TYPE_E_INVALIDSTATE The type library could not be opened.
TYPE_E_ELEMENTNOTFOUND The element was not found.
Comments
Gets information at the type information level (about the type information and
its members). The caller should free the BSTR parameters.
This function will call _DLLGetDocumentation in the specified DLL to retrieve th
e desired Help string, if there is a Help string context for this item. If no He
lp string context exists or an error occurs, then it will defer to the GetDocume
ntation method and return the associated documentation string.
17.2.7 ITypeComp
The ITypeComp interface provides a fast way to access information that compilers
need when binding to and instantiating structures and interfaces. Binding is th
e process of mapping names to types and type members.
Implemented by Used by Header file name
Oleaut32.dll (32-bit systems)
Typelib.dll (16-bit systems) Tools that need to access the descriptions of ob
jects contained in type libraries. Oleauto.h
Dispatch.h
17.2.7.1 ITypeComp::Bind
HRESULT Bind(
OLECHAR FAR* szName,
unsigned long lHashVal,
unsigned short wFlags,
ITypeInfo FAR*FAR* ppTInfo,
DESCKIND FAR* pDescKind,
BINDPTR FAR* pBindPtr
);
Maps a name to a member of a type, or binds global variables and functions conta
ined in a type library.
Parameters
szName
Name to be bound.
lHashVal
Hash value for the name computed by LHashValOfNameSys.
wFlags
Flags word containing one or more of the Invoke flags defined in the INVOKEKIND
enumeration. Specifies whether the name was referenced as a method or a property
. When binding to a variable, specify the flag INVOKE_PROPERTYGET. Specify zero
to bind to any type of member.
ppTInfo
If a FUNCDESC or VARDESC was returned, then ppTInfo points to a pointer to the t
ype description that contains the item to which it is bound.
pDescKind
Pointer to a DESCKIND enumerator that indicates whether the name bound to is a V
ARDESC, FUNCDESC, or TYPECOMP. If there was no match, points to DESCKIND_NONE.
pBindPtr
On return, contains a pointer to the bound-to VARDESC, FUNCDESC, or ITypeComp in
terface.
Return Value
The return value obtained from the returned HRESULT is one of the following:
Return value Meaning
S_OK Success.
E_OUTOFMEMORY Out of memory.
E_INVALIDARG One or more of the arguments is invalid.
TYPE_E_IOERROR The function could not read from the file.
TYPE_E_INVDATAREAD Invalid data.
TYPE_E_UNSUPFORMAT The type library has an older format.
TYPE_E_INVALIDSTATE The type library could not be opened.
TYPE_E_AMBIGUOUSNAME More than one instance of this name occurs in the type l
ibrary.
Comments
Use Bind for binding to the variables and methods of a type, or for binding to t
he global variables and methods in a type library. The returned DESCKIND pointer
pDescKind indicates whether the name was bound to a VARDESC, a FUNCDESC, or to
an ITypeComp instance. The returned pBindPtr points to the VARDESC, FUNCDESC, or
ITypeComp.
If a data member or method is bound to, then ppTInfo points to the type descript
ion that contains the method or data member.
If Bind binds the name to a nested binding context, it returns a pointer to an I
TypeComp instance in pBindPtr and a Null type description pointer in ppTInfo. Fo
r example, if the name of a type description is passed for a module (TKIND_MODUL
E), enumeration (TKIND_ENUM), or coclass (TKIND_COCLASS), Bind returns the IType
Comp instance of the type description for the module, enumeration, or coclass. T
his feature supports languages such as Visual Basic that allow references to mem
bers of a type description to be qualified by the name of the type description.
For example, a function in a module can be referenced by modulename.functionname
.
The members of TKIND_ENUM, TKIND_MODULE, and TKIND_COCLASS types marked as Appli
cation objects can be bound to directly from ITypeComp, without specifying the n
ame of the module. The ITypeComp of a coclass defers to the ITypeComp of its def
ault interface.
As with other methods of ITypeComp, ITypeInfo, and ITypeLib, the calling code is
responsible for releasing the returned object instances or structures. If a VAR
DESC or FUNCDESC is returned, the caller is responsible for deleting it with the
returned type description and releasing the type description instance itself. O
therwise, if an ITypeComp instance is returned, the caller must release it.
Special rules apply if you call a type library ' s Bind method, passing it the name of
a member of an Application object class (a class that has the TYPEFLAG_FAPPOBJEC
T flag set). In this case, Bind returns DESCKIND_IMPLICITAPPOBJ in pDescKind, a
VARDESC that describes the Application object in pBindPtr, and the ITypeInfo of
the Application object class in ppTInfo. To bind to the object, ITypeInfo::GetTy
peComp must make a call to get the ITypeComp of the Application object class, an
d then reinvoke its Bind method with the name initially passed to the type libra
ry ' s ITypeComp.
The caller should use the returned ITypeInfo pointer (ppTInfo) to get the addres
s of the member.
Note
The wflags parameter is the same as the wflags parameter in IDispatch::Invoke.
17.2.7.2 ITypeComp::BindType
HRESULT BindType(
OLECHAR FAR* szName,
unsigned long lHashVal,
ITypeInfo FAR* FAR* ppTInfo,
ITypeComp FAR* FAR* ppTComp
);
Binds to the type descriptions contained within a type library.
Parameters
szName
Name to be bound.
lHashVal
Hash value for the name computed by LHashValOfName.
ppTInfo
On return, contains a pointer to a pointer to an ITypeInfo of the type to which
the name was bound.
ppTComp
Passes a valid pointer, such as the address of an ITypeComp* variable.
Return Value
The return value obtained from the returned HRESULT is one of the following:
Return value Meaning
S_OK Success.
E_OUTOFMEMORY Out of memory.
E_INVALIDARG One or more of the arguments is invalid.
TYPE_E_IOERROR The function could not read from the file.
TYPE_E_INVDATAREAD Invalid data.
TYPE_E_UNSUPFORMAT The type library has an older format.
TYPE_E_INVALIDSTATE The type library could not be opened.
TYPE_E_AMBIGUOUSNAME More than one instance of this name occurs in the type l
ibrary.
Comments
Use the function BindType for binding a type name to the ITypeInfo that describe
s the type. This function is invoked on the ITypeComp that is returned by ITypeL
ib::GetTypeComp to bind to types defined within that library. It can also be use
d in the future for binding to nested types.
Example
TypeComp * ptcomp;
ptemp -> BindType(szName, lhashval, &ptinfo, &ptemp)
Return Value
The return value of the returned HRESULT is one of the following:
Return value Meaning
S_OK Success.
E_OUTOFMEMORY Out of memory.
STG_E_INSUFFICIENTMEMORY Out of memory.
E_INVALIDARG One or more of the arguments is invalid.
TYPE_E_IOERROR The function could not create the file.
Other return codes All FACILITY_STORAGE errors.
Comments
CreateTypeLib sets its output parameter (lplpctlib) to point to a newly created
object that supports the ICreateTypeLib interface.
17.3.2 LHashValOfName
HRESULT LHashValOfName(
LCID lcid,
OLECHAR FAR* szName
);
Computes a hash value for a name that can then be passed to ITypeComp::Bind, ITy
peComp::BindType, ITypeLib::FindName, or ITypeLib::IsName.
Parameters
lcid
The LCID for the string.
szName
String whose hash value is to be computed.
Return Value
A 32-bit hash value that represents the passed-in name.
Comments
This function is equivalent to LHashValOfNameSys. The header file Oleauto.h cont
ains macros that define LHashValOfName as LHashValOfNameSys, with the target ope
rating system (syskind) based on the build preprocessor flags.
LHashValOfName computes a 32-bit hash value for a name that can be passed to ITy
peComp::Bind, ITypeComp::BindType, ITypeLib::FindName, or ITypeLib::IsName. The
returned hash value is independent of the case of the characters in szName, as l
ong as the language of the name is one of the languages supported by the COM Nat
ional Language Specification API. Any two strings that match when a case-insensi
tive comparison is done using any language produce the same hash value.
17.3.3 LHashValOfNameSys
HRESULT LHashValOfNameSys(
SYSKIND syskind,
LCID lcid,
OLECHAR FAR* szName
);
Computes a hash value for a name that can then be passed to ITypeComp::Bind, ITy
peComp::BindType, ITypeLib::FindName, or ITypeLib::IsName.
Parameters
syskind
The SYSKIND of the target operating system.
lcid
The LCID for the string.
szName
String whose hash value is to be computed.
Return Value
A 32-bit hash value that represents the passed-in name.
17.3.4 LoadTypeLibEx
HRESULT LoadTypeLibEx(
OLECHAR FAR* szFile,
REGKIND regkind,
ITypeLib FAR* FAR* pptlib
);
Loads and optionally registers a type library.
Parameters
szFile
Contains the name of the file from which LoadTypeLib should attempt to load a ty
pe library.
regkind
Identifies the kind of registration to perform for the type library (REGKIND_DEF
AULT, REGKIND_REGISTER, or REGKIND_NONE).
pptlib
On return, contains a pointer to a pointer to the loaded type library.
Return Value
The return value obtained from the returned HRESULT is one of the following:
Return value Meaning
S_OK Success.
E_OUTOFMEMORY Out of memory.
E_INVALIDARG One or more of the arguments is invalid.
TYPE_E_IOERROR The function could not write to the file.
TYPE_E_INVALIDSTATE The type library could not be opened.
TYPE_E_INVDATAREAD The function could not read from the file.
TYPE_E_UNSUPFORMAT The type library has an older format.
TYPE_E_UNKNOWNLCID The LCID could not be found in the COM-supported DLLs.
TYPE_E_CANTLOADLIBRARY The type library or DLL could not be loaded.
TYPE_E_REGISTRYACCESS The system registration database could not be opened.
Other return codes All FACILITY_STORAGE errors can be returned.
Comments
The function LoadTypeLibEx loads a type library (usually created with MIDL) that
is stored in the specified file. If szFile specifies only a file name without a
ny path, LoadTypeLibEx searches for the file and proceeds as follows:
· If the file is a stand-alone type library (usually with a .TLB extension), the t
ype library is loaded directly.
· If the file is a DLL or an executable file, it is loaded. By default, the type l
ibrary is extracted from the first resource of type ITypeLib. To load a differen
t type of library resource, append an integer index to szFile. For example:
LoadTypeLib( " C:\MONTANA\EXE\MFA.EXE\3 " , pptlib)
This statement loads the type library resource 3 from the file Mfa.exe file.
· If the file is none of the above, the file name is parsed into a moniker (an obj
ect that represents a file-based link source) using MkParseDisplayName, and then
the moniker is bound to IID_ITypeLib. This approach allows LoadTypeLibEx to be
used on foreign type libraries, including in-memory type libraries. Foreign type
libraries cannot reside in a DLL or an executable file.
If the type library is already loaded, LoadTypeLibEx increments the type library ' s re
ference count and returns a pointer to the type library.
The regKind parameter enables programmers to specify whether or not the type lib
rary should be registered in the system registry (for future loading via LoadReg
TypeLib). When REGKIND_NONE is specified, the library is not registered in the s
ystem registry. When REGKIND_DEFAULT is specified, LoadTypeLibEx will register t
he type library if the path is not specified in the szFile parameter, otherwise
LoadTypeLibEx will not register the type library. When REGKIND_REGISTER is speci
fied, LoadTypeLibEx will always register the type library in the system registry
.
It is recommended that RegisterTypeLib be used to register a type library.
17.3.5 LoadRegTypeLib
HRESULT LoadRegTypeLib(
REFGUID rguid,
Unsigned short wVerMajor,
Unsigned short wVerMinor,
LCID lcid,
ITypeLib FAR* FAR* pptlib
);
Uses registry information to load a type library.
Parameters
rguid
The GUID of the library being loaded.
wVerMajor
Major version number of the library being loaded.
wVerMinor
Minor version number of the library being loaded.
lcid
National language code of the library being loaded.
pptlib
On return, points to a pointer to the loaded type library.
Return Value
The return value obtained from the returned HRESULT is one of the following:
Return value Meaning
S_OK Success.
E_OUTOFMEMORY Out of memory.
E_INVALIDARG One or more of the arguments is invalid.
TYPE_E_IOERROR The function could not read from the file.
TYPE_E_INVALIDSTATE The type library could not be opened.
TYPE_E_INVDATAREAD The function could not read from the file.
TYPE_E_UNSUPFORMAT The type library has an older format.
TYPE_E_UNKNOWNLCID The passed in LCID could not be found in the COM-support
ed DLLs.
TYPE_E_CANTLOADLIBRARY The type library or DLL could not be loaded.
Other return codes All FACILITY_STORAGE and system registry errors can also
be returned.
Comments
The function LoadRegTypeLib defers to LoadTypeLibEx to load the file.
LoadRegTypeLib compares the requested version numbers against those found in the
system registry, and takes one of the following actions:
· If one of the registered libraries exactly matches both the requested major and
minor version numbers, then that type library is loaded.
· If one or more registered type libraries exactly match the requested major versi
on number, and has a greater minor version number than that requested, the one w
ith the greatest minor version number is loaded.
· If none of the registered type libraries exactly match the requested major versi
on number (or if none of those that do exactly match the major version number al
so have a minor version number greater than or equal to the requested minor vers
ion number), then LoadRegTypeLib returns an error.
17.3.6 RegisterTypeLib
HRESULT RegisterTypeLib(
ITypeLib FAR* ptlib,
OLECHAR FAR* szFullPath,
OLECHAR FAR* szHelpDir
);
Adds information about a type library to the system registry.
Parameters
ptlib
Pointer to the type library being registered.
szFullPath
Fully qualified path specification for the type library being registered.
szHelpDir
Directory in which the Help file for the library being registered can be found.
Can be Null.
Return Value
The return value obtained from the returned HRESULT is one of the following:
Return value Meaning
S_OK Success.
E_OUTOFMEMORY Out of memory.
E_INVALIDARG One or more of the arguments is invalid.
TYPE_E_IOERROR The function could not write to the file.
TYPE_E_REGISTRYACCESS The system registration database could not be opened.
TYPE_E_INVALIDSTATE The type library could not be opened.
Comments
The function RegisterTypeLib can be used during application initialization to re
gister the application ' s type library correctly.
In addition to filling in a complete registry entry under the type library key,
RegisterTypeLib adds entries for each of the dispinterfaces and Automation-compa
tible interfaces, including dual interfaces. This information is required to cre
ate instances of these interfaces. Coclasses are not registered (that is, Regist
erTypeLib does not write any values to the CLSID key of the coclass).
17.3.7 UnRegisterTypeLib
HRESULT UnRegisterTypeLib(
REFGUID libID,
unsigned short wVerMajor,
unsigned short wVerMinor,
LCID lcid,
SYSKIND syskind
);
Removes type library information from the system registry. Use this API to allow
applications to properly uninstall themselves. In-process objects typically cal
l this API from DllUnregisterServer.
Parameters
libID
Globally unique identifier.
wVerMajor
Major version number of the type library being removed.
wVerMinor
Minor version number of the type library being removed.
lcid
Locale identifier.
syskind
The target operating system (SYSKIND).
Return Value
The return value obtained from the returned HRESULT is one of the following:
Return value Meaning
S_OK Success.
E_OUTOFMEMORY Out of memory.
E_INVALIDARG One or more of the arguments is invalid.
TYPE_E_IOERROR The function could not write to the file.
TYPE_E_REGISTRYACCESS The system registration database could not be opened.
TYPE_E_INVALIDSTATE The type library could not be opened.
Comments
In-process objects typically call this API from DllUnregisterServer.
17.3.8 QueryPathOfRegTypeLib
HRESULT QueryPathOfRegTypeLib(
REFGUID guid,
unsigned short wVerMajor,
unsigned short wVerMinor,
LCID lcid,
LPBSTR lpbstrPathName
);
Retrieves the path of a registered type library.
Parameters
guid
GUID of the library whose path is to be queried.
wVerMajor
Major version number of the library whose path is to be queried.
wVerMinor
Minor version number of the library whose path is to be queried.
lcid
National language code for the library whose path is to be queried.
lpbstrPathName
Caller-allocated BSTR in which the type library name is returned.
Return Value
The return value obtained from the returned HRESULT is one of the following:
Return value Meaning
S_OK Success.
Comments
Returns the fully qualified file name that is specified for the type library in
the registry. The caller allocates the BSTR that is passed in, and must free it
after use.
18. Automation
Automation provides a way to expose and access objects within an application in
a late bound way. Automation defines the following dispatch interfaces and funct
ions.
IDispatch interface Exposes objects, methods, and properties to Automation progr
amming tools and other applications.
Dispatch API functions Simplifies the implementation of the IDispatch interface.
Use these functions to generate an IDispatch interface automatically.
IEnumVARIANT interface Provides a way for COM clients to iterate over collection
objects. This is a dispatch interface.
18.1 Overview of the IDispatch Interface
The following table describes the member functions of the IDispatch interface.
Interface Member function Purpose
IDispatch GetIDsOfNames Maps a single member name and an optional set of
argument names to a corresponding set of integer dispatch identifiers (DISPIDs)
, which can then be used on subsequent calls to Invoke.
GetTypeInfo Retrieves the type information for an object.
GetTypeInfoCount Retrieves the number of type information interfa
ces that an object provides (either 0 or 1).
Invoke Provides access to properties and methods exposed by an object.
Function Purpose
CompareString Compares two strings of the same locale.
LCMapString Transforms the case or sort order of a string.
GetLocaleInfo Retrieves locale information from the user ' s system.
GetStringType Retrieves locale type information about each character in a stri
ng.
GetSystemDefaultLangID Retrieves the default language ID (LANGID) from a user ' s syst
em.
GetSystemDefaultLCID Retrieves the default LCID from a user ' s system.
GetUserDefaultLangID Retrieves the default LANGID from a user ' s system.
GetUserDefaultLCID Retrieves the default LCID from a user ' s system.1
Comments
An IDispatch implementation can associate any positive integer ID value with a g
iven name. Zero is reserved for the default, or Value property; 1 is reserved to
indicate an unknown name; and other negative values are defined for other purpos
es. For example, if GetIDsOfNames is called, and the implementation does not rec
ognize one or more of the names, it returns DISP_E_UNKNOWNNAME, and the rgDispId
array contains DISPID_UNKNOWN for the entries that correspond to the unknown na
mes.
The member and parameter DISPIDs must remain constant for the lifetime of the ob
ject. This allows a client to obtain the DISPIDs once, and cache them for later
use.
When GetIDsOfNames is called with more than one name, the first name (rgszNames[
0]) corresponds to the member name, and subsequent names correspond to the names
of the member ' s parameters.
The same name may map to different DISPIDs, depending on context. For example, a
name may have a DISPID when it is used as a member name with a particular inter
face, a different ID as a member of a different interface, and different mapping
for each time it appears as a parameter.
The IDispatch interface binds to names at run time. To bind at compile time inst
ead, an IDispatch client can map names to DISPIDs by using the type information
interfaces described in Chapter 17. This allows a client to bind to members at c
ompile time and avoid calling GetIDsOfNames at run time. For a description of bi
nding at compile time, see Chapter 17.
The implementation of GetIDsOfNames is case insensitive. Users that need case-se
nsitive name mapping should use type information interfaces to map names to DISP
IDs, rather than call GetIDsOfNames.
Examples
The following code from the Lines sample file Lines.cpp implements the GetIDsOfN
ames member function for the CLine class. The COM object uses the standard imple
mentation, DispGetIDsOfNames.
STDMETHODIMP
CLine::GetIDsOfNames(
REFIID riid,
OLECHAR FAR* FAR* rgszNames,
UINT cNames,
LCID lcid,
DISPID FAR* rgDispId)
{
return DispGetIDsOfNames(m_ptinfo, rgszNames, cNames, rgDispId);
}
The following code might appear in an COM client that calls GetIDsOfNames to get
the DISPID of the CLine Color property.
HRESULT hresult;
IDispatch FAR* pdisp = (IDispatch FAR*)NULL;
DISPID dispid;
OLECHAR FAR* szMember = "color";
// Code that sets a pointer to the dispatch (pdisp) is omitted.
hresult = pdisp->GetIDsOfNames(
IID_NULL,
&szMember,
1, LOCALE_SYSTEM_DEFAULT,
&dispid);
See Also
CreateStdDispatch, DispGetIDsOfNames, ITypeInfo::GetIDsOfNames
18.4.1.2 IDispatch::GetTypeInfo
HRESULT GetTypeInfo(
unsigned int iTInfo,
LCID lcid,
ITypeInfo FAR* FAR* ppTInfo
);
Retrieves the type information for an object, which can then be used to get the
type information for an interface.
Parameters
iTInfo
The type information to return. Pass 0 to retrieve type information for the IDis
patch implementation.
lcid
The locale identifier for the type information. An object may be able to return
different type information for different languages. This is important for classe
s that support localized member names. For classes that do not support localized
member names, this parameter can be ignored.
ppTInfo
Receives a pointer to the requested type information object.
Return Value
The return value obtained from the returned HRESULT is one of the following:
Return value Meaning
S_OK Success; the type information element exists.
DISP_E_BADINDEX Failure; iTInfo argument was not 0.
TYPE_E_ELEMENTNOTFOUND Failure; iTInfo argument was not 0.
Example
The following code from the sample file Lines.cpp loads information from the typ
e library and implements the member function GetTypeInfo:
// These lines are from CLines::Create load type information for the
// Lines collection from the type library.
hr = LoadTypeInfo(&pLines->m_ptinfo, IID_ILines);
if (FAILED(hr))
goto error;
// Additional code omitted for brevity.
// This function implements GetTypeInfo for the CLines collection.
STDMETHODIMP
CLines::GetTypeInfo(
UINT iTInfo,
LCID lcid,
ITypeInfo FAR* FAR* ppTInfo)
{
*ppTInfo = NULL;
if(iTInfo != 0)
return ResultFromScode(DISP_E_BADINDEX);
m_ptinfo->AddRef();
*ppTInfo = m_ptinfo;
return NOERROR;
}
See also
CreateStdDispatch, CreateDispTypeInfo.
18.4.1.3 IDispatch::GetTypeInfoCount
HRESULT GetTypeInfoCount(
unsigned int FAR* pctinfo
);
Retrieves the number of type information interfaces that an object provides (eit
her 0 or 1).
Parameter
pctinfo
Points to a location that receives the number of type information interfaces pro
vided by the object. If the object provides type information, this number is 1;
otherwise the number is 0.
Return Value
The return value obtained from the returned HRESULT is one of the following:
Return value Meaning
S_OK Success.
E_NOTIMPL Failure.
Comments
The function may return zero, which indicates that the object does not provide a
ny type information. In this case, the object may still be programmable through
IDispatch, but does not provide type information for browsers, compilers, or oth
er programming tools that access type information. This can be useful for hiding
an object from browsers or for preventing early binding on an object.
Example
This code from the Lines sample file Lines.cpp implements the GetTypeInfoCount m
ember function for the CLines class (COM object).
STDMETHODIMP
CLines::GetTypeInfoCount(UINT FAR* pctinfo)
{
*pctinfo = 1;
return NOERROR;
}
See Also
CreateStdDispatch
18.4.1.4 IDispatch::Invoke
HRESULT Invoke(dispIdMember, riid, lcid, wFlags, pDispParams, pVarResult, pExcep
Info, puArgErr)
DISPID dispIdMember,
REFIID riid,
LCID lcid,
WORD wFlags,
DISPPARAMS FAR* pDispParams,
VARIANT FAR* pVarResult,
EXCEPINFO FAR* pExcepInfo,
unsigned int FAR* puArgErr
);
Provides access to properties and methods exposed by an object. The dispatch fun
ction DispInvoke provides a standard implementation of IDispatch::Invoke.
Parameters
dispIdMember
Identifies the member. Use GetIDsOfNames or the object ' s documentation to obtain the
dispatch identifier.
riid
Reserved for future use. Must be IID_NULL.
lcid
The locale context in which to interpret arguments. The lcid is used by the GetI
DsOfNames function, and is also passed to Invoke to allow the object to interpre
t its arguments specific to a locale.
Applications that do not support multiple national languages can ignore this par
ameter.
wFlags
Flags describing the context of the Invoke call, include:
Value Description
DISPATCH_METHOD The member is invoked as a method. If a property has the same na
me, both this and the DISPATCH_PROPERTYGET flag may be set.
DISPATCH_PROPERTYGET The member is retrieved as a property or data member.
DISPATCH_PROPERTYPUT The member is changed as a property or data member.
DISPATCH_PROPERTYPUTREF The member is changed by a reference assignment, rather
than a value assignment. This flag is valid only when the property accepts a ref
erence to an object.
pDispParams
Pointer to a structure containing an array of arguments, an array of argument DI
SPIDs for named arguments, and counts for the number of elements in the arrays.
See the Comments section that follows for a description of the DISPPARAMS struct
ure.
pVarResult
Pointer to the location where the result is to be stored, or Null if the caller
expects no result. This argument is ignored if DISPATCH_PROPERTYPUT or DISPATCH_
PROPERTYPUTREF is specified.
pExcepInfo
Pointer to a structure that contains exception information. This structure shoul
d be filled in if DISP_E_EXCEPTION is returned. Can be Null.
puArgErr
The index within rgvarg of the first argument that has an error. Arguments are s
tored in pDispParams->rgvarg in reverse order, so the first argument is the one
with the highest index in the array. This parameter is returned only when the re
sulting return value is DISP_E_TYPEMISMATCH or DISP_E_PARAMNOTFOUND. For details
, see " Returning Errors " in the following Comments section.
Return Value
The return value obtained from the returned HRESULT is one of the following:
Return value Meaning
S_OK Success.
DISP_E_BADPARAMCOUNT The number of elements provided to DISPPARAMS is differe
nt from the number of arguments accepted by the method or property.
DISP_E_BADVARTYPE One of the arguments in rgvarg is not a valid variant ty
pe.
DISP_E_EXCEPTION The application needs to raise an exception. In this cas
e, the structure passed in pExcepInfo should be filled in.
DISP_E_MEMBERNOTFOUND The requested member does not exist, or the call to Invo
ke tried to set the value of a read-only property.
DISP_E_NONAMEDARGS This implementation of IDispatch does not support named
arguments.
DISP_E_OVERFLOW One of the arguments in rgvarg could not be coerced to the speci
fied type.
DISP_E_PARAMNOTFOUND One of the parameter DISPIDs does not correspond to a pa
rameter on the method. In this case, puArgErr should be set to the first argumen
t that contains the error.
DISP_E_TYPEMISMATCH One or more of the arguments could not be coerced. The i
ndex within rgvarg of the first parameter with the incorrect type is returned in
the puArgErr parameter.
DISP_E_UNKNOWNINTERFACE The interface identifier passed in riid is not IID_NULL.
DISP_E_UNKNOWNLCID The member being invoked interprets string arguments acc
ording to the LCID, and the LCID is not recognized. If the LCID is not needed to
interpret arguments, this error should not be returned.
DISP_E_PARAMNOTOPTIONAL A required parameter was omitted.
In 16-bit versions, you can define your own errors using the MAKE_SCODE value ma
cro.
Comments
Generally, you should not implement Invoke directly. Instead, use the dispatch i
nterface create functions CreateStdDispatch and DispInvoke.
If some application-specific processing needs to be performed before calling a m
ember, the code should perform the necessary actions, and then call ITypeInfo::I
nvoke to invoke the member. ITypeInfo::Invoke acts exactly like IDispatch::Invok
e. The standard implementations of IDispatch::Invoke created by CreateStdDispatc
h and DispInvoke defer to ITypeInfo::Invoke.
In an COM client, IDispatch::Invoke should be used to get and set the values of
properties, or to call a method of an COM object. The dispIdMember argument iden
tifies the member to invoke. The DISPIDs that identify members are defined by th
e implementor of the object and can be determined by using the object ' s documentation
, the IDispatch::GetIDsOfNames function, or the ITypeInfo interface.
The information that follows addresses developers of COM clients and others who
use code to expose COM objects. It describes the behavior that users of exposed
objects should expect.
18.4.1.4.1 Calling a Method With No Arguments
The simplest use of Invoke is to call a method that does not have any arguments.
You only need to pass the DISPID of the method, a LCID, the DISPATCH_METHOD fla
g, and an empty DISPPARAMS structure. For example:
HRESULT hresult;
IUnknown FAR* punk;
IDispatch FAR* pdisp = (IDispatch FAR*)NULL;
OLECHAR FAR* szMember = "Simple";
DISPID dispid;
DISPPARAMS dispparamsNoArgs = {NULL, NULL, 0, 0};
hresult = CoCreateInstance(CLSID_CMyObject, NULL, CLSCTX_SERVER,
IID_Unknown, (void FAR* FAR*)&punk);
hresult = punk->QueryInterface(IID_IDispatch,
(void FAR* FAR*)&pdisp);
hresult = pdisp->GetIDsOfNames(IID_NULL, &szMember, 1,
LOCALE_USER_DEFAULT, &dispid);
hresult = pdisp->Invoke(
dispid,
IID_NULL,
LOCALE_USER_DEFAULT,
DISPATCH_METHOD,
&dispparamsNoArgs, NULL, NULL, NULL);
The example invokes a method named Simple on an object of the class CMyObject. F
irst, it calls CoCreateInstance, which instantiates the object and returns a poi
nter to the object ' s IUnknown interface (punk). Next, it calls QueryInterface, receiv
ing a pointer to the object ' s IDispatch interface (pdisp). It then uses pdisp to call
the object ' s GetIDsOfNames function, passing the string Simple in szMember to get th
e DISPID for the Simple method. With the DISPID for Simple in dispid, it calls I
nvoke to invoke the method, specifying DISPATCH_METHOD for the wFlags parameter
and using the system default locale.
To further simplify the code, the example declares a DISPPARAMS structure named
dispparamsNoArgs that is appropriate to an Invoke call with no arguments.
Because the Simple method does not take any arguments and does not return a resu
lt, the puArgErr and pVarResult parameters are Null. In addition, the example pa
sses Null for pExcepInfo, indicating that it is not prepared to handle exception
s and will handle only HRESULT errors.
Most methods, however, take one or more arguments. To invoke these methods, the
DISPPARAMS structure should be filled in, as described in " Passing Parameters " la
is chapter.
Automation defines special DISPIDs for invoking an object ' s Value property (the defau
lt), and the members _NewEnum, and Evaluate.
18.4.1.4.2 Getting and Setting Properties
Properties are accessed in the same way as methods, except you specify DISPATCH_
PROPERTYGET or DISPATCH_PROPERTYPUT instead of DISPATCH_METHOD. Some languages c
an not distinguish between retrieving a property and calling a method. In this c
ase, you should set the flags DISPATCH_PROPERTYGET and DISPATCH_METHOD.
The following example gets the value of a property named On. You can assume that
the object has been created, and that its interfaces have been queried, as in t
he previous example.
VARIANT FAR *pVarResult;
// Code omitted for brevity.
szMember = "On";
hresult = pdisp->GetIDsOfNames(IID_NULL, &szMember, 1,
LOCALE_USER_DEFAULT, &dispid);
hresult = pdisp->Invoke(
dispid,
IID_NULL,
LOCALE_USER_DEFAULT,
DISPATCH_PROPERTYGET,
&dispparamsNoArgs, pVarResult, NULL, NULL);
As in the previous example, the code calls GetIDsOfNames for the DISPID of the O
n property, and then passes the ID to Invoke. Then, Invoke returns the property ' s val
ue in pVarResult. In general, the return value does not set VT_BYREF. However, t
his bit may be set and a pointer returned to the return value, if the lifetime o
f the return value is the same as that of the object.
To change the property ' s value, the call looks like this:
VARIANT FAR *pVarResult;
DISPPARAMS dispparams;
DISPID mydispid = DISP_PROPERTYPUT
// Code omitted for brevity.
szMember = "On";
dispparams.rgvarg[0].vt = VT_BOOL;
dispparams.rgvarg[0].bool = FALSE;
dispparams.rgdispidNamedArgs = &mydispid;
dispparams.cArgs = 1;
dispparams.cNamedArgs = 1;
hresult = pdisp->GetIDsOfNames(IID_NULL, &szMember, 1,
LOCALE_USER_DEFAULT, &dispid);
hresult = pdisp->Invoke(
dispid,
IID_NULL,
LOCALE_USER_DEFAULT,
DISPATCH_PROPERTYPUT,
&dispparams, NULL, NULL, NULL);
The new value for the property (the Boolean value False) is passed as an argumen
t when the On property ' s Put function is invoked. The DISPID for the argument is DISP
ID_PROPERTYPUT. This DISPID is defined by Automation to designate the parameter
that contains the new value for a property ' s Put function. The remaining details of t
he DISPPARAMS structure are described in the next section, " Passing Parameters. "
The DISPATCH_PROPERTYPUT flag in the previous example indicates that a property
is being set by value. In Visual Basic, the following statement assigns the Valu
e property (the default) of YourObj to the Prop property:
MyObj.Prop = YourObj
This statement should be flagged as a DISPATCH_PROPERTYPUT. Similarly, statement
s like the following assign the Value property of one object to the Value proper
ty of another object.
Worksheet.Cell(1,1) = Worksheet.Cell(6,6)
MyDoc.Text1 = YourDoc.Text1
These statements result in a PROPERTY_PUT operation on Worksheet.Cell(1,1) and M
yDoc.Text1.
Use the DISPATCH_PROPERTYPUTREF flag to indicate a property or data member that
should be set by reference. For example, the following Visual Basic statement as
signs the pointer YourObj to the property Prop, and should be flagged as DISPATC
H_PROPERTYPUTREF.
Set MyObj.Prop = YourObj
The Set statement causes a reference assignment, rather than a value assignment.
The parameter on the right side is always passed by name, and should not be acce
ssed positionally.
18.4.1.4.3 Passing Parameters
Arguments to the method or property being invoked are passed in the DISPPARAMS s
tructure. This structure consists of a pointer to an array of arguments represen
ted as variants, a pointer to an array of DISPIDs for named arguments, and the n
umber of arguments in each array.
typedef struct FARSTRUCT tagDISPPARAMS{
VARIANTARG FAR* rgvarg; // Array of arguments.
DISPID FAR* rgdispidNamedArgs; // Dispatch IDs of named arguments.
unsigned int cArgs; // Number of arguments.
unsigned int cNamedArgs; // Number of named arguments.
} DISPPARAMS;
The arguments are passed in the array rgvarg[ ], with the number of arguments pa
ssed in cArgs. The arguments in the array should be placed from last to first, s
o rgvarg[0] has the last argument and rgvarg[cArgs -1] has the first argument. T
he method or property may change the values of elements within the array rgvarg,
but only if it has set the VT_BYREF flag. Otherwise, consider the elements as
read-only.
A dispatch invocation can have named arguments as well as positional arguments.
If cNamedArgs is 0, all the elements of rgvarg[ ] represent positional arguments
. If cNamedArgs is not 0, each element of rgdispidNamedArgs[ ] contains the DISP
ID of a named argument, and the value of the argument is in the matching element
of rgvarg[ ]. The DISPIDs of the named arguments are always contiguous in rgdis
pidNamedArgs, and their values are in the first cNamedArgs elements of rgvarg. N
amed arguments cannot be accessed positionally, and positional arguments cannot
be named.
The DISPID of an argument is its zero-based position in the argument list. For e
xample, the following method takes three arguments.
BOOL _export CDECL
CCredit::CheckCredit(BSTR bstrCustomerID, // DISPID = 0.
BSTR bstrLenderID, // DISPI
D = 1.
CURRENCY cLoanAmt) // DISPI
D = 2.
{
// Code omitted.
}
If you include the DISPID with each named argument, you can pass the named argum
ents to Invoke in any order. For example, if a method is to be invoked with two
positional arguments, followed by three named arguments (A, B, and C), using the
following hypothetical syntax, then cArgs would be 5, and cNamedArgs would be 3
.
object.method("arg1", "arg2", A := "argA", B := "argB", C := "argC")
The first positional argument would be in rgvarg[4]. The second positional argum
ent would be in rgvarg[3]. The ordering of named arguments is not important to t
he IDispatch implementation, but these arguments are generally passed in reverse
order. The argument A would be in rgvarg[2], with the DISPID of A in rgdispidNa
medArgs[2]. The argument B would be in rgvarg[1], with the corresponding DISPID
in rgdispidNamedArgs[1]. The argument C would be in rgvarg[0], with the DISPID c
orresponding to C in rgdispidNamedArgs[0]. You can also use Invoke on members wi
th optional arguments, but all optional arguments must be of type VARIANT. As wi
th required arguments, the contents of the argument vector depend on whether the
arguments are positional or named. The invoked member must ensure that the argu
ments are valid. Invoke merely passes the DISPPARAMS structure it receives.
Omitting named arguments is straightforward. You would pass the arguments in rgv
arg and their DISPIDs in rgdispidNamedArgs. To omit the argument named B (in the
preceding example) you would set rgvarg[0] to the value of C, with its DISPID i
n rgdispidNamedArgs[0]; and rgvarg[1] to the value of A, with its DISPID in rgdi
spidNamedArgs[1]. The subsequent positional arguments would occupy elements 2 an
d 3 of the arrays. In this case, cArgs is 4 and cNamedArgs
is 2.
If the arguments are positional (unnamed), you would set cArgs to the total numb
er of possible arguments, cNamedArgs to 0, and pass VT_ERROR as the type of the
omitted arguments, with the status code DISP_E_PARAMNOTFOUND as the value. For e
xample, the following code invokes ShowMe (,1).
VARIANT FAR *pVarResult;
EXCEPINFO FAR *pExcepInfo;
unsigned int FAR *puArgErr;
DISPPARAMS dispparams;
// Code omitted for brevity.
szMember = "ShowMe";
hresult = pdisp->GetIDsOfNames(IID_NULL, &szMember, 1,
LOCALE_USER_DEFA
ULT, &dispid) ;
dispparams.rgvarg[0].vt = VT_I2;
dispparams.rgvarg[0].ival = 1;
dispparams.rgvarg[1].vt = VT_ERROR;
dispparams.rgvarg[1].scode = DISP_E_PARAMNOTFOUND;
dispparams.cArgs = 2;
dispparams.cNamedArgs = 0;
hresult = pdisp->Invoke(
dispid,
IID_NULL,
LOCALE_USER_DEFAULT,
DISPATCH_METHOD,
&dispparams, pVarResult, pExcepInfo, puArgErr);
The example takes two positional arguments, but omits the first. Therefore, rgva
rg[0] contains 1, the value of the last argument in the argument list, and rgvar
g[1] contains VT_ERROR and the error return value, indicating the omitted first
argument.
The calling code is responsible for releasing all strings and objects referred t
o by rgvarg[ ] or placed in *pVarResult. As with other parameters that are passe
d by value, if the invoked member must maintain access to a string after returni
ng, you should copy the string. Similarly, if the member needs access to a passe
d-object pointer after returning, it must call the AddRef function on the object
. A common example occurs when an object property is changed to refer to a new o
bject, using the DISPATCH_PROPERTYPUTREF flag.
For those implementing IDispatch::Invoke, Automation provides the DispGetParam f
unction to retrieve parameters from the argument vector and coerce them to the p
roper type. For details, see " DispGetParam " later in this chapter.
18.4.1.4.4 Indexed Properties
When you invoke indexed properties of any dimension, you must pass the indexes a
s additional arguments. To set an indexed property, place the new value in the f
irst element of the rgvarg[ ] vector, and the indexes in the subsequent elements
. To get an indexed property, pass the indexes in the first n elements of rgvarg
, and the number of indexes in cArg. Invoke returns the value of the property in
pVarResult.
Automation stores array data in column-major order, which is the same ordering s
cheme used by Visual Basic and FORTRAN, but different from C, C++, and Pascal. I
f you are programming in C, C++, or Pascal, you must pass the indexes in the rev
erse order. The following example shows how to fill the DISPPARAMS structure in
C++.
dispparams.rgvarg[0].vt = VT_I2;
dispparams.rgvarg[0].iVal = 99;
dispparams.rgvarg[1].vt = VT_I2;
dispparams.rgvarg[1].iVal = 2;
dispparams.rgvarg[2].vt = VT_I2;
dispparams.rgvarg[2].iVal = 1;
dispparams.rgdispidNamedArgs = DISPID_PROPERTYPUT;
dispparams.cArgs = 3;
dispparams.cNamedArgs = 1;
The example changes the value of Prop[1,2] to 99. The new property value is pass
ed in rgvarg[0]. The right-most index is passed in rgvarg[1], and the next index
in rgvarg[2]. The cArgs field specifies the number of elements of rgvarg[ ] tha
t contain data, and cNamedArgs is 1, indicating the new value for the property.
Property collections are an extension of this feature.
18.4.1.4.5 Raising Exceptions During Invoke
When you implement IDispatch::Invoke, errors can be communicated either through
the normal return value or by raising an exception. An exception is a special si
tuation that is normally handled by jumping to the nearest routine enclosing the
exception handler.
To raise an exception, IDispatch::Invoke returns DISP_E_EXCEPTION and fills the
structure passed through pExcepInfo with information about the cause of the exce
ption or error. You can use the information to understand the cause of the excep
tion and proceed as necessary.
The exception information structure includes an error code number that identifie
s the kind of exception (a string that describes the error in a human-readable w
ay). It also includes a Help file and a Help context number that can be passed t
o Windows Help for details about the error. At a minimum, the error code number
must be filled with a valid number.
If you consider IDispatch another way to call C++ methods in an interface, EXCEP
INFO models the raising of an exception or longjmp() call by such a method.
18.4.1.4.6 Returning Errors
Invoke returns DISP_E_MEMBERNOTFOUND if one of the following conditions occurs:
· A member or parameter with the specified DISPID and matching cArgs cannot be fou
nd, and the parameter is not optional.
· The member is a void function, and the caller did not set pVarResult to Null.
· The member is a read-only property, and the caller set wFlags to DISPATCH_PROPER
TYPUT or DISPATCH_PROPERTYPUTREF.
If Invoke finds the member, but uncovers errors in the argument list, it returns
one of several other errors. DISP_E_BAD_PARAMCOUNT means that the DISPPARAMS st
ructure contains an incorrect number of parameters for the property or method. D
ISP_E_NONAMEDARGS means that Invoke received named arguments, but they are not s
upported by the member.
DISP_E_PARAMNOTFOUND means that the correct number of parameters was passed, but
the DISPID for one or more parameters was incorrect. If Invoke cannot convert o
ne of the arguments to the desired type, it returns DISP_E_TYPEMISMATCH. In thes
e two cases, if it can identify which argument is incorrect, Invoke sets *puArgE
rr to the index within rgvarg of the argument with the error. For example, if an
Automation method expects a reference to a double-precision number as an argume
nt, but receives a reference to an integer, the argument is coerced. However, if
the method receives a date, IDispatch::Invoke returns DISP_E_TYPEMISMATCH and s
ets *puArgErr to the index of the integer in the argument array.
Automation provides functions to perform standard conversions of VARIANT, and th
ese functions should be used for consistent operation. DISP_E_TYPEMISMATCH is re
turned only when these functions fail.
Example
This code from the Lines sample file Lines.cpp implements the Invoke member func
tion for the CLines class.
STDMETHODIMP
CLines::Invoke(
DISPID dispidMember,
REFIID riid,
LCID lcid,
WORD wFlags,
DISPPARAMS FAR* pDispParams,
VARIANT FAR* pVarResult,
EXCEPINFO FAR* pExcepInfo,
UINT FAR* puArgErr)
{
return DispInvoke(
this, m_ptinfo,
dispidMember, wFlags, pDispParams,
pVarResult, pExcepInfo, puArgErr);
}
The next code example calls the CLines::Invoke member function to get the value
of the Color property:
HRESULT hr;
EXCEPINFO excepinfo;
UINT nArgErr;
VARIANT vRet;
DISPPARAMS FAR* pdisp;
OLECHAR FAR* szMember;
DISPPARAMS dispparamsNoArgs = {NULL, NULL, 0, 0};
// Initialization code omitted for brevity.
szMember = "Color";
hr = pdisp->GetIDsOfNames(IID_NULL, &szMember, 1, LOCALE_USER_DEFAULT,
&dispid);
// Get Color property.
hr = pdisp->Invoke(dispid, IID_NULL, LOCALE_SYSTEM_DEFAULT,
DISPATCH_PROPERTYGET, &dispparams, &vRet, &excepinfo, &nArgErr);
See Also
CreateStdDispatch, DispInvoke, DispGetParam, ITypeInfo::Invoke
ICreateTypeInfo Interface
The ICreateTypeInfo interface provides the tools for creating and administering
the type information defined through the type description
ICreateTypeInfo::AddFuncDesc
HRESULT AddFuncDesc(
unsigned int index,
FUNCDESC FAR* pFuncDesc
);
Adds a function description to the type description.
Parameters
index
Index of the new FUNCDESC in the type information.
pFuncDesc
Pointer to a FUNCDESC structure that describes the function. The bstrIDLInfo fie
ld in the FUNCDESC should be set to Null for future compatibility.
Return Value
The return value of the returned HRESULT is one of the following:
Return value Meaning
S_OK Success.
STG_E_INSUFFICIENTMEMORY Out of memory.
E_OUTOFMEMORY Out of memory.
E_INVALIDARG One or more of the arguments is invalid.
E_ACCESSDENIED Cannot write to the destination.
TYPE_E_WRONGTYPEKIND Type mismatch.
Comments
The index specifies the order of the functions within the type information. The
first function has an index of zero. If an index is specified that exceeds one l
ess than the number of functions in the type information, an error is returned.
Calling this function does not pass ownership of the FUNCDESC structure to ICrea
teTypeInfo. Therefore, the caller must still de-allocate the FUNCDESC structure.
The passed-in virtual function table (VTBL) field (oVft) of the FUNCDESC is igno
red. This attribute is set when ICreateTypeInfo::LayOut is called.
The function AddFuncDesc uses the passed-in member identifier (ID) fields within
each FUNCDESC for classes with TYPEKIND = TKIND_DISPATCH or TKIND_INTERFACE. If
the member IDs are set to MEMBERID_NIL, AddFuncDesc assigns member IDs to the f
unctions. Otherwise, the member ID fields within each FUNCDESC are ignored.
Any HREFTYPE fields in the FUNCDESC structure must have been produced by the sam
e instance of ITypeInfo for which AddFuncDesc is called.
The get and put accessor functions for the same property must have the same disp
atch identifier (DISPID).
ICreateTypeInfo::AddImplType
HRESULT AddImplType(
unsigned int index,
HREFTYPE hRefType
);
Specifies an inherited interface, or an interface implemented by a component obj
ect class (coclass).
Parameters
index
Index of the implementation class to be added. Specifies the order of the type r
elative to the other type.
hRefType
Handle to the referenced type description obtained from the AddRefType descripti
on.
Return Value
The return value of the returned HRESULT is one of the following:
Return value Meaning
S_OK Success.
STG_E_INSUFFICIENTMEMORY Out of memory.
E_OUTOFMEMORY Out of memory.
E_ACCESSDENIED Cannot write to the destination.
TYPE_E_WRONGTYPEKIND Type mismatch.
Comments
To specify an inherited interface, use index = 0. For a dispinterface with Synta
x 2, call ICreateTypeInfo::AddImplType twice, once with nindex = 0 for the inher
ited IDispatch and once with nindex = 1 for the interface that is being wrapped.
For a dual interface, call ICreateTypeInfo::AddImplType with nindex = -1 for th
e TKIND_INTERFACE type information component of the dual interface.
ICreateTypeInfo::AddRefTypeInfo
HRESULT AddRefTypeInfo(
ITypeInfo FAR* pTInfo,
HREFTYPE FAR* phRefType
);
Adds a type description to those referenced by the type description being create
d.
Parameters
pTInfo
Pointer to the type description to be referenced.
phRefType
On return, pointer to the handle that this type description associates with the
referenced type information.
Return Value
The return value of the returned HRESULT is one of the following:
Return value Meaning
S_OK Success.
STG_E_INSUFFICIENTMEMORY Out of memory.
E_OUTOFMEMORY Out of memory.
E_INVALIDARG One or more of the arguments is invalid.
E_ACCESSDENIED Cannot write to the destination.
TYPE_E_WRONGTYPEKIND Type mismatch.
Comments
The second parameter returns a pointer to the handle of the added type informati
on. If AddRefTypeInfo has been called previously for the same type information,
the index that was returned by the previous call is returned in phRefType. If th
e referenced type description is in the type library being created, its type inf
ormation can be obtained by calling IUnknown::QueryInterface(IID_ITypeInfo, ...)
on the ICreateTypeInfo interface of that type description.
ICreateTypeInfo::AddVarDesc
HRESULT AddVarDesc(
unsigned int index,
VARDESC FAR* pVarDesc
);
Adds a variable or data member description to the type description.
Parameters
index
Index of the variable or data member to be added to the type description.
pVarDesc
Pointer to the variable or data member description to be added.
Return Value
The return value of the returned HRESULT is one of the following:
Return value Meaning
S_OK Success.
STG_E_INSUFFICIENTMEMORY Out of memory.
E_OUTOFMEMORY Out of memory.
E_INVALIDARG One or more of the arguments is invalid.
E_ACCESSDENIED Cannot write to the destination.
TYPE_E_WRONGTYPEKIND Type mismatch.
Comments
The index specifies the order of the variables. The first variable has an index
of zero. ICreateTypeInfo::AddVarDesc returns an error if the specified index is
greater than the number of variables currently in the type information. Calling
this function does not pass ownership of the VARDESC structure to ICreateTypeInf
o. The instance field (oInst) of the VARDESC structure is ignored. This attribut
e is set only when ICreateTypeInfo::LayOut is called. Also, the member ID fields
within the VARDESCs are ignored unless the TYPEKIND of the class is TKIND_DISPA
TCH.
Any HREFTYPE fields in the VARDESC structure must have been produced by the same
instance of ITypeInfo for which AddVarDesc is called.
AddVarDesc ignores the contents of the idldesc field of the ELEMDESC.
ICreateTypeInfo::DefineFuncAsDllEntry
HRESULT DefineFuncAsDllEntry(
unsigned int index,
OLECHAR FAR* szDllName,
OLECHAR FAR* szProcName
);
Associates a DLL entry point with the function that has the specified index.
Parameters
index
Index of the function.
szDllName
Name of the DLL that contains the entry point.
szProcName
Name of the entry point or an ordinal (if the high word is zero).
Return Value
The return value of the returned HRESULT is one of the following:
Return value Meaning
S_OK Success.
STG_E_INSUFFICIENTMEMORY Out of memory.
E_OUTOFMEMORY Out of memory.
E_INVALIDARG One or more of the arguments is invalid.
TYPE_E_ELEMENTNOTFOUND The element cannot be found.
TYPE_E_WRONGTYPEKIND Type mismatch.
Comments
If the high word of szProcName is zero, then the low word must contain the ordin
al of the entry point; otherwise, szProcName points to the zero-terminated name
of the entry point.
ICreateTypeInfo::LayOut
HRESULT LayOut();
Assigns VTBL offsets for virtual functions and instance offsets for per-instance
data members, and creates the two type descriptions for dual interfaces.
Parameters
None
Return Value
The return value of the returned HRESULT is one of the following:
Return value Meaning
S_OK Success.
STG_E_INSUFFICIENTMEMORY Out of memory.
E_OUTOFMEMORY Out of memory.
E_ACCESSDENIED Cannot write to the destination.
TYPE_E_UNDEFINEDTYPE Bound to unrecognized type.
TYPE_E_INVALIDSTATE The state of the type library is not valid for this oper
ation.
TYPE_E_WRONGTYPEKIND Type mismatch.
TYPE_E_ELEMENTNOTFOUND The element cannot be found.
TYPE_E_AMBIGUOUSNAME More than one item exists with this name.
TYPE_E_SIZETOOBIG The type information is too long.
TYPE_E_TYPEMISMATCH Type mismatch.
Comments
LayOut also assigns member ID numbers to the functions and variables, unless the
TYPEKIND of the class is TKIND_DISPATCH. Call LayOut after all members of the t
ype information are defined, and before the type library is saved.
Use ICreateTypeLib::SaveAllChanges to save the type information after calling La
yOut. Other members of the ICreateTypeInfo interface should not be called after
calling LayOut.
Note
Different implementations of ICreateTypeInfo or other interfaces that create typ
e information are free to assign any member ID numbers, provided that all member
s (including inherited members), have unique IDs. For examples, see the ICreateT
ypeInfo2 interface later in this chapter..
ICreateTypeInfo::SetAlignment
HRESULT SetAlignment(
unsigned short cbAlignment
);
Specifies the data alignment for an item of TYPEKIND=TKIND_RECORD.
Parameter
cbAlignment
Alignment method for the type. A value of 0 indicates alignment on the 64K bound
ary; 1 indicates no special alignment. For other values, n indicates alignment o
n byte n.
Return Value
The return value of the returned HRESULT is one of the following:
Return value Meaning
S_OK Success.
STG_E_INSUFFICIENTMEMORY Out of memory.
E_OUTOFMEMORY Out of memory.
E_ACCESSDENIED Cannot write to the destination.
TYPE_E_INVALIDSTATE The state of the type library is not valid for this oper
ation.
Comments
The alignment is the minimum of the natural alignment (for example, byte data on
byte boundaries, word data on word boundaries, and so on), and the alignment de
noted by cbAlignment.
ICreateTypeInfo::SetDocString
HRESULT SetDocString(
OLECHAR FAR* pStrDoc
);
Sets the documentation string displayed by type browsers.
Parameter
pStrDoc
Pointer to the documentation string.
Return Value
The return value of the returned HRESULT is one of the following:
Return value Meaning
S_OK Success.
STG_E_INSUFFICIENTMEMORY Out of memory.
E_OUTOFMEMORY Out of memory.
E_ACCESSDENIED Cannot write to the destination.
TYPE_E_INVALIDSTATE The state of the type library is not valid for this oper
ation.
Comments
The documentation string is a brief description of the type description being cr
eated.
ICreateTypeInfo::SetFuncAndParamNames
HRESULT SetFuncAndParamNames(
unsigned int index,
OLECHAR FAR* FAR* rgszNames,
unsigned int cNames
);
Sets the name of a function and the names of its parameters to the names in the
array of pointers rgszNames.
Parameters
index
Index of the function whose function name and parameter names are to be set.
rgszNames
Array of pointers to names. The first element is the function name. Subsequent e
lements are names of parameters.
cNames
Number of elements in the rgszNames array.
Return Value
The return value of the returned HRESULT is one of the following:
Return value Meaning
S_OK Success.
STG_E_INSUFFICIENTMEMORY Out of memory.
E_OUTOFMEMORY Out of memory.
E_INVALIDARG One or more of the arguments is invalid.
E_ACCESSDENIED Cannot write to the destination.
TYPE_E_ELEMENTNOTFOUND The element cannot be found.
Comments
The function SetFuncAndParamNames needs to be used once for each property. The l
ast parameter for put and putref accessor functions is unnamed.
ICreateTypeInfo::SetFuncDocString
HRESULT SetFuncDocString(
unsigned int index,
OLECHAR FAR* szDocString
);
Sets the documentation string for the function with the specified index.
Parameters
index
Index of the function.
szDocString
Pointer to the documentation string.
Return Value
The return value of the returned HRESULT is one of the following:
Return value Meaning
S_OK Success.
STG_E_INSUFFICIENTMEMORY Out of memory.
E_OUTOFMEMORY Out of memory.
E_INVALIDARG One or more of the arguments is invalid.
E_ACCESSDENIED Cannot write to the destination.
TYPE_E_ELEMENTNOTFOUND The element cannot be found.
Comments
The documentation string is a brief description of the function intended for use
by tools such as type browsers. SetFuncDocString only needs to be used once for
each property, because all property accessor functions are identified by one na
me.
ICreateTypeInfo::SetFuncHelpContext
HRESULT SetFuncHelpContext(
unsigned int index,
unsigned long dwHelpContext
);
Sets the Help context ID for the function with the specified index.
Parameters
index
Index of the function.
dwHelpContext
Help context ID for the Help topic.
Return Value
The return value of the returned HRESULT is one of the following:
Return value Meaning
S_OK Success.
STG_E_INSUFFICIENTMEMORY Out of memory.
E_OUTOFMEMORY Out of memory.
E_ACCESSDENIED Cannot write to the destination.
TYPE_E_ELEMENTNOTFOUND The element cannot be found.
E_INVALIDARG One or more of the arguments is invalid.
Comments
SetFuncHelpContext only needs to be set once for each property, because all prop
erty accessor functions are identified by one name.
ICreateTypeInfo::SetGuid
HRESULT SetGuid(
REFGUID guid
);
Sets the globally unique identifier (GUID) associated with the type description.
Parameter
guid
Globally unique ID to be associated with the type description.
Return Value
The return value of the returned HRESULT is one of the following:
Return value Meaning
S_OK Success.
STG_E_INSUFFICIENTMEMORY Out of memory.
E_OUTOFMEMORY Out of memory.
E_ACCESSDENIED Cannot write to the destination.
Comments
For an interface, this is an interface ID (IID); for a coclass, it is a class ID
(CLSID).
ICreateTypeInfo::SetHelpContext
HRESULT SetHelpContext(
unsigned long dwHelpContext
);
Sets the Help context ID of the type information.
Parameter
dwHelpContext
Handle to the Help context.
Return Value
The return value of the returned HRESULT is one of the following:
Return value Meaning
S_OK Success.
STG_E_INSUFFICIENTMEMORY Out of memory.
E_OUTOFMEMORY Out of memory.
E_INVALIDARG One or more of the arguments is invalid.
E_ACCESSDENIED Cannot write to the destination.
ICreateTypeInfo::SetImplTypeFlags
HRESULT SetImplTypeFlags(
unsigned int index,
int implTypeFlags
);
Sets the attributes for an implemented or inherited interface of a type.
Parameters
index
Index of the interface for which to set type flags.
implTypeFlags
IMPLTYPE flags to be set.
Return Value
The return value of the returned HRESULT is one of the following:
Return value Meaning
S_OK Success.
STG_E_INSUFFICIENTMEMORY Out of memory.
E_OUTOFMEMORY Out of memory.
E_INVALIDARG One or more of the arguments is invalid.
E_ACCESSDENIED Cannot write to the destination.
Comments
SetImplTypeFlags sets the IMPLTYPE flags for the indexed interface. For more inf
ormation, see Chapter 17.
ICreateTypeInfo::SetMops
HRESULT SetMops(
unsigned int index
BSTR bstrMops
);
Sets the marshaling opcode string associated with the type description or the fu
nction.
Parameters
index
Index of the member for which to set the opcode string. If index is 1, sets the o
pcode string for the type description.
bstrMops
The marshaling opcode string.
Return Value
The return value of the returned HRESULT is one of the following:
Return value Meaning
S_OK Success.
STG_E_INSUFFICIENTMEMORY Out of memory.
E_OUTOFMEMORY Out of memory.
E_INVALIDARG One or more of the arguments is invalid.
E_ACCESSDENIED Cannot write to the destination.
ICreateTypeInfo::SetTypeDescAlias
HRESULT SetTypeDescAlias(
TYPEDESC FAR* pTDescAlias
);
Sets the type description for which this type description is an alias, if TYPEKI
ND=TKIND_ALIAS.
Parameter
pTDescAlias
Pointer to a type description that describes the type for which this is an alias
.
Return Value
The return value of the returned HRESULT is one of the following:
Return value Meaning
S_OK Success.
STG_E_INSUFFICIENTMEMORY Out of memory.
E_OUTOFMEMORY Out of memory.
E_INVALIDARG One or more of the arguments is invalid.
E_ACCESSDENIED Cannot write to the destination.
TYPE_E_WRONGTYPEKIND Type mismatch.
Comments
To set the type for an alias, call SetTypeDescAlias for a type description whose
TYPEKIND is TKIND_ALIAS.
ICreateTypeInfo::SetTypeFlags
HRESULT SetTypeFlags(
unsigned int uTypeFlags
);
Sets type flags of the type description being created.
Parameter
uTypeFlags
Settings for the type flags.
Return Value
The return value of the returned HRESULT is one of the following:
Return value Meaning
S_OK Success.
STG_E_INSUFFICIENTMEMORY Out of memory.
E_OUTOFMEMORY Out of memory.
E_INVALIDARG One or more of the arguments is invalid.
E_ACCESSDENIED Cannot write to the destination.
TYPE_E_WRONGTYPEKIND Type mismatch.
Comments
Use SetTypeFlags to set the flags for the type description. For details, see Cha
pter 17.
ICreateTypeInfo::SetVarDocString
HRESULT SetVarDocString(
unsigned int index,
OLECHAR FAR* szDocString
);
Sets the documentation string for the variable with the specified index.
Parameters
index
Index of the variable being documented.
szDocString
The documentation string to be set.
Return Value
The return value of the returned HRESULT is one of the following:
Return value Meaning
S_OK Success.
STG_E_INSUFFICIENTMEMORY Out of memory.
E_OUTOFMEMORY Out of memory.
E_ACCESSDENIED Cannot write to the destination.
TYPE_E_ELEMENTNOTFOUND The element was not found.
ICreateTypeInfo::SetVarHelpContext
HRESULT SetVarHelpContext(
unsigned int index,
unsigned long dwHelpContext
);
Sets the Help context ID for the variable with the specified index.
Parameters
index
Index of the variable described by the type description.
dwHelpContext
Handle to the Help context ID for the Help topic on the variable.
Return Value
The return value of the returned HRESULT is one of the following:
Return value Meaning
S_OK Success.
STG_E_INSUFFICIENTMEMORY Out of memory.
E_OUTOFMEMORY Out of memory.
E_ACCESSDENIED Cannot write to the destination.
TYPE_E_ELEMENTNOTFOUND The element cannot be found.
ICreateTypeInfo::SetVarName
HRESULT SetVarName(
unsigned int index,
OLECHAR FAR* szName
);
Sets the name of a variable.
Parameters
index
Index of the variable whose name is being set.
szName
Name for the variable.
Return Value
The return value of the returned HRESULT is one of the following:
Return value Meaning
S_OK Success.
STG_E_INSUFFICIENTMEMORY Out of memory.
E_OUTOFMEMORY Out of memory.
E_ACCESSDENIED Cannot write to the destination.
TYPE_E_ELEMENTNOTFOUND The element cannot be found.
ICreateTypeInfo::SetVersion
HRESULT SetVersion(
unsigned short wMajorVerNum,
unsigned short wMinorVerNum
);
Sets the major and minor version number of the type information.
Parameters
wMajorVerNum
Major version number for the type.
wMinorVerNum
Minor version number for the type.
Return Value
The return value of the returned HRESULT is one of the following:
Return value Meaning
S_OK Success.
E_ACCESSDENIED Cannot write to the destination.
TYPE_E_INVALIDSTATE The state of the type library is not valid for this oper
ation.
ICreateTypeInfo2 Interface
The ICreateTypeInfo2 interface derives from ICreateTypeInfo, and adds methods fo
r deleting items that have been added through ICreateTypeInfo.
The ICreateTypeInfo::LayOut method provides a way for the creator of the type in
formation to check for any errors. A call to QueryInterface() can be made to the
ICreateTypeInfo instance at any time for its ITypeInfo interface. Calling any o
f the methods in the ITypeInfo interface that require layout information lays ou
t the type information automatically.
Example
interface ICreateTypeInfo2 : ICreateTypeInfo
ICreateTypeInfo2::SetName
HRESULT SetName(
OLECHAR FAR* szName
);
Sets the name of the typeinfo.
Parameter
szName
Name to be assigned to the typeinfo.
Return Value
The return value of the returned HRESULT is one of the following:
Return value Meaning
S_OK Success.
STG_E_INSUFFICIENTMEMORY Out of memory.
E_OUTOFMEMORY Out of memory.
E_INVALIDARG One or more of the arguments is invalid.
TYPE_E_INVALIDSTATE The state of the type info is not valid for this operati
on.
ICreateTypeInfo2::DeleteFuncDesc
HRESULT DeleteFuncDesc(
unsigned int index
);
Deletes a function description specified by the index number.
Parameter
index
Index of the function whose description is to be deleted. The index should be in
the range of 0 to 1 less than the number of functions in this type.
Return Value
The return value obtained from the returned HRESULT is one of the following:
Return value Meaning
S_OK Success.
E_OUTOFMEMORY Out of memory.
E_INVALIDARG One or more of the arguments is invalid.
ICreateTypeInfo2::DeleteFuncDescByMemId
HRESULT DeleteFuncDescByMemId(
MEMBERID memid,
INVOKEKIND invKind
);
Deletes the function description (FUNCDESC) specified by memid.
Parameters
memid
Member identifier of the FUNCDESC to delete.
invKind
The type of the invocation.
Return Value
The return value obtained from the returned HRESULT is one of the following:
Return value Meaning
S_OK Success.
E_OUTOFMEMORY Out of memory.
E_INVALIDARG One or more of the arguments is invalid.
ICreateTypeInfo2::DeleteVarDesc
HRESULT DeleteVarDesc(
unsigned int index
);
Deletes the specified VARDESC structure.
Parameter
index
Index number of the VARDESC structure.
Return Value
The return value obtained from the returned HRESULT is one of the following:
Return value Meaning
S_OK Success.
E_OUTOFMEMORY Out of memory.
E_INVALIDARG One or more of the arguments is invalid.
TYPE_E_IOERROR The function cannot read from the file.
TYPE_E_INVDATAREAD The function cannot read from the file.
TYPE_E_UNSUPFORMAT The type library has an old format.
TYPE_E_INVALIDSTATE The type library cannot be opened.
Example
ptypeinfo->DeleteVarDesc(index);
ICreateTypeInfo2::DeleteVarDescByMemId
HRESULT DeleteVarDescByMemId(
MEMBERID memid
);
Deletes the specified VARDESC structure.
Parameter
memid
Member identifier of the VARDESC to be deleted.
Return Value
The return value obtained from the returned HRESULT is one of the following:
Return value Meaning
S_OK Success.
E_OUTOFMEMORY Out of memory.
E_INVALIDARG One or more of the arguments is invalid.
TYPE_E_IOERROR The function cannot read from the file.
TYPE_E_INVDATAREAD The function cannot read from the file.
TYPE_E_UNSUPFORMAT The type library has an older format.
TYPE_E_INVALIDSTATE The type library cannot be opened.
ICreateTypeInfo2::DeleteImplType
HRESULT DeleteImplType(
unsigned int index
);
Deletes the IMPLTYPE flags for the indexed interface.
Parameter
index
Index of the interface for which to delete the type flags.
Return Value
The return value obtained from the returned HRESULT is one of the following:
Return value Meaning
S_OK Success.
E_OUTOFMEMORY Out of memory.
E_INVALIDARG One or more of the arguments is invalid.
ICreateTypeInfo2::SetCustData
HRESULT SetCustData(
REFGUID guid,
VARIANT *pVarVal
);
Sets a value for custom data.
Parameters
guid
Unique identifier that can be used to identify the data.
pVarVal
The data to store (any variant except an object).
Return Value
The return value obtained from the returned HRESULT is one of the following:
Return value Meaning
S_OK Success.
E_OUTOFMEMORY Out of memory.
E_INVALIDARG One or more of the arguments is invalid.
ICreateTypeInfo2::SetHelpStringContext
HRESULT SetHelpStringContext(
DWORD *dwHelpStringContext
);
Sets the context number for the specified Help string.
Parameter
dwHelpStringContext
Pointer to the Help string context number.
Return Value
The return value obtained from the returned HRESULT is one of the following:
Return value Meaning
S_OK Success.
E_OUTOFMEMORY Out of memory.
E_INVALIDARG Argument is invalid.
ICreateTypeInfo2::SetFuncCustData
HRESULT SetFuncCustData(
unsigned int index,
REFGUID guid,
VARIANT *pVarVal
);
Sets a value for a specified custom function.
Parameters
index
The index of the function for which to set the custom data.
guid
Unique identifier used to identify the data.
pVarVal
The data to store (any variant except an object).
Return Value
The return value obtained from the returned HRESULT is one of the following:
Return value Meaning
S_OK Success.
E_OUTOFMEMORY Out of memory.
E_INVALIDARG One or more of the arguments is invalid.
ICreateTypeInfo2::SetFuncHelpStringContext
HRESULT SetFuncHelpStringContext(
unsigned int index,
DWORD dwHelpStringContext,
);
Sets a Help context value for a specified custom function.
Parameters
index
The index of the function for which to set the custom data.
dwHelpStringContext
Help string context for a localized string
Return Value
The return value obtained from the returned HRESULT is one of the following:
Return value Meaning
S_OK Success.
E_OUTOFMEMORY Out of memory.
E_INVALIDARG One or more of the arguments is invalid.
ICreateTypeInfo2::SetVarCustData
HRESULT SetVarCustData(
unsigned int index,
REFGUID guid,
VARIANT *pVarVal
);
Sets a custom data variable.
Parameters
index
Index of the variable for which to set the custom data.
guid
Globally unique ID (GUID) used to identify the data.
pVarVal
Data to store (any legal variant except an object).
Return Value
The return value obtained from the returned HRESULT is one of the following:
Return value Meaning
S_OK Success.
E_OUTOFMEMORY Out of memory.
E_INVALIDARG One or more of the arguments is invalid.
ICreateTypeInfo2::SetParamCustData
HRESULT SetParamCustData(
unsigned int indexFunc,
unsigned int indexParam,
REFGUID guid,
VARIANT *pVarVal
);
Sets the specified parameter for the custom data.
Parameters
indexFunc
Index of the function for which to set the custom data.
indexParam
Index of the parameter of the function for which to set the custom data.
guid
Globally unique identifier (GUID) used to identify the data.
pvarVal
The data to store (any legal variant except an object).
Return Value
The return value obtained from the returned HRESULT is one of the following:
Return value Meaning
S_OK Success.
E_OUTOFMEMORY Out of memory.
E_INVALIDARG One or more of the arguments is invalid.
ICreateTypeInfo2::SetImplTypeCustData
HRESULT SetImplTypeCustData(
unsigned int index,
REFGUID guid,
VARIANT *pVarVal,
);
Sets the implementation type for custom data.
Parameters
index
Index of the variable for which to set the custom data.
guid
Unique identifier used to identify the data.
pVarVal
Reference to the value of the variable.
Return Value
The return value obtained from the returned HRESULT is one of the following:
Return value Meaning
S_OK Success.
E_OUTOFMEMORY Out of memory.
E_INVALIDARG One or more of the arguments is invalid.
ICreateTypeInfo2::SetVarHelpStringContext
HRESULT SetVarHelpStringContext(
unsigned int index,
DWORD dwHelpStringContext,
);
Sets a Help context value for a specified variable.
Parameters
index
The index of the variable.
dwHelpStringContext
Help string context for a localized string
Return Value
The return value obtained from the returned HRESULT is one of the following:
Return value Meaning
S_OK Success.
E_OUTOFMEMORY Out of memory.
E_INVALIDARG One or more of the arguments is invalid.
ICreateTypeLib Interface
The ICreateTypeLib interface provides the methods for creating and managing the
component or file that contains type information. Type libraries are created fro
m type descriptions using the MkTypLib utility or the MIDL compiler. These type
libraries are accessed through the ITypeLib interface.
ICreateTypeLib::CreateTypeInfo
HRESULT CreateTypeInfo(
OLECHAR FAR* szName,
TYPEKIND tkind,
ICreateTypeInfo FAR* FAR* ppCTInfo
);
Creates a new type description instance within the type library.
Parameters
szName
Name of the new type.
tkind
TYPEKIND of the type description to be created.
ppCTInfo
On return, contains a pointer to the type description.
Return Value
The return value of the returned HRESULT is one of the following:
Return value Meaning
S_OK Success.
STG_E_INSUFFICIENTMEMORY Out of memory.
E_OUTOFMEMORY Out of memory.
E_INVALIDARG One or more of the arguments is invalid.
TYPE_E_INVALIDSTATE The state of the type library is not valid for this oper
ation.
TYPE_E_NAMECONFLICT The provided name is not unique.
TYPE_E_WRONGTYPEKIND Type mismatch.
Comments
Use the function CreateTypeInfo to create a new type description instance within
the library. An error is returned if the specified name already appears in the
library. Valid tkind values are described in Chapter 17. To get the type informa
tion of the type description that is being created, call IUnknown::QueryInterfac
e(IID_ITypeInfo, ...) on the returned ICreateTypeInfo. This type information can
be used by other type descriptions that reference it by using ICreateTypeInfo::
AddRefTypeInfo.
ICreateTypeLib::SaveAllChanges
HRESULT SaveAllChanges();
Saves the ICreateTypeLib instance following the layout of type information.
Parameters
None.
Return Value
The return value of the returned HRESULT is one of the following:
Return value Meaning
S_OK Success.
STG_E_INSUFFICIENTMEMORY Out of memory.
E_OUTOFMEMORY Out of memory.
E_INVALIDARG One or more of the arguments is invalid.
TYPE_E_IOERROR The function cannot write to the file.
TYPE_E_INVALIDSTATE The state of the type library is not valid for this oper
ation.
Other return codes All FACILITY_STORAGE errors.
Comments
You should not call any other ICreateTypeLib methods after calling SaveAllChange
s.
ICreateTypeLib::SetDocString
HRESULT SetDocString(
OLECHAR FAR* szDoc
);
Sets the documentation string associated with the library.
Parameter
szDoc
A documentation string that briefly describes the type library.
Return Value
The return value of the returned HRESULT is one of the following:
Return value Meaning
S_OK Success.
STG_E_INSUFFICIENTMEMORY Out of memory.
E_OUTOFMEMORY Out of memory.
E_INVALIDARG One or more of the arguments is invalid.
Comments
The documentation string is a brief description of the library intended for use
by type information browsing tools.
ICreateTypeLib::SetGuid
HRESULT SetGuid(
REFGUID guid
);
Sets the universal unique identifier (UUID) associated with the type library (Al
so known as the globally unique identifier (GUID)).
Parameter
guid
The globally unique identifier to be assigned to the library.
Return Value
The return value of the returned HRESULT is one of the following:
Return value Meaning
S_OK Success.
STG_E_INSUFFICIENTMEMORY Out of memory.
E_OUTOFMEMORY Out of memory.
E_INVALIDARG One or more of the arguments is invalid.
TYPE_E_INVALIDSTATE The state of the type library is not valid for this oper
ation.
Comments
ICreateTypeLib::SetHelpContext
HRESULT SetHelpContext(
unsigned long dwHelpContext
);
Sets the Help context ID for retrieving general Help information for the type li
brary.
Parameter
dwHelpContext
Help context ID to be assigned to the library.
Return Value
The return value of the returned HRESULT is one of the following:
Return value Meaning
S_OK Success.
STG_E_INSUFFICIENTMEMORY Out of memory.
E_OUTOFMEMORY Out of memory.
E_INVALIDARG One or more of the arguments is invalid.
TYPE_E_INVALIDSTATE The state of the type library is not valid for this oper
ation.
Comments
Calling SetHelpContext with a Help context of zero is equivalent to not calling
it at all, because zero indicates a null Help context.
ICreateTypeLib::SetHelpFileName
HRESULT SetHelpFileName(
OLECHAR FAR* szHelpFileName
);
Sets the name of the Help file.
Parameter
szHelpFileName
The name of the Help file for the library.
Return Value
The return value of the returned HRESULT is one of the following:
Return value Meaning
S_OK Success.
STG_E_INSUFFICIENTMEMORY Out of memory.
E_OUTOFMEMORY Out of memory.
E_INVALIDARG One or more of the arguments is invalid.
TYPE_E_INVALIDSTATE The state of the type library is not valid for this oper
ation.
Comments
Each type library can reference a single Help file.
The GetDocumentation method of the created ITypeLib returns a fully qualified pa
th for the Help file, which is formed by appending the name passed into szHelpFi
leName to the registered Help directory for the type library. The Help directory
is registered under:
\TYPELIB\<guid of library>\<Major.Minor version >\HELPDIR
ICreateTypeLib::SetLibFlags
HRESULT SetLibFlags(
unsigned int uLibFlags
);
Sets library flags, such as LIBFLAG_FRESTRICTED.
Parameter
uLibFlags
The flags to set for the library.
Return Value
The return value of the returned HRESULT is one of the following:
Return value Meaning
S_OK Success.
STG_E_INSUFFICIENTMEMORY Out of memory.
E_OUTOFMEMORY Out of memory.
E_INVALIDARG One or more of the arguments is invalid.
TYPE_E_INVALIDSTATE The state of the type library is not valid for this oper
ation.
Comments
ICreateTypeLib::SetLcid
HRESULT SetLcid(
LCID lcid
);
Sets the binary Microsoft national language ID associated with the library.
Parameter
lcid
Represents the locale ID for the type library.
Return Value
The return value of the returned HRESULT is one of the following:
Return value Meaning
S_OK Success.
STG_E_INSUFFICIENTMEMORY Out of memory.
E_OUTOFMEMORY Out of memory.
E_INVALIDARG One or more of the arguments is invalid.
TYPE_E_INVALIDSTATE The state of the type library is not valid for this oper
ation.
Comments
ICreateTypeLib::SetName
HRESULT SetName(
OLECHAR FAR* szName
);
Sets the name of the type library.
Parameter
szName
Name to be assigned to the library.
Return Value
The return value of the returned HRESULT is one of the following:
Return value Meaning
S_OK Success.
STG_E_INSUFFICIENTMEMORY Out of memory.
E_OUTOFMEMORY Out of memory.
E_INVALIDARG One or more of the arguments is invalid.
TYPE_E_INVALIDSTATE The state of the type library is not valid for this oper
ation.
ICreateTypeLib::SetVersion
HRESULT SetVersion(
unsigned short wMajorVerNum,
unsigned short wMinorVerNum
);
Sets the major and minor version numbers of the type library.
Parameters
wMajorVerNum
Major version number for the library.
wMinorVerNum
Minor version number for the library.
Return Value
The return value of the returned HRESULT is one of the following:
Return value Meaning
S_OK Success.
TYPE_E_INVALIDSTATE The state of the type library is not valid for this oper
ation.
ICreateTypeLib2 Interface
ICreateTypeLib2 inherits from ICreateTypeLib, and has four member functions. The
ICreateTypeInfo instance returned from ICreateTypeLib can be accessed through a
QueryInterface() call to ICreateTypeInfo2.
Example
interface ICreateTypeLib2 : ICreateTypeLib
ICreateTypeLib2::SetName
HRESULT SetName(
OLECHAR FAR* szName
);
Sets the name of the type library.
Parameter
szName
Name to be assigned to the library.
Return Value
The return value of the returned HRESULT is one of the following:
Return value Meaning
S_OK Success.
STG_E_INSUFFICIENTMEMORY Out of memory.
E_OUTOFMEMORY Out of memory.
E_INVALIDARG One or more of the arguments is invalid.
TYPE_E_INVALIDSTATE The state of the type library is not valid for this oper
ation.
ICreateTypeLib2::DeleteTypeInfo
HRESULT DeleteTypeInfo(
OLECHAR FAR* szName
);
Deletes a specified type information from the type library.
Parameter
szName
Name of the type information to remove.
Return Value
The return value obtained from the returned HRESULT is one of the following:
Return value Meaning
S_OK Success.
E_OUTOFMEMORY Out of memory.
E_INVALIDARG One or more of the arguments is invalid.
ICreateTypeLib2::SetCustData
HRESULT SetCustData(
REFGUID guid,
VARIANT *pVarVal
);
Sets a value to custom data.
Parameters
guid
Unique identifier used to identify the data.
pVarVal
The data to store (any variant except an object).
Return Value
The return value obtained from the returned HRESULT is one of the following:
Return value Meaning
S_OK Success.
E_OUTOFMEMORY Out of memory.
E_INVALIDARG One or more of the arguments is invalid.
ICreateTypeLib2::SetHelpStringContext
HRESULT SetHelpStringContext(
DWORD *dwHelpStringContext
);
Sets the Help string context number.
Parameter
DwHelpStringContext
The Help string context number.
Return Value
The return value obtained from the returned HRESULT is one of the following:
Return value Meaning
S_OK Success.
E_OUTOFMEMORY Out of memory.
E_INVALIDARG One or more of the arguments is invalid.
ICreateTypeLib2::SetHelpStringDll
HRESULT SetHelpStringDll(
LPOLESTR szFileName
);
Sets the DLL name to be used for Help string lookup (for localization purposes).
Parameter
szFileName
The DLL file name.
Return Value
The return value obtained from the returned HRESULT is one of the following:
Return value Meaning
S_OK Success.
E_OUTOFMEMORY Out of memory.
E_INVALIDARG One or more of the arguments is invalid.
Comments
You can construct type information at run time by using CreateDispTypeInfo and a
n INTERFACEDATA structure that describes the object being exposed.
The type information returned by this function is primarily designed to automate
the implementation of IDispatch. CreateDispTypeInfo does not return all of the
type information described in Chapter 17. The argument pidata is not a complete
description of an interface. It does not include Help information, comments, opt
ional parameters, and other type information that is useful in different context
s.
Accordingly, the recommended method for providing type information about an obje
ct is to describe the object using the Object Description Language (ODL), and to
compile the object description into a type library using the Microsoft Interfac
e Definition Language (MIDL) compiler or the MkTypLib utility.
To use type information from a type library, use the LoadTypeLib and GetTypeInfo
OfGuid functions instead of CreateDispTypeInfo. For more information, see Chapte
r 17.
Example
The code that follows creates type information from INTERFACEDATA to expose the
CCalc object.
static METHODDATA NEARDATA rgmdataCCalc[] =
{
PROPERTY(VALUE, IMETH_ACCUM, IDMEMBER_ACCUM, VT_I4)
PROPERTY(ACCUM, IMETH_ACCUM, IDMEMBER_ACCUM, VT_I4)
PROPERTY(OPND, IMETH_OPERAND, IDMEMBER_OPERAND, VT_I4)
PROPERTY(OP, IMETH_OPERATOR, IDMEMBER_OPERATOR, VT_I2)
METHOD0(EVAL, IMETH_EVAL, IDMEMBER_EVAL, VT_BOOL)
METHOD0(CLEAR, IMETH_CLEAR, IDMEMBER_CLEAR, VT_EMPTY)
METHOD0(DISPLAY, IMETH_DISPLAY, IDMEMBER_DISPLAY, VT_EMPTY)
METHOD0(QUIT, IMETH_QUIT, IDMEMBER_QUIT, VT_EMPTY)
METHOD1(BUTTON, IMETH_BUTTON, IDMEMBER_BUTTON, VT_BOOL)
};
INTERFACEDATA NEARDATA g_idataCCalc =
{
rgmdataCCalc, DIM(rgmdataCCalc)
};
// Use Dispatch interface API functions to implement IDispatch.
CCalc FAR*
CCalc::Create()
{
HRESULT hresult;
CCalc FAR* pcalc;
CArith FAR* parith;
ITypeInfo FAR* ptinfo;
IUnknown FAR* punkStdDisp;
extern INTERFACEDATA NEARDATA g_idataCCalc;
if((pcalc = new FAR CCalc()) == NULL)
return NULL;
pcalc->AddRef();
parith = &(pcalc->m_arith);
// Build type information for the functionality on this object that
// is being exposed for external programmability.
hresult = CreateDispTypeInfo(
&g_idataCCalc, LOCALE_SYSTEM_DEFAULT, &ptinfo);
if(hresult != NOERROR)
goto LError0;
// Create an aggregate with an instance of the default
// implementation of IDispatch that is initialized with
// type information.
hresult = CreateStdDispatch(
pcalc, // Controlling unknown.
parith, // Instance to dispatch on.
ptinfo, // Type information describing t
he instance.
&punkStdDisp);
ptinfo->Release();
if(hresult != NOERROR)
goto LError0;
pcalc->m_punkStdDisp = punkStdDisp;
return pcalc;
LError0:;
pcalc->Release();
return NULL;
}
18.5.3 CreateStdDispatch
HRESULT CreateStdDispatch(
IUnknown FAR* punkOuter,
void FAR* pvThis,
ITypeInfo FAR* ptinfo,
IUnknown FAR* FAR* ppunkStdDisp
);
Creates a standard implementation of the IDispatch interface through a single fu
nction call. This simplifies exposing objects through Automation.
Parameters
punkOuter
Pointer to the object ' s IUnknown implementation.
pvThis
Pointer to the object to expose.
ptinfo
Pointer to the type information that describes the exposed object.
ppunkStdDisp
This is the private unknown for the object that implements the IDispatch interfa
ce QueryInterface call. This pointer is Null if the function fails.
Return Value
The return value obtained from the returned HRESULT is one of the following:
Return value Meaning
S_OK Success.
E_INVALIDARG One of the first three arguments is invalid.
E_OUTOFMEMORY There was insufficient memory to complete the operation.
Comments
You can use CreateStdDispatch when creating an object instead of implementing th
e IDispatch member functions for the object. However, the implementation that Cr
eateStdDispatch creates has these limitations:
· Supports only one national language.
· Supports only dispatch-defined exception codes returned from Invoke.
LoadTypeLib, GetTypeInfoOfGuid, and CreateStdDispatch comprise the minimum set o
f functions that you need to call to expose an object using a type library. For
more information on LoadTypeLib and GetTypeInfoOfGuid, see Chapter 17.
CreateDispTypeInfo and CreateStdDispatch comprise the minimum set of dispatch co
mponents you need to call to expose an object using type information provided by
the INTERFACEDATA structure.
Example
The following code implements the IDispatch interface for the CCalc class using
CreateStdDispatch.
CCalc FAR*
CCalc::Create()
{
HRESULT hresult;
CCalc FAR* pcalc;
CArith FAR* parith;
ITypeInfo FAR* ptinfo;
IUnknown FAR* punkStdDisp;
extern INTERFACEDATA NEARDATA g_idataCCalc;
if((pcalc = new FAR CCalc()) == NULL)
return NULL;
pcalc->AddRef();
parith = &(pcalc->m_arith);
// Build type information for the functionality on this object that
// is being exposed for external programmability.
hresult = CreateDispTypeInfo(
&g_idataCCalc, LOCALE_SYSTEM_DEFAULT, &ptinfo);
if(hresult != NOERROR)
goto LError0;
// Create an aggregate with an instance of the default
// implementation of IDispatch that is initialized with
// type information.
hresult = CreateStdDispatch(
pcalc, // Controlling unknown.
parith, // Instance to dispatch on.
ptinfo, // Type information describing t
he instance.
&punkStdDisp);
ptinfo->Release();
if(hresult != NOERROR)
goto LError0;
pcalc->m_punkStdDisp = punkStdDisp;
return pcalc;
LError0:;
pcalc->Release();
return NULL;
}
18.5.4 DispGetIDsOfNames
HRESULT DispGetIDsOfNames(ptinfo, rgszNames, cNames, rgdispid)
ITypeInfo* ptinfo,
OLECHAR FAR* FAR* rgszNames,
unsigned int cNames,
DISPID FAR* rgdispid
);
Uses type information to convert a set of names to DISPIDs. This is the recommen
ded implementation of IDispatch::GetIDsOfNames.
Parameters
ptinfo
Pointer to the type information for an interface. This type information is speci
fic to one interface and language code, so it is not necessary to pass an interf
ace identifier (IID) or LCID to this function.
rgszNames
An array of name strings that can be the same array passed to DispInvoke in the
DISPPARAMS structure. If cNames is greater than 1, the first name is interpreted
as a method name, and subsequent names are interpreted as parameters to that me
thod.
cNames
The number of elements in rgszNames.
rgdispid
Pointer to an array of DISPIDs to be filled in by this function. The first ID co
rresponds to the method name. Subsequent IDs are interpreted as parameters to th
e method.
Return Value
The return value obtained from the returned HRESULT is one of the following:
Return value Meaning
S_OK The interface is supported.
E_INVALIDARG One of the arguments is invalid.
DISP_E_UNKNOWNNAME One or more of the given names were not known. The retur
ned array of DISPIDs contains DISPID_UNKNOWN for each entry that corresponds to
an unknown name.
Other return codes Any of the ITypeInfo::Invoke errors can also be returned
.
Example
This code from the Lines sample file Points.cpp implements the member function G
etIDsOfNames for the CPoints class using DispGetIDsOfNames.
STDMETHODIMP
CPoints::GetIDsOfNames(
REFIID riid,
char FAR* FAR* rgszNames,
UINT cNames,
LCID lcid,
DISPID FAR* rgdispid)
{
return DispGetIDsOfNames(m_ptinfo, rgszNames, cNames, rgdispid);
}
See Also
CreateStdDispatch, IDispatch::GetIDsOfNames
18.5.5 DispGetParam
HRESULT DispGetParam(pdispparams, position, vtTarg, pvarResult, puArgErr)
DISPPARAMS FAR* pdispparams,
unsigned int position,
VARTYPE vtTarg,
VARIANT FAR* pvarResult,
unsigned int FAR* puArgErr
);
Retrieves a parameter from the DISPPARAMS structure, checking both named paramet
ers and positional parameters, and coerces the parameter to the
specified type.
Parameters
pdispparams
Pointer to the parameters passed to IDispatch::Invoke.
position
The position of the parameter in the parameter list. DispGetParam starts at the
end of the array, so if position is 0, the last parameter in the array is return
ed.
vtTarg
The type the argument should be coerced to.
pvarResult
Pointer to the variant to pass the parameter into.
puArgErr
On return, pointer to the index of the argument that caused a DISP_E_TYPEMISMATC
H error. This pointer is returned to Invoke to indicate the position of the argu
ment in DISPPARAMS that caused the error.
Return Value
The return value obtained from the HRESULT is one of the following:
Return value Meaning
S_OK Success.
DISP_E_BADVARTYPE The variant type vtTarg is not supported.
DISP_E_OVERFLOW The retrieved parameter could not be coerced to the specified ty
pe.
DISP_E_PARAMNOTFOUND The parameter indicated by position could not be found.
DISP_E_TYPEMISMATCH The argument could not be coerced to the specified type.
E_INVALIDARG One of the arguments was invalid.
E_OUTOFMEMORY Insufficient memory to complete operation.
Comments
The output parameter pvarResult must be a valid variant. Any existing contents a
re released in the standard way. The contents of the variant are freed with Vari
antFree.
If you have used DispGetParam to get the right side of a property put operation,
the second parameter should be DISPID_PROPERTYPUT. For example:
DispGetParam(&dispparams, DISPID_PROPERTYPUT, VT_BOOL, &varResult)
Named parameters cannot be accessed positionally, and vice versa.
Example
The following example uses DispGetParam to set X and Y properties:
STDMETHODIMP
CPoint::Invoke(
DISPID dispidMember,
REFIID riid,
LCID lcid,
unsigned short wFlags,
DISPPARAMS FAR* pdispparams,
VARIANT FAR* pvarResult,
EXCEPINFO FAR* pExcepInfo,
unsigned int FAR* puArgErr)
{
unsigned int uArgErr;
HRESULT hresult;
VARIANTARG varg0;
VARIANT varResultDummy;
UNUSED(lcid);
UNUSED(pExcepInfo);
// Make sure the wFlags are valid.
if(wFlags & ~(DISPATCH_METHOD | DISPATCH_PROPERTYGET |
DISPATCH_PROPERTYPUT | DISPATCH_PROPERTYPUTREF))
return ResultFromScode(E_INVALIDARG);
// This object only exposes a "default" interface.
if(!IsEqualIID(riid, IID_NULL))
return ResultFromScode(DISP_E_UNKNOWNINTERFACE);
// It simplifies the following code if the caller
// ignores the return value.
if(puArgErr == NULL)
puArgErr = &uArgErr;
if(pvarResult == NULL)
pvarResult = &varResultDummy;
VariantInit(&varg0);
// Assume the return type is void, unless otherwise is found.
VariantInit(pvarResult);
switch(dispidMember){
case IDMEMBER_CPOINT_GETX:
V_VT(pvarResult) = VT_I2;
V_I2(pvarResult) = GetX();
break;
case IDMEMBER_CPOINT_SETX:
hresult = DispGetParam(pdispparams, 0, VT_I2, &varg0, puArgErr);
if(hresult != NOERROR)
return hresult;
SetX(V_I2(&varg0));
break;
case IDMEMBER_CPOINT_GETY:
V_VT(pvarResult) = VT_I2;
V_I2(pvarResult) = GetY();
break;
case IDMEMBER_CPOINT_SETY:
hresult = DispGetParam(pdispparams, 0, VT_I2, &varg0, puArgErr);
if(hresult != NOERROR)
return hresult;
SetY(V_I2(&varg0));
break;
default:
return ResultFromScode(DISP_E_MEMBERNOTFOUND);
}
return NOERROR;
}
See Also
CreateStdDispatch, IDispatch::Invoke
18.5.6 DispInvoke
HRESULT DispInvoke(_this, ptinfo, dispidMember, wFlags, pparams, pvarResult, pex
cepinfo, puArgErr)
void FAR* _this,
ITypeInfo FAR* ptinfo,
DISPID dispidMember,
unsigned short wFlags,
DISPPARAMS FAR* pparams,
VARIANT FAR* pvarResult,
EXCEPINFO pexcepinfo,
unsigned int FAR* puArgErr
);
Automatically calls member functions on an interface, given the type information
for the interface. You can describe an interface with type information and impl
ement IDispatch::Invoke for the interface using this single call.
Parameters
_this
Pointer to an implementation of the IDispatch interface described by ptinfo.
ptinfo
Pointer to the type information that describes the interface.
dispidMember
Identifies the member. Use GetIDsOfNames or the object ' s documentation to obtain the
DISPID.
wFlags
Flags describing the context of the Invoke call, as follows:
Value Description
DISPATCH_METHOD The member is invoked as a method. If a property has the same na
me, both this and the DISPATCH_PROPERTYGET flag can be set.
DISPATCH_PROPERTYGET The member is retrieved as a property or data member.
DISPATCH_PROPERTYPUT The member is changed as a property or data member.
DISPATCH_PROPERTYPUTREF The member is changed by a reference assignment, rather
than a value assignment. This flag is valid only when the property accepts a ref
erence to an object.
pparams
Pointer to a structure containing an array of arguments, an array of argument DI
SPIDs for named arguments, and counts for number of elements in the arrays.
pvarResult
Pointer to where the result is to be stored, or Null if the caller expects no re
sult. This argument is ignored if DISPATCH_PROPERTYPUT or DISPATCH_PROPERTYPUTRE
F is specified.
pexcepinfo
Pointer to a structure containing exception information. This structure should b
e filled in if DISP_E_EXCEPTION is returned.
puArgErr
The index within rgvarg of the first argument that has an error. Arguments are s
tored in pdispparams->rgvarg in reverse order, so the first argument is the one
with the highest index in the array. This parameter is returned only when the re
sulting return value is DISP_E_TYPEMISMATCH or DISP_E_PARAMNOTFOUND.
Return Value
The return value obtained from the returned HRESULT is one of the following:
Return value Meaning
S_OK Success.
DISP_E_BADPARAMCOUNT The number of elements provided in DISPPARAMS is differe
nt from the number of arguments accepted by the method or property.
DISP_E_BADVARTYPE One of the arguments in DISPPARAMS is not a valid varian
t type.
DISP_E_EXCEPTION The application needs to raise an exception. In this cas
e, the structure passed in pexcepinfo should be filled in.
DISP_E_MEMBERNOTFOUND The requested member does not exist.
DISP_E_NONAMEDARGS This implementation of IDispatch does not support named
arguments.
DISP_E_OVERFLOW One of the arguments in DISPPARAMS could not be coerced to the s
pecified type.
DISP_E_PARAMNOTFOUND One of the parameter IDs does not correspond to a parame
ter on the method. In this case, puArgErr is set to the first argument that cont
ains the error.
DISP_E_PARAMNOTOPTIONAL A required parameter was omitted.
DISP_E_TYPEMISMATCH One or more of the arguments could not be coerced. The i
ndex of the first parameter with the incorrect type within rgvarg is returned in
puArgErr.
E_INVALIDARG One of the arguments is invalid.
E_OUTOFMEMORY Insufficient memory to complete the operation.
Other return codes Any of the ITypeInfo::Invoke errors can also be returned
.
Comments
The parameter _this is a pointer to an implementation of the interface that is b
eing deferred to. DispInvoke builds a stack frame, coerces parameters using stan
dard coercion rules, pushes them on the stack, and then calls the correct member
function in the VTBL.
Example
The following code from the Lines sample file Lines.cpp implements IDispatch::In
voke using DispInvoke. This function uses m_bRaiseException to signal that an er
ror occurred during the DispInvoke call.
STDMETHODIMP
CLines::Invoke(
DISPID dispidMember,
REFIID riid,
LCID lcid,
WORD wFlags,
DISPPARAMS FAR* pdispparams,
VARIANT FAR* pvarResult,
EXCEPINFO FAR* pexcepinfo,
UINT FAR* puArgErr)
{
return DispInvoke(
this, m_ptinfo,
dispidMember, wFlags, pdispparams,
pvarResult, pexcepinfo, puArgErr);
}
See Also
CreateStdDispatch, IDispatch::Invoke
18.5.7 DosDateTimeToVariantTime
int DosDateTimeToVariantTime(
unsigned short wDOSDate,
unsigned short wDOSTime,
double FAR* pvtime
);
Converts the MS-DOS representation of time to the date and time representation s
tored in a variant.
Parameters
wDOSDate
The MS-DOS date to convert.
wDOSTime
The MS-DOS time to convert.
pvtime
Pointer to the location to store the converted time.
Return Value
The return value obtained from the returned HRESULT is one of the following.
Result Meaning
True Success.
False Failure.
Comments
MS-DOS records file dates and times as packed 16-bit values. An MS-DOS date has
the following format.
Bits Contents
0-4 Day of the month (1-31).
5-8 Month (1 = January, 2 = February, and so on).
9-15 Year offset from 1980 (add 1980 to get the actual year).
An MS-DOS time has the following format.
Bits Contents
0-4 Second divided by 2.
5-10 Minute (0-59).
11-15 Hour (0- 23 on a 24-hour clock).
18.5.8 GetActiveObject
HRESULT GetActiveObject(
REFCLSID rclsid,
void FAR* pvReserved,
IUnknown FAR* FAR* ppunk
);
Retrieves a pointer to a running object that has been registered with COM.
Parameters
rclsid
Pointer to the class identifier (CLSID) of the active object from the COM regist
ration database.
pvReserved
Reserved for future use. Must be Null.
ppunk
On return, a pointer to the requested active object.
Return Value
The return value obtained from the returned HRESULT is one of the following:
Return value Meaning
S_OK Success.
Other return codes Failure.
18.5.9 RegisterActiveObject
HRESULT RegisterActiveObject(
IUnknown FAR* punk,
REFCLSID rclsid,
DWORD dwFlags,
Unsigned long FAR* pdwRegister
);
Registers an object as the active object for its class.
Parameters
punk
Pointer to the IUnknown interface of the active object.
rclsid
Pointer to the CLSID of the active object.
dwFlags
Flags controlling registration of the object. Possible values are ACTIVEOBJECT_S
TRONG and ACTIVEOBJECT_WEAK.
pdwRegister
On return, a pointer to a handle. This handle must be passed to RevokeActiveObje
ct to end the object ' s active status.
Return Value
The return value obtained from the returned HRESULT is one of the following:
Return value Meaning
S_OK Success.
Other return codes Failure.
Comments
The RegisterActiveObject function registers the object to which punk points as t
he active object for the class denoted by rclsid. Registration causes the object
to be listed in the running object table (ROT) of COM, a globally accessible lo
okup table that keeps track of objects that are currently running on the compute
r. (For more information about the running object table, see the OLE Programmer'
s Reference.) The dwFlags parameter specifies the strength or weakness of the re
gistration, which affects the way the object is shut down.
In general, COM objects should behave in the following manner:
· If the object is visible, it should shut down only in response to an explicit us
er command (such as the Exit command on the File menu), or to the equivalent com
mand from an COM client (invoking the Quit or Exit method on the Application obj
ect).
· If the object is not visible, it should shut down only when the last external co
nnection to it is gone.
Strong registration performs an AddRef on the object, incrementing the reference
count of the object (and its associated stub) in the running object table. A st
rongly registered object must be explicitly revoked from the table with RevokeAc
tiveObject. The default is strong registration (ACTIVEOBJECT_STRONG).
Weak registration keeps a pointer to the object in the running object table, but
does not increment the reference count. Consequently, when the last external co
nnection to a weakly registered object disappears, COM releases the object ' s stub, an
d the object itself is no longer available.
To ensure the desired behavior, consider not only the default actions of COM, bu
t also the following:
· Even though code can create an invisible object, the object may become visible a
t some later time. Once the object is visible, it should remain visible and acti
ve until it receives an explicit command to shut down. This can occur after refe
rences from the code disappear.
· Other COM clients may be using the object. If so, the code should not force the
object to shut down.
To avoid possible conflicts, you should always register COM objects with ACTIVEO
BJECT_WEAK, and call CoLockObjectExternal, when necessary, to guarantee the obje
ct remains active. CoLockObjectExternal adds a strong lock, thereby preventing t
he object ' s reference count from reaching zero. For detailed information about this f
unction, refer to the OLE Programmer's Reference.
Most commonly, objects need to call CoLockObjectExternal when they become visibl
e, so they remain active until the user requests the object to shut down. The fo
llowing procedure lists the steps your code should follow to shut down an object
correctly.
To shut down an active object:
1. When the object becomes visible, make the following call to add
a lock for the user:
CoLockObjectExternal(punk, TRUE, TRUE)
The lock remains in effect until a user explicitly requests the object to be shu
t down, such as with a Quit or Exit command.
2. When the user requests the object to be shut down, call CoLockOb
jectExternal again to free the lock, as follows:
CoLockObjectExternal(punk, FALSE, TRUE)
3. Call RevokeActiveObject to make the object inactive.
4. To end all connections from remote processes, call CoDisconnectO
bject as follows:
CoDisconnectObject(punk, 0)
This function is described in more detail in the OLE Programmer's Reference.
18.5.10 RevokeActiveObject
HRESULT RevokeActiveObject(
Unsigned long dwRegister,
void FAR* pvReserved
);
Ends an object ' s status as active.
Parameters
dwRegister
A handle previously returned by RegisterActiveObject.
pvReserved
Reserved for future use. Must be Null.
Return Value
The return value obtained from the returned HRESULT is one of the following:
Return value Meaning
S_OK Success.
Other return codes Failure.
18.5.11 CompareString
int CompareString(
LCID lcid,
DWORD dwCmpFlags,
LPCWSTR lpString1,
integer cchCount1,
LPWSTR lpString2,
integer cchCount2,
);
Compares two character strings of the same locale according to the supplied LCID
.
Parameters
lcid
Locale context for the comparison. The strings are assumed to be represented in
the default ANSI code page for this locale.
dwCmpFlags
Flags that indicate the character traits to use or ignore when comparing the two
strings. Several flags can be combined , or none can be used. (In the case of t
his function, there are no illegal combinations of flags.) Compare flags include
the following.
Value Meaning
Ignore case. Default is Off.
Ignore Japanese hiragana/katakana character differences. Default is Off.
Ignore nonspacing marks (accents, diacritics, and vowel marks). Default
is Off.
Ignore symbols. Default is Off.
Ignore character width. Default is Off.
lpString1 and lpString2
The two strings to be compared.
cchCount1 and cchCount2
The character counts of the two strings. The count does not include the null-ter
minator (if any). If either cchCount1 or cchCount2 is *1, the corresponding stri
ng is assumed to be null-terminated, and the length is calculated automatically.
Return Value
Value Meaning
Failure.
lpString1 is less than lpString2.
lpString1 is equal to lpString2.
lpString1 is greater than lpString2.
Comments
When used without any flags, this function uses the same sorting algorithm as ls
trcmp in the given locale. When used with NORM_IGNORECASE, the same algorithm as
lstrcmpi is used.
For double-byte character set (DBCS) locales, the flag NORM_IGNORECASE has an ef
fect on all the wide (two-byte) characters as well as the narrow (one-byte) char
acters. This includes the wide Greek and Cyrillic characters.
In Chinese Simplified, the sorting order used to compare the strings is based on
the following sequence: symbols, digit numbers, English letters, and Chinese Si
mplified characters. The characters within each group sort in character-code ord
er.
In Chinese Traditional, the sorting order used to compare the strings is based o
n the number of strokes in the characters. Symbols, digit numbers, and English c
haracters are considered to have zero strokes. The sort sequence is symbols, dig
it numbers, English letters, and Chinese Traditional characters. The characters
within each stroke-number group sort in character-code order.
In Japanese, the sorting order used to compare the strings is based on the Japan
ese 50-on sorting sequence. The Kanji ideographic characters sort in character-c
ode order.
In Japanese, the flag NORM_IGNORENONSPACE has an effect on the daku-on, handaku-
on, chou-on, you-on, and soku-on modifiers, and on the repeat kana/kanji charact
ers.
In Korean, the sort order is based on the sequence: symbols, digit numbers, Jaso
and Hangeul, Hanja, and English. Within the Jaso-Hangeul group, each Jaso chara
cter is followed by the Hangeuls that start with that Jaso. Hanja characters are
sorted in Hangeul pronunciation order. Where multiple Hanja have the same Hange
ul pronunciation, they are sorted in character-code order.
The NORM_IGNORENONSPACE flag only has an effect for the locales in which accente
d characters are sorted in a second pass from main characters. All characters in
the string are first compared without regard to accents and (if the strings are
equal) a second pass over the strings to compare accents is performed. In this
case, this flag causes the second pass to not be performed. Some locales sort ac
cented characters in the first pass, in which case this flag will have no effect
.
If the return value is 2, the two strings are equal in the collation sense, thou
gh not necessarily identical (the case might be ignored, and so on).
If the two strings are of different lengths, they are compared up to the length
of the shortest one. If they are equal to that point, the return value will indi
cate that the longer string is greater.
To maintain the C run-time convention of comparing strings, the value 2 can be s
ubtracted from a non-zero return value. The meaning of < 0, == 0, and > 0 is the
n consistent with the C run-time conventions.
18.5.12 LCMapString
int LCMapString(
LCID lcid,
DWORD dwMapFlags,
LPCWSTR lpSrcStr,
int cchSrc,
LPWSTR lpDestStr,
int cchDest,
);
Transforms the case or sort order of a string.
Parameters
lcid
Locale ID context for mapping. The strings are assumed to be represented in the
default ANSI code page for this locale.
dwMapFlags
Flags that indicate what type of transformation is to occur during mapping. Seve
ral flags can be combined on a single transformation (though some combinations a
re illegal). Mapping options include the following.
Name Meaning
Lowercase.
Uppercase.
Character sort key.
Narrow characters (where applicable).
Wide characters (where applicable).
Hiragana.
Katakana.
Ignore case. Default is Off.
Ignore nonspacing. Default is Off.
Ignore character width. Default is Off.
Ignore Japanese hiragana/katakana character differences. Default is Off.
Ignore symbols. Default is Off.
The latter five options (NORM_IGNORECASE, NORM_IGNORENONSPACE, NORM_IGNOREWIDTH,
NORM_IGNOREKANATYPE, and NORM_IGNORESYMBOLS) are normalization options that can
only be used in combination with the LCMAP_SORTKEY conversion option.
Conversion options can be combined only when they are taken from the following t
hree groups, and then only when there is no more than one option from each group
:
* Casing options (LCMAP_LOWERCASE, LCMAP_UPPERCASE)
* Width options (LCMAP_HALFWIDTH, LCMAP_FULLWIDTH)
* Kana options (LCMAP_HIRAGANA, LCMAP_KATAKANA)
lpSrcStr
Pointer to the supplied string to be mapped.
cchSrc
Character count of the input string buffer. If *1, lpSrcStr is assumed to be nul
l-terminated and the length is calculated automatically.
lpDestStr
Pointer to the memory buffer that stores the resulting mapped string.
cchDest
Character count of the memory buffer pointed to by lpDestStr. If cchDest is 0, t
hen the return value of this function is the number of characters required to ho
ld the mapped string. In this case, the lpDestStr pointer is not referenced.
Return Value
Value Meaning
Failure.
Success.
Comments
LCMapStringA maps one character string to another, performing the specified loca
le-dependent translation.
The flag LCMAP_UPPER produces the same result as AnsiUpper in the given locale.
The flag LCMAP_LOWER produces the same result as AnsiLower. This function always
maps a single character to a single character.
The mapped string is null-terminated if the source string is null-terminated.
When used with LCMAP_UPPER and LCMAP_LOWER, the lpSrcStr and lpDestStr may be th
e same to produce an in-place mapping. When LCMAP_SORTKEY is used, the lpSrcStr
and lpDestStr pointers may not be the same. In this case, an error will result.
The LCMAP_SORTKEY transforms two strings so that when they are compared with the
standard C library function strcmp (by strict numerical valuation of their char
acters), the same order will result, as if the original strings were compared wi
th CompareStringA. When LCMAP_SORTKEY is specified, the output string is a strin
g (without Nulls, except for the terminator), but the character values will not
be meaningful display values. This is similar behavior to the ANSI C function st
rxfrm.
18.5.13 GetLocaleInfo
int GetLocaleInfoA(
LCID lcid,
LCTYPE LCType,
LPSTR lpLCData,
int cchData,
);
Retrieves locale information from the user ' s system.
Parameters
lcid
The locale ID. The returned string is represented in the default ANSI code page
for this locale.
LCType
Flag that indicates the type of information to be returned by the call. See the
listing of constant values defined in this chapter. LOCALE_NOUSEROVERRIDE | LCTY
PE indicates that the desired information will always be retrieved from the loca
le database, even if the LCID is the current one and the user has changed some o
f the values in the Windows 95 Control Panel. If this flag is not specified, the
values in Win.ini take precedence over the database settings when getting value
s for the current system default locale.
lpLCData
Pointer to the memory where GetLocaleInfoA will return the requested data. This
pointer is not referenced if cchData is 0.
cchData
Character count of the supplied lpLCData memory buffer. If cchData is 0, the ret
urn value is the number of characters required to hold the string, including the
terminating null character. In this case, lpLCData is not referenced.
Return Value
Value Meaning
Failure.
Success.
Comments
GetLocaleInfoA returns one of the various pieces of information about a locale b
y querying the stored locale database or Win.ini. The call also indicates how mu
ch memory is necessary to contain the desired information.
The information returned is always a null-terminated string. No integers are ret
urned by this function and numeric values are returned as text. (See the format
descriptions under LCTYPE).
18.5.14 GetStringType
BOOL GetStringTypeA(
LCID lcid,
DWORD dwInfoType,
LPCSTR lpSrcStr,
int cchSrc,
LPWORD lpCharType,
);
Retrieves locale type information about each character in a string.
Parameters
lcid
Locale context for the mapping. The string is assumed to be represented in the d
efault ANSI code page for this locale.
dwInfoType
Type of character information to retrieve. The various types are divided into di
fferent levels. (See the Comments section for a list of information included in
each type). The options are mutually exclusive. The following types are supporte
d:
* CT_CTYPE1
* CT_CTYPE2
* CT_CTYPE3
lpSrcStr
String for which character types are requested. If cchSrc is *1, lpSrcStr is ass
umed to be null-terminated.
cchSrc
Character count of lpSrcStr. If cchSrc is *1, lpSrcStr is assumed to be null-ter
minated. This must also be the character count of lpCharType.
lpCharType
Array of the same length as lpSrcStr (cchSrc). On output, the array contains one
word corresponding to each character in lpSrcStr.
Return Value
Return value Meaning
Failure.
Success.
Comments
The lpSrcStr and lpCharType pointers cannot be the same. In this case, the error
ERROR_INVALID_PARAMETER results.
The character type bits are divided up into several levels. One level ' s information c
an be retrieved by a single call.
This function supports three character types:
* Ctype 1
* Ctype 2
* Ctype 3
Ctype 1 character types support ANSI C and POSIX character typing functions. A b
itwise OR of these values is returned when dwInfoType is set to CT_CTYPE1. For D
BCS locales, the Ctype 1 attributes apply to both narrow characters and wide cha
racters. The Japanese hiragana and katakana characters, and the kanji ideograph
characters all have the C1_ALPHA attribute.
The following table lists the Ctype 1 character types.
Name Value Meaning
0x0001 Uppercase1.
0x0002 Lowercase1.
0x0004 Decimal digits.
0x0008 Space characters.
0x0010 Punctuation.
0x0020 Control characters.
0x0040 Blank characters.
0x0080 Hexadecimal digits.
0x0100 Any letter.
1 The Windows version 3.1 functions IsCharUpper and IsCharLower do not alw
ays produce correct results for characters in the range 0x80-0x9f, so they may p
roduce different results than this function for characters in that range. (For e
xample, the German Windows version 3.1 language driver incorrectly reports 0x9a,
lowercase s hacek, as uppercase).
Ctype 2 character types support the proper layout of text. For DBCS locales, Cty
pe 2 applies to both narrow and wide characters. The directional attributes are
assigned so that the BiDi layout algorithm standardized by Unicode produces the
correct results. For more information on the use of these attributes, see The Un
icode Standard: Worldwide Character Encoding from Addison-Wesley publishers.
Attribute Name Value Meaning
C2_LEFTTORIGHT 0x1 Left to right.
C2_RIGHTTOLEFT 0x2 Right to left.
C2_EUROPENUMBER 0x3 European number, European digit.
C2_EUROPESEPARATOR 0x4 European numeric separator.
C2_EUROPETERMINATOR 0x5 European numeric terminator.
C2_ARABICNUMBER 0x6 Arabic number.
C2_COMMONSEPARATOR 0x7 Common numeric separator.
C2_BLOCKSEPARATOR 0x8 Block separator.
C2_SEGMENTSEPARATOR 0x9 Segment separator.
C2_WHITESPACE 0xA White space.
C2_OTHERNEUTRAL 0xB Other neutrals.
C2_NOTAPPLICABLE 0x0 No implicit direction (for example, cont
rol codes).
Ctype 3 character types are general text-processing information. A bitwise OR of
these values is returned when dwInfoType is set to CT_CTYPE3. For DBCS locales,
the Ctype 3 attributes apply to both narrow characters and wide characters. The
Japanese hiragana and katakana characters, and the kanji ideograph characters a
ll have the C3_ALPHA attribute.
Name Value Meaning
0x1 Nonspacing mark.
0x2 Diacritic nonspacing mark.
0x4 Vowel nonspacing mark.
0x8 Symbol.
0x10 Katakana character.
0x20 Hiragana character.
0x40 Narrow character.
0x80 Wide character.
0x100 Ideograph.
0x8000 Any letter.
0x0 Not applicable.
18.5.15 GetSystemDefaultLangID
LANGID GetSystemDefaultLangID();
Retrieves the default LANGID from a user ' s system.
Return Value
Return value Meaning
Failure.
Success.
Comments
Returns the system default LANGID. For information on how this value is determin
ed, see GetSystemDefaultLCID in the following section..
18.5.16 GetSystemDefaultLCID
LCID GetSystemDefaultLCID();
Retrieves the default LCID from a user ' s system.
Return Value
Return value Meaning
Failure.
Success.
Comments
Returns the system default LCID. The return value is determined by examining the
values of sLanguage and iCountry in Win.ini, and comparing the values to those
in the stored locale database. If no matching values are found, or the required
values cannot be read from Win.ini, or if the stored locale database cannot be l
oaded, the value 0 is returned.
18.5.17 GetUserDefaultLangID
LANGID GetUserDefaultLangID();
Retrieves the default LANGID from a user ' s system.
Return Value
Value Meaning
Failure.
Success.
Comments
Returns the user default LANGID. On single-user systems, the value returned from
this function is always the same as that returned from GetSystemDefaultLangID.
18.5.18 GetUserDefaultLCID
LCID GetUserDefaultLCID();
Retrieves the default LCID from a user ' s system.
Return Value
Return value Meaning
Failure.
Success.
Comments
Returns the user default LCID. On single-user systems, the value returned by thi
s function is always the same as that returned from GetSystemDefaultLCID.
18.5.19 SafeArrayAccessData
HRESULT SafeArrayAccessData (
SAFEARRAY FAR* psa,
void HUGEP* FAR* ppvdata
);
Increments the lock count of an array, and retrieves a pointer to the array data
.
Parameters
psa
Pointer to an array descriptor created by SafeArrayCreate.
ppvdata
Return Value
The return value obtained from the returned HRESULT is one of the following.
Return value Meaning
S_OK Success.
E_INVALIDARG The argument psa was not a valid safe array descriptor.
E_UNEXPECTED The array could not be locked.
Example
The following example sorts a safe array of one dimension that contains BSTRs by
accessing the array elements directly. This approach is faster than using SafeA
rrayGetElement and SafeArrayPutElement.
long i, j, min;
BSTR bstrTemp;
BSTR HUGEP *pbstr;
HRESULT hr;
// Get a pointer to the the elements of the array.
hr = SafeArrayAccessData(psa, (void HUGEP* FAR*)&pbstr);
if (FAILED(hr))
goto error;
// Bubble sort.
cElements = lUBound-lLBound+1;
for (i = 0; i < cElements-1; i++)
{
min = i;
for (j = i+1; j < cElements; j++)
{
if (wcscmp(pbstr[j], pbstr[min]) < 0)
min = j;
}
// Swap array[min] and array[i].
bstrTemp = pbstr[min];
pbstr[min] = pbstr[i];
pbstr[i] = bstrTemp;
}
SafeArrayUnaccessData(psa);
18.5.20 SafeArrayAllocData
HRESULT SafeArrayAllocData(
SAFEARRAY FAR* psa
);
Allocates memory for a safe array, based on a descriptor created with SafeArrayA
llocDescriptor.
Parameter
psa
Pointer to an array descriptor created by SafeArrayAllocDescriptor.
Return Value
The return value obtained from the returned HRESULT is one of the following.
Return value Meaning
S_OK Success.
E_INVALIDARG The argument psa was not a valid safe array descriptor.
E_UNEXPECTED The array could not be locked.
Example
The following example creates a safe array using the SafeArrayAllocDescriptor an
d SafeArrayAllocData functions.
SAFEARRAY FAR* FAR*ppsa;
unsigned int ndim = 2;
HRESULT hresult = SafeArrayAllocDescriptor(ndim, ppsa);
if( FAILED(hresult))
return ERR_OutOfMemory;
(*ppsa)->rgsabound[ 0 ].lLbound = 0;
(*ppsa)->rgsabound[ 0 ].cElements = 5;
(*ppsa)->rgsabound[ 1 ].lLbound = 1;
(*ppsa)->rgsabound[ 1 ].cElements = 4;
hresult = SafeArrayAllocData(*ppsa);
if( FAILED(hresult)) {
SafeArrayDestroyDescriptor(*ppsa)
return ERR_OutOfMemory;
}
See Also
SafeArrayAllocData, SafeArrayDestroyData, SafeArrayDestroyDescriptor
18.5.21 SafeArrayAllocDescriptor
HRESULT SafeArrayAllocDescriptor(
unsigned int cDims,
SAFEARRAY FAR* FAR* ppsaOut
);
Allocates memory for a safe array descriptor.
Parameters
cDims
The number of dimensions of the array.
ppsaOut
Pointer to a location in which to store the created array descriptor.
Return Value
The return value obtained from the returned HRESULT is one of the following.
Return value Meaning
S_OK Success.
E_INVALIDARG The argument psa was not a valid safe array descriptor.
E_UNEXPECTED The array could not be locked.
Comments
This function allows the creation of safe arrays that contain elements with data
types other than those provided by SafeArrayCreate. After creating an array des
criptor using SafeArrayAllocDescriptor, set the element size in the array descri
ptor, an call SafeArrayAllocData to allocate memory for the array elements.
Example
The following example creates a safe array using the SafeArrayAllocDescriptor an
d SafeArrayAllocData functions.
SAFEARRAY FAR* FAR*ppsa;
unsigned int ndim = 2;
HRESULT hresult = SafeArrayAllocDescriptor( ndim, ppsa );
if( FAILED( hresult ) )
return ERR_OutOfMemory;
(*ppsa)->rgsabound[ 0 ].lLbound = 0;
(*ppsa)->rgsabound[ 0 ].cElements = 5;
(*ppsa)->rgsabound[ 1 ].lLbound = 1;
(*ppsa)->rgsabound[ 1 ].cElements = 4;
hresult = SafeArrayAllocData( *ppsa );
if( FAILED( hresult ) ) {
SafeArrayDestroyDescriptor( *ppsa )
return ERR_OutOfMemory;
}
See Also
SafeArrayAllocData, SafeArrayDestroyData, SafeArrayDestroyDescriptor
18.5.22 SafeArrayCopy
HRESULT SafeArrayCopy(
SAFEARRAY FAR* psa,
SAFEARRAY FAR* FAR* ppsaOut
);
Creates a copy of an existing safe array.
Parameters
psa
Pointer to an array descriptor created by SafeArrayCreate.
ppsaOut
Pointer to a location in which to return the new array descriptor.
Return Value
The return value obtained from the returned HRESULT is one of the following.
Return value Meaning
S_OK Success.
E_INVALIDARG The argument psa was not a valid safe array descriptor.
E_OUTOFMEMORY Insufficient memory to create the copy.
Comments
SafeArrayCopy calls the string or variant manipulation functions if the array to
copy contains either of these data types. If the array being copied contains ob
ject references, the reference counts for the objects are incremented.
See Also
SysAllocStringLen, VariantCopy, VariantCopyInd
18.5.23 SafeArrayCopyData
HRESULT SafeArrayCopyData(
SAFEARRAY FAR* psaSource,
SAFEARRAY FAR* FAR* ppsaTarget
);
Copies the source array to the target array after releasing any resources in the
target array. This is similar to SafeArrayCopy, except that the target array ha
s to be set up by the caller. The target is not allocated or reallocated.
Parameters
psaSource
The safe array from which to be copied.
ppsaTarget
On exit, the array referred to by ppsaTarget contains a copy of the data in psaS
ource.
Return Value
The return value obtained from the returned HRESULT is one of the following.
Return value Meaning
S_OK Success.
E_INVALIDARG The argument psa was not a valid safe array descriptor.
E_OUTOFMEMORY Insufficient memory to create the copy.
Comments
Visual Basic for Applications and Automation use the same set of rules with case
s in which the size or types of source and destination arrays do not match. The
rules of Visual Basic are described in the following comments.
Array Assignment
In general, VBA3 supports array assignment.
Dim lhs(1 To 10) As Integer
Dim rhs(1 To 10) As Integer
lhs = rhs
When the number of dimensions, the size of those dimensions, and the element typ
es match, data types are differentiated based on the following factors:
· Fixed-size, left side. The left side is fixed if the type of the expression on
the left side is a fixed-size array. For example, the following statement is a d
eclaration of a fixed-size array.
Dim x (1 To 10) As Integer
· Matching number of dimensions. The number of dimensions of the left side may or
may not match the number of dimensions of the array on the right side.
· Dimensions match. The dimensions match if, for each dimension, the number of el
ements match. The dimensions can match even if the declarations are slightly dif
ferent, such as when one array is zero-based and another is one-based, but they
have the same number of elements.
The following table shows what happens when the number of dimensions, size of th
e dimension, and element types do not match:
Fixed-size, left side Number of dimensions Dimensions match What hap
pens
No Yes or No Yes or No Success. If necessary, the left side is
resized to the size of the right side.
Yes No Failure.
Yes Yes No Treated in same manner as fixed-length strings.If the ri
ght side has more elements than the left side, the assignment succeeds and the e
xtra elements have no effect. If the left side has more elements than the right
side, the assignment succeeds and the unaffected elements of the left side are z
ero-, null-, or empty-filled, depending on the types of the elements.
Yes Yes Yes Success.
See Also
SysAllocStringLen, VariantCopy, VariantCopyInd
18.5.24 SafeArrayCreate
HRESULT SafeArrayCreate(
VARTYPE vt,
unsigned int cDims,
SAFEARRRAYBOUND FAR* rgsabound
);
Creates a new array descriptor, allocates and initializes the data for the array
, and returns a pointer to the new array descriptor.
Parameters
vt
The base type of the array (the VARTYPE of each element of the array). The VARTY
PE is restricted to a subset of the variant types. Neither the VT_ARRAY nor the
VT_BYREF flag can be set. VT_EMPTY and VT_NULL are not valid base types for the
array. All other types are legal.
cDims
Number of dimensions in the array. The number cannot be changed after the array
is created.
rgsabound
Pointer to a vector of bounds (one for each dimension) to allocate for the array
.
Return Value
Points to the array descriptor, or Null if the array could not be created.
Example
HRESULT PASCAL __export CPoly::EnumPoints(IEnumVARIANT FAR* FAR* ppenum)
{
unsigned int i;
HRESULT hresult;
VARIANT var;
SAFEARRAY FAR* psa;
CEnumPoint FAR* penum;
POINTLINK FAR* ppointlink;
SAFEARRAYBOUND rgsabound[1];
rgsabound[0].lLbound = 0;
rgsabound[0].cElements = m_cPoints;
psa = SafeArrayCreate(VT_VARIANT, 1, rgsabound);
if(psa == NULL){hresult = ReportResult(0, E_OUTOFMEMORY, 0, 0);
goto LError0}
// Code omitted here for brevity.
LError0:;
return hresult;
}
18.5.25 SafeArrayCreateVector
HRESULT SafeArrayCreateVector(
VARTYPE vt,
long lbound,
unsigned int cElements
);
Creates a one-dimensional array whose lower bound is always zero. A safe array c
reated with SafeArrayCreateVector is a fixed size, so the constant FADF_FIXEDSIZ
E is always set.
Parameters
vt
The base type of the array (the VARTYPE of each element of the array). The VARTY
PE is restricted to a subset of the variant types. Neither the VT_ARRAY nor the
VT_BYREF flag can be set. VT_EMPTY and VT_NULL are not valid base types for the
array. All other types are legal.
lbound
The lower bound for the array. Can be negative.
cElements
The number of elements in the array.
Return Value
Points to the array descriptor, or Null if the array could not be created.
Comments
SafeArrayCreateVector allocates a single block of memory containing a SAFEARRAY
structure for a single-dimension array (24 bytes), immediately followed by the a
rray data. All of the existing safe array functions work correctly for safe arra
ys that are allocated with SafeArrayCreateVector.
A SafeArrayCreateVector is allocated as a single block of memory. Both the SafeA
rray descriptor and the array data block are allocated contiguously in one alloc
ation, which speeds up array allocation. However, a user can allocate the descri
ptor and data area separately using the SafeArrayAllocDescriptor and SafeArrayAl
locData calls.
18.5.26 SafeArrayDestroy
HRESULT SafeArrayDestroy(
SAFEARRAY FAR* psa
);
Destroys an existing array descriptor and all of the data in the array. If objec
ts are stored in the array, Release is called on each object in the array.
Parameter
psa
Pointer to an array descriptor created by SafeArrayCreate.
Return Value
The return value obtained from the returned HRESULT is one of the following.
Return value Meaning
S_OK Success.
DISP_E_ARRAYISLOCKED The array is currently locked.
E_INVALIDARG The item pointed to by psa is not a safe array descriptor.
Example
STDMETHODIMP_(ULONG) CEnumPoint::Release()
{
if(--m_refs == 0){
if(m_psa != NULL)
SafeArrayDestroy(m_psa);
delete this;
return 0;
}
return m_refs;
}
18.5.27 SafeArrayDestroyData
HRESULT SafeArrayDestroyData(
SAFEARRAY FAR* psa
);
Destroys all the data in a safe array.
Parameter
psa
Pointer to an array descriptor.
Return Value
The return value obtained from the returned HRESULT is one of the following.
Return value Meaning
S_OK Success.
DISP_E_ARRAYISLOCKED The array is currently locked.
E_INVALIDARG The item pointed to by psa is not a safe array descriptor.
Comments
This function is typically used when freeing safe arrays that contain elements w
ith data types other than variants. If objects are stored in the array, Release
is called on each object in the array.
See Also
SafeArrayAllocData, SafeArrayAllocDescriptor, SafeArrayDestroyDescriptor
18.5.28 SafeArrayDestroyDescriptor
HRESULT SafeArrayDestroyDescriptor(
SAFEARRAY FAR* psa
);
Destroys a descriptor of a safe array.
Parameter
psa
Pointer to a safe array descriptor.
Return Value
The return value obtained from the returned HRESULT is one of the following.
Return value Meaning
S_OK Success.
DISP_E_ARRAYISLOCKED The array is currently locked.
E_INVALIDARG The item pointed to by psa is not a safe array descriptor.
Comments
This function is typically used to destroy the descriptor of a safe array that c
ontains elements with data types other than variants. Destroying the array descr
iptor does not destroy the elements in the array. Before destroying the array de
scriptor, call SafeArrayDestroyData to free the elements.
See Also
SafeArrayAllocData, SafeArrayAllocDescriptor, SafeArrayDestroyData
18.5.29 SafeArrayGetDim
HRESULT SafeArrayGetDim(
unsigned int SafeArrayGetDim(psa),
SAFEARRAY FAR* psa
);
Returns the number of dimensions in the array.
Parameters
psa
Pointer to an array descriptor created by SafeArrayCreate.
Return Value
Returns the number of dimensions in the array.
Example
HRESULT
CEnumPoint::Create(SAFEARRAY FAR* psa, CEnumPoint FAR* FAR* ppenum)
{
long lBound;
HRESULT hresult;
CEnumPoint FAR* penum;
// Verify that the SafeArray is the proper shape.
if(SafeArrayGetDim(psa) != 1)
return ReportResult(0, E_INVALIDARG, 0, 0);
// Code omitted here for brevity.
}
18.5.30 SafeArrayGetElement
HRESULT SafeArrayGetElement(
SAFEARRAY FAR* psa,
long FAR* rgIndices,
void FAR* pvData
);
Retrieves a single element of the array.
Parameters
psa
Pointer to an array descriptor created by SafeArrayCreate.
rgIndices
Pointer to a vector of indexes for each dimension of the array. The right-most (
least significant) dimension is rgIndices[0]. The left-most dimension is stored
at rgIndices[psa->cDims - 1].
pvData
Pointer to the location to place the element of the array.
Comments
This function calls SafeArrayLock and SafeArrayUnlock automatically, before and
after retrieving the element. The caller must provide a storage area of the corr
ect size to receive the data. If the data element is a string, object, or varian
t, the function copies the element in the correct way.
Return Value
The return value obtained from the returned HRESULT is one of the following.
Return value Meaning
S_OK Success.
DISP_E_BADINDEX The specified index is invalid.
E_INVALIDARG One of the arguments is invalid.
E_OUTOFMEMORY Memory could not be allocated for the element.
Example
STDMETHODIMP CEnumPoint::Next(
ULONG celt,
VARIANT FAR rgvar[],
ULONG FAR* pceltFetched)
{
unsigned int i;
long ix;
HRESULT hresult;
for(i = 0; i < celt; ++i)
VariantInit(&rgvar[i]);
for(i = 0; i < celt; ++i){
if(m_iCurrent == m_celts){
hresult = ReportResult(0, S_FALSE, 0, 0);
goto LDone;
}
ix = m_iCurrent++;
hresult = SafeArrayGetElement(m_psa, &ix, &rgvar[i]);
if(FAILED(hresult))
goto LError0;
}
hresult = NOERROR;
LDone:;
*pceltFetched = i;
return hresult;
LError0:;
for(i = 0; i < celt; ++i)
VariantClear(&rgvar[i]);
return hresult;
}
18.5.31 SafeArrayGetElemsize
HRESULT SafeArrayGetElemsize(
unsigned int SafeArrayGetElemsize(psa),
SAFEARRAY FAR* psa
);
Returns the size (in bytes) of the elements of a safe array.
Parameter
psa
Pointer to an array descriptor created by SafeArrayCreate.
18.5.32 SafeArrayGetLBound
HRESULT SafeArrayGetLBound(
SAFEARRAY FAR* psa,
unsigned int nDim,
long FAR* plLbound
);
Returns the lower bound for any dimension of a safe array.
Parameters
psa
Pointer to an array descriptor created by SafeArrayCreate.
nDim
The array dimension for which to get the lower bound.
plLbound
Pointer to the location to return the lower bound.
Return Value
The return value obtained from the returned HRESULT is one of the following.
Return value Meaning
S_OK Success.
DISP_E_BADINDEX The specified index is out of bounds.
E_INVALIDARG One of the arguments is invalid.
Example
HRESULT
CEnumPoint::Create(SAFEARRAY FAR* psa, CEnumPoint FAR* FAR* ppenum)
{
long lBound;
HRESULT hresult;
CEnumPoint FAR* penum;
}
18.5.33 SafeArrayGetUBound
HRESULT SafeArrayGetUBound(
SAFEARRAY FAR* psa,
unsigned int nDim,
long FAR* plUbound
);
Returns the upper bound for any dimension of a safe array.
Parameters
psa
Pointer to an array descriptor created by SafeArrayCreate().
nDim
The array dimension for which to get the upper bound.
plUbound
Pointer to the location to return the upper bound.
Return Value
The return value obtained from the returned HRESULT is one of the following.
Return value Meaning
S_OK Success.
DISP_E_BADINDEX The specified index is out of bounds.
E_INVALIDARG One of the arguments is invalid.
Example
HRESULT
CEnumPoint::Create(SAFEARRAY FAR* psa, CEnumPoint FAR* FAR* ppenum)
{
long lBound;
HRESULT hresult;
CEnumPoint FAR* penum;
// Verify that the SafeArray is the proper shape.
hresult = SafeArrayGetUBound(psa, 1, &lBound);
if(FAILED(hresult))
goto LError0;
// Code omitted here for brevity.
LError0:;
penum->Release();
return hresult;
}
18.5.34 SafeArrayLock
HRESULT SafeArrayLock(
SAFEARRAY FAR* psa
);
Increments the lock count of an array, and places a pointer to the array data in
pvData of the array descriptor.
Parameter
psa
Pointer to an array descriptor created by SafeArrayCreate.
Comments
The pointer in the array descriptor is valid until SafeArrayUnlock is called. Ca
lls to SafeArrayLock can be nested. An equal number of calls to SafeArrayUnlock
are required.
An array cannnot be deleted while it is locked.
Return Value
The return value obtained from the returned HRESULT is one of the following.
Return value Meaning
S_OK Success.
E_INVALIDARG The argument psa was not a valid safe array descriptor.
E_UNEXPECTED The array could not be locked.
18.5.35 SafeArrayPtrOfIndex
HRESULT SafeArrayPtrOfIndex(
SAFEARRAY FAR* psa,
long FAR* rgIndices,
void HUGEP* FAR* ppvData
);
Returns a pointer to an array element.
Parameters
psa
Pointer to an array descriptor created by SafeArrayCreate.
rgIndices
An array of index values that identify an element of the array. All indexes for
the element must be specified.
ppvData
On return, pointer to the element identified by the values in rgIndices.
Return Value
The return value obtained from the returned HRESULT is one of the following.
Return value Meaning
S_OK Success.
E_INVALIDARG The argument psa was not a valid safe array descriptor.
DISP_E_BADINDEX The specified index was invalid.
Comments
The array should be locked before SafeArrayPtrOfIndex is called. Failing to lock
the array can cause unpredictable results.
18.5.36 SafeArrayPutElement
HRESULT SafeArrayPutElement(
SAFEARRAY FAR* psa,
long FAR* rgIndices,
void FAR* pvData
);
Assigns a single element to the array.
Parameters
psa
Pointer to an array descriptor created by SafeArrayCreate.
rgIndices
Pointer to a vector of indexes for each dimension of the array. The right-most (
least significant) dimension is rgIndices[0]. The left-most dimension is stored
at rgIndices[psa->cDims - 1].
pvData
Pointer to the data to assign to the array. The variant types VT_DISPATCH, VT_UN
KNOWN, and VT_BSTR are pointers, and do not require another level of indirection
.
Return Value
The return value obtained from the returned HRESULT is one of the following.
Return value Meaning
S_OK Success.
DISP_E_BADINDEX The specified index was invalid.
E_INVALIDARG One of the arguments is invalid.
E_OUTOFMEMORY Memory could not be allocated for the element.
Comments
This function automatically calls SafeArrayLock and SafeArrayUnlock before and a
fter assigning the element. If the data element is a string, object, or variant,
the function copies it correctly. If the existing element is a string, object,
or variant, it is cleared correctly.
Note Multiple locks can be on an array. Elements can be put into an array while
the array is locked by other operations.
Example
HRESULT PASCAL __export CPoly::EnumPoints(IEnumVARIANT FAR* FAR* ppenum)
{
unsigned int i;
HRESULT hresult;
VARIANT var;
SAFEARRAY FAR* psa;
CEnumPoint FAR* penum;
POINTLINK FAR* ppointlink;
SAFEARRAYBOUND rgsabound[1];
rgsabound[0].lLbound = 0;
rgsabound[0].cElements = m_cPoints;
psa = SafeArrayCreate(VT_VARIANT, 1, rgsabound);
if(psa == NULL){
hresult = ResultFromScode(E_OUTOFMEMORY);
goto LError0;
}
// Code omitted here for brevity.
V_VT(&var) = VT_DISPATCH;
hresult = ppointlink->ppoint->QueryInterface(
IID_IDispatch, (void FAR* FAR*)&V_DISPATCH(&var));
if(hresult != NOERROR)
goto LError1;
ix[0] = i;
SafeArrayPutElement(psa, ix, &var);
ppointlink = ppointlink->next;
}
hresult = CEnumPoint::Create(psa, &penum);
if(hresult != NOERROR)
goto LError1;
*ppenum = penum;
return NOERROR;
LError1:;
SafeArrayDestroy(psa);
LError0:;
return hresult;
}
18.5.37 SafeArrayRedim
HRESULT SafeArrayRedim(
SAFEARRAY FAR* psa,
SAFEARRAYBOUND FAR* psaboundNew
);
Changes the right-most (least significant) bound of a safe array.
Parameters
psa
Pointer to an array descriptor.
psaboundNew
Pointer to a new safe array bound structure that contains the new array boundary
. You can change only the least significant dimension of an array.
Return Value
The return value obtained from the returned HRESULT is one of the following.
Return value Meaning
S_OK Success.
DISP_E_ARRAYISLOCKED The array is currently locked.
E_INVALIDARG The item pointed to by psa is not a safe array descriptor.
Comments
If you reduce the bound of an array, SafeArrayRedim deallocates the array elemen
ts outside the new array boundary. If the bound of an array is increased, SafeAr
rayRedim allocates and initializes the new array elements. The data is preserved
for elements that exist in both the old and new array.
18.5.38 SafeArrayUnaccessData
HRESULT SafeArrayUnaccessData(
SAFEARRAY FAR* psa
);
Decrements the lock count of an array, and invalidates the pointer retrieved by
SafeArrayAccessData.
Parameter
psa
Pointer to an array descriptor created by SafeArrayCreate.
Return Value
The return value obtained from the returned HRESULT is one of the following.
Return value Meaning
S_OK Success.
E_INVALIDARG The argument psa was not a valid safe array descriptor.
E_UNEXPECTED The array could not be unlocked.
18.5.39 SafeArrayUnlock
HRESULT SafeArrayUnlock(
SAFEARRAY FAR* psa
);
Decrements the lock count of an array so it can be freed or resized.
Parameter
psa
Pointer to an array descriptor created by SafeArrayCreate.
Return Value
The return value obtained from the returned HRESULT is one of the following.
Return value Meaning
S_OK Success.
E_INVALIDARG The argument psa was not a valid safe array descriptor.
E_UNEXPECTED The array could not be unlocked.
Comments
This function is called after access to the data in an array is finished.
18.5.40 SysAllocString
BSTR SysAllocString(
OLECHAR FAR* sz
);
Allocates a new string and copies the passed string into it. Returns Null if the
re is insufficient memory, and if Null, Null is passed in.
Parameter
sz
A zero-terminated string to copy. The sz parameter must be a Unicode string in 3
2-bit applications, and an ANSI string in 16-bit applications.
Return Value
If successful, points to a BSTR containing the string. If insufficient memory ex
ists or sz was Null, returns Null.
Comments
You can free strings created with SysAllocString using SysFreeString.
Example
inline void CStatBar::SetText(OLECHAR FAR* sz)
{
SysFreeString(m_bstrMsg);
m_bstrMsg = SysAllocString(sz);
}
18.5.41 SysAllocStringByteLen
BSTR SysAllocStringByteLen(
char FAR* psz,
unsigned int len
);
Takes an ANSI string as input, and returns a BSTR that contains an ANSI string.
Does not perform any ANSI-to-Unicode translation.
Parameters
psz
A zero-terminated string to copy, or Null to keep the string uninitialized.
len
Number of bytes to copy from psz. A null character is placed afterwards, allocat
ing a total of len+1 bytes.
Allocates a new string of len bytes, copies len bytes from the passed string int
o it, and then appends a null character. Valid only for 32-bit systems.
Return Value
Points to a copy of the string, or Null if insufficient memory exists.
Comments
This function is provided to create BSTRs that contain binary data. You can use
this type of BSTR only in situations where it will not be translated from ANSI t
o Unicode, or vice versa.
For example, do not use these BSTRs between a 16-bit and a 32-bit application ru
nning on a 32-bit Windows system. The COM 16-bit to 32-bit (and 32-bit to 16-bit
) interoperability layer will translate the BSTR and corrupt the binary data. Th
e preferred method of passing binary data is to use a SAFEARRAY of VT_UI1, which
will not be translated by COM.
If psz is Null, a string of the requested length is allocated, but not initializ
ed. The string psz can contain embedded null characters, and does not need to en
d with a Null. Free the returned string later with SysFreeString.
18.5.42 SysAllocStringLen
BSTR SysAllocStringLen(
OLECHAR FAR* pch,
unsigned int cch
);
Allocates a new string, copies cch characters from the passed string into it, an
d then appends a null character.
Parameters
pch
A pointer to cch characters to copy, or Null to keep the string uninitialized.
cch
Number of characters to copy from pch. A null character is placed afterwards, al
locating a total of cch+1 characters.
Return Value
Points to a copy of the string, or Null if insufficient memory exists.
Comments
If pch is Null, a string of the requested length is allocated, but not initializ
ed. The pch string can contain embedded null characters and does not need to end
with a Null. Free the returned string later with SysFreeString.
18.5.43 SysFreeString
void SysFreeString(
BSTR bstr
);
Frees a string allocated previously by SysAllocString, SysAllocStringByteLen, Sy
sReAllocString, SysAllocStringLen, or SysReAllocStringLen.
Parameter
bstr
A BSTR allocated previously, or Null. If Null, the function simply returns.
Return Value
None.
Example
CStatBar::~CStatBar()
{
SysFreeString(m_bstrMsg);
}
18.5.44 SysReAllocString
BOOL SysReAllocString(
BSTR FAR* pbstr,
OLECHAR FAR* sz
);
Allocates a new BSTR and copies the passed string into it, then frees the BSTR r
eferenced by pbstr, and finally resets pbstr to point to the new BSTR.
Parameters
pbstr
Points to a variable containing a BSTR.
sz
A zero-terminated string to copy.
Return Value
Returns False if insufficient memory exists.
18.5.45 SysReAllocStringLen
BOOL SysReAllocStringLen(
BSTR FAR* pbstr,
OLECHAR FAR* pch,
unsigned int cch
);
Creates a new BSTR containing a specified number of characters from an old BSTR,
and frees the old BSTR.
Parameters
pbstr
Pointer to a variable containing a BSTR.
pch
Pointer to cch characters to copy, or Null to keep the string uninitialized.
cch
Number of characters to copy from pch. A null character is placed afterward, all
ocating a total of cch+1 characters.
Return Value
Returns True if the string is reallocated successfully, or False if insufficient
memory exists.
Comments
Allocates a new string, copies cch characters from the passed string into it, an
d then appends a null character. Frees the BSTR referenced currently by pbstr, a
nd resets pbstr to point to the new BSTR. If pch is Null, a string of length cch
is allocated but not initialized.
The pch string can contain embedded null characters and does not need to end wit
h a Null.
18.5.46 SysStringByteLen
unsigned int SysStringByteLen(
BSTR bstr
);
Returns the length (in bytes) of a BSTR. Valid for 32-bit systems only.
Parameter
bstr
A BSTR allocated previously. It cannot be Null.
Return Value
The number of bytes in bstr, not including a terminating null character.
Comments
The returned value may be different from fstrlen(bstr) if the BSTR was allocated
with Sys[Re]AllocStringLen or SysAllocStringByteLen, and the passed-in characte
rs included a null character in the first len characters. For a BSTR allocated w
ith Sys[Re]AllocStringLen or SysAllocStringByteLen, this function always returns
the number of bytes specified in the len parameter at allocation time.
Example
// Display the status message.
TextOut(
hdc,
rcMsg.left + (m_dxFont / 2),
rcMsg.top + ((rcMsg.bottom - rcMsg.top - m_dyFont) / 2),
m_bstrMsg, SysStringByteLen(m_bstrMsg));
18.5.47 SysStringLen
unsigned int SysStringLen(
BSTR bstr
);
Returns the length of a BSTR.
Parameter
bstr
A BSTR allocated previously. Cannot be Null.
Return Value
The number of characters in bstr, not including a terminating null character.
Comments
The returned value may be different from _fstrlen(bstr) if the BSTR was allocate
d with Sys[Re]AllocStringLen or SysAllocStringByteLen, and the passed-in charact
ers included a null character in the first cch characters. For a BSTR allocated
with Sys[Re]AllocStringLen or SysAllocStringByteLen, this function always return
s the number of characters specified in the cch parameter at allocation time.
Example
// Display the status message.
//
TextOut(
hdc,
rcMsg.left + (m_dxFont / 2),
rcMsg.top + ((rcMsg.bottom - rcMsg.top - m_dyFont) / 2),
m_bstrMsg, SysStringLen(m_bstrMsg));
18.5.48 SystemTimeToVariantTime
int SystemTimeToVariantTime(psystime, pvtime)
SYSTEMTIME *psystime
double *vtime
Converts the variant representation of time-to-system time values.
Parameters
psystime
The system time.
vtime
Returned variant time.
Return Value
The return value obtained from the returned HRESULT is one of the following.
Result Meaning
True Success.
False Failure.
Comments
A variant time is stored as an 8-byte real value (double), representing a date b
etween January 1, 1753 and December 31, 2078, inclusive. The value 2.0 represent
s January 1, 1900; 3.0 represents January 2, 1900, and so on. Adding 1 to the va
lue increments the date by a day. The fractional part of the value represents th
e time of day. Therfore, 2.5 represents noon on January 1, 1900; 3.25 represents
6:00 a.m. on January 2, 1900, and so on. Negative numbers represent the dates p
rior to December 30, 1899.
The SYSTEMTIME structure is useful for the following reasons:
· It spans all time/date periods. MS-DOS date/time is limited to representing only
those dates between 1/1/1980 and 12/31/2107.
· The date/time elements are all easily accessible without needing to do any bit d
ecoding.
· The National Data Support data and time formating functions GetDateFormat() and
GetTimeFormat() take a SYSTEMTIME value as input.
18.5.49 VariantChangeType
HRESULT VariantChangeType(
VARIANTARG FAR* pvargDest,
VARIANTARG FAR* pvargSrc,
unsigned short wFlags,
VARTYPE vtNew
);
Converts a variant from one type to another.
Parameters
pvargDest
Pointer to the VARIANTARG to receive the coerced type. If this is the same as pv
argSrc, the variant will be converted in place.
pvargSrc
Pointer to the source VARIANTARG to be coerced.
wFlags
Flags that control the coercion. The only defined flag is VARIANT_NOVALUEPROP, w
hich prevents the function from attempting to coerce an object to a fundamental
type by getting the Value property. Applications should set this flag only if ne
cessary, because it makes their behavior inconsistent with other applications.
vtNew
The type to coerce to. If the return code is S_OK, the vt field of the *pvargDes
t is always the same as this value.
Return Value
The return value obtained from the returned HRESULT is one of the following.
Return value Meaning
S_OK Success.
DISP_E_BADVARTYPE The variant type vtNew is not a valid type of variant.
DISP_E_OVERFLOW The data pointed to by pvargSrc does not fit in the destination
type.
DISP_E_TYPEMISMATCH The argument could not be coerced to the specified type.
E_INVALIDARG One of the arguments is invalid.
E_OUTOFMEMORY Memory could not be allocated for the conversion.
Comments
The VariantChangeType function handles coercions between the fundamental types (
including numeric-to-string and string-to-numeric coercions). A variant that has
VT_BYREF set is coerced to a value by obtaining the referenced value. An object
is coerced to a value by invoking the object's Value property (DISPID_VALUE).
Typically, the implementor of IDispatch::Invoke determines which member is being
accessed, and then calls VariantChangeType to get the value of one or more argu
ments. For example, if the IDispatch call specifies a SetTitle member that takes
one string argument, the implementor would call VariantChangeType to attempt to
coerce the argument to VT_BSTR. If VariantChangeType does not return an error,
the argument could then be obtained directly from the bstrVal field of the VARIA
NTARG. If VariantChangeType returns DISP_E_TYPEMISMATCH, the implementor would s
et *puArgErr to 0 (indicating the argument in error) and return DISP_E_TYPEMISMA
TCH from IDispatch::Invoke.
Arrays of one type cannnot be converted to arrays of another type with this func
tion.
Note The type of a VARIANTARG should not be changed in the rgvarg array in plac
e.
See Also
VariantChangeTypeEx
18.5.50 VariantChangeTypeEx
HRESULT VariantChangeTypeEx(
VARIANTARG FAR* pvargDest,
VARIANTARG FAR* pvargSrc,
LCID lcid,
unsigned short wFlags,
VARTYPE vtNew
);
Converts a variant from one type to another, using a locale ID.
Parameters
pvargDest
Pointer to the VARIANTARG to receive the coerced type. If this is the same as pv
argSrc, the variant will be converted in place.
pvargSrc
Pointer to the source VARIANTARG to be coerced.
lcid
The locale ID for the variant to coerce. The locale ID is useful when the type o
f the source or destination VARIANTARG is VT_BSTR, VT_DISPATCH, or VT_DATE.
wFlags
Flags that control the coercion. The only defined flag is VARIANT_NOVALUEPROP, w
hich prevents the function from attempting to coerce an object to a fundamental
type by getting its Value property. Applications should set this flag only if ne
cessary, because it makes their behavior inconsistent with other applications.
vtNew
The type to coerce to. If the return code is S_OK, the vt field of the *pvargDes
t is guaranteed to be equal to this value.
Return Value
The return value obtained from the returned HRESULT is one of the following.
Return value Meaning
S_OK Success.
DISP_E_BADVARTYPE The variant type vtNew is not a valid type of variant.
DISP_E_OVERFLOW The data pointed to by pvargSrc does not fit in the destination
type.
DISP_E_TYPEMISMATCH The argument could not be coerced to the specified type.
E_INVALIDARG One of the arguments is invalid.
E_OUTOFMEMORY Memory could not be allocated for the conversion.
Comments
The VariantChangeTypeEx function handles coercions between the fundamental types
(including numeric-to-string and string-to-numeric coercions). To change a type
with the VT_BYREF flag set to one without VT_BYREF, change the referenced value
to VariantChangeTypeEx. To coerce objects to fundamental types, obtain the valu
e of the Value property.
Typically, the implementor of IDispatch::Invoke determines which member is being
accessed, and then calls VariantChangeType to get the value of one or more argu
ments. For example, if the IDispatch call specifies a SetTitle member that takes
one string argument, the implementor would call VariantChangeTypeEx to attempt
to coerce the argument to VT_BSTR.
If VariantChangeTypeEx does not return an error, the argument could then be obta
ined directly from the bstrVal field of the VARIANTARG. If VariantChangeTypeEx r
eturns DISP_E_TYPEMISMATCH, the implementor would set *puArgErr to 0 (indicating
the argument in error) and return DISP_E_TYPEMISMATCH from IDispatch::Invoke.
Arrays of one type cannot be converted to arrays of another type with this funct
ion.
Note The type of a VARIANTARG should not be changed in the rgvarg array in plac
e.
See Also
VariantChangeType
18.5.51 VariantClear
HRESULT VariantClear(
VARIANTARG FAR* pvarg
);
Clears a variant.
Parameter
pvarg
Pointer to the VARIANTARG to clear.
Return Value
The return value obtained from the returned HRESULT is one of the following.
Return value Meaning
S_OK Success.
DISP_E_ARRAYISLOCKED The variant contains an array that is locked.
DISP_E_BADVARTYPE The variant type pvarg is not a valid type of variant.
E_INVALIDARG One of the arguments is invalid.
Comments
Use this function to clear variables of type VARIANTARG (or VARIANT) before the
memory containing the VARIANTARG is freed (as when a local variable goes out of
scope).
The function clears a VARIANTARG by setting the vt field to VT_EMPTY and the wRe
served field to 0. The current contents of the VARIANTARG are released first. If
the vt field is VT_BSTR, the string is freed. If the vt field is VT_DISPATCH, t
he object is released. If the vt field has the VT_ARRAY bit set, the array is fr
eed.
In certain cases, it may be preferable to clear a variant in code without callin
g VariantClear. For example, you can change the type of a VT_I4 variant to anoth
er type without calling this function. However, you must call VariantClear if a
VT_type is received but cannot be handled. Using VariantClear in these cases ens
ures that code will continue to work if Automation adds new variant types in th
e future.
Example
for(i = 0; i < celt; ++i)
VariantClear(&rgvar[i]);
18.5.52 VariantCopy
HRESULT VariantCopy(
VARIANTARG FAR* pvargDest,
VARIANTARG FAR* pvargSrc
);
Frees the destination variant and makes a copy of the source variant.
Parameters
pvargDest
Pointer to the VARIANTARG to receive the copy.
pvargSrc
Pointer to the VARIANTARG to be copied.
Return Value
The return value obtained from the returned HRESULT is one of the following.
Return value Meaning
S_OK Success.
DISP_E_ARRAYISLOCKED The variant contains an array that is locked.
DISP_E_BADVARTYPE The source and destination have an invalid variant type
(usually uninitialized).
E_OUTOFMEMORY Memory could not be allocated for the copy.
E_INVALIDARG The argument pvargSrc was VT_BYREF.
Comments
First, free any memory that is owned by pvargDest, such as VariantClear (pvargDe
st must point to a valid initialized variant, and not simply to an uninitialized
memory location). Then pvargDest receives an exact copy of the contents of pvar
gSrc.
If pvargSrc is a VT_BSTR, a copy of the string is made. If pvargSrc is a VT_ARRA
Y, the entire array is copied. If pvargSrc is a VT_DISPATCH or VT_UNKNOWN, AddRe
f is called to increment the object's reference count.
18.5.53 VariantCopyInd
HRESULT VariantCopyInd(
VARIANT FAR* pvarDest,
VARIANTARG FAR* pvargSrc
);
Frees the destination variant and makes a copy of the source VARIANTARG, perform
ing the necessary indirection if the source is specified to be VT_BYREF.
Parameters
pvarDest
Pointer to the VARIANTARG that will receive the copy.
pvargSrc
Pointer to the VARIANTARG that will be copied.
Return Value
The return value obtained from the returned HRESULT is one of the following.
Return value Meaning
S_OK Success.
DISP_E_ARRAYISLOCKED The variant contains an array that is locked.
DISP_E_BADVARTYPE The source and destination have an invalid variant type
(usually uninitialized).
E_OUTOFMEMORY Memory could not be allocated for the copy.
E_INVALIDARG The argument pvargSrc was VT_ARRAY.
Comments
This function is useful when a copy of a variant is needed, and to guarantee tha
t it is not VT_BYREF, such as when handling arguments in an implementation of ID
ispatch::Invoke.
For example, if the source is a (VT_BYREF | VT_I2), the destination will be a BY
VAL | VT_I2. The same is true for all legal VT_BYREF combinations, including VT_
VARIANT.
If pvargSrc is (VT_BYREF | VT_VARIANT), and the contained variant is VT_BYREF, t
he contained variant is also dereferenced.
This function frees any existing contents of pvarDest.
18.5.54 VariantInit
void VariantInit(
VARIANTARG FAR* pvarg
);
Initializes a variant.
Parameter
pvarg
Pointer to the VARIANTARG that will be initialized.
Comments
The VariantInit function initializes the VARIANTARG by setting the vt field to V
T_EMPTY. Unlike VariantClear, this function does not interpret the current conte
nts of the VARIANTARG. Use VariantInit to initialize new local variables of type
VARIANTARG (or VARIANT).
Example
for(i = 0; i < celt; ++i)
VariantInit(&rgvar[i]);
18.5.55 VariantTimeToDosDateTime
int VariantTimeToDosDateTime(
double vtime,
unsigned short FAR* pwDOSDate,
unsigned short FAR* pwDOSTime
);
Converts the variant representation of a date and time to MS-DOS date and time v
alues.
Parameters
vtime
The variant time to convert.
pwDOSDate
Pointer to the location to store the converted MS-DOS date.
pwDOSTime
Pointer to the location to store the converted MS-DOS time.
Return Value
The return value obtained from the returned HRESULT is one of the following.
Result Meaning
True Success.
False Failure.
Comments
A variant time is stored as an 8-byte real value (double), representing a date b
etween January 1, 1753 and December 31, 2078, inclusive. The value 2.0 represent
s January 1, 1900; 3.0 represents January 2, 1900, and so on. Adding 1 to the va
lue increments the date by a day. The fractional part of the value represents th
e time of day. Therefore, 2.5 represents noon on January 1, 1900; 3.25 represent
s 6:00 a.m. on January 2, 1900, and so on. Negative numbers represent the dates
prior to December 30, 1899.
For a description of the MS-DOS date and time formats, see DosDateTimeToVariantT
ime.
18.5.56 VariantTimeToSystemTime
int VariantTimeToSystemTime(
double vtime,
SYSTEMTIME *psystime
);
Converts the variant representation of time-to-system time values.
Parameters
vtime
The variant time that will be converted.
psystime
Pointer to the location where the converted time will be stored.
Return Value
The return value obtained from the returned HRESULT is one of the following.
Result Meaning
True Success.
False Failure.
Comments
A variant time is stored as an 8-byte real value (double), representing a date b
etween January 1, 1753 and December 31, 2078, inclusive. The value 2.0 represent
s January 1, 1900; 3.0 represents January 2, 1900, and so on. Adding 1 to the va
lue increments the date by a day. The fractional part of the value represents th
e time of day. Therefore, 2.5 represents noon on January 1, 1900; 3.25 represent
s 6:00 A.M. on January 2, 1900, and so on. Negative numbers represent the dates
prior to December 30, 1899.
Using the SYSTEMTIME structure is useful because:
· It spans all time/date periods. MS-DOS date/time is limited to representing only
those dates between 1/1/1980 and 12/31/2107.
· The date/time elements are all easily accessible without needing to do any bit d
ecoding.
· The National Language Support data and time formating functions GetDateFormat()
and GetTimeFormat() take a SYSTEMTIME value as input.
18.5.57 VarNumFromParseNum
HRESULT VarNumFromParseNum(
[in] NUMPARSE *pnumprs,,
[in] unsigned char *rgbDig,
[in] unsigned long dwVtBits,
[out] VARIANT *pvar
);
Once the number is parsed, the caller can call VarNumFromParseNum() to convert t
he parse results to a number. The NUMPARSE structure and digit array must be pas
sed in unchanged from the VarParseNumFromStr() call. This function will choose t
he smallest type allowed that can hold the result value with as little precision
loss as possible. The result variant is an [out] parameter, so its contents are
not freed before storing the result.
Parameters
pnumprs
Parsed results.
rgbDig
Array.
dwVtBits
Contains one bit set for each type that is acceptable as a return value (in many
cases, just one bit).
Pvar
Result variant.
Return Value
The return value obtained from the returned HRESULT is one of the following.
Return value Meaning
S_OK Success.
E_OUTOFMEMORY Out of memory.
DISP_E_OVERFLOW The number is too large to be represented in an allowed type. Th
ere is no error if precision is lost in the conversion.
The rgbDig array is filled in with the values for the digits in the range 0-7, 0
-9, or 0-15, depending on whether the number is octal, decimal, or hexadecimal.
All leading zeros have been stripped off. For decimal numbers, trailing zeros ar
e also stripped off, unless the number is zero, in which case a single zero digi
t will be present.
For rounding decimal numbers, the digit array must be at least one digit longer
than the maximum required for data types. The maximum number of digits required
for the DECIMAL data type is 29, so the digit array must have room for 30 digits
. There must also be enough digits to accept the number in octal, if that parsin
g options is selected. (Hexadecimal and octal numbers are limited by VarNumFromP
arseNum() to the magnitude of an unsigned long [32 bits], so they need 11 octal
digits.)
18.5.58 VarParseNumFromStr
HRESULT VarParseNumFromStr(
[in] OLECHAR* strIn,
[in] LCID lcid,
[in] unsigned long dwFlags,
[in] NUMPARSE *pnumprs,
[out] unsigned char *rgbDig
);
Parses a string, and creates a type-independent description of the number it rep
resents. The first three parameters are identical to the first three parameters
of VarI2FromStr, VarI4FromStr, VarR8FromStr, and so on. The fourth parameter is
a pointer to a NUMPARSE structure, which contains both input information to the
function as well as the results, as described above. The last parameter is a poi
nter to an array of digits, filled in by the function.
The VarParseNumFromStr function fills in the dwOutFlags element with each corres
ponding feature that was actually found in the string. This allows the caller to
make decisions about what numeric type to use for the number, based on the form
at in which it was entered. For example, one application might want to use the C
URRENCY data type if the currency symbol is used, and others may want to force a
floating point type if an exponent was used.
Parameters
[in] strIn
Input string to be converted to a number.
lcid
Locale identifier
dwFlags
Allows the caller to control parsing, therefore defining the acceptable syntax o
f a number. If this field is set to zero, the input string must contain nothing
but decimal digits. Setting each defined flag bit enables parsing of that syntac
tic feature. Standard Automation parsing (for example, as used by VarI2FromStr)
has all flags set (NUMPRS_STD).
Return Value
The return value obtained from the returned HRESULT is one of the following.
Return value Meaning
S_OK Success.
E_OUTOFMEMORY Internal memory allocation failed. (Used for DBCS only to create
a copy with all wide characters mapped narrow.)
DISP_E_TYPEMISMATCH There is no valid number in the string, or there is no c
losing parenthesis to match an opening one. In the former case, cDig and cchUsed
in the NUMPARSE structure will be zero. In the latter, the NUMPARSE structure a
nd digit array are fully updated, as if the closing parenthesis was present.
DISP_E_OVERFLOW For hexadecimal and octal digists, there are more digits than wi
ll fit into the array. For decimal, the exponent exceeds the maximum possible. I
n both cases, the NUMPARSE structure and digit array are fully updated (for deci
mal, the cchUsed field excludes the entire exponent).
18.5.59 VectorFromBstr
HRESULT VectorFromBstr(
BSTR bstr,
SAFEARRAY FAR* FAR* ppsa
);
Returns a vector, assigning each character in the BSTR to an element of the vect
or.
Parameters
bstr
The BSTR to be converted to a vector.
ppsa
On exit, ppsa points to a one-dimensional safe array containing the characters i
n the BSTR.
Return Value
The return value obtained from the returned HRESULT is one of the following.
Return value Meaning
S_OK Success.
E_OUTOFMEMORY Out of memory.
E_INVALIDARG BSTR is Null.
18.6 Automation Related Structure Definitions
18.6.1 NUMPARSE
The caller of VarParseNumFromStr() must initialize two elements of the passed-in
NUMPARSE structure:
typedef struct {
int cDig;
unsigned long dwInFlags;
unsigned long dwOutFlags;
int cchUsed;
int nBaseShift;
int nPwr10;
} NUMPARSE;
The cDig element is set to the size of the rgbDig array, and dwInFlags is set to
parsing options. All other elements may be uninitialized and are set by the fun
ction, except on error, as described in the following paragraphs. The cDig eleme
nt is also modified by the function to reflect the actual number of digits writt
en to the rgbDig array.
The cchUsed element of the NUMPARSE sturcture is filled in with the number of ch
aracters (from the beginning of the string) that were successfully parsed. This
allows the caller to determine if the entire string was part of the number (as r
equired by functions such as VarI2FromStr), or where to continue parsing the str
ing.
The nBaseShift element gives the number of bits per digit (3 or 4 for octal and
hexadecimal numbers, and zero for decimal).
The following apply only to decimal numbers:
· nPwr10 sets the decimal point position by giving the power of 10 of the least si
gnificant digit.
· If the number is negative, NUMPRS_NEG will be set in dwOutFlags.
· If there are more non-zero decimal digits than will fit into the digit array, th
e NUMPRS_INEXACT flag will be set.
18.6.2 SAFEARRAY
The definition for a safe array varies, depending on the target operating system
platform. On 32-bit Windows systems, both the cbElements and cLocks parameters
are unsigned long integers, and the handle parameter is omitted. On 16-bit Windo
ws systems, cbElements and cLocks are unsigned short integers The handle paramet
er is retained for compatibility with earlier software. For example:
typedef struct FARSTRUCT tagSAFEARRAY {
unsigned short cDims; // Count of dimensions in this array.
unsigned short fFeatures; // Flags used by the SafeArray
// routines docu
mented below.
#if defined(WIN32)
unsigned long cbElements; // Size of an element of the array.
// Does not incl
ude size of
// pointed-to da
ta.
unsigned long cLocks; // Number of times the array has been
// locked withou
t corresponding unlock.
#else
unsigned short cbElements;
unsigned short cLocks;
unsigned long handle; // Unused but kept for compatibility.
#endif
void HUGEP* pvData; // Pointer to the data.
SAFEARRAYBOUND rgsabound[1]; // One bound for each dimension.
} SAFEARRAY;
The array rgsabound is stored with the left-most dimension in rgsabound[0] and t
he right-most dimension in rgsabound[cDims - 1]. If an array was specified in a
C-like syntax as a [2][5], it would have two elements in the rgsabound vector. E
lement 0 has an lLbound of 0 and a cElements of 2. Element 1 has an lLbound of 0
and a cElements of 5.
The fFeatures flags describe attributes of an array that can affect how the arra
y is released. This allows freeing the array without referencing its containing
variant. The bits are accessed using the following constants:
#define FADF_AUTO 0x0001 // Array is allocated on the stack.
#define FADF_STATIC 0x0002 // Array is statically allocated.
#define FADF_EMBEDDED 0x0004 // Array is embedded in a structure.
#define FADF_FIXEDSIZE 0x0010 // Array may not be resized or
// reallocated.
#define FADF_BSTR 0x0100 // An array of BSTRs.
#define FADF_UNKNOWN 0x0200 // An array of IUnknown*.
#define FADF_DISPATCH 0x0400 // An array of IDispatch*.
#define FADF_VARIANT 0x0800 // An array of VARIANTs.
#define FADF_RESERVED 0xF0E8 // Bits reserved for future use.
18.6.3 SAFEARRAYBOUND
Represents the bounds of one dimension of the array. The lower bound of the dime
nsion is represented by lLbound, and cElements represents the number of elements
in the dimension. The structure is defined as follows:
typedef struct tagSAFEARRAYBOUND {
unsigned long cElements;
long lLbound;
} SAFEARRAYBOUND;
19. Support for Remote Debugging
The COM Library and the COM Network Protocol provide support for debugging engin
es on the client and the server side of a remote COM invocation to cooperate in
allowing the overall application to be debugged. This section describes the runt
ime infrastructure provided by the Microsoft Windows implementation of the COM L
ibrary by which that is accomplished; other implementations will provide similar
infrastructures, though in practice the details of such support will be highly
sensitive to the mechanisms by which debugging engines are supported on the give
n platform. This section also specifies the standard data formats transmitted be
tween client and server by which this cooperation is carried out.
The following a brief example of the sort of debugging session scenario which ca
n be supported with this infrastructure.
Suppose the programmer is debugging an application with is an OLE document conta
iner, and that the application is presently stopped in the debugger at a point i
n the code where the container is about to invoke a method in some interface on
one of its contained objects, the implementation of which happens to be in anoth
er executable. That is, the pointer that the container has in hand actually poin
ts to an occurrence of part of the remoting infrastructure known as an interface
proxy (see above). Interface proxies and the rest of the remoting infrastructure
are not (normally) part of the programmer s concern when debugging client and serv
er applications, as the whole raison d être of the RPC infrastructure is to be trans
parent, is to make remote object invocations appear to be local ones. Unless the
programmer is debugging the remoting infrastructure himself, this should apply
to debugging as well.
This perspective leads to some of the following scenarios that need to be suppor
table by the debugger. If the programmer Single Steps into the function invocati
on, then the debugger should next stop just inside the real implementation of th
e remote server object, having transparently passed through the RPC infrastructu
re. (Notice that before the Step command is executed, the remote process may not
presently have the debugger attached to it, and so the act of doing the step ma
y need to cause the debugger to attach itself.) The programmer will now be able
to step line by line through the server's function. When he steps past the closi
ng brace of the function, he should wind up back in the debugger of the client p
rocess immediately after the function call.
A similar scenario is one where we skip the incoming single step but instead, ou
t of the blue, hit a breakpoint in the server, then start single stepping. This,
too, should single step over the end of the server function back into the client
process. The twist is that this time, the client debugger may not presently be
running, and therefore may need to be started.
19.1 Implementation
The ability for debuggers to support scenarios such as these is provided by hook
s in the client and server side RPC infrastructure. If requested by the debugger
, at certain important times, these hooks inform the debugger of the fact that a
transmission of a remote call about to be made or that transmission of return v
alues is about to occur. That is, when the COM Library is about to make or retur
n from a call to an object, it notifies the debugger of what is happening, so th
at the debugger can take any special actions it desires.
19.1.1 DllDebugObjectRPCHook
BOOL WINAPI DllDebugObjectRPCHook(BOOL fTrace, LPORPC_INIT_ARGS lpOrpcInitArgs)
This function is to be exported by name from one or more DLLs that wish to be in
formed when from the user s point of view that debugging is engaged. Debuggers wil
l should call this function to inform each of their loaded DLLs that export this
function as to whether they are presently being debugged or not. When the debug
ger wants to enable debugging, it calls DllDebugObjectRpcHook with fTrace=TRUE and
when it wants to disable it, it calls DllDebugObjectRpcHook with fTrace=FALSE
. When enabled, debugging support such as the tracing described herein should be
enabled.
Certain of the COM Library DLLs, for example, implement this function. When debu
gging is enabled, they turn on what is here called COM remote debugging, and whi
ch is the focus of this section.
The second argument points to an ORPC_INIT_ARGS structure whose definition is gi
ven below. The pvPSN member is used only on the Macintosh, where the calling deb
ugger is required in this field to pass the process serial number of the debugge
e s process. On other systems pvPSN should be NULL.
The lpIntfOrpcDebug member is a pointer to an interface. This is used by in-proc
ess debuggers and is discussed in more detail later. Debuggers that are neither
in-process debuggers nor are Macintosh debuggers should pass NULL for lpIntfOrpc
Debug.
typedef struct ORPC_INIT_ARGS {
IOrpcDebugNotify __RPC_FAR * lpIntfOrpcDebug;
void * pvPSN;
// contains ptr to Process Serial No. for Mac COM debugging.
DWORD dwReserved1; // For f
uture use, must be 0.
DWORD dwReserved2; // For f
uture use, must be 0.
} ORPC_INIT_ARGS;
typedef ORPC_INIT_ARGS __RPC_FAR * LPORPC_INIT_ARGS;
interface IOrpcDebugNotify : IUnknown {
VOID ClientGetBufferSize(LPORPC_DBG_ALL);
VOID ClientFillBuffer(LPORPC_DBG_ALL);
VOID ClientNotify(LPORPC_DBG_ALL);
VOID ServerNotify(LPORPC_DBG_ALL);
VOID ServerGetBufferSize(LPORPC_DBG_ALL);
VOID ServerFillBuffer(LPORPC_DBG_ALL);
};
As one would expect, a debugger calls DllDebugObjectRPCHook within the context (
that is, within the process) of the relevant debuggee. Thus, the implementation
of this function most often will merely store the arguments in global DLL-specif
ic state.
Further, as this function is called from the debugger, the function can be calle
d when the DLL in which it is implemented is in pretty well any state; no synchr
onization with other internal DLL state can be relied upon. Thus, it is recommen
ded that the implementation of this function indeed do nothing more than set int
ernal global variables.
Argument Type Description
fTrace BOOL TRUE if debugging is enabled, FALSE otherwise
lpOrpcInitArgs LPORPC_INIT_ARGS typically NULL; see comments abo
ve for MAC COM debuggers or in-process debuggers.
return value BOOL TRUE if the function was successful (the DLL und
erstood and executed the request), FALSE otherwise
19.1.2 Architectural Overview
When COM remote debugging is enabled, there are a total of six notifications tha
t occur in the round-trip of one COM RPC call: three on the client side and thre
e on the server side. The overall sequence of events is as follows.
Suppose the client has an interface pointer pFoo of type IFoo* which happens to
be a proxy for another object in a remote server process.
interface IFoo : IUnknown {
HRESULT Func();
};
IFoo *pFoo;
When the client invokes pFoo->Func(), it executes code in the interface proxy. T
his code is responsible for marshaling the arguments into a buffer, calling the
server, and unmarshaling the return values. To do so, it draws on the services o
f an IRpcChannelBuffer instance with which it was initialized by the COM Library
.
To get the buffer, the interface proxy calls IRpcChannelBuffer::GetBuffer(), pas
sing in (among other things) the requested size for the buffer. Before actually
allocating the buffer, the GetBuffer() implementation (normally) checks to see if
debugging is enabled per DllDebugObjectRPCHook(). If so, then the channel calls
DebugORPCClientGetBufferSize() (see below for details) to inform the debugger that
an COM RPC call is about to take place and to ask the debugger how many bytes of
information it would like to transmit to the remote server debugger. The channel
then, unbeknownst to the interface proxy, allocates a buffer with this many addi
tional bytes in it.
The interface proxy marshals the incoming arguments in the usual way into the bu
ffer that it received, then calls IRpcChannelBuffer::SendReceive(). Immediately o
n function entry, the channel again checks to see if debugging is enabled. If so
, then it calls DebugORPCClientFillBuffer() passing in the pointer to (the debug
ger s part of) the marshaling buffer. The debugger will write some information int
o the buffer, but this need be of no concern to the channel implementation other
than that it is to ferry the contents of the buffer to the server debugger. Onc
e DebugORPCClientFillBuffer() returns, the channel implementation of SendReceive
() proceeds as in the normal case.
We now switch context in our explanation here to the server-side RPC channel. Su
ppose that it has received an incoming call request and has done what it normall
y does just up to the point where it is about to call IRpcStubBuffer::Invoke(),
which when will cause the arguments to be unmarshaled, etc. Just before calling
Invoke(), if there was any debugger information (i.e.: it exists in the incoming
request and is of non-zero size) in the incoming request or if debugging is pre
sently already enabled per DllDebugObjectRPCHook() (irrespective of the presence
or size of the debug info), then the channel is to call DebugORPCServerNotify().
The act of calling this function may in fact start a new debugger if needed and
attach it to this (the server) process; however, this need not be of concern to
the channel implementation. Having made the request, the channel proceeds to ca
ll Invoke() as in the normal case.
The implementation of Invoke() will unmarshal the incoming arguments, then call
the appropriate method on the server object. When the server object returns, Inv
oke() marshals the return values for transmission back to the client. As on the
client side, the marshaling process begins by calling IRpcChannelBuffer::GetBuffer()
to get a marshaling buffer. As on the client side, the server side channel GetB
uffer() implementation when being debugged (per the present setting of DllDebugObje
ctRPCHook(), not per the presence of the incoming debug info) asks the debugger
how many bytes it wishes to transmit back to the client debugger. The channel al
locates the buffer accordingly and returns it to the Invoke() implementation who
marshals the return values into it, then returns to its caller.
The caller of IRpcStubBuffer::Invoke() then checks to see if he is presently bei
ng debugged. If so, then he at this time calls DebugORPCServerFillBuffer(), pass
ing in the pointer to the debug-buffer that was allocated in the (last, should t
here erroneously be more than one) call to GetBuffer() made inside Invoke(); sho
uld no such call exist, and thus there is no such buffer, NULL is passed. The by
tes written into the buffer (if any) by the debugger are ferried to the client s
ide.
We now switch our explanatory context back to the client side. Eventually the cl
ient channel either receives a reply from the server containing the marshaled re
turn values (and possibly debug info), receives an error indication from the ser
ver RPC infrastructure, or decides to stop waiting. That is, eventually the clien
t channel decides that it is about to return from IRpcChannel::SendReceive(). Im
mediately before doing so, it checks to see if it is either already presently be
ing debugged or if in the reply it received any (non-zero sized) information fro
m the server debugger. If so, then it calls DebugORPCClientNotify(), passing in t
he server-debugger s info if it has any; doing so may start and attach the debugge
r if needed. The channel then returns from SendReceive().
19.1.3 Calling Convention for Notifications
The preceding discussion discussed the COM RPC debugging architecture in terms o
f six of debugger-notification APIs (DebugORPC...()). However, rather than being
actual API-entry points in a a static-linked or dynamically-linked library, the
se notifications use an somewhat unusual calling convention to communicate with
the notification implementations, which are found inside debugger products. This
somewhat strange calling convention is used for the following reasons:
Two of the six notifications need to start and attach the debugger if it is not
already attached to the relevant process.
The convention used transitions into the debugger code with the least possible d
isturbance of the debuggee s state and executing the minimal amount of debuggee co
de. This increases robustness of debugging.
The debugger is necessarily equipped to deal with concurrency issues of other th
reads executing in the same process. Therefore, it is important to transition to
the debugger as fast as possible to avoid inadvertent concurrency problems.
The actual calling convention used is by its nature inherently processor and ope
rating-system specific. On Win32 implementations, the default calling conventio
n for notifications takes the form of a software exception, which is raised by a
call to the RaiseException Win32 API:
VOID RaiseException(
DWORD dwExceptionCode, // exception code
DWORD dwExceptionFlags, // continuable exception flag
DWORD cArguments, // number of arguments in array
CONST DWORD * lpArguments // address of array of arguments
);
As used here, the arguments to this raised exception call in order are:
dwExceptionCode: An exception code EXCEPTION_ORPC_DEBUG (0x804F4C45) is used. Th
e debugger should recognize this exception as a special one indicating an COM R
PC debug notification.
dwExceptionFlags: This is zero to indicate a continuable exception.
cArguments: One
lpArguments: The array contains one argument. This argument is a pointer to a st
ructure which contains the notification specific information that the COM RPC sy
stem passes to the debugger. The definition of this structure ORPC_DBG_ALL is gi
ven below. The same structure is used for all the notifications. The structure i
s just the union of the arguments of the six debugger notification APIs. For a p
articular notification not all the fields in the structure are meaningful and th
ose that are not relevant have undefined values; details on this are below:
typedef struct ORPC_DBG_ALL {
BYTE * pSignature;
RPCOLEMESSAGE * pMessage;
const IID * iid;
void* reserved1;
void* reserved2;
void* pInterface;
IUnknown * pUnkObject;
HRESULT hresult;
void * pvBuffer;
ULONG cbBuffer;
ULONG * lpcbBuffer;
void * reserved3;
} ORPC_DBG_ALL;
The pSignature member of this structure points to a sequence of bytes which cont
ains:
a four-byte sanity-check signature of the ASCII characters MARB in increasing memo
ry order.
a 16-byte GUID indicating which notification this is. Each of the six notificati
ons defined here has a different GUID. More notifications and corresponding GUID
s can be defined in the future and be known not to collide with existing notific
ations.
a four-byte value which is reserved for future use. This value is NULL currently
.
The notifications specified here pass their arguments by filling in the appropri
ate structure members. See each notification description for details.
Using software exceptions for COM debugging notifications is inconvenient for in-
process debugging. In-process debuggers can alternately get these notifications v
ia direct calls into the debugger s code. The debugger which wants to be notified
by a direct call passes in an IOrpcDebugNotify interface in the LPORPC_INIT_ARGS a
rgument to DllDebugObjectRPCHook. If this interface pointer is available, COM ma
kes the debug notifications by calling the methods on this interface. The method
s all take an LPORPC_DBG_ALL as the only argument. The information passed in th
is structure is identical to that passed when the notification is done by raisin
g a software exception.
19.1.4 Notifications
What follows is a detailed description of each of the relevant notifications.
Note that in the network case, depending on the notification in question the byt
e order used may be different than that of the local machine. The byte order, et
c., of the incoming data is provided from the dataRep contained the passed RPCOL
EMESSAGE structure.
Though each function is documented here for purely historical reasons as if it w
ere in fact a function call, we have seen above that this is not the case. Unles
s otherwise specified, the name of the argument to the DebugORPC... notification
call is the same as the name of the structure member in ORPC_DBG_ALL used to pa
ss it to the debugger. So for example the pMessage argument of the DebugORPCClie
ntGetBufferSize notification is passed to the debugger in the pMessage structure
member of ORPC_DBG_ALL. We trust that readers will not be too confused by this,
and apologize profusely should this prove not to be the case.
19.1.4.1 DebugORPCClientGetBufferSize
ULONG DebugORPCClientGetBufferSize(pMessage, iid, reserved, pUnkProxyObject)
Called on the client side in IRpcChannel::GetBuffer().
The GUID for this notification is 9ED14F80-9673-101A-B07B-00DD01113F11
GUID __private_to_macro__ = { /* 9ED14F80-9673-101A-B07B-00DD01113F11 */
0x9ED14F80,
0x9673,
0x101A,
0xB0,
0x7B,
{0x00, 0xDD, 0x1, 0x11, 0x3F, 0x11}
};
Argument Type Description
pMessage RPCOLEMESSAGE* identification of the method being invoked, etc.
iid REFIID contains the IID of the interface being called.
reserved void * reserved for future use.
pUnkProxyObject IUnknown * an IUnknown (no particular one) on the object in
volved in this invocation. May legally be NULL, though this reduces debugging fu
nctionality. Further, this and like-named parameters must consistently be either
NULL or non-NULL in all notifications in a given client side COM RPC implementat
ion.
return value ULONG the number of bytes that the client debugger wishes to t
ransmit to the server debugger. May legitimately be zero, which indicates that n
o information need be transmitted. The lpcbBuffer field in the ORPC_DBG_ALL stru
cture holds a pointer to a ULONG. The debugger writes the number of bytes it wan
ts to transmit with the packet in that location.
19.1.4.2 DebugORPCClientFillBuffer
void DebugORPCClientFillBuffer(pMessage, iid, reserved, pUnkProxyObject, pvBuffe
r, cbBuffer)
Called on the client side on entry to IRpcChannel::SendReceive(). See the above
overview for further details.
The GUID for this notification is DA45F3E0-9673-101A-B07B-00DD01113F11:
GUID __private_to_macro__ = { /* DA45F3E0-9673-101A-B07B-00DD01113F11 */
0xDA45F3E0,
0x9673,
0x101A,
0xB0,
0x7B,
{0x00, 0xDD, 0x01, 0x11, 0x3F, 0x11}
};
Argument Type Description
pMessage RPCOLEMESSAGE* as in DebugORPCClientGetBufferSize().
iid REFIID as in DebugORPCClientGetBufferSize().
reserved void * as in DebugORPCClientGetBufferSize().
pUnkProxyObject IUnknown * as in DebugORPCClientGetBufferSize().
pvBuffer void * the debug-data buffer which is to be filled. Is undefine
d (may or may not be NULL) if cbBuffer is zero.
cbBuffer ULONG the size of the data pointed to by pvBuffer.
19.1.4.3 DebugORPCServerNotify
void DebugORPCServerNotify(pMessage, iid, pChannel, pInterface, pUnkObject, pvBu
ffer, cbBuffer)
Called on the server side immediately before calling IRpcStubBuffer::Invoke() to
inform it that there is an incoming request. Will start the debugger in this pr
ocess if need be. See the above overview for further details.
The GUID for this notification is 1084FA00-9674-101A-B07B-00DD01113F11:
GUID __private_to_macro__ = { /* 1084FA00-9674-101A-B07B-00DD01113F11 */
0x1084FA00,
0x9674,
0x101A,
0xB0,
0x7B,
{0x00, 0xDD, 0x01, 0x11, 0x3F, 0x11}
};
On entry, the members of pMessage are set as follows:
Upper word: NDR representation flags as defined by DCE: floating point, endianes
s and character representations.
Lower word: marshaling context flags as defined by the COM channel. The flags ar
e defined in the public wtypes.h file (and in wtypes.idl file). Currently the fo
llowing flags are defined:
typedef
enum tagMSHCTX
{ MSHCTX_LOCAL = 0,
MSHCTX_NOSHAREDMEM = 1,
MSHCTX_DIFFERENTMACHINE = 2,
MSHCTX_INPROC = 3
} MSHCTX;
The flags make it possible to differ the behavior of the routines depending on t
he context for the RPC call. For example when a handle is remoted in-process it
could be sent as a handle (a long), while sending it remotely would mean sending
the data related to the handle.
20.1.9.1 _UserSize
The *_UserSize routine is called when sizing the RPC data buffer before the mars
haling on the client or server side. The routine should work in terms of cumula
tive size. The StartingSize argument is the current buffer offset . The routine
should return the cumulative size that includes the possible padding and then th
e data size. The starting size indicates the buffer offset for the user object a
nd it may or may not be aligned properly. User s routine should account for all pa
dding as necessary. In other words, the routine should return a new offset, afte
r the user object. The sizing routine is not called if the wire size can be comp
uted at the compile time. Note that for most unions, even if there are no pointe
rs, the actual size of the wire representation may be determined only at the run
time.
This routine actually can return an overestimate as long as the marshaling routi
ne does not use more than the sizing routine promised and so the marshaling buff
er is not overwritten then or later (by subsequent objects).
20.1.9.2 _UserMarsahal
The *_UserMarshal routine is called when marshaling the data on the client or se
rver side. The buffer pointer may or may not be aligned upon the entry. The rout
ine should align the buffer pointer appropriately, marshal the data and then ret
urn the new buffer pointer position which is at the first free byte after the mars
haled object. For the complications related to pointees see the next chapter.
Please note that the wire type specification is a contract that determines the a
ctual layout of the data in the buffer. For example, if the conversion is needed
and done by the NDR engine, it follows from the wire type definitions how much
data would be processed in the buffer for the type.
20.1.9.3 _UserUnmarshal
The *_UserUnmarshal routine is called when unmarshaling the data on the client o
r server side. The flags indicate if data conversion is needed (if needed, it ha
s been performed by the NDR engine before the call to the routine). The buffer p
ointer may or may not be aligned upon the entry. The routine should align the bu
ffer as appropriate, unmarshal the data and then return the new buffer pointer p
osition, which is at the first free byte after the unmarshaled object. For the com
plications related to pointees see the next chapter
20.1.9.4 _UserFree
The *_UserFree routine is called when freeing the data on the server side. The o
bject itself doesn t get freed as the engine takes care of it. The user shall free
the pointees of the top level objects.
20.1.10 The library keyword
[attributes] library libname {definitions};
The library keyword indicates that a type library (See Chapter 17) should be gen
erated. Below is an example library section.
[
uuid(3C591B22-1F13-101B-B826-00DD01103DE1), // IID_ISome
object
]
interface ISome : IUnknown
{
HRESULT DoSomething(void);
}
[
uuid(3C591B20-1F13-101B-B826-00DD01103DE1), // LIBID_Lines
helpstring("Lines 1.0 Type Library"),
lcid(0x0409),
version(1.0)
]
library Lines
{
importlib("stdole.tlb");
[
uuid(3C591B21-1F13-101B-B826-00DD01103DE1), // CLSID_Lines
helpstring("Lines Class"),
appobject
]
coclass Lines
{
[default] interface ISome;
interface IDispatch;
}
}
20.2 Mapping from ORPC IDL to DCE RPC IDL.
From the above extensions, and the wire representation definitions, one can conc
lude the following rules for converting ORPC IDL files to DCE IDL files:
Remove the [object] attribute from the interface definition.
Insert [in] handle_t h as the first argument of each method, [in] ORPCTHIS *_orpcth
is as the second, and [out] ORPCTHAT *_orpcthat as the third.
Manually insert declarations for the operations that were inherited, if any. You
may want to make the method names unique, unless the EPV invocation style is al
ways going to be used. One way to do this is to prefix each method with the nam
e of the interface. (Note that the IUnknown methods will never be called, as the
IRemUnknown interface is used instead.)
Replace each occurrence of a type name derived from an interface name, or an [ii
d_is] qualified void* with OBJREF. Remove [iid_is] attributes.
20.2.1 An Example
20.2.1.1 Object RPC Style
[object, uuid(b5483f00-4f6c-101b-a1c7-00aa00389acb)]
interface IFoo: IUnknown
{
HRESULT Bar([in] short i, [in] IBozo* pIB, [out] IWaz** ppIW);
HRESULT Zork([in, ref] UUID* iid, [out, iid_is(iid)] void** ppvoid);
};
20.2.1.2 DCE style
[uuid(b5483f00-4f6c-101b-a1c7-00aa00389acb)]
interface IFoo
{
HRESULT IFoo_QueryInterface([in] handle_t h, [in] ORPCTHIS* _orpcthis, [
out] ORPCTHAT* _orpcthat, [in, ref] UUID* iid, [out] OBJREF** ppOR);
ULONG IFoo_AddRef([in] handle_t, [in] ORPCTHIS* _orpcthis, [out] ORPCTHA
T* _orpcthat);
ULONG IFoo_Release([in] handle_t, [in] ORPCTHIS* _orpcthis, [out] ORPCTH
AT* _orpcthat);
HRESULT IFoo_Bar([in] handle_t h, [in] ORPCTHIS* _orpcthis, [out] ORPCTH
AT* _orpcthat, [in, ref] OBJREF* porIB, [out, ref] OBJREF** pporIW);
HRESULT IFoo_Zork([in]handle_t h, [in] ORPCTHIS* _orpcthis, [out] ORPCTH
AT* _orpcthat, [in, ref] UUID* iid, [out] OBJREF** ppvoid);
};
See Chapter 21 Component Object Model Protocol for information on the ORPCTHIS a
nd ORPCTHAT structures and the IRemUnknown interface.
21. Component Object Model Protocol
The Distributed Component Object Model protocol (DCOM) is an application-level p
rotocol for object-oriented remote procedure calls and is thus also called "Obje
ct RPC" or ORPC. The protocol consists of a set of extensions, layered on the di
stributed computing environment (DCE) RPC specification [CAE RPC], with which fa
miliarity is assumed. Familiarity is also assumed with the COM (Component Object
Model) specification [COM].
Object RPC specifies:
How calls are made on an object
How object references are represented, communicated, and maintained
21.1 Purpose
There is a natural tendency in a networked environment to create entirely new ap
plication-level protocols as each new or seemingly unique combination of client,
user agent, and server requirement arises.
While in many situations the definition of a new protocol is useful and justifia
ble, there are numerous features which have eventually been added to or required
from each new protocol (or which become layered above them) as they evolve and
become used in broader contexts.
A design goal of the DCOM protocol is the inherent support of standard features
required by any distributed application communication protocol. In other words,
to act as a framework to facilitate the construction of task-specific communicat
ion paths between distributed applications.
Data Marshaling
A common occurrence among user agents using the HTTP protocol today is the use o
f complex, task-specific Query URL syntax and HTTP POSTs. Also increasingly comm
on is the POSTing and response with custom MIME types to and from resources whic
h interpret the format and reply in same. While workable, there are drawbacks to
this approach including increased complexity and work to produce and consume ea
ch new (and unique) format in the client and server, lessened ability to build t
ask-specific firewalls for administration and security purposes, and in many cas
es definition of platform-centric formats.
DCOM utilizes the Network Data Representation (NDR) for arbitrary data types sup
ported by DCE RPC.
Security
DCOM leverages the authentication, authorization, and message integrity capabili
ties of DCE RPC. An implementation may support any level of DCE RPC security. An
y connection or call can be made as secure or as insecure as negotiated by the c
lient and the server.
Safe Non-Coordinated Versioning of Interfaces
In DCOM versioning of interfaces is done through identifiers which are universal
ly unique (UUID's). To version a published interface, a new interface is defined
with a different UUID to the updated specification. Multiple parties can simult
aneously introduce "revisions" to interfaces by defining related but distinct in
terfaces without fear of colliding with each other's version numbers and without
fear of breaking each other's down-level or up-level clients.
To date, the bulk of task-specific protocols (such as custom POSTs or MIME types
using HTTP) have little or no concept of versioning at all, and simply "narrow"
the incompatibility window by updating clients (typically pages which are being
downloaded anyway) and servers (CGI scripts or other HTTP server infrastructure
) simultaneously.
21.2 Overall Operation
The Object RPC protocol highly leverages the OSF DCE RPC network protocol (see t
he reference [CAE RPC]). This leverage occurs at both the specification level an
d the implementation level: the bulk of the implementation effort involved in im
plementing the DCOM network protocol is in fact that of implementing the DCE RPC
network protocol on which it is built.
21.2.1 Object Calls
An actual COM network remote procedure call (hereinafter referred to as "an ORPC
") is in fact a true DCE remote procedure call (herein termed "a DCE RPC"), a "R
equest PDU" conforming to the specification for such calls per [CAE RPC].
In an ORPC, the object ID field of the invocation header as specified in [CAE RP
C] contains an "IPID". An IPID is a 128-bit identifier known as an interface poi
nter identifier which represents a particular interface on a particular object i
n a particular server. As it is passed in the object ID fields of a DCE RPC, the
static type of an IPID is in fact a UUID. However, IPIDs are scoped not globall
y but rather only relative to the server process which originally allocated th
em; IPIDs do not necessarily use the standard UUID allocation algorithm, but rat
her may use a machine-specific algorithm which can assist with dispatching.
In an ORPC, the interface ID field of the RPC header specifies the IID, and argu
ments are found in the body, as usual. However, when viewed from the DCE RPC per
spective an additional first argument is always present that is absent in the co
rresponding COM interface specification. This argument is of type ORPCTHIS, whic
h is described in Section 3.7. It is placed first in the body of the Request PDU
, before the actual arguments of the ORPC.
It is specifically legal for an ORPC to attempt a call a method number on a give
n interface which is beyond the number of methods believed by the server to be i
n that interface. Such calls should cause a fault.
Similarly, in a reply to an ORPC (a DCE RPC "Response PDU"), when viewed from th
e DCE RPC perspective, an additional first return value is always present that i
s absent in the corresponding COM interface specification. This argument is of t
ype ORPCTHAT, which is described in Section 3.8. It is placed first in the body
of the Response PDU, before the actual return values of the ORPC.
An ORPCTHAT may also be present in a "Fault PDU." In the Connectionless (CL) Fau
lt PDU, it is placed four bytes after the 32- bit fault code which normally comp
rises the entire body of the PDU, thus achieving eight byte alignment for the OR
PCTHAT; the intervening padding bytes are presently reserved and must be zero. T
he PDU body length is of course set to encompass the entire body of the Fault PD
U, including the ORPCTHAT. In the Connection- Oriented (CO) Fault PDU, the ORPCT
HAT is placed in the standard location allocated for the "stub data." In a Fault
PDU of either form that results from an ORPC, if an ORPCTHAT is not present the
n no other data may be substituted in its here-specified location in the PDU.
21.2.2 OXIDs and Object Exporters
Although an IPID from a logical perspective semantically determines the server,
object and interface to which a particular call should be directed, it does not
by itself indicate the binding information necessary to actually carry out an in
vocation.
The protocol represents this "how-to" communication information in a 64-bit val
ue called an object exporter identifier, otherwise known as an OXID. Conceptuall
y, an OXID can be thought of as an implementation scope for an object, which may
be a whole machine, a given process, a thread within that process, or other mor
e esoteric implementation scope, but the exact definition of such scopes has no
bearing on the protocol itself. Data structures in each Object Exporter keep tra
ck of the IPIDs exported and imported by that Object Exporter.
A given machine at any moment may support several OXIDs; however there is always
a unique OXID Resolver service per machine which coordinates the management o
f all the OXIDs on the machine. The OXID Resolver typically (but not necessaril
y) resides at well-known ports (or endpoints, depending on your terminology -- o
ne per protocol, of course) on the machine. It supports a DCE RPC interface know
n as IOXIDResolver, described in Section 5.2.
An OXID is used to determine the RPC string bindings that allow calls to reach t
heir target IPID. Before making a call, the calling process must translate an OX
ID into a set of bindings that the underlying RPC implementation understands. It
accomplishes this by maintaining a cache of these mappings. When the destinatio
n application receives an object reference, it checks to see if it recognizes th
e OXID. If it does not, then it asks the OXID Resolver which scopes the OXID sp
ecified in the object reference for the translation, and saves the resulting se
t of string bindings in a local table that maps OXIDs to string bindings.
Associated with each OXID (ie each Object Exporter) is COM object termed an "OXI
D object." OXID objects implement (at least) the IRemUnknown interface, a COM i
nterface through which remote management of reference counts and requests for in
terfaces are returned.
21.2.3 Marshaled Interface References
The DCOM protocol extends the Network Data Representation (NDR) standard specifi
ed in [CAE RPC] by defining what can be thought of as a new primitive data type
that can be marshaled: that of an interface reference to an object. This is the
only extension to NDR made by the DCOM protocol.
A marshaled interface reference is described by a type known as an OBJREF, which
is described in detail in Section 3.3. An OBJREF in actuality has several varia
tions:
NULL
This is a reference to no object.
STANDARD
A standard remote reference. Known as a STDOBJREF. A STDOBJREF contains:
An IPID, which uniquely specifies the interface and object.
An object ID (OID), which uniquely specifies the identity of the object on which
the IPID is found (scoped to the object exporter with which the object is assoc
iated).
An OXID, which identifies the scope where the implementation of the object is ac
tive, and can be used to reach the interface pointer.
A reference count, indicating the number of references to this IPID that are con
veyed by this marshaling. This count, though typically a value of one, may in fa
ct be zero, one, or more (see the next section).
Some flags, explained later.
CUSTOM
Contains a class ID (CLSID) and class-specific information.
The Custom format gives an object control over the representation of references
to itself. For example, an immutable object might be passed by value, in which c
ase the class-specific information would contain the object's immutable data.
HANDLER
A sub-case of the custom reference in which the class- specific information is s
tandardized.
For example, an object wishes to be represented in client address spaces by a pr
oxy object that caches state. In this case, the class-specific information is ju
st a standard reference to an interface pointer that the handler (proxy object)
will use to communicate with the original object.
Interface references are always marshaled in little-endian byte order, irrespect
ive of the byte order prevailing in the remainder of the data being marshaled.
21.2.4 Reference Counting
In the DCOM protocol, remote reference counting is conducted per interface (per
IPID).
The actual increment and decrement calls are carried out using (respectively) th
e RemAddRef and RemRelease methods in a COM interface known as IRemUnknown found
on the OXID object associated with each OXID, the IPID of which is returned fr
om the function IOXIDResolver::ResolveOxid (section 5.2.1). In contrast to their
analogues in IUnknown, RemAddRef and RemRelease can in one call increment or de
crement the reference count of many different IPIDs by an arbitrary amount; this
allows for greater network efficiency. In the interests of performance, client
COM implementations typically do not immediately translate each local AddRef and
Release into a remote RemAddRef and RemRelease. Rather, the actual remote relea
se of all interfaces on an object is typically deferred until all local referenc
es to all interfaces on that object have been released. Further, one actual remo
te reference count may be used to service many local reference counts; that is,
the client infrastructure may multiplex zero or more local references to an inte
rface into zero or one remote references on the actual IPID.
To prevent a malicious application from calling RemRelease incorrectly, an appli
cation may request secure references. In that case the application must call Re
mAddRef (and RemRelease later on) securely and must request private references.
Private references are stored by client identity so one client cannot release a
nother client s references. DCOM requires that each client make a call to get his
own secure references, rather then receiving a secure reference from someone who
already has one. This reduces the efficiency of interface marshalling because
the client must make a callback.
21.2.5 Pinging
The above reference counting scheme would be entirely adequate on its own if cli
ents never terminated abnormally, but in fact they do, and the system needs to b
e robust in the face of clients terminating abnormally when they hold remote ref
erences. In a DCE RPC, one typically addresses this issue through the use of con
text handles. Context handles are not used, however, by the DCOM protocol, for r
easons of expense. The basic underlying technology used in virtually all protoco
ls for detecting remote abnormal termination is that of periodic pings. Naive us
e of RPC context handles would result in per object per client process pings bei
ng sent to the server. The DCOM protocol includes a pinging infrastructure to si
gnificantly reduce network traffic by relying on the client OXID Resolver imple
mentation to do local management of client liveness detection, and having the ac
tual pings be sent only on a machine by machine basis.
Pinging is carried out on a per-object (per OID), not a per- interface (per-IPID
) basis. Architecturally, at its server machine, each exported object (each expo
rted OID) has associated with it a pingPeriod time value and a numPingsToTimeOut
count which together (through their product) determine the overall amount of ti
me known as the "ping period" that must elapse without receiving a ping on that
OID before all the remote references to IPIDs associated with that OID can be co
nsidered to have expired. Once expiration has occurred, the interfaces behind th
e IPIDs can, as would be expected, be reclaimed solely on the basis of local kno
wledge, though the timeliness with which this is carried out, if at all, is impl
ementation specific detail of the server. If the server COM infrastructure defer
s such garbage collection in this situation (perhaps because it has local refere
nces keeping the interface pointer alive) and it later hears a ping , then it kn
ows a network partition healed. It can consider the extant remote references to
be reactivated and can continue remote operations.
When interface pointers are conveyed from one client to another, such as being p
assed as either [in] or [out] parameters to a call, the interface pointer is mar
shaled in one client and unmarshaled in the other. In order to successfully unma
rshal the interface, the destination client must obtain at least one reference c
ount on the interface. This is usually accomplished by passing in the marshaled
interface STDOBJREF a cPublicRefs of (at least) one; the destination client then
takes ownership of that many (more) reference counts to the indicated IPID, and
the source client then owns that many fewer reference counts on the IPID. It is
legal, however, for zero reference counts to be passed in the STDOBJREF; here,
the destination client must (if it does not already have access to that IPID and
thus have a non-zero reference count for it) before it successfully unmarshals
the interface reference (concretely, e.g., before CoUnmarshalInterface returns)
call to the object exporter using IRemUnknown::RemAddRef to obtain a reference c
ount for it. If the destination client is in fact the object's server, then spec
ial processing is required by the destination client. The remote reference count
s being passed to it should, in effect, be "taken out of circulation," as what w
here heretofore remote references are being converted into local references. Thu
s, the reference counts present in the STDOBJREF are in fact decremented from th
e remote reference count for the IPID in question.
Some objects have a usage model such that they do not need to be pinged at all;
such objects are indicated by the presence of a flag in a STDOBJREF to an interf
ace on the object. Objects which are not pinged in fact need not be reference co
unted either, though it is legal (but pointless) for a client to reference count
the IPIDs of such objects.
For all other objects, assuming a non-zero ping period, it is the responsibility
of the holder of an interface reference on some object to ensure that pings rea
ch the server frequently enough to prevent expiration of the object. The frequen
cy used by a client depends on the ping period, the reliability of the channel b
etween the client and the server, and the probability of failure (no pings getti
ng through and possible premature garbage-collection) that the client is willing
to tolerate. The ping packet and / or its reply may both request changes to the
ping period. Through this mechanism, network traffic may be reduced in the face
of slow links to busy servers.
21.2.5.1 Delta Pinging
Without any further refinements, ping messages could be quite hefty. If machine
A held 1024 remote object references (OIDs) on machine B, then it would send 16K
byte ping messages. This would be annoying if the set of remote objects was rel
atively stable and the ping messages were the same from ping to ping.
The delta mechanism reduces the size of ping messages. It uses a ping-set interf
ace that allows the pinging of a single set to replace the pinging of multiple O
IDs.
Instead of pinging each OID, the client defines a set. Each ping contains only t
he set id and the list of additions and subtractions to the set. Objects that co
me and go within one ping period are removed from the set without ever having be
en added.
The pinging protocol is carried out using two methods in the (DCE RPC) interface
IOXIDResolver on the OXID Resolver: ComplexPing, and SimplePing. ComplexPing is
used by clients to group the set of OIDs that they must ping into sets known t
o the server. These entire sets of OIDs can then be subsequently pinged with a s
ingle, short, call to SimplePing.
21.2.6 QueryInterface
The IRemUnknown interface on the OXID object, in addition to servicing reference
counting as described above also services QueryInterface calls for remote clien
ts for IPIDs managed by that object exporter. IRemUnknown::RemQueryInterface dif
fers from IUnknown::QueryInterface in much the same way as RemAddRef and RemRele
ase differ from AddRef and Release, in that it is optimized for network access b
y being able to retrieve many interfaces at once.
21.2.7 Causality ID
Each ORPC carries with it a UUID known as the causality id that connects togethe
r the chain of ORPC calls that are causally related. If an outgoing ORPC is made
while servicing an incoming ORPC, the outgoing call is to have the same causali
ty id as the incoming call. If an outgoing ORPC is made while not servicing an i
ncoming ORPC, then a new causality id is allocated for it.
Causality ids may in theory be reused as soon as it is certain that no transitiv
ely outstanding call is still in progress which uses that call. In practice, how
ever, in the face of transitive calls and the possibility of network failures in
the middle of such call chains, it is difficult to know for certain when this o
ccurs. Thus, pragmatically, causality ids are not reusable.
The causality id can be used by servers to understand when blocking or deferring
an incoming call (supported in some COM server programming models) is very high
ly probable to cause a deadlock, and thus should be avoided.
The causality id for maybe, idempotent, and broadcast calls must be set to null
(e.g., all zeros). If a server makes a ORPC call while processing such a call, a
new causality id must be generated as if it were a top level call.
21.3 Data Types and Structures
This following several sections present the technical details of the DCOM protoc
ol.
21.3.1 DCE Packet Headers
Object RPC sits entirely on top of DCE RPC. The following list describes the ele
ments of ORPC that are specified above and beyond DCE RPC.
The object id field of the header must contain the IPID.
The interface id of the RPC header must contain the IID, even though it is not n
eeded given the IPID. This allows ORPC to sit on top of DCE RPC. An unmodified D
CE RPC implementation will correctly dispatch based on IID and IPID. An optimize
d RPC need only dispatch based on IPID.
An IPID uniquely identifies a particular interface on a particular object on a m
achine. The converse is not true; a particular interface on a particular object
may be represented by multiple IPIDs. IPIDs are unique on their OXID. IPIDs may
be reused, however reuse of IPIDs should be avoided.
Datagram, maybe, and idempotent calls are all allowed in ORPC.
Interface pointers may not be passed on maybe or idempotent calls.
Datagram broadcasts are not allowed in ORPC.
Faults are returned in the stub fault field of the DCE RPC fault packet. Any 32
bit value may be returned. Only RPC_E_VERSION_MISMATCH is pre-specified:
DCE RPC cancel is supported.
All interface version numbers must be 0.0.
21.3.2 ORPC Base Definitions
There are several fundamental data types and structures on which the COM network
protocol is built. These types are shown here in standard C header format.
////////////////////////////////////////////////////////////
// Basic Definitions
////////////////////////////////////////////////////////////
typedef unsiged long HRESULT; // 32-bit integer: success/failure
typedef t_uuid UUID; // rename DCE-RPC type
typedef UUID GUID; // Globally Unique IDentifier
typedef unsigned hyper ID; // 64-bit integer
typedef ID OXID; // Object Exporter Identifier
typedef ID OID; // Object Identifer
typedef ID SETID; // Ping Set Identifier
typedef GUID IPID; // Interface Pointer Identifier
typedef GUID* REFIPID;
typedef GUID CID; // Causality Identifier
#define CID_NULL uuid_null; // All zeros
//////////////////////////////////////////////////////////////////
// ORPC Call Packet Format
//////////////////////////////////////////////////////////////////
const unsigned short COM_MAJOR_VERSION = 5;
const unsigned short COM_MINOR_VERSION = 1;
typedef struct tagCOMVERSION {
unsigned short MajorVersion; // Major version number
unsigned short MinorVersion; // Minor version number
} COMVERSION;
const unsigned long ORPCF_NULL = 0; // no additional info
// in packet
const unsigned long ORPCF_LOCAL = 1; // call is local to this
// machine
const unsigned long ORPCF_RESERVED1 = 2; // reserved for local use
const unsigned long ORPCF_RESERVED2 = 4; // reserved for local use
const unsigned long ORPCF_RESERVED3 = 8; // reserved for local use
const unsigned long ORPCF_RESERVED4 = 16; // reserved for local use
// Extension to implicit parameters.
typedef struct tagORPC_EXTENT {
GUID id; // Extension identifier
unsigned long size; // Extension size
byte data[]; // [size_is((size+7)&~7)]
} ORPC_EXTENT;
// Array of extensions.
typedef struct tagORPC_EXTENT_ARRAY {
unsigned long size; // Num extents.
unsigned long reserved; // Must be zero.
ORPC_EXTENT** extent; // [size_is((size+1)&~1), unique]
} ORPC_EXTENT_ARRAY;
// implicit 'this' pointer which is the first [in] parameter on
// every ORPC call.
typedef struct tagORPCTHIS {
COMVERSION version; // COM version number
unsigned long flags; // ORPCF flags for presence of
// other data
unsigned long reserved1; // set to zero
CID cid; // causality id of caller
ORPC_EXTENT_ARRAY* extensions; // [unique] extensions
} ORPCTHIS;
// implicit 'that' pointer which is the first [out] parameter on
// every ORPC call.
typedef struct tagORPCTHAT {
unsigned long flags; // ORPCF flags for presence
// of other data
ORPC_EXTENT_ARRAY *extensions; // [unique] extensions
} ORPCTHAT;
//////////////////////////////////////////////////////////////////
// Marshaled COM Interface Wire Format
//////////////////////////////////////////////////////////////////
typedef enum tagMSHLFLAGS {
MSHLFLAGS_NORMAL = 0,
MSHLFLAGS_TABLESTRONG = 1,
MSHLFLAGS_TABLEWEAK = 2,
} MSHLFLAGS;
// Tower IDs for common protocols
const unsigned short NCADG_IP_UDP = 0x08;
const unsigned short NCACN_IP_TCP = 0x07;
const unsigned short NCADG_IPX = 0x0E;
const unsigned short NCACN_SPX = 0x0C;
const unsigned short NCACN_NB_NB = 0x12;
const unsigned short NCACN_NB_IPX = 0x0D;
const unsigned short NCACN_DNET_NSP = 0x04;
const unsigned short NCALRPC = 0x10;
// This is the return type for arrays of string bindings or protseqs
// used by many ORPC interfaces.
typedef struct tagSTRINGBINDING {
unsigned short wTowerId; // Cannot be zero.
unsigned short aNetworkAddr; // Zero terminated.
} STRINGBINDING;
// this value (invalid in DCE RPC) indicates to use default authz
const unsigned short COM_C_AUTHZ_NONE = 0xffff;
typedef struct tagSECURITYBINDING {
unsigned short wAuthnSvc; // Must not be zero
unsigned short wAuthzSvc; // Must not be zero
unsigned short aPrincName; // NULL terminated
} SECURITYBINDING;
// DUALSTRINGARRAYS are the return type for arrays of network
// addresses, arrays of endpoints and arrays of both used in
// many ORPC interfaces
typedef struct tagDUALSTRINGARRAY {
unsigned short wNumEntries; // # of entries in array
unsigned short wSecurityOffset; // Offset of security info
// The array contains two parts, a set of STRINGBINDINGs
// and a set of SECURITYBINDINGs. Each set is terminated by an
// extra zero. The shortest array contains four zeros.
unsigned short aStringArray[]; // [size_is(wNumEntries)]
} DUALSTRINGARRAY;
// arbitrary value to help ensure validity
const unsigned long OBJREF_SIGNATURE = 0x574f454d;
const unsigned long OBJREF_STANDARD = 0x1;
const unsigned long OBJREF_HANDLER = 0x2;
const unsigned long OBJREF_CUSTOM = 0x4;
// Flag values for a STDOBJREF (standard part of an OBJREF).
// SORF_OXRES1 - SORF_OXRES8 are reserved for the object exporters
// use only, object importers must ignore them and must not enforce
// MBZ.
const unsigned long SORF_NULL = 0x0000; // convenient for init
const unsigned long SORF_OXRES1 = 0x0001; // reserved by exporter
const unsigned long SORF_OXRES2 = 0x0020; // reserved by exporter
const unsigned long SORF_OXRES3 = 0x0040; // reserved by exporter
const unsigned long SORF_OXRES4 = 0x0080; // reserved by exporter
const unsigned long SORF_OXRES5 = 0x0100; // reserved by exporter
const unsigned long SORF_OXRES6 = 0x0200; // reserved by exporter
const unsigned long SORF_OXRES7 = 0x0400; // reserved by exporter
const unsigned long SORF_OXRES8 = 0x0800; // reserved by exporter
const unsigned long SORF_NOPING = 0x1000; // Pinging not required
typedef struct tagSTDOBJREF {
unsigned long flags; // SORF_ flags (see above)
unsigned long cPublicRefs; // count of references passed
OXID oxid; // oxid of server with this oid
OID oid; // oid of object with this ipid
IPID ipid; // ipid of Interface
} STDOBJREF;
// although this structure is conformant, it is always marshaled
// in little-endian byte-order.
typedef struct tagOBJREF {
unsigned long signature; // must be OBJREF_SIGNATURE
unsigned long flags; // OBJREF flags (see above)
GUID iid; // interface identifier
union { // [switch_is(flags), switch_type(unsigned long)]
struct { // [case(OBJREF_STANDARD)]
STDOBJREF std; // standard objref
DUALSTRINGARRAY saResAddr; // resolver address
} u_standard;
struct { // [case(OBJREF_HANDLER)]
STDOBJREF std; // standard objref
CLSID clsid; // Clsid of handler code
DUALSTRINGARRAY saResAddr; // resolver address
} u_handler;
struct { // [case(OBJREF_CUSTOM)]
CLSID clsid; // Clsid of unmarshaling code
unsigned long cbExtension; // size of extension data
unsigned long size; // size of data that follows
byte *pData; // extension +
// class specific data
// [size_is(size), ref]
} u_custom;
} u_objref;
} OBJREF;
// wire representation of a marshalled interface pointer,
// always the little-endian form of an OBJREF
typedef struct tagMInterfacePointer {
ULONG ulCntData; // size of data
byte abData[]; // [size_is(ulCntData)] data
} MInterfacePointer, *PMInterfacePointer;
// OXID Resolver information associated with each OXID.
typedef struct tagOXID_INFO {
DWORD dwTid; // thread id of object exporter
DWORD dwPid; // process id of obj exporter
IPID ipidRemUnknown; // IRemUnknown IPID for object exporter
DWORD dwAuthnHint;
DUALSTRINGARRAY *psa; // protocol and security info
} OXID_INFO;
//////////////////////////////////////////////////////////////////
21.3.3 OBJREF
An OBJREF is the data type used to represent an actual marshaled object referenc
e. An OBJREF can either be empty or assume one of three variations, depending on
the degree to which the object being marshaled uses the hook architecture (IMar
shal, etc.) in the marshaling infrastructure. The OBJREF structure is a union co
nsisting of a switch flag followed by the appropriate data.
21.3.3.1 OBJREF_STANDARD
Contains one interface of an object marshaled in standard form. Contains a stand
ard reference, along with a set of protocol sequences and network addresses that
can be used to bind to an OXID resolver that is able to resolve the OXID in the
STDOBJREF. This is useful when marshaling a proxy to give to another machine (a
.k.a. the "middleman" case). The marshaling machine specifies the saResAddr for
the OXID Resolver on the server machine, eliminating the need for the unmarshale
r to call the marshaler (middleman) back to get this information. Further, the
marshaler does not need to keep the OXID in its cache beyond the lifetime of its
own references in order to satisfy requests from parties that it just gave the
OBJREF to.
Member Semantic
flags Flag values taken from the enumeration SORFFLAGS. These are described in
Section 3.5.
cPublicRefs The number of reference counts on ipid that are being transferre
d in this marshaling.
oxid The OXID of the server that owns this OID.
oid The OID of the object to which ipid corresponds.
ipid The IPID of the interface being marshaled.
21.3.5 SORFLAGS
The various SORFLAGS values have the following meanings. The SORF_OXRESxxx bit f
lags are reserved for the object exporter's use only, and must be ignored by obj
ect importers. They need not be passed through when marshaling an interface prox
y.
Flag Meaning
ORPCF_NULL (Not a real flag. Merely a defined constant indicating the absen
ce of any flag values.)
ORPCF_LOCAL The destination of this call is on the same machine on which it
originates. This value is never to be specified in calls which are not in fact l
ocal.
ORPCF_RESERVED1 If ORPCF_LOCAL is set, then reserved for local use; othe
rwise, reserved for future use.
ORPCF_RESERVED2 If ORPCF_LOCAL is set, then reserved for local use; othe
rwise, reserved for future use.
ORPCF_RESERVED3 If ORPCF_LOCAL is set, then reserved for local use; othe
rwise, reserved for future use.
ORPCF_RESERVED4 If ORPCF_LOCAL is set, then reserved for local use; othe
rwise, reserved for future use.
Implementations may use the local and reserved flags to indicate any extra infor
mation needed for local calls. Note that if the ORPCF_LOCAL bit is not set and a
ny of the other bits are set then the receiver should return a fault.
21.3.7 ORPCTHIS
In every Request PDU that is an ORPC, the body (CL case) or the stub data (CO ca
se) which normally contains the marshaled arguments in fact begins with an insta
nce of the ORPCTHIS structure. The marshaled arguments of the COM interface invo
cation follow the ORPCTHIS; thus, viewed at the DCE RPC perspective, the call ha
s an additional first argument. The ORPCTHIS is padded with zero-bytes if necess
ary to achieve an overall size that is a multiple of eight bytes; thus, the rema
ining arguments are as a whole eight byte aligned.
As in regular calls, the causality id must be propagated. If A calls ComputePi o
n B, B calls Release on C (which gets converted to RemRelease), and C calls Add
on A, A will see the same causality id that it called B with.
pSetId SETID The SETID being manipulated. SequenceNum unsigned short The sequ
ence number allows the object exporter to detect duplicate packets. Since the ca
ll is idempotent, it is possible for duplicates to get executed and for calls to
arrive out of order when one ping is delayed.
cAddToSet unsigned short The size of the array AddToSet.
cDelFromSet unsigned short The size of the array DelFromSet.
AddToSet OID[] The list of OIDs which are to be added to this set. Addi
ng an OID to a set in which it already exists is permitted; such an action, as w
ould be expected, is considered to ping the OID.
DelFromSet OID[] The list of OIDs which are to be removed from this set.
Removal counts as a ping. An OID removed from a set will expire after the number
of ping periods has expired without any pings (not the number of ping periods -
1). If an id is added and removed from a set in the same ComplexPing, the id is
considered to have been deleted.
PPingBackoffFactor unsigned short* Acts as a hint (only) from the s
erver to the client in order to reduce ping traffic. Clients are requested to no
t ping more often than (1<<*pPingBackoffFactor)* (BasePingInterval=120) seconds,
and the number of pings until timeout remains unchanged at the default of 3. Cl
ients may choose to assume that this parameter is always zero.
// Array of extensions.
typedef struct
{
unsigned long rounded_size; // Actual number of extents
unsigned long size; // Number of extents
unsigned long unique_flag[]; // Flags to indicate presense of ORPC_EXTENTs
} ORPC_EXTENT_ARRAY;
typedef struct
{
unsigned long flags; // INFO flags for presence of other data
unsigned long unique; // tag to indicate presence of extensions
} ORPCTHAT_WITH_NOEXTENSIONS;
samDesired
Specifies an access mask that specifies the desired security access for the new
key. This parameter can be a combination of the following values:
Value Meaning
KEY_ALL_ACCESS Combination of KEY_QUERY_VALUE, KEY_ENUMERATE_SUB_KEYS, KEY_NOTI
FY, KEY_CREATE_SUB_KEY, KEY_CREATE_LINK, and KEY_SET_VALUE access.
KEY_CREATE_LINK Permission to create a symbolic link.
KEY_CREATE_SUB_KEY Permission to create subkeys.
KEY_ENUMERATE_SUB_KEYS Permission to enumerate subkeys.
KEY_EXECUTE Permission for read access.
KEY_NOTIFY Permission for change notification.
KEY_QUERY_VALUE Permission to query subkey data.
KEY_READ Combination of KEY_QUERY_VALUE, KEY_ENUMERATE_SUB_KEYS, and KEY_
NOTIFY access.
KEY_SET_VALUE Permission to set subkey data.
KEY_WRITE Combination of KEY_SET_VALUE and KEY_CREATE_SUB_KEY access.
lpSecurityAttributes
Pointer to a SECURITY_ATTRIBUTES structure that determines whether the returned
handle can be inherited by child processes. If lpSecurityAttributes is NULL, the
handle cannot be inherited.
phkResult
Points to a variable that receives the handle of the opened or created key.
lpdwDisposition
Points to a variable that receives one of the following disposition values:
Value Meaning
REG_CREATED_NEW_KEY The key did not exist and was created.
REG_OPENED_EXISTING_KEY The key existed and was simply opened without being chan
ged.
Return Values
If the function succeeds, the return value is ERROR_SUCCESS.
If the function fails, the return value is a nonzero error code defined in WINER
ROR.H. You can use the FormatMessage function with the FORMAT_MESSAGE_FROM_SYSTE
M flag to get a generic description of the error.
Remarks
The key that the RegCreateKeyEx function creates has no values. An application c
an use the RegSetValue or RegSetValueEx function to set key values.
The key identified by the hKey parameter must have been opened with KEY_CREATE_S
UB_KEY access. To open the key, use the RegCreateKeyEx or RegOpenKeyEx function.
An application cannot create a key under HKEY_USERS or HKEY_LOCAL_MACHINE.
An application can use RegCreateKeyEx to temporarily lock a portion of the regis
try. When the locking process creates a new key, it receives the disposition val
ue REG_CREATED_NEW_KEY, indicating that it owns the lock. Another process attempti
ng to create the same key receives the disposition value REG_OPENED_EXISTING_KEY
, indicating that another process already owns the lock.
See Also
RegCloseKey, RegDeleteKey, RegOpenKeyEx, RegSaveKey, SECURITY_ATTRIBUTES
23.12 RegDeleteKey
writer TODO note: need to tweak this page s use of key to distinguish between the sub
key that s being deleted and the parent key. v-alans, 2/15/95: Something like this
for the opening paragraph: 4/11/95- - this is Gary- - -brad s update doc requires
the following separation for Win95. The RegDeleteKey function deletes a named s
ubkey from the specified registry key. The subkey to be deleted cannot have any
subkeys.
LONG RegDeleteKey(
HKEY hKey, // handle of open key
LPCTSTR lpSubKey // address of name of subkey to delete
);
Parameters
hKey
Identifies a currently open key or one of the following predefined reserved hand
le values:
HKEY_CLASSES_ROOT
HKEY_CURRENT_CONFIG
HKEY_CURRENT_USER
HKEY_LOCAL_MACHINE
HKEY_USERS
The key specified by the lpSubKey parameter must be a subkey of the key identifi
ed by hKey.
lpSubKey
Points to a null-terminated string specifying the name of the key to delete. Thi
s parameter cannot be NULL.
Return Values
If the function succeeds, the return value is ERROR_SUCCESS.
If the function fails, the return value is a nonzero error code defined in WINER
ROR.H. You can use the FormatMessage function with the FORMAT_MESSAGE_FROM_SYSTE
M flag to get a generic description of the error.
Remarks
If the function succeeds, RegDeleteKey removes the specified key from the regist
ry. The entire key, including all of its values, is removed.
To open the key, use the RegCreateKeyEx or RegOpenKeyEx function.
See Also
RegCloseKey, RegCreateKeyEx, RegOpenKeyEx
23.13 RegDeleteValue
The RegDeleteValue function removes a named value from the specified registry ke
y.
LONG RegDeleteValue(
HKEY hKey, // handle of key
LPCTSTR lpValueName // address of value name
);
Parameters
hKey
Identifies a currently open key or any of the following predefined reserved hand
le values:
HKEY_CLASSES_ROOT
HKEY_CURRENT_CONFIG
HKEY_CURRENT_USER
HKEY_LOCAL_MACHINE
HKEY_USERS
lpValueName
Points to a null-terminated string that names the value to remove. If this param
eter is NULL or points to an empty string, the value set by the RegSetValue func
tion is removed.
Return Values
If the function succeeds, the return value is ERROR_SUCCESS.
If the function fails, the return value is a nonzero error code defined in WINER
ROR.H. You can use the FormatMessage function with the FORMAT_MESSAGE_FROM_SYSTE
M flag to get a generic description of the error.
Remarks
The key identified by the hKey parameter must have been opened with KEY_SET_VALU
E access (KEY_WRITE access includes KEY_SET_VALUE access).
See Also
RegSetValueEx
23.14 RegEnumKeyEx
The RegEnumKeyEx function enumerates subkeys of the specified open registry key.
The function retrieves information about one subkey each time it is called. Unl
ike the RegEnumKey function, RegEnumKeyEx retrieves the class name of the subkey
and the time it was last modified.
LONG RegEnumKeyEx(
HKEY hKey, // handle of key to enumerate
DWORD dwIndex, // index of subkey to enumerate
LPTSTR lpName, // address of buffer for subkey name
LPDWORD lpcbName, // address for size of subkey buffer
LPDWORD lpReserved, // reserved
LPTSTR lpClass, // address of buffer for class string
LPDWORD lpcbClass, // address for size of class buffer
PFILETIME lpftLastWriteTime // address for time key last written to
);
Parameters
hKey
Identifies a currently open key or one of the following predefined reserved hand
le values:
HKEY_CLASSES_ROOT
HKEY_CURRENT_CONFIG
HKEY_CURRENT_USER
HKEY_LOCAL_MACHINE
HKEY_USERS
The enumerated keys are subkeys of the key identified by hKey.
dwIndex
Specifies the index of the subkey to retrieve. This parameter should be zero for
the first call to the RegEnumKeyEx function and then incremented for subsequent
calls.
Because subkeys are not ordered, any new subkey will have an arbitrary index. Th
is means that the function may return subkeys in any order.
lpName
Points to a buffer that receives the name of the subkey, including the terminati
ng null character. The function copies only the name of the subkey, not the full
key hierarchy, to the buffer.
lpcbName
Points to a variable that specifies the size, in characters, of the buffer speci
fied by the lpName parameter. This size should include the terminating null char
acter. When the function returns, the variable pointed to by lpcbName contains t
he number of characters stored in the buffer. The count returned does not includ
e the terminating null character.
lpReserved
Reserved; must be NULL.
lpClass
Points to a buffer that contains the class of the enumerated subkey when the fun
ction returns. This parameter can be NULL if the class is not required.
lpcbClass
Points to a variable that specifies the size, in characters, of the buffer speci
fied by the lpClass parameter. The size should include the terminating null char
acter. When the function returns, lpcbClass contains the number of characters st
ored in the buffer. The count returned does not include the terminating null cha
racter. This parameter can be NULL only if lpClass is NULL.
lpftLastWriteTime
Points to a variable that receives the time the enumerated subkey was last writt
en to.
Return Values
If the function succeeds, the return value is ERROR_SUCCESS.
If the function fails, the return value is a nonzero error code defined in WINER
ROR.H. You can use the FormatMessage function with the FORMAT_MESSAGE_FROM_SYSTE
M flag to get a generic description of the error.
Remarks
To enumerate subkeys, an application should initially call the RegEnumKeyEx func
tion with the dwIndex parameter set to zero. The application should then increme
nt the dwIndex parameter and call RegEnumKeyEx until there are no more subkeys (
until the function returns ERROR_NO_MORE_ITEMS).
The application can also set dwIndex to the index of the last subkey on the firs
t call to the function and decrement the index until the subkey with the index 0
is enumerated. To retrieve the index of the last subkey, use the RegQueryInfoKe
y function.
While an application is using the RegEnumKeyEx function, it should not make call
s to any registration functions that might change the key being enumerated.
The key identified by hKey must have been opened with KEY_ENUMERATE_SUB_KEYS acc
ess (KEY_READ includes KEY_ENUMERATE_SUB_KEYS). Use the RegCreateKeyEx or RegOpe
nKeyEx function to open the key.
See Also
RegCreateKeyEx, RegDeleteKey, RegOpenKeyEx, RegQueryInfoKey
23.15 RegEnumValue
The RegEnumValue function enumerates the values for the specified open registry
key. The function copies one indexed value name and data block for the key each
time it is called.
LONG RegEnumValue(
HKEY hKey, // handle of key to query
DWORD dwIndex, // index of value to query
LPTSTR lpValueName, // address of buffer for value string
LPDWORD lpcbValueName, // address for size of value buffer
LPDWORD lpReserved, // reserved
LPDWORD lpType, // address of buffer for type code
LPBYTE lpData, // address of buffer for value data
LPDWORD lpcbData // address for size of data buffer
);
Parameters
hKey
Identifies a currently open key or one of the following predefined reserved hand
le values:
HKEY_CLASSES_ROOT
HKEY_CURRENT_CONFIG
HKEY_CURRENT_USER
HKEY_LOCAL_MACHINE
HKEY_USERS
The enumerated values are associated with the key identified by hKey.
dwIndex
Specifies the index of the value to retrieve. This parameter should be zero for
the first call to the RegEnumValue function and then be incremented for subseque
nt calls.
Because values are not ordered, any new value will have an arbitrary index. This
means that the function may return values in any order.
lpValueName
Points to a buffer that receives the name of the value, including the terminatin
g null character.
lpcbValueName
Points to a variable that specifies the size, in characters, of the buffer point
ed to by the lpValueName parameter. This size should include the terminating nul
l character. When the function returns, the variable pointed to by lpcbValueName
contains the number of characters stored in the buffer. The count returned does
not include the terminating null character.
lpReserved
Reserved; must be NULL.
lpType
Points to a variable that receives the type code for the value entry. The type c
ode can be one of the following values:
Value Meaning
REG_BINARY Binary data in any form.
REG_DWORD A 32-bit number.
REG_DWORD_LITTLE_ENDIAN A 32-bit number in little-endian format (same as REG_DWO
RD). In little-endian format, the most significant byte of a word is the high-or
der byte. This is the most common format for computers running
REG_DWORD_BIG_ENDIAN A 32-bit number in big-endian format. In big-endian form
at, the most significant byte of a word is the low-order byte.
REG_EXPAND_SZ A null-terminated string that contains unexpanded references to
environment variables (for example, %PATH% ). It will be a Unicode or ANSI string d
epending on whether you use the Unicode or ANSI functions.
REG_LINK A Unicode symbolic link.
REG_MULTI_SZ An array of null-terminated strings, terminated by two null char
acters.
REG_NONE No defined value type.
REG_RESOURCE_LIST A device-driver resource list.
REG_SZ A null-terminated string. It will be a Unicode or ANSI string, depending
on whether you use the Unicode or ANSI functions.
The lpType parameter can be NULL if the type code is not required.
lpData
Points to a buffer that receives the data for the value entry. This parameter ca
n be NULL if the data is not required.
lpcbData
Points to a variable that specifies the size, in bytes, of the buffer pointed to
by the lpData parameter. When the function returns, the variable pointed to by
the lpcbData parameter contains the number of bytes stored in the buffer. This p
arameter can be NULL, only if lpData is NULL.
Return Values
If the function succeeds, the return value is ERROR_SUCCESS.
If the function fails, the return value is a nonzero error code defined in WINER
ROR.H. You can use the FormatMessage function with the FORMAT_MESSAGE_FROM_SYSTE
M flag to get a generic description of the error.
Remarks
To enumerate values, an application should initially call the RegEnumValue funct
ion with the dwIndex parameter set to zero. The application should then incremen
t dwIndex and call the RegEnumValue function until there are no more values (unt
il the function returns ERROR_NO_MORE_ITEMS).
The application can also set dwIndex to the index of the last value on the first
call to the function and decrement the index until the value with index 0 is en
umerated. To retrieve the index of the last value, use the RegQueryInfoKey funct
ion.
While using RegEnumValue, an application should not call any registration functi
ons that might change the key being queried.
The key identified by the hKey parameter must have been opened with KEY_QUERY_VA
LUE access. To open the key, use the RegCreateKeyEx or RegOpenKeyEx function.
To determine the maximum size of the name and data buffers, use the RegQueryInfo
Key function.
See Also
RegCreateKeyEx, RegEnumKeyEx, RegOpenKeyEx, RegQueryInfoKey
23.16 RegFlushKey
The RegFlushKey function writes all the attributes of the specified open key int
o the registry.
LONG RegFlushKey(
HKEY hKey // handle of key to write
);
Parameters
hKey
Identifies a currently open key or one of the following predefined reserved hand
le values:
HKEY_CLASSES_ROOT
HKEY_CURRENT_CONFIG
HKEY_CURRENT_USER
HKEY_LOCAL_MACHINE
HKEY_USERS
Return Values
If the function succeeds, the return value is ERROR_SUCCESS.
If the function fails, the return value is a nonzero error code defined in WINER
ROR.H. You can use the FormatMessage function with the FORMAT_MESSAGE_FROM_SYSTE
M flag to get a generic description of the error.
Remarks
It is not necessary to call RegFlushKey to change a key. Registry changes are fl
ushed to disk by the registry using its lazy flusher. Registry changes are also
flushed to disk at system shutdown.
Unlike RegCloseKey, the RegFlushKey function returns only when all the data has
been written to the registry.
The RegFlushKey function may also write out parts of or all of the other keys. C
alling this function excessively can have a negative effect on an application s pe
rformance.
An application should only call RegFlushKey if it requires absolute certainty th
at registry changes are on disk. In general, RegFlushKey rarely, if ever, need b
e used.
See Also
RegCloseKey, RegDeleteKey
23.17 RegGetKeySecurity
The RegGetKeySecurity function retrieves a copy of the security descriptor prote
cting the specified open registry key.
LONG RegGetKeySecurity(
HKEY hKey, // open handle of key to set
SECURITY_INFORMATION SecurityInformation, // descriptor contents
PSECURITY_DESCRIPTOR pSecurityDescriptor, // address of descriptor for key
LPDWORD lpcbSecurityDescriptor // address of size of buffer and descrip
tor
);
Parameters
hKey
Identifies an open key for which to retrieve the security descriptor.
SecurityInformation
Specifies a SECURITY_INFORMATION structure that indicates the requested security
information.
The SECURITY_INFORMATION structure has the following form:
typedef DWORD SECURITY_INFORMATION;
For a full description of this structure, see the Microsoft Win32 Programmer's R
eference, Volume 5.
pSecurityDescriptor
Points to a buffer that receives a copy of the requested security descriptor.
lpcbSecurityDescriptor
Points to a variable that specifies the size, in bytes, of the buffer pointed to
by the pSecurityDescriptor parameter. When the function returns, the variable c
ontains the number of bytes written to the buffer.
Return Values
If the function succeeds, the return value is ERROR_SUCCESS.
If the function fails, the return value is a nonzero error code defined in WINER
ROR.H. You can use the FormatMessage function with the FORMAT_MESSAGE_FROM_SYSTE
M flag to get a generic description of the error.
Remarks
If the buffer specified by the pSecurityDescriptor parameter is too small, the f
unction returns ERROR_INSUFFICIENT_BUFFER and the lpcbSecurityDescriptor paramet
er contains the number of bytes required for the requested security descriptor.
To read the security descriptor for the specified key, the calling process must
have been granted READ_CONTROL access when the key was opened, or it must be the
owner of the key. (READ_CONTROL access is granted by the KEY_READ, KEY_WRITE, K
EY_EXECUTE, and KEY_ALL_ACCESS access rights.) In addition, the caller must have
the SE_SECURITY_NAME privilege to read the system access-control list (SACL).
See Also
RegDeleteKey, RegOpenKeyEx, RegSetKeySecurity, SECURITY_INFORMATION
23.18 RegLoadKey
The RegLoadKey function creates a subkey under HKEY_USER or HKEY_LOCAL_MACHINE a
nd stores registration information from a specified file into that subkey. This
registration information is in the form of a hive. A hive is a discrete body of
keys, subkeys, and values that is rooted at the top of the registry hierarchy. A
hive is backed by a single file and .LOG file.
LONG RegLoadKey(
HKEY hKey, // handle of open key
LPCTSTR lpSubKey, // address of name of subkey
LPCTSTR lpFile // address of filename for registry information
);
Parameters
hKey
Specifies the key where the subkey will be created. This can be a predefined res
erved handle value, or a handle returned by a call to RegConnectRegistry. The pr
edefined reserved handle values are:
HKEY_LOCAL_MACHINE
HKEY_USERS
This function always loads information at the top of the registry hierarchy. The
HKEY_CLASSES_ROOT and HKEY_CURRENT_USER handle values cannot be specified for t
his parameter, because they represent subsets of the HKEY_LOCAL_MACHINE and HKEY
_USERS handle values, respectively.
lpSubKey
Points to a null-terminated string that specifies the name of the key to be crea
ted under hKey. This subkey is where the registration information from the file
will be loaded.
lpFile
Points to a null-terminated string containing the name of a file that has regist
ration information. This file must have been created with the RegSaveKey functio
n. Under the file allocation table (FAT) file system, the filename may not have
an extension.
Return Values
If the function succeeds, the return value is ERROR_SUCCESS.
If the function fails, the return value is a nonzero error code defined in WINER
ROR.H. You can use the FormatMessage function with the FORMAT_MESSAGE_FROM_SYSTE
M flag to get a generic description of the error.
Remarks
If hKey is a handle returned by RegConnectRegistry, then the path specified in l
pFile is relative to the remote computer.
See Also
RegConnectRegistry, RegDeleteKey, RegReplaceKey, RegRestoreKey, RegSaveKey, RegU
nloadKey
23.19 RegNotifyChangeKeyValue
The RegNotifyChangeKeyValue function notifies the caller about changes to the at
tributes or contents of a specified registry key. Note that the function does no
t notify the caller if the specified key is deleted.
LONG RegNotifyChangeKeyValue(
HKEY hKey, // handle of key to watch
BOOL bWatchSubtree, // flag for subkey notification
DWORD dwNotifyFilter, // changes to be reported
HANDLE hEvent, // handle of signaled event
BOOL fAsynchronous // flag for asynchronous reporting
);
Parameters
hKey
Identifies a currently open key or any of the following predefined reserved hand
le values:
HKEY_CLASSES_ROOT
HKEY_CURRENT_CONFIG
HKEY_CURRENT_USER
HKEY_LOCAL_MACHINE
HKEY_USERS
bWatchSubtree
Specifies a flag that indicates whether to report changes in the specified key a
nd all of its subkeys or only in the specified key. If this parameter is TRUE, t
he function reports changes in the key and its subkeys. If the parameter is FALS
E, the function reports changes only in the key.
dwNotifyFilter
Specifies a set of flags that control which changes should be reported. This par
ameter can be a combination of the following values:
Value Meaning
REG_NOTIFY_CHANGE_NAME Notify the caller if a subkey is added or deleted.
REG_NOTIFY_CHANGE_ATTRIBUTES Notify the caller of changes to the attributes o
f the key, such as the security descriptor information.
REG_NOTIFY_CHANGE_LAST_SET Notify the caller of changes to a value of the k
ey. This can include adding or deleting a value, or changing an existing value.
REG_NOTIFY_CHANGE_SECURITY Notify the caller of changes to the security des
criptor of the key.
hEvent
Identifies an event. If the fAsynchronous parameter is TRUE, the function return
s immediately and changes are reported by signaling this event. If fAsynchronous
is FALSE, hEvent is ignored.
fAsynchronous
Specifies a flag that indicates how the function reports changes. If this parame
ter is TRUE, the function returns immediately and reports changes by signaling t
he specified event. When this parameter is FALSE, the function does not return u
ntil a change has occurred.
If hEvent does not specify a valid event, the fAsynchronous parameter cannot be
TRUE.
Return Values
If the function succeeds, the return value is ERROR_SUCCESS.
If the function fails, the return value is a nonzero error code defined in WINER
ROR.H. You can use the FormatMessage function with the FORMAT_MESSAGE_FROM_SYSTE
M flag to get a generic description of the error.
Remarks
If the key identified by the hKey parameter is closed, the event is signaled. Th
is means that an application should not depend on the key being open after retur
ning from a wait operation on the event.
RegNotifyChangeKeyValue does not work with remote handles. If RegNotifyChangeKey
Value is called with an hKey value that is a remote handle, it returns ERROR_INV
ALID_HANDLE.
See Also
RegDeleteKey, RegEnumKeyEx, RegEnumValue, RegQueryInfoKey, RegQueryValueEx
23.20 RegOpenKeyEx
The RegOpenKeyEx function opens the specified key.
LONG RegOpenKeyEx(
HKEY hKey, // handle of open key
LPCTSTR lpSubKey, // address of name of subkey to open
DWORD ulOptions, // reserved
REGSAM samDesired, // security access mask
PHKEY phkResult // address of handle of open key
);
Parameters
hKey
Identifies a currently open key or any of the following predefined reserved hand
le values:
HKEY_CLASSES_ROOT
HKEY_CURRENT_CONFIG
HKEY_CURRENT_USER
HKEY_LOCAL_MACHINE
HKEY_USERS
lpSubKey
Points to a null-terminated string containing the name of the subkey to open. If
this parameter is NULL or a pointer to an empty string, the function will open
a new handle of the key identified by the hKey parameter. In this case, the func
tion will not close the handles previously opened.
ulOptions
Reserved; must be zero.
samDesired
Specifies an access mask that describes the desired security access for the new
key. This parameter can be a combination of the following values:
Value Meaning
KEY_ALL_ACCESS Combination of KEY_QUERY_VALUE, KEY_ENUMERATE_SUB_KEYS, KEY_NOTI
FY, KEY_CREATE_SUB_KEY, KEY_CREATE_LINK, and KEY_SET_VALUE access.
KEY_CREATE_LINK Permission to create a symbolic link.
KEY_CREATE_SUB_KEY Permission to create subkeys.
KEY_ENUMERATE_SUB_KEYS Permission to enumerate subkeys.
KEY_EXECUTE Permission for read access.
KEY_NOTIFY Permission for change notification.
KEY_QUERY_VALUE Permission to query subkey data.
KEY_READ Combination of KEY_QUERY_VALUE, KEY_ENUMERATE_SUB_KEYS, and KEY_
NOTIFY access.
KEY_SET_VALUE Permission to set subkey data.
KEY_WRITE Combination of KEY_SET_VALUE and KEY_CREATE_SUB_KEY access.
phkResult
Points to a variable that receives the handle of the opened key.
Return Values
If the function succeeds, the return value is ERROR_SUCCESS.
If the function fails, the return value is a nonzero error code defined in WINER
ROR.H. You can use the FormatMessage function with the FORMAT_MESSAGE_FROM_SYSTE
M flag to get a generic description of the error.
Remarks
Unlike the RegCreateKeyEx function, the RegOpenKeyEx function does not create th
e specified key if the key does not exist in the registry.
See Also
RegCloseKey, RegCreateKeyEx, RegDeleteKey,
23.21 RegQueryInfoKey
The RegQueryInfoKey function retrieves information about a specified registry ke
y.
LONG RegQueryInfoKey (
HKEY hKey, // handle of key to query
LPTSTR lpClass, // address of buffer for class string
LPDWORD lpcbClass, // address of size of class string buffer
LPDWORD lpReserved, // reserved
LPDWORD lpcSubKeys, // address of buffer for number of subkeys
LPDWORD lpcbMaxSubKeyLen, // address of buffer for longest subkey name len
gth
LPDWORD lpcbMaxClassLen, // address of buffer for longest class string le
ngth
LPDWORD lpcValues, // address of buffer for number of value entries
LPDWORD lpcbMaxValueNameLen, // address of buffer for longest value n
ame length
LPDWORD lpcbMaxValueLen, // address of buffer for longest value data leng
th
LPDWORD lpcbSecurityDescriptor, // address of buffer for security descri
ptor length
PFILETIME lpftLastWriteTime // address of buffer for last write time
);
Parameters
hKey
Identifies a currently open key or any of the following predefined reserved hand
le values:
HKEY_CLASSES_ROOT
HKEY_CURRENT_CONFIG
HKEY_CURRENT_USER
HKEY_LOCAL_MACHINE
HKEY_USERS
lpClass
Points to a buffer that receives the key s class name. This parameter can be NULL.
lpcbClass
Points to a variable that specifies the size, in characters, of the buffer point
ed to by the lpClass parameter. This size should include the terminating null ch
aracter. When the function returns, this variable contains the length of the cla
ss string stored in the buffer. The count returned does not include the terminat
ing null character. If the buffer is not big enough, the function returns ERROR_
MORE_DATA, and the variable contains the size of the string, in characters, with
out counting the null character.
If lpClass is NULL, lpcbClass can be NULL.
lpReserved
Reserved; must be NULL.
lpcSubKeys
Points to a variable that receives the number of subkeys contained by the specif
ied key. This parameter can be NULL.
lpcbMaxSubKeyLen
Points to a variable that receives the length, in characters, of the key s subkey
with the longest name. The count returned does not include the terminating null
character. This parameter can be NULL.
lpcbMaxClassLen
Points to a variable that receives the length, in characters, of the longest str
ing specifying a subkey class. The count returned does not include the terminati
ng null character. This parameter can be NULL.
lpcValues
Points to a variable that receives the number of values associated with the key.
This parameter can be NULL.
lpcbMaxValueNameLen
Points to a variable that receives the length, in characters, of the key s longest
value name. The count returned does not include the terminating null character.
This parameter can be NULL.
lpcbMaxValueLen
Points to a variable that receives the length, in bytes, of the longest data com
ponent among the key s values. This parameter can be NULL.
lpcbSecurityDescriptor
Points to a variable that receives the length, in bytes, of the key s security des
criptor. This parameter can be NULL.
lpftLastWriteTime
Pointer to a FILETIME structure. This parameter can be NULL.
Return Values
If the function succeeds, the return value is ERROR_SUCCESS.
If the function fails, the return value is a nonzero error code defined in WINER
ROR.H. You can use the FormatMessage function with the FORMAT_MESSAGE_FROM_SYSTE
M flag to get a generic description of the error.
Remarks
The key identified by the hKey parameter must have been opened with KEY_QUERY_VA
LUE access (KEY_READ access includes KEY_QUERY_VALUE access).
See Also
FILETIME, RegDeleteKey, RegEnumKeyEx, RegEnumValue, RegQueryValueEx
23.22 RegQueryMultipleValues
The RegQueryMultipleValues function retrieves the type and data for a list of va
lue names associated with an open registry key.
LONG RegQueryMultipleValues(
HKEY hKey, // handle of key to query
PVALENT val_list, // address of array of value entry structures
DWORD num_vals, // size of array of value entry structures
LPTSTR lpValueBuf, // address of buffer for value information
LPDWORD ldwTotsize // address of size of value buffer
);
Parameters
hKey
Identifies a currently open key or any of the pre-defined reserved handle values
:
HKEY_CLASSES_ROOT
HKEY_CURRENT_CONFIG
HKEY_CURRENT_USER
HKEY_LOCAL_MACHINE
HKEY_USERS
val_list
Address of an array of VALENT structures that describe one or more value entries
. On input, the ve_valuename member of each structure must contain a pointer to
the name of a value to retrieve. The function fails if any of the specified valu
es do not exist in the specified key.
If the function succeeds, each element of the array contains the information for
the specified value.
num_vals
Specifies the number of elements in the val_list array.
lpValueBuf
Pointer to a buffer. If the function succeeds, the buffer receives the data for
each value.
If lpValueBuf is NULL, the function returns success, and ldwTotsize returns the
required size, in bytes, of the buffer.
ldwTotsize
Pointer to a value that specifies the size, in bytes, of the buffer pointed to b
y the lpValueBuf parameter. If the function succeeds, ldwTotsize returns the num
ber of bytes copied to the buffer. If the function fails because the buffer is t
oo small, ldwTotsize receives the required size, in bytes.
Return Values
If the function succeeds, the return value is ERROR_SUCCESS.
If the function fails, the return value is one of the following error codes:
Value Meaning
ERROR_CANTREAD RegQueryMultipleValues cannot instantiate or access the provider
of the dynamic key.
ERROR_MORE_DATA The buffer pointed to by lpValueBuf was too small. In this case,
ldwTotsize returns the required buffer size.
ERROR_TRANSFER_TOO_LONG The total length of the requested data (size of the val_
list array + ldwTotSize) is more than the system limit of one megabyte.
Remarks
The RegQueryMultipleValues function allows an application to query one or more v
alues of a static or dynamic key. If the target key is a static key, the system
provides all of the values in an atomic fashion. To prevent excessive serializat
ion, the aggregate data returned by the function can not exceed one megabyte.
If the target key is a dynamic key, its provider must provide all the values in
an atomic fashion. This means the provider should fill the results buffer synchr
onously, providing a consistent view of all the values in the buffer while avoid
ing excessive serialization. The provider can provide at most one megabyte of to
tal output data during an atomic call to this function.
RegQueryMultipleValues is supported remotely; that is, the hKey parameter passed
to the function can refer to a remote computer.
See Also
VALENT
23.23 RegQueryValueEx
The RegQueryValueEx function retrieves the type and data for a specified value n
ame associated with an open registry key.
LONG RegQueryValueEx(
HKEY hKey, // handle of key to query
LPTSTR lpValueName, // address of name of value to query
LPDWORD lpReserved, // reserved
LPDWORD lpType, // address of buffer for value type
LPBYTE lpData, // address of data buffer
LPDWORD lpcbData // address of data buffer size
);
Parameters
hKey
Identifies a currently open key or any of the following predefined reserved hand
le values:
HKEY_CLASSES_ROOT
HKEY_CURRENT_CONFIG
HKEY_CURRENT_USER
HKEY_LOCAL_MACHINE
HKEY_USERS
lpValueName
Points to a null-terminated string containing the name of the value to be querie
d.
lpReserved
Reserved; must be NULL.
lpType
Points to a variable that receives the key s value type. The value returned throug
h this parameter will be one of the following:
Value Meaning
REG_BINARY Binary data in any form.
REG_DWORD A 32-bit number.
REG_DWORD_LITTLE_ENDIAN A 32-bit number in little-endian format (same as REG_DWO
RD). In little-endian format, the most significant byte of a word is the high-or
der byte. This is the most common format for computers running
REG_DWORD_BIG_ENDIAN A 32-bit number in big-endian format. In big-endian form
at, the most significant byte of a word is the low-order byte.
REG_EXPAND_SZ A null-terminated string that contains unexpanded references to
environment variables (for example, %PATH% ). It will be a Unicode or ANSI string d
epending on whether you use the Unicode or ANSI functions.
REG_LINK A Unicode symbolic link.
REG_MULTI_SZ An array of null-terminated strings, terminated by two null char
acters.
REG_NONE No defined value type.
REG_RESOURCE_LIST A device-driver resource list.
REG_SZ A null-terminated string. It will be a Unicode or ANSI string depending
on whether you use the Unicode or ANSI functions.
The lpType parameter can be NULL if the type is not required.
lpData
Points to a buffer that receives the value s data. This parameter can be NULL if t
he data is not required.
lpcbData
Pointer to a variable that specifies the size, in bytes, of the buffer pointed t
o by the lpData parameter. When the function returns, this variable contains the
size of the data copied to lpData.
If the data has the REG_SZ, REG_MULTI_SZ or REG_EXPAND_SZ type, then lpcbData wi
ll also include the size of the terminating null character.
The lpcbData parameter can be NULL only if lpData is NULL.
If the buffer specified by lpData parameter is not large enough to hold the data
, the function returns the value ERROR_MORE_DATA, and stores the required buffer
size, in bytes, into the variable pointed to by lpcbData.
If lpData is NULL, and lpcbData is non-NULL, the function returns ERROR_SUCCESS,
and stores the size of the data, in bytes, in the variable pointed to by lpcbDa
ta. This lets an application determine the best way to allocate a buffer for the
value s data.
Return Values
If the function succeeds, the return value is ERROR_SUCCESS.
If the function fails, the return value is a nonzero error code defined in WINER
ROR.H. You can use the FormatMessage function with the FORMAT_MESSAGE_FROM_SYSTE
M flag to get a generic description of the error.
Remarks
The key identified by hKey must have been opened with KEY_QUERY_VALUE access. To
open the key, use the RegCreateKeyEx or RegOpenKeyEx function.
This function does not expand the environment-variable names in the value data w
hen the value type is REG_EXPAND_SZ
If the value data has the REG_SZ, REG_MULTI_SZ or REG_EXPAND_SZ type, and the AN
SI version of this function is used (either by explicitly calling RegQueryValueE
xA or by not defining UNICODE before including the WINDOWS.H file), this functio
n converts the stored Unicode string to an ANSI string before copying it to the
buffer pointed to by lpData.
See Also
RegCreateKeyEx, RegEnumKeyEx, RegOpenKeyEx, RegQueryInfoKey,
23.24 RegReplaceKey
The RegReplaceKey function replaces the file backing a key and all its subkeys w
ith another file, so that when the system is next started, the key and subkeys w
ill have the values stored in the new file.
LONG RegReplaceKey(
HKEY hKey, // handle of open key
LPCTSTR lpSubKey, // address of name of subkey
LPCTSTR lpNewFile, // address of filename for file with new data
LPCTSTR lpOldFile // address of filename for backup file
);
Parameters
hKey
Identifies a currently open key or any of the following predefined reserved hand
le values:
HKEY_CLASSES_ROOT
HKEY_CURRENT_CONFIG
HKEY_CURRENT_USER
HKEY_LOCAL_MACHINE
HKEY_USERS
lpSubKey
Points to a null-terminated string containing the name of a key whose subkeys an
d values are replaced by this function. This key must be a subkey of the key ide
ntified by the hKey parameter. This parameter can be NULL.
The selected key must be the root of a hive; that is, it must be an immediate de
scendent of HKEY_LOCAL_MACHINE or HKEY_USERS.
lpNewFile
Points to a null-terminated string containing the name of the file with registra
tion information. This file is typically created by using the RegSaveKey functio
n. Under the file allocation table (FAT) file system, the filename may not have
an extension.
lpOldFile
Points to a null-terminated string containing the name of a file that receives a
backup copy of the registry information being replaced. If this file is created
under the FAT file system, it should not have an extension.
Return Values
If the function succeeds, the return value is ERROR_SUCCESS.
If the function fails, the return value is a nonzero error code defined in WINER
ROR.H. You can use the FormatMessage function with the FORMAT_MESSAGE_FROM_SYSTE
M flag to get a generic description of the error.
Remarks
The file specified by the lpNewFile parameter remains open until the system is r
estarted.
If hKey is a handle returned by RegConnectRegistry, then the paths specified in
lpNewFile and lpOldFile are relative to the remote computer.
See Also
RegConnectRegistry, RegDeleteKey, RegLoadKey, RegRestoreKey
23.25 RegRestoreKey
The RegRestoreKey function reads the registry information in a specified file an
d copies it over the specified key. This registry information may be in the form
of a key and multiple levels of subkeys.
LONG RegRestoreKey(
HKEY hKey, // handle of key where restore begins
LPCTSTR lpFile, // address of filename containing saved tree
DWORD dwFlags // optional flags
);
Parameters
hKey
Identifies a currently open key or any of the following predefined reserved hand
le values:
HKEY_CLASSES_ROOT
HKEY_CURRENT_CONFIG
HKEY_CURRENT_USER
HKEY_LOCAL_MACHINE
HKEY_USERS
Any information contained in this key and its descendent keys is overwritten by
the information in the file pointed to by the lpFile parameter.
lpFile
Points to a null-terminated string containing the name of the file with registry
information. This file is typically created by using the RegSaveKey function. U
nder the file allocation table (FAT) file system, the filename may not have an e
xtension.
dwFlags
Specifies a flag indicating whether the key is volatile. (A volatile key is vali
d only until the next time the system is started.) This parameter is optional; i
f no value is specified, the key is not volatile.
This parameter can be the REG_WHOLE_HIVE_VOLATILE flag set. Instead of restoring
the given key, this flag causes a new, volatile (memory only) set of registry i
nformation to be created. (A hive is a large set of registry information, typica
lly containing all of the pertinent information for part of the system. For exam
ple, HKEY_LOCAL_MACHINE\Hardware is a volatile hive.)
If REG_WHOLE_HIVE_VOLATILE is specified, the key identified by the hKey paramete
r must be either the HKEY_USERS or HKEY_LOCAL_MACHINE value.
Return Values
If the function succeeds, the return value is ERROR_SUCCESS.
If the function fails, the return value is a nonzero error code defined in WINER
ROR.H. You can use the FormatMessage function with the FORMAT_MESSAGE_FROM_SYSTE
M flag to get a generic description of the error.
Remarks
If any subkeys of the hKey parameter are open, RegRestoreKey fails. The function
also fails if the calling process does not have the SE_RESTORE_NAME privilege.
For more information about privileges, see Privileges.
This function replaces the keys and values below the specified key with the keys
and values that are subsidiary to the top-level key in the file, no matter what
the name of the top-level key in the file might be. For example, hKey might ide
ntify a key A with subkeys B and C, while the lpFile parameter specifies a file
containing key X with subkeys Y and Z. After a call to RegRestoreKey, the regist
ry would contain key A with subkeys Y and Z. The value entries of A would be rep
laced by the value entries of X.
The new information in the file specified by lpFile overwrites the contents of t
he key specified by the hKey parameter, except for the key name.
If hKey represents a key in a remote computer, the path described by lpFile is r
elative to the remote computer.
See Also
RegDeleteKey, RegLoadKey, RegReplaceKey, RegSaveKey
23.26 RegSaveKey
The RegSaveKey function saves the specified key and all of its subkeys and value
s to a new file.
LONG RegSaveKey(
HKEY hKey, // handle of key where save begins
LPCTSTR lpFile, // address of filename to save to
LPSECURITY_ATTRIBUTES lpSecurityAttributes // address of security structure
);
Parameters
hKey
Specifies a handle of the key where the save operation is to begin, or any of th
e following predefined reserved handle values:
HKEY_CLASSES_ROOT
HKEY_CURRENT_CONFIG
HKEY_CURRENT_USER
HKEY_LOCAL_MACHINE
HKEY_USERS
lpFile
Points to a null-terminated string containing the name of the file in which the
specified key and subkeys are saved.
If this filename includes an extension, it cannot be used on file allocation tab
le (FAT) file systems by the RegLoadKey, RegReplaceKey, or RegRestoreKey functio
n.
lpSecurityAttributes
This parameter is ignored.
Return Values
If the function succeeds, the return value is ERROR_SUCCESS.
If the function fails, the return value is a nonzero error code defined in WINER
ROR.H. You can use the FormatMessage function with the FORMAT_MESSAGE_FROM_SYSTE
M flag to get a generic description of the error.
Remarks
If hKey represents a key on a remote computer, the path described by lpFile is r
elative to the remote computer.
The RegSaveKey function saves only nonvolatile keys. It does not save volatile k
eys. A key is made volatile or nonvolatile at its creation; see RegCreateKeyEx.
See Also
RegCreateKeyEx, RegDeleteKey, RegLoadKey, RegReplaceKey, RegRestoreKey, SECURITY
_ATTRIBUTES
23.27 RegSetKeySecurity
The RegSetKeySecurity function sets the security of an open registry key.
LONG RegSetKeySecurity(
HKEY hKey, // open handle of key to set
SECURITY_INFORMATION SecurityInformation, // descriptor contents
PSECURITY_DESCRIPTOR pSecurityDescriptor // address of descriptor for key
);
Parameters
hKey
Identifies an open key for which the security descriptor is set.
SecurityInformation
Specifies a SECURITY_INFORMATION structure that indicates the contents of the su
pplied security descriptor.
Because subkeys are not ordered, any new subkey will have an arbitrary index. Th
is means the function may return subkeys in any order.
pSecurityDescriptor
Points to a SECURITY_DESCRIPTOR structure that specifies the security attributes
to set for the specified key.
Return Values
If the function succeeds, the return value is ERROR_SUCCESS.
If the function fails, the return value is a nonzero error code defined in WINER
ROR.H. You can use the FormatMessage function with the FORMAT_MESSAGE_FROM_SYSTE
M flag to get a generic description of the error.
Remarks
This function succeeds only if the following conditions are met:
· If the key s owner or group is being set, the caller must have WRITE_OWNER permiss
ion or have the SE_TAKE_OWNERSHIP_NAME privilege.
· If the key s discretionary access-control list (DACL) is being set, the caller mus
t have WRITE_DAC permission or be the object s owner.
· If the key s system access-control list (SACL) is being set, the caller must have
the SE_SECURITY_NAME privilege.
If hKey is one of the predefined keys, the predefined key should be closed with
RegCloseKey. That ensures that the new security information is in effect the nex
t time the predefined key is referenced.
See Also
RegCloseKey, RegDeleteKey, RegGetKeySecurity, SECURITY_INFORMATION
23.28 RegSetValueEx
The RegSetValueEx function stores data in the value field of an open registry ke
y. It can also set additional value and type information for the specified key.
LONG RegSetValueEx(
HKEY hKey, // handle of key to set value for
LPCTSTR lpValueName, // address of value to set
DWORD Reserved, // reserved
DWORD dwType, // flag for value type
CONST BYTE *lpData, // address of value data
DWORD cbData // size of value data
);
Parameters
hKey
Identifies a currently open key or any of the following predefined reserved hand
le values:
HKEY_CLASSES_ROOT
HKEY_CURRENT_CONFIG
HKEY_CURRENT_USER
HKEY_LOCAL_MACHINE
HKEY_USERS
lpValueName
Points to a string containing the name of the value to set. If a value with this
name is not already present in the key, the function adds it to the key.
If this parameter is NULL or points to an empty string and the dwType parameter
is the REG_SZ type, this function sets the same value the RegSetValuefunction wo
uld set.
Reserved
Reserved; must be zero.
dwType
Specifies the type of information to be stored as the value s data. This parameter
can be one of the following values:
Value Meaning
REG_BINARY Binary data in any form.
REG_DWORD A 32-bit number.
REG_DWORD_LITTLE_ENDIAN A 32-bit number in little-endian format (same as REG_DWO
RD). In little-endian format, the most significant byte of a word is the high-or
der byte. This is the most common format for computers running
REG_DWORD_BIG_ENDIAN A 32-bit number in big-endian format. In big-endian form
at, the most significant byte of a word is the low-order byte.
REG_EXPAND_SZ A null-terminated string that contains unexpanded references to
environment variables (for example, %PATH% ). It will be a Unicode or ANSI string d
epending on whether you use the Unicode or ANSI functions.
REG_LINK A Unicode symbolic link.
REG_MULTI_SZ An array of null-terminated strings, terminated by two null char
acters.
REG_NONE No defined value type.
REG_RESOURCE_LIST A device-driver resource list.
REG_SZ A null-terminated string. It will be a Unicode or ANSI string depending
on whether you use the Unicode or ANSI functions.
lpData
Points to a buffer containing the data to be stored with the specified value nam
e.
cbData
Specifies the size, in bytes, of the information pointed to by the lpData parame
ter. If the data is of type REG_SZ, REG_EXPAND_SZ, or REG_MULTI_SZ, cbData must
include the size of the terminating null character.
Return Values
If the function succeeds, the return value is ERROR_SUCCESS.
If the function fails, the return value is a nonzero error code defined in WINER
ROR.H. You can use the FormatMessage function with the FORMAT_MESSAGE_FROM_SYSTE
M flag to get a generic description of the error.
Remarks
Value lengths are limited by available memory. Long values (more than 2048 bytes
) should be stored as files with the filenames stored in the registry. This help
s the registry perform efficiently. Application elements such as icons, bitmaps,
and executable files should be stored as files and not be placed in the registr
y.
The key identified by the hKey parameter must have been opened with KEY_SET_VALU
E access. To open the key, use the RegCreateKeyEx or RegOpenKeyEx function.
If dwType is the REG_SZ, REG_MULTI_SZ or REG_EXPAND_SZ type and the ANSI version
of this function is used (either by explicitly calling RegSetValueExA or by not
defining UNICODE before including the WINDOWS.H file), the data pointed to by t
he lpData parameter must be an ANSI character string. The string is converted to
Unicode before it is stored in the registry.
See Also
RegCreateKeyEx, RegFlushKey, RegOpenKeyEx, RegQueryValueEx,
23.29 RegUnLoadKey
The RegUnLoadKey function unloads the specified key and subkeys from the registr
y.
LONG RegUnLoadKey(
HKEY hKey, // handle of open key
LPCTSTR lpSubKey // address of name of subkey to unload
);
Parameters
hKey
Specifies the key to be unloaded. This can be a predefined reserved handle value
, or a handle returned by a call to RegConnectRegistry. The predefined reserved
handle values are:
HKEY_LOCAL_MACHINE
HKEY_USERS
lpSubKey
Points to a null-terminated string containing the name of the subkey to be unloa
ded. The key referred to by the lpSubKey parameter must have been created by usi
ng the RegLoadKey function.
Return Values
If the function succeeds, the return value is ERROR_SUCCESS.
If the function fails, the return value is a nonzero error code defined in WINER
ROR.H. You can use the FormatMessage function with the FORMAT_MESSAGE_FROM_SYSTE
M flag to get a generic description of the error.
Remarks
This function removes a hive from the registry but does not modify the file cont
aining the registry information. A hive is a discrete body of keys, subkeys, and
values that is rooted at the top of the registry hierarchy.
See Also
RegConnectRegistry, RegDeleteKey, RegLoadKey, RegRestoreKey
23.30 Registry Structures
23.31 VALENT
The VALENT structure contains information about a registry value. The RegQueryMu
ltipleValues function uses this structure.
typedef struct value_ent {
LPTSTR ve_valuename;
DWORD ve_valuelen;
DWORD ve_valueptr;
DWORD ve_type;
}VALENT;
Members
ve_valuename
Pointer to a null-terminated string. Before calling RegQueryMultipleValues, set
this member to point to the name of a value to retrieve.
ve_valuelen
Specifies the size, in bytes, of the data pointed to by ve_valueptr.
ve_valueptr
Pointer to the data for the value entry. This is a pointer to the value s data ret
urned in the lpValueBuf buffer filled in by RegQueryMultipleValues.
ve_type
Specifies the type code for the value entry. The type code can be one of the fol
lowing values:
Value Meaning
REG_BINARY Binary data in any form.
REG_DWORD A 32-bit number.
REG_DWORD_LITTLE_ENDIAN A 32-bit number in little-endian format (same as REG_DWO
RD). In little-endian format, the most significant byte of a word is the high-or
der byte. This is the most common format for computers running
REG_DWORD_BIG_ENDIAN A 32-bit number in big-endian format. In big-endian form
at, the most significant byte of a word is the low-order byte.
REG_EXPAND_SZ A null-terminated string that contains unexpanded references to
environment variables (for example, %PATH% ). It will be a Unicode or ANSI string d
epending on whether you use the Unicode or ANSI functions.
REG_LINK A Unicode symbolic link.
REG_MULTI_SZ An array of null-terminated strings, terminated by two null char
acters.
REG_NONE No defined value type.
REG_RESOURCE_LIST A device-driver resource list.
REG_SZ A null-terminated string. It will be a Unicode or ANSI string, depending
on whether you use the Unicode or ANSI functions.
See Also
RegQueryMultipleValues
24. Security Support Provider Iinterface
The Security Support Provider Interface (SSPI) provides a common interface betwe
en transport-level applications and security providers. SSPI provides a mechanis
m by which a distributed application can call one of several security providers
to obtain an authenticated connection without knowledge of the details of the se
curity protocol.
SSPI consists of following APIs:
Credential Management APIs Credential Management APIs provide access to credential
s (password data, tickets, and so on) of a principal or free such access. The AP
Is are:
AcquireCredentialsHandle This method acquires a handle to the reference credential
s.
FreeCredentialsHandle This method releases a credential handle and associated reso
urces.
QueryCredentialAttributes This method allows queries on various credential attribu
tes like associated name, domain name, and so forth.
Context Management APIs Context management APIs provide methods for creating and u
sing security contexts. The contexts are created on both the client and the serv
er side of a communication link. These contexts can then be used later with the
message support APIs. The APIs are:
InitializeSecurityContext Initiates a security context by generating an opaque mes
sage (security token) that can be passed to the server.
AcceptSecurityContext Creates a security context using the opaque message received
from the client.
DeleteSecurityContext Frees a security context and associated
resources.
QueryContextAttributes Allows queries on various context attributes.
ApplyControlToken Applies a supplemental security message to an existing security
context.
CompleteAuthToken Completes an authentication token, since some protocols, like DC
E RPC, need to revise the security information once the transport has updated so
me message fields.
ImpersonateSecurityContext Attaches the client s security context as an impersonatio
n token to the calling thread.
RevertSecurityContext Ceases impersonation and defaults the calling thread to its
primary token.
Message Support APIs Message support APIs provide communication integrity and priv
acy services based on a security context. The APIs are:
MakeSignature Generates a secure signature based on a message and a security conte
xt.
VerifySignature Verifies that the signature matches a received message.
Package Management APIs Package Managment APIs provide services for different secu
rity packages that the security provider supports. The APIs are:
EnumerateSecurityPackages Lists available security packages and their capabilities
.
QuerySecurityPackageInfo Queries an individual security package for its capabiliti
es.
SSPI does not currently provide any public interfaces for encryption/decryption
functionality. Future versions of the SSPI will make message support routines fo
r encryption available.
A security provider is a dynamic-link library that implements the Security Suppo
rt Provider Interface and makes one or more security packages available to appli
cations. A security package maps the SSPI functions to an implementation of the
security protocol specific to that package, such as NTLM, Kerberos, or SSL. Secu
rity packages are sometimes referred to as SSPs, such as the NTLM SSP. The name of t
he security package is used in the initialization step to identify a specific pa
ckage.
The Security Support Provider Interface allows an application to use any of the
available security packages on a system without changing the interface to use se
curity services. SSPI does not establish logon credentials because that is gener
ally a privileged operation handled by the operating system.
An application can use the package management functions to list the security pac
kages available and select one to support its needs. The application then uses t
he credential management functions to obtain a handle to the credentials of the
user on whose behalf they are executing. With this handle, the application can u
se the context management functions to create a security context to a service. A
security context is an opaque data structure that contains the security data re
levant to a connection, such as a session key, the duration of the session, and
so on. Finally, the application uses the security context with the message suppo
rt functions to ensure message integrity and privacy during the connection.
24.1 Security Package Capabilities
The capabilities of the security package determine what services it provides to
the application. These capabilities include, for example, support for client-onl
y authentication or mutual authentication, or support for message integrity and
message privacy. In addition, some packages are designed for use only on reliabl
e transport protocols and are not designed for use on datagram transports.
The security package capabilities available by a specific package are obtained u
sing the QuerySecurityPackageInfo API. The following lists show the security pac
kage capabilities:
Authentication-related capabilities:
Client-only authentication
Multileg authentication required
Transport-related capabilities:
Datagram-style transports
Connection-oriented transports
Data stream connection semantics
Message-related capabilities
Supports message integrity
Supports message privacy
Applications will typically select security packages based on the type of securi
ty capabilities available to meet the application needs. More discussion on secu
rity package capabilities can be found in the section below on Security Context
Semantics.
24.2 Initializing the Security Provider
This section describes how applications-level protocols initialize and use the S
ecurity Support Provider Interface. The section describes various stages of a se
cure network connection setup. The stages include:
Initializing the SSPI
Establishing an authenticated connection
Ensuring communication integrity during message exchange
Security quality of service to service a client request
These stages are described in the following sections.
24.2.1 Initializing the SSPI
Both the client and server use the same sequence of operations to initialize the
security provider and select the appropriate security package.
Initializing the security interface involves the following steps:
Load the security provider DLL
Get a pointer to the provider initialization function
Use the initialization function to get a reference to the provider s security func
tion table
Get specific information about the security package, such as the maximum token s
ize
The security function table contains the SSPI entry points for the security pack
age. The function table is used to invoke the calls implemented by the security
package.
24.3 Loading the Security Provider DLL
In order to initialize security, we need to load the provider. In all our discussi
ons it will be assumed that the client side of the provider is a DLL..
The provider is loaded using a call to the LoadLibrary function, shown in the ex
ample below:
void * DllHandle;
//loading NTLM SSP
DllHandle = (void *)LoadLibrary(TEXT( security.dll );
if(!DllHandle)
{
//
// DLL did not get loaded.
//
Status = GetLastError();
return Status;
}
//
// DllHandle is valid
//
NTLM
MSN
Schannel (SSL/ Private Communications Technology [PCT])
24.4 Provider Initialization
Once the provider has been loaded successfully, you need to perform some setup t
o use the security interface conveniently in the rest of the application. First,
you need to get a pointer to the initialization function for the provider. Then
you will use the initialization function to get a reference to the provider s sec
urity function table. Finally, you can get information from the provider about t
he security packages, or protocols, supported by this security provider. Each se
curity package may have unique capabilities of interest to the application. Howe
ver, in most cases, applications use security packages that support default or c
ommon capabilities.
The example below shows how to initialize the security provider.
//
// Initial provider setup.
//
INIT_SECURITY_INTERFACE InitSecurityInterface;
PSecurityFunctionTable SecurityInterface = 0;
SecPkgInfo PAPI * SecurityPackages;
DWORD NumOfPkgs;
SECURITY_PROVIDER_INFO PAPI * List;
InitSecurityInterface = GetProcAddress(DllHandle, SECURITY_ENDPOINT);
if(!InitSecurityInterface)
{
//
// Something is amiss..
//
}
//
// We got the InitSecurityInterface!
// Now use it to get the function table.
//
SecurityInterface = (*InitSecurityInterface)();
if(!SecurityInterface)
{
//
// we have a problem
//
}
//
// Lets find out the security packages supported by the provider.
//
Status = (*SecurityInterface->EnumerateSecurityPackages)( &NumOfPkgs, &SecurityP
ackages);
//
// Now using the capabilities information figure out which package you want to u
se.
//
PkgToUseIndex = -1;
for(I=0;I<NumOfPackages;I++)
{
//
// for example, if app needs integrity & privacy on messages, it checks
//
if(SecurityPackages[I].fCapabilities & (SECPKG_FLAG_INTEGRITY | SECPKG_F
LAG_PRIVACY))
{
PkgToUseIndex = I;
break;
}
}
if(PkgToUseIndex > 0)
{
//
// Find out the maximum token size for this package
//
g_MaxToken = SecurityPackages[I].cbMaxToken;
}
Both the client and server need to agree on the security package they will use b
efore the SSPI initialization steps shown above.
At this point the application has successfully initialized a security support pr
ovider and chosen a security package with sufficient capabilities needed by the
application protocol. The SecurityInterface points to an array of function point
ers as defined by SSPI.
Notice that the call to EnumerateSecurityPackages initializes the reference poin
ter SecurityPackages, with return data. Some SSPI functions have return output p
arameters, such as security package information. For the output data parameters,
the caller passes in a pointer to a pointer to the return structure type, and t
he security provider allocates memory and returns the data to the caller by assi
gning the address of the return data buffer to the argument. The convention used
by SSPI to return data is the following:
The security package allocates, and the caller frees.
Therefore, the calling program will use FreeContextBuffer to free the memory con
taining data allocated by the security provider when it is done referencing the
data. The examples below will continue to reference SecurityPackages information
, so it must be freed later.
24.5 Security Function Table
The Security Function Table is an array of function pointers which are defined i
n the include file, SSPI.H. The function names correspond to the interface speci
fication for SSPI.
The definition of the Security Function Table is shown below:
typedef struct _SECURITY_FUNCTION_TABLE_W {
unsigned long dwVersion;
ENUMERATE_SECURITY_PACKAGES_FN_W EnumerateSecurityPackagesW;
void SEC_FAR * Reserved1;
// QUERY_CREDENTIALS_ATTRIBUTES_FN_W QueryCredentialsAttributesW;
ACQUIRE_CREDENTIALS_HANDLE_FN_W AcquireCredentialsHandleW;
FREE_CREDENTIALS_HANDLE_FN FreeCredentialHandle;
void SEC_FAR * Reserved2;
INITIALIZE_SECURITY_CONTEXT_FN_W InitializeSecurityContextW;
ACCEPT_SECURITY_CONTEXT_FN AcceptSecurityContext;
COMPLETE_AUTH_TOKEN_FN CompleteAuthToken;
DELETE_SECURITY_CONTEXT_FN DeleteSecurityContext;
APPLY_CONTROL_TOKEN_FN ApplyControlToken;
QUERY_CONTEXT_ATTRIBUTES_FN_W QueryContextAttributesW;
IMPERSONATE_SECURITY_CONTEXT_FN ImpersonateSecurityContext;
REVERT_SECURITY_CONTEXT_FN RevertSecurityContext;
MAKE_SIGNATURE_FN MakeSignature;
VERIFY_SIGNATURE_FN VerifySignature;
FREE_CONTEXT_BUFFER_FN FreeContextBuffer;
QUERY_SECURITY_PACKAGE_INFO_FN_W QuerySecurityPackageInfoW;
void SEC_FAR * Reserved3;
void SEC_FAR * Reserved4;
QUERY_SECURITY_CONTEXT_TOKEN_FN QuerySecurityContextToken;
} SecurityFunctionTableW, SEC_FAR * PSecurityFunctionTableW;
24.5.1 Memory Use, Security Buffers, and Descriptor
Most of the SSPI functions have variable length arguments for the caller (applic
ation) to provide message data to the security package and for the security pack
age to return security data to the caller. SSPI APIs use a parameter type, Buffe
rDescriptor, to define the size and location of the variable length data. Securi
ty buffers are used by the caller, for example, to pass message data to the secu
rity package, or to receive an output security token.
Security buffers can be passed in as an array of buffers. The security buffer de
scriptor identifies the number of buffers and starting address of the buffer arr
ay. Each security buffer also has a buffer type field to identify the contents o
f the buffer.
The definition of security buffers, buffer descriptors, and buffer data types fr
om SSPI.H are shown below:
//
// SecBuffer
//
// Generic memory descriptors for buffers passed in to the security
// API
//
typedef struct _SecBuffer {
unsigned long cbBuffer; // Size of the buffer, in bytes
unsigned long BufferType; // Type of the buffer (below)
void SEC_FAR * pvBuffer; // Pointer to the buffer
} SecBuffer, SEC_FAR * PSecBuffer;
typedef struct _SecBufferDesc {
unsigned long ulVersion; // Version number
unsigned long cBuffers; // Number of buffers
#ifdef MIDL_PASS
[size_is(cBuffers)]
#endif
PSecBuffer pBuffers; // Pointer to array of buffers
} SecBufferDesc, SEC_FAR * PSecBufferDesc;
#define SECBUFFER_VERSION 0
#define SECBUFFER_EMPTY 0 // Undefined, replaced by provider
#define SECBUFFER_DATA 1 // Packet data
#define SECBUFFER_TOKEN 2 // Security token
#define SECBUFFER_PKG_PARAMS 3 // Package specific parameters
#define SECBUFFER_MISSING 4 // Missing Data indicator
#define SECBUFFER_EXTRA 5 // Extra data
#define SECBUFFER_STREAM_TRAILER 6 // Security Trailer
#define SECBUFFER_STREAM_HEADER 7 // Security Header
#define SECBUFFER_ATTRMASK 0xF0000000
#define SECBUFFER_READONLY 0x80000000 // Buffer is read-only
Each time a security API is called that takes a SecBufferDesc parameter, it shou
ld be setup with one or more SecBuffers. For example, there can be two security
buffers, one that contains input message data and the other for the output opaqu
e security token returned by the security package. The order of security buffers
in the security buffer descriptor is not important but they should be tagged wi
th appropriate type. Also, an input buffer that can not be modified by the secur
ity package should additionally be tagged as read only.
The size of the output buffer that is expected to contain the security token is
important. An application can find the maximum token size for a security package
during initial setup. The call to EnumerateSecurityPackages returns an array of
pointers to security package information. The security package information stru
cture contains maximum token size value. In the example code, the information is
in SecPkgInfo.cbMaxToken. It can also be obtained later on using QuerySecurityP
ackageInfo.
The application initializes the buffer pointers and sizes in the buffer descript
ion to indicate where message data and other information may be found.
The example below shows how to initialize an array of security buffers. This par
ticular case shows how input security buffers are initialized by the server-side
of a connection in a call to AcceptSecurityContext. Note that the last buffer c
ontains the opaque security token received by the client and the SECBUFFER_READO
NLY flag is also set.
SecBuffer Buffers[3];
SecBufferDesc BufferDesc;
...
BufferDesc.ulVersion = SECBUFFER_VERSION;
BufferDesc.cBuffers = 3;
BufferDesc.pBuffers = &Buffers;
Buffers[0].cbBuffer = sizeof(Protocol_Header);
Buffers[0].BufferType = SECBUFFER_READONLY | SECBUFFER_DATA;
Buffers[0].pvBuffer = pHeader;
Buffers[1].cbBuffer = pHeader->MessageSize;
Buffers[1].BufferType = SECBUFFER_DATA;
Buffers[1].pvBuffer = pMessage;
Buffers[2].cbBuffer = pHeader->TrailerSize;
Buffers[2].BufferType = SECBUFFER_READONLY | SECBUFFER_TOKEN;
Buffers[2].pvBuffer = pSecurityTrailer;
24.6 Establishing an Authenticated Connection
In a client/server application protocol, a server typically binds to a well know
n communication port (for example, a socket, RPC interface, and so forth) and wa
its for clients to connect and request service. The role of security at connecti
on setup is two fold:
Server should be able to authenticate the client.
Client should be able to authenticate the server.
Associated with these two basic requirements are other security issues, such as,
the authentication information should not be prone to replay, corruption, and s
o on. The application does not need to worry about how these are handled. It can
simply request it from the chosen provider which will encapsulate the underlyin
g security protocol.
The protocol used to establish an authenticated connection involves the exchange
of one or more security tokens between the security providers on each side. These
tokens are sent as opaque messages by the two sides along with any other applicat
ion protocol specific information. The application level protocol strips the sec
urity token out of the received message and passes on to the security package on
their side to figure out if authentication is complete or if further exchange o
f tokens is required. Theoretically, the exchange of security tokens can continu
e ad infinitum, however, in practice it contains one to three legs of message ex
change.
For example, NTLM authentication is based on the challenge/response scheme, and
uses three legs to authenticate a client to the server, as shown in the figure b
elow.
Figure 24-1 : Using NTLM Challenge Response Authentication Protocol via SSPI
24.6.1 Client Context Initialization
To establish a secure connection, the client needs to acquire an outbound creden
tials handle so that it can send over an authentication request to the server. T
he server creates a security context for the client from the authentication requ
est. There are two client-side SSPI functions involved in authentication setup:
AcquireCredentialsHandle to obtain a reference to previously obtained logon cred
entials
InitializeSecurityContext to create the initial authentication request security
tokens
Using the reference to the Security Function Table initialized during the securi
ty provider setup stage, the client calls AcquireCredentialsHandle as follows:
//
// Acquire an out-bound Credentials handle using the chosen security package.
//
SecurityStatus = (*SecurityInterface->AcquireCredentialsHandle)(
0,
SecurityPackages[PkgToUseIndex].Name,
SECPKG_CRED_OUTBOUND,
0,
0,
0,
0,
&Credentials,
&TimeStamp
);
The arguments to AcquireCredentialHandle are the following:
Arg1 = Principal Name, set to NULL here to let the security package use the defa
ult.
Arg2 = Security Package Name, set to the one that was selected during package se
tup.
Arg3 = Type of credential, the client will use outbound credentials.
Arg4 = Pointer to LogonID, set to NULL to let the security package use the defau
lt.
Arg5 =AuthIdentity, set to NULL to use the process s default credentials. This par
ameter may be used to provide. package specific data. For an NTLM security packa
ge it may contain a pointer to the SEC_WINNT_AUTH_IDENTIY structure that contain
s the username, domainname, and password. This feature is used, for example, by
file system redirectors to allow users to specify an alternate account name than
the one they are currently logged in as when connecting to a remote file server
.
Arg6 = GetKey function, set to NULL, not used.
Arg7 = Any argument to the GetKey function, also set to NULL.
Arg8 = returned Credentials Handle, used for additional SSPI calls.
Arg9 =returned TimeStamp which indicates the lifespan of the credentials handle.
Once the client has acquired an outbound credentials handle, it is ready to star
t the authentication protocol to establish a connection with the server. The app
lication client calls the security package again to initialize the security cont
ext.
To initiate the first leg of the authentication, the client calls InitializeSecu
rityContext to obtain an initial security token that will be sent in a connectio
n request message to the server.
The example of the client call to InitializeSecurityContext is shown below:
//
// Set up the Buffer Descriptor.
//
OutBufferDesc.ulVersion = 0;
OutBufferDesc.cBuffers = 1;
OutBufferDesc.pBuffers = &OutSecBuffer;
OutSecBuffer.cbBuffer = BufferLen;
OutSecBuffer.BufferType = SECBUFFER_TOKEN;
OutSecBuffer.pvBuffer = Buffer;
//
// Lets get the authentication token from the security package
// to send to the server to request an authenticated connection.
//
SecurityStatus = (*SecurityInterface->InitializeSecurityContext(
Credentials,
0,
ServerPrincipalName,
ISC_REQ_USE_DCE_STYLE | ISC_REQ_DELEGATE |
ISC_REQ_MUTUAL_AUTH |ISC_REQ_REPLAY_DETECT |
ISC_REQ_SEQUENCE_DETECT |ISC_REQ_CONFIDENTIALITY
|
ISC_REQ_CONNECTION,
0,
0,
0,
0,
&SecurityContext,
BufferDescriptor,
&ContextAttributes,
&TimeStamp
);
The arguments to InitializeSecurityContext are the following:
Arg1 = Credentials handle received from AcquireCredentialsHandle call.
Arg2 = Old Context handle if any.
Arg3 = Target server name, which is ignored by NTLM SSP.
Arg4 = Context Attributes Requested (See SSPI.H for valid values).
Arg5 = Reserved Parameter.
Arg6 = Data Representation (see SSPI.H for valid values).
Arg7 = Input Buffer Descriptor (if there is one received from the server).
Arg8 = Reserved Parameter.
Arg9 = New Context Handle.
Arg10 = Output Buffer Descriptor (contains what will be sent to the server).
Arg11 = Context Attributes that are supported by the provider.
Arg12 = TimeStamp for the lifespan of context validity.
The client then uses the security token information received in the output buffe
r descriptor to generate a message to send to the server. The construction of th
e message in terms of placement of various buffers and so forth, is part of the
application protocol and should be understood between the two parties.
The client checks the return status from InitializeSecurityContext to see if aut
hentication will complete in a single call. Otherwise it expects to receive a se
rver-side authentication token in a response message to continue the security pr
otocol. The return status SEC_I_CONTINUE_NEEDED, indicates the security protocol
requires multiple authentication messages.
24.6.2 Server Context Initialization
To establish an authenticated connection, the server needs to acquire a credenti
als handle so that it can receive an incoming authentication request from the cl
ient. The server s credentials may be used to authenticate the server in security
protocols that support server authentication or mutual authentication. When a co
nnection request is received, the server creates a local security context to rep
resent the client. The server uses the security context to carry out future requ
ests by the same client.
First, the server obtains a handle to its credentials, which may be defined by t
he service account used to start the server. It does so by calling AcquireCreden
tialsHandle as follows:
//
// Acquire an out-bound Credentials handle using the chosen security package.
//
SecurityStatus = (*SecurityInterface->AcquireCredentialsHandle)(
0,
SecurityPackages[PkgToUseIndex].Name,
SECPKG_CRED_INBOUND,
0,
0,
0,
0,
&Credentials,
&TimeStamp
);
The arguments to the server-side call to AcquireCredentialHandle are as follows:
Arg1 = Principal Name, set to NULL here to let the security package use the defa
ult
Arg2 = Security Package Name, set to the one that was selected at initialization
Arg3 = Type of credentials, inbound for a server, use SECPKG_CRED_BOTH if this s
erver is going to be a client to another server.
Arg4 = Pointer to LogonID (set to NULL to let the security package use the defau
lt).
Arg5 = AuthIdentity Package specific authentication data. Since NTLM does not su
pport server authentication, this can be NULL. For other security providers, thi
s can be server authentication data, such as public key credentials.
Arg6 = GetKey function (set to NULL)
Arg7 = Any argument to the GetKey function (also set to NULL)
Arg8 = Returned Credentials Handle.
Arg9 = Returned TimeStamp which indicates the life span of the credentials handl
e.
The returned Credentials Handle should be assigned to a global variable that is
used for the lifetime of the server process. The returned TimeStamp is a tempora
ry variable.
The server can wait (in a listen state) until a connection request arrives befor
e acquiring an inbound credentials handle or it may acquire the handle and then
go into a listen state.
When the server receives a connection request message from a client, it creates
a security context for the client using AcceptSecurityContext. The server initia
lizes the SecurityBufferDescriptors to refer to sections of the data message rec
eived, rather than copying data to an alternate buffer.
The following example shows the call to AcceptSecurityContext.
//
// Set up the Input and OutputBuffer Descriptor using the information from messa
ge received
// from the client.
//
OutBufferDesc.ulVersion = 0;
OutBufferDesc.cBuffers = 1;
OutBufferDesc.pBuffers = &OutSecBuffer;
OutSecBuffer.cbBuffer = BufferLen;
OutSecBuffer.BufferType = SECBUFFER_TOKEN;
OutSecBuffer.pvBuffer = Buffer;
InBufferDesc.ulVersion = 0;
InBufferDesc.cBuffers = 1;
InBufferDesc.pBuffers = &InSecBuffer;
InSecBuffer.cbBuffer = InBufferLen;
InSecBuffer.BufferType = SECBUFFER_TOKEN;
InSecBuffer.pvBuffer = InBuffer;
//
// Lets initialize client s context from the SSP and see if
// we need to send anything back to the client
//
SecurityStatus = (*SecurityInterface->AcceptSecurityContext(
Credentials,
0,
InputBufferDescriptor,
ISC_REQ_USE_DCE_STYLE | ISC_REQ_DELEGATE |
ISC_REQ_MUTUAL_AUTH |ISC_REQ_REPLAY_DETECT |
ISC_REQ_SEQUENCE_DETECT |ISC_REQ_CONFIDENTIALITY
|
ISC_REQ_CONNECTION,
DataRepresentation,
&SecurityContext,
OutputBufferDescriptor,
&ContextAttributes,
&TimeStamp
);
The arguments to AcceptSecurityContext are as follows:
Arg1 = Credentials handle returned from the AcquireCredentialsHandle call.
Arg2 = Old Context handle if any.
Arg3 = Input Buffer Descriptor (if there is one received from client).
Arg4 = Context Attributes Requested (See the Security Context Details section be
low for for more information).
Arg5 = Data Representation (see SSPI.H for valid values).
Arg6 = New Context Handle.
Arg7 = Output Buffer Descriptor, containing what will be sent back to the client
.
Arg8 = Context Attributes that are supported by the provider.
Arg9 = TimeStamp for the lifespan of context validity.
The server checks the return status and output buffer descriptor to ensure there
are no errors so far, otherwise it rejects the connection request. If there is
information in the output buffer it bundles it into a response message to the cl
ient as per the application protocol.
If the return status requires the protocol to continue (SEC_I_CONTINUE_NEEDED or
SEC_I_COMPLETE_AND_CONTINUE), then another message exchange with the client is
required. Otherwise the authentication is complete. For third leg, the server wa
its for the client to respond with another message. Note that this wait maybe ti
med out so as to avoid a denial of service attack (a malicious client may never
respond hanging this server thread, and soon it will hang all server threads!!).
24.6.3 Client Continuation
On receipt of the response from the server, the client decomposes the message an
d, using the continue status from the previous call, it calls InitializeSecurity
Context again:
if(SecurityStatus == SEC_I_CONTINUE_NEEDED || SecurityStatus = SEC_I_COMPLETE_AN
D_CONTINUE)
{
//
// Set up the Input and OutputBuffer Descriptor using the information from messa
ge
// received from the server.
//
OutBufferDesc.ulVersion = 0;
OutBufferDesc.cBuffers = 1;
OutBufferDesc.pBuffers = &OutSecBuffer;
OutSecBuffer.cbBuffer = BufferLen;
OutSecBuffer.BufferType = SECBUFFER_TOKEN;
OutSecBuffer.pvBuffer = Buffer;
InBufferDesc.ulVersion = 0;
InBufferDesc.cBuffers = 1;
InBufferDesc.pBuffers = &InSecBuffer;
InSecBuffer.cbBuffer = InBufferLen;
InSecBuffer.BufferType = SECBUFFER_TOKEN;
InSecBuffer.pvBuffer = InBuffer;
//
//
SecurityStatus = (*SecurityInterface->InitializeSecurityContext(
0,
&SecurityContext,
0,
0,
0,
DataRepresentation,
InputBufferDescriptor,
0,
&SecurityContext,
OutputBufferDescriptor,
&ContextAttributes,
&TimeStamp
);
}
The client checks the return status from this call and may be required to contin
ue for another leg. It uses the information in the OutputBufferDescriptor to con
struct a message and sends it to the server.
24.6.4 Server Continuation
The server should be waiting for the response based on the return code from prev
ious call to AcquireSecurityContext. To continue the authentication protocol, th
e server also calls AcceptSecurityContext again.
if(SecurityStatus = SEC_I_CONTINUE_NEEDED || SecurityStatus = SEC_I_COMPLETE_AND
_CONTINUE)
{
//
// Set up the Input and OutputBuffer Descriptor using the information from messa
ge
// receivedfrom the client.
//
OutBufferDesc.ulVersion = 0;
OutBufferDesc.cBuffers = 1;
OutBufferDesc.pBuffers = &OutSecBuffer;
OutSecBuffer.cbBuffer = BufferLen;
OutSecBuffer.BufferType = SECBUFFER_TOKEN;
OutSecBuffer.pvBuffer = Buffer;
InBufferDesc.ulVersion = 0;
InBufferDesc.cBuffers = 1;
InBufferDesc.pBuffers = &InSecBuffer;
InSecBuffer.cbBuffer = InBufferLen;
InSecBuffer.BufferType = SECBUFFER_TOKEN;
InSecBuffer.pvBuffer = InBuffer;
//
// Lets do the next leg of client s context initialization from the security packa
ge and see if we need
// to send anything back to the client
//
SecurityStatus = (*SecurityInterface->AcceptSecurityContext(
0,
&SecurityContext,
InputBufferDescriptor,
0,
DataRepresentation,
&SecurityContext,
OutputBufferDescriptor,
&ContextAttributes,
&TimeStamp
);
}
The return status is checked to see if the server needs to wait for another leg
from the client. In most existing authentication protocols this is the maximum e
ven for mutual authentication. NTLM security package performs client authenticat
ion and Kerberos security package does mutual authentication in three legs.
24.7 Secure Message Exchange
Microsoft SSPI provides message APIs that can be used to ensure application prot
ocol message integrity. Message privacy APIs (data encryption) are not exposed d
irectly but a particular provider may expose them and document them separately.
If the application wants to generate signed messages, the client must have speci
fied the ISC_REQ_REPLAY_DETECT or ISC_REQ_SEQUENCE_DETECT flag as the Context At
tributes argument in the first call to the InitializeSecurityContext function.
After an authenticated connection has been established, the security support pro
viders on each side establish a common session key that is used to sign messages
on the sending side and to verify messages on the receiving side. The algorithm
s used in message signatures are private to the security package.
The SSPI message APIs are the following:
MakeSignature Generates a secure signature based on a message and a security conte
xt.
VerifySignature Verifies that the signature matches a received message.
The message APIs provide integrity for application data messages. MakeSignature
generates a checksum of the message and also includes sequencing information to
prevent message loss or insertion. The next sections show how the sender and rec
eiver use the SSPI Message APIs.
24.7.1 Sender
The sender of a message calls MakeSignature API to get a signature for the messa
ge and appends it to the message at an appropriate place so that the receiver is
able to extract it on receipt:
//
// Setup the Buffer Descriptors.
//
OutBufferDesc.ulVersion = 0;
OutBufferDesc.cBuffers = 2;
OutBufferDesc.pBuffers = &OutSecBuffer;
OutSecBuffer[0].cbBuffer = MessageLen;
OutSecBuffer[0].BufferType = SECBUFFER_DATA | SECBUFFER_READONLY;
OutSecBuffer[0].pvBuffer = Message;
OutSecBuffer[1].cbBuffer = SignatureLen;
OutSecBuffer[1].BufferType = SECBUFFER_EMPTY;
OutSecBuffer[1].pvBuffer = (Message + MessageLen); // just after the message
//
// Now call MakeSignature API to get it signed.
//
SecurityStatus = (*SecurityInterface->MakeSignature)(
&SecurityContext,
0,
BufferDescriptor,
Sequence
);
The arguments to MakeSignature are the following:
Arg1 = Context Handle for the active security context
Arg2 = Quality of protection
Arg3 = Buffer descriptor containing the message for signing.
Arg4 = Sequence number of the message if sequence detection is on.
The sender then uses the buffer descriptor (including the signature) to construc
t a message to send to the receiver.
The quality of protection value allows applications to select different cryptogr
aphic algorithms supported by the security package. By default NTLM does not sup
port this parameter. Other security packages, however, may provide different qua
lity of protection options.
24.7.2 Receiver
The receiver takes the message and breaks it down to create the buffer descripto
r as before. It then passes this buffer descriptor on to the VerifySignature API
to verify the message integrity.
//
// Setup the Buffer Descriptors.
//
InBufferDesc.ulVersion = 0;
InBufferDesc.cBuffers = 2;
InBufferDesc.pBuffers = &InSecBuffer;
InSecBuffer[0].cbBuffer = MessageLen;
InSecBuffer[0].BufferType = SECBUFFER_DATA | SECBUFFER_READONLY;
InSecBuffer[0].pvBuffer = Message;
InSecBuffer[1].cbBuffer = SignatureLen;
InSecBuffer[1].BufferType = SECBUFFER_TOKEN;
InSecBuffer[1].pvBuffer = (Message + MessageLen); // just after the message
//
// Now call MakeSignature API to get it signed.
//
SecurityStatus = (*SecurityInterface->VerifySignature)(
&SecurityContext,
BufferDescriptor,
Sequence,
&QualityOfProtection
);
The arguments to VerifySignature are the following:
Arg1 = Context Handle for the active context
Arg2 = Buffer descriptor containing received message
Arg3 = Sequence number expected for the received message
Arg4 = Quality of protection on the message (if any)
Once the receiver is ensured of the authenticity and integrity of the message, t
he receiver is free to use it as per the application protocol.
24.7.4 Impersonation
An important aspect of client/server communication besides authentication and me
ssage exchange is the ability of a server to determine whether it should service
the client s request. A large number of servers run under system s context and ther
efore have far more privileges and abilities than a typical client requesting se
rvice. An example of this is a network file server which has full access to all
files, whereas requesting users may not. Therefore, the server should carry out
a client request if and only if the client has sufficient access rights for the
requested service.
There are two approaches for determining whether a client has sufficient access
rights for the operation: an access check by the server, or an access check by t
he system. The brute force approach builds the logic of doing authorization chec
ks for client access into the server. The server code uses authorization informa
tion, for example, from a separate authorization file, and determines if the cli
ent has sufficient rights to perform the requested operation.
SSPI provides an API, ImpersonateSecurityContext, that allows a server to impers
onate the client s security context as well as to revert back to it s own security c
ontext (RevertSecurityContext) when done servicing.
The example below shows how to use ImpersonateSecurityContext and RevertSecurity
Context APIs:
//
// When accessing a resource on behalf the client, we need to
// impersonate the client so that appropriate access check is done.
//
SecurityStatus = (*SecurityInterface->ImpersonateSecurityContext) (&SecurityCont
ext);
if(SecurityStatus != SEC_E_OK)
{
//
// We have a problem
// This security context is not at least impersonation level.
//
return error;
}
//
// At this point the calling thread is under an impersonation token with client s
credentials
//
//
// Process the request..
//
. . .
//
// Revert to primary token once we are done.
//
SecurityStatus = (*SecurityInterface->RevertSecurityContext)(&SecurityContext);
if(SecurityStatus != SEC_E_OK)
{
//
// check for any errors
//
return error;
}
//
// The server thread is back to its original context.
//
24.7.5 Using Delegation in Kerberos
The Kerberos authentication protocol supports delegation. When delegation is sup
ported, the impersonating server can use the client s delegation level credentials
to initialize a security context with a remote server to request a service on t
he client s behalf.
The diagram below shows how the client s security context, identified by C, is est
ablished on Server 1. When Server 1 impersonates the client, the impersonation c
ontext on Server 1 is identified as C/S1. Server 1 makes an off-machine connecti
on to Server 2. Through the use of delegation, Server 2 is also able to imperson
ate the client s security context. Server 2 s impersonation of the client is identif
ied as C/S2.
Figure 24-2: Delegation of Security
The following example shows how delegation can be accomplished using SSPI:
//
// When accessing a resource on behalf the client, we need to impersonate the cl
ient so that
// appropriate access check is done.
//
SecurityStatus = (*SecurityInterface->ImpersonateSecurityContext)(&SecurityConte
xt);
if(SecurityStatus != SEC_E_OK)
{
//
// We have a problem
// This security context is not at least impersonation level.
//
return error;
}
//
// At this point the calling thread is under an impersonation token with client s
credentials
//
//
// Now we can call InitializeSecurityContext to get an authentication token with
current
// credentials (client s) to send to another remote server:
//
// Set up security buffers and the descriptor.
//
//
// Call InitializeSecurityContext
// If this fails, then the client security context is not delegation level,
// WATCH OUT FOR THIS, and handle according to the application protocol.
//
//
// construct a message with the auth token from the SSP to send to the remote se
rver.
// and send the message.
//
// Wait for the reply from the server.
//
//
// If SEC_I_CONTINUE_NEEDED is returned by the first call to Initialize, use
// the auth token returned by the remote server to call InitializeSecurityContex
t again.
//
if(SecurityStatus == SEC_I_CONTINUE_NEEDED || SecurityStatus = SEC_I_COMPLETE_AN
D_CONTINUE)
{
//
// Fill up Input security buffers and setup output security buffers.
//
//
// call InitializeSecurityContext.
//
//
// Convert the security buffers into a message.
// and send the message.
//
//
// wait for reply.
//
}
//
// At this point the connection is established.
//
//
// Request service from the remote server by exchanging messages. Note that
// the remote server will process these assuming that they are coming from the c
lient.
//
. . .
//
// Once done, tear down the connection.
//
//
// Now, you may revert to primary token.
//
SecurityStatus = (*SecurityInterface->RevertSecurityContext)(&SecurityContext);
if(SecurityStatus != SEC_E_OK)
{
//
// check for any errors
//
return error;
}
//
// The server thread is back to its original context.
//
24.7.6 Security Context Details
The Security Support Provider Interface model supports three types of security c
ontexts, which are summarized in the following table.
Type Description
Connection A connection-oriented context is the most common security contex
t, and the simplest to use. The caller is responsible for the overall message fo
rmat. The caller is responsible for the location of the data in the message. The
caller is also responsible for the location of the security-relevant fields wit
hin a message, such as the location of the signature data.
Datagram A datagram-oriented context has extra support for DCE RPC style
datagram communication. It can also be used generically for a datagram-oriented
transport application.
Stream A stream-oriented context is responsible for the blocking and message fo
rmatting within the security package. The caller is not interested in formatting
, but rather a raw stream of data.
24.7.6.1 Connection-Oriented Contexts
With a connection-oriented context, the caller of the function is responsible fo
r formatting messages. The caller also relies on the security provider to authen
ticate connections, and to ensure the integrity of specific parts of the message
. Most of the range of context options are available to connection-oriented cont
exts. These options include mutual authentication, replay detection, and sequenc
e detection, as described in Context Requirements.
A security package sets the SECPKG_FLAG_CONNECTION flag to indicate that it supp
orts connection-oriented semantics.
24.7.6.2 Datagram Contexts
Datagram, or connectionless, contexts have slightly different semantics from con
nection-oriented contexts. A connectionless context implies that the server has
no way of determining when the client has shut down or otherwise terminated the
connection. In other words, no termination notice is passed from the transport a
pplication to the server, as would occur in a connection context. To better supp
ort some models, particularly DCE-style RPC, the following rules apply when the
client specifies the ISC_REQ_DATAGRAM flag in its call to the InitializeSecurity
Context function:
The security package does not produce an authentication blob (binary large objec
t) on the first call to the InitializeSecurityContext function. However, the cli
ent can immediately use the returned security context in a call to the MakeSigna
ture function to generate a signature for a message.
The security package must allow for the context to be re-established multiple ti
mes to allow the server to drop the connection without notice. This also implies
that any keys used in the MakeSignature and VerifySignature functions can be re
set to a consistent state.
The security package must allow for the caller to specify sequence information,
and must provide it back again at the other end. This is not exclusive of any se
quence information maintained by the package and can be viewed as a special payl
oad.
A security package sets the SECPKG_FLAG_DATAGRAM flag to indicate that it suppor
ts datagram semantics.
24.7.6.3 Stream Contexts
Stream contexts are quite different from either connection or datagram contexts.
Stream contexts were introduced to handle the secure streams-oriented protocols
such as SSL or PCT.
In the interest of sharing the same interface, similar credential management, an
d so on, the Security Support Provider Interface has been extended to provide su
pport for stream contexts. The security protocol incorporated both the authentic
ation scheme, and the record formats. This posed a problem to the typical implem
entation, which required the blocking to be done by the caller.
To satisfy the requirements of the stream-oriented protocols, a security package
that supports stream contexts has the following characteristics:
The package sets the SECPKG_FLAG_STREAM flag to indicate that it supports stream
semantics, just as it would set a flag to indicate support for connection and d
atagram semantics.
A transport application requests stream semantics by setting the ISC_REQ_STREAM
and ASC_REQ_STREAM flags in the calls to the InitializeSecurityContext and Accep
tSecurityContext functions.
The application calls the QueryContextAttributes function with a SecPkgContext_S
treamSizes structure to query the security context for the number of buffers to
provide, and the sizes to reserve for headers or trailers.
The application provides buffer descriptors to spare during the actual processin
g of the data.
Obviously, item 4 is of the most interest. By specifying stream semantics, the c
aller is indicating a willingness to do extra work so the security provider can
handle the blocking of the messages.
In essence, for the MakeSignature and VerifySignature functions, the caller pass
es in a list of buffers. When a message is received from a channel that
is stream-oriented (such as a TCP port), the caller passes in a buffer list as f
ollows:
Buffer Length Buffer Type
1 MessageLength SECBUFFER_DATA
2 0 SECBUFFER_EMPTY
3 0 SECBUFFER_EMPTY
4 0 SECBUFFER_EMPTY
5 0 SECBUFFER_EMPTY
The security package then goes to work on the blob. If the function returns succ
essfully, the buffer list looks like this:
Buffer Length Buffer Type
1 Header Length SECBUFFER_STREAM_HEADER
2 Data Length SECBUFFER_DATA
3 Trailer Length SECBUFFER_STREAM_TRAILER
4 0 SECBUFFER_EMPTY
5 0 SECBUFFER_EMPTY
The provider could have also returned buffer #4 as follows:
Buffer Length Buffer Type
4 x SECBUFFER_EXTRA
This indicates that the data in this buffer is part of the next record, and has
not yet been processed.
Conversely, if the message function returns the SEC_E_INCOMPLETE_MESSAGE error c
ode, the returned buffer list would look like this:
Buffer Length Buffer Type
1 x SECBUFFER_MISSING
This indicates that more data was needed to process the record. Unlike most erro
rs returned from a message function, this buffer type does not indicate that the
context has been compromised, just that more data is needed. Security providers
must not update their state in this condition.
Similarly, on the send side of the communication, the caller can simply call the
MakeSignature function, in which case the security package may need to realloca
te the buffer, copy things around, and so on. Or the caller can be more efficien
t by providing a buffer list as follows:
Buffer Length Type
1 Header Length SECBUFFER_STREAM_HEADER
2 Data Length SECBUFFER_DATA
3 Trailer Length SECBUFFER_STREAM_TRAILER
This allows the caller to use the buffers more efficiently. By calling the Query
ContextAttributes function to determine the amount of space to reserve before ca
lling MakeSignature, the operation is more efficient for the application and the
security package.
24.7.6.4 Context Requirements
Context requirements are expressed as a combination of bit flags, passed to eith
er the InitializeSecurityContext or AcceptSecurityContext function. These flags
affect the context in a number of ways, and are detailed in the following table.
Not all flags apply to all contexts; some are valid only for the server, others
only for the client.
The caller uses the fContextReq parameter of the InitializeSecurityContext or Ac
ceptSecurityContext call to specify a set of flags that indicate the required ca
pabilities. When the function returns, the pfContextAttr parameter indicates the
attributes of the established context. The caller is responsible for determinin
g whether the final context attributes are acceptable. For example, if the calle
r requested mutual authentication, but the security package indicates that it wa
s not or could not be performed, the caller must decide whether to cancel the co
ntext or continue on.
The following table describes the various context requirements.
Type Description
DELEGATE Indicates that the server in the transport application should be
allowed simple delegation rights, that is, impersonation of the client on the n
ode at which the server is executing.
MUTUAL_AUTH Indicates that both parties must authenticate the identity of th
e peer.
REPLAY_DETECT Indicates that the context should be established to allow detect
ion of replayed packets later through the message support functions, MakeSignatu
re and VerifySignature. Implies INTEGRITY.
SEQUENCE_DETECT Indicates that the context should be established to allow detect
ion of out-of-order delivery of packets later through the message support functi
ons. Implies INTEGRITY.
CONFIDENTIALITY Indicates that the context should be established to protect data
while in transit. Reserved for future use.
USE_SESSION_KEY Indicates that a new session key should be negotiated.
PROMPT_FOR_CREDS Indicates that, if the client is an interactive user, th
e security package should prompt the user for the appropriate credentials to use
, if possible.
USE_SUPPLIED_CREDS Indicates that package-specific credential information i
s available in the input buffer. The security package should use these credentia
ls to authenticate the connection.
ALLOCATE_MEMORY Indicates that the security package should allocate the memory.
The caller must eventually call the FreeContextBuffer function to free memory al
located by the security package.
USE_DCE_STYLE Indicates that the caller expects a three-leg authentication tra
nsaction.
DATAGRAM Indicates that datagram semantics should be used. For more infor
mation, see Datagram Contexts.
CONNECTION Indicates that connection semantics should be used. For more inf
ormation, see Connection-Oriented Contexts.
STREAM Indicates that stream semantics should be used. For more information, se
e Stream Contexts.
Type Description
EXTENDED_ERROR Indicates that if the context fails (or failed), it will generat
e an error reply message for the peer.
INTEGRITY Buffer integrity can be verified, but no sequencing or reply det
ection is enabled.
24.8 Datatype Descriptions
BINDPTR
A union containing a pointer to a FUNCDESC, VARDESC, or an ITypeComp interface.
It is defined as follows:
typedef union tagBINDPTR {
FUNCDESC FAR* lpfuncdesc;
VARDESC FAR* lpvardesc;
ITypeComp FAR* lptcomp;
} BINDPTR;
BOOL
Boolean variable (should be TRUE or FALSE).
Quick Info
Header file: WTYPES.H
typedef long BOOL;
BSTR
A length-prefixed string used by Automation data manipulation functions.
typedef OLECHAR *BSTR;
BSTRs are wide, double-byte (Unicode) strings on 32-bit Windows platforms and na
rrow, single-byte strings on the Apple® PowerMac .
Quick Info
Header file: WTYPES.H
typedef [wire_marshal( wireBSTR )] OLECHAR * BSTR;
BYTE
BYTE is an unsigned character data type that is binary data.
Quick Info
Header file: WINDEF.H
typedef unsigned char BYTE;
CLIPFORMAT
typedef union _userCLIPFORMAT switch(long fContext) u
{
case WDT_INPROC_CALL: DWORD dwValue;
case WDT_REMOTE_CALL: [string] wchar_t * pwszName;
} userCLIPFORMAT;
typedef [unique] userCLIPFORMAT * wireCLIPFORMAT;
typedef [wire_marshal(wireCLIPFORMAT)] WORD CLIPFORMAT;
CONST
Variable that remains constant during an execution.
Quick Info
Header file: WTYPES.H
#define CONST const
CUSTDATA
Used for retrieving custom data. It is defined as follows:
typedef struct tagCUSTDATA
{
DWORD cCustData;
/* [size_is] */ LPCUSTDATAITEM prgCustData;
} CUSTDATA;
The following table describes the fields of the CUSTDATA structure.
Value Description
cCustData Number of custom data items in prgCustData
prgCustData Array of custom data items
DISPID
Used by IDispatch::Invoke to identify methods, properties, and arguments.
typedef LONG DISPID;
The following dispatch identifiers (DISPIDs) have special meaning.
DISPID Description
DISPID_VALUE The default member for the object. This property or method is in
voked when an COM client specifies the object name without a property or method.
DISPID_NEWENUM The _NewEnum property. This special, restricted property is requ
ired for collection objects. It returns an enumerator object that supports IEnum
VARIANT, and should have the restricted attribute specified in Object Definition
Language.
DISPID_EVALUATE The Evaluate method. This method is implicitly invoked when the
COM client encloses the arguments in square brackets. For example, the following
two lines are equivalent:
x.[A1:C1].value = 10
x.Evaluate("A1:C1").value = 10
The Evaluate method has the DISPID DISPID_EVALUATE.
DISPID_PROPERTYPUT The parameter that receives the value of an assignment i
n a PROPERTYPUT.
DISPID_CONSTRUCTOR The C++ constructor function for the object.
DISPID_DESTRUCTOR The C++ destructor function for the object.
DISPID_UNKNOWN The value returned by IDispatch::GetIDsOfNames to indicate that
a member or parameter name was not found.
Note: The reserved DISPIDs are:
DISPID_Name-800
DISPID_Delete-801
DISPID_Object-802
DISPID_Parent-803
DISPPARAMS
Used by IDispatch::Invoke to contain the arguments passed to a method or propert
y.
typedef struct FARSTRUCT tagDISPPARAMS{
VARIANTARG FAR* rgvarg; // Array of arguments.
DISPID FAR* rgdispidNamedArgs; // Dispatch IDs of named arguments.
unsigned int cArgs; // Number of arguments.
unsigned int cNamedArgs; // Number of named arguments.
} DISPPARAMS;
DWORD
A 32-bit unsigned integer or the address of a segment and its associated offset.
Quick Info
Header file: WTYPES.H
typedef unsigned long DWORD;
FAR *
Defined to nothing.
#define far
#define FAR far
FUNCDESC
Describes a function, and is defined as follows:
typedef struct tagFUNCDESC {
MEMBERID memid; // Function member ID.
/* [size_is] */ SCODE __RPC_FAR *lprgscode;
/* [size_is] */ ELEMDESC __RPC_FAR *lprgelemdescParam; FUNCKIND funckind;
// Specifies whether the
// function is virtual, static,
// or dispatch-only.
INVOKEKIND invkind; // Invocation kind. Indicates if this is a
// property function, and if so, what kind.
CALLCONV callconv; // Specifies the function's calling
// convention.
short cParams; // Count of total number of parameters.
short cParamsOpt; // Count of optional parameters (detailed
// description follows).
short oVft; // For FUNC_VIRTUAL, specifies the offset in
// the VTBL.
short cScodes; // Count of permitted return values.
ELEMDESC elemdescFunc; // Contains the return type of the function.
WORD wFuncFlags; // Definition of flags follows.
} FUNCDESC;
The cParams field specifies the total number of required and optional parameters
.
The cParamsOpt field specifies the form of optional parameters accepted by the f
unction, as follows:
A value of 0 specifies that no optional arguments are supported.
A value of 1 specifies that the method's last parameter is a pointer to a safe ar
ray of variants. Any number of variant arguments greater than cParams 1 must be p
ackaged by the caller into a safe array and passed as the final parameter. The c
aller must free this array of optional parameters after control is returned from
the call.
Any other number indicates that the last n parameters of the function are varian
ts and do not need to be specified by the caller explicitly. The parameters left
unspecified should be filled in by the compiler or interpreter as variants of t
ype VT_ERROR with the value DISP_E_PARAMNOTFOUND.
For 16-bit systems (Macintosh), the fields cScodes and lprgscode store the count
and the set of errors that a function can return. If cScodes = 1, then the set o
f errors is unknown. If cScodes = 1, or if cScodes = 0, then lprgscodeis undefine
d.
HANDLE
A pointer to any type.
Quick Info
Header file: WTYPES.H
typedef void *HANDLE;
HBITMAP
Handle to a bitmap.
typedef HANDLE HBITMAP;
HENHMETAFILE
Handle to an enhanced metafile.
typedef HANDLE HENHMETAFILE;
HGLOBAL
Handle to a global memory block.
typedef HANDLE HGLOBAL;
HINSTANCE
Handle to an instance.
typedef HANDLE HINSTANCE;
HKEY
Handle to a registry key.
typedef HANDLE HKEY;
HMETAFILEPICT
typedef struct _remoteMETAFILEPICT
{
long mm;
long xExt;
long yExt;
userHMETAFILE * hMF;
} remoteMETAFILEPICT;
typedef union _userHMETAFILEPICT switch( long fContext ) u
{
case WDT_INPROC_CALL: long hInproc;
case WDT_REMOTE_CALL: remoteMETAFILEPICT* hRemote;
default: long hGlobal;
} userHMETAFILEPICT;
HREFTYPE
A handle that identifies a type description.
typedef unsigned long HREFTYPE;
HTASK
A handle to a task.
typedef HANDLE HTASK;
HUGEP
#ifndef HUGEP
#if defined(_WIN32) || defined(_MPPC_)
#define HUGEP
#else
#define HUGEP __huge
#endif // WIN32
#endif // HUGEP
INVOKEKIND
Defined as follows:
typedef enum tagINVOKEKIND {
INVOKE_FUNC = DISPATCH_METHOD,
INVOKE_PROPERTYGET = DISPATCH_PROPERTYGET,
INVOKE_PROPERTYPUT = DISPATCH_PROPERTYPUT,
INVOKE_PROPERTYPUTREF = DISPATCH_PROPERTYPUTREF
} INVOKEKIND;
Value Description
INVOKE_FUNC The member is called using normal function invocation syntax.
INVOKE_PROPERTYGET The function is invoked using normal property-access syn
tax.
INVOKE_PROPERTYPUT The function is invoked using property value assignment
syntax. Syntactically, a typical programming language might represent changing a
property in the same way as assignment. For example:
object.property : = value.
INVOKE_PROPERTYPUTREF The function is invoked using property reference assignm
ent syntax.
In C, value assignment is written as *pobj1 = *pobj2, while reference assignment
is written as pobj1 = pobj2. Other languages have other syntactic conventions.
A property or data member can support only a value assignment, a reference assig
nment, or both. The INVOKEKIND enumeration constants are the same constants tha
t are passed to IDispatch::Invoke to specify the way in which a function is invo
ked.
IPID
Interface pointer identifier. It is identical to a GUID.
typedef GUID IPID;
LANGID
Language identifier.
The first release of Windows NT supports 35 sublanguages/locales.
The following 28 sublanguages/locales use the Latin 1 script:
Latin 1 Script
Identifier Language Sublanguage/Locale Language Code
0x0406 Danish Danish DAN
0x0413 Dutch Dutch (Standard) NLD
0x0813 Dutch Belgian (Flemish) NLB
0x0409 English American ENU
0x0809 English British ENG
0x0c09 English Australian ENA
0x1009 English Canadian ENC
0x1409 English New Zealand ENZ
0x1809 English Ireland ENI
0x040b Finnish Finnish FIN
0x040c French French (Standard) FRA
0x080c French Belgian FRB
0x0c0c French Canadian FRC
0x100c French Swiss FRS
0x0407 German German (Standard) DEU
0x0807 German Swiss DES
0x0c07 German Austrian DEA
0x040f Icelandic Icelandic ISL
0x0410 Italian Italian (Standard) ITA
0x0810 Italian Swiss ITS
0x0414 Norwegian Norwegian (Bokmal) NOR
0x0814 Norwegian Norwegian (Nynorsk) NON
0x0416 Portuguese Portuguese (Brazilian) PTB
0x0816 Portuguese Portuguese (Standard) PTG
0x041D Swedish Swedish SVE
0x040a Spanish Spanish (Standard/Traditional) ESP
0x080a Spanish Mexican ESM
0x0c0a Spanish Spanish (Modern) ESN
The following 5 sublanguages/locales use the Latin 2 script:
Latin 2 Script
Identifier Sublanguage/Locale Language Code
0x041f Turkish TRK
0x0415 Polish PLK
0x0405 Czech CSY
0x041b Slovak SKY
0x040e Hungarian HUN
The following sublanguage/locale uses the Cyrillic script:
Cyrillic Script
Identifier Sublanguage/Locale Language Code
0x0419 Russian RUS
The following sublanguage/locale uses another script:
Other Script
Identifier Sublanguage/Locale Language Code
0x0408 Greek ELL
The following special identifiers are also defined:
Special Identifiers
Identifier Sublanguage/Locale
0x0000 Language-Neutral
0x0400 Process Default Language
LCID
Identifies a locale for national language support. Locale information is used f
or international string comparisons and localized member names.
typedef unsigned long LCID;
LCTYPE
An LCTYPE constant is a constant that specifies a particular piece of locale inf
ormation.
The values in the following list correspond to the names of these values in the
configuration registry, under both the user's preferences (as values in the regi
stry key HKEY_CURRENT_USER\Control Panel\International) and the system's install
ed languages (as files pointed to by registry keys, one key per language install
ed, under HKEY_LOCAL_MACHINE\System\CurrentControlSet\Control\NLS). All values a
re null-terminated Unicode strings. If no maximum length is indicated, the string
s may vary in length.
Constant Description
LOCALE_ILANGUAGE Language identifier indicating the language. The maximum
number of characters allowed for this string is 5.
LOCALE_SLANGUAGE Full localized name of the language.
LOCALE_SENGLANGUAGE Full English name of the language from the International
Organization for Standardization (ISO) Standard 639. This is always restricted
to characters mappable into the ASCII 127-character subset.
LOCALE_SABBREVLANGNAME Abbreviated name of the language, created by taking the
2-letter language abbreviation from the ISO Standard 639 and adding a third lett
er, as appropriate, to indicate the sublanguage.
LOCALE_SNATIVELANGNAME Native name of the language.
LOCALE_SSORTNAME The full localized name of the sort for the given locale
ID.
LOCALE_ICOUNTRY Country code, based on international phone codes, also referred
to as IBM country codes. The maximum number of characters allowed for this strin
g is 6.
LOCALE_SCOUNTRY Full localized name of the country.
LOCALE_SENGCOUNTRY Full English name of the country. This is always restric
ted to characters mappable into the ASCII 127-character subset.
LOCALE_SABBREVCTRYNAME Abbreviated name of the country from the ISO Standard 31
66.
LOCALE_SNATIVECTRYNAME Native name of the country.
LOCALE_IDEFAULTLANGUAGE Language identifier for the principal language spoken in
this locale. This is provided so that partially specified locales can be comple
ted with default values. The maximum number of characters allowed for this strin
g is 5.
LOCALE_IDEFAULTCOUNTRY Country code for the principal country in this locale. T
his is provided so that partially specified locales can be completed with defaul
t values. The maximum number of characters allowed for this string is 6.
LOCALE_IDEFAULTANSICODEPAGE American National Standards Institute (ANSI) cod
e page associated with this locale. The maximum number of characters allowed for
this string is 6.
LOCALE_IDEFAULTOEMCODEPAGE Original equipment manufacturer (OEM) code page
associated with the locale. The maximum number of characters allowed for this st
ring is 6.
LOCALE_IDEFAULTCODEPAGE Original equipment manufacturer (OEM) code page associat
ed with the country. The maximum number of characters allowed for this string is
6.
LOCALE_IDEFAULTEBCDICCODEPAGE Default EBCDIC code page associated with the loc
ale. The maximum number of characters allowed for this string is 6.
LOCALE_SLIST Character(s) used to separate list items. For example, a comma i
s used in many locales.
LOCALE_IMEASURE System of measurement. This value is 0 if the metric system (Sys
téme International d'Unités, or S.I.) is used and 1 if the U.S. system is used. The
maximum number of characters allowed for this string is 2.
LOCALE_SDECIMAL Character(s) used as the decimal separator.
LOCALE_STHOUSAND Character(s) used to separate groups of digits to the le
ft of the decimal.
LOCALE_SGROUPING Sizes for each group of digits to the left of the decima
l. An explicit size is needed for each group; semicolons separate sizes. If the
last value is zero, the proceeding value is repeated. To group thousands, specif
y 3;0, for example.
LOCALE_IDIGITS Number of fractional digits. The maximum number of characters al
lowed for this string is 3.
LOCALE_ILZERO Specifier for leading zeros in decimal fields. The maximum numbe
r of characters allowed for this string is 2. The specifier can be one of the fo
llowing values:
Value Meaning
0 No leading zeros
1 Leading zeros
LOCALE_INEGNUMBER Negative number mode. The mode can be one of these value
s:
Value Meaning
0 (1.1)
1 1.1
2 1.1
3 1.1
4 1.1
LOCALE_SNATIVEDIGITS Native equivalents to ASCII 0 through 9.
LOCALE_SENGCURRNAME The full English name of the currency associated with th
e locale.
LOCALE_SNATIVECURRNAME The native name of the currency associated with the loca
le.
LOCALE_SCURRENCY String used as the local monetary symbol.
LOCALE_SINTLSYMBOL Three characters of the international monetary symbol sp
ecified in ISO 4217, "Codes for the Representation of Currencies and Funds," fol
lowed by the character separating this string from the amount.
LOCALE_SMONDECIMALSEP Character(s) used as the monetary decimal separator.
LOCALE_SMONTHOUSANDSEP Character(s) used as the monetary separator between grou
ps of digits to the left of the decimal.
LOCALE_SMONGROUPING Sizes for each group of monetary digits to the left of t
he decimal. An explicit size is needed for each group; sizes are separated by se
micolons. If the last value is zero, the preceding value is repeated. To group t
housands, specify 3;0, for example.
LOCALE_ICURRDIGITS Number of fractional digits for the local monetary forma
t. The maximum number of characters allowed for this string is 3.
LOCALE_IINTLCURRDIGITS Number of fractional digits for the international moneta
ry format. The maximum number of characters allowed for this string is 3.
LOCALE_ICURRENCY Positive currency mode. The maximum number of characters
allowed for this string is 2. The mode can be one of the following values:
Value Meaning
0 Prefix, no separation
1 Suffix, no separation
2 Prefix, 1-char. separation
3 Suffix, 1-char. separation
LOCALE_INEGCURR Negative currency mode. The maximum number of characters allowed
for this string is 3. The mode can be one of the following values:
Value Example
0 ($1.1)
1 $1.1
2 $ 1.1
3 $1.1
4 (1.1$)
5 1.1$
6 1.1 $
7 1.1$
8 1.1 $ (space before $)
9 $ 1.1 (space after $)
10 1.1 $ (space before $)
11 $ 1.1 (space after $)
12 $ 1.1 (space after $)
13 1.1 $ (space before $)
14 ($ 1.1) (space after $)
15 (1.1 $) (space before $)
LOCALE_SDATE Character(s) for the date separator.
LOCALE_STIME Character(s) for the time separator.
LOCALE_STIMEFORMAT Time formatting strings for this locale. The string can
consist of a combination of the hour, minute, and second format pictures defined
in the Error! Bookmark not defined. table in National Language Support Constant
s.
LOCALE_SYEARMONTH The Year/Month formatting string for the locale. This st
ring shows the proper format for a date string that contains only the year and t
he month.
LOCALE_SSHORTDATE Short date formatting string for this locale. The string
can consist of a combination of day, month, and year format pictures defined in
Error! Bookmark not defined. table in National Language Support Constants.
LOCALE_SLONGDATE Long date formatting string for this locale. The string
can consist of a combination of day, month, and year format pictures defined in
the Error! Bookmark not defined. table in National Language Support Constants an
d any string of characters enclosed in single quotes. Characters in single quote
s remain as given.
LOCALE_IDATE Short date format-ordering specifier. The maximum number of char
acters allowed for this string is 2. The specifier can be one of the following v
alues:
Value Meaning
0 Month-Day-Year
1 Day-Month-Year
2 Year-Month-Day
LOCALE_ILDATE Long date format-ordering specifier. The maximum number of chara
cters allowed for this string is 2. The specifier can be one of the following va
lues:
Value Meaning
0 Month-Day-Year
1 Day-Month-Year
2 Year-Month-Day
LOCALE_ITIME Time format specifier. The maximum number of characters allowed
for this string is 2. The specifier can be one of the following values:
Value Meaning
0 AM / PM 12-hour format
1 24-hour format
LOCALE_ICENTURY Specifier for full 4-digit century. The maximum number of charac
ters allowed for this string is 2. The specifier can be one of the following val
ues:
Value Meaning
0 Abbreviated 2-digit century
1 Full 4-digit century
LOCALE_ITLZERO Specifier for leading zeros in time fields. The maximum number o
f characters allowed for this string is 2. The specifier can be one of the follo
wing values:
Value Meaning
0 No leading zeros for hours
1 Leading zeros for hours
LOCALE_IDAYLZERO Specifier for leading zeros in day fields. The maximum n
umber of characters allowed for this string is 2. The specifier can be one of th
e following values:
Value Meaning
0 No leading zeros for days
1 Leading zeros for days
LOCALE_IMONLZERO Specifier for leading zeros in month fields. The maximum
number of characters allowed for this string is 2. The specifier can be one of
the following values:
Value Meaning
0 No leading zeros for months
1 Leading zeros for months
LOCALE_S1159 String for the AM designator.
LOCALE_S2359 String for the PM designator.
LOCALE_ICALENDARTYPE Current calendar type. This type can be one of these val
ues:
Value Meaning
1 Gregorian (as in United States)
2 Gregorian (English strings always)
3 Era: Year of the Emperor (Japan)
4 Era: Year of Taiwan Region
5 Tangun Era (Korea)
LOCALE_IOPTIONALCALENDAR Additional calendar types. This can be a zero-se
parated list of one or more of these calendars type values:
Value Meaning
0 No additional types valid
1 Gregorian (as in United States)
2 Gregorian (English strings always)
3 Era: Year of the Emperor (Japan)
4 Era: Year of Taiwan Region
5 Tangun Era (Korea)
LOCALE_IFIRSTDAYOFWEEK Specifier for the first day in a week. The specifier can
be one of these values:
Value Meaning
0 LOCALE_SDAYNAME1
1 LOCALE_SDAYNAME2
2 LOCALE_SDAYNAME3
3 LOCALE_SDAYNAME4
4 LOCALE_SDAYNAME5
5 LOCALE_SDAYNAME6
6 LOCALE_SDAYNAME7
LOCALE_IFIRSTWEEKOFYEAR Specifier for the first week of the year. The specifier
can be one of these values:
Value Meaning
0 Week containing 1/1 is the first week of that year.
1 First full week following 1/1 is the first week of that year.
2 First week containing at least 4 days is the first week of that year.
LONG
32-bit signed integer.
typedef long LONG;
LPBC
A pointer to a Bind Context.
typedef [unique] IbindCtx *LPBC;
LPBYTE
Pointer to a BYTE.
typedef unsigned char FAR *LPBYTE;
LPCLSID
A pointer to a class ID.
typedef CLSID *LPCLSID;
LPCOLESTR
A pointer to an OLECHAR array.
typedef [string] const OLECHAR *LPOLESTR;
LPCTSTR
Pointer to a constant null-terminated Unicode or Windows character string.
typedef const TCHAR FAR *LPCTSTR;
LPCWSTR
Pointer to a constant null-terminated Unicode character string.
typedef [string] const WCHAR *LPCWSTR;
LPDWORD
Pointer to a DWORD.
typedef DWORD *LPDWORD;
LPIID
A pointer to an interface identifier.
typedef IID *LPIID;
LPMALLOC
A pointer to an IMalloc interface.
typedef [unique] IMalloc *LPMALLOC;
LPMALLOCSPY
A pointer to an IMallocSpy interface.
typedef [unique] IMallocSpy *LPMALLOCSPY;
LPMARSHAL
A pointer to an IMarshal interface.
typedef [unique] IMarshal *LPMARSHAL;
LPMONIKER
A pointer to an IMoniker interface.
typedef [unique] IMoniker *LPMONIKER;
LPOLESTR
A pointer to an OLECHAR array.
typedef [string] OLECHAR *LPOLESTR;
LPRUNNINGOBJECTTABLE
A pointer to the running object table interface.
Typedef [unique] IRunningObjectTable *LPRUNNINGOBJECTTABLE;
LPSECURITY_ATTRIBUTES
typedef struct _SECURITY_ATTRIBUTES {
DWORD nLength;
[size_is(nLength)] LPVOID lpSecurityDescriptor;
BOOL bInheritHandle;
} SECURITY_ATTRIBUTES, *PSECURITY_ATTRIBUTES, *LPSECURITY_ATTRIBUTES;
LPSTR
Pointer to a null-terminated Windows character string.
typedef [string] CHAR *LPSTR;
LPSTREAM
Pointer to an IStream interface.
typedef [unique] IStream *LPSTREAM;
LPUNKNOWN
A pointer to an IUnknown interface.
typedef [unique] IUnknown *LPUNKNOWN;
LPVOID
Pointer to any type.
typedef void *LPVOID;
LPWORD
Pointer to a WORD.
typedef WORD *LPWORD;
LPWSTR
Pointer to a null-terminated Unicode character string.
typedef [string] WCHAR *LPWSTR;
MEMBERID
Identifies the member in a type description. For IDispatch interfaces, this is t
he same as DISPID.
typedef DISPID MEMBERID;
This is a 32-bit integral value in the following format.
Bits Value
0 15 Offset. Any value is permissible.
16 21 The nesting level of this type information in the inheritance hierarchy.
For example:
interface mydisp : IDispatch
The nesting level of IUnknown is 0, IDispatch is 1, and MyDisp is 2.
22 25 Reserved. Must be zero.
26 28 Value of the DISPID.
29 True if this is the member ID for a FUNCDESC; otherwise False.
30 31 Must be 01.
Negative IDs are reserved for use by Automation.
OLECHAR
A wide character.
typedef WCHAR OLECHAR;
PFILETIME
typedef struct _FILETIME
{
DWORD dwLowDateTime;
DWORD dwHighDateTime;
} FILETIME, *PFILETIME, *LPFILETIME;
PHKEY
Pointer to a registry key.
typedef HKEY FAR *PHKEY;
PROPID
A pointer to an unsigned long.
typedef ULONG PROPID;
PROPSPEC
The PROPSPEC structure is used by many of the methods of IPropertyStorage to spe
cify a property either by its property identifier or the associated string name.
The structure and related definitions are defined as follows in the header file
s:
const ULONG PRSPEC_LPWSTR = 0
const ULONG PRSPEC_PROPID = 1
typedef ULONG PROPID
typedef struct tagPROPSPEC
{
ULONG ulKind; // PRSPEC_LPWSTR or PRSPEC_PROPID
union
{
PROPID propid;
LPOLESTR lpwstr;
}
} PROPSPEC
Members
ulKind
If ulKind is set to PRSPEC_LPWSTR, lpwstr is used and set to a string name. If u
lKind is set to PRSPEC_PROPID, propid is used and set to a property identifier v
alue.
propid
Specifies the value of the property identifier. Use either this value or the fol
lowing lpwstr, not both.
lpwstr
Specifies the string name of the property as a null-terminated Unicode string.
Remarks
String names are optional and can be assigned to a set of properties when the pr
operty is created with a call to IPropertyStorage::WriteMultiple, or later, with
a call to IPropertyStorage::WritePropertyNames.
QuickInfo
Windows NT: Use version 4.0 or later.
Windows: Use Windows 95 or later. Available as a redistributable for Windows 95.
Windows CE: Unsupported.
Header: Declared in objidl.h.
PROPVARIANT
The PROPVARIANT structure is used in most of the methods of IPropertyStorage to
define the type tag and the value of a property in a property set. There are fiv
e members. The first, the value type tag, and the last, the value of the propert
y, are significant. The middle three are reserved for future use. The PROPVARIAN
T structure is defined as follows:
Note The bool member in previous definitions of this structure has been renamed
to boolVal, since some compilers now recognize bool as a keyword.
struct PROPVARIANT{
VARTYPE vt; // value type tag
WORD wReserved1;
WORD wReserved2;
WORD wReserved3;
union {
// none // VT_EMPTY, VT_NULL, VT_ILLEGAL
unsigned char bVal; // VT_UI1
short iVal; // VT_I2
USHORT uiVal; // VT_UI2
long lVal; // VT_I4
ULONG ulVal; // VT_UI4
LARGE_INTEGER hVal; // VT_I8
ULARGE_INTEGER uhVal; // VT_UI8
float fltVal; // VT_R4
double dblVal; // VT_R8
CY cyVal; // VT_CY
DATE date; // VT_DATE
BSTR bstrVal; // VT_BSTR
VARIANT_BOOL boolVal; // VT_BOOL
SCODE scode; // VT_ERROR
FILETIME filetime; // VT_FILETIME
LPSTR pszVal; // VT_LPSTR // string in the current system
Ansi code page
LPWSTR pwszVal; // VT_LPWSTR // string in Unicode
CLSID* puuid; // VT_CLSID
CLIPDATA* pclipdata; // VT_CF
BLOB blob; // VT_BLOB, VT_BLOBOBJECT
IStream* pStream; // VT_STREAM, VT_STREAMED_OBJECT
IStorage* pStorage; // VT_STORAGE, VT_STORED_OBJECT
CAUB caub; // VT_VECTOR | VT_UI1
CAI cai; // VT_VECTOR | VT_I2
CAUI caui; // VT_VECTOR | VT_UI2
CAL cal; // VT_VECTOR | VT_I4
CAUL caul; // VT_VECTOR | VT_UI4
CAH cah; // VT_VECTOR | VT_I8
CAUH cauh; // VT_VECTOR | VT_UI8
CAFLT caflt; // VT_VECTOR | VT_R4
CADBL cadbl; // VT_VECTOR | VT_R8
CACY cacy; // VT_VECTOR | VT_CY
CADATE cadate; // VT_VECTOR | VT_DATE
CABSTR cabstr; // VT_VECTOR | VT_BSTR
CABOOL cabool; // VT_VECTOR | VT_BOOL
CASCODE cascode; // VT_VECTOR | VT_ERROR
CALPSTR calpstr; // VT_VECTOR | VT_LPSTR
CALPWSTR calpwstr; // VT_VECTOR | VT_LPWSTR
CAFILETIME cafiletime; // VT_VECTOR | VT_FILETIME
CACLSID cauuid; // VT_VECTOR | VT_CLSID
CACLIPDATA caclipdata; // VT_VECTOR | VT_CF
CAPROPVARIANT capropvar; // VT_VECTOR | VT_VARIANT
}} PROPVARIANT
Remarks
PROPVARIANT is the fundamental data type by which property values are read and w
ritten through the IPropertyStorage interface.
The data type PROPVARIANT is related to the data type VARIANT, defined as part o
f Automation in OLE2 and defined in the Win32 SDK header file oleauto.h. Several
definitions are reused from Automation, as follows:
typedef struct tagCY {
unsigned long Lo;
long Hi;
} CY
typedef CY CURRENCY;
typedef short VARIANT_BOOL;
typedef unsigned short VARTYPE;
typedef double DATE;
typedef OLECHAR* BSTR;
typedef struct tagCLIPDATA {
ULONG cbSize; //Includes sizeof(ulClipFmt)
long ulClipFmt;
BYTE* pClipData;
} CLIPDATA
In addition, several new data types that define counted arrays of other data typ
es are required. The data types of all counted arrays begin with the letters CA
(such as CAUB) and have an ORed vt value. The counted array structure has the fo
llowing form (where name is the specific name of the counted array):
#define TYPEDEF_CA(type, name)
typedef struct tag ## name {\
ULONG cElems;\
type *pElems;\
} name
Value Description
REGKIND_DEFAULT Use default register behavior
REGKIND_REGISTER Registered type
REGKIND_NONE Not a registered type
REGSAM
Data type used for specifying the security access attributes in the registry. A
REGSAM value can be one or more of the following values:
KEY_ALL_ACCESS
Combination of KEY_QUERY_VALUE, KEY_ENUMERATE_SUB_KEYS, KEY_NOTIFY, KEY_CREATE_S
UB_KEY, KEY_CREATE_LINK, and KEY_SET_VALUE access.
KEY_CREATE_LINK
Permission to create a symbolic link.
KEY_CREATE_SUB_KEY
Permission to create subkeys.
KEY_ENUMERATE_SUB_KEYS
Permission to enumerate subkeys.
KEY_EXECUTE
Permission for read access.
KEY_NOTIFY
Permission for change notification.
KEY_QUERY_VALUE
Permission to query subkey data.
KEY_READ
Combination of KEY_QUERY_VALUE, KEY_ENUMERATE_SUB_KEYS, and KEY_NOTIFY access.
KEY_SET_VALUE
Permission to set subkey data.
KEY_WRITE
Combination of KEY_SET and KEY_CREATE_SUB_KEY access.
RPC_AUTH_IDENTITY_HANDLE
typedef void * RPC_AUTH_IDENTITY_HANDLE;
Remarks
An identity handle points to the data structure that contains the client's authe
ntication and authorization credentials specified for remote procedure calls.
RPC_AUTHZ_HANDLE
A pointer to the authorization service.
typedef void __RPC_FAR *RPC_AUTHZ_HANDLE;
RPC_FAR
Defined to nothing.
#define RPC_FAR
RPCOLEMESSAGE
typedef struct tagRPCOLEMESSAGE
{
void *reserved1;
RPCOLEDATAREP dataRepresentation;
void *Buffer;
ULONG cbBuffer;
ULONG iMethod;
void *reserved2[5];
ULONG rpcFlags;
} RPCOLEMESSAGE;
SECURITY_INFORMATION
The SECURITY_INFORMATION structure identifies the object-related security inform
ation being set or queried. This security information includes:
The owner of an object
The primary group of an object
The discretionary access-control list (ACL) of an object
The system ACL of an object
typedef DWORD SECURITY_INFORMATION;
Each item of security information is designated by a bit flag. The following val
ues specify the bits:
Value Meaning
OWNER_SECURITY_INFORMATION Indicates the owner identifier of the object is
being referenced.
GROUP_SECURITY_INFORMATION Indicates the primary group identifier of the ob
ject is being referenced.
DACL_SECURITY_INFORMATION Indicates the discretionary ACL of the object is
being referenced.
SACL_SECURITY_INFORMATION Indicates the system ACL of the object is being
referenced.
QuickInfo
Windows NT: Use version 3.1 or later.
Windows: Unsupported.
Windows CE: Unsupported.
Header: Declared in winnt.h.
SIZEL
typedef struct tagSIZEL
{
LONG cx;
LONG cy;
} SIZEL, *PSIZEL, *LPSIZEL;
SOLE_AUTHENTICATION_SERVICE
Identifies an authentication service. This structure is retrieved through a call
to CoQueryAuthenticationServices, and passed in to CoInitializeSecurity.
typedef struct tagSOLE_AUTHENTICATION_SERVICE {
DWORD dwAuthnSvc;
DWORD dwAuthzSvc;
OLECHAR* pPrincipalName;
HRESULT hr;
} SOLE_AUTHENTICATION_SERVICE;
Members
dwAuthnSvc
The authentication service. It may contain a single value taken from the list of
RPC_C_AUTHN_xxx constants defined in rpcdce.h. RPC_C_AUTHN_NONE turns off authe
ntication. On Win32, RPC_C_AUTHN_DEFAULT causes COM to use the RPC_C_AUTHN_WINNT
authentication.
dwAuthzSvc
The authorization service. It may contain a single value taken from the list of
RPC_C_AUTHZ_xxx constants defined in rpcdce.h. The validity and trustworthiness
of authorization data, like any application data, depends on the authentication
service and authentication level selected. This parameter is ignored when using
the RPC_C_AUTHN_WINNT authentication service.
pPrincipalName
Principal name to be used with the authentication service. If the principal name
is NULL, COM assumes the current user identifier. A NULL principal name is allo
wed for NT LM SSP and kerberos authentication services, but may not work for oth
er authentication services.
hr
When used in CoInitializeSecurity, set on return to indicate the status of the c
all to register the authentication services.
QuickInfo
Windows NT: Use version 4.0 or later.
Windows: Use Windows 95 or later. Available as a redistributable for Windows 95.
Windows CE: Unsupported.
Header: Declared in objidl.h.
STDAPI
Standard API calling convention.
#define STDAPI EXTERN_C HRESULT STDAPICALLTYPE
SYSKIND
Identifies the target operating system platform. It is defined as follows:
typedef enum tagSYSKIND {
SYS_WIN16,
SYS_WIN32,
SYS_MAC
} SYSKIND;
Value Description
SYS_WIN16 The target operating system for the type library is 16-bit Windo
ws systems. By default, data members are packed.
SYS_WIN32 The target operating system for the type library is 32-bit Windo
ws systems. By default, data members are naturally aligned (for example, 2-byte
integers are aligned on even-byte boundaries; 4-byte integers are aligned on qua
d-word boundaries, and so on).
SYS_MAC The target operating system for the type library is Apple Macintosh. By
default, all data members are aligned on even-byte boundaries.
SYSTEMTIME
The SYSTEMTIME structure has the following form:
typedef struct _SYSTEMTIME {
WORD wYear;
WORD wMonth;
WORD wDayOfWeek;
WORD wDay;
WORD wHour;
WORD wMinute;
WORD wSecond;
WORD wMilliseconds;
} SYSTEMTIME;
The SYSTEMTIME structure represents a date and time using individual members for
the month, day, year, weekday, hour, minute, second, and millisecond.
Members
wYear The current year.
wMonth The current month; January is 1.
wDayOfWeek The current day of the week; Sunday is 0, Monday is 1, and so on.
wDay The current day of the month.
wHour The current hour.
wMinute The current minute.
wSecond The current second.
wMilliseconds The current millisecond.
TLIBATTR
Contains information about a type library. Information from this structure is us
ed to identify the type library and to provide national language support for mem
ber names. It is defined as follows:
typedef struct FARSTRUCT tagTLIBATTR {
GUID guid; // Unique ID of the library.
LCID lcid; // Language/locale of the library.
SYSKIND syskind; // Target hardware platform.
unsigned short wMajorVerNum; // Major version number.
unsigned short wMinorVerNum; // Minor version number.
unsigned short wLibFlags; // Library flags.
} TLIBATTR, FAR * LPTLIBATTR;
TYPEATTR
Contains attributes of an ITypeInfo, and is defined as follows:
typedef struct FARSTRUCT tagTYPEATTR {
GUID guid; // The GUID of the type information.
LCID lcid; // Locale of member names and doc
// strings.
unsigned long dwReserved;
MEMBERID memidConstructor; // ID of constructor, or MEMBERID_NIL if
// none.
MEMBERID memidDestructor; // ID of destructor, or MEMBERID_NIL if
// none.
OLECHAR FAR* lpstrSchema; // Reserved for future use.
unsigned long cbSizeInstance;// The size of an instance of
// this type.
TYPEKIND typekind; // The kind of type this information
// describes.
unsigned short cFuncs; // Number of functions.
unsigned short cVars; // Number of variables/data members.
unsigned short cImplTypes; // Number of implemented interfaces.
unsigned short cbSizeVft; // The size of this type's VTBL.
unsigned short cbAlignment; // Byte alignment for an instance
// of this type.
unsigned short wTypeFlags;
unsigned short wMajorVerNum; // Major version number.
unsigned short wMinorVerNum; // Minor version number.
TYPEDESC tdescAlias; // If TypeKind == TKIND_ALIAS,
// specifies the type for which
// this type is an alias.
IDLDESC idldescType; // IDL attributes of the
// described type.
} TYPEATTR, FAR* LPTYPEATTR;
The cbAlignment field indicates how addresses are aligned. A value of 0 indicate
s alignment on the 64K boundary; 1 indicates no special alignment. For other val
ues, n indicates aligned on byte n.
UINT
Unsigned integer.
typedef unsigned int UINT;
ULARGE_INTEGER
The ULARGE_INTEGER structure is used to specify a 64-bit unsigned integer value.
typedef union _ULARGE_INTEGER {
struct {
DWORD LowPart;
DWORD HighPart;
};
DWORDLONG QuadPart;
} ULARGE_INTEGER;
Members
LowPart
Specifies the low-order 32 bits.
HighPart
Specifies the high-order 32 bits.
QuadPart
Specifies a 64-bit unsigned integer.
Remarks
The ULARGE_INTEGER structure is actually a union. If your compiler has built-in
support for 64-bit integers, use the QuadPart member to store the 64-bit integer
. Otherwise, use the LowPart and HighPart members to store the 64-bit integer.
QuickInfo
Windows NT: Use version 3.1 or later.
Windows: Use Windows 95 or later.
Windows CE: Use version 1.0 or later.
Header: Declared in winnt.h.
ULONG
Unsigned long integer.
typedef DWORD ULONG;
USHORT
Unsigned short integer.
typedef unsigned short USHORT;
VARDESC
Describes a variable, constant, or data member. It is defined as follows:
typedef struct FARSTRUCT tagVARDESC {
MEMBERID memid;
OLECHAR FAR* lpstrSchema; // Reserved for future use.
union {
// VAR_PERINSTANCE, the offset of this
// variable within the instance.
unsigned long oInst;
// VAR_CONST, the value of the constant.
VARIANT FAR* lpvarValue;
} UNION_NAME(u);
ELEMDESC elemdescVar;
unsigned short wVarFlags;
VARKIND varkind;
} VARDESC
VARTYPE
An enumeration type used in VARIANT, TYPEDESC, OLE property sets, and safe array
s.
The enumeration constants listed in the following VARENUM section are valid in t
he vt field of a VARIANT structure.
typedef unsigned short VARTYPE;
enum VARENUM{
VT_EMPTY = 0, // Not specified.
VT_NULL = 1, // Null.
VT_I2 = 2, // 2-byte signed int.
VT_I4 = 3, // 4-byte signed int.
VT_R4 = 4, // 4-byte real.
VT_R8 = 5, // 8-byte real.
VT_CY = 6, // Currency.
VT_DATE = 7, // Date.
VT_BSTR = 8, // Binary string.
VT_DISPATCH = 9, // IDispatch
VT_ERROR = 10, // Scodes.
VT_BOOL = 11, // Boolean; True=-1, False=0.
VT_VARIANT = 12, // VARIANT FAR*.
VT_UNKNOWN = 13, // IUnknown FAR*.
VT_UI1 = 17, // Unsigned char.
// Other constants that are not valid in VARIANTs omitted here.
};
VT_RESERVED = (int) 0x8000
// By reference, a pointer to the data is passed.
VT_BYREF = (int) 0x4000
VT_ARRAY = (int) 0x2000 // A safe array of the data is passed.
VOID
Any type.
#define VOID void
WCHAR
Unicode character.
typedef wchar_t WCHAR
WINAPI
Calling convention for the Win32 API.
#define WINAPI FAR PASCAL
WINOLEAPI
Calling convention for the Windows OLE API.
#define WINOLEAPI STDAPI
WORD
16-bit unsigned integer.
typedef unsigned short WORD;