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

    FILE:       actestp.c

    PURPOSE:    
                
    FUNCTIONS:  
    COMMENTS:

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

#include <windows.h>
#include <ole2.h>
#include <oleext.h> // IAccessControl interface definition
#include <wchar.h>
#include <tchar.h>

#include <stdlib.h>
#include <stdio.h>
#include "oactest.h"    // header file generated by MIDL compiler

void DecrementLockCount();
void IncrementLockCount();
void ObjectCreated();
void ObjectDestroyed();

const CLSID CLSID_COAccessControl_DCOM
    = {0x52c0e9e1,0xc0c0,0x11cf,{0xae,0xec,0x00,0xaa,0x00,0x44,0xfb,0x89}};

extern "C" const CLSID CLSID_COAccessControlTest;
extern ULONG g_ulFrequency;
DWORD g_dwRegister;
long  g_fClassRegistered = FALSE;

// IAccessControlTest implementation class
class CAccessControlTest : public IAccessControlTest
{
private:
    IUnknown         *m_pIUnknown;
    IPersistStream   *m_pIPersistStream;
    IAccessControl   *m_pIAccessControl;
    ULONG            m_cRef;
    BOOL             m_bInitialized;

    // destructor
    ~CAccessControlTest()
    {
        DecrementLockCount();
        ObjectDestroyed();
    }


public:
    
    // contructor
    CAccessControlTest()
    {
        m_cRef = 0;
        m_bInitialized = FALSE;
        ObjectCreated();
        IncrementLockCount();
    }


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

    STDMETHODIMP_(ULONG) AddRef();

    STDMETHODIMP_(ULONG) Release();

    STDMETHODIMP_(HRESULT) TestServer
    (
    LPSTR pszTestString
    );

    STDMETHODIMP_(HRESULT) GetClassID
    (
    CLSID   *pClassID,
    DOUBLE  *pdMillisec
    );

    STDMETHODIMP_(HRESULT) InitNewACL
    (
    DOUBLE*pdMillisec
    );

    STDMETHODIMP_(HRESULT) LoadACL
    (
    LPCSTR  pszFilename,
    DOUBLE  *pdMillisec
    );

    STDMETHODIMP_(HRESULT) SaveACL
    (
    LPCSTR  pszFilename,
    BOOL    fClearDirty,
    ULONG   *pulBytesWritten,
    DOUBLE  *pdMillisec
    );

    STDMETHODIMP_(HRESULT) GetSizeMax
    (
    ULONG           *pcdSize,
    DOUBLE          *pdMillisec
    );

    STDMETHODIMP_(HRESULT) IsDirty
    (
    DOUBLE  *pdMillisec
    );

    STDMETHODIMP_(HRESULT) GrantAccessRights
    (
    ULONG            cCount,
    E_ACCESS_REQUEST *pAccessRequestList,
    DOUBLE           *pdMillisec
    );

    STDMETHODIMP_(HRESULT) DenyAccessRights
    (
    ULONG            cCount,
    E_ACCESS_REQUEST pAccessRequestList[],
    DOUBLE           *pdMillisec
    );

    STDMETHODIMP_(HRESULT) SetAccessRights
    (
    ULONG            cCount,
    E_ACCESS_REQUEST pAccessRequestList[],
    DOUBLE           *pdMillisec
    );

    STDMETHODIMP_(HRESULT) ReplaceAllAccessRights
    (
    ULONG             cCount,
    E_EXPLICIT_ACCESS pExplicitAccessList[],
    DOUBLE            *pdMillisec
    );

    STDMETHODIMP_(HRESULT) RevokeExplicitAccessRights
    (
    ULONG      cCount,
    E_TRUSTEE  pTrustee[],
    DOUBLE     *pdMillisec
    );

    STDMETHODIMP_(HRESULT) IsAccessPermitted
    (
    E_TRUSTEE   *pTrustee,
    DWORD       grfAccessPermissions,
    DOUBLE      *pdMillisec 
    );

    STDMETHODIMP_(HRESULT) GetEffectiveAccessRights
    (
    E_TRUSTEE   *pTrustee,  
    DWORD       *pdwRights,
    DOUBLE      *pdMillisec
    );

    STDMETHODIMP_(HRESULT) GetExplicitAccessRights
    (
    ULONG               *pcCount,
    PE_EXPLICIT_ACCESS  *ppExplicitAccessList,
    DOUBLE              *pdMillisec
    );

    STDMETHODIMP_(HRESULT) RevertAccessRights
    (
    );

    STDMETHODIMP_(HRESULT) CommitAccessRights
    (
    DWORD   grfCommitFlags
    );

}; // CAccessControlTest

//+-------------------------------------------------------------------------
//
//  Method:     CAccessControlTest::AddRef, public
//
//  Synopsis:   Increment reference count
//
//  See Also:   IUnknown::AddRef
//
//--------------------------------------------------------------------------
STDMETHODIMP_(ULONG) 
CAccessControlTest::AddRef()
{
    InterlockedIncrement((long *) &m_cRef);
    return m_cRef;
}

//+-------------------------------------------------------------------------
//
//  Method:     CAccessControlTest::Release, public
//
//  Synopsis:   Decrement DLL reference count
//
//  Notes:      After the m_cRef is decremented, the object may be 
//              deleted by another thread.  In order to make this code safe
//              for multiple threads, we have to access the object state 
//              before decrementing m_cRef.
//
//  See Also:   IUnknown::Release.
//
//--------------------------------------------------------------------------
STDMETHODIMP_(ULONG)
CAccessControlTest::Release()
{
    unsigned long count;
    
    count = m_cRef - 1;

    if(InterlockedDecrement((long *) &m_cRef) == 0)
    {
        count = 0;
        if(m_bInitialized)
        {
            m_pIUnknown->Release();
            m_pIPersistStream->Release();
            m_pIAccessControl->Release();
        }
        delete this;
    }

    return count;
}

//+-------------------------------------------------------------------------
//
//  Method:     CAccessControlTest::QueryInterface, public
//
//  Synopsis:   Query for an interface on the class factory.
//
//  See Also:   IUnknown:QueryInterface
//
//--------------------------------------------------------------------------
STDMETHODIMP_(HRESULT)
CAccessControlTest::QueryInterface
(
REFIID iid,
void **ppv
)
{
    HRESULT hr;

    if (!m_bInitialized)
    {
        hr = CoCreateInstance( CLSID_COAccessControl_DCOM
                             , NULL
                             , CLSCTX_INPROC_SERVER
                             , IID_IUnknown
                             , (void **)&m_pIUnknown);
        if(FAILED(hr))      
        {
            printf("Failed to create an instance of COAccessControl\n.");
            return hr;
        }

        hr = m_pIUnknown->QueryInterface(IID_IPersistStream, (void **)&m_pIPersistStream);

        if(FAILED(hr))      
        {
            printf("Failed to query for the IPersistStream Interface.\n");
            return hr;
        }
        hr = m_pIUnknown->QueryInterface(IID_IAccessControl, (void **)&m_pIAccessControl);

        if(FAILED(hr))
        {
            printf("Failed to query for the IAccessControl interface.\n");
            return hr;
        }
        m_bInitialized = TRUE;
    }


    if ( IsEqualGUID( iid, IID_IUnknown ) )
    {
        *ppv = (IUnknown *) this;
        ((IUnknown *)(*ppv))->AddRef();
	    hr = S_OK;
    }
    else if (IsEqualGUID( iid, IID_IAccessControlTest))
    {
        *ppv = (IUnknown *)(IAccessControlTest *)this;
        ((IAccessControlTest *)(*ppv))->AddRef();
        hr = S_OK;
    }
    else
    {
        *ppv = 0;
        hr = E_NOINTERFACE;
    }

    return hr;
}

STDMETHODIMP_(HRESULT) CAccessControlTest::TestServer
(
LPSTR pszTestString
)
{
    printf("The test string is: %s\n", pszTestString);

    return S_OK;
}

STDMETHODIMP_(HRESULT) CAccessControlTest::GetClassID
(
CLSID   *pClassID,
DOUBLE  *pdMillisec
)
{
    HRESULT    localhr;
    CLSID      clsid;

    LARGE_INTEGER liCount1;
    LARGE_INTEGER liCount2;

    QueryPerformanceCounter(&liCount1);
    localhr = m_pIPersistStream->GetClassID(&clsid);
    QueryPerformanceCounter(&liCount2);

    // Assign calues to the out parameters
    *pClassID = clsid;
    *pdMillisec = ((DOUBLE)(liCount2.LowPart) - (DOUBLE)(liCount1.LowPart)) / (DOUBLE)(g_ulFrequency) * 1000.0;
    return localhr;
}

STDMETHODIMP_(HRESULT) CAccessControlTest::InitNewACL
(
DOUBLE  *pdMillisec
)
{
    HRESULT    localhr;

    LARGE_INTEGER liCount1;
    LARGE_INTEGER liCount2;

    QueryPerformanceCounter(&liCount1);
    localhr = m_pIPersistStream->Load(NULL);
    QueryPerformanceCounter(&liCount2);

    // Assign calues to the out parameters
    *pdMillisec = ((DOUBLE)(liCount2.LowPart) - (DOUBLE)(liCount1.LowPart)) / (DOUBLE)(g_ulFrequency) * 1000.0;
    return localhr;

}

STDMETHODIMP_(HRESULT) CAccessControlTest::LoadACL
(
LPCSTR  pszFilename,
DOUBLE  *pdMillisec
)
{
    HRESULT    localhr;
    IStream    *pIStream = NULL;
    HANDLE     FileHandle;
    DWORD      dwFileSize;
    void       *pvBuffer;

    LARGE_INTEGER liCount1;
    LARGE_INTEGER liCount2;

    // Open the file specified by the client
    FileHandle = CreateFileA( pszFilename
                            , GENERIC_READ
                            , FILE_SHARE_READ | FILE_SHARE_WRITE
                            , NULL
                            , OPEN_EXISTING
                            , FILE_ATTRIBUTE_NORMAL
                            , NULL );

    if( FileHandle == INVALID_HANDLE_VALUE )
    {   
        printf("Cannot open file %s.\n", pszFilename);
        *pdMillisec = 0;
        return HRESULT_FROM_WIN32(GetLastError());
    }

    // Get the size of the file
    dwFileSize = GetFileSize(FileHandle, NULL);

    // Create a buffer to hold the data in the file
    pvBuffer = CoTaskMemAlloc(dwFileSize);


    DWORD dwBytesRead;
    // Read the data of the opened file into a buffer
    if(!ReadFile( FileHandle
                , pvBuffer
                , dwFileSize
                , &dwBytesRead
                , NULL ))
    {
    
        return HRESULT_FROM_WIN32(GetLastError());
    }

    // Once we have read the file data into a buffer, we can
    // close the file handle
    CloseHandle( FileHandle);

    // Create a stream on the the buffer 
    localhr = CreateStreamOnHGlobal(NULL, TRUE, &pIStream);

    if (FAILED(localhr))
    {
        printf("Cannot create stream object.\n");
        CoTaskMemFree(pvBuffer);
        *pdMillisec = 0;
        return localhr;
    }

    // Load the data in the buffer into the IStream object
    localhr = pIStream->Write(pvBuffer, dwFileSize, NULL);

    // Release the local buffer
    CoTaskMemFree(pvBuffer);


    if (FAILED(localhr))
    {
        printf("Failed to load data into stream object.\n");
        *pdMillisec = 0;
        return localhr;
    }

    // Rewind the stream pointer the starting position
    LARGE_INTEGER li;
    li.LowPart = 0;
    li.HighPart = 0;
    localhr = pIStream->Seek(li, STREAM_SEEK_SET, NULL);

    if (FAILED(localhr))
    {
        printf("Failed to set the stream pointer to the starting position.\n");
        *pdMillisec = 0;
        return localhr;
    }

    QueryPerformanceCounter(&liCount1);
    localhr = m_pIPersistStream->Load(pIStream);
    QueryPerformanceCounter(&liCount2);
    

    // Assign calues to the out parameters
    *pdMillisec = ((DOUBLE)(liCount2.LowPart) - (DOUBLE)(liCount1.LowPart)) / (DOUBLE)(g_ulFrequency) * 1000.0;

    // Release the local stream pointer
    pIStream->Release();

    return localhr;
}

STDMETHODIMP_(HRESULT) CAccessControlTest::SaveACL
(
LPCSTR  pszFilename,
BOOL    fClearDirty,
ULONG   *pulNumOfBytesWritten,
DOUBLE  *pdMillisec
)
{
    HRESULT    localhr;
    IStream    *pIStream = NULL;
    HANDLE     FileHandle;
    DWORD      dwFileSize;
    void       *pvBuffer;
    STATSTG    StreamInfo;

    LARGE_INTEGER liCount1;
    LARGE_INTEGER liCount2;

    // Create a stream on the the buffer 
    localhr = CreateStreamOnHGlobal(NULL, TRUE, &pIStream);

    if (FAILED(localhr))
    {
        printf("Cannot create stream object.\n");
        *pdMillisec = 0;
        return localhr;
    }

    QueryPerformanceCounter(&liCount1);
    localhr = m_pIPersistStream->Save(pIStream, fClearDirty);
    QueryPerformanceCounter(&liCount2);

    if(FAILED(localhr))
    {
        *pdMillisec = ((DOUBLE)(liCount2.LowPart) - (DOUBLE)(liCount1.LowPart)) / (DOUBLE)(g_ulFrequency) * 1000.0;
        return localhr;
    }

    // Get the number of bytes written to the stream
    localhr = pIStream->Stat(&StreamInfo, STATFLAG_NONAME);
    if (FAILED(localhr))
    {
        printf("Unable to get information about the local stream.\n");
        *pdMillisec = ((DOUBLE)(liCount2.LowPart) - (DOUBLE)(liCount1.LowPart)) / (DOUBLE)(g_ulFrequency) * 1000.0;
        return localhr;
    }

    dwFileSize = StreamInfo.cbSize.LowPart;

    LARGE_INTEGER liOffset;

    liOffset.QuadPart = Int32x32To64(dwFileSize, -1);
    pIStream->Seek(liOffset,STREAM_SEEK_CUR, NULL);

    // Allocate a buffer to store the data in the stream
    pvBuffer = CoTaskMemAlloc(dwFileSize);

    // Write the stream
    localhr = pIStream->Read(pvBuffer, dwFileSize, NULL);

    if(FAILED(localhr))
    {
        printf("Unable to write data from stream to buffer.\n");
        CoTaskMemFree(pvBuffer);
        *pdMillisec = ((DOUBLE)(liCount2.LowPart) - (DOUBLE)(liCount1.LowPart)) / (DOUBLE)(g_ulFrequency) * 1000.0;
        return localhr;
    }    

    // Open the file specified by the client
    FileHandle = CreateFileA( pszFilename
                            , GENERIC_WRITE | GENERIC_READ
                            , FILE_SHARE_READ | FILE_SHARE_WRITE
                            , NULL
                            , CREATE_ALWAYS
                            , FILE_ATTRIBUTE_NORMAL
                            , NULL );

    if( FileHandle == INVALID_HANDLE_VALUE )
    {   
        printf("Cannot open file %s.\n", pszFilename);
        CoTaskMemFree(pvBuffer);
        *pdMillisec = ((DOUBLE)(liCount2.LowPart) - (DOUBLE)(liCount1.LowPart)) / (DOUBLE)(g_ulFrequency) * 1000.0;
        return HRESULT_FROM_WIN32(GetLastError());
    }

    // Read the data of the opened file into a buffer
    if(!WriteFile( FileHandle
                 , pvBuffer
                 , dwFileSize
                 , pulNumOfBytesWritten
                 , NULL ))
    {
        DWORD dwLastError;
        dwLastError = GetLastError();
        printf("Write failed with error code %x.", dwLastError);
    }

    // Flush the file buffers
    FlushFileBuffers(FileHandle);

    // Close the file handle
    CloseHandle(FileHandle);

    CoTaskMemFree(pvBuffer);


    // Assign calues to the out parameters
    *pdMillisec = ((DOUBLE)(liCount2.LowPart) - (DOUBLE)(liCount1.LowPart)) / (DOUBLE)(g_ulFrequency) * 1000.0;
    *pulNumOfBytesWritten = dwFileSize;


    // Release the local stream pointer
    pIStream->Release();

    return localhr;
}

STDMETHODIMP_(HRESULT) CAccessControlTest::GetSizeMax
(
ULONG   *pcdSize,
DOUBLE  *pdMillisec
)
{
    ULARGE_INTEGER  uliSize;
    HRESULT         localhr;    
    
    LARGE_INTEGER liCount1;
    LARGE_INTEGER liCount2;


    QueryPerformanceCounter(&liCount1);
    localhr = m_pIPersistStream->GetSizeMax(&uliSize);
    QueryPerformanceCounter(&liCount2);

    // Assign calues to the out parameters
    *pcdSize = uliSize.LowPart;
    *pdMillisec = ((DOUBLE)(liCount2.LowPart) - (DOUBLE)(liCount1.LowPart)) / (DOUBLE)(g_ulFrequency) * 1000.0;
    return localhr;
}

STDMETHODIMP_(HRESULT) CAccessControlTest::IsDirty
(
DOUBLE  *pdMillisec
)
{
    HRESULT    localhr;

    LARGE_INTEGER liCount1;
    LARGE_INTEGER liCount2;

    
    QueryPerformanceCounter(&liCount1);
    localhr = m_pIPersistStream->IsDirty();
    QueryPerformanceCounter(&liCount2);

    // Assign calues to the out parameters
    *pdMillisec = ((DOUBLE)(liCount2.LowPart) - (DOUBLE)(liCount1.LowPart)) / (DOUBLE)(g_ulFrequency) * 1000.0;

    return localhr;
}

STDMETHODIMP_(HRESULT) CAccessControlTest::GrantAccessRights
(
ULONG            cCount,
E_ACCESS_REQUEST pAccessRequestList[],
DOUBLE           *pdMillisec
)
{
    HRESULT    localhr;

    LARGE_INTEGER liCount1;
    LARGE_INTEGER liCount2;

    
    QueryPerformanceCounter(&liCount1);
    localhr = m_pIAccessControl->GrantAccessRights(cCount, (ACCESS_REQUEST_W *)pAccessRequestList);
    QueryPerformanceCounter(&liCount2);

    // Assign calues to the out parameters
    *pdMillisec = ((DOUBLE)(liCount2.LowPart) - (DOUBLE)(liCount1.LowPart)) / (DOUBLE)(g_ulFrequency) * 1000.0;
    return localhr;
}

STDMETHODIMP_(HRESULT) CAccessControlTest::SetAccessRights
(
ULONG            cCount,
E_ACCESS_REQUEST pAccessRequestList[],
DOUBLE           *pdMillisec
)
{
    HRESULT    localhr;

    LARGE_INTEGER liCount1;
    LARGE_INTEGER liCount2;

    QueryPerformanceCounter(&liCount1);
    localhr = m_pIAccessControl->SetAccessRights(cCount, (ACCESS_REQUEST_W *)pAccessRequestList);
    QueryPerformanceCounter(&liCount2);

    // Assign calues to the out parameters
    *pdMillisec = ((DOUBLE)(liCount2.LowPart) - (DOUBLE)(liCount1.LowPart)) / (DOUBLE)(g_ulFrequency) * 1000.0;
    return localhr;
}

STDMETHODIMP_(HRESULT) CAccessControlTest::DenyAccessRights
(
ULONG            cCount,
E_ACCESS_REQUEST pAccessRequestList[],
DOUBLE           *pdMillisec
)
{
    HRESULT    localhr;

    LARGE_INTEGER liCount1;
    LARGE_INTEGER liCount2;

    
    QueryPerformanceCounter(&liCount1);
    localhr = m_pIAccessControl->DenyAccessRights(cCount, (ACCESS_REQUEST_W *)pAccessRequestList);
    QueryPerformanceCounter(&liCount2);

    // Assign calues to the out parameters
    *pdMillisec = ((DOUBLE)(liCount2.LowPart) - (DOUBLE)(liCount1.LowPart)) / (DOUBLE)(g_ulFrequency) * 1000.0;
    return localhr;
}

STDMETHODIMP_(HRESULT) CAccessControlTest::ReplaceAllAccessRights
(
ULONG             cCount,
E_EXPLICIT_ACCESS pExplicitAccessList[],
DOUBLE            *pdMillisec
)
{
    HRESULT    localhr;

    LARGE_INTEGER liCount1;
    LARGE_INTEGER liCount2;

    
    QueryPerformanceCounter(&liCount1);
    localhr = m_pIAccessControl->ReplaceAllAccessRights(cCount, (EXPLICIT_ACCESS_W *)pExplicitAccessList);
    QueryPerformanceCounter(&liCount2);

    // Assign calues to the out parameters
    *pdMillisec = ((DOUBLE)(liCount2.LowPart) - (DOUBLE)(liCount1.LowPart)) / (DOUBLE)(g_ulFrequency) * 1000.0;
    return localhr;
}

STDMETHODIMP_(HRESULT) CAccessControlTest::RevokeExplicitAccessRights
(
ULONG             cCount,
E_TRUSTEE         pTrustee[],
DOUBLE            *pdMillisec
)
{
    char       *pszClientName;
    RPC_STATUS status;
    HRESULT    localhr;

    LARGE_INTEGER liCount1;
    LARGE_INTEGER liCount2;

    QueryPerformanceCounter(&liCount1);
    localhr = m_pIAccessControl->RevokeExplicitAccessRights(cCount, (TRUSTEE_W *)pTrustee);
    QueryPerformanceCounter(&liCount2);


    // Assign calues to the out parameters
    *pdMillisec = ((DOUBLE)(liCount2.LowPart) - (DOUBLE)(liCount1.LowPart)) / (DOUBLE)(g_ulFrequency) * 1000.0;
    return localhr;
}

STDMETHODIMP_(HRESULT) CAccessControlTest::IsAccessPermitted
(
E_TRUSTEE         *pTrustee,
DWORD             grfAccessPermissions,
DOUBLE            *pdMillisec
)
{
    HRESULT    localhr;

    LARGE_INTEGER liCount1;
    LARGE_INTEGER liCount2;

    QueryPerformanceCounter(&liCount1);
    localhr = m_pIAccessControl->IsAccessPermitted((TRUSTEE_W *)pTrustee, grfAccessPermissions);
    QueryPerformanceCounter(&liCount2);

    // Assign calues to the out parameters
    *pdMillisec = ((DOUBLE)(liCount2.LowPart) - (DOUBLE)(liCount1.LowPart)) / (DOUBLE)(g_ulFrequency) * 1000.0;
    return localhr;
}

STDMETHODIMP_(HRESULT) CAccessControlTest::GetEffectiveAccessRights
(
E_TRUSTEE         *pTrustee,
DWORD             *pdwRights,
DOUBLE            *pdMillisec
)
{
    HRESULT    localhr;

    LARGE_INTEGER liCount1;
    LARGE_INTEGER liCount2;

    QueryPerformanceCounter(&liCount1);
    localhr = m_pIAccessControl->GetEffectiveAccessRights((TRUSTEE_W *)pTrustee, pdwRights);
    QueryPerformanceCounter(&liCount2);

    // Assign calues to the out parameters
    *pdMillisec = ((DOUBLE)(liCount2.LowPart) - (DOUBLE)(liCount1.LowPart)) / (DOUBLE)(g_ulFrequency) * 1000.0;
    return localhr;
}

STDMETHODIMP_(HRESULT) CAccessControlTest::GetExplicitAccessRights
(
ULONG              *pcCount,
PE_EXPLICIT_ACCESS *ppExplicitAccessList,
DOUBLE             *pdMillisec
)
{
    HRESULT    localhr;

    LARGE_INTEGER liCount1;
    LARGE_INTEGER liCount2;

    QueryPerformanceCounter(&liCount1);
    localhr = m_pIAccessControl->GetExplicitAccessRights(pcCount, (PEXPLICIT_ACCESS_W *)ppExplicitAccessList);
    QueryPerformanceCounter(&liCount2);

    // Assign calues to the out parameters
    *pdMillisec = ((DOUBLE)(liCount2.LowPart) - (DOUBLE)(liCount1.LowPart)) / (DOUBLE)(g_ulFrequency) * 1000.0;
    return localhr;
}

STDMETHODIMP_(HRESULT) CAccessControlTest::RevertAccessRights
(
)
{
    return m_pIAccessControl->RevertAccessRights();

}


STDMETHODIMP_(HRESULT) CAccessControlTest::CommitAccessRights
(
DWORD   grfCommitFlags
)
{
    return m_pIAccessControl->CommitAccessRights(grfCommitFlags);
}

class CACTestClassFactory : public IClassFactory
{
private:
    unsigned long    m_cRef;

    //destructor
    ~CACTestClassFactory()
    {
        ObjectDestroyed();
    }

public:
    //constructor
    CACTestClassFactory()
    {
        m_cRef = 0;
        ObjectCreated();
    }

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

};

//+-------------------------------------------------------------------------
//
//  Method:     CACTestClassFactory::AddRef, public
//
//  Synopsis:   Increment DLL reference counts
//
//  See Also:   IUnknown::AddRef
//
//--------------------------------------------------------------------------
ULONG STDMETHODCALLTYPE 
CACTestClassFactory::AddRef()
{
    InterlockedIncrement((long *) &m_cRef);
    return m_cRef;
}

//+-------------------------------------------------------------------------
//
//  Method:     CACTestClassFactory::CreateInstance, public
//
//  Synopsis:   Create an instance of CAccessControlTest.
//
//  See Also:   IClassFactory::CreateInstance
//
//--------------------------------------------------------------------------
HRESULT STDMETHODCALLTYPE 
CACTestClassFactory::CreateInstance
(
    IUnknown *punkOuter,
    REFIID riid,
    void **ppv
)
{
    HRESULT hr;
    CAccessControlTest *pACTest;

    if(punkOuter != 0)
    {
        //The CAccessControlTest class doesn't support aggregation.
        return CLASS_E_NOAGGREGATION;
    }

    pACTest = new CAccessControlTest();
    if(pACTest != 0)
    {
        hr = pACTest->QueryInterface(riid, ppv);
    }
    else
    {
        hr = E_OUTOFMEMORY;
        *ppv = 0;
    }

    return hr;
}

//+-------------------------------------------------------------------------
//
//  Method:     CACTestClassFactory::LockServer, public
//
//  Synopsis:   Lock the server in memory (by adding an extra reference)
//
//  Notes:      The class factory will be revoked when the lock count
//              is decremented to zero.  LockServer(TRUE) will increment the
//              lock count and ensure that the class factory will
//              not be revoked.
//
//  See Also:   IClassFactory::LockServer
//
//--------------------------------------------------------------------------
HRESULT STDMETHODCALLTYPE 
CACTestClassFactory::LockServer(
    BOOL fLock )
{
    if (fLock == TRUE)
        IncrementLockCount();
    else
        DecrementLockCount();

    return S_OK;
}


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

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

    return hr;
}
//+-------------------------------------------------------------------------
//
//  Method:     CACTestClassFactory::Release, public
//
//  Synopsis:   Decrement DLL reference count
//
//  See Also:   IUnknown::Release
//
//--------------------------------------------------------------------------
ULONG STDMETHODCALLTYPE
CACTestClassFactory::Release()
{
    unsigned long count;
    
    count = m_cRef - 1;

    if(InterlockedDecrement((long *) &m_cRef) == 0)
    {
        count = 0;
        delete this;
    }
    return count;
}

//+-------------------------------------------------------------------------
//
//  Function:   RegisterClassFactory.
//
//  Synopsis:   Register the class factory if it is not currently registered.
//
//--------------------------------------------------------------------------
HRESULT RegisterClassFactory()
{
    HRESULT hr;
    CACTestClassFactory *pClassFactory;

    if(InterlockedExchange(&g_fClassRegistered, TRUE) == FALSE)
    {
        pClassFactory = new CACTestClassFactory;
        
        if(pClassFactory != 0)
        {
            hr = CoRegisterClassObject(CLSID_COAccessControlTest,
	   	        		               (IUnknown *) pClassFactory,
	    	        	               CLSCTX_LOCAL_SERVER,
		    	                       REGCLS_MULTIPLEUSE,
			                           &g_dwRegister);
        }
        else
        {
           hr = E_OUTOFMEMORY;
        }
    }
    else
    {
        hr = S_OK;
    }
    return hr;  
}

//+-------------------------------------------------------------------------
//
//  Function:   RevokeClassFactory.
//
//  Synopsis:   Revoke the registered class factories if they have not
//              already been revoked.
//
//--------------------------------------------------------------------------
HRESULT RevokeClassFactory()
{
    HRESULT hr;

    if(InterlockedExchange(&g_fClassRegistered, FALSE) == TRUE)
    {
        hr = CoRevokeClassObject(g_dwRegister);
    }
    else
    {
        hr = S_OK;
    }
    return hr;
}


