All applications, that is, running programs that define a task or a process be they client or servers, have specific responsibilities. This chapter examines the roles and responsibilities of all COM applications and the necessary COM library support functions for those responsibilities.
In short, any application that makes use of COM, client or server, has three specific 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 resources and perform any cleanup operations as necessary.
Each of these responsibilities requires support from the COM Library itself as detailed in the following sections. For convenience, initialization and uninitialization are described together. Additional COM Library functions related to initialization and memory management are also given in this chapter.
To use basic COM services, all COM threads of execution in clients and
out-of-process servers must call either the
CoInitialize()
or the
CoInitializeEx()
function before calling any other COM function except memory allocation
calls.
CoInitializeEx()
replaces the other function, adding
a parameter that allows you to specify the threading model of the thread--either
apartment-threaded or free-threaded.
A call to
CoInitialize()
simply sets the threading model to apartment-threaded.
For information on
threading in clients and servers, refer to
Chapter 6.
In-process servers do not call the initialization functions, because
they are
being
loaded into a process that has already done so.
As a result, in-process servers
must set their threading model in the registry under the
InprocServer32
key.
For detailed information on threading issues in in-process
servers, refer to Section
Section 6.5.
It is also important to uninitialize the library.
For each call to
CoInitialize()
or
CoInitializeEx()
, there must
be a corresponding call to
CoUninitialize()
.
[Footnote 39]
As was articulated earlier in this specification, when ownership
of allocated memory is passed through an interface, COM requires
[Footnote 39]
that the memory be allocated with a specific
``task allocator.'' Most general purpose access to the task allocator is provided
through the
IMalloc()
interface instance returned from
CoGetMalloc()
.
Simple shortcut allocation and freeing APIs are also provided in the form
of
CoTaskMemAlloc()
and
CoTaskMemFree()
.
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. When such a situation arises the object must use the task allocator as described in Chapter 2. That is, the object must allocate memory whose ownership is transferred from one party to another through an interface function by using the local task allocator.
CoGetMalloc()
provides a convenient way for objects
to allocate working memory as well.
For example, when the
TextRender
object (see Section
Section 4.6) under consideration
in this document loads text from a file in the 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 reading data are omitted for simplicity):
//Implementation ofIPersistFile::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 its lifetime, it
makes sense to 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 destroyed.
Alternatively, the APIs
CoTaskMemAlloc()
and its friends may be used.
IMalloc()
allocates, frees, and manages memory.
In general, you should not implement
IMalloc()
, instead
using the COMOLE implementation, 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
CoGetMalloc()
function.
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 handlers should call
CoGetMalloc()
to get a pointer to the
IMalloc()
implementation on the task allocator object, and use the implementation of
those methods to manage task memory.
The
IMalloc()
methods
Alloc
,
Free
, and
Realloc
are similar to the C library
functions
malloc
,
free
, and
realloc
.
For debugging, refer to the functions
CoRegisterMallocSpy()
and
CoRevokeMallocSpy()
.
IUnknown Methods
|
Description
|
QueryInterface()
|
Returns pointers to supported interfaces. |
AddRef()
|
Increments the reference count. |
Release()
|
Decrements the reference count. |
|
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 system. |
CoGetMalloc()
,
IMallocSpy()
,
CoRegisterMallocSpy()
,
CoRevokeMallocSpy()
- Allocates a block of memory.
IMalloc::Alloc()
void * Alloc(
#include <objidl.h>
ULONG cb
);
The
IMalloc::Alloc()
method allocates a memory block
in essentially
the same way that the C Library
malloc
function does.
The initial contents of the returned memory block are undefined - there is no guarantee that the block has been initialized, so you should initialize it in your code. The allocated block may be larger than cb bytes because of the space required for alignment and for maintenance information.
If
cb
is zero,
IMalloc::Alloc()
allocates a zero-length item and
returns a valid pointer to that item.
If there is insufficient memory
available,
IMalloc::Alloc()
returns
NULL
.
Applications should always check the return value from this method, even when requesting small amounts of memory, because there is no guarantee the memory will be allocated.
[in] Size , in bytes, of the memory block to be allocated.
If successful,
Alloc
returns a pointer to the allocated
memory
block.
NULL
If insufficient memory is available,
Alloc
returns
NULL
.
IMalloc::Free()
,
IMalloc::Realloc()
,
CoTaskMemAlloc()
- Determines if this allocator was used to allocate the specified block of memory.
IMalloc::DidAlloc()
int DidAlloc(
#include <objidl.h>
void * pv
);
Calling
IMalloc::DidAlloc()
is useful if a application
is using
multiple allocations, and needs to know whether a previously allocated block
of
memory was allocated by a particular allocation.
[in] Pointer to the memory block; can be a
NULL
pointer,
in
which case, -1 is returned.
The memory block was allocated by this
IMalloc()
instance.
The memory block was
not
allocated by
this
IMalloc()
instance.
DidAlloc
is unable to determine whether
or not it
allocated the memory block.
IMalloc::Alloc()
,
IMalloc::HeapMinimize()
,
IMalloc::Realloc()
- Frees a previously allocated block of memory.
IMalloc::Free()
void Free(
#include <objidl.h>
void * pv
);
IMalloc:Free
frees a block of memory previously allocated
through a call
to
IMalloc::Alloc()
or
IMalloc::Realloc()
.
The number
of bytes freed equals the number of bytes that were allocated.
After the call,
the memory block pointed to by
pv
is invalid and can
no longer be
used.
The pv parameter can be
NULL
. If so, this method has no effect.
[in] Pointer to the memory block to be freed.
IMalloc::Alloc()
,
IMalloc::Realloc()
,
CoTaskMemFree()
- Returns the size (in bytes) of a memory block previously allocated with
IMalloc::GetSize()
IMalloc::Alloc()
or
IMalloc::Realloc()
.
ULONG GetSize(
#include <objidl.h>
void * pv
);
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 actual size of the allocation,
which may be greater than the size requested when the allocation was made.
[in] Pointer to the memory block for which the size is requested.
The size of the allocated memory block in bytes or, if
pv
is a
NULL
pointer, -1.
IMalloc::Alloc()
,
IMalloc::Realloc()
- Minimizes the heap as much as possible by releasing unused memory
to the operating system, coalescing adjacent free blocks and committing free
pages.
IMalloc::HeapMinimize()
void HeapMinimize(
#include <objidl.h>
);
Calling
IMalloc::HeapMinimize()
is useful when an
application has
been running for some time and the heap may be fragmented.
IMalloc::Alloc()
,
IMalloc::Free()
,
IMalloc::Realloc()
- Changes the size of a previously allocated memory block.
IMalloc::Realloc()
void *Realloc(
#include <objidl.h>
void * pv,
ULONG cb
);
IMalloc::Realloc()
reallocates a block of memory,
but does not guarantee that
the contents of the returned memory block are initialized.
Therefore, the
caller is responsible for intializing it in code, subsequent to the
reallocation.
The allocated 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
,
IMalloc::Realloc()
allocates a new memory block in the
same way that
IMalloc::Alloc()
does.
If
pv
is not
NULL
, it
should be a pointer returned by a prior call to
IMalloc::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 different memory location, the pointer returned by
IMalloc::Realloc()
is not guaranteed 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 argument is not
NULL
, or if there is not enough
memory available to
expand the block to 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
aligned for storage of any type of object.
To get a pointer to a type other
than
void
, use a type cast on the return value.
[in] Pointer to the memory block to be reallocated.
The pointer
can
have a
NULL
value, as discussed in the following Remarks section.
[in] Size of the memory block (in bytes) to be reallocated. It can be zero, as discussed in the following remarks.
Memory block successfully reallocated.
NULL
Insufficient memory or
cb
is zero and
pv
is not
NULL
.
IMalloc::Alloc()
,
IMalloc::Free()
The
IMallocSpy()
interface is a debugging interface
that allows
application developers to monitor (spy on) memory allocation, detect memory
leaks
and simulate memory failure in calls to
IMalloc()
methods.
Caution: The
IMallocSpy()
interface is intended to be used only to debug application code under development. Do not ship this interface to retail customers of your application, because it causes severe performance degradation and could conflict with user-installed software to produce unpredictable results.
Implement this interface to debug memory allocation during application development.
When an implementation of
IMallocSpy()
is registered
with
CoRegisterMallocSpy()
,
COM calls the pair of
IMallocSpy()
methods around the corresponding
IMalloc()
method.
You would not make direct calls to
IMallocSpy()
methods.
The COM
SDK contains a sample 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-threaded operations.
IUnknown()
Methods
|
Description
|
QueryInterface()
|
Returns pointers to supported interfaces. |
AddRef()
|
Increments reference count. |
Release()
|
Decrements reference count. |
|
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()
.
|
IMalloc()
,
CoGetMalloc()
,
CoRegisterMallocSpy()
- Called just prior to invoking
IMallocSpy::PreAlloc()
IMalloc::Alloc()
.
ULONG PreAlloc(
#include <objidl.h>
ULONG cbRequest
);
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
allocation failure is effective only if
cbRequest
is
not equal to 0.
If
PreAlloc
is forcing failure by returning
NULL
,
PostAlloc
is not called.
However, if
IMalloc::Alloc()
encounters a real memory failure and returns
NULL
,
PostAlloc
is called.
The call to
PreAlloc
through the return from
PostAlloc
is guaranteed to be thread safe.
[in] Number of bytes specified in the allocation request the
caller is passing to
IMalloc::Alloc()
.
The byte count actually passed to
IMalloc::Alloc()
,
which should be greater than or equal to the value of
cbRequest.
IMalloc::Alloc()
,
IMallocSpy::PostAlloc()
,
CoRegisterMallocSpy()
,
CoRevokeMallocSpy()
- Called just after invoking
IMallocSpy::PostAlloc()
IMalloc::Alloc()
,
taking as input a pointer to the
IMalloc::Alloc()
caller's
allocation, and returning a pointer to the actual allocation.
void * PostAlloc(
#include <objidl.h>
void * pActual
);
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 returns a pointer to the beginning of the total allocation,
which could include a forward offset from the other value if
IMallocSpy::Prealloc()
was implemented to attach debug information to the allocation
in this way.
If not, the same pointer is returned, and also becomes the return
value to the caller of
IMalloc::Alloc()
.
[in] Pointer to the allocation done by
IMalloc::Alloc()
.
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 written 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.
IMalloc::Alloc()
,
IMallocSpy::PreAlloc()
,
CoRegisterMallocSpy()
,
- Called by COM just prior to invoking
IMallocSpy::PreDidAlloc()
IMalloc::DidAlloc()
.
void * PreDidAlloc(
#include <objidl.h>
void * pRequest,
BOOL fSpyed
);
When a spy object implementing
IMallocSpy()
is registered
with
CoRegisterMallocSpy()
, COM calls this method immediately
before any call
to
IMalloc::DidAlloc()
.
This method is included for completeness
and
consistency--it is not anticipated that developers will implement significant
functionality in this method.
[in] Pointer the caller is passing to
IMalloc::DidAlloc()
.
[in]
TRUE
if the allocation was done while
this spy was active.
The pointer for which allocation status is determined.
This pointer
is passed to
PostDidAlloc
as the
fActual
parameter.
IMalloc::DidAlloc()
,
IMallocSpy::PostDidAlloc()
,
CoRegisterMallocSpy()
,
CoRevokeMallocSpy()
- Called just after invoking
IMallocSpy::PostDidAlloc()
IMalloc::DidAlloc()
.
int PostDidAlloc(
#include <objidl.h>
void * pRequest,
BOOL fSpyed,
int fActual
);
When a spy object implementing
IMallocSpy()
is registered
with
CoRegisterMallocSpy()
, COM calls this method immediately
after any call to
IMalloc::DidAlloc()
.
This method is included for completeness
and
consistency--it is not anticipated that developers will implement significant
functionality in this method.
For convenience,
pRequest, the original pointer passed
in the call to
IMalloc::DidAlloc()
, is passed to
PostDidAlloc
.
In addition, the
parameter
fActual
is a boolean 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.
[in] Pointer specified in the original call to
IMalloc::DidAlloc()
.
[in]
TRUE
if the allocation was done while
this spy
was active.
[in] Actual value returned by
IMalloc::DidAlloc()
.
The value returned to the caller of
IMalloc::DidAlloc()
.
IMalloc::DidAlloc()
,
IMallocSpy::PreDidAlloc()
,
CoRegisterMallocSpy()
,
CoRevokeMallocSpy()
- Called just before invoking
IMallocSpy::PreFree()
IMalloc::Free()
to ensure that the pointer passed
to
IMalloc::Free()
points to
the beginning of the actual allocation.
void * PreFree(
#include <objidl.h>
void * pRequest,
BOOL fSpyed
);
If
IMallocSpy::PreAlloc()
modified the original allocation
request passed
to
IMalloc::Alloc()
(or
IMalloc::Realloc()
),
IMallocSpy::PreFree()
must supply a pointer to the actual
allocation,
which COM will pass to
IMalloc::Free()
.
For example, if
the
PreAlloc
/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 beginning of this header, so all of the block that
was
allocated can be freed.
[in] Pointer to the block of memory that the caller is passing
to
IMalloc::Free()
.
[in]
TRUE
if the
pRequest
parameter
of
IMallocSpy::PreFree()
was allocated while the spy was installed.
This value is also passed to
IMallocSpy::PostFree()
.
The actual pointer to pass to
IMalloc::Free()
.
IMalloc::Free()
,
IMallocSpy::PostFree()
,
CoRegisterMallocSpy()
,
CoRevokeMallocSpy()
- Called just after invoking
IMallocSpy::PostFree()
IMalloc::Free()
.
void PostFree(
#include <objidl.h>
BOOL fSpyed
);
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 developers will implement significant
functionality in this method.
On return, the
fSpyed
parameter
simply
indicates whether the memory was freed while the current spy was active.
[in]
TRUE
if the memory block to be freed
was allocated
while the current spy was active, otherwise
FALSE
.
IMalloc::Free()
,
IMallocSpy::PreFree()
,
CoRegisterMallocSpy()
,
CoRevokeMallocSpy()
- Called by COM just prior to any call to
IMallocSpy::PreGetSize()
IMalloc::GetSize()
.
void * PreGetSize(
#include <objidl.h>
void * pRequest,
BOOL fSpyed
);
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 allocation, which may have altered
pRequest
in the implementation of either the
PreAlloc
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.
The size determined by
IMalloc::GetSize()
is the value returned by the Win32 functionHeapSize
. On Windows NT, this is the size originally requested. On Windows 95, memory allocations are done on eight-byte boundaries. For example, a memory allocation request of 27 bytes on Windows NT would return an allocation of 32 bytes andGetSize
would return 27. On Windows 95, the same request would return an allocation of 28 bytes andGetSize
would return 28. Implementers ofIMallocSpy::PostGetSize()
cannot assume, for example, that if cbActual issizeof(debug_header)
, that the value is the actual size of the user's allocation.
[in] Pointer the caller is passing to
IMalloc::GetSize()
.
[in]
TRUE
if the allocation was done while
the spy was active.
Pointer to the actual allocation for which the size is to be determined.
IMalloc::GetSize()
,
IMallocSpy::PostGetSize()
,
CoRegisterMallocSpy()
,
CoRevokeMallocSpy()
- Called just after invoking
IMallocSpy::PostGetSize()
IMalloc::GetSize()
.
ULONG PostGetSize(
#include <objidl.h>
ULONG cbActual,
BOOL fSpyed
);
The size determined by
IMalloc::GetSize()
is the
value returned by the
Win32 function
HeapSize
.
On Windows NT, this is the size
originally
requested.
On Windows 95, memory allocations are done on eight-byte boundaries.
For example, a memory allocation request of 27 bytes on Windows NT would return
an allocation of 32 bytes 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.
[in] Actual number of bytes in the allocation, as returned
by
IMalloc::GetSize()
.
[in]
TRUE
if the allocation was done while
a spy was active.
The same value returned by
IMalloc::GetSize()
, which
is the size of the allocated memory block in bytes.
IMalloc::GetSize()
,
IMallocSpy::PreGetSize()
,
CoRegisterMallocSpy()
,
CoRevokeMallocSpy()
- Called just prior to invoking
IMallocSpy::PreHeapMinimize()
IMalloc::HeapMinimize()
.
void PreHeapMinimize(
#include <objidl.h>
void
);
This method is included for completeness; it is not anticipated that developers will implement significant functionality in this method.
IMalloc::HeapMinimize()
,
IMallocSpy::PostHeapMinimize()
,
CoRegisterMallocSpy()
,
CoRevokeMallocSpy()
- Called just after invoking
IMallocSpy::PostHeapMinimize()
IMalloc::HeapMinimize()
.
void PostHeapMinimize(
#include <objidl.h>
void
);
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 developers will implement significant
functionality in this method.
IMalloc::HeapMinimize()
,
IMallocSpy::PreHeapMinimize()
,
CoRegisterMallocSpy()
,
CoRevokeMallocSpy()
- Called just before invoking
IMallocSpy::PreRealloc()
IMalloc::Alloc()
.
ULONG PreRealloc(
#include <objidl.h>
void * pRequest,
ULONG cbRequest,
void ** ppNewRequest,
BOOL fSpyed
);
The
IMallocSpy::PreRealloc()
implementation may extend
and/or modify the
allocation to store debug-specific information with the allocation.
Thus,
the
ppNewRequest
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 cases.
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 equal to
0.
[in] Pointer specified in the original call to
IMalloc::Realloc()
, indicating the the memory block to
be reallocated.
[in] Memory block's byte count as specified in the original
call to
IMalloc::Realloc()
.
[out] Address of pointer variable that receives a pointer
to the actual memory block to be reallocated.
This may be different from the
pointer in
pRequest
if the implementation of
IMallocSpy::PreRealloc()
extends or modifies the reallocation.
This
is an out pointer and should always be stored by
PreRealloc
.
[in]
TRUE
if the original allocation was
done while the spy was active.
The actual byte count to be passed to
IMalloc::Realloc()
.
IMalloc::Realloc()
,
IMallocSpy::PostRealloc()
,
CoRegisterMallocSpy()
,
CoRevokeMallocSpy()
- Called after invoking
IMallocSpy::PostRealloc()
IMalloc::Realloc()
.
void * PostRealloc(
#include <objidl.h>
void * pActual,
BOOL fSpyed
);
[in] Pointer to the memory block reallocated by
IMalloc::Realloc()
.
[in] If
TRUE
, the original memory allocation
was
done while the spy was active.
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 written 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 appended or if no debug
information is
attached.
IMalloc::Realloc()
,
IMallocSpy::PreRealloc()
,
CoRegisterMallocSpy()
,
CoRevokeMallocSpy()
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.
Applications
that support links and links to embedded objects implement this interface
to
provide object enumeration, name parsing, and silent updates of link sources.
Simple, nonlinking containers do not need to implement
IOleContainer
if
it is useful mainly to support links to embedded objects.
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
IOleItemContainer()
, which is used to bind item monikers.
|
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. |
IOleItemContainer()
,
IParseDisplayName()
- Enumerates objects in the current container.
IOleContainer::EnumObjects()
HRESULT EnumObjects(
#include <ole2.h>
DWORD grfFlags,
IEnumUnknown ** ppenum
);
A container should implement
EnumObjects
to enable
programmatic clients
to find out what objects it holds.
This method, however, is not called in
standard linking scenarios.
[in] Value that specifies which objects in a container are
to be enumerated,
as defined
in the enumeration
OLECONTF
.
[out] Address of
IEnumUnknown()
* pointer
variable
that receives
the interface pointer to the enumerator object.
Each time a container receives
a
successful call to
EnumObjects
, it must increase the reference
count on the *ppenum
pointer the method 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
set *ppenum
to
NULL
.
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.
IEnumUnknown()
,
IOleItemContainer()
,
OLECONTF
- Keeps an embedded object's container running.
IOleContainer::LockContainer()
HRESULT LockContainer(
#include <ole2.h>
BOOL fLock
);
An embedded object calls
IOleContainer::LockContainer
to keep its
container running when the object has link clients that require an update.
If
an end user selects File Close from the container's menu, however, the
container ignores all outstanding
LockContainer
locks and
closes the
document anyway.
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 call
LockContainer
;
the default
handler makes these calls automatically for object applications implemented
as
.EXEs as the object makes the transition to and from 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
Object 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 Table, object handlers and DLL object applications, as part of their
implementation of
IRunnableObject::Run()
,
should call
IOleContainer::LockContainer(TRUE)
to lock the object.
The container must keep track of whether and how many calls to
LockContainer(TRUE)
have been made.
To increment or decrement the
reference count,
IOleContainer::LockContainer
calls
CoLockObjectExternal()
with a flag set to match
fLock.
[in] Value that specifies whether to lock (TRUE
)
or
unlock (FALSE
) a container.
This method supports the standard return values
E_FAIL
and
E_OUTOFMEMORY
, as
well as the following:
S_OK
Container was locked successfully.
CoLockObjectExternal()
,
IRunnableObject::Run()
Objects, especially asynchronous-aware objects, can expose the
IPersistMoniker()
interface to obtain more control over the way they bind to their persistent
data.
Existing moniker implementations call
QueryInterface()
on the client object for
persistence interfaces such as
IPersistFile()
,
IPersistStream[Init]()
, or
IPersistStorage()
as part of their
IMoniker::BindToObject()
implementation
when they are instantiating 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 persistent data.
An object
could, for
example, implement
IPersistMoniker::Load()
by calling
IMoniker::BindToStorage()
for the interface it prefers:
IStorage()
,
IStream()
, asynchronous
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
to initialize the object should
QueryInterface()
for a different persistence interface
that contains an
InitNew()
method,
such as
IPersistStreamInit()
,
IPersistMemory()
,
or
IPersistPropertyBag()
.
Then, the client
can use the
InitNew()
method found in the other persistence
interface to initialize the
object.
The client can still safely 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()
.
Implement
IPersistMoniker()
on any object that can be saved persistently
to multiple
storage mediums or can take advantage of any of the asynchronous stream,
storage, or
IMoniker::BindToStorage()
behavior described
above.
Custom moniker implementations should support
IPersistMoniker()
as the most
flexible persistence interface in their implementation of
IMoniker::BindToObject()
if they are instantiating an arbitrary
class and
need to initialize it from persistent data.
Typically, these monikers should
use the published persistence interfaces in the following order:
IPersistMoniker()
,
IPersistStream[Init]
,
IPersistStorage()
,
IPersistFile()
, and
IPersistMemory()
.
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. |
|
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. |
- Retrieves the moniker that refers to the object's persistent state.
IPersistMoniker::GetCurMoniker()
HRESULT GetCurMoniker(
#include <urlmon.h>
IMoniker ** ppmkCur
);
Typically, this method returns the moniker last passed to the object
by means of
IPersistMoniker::Load()
,
IPersistMoniker::Save
, or
IPersistMoniker::SaveCompleted()
.
[out] Address of
IMoniker()
* pointer variable
that receives the interface pointer to the object's current persistent state.
IPersistMoniker::Load()
,
IPersistMoniker::Save()
,
IPersistMoniker::SaveCompleted()
- Checks an object for changes since it was last saved.
IPersistMoniker::IsDirty()
HRESULT IsDirty(
#include <urlmon.h>
void
);
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 saved.
S_OK
The object has changed since it was last saved.
S_FALSE
The object has not changed since the last save.
- Loads the object from its persistent state indicated by a supplied
moniker.
IPersistMoniker::Load()
HRESULT Load(
#include <urlmon.h>
BOOL fFullyAvailable,
IMoniker * pmkSrc,
IBindCtx * pbc,
DWORD grfMode
);
Typically, the object will immediately bind to its persistent state
through a
call to the source moniker's
IMoniker::BindToStorage()
method, requesting
either the
IStream()
or
IStorage()
interface.
[in] If
TRUE
, then the data referred to
by the moniker
has already been loaded once,
and subsequent binding to the moniker should be synchronous.
If
FALSE
, then an
asynchronous bind operation should be launched.
[in] Pointer to a moniker that references the persistent state for the object to be loaded.
[in] Pointer to the
IBindCtx()
interface
for the
bind context to be
used for any moniker binding during this method.
[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()
method 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.
S_OK
The object was successfully loaded.
E_INVALIDARG
One or more parameters are invalid.
IPersistMoniker::Save()
,
IPersistMoniker::SaveCompleted()
- Requests that the object save itself to the location referred
to by
pmkDst.
IPersistMoniker::Save()
HRESULT Save(
#include <urlmon.h>
IMoniker * pmkDst,
IBindCtx * pbc,
BOOL fRemember
);
[in] Pointer to the moniker referencing the location where
the object
should
persistently store itself.
The object typically binds to the location through
a call 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 binding, since it has typically already bound to the moniker
when
it was loaded.
[in] Pointer to
IBindCtx()
for the bind
context to
be used for
any moniker binding during this method.
[in] Indicates whether
pmkDst
is to be
used as
the reference
to the current persistent state after the save.
If
TRUE
,
pmkDst
becomes the reference to the current 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, the 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 the
fRemember
flag.
S_OK
The object was successfully saved.
E_INVALIDARG
One or more parameters are invalid.
IPersistMoniker::GetCurMoniker()
,
IPersistMoniker::Load()
,
IPersistMoniker::SaveCompleted()
- Notifies the object that it has been completely saved and points
it to its new persisted state.
IPersistMoniker::SaveCompleted()
HRESULT SaveCompleted(
#include <urlmon.h>
IMoniker * pmkNew,
IBindCtx * pbc
);
Typically, the object will immediately bind to its persistent state
through a
call to
pmkNew
->BindToStorage
method,
requesting either the
IStream()
or
IStorage()
interface, as in
IPersistMoniker::Load()
.
[in] Pointer to the moniker for the object's new persistent
state.
This
parameter
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 allowed 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.
[in] Pointer to the bind context to use for any moniker binding during this method.
S_OK
The operation was successful.
E_INVALIDARG
One or more parameters are invalid.
IPersistMoniker::Load()
,
IPersistMoniker::Save()
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, calling launches the server's .EXE file.
In the case of an
object implemented with an in-process server, calling the
Run()
method causes
the object .DLL file to transition into the running state.
Object
handlers should implement
IRunnableObject()
to provide
their containers
with a way to run them and manage their running state.
DLL object applications
should implement
IRunnableObject()
to support silent updates
of their
objects.
Containers
call
IRunnableObject()
to determine if an embedded object
is running, to
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.
IUnknown()
Methods
|
Description
|
QueryInterface()
|
Returns pointers to supported interfaces. |
AddRef()
|
Increments reference count. |
Release()
|
Decrements reference count. |
|
Description
|
GetRunningClass()
|
Returns CLSID of a running object. |
Run()
|
Forces an object to run. |
IsRunning()
|
Determines if an object is running. |
LockRunning()
|
Locks an object into running state. |
SetContainedObject()
|
Indicates that an object is embedded. |
- Returns the CLSID of a running object.
IRunnableObject::GetRunningClass()
HRESULT GetRunningClass((
#include <objidl.h>
LPCLSID lpClsid
);
If an embedded document was created by an application that is not available
on
the user's computer, the document, by a call to
CoTreatAsClass()
,
may be able to display itself for editing by emulating a class that
is
supported on the user's machine.
In this case, the CLSID returned by a call
to
IRunnableObject::GetRunningClass()
will be that of the
class being
emulated, rather than the document's native class.
[out] Pointer to the object's class identifier.
This method supports the standard return values
E_INVALIDARG
and
E_UNEXPECTED
, as well as the following:
S_OK
CLSID was returned successfully.
- Determines whether an object is currently in the running state.
IRunnableObject::IsRunning()
BOOL IsRunning((
#include <objidl.h>
);
A container application could call
IRunnableObject::IsRunning()
when it
needs to know if the server is immediately available.
An object handler could call
IRunnableObject::IsRunning()
when it wants to
avoid conflicts 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
implementation of
OleIsRunning()
was changed so that it
calls
QueryInterface()
, asks for
IRunnableObject()
,
and then calls
IRunnableObject::IsRunning()
.
In other words,
you can use
the interface and the helper function interchangeably.
TRUE
The object is in the running state.
FALSE
The object is not in the running state.
- Locks an already running object into its running state or unlocks
it from its running state.
IRunnableObject::LockRunning()
HRESULT LockRunning((
#include <objidl.h>
BOOL fLock,
BOOL fLastUnlockCloses
);
Most implementations of
IRunnableObject::LockRunning()
call
CoLockObjectExternal()
.
OleLockRunning()
is a helper function that conveniently repackages the functionality offered
by
IRunnableObject::LockRunning()
.
With the release of
OLE 2.01, the
implementation of
OleLockRunning()
was changed to call
QueryInterface()
, ask for
IRunnableObject()
,
and then call
IRunnableObject::LockRunning()
.
In other
words, you can use
the interface and the helper function interchangeably.
[in]
TRUE
locks the object into its running
state.
FALSE
unlocks the object from its running state.
[in]
TRUE
specifies that if the connection
being
released
is the last external lock on the object, the object should close.
FALSE
specifies that the object should remain open until closed by the user or another
process.
This method supports the standard return values
E_FAIL
,
E_INVALIDARG
,
E_OUTOFMEMORY
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.
- Runs an object.
IRunnableObject::Run()
HRESULT Run((
#include <objidl.h>
LPBC lpbc
);
Containers call
IRunnableObject::Run()
to force their
objects to enter the
running state.
If the object is not already running, calling
IRunnableObject::Run()
can be an expensive operation, on
the order of many
seconds.
If the object is already running, then this method has no effect
on
the object.
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 offered by
IRunnableObject::Run()
.
With the
release
of OLE 2.01, the implementation of
OleRun
was changed so
that it calls
QueryInterface()
, asks for
IRunnableObject()
,
and then calls
IRunnableObject::Run()
.
In other words,
you can use the
interface and the helper function interchangeably.
The object should register in the running object table if it has a moniker assigned. The object should not hold any strong locks on itself; instead, it should remain in the unstable, unlocked state. The object should be locked when the first external connection is made to the object.
An embedded object must hold a lock on its embedding container while it is in the 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 application.
[in] Pointer to the binding context of the run operation.
May be
NULL
.
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.
- Notifies an object that it is embedded in an OLE container, which
ensures
that reference counting is done correctly for containers that support links
to embedded
objects.
IRunnableObject::SetContainedObject()
HRESULT SetContainedObject((
#include <objidl.h>
BOOL fContained
);
The
IRunnableObject::SetContainedObject()
method
enables a container to
inform an object handler that it is embedded in the container, rather than
acting as a link.
This call changes the container's reference on the object
from strong, the default for external connections, to weak.
When the object
is
running visibly, this 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 should not be able to hold an object in the running
state after the link has been broken.
For this reason, the container's
reference to the object must be weak.
A container application must call
IRunnableObject::SetContainedObject()
if
it supports linking to embedded objects.
It normally makes the call immediately
after calling
OleLoad()
or
OleCreate()
and never calls
the method again,
even before it closes.
Moreover, a container almost always calls this method
with
fContained
set to
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 container.
If your container application does not support linking to
embedded objects; it is preferable, but not necessary, to call
IRunnableObject::SetContainedObject()
.
OleSetContainedObject()
is a helper function that
conveniently repackages
the functionality offered by
IRunnableObject::SetContainedObject()
.
With
the release of OLE 2.01, the implementation of
OleSetContainedObject
was changed to call
QueryInterface()
, ask for
IRunnableObject()
,
and then call
IRunnableObject::SetContainedObject()
.
In
other words, you
can use the interface and the helper function interchangeably.
[in]
TRUE
specifies that the object is
contained
in an
OLE container.
FALSE
indicates that it is not.
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.
OleSetContainedObject()
,
OleNoteObjectVisible()
,
CoLockObjectExternal()
- Retrieves a pointer to the default COM task memory allocator (which
supports the system implementation of the
CoGetMalloc()
IMalloc()
interface) so applications can call its methods to manage memory.
HRESULT CoGetMalloc((
#include <objbase.h>
DWORD dwMemContext,
LPMALLOC * ppMalloc
);
The pointer to the
IMalloc()
interface pointer received
through the
ppMalloc
parameter cannot be used from a
remote process;
each process must have its own allocator.
[in] Reserved; value must be 1.
[out] Address of
IMalloc*
pointer variable
that receives
the
interface pointer to the memory allocator.
This function supports the standard return values
E_INVALIDARG
and
E_OUTOFMEMORY
, as well as the following:
S_OK
Indicates the allocator was retrieved successfully.
- Initializes COM library on the current apartment and identifies
the concurrency model as single-thread apartment (STA).
Applications
must initialize the COM library before they can call COM library functions
other than
CoInitialize()
CoGetMalloc()
and memory allocation functions.
New applications
should call
CoInitializeEx()
instead of
CoInitialize()
.
HRESULT CoInitialize((
#include <objbase.h>
LPVOID pvReserved
);
CoInitializeEx()
provides the same functionality
as
CoInitialize()
and also provides a parameter to explicitly specify the apartment's concurrency
model.
CoInitialize()
calls
CoInitializeEx()
and specifies the concurrency
model as single-thread apartment.
Applications developed today should call
CoInitializeEx()
rather than
CoInitialize()
.
You need initialize the COM library on an apartment before you call
any of the library functions
except
CoGetMalloc()
, to get a pointer to the standard
allocator, and the
memory allocation functions.
Typically, the COM library is initialized on an apartment only once.
Subsequent calls
will succeed, as long as they do not attempt to change the concurrency model,
but will
return
S_FALSE
.
To close the COM library gracefully, each
successful call
to
CoInitialize()
or
CoInitializeEx()
,
including those that
return
S_FALSE
,
must
be balanced by
a corresponding
call to
CoUninitialize()
.
Once the concurrency model for an apartment is set, it cannot be changed.
A call to
CoInitialize()
on an apartment that was previously initialized
as multithreaded will
fail and return
RPC_E_CHANGED_MODE
.
[in] Reserved; must be
NULL
.
This function supports the standard return values
E_INVALIDARG
,
E_OUTOFMEMORY
, and
E_UNEXPECTED
, as
well as the following:
S_OK
The COM library was initialized successfully on this apartment.
S_FALSE
The COM library is already initialized on this apartment.
RPC_E_CHANGED_MODE
A previous call to
CoInitializeEx()
specified
the
concurrency model for
this apartment as multithread apartment (MTA).
CoInitializeEx()
,
CoUninitialize()
,
OleInitialize
,
Processes and Threads
- Initializes the COM library for use by the current apartment and
specifies the apartment's concurrency model.
CoInitializeEx()
HRESULT CoInitializeEx((
#include <objbase.h>
void * pvReserved,
DWORD dwCoInit
);
If neither concurrency model is specified by the
dwCoInit
parameter, the default is
COINIT_APARTMENTTHREADED
.
Objects created on a COM thread in a multithread apartment (MTA) must be able to receive method calls from other threads at any time. You would typically implement some form of concurrency control in a multithreaded object's code using Win32 synchronization primitives such as critical sections, semaphores, or mutexes to protect the object's data.
Objects created in a single-threaded apartment (STA) receive method
calls
only from their apartment's thread, so calls are serialized and
arrive only at message-queue boundaries (PeekMessage
,
SendMessage
).
Apartments must call
CoInitializeEx()
or
CoInitialize()
before
calling any other COM library functions except
CoGetMalloc()
and other memory allocation calls (CoTaskMemAlloc()
,
CoTaskMemFree()
,
CoTaskMemReAlloc
, and
the
IMalloc()
methods on the task allocator supplied by
CoGetMalloc()
).
CoInitializeEx()
provides the same functionality
as
CoInitialize()
and also provides a parameter to explicitly
specify the
thread's concurrency model.
The current implementation of
CoInitialize()
calls
CoInitializeEx()
and specifies the concurrency model
as single-thread
apartment.
Applications developed today should call
CoInitializeEx()
rather than
CoInitialize()
.
Typically,
CoInitializeEx()
is called only once by
each apartment in the
process that uses the COM library.
For a multithread apartment, one call is sufficient for all threads in the
apartment.
Multiple calls to
CoInitializeEx()
by the same thread are
allowed as long as they pass the same concurrency flag, but subsequent valid
calls return
S_FALSE
.
To close the library gracefully,
each successful call to
CoInitialize()
or
CoInitializeEx()
,
including calls that return
S_FALSE
,
must
be balanced by a corresponding
call to
CoUninitialize()
.
Once the concurrency model for an apartment is set, it cannot be changed.
A call to
CoInitializeEx()
on an apartment that was previously initialized
with
a different concurrency model will fail and return
RPC_E_CHANGED_MODE
.
Because COM technologies are not thread-safe, the
OleInitialize
function calls
CoInitializeEx()
with the
COINIT_APARTMENTTHREADED
flag.
As a result, an apartment that is initialized for multi-threaded object concurrency
cannot use
the features enabled by
OleInitialize
.
[in] Reserved; must be
NULL
.
Flags specifying the concurrency model and initialization
options for
the
thread.
Values for this parameter are taken from the
COINIT
enumeration,
except that the
COINIT_APARTMENTTHREADED
and
COINIT_MULTITHREADED
flags cannot both be set.
This function supports the standard return values
E_INVALIDARG
,
E_OUTOFMEMORY
, and
E_UNEXPECTED
,
as well as the following:
S_OK
The COM library was initialized successfully.
S_FALSE
The COM library is already initialized.
RPC_E_CHANGED_MODE
A previous call to
CoInitializeEx()
specified
a different
concurrency
model for this thread.
COINIT
,
CoInitialize()
,
Processes and
Threads
- Allocates a block of task memory in the same way that
CoTaskMemAlloc()
IMalloc::Alloc()
does.
LPVOID CoTaskMemAlloc((
#include <objbase.h>
ULONG cb
);
The
CoTaskMemAlloc()
function uses the default allocator
to
allocate a memory block in the same way that
IMalloc::Alloc()
does.
It is not necessary to call the
CoGetMalloc()
function
before
calling
CoTaskMemAlloc()
.
The initial contents of the returned memory block are undefined - there is no guarantee that the block has been initialized. The allocated block may be larger than cb bytes because of the space required for alignment and for maintenance information.
If
cb
is zero,
CoTaskMemAlloc()
allocates a zero-length item and
returns a valid pointer to that item.
If there is insufficient memory
available,
CoTaskMemAlloc()
returns
NULL
.
Applications should always check the return value from this method, even when requesting small amounts of memory, because there is no guarantee the memory will be allocated.
[in] Size, in bytes, of the memory block to be allocated.
Memory block allocated successfully.
NULL
Insufficient memory available.
IMalloc::Alloc()
,
CoGetMalloc()
,
CoTaskMemFree()
,
CoTaskMemRealloc()
- Frees a block of task memory previously allocated through a call to the
CoTaskMemFree()
CoTaskMemAlloc()
or
CoTaskMemRealloc()
function.
void CoTaskMemFree((
#include <objbase.h>
void pv
);
The
CoTaskMemFree()
function, using the default COM
allocator,
frees a block of memory previously allocated through a call to the
CoTaskMemAlloc()
or
CoTaskMemRealloc()
function.
The number of bytes freed equals the number of bytes that were originally allocated or reallocated. After the call, the memory block pointed to by pv is invalid and can no longer be used.
The pv parameter can be
NULL
, in which case this method has no effect.
[in] Pointer to the memory block to be freed.
CoTaskMemAlloc()
,
CoTaskMemRealloc()
,
CoGetMalloc()
,
IMalloc::Free()
- Changes the size of a previously allocated block of task memory.
CoTaskMemRealloc()
LPVOID CoTaskMemRealloc((
#include <objbase.h>
LPVOID pv,
ULONG cb
);
The
CoTaskMemRealloc()
function changes the size
of a previously
allocated memory block in the same way that
IMalloc::Realloc()
does.
It is not necessary to call the
CoGetMalloc()
function
to get
a pointer to the COM allocator before calling
CoTaskMemRealloc()
.
The
pv
argument points to the beginning of the
memory block.
If
pv
is
NULL
,
CoTaskMemRealloc()
allocates a new memory block in the
same way as the
CoTaskMemAlloc()
function.
If
pv
is not
NULL
, it should be a pointer returned by a prior call to
CoTaskMemAlloc()
.
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 different memory location, the pointer returned by
CoTaskMemRealloc()
is not guaranteed 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.
CoTaskMemRealloc()
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 argument is not
NULL
, or if there is not enough
memory available to
expand the block to 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
aligned for storage of any type of object.
To get a pointer to a type other
than
void
, use a type cast on the return value.
[in] Pointer to the memory block to be reallocated.
It can
be a
NULL
pointer, as discussed in the Remarks.
[in] Size, in bytes, of the memory block to be reallocated. It can be zero, as discussed in the following remarks.
Memory block successfully reallocated.
NULL
Insufficient memory or
cb
is zero and
pv
is not
NULL
.
CoTaskMemAlloc()
,
CoTaskMemFree()
,
CoGetMalloc()
,
IMalloc::Realloc()
- Closes the COM library on the current apartment, unloads all DLLs loaded by
the apartment, and frees any resources that it maintains, and forces all RPC
connections
on the apartment to close.
CoUninitialize()
void CoUninitialize((
#include <objbase.h>
);
The
CoInitialize()
and
CoUninitialize()
calls must
call
CoUninitialize()
once for each successful call it
has made
to
CoInitialize()
or
CoInitializeEx()
.
Only the
CoUninitialize()
call corresponding to the
CoInitialize()
call that
initialized the library can close it.
Calls to
OleInitialize
must be balanced by calls
to
OleUnitialize
.
The
OleUninitialize
function
calls
CoUninitialize()
internally, so
applications that call
OleUninitialize
do not also need
to call
CoUninitialize()
.
CoUninitialize()
should be called on application
shutdown, as the last
call made to the COM library after the application hides its main windows
and
falls through its main message loop.
If there are open conversations remaining,
CoUninitialize()
starts a modal message loop and dispatches
any pending
messages from the containers or server for this COM application.
By dispatching
the messages,
CoUninitialize()
ensures that the application
does not quit
before receiving all of its pending messages.
Non-COM messages are discarded.
CoInitialize()
,
CoInitializeEx()
- Registers an implementation of the
CoRegisterMallocSpy()
IMallocSpy()
interface
in COM, thereafter
requiring COM to call its wrapper methods around every call to the corresponding
IMalloc()
method.
IMallocSpy()
is defined in COM to allow developers
to debug memory allocations.
HRESULT CoRegisterMallocSpy((
#include <objbase.h>
LPMALLOCSPY pMallocSpy
);
The
CoRegisterMallocSpy()
function registers the
IMallocSpy()
object, which is used to debug calls to
IMalloc()
methods.
The function calls
QueryInterface()
on the
pointer
pMallocSpy
for the interface
IID_IMallocSpy
.
This is to
ensure that
pMallocSpy
really points to an implementation
of
IMallocSpy()
.
By the rules of COM, it is expected that
a successful call
to
QueryInterface()
has added a reference (through the
AddRef
method) to the
IMallocSpy()
object.
That
is,
CoRegisterMallocSpy()
does not directly call
AddRef()
on
pMallocSpy, but fully expects that the
QueryInterface()
call
will.
When the
IMallocSpy()
object is registered, whenever
there is a call to
one of the
IMalloc()
methods, COM first calls the corresponding
IMallocSpy()
pre-method.
Then, after executing the
IMalloc()
method,
COM calls the corresponding
IMallocSpy()
post-method.
For
example,
whenever there is a call to
IMalloc::Alloc()
, from whatever
source, COM
calls
IMallocSpy::PreAlloc()
, calls
IMalloc::Alloc()
, and after that
allocation is completed, calls
IMallocSpy::PostAlloc()
.
[in] Pointer to an instance of the
IMallocSpy()
implementation.
This function supports the standard return value
E_INVALIDARG
, as well
as the following:
S_OK
The
IMallocSpy()
object is successfully
registered.
CO_E_OBJISREG
There is already a registered spy.
IMallocSpy()
,
CoRevokeMallocSpy()
,
CoGetMalloc()
- Revokes a registered
CoRevokeMallocSpy()
IMallocSpy()
object.
HRESULT CoRevokeMallocSpy((
#include <objbase.h>
);
The
IMallocSpy()
object is released when it is revoked.
This
release corresponds to the call to
IUnknown::AddRef()
in
the
implementation of the
QueryInterface()
function by the
CoRegisterMallocSpy()
function.
The implementation of the
IMallocSpy()
interface should then do any appropriate cleanup.
If the return code is
E_ACCESSDENIED
, there are still
outstanding allocations
that were made while the spy was active.
In this case, the registered spy
cannot be revoked at this time because it may have attached arbitrary headers
and/or trailers to these allocations that only the spy knows about.
Only the
spy's
PreFree
(or
PreRealloc
) method
knows how to account for
these headers and trailers.
Before returning
E_ACCESSDENIED
,
CoRevokeMallocSpy()
notes internally that a revoke is pending.
When the
outstanding allocations have been freed, the revoke proceeds automatically,
releasing the
IMallocSpy()
object.
Thus, it is necessary
to call
CoRevokeMallocSpy()
only once for each call to
CoRegisterMallocSpy()
,
even if
E_ACCESSDENIED
is returned.
S_OK
The
IMallocSpy()
object is successfully
revoked.
CO_E_OBJNOTREG
No spy is currently registered.
E_ACCESSDENIED
Spy is registered but there are outstanding allocations (not yet freed) made while this spy was active.
IMallocSpy()
,
CoRegisterMallocSpy()
,
CoGetMalloc()
- Looks up a CLSID in the registry, given a ProgID.
CLSIDFromProgID()
HRESULT CLSIDFromProgID((
#include <objbase.h>
LPCOLESTR lpszProgID,
LPCLSID pclsid
);
Given a ProgID,
CLSIDFromProgID()
looks up its associated
CLSID in
the registry.
If the ProgID cannot be found in the registry,
CLSIDFromProgID()
creates an OLE 1 CLSID for the ProgID
and a CLSID
entry in the registry.
Because of the restrictions placed on OLE 1 CLSIDs,
CLSIDFromProgID()
and
CLSIDFromString()
are the
only
two functions that can be used to generate a CLSID
for an
OLE 1 object.
[in] Pointer to the ProgID whose CLSID is requested.
[out] Pointer to the retrieved CLSID on return.
S_OK
The CLSID was retrieved successfully.
CO_E_CLASSSTRING
The registered CLSID for the ProgID is invalid.
REGDB_E_WRITEREGDB
An error occurred writing the CLSID to the registry. See Description.
- Converts a string generated by the
CLSIDFromString()
StringFromCLSID()
function
back into the original CLSID.
HRESULT CLSIDFromString((
#include <objbase.h>
LPOLESTR lpsz,
LPCLSID pclsid
);
Because of the restrictions placed on OLE 1 CLSID values,
CLSIDFromProgID()
and
CLSIDFromString()
are the
only
two functions that can be used to generate a CLSID for an OLE 1 object.
[in] Pointer to the string representation of the CLSID.
[out] Pointer to the CLSID on return.
This function supports the standard return value
E_INVALIDARG
, as well
as the following:
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.
CLSIDFromProgID()
,
StringFromCLSID()
- Creates a GUID, a unique 128-bit integer used for CLSIDs and interface identifiers.
CoCreateGuid()
HRESULT CoCreateGuid((
#include <objbase.h>
GUID * pguid
);
The
CoCreateGuid()
function calls the RPC function
UuidCreate
, which creates a GUID, a globally unique 128-bit
integer.
Use
the
CoCreateGuid()
function when you need 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 returns a unique value--no other
invocation, on the same or any other system (networked or not), should return
the same value.
[out] Pointer to the requested GUID on return.
S_OK
The GUID was successfully created.
Win32 errors are returned by
UuidCreate
but wrapped
as an
HRESULT
.
UuidCreate
<
(documented in
the
RPC Programmer's
Guide and Reference)>
- Converts the MS-DOS representation of the time and date to a
CoDosDateTimeToFileTime()
FILETIME
structure, which Win32 uses to determine
the date and time.
BOOL CoDosDateTimeToFileTime((
#include <objbase.h>
WORD nDosDate,
WORD nDosTime,
FILETIME * lpFileTime
);
The
FILETIME
structure and the
CoDosDateTimeToFileTime()
and
CoFileTimeToDosDateTime()
functions are part of the Win32
API
definition.
They are provided for compatibility in all OLE 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). |
[in] 16-bit MS-DOS date.
[in] 16-bit MS-DOS time.
[out] Pointer to the
FILETIME
structure.
TRUE
The
FILETIME
structure was created successfully.
FALSE
The
FILETIME
structure was not created
successfully,
probably
because of invalid arguments.
CoFileTimeToDosDateTime()
,
CoFileTimeNow()
- Returns the current time as a
CoFileTimeNow()
FILETIME
structure.
HRESULT CoFileTimeNow((
#include <objbase.h>
FILETIME * lpFileTime
);
[out] Pointer to return the
FILETIME
structure.
S_OK
The current time was converted to a
FILETIME
structure.
CoDosDateTimeToFileTime()
,
CoFileTimeToDosDateTime()
- Converts a
CoFileTimeToDosDateTime ()
FILETIME
into MS-DOS date and time
values.
BOOL CoFileTimeToDosDateTime((
#include <objbase.h>
FILETIME * lpFileTime,
LPWORD lpDosDate,
LPWORD lpDosTime
);
This is the inverse of the operation provided by the
CoDosDateTimeToFileTime()
function.
[in] Pointer to the
FILETIME
structure
to be converted.
[out] Pointer to the 16-bit MS-DOS date.
[out] Pointer to the 16-bit MS-DOS time.
TRUE
The
FILETIME
structure was converted successfully.
FALSE
The
FILETIME
structure was not converted
successfully.
CoDosDateTimeToFileTime()
,
CoFileTimeNow()
- Returns a value that is unique to the current thread.
It can be
used to avoid
CoGetCurrentProcess()
PROCESSID
reuse problems.
DWORD CoGetCurrentProcess((
#include <objbase.h>
);
The
CoGetCurrentProcess
function returns a value
that is
effectively unique, because it is not used again until 232
more
threads have been created on the current workstation or until the workstation
is rebooted.
Using the value returned from a call to
CoGetCurrentProcess()
can help you
maintain 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
HTASK
task handle value returned by the Win32
function
GetCurrentTask
, because Windows task handles can be reused
relatively
quickly when a window's task dies.
DWORD
valueUnique value for the current thread that can be used to avoid
PROCESSID
reuse
problems.
- Converts a string generated by the
IIDFromString()
StringFromIID()
function
back into the original interface identifier (IID).
WINOLEAPI IIDFromString((
#include <objbase.h>
LPOLESTR lpsz,
LPIID lpiid
);
The function converts the interface identifier in a way that guarantees different interface identifiers will always be converted to different strings.
[in] Pointer to the string representation of the IID.
[out] Pointer to the requested IID on return.
This function supports the standard return values
E_INVALIDARG
and
E_OUTOFMEMORY
, as well as the following:
S_OK
The string was successfully converted.
- Determines whether two GUIDs are equal.
IsEqualGUID()
BOOL IsEqualGUID((
#include <objbase.h>
REFGUID rguid1,
REFGUID rguid2
);
IsEqualGUID()
is used by the
IsEqualCLSID()
and
IsEqualIID()
functions.
[in] GUID to compare to rguid2.
[in] GUID to compare to rguid1.
TRUE
The GUIDs are equal.
FALSE
The GUIDs are not equal.
- Determines whether two CLSIDs are equal.
IsEqualCLSID()
BOOL IsEqualCLSID((
#include <winerror.h>
REFCLSID rclsid1,
REFCLSID rclsid2
);
[in] CLSID to compare to rclsid2.
[in] CLSID to compare to rclsid1.
TRUE
The CLSIDs are equal.
FALSE
The CLSIDs are not equal.
- Determines whether two interface identifiers are equal.
IsEqualIID()
BOOL IsEqualIID((
#include <winerror.h>
REFGUID riid1,
REFGUID riid2
);
[in] Interface identifier to compare with riid2.
[in] Interface identifier to compare with riid1.
TRUE
The interface identifiers are equal.
FALSE
The interface identifiers are not equal.
- Supplies a pointer to the
GetRunningObjectTable()
IRunningObjectTable()
interface
on the local Running Object Table (ROT).
WINOLEAPI GetRunningObjectTable((
#include <objbase.h>
DWORD reserved,
LPRUNNINGOBJECTTABLE * pprot
);
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
IRunningObjectTable()
interface pointer, which provides
access to
that table.
Moniker providers, which hand out monikers that identify objects so
they are
accessible to others, should call
GetRunningObjectTable()
.
Use the
interface pointer returned by this function to register your objects when
they
begin running, to record the times that those objects are modified, and to
revoke their registrations when they stop running.
See the
IRunningObjectTable()
interface for more information.
Compound-document link sources are the most common example of moniker providers. These include server applications that support linking to their documents (or portions of a document) and container applications that support linking to embeddings 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 implementations
of
the
IBindCtx()
interface to modify binding behavior.
[in] Reserved for future use; must be zero.
[out] Address of
IRunningObjectTable*
pointer
variable
that receives the interface pointer to the local ROT.
When the function is successful, the caller
is responsible for calling
IUnknown::Release()
on the interface
pointer.
If an error occurs,
pprot
is undefined.
This function supports the standard return value
E_UNEXPECTED
, as well
as the following:
S_OK
An
IRunningObjectTable()
pointer was successfully
returned.
IBindCtx::GetRunningObjectTable()
,
IMoniker
,
IRunningObjectTable()
- Retrieves the ProgID for a given CLSID.
ProgIDFromCLSID()
WINOLEAPI ProgIDFromCLSID((
#include <objbase.h>
REFCLSID clsid,
LPOLESTR * lplpszProgID
);
Every COM object class listed in the Insert Object dialog box must have a programmatic identifier (ProgID), a string that uniquely identifies a given class, stored in the registry. In addition to determining the eligibility for the Insert Object dialog box, the ProgID can be used as an identifier in a macro programming language to identify a class. Finally, the ProgID is also the class name used for an object of an COM class that is placed in an OLE 1 container.
The
ProgIDFromCLSID
function uses entries in the
registry to do the
conversion.
COM application authors are responsible for ensuring that the
registry is configured correctly in the application's setup program.
The ProgID string must be different than the class name of any OLE 1 application, including the OLE 1 version of the same application, if there is one. In addition, a ProgID string must not contain more than 39 characters, start with a digit, or, except for a single period, contain any punctuation (including underscores).
The ProgID must never be shown to the user in the user interface.
Call the
CLSIDFromProgID()
function to find the CLSID
associated
with a given ProgID.
CLSIDs can be freed with the task allocator (refer to
the
CoGetMalloc()
function).
[in] Specifies the CLSID for which the ProgID is requested.
[out] Address of
LPOLESTR
pointer variable
that receives
a pointer
to the ProgID string.
S_OK
The ProgID was returned successfully.
REGDB_E_CLASSNOTREG
Class not registered in the registry.
REGDB_E_READREGDB
Error reading registry.
- Converts a CLSID into a string of printable characters.
Different
CLSIDs always convert to different strings.
StringFromCLSID()
WINOLEAPI StringFromCLSID((
#include <objbase.h>
REFCLSID rclsid,
LPOLESTR * ppsz
);
The
StringFromCLSID
function calls the
StringFromGuid2
function to convert a globally unique identifier (GUID) into a string of
printable characters.
[in] CLSID to be converted.
[out] Address of
LPOLESTR
pointer variable
that receives
a pointer to the
resulting string.
This function supports the standard return value
E_OUTOFMEMORY
; as well
as the following:
S_OK
Indicates the CLSID was successfully converted and returned.
CLSIDFromString()
,
StringFromGuid2
- Converts a globally unique identifier (GUID) into a string of printable characters.
StringFromGUID2()
StringFromGUID2(
#include <objbase.h>
REFGUID rguid,
LPOLESTR lpsz,
int cbMax
);
The string that the lpsz parameter receives has a format like that of the following sample:
{c200e360-38c5-11ce-ae62-08002b2b79ef}
where the successive fields break the GUID into the form
DWORD-WORD-WORD-WORD-WORD.DWORD
covering the 128-bit GUID.
The string includes
enclosing braces, which are a COM convention.
[in] Interface identifier to be converted.
[out] Pointer to the resulting string on return.
[in] Maximum size the returned string is expected to be.
Buffer is too small for returned string.
The number of characters in the returned string, including the null terminator.
- Converts an interface identifier into a string of printable characters.
StringFromIID()
WINOLEAPI StringFromIID((
#include <objbase.h>
REFIID rclsid,
LPOLESTR * lplpsz
);
The string returned by the function is freed in the standard way, using
the task allocator (refer to the
CoGetMallocfunction()
).
[in] Interface identifier to be converted.
[out] Address of
LPOLESTR
pointer variable
that receives
a pointer
to the resulting string.
This function supports the standard return value
E_OUTOFMEMORY
; as well
as the following:
S_OK
The character string was successfully returned.
IIDFromString()
,
CoGetMalloc()
- Registers with OLE the instance of an EXE application's interface,
which is to be used for handling concurrency issues.
DLL object applications
cannot register a message filter.
CoRegisterMessageFilter()
HRESULT CoRegisterMessageFilter((
#include <objbase.h>
LPMALLOCSPY lpMessageFilter,
LPMESSAGEFILTER * lplpMessageFilter
);
[in] Pointer to the
IMessageFilter()
interface on the message filter supplied by the application.
Can be
NULL
,
indicating that the current
IMessageFilter()
registration
should be
revoked.
[out] Address of
IMessageFilter()
* pointer
variable
that receives the
interface pointer to the previously registered message filter.
If there was
no
previously registered message filter, the value of *lplpMessageFilter
is
NULL
.
The value contained in the output variable is rarely
NULL
, however, containing instead a pointer to the default
message filter.
S_OK
The
IMessageFilter()
instance registered
or revoked
successfully.
S_FALSE
Error registering or revoking
IMessageFilter()
instance.
- A set
of values from the
COINIT()
COINIT
enumeration is passed as the
dwCoInit
parameter to
CoInitializeEx()
.
This
value determines the concurrency model used for incoming calls to objects
created by this thread.
This concurrency model can be either apartment-threaded
or multi-threaded.
COINIT(
);
#include <objbase.h>
The
COINIT
enumeration is defined as follows:
typedef enum tagCOINIT{ COINIT_APARTMENTTHREADED = 0x2, // Apartment model COINIT_MULTITHREADED = 0x0, // COM calls objects on any thread. } COINIT;
When a thread is initialized through a call to
CoInitializeEx()
, you choose whether to initialize it as apartment-threaded or
multi-threaded by designating one of the members of
COINIT
as its second parameter.
This designates how incoming calls to any object
created by that thread are handled, that is, the object's concurrency.
Apartment-threading, while allowing for multiple threads of execution,
serializes all incoming calls by requiring that calls to methods of objects
created by this thread always run on the same thread--the apartment/thread
that created them.
In addition,
calls
can arrive only at message-queue boundaries (i.e., only during a
PeekMessage
,
SendMessage
,
DispatchMessage
, etc.).
Because
of this serialization, it is not typically necessary to write concurrency
control into the code for the object, other than to avoid calls to
PeekMessage
and
SendMessage
during
processing that must not be interrupted by other method invocations or calls
to
other objects in the same apartment/thread.
Multi-threading (also called free-threading) allows calls to methods of objects created by this thread to be run on any thread. There is no serialization of calls--many calls may occur to the same method or to the same object or simultaneously. Multi-threaded object concurrency offers the highest performance and takes the best advantage of multi-processor hardware for cross-thread, cross-process, and cross-machine calling, since calls to objects are not serialized in any way. This means, however, that the code for objects must enforce its own concurrency model, typically through the use of Win32 synchronization primitives, such as critical sections, semaphores, or mutexes. In addition, because the object doesn't control the lifetime of the threads that are accessing it, no thread-specific state may be stored in the object (in Thread-Local-Storage).
COINIT_MULTITHREADED
Initializes the thread for multi-threaded object concurrency (see Description).
COINIT_APARTMENTTHREADED
Initializes the thread for apartment-threaded object concurrency (see Description).
CoInitializeEx()
,
Processes and Threads