APTCLIEN - Client of apartment-threaded, out-of-process local server


SUMMARY
=======

The APTCLIEN sample shows a client of the APTSERVE apartment-threaded
server. APTCLIEN is a client of the multiple component apartments in
APTSERVE. Its main purpose is to exercise and reveal for study the
multiple apartments in the APTSERVE local out-of-process server.  The
following REMCLIEN sample, run in conjunction with APTCLIEN, shows the
effects of multiple clients on the APTSERVE multithreaded server, with one
client controlling from a remote machine.

The COM objects that APTCLIEN manipulates are the car-related ones from
previous samples in this tutorial series, with the following interfaces:
ICar, IUtility, and ICruise. APTCLIEN works in conjunction with the
separate APTSERVE.EXE, which provides the COCar, COUtilityCar, and
COCruiseCar COM objects.

APTCLIEN.EXE creates its own COUtilityCruiseCar COM object by reusing the
COCruiseCar COM object by containment and augmenting it with a native
implementation of the IUtility interface. Like LOCCLIEN, APTCLIEN's
COUtilityCruiseCar composite object reuses COCruiseCar by containment.
However, because COCruiseCar and COCar are in different apartments,
COCruiseCar reuses COCar by containment.

The composition of COUtilityCruiseCar is also interesting because the
COUtilityCruiseCar object's containment of the COCruiseCar object crosses
the process boundary between APTCLIEN and the out-of-process local server
APTSERVE.EXE. In addition, COCruiseCar's containment of COCar crosses
thread boundaries within APTSERVE. APTCLIEN uses standard marshaling
support for the custom interfaces it uses on the COCruiseCar and COCar
objects. This marshaling support is provided by the previous MARSHAL
code sample, so you must build the MARSHAL code sample prior to building
and running APTCLIEN and APTSERVE.

For functional descriptions and a tutorial code tour of APTCLIEN, see the
Code Tour section below. See also APTSERVE.TXT in the sibling \APTSERVE
directory for more details on how APTSERVE works and exposes its services
to APTCLIEN. You must build APTSERVE.EXE before building APTCLIEN. The
makefile for APTSERVE automatically registers that server in the registry,
so you must build APTSERVE before attempting to run APTCLIEN. For details
on the external user operation of APTCLIEN, see the Operation section
below.

For details on setting up your system to build and test the code samples
in this OLE Tutorial series, see TUTORIAL.TXT. The supplied MAKEFILE is
Microsoft NMAKE-compatible. To create a debug build, issue the NMAKE
command in the Command Prompt window.

Usage
-----

APTCLIEN is an application that you can execute directly from Windows in
the normal manner or from the Command Prompt window. No command line
parameters are recognized by APTCLIEN.


OPERATION
=========

The APTCLIEN.EXE application provides the user interface for this lesson.
It exercises the associated, but independent, APTSERVE.EXE out-of-process
local server. Here is a summary of operation from the standpoint of
APTCLIEN.EXE as a COM client of the APTSERVE.EXE COM server.

The APTCLIEN and APTSERVE samples are directly analogous to the LOCCLIEN
and LOCSERVE samples. The same components are used, and the same menu
system exercises those objects.

As in the LOCCLIEN code sample, support is provided for a trace logging
facility that will display in the APTCLIEN client application an
integrated trace log of activity in both client and server.

Although APTCLIEN functions much like the prior LOCCLIEN sample, here is a
short review for those readers who are visiting this code sample out of
sequence. The COM objects that are used in the APTCLIEN and APTSERVE code
samples represent sport utility vehicles. We invent some basic feature
sets for modeling such car objects. These feature sets are implemented as
interfaces to COM objects. The ICar interface provides some basic car
behavior: Shift, Clutch, Speed, and Steer. The IUtility interface provides
off-road utility systems: Offroad and Winch. The ICruise interface
provides automatic cruise control facilities: Engage and Adjust.

APTCLIEN.EXE provides menus for creating, releasing, and invoking methods
for four COM objects: COCar, COUtilityCar, COCruiseCar, and
COUtilityCruiseCar. These objects have combinations of the ICar, IUtility,
and ICruise interfaces. COCar objects expose the ICar interface.
COUtilityCar objects expose the ICar and IUtility interfaces. COCruiseCar
objects expose the ICar and ICruise interfaces. COUtilityCruiseCar objects
expose the ICar, ICruise, and IUtility interfaces. As a result, COCar
objects have only the basic car behavior (ICar). COUtilityCar objects have
basic car behavior (ICar) with sport utility systems (IUtility).
COCruiseCar objects have basic car behavior (ICar) with an automatic
cruise control system (ICruise). COUtilityCruiseCar objects have basic car
behavior (ICar), a cruise control system (ICruise), and a sport utility
system (IUtility).

COCar is constructed as an aggregatable COM object with a native
implementation of the ICar interface. COUtilityCar is constructed using
containment and is implemented in APTSERVE.EXE. For details, see the
APTSERVE lesson. COCruiseCar is also constructed using containment and is
also implemented in APTSERVE.EXE. COUtilityCruiseCar is constructed using
containment and is implemented in APTCLIEN.EXE. In this sample,
COUtilityCruiseCar reuses COCruiseCar by containment, which in turn reuses
COCar by containment to illustrate three levels of nested object reuse by
containment.

APTCLIEN.EXE presents a menu for each of these four main COM objects. Each
menu has commands that call the methods of the various available
interfaces. The code samples (both APTCLIEN and APTSERVE) issue trace
message log statements throughout. When you exercise the objects from
APTCLIEN.EXE, the main APTCLIEN window will display a log of internal
activity in these COM objects.

Here is a description of the menu operation of APTCLIEN.

Menu Selection: File/Exit
Exits APTCLIEN.

Menu Selection: Car/Create
Creates a COCar COM object. A checkmark beside the menu item indicates
that there is already an instance of the object.

Menu Selection: Car/Release
Releases the COCar COM object.

Menu Selection: Car/ICar::Shift
Calls the ICar::Shift method on the COCar object.

Menu Selection: Car/ICar::Clutch
Calls the ICar::Clutch method on the COCar object.

Menu Selection: Car/ICar::Speed
Calls the ICar::Speed method on the COCar object.

Menu Selection: Car/ICar::Steer
Calls the ICar::Steer method on the COCar object.

Menu Selection: UtilityCar/Create
Creates the COUtilityCar COM object. A checkmark beside the menu item
indicates that there is already an instance of the object.

Menu Selection: UtilityCar/Release
Releases the COUtilityCar COM object.

Menu Selection: UtilityCar/ICar::Shift
Calls the ICar::Shift method on the COUtilityCar object.

Menu Selection: UtilityCar/ICar::Clutch
Calls the ICar::Clutch method on the COUtilityCar object.

Menu Selection: UtilityCar/ICar::Speed
Calls the ICar::Speed method on the COUtilityCar object.

Menu Selection: UtilityCar/ICar::Steer
Calls the ICar::Steer method on the COUtilityCar object.

Menu Selection: UtilityCar/IUtility::Offroad
Calls the IUtility::Offroad method on the COUtilityCar object.

Menu Selection: UtilityCar/IUtility::Winch
Calls the IUtility::Winch method on the COUtilityCar object.

Menu Selection: CruiseCar/Create
Creates the COCruiseCar COM object. A checkmark beside the menu item
indicates that there is already an instance of the object.

Menu Selection: CruiseCar/Release
Releases the COCruiseCar COM object.

Menu Selection: CruiseCar/ICar::Shift
Calls the ICar::Shift method on the COCruiseCar object.

Menu Selection: CruiseCar/ICar::Clutch
Calls the ICar::Clutch method on the COCruiseCar object.

Menu Selection: CruiseCar/ICar::Speed
Calls the ICar::Speed method on the COCruiseCar object.

Menu Selection: CruiseCar/ICar::Steer
Calls the ICar::Steer method on the COCruiseCar object.

Menu Selection: CruiseCar/ICruise::Engage
Calls the ICruise::Engage method on the COCruiseCar object.

Menu Selection: CruiseCar/ICruise::Adjust
Calls the ICruise::Adjust method on the COCruiseCar object.

Menu Selection: UtilityCruiseCar/Create
Creates the COUtilityCruiseCar COM object. A checkmark beside the menu
item indicates that there is already an instance of the object.

Menu Selection: UtilityCruiseCar/Release
Releases the COUtilityCruiseCar COM object.

Menu Selection: UtilityCruiseCar/ICar::Shift
Calls the ICar::Shift method on the COUtilityCruiseCar object.

Menu Selection: UtilityCruiseCar/ICar::Clutch
Calls the ICar::Clutch method on the COUtilityCruiseCar object.

Menu Selection: UtilityCruiseCar/ICar::Speed
Calls the ICar::Speed method on the COUtilityCruiseCar object.

Menu Selection: UtilityCruiseCar/ICar::Steer
Calls the ICar::Steer method on the COUtilityCruiseCar object.

Menu Selection: UtilityCruiseCar/ICruise::Engage
Calls the ICruise::Engage method on the COUtilityCruiseCar object.

Menu Selection: UtilityCruiseCar/ICruise::Adjust
Calls the ICruise::Adjust method on the COUtilityCruiseCar object.

Menu Selection: UtilityCruiseCar/IUtility::Offroad
Calls the IUtility::Offroad method on the COUtilityCruiseCar object.

Menu Selection: UtilityCruiseCar/IUtility::Winch
Calls the IUtility::Winch method on the COUtilityCruiseCar object.

Menu Selection: Log/Clear
Clears the trace message log display.

Menu Selection: Log/Logging
Toggles the trace message logging facility on or off. A checkmark beside
the menu item indicates that logging is on. Logging can be engaged but
simply turned on or off. Unchecking this command turns the trace message
logging facility off but does not disengage the logging mechanisms.

Menu Selection: Log/Copy
Copies the current contents of the trace message log to the Windows
Clipboard.

Menu Selection: Help/Read APTCLIEN.TXT
Opens the APTCLIEN.TXT file (this file) in the Windows Notepad.

Menu Selection: Help/Read APTSERVE.TXT
Opens the APTSERVE.TXT file from the sibling \APTSERVE directory in the
Windows Notepad.

Menu Selection: Help/Read MARSHAL.TXT
Opens the MARSHAL.TXT file from the sibling \MARSHAL directory in the
Windows Notepad.

Menu Selection: Help/Read Source File
Displays the Open common dialog box so you can open a source file from
this lesson or another one in the Windows Notepad.

Menu Selection: Help/About APTCLIEN
Displays the About dialog box for this application.

Menu Selection: Help/About APTSERVE
Displays the About dialog box for APTSERVE.EXE, which is used by this
application.


CODE TOUR
=========

Files          Description

APTCLIEN.TXT   This file.
MAKEFILE       The generic makefile for building the code sample
               application of this tutorial lesson.
APTCLIEN.H     The include file for the APTCLIEN application. Contains
               class declarations, function prototypes, and resource
               identifiers.
APTCLIEN.CPP   The main implementation file for APTCLIEN.EXE. Has WinMain
               and CMainWindow implementation, as well as the main menu
               dispatching.
APTCLIEN.RC    The application resource definition file.
APTCLIEN.ICO   The application icon resource.
UTCRUCAR.H     The class declaration for the COUtilityCruiseCar COM object.
UTCRUCAR.CPP   Implementation file for the COUtilityCruiseCar COM object.
               Also has the definition of the CreateUtilityCruiseCar
               function.

Like all code samples in the series, APTCLIEN uses many of the utility
classes and services provided by APPUTIL. For more details on APPUTIL,
study the APPUTIL library source code and APPUTIL.TXT, which are located
in the sibling \APPUTIL directory.

The goal of this lesson is to examine the internal behavior of the
APTCLIEN and APTSERVE client/server pair. As a client, APTCLIEN offers
nothing beyond what was shown in LOCCLIEN. The significant difference is
simply the use of different CLSIDs (CLSID_AptCar, CLSID_AptUtilityCar, and
CLSID_AptCruiseCar) for the creation of the APTSERVE objects to be
controlled.

We will tour internal behavior in both APTCLIEN and APTSERVE by looking at
some representative trace logs. Trace lines that begin with "C:" mark
behavior reported in the APTCLIEN.EXE client. Lines that begin with "L:"
mark behavior reported in the APTSERVE.EXE local out-of-process server.
The internal APTSERVE trace lines will also show the thread ID of the
executing thread in angle brackets after the "L". Since the client is
single-threaded, its thread ID is not shown. These trace logs were
obtained under the Windows 95 operating system. Because a multithreaded
program is being traced, your results may be slightly different if you
replicate this logged behavior on you own machine. For example, the
server's AptThreadProc function will execute at different times depending
on the operating system's task load and scheduling priorities.

After running APTCLIEN, choose the Create command from the Car menu. Here
is the resulting trace log.

  C: === Car Menu: Create.
  L: APTSERVE now logging to client.
  L<FFFE7005>: CmdLine Switches= -Embedding
  L<FFFE7005>: CServer::OpenFactories. Begin.
  L: CServer::OwnThis. Thread <FFFE7005> waiting to own CServer.
  L: CServer::OwnThis. CServer now owned by Thread <FFFE7005>.
  L<FFFE7005>: CFCar::CImpIClassFactory Constructor. Non-Aggregating.
  L<FFFE7005>: CFCar Constructor. m_pUnkOuter=0x0.
  L<FFFE7005>: CFUtilityCar::CImpIClassFactory Constructor. Non-Aggregating.
  L<FFFE7005>: CFUtilityCar Constructor. m_pUnkOuter=0x0.
  L<FFFE7005>: CFCruiseCar::CImpIClassFactory Constructor. Non-Aggregating.
  L<FFFE7005>: CFCruiseCar Constructor. m_pUnkOuter=0x0.
  L<FFFE7005>: CServer::OpenFactories. AptCar.
  L<FFFE7005>: CFCar::AddRef. New cRefs=1.
  L<FFFE7005>: CFCar::AddRef. New cRefs=2.
  L<FFFE7005>: CServer::OpenFactories. AptUtilityCar.
  L<FFFE7005>: CFUtilityCar::AddRef. New cRefs=1.
  L<FFFE7005>: CFUtilityCar::AddRef. New cRefs=2.
  L<FFFE7005>: CServer::OpenFactories. AptCruiseCar.
  L<FFFE7005>: CFCruiseCar::AddRef. New cRefs=1.
  L: AptThreadProc. Starting Apartment Thread <FFFEE289>.
  L: AptThreadProc. Starting Apartment Thread <FFFEE4B1>.
  L<FFFE7005>: CFCruiseCar::AddRef. New cRefs=2.
  L: AptThreadProc. Registering class factory of apartment <FFFEE289>.
  L: AptThreadProc. Registering class factory of apartment <FFFEE4B1>.
  L<FFFEE289>: CFCar::AddRef. New cRefs=3.
  L<FFFEE4B1>: CFUtilityCar::AddRef. New cRefs=3.
  L: CServer::UnOwnThis. Ownership relinquished by <FFFE7005>.
  L<FFFE7005>: CServer::OpenFactories. End.
  L: AptThreadProc. Starting Apartment Thread <FFFEE811>.
  L: AptThreadProc. Registering class factory of apartment <FFFEE811>.
  L<FFFEE811>: CFCruiseCar::AddRef. New cRefs=3.
  L<FFFEE289>: CFCar::QueryInterface. pIClassFactory returned.
  L<FFFEE289>: CFCar::CImpIClassFactory::Addref. Delegating. New cI=1.
  L<FFFEE289>: CFCar::AddRef. New cRefs=4.
  L<FFFEE289>: CFCar::CImpIClassFactory::QueryInterface. Delegating.
  L<FFFEE289>: CFCar::QueryInterface. pIClassFactory returned.
  L<FFFEE289>: CFCar::CImpIClassFactory::Addref. Delegating. New cI=2.
  L<FFFEE289>: CFCar::AddRef. New cRefs=5.
  L<FFFEE289>: CFCar::CImpIClassFactory::QueryInterface. Delegating.
  L<FFFEE289>: CFCar::CImpIClassFactory::QueryInterface. Delegating.
  L<FFFEE289>: CFCar::CImpIClassFactory::QueryInterface. Delegating.
  L<FFFEE289>: CFCar::QueryInterface. 'this' pIUnknown returned.
  L<FFFEE289>: CFCar::AddRef. New cRefs=6.
  L<FFFEE289>: CFCar::AddRef. New cRefs=7.
  L<FFFEE289>: CFCar::Release. New cRefs=6.
  L<FFFEE289>: CFCar::AddRef. New cRefs=7.
  L<FFFEE289>: CFCar::QueryInterface. pIClassFactory returned.
  L<FFFEE289>: CFCar::CImpIClassFactory::Addref. Delegating. New cI=3.
  L<FFFEE289>: CFCar::AddRef. New cRefs=8.
  L<FFFEE289>: CFCar::CImpIClassFactory::Release. Delegating. New cI=2.
  L<FFFEE289>: CFCar::Release. New cRefs=7.
  L<FFFEE289>: CFCar::QueryInterface. pIClassFactory returned.
  L<FFFEE289>: CFCar::CImpIClassFactory::Addref. Delegating. New cI=3.
  L<FFFEE289>: CFCar::AddRef. New cRefs=8.
  L<FFFEE289>: CFCar::CImpIClassFactory::Release. Delegating. New cI=2.
  L<FFFEE289>: CFCar::Release. New cRefs=7.
  L<FFFEE289>: CFCar::CImpIClassFactory::Release. Delegating. New cI=1.
  L<FFFEE289>: CFCar::Release. New cRefs=6.
  L<FFFEE289>: CFCar::CImpIClassFactory::CreateInstance. pUnkOuter=0x0.
  L<FFFEE289>: COCar::CImpICar Constructor. Non-Aggregating.
  L<FFFEE289>: COCar Constructor. m_pUnkOuter=0x0.
  L: CServer::OwnThis. Thread <FFFEE289> waiting to own CServer.
  L: CServer::OwnThis. CServer now owned by Thread <FFFEE289>.
  L<FFFEE289>: CServer::ObjectsUp. New cObjects=1.
  L: CServer::UnOwnThis. Ownership relinquished by <FFFEE289>.
  L<FFFEE289>: COCar::QueryInterface. 'this' pIUnknown returned.
  L<FFFEE289>: COCar::AddRef. New cRefs=1.
  L<FFFEE289>: CFCar::CImpIClassFactory::CreateInstance Succeeded. *ppv=0x870658.
  L<FFFEE289>: COCar::QueryInterface. 'this' pIUnknown returned.
  L<FFFEE289>: COCar::AddRef. New cRefs=2.
  L<FFFEE289>: COCar::QueryInterface. 'this' pIUnknown returned.
  L<FFFEE289>: COCar::AddRef. New cRefs=3.
  L<FFFEE289>: COCar::AddRef. New cRefs=4.
  L<FFFEE289>: COCar::Release. New cRefs=3.
  L<FFFEE289>: COCar::AddRef. New cRefs=4.
  L<FFFEE289>: COCar::Release. New cRefs=3.
  L<FFFEE289>: COCar::Release. New cRefs=2.
  L<FFFEE289>: CFCar::CImpIClassFactory::Release. Delegating. New cI=0.
  L<FFFEE289>: CFCar::Release. New cRefs=5.
  L<FFFEE289>: CFCar::Release. New cRefs=4.
  L<FFFEE289>: CFCar::Release. New cRefs=3.

This log shows that the following threads are started.

  <FFFE7005> - Main thread for the APTSERVE local server application.
  <FFFEE289> - AptCar component apartment thread.
  <FFFEE4B1> - AptUtilityCar component apartment thread.
  <FFFEE811> - AptCruiseCar component apartment thread.

We will abbreviate these to <05>, <89>, <B1>, and <11>. The main thread,
<05>, is also called the main apartment thread and could be exploited more
fully as an apartment in the strict sense. But it is not exploited as such
in this code sample.

The main thread, <05>, executes the OpenFactories method. We see the use
of the CThreaded ownership mechanism, with the main thread requesting and
getting ownership of CServer. On this main thread we see the constructors
for each class factory. The class factories create the threads for the
AptCar, AptUtilityCar, and AptCruiseCar objects. At some variable length
of time after the thread creation calls, the operating system calls each
thread's AptThreadProc function to start the thread. We see these calls
reported as the threads for AptCar (<89>), AptUtilityCar (<B1>), and
AptCruiseCar (<11>) are started. Within AptThreadProc, each thread also
registers the apartment's new class factory with COM. The main thread,
<05>, relinquishes ownership of CServer, and the log then reports that
OpenFactories has ended.

We then see the CFCar class factory used to create the requested new COCar
object. CFCar and the constructor of the new COCar object both execute on
the AptCar thread, <89>. When the class factory is successful in creating
the COCar object, we see the server's object count incremented to 1 inside
the protection of the OwnThis ownership by thread <89>. We then see the
delegated release of the IClassFactory held by the client. COM still holds
three outstanding references to the registered CFCar class factory and two
outstanding references to the COCar object.

Next choose the ICar::Shift command from the Car menu to see the client
call the interface methods of the new COCar object.

  C: === Car Menu: ICar::Shift
  C: --Obtaining Interface Pointer.
  L<FFFEE289>: COCar::QueryInterface. pICar returned.
  L<FFFEE289>: COCar::CImpICar::Addref. Delegating. New cI=1.
  L<FFFEE289>: COCar::AddRef. New cRefs=3.
  L<FFFEE289>: COCar::CImpICar::Release. Delegating. New cI=0.
  L<FFFEE289>: COCar::Release. New cRefs=2.
  L<FFFEE289>: COCar::QueryInterface. pICar returned.
  L<FFFEE289>: COCar::CImpICar::Addref. Delegating. New cI=1.
  L<FFFEE289>: COCar::AddRef. New cRefs=3.
  C: Interface obtained. *ppv=0x520BC4
  C: --Calling pICar->Shift
  L<FFFEE289>: COCar::CImpICar::Shift. Called. ICar calls=1.
  C: --Releasing pICar

In the process of obtaining the interface pointer, ICar's own AddRef and
Release functions are called. Before this Shift call, COCar had two
outstanding references.  Afterwards, it ended with three references prior
to the actual call to pICar->Shift. The Shift method call indicates this
is the first call to this object instance's ICar interface.

We see COM efficiency at work if we choose the ICar::Shift command from
the Car menu again.

  C: === Car Menu: ICar::Shift
  C: --Obtaining Interface Pointer.
  C: Interface obtained. *ppv=0x520BC4
  C: --Calling pICar->Shift
  L<FFFEE289>: COCar::CImpICar::Shift. Called. ICar calls=2.
  C: --Releasing pICar

COM had cached the interface information during the previous ICar::Shift
call, so that on this second call the interface pointer was returned
directly without QueryInterface calls to the COCar object. The actual
Shift call is executed on thread <89>. This call was marshaled from the
client process to this server's AptCar thread, <89>. The ICar interface
call counter indicates 2 for this second call to ICar::Shift.

To show the functioning of a composite multithreaded object in the server,
choose the Create command from the UtilityCruiseCar menu.

  C: === UtilityCruiseCar Menu: Create.
  C: CreateUtilityCruiseCar. pUnkOuter=0x0.
  C: COUtilityCruiseCar::CImpICar Constructor. Non-Aggregating
  C: COUtilityCruiseCar::CImpICruise Constructor. Non-Aggregating
  C: COUtilityCruiseCar::CImpIUtility Constructor. Non-Aggregating.
  C: COUtilityCruiseCar Constructor. m_pUnkOuter=0x0.
  C: COUtilityCruiseCar::Init. pUnkOuter=0x870138
  C: COUtilityCruiseCar::Init. Obtain CruiseCar Class Factory.
  L<FFFEE811>: CFCruiseCar::QueryInterface. pIClassFactory returned.
  L<FFFEE811>: CFCruiseCar::CImpIClassFactory::Addref. Delegating. New cI=1.
  L<FFFEE811>: CFCruiseCar::AddRef. New cRefs=4.
  L<FFFEE811>: CFCruiseCar::CImpIClassFactory::QueryInterface. Delegating.
  L<FFFEE811>: CFCruiseCar::QueryInterface. pIClassFactory returned.
  L<FFFEE811>: CFCruiseCar::CImpIClassFactory::Addref. Delegating. New cI=2.
  L<FFFEE811>: CFCruiseCar::AddRef. New cRefs=5.
  L<FFFEE811>: CFCruiseCar::CImpIClassFactory::QueryInterface. Delegating.
  L<FFFEE811>: CFCruiseCar::CImpIClassFactory::QueryInterface. Delegating.
  L<FFFEE811>: CFCruiseCar::CImpIClassFactory::QueryInterface. Delegating.
  L<FFFEE811>: CFCruiseCar::QueryInterface. 'this' pIUnknown returned.
  L<FFFEE811>: CFCruiseCar::AddRef. New cRefs=6.
  L<FFFEE811>: CFCruiseCar::AddRef. New cRefs=7.
  L<FFFEE811>: CFCruiseCar::Release. New cRefs=6.
  L<FFFEE811>: CFCruiseCar::AddRef. New cRefs=7.
  L<FFFEE811>: CFCruiseCar::QueryInterface. pIClassFactory returned.
  L<FFFEE811>: CFCruiseCar::CImpIClassFactory::Addref. Delegating. New cI=3.
  L<FFFEE811>: CFCruiseCar::AddRef. New cRefs=8.
  L<FFFEE811>: CFCruiseCar::CImpIClassFactory::Release. Delegating. New cI=2.
  L<FFFEE811>: CFCruiseCar::Release. New cRefs=7.
  L<FFFEE811>: CFCruiseCar::QueryInterface. pIClassFactory returned.
  L<FFFEE811>: CFCruiseCar::CImpIClassFactory::Addref. Delegating. New cI=3.
  L<FFFEE811>: CFCruiseCar::AddRef. New cRefs=8.
  L<FFFEE811>: CFCruiseCar::CImpIClassFactory::Release. Delegating. New cI=2.
  L<FFFEE811>: CFCruiseCar::Release. New cRefs=7.
  L<FFFEE811>: CFCruiseCar::CImpIClassFactory::Release. Delegating. New cI=1.
  L<FFFEE811>: CFCruiseCar::Release. New cRefs=6.
  C: COUtilityCruiseCar::Init. CruiseCar Class Factory obtained.
  C: COUtilityCruiseCar::Init. Calling CFCruiseCar::CreateInstance.
  L<FFFEE811>: CFCruiseCar::CImpIClassFactory::CreateInstance. pUnkOuter=0x0.
  L<FFFEE811>: COCruiseCar::CImpICar Constructor. Non-Aggregating
  L<FFFEE811>: COCruiseCar::CImpICruise Constructor. Non-Aggregating.
  L<FFFEE811>: COCruiseCar Constructor. m_pUnkOuter=0x0.
  L: CServer::OwnThis. Thread <FFFEE811> waiting to own CServer.
  L: CServer::OwnThis. CServer now owned by Thread <FFFEE811>.
  L<FFFEE811>: CServer::ObjectsUp. New cObjects=2.
  L: CServer::UnOwnThis. Ownership relinquished by <FFFEE811>.
  L<FFFEE811>: COCruiseCar::Init.
  L<FFFEE289>: CFCar::QueryInterface. pIClassFactory returned.
  L<FFFEE289>: CFCar::CImpIClassFactory::Addref. Delegating. New cI=1.
  L<FFFEE289>: CFCar::AddRef. New cRefs=4.
  L<FFFEE289>: CFCar::CImpIClassFactory::QueryInterface. Delegating.
  L<FFFEE289>: CFCar::QueryInterface. pIClassFactory returned.
  L<FFFEE289>: CFCar::CImpIClassFactory::Addref. Delegating. New cI=2.
  L<FFFEE289>: CFCar::AddRef. New cRefs=5.
  L<FFFEE289>: CFCar::CImpIClassFactory::QueryInterface. Delegating.
  L<FFFEE289>: CFCar::CImpIClassFactory::QueryInterface. Delegating.
  L<FFFEE289>: CFCar::CImpIClassFactory::QueryInterface. Delegating.
  L<FFFEE289>: CFCar::QueryInterface. 'this' pIUnknown returned.
  L<FFFEE289>: CFCar::AddRef. New cRefs=6.
  L<FFFEE289>: CFCar::AddRef. New cRefs=7.
  L<FFFEE289>: CFCar::Release. New cRefs=6.
  L<FFFEE289>: CFCar::AddRef. New cRefs=7.
  L<FFFEE289>: CFCar::QueryInterface. pIClassFactory returned.
  L<FFFEE289>: CFCar::CImpIClassFactory::Addref. Delegating. New cI=3.
  L<FFFEE289>: CFCar::AddRef. New cRefs=8.
  L<FFFEE289>: CFCar::CImpIClassFactory::Release. Delegating. New cI=2.
  L<FFFEE289>: CFCar::Release. New cRefs=7.
  L<FFFEE289>: CFCar::QueryInterface. pIClassFactory returned.
  L<FFFEE289>: CFCar::CImpIClassFactory::Addref. Delegating. New cI=3.
  L<FFFEE289>: CFCar::AddRef. New cRefs=8.
  L<FFFEE289>: CFCar::CImpIClassFactory::Release. Delegating. New cI=2.
  L<FFFEE289>: CFCar::Release. New cRefs=7.
  L<FFFEE289>: CFCar::CImpIClassFactory::Release. Delegating. New cI=1.
  L<FFFEE289>: CFCar::Release. New cRefs=6.
  L<FFFEE289>: CFCar::CImpIClassFactory::CreateInstance. pUnkOuter=0x0.
  L<FFFEE289>: COCar::CImpICar Constructor. Non-Aggregating.
  L<FFFEE289>: COCar Constructor. m_pUnkOuter=0x0.
  L: CServer::OwnThis. Thread <FFFEE289> waiting to own CServer.
  L: CServer::OwnThis. CServer now owned by Thread <FFFEE289>.
  L<FFFEE289>: CServer::ObjectsUp. New cObjects=3.
  L: CServer::UnOwnThis. Ownership relinquished by <FFFEE289>.
  L<FFFEE289>: COCar::QueryInterface. pICar returned.
  L<FFFEE289>: COCar::CImpICar::Addref. Delegating. New cI=1.
  L<FFFEE289>: COCar::AddRef. New cRefs=1.
  L<FFFEE289>: CFCar::CImpIClassFactory::CreateInstance Succeeded. *ppv=0x8706BC.
  L<FFFEE289>: COCar::CImpICar::QueryInterface. Delegating.
  L<FFFEE289>: COCar::CImpICar::QueryInterface. Delegating.
  L<FFFEE289>: COCar::QueryInterface. pICar returned.
  L<FFFEE289>: COCar::CImpICar::Addref. Delegating. New cI=2.
  L<FFFEE289>: COCar::AddRef. New cRefs=2.
  L<FFFEE289>: COCar::CImpICar::QueryInterface. Delegating.
  L<FFFEE289>: COCar::CImpICar::QueryInterface. Delegating.
  L<FFFEE289>: COCar::CImpICar::QueryInterface. Delegating.
  L<FFFEE289>: COCar::QueryInterface. 'this' pIUnknown returned.
  L<FFFEE289>: COCar::AddRef. New cRefs=3.
  L<FFFEE289>: COCar::AddRef. New cRefs=4.
  L<FFFEE289>: COCar::Release. New cRefs=3.
  L<FFFEE289>: COCar::AddRef. New cRefs=4.
  L<FFFEE289>: COCar::QueryInterface. pICar returned.
  L<FFFEE289>: COCar::CImpICar::Addref. Delegating. New cI=3.
  L<FFFEE289>: COCar::AddRef. New cRefs=5.
  L<FFFEE289>: COCar::CImpICar::Release. Delegating. New cI=2.
  L<FFFEE289>: COCar::Release. New cRefs=4.
  L<FFFEE289>: COCar::QueryInterface. pICar returned.
  L<FFFEE289>: COCar::CImpICar::Addref. Delegating. New cI=3.
  L<FFFEE289>: COCar::AddRef. New cRefs=5.
  L<FFFEE289>: COCar::CImpICar::Release. Delegating. New cI=2.
  L<FFFEE289>: COCar::Release. New cRefs=4.
  L<FFFEE289>: COCar::CImpICar::Release. Delegating. New cI=1.
  L<FFFEE289>: COCar::Release. New cRefs=3.
  L<FFFEE289>: CFCar::CImpIClassFactory::Release. Delegating. New cI=0.
  L<FFFEE289>: CFCar::Release. New cRefs=5.
  L<FFFEE289>: CFCar::Release. New cRefs=4.
  L<FFFEE289>: CFCar::Release. New cRefs=3.
  L<FFFEE811>: COCruiseCar::Init (New Containment of COCar) Succeeded.
  L<FFFEE811>: COCruiseCar::QueryInterface. pICruise returned.
  L<FFFEE811>: COCruiseCar::CImpICruise::Addref. Delegating. New cI=1.
  L<FFFEE811>: COCruiseCar::AddRef. New cRefs=1.
  L<FFFEE811>: CFCruiseCar::CImpIClassFactory::CreateInstance Succeeded. *ppv=0x870698.
  L<FFFEE811>: COCruiseCar::CImpICruise::QueryInterface. Delegating.
  L<FFFEE811>: COCruiseCar::CImpICruise::QueryInterface. Delegating.
  L<FFFEE811>: COCruiseCar::QueryInterface. pICruise returned.
  L<FFFEE811>: COCruiseCar::CImpICruise::Addref. Delegating. New cI=2.
  L<FFFEE811>: COCruiseCar::AddRef. New cRefs=2.
  L<FFFEE811>: COCruiseCar::CImpICruise::QueryInterface. Delegating.
  L<FFFEE811>: COCruiseCar::CImpICruise::QueryInterface. Delegating.
  L<FFFEE811>: COCruiseCar::CImpICruise::QueryInterface. Delegating.
  L<FFFEE811>: COCruiseCar::QueryInterface. 'this' pIUnknown returned.
  L<FFFEE811>: COCruiseCar::AddRef. New cRefs=3.
  L<FFFEE811>: COCruiseCar::AddRef. New cRefs=4.
  L<FFFEE811>: COCruiseCar::Release. New cRefs=3.
  L<FFFEE811>: COCruiseCar::AddRef. New cRefs=4.
  L<FFFEE811>: COCruiseCar::QueryInterface. pICruise returned.
  L<FFFEE811>: COCruiseCar::CImpICruise::Addref. Delegating. New cI=3.
  L<FFFEE811>: COCruiseCar::AddRef. New cRefs=5.
  L<FFFEE811>: COCruiseCar::CImpICruise::Release. Delegating. New cI=2.
  L<FFFEE811>: COCruiseCar::Release. New cRefs=4.
  L<FFFEE811>: COCruiseCar::QueryInterface. pICruise returned.
  L<FFFEE811>: COCruiseCar::CImpICruise::Addref. Delegating. New cI=3.
  L<FFFEE811>: COCruiseCar::AddRef. New cRefs=5.
  L<FFFEE811>: COCruiseCar::CImpICruise::Release. Delegating. New cI=2.
  L<FFFEE811>: COCruiseCar::Release. New cRefs=4.
  L<FFFEE811>: COCruiseCar::CImpICruise::Release. Delegating. New cI=1.
  L<FFFEE811>: COCruiseCar::Release. New cRefs=3.
  C: COUtilityCruiseCar::Init. Releasing CruiseCar Class Factory.
  L<FFFEE811>: CFCruiseCar::CImpIClassFactory::Release. Delegating. New cI=0.
  L<FFFEE811>: CFCruiseCar::Release. New cRefs=5.
  L<FFFEE811>: CFCruiseCar::Release. New cRefs=4.
  L<FFFEE811>: CFCruiseCar::Release. New cRefs=3.
  L<FFFEE811>: COCruiseCar::QueryInterface. pICar returned
  L<FFFEE811>: COCruiseCar::CImpICar::Addref. Delegating. New cI=1.
  L<FFFEE811>: COCruiseCar::AddRef. New cRefs=4.
  L<FFFEE811>: COCruiseCar::CImpICar::Release. Delegating. New cI=0.
  L<FFFEE811>: COCruiseCar::Release. New cRefs=3.
  L<FFFEE811>: COCruiseCar::QueryInterface. pICar returned
  L<FFFEE811>: COCruiseCar::CImpICar::Addref. Delegating. New cI=1.
  L<FFFEE811>: COCruiseCar::AddRef. New cRefs=4.
  C: COUtilityCruiseCar::Init (CruiseCar Containment) Succeeded.
  C: COUtilityCruiseCar::QueryInterface. 'this' pIUnknown returned.
  C: COUtilityCruiseCar::AddRef. New cRefs=1.
  C: CreateUtilityCruiseCar Succeeded. *ppv=0x870138.

COUtilityCruiseCar is a composite COM object created in the client. It
reuses the COCruiseCar COM object provided by the server. COCruiseCar in
turn reuses the COCar COM object provided by the server. In the server, we
see the CruiseCar class factory executing on the AptCruiseCar thread,
<11>, to create a new COCruiseCar whose constructor also runs on this
thread. The server object count is incremented to 2 by this thread when it
obtains ownership of CServer. The object count is now 2, one for the
original COCar created at the start of this lesson and one for the new
COCruiseCar.

To complete the creation of COCruiseCar its Init method is called on the
AptCruiseCar thread, <11>. We see the resulting CFCar class factory
executed on the AptCar thread, <89>. The creation of this new COCar object
is completed on this thread, and it increments the server's object count
to 3. Through the remainder of the log, the behavior winds back out of the
object creations with COM, causing various QueryInterface, AddRef, and
Release calls. Upon completion, there are three outstanding references on
CFCar, three on the new COCar object, three on CFCruiseCar, and four on
the new COCruiseCar object. Most of these outstanding references to our
custom interfaces are held within COM.

Now choose the ICar::Shift command from the UtilityCruiseCar menu.

  C: === UtilityCruiseCar Menu: ICar::Shift
  C: --Obtaining Interface Pointer.
  C: COUtilityCruiseCar::QueryInterface. pICar returned
  C: COUtilityCruiseCar::CImpICar::Addref. Delegating. New cI=1.
  C: COUtilityCruiseCar::AddRef. New cRefs=2.
  C: Interface obtained. *ppv=0x870144
  C: --Calling pICar->Shift
  C: COUtilityCruiseCar::CImpICar::Shift. Delegating. nGear=1.
  L<FFFEE811>: COCruiseCar::CImpICar::Shift. Delegating. nGear=1.
  L<FFFEE289>: COCar::CImpICar::Shift. Called. ICar calls=1.
  C: --Releasing pICar
  C: COUtilityCruiseCar::CImpICar::Release. Delegating. New cI=0.
  C: COUtilityCruiseCar::Release. New cRefs=1.

The interface obtained is on the composite COUtilityCruiseCar object that
is created within the client. Using this interface, the Shift call is
delegated to the contained COCruiseCar object. At this point COM has to
marshal the call from the APTCLIEN client process to thread <11>, where
the COCruiseCar object resides. COCruiseCar is a composite object and
delegates the ICar::Shift call to its contained COCar object. COM now has
to marshal the call again within the server from the COCruiseCar apartment
thread, <11>, to the COCar thread, <89>. On this AptCar thread, <89>, we
see the Shift action finally performed.

For this call to ICar::Shift on the COUtilityCruiseCar object, COM
enforces the apartment model and ensures that, regardless of the calling
thread, the call performed in the particular object is executed on the
thread of that object. The ICar interface call counter shows 1, indicating
a first call to this interface on the new contained COCar object. This
count confirms that this is a new instance of COCar. If the COCar
originally created at the start of this lesson had been somehow mistakenly
used, we would see an interface call count of 3 because of the two Shift
calls to that COCar object earlier in this lesson.

To watch the shutdown of the COUtilityCruiseCar object, choose the Release
command from the UtilityCruiseCar menu.

  C: === UtilityCruiseCar Menu: Release.
  C: COUtilityCruiseCar::Release. New cRefs=0.
  C: COUtilityCruiseCar::Destructor.
  L<FFFEE811>: COCruiseCar::CImpICruise::Release. Delegating. New cI=0.
  L<FFFEE811>: COCruiseCar::Release. New cRefs=3.
  L<FFFEE811>: COCruiseCar::CImpICar::Release. Delegating. New cI=0.
  L<FFFEE811>: COCruiseCar::Release. New cRefs=2.
  L<FFFEE811>: COCruiseCar::Release. New cRefs=1.
  L<FFFEE811>: COCruiseCar::Release. New cRefs=0.
  L: CServer::OwnThis. Thread <FFFEE811> waiting to own CServer.
  L: CServer::OwnThis. CServer now owned by Thread <FFFEE811>.
  L<FFFEE811>: CServer::ObjectsDown. New cObjects=2.
  L: CServer::UnOwnThis. Ownership relinquished by <FFFEE811>.
  L<FFFEE811>: COCruiseCar::Destructor.
  L<FFFEE289>: COCar::CImpICar::Release. Delegating. New cI=0.
  L<FFFEE289>: COCar::Release. New cRefs=2.
  L<FFFEE289>: COCar::Release. New cRefs=1.
  L<FFFEE289>: COCar::Release. New cRefs=0.
  L: CServer::OwnThis. Thread <FFFEE289> waiting to own CServer.
  L: CServer::OwnThis. CServer now owned by Thread <FFFEE289>.
  L<FFFEE289>: CServer::ObjectsDown. New cObjects=1.
  L: CServer::UnOwnThis. Ownership relinquished by <FFFEE289>.
  L<FFFEE289>: COCar::Destructor.
  L<FFFEE289>: COCar::CImpICar Destructor.
  L<FFFEE811>: COCruiseCar::CImpICruise Destructor.
  L<FFFEE811>: COCruiseCar::CImpICar Destructor.
  C: COUtilityCruiseCar::CImpIUtility Destructor.
  C: COUtilityCruiseCar::CImpICruise Destructor.
  C: COUtilityCruiseCar::CImpICar Destructor.

This event causes the COUtilityCruiseCar destructor to run. It releases
the IUnknown of the contained COCruiseCar object. In the server, we see
the resulting releases of interfaces on COCruiseCar held by the client and
by COM. These releases run on the AptCruiseCar thread, <11>, and decrement
the COCruiseCar reference count to 0, forcing the destruction of the
COCruiseCar object. Thread <11> gains ownership of CServer and decrements
the server's object count to 2. The COCruiseCar destruction causes this
object to release its hold on its contained COCar. We see the resulting
releases of the interfaces on COCar held by COCruiseCar and by COM. These
run on the AptCar thread, <89>, and decrement of the COCar reference count
to 0, which forces the destruction of the COCar object. The AptCar thread,
<89>, gains ownership of CServer and decrements the server's object count
to 1. Finally, we see the destructors for all the various interface
implementation C++ objects.

The resulting object count of 1 reflects the remaining existence of the
original COCar object created at the start of this lesson. We will now
release this only remaining object supplied by APTSERVE and watch the
server shutdown.  From the Car menu, choose Release.

  C: === Car Menu: Release.
  L<FFFEE289>: COCar::Release. New cRefs=2.
  L<FFFEE289>: COCar::Release. New cRefs=1.
  L<FFFEE289>: COCar::Release. New cRefs=0.
  L: CServer::OwnThis. Thread <FFFEE289> waiting to own CServer.
  L: CServer::OwnThis. CServer now owned by Thread <FFFEE289>.
  L<FFFEE289>: CServer::ObjectsDown. New cObjects=0.
  L<FFFEE289>: CServer::ObjectsDown. Closing down APTSERVE server.
  L: CServer::UnOwnThis. Ownership relinquished by <FFFEE289>.
  L<FFFE7005>: CServer::CloseFactories. Begin.
  L<FFFEE289>: COCar::Destructor.
  L: CServer::OwnThis. Thread <FFFE7005> waiting to own CServer.
  L<FFFEE289>: COCar::CImpICar Destructor.
  L: CServer::OwnThis. CServer now owned by Thread <FFFE7005>.
  L<FFFE7005>: CServer::CloseFactories. Terminate AptCar Apartment.
  L<FFFE7005>: CServer::CloseFactories. Terminate AptUtilityCar Apartment.
  L: AptThreadProc. Revoking class factory of apartment <FFFEE289>.
  L<FFFE7005>: CServer::CloseFactories. Terminate AptCruiseCar Apartment.
  L: AptThreadProc. Revoking class factory of apartment <FFFEE4B1>.
  L<FFFEE289>: CFCar::QueryInterface. 'this' pIUnknown returned.
  L<FFFE7005>: CServer::CloseFactories. Releasing all Classfactory interfaces.
  L<FFFEE289>: CFCar::AddRef. New cRefs=4.
  L<FFFE7005>: CFCar::Release. New cRefs=3.
  L<FFFE7005>: CFCar::Release. New cRefs=2.
  L: AptThreadProc. Revoking class factory of apartment <FFFEE811>.
  L<FFFEE4B1>: CFUtilityCar::QueryInterface. 'this' pIUnknown returned.
  L<FFFEE289>: CFCar::Release. New cRefs=1.
  L<FFFE7005>: CFUtilityCar::Release. New cRefs=2.
  L<FFFEE811>: CFCruiseCar::QueryInterface. 'this' pIUnknown returned.
  L<FFFEE4B1>: CFUtilityCar::AddRef. New cRefs=3.
  L<FFFEE289>: CFCar::Release. New cRefs=0.
  L<FFFE7005>: CFUtilityCar::Release. New cRefs=2.
  L<FFFEE811>: CFCruiseCar::AddRef. New cRefs=4.
  L<FFFEE4B1>: CFUtilityCar::Release. New cRefs=1.
  L<FFFEE289>: CFCar::Destructor.
  L<FFFEE811>: CFCruiseCar::Release. New cRefs=3.
  L<FFFEE4B1>: CFUtilityCar::Release. New cRefs=0.
  L<FFFEE289>: CFCar::CImpIClassFactory Destructor.
  L<FFFE7005>: CFUtilityCar::Destructor.
  L<FFFEE811>: CFCruiseCar::Release. New cRefs=2.
  L: AptThreadProc. Apartment Thread <FFFEE4B1> Terminated.
  L<FFFE7005>: CFUtilityCar::CImpIClassFactory Destructor.
  L: AptThreadProc. Apartment Thread <FFFEE811> Terminated.
  L: AptThreadProc. Apartment Thread <FFFEE289> Terminated.
  L<FFFE7005>: CFCruiseCar::Release. New cRefs=1.
  L<FFFE7005>: CFCruiseCar::Release. New cRefs=0.
  L<FFFE7005>: CFCruiseCar::Destructor.
  L<FFFE7005>: CFCruiseCar::CImpIClassFactory Destructor.
  L: CServer::UnOwnThis. Ownership relinquished by <FFFE7005>.
  L<FFFE7005>: CServer::CloseFactories. End.
  L<FFFE7005>: Exiting APTSERVE local server application.

The client releases the IUnknown of the COCar object. In the server, we
see a resulting cascade of releases of COCar interfaces held by the client
and by COM. These are executed on the AptCar thread, <89>, and decrement
the COCar reference count to 0, which forces the destruction of the COCar
object. Thread <89> gains ownership of CServer and decrements the server's
object count to 0, triggering a shutdown of the entire server. This
happens in the ObjectsDown method, where a WM_CLOSE message is sent to the
main thread, <05>, of the server process. This message causes an exit of
the server application's message loop. The server's
CServer::CloseFactories method is then called.

Within CloseFactories, we see the unregistering of the class factories
with COM and the termination of the AptCar, AptUtilityCar, and
AptCruiseCar threads. The apartment thread message loops are exited after
WM_QUIT messages are sent to each apartment thread from CloseFactories,
which is running on the main thread, <05>. Before CloseFactories returns,
we see the releases of the interfaces held on the class factories. These
releases decrement each factory's reference count to 0 and cause the
destructors to run for the CFCar, CFUtilityCar, and CFCruiseCar objects.
After CloseFactories, execution exits the main application, and the
operating system unloads APTSERVE.

One final note about logging. You can run the APTSERVE server in a visible
state, in which case it will log its internal behavior to its own log
display. In this way both APTCLIEN and APTSERVE can be visible on screen
at the same time, with separate log displays of their own activity. Here's
how to do it: Run APTSERVE first (before APTCLIEN) with the -Embedding
command line switch, and then run APTCLIEN. Both the APTSERVE server and
the APTCLIEN client will be present on screen at the same time. Each
running EXE will log its internal behavior to its own separate logging
display.
