Leaked source code of windows server 2003
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 
 
 
 

240 lines
6.6 KiB

#ifndef _REFHANDLE_H_
#define _REFHANDLE_H_
// ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
//
// REFHANDLE.H
//
// Copyright 1999 Microsoft Corporation, All Rights Reserved
//
#include <ex\refcnt.h>
#include <ex\autoptr.h>
// ========================================================================
//
// CLASS IRefHandle
//
// Implements a refcounted handle. AddRef() and Release() replace the
// much slower in-process DuplicateHandle() calls.
//
// The reason for the interface is that handles may come from many sources
// and it is not always clear what we should do once we are done with one
// when the last ref goes away. In the most common case (where we own the
// raw handle) we just want to call CloseHandle(). But we don't always own
// the raw handle. When someone else owns the raw handle, we must use
// their mechanisms to indicate when we are done using it. CIFSHandle in
// davex\exifs.cpp is one such instance.
//
class IRefHandle : public CRefCountedObject
{
// NOT IMPLEMENTED
//
IRefHandle( const IRefHandle& );
IRefHandle& operator=( const IRefHandle& );
protected:
// CREATORS
// Only create this object through it's descendents!
//
IRefHandle()
{
//
// Start the ref count at 1. The expectation is that we will
// typically use constructs like this
//
// auto_ref_handle hf;
// hf.take_ownership(new CFooRefHandle());
//
// or this
//
// auto_ref_ptr<IRefHandle> pRefHandle;
// pRefHandle.take_ownership(new CFooRefHandle());
//
// when creating these objects.
//
m_cRef = 1;
}
public:
// CREATORS
//
virtual ~IRefHandle() = 0 {}
// ACCESSORS
//
virtual HANDLE Handle() const = 0;
};
// ========================================================================
//
// CLASS CRefHandle
//
// By far the most common form of a refcounted handle -- the one where we
// own the raw HANDLE and must call CloseHandle() on it when we are done.
//
// This is implemented as a simple refcounted auto_handle.
//
class CRefHandle : public IRefHandle
{
//
// The handle
//
auto_handle<HANDLE> m_h;
// NOT IMPLEMENTED
//
CRefHandle( const CRefHandle& );
CRefHandle& operator=( const CRefHandle& );
public:
// CREATORS
//
CRefHandle(auto_handle<HANDLE>& h)
{
// Take ownership of the passed-in auto_handle
//
*m_h.load() = h.relinquish();
}
// ACCESSORS
//
HANDLE Handle() const
{
return m_h;
}
};
// ========================================================================
//
// CLASS auto_ref_handle
//
// Implements automatic refcounting on IRefHandle objects. The idea is
// that an auto_ref_handle can be used in most cases to replace a raw
// HANDLE. The main difference is that copying a raw HANDLE introduces
// an issue of ownership, but copying an auto_ref_handle does not.
// Typically, a raw handle is copied with an expensive DuplicateHandle()
// call. Copying an auto_ref_handle just does a cheap AddRef().
//
class auto_ref_handle
{
auto_ref_ptr<IRefHandle> m_pRefHandle;
public:
// CREATORS
//
auto_ref_handle() {}
auto_ref_handle(const auto_ref_handle& rhs)
{
m_pRefHandle = rhs.m_pRefHandle;
}
// ACCESSORS
//
HANDLE get() const
{
return m_pRefHandle.get() ? m_pRefHandle->Handle() : NULL;
}
// MANIPULATORS
//
auto_ref_handle& operator=(const auto_ref_handle& rhs)
{
if ( m_pRefHandle.get() != rhs.m_pRefHandle.get() )
m_pRefHandle = rhs.m_pRefHandle;
return *this;
}
VOID take_ownership(IRefHandle * pRefHandle)
{
Assert( !m_pRefHandle.get() );
m_pRefHandle.take_ownership(pRefHandle);
}
// ------------------------------------------------------------------------
//
// auto_ref_handle::FCreate()
//
// This function serves to simplify the very specific -- but very common --
// case of having an auto_ref_handle take ownership of a raw HANDLE.
// Without this function, callers would essentially need to go through all
// of the same steps that we do here. The number of different objects
// required to get to the final auto_ref_handle (a temporary auto_handle,
// a CRefHandle, and an auto_ref_ptr to hold it) and how to assemble them
// correctly would be confusing enough to be bug prone. It is far better
// to keep things simple from the caller's perspective.
//
// Returns:
// TRUE if the auto_ref_handle successfully takes ownership of the
// specified valid handle.
// FALSE if the specified handle is NULL or invalid or if there is
// some other failure in the function. In the latter case
// the function also CLOSES THE RAW HANDLE.
//
// !!! IMPORTANT !!!
// This function is designed to be called with the direct return value
// from any API that creates a raw HANDLE. If this call fails
// (i.e. returns FALSE) then it will close the raw HANDLE passed in!
// The whole point of the auto_ref_handle class is to replace usage of
// the raw HANDLE.
//
BOOL FCreate(HANDLE h)
{
Assert( !m_pRefHandle.get() );
// Don't even bother with NULL or invalid handles.
//
if (NULL == h || INVALID_HANDLE_VALUE == h)
return FALSE;
// Put the raw handle into an auto_handle so that we clean up properly
// (i.e. close the handle) if instantiating the CRefHandle below fails
// by throwing an exception (as it would with a throwing allocator).
//
auto_handle<HANDLE> hTemp(h);
// Preserve the last error from our caller. Our caller could have passed
// in a raw HANDLE from a CreateFile() call and may need to check the last
// error even in the success case -- to determine whether the file already
// existed, for example.
//
DWORD dw = GetLastError();
// Create a new refcounted handle object to control the lifetime
// of the handle that we are taking ownership of.
//
// Note: the reason we preserved the last error above is that the
// allocator clears the last error when we create the CRefHandle
// here if the allocation succeeds.
//
m_pRefHandle.take_ownership(new CRefHandle(hTemp));
if (!m_pRefHandle.get())
{
// Return a failure. Note that we don't restore the last
// error here -- callers should expect the last error to
// be set to a value appropriate for the last call that
// failed which is us.
//
return FALSE;
}
// Restore our caller's last error before returning.
//
SetLastError(dw);
// We now own the handle.
//
return TRUE;
}
VOID clear()
{
m_pRefHandle = NULL;
}
};
#endif // !defined(_REFHANDLE_H_)