// $Id: Registry.cpp 91286 2010-08-05 09:04:31Z johnnyw $

#include "ace/Registry.h"

#if defined (ACE_WIN32) && !defined (ACE_LACKS_WIN32_REGISTRY)

#  include "ace/os_include/os_netdb.h"
#  include "ace/OS_NS_unistd.h"

// Funky macro to deal with strange error passing semantics
// of Win32 Reg*() functions
#define ACE_REGISTRY_CALL_RETURN(X) \
  do { \
    if (X != ERROR_SUCCESS) \
    { \
      errno = X; \
      return -1; \
    } \
    else \
      return 0; \
    } while (0)


ACE_BEGIN_VERSIONED_NAMESPACE_DECL

ACE_TCHAR const ACE_Registry::STRING_SEPARATOR[] = ACE_TEXT ("\\");

bool
ACE_Registry::Name_Component::operator== (const Name_Component &rhs) const
{
  return
    rhs.id_ == this->id_ &&
    rhs.kind_ == this->kind_;
}

bool
ACE_Registry::Name_Component::operator!= (const Name_Component &rhs) const
{
  return !this->operator== (rhs);
}

// Simple binding constructor
ACE_Registry::Binding::Binding ()
  : name_ (),
    type_ (INVALID)
{
}


// Binding constructor
// (Name version)
ACE_Registry::Binding::Binding (const Name &name,
                                Binding_Type type)
  : name_ (ACE_Registry::make_string (name)),
    type_ (type)
{
}


// Binding constructor
// (String version)
ACE_Registry::Binding::Binding (const ACE_TString &name,
                                Binding_Type type)
  : name_ (name),
    type_ (type)
{
}


bool
ACE_Registry::Binding::operator== (const Binding &rhs) const
{
  return
    rhs.name_ == this->name_ &&
    rhs.type_ == this->type_;
}

bool
ACE_Registry::Binding::operator!= (const Binding &rhs) const
{
  return !this->operator== (rhs);
}

// Name accessor
// (Name version)
void
ACE_Registry::Binding::name (Name &name)
{
  name = ACE_Registry::make_name (this->name_);
}


// Name accessors
// (String version)
void
ACE_Registry::Binding::name (ACE_TString &name)
{
  name = this->name_;
}


// Name accessors
// (String version)
ACE_TString
ACE_Registry::Binding::name (void)
{
  return this->name_;
}


// Type accessor
ACE_Registry::Binding_Type
ACE_Registry::Binding::type (void)
{
  return this->type_;
}


// Simple object constructor
ACE_Registry::Object::Object (void *data,
                              u_long size,
                              u_long type)
  : data_ (data),
    size_ (size),
    type_ (type)
{
}

// Object accessors and set methods
void
ACE_Registry::Object::data (void *data)
{
  this->data_ = data;
}


void *
ACE_Registry::Object::data (void) const
{
  return this->data_;
}


void
ACE_Registry::Object::size (u_long size)
{
  this->size_ = size;
}


u_long
ACE_Registry::Object::size (void) const
{
  return this->size_;
}


void
ACE_Registry::Object::type (u_long type)
{
  this->type_ = type;
}


u_long
ACE_Registry::Object::type (void) const
{
  return this->type_;
}


// Simple context constructor
ACE_Registry::Naming_Context::Naming_Context (void)
  : key_ ((HKEY) 0),
    parent_key_ ((HKEY) 0),
    name_ ()
{
}


// Context constructor
ACE_Registry::Naming_Context::Naming_Context (const HKEY &key)
  : key_ (key),
    parent_key_ ((HKEY) 0),
    name_ ()
{
}


ACE_Registry::Naming_Context::Naming_Context (const Naming_Context &rhs)
  : key_ (rhs.key_),
    parent_key_ (rhs.parent_key_),
    name_ (rhs.name_)
{
  // This is incorrect.
  // Rather than copying key, we should call ::DuplicateHandle()
  // But since this is private (and not used), I don't care much
}


const ACE_Registry::Naming_Context &
ACE_Registry::Naming_Context::operator= (const Naming_Context &rhs)
{
        ACE_UNUSED_ARG(rhs);

        // Not implemented
        return *this;
}


// Destructor
ACE_Registry::Naming_Context::~Naming_Context ()
{
  this->close ();
}


// Insert <object> with <name> into <this> context
// (Name version)
int
ACE_Registry::Naming_Context::bind_new (const Name &name,
                                        const Object &object)
{
  return this->bind_new (ACE_Registry::make_string (name), object);
}


// Insert <object> with <name> into <this> context
// (String version)
int
ACE_Registry::Naming_Context::bind_new (const ACE_TString &name,
                                        const Object &object)
{
  // temporary object
  Object temp;
  long result = this->resolve (name, temp);
  if (result == 0)
    // resolve succeeded
    result = -1;
  else
    // resolve failed
    result = this->bind (name, object);
  return result;
}


// Insert or update <object> with <name> into <this> context
// (Name version)
int
ACE_Registry::Naming_Context::bind (const Name &name,
                                    const Object &object)
{
  return this->bind (ACE_Registry::make_string (name), object);
}


// Insert or update <object> with <name> into <this> context
// (String version)
int
ACE_Registry::Naming_Context::bind (const ACE_TString &name,
                                    const Object &object)
{
  long result = ACE_TEXT_RegSetValueEx (this->key_,
                                        name.c_str (),
                                        0,
                                        object.type (),
                                        (const BYTE *) object.data (),
                                        object.size ());
  ACE_REGISTRY_CALL_RETURN (result);
}


// Update <object> with <name> in <this> context
// (Name version)
int
ACE_Registry::Naming_Context::rebind (const Name &name,
                                      const Object &new_object)
{
  return this->rebind (ACE_Registry::make_string (name), new_object);
}


// Update <object> with <name> in <this> context
// (String version)
int
ACE_Registry::Naming_Context::rebind (const ACE_TString &name,
                                      const Object &new_object)
{
  Object old_object;
  // find the old one first
  long result = this->resolve (name, old_object);
  if (result == 0)
    // no need to delete first
    result = this->bind (name, new_object);
  return result;
}


// Find <object> with <name> in <this> context
// (Name version)
int
ACE_Registry::Naming_Context::resolve (const Name &name,
                                       Object &object)
{
  return this->resolve (ACE_Registry::make_string (name), object);
}


// Find <object> with <name> in <this> context
// (String version)
int
ACE_Registry::Naming_Context::resolve (const ACE_TString &name,
                                       Object &object)
{
  // Get object state
  u_long type;
  void *data = object.data ();
  u_long size = object.size ();

  long result = ACE_TEXT_RegQueryValueEx (this->key_,
                                          name.c_str (),
                                          0,
                                          &type,
                                          (BYTE *)data,
                                          &size);
  if (result == ERROR_SUCCESS)
    {
      // Reset object state
      // No need to set object.data()
      object.type (type);
      object.size (size);
    }

  ACE_REGISTRY_CALL_RETURN (result);
}


// Remove object with <name> in <this> context
// (Name version)
int
ACE_Registry::Naming_Context::unbind (const Name &name)
{
  return this->unbind (ACE_Registry::make_string (name));
}


// Remove object with <name> in <this> context
// (String version)
int
ACE_Registry::Naming_Context::unbind (const ACE_TString &name)
{
  long result = ACE_TEXT_RegDeleteValue (this->key_,
                                         name.c_str ());

  ACE_REGISTRY_CALL_RETURN (result);
}


// Create new <naming_context> relative to <this> context
// This method may not mean a lot in this implementation
int
ACE_Registry::Naming_Context::new_context (Naming_Context &naming_context)
{
  // Make sure that we reset the state and close keys
  return naming_context.close ();
}


// Insert <naming_context> with <name> relative to <this> context
// (Name version)
int
ACE_Registry::Naming_Context::bind_new_context (const Name &name,
                                                Naming_Context &naming_context,
                                                u_long persistence,
                                                u_long security_access,
                                                LPSECURITY_ATTRIBUTES security_attributes)
{
  return this->bind_new_context (ACE_Registry::make_string (name),
                                 naming_context,
                                 persistence,
                                 security_access,
                                 security_attributes);
}


// Insert <naming_context> with <name> relative to <this> context
// (String version)
int
ACE_Registry::Naming_Context::bind_new_context (const ACE_TString &name,
                                                Naming_Context &naming_context,
                                                u_long persistence,
                                                u_long security_access,
                                                LPSECURITY_ATTRIBUTES security_attributes)
{
  u_long reason;

  long result = ACE_TEXT_RegCreateKeyEx (this->key_,
                                         name.c_str (),
                                         0,
                                         0,
                                         persistence,
                                         security_access,
                                         security_attributes,
                                         &naming_context.key_,
                                         &reason);
  if (result == ERROR_SUCCESS)
    // If create succeeds
    {
      if (reason == REG_CREATED_NEW_KEY)
        // If new key: success
        {
          // Set the correct parent
          naming_context.parent (this->key_);
          // Set the correct name
          naming_context.name (name);
        }
      else
        // reason == REG_OPENED_EXISTING_KEY
        // Failed to make new key
        {
          // reset result to failure
          result = -1;
          // Close the key first
          ::RegCloseKey (naming_context.key_);
          // Reset key
          naming_context.key_ = (HKEY) 0;
        }
    }

  ACE_REGISTRY_CALL_RETURN (result);
}


// Insert or update <naming_context> with <name> relative to <this> context
// (Name version)
int
ACE_Registry::Naming_Context::bind_context (const Name &name,
                                            /* const */ Naming_Context &naming_context,
                                            u_long persistence,
                                            u_long security_access,
                                            LPSECURITY_ATTRIBUTES security_attributes)
{
  return this->bind_context (ACE_Registry::make_string (name),
                             naming_context,
                             persistence,
                             security_access,
                             security_attributes);
}


// Insert or update <naming_context> with <name> relative to <this> context
// (String version)
int
ACE_Registry::Naming_Context::bind_context (const ACE_TString &name,
                                            /* const */ Naming_Context &naming_context,
                                            u_long persistence,
                                            u_long security_access,
                                            LPSECURITY_ATTRIBUTES security_attributes)
{
  u_long reason;

  long result = ACE_TEXT_RegCreateKeyEx (this->key_,
                                         name.c_str (),
                                         0,
                                         0,
                                         persistence,
                                         security_access,
                                         security_attributes,
                                         &naming_context.key_,
                                         &reason);
  if (result == ERROR_SUCCESS)
    {
      // Set the correct parent
      naming_context.parent (this->key_);
      // Set the correct name
      naming_context.name (name);
    }

  ACE_REGISTRY_CALL_RETURN (result);
}


// Rename <naming_context> to <name>
// (Name version)
int
ACE_Registry::Naming_Context::rebind_context (const Name &name,
                                              /* const */ Naming_Context &new_naming_context)
{
  return this->rebind_context (ACE_Registry::make_string (name),
                               new_naming_context);
}


// Rename <naming_context> to <name>
// (String version)
int
ACE_Registry::Naming_Context::rebind_context (const ACE_TString &name,
                                              /* const */ Naming_Context &new_naming_context)
{
  Naming_Context old_naming_context;
  // find the old one first
  long result = this->resolve_context (name,
                                       old_naming_context);
  if (result == 0)
    {
      // naming_context is found: delete entry
      result = this->unbind_context (name);
      if (result == 0)
        {
          // successful deletion; rebind
          // beware of race conditions here
          // (lets resolve this later)
          result = this->bind_new_context (name, new_naming_context);
        }
    }
  return result;
}


// Remove naming_context with <name> from <this> context
// (Name version)
int
ACE_Registry::Naming_Context::unbind_context (const Name &name)
{
  return this->unbind_context (ACE_Registry::make_string (name));
}


// Remove naming_context with <name> from <this> context
// (String version)
int
ACE_Registry::Naming_Context::unbind_context (const ACE_TString &name)
{
  long result = ACE_TEXT_RegDeleteKey (this->key_,
                                                       name.c_str ());

  ACE_REGISTRY_CALL_RETURN (result);
}


// Find <naming_context> with <name> in <this> context
// (Name version)
int
ACE_Registry::Naming_Context::resolve_context (const Name &name,
                                               Naming_Context &naming_context,
                                               u_long security_access)
{
  return this->resolve_context (ACE_Registry::make_string (name),
                                naming_context,
                                security_access);
}


// Find <naming_context> with <name> in <this> context
// (String version)
int
ACE_Registry::Naming_Context::resolve_context (const ACE_TString &name,
                                               Naming_Context &naming_context,
                                               u_long security_access)
{
  long result = ACE_TEXT_RegOpenKeyEx (this->key_,
                                       name.c_str (),
                                       0,
                                       security_access,
                                       &naming_context.key_);
  if (result == ERROR_SUCCESS)
    {
      // set the correct parent
      naming_context.parent (this->key_);
      // set the correct name
      naming_context.name (name);
    }

  ACE_REGISTRY_CALL_RETURN (result);
}


// Same as unbind_context() with <this> as naming_context
int
ACE_Registry::Naming_Context::destroy (void)
{
  // hopefully the parent_key_ is still open
  long result = ACE_TEXT_RegDeleteKey (this->parent_key_,
                                                       this->name_.c_str ());

  ACE_REGISTRY_CALL_RETURN (result);
}


// Sync content of context to disk
int
ACE_Registry::Naming_Context::flush (void)
{
  long result = ::RegFlushKey (this->key_);
  ACE_REGISTRY_CALL_RETURN (result);
}


// Close the handle of the context
int
ACE_Registry::Naming_Context::close (void)
{
  long result = this->key_ ? ::RegCloseKey (this->key_) : ERROR_SUCCESS;
  ACE_REGISTRY_CALL_RETURN (result);
}


// Convert a <name> to a <string>
ACE_TString
ACE_Registry::make_string (const Name &const_name)
{
  ACE_TString string;
  Name &name = const_cast<Name &> (const_name);

  // Iterator through the components of name
  for (Name::iterator iterator = name.begin ();
       iterator != name.end ();
       iterator++)
    {
      if (iterator != name.begin ())
        // If this is not the first component, we will add separators
        string += STRING_SEPARATOR;
      const Name_Component &component = *iterator;
      // Add to string
      string += component.id_;
    }

  return string;
}


// Convert a <string> to a <name>
ACE_Registry::Name
ACE_Registry::make_name (const ACE_TString &string)
{
  ACE_TString::size_type new_position = 0;
  ACE_TString::size_type last_position = 0;
  Name name;

  // Rememeber: NPOS is -1
  while (new_position != ACE_TString::npos)
    {
      Name_Component component;
      // Find the separator
      new_position = string.find (STRING_SEPARATOR, new_position);
      if (new_position != ACE_TString::npos)
        // If we have not gone past the end
        {
          // Get the substring
          component.id_ = string.substr (last_position,
                                         new_position - last_position);
          // Skip past the seperator
          new_position +=
            ACE_OS::strlen (STRING_SEPARATOR);
        }
      else
        {
          // Get the last substring
          component.id_ = string.substr (last_position);
        }
      // Update positions
      last_position = new_position;
      // Insert component into name
      name.insert (component);
    }

  return name;
}


// Set key
void
ACE_Registry::Naming_Context::key (HKEY key)
{
  this->key_ = key;
}


// Get key
HKEY
ACE_Registry::Naming_Context::key (void)
{
  return this->key_;
}


// Set parent
void
ACE_Registry::Naming_Context::parent (HKEY parent)
{
  this->parent_key_ = parent;
}


// Get parent
HKEY
ACE_Registry::Naming_Context::parent (void)
{
  return this->parent_key_;
}


// Set name
// (Name version)
void
ACE_Registry::Naming_Context::name (const Name &name)
{
  this->name_ = ACE_Registry::make_string (name);
}


// Get name
// (Name version)
void
ACE_Registry::Naming_Context::name (Name &name)
{
  name = ACE_Registry::make_name (this->name_);
}


// Set name
// (String version)
void
ACE_Registry::Naming_Context::name (const ACE_TString &name)
{
  this->name_ = name;
}


// Get name
// (String version)
ACE_TString
ACE_Registry::Naming_Context::name (void)
{
  return this->name_;
}


// Get name
// (String version)
void
ACE_Registry::Naming_Context::name (ACE_TString &name)
{
  name = this->name_;
}

// Empty list
static const ACE_Registry::Binding_List ace_binding_empty_list;

// listing function: iterator creator
// This is useful when there are many objects and contexts
// in <this> context and you only want to look at a few entries
// at a time
int
ACE_Registry::Naming_Context::list (u_long how_many,
                                    Binding_List &list,
                                    Binding_Iterator &iter)
{
  // Make sure that the list is empty
  list = ace_binding_empty_list;

  // Correctly initalize the iterator
  iter.reset ();

  // Make sure that the iterator uses <this> naming context
  iter.naming_context (*this);

  // Start iterations from the objects
  iter.current_enumeration (iter.object_iteration_);

  // Get the next <how_many> values
  return iter.next_n (how_many, list);
}


// listing function: iterator creator
// This gives back a listing of all entries in <this> context.
int
ACE_Registry::Naming_Context::list (Binding_List &list)
{
  // Make sure that the list is empty
  list = ace_binding_empty_list;

  // Create an iterator
  ACE_Registry::Binding_Iterator iterator;

  // Make sure that the iterator uses <this> naming context
  iterator.naming_context (*this);

  // Start iterations from the objects
  iterator.current_enumeration (iterator.object_iteration_);

  long result = 0;
  while (1)
    {
      ACE_Registry::Binding binding;
      result = iterator.next_one (binding);
      if (result == 0)
        list.insert (binding);
      else
        break;
    }
  return 0;
}


// Default constructor
ACE_Registry::Binding_Iterator::Binding_Iterator ()
{
  this->object_iteration_.iterator (this);
  this->context_iteration_.iterator (this);
  this->iteration_complete_.iterator (this);
  this->reset ();
}


void
ACE_Registry::Binding_Iterator::reset ()
{
  this->current_enumeration_ = &this->iteration_complete_;
  this->iteration_complete_.reset ();
  this->object_iteration_.reset ();
  this->context_iteration_.reset ();
}


void
ACE_Registry::Binding_Iterator::Iteration_State::reset ()
{
  this->index_ = 0;
}


void
ACE_Registry::Binding_Iterator::Iteration_State::iterator (Binding_Iterator *iter)
{
  this->parent_ = iter;
}


ACE_Registry::Binding_Iterator::Iteration_State::Iteration_State (void)
  : index_ (0)
{
}

ACE_Registry::Binding_Iterator::Iteration_State::~Iteration_State (void)
{
}

// Next entry
int
ACE_Registry::Binding_Iterator::next_one (Binding &binding)
{
  u_long how_many = 1;
  Binding_List list;

  // Get next n (where n is one)
  long result = this->next_n (how_many, list);

  if (result == 0)
    // Success
    binding = (*list.begin ());

  return result;
}


// Next <how_many> entries
int
ACE_Registry::Binding_Iterator::next_n (u_long how_many,
                                        Binding_List &list)
{
  // Make sure that the list is empty
  list = ace_binding_empty_list;

  return this->current_enumeration_->next_n (how_many, list);
}


// Destroy iterator
int
ACE_Registry::Binding_Iterator::destroy (void)
{
  this->reset ();
  return 0;
}


// Set/Get naming_context
void
ACE_Registry::Binding_Iterator::naming_context (Naming_Context &naming_context)
{
  this->naming_context_ = &naming_context;
}


ACE_Registry::Naming_Context &
ACE_Registry::Binding_Iterator::naming_context (void)
{
  return *this->naming_context_;
}


// Set/Get current enumeration
void
ACE_Registry::Binding_Iterator::current_enumeration (Iteration_State &current_enumeration)
{
  this->current_enumeration_ = &current_enumeration;
}


ACE_Registry::Binding_Iterator::Iteration_State &
ACE_Registry::Binding_Iterator::current_enumeration (void)
{
  return *this->current_enumeration_;
}


int
ACE_Registry::Binding_Iterator::Object_Iteration::next_n (u_long how_many,
                                                          Binding_List &list)
{
  // Make a copy
  u_long requested = how_many;

  // While there are more entries to be added to the list
  while (how_many > 0)
    {
      ACE_TCHAR string [ACE_Registry::Naming_Context::MAX_OBJECT_NAME_SIZE];
      u_long size = sizeof string / sizeof (ACE_TCHAR);
      long result = ACE_TEXT_RegEnumValue (this->parent_->naming_context ().key (),
                                           this->index_,
                                           string,
                                           &size,
                                           0,
                                           0,
                                           0,
                                           0);
      switch (result)
        {
        case ERROR_SUCCESS:
          // Object found
          {
            // Readjust counters
            this->index_++;
            how_many--;

            // Add to list
            // Create binding
            Binding binding (string, OBJECT);
            // Add to binding list
            list.insert (binding);
          }
        // Continue to add to list
        break;

        case ERROR_NO_MORE_ITEMS:
          // Enumeration of objects complete
          // Reset index
          this->index_ = 0;

          // Current enumeration will become CONTEXTS
          this->parent_->current_enumeration (this->parent_->context_iteration_);
          result = this->parent_->current_enumeration ().next_n (how_many,
                                                                 list);
          // If we were able to add objects
          if (requested != how_many)
            return 0;
          else
            return result;

        default:
          // Strange error
          // Reset index
          this->index_ = 0;
          // Current enumeration will become COMPLETE
          this->parent_->current_enumeration (this->parent_->iteration_complete_);
          // strange error
          return -1;
        }
    }
  // If we reach here, all of <how_many> pairs were added to the list
  // Since more entries may be available
  // current enumeration will remain OBJECTS
  return 0;
}


int
ACE_Registry::Binding_Iterator::Context_Iteration::next_n (u_long how_many,
                                                           Binding_List &list)
{
  // Make a copy
  u_long requested = how_many;

  // While there are more entries to be added to the list
  while (how_many > 0)
    {
      ACE_TCHAR string [ACE_Registry::Naming_Context::MAX_CONTEXT_NAME_SIZE];
      u_long size = sizeof string / sizeof (ACE_TCHAR);
      long result = ACE_TEXT_RegEnumKeyEx (this->parent_->naming_context (). key (),
                                           this->index_,
                                           string,
                                           &size,
                                           0,
                                           0,
                                           0,
                                           0);
      switch (result)
        {
        case ERROR_SUCCESS:
          // Object found
          {
            // Readjust counters
            this->index_++;
            how_many--;

            // Add to list
            // Create binding
            Binding binding (string, CONTEXT);
            // Add to binding list
            list.insert (binding);
          }
        // Continue to add to list
        break;

        case ERROR_NO_MORE_ITEMS:
          // Enumeration of objects complete

          /* FALL THROUGH */

        default:
          // Strange error

          // Reset index
          this->index_ = 0;
          // Current enumeration will become CONTEXTS
          this->parent_->current_enumeration (this->parent_->iteration_complete_);

          // If we were able to add contexts
          if (requested != how_many)
            return 0;
          else
            return -1;
        }
    }
  // If we reach here, all of <how_many> pairs were added to the list
  // Since more entries may be available
  // current enumeration will remain CONTEXTS
  return 0;
}


int
ACE_Registry::Binding_Iterator::Iteration_Complete::next_n (u_long how_many,
                                                            Binding_List &list)
{
        ACE_UNUSED_ARG(list);
        ACE_UNUSED_ARG(how_many);

        // No more values
        return -1;
}


// Factory method to connect to predefined registries
// This method works for both remote and local machines
// However, for remote machines CLASSES_ROOT and CURRENT_USER
// types are not allowed
/* static */
int
ACE_Predefined_Naming_Contexts::connect (ACE_Registry::Naming_Context &naming_context,
                                         HKEY predefined,
                                         const ACE_TCHAR *machine_name)
{
#if defined (ACE_HAS_WINCE)
  ACE_UNUSED_ARG(naming_context);
  ACE_UNUSED_ARG(predefined);
  ACE_UNUSED_ARG(machine_name);
  return -1;
#else
  long result = -1;

  if (machine_name != 0 && ACE_OS::strcmp (ACE_TEXT ("localhost"), machine_name) == 0)
    machine_name = 0;

  if (predefined == HKEY_LOCAL_MACHINE || predefined == HKEY_USERS)
    result =
      ACE_TEXT_RegConnectRegistry (const_cast<ACE_TCHAR *> (machine_name),
                                   predefined,
                                   &naming_context.key_);
  if (predefined == HKEY_CURRENT_USER || predefined == HKEY_CLASSES_ROOT)
    {
    // Make sure that for these types, the machine is local
    if (machine_name == 0 ||
        ACE_Predefined_Naming_Contexts::is_local_host (machine_name))
      {
        naming_context.key_ = predefined;
        result = 0;
      }
    else
      result = -1;
    }

  ACE_REGISTRY_CALL_RETURN (result);
#endif  // ACE_HAS_WINCE
}

// Check if <machine_name> is the local host
/* static */
int
ACE_Predefined_Naming_Contexts::is_local_host (const ACE_TCHAR *machine_name)
{
  ACE_TCHAR local_host[MAXHOSTNAMELEN];
  int result = ACE_OS::hostname (local_host, sizeof local_host / sizeof (ACE_TCHAR));
  if (result == 0)
    result = !ACE_OS::strcmp (local_host, machine_name);
  else
    result = 0;
  return result;
}

ACE_END_VERSIONED_NAMESPACE_DECL

#endif /* ACE_WIN32 && !ACE_LACKS_WIN32_REGISTRY */
