SERVER.CXX

/**************************************************************************** 
Microsoft RPC
Copyright Microsoft Corp. 1992-1996
object call_as Example

FILE: server.cxx

USAGE: server - note that this is auto-loaded by the client
requesting this server, and exits at completion

PURPOSE: Server side of RPC distributed application

FUNCTIONS: main() - binds to server and calls remote procedure

COMMENTS: This version of the Ole2 distributed application that
prints "hello, world" (or other string) on the server
features a non-rpcable custom interface being remoted with
[call_as].

It provides a class factory to manufacture a server object,
and the implementation of the callas server object

****************************************************************************/

#define INC_OLE2
#include <windows.h>
#include <stdio.h>
#include <assert.h>
#include "callas.h"

unsigned long ObjectCount = 0;
BOOL fClassRegistered = FALSE;
DWORD dwHandle = 0;

// this is the CLSID for the class factory for the server

const CLSID CLSID_CallAs
= {0xf9246030,0x9f33,0x11cd,{0xb2,0x3f,0x00,0xaa,0x00,0x33,0x9c,0xce}};

IClassFactory *GetCallAsFactory();




// here are some convenient inline functions to reduce the casting involved
// with having the RefCount be unsigned instead of signed, and pass by
// reference

inline
unsigned long
IncrementRefCount( unsigned long & RefCount )
{
return InterlockedIncrement( (long *) &RefCount );
}

inline
unsigned long
DecrementRefCount( unsigned long & RefCount )
{
return InterlockedDecrement( (long *) &RefCount );
}







// this is the class factory for the CCallAs server
// it manufactures CCallAs server objects in response to a CreateInstance
// call

class CCallAsFactory : public IClassFactory

{
public:
// note that the virtual methods must exactly match the set for
// the IClassFactory in the idl (and callas.h)
unsigned long RefCount;

CCallAsFactory()
{
RefCount = 0;
}

HRESULT STDMETHODCALLTYPE QueryInterface(
REFIID iid,
void **ppv);

ULONG STDMETHODCALLTYPE AddRef();

ULONG STDMETHODCALLTYPE Release();

HRESULT STDMETHODCALLTYPE CreateInstance(
IUnknown *punkOuter,
REFIID riid,
void **ppv);

HRESULT STDMETHODCALLTYPE LockServer(
BOOL fLock );
};

// allocate a static classfactory to avoid construction races if
// we were multithreaded.
CCallAsFactory gCallAsClassFactory;





class CCallAs : public IHelloCallAs

{

unsigned long RefCount;

public:

// remoted functions (virtual)

HRESULT STDMETHODCALLTYPE QueryInterface(
REFIID iid,
void **ppv);

ULONG STDMETHODCALLTYPE AddRef();

ULONG STDMETHODCALLTYPE Release();

MyBoolean __stdcall HelloProc(
unsigned char *pszString);

// local functions
// constructor
CCallAs()
{
RefCount = 0;
}

void * operator new( size_t s )
{
return CoTaskMemAlloc( s );
}

void operator delete( void * pv )
{
CoTaskMemFree( pv );
}

};


//+---------------------------------------------------------------------------
//
// Function: main
//
// Synopsis:
//
// Arguments:
//
// Returns: void
//
// Modifies: nothing
//
// Notes: none
//
//----------------------------------------------------------------------------

void _cdecl main()
{
HRESULT hr;
MSG msg;
IClassFactory *pClassFactory;

//
// Initialize OLE before calling any other OLE functions.
//

hr = CoInitialize(NULL);

if( FAILED(hr))
{
printf("Server: CoInitialize failed(%x)\n",hr);
return;
}

pClassFactory = GetCallAsFactory();

hr = CoRegisterClassObject(CLSID_CallAs,
(IUnknown *) pClassFactory,
CLSCTX_LOCAL_SERVER,
REGCLS_SINGLEUSE,
&dwHandle);

pClassFactory->Release();

if (FAILED(hr))
printf("Server: CoRegisterClassObject failed %x\n", hr);
else
{
fClassRegistered = TRUE;

// message loop
while (GetMessage(&msg, NULL, 0, 0))
{
TranslateMessage(&msg);
DispatchMessage(&msg);
}
}
CoUninitialize();

return;
}

//+-------------------------------------------------------------------------
//
// Method: GetCallAsFactory
//
// Synopsis: Get an IClassFactory * for the CallAs class.
//
//--------------------------------------------------------------------------
IClassFactory *GetCallAsFactory()
{
// increment the file object count the first time it is created
if(gCallAsClassFactory.RefCount == 0)
{
IncrementRefCount(gCallAsClassFactory.RefCount);
IncrementRefCount(ObjectCount);
}
else
{
IncrementRefCount(gCallAsClassFactory.RefCount);
}
return &gCallAsClassFactory;
}

//+-------------------------------------------------------------------------
//
// Method: CCallAsFactory::QueryInterface, public
//
// Synopsis: Query for an interface on the class factory.
//
// Derivation: IUnknown
//
//--------------------------------------------------------------------------
HRESULT STDMETHODCALLTYPE
CCallAsFactory::QueryInterface (
REFIID iid,
void **ppv )
{
HRESULT hr = E_NOINTERFACE;

assert(ppv);

*ppv = 0;
if ( IsEqualGUID( iid, IID_IUnknown) ||
IsEqualGUID( iid, IID_IClassFactory ) )
{
*ppv = this;
AddRef();
hr = S_OK;
}

return hr;
}
//+-------------------------------------------------------------------------
//
// Method: CCallAsFactory::AddRef, public
//
// Synopsis: Increment DLL reference counts
//
// Derivation: IUnknown
//
// Notes: We have a single instance of the CCallAsFactory.
//
//--------------------------------------------------------------------------
ULONG STDMETHODCALLTYPE
CCallAsFactory::AddRef()
{
IncrementRefCount(RefCount);
return RefCount;
}

//+-------------------------------------------------------------------------
//
// Method: CCallAsFactory::Release, public
//
// Synopsis: Decrement DLL reference count
//
// Derivation: IUnknown
//
//--------------------------------------------------------------------------
ULONG STDMETHODCALLTYPE
CCallAsFactory::Release()
{
long t;
unsigned long count;

t = DecrementRefCount(RefCount);

if(t == 0)
{
count = 0;
//decrement the object count
if(DecrementRefCount(ObjectCount) == 0)
{
//The last object has been destroyed.
PostQuitMessage(0);
}
}
else
count = RefCount;

return count;
}

//+-------------------------------------------------------------------------
//
// Method: CCallAsFactory::CreateInstance, public
//
// Synopsis: Create an instance of CCallAs.
//
//--------------------------------------------------------------------------
HRESULT STDMETHODCALLTYPE
CCallAsFactory::CreateInstance
(
IUnknown *punkOuter,
REFIID riid,
void **ppv
)
{
HRESULT hr = E_OUTOFMEMORY;
CCallAs *pCallAs;

assert(ppv);

*ppv = 0;

if(fClassRegistered == TRUE)
{
fClassRegistered = FALSE;
CoRevokeClassObject(dwHandle);
}

pCallAs = new CCallAs();
if(pCallAs)
{
// invoke the constructor
*pCallAs = CCallAs();

//increment the object count.
//The object count will keep this process alive until all
//objects are released.
IncrementRefCount(ObjectCount);
hr = pCallAs->QueryInterface( riid, ppv);
}

return hr;
}

//+-------------------------------------------------------------------------
//
// Method: CCallAsFactory::LockServer, public
//
// Synopsis: Lock the server in memory (by adding an extra reference)
//
//--------------------------------------------------------------------------
HRESULT STDMETHODCALLTYPE
CCallAsFactory::LockServer(
BOOL fLock )
{
if ( fLock )
IncrementRefCount( ObjectCount );
else
DecrementRefCount( ObjectCount );

return S_OK;

}

//+-------------------------------------------------------------------------
//
// Method: CCallAs::QueryInterface, public
//
// Synopsis: Query for an interface on the class factory.
//
// Derivation: IUnknown
//
//--------------------------------------------------------------------------
HRESULT STDMETHODCALLTYPE
CCallAs::QueryInterface (
REFIID iid,
void **ppv )
{
HRESULT hr = E_NOINTERFACE;

assert(ppv);

*ppv = 0;
if ( IsEqualGUID( iid, IID_IUnknown ) ||
IsEqualGUID( iid, IID_IHelloCallAs ) )
{
*ppv = this;
AddRef();
hr = S_OK;
}

return hr;
}
//+-------------------------------------------------------------------------
//
// Method: CCallAs::AddRef, public
//
// Synopsis: Increment reference count
//
// Derivation: IUnknown
//
//--------------------------------------------------------------------------
ULONG STDMETHODCALLTYPE
CCallAs::AddRef()
{
IncrementRefCount(RefCount);
return RefCount;
}

//+-------------------------------------------------------------------------
//
// Method: CCallAs::Release, public
//
// Synopsis: Decrement DLL reference count
//
// Derivation: IUnknown
//
//--------------------------------------------------------------------------
ULONG STDMETHODCALLTYPE
CCallAs::Release()
{
long t;
unsigned long count;

t = DecrementRefCount(RefCount);

if(t == 0)
{
count = 0;

//decrement the object count
if(DecrementRefCount(ObjectCount) == 0)
{
//The last object has been destroyed.
PostQuitMessage(0);
}
delete this;
}
else
count = RefCount;

return count;
}

//+---------------------------------------------------------------------------
//
// Function: CCallAs::HelloProc()
//
// Synopsis: Displays the specified string
//
// Arguments: void
//
// Returns: Success.
//
// Modifies: nothing
//
// Notes: none
//
//----------------------------------------------------------------------------
MyBoolean __stdcall
CCallAs::HelloProc(unsigned char *pszString)
{
printf("HelloProc: %s \n", pszString);
printf(" <pausing for 5 sec>\n");
// pretend to be busy computing for a bit
Sleep( 5000 ); // 5000 msec = 5 sec

return TRUE;
}