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

📄 freserve.txt

📁 服务器方面的
💻 TXT
📖 第 1 页 / 共 2 页
字号:
FRESERVE - Free-threaded COM objects in an in-process server


SUMMARY
=======

The FRESERVE sample shows how to construct a COM object in a free-threaded
in-process server. This sample departs from the sport utility vehicle
metaphor and associated interfaces used in other samples of this series.
FRESERVE introduces a new custom interface, IBall, and a new COM object,
COBall. COBall implements the IBall interface. Both COBall and its
in-process server are coded to support COM free threading in anticipation
of their use by the free-threaded client, FRECLIEN, in the next lesson.

The CThreaded facility in APPUTIL is used to achieve thread safety as it
was in the previous APTSERVE sample. COBall objects are derived from the
CThreaded class and so inherit its OwnThis and UnOwnThis methods. These
methods enforce mutually exclusive access to the FRESERVE server and to
COBall objects managed by the server.

FRESERVE works with the FRECLIEN code sample to illustrate FRESERVE's COM
server facilities in a free-threaded server and the subsequent manipulation
of its components by a free-threaded client.

For functional descriptions and a tutorial code tour of FRESERVE, see the
Code Tour section below. See also FRECLIEN.TXT in the sibling FRECLIEN
directory for more details on the FRECLIEN client application and how it
works with FRESERVE.DLL. You must build FRESERVE.DLL before building or
running FRECLIEN.

FRESERVE's makefile automatically registers FRESERVE's DllBall component
in the registry. This component must be registered before FRESERVE is
available to outside COM clients as a server for that component. This
self-registration is done using the REGISTER.EXE utility built in the
previous REGISTER lesson. To build or run FRESERVE, you should build the
REGISTER code sample first.

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
-----

FRESERVE is a DLL that is intended primarily as a free-threaded COM
server. Although it can be implicitly loaded by linking to its associated
.LIB file, it is normally used after an explicit LoadLibrary call, usually
from within COM's CoGetClassObject function. FRESERVE is a
self-registering in-process server. The makefile that builds this sample
automatically registers this server in the registry. You can manually
initiate its self registration by issuing the following command at the
command prompt:

  nmake register

This registration process requires a prior build of the REGISTER sample
in this series.

To use FRESERVE, a client program does not need to include FRESERVE.H or
link to FRESERVE.LIB. A COM client of FRESERVE obtains access solely
through its component's CLSID and OLE services. For FRESERVE, that CLSID
is CLSID_DllBall (defined in file BALLGUID.H in the INC sibling
directory). The FRECLIEN code sample shows how the client obtains this
access.


CODE TOUR
=========

Files         Description

FRESERVE.TXT  This file.
MAKEFILE      The generic makefile for building the FRESERVE.DLL
              code sample of this lesson.
FRESERVE.H    The include file for declaring as imported or defining as
              exported the service functions in FRESERVE.DLL.
FRESERVE.CPP  The main implementation file for FRESERVE.DLL. Has DllMain
              and the COM server functions (for example, DllGetClassObject).
FRESERVE.RC   The DLL resource definition file for the executable.
FRESERVE.ICO  The icon resource for the executable.
SERVER.H      The include file for the server control C++ object.
SERVER.CPP    The implementation file for the server control object.
FACTORY.H     The include file for the server's class factory COM objects.
FACTORY.CPP   The implementation file for the server's class factories.
BALL.H        The include file for the COBall COM object class.
BALL.CPP      The implementation file for the COBall COM object class.


FRESERVE uses many of the utility classes and services provided by
APPUTIL. For more details on APPUTIL, study the APPUTIL library's source
code and APPUTIL.TXT, located in the sibling \APPUTIL directory.

This sample is part of a graduated series of tutorial samples. This tour
assumes that you have some exposure to those previous samples. It does not
revisit earlier topics of basic interface implementation techniques, COM
object construction, in-process server construction, and class factory
construction. For information on these topics, study the earlier tutorial
samples.

The major topics covered in this code tour are an overview of how FRESERVE
works; thread-safe mechanisms in FRESERVE; an overview of COM free
threading; self-registration of COM objects in a free-threaded server; the
IBall interface; the construction of the COBall COM object; and issues in
class factory construction in a free-threaded server.

The COBall COM object is the single object type managed by this FRESERVE
in-process server. COBall is constructed as an aggregatable COM object
with a native implementation of the IBall interface. COBall exposes the
IBall interface to allow clients to perform a small set of operations on
an instance of COBall. The COBall object encapsulates data that defines a
moving ball. Data such as position, size, and color are encapsulated. No
graphical images are managed in this object. When a COBall object is
initialized with a call to its Reset method, it is given a rectangle (a
standard Win32 RECT structure) that defines the boundaries within which
the ball may move. The COBall object contains coded logic to move the ball
within those boundaries, to bounce the ball off any boundary when
appropriate, and to provide clients with current data on the ball's
location, size, and color. The object maintains a current color property
indicating the particular executing thread that most recently moved the
ball by calling the ball's Move method.

A client can then use the IBall interface to move the ball and to obtain
the data necessary to paint an image of the moving ball. The COBall object
is coded to support the free-threaded COM model, in which any number of
threads may freely make asynchronous calls directly to the object's
interface methods. In the following FRECLIEN code sample, several threads
running concurrently attempt to move a single COBall object. An
independent client thread runs concurrently to continuously obtain ball
position and color data and to paint snapshot images that graphically
reflect the COBall's changing data. Many different threads may
concurrently attempt to change and read the ball's data. The ball is kept
"alive" by one set of client threads, while another client thread
passively paints images of the moving ball. Because the ball updates its
own data to reflect the executing threads, the ball image painted by the
client changes color as it moves to continuously reflect which thread is
currently executing.

Aside from the COBall logic needed to maintain the bouncing ball as a
mathematical entity, FRESERVE also requires some special code to support
free threading. We will start with this code, because it borrows from
techniques previously shown in the APTSERVE sample. Like APTSERVE, the
FRESERVE server housing is constructed to guard shared data in the server
from conflicting access by multiple concurrent threads of execution. The
technique used to enforce serialized access to this server data is based
on the use of Win32 mutexes. APPUTIL's CThreaded utility base class
encapsulates the mutex protection mechanism. This utility is presented in
detail in the APTSERVE lesson.

In the FRESERVE server housing, the CServer C++ class is derived from the
CThreaded base class to inherit the OwnThis and UnOwnThis methods. These
methods are used in bracketed pairs to protect access to CServer's data,
such as the server's object and lock counts. One new addition to this
in-process server housing is the CServer::CanUnloadNow method. It uses the
CThreaded facility. Here it is from SERVER.CPP.

  HRESULT CServer::CanUnloadNow(void)
  {
    HRESULT hr = S_FALSE;
    LONG cObjects, cLocks;

    if (OwnThis())
    {
      cObjects = m_cObjects;
      cLocks = m_cLocks;

      hr = (0L==cObjects && 0L==cLocks) ? S_OK : S_FALSE;

      UnOwnThis();
  }

    return hr;
  }

The OwnThis, UnOwnThis pair is used to protect access to the server's
m_CObjects and m_cLocks variables. Within the range of this protection,
copies of the variable values are made on the local stack, and the copies
are then used for most logic. The logic implemented here is to support the
in-process server's familiar DllCanUnloadNow exported function. This
arrangement is convenient because DllCanUnloadNow is not a method of a
class that is derived from CThreaded, such that it can benefit from the
OwnThis protection mechanism. Yet such protection is needed, because the
server data is vulnerable to concurrent access by multithreaded clients.
In fact, the server data is potentially vulnerable to concurrent access by
multiple threads that could be spawned within the server or its
components. The CanUnloadNow method benefits from CThreaded not only for
the protection it offers, but also for the simple programming
encapsulation it provides. Such encapsulation will pay off later if the
free-threaded server evolves to one that spawns multiple threads within it.

The default model for multithreaded programming with COM is the apartment
model. This model was presented in the previous APTSERVE and APTCLIEN
samples, where multiple apartment threads were provided within a server.
COM's support of the apartment model ensures that calls to interface
methods on objects created within an apartment will always be on the same
thread as that of the class factory that created the object. The first
point of recognition by COM in this regard is the occasion of the object's
first marshaled interface when the object is created. This is usually the
IClassFactory interface pointer requested in the CoGetClassObject call. At
this point of recognition COM associates the object with its apartment
thread.

The apartment model supported by COM is convenient and largely transparent
to the client. It enforces a serialized access among contending threads to
a COM object. The object is always called on the thread that "owns" it,
even if the caller is on a different thread. This model entails some
overhead as COM performs thread switching during such cross-thread calls.

Performance can be significantly improved by using the free-threaded
model. In this model, COM does not make thread switches on behalf of
cross-thread calls to interface methods. Instead, COM freely ushers the
call through on the same thread originating the call. This means that the
thread-safe serialized access to the object that was enforced by the
apartment model is not enforced by the free threading model. COM objects
must therefore provide their own serialization for access by multiple
threads. Earlier in this lesson we saw the CThreaded mechanism that
provides such access safety in this sample.

The way that COM is informed that this in-process server and its managed
components support the free-threaded model is by an additional entry in
the component's registration in the registry. As with all the previous
in-process servers of this series, the FRESERVE server self-registers the
components it houses. Here is the DllRegisterServer function from
FRESERVE.CPP.

  STDAPI DllRegisterServer(void)
  {
    HRESULT  hr = NOERROR;
    TCHAR    szID[GUID_SIZE+1];
    TCHAR    szCLSID[GUID_SIZE+1];
    TCHAR    szModulePath[MAX_PATH];

    // Obtain the path to this module's executable file for later use.
    GetModuleFileName(
      g_pServer->m_hDllInst,
      szModulePath,
      sizeof(szModulePath)/sizeof(TCHAR));

    /*--------------------------------------------------------------------
      Create registry entries for the DllBall Component.
    --------------------------------------------------------------------*/
    // Create some base key strings.
    StringFromGUID2(CLSID_DllBall, szID, GUID_SIZE);
    lstrcpy(szCLSID, TEXT("CLSID\\"));
    lstrcat(szCLSID, szID);

    // Create ProgID keys.
    SetRegKeyValue(
      TEXT("DllBall1.0"),
      NULL,
      TEXT("DllBall Component - FRESERVE Code Sample"));
    SetRegKeyValue(
      TEXT("DllBall1.0"),
      TEXT("CLSID"),
      szID);

    // Create VersionIndependentProgID keys.
    SetRegKeyValue(
      TEXT("DllBall"),
      NULL,
      TEXT("DllBall Component - FRESERVE Code Sample"));
    SetRegKeyValue(
      TEXT("DllBall"),
      TEXT("CurVer"),
      TEXT("DllBall1.0"));
    SetRegKeyValue(
      TEXT("DllBall"),
      TEXT("CLSID"),
      szID);

    // Create entries under CLSID.
    SetRegKeyValue(
      szCLSID,
      NULL,
      TEXT("DllBall Component - FRESERVE Code Sample"));
    SetRegKeyValue(
      szCLSID,
      TEXT("ProgID"),

⌨️ 快捷键说明

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