//+---------------------------------------------------------------------------
//
//  Microsoft Windows
//  Copyright (C) Microsoft Corporation, 1992 - 1993.
//
//  File:	df32.hxx
//
//  Contents:	Docfile generic header for 32-bit functions
//
//  Classes:	CGlobalSecurity
//              CDfMutex
//
//  History:	09-Oct-93	DrewB	Created
//
//----------------------------------------------------------------------------

#ifndef __DF32_HXX__
#define __DF32_HXX__

#ifdef WIN32

#include <dfexcept.hxx>

// Make an scode out of the last Win32 error
// Error that may map to STG_* scodes should go through Win32ErrorToScode
#define WIN32_SCODE(err) HRESULT_FROM_WIN32(err)
#define LAST_SCODE WIN32_SCODE(GetLastError())
#define LAST_STG_SCODE Win32ErrorToScode(GetLastError())

//+---------------------------------------------------------------------------
//
//  Class:	CGlobalSecurity (gs)
//
//  Purpose:	Encapsulates a global SECURITY_DESCRIPTOR and
//              SECURITY_ATTRIBUTES
//
//  Interface:	See below
//
//  History:	18-Jun-93	DrewB	Created
//
//  Notes:	Only active for Win32 platforms which support security
//              Init MUST be called before this is used
//
//----------------------------------------------------------------------------

#if WIN32 == 100 || WIN32 > 200

// This leaves space for 8 sub authorities.  Currently NT only uses 6
const DWORD SIZEOF_SID = 44;

// This leaves space for 1 access allowed ACEs in the ACL.
const DWORD SIZEOF_ACL = sizeof(ACL) + sizeof(ACCESS_ALLOWED_ACE) + SIZEOF_SID;

const DWORD SIZEOF_TOKEN_USER   = sizeof(TOKEN_USER) + SIZEOF_SID;

class CGlobalSecurity
{
private:
    BYTE _acl[SIZEOF_ACL];
    SECURITY_DESCRIPTOR _sd;
    BYTE _sdExt[SIZEOF_SID*2 + SIZEOF_ACL];
    SECURITY_ATTRIBUTES _sa;
#if DBG == 1
    BOOL _fInit;
#endif

public:
#if DBG == 1
    CGlobalSecurity(void) { _fInit = FALSE; }
#endif    
    SCODE Init(BOOL fAcl)
    {
#ifdef MULTIHEAP
        ACL *pacl = fAcl ? (ACL *) &_acl : NULL;
        BYTE pTokenUser[SIZEOF_TOKEN_USER];

        if (pacl != NULL)
        {
            BOOL fToken = TRUE;
            HANDLE hToken;
            DWORD lIgnore;

            // Initialize a new ACL.
            if (!InitializeAcl( pacl, SIZEOF_ACL, ACL_REVISION))
                return LAST_SCODE;

            if (!OpenThreadToken(GetCurrentThread(), TOKEN_READ, TRUE, &hToken))
            {
                if (!OpenProcessToken(GetCurrentProcess(), TOKEN_READ, &hToken))
                    fToken = FALSE;
            }

            if (fToken)
            {
                if (!GetTokenInformation( hToken, TokenUser,
                    (TOKEN_USER*)pTokenUser, SIZEOF_TOKEN_USER, &lIgnore ))
                {
                    CloseHandle (hToken);
                    return LAST_SCODE;
                }
                CloseHandle (hToken);

                // Allow current user access.
                if (!AddAccessAllowedAce( pacl, ACL_REVISION,
                     STANDARD_RIGHTS_ALL | GENERIC_ALL,
                     ((TOKEN_USER *)pTokenUser)->User.Sid ))
                    return LAST_SCODE;
            }
        }
#else
        ACL *pacl = NULL;
#endif

        if (!InitializeSecurityDescriptor(&_sd, SECURITY_DESCRIPTOR_REVISION))
            return LAST_SCODE;

        if (!SetSecurityDescriptorDacl(&_sd, TRUE, pacl, FALSE))
            return LAST_SCODE;

        _sa.nLength = sizeof(SECURITY_ATTRIBUTES);
        _sa.lpSecurityDescriptor = &_sd;
        _sa.bInheritHandle = FALSE;
#if DBG == 1
        _fInit = TRUE;
#endif        
        return S_OK;
    }

    operator SECURITY_DESCRIPTOR *(void) { olAssert(_fInit); return &_sd; }
    operator SECURITY_ATTRIBUTES *(void) { olAssert(_fInit); return &_sa; }
};
#endif


//
// Global Critical Sections have two components. One piece is shared between 
// all applications using the global lock. This portion will typically reside 
// in some sort of shared memory.  The second piece is per-process. This 
// contains a per-process handle to the shared critical section lock semaphore.
// The semaphore is itself shared, but each process may have a different handle
// value to the semaphore.
//
// Global critical sections are attached to by name. The application wishing to
// attach must know the name of the critical section (actually the name of the
// shared lock semaphore, and must know the address of the global portion of 
// the critical section
//

#define SUPPORT_RECURSIVE_LOCK

typedef struct _GLOBAL_SHARED_CRITICAL_SECTION {
    LONG  LockCount;
#ifdef SUPPORT_RECURSIVE_LOCK
    LONG  RecursionCount;
    DWORD OwningThread;
#else
#if DBG == 1
    DWORD OwningThread;
#endif
#endif
    DWORD Reserved;
} GLOBAL_SHARED_CRITICAL_SECTION, *PGLOBAL_SHARED_CRITICAL_SECTION;



//+---------------------------------------------------------------------------
//
//  Class:	CDfMutex (dmtx)
//
//  Purpose:	A multi-process synchronization object
//
//  Interface:	See below
//
//  History:	05-Apr-93	DrewB	Created
//		19-Jul-95	SusiA	Added HaveMutex
//
//  Notes:      Only active for Win32 implementations which support threads
//              For platforms with security, a global security descriptor is
//              used
//
//----------------------------------------------------------------------------

// Default timeout of twenty minutes
#define DFM_TIMEOUT 1200000

class CDfMutex
{
public:
    inline CDfMutex(void);
    SCODE Init(TCHAR *ptcsName);
    ~CDfMutex(void);

    SCODE Take(DWORD dwTimeout);
    void Release(void);

    BOOL IsHandleValid (TCHAR *ptcsName);

#if DBG == 1
    //check to see if the current thread already has the mutex
    inline BOOL  HaveMutex(void);  
#endif
private:
    PGLOBAL_SHARED_CRITICAL_SECTION _pGlobalPortion;
    HANDLE _hLockSemaphore;
    HANDLE _hSharedMapping;
};

inline CDfMutex::CDfMutex(void)
{
    _pGlobalPortion = NULL;
    _hLockSemaphore = NULL;
    _hSharedMapping = NULL;
}

#if DBG == 1
//+--------------------------------------------------------------
//
//  Member:     CDfMutex::HaveMutex, public
//
//  Synopsis:   This routine checks to see if the current thread 
//		already has the mutex
//
//  History:    19-Jul-95       SusiA   Created
//
//  Algorithm:  Checks the current thread to see if it already owns 
//		the mutex.  Returns TRUE if it does, FALSE otherwise
//              
//
//---------------------------------------------------------------

inline BOOL 
CDfMutex::HaveMutex(
    void
    )
{
	if ( _pGlobalPortion->OwningThread == GetCurrentThreadId()) 
	   	return TRUE;
	else 
		return FALSE;
}
#endif

//+---------------------------------------------------------------------------
//
//  Class:	CStaticDfMutex (sdmtx)
//
//  Purpose:	Static version of CDfMutex
//
//  Interface:	CDfMutex
//
//  History:	10-Oct-93	DrewB	Created
//
//  Notes:	Throws exceptions on initialization failures
//
//----------------------------------------------------------------------------

class CStaticDfMutex : public CDfMutex
{
public:
    inline CStaticDfMutex(TCHAR *ptcsName);
};

inline CStaticDfMutex::CStaticDfMutex(TCHAR *ptcsName)
        : CDfMutex()
{
    SCODE sc;

    sc = Init(ptcsName);
    if (FAILED(sc))
        THROW_SC(sc);
}

#ifdef ONETHREAD
//Mutex used to control access for based pointers.
extern CStaticDfMutex s_dmtxProcess;
#endif

#endif // WIN32

#endif // #ifndef __DF32_HXX__