NATCOM.CPP

/* 
Copyright (c) 1996-1997 Microsoft Corporation. All rights reserved.
*/

#include <windows.h>
#include "natcom.h"
#include <iostream.h>
#include <olectl.h>
#include <stdio.h>

// globals

ULONGg_cObject = 0 ;
HANDLEg_hDllMain ;

////////////////////////////////////////////////////////////////////////////////
//
//ObjectCreated()
//
//increments ref count of objects which reference this .DLL
//
////
VOID ObjectCreated(VOID)
{
InterlockedIncrement( (LONG*)&g_cObject ) ;
}

////////////////////////////////////////////////////////////////////////////////
//
//ObjectDestroyed()
//
//decrements ref count of objects which reference this .dll
//
////
VOID ObjectDestroyed(VOID)
{
InterlockedDecrement( (LONG*)&g_cObject ) ;
}

////////////////////////////////////////////////////////////////////////////////
//
//CNatCom
//
//contains our COM object
//
////
class CNatCom : public IUnknown
{
////////////////////////////////////////////////////////////////////////
//
//CImpINatCom
//
//implements the INatCom interface. IUnknown delegates to
//controlling unknown (CNatCom if not aggregated).
//
////
class CImpINatCom : public INatCom
{
friend class CNatCom ;

// PUBLIC ------------------------------------------------------

public :

////////////////////////////////////////////////////////////////
//
//
//CImpINatCom()
//
//constructor; Initialize member variables.
//
////
CImpINatCom()
{
m_cRef = 0 ;
m_pNatCom = NULL ;
m_punkCCW = NULL ;
}

////////////////////////////////////////////////////////////////
//
//~CImpINatCom()
//
//destructor; release CCW if we have one.
//
////
~CImpINatCom()
{
if (m_punkCCW)
{
m_punkCCW->Release() ;
}
}

////////////////////////////////////////////////////////////////
//
//QueryInterface()
//
//delegating QI.
//
////
HRESULT __stdcall QueryInterface(REFIID riid, void **ppv)
{
return m_pUnkOuter->QueryInterface(riid,ppv) ;
}

////////////////////////////////////////////////////////////////
//
//AddRef()
//
////
ULONG __stdcall AddRef(void)
{
return m_pUnkOuter->AddRef() ;
}

////////////////////////////////////////////////////////////////
//
//Release()
//
//delegating Release
//
////
ULONG __stdcall Release(void)
{
return m_pUnkOuter->Release() ;
}

////////////////////////////////////////////////////////////////
//
//MultParam()
//
//multiplies the two passed arguments and returns the
//value back in lVal.
//
//parameters:
//lMultmultiplier
//lValreturns value we are multiplied by
//
////
HRESULT __stdcall MultParam(long lMult, long *lVal)
{
*lVal = *lVal * lMult ;

return S_OK ;
}

////////////////////////////////////////////////////////////////
//
//Square()
//
//squares lVal, returning the result back in lResult.
//
//parameters:
//lValvalue to be squared
//lResult return value = lVal squared
//
////
HRESULT __stdcall Square(long lVal, long *lResult)
{
*lResult = lVal * lVal ;

return S_OK ;
}

////////////////////////////////////////////////////////////////
//
//GetClass()
//
//CoCreates a java-implemented object (CCW); returns the
//pointer into the v-table to the callee; exercises one
//method in the ccw.
//
//parameters:
//pjNatCompointer to our CCW.
//
////
HRESULT __stdcall GetClass(jINatCom **pjNatCom)
{
HRESULT hr ;

if (FAILED(hr = CoCreateInstance(CLSID_jCNatCom, NULL, CLSCTX_SERVER, IID_IUnknown, (void **)&m_punkCCW)))
{
return hr ;
}

if (FAILED(hr = m_punkCCW->QueryInterface(IID_jINatCom, (void **)&m_pNatCom)))
{
m_punkCCW->Release() ;// IID_IUnknown
m_punkCCW = NULL ;

return hr ;
}

// per the rules of COM we leave the refcount at 2, since
// we're passing the pointer back to the caller. Caller
// must Release() the object.

// set member variable
*pjNatCom = m_pNatCom ;

// invoke java-implemented method
m_pNatCom->ccwHelloWorld() ;

return S_OK ;
}

////////////////////////////////////////////////////////////////

private :

ULONGm_cRef ;// ref count
IUnknown*m_pUnkOuter ;// controlling unknown
jINatCom*m_pNatCom ;// ccw interface pointer
IUnknown*m_punkCCW ;// IUnknown of our CCW
} ;

CImpINatCom m_CImpINatCom ;

// PUBLIC --------------------------------------------------------------

public :

////////////////////////////////////////////////////////////////////////
//
//CNatCom()
//
//constructor; initializes variables, including those of
//CImpINatCom to point to controlling unknown.
//
////
CNatCom(IUnknown *punkOuter)
{
ObjectCreated() ;

m_cRef = 0 ;

// if this is non-null, we're being aggregated
if (punkOuter)
{
m_pUnkOuter = punkOuter ;
m_CImpINatCom.m_pUnkOuter = punkOuter ;
}
else
{
m_pUnkOuter = this ;
m_CImpINatCom.m_pUnkOuter = this ;
}
}

////////////////////////////////////////////////////////////////////////
//
//~CNatCom()
//
//destructor.
//
////
~CNatCom()
{
ObjectDestroyed() ;
}

////////////////////////////////////////////////////////////////////////
//
//QueryInterface()
//
//non-delegating QI
//
////
HRESULT __stdcall QueryInterface(REFIID riid, void **ppv)
{
*ppv = NULL ;

if (riid == IID_IUnknown)
{
*ppv = this ;
}

if (riid == IID_INatCom)
{
*ppv = &m_CImpINatCom ;
}

if (*ppv == NULL)
{
return E_NOINTERFACE ;
}

((IUnknown *) *ppv)->AddRef() ;

return NOERROR ;
}

////////////////////////////////////////////////////////////////////////
//
//AddRef()
//
//non-delegating AddRef()
//
////
ULONG __stdcall AddRef(void)
{
InterlockedIncrement( (LONG*)&m_cRef ) ;

return m_cRef ;
}

////////////////////////////////////////////////////////////////////////
//
//Release()
//
//non-delegating Release
//
////
ULONG __stdcall Release(void)
{
if (!InterlockedDecrement( (LONG*)&m_cRef ))
{
delete this ;
return 0 ;
}

return m_cRef ;
}

// PRIVATE -------------------------------------------------------------

private :

ULONGm_cRef ;// ref count
IUnknown*m_pUnkOuter ;// controlling unknown
} ;

// CLASS FACTORY --------------------------------------------------------------

////////////////////////////////////////////////////////////////////////////////
//
//CNatComCF
//
//class factory for CNatCom
//
////
class CNatComCF : public IClassFactory
{
public :

////////////////////////////////////////////////////////////////////////
//
//CNatComCF()
//
//constructor
//
////
CNatComCF()
{
m_cRef = 0 ;
}

///////////////////////////////////////////////////////////////////////
//
//CreateInstance()
//
//IClassFactory CreateInstance() method implementation
//
////
HRESULT __stdcall CreateInstance(IUnknown *punkOuter, REFIID riid, void **ppv)
{
CNatCom *cmg ;
HRESULT hr ;

*ppv = NULL ;

if ((punkOuter) && (riid != IID_IUnknown))
{
return CLASS_E_NOAGGREGATION ;
}

cmg = new CNatCom(punkOuter) ;

hr = cmg->QueryInterface(riid, ppv) ;

if (FAILED(hr))
{
delete cmg ;
return hr ;
}

return S_OK ;
}

////////////////////////////////////////////////////////////////////////
//
//QueryInterface()
//
//IUnknown QueryInterface() method implementation
//
////
HRESULT __stdcall QueryInterface(REFIID iid, void **ppv)
{
*ppv = NULL ;

if (iid == IID_IUnknown || iid == IID_IClassFactory)
*ppv = this ;
else
return E_NOINTERFACE ;

AddRef() ;

return S_OK ;
}

////////////////////////////////////////////////////////////////////////
//
//AddRef()
//
//IUnknown AddRef() method implementation
//
////
ULONG __stdcall AddRef(void)
{
return ++m_cRef ;
}

////////////////////////////////////////////////////////////////////////
//
//Release()
//
//IUnknown Release() method implementation
//
////
ULONG __stdcall Release(void)
{
if (--m_cRef == 0)
{
delete this ;
return 0 ;
}

return m_cRef ;
}

////////////////////////////////////////////////////////////////////////
//
//LockServer()
//
//IClassFactory LockServer() method implementation
//
////
HRESULT __stdcall LockServer(BOOL bLock)
{
bLock ? ObjectCreated() : ObjectDestroyed() ;

return S_OK ;
}


// PRIVATE -------------------------------------------------------------

private :

ULONGm_cRef ;// refcount
} ;

////////////////////////////////////////////////////////////////////////////////
//
//DllMain()
//
//entry point
//
////
BOOL WINAPI DllMain(HINSTANCE hDLLInst, DWORD fdwReason, LPVOID lpvReserved)
{
switch (fdwReason)
{
case DLL_PROCESS_ATTACH :
g_hDllMain = hDLLInst ;
}

return TRUE ;
}

// -----------------------------------------------------------------------------

TCHAR achSampleDesc[]= "CNatCom";
TCHAR achInprocServer32[]= "InprocServer32";
TCHAR achSampleProgID[] = "CNatCom";
TCHAR achProgID[]= "CNatCom";
TCHAR achThreadingModel[]= "ThreadingModel";
TCHAR achFree[] = "Both";

#define GUIDSTR_MAX(1+ 8 + 1 + 4 + 1 + 4 + 1 + 4 + 1 + 12 + 1 + 1)
static const CHAR szDigits[]= "0123456789ABCDEF";
static const BYTE GuidMap[]= { 3, 2, 1, 0, '-', 5, 4, '-', 7, 6, '-',
8, 9, '-', 10, 11, 12, 13, 14, 15 };

////////////////////////////////////////////////////////////////////////////////
//
//GUID2StringA()
//
//converts GUID to string form
//
////
VOID GUID2StringA(REFGUID rguid, LPSTR lpsz)
{
inti;
LPSTRp = lpsz;

const BYTE * pBytes = (const BYTE *) &rguid;

*p++ = '{';

for (i = 0; i < sizeof(GuidMap); i++)
{
if (GuidMap[i] == '-')
{
*p++ = '-';
}
else
{
*p++ = szDigits[ (pBytes[GuidMap[i]] & 0xF0) >> 4 ];
*p++ = szDigits[ (pBytes[GuidMap[i]] & 0x0F) ];
}
}

*p++ = '}';
*p = '\0';
}

////////////////////////////////////////////////////////////////////////////////
//
//NTCompatibleRegDeleteKey()
//
//checks that registry key does not have any subkeys prior to deletion
//
////
LONG NTCompatibleRegDeleteKey(HKEY hKey, LPCTSTR szSubKey)
{
TCHAR achName[MAX_PATH+1];
HKEY hSubkey;

if (ERROR_SUCCESS != RegOpenKey(hKey, szSubKey, &hSubkey))
return REGDB_E_INVALIDVALUE;

if (ERROR_SUCCESS == RegEnumKey(hSubkey, 0, achName, sizeof(achName)/sizeof(TCHAR)))
{
RegCloseKey(hSubkey);
// There's still one subkey: fail the call.
return REGDB_E_INVALIDVALUE;
}

RegCloseKey(hSubkey);
return RegDeleteKey(hKey, szSubKey);
}

////////////////////////////////////////////////////////////////////////////////
//
//DllRegisterServer()
//
//registers this COM server via the registry.
//
////
STDAPI DllRegisterServer(VOID)
{
HKEYhKey = NULL;
HKEYhKey2 = NULL;
HKEYhKey3 = NULL;
DWORDresult;
HRESULT hr = SELFREG_E_CLASS;
CHARachCLSID[GUIDSTR_MAX];
CHARachLIBID[GUIDSTR_MAX] ;
TCHARachModulePathName[MAX_PATH];
TCHARachCurrentDirectory[MAX_PATH] ;

// CLSID

GUID2StringA(CLSID_CNatCom, achCLSID) ;

// If we fail in the middle, the state of the registry entries
// is indeterminate (as per Ole specs.)

// Create HKEY_CLASSES_ROOT\progid\CLSID
result = RegCreateKey(HKEY_CLASSES_ROOT, achSampleProgID, &hKey);
if (result != ERROR_SUCCESS) goto lExit;

result = RegSetValue(hKey, NULL, REG_SZ, achSampleDesc, lstrlen(achSampleDesc));
if (result != ERROR_SUCCESS) goto lExit;

result = RegCreateKey(hKey, TEXT("CLSID"), &hKey2);
if (result != ERROR_SUCCESS) goto lExit;

result = RegSetValue(hKey2, NULL, REG_SZ, achCLSID, GUIDSTR_MAX-1);
if (result != ERROR_SUCCESS) goto lExit;

RegCloseKey(hKey);
RegCloseKey(hKey2);
hKey = NULL;
hKey2 = NULL;

// Create HKEY_CLASSES_ROOT\CLSID\...

// create CLSID key
result = RegCreateKey(HKEY_CLASSES_ROOT, TEXT("CLSID"), &hKey);
if (result != ERROR_SUCCESS) goto lExit ;

// create CLSID/GUID key
result = RegCreateKey(hKey, achCLSID, &hKey2);
if (result != ERROR_SUCCESS) goto lExit ;

// put in sample description value into CLSID\GUID key
result = RegSetValue(hKey2, NULL, REG_SZ, achSampleDesc, lstrlen(achSampleDesc));
if (result != ERROR_SUCCESS) goto lExit ;

// get our path ..
result = GetModuleFileName(g_hDllMain, achModulePathName, sizeof(achModulePathName)/sizeof(TCHAR));
if (result == 0) goto lExit ;

// create subkey under CLSID\GUID
result = RegCreateKey(hKey2, achInprocServer32, &hKey3);
if (result != ERROR_SUCCESS) goto lExit ;

// set key value to the path obtained above
result = RegSetValue(hKey3, NULL, REG_SZ, achModulePathName, lstrlen(achModulePathName));
if (result != ERROR_SUCCESS) goto lExit ;

// both
result = RegSetValueEx(hKey3, achThreadingModel, 0, REG_SZ, (BYTE*)achFree, sizeof(achFree));
if (result != ERROR_SUCCESS) goto lExit;

RegCloseKey(hKey3);
hKey3 = NULL;

// PROGID

result = RegCreateKey(hKey2, achProgID, &hKey3);
if (result != ERROR_SUCCESS) goto lExit;

result = RegSetValue(hKey3, NULL, REG_SZ, achSampleProgID, lstrlen(achSampleProgID));
if (result != ERROR_SUCCESS) goto lExit;

RegCloseKey(hKey3);
hKey3 = NULL;


hr = S_OK ;

lExit :

// close up
if (hKey) RegCloseKey(hKey);
if (hKey2) RegCloseKey(hKey2);
if (hKey3) RegCloseKey(hKey3);

return hr ;
}

////////////////////////////////////////////////////////////////////////////////
//
//DllUnregisterServer()
//
//removes our registry entries (entered via DllRegisterServer())
//
////
STDAPI DllUnregisterServer(VOID)
{
HKEYhKey = NULL;
HKEYhKey2 = NULL;
DWORDresult;
HRESULT hr = SELFREG_E_CLASS;
CHARachCLSID[GUIDSTR_MAX];
CHARachLIBID[GUIDSTR_MAX];

// If we fail in the middle, the state of the registry entries
// is indeterminate (as per Ole specs.)
GUID2StringA(CLSID_CNatCom, achCLSID);

result = RegOpenKey(HKEY_CLASSES_ROOT, achSampleProgID, &hKey);
if (result == ERROR_SUCCESS)
{
NTCompatibleRegDeleteKey(hKey, TEXT("CLSID"));
RegCloseKey(hKey);
hKey = NULL;
NTCompatibleRegDeleteKey(HKEY_CLASSES_ROOT, achSampleProgID);
}

result = RegOpenKey(HKEY_CLASSES_ROOT, TEXT("CLSID"), &hKey);
result = RegOpenKey(hKey, achCLSID, &hKey2);

if (result == ERROR_SUCCESS)
{
NTCompatibleRegDeleteKey(hKey2, achInprocServer32);
NTCompatibleRegDeleteKey(hKey2, achProgID);
RegCloseKey(hKey2);
hKey2 = NULL;
NTCompatibleRegDeleteKey(hKey, achCLSID);
}

// If this fails, it means somebody else added a subkey to this tree.
// We're not allowed to touch it so ignore the failure.

RegCloseKey(hKey);
hKey = NULL;

hr = S_OK;

return hr;
}


////////////////////////////////////////////////////////////////////////////////
//
//DllGetClassObject()
//
//COM entry point
//
////
STDAPI DllGetClassObject(REFCLSID rclsid, REFIID riid, VOID **ppv)
{
HRESULT hr ;
class CNatComCF *pcf;

*ppv = NULL ;

if (rclsid != CLSID_CNatCom)
{
return CLASS_E_CLASSNOTAVAILABLE;
}

pcf = new CNatComCF() ;

if (!pcf)
{
return CLASS_E_CLASSNOTAVAILABLE;
}

hr = pcf->QueryInterface(riid, ppv) ;

if (FAILED(hr))
{
delete pcf ;
return hr ;
}

return S_OK ;
}

////////////////////////////////////////////////////////////////////////////////
//
//DllCanUnloadNow()
//
//returns refcount of objects which are using this .dll
//
////
STDAPI DllCanUnloadNow()
{
return g_cObject ;
}