From 4c484ff6ea57ce79c5072a830e6536ac41c820c3 Mon Sep 17 00:00:00 2001
From: jvergara <jvergara@localhost>
Date: Thu, 15 Mar 2007 15:52:50 +0000
Subject: [PATCH] Fix for issue 528 (Windows Service Definition for Automatic Startup).

---
 opendj-sdk/opends/src/quicksetup/org/opends/quicksetup/installer/InstallerHelper.java             |   27 
 opendj-sdk/opends/build-tools/src/windows/Makefile                                                |   86 
 opendj-sdk/opends/src/quicksetup/org/opends/quicksetup/installer/Installer.java                   |   15 
 opendj-sdk/opends/resource/bin/stop-ds                                                            |  158 
 opendj-sdk/opends/build-tools/src/windows/common.c                                                |   96 
 opendj-sdk/opends/src/quicksetup/org/opends/quicksetup/installer/webstart/WebStartDownloader.java |    4 
 opendj-sdk/opends/src/quicksetup/org/opends/quicksetup/installer/offline/OfflineInstaller.java    |   13 
 opendj-sdk/opends/src/server/org/opends/server/tools/StopDS.java                                  |  219 +
 opendj-sdk/opends/resource/bin/start-ds                                                           |   55 
 opendj-sdk/opends/src/quicksetup/org/opends/quicksetup/uninstaller/Uninstaller.java               |  256 ++
 opendj-sdk/opends/src/server/org/opends/server/tools/ConfigureWindowsService.java                 |  612 ++++++
 opendj-sdk/opends/src/quicksetup/org/opends/quicksetup/uninstaller/UninstallProgressStep.java     |    4 
 opendj-sdk/opends/src/server/org/opends/server/messages/CoreMessages.java                         |   31 
 opendj-sdk/opends/build-tools/src/windows/winlauncher.h                                           |   53 
 opendj-sdk/opends/build-tools/src/windows/service.h                                               |  109 +
 opendj-sdk/opends/lib/opends_service.exe                                                          |    0 
 opendj-sdk/opends/build-tools/src/windows/common.h                                                |   35 
 opendj-sdk/opends/lib/winlauncher.exe                                                             |    0 
 opendj-sdk/opends/resource/bin/stop-ds.bat                                                        |   92 
 opendj-sdk/opends/src/quicksetup/org/opends/quicksetup/installer/InstallException.java            |    4 
 opendj-sdk/opends/src/quicksetup/org/opends/quicksetup/uninstaller/UninstallException.java        |    4 
 opendj-sdk/opends/build-tools/src/windows/winlauncher.c                                           |  661 ++---
 opendj-sdk/opends/src/quicksetup/org/opends/quicksetup/resources/Resources.properties             |   49 
 opendj-sdk/opends/src/server/org/opends/server/core/DirectoryServer.java                          |  223 +
 opendj-sdk/opends/build-tools/src/windows/EventLogMsg.mc                                          |  103 +
 opendj-sdk/opends/build-tools/src/windows/service.c                                               | 2167 +++++++++++++++++++++
 opendj-sdk/opends/src/quicksetup/org/opends/quicksetup/installer/InstallLauncher.java             |   11 
 opendj-sdk/opends/build.xml                                                                       |    8 
 opendj-sdk/opends/resource/bin/start-ds.bat                                                       |   32 
 opendj-sdk/opends/build-tools/src/windows/README                                                  |   86 
 opendj-sdk/opends/resource/bin/windowsservice.bat                                                 |   33 
 opendj-sdk/opends/src/server/org/opends/server/tools/StartWindowsService.java                     |  142 +
 opendj-sdk/opends/src/server/org/opends/server/tools/WaitForFileDelete.java                       |   59 
 opendj-sdk/opends/src/quicksetup/org/opends/quicksetup/installer/webstart/WebStartInstaller.java  |   13 
 opendj-sdk/opends/src/quicksetup/org/opends/quicksetup/installer/InstallProgressStep.java         |    4 
 opendj-sdk/opends/src/server/org/opends/server/tools/StopWindowsService.java                      |  147 +
 opendj-sdk/opends/src/server/org/opends/server/messages/ToolMessages.java                         |  338 +++
 opendj-sdk/opends/src/server/org/opends/server/tools/InstallDS.java                               |   45 
 38 files changed, 5,328 insertions(+), 666 deletions(-)

diff --git a/opendj-sdk/opends/build-tools/src/windows/EventLogMsg.mc b/opendj-sdk/opends/build-tools/src/windows/EventLogMsg.mc
new file mode 100644
index 0000000..3f9114e
--- /dev/null
+++ b/opendj-sdk/opends/build-tools/src/windows/EventLogMsg.mc
@@ -0,0 +1,103 @@
+;/*
+; * CDDL HEADER START
+; *
+; * The contents of this file are subject to the terms of the
+; * Common Development and Distribution License, Version 1.0 only
+; * (the "License").  You may not use this file except in compliance
+; * with the License.
+; *
+; * You can obtain a copy of the license at
+; * trunk/opends/resource/legal-notices/OpenDS.LICENSE
+; * or https://OpenDS.dev.java.net/OpenDS.LICENSE.
+; * See the License for the specific language governing permissions
+; * and limitations under the License.
+; *
+; * When distributing Covered Code, include this CDDL HEADER in each
+; * file and include the License file at
+; * trunk/opends/resource/legal-notices/OpenDS.LICENSE.  If applicable,
+; * add the following below this CDDL HEADER, with the fields enclosed
+; * by brackets "[]" replaced with your own identifying * information:
+; *      Portions Copyright [yyyy] [name of copyright owner]
+; *
+; * CDDL HEADER END
+; *
+; *
+; *      Portions Copyright 2007 Sun Microsystems, Inc.
+; */
+;/*
+; * ==========================================================================
+; *
+; *  Definition of the messages sent to the Windows Event Log.
+; *
+; * ==========================================================================
+; */
+
+;/*
+; * ==========================================================================
+; *  Header Section
+; * ==========================================================================
+; */
+MessageIdTypedef = DWORD
+
+LanguageNames = (
+	English	= 0x409 : MSG00409
+	)
+
+SeverityNames = (
+   Success       = 0x0 : WIN_STATUS_SEVERITY_SUCCESS
+   Informational = 0x1 : WIN_STATUS_SEVERITY_INFORMATIONAL
+   Warning       = 0x2 : WIN_STATUS_SEVERITY_WARNING
+   Error         = 0x3 : WIN_STATUS_SEVERITY_ERROR
+   )
+
+FacilityNames = (
+   OPENDS	= 0xFA0 : WIN_FACILITY_NAME_OPENDS
+   )
+
+
+;/*
+; * ==========================================================================
+; *  Message Definition
+; * ==========================================================================
+; */
+
+MessageId    = 0x1
+Severity     = Success
+Facility     = OPENDS
+SymbolicName = WIN_EVENT_ID_SERVER_STARTED
+Language     = English
+OpenDS has started.
+OpenDS is in %1.
+.
+MessageId    = 0x2
+Severity     = Success
+Facility     = OPENDS
+SymbolicName = WIN_EVENT_ID_SERVER_STOP
+Language     = English
+OpenDS has shutdown.
+OpenDS is in %1.
+.
+MessageId    = 0x3
+Severity     = Error
+Facility     = OPENDS
+SymbolicName = WIN_EVENT_ID_SERVER_START_FAILED
+Language     = English
+OpenDS failed in startup.
+OpenDS is in %1.
+.
+MessageId    = 0x4
+Severity     = Error
+Facility     = OPENDS
+SymbolicName = WIN_EVENT_ID_SERVER_STOP_FAILED
+Language     = English
+OpenDS failed in stop.
+OpenDS is in %1.
+.
+MessageId    = 0x5
+Severity     = Informational
+Facility     = OPENDS
+SymbolicName = WIN_EVENT_ID_DEBUG
+Language     = English
+%1
+.
+
diff --git a/opendj-sdk/opends/build-tools/src/windows/Makefile b/opendj-sdk/opends/build-tools/src/windows/Makefile
new file mode 100644
index 0000000..93fd9fa
--- /dev/null
+++ b/opendj-sdk/opends/build-tools/src/windows/Makefile
@@ -0,0 +1,86 @@
+#
+# CDDL HEADER START
+#
+# The contents of this file are subject to the terms of the
+# Common Development and Distribution License, Version 1.0 only
+# (the "License").  You may not use this file except in compliance
+# with the License.
+#
+# You can obtain a copy of the license at
+# trunk/opends/resource/legal-notices/OpenDS.LICENSE
+# or https://OpenDS.dev.java.net/OpenDS.LICENSE.
+# See the License for the specific language governing permissions
+# and limitations under the License.
+#
+# When distributing Covered Code, include this CDDL HEADER in each
+# file and include the License file at
+# trunk/opends/resource/legal-notices/OpenDS.LICENSE.  If applicable,
+# add the following below this CDDL HEADER, with the fields enclosed
+# by brackets "[]" replaced with your own identifying information:
+#      Portions Copyright [yyyy] [name of copyright owner]
+#
+# CDDL HEADER END
+#
+#
+#      Portions Copyright 2007 Sun Microsystems, Inc.
+
+#
+# This is the Makefile than can be used to generate the executables
+# winlauncher.exe and opends_service.exe that are used by OpenDS in
+# windows.
+#
+# The compilation of winlauncher.exe is straightforward but in the case of
+# opends_service.exe uses a Message File called EventLogMsg.mc which
+# makes the compilation a little bit more complex.
+# During compilation the first step is to generate EventLogMsg.h and
+# EventLogMsg.res using the rc.exe and mc.exe utilities.
+#
+# EventLogMsg.h contains some references to the message IDs that are sent to
+# the Windows Event Log and is required in order service.c to be compiled.
+# Once the EvenLogMsg.h file is generated we can compile the service.c and
+# common.c and finally we link the service.obj, common.obj and
+# EventLogMsg.res files and we generate the opends_service.exe executable.
+#
+
+CC=cl
+SERVICE_PROGNAME=opends_service.exe
+WINLAUNCHER_PROGNAME=winlauncher.exe
+LINKER=link -nologo
+LIBS=advapi32.lib
+
+CFLAGS= -D_WINDOWS  -nologo -MD  -W3 -O2 -G6
+RC=rc
+MC=mc
+
+SRCS = common.c winlauncher.c service.c 
+
+SERVICE_OBJS = common.obj service.obj
+WINLAUNCHER_OBJS = common.obj winlauncher.obj
+
+EVENTLOG_H = EventLogMsg.h
+
+MC_FILE = EventLogMsg.mc
+
+RC_FILE = EventLogMsg.rc
+
+RES_FILE = EventLogMsg.res
+
+.c.obj:
+  $(CC) $(CFLAGS) -c $< -Fo$@
+  
+$(RES_FILE):
+  $(MC) $(MC_FILE)
+  $(RC) /fo $(RES_FILE) $(RC_FILE)
+
+
+all: $(SERVICE_PROGNAME) $(WINLAUNCHER_PROGNAME)
+
+$(SERVICE_PROGNAME) : $(RES_FILE) $(SERVICE_OBJS)
+  $(LINKER) /OUT:$(SERVICE_PROGNAME) $(RES_FILE) $(SERVICE_OBJS) $(LIBS)
+
+$(WINLAUNCHER_PROGNAME) : $(WINLAUNCHER_OBJS)
+  $(LINKER) $(WINLAUNCHER_OBJS) /OUT:$(WINLAUNCHER_PROGNAME)
+
+clean:
+  del $(SERVICE_OBJS) $(EVENTLOG_H) $(WINLAUNCHER_OBJS) $(RC_FILE) $(RES_FILE) $(SERVICE_PROGNAME) $(WINLAUNCHER_PROGNAME) core
+
diff --git a/opendj-sdk/opends/build-tools/src/windows/README b/opendj-sdk/opends/build-tools/src/windows/README
index 65c76c3..6a19ec2 100644
--- a/opendj-sdk/opends/build-tools/src/windows/README
+++ b/opendj-sdk/opends/build-tools/src/windows/README
@@ -27,37 +27,55 @@
  
  WHAT is winlauncher.exe
  ========================
- winlauncher.exe is a small windows executable that is intended to be used by
- the command line files to perform certain operations.  It is not intended to
- be a final user interface and that is one of the reasons why is placed under
- the lib subdirectory.
+winlauncher.exe is a small windows executable that is intended to be used by
+the command line files to perform certain operations.  It is not intended to
+be a final user interface and that is one of the reasons why is placed under
+the lib subdirectory.
 
- See the comments in winlauncher.c file for more information.
- 
- 
- INSTRUCTIONS TO COMPILE winlauncher
+See the comments in winlauncher.c file and common.c for more information.
+
+ WHAT is opends_service.exe
  ========================
- 
- Using Visual C++ and the command line  you must set your environment
- variables to point to your Visual Studio install.  You can set the environment
- variables by changing to the \bin subdirectory of your Visual C++ installation
- and running the VCVARS32.bat batch file.
- 
- This will basically update your PATH, INCLUDE and LIB environment variables
- to point to the correct paths of your Visual Studio install.
- 
-Go to the directory where the source files winlauncher.c and winlauncher.h are
-and launch the following command:
+opends_service.exe is a small windows executable that is intended to be used by
+the command line files to be able to run OpenDS as a windows service (or not
+to configure it as windows service).  It is not intended to be a final user
+interface and that is one of the reasons why is placed under the lib
+subdirectory.
 
-> cl winlauncher.c
+See the comments in service.c file and common.c for more information.
+
+
+ INSTRUCTIONS TO COMPILE winlauncher.exe
+ ========================
+
+Using Visual C++ and the command line  you must set your environment
+variables to point to your Visual Studio install.  You can set the environment
+variables by changing to the \bin subdirectory of your Visual C++ installation
+and running the VCVARS32.bat batch file.
+
+This will basically update your PATH, INCLUDE and LIB environment variables
+to point to the correct paths of your Visual Studio install.
+
+Go to the directory where the source files winlauncher.c, winlauncher.h,
+common.c and common.h are and launch the following command:
+
+> cl winlauncher.c common.c
 
 This will generate the binary winlauncher.exe.
 
+NOTE: An alternative to this mode is to compile winlauncher.exe using the
+Makefile by running:
+
+> nmake all
+
+(See INSTRUCTIONS TO COMPILE opends_service.exe for more information).
+
 ************************
 
 Using Visual C++ graphical interface you just must to Create a Project and add
-winlauncher.c and winlauncher.h to the project.   You can build winlauncher.c
-and then winlauncher.exe with the commands in the menu 'Build'.
+winlauncher.c, winlauncher.h, common.c and common.h to the project.
+You can build winlauncher.c and then winlauncher.exe with the commands in the
+menu 'Build'.
 
 ************************
 
@@ -67,6 +85,28 @@
 Go to the directory where the source files winlauncher.c and winlauncher.h are
 and launch the following command:
 
-> gcc winlauncher.c -o winlauncher.exe
+> gcc common.c winlauncher.c -o winlauncher.exe
 
 This will generate the binary winlauncher.exe.
+
+
+ INSTRUCTIONS TO COMPILE opends_service.exe
+ ========================
+service.c (the main code file for opends_service.exe) uses windows resources and
+so 
+
+The fastest way of generating opends_service.exe is to do it using the command
+line.
+Using Visual C++ and the command line  you must set your environment
+variables to point to your Visual Studio install.  You can set the environment
+variables by changing to the \bin subdirectory of your Visual C++ installation
+and running the VCVARS32.bat batch file.
+
+Then go to the directory where the source files are and run the following
+command:
+
+> nmake all
+
+This command will generate both opends_service.exe and winlauncher.exe.
+
+See the comments in the file Makefile for more information.
diff --git a/opendj-sdk/opends/build-tools/src/windows/common.c b/opendj-sdk/opends/build-tools/src/windows/common.c
new file mode 100644
index 0000000..0868745
--- /dev/null
+++ b/opendj-sdk/opends/build-tools/src/windows/common.c
@@ -0,0 +1,96 @@
+/*
+* CDDL HEADER START
+*
+* The contents of this file are subject to the terms of the
+* Common Development and Distribution License, Version 1.0 only
+* (the "License").  You may not use this file except in compliance
+* with the License.
+*
+* You can obtain a copy of the license at
+* trunk/opends/resource/legal-notices/OpenDS.LICENSE
+* or https://OpenDS.dev.java.net/OpenDS.LICENSE.
+* See the License for the specific language governing permissions
+* and limitations under the License.
+*
+* When distributing Covered Code, include this CDDL HEADER in each
+* file and include the License file at
+* trunk/opends/resource/legal-notices/OpenDS.LICENSE.  If applicable,
+* add the following below this CDDL HEADER, with the fields enclosed
+* by brackets "[]" replaced with your own identifying * information:
+*      Portions Copyright [yyyy] [name of copyright owner]
+*
+* CDDL HEADER END
+*
+*
+*      Portions Copyright 2007 Sun Microsystems, Inc.
+*/
+
+#include "common.h"
+
+// ----------------------------------------------------
+// Function used to create a process with the given command.
+// The information about the process is stored in procInfo.
+// The function returns TRUE if the process could be created
+// and FALSE otherwise.
+// ----------------------------------------------------
+BOOL createChildProcess(char* command, BOOL background,
+PROCESS_INFORMATION* procInfo)
+{
+  BOOL createOk;
+  STARTUPINFO startInfo; // info to pass to the new process
+  DWORD processFlag; // background process flag
+
+  // reset process info first
+  ZeroMemory(procInfo, sizeof(PROCESS_INFORMATION));
+
+  // initialize handles to pass to the child process
+  ZeroMemory(&startInfo, sizeof(STARTUPINFO));
+  startInfo.cb = sizeof(STARTUPINFO);
+  startInfo.dwFlags |= STARTF_USESTDHANDLES;  // use handles above
+
+  // Create the child process
+  processFlag = background == TRUE ? DETACHED_PROCESS : 0;
+  createOk = CreateProcess(
+  NULL,          // application name
+  command,       // command line
+  NULL,          // process security attributes
+  NULL,          // primary thread security attributes
+  TRUE,          // handles are inherited
+  processFlag,   // creation flags
+  NULL,          // use parent's environment
+  NULL,          // use parent's current directory
+  &startInfo,    // STARTUPINFO pointer
+  procInfo       // receives PROCESS_INFORMATION
+  );
+
+  return createOk;
+} // createChildProcess
+
+// ----------------------------------------------------
+// Function used to launch a process for the given command
+// If the process could be created it returns the pid of
+// the created process and -1 otherwise.
+// ----------------------------------------------------
+int spawn(const char* command, BOOL background)
+{
+  DWORD childPid; // child's pid
+  PROCESS_INFORMATION procInfo; // info on the new process
+  BOOL createOk;
+
+  createOk = createChildProcess((char*)command, background, &procInfo);
+
+  if(createOk)
+  {
+    childPid = procInfo.dwProcessId;
+  }
+
+  if (childPid != -1)
+  {
+    return childPid;
+  }
+  else
+  {
+    return -1;
+  }
+} // spawn
+
diff --git a/opendj-sdk/opends/build-tools/src/windows/common.h b/opendj-sdk/opends/build-tools/src/windows/common.h
new file mode 100644
index 0000000..969909d
--- /dev/null
+++ b/opendj-sdk/opends/build-tools/src/windows/common.h
@@ -0,0 +1,35 @@
+/*
+* CDDL HEADER START
+*
+* The contents of this file are subject to the terms of the
+* Common Development and Distribution License, Version 1.0 only
+* (the "License").  You may not use this file except in compliance
+* with the License.
+*
+* You can obtain a copy of the license at
+* trunk/opends/resource/legal-notices/OpenDS.LICENSE
+* or https://OpenDS.dev.java.net/OpenDS.LICENSE.
+* See the License for the specific language governing permissions
+* and limitations under the License.
+*
+* When distributing Covered Code, include this CDDL HEADER in each
+* file and include the License file at
+* trunk/opends/resource/legal-notices/OpenDS.LICENSE.  If applicable,
+* add the following below this CDDL HEADER, with the fields enclosed
+* by brackets "[]" replaced with your own identifying * information:
+*      Portions Copyright [yyyy] [name of copyright owner]
+*
+* CDDL HEADER END
+*
+*
+*      Portions Copyright 2007 Sun Microsystems, Inc.
+*/
+
+// Just some functions and constants to be used by winlauncher.c
+// and service.c
+
+#include <Windows.h>
+
+int spawn(const char* command, BOOL background);
+BOOL createChildProcess(char* command, BOOL background,
+PROCESS_INFORMATION* procInfo);
diff --git a/opendj-sdk/opends/build-tools/src/windows/service.c b/opendj-sdk/opends/build-tools/src/windows/service.c
new file mode 100644
index 0000000..2442c82
--- /dev/null
+++ b/opendj-sdk/opends/build-tools/src/windows/service.c
@@ -0,0 +1,2167 @@
+/*
+* CDDL HEADER START
+*
+* The contents of this file are subject to the terms of the
+* Common Development and Distribution License, Version 1.0 only
+* (the "License").  You may not use this file except in compliance
+* with the License.
+*
+* You can obtain a copy of the license at
+* trunk/opends/resource/legal-notices/OpenDS.LICENSE
+* or https://OpenDS.dev.java.net/OpenDS.LICENSE.
+* See the License for the specific language governing permissions
+* and limitations under the License.
+*
+* When distributing Covered Code, include this CDDL HEADER in each
+* file and include the License file at
+* trunk/opends/resource/legal-notices/OpenDS.LICENSE.  If applicable,
+* add the following below this CDDL HEADER, with the fields enclosed
+* by brackets "[]" replaced with your own identifying * information:
+*      Portions Copyright [yyyy] [name of copyright owner]
+*
+* CDDL HEADER END
+*
+*
+*      Portions Copyright 2007 Sun Microsystems, Inc.
+*/
+
+#include "service.h"
+
+int _serviceCurStatus;
+SERVICE_STATUS_HANDLE *_serviceStatusHandle;
+HANDLE _terminationEvent = NULL;
+char *_instanceDir = NULL;
+HANDLE _eventLog = NULL;
+BOOL DEBUG = FALSE;
+
+
+// ----------------------------------------------------
+// Register a service handler to the service control dispatcher.
+// A service handler will manage the control function such as:
+// stop, pause, continue, shutdown, interrogate. The control functions
+// are sent by the service control dispatcher upon user request
+// (ie. NET STOP)
+//
+// serviceName     the internal name of the service (unique in the system)
+// serviceHandler  the handler of the service
+// serviceStatusHandle  the service status handle returned by the SCM
+// The functions returns SERVICE_RETURN_OK if we could start the service
+// and SERVICE_RETURN_ERROR otherwise.
+// ----------------------------------------------------
+
+ServiceReturnCode registerServiceHandler (
+char*                   serviceName,
+LPHANDLER_FUNCTION      serviceHandler,
+SERVICE_STATUS_HANDLE*  serviceStatusHandle
+)
+{
+  ServiceReturnCode returnValue;
+
+  // register the service to the service control dispatcher (SCM)
+  *serviceStatusHandle = RegisterServiceCtrlHandler (
+  serviceName, (LPHANDLER_FUNCTION) serviceHandler
+  );
+  if (serviceStatusHandle == NULL)
+  {
+    returnValue = SERVICE_RETURN_ERROR;
+  }
+  else
+  {
+    returnValue = SERVICE_RETURN_OK;
+  }
+  return returnValue;
+}  // registerServiceHandler
+
+// ---------------------------------------------------
+// Debug utility.  If the _eventLog is not NULL and the DEBUG variable is
+// TRUE send the message to the event log.
+// If the _eventLog is NULL and the DEBUG variable is TRUE send the message
+// to the standard output.
+// ---------------------------------------------------
+void debug(char* msg)
+{
+  if (DEBUG == TRUE)
+  {
+    if (_eventLog != NULL)
+    {
+      const char* args[1];
+      args[0] = msg;
+
+      // report the event
+      ReportEvent(
+      _eventLog,          // event log handle
+      EVENTLOG_INFORMATION_TYPE,  // info, warning, error
+      WIN_FACILITY_NAME_OPENDS,   // unique category for OPENDS
+      WIN_EVENT_ID_DEBUG,
+      NULL,           // no user security identifier
+      1,              // number of  args
+      0,              // raw data size
+      (const char**)args,     // args
+      NULL            // no war data
+      );
+    }
+    else
+    {
+      fprintf(stdout, "%s\n", msg);
+    }
+  }
+}
+
+// ---------------------------------------------------
+// Reports a log event of a given type, id and arguments
+// serviceBinPath the binary associated with the service.
+// The function returns TRUE if the event could be logged and FALSE otherwise.
+// ---------------------------------------------------
+BOOL reportLogEvent(WORD eventType, DWORD eventId, WORD argCount,
+const char** args)
+{
+  BOOL reportOk;
+
+  if (argCount > 0)
+  {
+    // report the event
+    reportOk = ReportEvent(
+    _eventLog,              // event log handle
+    eventType,              // info, warning, error
+    WIN_FACILITY_NAME_OPENDS,     // unique category for OPENDS
+    eventId,
+    NULL,               // no user security identifier
+    argCount,             // number of args
+    0,                  // raw data size
+    args,               // args
+    NULL                // no raw data
+    );
+  }
+  else
+  {
+    // report the event
+    reportOk = ReportEvent(
+    _eventLog,              // event log handle
+    eventType,              // info, warning, error
+    WIN_FACILITY_NAME_OPENDS,     // unique category for OPENDS
+    eventId,
+    NULL,               // no user security identifier
+    argCount,             // number of args
+    0,                  // raw data size
+    NULL,               // args
+    NULL                // no raw data
+    );
+  }
+
+
+  return reportOk;
+}
+
+// ---------------------------------------------------------------
+// Get a handle to the Service Control Manager (SCM).
+// accessRights  the desired access rights; generic access are:
+//  - GENERIC_READ     use to get the list of services
+//  - GENERIC_WRITE    use to create & remove a service
+//  - GENERIC_EXECUTE
+//  - GENERIC_ALL
+// scm  the handler to the SCM
+// The function returns SERVICE_RETURN_OK if we could get the SCM
+// and SERVICE_RETURN_ERROR otherwise.
+// ---------------------------------------------------------------
+
+ServiceReturnCode openScm(DWORD accessRights, SC_HANDLE *scm)
+{
+  ServiceReturnCode returnValue;
+
+  // open Service Control Manager
+  *scm = (SC_HANDLE)OpenSCManager (
+  NULL,           // local machine
+  NULL,           // ServicesActive database
+  accessRights    // desired rights
+  );
+  if (scm == NULL)
+  {
+    debug("scm is NULL.");
+    returnValue = SERVICE_RETURN_ERROR;
+  }
+  else
+  {
+    returnValue = SERVICE_RETURN_OK;
+  }
+  return returnValue;
+} // openScm
+
+// ---------------------------------------------------
+// Creates the registry key to send events based on the name of the service.
+// serviceName the serviceName.
+// serviceBinPath the binary associated with the service.
+// The function returns TRUE if the key could be registered (or was already
+// registered) and FALSE otherwise.
+// ---------------------------------------------------
+BOOLEAN createRegistryKey(char* serviceName)
+{
+  // true if the server is already registered
+  BOOL alreadyRegistered = FALSE;
+
+  // false as soon as an error occurs
+  BOOL success = TRUE;
+
+  // handle to the created/opened key
+  HKEY hkey = NULL;
+
+  // Create the event source subkey (or open it if it already exists)
+  char subkey [MAX_REGISTRY_KEY];
+
+  long result;
+
+  DWORD nbCategories = 1;
+
+  // get the full path to the current executable file: is safe to do it
+  // here because we already required it to figure out to get the service
+  // name based on the command to run associated with it.
+  char execName [MAX_PATH];
+  GetModuleFileName (
+  NULL,
+  execName,
+  MAX_PATH
+  );
+
+  // Check whether the Registry Key is already created,
+  // If so don't create a new one.
+  sprintf (subkey, EVENT_LOG_KEY, serviceName);
+  result = RegOpenKeyEx(
+  HKEY_LOCAL_MACHINE,
+  subkey,
+  0,
+  KEY_QUERY_VALUE,      // to query the values of a registry key.
+  &hkey           // OUT
+  );
+  if (result == ERROR_SUCCESS)
+  {
+    alreadyRegistered = TRUE;
+    success = FALSE;
+  }
+
+  if (success)
+  {
+    DWORD disposition;
+    result = RegCreateKeyEx(
+    HKEY_LOCAL_MACHINE,         //
+    subkey,                     //
+    0,                          // reserved
+    NULL,                       // key object class
+    REG_OPTION_NON_VOLATILE,    // option
+    KEY_WRITE,                  // desired access
+    NULL,                       // hkey cannot be inherited
+    &hkey,                      // OUT
+    &disposition                // OUT new key / existing key
+    );
+    if (result != ERROR_SUCCESS)
+    {
+      debug("RegCreateKeyEx failed.");
+      success = FALSE;
+    }
+  }
+
+  if (success)
+  {
+    result = RegSetValueEx(
+    hkey,                           // subkey handle
+    "EventMessageFile",             // value name
+    0,                              // must be zero
+    REG_EXPAND_SZ,          // value type
+    (LPBYTE)execName,       // pointer to value data
+    (DWORD) (lstrlen(execName) + 1)
+    * sizeof(TCHAR)         // length of value data
+    );
+    if (result != ERROR_SUCCESS)
+    {
+      success = FALSE;
+    }
+  }
+
+  // Set the supported event types
+  if (success)
+  {
+    DWORD supportedTypes =
+    EVENTLOG_SUCCESS
+    | EVENTLOG_ERROR_TYPE
+    | EVENTLOG_WARNING_TYPE
+    | EVENTLOG_INFORMATION_TYPE;
+
+    result = RegSetValueEx(
+    hkey,                          // subkey handle
+    "TypesSupported",              // value name
+    0,                             // must be zero
+    REG_DWORD,                     // value type
+    (LPBYTE) &supportedTypes,      // pointer to value data
+    sizeof(DWORD)                  // length of value data
+    );
+    if (result != ERROR_SUCCESS)
+    {
+      success = FALSE;
+    }
+  }
+
+  // Set the category message file
+  if (success)
+  {
+    result = RegSetValueEx(
+    hkey,                           // subkey handle
+    "CategoryMessageFile",          // value name
+    0,                              // must be zero
+    REG_EXPAND_SZ,                  // value type
+    (LPBYTE)execName,       // pointer to value data
+    (DWORD) (lstrlen(execName) + 1)
+    *sizeof(TCHAR)          // length of value data
+    );
+    if (result != ERROR_SUCCESS)
+    {
+      success = FALSE;
+    }
+  }
+
+  // Set the number of categories: 1 (OPENDS)
+  if (success)
+  {
+    long result = RegSetValueEx(
+    hkey,                    // subkey handle
+    "CategoryCount",         // value name
+    0,                       // must be zero
+    REG_DWORD,               // value type
+    (LPBYTE) &nbCategories,  // pointer to value data
+    sizeof(DWORD)            // length of value data
+    );
+    if (result != ERROR_SUCCESS)
+    {
+      success = FALSE;
+    }
+  }
+
+  // close the key before leaving
+  if (hkey != NULL)
+  {
+    RegCloseKey (hkey);
+  }
+
+  if (alreadyRegistered || success)
+  {
+    return TRUE;
+  }
+  else
+  {
+    debug("Could not create a registry key.");
+    return FALSE;
+  }
+}  // createRegistryKey
+
+
+// ---------------------------------------------------
+// Removes the registry key to send events based on the name of the service.
+// serviceName the serviceName.
+// The function returns TRUE if the key could be unregistered (or it was not
+// registered) and FALSE otherwise.
+// ---------------------------------------------------
+BOOLEAN removeRegistryKey(char* serviceName)
+{
+  BOOL returnValue;
+
+  // Create the event source subkey (or open it if it already exists)
+  char subkey [MAX_REGISTRY_KEY];
+
+  long result;
+
+  HKEY hkey = NULL;
+
+  // Check whether the Registry Key is already created,
+  // If so don't create a new one.
+  sprintf (subkey, EVENT_LOG_KEY, serviceName);
+  result = RegOpenKeyEx(
+  HKEY_LOCAL_MACHINE,
+  subkey,
+  0,
+  KEY_QUERY_VALUE,      // to query the values of a registry key.
+  &hkey           // OUT
+  );
+  if (result != ERROR_SUCCESS)
+  {
+    // Assume that the registry key does not exist.
+    returnValue = TRUE;
+  }
+  else
+  {
+    result = RegDeleteKey (HKEY_LOCAL_MACHINE, subkey);
+    if (result == ERROR_SUCCESS)
+    {
+      returnValue = TRUE;
+    }
+  }
+
+  return returnValue;
+}  // removeRegistryKey
+
+// ---------------------------------------------------
+// Register the source of event and returns the handle
+// for the event log.
+// serviceName the serviceName.
+// ---------------------------------------------------
+HANDLE registerEventLog(char *serviceName)
+{
+  HANDLE eventLog = NULL;
+
+  // subkey under Eventlog registry key
+  char subkey [MAX_SERVICE_NAME];
+  sprintf (subkey, serviceName);
+
+  eventLog = RegisterEventSource(
+  NULL,      // local host
+  subkey     // subkey under Eventlog registry key
+  );
+
+  return eventLog;
+
+}  // registerEventLog
+
+// ---------------------------------------------------
+// Deregister the source of event.
+// ---------------------------------------------------
+void deregisterEventLog()
+{
+  if (_eventLog != NULL)
+  {
+    DeregisterEventSource(_eventLog);
+  }
+}
+
+// ----------------------------------------------------
+// Check if the server is running or not.
+// The functions returns SERVICE_RETURN_OK if we could determine if
+// the server is running or not and false otherwise.
+// ----------------------------------------------------
+ServiceReturnCode isServerRunning(BOOL *running)
+{
+  ServiceReturnCode returnValue;
+  char* relativePath = "\\locks\\server.lock";
+  char lockFile[MAX_PATH];
+  if (strlen(relativePath)+strlen(_instanceDir)+1 < MAX_PATH)
+  {
+    int fd;
+
+    sprintf(lockFile, "%s%s", _instanceDir, relativePath);
+
+    fd = _open(lockFile, _O_RDWR);
+
+    if (fd != -1)
+    {
+      returnValue = SERVICE_RETURN_OK;
+      // Test if there is a lock
+      /* Lock some bytes and read them. Then unlock. */
+      if(_locking(fd, LK_NBLCK, 1) != -1)
+      {
+        *running = FALSE;
+      }
+      else
+      {
+        if (errno == EACCES)
+        {
+          *running = TRUE;
+        }
+        else
+        {
+          *running = FALSE;
+          returnValue = SERVICE_RETURN_ERROR;
+          debug("Unexpected error locking");
+        }
+      }
+      _close(fd);
+    }
+    else
+    {
+      *running = FALSE;
+      returnValue = SERVICE_RETURN_ERROR;
+    }
+  }
+  else
+  {
+    *running = FALSE;
+    returnValue = SERVICE_RETURN_ERROR;
+  }
+  return returnValue;
+}  // isServerRunning
+
+// ----------------------------------------------------
+// Start the application using start-ds.bat
+// The functions returns SERVICE_RETURN_OK if we could start the server
+// and SERVICE_RETURN_ERROR otherwise.
+// ----------------------------------------------------
+ServiceReturnCode doStartApplication()
+{
+  ServiceReturnCode returnValue;
+  // init out params
+  char* relativePath = "\\bin\\start-ds.bat";
+  char command[COMMAND_SIZE];
+  if (strlen(relativePath)+strlen(_instanceDir)+1 < COMMAND_SIZE)
+  {
+    sprintf(command, "\"%s%s\" --windowsNetStart", _instanceDir, relativePath);
+
+    // launch the command
+    if (spawn(command, FALSE) != 0)
+    {
+      // Try to see if server is really running
+      int nTries = 10;
+      BOOL running = FALSE;
+      // Wait to be able to launch the java process in order it to free the lock
+      // on the file.
+      Sleep(3000);
+      while ((nTries > 0) && !running)
+      {
+        if (isServerRunning(&running) != SERVICE_RETURN_OK)
+        {
+          break;
+        }
+        if (!running)
+        {
+          Sleep(2000);
+        }
+      }
+      if (running)
+      {
+        returnValue = SERVICE_RETURN_OK;
+      }
+      else
+      {
+        returnValue = SERVICE_RETURN_ERROR;
+      }
+    }
+    else
+    {
+      returnValue = SERVICE_RETURN_ERROR;
+    }
+  }
+  else
+  {
+    returnValue = SERVICE_RETURN_ERROR;
+  }
+  return returnValue;
+}  // doStartApplication
+
+// ----------------------------------------------------
+// Start the application using stop-ds.bat
+// The functions returns SERVICE_RETURN_OK if we could stop the server
+// and SERVICE_RETURN_ERROR otherwise.
+// ----------------------------------------------------
+ServiceReturnCode doStopApplication()
+{
+  ServiceReturnCode returnValue;
+  // init out params
+  char* relativePath = "\\bin\\stop-ds.bat";
+  char command[COMMAND_SIZE];
+  if (strlen(relativePath)+strlen(_instanceDir)+1 < COMMAND_SIZE)
+  {
+    sprintf(command, "\"%s%s\" --windowsNetStop", _instanceDir, relativePath);
+
+    // launch the command
+    if (spawn(command, FALSE) != 0)
+    {
+      // Try to see if server is really stopped
+      int nTries = 10;
+      BOOL running = TRUE;
+      // Wait to be able to launch the java process in order it to free the lock
+      // on the file.
+      Sleep(3000);
+      while ((nTries > 0) && running)
+      {
+        if (isServerRunning(&running) != SERVICE_RETURN_OK)
+        {
+          break;
+        }
+        if (running)
+        {
+          Sleep(2000);
+        }
+      }
+      if (!running)
+      {
+        returnValue = SERVICE_RETURN_OK;
+      }
+      else
+      {
+        returnValue = SERVICE_RETURN_ERROR;
+      }
+    }
+    else
+    {
+      returnValue = SERVICE_RETURN_ERROR;
+    }
+  }
+  else
+  {
+    returnValue = SERVICE_RETURN_ERROR;
+  }
+  return returnValue;
+}  // doStopApplication
+
+// ---------------------------------------------------------------
+// Build the path to the binary that contains serviceMain.
+// Actually, the binary is the current executable file...
+// serviceBinPath  the path to the service binary.
+// instanceDir the instanceDirectory.
+// The string stored in serviceBinPath looks like
+// <SERVER_ROOT>/lib/service.exe start <_instanceDir>
+// It is up to the caller of the function to allocate
+// at least MAX_PATH bytes in serviceBinPath.
+// The function returns SERVICE_RETURN_OK if we could create the binary
+// path name and SERVICE_RETURN_ERROR otherwise.
+// ---------------------------------------------------------------
+
+ServiceReturnCode createServiceBinPath(char* serviceBinPath)
+{
+  ServiceReturnCode returnValue = SERVICE_RETURN_OK;
+
+  // get the full path to the current executable file
+  char fileName [MAX_PATH];
+  DWORD result = GetModuleFileName (
+  NULL,    // get the path to the current executable file
+  fileName,
+  MAX_PATH
+  );
+
+  if (result == 0)
+  {
+    // failed to get the path of the executable file
+    returnValue = SERVICE_RETURN_ERROR;
+  }
+  else
+  {
+    if (result == MAX_PATH)
+    {
+      // buffer was too small, executable name is probably not valid
+      returnValue = SERVICE_RETURN_ERROR;
+    }
+    else
+    {
+      if (strlen(fileName) + strlen(" start ") + strlen(_instanceDir)
+        < MAX_PATH)
+      {
+        sprintf(serviceBinPath, "%s start \"%s\"", fileName,
+        _instanceDir);
+      }
+      else
+      {
+        // buffer was too small, executable name is probably not valid
+        returnValue = SERVICE_RETURN_ERROR;
+      }
+    }
+  }
+
+  return returnValue;
+} // createServiceBinPath
+
+// ----------------------------------------------------
+// Returns the service name that maps the command used to start the
+// product. All commands are supposed to be unique because they have
+// the instance dir as parameter.
+//
+// The functions returns SERVICE_RETURN_OK if we could create a service name
+// and SERVICE_RETURN_ERROR otherwise.
+// The serviceName buffer must be allocated OUTSIDE the function and its
+// minimum size must be of 256 (the maximum string length of a Service Name).
+// ----------------------------------------------------
+
+ServiceReturnCode getServiceName(char* cmdToRun, char* serviceName)
+{
+  // returned status code
+  ServiceReturnCode returnValue = SERVICE_RETURN_OK;
+
+  // retrieve list of services
+  ServiceDescriptor* serviceList = NULL;
+  int nbServices = -1;
+  returnValue = getServiceList(&serviceList, &nbServices);
+
+  // go through the list of services and search for the service name
+  // whose display name is [displayName]
+  if (returnValue == SERVICE_RETURN_OK)
+  {
+    int i;
+    returnValue = SERVICE_RETURN_ERROR;
+    if (nbServices > 0)
+    {
+      for (i = 0; i<nbServices; i++)
+      {
+        ServiceDescriptor curService = serviceList[i];
+        if (curService.cmdToRun != NULL)
+        {
+          if (_stricmp(cmdToRun, curService.cmdToRun) == 0)
+          {
+            if (strlen(curService.serviceName) < MAX_SERVICE_NAME)
+            {
+              // This function assumes that there are at least
+              // MAX_SERVICE_NAME (256) characters reserved in
+              // servicename.
+              sprintf(serviceName, curService.serviceName);
+              returnValue = SERVICE_RETURN_OK;
+            }
+            break;
+          }
+        }
+      }
+      free (serviceList);
+    }
+  }
+  else
+  {
+    debug("getServiceName: could not get service list.");
+  }
+  return returnValue;
+
+}  // getServiceName
+
+// ----------------------------------------------------
+// Set the current status for the service.
+//
+// statusToSet current service status to set
+// win32ExitCode determine which exit code to use
+// serviceExitCode service code to return in case win32ExitCode says so
+// checkPoint incremental value use to report progress during a lenghty
+// operation (start, stop...).
+// waitHint estimated time required for a pending operation (in ms); if
+// the service has not updated the checkpoint or change the state then
+// the service controler thinks the service should be stopped!
+// serviceStatusHandle  the handle used to set the service status
+// The functions returns SERVICE_RETURN_OK if we could start the service
+// and SERVICE_RETURN_ERROR otherwise.
+// ----------------------------------------------------
+
+ServiceReturnCode updateServiceStatus (
+DWORD  statusToSet,
+DWORD  win32ExitCode,
+DWORD  serviceExitCode,
+DWORD  checkPoint,
+DWORD  waitHint,
+SERVICE_STATUS_HANDLE *serviceStatusHandle
+)
+{
+  ServiceReturnCode returnValue;
+
+  // elaborate service type:
+  // SERVICE_WIN32_OWN_PROCESS means this is not a driver and there is
+  // only one service in the process
+  DWORD serviceType = SERVICE_WIN32_OWN_PROCESS;
+
+  // elaborate the commands supported by the service:
+  // - STOP        customer has performed a stop-ds (or NET STOP)
+  // - SHUTDOWN    the system is rebooting
+  // - INTERROGATE service controler can interogate the service
+  // - No need to support PAUSE/CONTINUE
+  //
+  // Note: INTERROGATE *must* be supported by the service handler
+  DWORD controls;
+  SERVICE_STATUS serviceStatus;
+  BOOL success;
+  if (statusToSet == SERVICE_START_PENDING)
+  {
+    // do not accept any command when the service is starting up...
+    controls = SERVICE_ACCEPT_NONE;
+  }
+  else
+  {
+    controls =
+    SERVICE_ACCEPT_STOP
+    | SERVICE_ACCEPT_SHUTDOWN
+    | SERVICE_CONTROL_INTERROGATE;
+  }
+
+  // fill in the status structure
+  serviceStatus.dwServiceType              = serviceType;
+  serviceStatus.dwCurrentState             = statusToSet;
+  serviceStatus.dwControlsAccepted         = controls;
+  serviceStatus.dwWin32ExitCode            = win32ExitCode;
+  serviceStatus.dwServiceSpecificExitCode  = serviceExitCode;
+  serviceStatus.dwCheckPoint               = checkPoint;
+  serviceStatus.dwWaitHint                 = waitHint;
+
+
+  // set the service status
+
+  success = SetServiceStatus(
+  *serviceStatusHandle,
+  &serviceStatus
+  );
+
+  if (!success)
+  {
+    returnValue = SERVICE_RETURN_ERROR;
+  }
+  else
+  {
+    returnValue = SERVICE_RETURN_OK;
+  }
+
+  return returnValue;
+}  // updateServiceStatus
+
+// ----------------------------------------------------
+// This function is the "main" of the service. It has been registered
+// to the SCM by the main right after the service has been started through
+// NET START command.
+//
+//  The job of the serviceMain is
+//
+//  1- to register a handler to manage the commands STOP, PAUSE, CONTINUE,
+//     SHUTDOWN and INTERROGATE sent by the SCM
+//  2- to start the main application using "start-ds"
+//
+//  The serviceMain will return only when the service is terminated.
+// ----------------------------------------------------
+void serviceMain(int argc, char* argv[])
+{
+  // returned status
+  char cmdToRun[MAX_PATH];
+  char serviceName[MAX_SERVICE_NAME];
+  ServiceReturnCode code;
+  // a checkpoint value indicate the progress of an operation
+  DWORD checkPoint = CHECKPOINT_FIRST_VALUE;
+  SERVICE_STATUS_HANDLE serviceStatusHandle;
+
+  code = createServiceBinPath(cmdToRun);
+
+  if (code == SERVICE_RETURN_OK)
+  {
+    code = getServiceName(cmdToRun, serviceName);
+  }
+
+  if (code == SERVICE_RETURN_OK)
+  {
+    // first register the service control handler to the SCM
+    code = registerServiceHandler(serviceName,
+    (LPHANDLER_FUNCTION) serviceHandler,
+    &serviceStatusHandle);
+    if (code == SERVICE_RETURN_OK)
+    {
+      _serviceStatusHandle = &serviceStatusHandle;
+    }
+  }
+
+
+  // update the service status to START_PENDING
+  if (code == SERVICE_RETURN_OK)
+  {
+    _serviceCurStatus = SERVICE_START_PENDING;
+    code = updateServiceStatus (
+    SERVICE_START_PENDING,
+    NO_ERROR,
+    0,
+    checkPoint++,
+    TIMEOUT_CREATE_EVENT,
+    _serviceStatusHandle);
+  }
+
+  // create an event to signal the application termination
+  if (code == SERVICE_RETURN_OK)
+  {
+    _terminationEvent = CreateEvent(
+    NULL,   // handle is not inherited by the child process
+    TRUE,   // event has to be reset manually after a signal
+    FALSE,  // initial state is "non signaled"
+    NULL    // the event has no name
+    );
+  }
+
+  // update the service status to START_PENDING
+  if (code == SERVICE_RETURN_OK)
+  {
+    _serviceCurStatus = SERVICE_START_PENDING;
+    updateServiceStatus (
+    _serviceCurStatus,
+    NO_ERROR,
+    0,
+    checkPoint++,
+    TIMEOUT_START_SERVICE,
+    _serviceStatusHandle
+    );
+  }
+
+  // start the application
+  if (code == SERVICE_RETURN_OK)
+  {
+    WORD argCount = 1;
+    const char *argc[] = {_instanceDir};
+    code = doStartApplication();
+
+    switch (code)
+    {
+      case SERVICE_RETURN_OK:
+      // start is ok
+      _serviceCurStatus = SERVICE_RUNNING;
+      updateServiceStatus (
+      _serviceCurStatus,
+      NO_ERROR,
+      0,
+      CHECKPOINT_NO_ONGOING_OPERATION,
+      TIMEOUT_NONE,
+      _serviceStatusHandle
+      );
+      reportLogEvent(
+      EVENTLOG_SUCCESS,
+      WIN_EVENT_ID_SERVER_STARTED,
+      argCount, argc
+      );
+      break;
+
+      default:
+      code = SERVICE_RETURN_ERROR;
+      _serviceCurStatus = SERVICE_STOPPED;
+      updateServiceStatus (
+      _serviceCurStatus,
+      ERROR_SERVICE_SPECIFIC_ERROR,
+      -1,
+      CHECKPOINT_NO_ONGOING_OPERATION,
+      TIMEOUT_NONE,
+      _serviceStatusHandle);
+      reportLogEvent(
+      EVENTLOG_ERROR_TYPE,
+      WIN_EVENT_ID_SERVER_START_FAILED,
+      argCount, argc
+      );
+    }
+  }
+  else
+  {
+    updateServiceStatus (
+    _serviceCurStatus,
+    ERROR_SERVICE_SPECIFIC_ERROR,
+    0,
+    CHECKPOINT_NO_ONGOING_OPERATION,
+    TIMEOUT_NONE,
+    _serviceStatusHandle);
+  }
+
+  // if all is ok wait for the application to die before we leave
+  if (code == SERVICE_RETURN_OK)
+  {
+    WaitForSingleObject (_terminationEvent, INFINITE);
+  }
+
+  // update the service status to STOPPED if it's not already done
+  if ((_serviceCurStatus != SERVICE_STOPPED) &&
+    (_serviceStatusHandle != NULL))
+  {
+    _serviceCurStatus = SERVICE_STOPPED;
+    updateServiceStatus (
+    _serviceCurStatus,
+    NO_ERROR,
+    0,
+    CHECKPOINT_NO_ONGOING_OPERATION,
+    TIMEOUT_NONE,
+    _serviceStatusHandle
+    );
+  }
+}  // serviceMain
+
+
+// ----------------------------------------------------
+// Notify the serviceMain that service is now terminated.
+//
+// terminationEvent  the event upon which serviceMain is blocked
+// ----------------------------------------------------
+void doTerminateService(HANDLE terminationEvent)
+{
+  SetEvent(terminationEvent);
+  return;
+
+}  // doTerminateService
+
+// ----------------------------------------------------
+// This function is the handler of the service. It is processing the
+// commands send by the SCM. Commands can be: STOP, PAUSE, CONTINUE,
+// SHUTDOWN and INTERROGATE.
+//  controlCode  the code of the command
+// ----------------------------------------------------
+
+void serviceHandler(DWORD controlCode)
+{
+  ServiceReturnCode code;
+  DWORD checkpoint;
+  BOOL running;
+  switch (controlCode)
+  {
+    case SERVICE_CONTROL_SHUTDOWN:
+    // If system is shuting down then stop the service
+    // -> no break here
+    case SERVICE_CONTROL_STOP:
+    {
+      // update service status to STOP_PENDING
+      debug("Stop called");
+      _serviceCurStatus = SERVICE_STOP_PENDING;
+      checkpoint = CHECKPOINT_FIRST_VALUE;
+      updateServiceStatus (
+      _serviceCurStatus,
+      NO_ERROR,
+      0,
+      checkpoint++,
+      TIMEOUT_STOP_SERVICE,
+      _serviceStatusHandle
+      );
+
+      // let's try to stop the application whatever may be the status above
+      // (best effort mode)
+      code = doStopApplication();
+      if (code == SERVICE_RETURN_OK)
+      {
+        WORD argCount = 1;
+        const char *argc[] = {_instanceDir};
+        _serviceCurStatus = SERVICE_STOPPED;
+        updateServiceStatus (
+        _serviceCurStatus,
+        NO_ERROR,
+        0,
+        CHECKPOINT_NO_ONGOING_OPERATION,
+        TIMEOUT_NONE,
+        _serviceStatusHandle
+        );
+
+        // again, let's ignore the above status and
+        // notify serviceMain that service has stopped
+        doTerminateService (_terminationEvent);
+        reportLogEvent(
+        EVENTLOG_SUCCESS,
+        WIN_EVENT_ID_SERVER_STOP,
+        argCount, argc
+        );
+      }
+      else
+      {
+        WORD argCount = 1;
+        const char *argc[] = {_instanceDir};
+        // We could not stop the server
+        reportLogEvent(
+        EVENTLOG_ERROR_TYPE,
+        WIN_EVENT_ID_SERVER_STOP_FAILED,
+        argCount, argc
+        );
+      }
+      break;
+    }
+
+
+    // Request to pause the service
+    // ----------------------------
+    case SERVICE_CONTROL_PAUSE:
+    // not supported
+    break;
+
+    // Request to resume the service
+    // -----------------------------
+    case SERVICE_CONTROL_CONTINUE:
+    // not supported
+    break;
+
+    // Interrogate the service status
+    // ------------------------------
+    case SERVICE_CONTROL_INTERROGATE:
+    code = isServerRunning(&running);
+    if (code != SERVICE_RETURN_OK)
+    {
+
+    }
+    else if (running)
+    {
+      _serviceCurStatus = SERVICE_RUNNING;
+    }
+    else
+    {
+      _serviceCurStatus = SERVICE_STOPPED;
+    }
+    updateServiceStatus (
+    _serviceCurStatus,
+    NO_ERROR,
+    0,
+    CHECKPOINT_NO_ONGOING_OPERATION,
+    TIMEOUT_NONE,
+    _serviceStatusHandle
+    );
+    break;
+
+    // Other codes are ignored
+    default:
+
+    break;
+  }
+
+}  // serviceHandler
+
+// ---------------------------------------------------------------
+// Retrieve the binaryPathName from the SCM database for a given service.
+//
+// scm is the SCM handler (must not be NULL)
+// serviceName  the name of the service.
+// It is up to the caller of the function to allocate at least MAX_PATH bytes
+// in binPathName.
+// The function returns SERVICE_RETURN_OK if we could create the binary
+// path name and SERVICE_RETURN_ERROR otherwise.
+// ---------------------------------------------------------------
+
+ServiceReturnCode getBinaryPathName(HANDLE scm, char* serviceName,
+char* binPathName)
+{
+  ServiceReturnCode returnValue;
+  // pathtname to return
+  char* binPathname = NULL;
+
+  // handle to the service
+  SC_HANDLE myService = NULL;
+
+
+  BOOL  getConfigOk = FALSE;
+  DWORD configSize  = 4096;
+  LPQUERY_SERVICE_CONFIG serviceConfig =
+  (LPQUERY_SERVICE_CONFIG)malloc(configSize);
+
+  returnValue = SERVICE_RETURN_ERROR;
+
+  // if SCM exists then retrieve the config info of the service
+  if (scm != NULL)
+  {
+    myService = OpenService(
+    scm,
+    serviceName,
+    SERVICE_QUERY_CONFIG
+    );
+  }
+
+  if (myService != NULL)
+  {
+    while (!getConfigOk)
+    {
+      DWORD bytesNeeded;
+
+      getConfigOk = QueryServiceConfig(
+      myService,
+      serviceConfig,
+      configSize,
+      &bytesNeeded
+      );
+
+      if (!getConfigOk)
+      {
+        DWORD errCode = GetLastError();
+        if (errCode == ERROR_INSUFFICIENT_BUFFER)
+        {
+          // buffer nor big enough...
+          configSize += bytesNeeded;
+          serviceConfig =
+          (LPQUERY_SERVICE_CONFIG)realloc(serviceConfig, configSize);
+          continue;
+        }
+        else
+        {
+          break;
+        }
+      }
+      else
+      {
+        if (strlen(serviceConfig->lpBinaryPathName) < MAX_PATH)
+        {
+          sprintf(binPathName, serviceConfig->lpBinaryPathName);
+          returnValue = SERVICE_RETURN_OK;
+        }
+      }
+    }
+  }
+
+  // free buffers
+  if (serviceConfig != NULL)
+  {
+    free(serviceConfig);
+  }
+
+  return returnValue;
+} // getBinaryPathName
+
+// ---------------------------------------------------------------
+// Returns the list of NT services being created on the current host.
+// The function allocates the memory for the returned buffer.
+// serviceList contains the list of services.
+// nbServices the number of services returned in the list.
+// The functions returns SERVICE_RETURN_OK if we could create the service
+// list and SERVICE_RETURN_ERROR otherwise.
+// ---------------------------------------------------------------
+
+ServiceReturnCode getServiceList(ServiceDescriptor** serviceList,
+int *nbServices)
+{
+  ServiceReturnCode returnValue;
+
+  // open Service Control Manager
+  SC_HANDLE scm = NULL;
+  // get the list of services being configured in the SCM database
+  // 1- first try with a single data structure ENUM_SERVICE_STATUS
+  ENUM_SERVICE_STATUS  serviceData;
+  ENUM_SERVICE_STATUS* lpServiceData = &serviceData;
+  DWORD dataSize = sizeof (serviceData);
+  DWORD neededSize;
+  DWORD resumeHandle  = 0;
+  unsigned long nbSvc = 0;
+
+  if (openScm(SC_MANAGER_ENUMERATE_SERVICE, &scm) == SERVICE_RETURN_OK)
+  {
+    BOOL svcStatusOk = EnumServicesStatus(
+    scm,                   // handle to the SCM
+    SERVICE_WIN32,         // for OWN_PROCESS | SHARE_PROCESS
+    SERVICE_STATE_ALL,     // all services (runing & stopped)
+    &serviceData,          // output buffer
+    dataSize,              // output buffer size
+    &neededSize,           // sized needed to get the entries
+    &nbSvc,                // number of services
+    &resumeHandle          // next service entry to read
+    );
+
+    if (! svcStatusOk)
+    {
+      DWORD lastError = GetLastError();
+      if (lastError != ERROR_MORE_DATA)
+      {
+        char msg[200];
+        sprintf(msg, "getServiceList: generic error. Code [%d]",
+        lastError);
+        // error
+        debug(msg);
+        returnValue = SERVICE_RETURN_ERROR;
+      }
+      else
+      {
+        debug("getServiceList: error More Data.");
+        // buffer is not big enough: try again with a proper size
+        dataSize += neededSize;
+        lpServiceData = (ENUM_SERVICE_STATUS*)calloc(
+        dataSize, sizeof(ENUM_SERVICE_STATUS));
+
+        svcStatusOk = EnumServicesStatus(
+        scm,                   // handle to the SCM
+        SERVICE_WIN32,         // for OWN_PROCESS | SHARE_PROCESS
+        SERVICE_STATE_ALL,     // all services (running & stopped)
+        lpServiceData,         // output buffer
+        dataSize,              // output buffer size
+        &neededSize,           // sized needed to get the entries
+        &nbSvc,                // number of services
+        &resumeHandle          // next service entry to read
+        );
+
+        if (! svcStatusOk)
+        {
+          DWORD lastError = GetLastError();
+          if (lastError != ERROR_MORE_DATA)
+          {
+            returnValue = SERVICE_RETURN_ERROR;
+          }
+          else
+          {
+            // Data buffer is not large enough. This case should
+            // never happen as proper buffer size has been
+            // provided!...
+            debug("getServiceList: buffer error");
+            returnValue = SERVICE_RETURN_ERROR;
+          }
+        }
+        else
+        {
+          returnValue = SERVICE_RETURN_OK;
+        }
+      }
+    }
+    else
+    {
+      returnValue = SERVICE_RETURN_OK;
+    }
+  }
+  else
+  {
+    returnValue = SERVICE_RETURN_ERROR;
+  }
+
+  // now elaborate the list of service to return...
+  if (returnValue == SERVICE_RETURN_OK)
+  {
+    int i;
+    int aux = (int)nbSvc;
+    ServiceDescriptor* l;
+
+    ENUM_SERVICE_STATUS* curService = lpServiceData;
+
+    *nbServices = aux;
+    if (aux > 0)
+    {
+      char binPath[MAX_PATH];
+      l = (ServiceDescriptor*)calloc(sizeof(ServiceDescriptor), aux);
+      for (i = 0; i < aux; i++)
+      {
+        l[i].serviceName = strdup(curService->lpServiceName);
+        l[i].displayName = strdup(curService->lpDisplayName);
+
+        if (getBinaryPathName(scm, l[i].serviceName, binPath) ==
+          SERVICE_RETURN_OK)
+        {
+          l[i].cmdToRun = strdup(binPath);
+        }
+        curService++;
+      }
+      *serviceList = l;
+    }
+  }
+
+  // close the handle to the SCM
+  if (scm != NULL)
+  {
+    CloseServiceHandle (scm);
+    // free the result buffer
+    if (lpServiceData != NULL)
+    {
+      free (lpServiceData);
+    }
+  }
+
+  return returnValue;
+} // getServiceList
+
+// ---------------------------------------------------------------
+// Function used to know if a given service name is in use or not.
+// Returns SERVICE_IN_USE if the provided service name is in use.
+// Returns NOT_SERVICE_IN_USE if the provided service name is not in use.
+// Returns SERVICE_RETURN_ERROR if the function could not determine if the
+// service name is in use or not.
+// ---------------------------------------------------------------
+
+ServiceReturnCode serviceNameInUse(char* serviceName)
+{
+  ServiceReturnCode returnValue;
+
+  // retrieve list of services
+  ServiceDescriptor* serviceList = NULL;
+  ServiceDescriptor curService;
+  int nbServices = -1;
+  int i;
+
+  // go through the list of services and search for the service name
+  if (getServiceList(&serviceList, &nbServices) == SERVICE_RETURN_OK)
+  {
+    returnValue = SERVICE_NOT_IN_USE;
+
+    if (nbServices > 0)
+    {
+      for (i = 0; i < nbServices && (returnValue == SERVICE_NOT_IN_USE);
+      i++)
+      {
+        curService = serviceList[i];
+        if (curService.serviceName == NULL)
+        {
+          debug("The service name is NULL.\n");
+        }
+        else
+        {
+          if (strcmp (serviceName, curService.serviceName) == 0)
+          {
+            // found the service!
+            returnValue = SERVICE_IN_USE;
+          }
+        }
+      }
+      free(serviceList);
+    }
+  }
+  else
+  {
+    returnValue = SERVICE_RETURN_ERROR;
+  }
+  return returnValue;
+} // serviceNameInUse
+
+// ---------------------------------------------------------------
+// Build a service name for OpenDS and make sure
+// the service name is unique on the system. To achieve this requirement
+// the service name looks like OpenDS for the first OpenDS and
+// OpenDS-n if there are more than one.
+//
+// The functions returns SERVICE_RETURN_OK if we could create a service
+// name and SERVICE_RETURN_ERROR otherwise.
+// The serviceName buffer must be allocated OUTSIDE the function and its
+// minimum size must be of 256 (the maximum string length of a Service Name).
+// ---------------------------------------------------------------
+
+ServiceReturnCode createServiceName(char* serviceName)
+{
+  ServiceReturnCode returnValue = SERVICE_RETURN_OK;
+  int i = 1;
+  BOOL ended = FALSE;
+  ServiceReturnCode nameInUseResult;
+  while (!ended)
+  {
+    if (i == 1)
+    {
+      sprintf(serviceName, "OpenDS");
+    }
+    else
+    {
+      sprintf(serviceName, "OpenDS-%d", i);
+    }
+
+    nameInUseResult = serviceNameInUse(serviceName);
+
+    if (nameInUseResult == SERVICE_IN_USE)
+    {
+      // this service name is already in use: try another one...
+      i++;
+    }
+    else if (nameInUseResult == SERVICE_NOT_IN_USE)
+    {
+      // this service name is not used so it's a good candidate
+      ended = TRUE;
+    }
+    else
+    {
+      // an error occurred checking the service name
+      returnValue = SERVICE_RETURN_ERROR;
+      ended = TRUE;
+    }
+  }
+
+  return returnValue;
+} // createServiceName
+
+
+// ---------------------------------------------------------------
+// Create a service in the SCM database. Once the service is created,
+// we can view it with "service list".
+// displayName is the display name of the service
+// description is the description of the service
+// cmdToRun    is the command to be run by the SCM upon NET START
+//
+// The function returns SERVICE_RETURN_OK if we could create the service and
+// SERVICE_RETURN_ERROR otherwise.
+// ---------------------------------------------------------------
+
+ServiceReturnCode createServiceInScm(char* displayName, char* description,
+char* cmdToRun)
+{
+  ServiceReturnCode returnValue;
+  SC_HANDLE scm       = NULL;
+  SC_HANDLE myService = NULL;
+
+  // local vars
+  // - serviceName is the service name
+  char* serviceName = (char*) calloc(1, MAX_SERVICE_NAME);
+
+  // elaborate the service name
+  returnValue = createServiceName(serviceName);
+
+  // create the service
+  if (returnValue == SERVICE_RETURN_OK)
+  {
+    if (openScm(GENERIC_WRITE, &scm) != SERVICE_RETURN_OK)
+    {
+      returnValue = SERVICE_RETURN_ERROR;
+      debug("createServiceInScm: openScm did not work.");
+    }
+  }
+  else
+  {
+    returnValue = SERVICE_RETURN_ERROR;
+    debug("createServiceInScm: createServiceName did not work.");
+  }
+
+  if (returnValue == SERVICE_RETURN_OK)
+  {
+    myService = CreateService(
+    scm,
+    serviceName,                // name of service
+    displayName,                // service name to display
+    SERVICE_ALL_ACCESS,         // desired access
+    SERVICE_WIN32_OWN_PROCESS,  // service type
+    SERVICE_AUTO_START,         // start service during
+    // system startup
+    SERVICE_ERROR_NORMAL,       // error control type
+    cmdToRun,                   // path to service's binary
+    NULL,                       // no load ordering group
+    NULL,                       // no tag identifier
+    NULL,                       // no dependencies
+    NULL,                       // LocalSystem account
+    NULL                        // no password
+    );
+  }
+
+  if ((returnValue == SERVICE_RETURN_OK) && (myService == NULL))
+  {
+    DWORD errCode = GetLastError();
+    if (errCode == ERROR_DUPLICATE_SERVICE_NAME)
+    {
+      returnValue = DUPLICATED_SERVICE_NAME;
+    }
+    else if (errCode == ERROR_SERVICE_EXISTS)
+    {
+      returnValue = SERVICE_ALREADY_EXISTS;
+    }
+    else
+    {
+      returnValue = SERVICE_RETURN_ERROR;
+    }
+  }
+
+  // add description field
+  if (returnValue == SERVICE_RETURN_OK)
+  {
+    BOOL success;
+    SERVICE_DESCRIPTION serviceDescription;
+    serviceDescription.lpDescription = description;
+
+    success = ChangeServiceConfig2(
+    myService,
+    SERVICE_CONFIG_DESCRIPTION,
+    (LPVOID) &serviceDescription
+    );
+
+    if (!success)
+    {
+      returnValue = SERVICE_RETURN_ERROR;
+    }
+  }
+
+  // close handles
+  if (myService != NULL)
+  {
+    CloseServiceHandle (myService);
+  }
+
+  if (scm != NULL)
+  {
+    CloseServiceHandle (scm);
+  }
+
+  // free names
+  if (serviceName != NULL)
+  {
+    free (serviceName);
+  }
+
+  return returnValue;
+} // createServiceInScm
+
+
+// ---------------------------------------------------------------
+// Remove a service with the name serviceName from SCM.
+// If the service could be removed returns SERVICE_RETURN_OK.
+// If the service cannot be removed because still in use by any process
+// then returned status is SERVICE_MARKED_FOR_DELETION.
+// If an error occurs returns SERVICE_RETURN_ERROR.
+// ---------------------------------------------------------------
+ServiceReturnCode removeServiceFromScm(char* serviceName)
+{
+  // local vars
+  ServiceReturnCode returnValue = SERVICE_RETURN_OK;
+  SC_HANDLE scm       = NULL;
+  SC_HANDLE myService = NULL;
+  SERVICE_STATUS serviceStatus;
+
+  returnValue = openScm(GENERIC_WRITE, &scm);
+
+  // open the service
+  if (returnValue == SERVICE_RETURN_OK)
+  {
+    myService = OpenService(
+    scm,
+    serviceName,
+    SERVICE_ALL_ACCESS | DELETE
+    );
+    if (myService == NULL)
+    {
+      returnValue = SERVICE_RETURN_ERROR;
+    }
+  }
+
+  if (returnValue == SERVICE_RETURN_OK)
+  {
+    BOOL success = QueryServiceStatus(
+    myService,
+    &serviceStatus
+    );
+    if (!success)
+    {
+      returnValue = SERVICE_RETURN_ERROR;
+    }
+  }
+
+  // stop the service if necessary
+  if (returnValue == SERVICE_RETURN_OK)
+  {
+    if (serviceStatus.dwCurrentState != SERVICE_STOPPED)
+    {
+      BOOL success = ControlService (
+      myService,
+      SERVICE_CONTROL_STOP,
+      &serviceStatus
+      );
+      if (!success)
+      {
+        DWORD errCode = GetLastError();
+        if (errCode == ERROR_SERVICE_MARKED_FOR_DELETE)
+        {
+          returnValue = SERVICE_MARKED_FOR_DELETION;
+        }
+        else
+        {
+          returnValue = SERVICE_RETURN_ERROR;
+        }
+      }
+      else
+      {
+        Sleep (500);
+      }
+    }
+  }
+
+  // remove the service
+  if (returnValue == SERVICE_RETURN_OK)
+  {
+    BOOL success = DeleteService (myService);
+    if (!success)
+    {
+
+      DWORD errCode = GetLastError();
+      if (errCode == ERROR_SERVICE_MARKED_FOR_DELETE)
+      {
+        returnValue = SERVICE_MARKED_FOR_DELETION;
+      }
+      else
+      {
+        returnValue = SERVICE_RETURN_ERROR;
+      }
+    }
+  }
+
+  // close handles
+  if (myService != NULL)
+  {
+    CloseServiceHandle (myService);
+  }
+
+  if (scm != NULL)
+  {
+    CloseServiceHandle (scm);
+  }
+
+  return returnValue;
+
+}  // removeServiceFromScm
+
+
+// ---------------------------------------------------------------
+// Function called to create a service for the OpenDS instance
+// where this executable is installed.
+// The first argument that is passed is the displayName of the service
+// and the second the description,
+//
+// Returns 0 if the service was successfully created.
+// Returns 1 if the service already existed for this instance.
+// Returns 2 if the service name we created already exists.
+// Returns 3 if an error occurred.
+// ---------------------------------------------------------------
+int createService(char* displayName, char* description)
+{
+  int returnCode = 0;
+  char cmdToRun[MAX_PATH];
+  ServiceReturnCode code;
+
+  code = createServiceBinPath(cmdToRun);
+
+  if (code == SERVICE_RETURN_OK)
+  {
+    char serviceName[MAX_SERVICE_NAME];
+    code = getServiceName(cmdToRun, serviceName);
+    if (code == SERVICE_RETURN_OK)
+    {
+      // There is a valid serviceName for the command to run, so
+      // OpenDS is registered as a service.
+      code = SERVICE_ALREADY_EXISTS;
+      createRegistryKey(serviceName);
+      debug("createService: service already exists for this instance.");
+    }
+    else
+    {
+      // We could not find a serviceName for the command to run, so
+      // try to create the service.
+      code = createServiceInScm(displayName, description, cmdToRun);
+      if (code == SERVICE_RETURN_OK)
+      {
+        code = getServiceName(cmdToRun, serviceName);
+        if (code == SERVICE_RETURN_OK)
+        {
+          createRegistryKey(serviceName);
+        }
+      }
+    }
+  }
+
+  switch (code)
+  {
+    case SERVICE_RETURN_OK:
+    returnCode = 0;
+    break;
+    case SERVICE_ALREADY_EXISTS:
+    returnCode = 1;
+    break;
+    case DUPLICATED_SERVICE_NAME:
+    returnCode = 2;
+    break;
+    default:
+    returnCode = 3;
+  }
+
+  return returnCode;
+} // createService
+
+// ---------------------------------------------------------------
+// Function called to know if the OpenDS instance where this
+// executable is installed is running as a service or not.
+// Returns 0 if the instance is running as a service and print the
+// serviceName in the standard output.
+// Returns 1 if the instance is not running as a service.
+// Returns 2 if an error occurred or we cannot determine if Open DS
+// is running as a service or not.
+// ---------------------------------------------------------------
+int serviceState()
+{
+  int returnCode = 0;
+  char cmdToRun[MAX_PATH];
+  char serviceName[MAX_SERVICE_NAME];
+  ServiceReturnCode code;
+
+  code = createServiceBinPath(cmdToRun);
+
+  if (code == SERVICE_RETURN_OK)
+  {
+    code = getServiceName(cmdToRun, serviceName);
+    if (code == SERVICE_RETURN_OK)
+    {
+      // There is a valid serviceName for the command to run, so
+      // OpenDS is registered as a service.
+      fprintf(stdout, serviceName);
+      returnCode = 0;
+    }
+    else
+    {
+      returnCode = 1;
+    }
+  }
+  else
+  {
+    returnCode = 2;
+  }
+
+  return returnCode;
+} // serviceState
+
+
+
+// ---------------------------------------------------------------
+// Function called to remove the service for the OpenDS instance
+// where this executable is installed.
+// Returns 0 if the service was successfully removed.
+// Returns 1 if the service does not exist.
+// Returns 2 if the service was marked for deletion but is still in
+// use.
+// Returns 3 if an error occurred.
+// ---------------------------------------------------------------
+int removeService()
+{
+  int returnCode = 0;
+  char cmdToRun[MAX_PATH];
+  char serviceName[MAX_SERVICE_NAME];
+  ServiceReturnCode code;
+
+  code = createServiceBinPath(cmdToRun);
+
+  if (code == SERVICE_RETURN_OK)
+  {
+    code = getServiceName(cmdToRun, serviceName);
+    if (code == SERVICE_RETURN_OK)
+    {
+      code = removeServiceFromScm(serviceName);
+
+      switch (code)
+      {
+        case SERVICE_RETURN_OK:
+        removeRegistryKey(serviceName);
+        returnCode = 0;
+        break;
+        case SERVICE_MARKED_FOR_DELETION:
+        removeRegistryKey(serviceName);
+        returnCode = 2;
+        break;
+        default:
+        returnCode = 3;
+      }
+    }
+    else
+    {
+      returnCode = 1;
+    }
+  }
+  else
+  {
+    returnCode = 2;
+  }
+
+  return returnCode;
+} // removeService
+
+
+// ---------------------------------------------------------------
+// Function called to start the service where this executable is installed.
+// Returns 0 if the service runs.
+// Returns 1 if an error occurred.
+// ---------------------------------------------------------------
+
+int startService()
+{
+  int returnCode;
+  char serviceName[MAX_SERVICE_NAME];
+  char cmdToRun[MAX_PATH];
+  ServiceReturnCode code;
+
+  code = createServiceBinPath(cmdToRun);
+
+  if (code == SERVICE_RETURN_OK)
+  {
+    code = getServiceName(cmdToRun, serviceName);
+  }
+
+  if (code == SERVICE_RETURN_OK)
+  {
+    BOOL success;
+    SERVICE_TABLE_ENTRY serviceTable[] =
+    {
+      {serviceName, (LPSERVICE_MAIN_FUNCTION) serviceMain},
+      {NULL, NULL}
+    };
+    _eventLog = registerEventLog(serviceName);
+
+    // register the service to the SCM. The function will return once the
+    // service is terminated.
+    success = StartServiceCtrlDispatcher(serviceTable);
+    if (!success)
+    {
+      WORD argCount = 2;
+      DWORD lastError = GetLastError();
+      const char *argc[2];
+      argc[0] = _instanceDir;
+      if (lastError == ERROR_FAILED_SERVICE_CONTROLLER_CONNECT)
+      {
+        argc[1] =
+        "startService: StartServiceCtrlDispatcher did not work: \
+        ERROR_FAILED_SERVICE_CONTROLLER_CONNECT.";
+      }
+      else if (lastError == ERROR_INVALID_DATA)
+      {
+        argc[1] =
+        "startService: StartServiceCtrlDispatcher did not work: \
+        ERROR_INVALID_DATA.";
+      }
+      else if (lastError == ERROR_SERVICE_ALREADY_RUNNING)
+      {
+        argc[1] =
+        "startService: StartServiceCtrlDispatcher did not work: \
+        ERROR_SERVICE_ALREADY_RUNNING.";
+      }
+      else
+      {
+        argc[1] =
+        "startService: StartServiceCtrlDispatcher did not work.";
+      }
+      code = SERVICE_RETURN_ERROR;
+      reportLogEvent(
+      EVENTLOG_ERROR_TYPE,
+      WIN_EVENT_ID_SERVER_START_FAILED,
+      argCount, argc
+      );
+    }
+    deregisterEventLog();
+  }
+  else
+  {
+    debug("startService: Could not get service name.");
+  }
+
+  if (code == SERVICE_RETURN_OK)
+  {
+    returnCode = 0;
+  }
+  else
+  {
+    returnCode = 1;
+  }
+  return returnCode;
+
+}  // startService
+
+
+// ---------------------------------------------------------------
+// Function called to know if the --debug option was passed
+// when calling this executable or not.  The DEBUG variable is
+// updated accordingly.
+// ---------------------------------------------------------------
+
+void updateDebugFlag(char* argv[], int argc, int startIndex)
+{
+  int i;
+  DEBUG = FALSE;
+  for (i=startIndex; (i<argc) && !DEBUG; i++)
+  {
+    if (strcmp(argv[i], "--debug") == 0)
+    {
+      DEBUG = TRUE;
+    }
+  }
+}
+
+void formatMessage(DWORD msgId, int count, ...)
+{
+  char buf[2048];
+  int result;
+  va_list args;
+  char execName [MAX_PATH];
+  GetModuleFileName (
+  NULL,
+  execName,
+  MAX_PATH
+  );
+  if (count > 0)
+  {
+    va_start(args, count);
+
+    // Retrieve the English message string.
+    result = FormatMessage(
+    FORMAT_MESSAGE_FROM_HMODULE,
+    (LPBYTE)execName,
+    WIN_EVENT_ID_SERVER_STARTED, //msgId,
+    MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT),
+    (LPTSTR) &buf,
+    2048,
+    &args);
+  }
+  else
+  {
+    result = FormatMessage(
+    FORMAT_MESSAGE_FROM_HMODULE,
+    (LPBYTE)execName,
+    msgId,
+    LANG_NEUTRAL,
+    (LPTSTR) &buf,
+    2048,
+    NULL);
+  }
+  if (execName != NULL)
+  {
+    fprintf(stderr, "The module is [%s]\n", execName);
+  }
+  else
+  {
+    fprintf(stderr, "The module is NULL\n");
+  }
+  if (result > 0)
+  {
+    fprintf(stderr, "formatMessage worked: [%s]\n", buf);
+  }
+  else
+  {
+    fprintf(stderr, "formatMessage failed, error is: %d\n",
+    GetLastError());
+  }
+}
+
+void logMsgTest(char *serviceName)
+{
+  DWORD ids[] = {WIN_EVENT_ID_SERVER_STARTED, WIN_EVENT_ID_SERVER_STOP,
+    WIN_EVENT_ID_SERVER_START_FAILED, WIN_EVENT_ID_SERVER_STOP_FAILED,
+  WIN_EVENT_ID_DEBUG};
+
+  const char* args[] = {"c:\\temp\\OpenDS tarara"};
+  int evCount = 5;
+
+  int i;
+
+  _eventLog = registerEventLog(serviceName);
+
+  for (i = 0; i<evCount; i++)
+  {
+    if (i != 5)
+    {
+      formatMessage(ids[i], 1, args[0]);
+      if(reportLogEvent(EVENTLOG_SUCCESS, ids[i], 1, args))
+      {
+        fprintf(stderr, "reportLogEvent successful.\n");
+      }
+      else
+      {
+        fprintf(stderr, "reportLogEvent failed: %d.\n", GetLastError());
+      }
+    }
+    else
+    {
+      formatMessage(ids[i], 0);
+      if (reportLogEvent(EVENTLOG_SUCCESS, ids[i], 1, args))
+      {
+        fprintf(stderr, "reportLogEvent successful.\n");
+      }
+      else
+      {
+        fprintf(stderr, "reportLogEvent failed: %d.\n", GetLastError());
+      }
+    }
+  }
+
+  deregisterEventLog();
+}
+
+int main(int argc, char* argv[])
+{
+  char* subcommand;
+  int returnCode = 0;
+
+  if (argc <= 1)
+  {
+    fprintf(stderr, "Subcommand required: create, state, remove or start\n");
+    returnCode = -1;
+  }
+  else
+  {
+    subcommand = argv[1];
+    if (strcmp(subcommand, "create") == 0)
+    {
+      if (argc <= 4)
+      {
+        fprintf(stderr,
+        "Subcommand create requires instance dir, service name and description.\n");
+        returnCode = -1;
+      }
+      else
+      {
+        _instanceDir = strdup(argv[2]);
+        updateDebugFlag(argv, argc, 5);
+        returnCode = createService(argv[3], argv[4]);
+        free(_instanceDir);
+      }
+    }
+    else if (strcmp(subcommand, "state") == 0)
+    {
+      if (argc <= 2)
+      {
+        fprintf(stderr,
+        "Subcommand state requires instance dir\n");
+        returnCode = -1;
+      }
+      else
+      {
+        _instanceDir = strdup(argv[2]);
+        updateDebugFlag(argv, argc, 3);
+        returnCode = serviceState();
+        free(_instanceDir);
+      }
+    }
+    else if (strcmp(subcommand, "remove") == 0)
+    {
+      if (argc <= 2)
+      {
+        fprintf(stderr,
+        "Subcommand remove requires instance dir\n");
+        returnCode = -1;
+      }
+      else
+      {
+        _instanceDir = strdup(argv[2]);
+        updateDebugFlag(argv, argc, 3);
+        returnCode = removeService();
+        free(_instanceDir);
+      }
+    }
+    else if (strcmp(subcommand, "start") == 0)
+    {
+      if (argc <= 2)
+      {
+        fprintf(stderr,
+        "Subcommand start requires instancedir.\n");
+        returnCode = -1;
+      }
+      else
+      {
+        _instanceDir = strdup(argv[2]);
+        updateDebugFlag(argv, argc, 3);
+        returnCode = startService();
+        free(_instanceDir);
+      }
+    }
+    else if (strcmp(subcommand, "isrunning") == 0)
+    {
+      if (argc <= 2)
+      {
+        fprintf(stderr,
+        "Subcommand isrunning requires instancedir.\n");
+        returnCode = -1;
+      }
+      else
+      {
+        BOOL running;
+        ServiceReturnCode code;
+        _instanceDir = strdup(argv[2]);
+        updateDebugFlag(argv, argc, 3);
+        code = isServerRunning(&running);
+        if (code == SERVICE_RETURN_OK)
+        {
+          returnCode = 0;
+        }
+        else
+        {
+          returnCode = -1;
+        }
+        free(_instanceDir);
+      }
+
+    }
+    else if (strcmp(subcommand, "logevents") == 0)
+    {
+      if (argc <= 2)
+      {
+        fprintf(stderr,
+        "Subcommand logevents requires instancedir.\n");
+        returnCode = -1;
+      }
+      else
+      {
+        ServiceReturnCode code;
+        char cmdToRun[MAX_PATH];
+        char serviceName[MAX_SERVICE_NAME];
+        _instanceDir = strdup(argv[2]);
+
+        code = createServiceBinPath(cmdToRun);
+
+        if (code == SERVICE_RETURN_OK)
+        {
+          code = getServiceName(cmdToRun, serviceName);
+        }
+
+        if (code == SERVICE_RETURN_OK)
+        {
+          logMsgTest(serviceName);
+          returnCode = 0;
+        }
+        else
+        {
+          returnCode = -1;
+        }
+
+        free(_instanceDir);
+      }
+
+    }
+    else
+    {
+      fprintf(stderr, "Unknown subcommand: [%s]\n", subcommand);
+      returnCode = -1;
+    }
+  }
+
+  return returnCode;
+} // main
+
diff --git a/opendj-sdk/opends/build-tools/src/windows/service.h b/opendj-sdk/opends/build-tools/src/windows/service.h
new file mode 100644
index 0000000..cc69bee
--- /dev/null
+++ b/opendj-sdk/opends/build-tools/src/windows/service.h
@@ -0,0 +1,109 @@
+/*
+ * CDDL HEADER START
+ *
+ * The contents of this file are subject to the terms of the
+ * Common Development and Distribution License, Version 1.0 only
+ * (the "License").  You may not use this file except in compliance
+ * with the License.
+ *
+ * You can obtain a copy of the license at
+ * trunk/opends/resource/legal-notices/OpenDS.LICENSE
+ * or https://OpenDS.dev.java.net/OpenDS.LICENSE.
+ * See the License for the specific language governing permissions
+ * and limitations under the License.
+ *
+ * When distributing Covered Code, include this CDDL HEADER in each
+ * file and include the License file at
+ * trunk/opends/resource/legal-notices/OpenDS.LICENSE.  If applicable,
+ * add the following below this CDDL HEADER, with the fields enclosed
+ * by brackets "[]" replaced with your own identifying * information:
+ *      Portions Copyright [yyyy] [name of copyright owner]
+ *
+ * CDDL HEADER END
+ *
+ *
+ *      Portions Copyright 2007 Sun Microsystems, Inc.
+ */
+
+#include <errno.h>
+#include <fcntl.h>
+#include <io.h>
+#include <stdio.h>
+#include <sys/locking.h>
+#include "common.h"
+#include "EventLogMsg.h"
+
+#define MAX_SERVICE_NAME 256
+
+// ----------------------------------------------------
+// Estimated time for a given operation (in ms).
+// Note: if the estimated value is too short then the service controler
+//       may consider the service as not alive anymore! so the value
+//       must be as precise as possible (better have it too big rather
+//       than to small)
+// ----------------------------------------------------
+
+#define TIMEOUT_NONE              0
+#define TIMEOUT_CREATE_EVENT   5000
+#define TIMEOUT_START_SERVICE 30000
+#define TIMEOUT_STOP_SERVICE  30000
+
+// ----------------------------------------------------
+// The first value to use for checkpoints
+// ----------------------------------------------------
+#define CHECKPOINT_FIRST_VALUE 1
+
+// ----------------------------------------------------
+// Checkpoint value to use to let the SCM knows that there is
+// no ongoing operation
+// ----------------------------------------------------
+#define CHECKPOINT_NO_ONGOING_OPERATION 0
+
+// ----------------------------------------------------
+// Event Log Key.
+// ----------------------------------------------------
+#define EVENT_LOG_KEY "SYSTEM\\CurrentControlSet\\Services\\EventLog\\Application\\%s"
+
+// ----------------------------------------------------
+// Max size of the registry key
+// ----------------------------------------------------
+#define MAX_REGISTRY_KEY 512
+
+// ----------------------------------------------------
+// Max size of the binary to run the service
+// ----------------------------------------------------
+#define COMMAND_SIZE 2048
+
+#define SERVICE_ACCEPT_NONE 0
+
+typedef struct {
+      char* serviceName;   // the name of the service
+      char* displayName;   // the display name of the service
+    char* cmdToRun;    // the executable to run
+      } ServiceDescriptor;
+
+typedef enum {
+    SERVICE_RETURN_OK, SERVICE_RETURN_ERROR, SERVICE_IN_USE,
+  SERVICE_NOT_IN_USE, DUPLICATED_SERVICE_NAME, SERVICE_ALREADY_EXISTS,
+  SERVICE_MARKED_FOR_DELETION
+} ServiceReturnCode;
+
+
+ServiceReturnCode registerServiceHandler (char* serviceName,
+LPHANDLER_FUNCTION serviceHandler, SERVICE_STATUS_HANDLE* serviceStatusHandle);
+ServiceReturnCode serviceNameInUse(char* serviceName);
+ServiceReturnCode createServiceName(char* serviceName);
+ServiceReturnCode getServiceList(ServiceDescriptor** serviceList,
+int *nbServices);
+ServiceReturnCode createServiceBinPath(char* serviceBinPath);
+ServiceReturnCode getServiceName(char* cmdToRun, char* serviceName);
+ServiceReturnCode updateServiceStatus (
+   DWORD  statusToSet,
+   DWORD  win32ExitCode,
+   DWORD  serviceExitCode,
+   DWORD  checkPoint,
+   DWORD  waitHint,
+   SERVICE_STATUS_HANDLE *serviceStatusHandle
+   );
+void serviceHandler(DWORD controlCode);
+
diff --git a/opendj-sdk/opends/build-tools/src/windows/winlauncher.c b/opendj-sdk/opends/build-tools/src/windows/winlauncher.c
index fd6464b..5bd057d 100644
--- a/opendj-sdk/opends/build-tools/src/windows/winlauncher.c
+++ b/opendj-sdk/opends/build-tools/src/windows/winlauncher.c
@@ -1,30 +1,30 @@
 /*
- * CDDL HEADER START
- *
- * The contents of this file are subject to the terms of the
- * Common Development and Distribution License, Version 1.0 only
- * (the "License").  You may not use this file except in compliance
- * with the License.
- *
- * You can obtain a copy of the license at
- * trunk/opends/resource/legal-notices/OpenDS.LICENSE
- * or https://OpenDS.dev.java.net/OpenDS.LICENSE.
- * See the License for the specific language governing permissions
- * and limitations under the License.
- *
- * When distributing Covered Code, include this CDDL HEADER in each
- * file and include the License file at
- * trunk/opends/resource/legal-notices/OpenDS.LICENSE.  If applicable,
- * add the following below this CDDL HEADER, with the fields enclosed
- * by brackets "[]" replaced with your own identifying information:
- *      Portions Copyright [yyyy] [name of copyright owner]
- *
- * CDDL HEADER END
- *
- *
- *      Portions Copyright 2007 Sun Microsystems, Inc.
- */
- 
+* CDDL HEADER START
+*
+* The contents of this file are subject to the terms of the
+* Common Development and Distribution License, Version 1.0 only
+* (the "License").  You may not use this file except in compliance
+* with the License.
+*
+* You can obtain a copy of the license at
+* trunk/opends/resource/legal-notices/OpenDS.LICENSE
+* or https://OpenDS.dev.java.net/OpenDS.LICENSE.
+* See the License for the specific language governing permissions
+* and limitations under the License.
+*
+* When distributing Covered Code, include this CDDL HEADER in each
+* file and include the License file at
+* trunk/opends/resource/legal-notices/OpenDS.LICENSE.  If applicable,
+* add the following below this CDDL HEADER, with the fields enclosed
+* by brackets "[]" replaced with your own identifying information:
+*      Portions Copyright [yyyy] [name of copyright owner]
+*
+* CDDL HEADER END
+*
+*
+*      Portions Copyright 2007 Sun Microsystems, Inc.
+*/
+
 #include "winlauncher.h"
 
 
@@ -36,18 +36,18 @@
 // ----------------------------------------------------
 BOOL getPidFile(const char* instanceDir, char* pidFile, unsigned int maxSize)
 {
-    BOOL returnValue;
-    char* relativePath = "\\logs\\server.pid";
-    if ((strlen(relativePath) + strlen(instanceDir)) < maxSize)
-    {
-        sprintf(pidFile, "%s\\logs\\server.pid", instanceDir);
-        returnValue = TRUE;
-    }
-    else
-    {
-        returnValue = FALSE;
-    }
-    return returnValue;
+  BOOL returnValue;
+  char* relativePath = "\\logs\\server.pid";
+  if ((strlen(relativePath) + strlen(instanceDir)) < maxSize)
+  {
+    sprintf(pidFile, "%s\\logs\\server.pid", instanceDir);
+    returnValue = TRUE;
+  }
+  else
+  {
+    returnValue = FALSE;
+  }
+  return returnValue;
 } // getPidFile
 
 
@@ -57,19 +57,19 @@
 // ----------------------------------------------------
 BOOL fileExists(const char *fileName)
 {
-   struct stat finfo;
-   BOOL returnValue = FALSE;
-
-   if(stat(fileName, &finfo) < 0)
-   {
-      returnValue = FALSE;
-   }
-   else
-   {
-      returnValue = TRUE;
-   }
-   
-   return returnValue;
+  struct stat finfo;
+  BOOL returnValue = FALSE;
+  
+  if(stat(fileName, &finfo) < 0)
+  {
+    returnValue = FALSE;
+  }
+  else
+  {
+    returnValue = TRUE;
+  }
+  
+  return returnValue;
 } // fileExists
 
 
@@ -80,28 +80,28 @@
 // ----------------------------------------------------
 BOOL deletePidFile(const char* instanceDir)
 {
-    BOOL returnValue = FALSE;
-    char pidFile[PATH_SIZE];
-    int nTries = 10;
-    
-    // Sometimes the lock on the system in windows takes time to be released.
-    if (getPidFile(instanceDir, pidFile, PATH_SIZE))
+  BOOL returnValue = FALSE;
+  char pidFile[PATH_SIZE];
+  int nTries = 10;
+  
+  // Sometimes the lock on the system in windows takes time to be released.
+  if (getPidFile(instanceDir, pidFile, PATH_SIZE))
+  {
+    while (fileExists(pidFile) && (nTries > 0) && !returnValue)
     {
-        while (fileExists(pidFile) && (nTries > 0) && !returnValue)
-        {
-            if (remove(pidFile) == 0)
-            {
-                returnValue = TRUE;
-            }
-            else
-            {
-                Sleep(500);
-                nTries--;
-            }
-        }
+      if (remove(pidFile) == 0)
+      {
+        returnValue = TRUE;
+      }
+      else
+      {
+        Sleep(500);
+        nTries--;
+      }
     }
-    
-    return returnValue;
+  }
+  
+  return returnValue;
 }  // deletePidFile
 
 
@@ -112,27 +112,35 @@
 // ----------------------------------------------------
 int getPid(const char* instanceDir)
 {
-    int returnValue;
-    char pidFile[PATH_SIZE];
-    FILE *f;
-    char buf[BUF_SIZE];
-    int read;
-    
-    if (getPidFile(instanceDir, pidFile, PATH_SIZE))
+  int returnValue;
+  char pidFile[PATH_SIZE];
+  FILE *f;
+  char buf[BUF_SIZE];
+  int read;
+  
+  if (getPidFile(instanceDir, pidFile, PATH_SIZE))
+  {
+    if ((f = fopen(pidFile, "r")) != NULL)
     {
-        if ((f = fopen(pidFile, "r")) != NULL)
-        {
-            read = fread(buf, 1, sizeof(buf),f);
-        }
-        
-        fclose(f);
-        returnValue = (int)strtol(buf, (char **)NULL, 10);
+      read = fread(buf, 1, sizeof(buf),f);
+    }
+    
+    if (f != NULL)
+    {
+      fclose(f);
+      returnValue = (int)strtol(buf, (char **)NULL, 10);
     }
     else
     {
-        returnValue = 0;
+      fprintf(stderr, "File %s could not be opened", pidFile);
+      returnValue = 0;
     }
-    return returnValue;
+  }
+  else
+  {
+    returnValue = 0;
+  }
+  return returnValue;
 }  // getPid
 
 
@@ -143,52 +151,52 @@
 // ----------------------------------------------------
 BOOL killProcess(int pid)
 {
-    BOOL processDead;
-    HANDLE procHandle = OpenProcess(
-       PROCESS_TERMINATE               // to terminate the process
-       | PROCESS_QUERY_INFORMATION,    // to get exit code
-       FALSE,                          // handle is not inheritable
-       pid
-       );
-       
-    if (procHandle == NULL)
+  BOOL processDead;
+  HANDLE procHandle = OpenProcess(
+  PROCESS_TERMINATE               // to terminate the process
+  | PROCESS_QUERY_INFORMATION,    // to get exit code
+  FALSE,                          // handle is not inheritable
+  pid
+  );
+  
+  if (procHandle == NULL)
+  {
+    // process already dead
+    processDead = TRUE;
+  }
+  else
+  {
+    if (!TerminateProcess(procHandle, 0))
     {
-       // process already dead
-       processDead = TRUE;
+      // failed to terminate the process
+      processDead = FALSE;
     }
     else
     {
-       if (!TerminateProcess(procHandle, 0))
-       {
-          // failed to terminate the process
-          processDead = FALSE;
-       }
-       else
-       {
-          // wait for the process to end.
-          DWORD exitCode;
-          int nTries = 20;
-          
-          processDead = FALSE;
-          while ((nTries > 0) && !processDead)
-          {
-             GetExitCodeProcess(procHandle, &exitCode);
-             if (exitCode == STILL_ACTIVE)
-             {
-                 // process is still alive, let's wait 1 sec and loop again
-                 Sleep(1000);
-                 nTries--;
-             }
-             else
-             {
-                 processDead = TRUE;
-             }
-          }
-       }
-       CloseHandle(procHandle);
+      // wait for the process to end.
+      DWORD exitCode;
+      int nTries = 20;
+      
+      processDead = FALSE;
+      while ((nTries > 0) && !processDead)
+      {
+        GetExitCodeProcess(procHandle, &exitCode);
+        if (exitCode == STILL_ACTIVE)
+        {
+          // process is still alive, let's wait 1 sec and loop again
+          Sleep(1000);
+          nTries--;
+        }
+        else
+        {
+          processDead = TRUE;
+        }
+      }
     }
-    
-    return processDead;
+    CloseHandle(procHandle);
+  }
+  
+  return processDead;
 } // killProcess
 
 // ----------------------------------------------------
@@ -199,103 +207,31 @@
 // ----------------------------------------------------
 BOOL createPidFile(const char* instanceDir, int pid)
 {
-    BOOL returnValue = FALSE;
-    char pidFile[PATH_SIZE];
-    FILE *f;
-    
-    if (getPidFile(instanceDir, pidFile, PATH_SIZE))
+  BOOL returnValue = FALSE;
+  char pidFile[PATH_SIZE];
+  FILE *f;
+  
+  if (getPidFile(instanceDir, pidFile, PATH_SIZE))
+  {
+    if ((f = fopen(pidFile, "w")) != NULL)
     {
-        if ((f = fopen(pidFile, "w")) != NULL)
-        {
-            fprintf(f, "%d", pid);
-            fclose (f);
-            returnValue = TRUE;
-        }
-        else
-        {
-            returnValue = FALSE;
-        }
+      fprintf(f, "%d", pid);
+      fclose (f);
+      returnValue = TRUE;
     }
     else
     {
-        returnValue = FALSE;
+      returnValue = FALSE;
     }
-   
-    return returnValue;
+  }
+  else
+  {
+    returnValue = FALSE;
+  }
+  
+  return returnValue;
 }  // createPidFile
 
-// ----------------------------------------------------
-// Function used to create a process with the given command.
-// The information about the process is stored in procInfo.
-// The function returns TRUE if the process could be created
-// and FALSE otherwise.
-// ----------------------------------------------------
-BOOL createChildProcess(char* command, BOOL background,
-PROCESS_INFORMATION* procInfo)
-{
-   BOOL createOk;
-   STARTUPINFO startInfo; // info to pass to the new process
-   DWORD processFlag; // background process flag
-
-   // reset process info first
-   ZeroMemory(procInfo, sizeof(PROCESS_INFORMATION));
-
-   // initialize handles to pass to the child process
-   ZeroMemory(&startInfo, sizeof(STARTUPINFO));
-   startInfo.cb = sizeof(STARTUPINFO);
-   startInfo.dwFlags |= STARTF_USESTDHANDLES;  // use handles above
-
-   // Create the child process
-   processFlag = background == TRUE ? DETACHED_PROCESS : 0;
-   createOk = CreateProcess(
-      NULL,          // application name
-      command,       // command line
-      NULL,          // process security attributes
-      NULL,          // primary thread security attributes
-      TRUE,          // handles are inherited
-      processFlag,   // creation flags
-      NULL,          // use parent's environment
-      NULL,          // use parent's current directory
-      &startInfo,    // STARTUPINFO pointer
-      procInfo       // receives PROCESS_INFORMATION
-      );
-
-   if (!createOk)
-   {
-      fprintf(stderr, "Failed to create child process [%s]\n", command);
-   }
-
-   return createOk;
-} // createChildProcess
-
-// ----------------------------------------------------
-// Function used to launch a process for the given command
-// If the process could be created it returns the pid of
-// the created process and -1 otherwise.
-// ----------------------------------------------------
-int spawn(const char* command)
-{
-    DWORD childPid; // child's pid
-    PROCESS_INFORMATION procInfo; // info on the new process
-    BOOL createOk;
-    
-    createOk = createChildProcess((char*)command, TRUE, &procInfo);
-    
-    if(createOk)
-    {
-        childPid = procInfo.dwProcessId;
-    }
-    
-    if (childPid != -1)
-    {
-        return childPid;
-    }
-    else
-    {
-        return -1;
-    }
-} // spawn
-
 
 // ----------------------------------------------------
 // Elaborate the command line: "cmd arg1 arg2..."
@@ -307,84 +243,84 @@
 // ----------------------------------------------------
 BOOL getCommandLine(const char* argv[], char* command, unsigned int maxSize)
 {
-   int curCmdInd = 0;
-   int i = 0;
-   BOOL overflow = FALSE;
-   
-   while ((argv[i] != NULL) && !overflow)
-   {
-      const char* curarg = argv[i++];
-      if (i > 1)
+  int curCmdInd = 0;
+  int i = 0;
+  BOOL overflow = FALSE;
+  
+  while ((argv[i] != NULL) && !overflow)
+  {
+    const char* curarg = argv[i++];
+    if (i > 1)
+    {
+      if (curCmdInd + strlen(" ") < maxSize)
       {
-          if (curCmdInd + strlen(" ") < maxSize)
-          {
-              sprintf (&command[curCmdInd], " ");
-              curCmdInd = strlen(command);
-          }
-          else
-          {
-              overflow = TRUE;
-          }
+        sprintf (&command[curCmdInd], " ");
+        curCmdInd = strlen(command);
+      }
+      else
+      {
+        overflow = TRUE;
+      }
+    }
+    
+    if (curarg[0] != '\0')
+    {
+      int argInd = 0;
+      
+      if (curarg[0] == '"')
+      {
+        // there is a quote: no need to add extra quotes
+      }
+      else
+      {
+        while (curarg[argInd] != ' '
+          && curarg[argInd] != '\0'
+        && curarg[argInd] != '\n')
+        {
+          argInd++;
+        }
+      }
+      if (curarg[0] != '"' && curarg[argInd] == ' ')
+      {
+        if (curCmdInd + strlen("\"\"") + strlen(curarg) < maxSize)
+        {
+          // no begining quote and white space inside => add quotes
+          sprintf (&command[curCmdInd], "\"%s\"", curarg);
+          curCmdInd = strlen (command);
+        }
+        else
+        {
+          overflow = TRUE;
+        }
+      }
+      else
+      {
+        if (curCmdInd + strlen(curarg) < maxSize)
+        {
+          // no white space or quotes detected, keep the arg as is
+          sprintf (&command[curCmdInd], "%s", curarg);
+          curCmdInd = strlen (command);
+        }
+        else
+        {
+          overflow = TRUE;
+        }
       }
       
-      if (curarg[0] != '\0')
+    } else {
+      if (curCmdInd + strlen("\"\"") < maxSize)
       {
-         int argInd = 0;
-         
-         if (curarg[0] == '"')
-         {
-            // there is a quote: no need to add extra quotes
-         }
-         else
-         {
-             while (curarg[argInd] != ' '
-                && curarg[argInd] != '\0'
-                && curarg[argInd] != '\n')
-            {
-               argInd++;
-            }
-         }
-         if (curarg[0] != '"' && curarg[argInd] == ' ')
-         {
-             if (curCmdInd + strlen("\"\"") + strlen(curarg) < maxSize)
-             {
-                 // no begining quote and white space inside => add quotes
-                 sprintf (&command[curCmdInd], "\"%s\"", curarg);
-                 curCmdInd = strlen (command);
-             }
-             else
-             {
-                 overflow = TRUE;
-             }
-         }
-         else
-         {
-             if (curCmdInd + strlen(curarg) < maxSize)
-             {
-                 // no white space or quotes detected, keep the arg as is
-                 sprintf (&command[curCmdInd], "%s", curarg);
-                 curCmdInd = strlen (command);
-             }
-             else
-             {
-                 overflow = TRUE;
-             }
-         }
-         
-      } else {
-            if (curCmdInd + strlen("\"\"") < maxSize)
-            {
-                sprintf (&command[curCmdInd], "\"\"");
-                curCmdInd = strlen (command);
-            }
-            else
-            {
-                overflow = TRUE;
-            }
+        sprintf (&command[curCmdInd], "\"\"");
+        curCmdInd = strlen (command);
       }
-   }
-   
-   return !overflow;
+      else
+      {
+        overflow = TRUE;
+      }
+    }
+  }
+  
+  return !overflow;
 } // getCommandLine
 
 // ----------------------------------------------------
@@ -410,31 +346,31 @@
 // ----------------------------------------------------
 int start(const char* instanceDir, char* argv[])
 {
-    int returnValue;
-    int childPid;
+  int returnValue;
+  int childPid;
+  
+  char command[COMMAND_SIZE];
+  
+  if (getCommandLine(argv, command, COMMAND_SIZE))
+  {
+    childPid = spawn(command, TRUE);
     
-    char command[COMMAND_SIZE];
-    
-    if (getCommandLine(argv, command, COMMAND_SIZE))
+    if (childPid > 0)
     {
-        childPid = spawn(command);
-        
-        if (childPid > 0)
-        {
-            createPidFile(instanceDir, childPid);
-            returnValue = childPid;
-        }
-        else
-        {
-            returnValue = -1;
-        }
+      createPidFile(instanceDir, childPid);
+      returnValue = childPid;
     }
     else
     {
-        returnValue = -1;
+      returnValue = -1;
     }
-   
-    return returnValue;
+  }
+  else
+  {
+    returnValue = -1;
+  }
+  
+  return returnValue;
 } // start
 
 
@@ -461,22 +397,22 @@
 // ----------------------------------------------------
 int stop(const char* instanceDir)
 {
-    int returnCode = -1;
-    
-    int childPid;
-    
-    childPid = getPid(instanceDir);
-    
-    if (childPid != 0)
+  int returnCode = -1;
+  
+  int childPid;
+  
+  childPid = getPid(instanceDir);
+  
+  if (childPid != 0)
+  {
+    if (killProcess(childPid))
     {
-        if (killProcess(childPid))
-        {
-            returnCode = 0;
-            deletePidFile(instanceDir);
-        }
+      returnCode = 0;
+      deletePidFile(instanceDir);
     }
-   
-    return returnCode;
+  }
+  
+  return returnCode;
 } // stop
 
 
@@ -507,20 +443,20 @@
 // ----------------------------------------------------
 int launch(char* argv[])
 {
-    int returnValue;
-    
-    char command[COMMAND_SIZE];
-    
-    if (getCommandLine(argv, command, COMMAND_SIZE))
-    {
-        returnValue = spawn(command);
-    }
-    else
-    {
-        returnValue = -1;
-    }
-   
-    return returnValue;
+  int returnValue;
+  
+  char command[COMMAND_SIZE];
+  
+  if (getCommandLine(argv, command, COMMAND_SIZE))
+  {
+    returnValue = spawn(command, TRUE);
+  }
+  else
+  {
+    returnValue = -1;
+  }
+  
+  return returnValue;
 } // launch
 
 // ----------------------------------------------------
@@ -534,28 +470,29 @@
 // ----------------------------------------------------
 int main(int argc, char* argv[])
 {
-    int returnCode;
-    char* subcommand = argv[1];
-    char* instanceDir = argv[2];
-    
-    argv += 3;
-    
-    if (strcmp(subcommand, "start") == 0)
-    {
-        returnCode = start(instanceDir, argv);
-    }
-    else if (strcmp(subcommand, "stop") == 0)
-    {
-        returnCode = stop(instanceDir);
-    }
-    else if (strcmp(subcommand, "launch") == 0)
-    {
-        returnCode = launch(argv);
-    }
-    else
-    {
-        fprintf(stderr, "Unknown subcommand: [%s]", subcommand);
-        returnCode = -1;
-    }
-    return returnCode;
+  int returnCode;
+  char* subcommand = argv[1];
+  char* instanceDir = argv[2];
+  
+  argv += 3;
+  
+  if (strcmp(subcommand, "start") == 0)
+  {
+    returnCode = start(instanceDir, argv);
+  }
+  else if (strcmp(subcommand, "stop") == 0)
+  {
+    returnCode = stop(instanceDir);
+  }
+  else if (strcmp(subcommand, "launch") == 0)
+  {
+    returnCode = launch(argv);
+  }
+  else
+  {
+    fprintf(stderr, "Unknown subcommand: [%s]", subcommand);
+    returnCode = -1;
+  }
+  return returnCode;
 }
+
diff --git a/opendj-sdk/opends/build-tools/src/windows/winlauncher.h b/opendj-sdk/opends/build-tools/src/windows/winlauncher.h
index 273ced3..e577a39 100644
--- a/opendj-sdk/opends/build-tools/src/windows/winlauncher.h
+++ b/opendj-sdk/opends/build-tools/src/windows/winlauncher.h
@@ -1,37 +1,38 @@
 /*
- * CDDL HEADER START
- *
- * The contents of this file are subject to the terms of the
- * Common Development and Distribution License, Version 1.0 only
- * (the "License").  You may not use this file except in compliance
- * with the License.
- *
- * You can obtain a copy of the license at
- * trunk/opends/resource/legal-notices/OpenDS.LICENSE
- * or https://OpenDS.dev.java.net/OpenDS.LICENSE.
- * See the License for the specific language governing permissions
- * and limitations under the License.
- *
- * When distributing Covered Code, include this CDDL HEADER in each
- * file and include the License file at
- * trunk/opends/resource/legal-notices/OpenDS.LICENSE.  If applicable,
- * add the following below this CDDL HEADER, with the fields enclosed
- * by brackets "[]" replaced with your own identifying information:
- *      Portions Copyright [yyyy] [name of copyright owner]
- *
- * CDDL HEADER END
- *
- *
- *      Portions Copyright 2007 Sun Microsystems, Inc.
- */
+* CDDL HEADER START
+*
+* The contents of this file are subject to the terms of the
+* Common Development and Distribution License, Version 1.0 only
+* (the "License").  You may not use this file except in compliance
+* with the License.
+*
+* You can obtain a copy of the license at
+* trunk/opends/resource/legal-notices/OpenDS.LICENSE
+* or https://OpenDS.dev.java.net/OpenDS.LICENSE.
+* See the License for the specific language governing permissions
+* and limitations under the License.
+*
+* When distributing Covered Code, include this CDDL HEADER in each
+* file and include the License file at
+* trunk/opends/resource/legal-notices/OpenDS.LICENSE.  If applicable,
+* add the following below this CDDL HEADER, with the fields enclosed
+* by brackets "[]" replaced with your own identifying information:
+*      Portions Copyright [yyyy] [name of copyright owner]
+*
+* CDDL HEADER END
+*
+*
+*      Portions Copyright 2007 Sun Microsystems, Inc.
+*/
 
 #include <stdio.h>
 #include <stdlib.h>
 #include <sys/stat.h>
 #include <process.h>
-#include <windows.h>
+#include "common.h"
 
 #define PATH_SIZE 1024
 #define BUF_SIZE 1024
 #define COMMAND_SIZE 2048
 
+
diff --git a/opendj-sdk/opends/build.xml b/opendj-sdk/opends/build.xml
index 78d6fe4..b5be56f 100644
--- a/opendj-sdk/opends/build.xml
+++ b/opendj-sdk/opends/build.xml
@@ -286,6 +286,10 @@
       <fileset dir="${basedir}" includes="**/*.bat" excludes="build/**/* " />
       <fileset dir="${basedir}" includes="**/*.ldif" excludes="build/**/*" />
       <fileset dir="${basedir}" includes="**/*.txt" excludes="build/**/*" />
+      <fileset dir="${basedir}" includes="**/*.c" excludes="build/**/*" />
+      <fileset dir="${basedir}" includes="**/*.h" excludes="build/**/*" />
+      <fileset dir="${basedir}" includes="**/*.mc" excludes="build/**/*" />
+      <fileset dir="${basedir}" includes="**/Makefile" excludes="build/**/*" />
       <fileset dir="${scripts.dir}" includes="**/*" />
     </checkcopyrightdates>
   </target>
@@ -316,6 +320,10 @@
       <fileset dir="${basedir}" includes="**/*.bat" excludes="build/**/* " />
       <fileset dir="${basedir}" includes="**/*.ldif" excludes="build/**/*" />
       <fileset dir="${basedir}" includes="**/*.txt" excludes="build/**/*" />
+      <fileset dir="${basedir}" includes="**/*.c" excludes="build/**/*" />
+      <fileset dir="${basedir}" includes="**/*.h" excludes="build/**/*" />
+      <fileset dir="${basedir}" includes="**/*.mc" excludes="build/**/*" />
+      <fileset dir="${basedir}" includes="**/Makefile" excludes="build/**/*" />
       <fileset dir="${scripts.dir}" includes="**/*" />
     </checkeolstyle>
   </target>
diff --git a/opendj-sdk/opends/lib/opends_service.exe b/opendj-sdk/opends/lib/opends_service.exe
new file mode 100755
index 0000000..7a5a5b3
--- /dev/null
+++ b/opendj-sdk/opends/lib/opends_service.exe
Binary files differ
diff --git a/opendj-sdk/opends/lib/winlauncher.exe b/opendj-sdk/opends/lib/winlauncher.exe
index a92ef27..0b278e2 100755
--- a/opendj-sdk/opends/lib/winlauncher.exe
+++ b/opendj-sdk/opends/lib/winlauncher.exe
Binary files differ
diff --git a/opendj-sdk/opends/resource/bin/start-ds b/opendj-sdk/opends/resource/bin/start-ds
index 1d21ce9..d7f6e57 100755
--- a/opendj-sdk/opends/resource/bin/start-ds
+++ b/opendj-sdk/opends/resource/bin/start-ds
@@ -114,39 +114,11 @@
             --configClass org.opends.server.extensions.ConfigFileHandler \
             --configFile "${CONFIG_FILE}" --checkStartability "${@}"
 EC=${?}
-if test ${EC} -ne 99
+if test ${EC} -eq 99
 then
-  exit ${EC}
-fi
-
-
-# See if an "-N" or a "--nodetach" argument was provided as a command-line
-# argument.  If it was, then don't use nohup to send to the  background, and
-# send all output to both the console and a lot file.
-NODETACH=0
-for ARG in "${@}"
-do
-  if test "${ARG}" = "-N"
-  then
-    NODETACH=1
-  else
-    ARG=`echo ${ARG} | tr '[A-Z]' '[a-z]'`
-    if test "${ARG}" = "--nodetach"
-    then
-      NODETACH=1
-    fi
-  fi
-done
-
-if test ${NODETACH} -eq 1
-then
-  echo $$ > "${PID_FILE}"
-  rm -f "${PID_FILE}" "${LOG_FILE}"
-  exec "${JAVA_BIN}" ${JAVA_ARGS} ${SCRIPT_NAME_ARG} \
-       org.opends.server.core.DirectoryServer \
-       --configClass org.opends.server.extensions.ConfigFileHandler \
-       --configFile "${CONFIG_FILE}" "${@}"
-else
+  #
+  # run detach
+  #
   touch "${STARTING_FILE}"
   nohup "${JAVA_BIN}" ${JAVA_ARGS} ${SCRIPT_NAME_ARG} \
        org.opends.server.core.DirectoryServer \
@@ -156,4 +128,23 @@
   "${JAVA_BIN}" -Xms8M -Xmx8M org.opends.server.tools.WaitForFileDelete \
        --targetFile "${STARTING_FILE}" --logFile "${LOG_FILE}"
   exit ${?}
+else
+  if test ${EC} -eq 100
+  then
+    #
+    # run no detach
+    #
+    echo $$ > "${PID_FILE}"
+    rm -f "${PID_FILE}" "${LOG_FILE}"
+    exec "${JAVA_BIN}" ${JAVA_ARGS} ${SCRIPT_NAME_ARG} \
+      org.opends.server.core.DirectoryServer \
+      --configClass org.opends.server.extensions.ConfigFileHandler \
+      --configFile "${CONFIG_FILE}" "${@}"
+  else
+    #
+    # an error or the server is already started.  Just return the code provided
+    # by checkstartability
+    #
+    exit ${EC}
+  fi
 fi
diff --git a/opendj-sdk/opends/resource/bin/start-ds.bat b/opendj-sdk/opends/resource/bin/start-ds.bat
index effbb06..7cd4fcd 100644
--- a/opendj-sdk/opends/resource/bin/start-ds.bat
+++ b/opendj-sdk/opends/resource/bin/start-ds.bat
@@ -58,13 +58,17 @@
 
 set SCRIPT_NAME_ARG=-Dorg.opends.server.scriptName=start-ds
 
-set NODETACH=0
-for %%x in (%*) DO if "%%x" == "-N" set NODETACH=1
-for %%x in (%*) DO if "%%x" == "--nodetach" set NODETACH=1
+"%JAVA_BIN%" -Xms8M -Xmx8M org.opends.server.core.DirectoryServer --configClass org.opends.server.extensions.ConfigFileHandler --configFile "%DIR_HOME%\config\config.ldif" --checkStartability %*
 
-if "%NODETACH%" == "1" goto runNoDetach
-goto runDetach
+if %errorlevel% == 98 goto serverAlreadyStarted
+if %errorlevel% == 99 goto runDetach
+if %errorlevel% == 100 goto runNoDetach
+if %errorlevel% == 101 goto runAsService
+if %errorlevel% == 102 goto runDetachCalledByWinService
+goto end
 
+:serverAlreadyStarted
+goto end
 
 :runNoDetach
 if not exist "%DIR_HOME%\logs\server.out" echo. > "%DIR_HOME%\logs\server.out"
@@ -74,14 +78,28 @@
 
 
 :runDetach
-"%JAVA_BIN%" %JAVA_ARGS%  org.opends.server.core.DirectoryServer --configClass org.opends.server.extensions.ConfigFileHandler --configFile "%DIR_HOME%\config\config.ldif" --checkStartability %*
-if not %errorlevel% == 99 goto end
 if not exist "%DIR_HOME%\logs\server.out" echo. > "%DIR_HOME%\logs\server.out"
 if not exist "%DIR_HOME%\logs\server.starting" echo. > "%DIR_HOME%\logs\server.starting"
 "%DIR_HOME%\lib\winlauncher.exe" start "%DIR_HOME%" "%JAVA_BIN%" %JAVA_ARGS%  org.opends.server.core.DirectoryServer --configClass org.opends.server.extensions.ConfigFileHandler --configFile "%DIR_HOME%\config\config.ldif" %*
 "%JAVA_BIN%" -Xms8M -Xmx8M org.opends.server.tools.WaitForFileDelete --targetFile "%DIR_HOME%\logs\server.starting" --logFile "%DIR_HOME%\logs\server.out"
 goto end
 
+:runDetachCalledByWinService
+rem We write the output of the start command to the winwervice.out file.
+if not exist "%DIR_HOME%\logs\server.out" echo. > "%DIR_HOME%\logs\server.out"
+if not exist "%DIR_HOME%\logs\server.starting" echo. > "%DIR_HOME%\logs\server.starting"
+echo. > "%DIR_HOME%\logs\server.startingservice"
+echo. > "%DIR_HOME%\logs\winservice.out"
+"%DIR_HOME%\lib\winlauncher.exe" start "%DIR_HOME%" "%JAVA_BIN%" %JAVA_ARGS%  org.opends.server.core.DirectoryServer --configClass org.opends.server.extensions.ConfigFileHandler --configFile "%DIR_HOME%\config\config.ldif" %*
+"%JAVA_BIN%" -Xms8M -Xmx8M org.opends.server.tools.WaitForFileDelete --targetFile "%DIR_HOME%\logs\server.starting" --logFile "%DIR_HOME%\logs\server.out" --outputFile "%DIR_HOME%\logs\winservice.out"
+erase "%DIR_HOME%\logs\server.startingservice"
+goto end
 
+:runAsService
+"%JAVA_BIN%" -Xms8M -Xmx8M org.opends.server.tools.StartWindowsService
+"%JAVA_BIN%" -Xms8M -Xmx8M org.opends.server.tools.WaitForFileDelete --targetFile "%DIR_HOME%\logs\server.startingservice"
+rem Type the contents the winwervice.out file and delete it.
+if exist "%DIR_HOME%\logs\winservice.out" type "%DIR_HOME%\logs\winservice.out"
+if exist "%DIR_HOME%\logs\winservice.out" erase "%DIR_HOME%\logs\winservice.out"
 :end
 
diff --git a/opendj-sdk/opends/resource/bin/stop-ds b/opendj-sdk/opends/resource/bin/stop-ds
index 9969147..8269397 100755
--- a/opendj-sdk/opends/resource/bin/stop-ds
+++ b/opendj-sdk/opends/resource/bin/stop-ds
@@ -105,87 +105,105 @@
 export SCRIPT_NAME_ARG
 
 
-# If there were no arguments (or only the -R argument was passed) we assume that
-# the server to be stopped is the local server.  If this is the case we check if
-# the server is running or not.
-# If the server is running then try to stop the server with a kill command.  If
-# there are more arguments, try to stop the server using LDAP protocol.
-NO_ARG_OR_ONLY_RESTART=1
-RESTART=0
-for ARG in "${@}"
-do
-  if test "${ARG}" != "-R"
-  then
-    if test "${ARG}" != "--restart"
-    then
-        NO_ARG_OR_ONLY_RESTART=0
-    else
-        RESTART=1
-    fi
-  else
-    RESTART=1
-  fi
-done
+"${JAVA_BIN}" ${JAVA_ARGS} ${SCRIPT_NAME_ARG} \
+  org.opends.server.tools.StopDS --checkStoppability "${@}"
+EC=${?}
 
-if test ${NO_ARG_OR_ONLY_RESTART} -eq 1
+STOPPED=1
+EXIT_CODE=1
+MUST_START_USING_SYSTEM_CALL=1
+MUST_STOP_USING_SYSTEM_CALL=1
+
+if test ${EC} -eq 98
+#
+# Already stopped and nothing else to do.
+#
 then
-  # Use the code in StopDS class to know if the server is already
-  # stopped.  An exit code of 99 means that the server is stopped.
   STOPPED=0
-  "${JAVA_BIN}" ${JAVA_ARGS} ${SCRIPT_NAME_ARG} \
-     org.opends.server.tools.StopDS --checkStoppability
-  EC=${?}
-  if test ${EC} -ne 99
+else
+  if test ${EC} -eq 99
+  #
+  # Already stopped and must start locally.
+  #
   then
-    STOPPED=1
-  fi
-  
-  EXIT_CODE=0
-  if test "${STOPPED}" -eq 1
-  then
-    if test -f "${INSTANCE_ROOT}/logs/server.pid"
+    STOPPED=0
+    MUST_START_USING_SYSTEM_CALL=0
+  else
+    if test ${EC} -eq 100
     then
-        kill `cat "${INSTANCE_ROOT}/logs/server.pid"`
-        EXIT_CODE=${?}
-        if test "${EXIT_CODE}" -eq 0
+      #
+      # Stop using system call
+      #
+      MUST_STOP_USING_SYSTEM_CALL=0
+    else
+      if test ${EC} -eq 101
+      then
+        #
+        # Restart using system call
+        #
+        MUST_STOP_USING_SYSTEM_CALL=0
+        MUST_START_USING_SYSTEM_CALL=0
+      else
+        if test ${EC} -ne 102
         then
-            "${JAVA_BIN}" -Xms8M -Xmx8M \
-            org.opends.server.tools.WaitForFileDelete \
-            --targetFile "${INSTANCE_ROOT}/logs/server.pid" \
-            --logFile "${INSTANCE_ROOT}/logs/errors"
-            EXIT_CODE=${?}
-            if test "${EXIT_CODE}" -eq 0
-            then
-                STOPPED=0
-            fi
+          exit ${EC}
         fi
+      fi
     fi
   fi
-  
-  # Delete the pid file if the server is stopped (this can occur if the process has
-  # been killed using kill -9).
-  if test "{$STOPPED}" -eq 0
-  then
-  	if test -f "${INSTANCE_ROOT}/logs/server.pid"
-  	then
-  		rm "${INSTANCE_ROOT}/logs/server.pid"
-    fi
-  fi
-  
-  # Now if the user wants to restart the server, try to restart it if the server
-  # is stopped.
-  if test "${RESTART}" -eq 1
-  then
-    if test "${STOPPED}" -eq 0
-    then
-        "${INSTANCE_ROOT}/bin/start-ds"
-        EXIT_CODE=${?}
-    fi
-  fi
-  exit ${EXIT_CODE}
 fi
 
+if test ${MUST_STOP_USING_SYSTEM_CALL} -eq 0
+then
+  if test -f "${INSTANCE_ROOT}/logs/server.pid"
+  then
+    kill `cat "${INSTANCE_ROOT}/logs/server.pid"`
+    EXIT_CODE=${?}
+    if test ${EXIT_CODE} -eq 0
+    then
+      "${JAVA_BIN}" -Xms8M -Xmx8M org.opends.server.tools.WaitForFileDelete \
+        --targetFile "${INSTANCE_ROOT}/logs/server.pid" \
+        --logFile "${INSTANCE_ROOT}/logs/errors"
+      EXIT_CODE=${?}
+      if test ${EXIT_CODE} -eq 0
+      then
+        STOPPED=0
+      fi
+    fi
+  fi
+fi
+
+# Delete the pid file if the server is stopped (this can occur if the process
+# has been killed using kill -9).
+if test ${STOPPED} -eq 0
+then
+  if test -f "${INSTANCE_ROOT}/logs/server.pid"
+  then
+    rm "${INSTANCE_ROOT}/logs/server.pid"
+  fi
+fi
+  
+# Now if the user wants to restart the server, try to restart it if the server
+# is stopped.
+if test ${MUST_START_USING_SYSTEM_CALL} -eq 0
+then
+  if test ${STOPPED} -eq 0
+  then
+    "${INSTANCE_ROOT}/bin/start-ds"
+    EXIT_CODE=${?}
+    exit ${EXIT_CODE}
+  fi
+#
+# The user does not want to start the server locally and it is already stopped.
+# Just exit.
+#
+else
+  if test ${STOPPED} -eq 0
+  then
+    exit 0
+  fi
+fi
 
 # If we've gotten here, then we should try to stop the server over LDAP.
 "${JAVA_BIN}" ${JAVA_ARGS} ${SCRIPT_NAME_ARG} \
-     org.opends.server.tools.StopDS "${@}"
+  org.opends.server.tools.StopDS "${@}"
diff --git a/opendj-sdk/opends/resource/bin/stop-ds.bat b/opendj-sdk/opends/resource/bin/stop-ds.bat
index fc9fe8c..9145664 100644
--- a/opendj-sdk/opends/resource/bin/stop-ds.bat
+++ b/opendj-sdk/opends/resource/bin/stop-ds.bat
@@ -57,60 +57,52 @@
 :setClassPath
 FOR %%x in ("%DIR_HOME%\lib\*.jar") DO call "%DIR_HOME%\bin\setcp.bat" %%x
 
+"%JAVA_BIN%" -Xms8M -Xmx8M %SCRIPT_NAME_ARG%  org.opends.server.tools.StopDS --checkStoppability %*
 
-set RESTART=0
-set NO_ARG_OR_ONLY_RESTART=1
-
-for %%x in (%*) DO set NO_ARG_OR_ONLY_RESTART=0
-if "%NO_ARG_OR_ONLY_RESTART%" == "1" goto execute
-
-for %%x in (%*) DO if "%%x" == "-R" set RESTART=1
-for %%x in (%*) DO if "%%x" == "--restart" set RESTART=1
-
-goto testParameter1
-
-:testParameter1
-if not "%1" == "-R" goto testParameter1b
-goto testParameter2
-
-:testParameter1b
-if not "%1" == "--restart" goto execute
-goto testParameter2
-
-:testParameter2
-if "%2" == "" set NO_ARG_OR_ONLY_RESTART=1
-if "%NO_ARG_OR_ONLY_RESTART%" == "1" goto execute
-if not "%2" == "-R" goto testParameter2b
-goto testParameter3
-
-:testParameter2b
-if not "%2" == "--restart" goto execute
-goto testParameter3
-
-:testParameter3
-if not "%3" == "" goto execute
-set NO_ARG_OR_ONLY_RESTART=1
-goto execute
-
-:execute
-if "%NO_ARG_OR_ONLY_RESTART%" == "0" goto stopWithLDAP
-
-rem  	Use the code in StopDS class to know if the server is already
-rem  	stopped.  An exit code of 99 means that the server is stopped.
-"%JAVA_BIN%" %JAVA_ARGS% %SCRIPT_NAME_ARG%  org.opends.server.tools.StopDS --checkStoppability
-if %errorlevel% == 99 goto serverStopped
-
-if not exist "%DIR_HOME%\logs\server.pid" goto stopWithLDAP
-"%DIR_HOME%\lib\winlauncher.exe" stop "%DIR_HOME%"
-if not %errorlevel% == 0 goto end
-
-:serverStopped
-if exist "%DIR_HOME%\logs\server.pid" erase "%DIR_HOME%\logs\server.pid"
-if "%RESTART%" == "1" "%DIR_HOME%\bin\start-ds.bat"
+if %errorlevel% == 98 goto serverAlreadyStopped
+if %errorlevel% == 99 goto startUsingSystemCall
+if %errorlevel% == 100 goto stopUsingSystemCall
+if %errorlevel% == 101 goto restartUsingSystemCall
+if %errorlevel% == 102 goto stopUsingProtocol
+if %errorlevel% == 103 goto stopAsWindowsService
+if %errorlevel% == 104 goto restartAsWindowsService
+rem An error or we display usage
 goto end
 
-:stopWithLDAP
+:serverAlreadyStopped
+if exist "%DIR_HOME%\logs\server.pid" erase "%DIR_HOME%\logs\server.pid"
+goto end
+
+:startUsingSystemCall
+"%DIR_HOME%\bin\start-ds.bat"
+goto end
+
+:stopUsingSystemCall
+"%DIR_HOME%\lib\winlauncher.exe" stop "%DIR_HOME%"
+goto end
+
+:restartUsingSystemCall
+"%DIR_HOME%\lib\winlauncher.exe" stop "%DIR_HOME%"
+if not %errorlevel% == 0 goto end
+goto startUsingSystemCall
+
+:stopUsingProtocol
 call "%~dP0\_client-script.bat" %*
+goto end
+
+:stopAsWindowsService
+"%JAVA_BIN%" -Xms8M -Xmx8M org.opends.server.tools.StopWindowsService
+goto end
+
+:restartAsWindowsService
+"%JAVA_BIN%" -Xms8M -Xmx8M org.opends.server.tools.StopWindowsService
+if not %errorlevel% == 0 goto end
+"%JAVA_BIN%" -Xms8M -Xmx8M org.opends.server.tools.StartWindowsService
+"%JAVA_BIN%" -Xms8M -Xmx8M org.opends.server.tools.WaitForFileDelete --targetFile "%DIR_HOME%\logs\server.startingservice"
+rem Type the contents the winwervice.out file and delete it.
+if exist "%DIR_HOME%\logs\winservice.out" type "%DIR_HOME%\logs\winservice.out"
+if exist "%DIR_HOME%\logs\winservice.out" erase "%DIR_HOME%\logs\winservice.out"
+goto end
 
 :end
 
diff --git a/opendj-sdk/opends/resource/bin/windowsservice.bat b/opendj-sdk/opends/resource/bin/windowsservice.bat
new file mode 100644
index 0000000..14ddae7
--- /dev/null
+++ b/opendj-sdk/opends/resource/bin/windowsservice.bat
@@ -0,0 +1,33 @@
+
+@echo off
+rem CDDL HEADER START
+rem
+rem The contents of this file are subject to the terms of the
+rem Common Development and Distribution License, Version 1.0 only
+rem (the "License").  You may not use this file except in compliance
+rem with the License.
+rem
+rem You can obtain a copy of the license at
+rem trunk/opends/resource/legal-notices/OpenDS.LICENSE
+rem or https://OpenDS.dev.java.net/OpenDS.LICENSE.
+rem See the License for the specific language governing permissions
+rem and limitations under the License.
+rem
+rem When distributing Covered Code, include this CDDL HEADER in each
+rem file and include the License file at
+rem trunk/opends/resource/legal-notices/OpenDS.LICENSE.  If applicable,
+rem add the following below this CDDL HEADER, with the fields enclosed
+rem by brackets "[]" replaced with your own identifying information:
+rem      Portions Copyright [yyyy] [name of copyright owner]
+rem
+rem CDDL HEADER END
+rem
+rem
+rem      Portions Copyright 2007 Sun Microsystems, Inc.
+
+setlocal
+
+set OPENDS_INVOKE_CLASS="org.opends.server.tools.ConfigureWindowsService"
+set SCRIPT_NAME_ARG="-Dorg.opends.server.scriptName=windowsservice"
+call "%~dP0\_client-script.bat" %*
+
diff --git a/opendj-sdk/opends/src/quicksetup/org/opends/quicksetup/installer/InstallException.java b/opendj-sdk/opends/src/quicksetup/org/opends/quicksetup/installer/InstallException.java
index cd9889f..772d9a9 100644
--- a/opendj-sdk/opends/src/quicksetup/org/opends/quicksetup/installer/InstallException.java
+++ b/opendj-sdk/opends/src/quicksetup/org/opends/quicksetup/installer/InstallException.java
@@ -71,6 +71,10 @@
      */
     START_ERROR,
     /**
+     * Error enabling the Windows service.
+     */
+    WINDOWS_SERVICE_ERROR,
+    /**
      * A bug (for instance when we throw an IllegalStateException).
      */
     BUG
diff --git a/opendj-sdk/opends/src/quicksetup/org/opends/quicksetup/installer/InstallLauncher.java b/opendj-sdk/opends/src/quicksetup/org/opends/quicksetup/installer/InstallLauncher.java
index 5a283ee..165edc2 100644
--- a/opendj-sdk/opends/src/quicksetup/org/opends/quicksetup/installer/InstallLauncher.java
+++ b/opendj-sdk/opends/src/quicksetup/org/opends/quicksetup/installer/InstallLauncher.java
@@ -98,7 +98,16 @@
        * This is required because the usage message contains '{' characters that
        * mess up the MessageFormat.format method.
        */
-      String msg = getMsg("setup-launcher-usage");
+      String msg;
+
+      if (Utils.isWindows())
+      {
+        msg= getMsg("setup-launcher-usage-windows");
+      }
+      else
+      {
+        msg= getMsg("setup-launcher-usage-unix");
+      }
       msg = msg.replace("{0}", arg);
       System.err.println(msg);
       System.exit(1);
diff --git a/opendj-sdk/opends/src/quicksetup/org/opends/quicksetup/installer/InstallProgressStep.java b/opendj-sdk/opends/src/quicksetup/org/opends/quicksetup/installer/InstallProgressStep.java
index 05ade2c..df25583 100644
--- a/opendj-sdk/opends/src/quicksetup/org/opends/quicksetup/installer/InstallProgressStep.java
+++ b/opendj-sdk/opends/src/quicksetup/org/opends/quicksetup/installer/InstallProgressStep.java
@@ -68,6 +68,10 @@
    */
   STARTING_SERVER,
   /**
+   * Enabling Windows service.
+   */
+  ENABLING_WINDOWS_SERVICE,
+  /**
    * Installation finished successfully.
    */
   FINISHED_SUCCESSFULLY,
diff --git a/opendj-sdk/opends/src/quicksetup/org/opends/quicksetup/installer/Installer.java b/opendj-sdk/opends/src/quicksetup/org/opends/quicksetup/installer/Installer.java
index bef514e..c972175 100644
--- a/opendj-sdk/opends/src/quicksetup/org/opends/quicksetup/installer/Installer.java
+++ b/opendj-sdk/opends/src/quicksetup/org/opends/quicksetup/installer/Installer.java
@@ -46,6 +46,7 @@
 import org.opends.quicksetup.util.Utils;
 import org.opends.server.util.SetupUtils;
 
+
 /**
  * This is an abstract class that is in charge of actually performing the
  * installation.
@@ -860,6 +861,18 @@
   }
 
   /**
+   * This methods enables this server as a Windows service.
+   * @throws InstallException if something goes wrong.
+   */
+  protected void enableWindowsService() throws InstallException
+  {
+      notifyListeners(getFormattedProgress(
+        getMsg("progress-enabling-windows-service")));
+      InstallerHelper helper = new InstallerHelper();
+      helper.enableWindowsService();
+  }
+
+  /**
    * This methods starts the server.
    * @throws InstallException if something goes wrong.
    */
@@ -1043,6 +1056,8 @@
             getMsg("summary-importing-automatically-generated")));
     hmSummary.put(InstallProgressStep.STARTING_SERVER,
         getFormattedSummary(getMsg("summary-starting")));
+    hmSummary.put(InstallProgressStep.ENABLING_WINDOWS_SERVICE,
+        getFormattedSummary(getMsg("summary-enabling-windows-service")));
 
     String cmd;
     if (Utils.isWindows())
diff --git a/opendj-sdk/opends/src/quicksetup/org/opends/quicksetup/installer/InstallerHelper.java b/opendj-sdk/opends/src/quicksetup/org/opends/quicksetup/installer/InstallerHelper.java
index a81f378..94da554 100644
--- a/opendj-sdk/opends/src/quicksetup/org/opends/quicksetup/installer/InstallerHelper.java
+++ b/opendj-sdk/opends/src/quicksetup/org/opends/quicksetup/installer/InstallerHelper.java
@@ -84,6 +84,33 @@
         MSGID_DIRECTORY_SERVER_STARTED);
   }
 
+  /**
+   * This methods enables this server as a Windows service.
+   * @throws InstallException if something goes wrong.
+   */
+  protected void enableWindowsService() throws InstallException
+  {
+    int code = org.opends.server.tools.ConfigureWindowsService.enableService(
+    System.out, System.err);
+
+    String errorMessage = ResourceProvider.getInstance().getMsg(
+    "error-enabling-windows-service");
+
+    switch (code)
+    {
+      case
+      org.opends.server.tools.ConfigureWindowsService.SERVICE_ENABLE_SUCCESS:
+      break;
+      case
+      org.opends.server.tools.ConfigureWindowsService.SERVICE_ALREADY_ENABLED:
+      break;
+      default:
+      throw new InstallException(InstallException.Type.WINDOWS_SERVICE_ERROR,
+      errorMessage, null);
+    }
+  }
+
+
   private String getThrowableMsg(String key, Throwable t)
   {
     return getThrowableMsg(key, null, t);
diff --git a/opendj-sdk/opends/src/quicksetup/org/opends/quicksetup/installer/offline/OfflineInstaller.java b/opendj-sdk/opends/src/quicksetup/org/opends/quicksetup/installer/offline/OfflineInstaller.java
index 3e0b3f5..f0b4bf8 100644
--- a/opendj-sdk/opends/src/quicksetup/org/opends/quicksetup/installer/offline/OfflineInstaller.java
+++ b/opendj-sdk/opends/src/quicksetup/org/opends/quicksetup/installer/offline/OfflineInstaller.java
@@ -142,6 +142,13 @@
 
       writeJavaHome();
 
+      if (Utils.isWindows())
+      {
+          notifyListeners(getTaskSeparator());
+          status = InstallProgressStep.ENABLING_WINDOWS_SERVICE;
+          enableWindowsService();
+      }
+
       if (getUserData().getStartServer())
       {
         notifyListeners(getTaskSeparator());
@@ -211,6 +218,7 @@
     hmTime.put(InstallProgressStep.IMPORTING_LDIF, 20);
     hmTime.put(InstallProgressStep.IMPORTING_AUTOMATICALLY_GENERATED,
         20);
+    hmTime.put(InstallProgressStep.ENABLING_WINDOWS_SERVICE, 5);
     hmTime.put(InstallProgressStep.STARTING_SERVER, 10);
 
     int totalTime = 0;
@@ -234,6 +242,11 @@
               InstallProgressStep.IMPORTING_AUTOMATICALLY_GENERATED);
       break;
     }
+    if (Utils.isWindows())
+    {
+      totalTime += hmTime.get(InstallProgressStep.ENABLING_WINDOWS_SERVICE);
+      steps.add(InstallProgressStep.ENABLING_WINDOWS_SERVICE);
+    }
     if (getUserData().getStartServer())
     {
       totalTime += hmTime.get(InstallProgressStep.STARTING_SERVER);
diff --git a/opendj-sdk/opends/src/quicksetup/org/opends/quicksetup/installer/webstart/WebStartDownloader.java b/opendj-sdk/opends/src/quicksetup/org/opends/quicksetup/installer/webstart/WebStartDownloader.java
index 975028d..9d46da2 100644
--- a/opendj-sdk/opends/src/quicksetup/org/opends/quicksetup/installer/webstart/WebStartDownloader.java
+++ b/opendj-sdk/opends/src/quicksetup/org/opends/quicksetup/installer/webstart/WebStartDownloader.java
@@ -244,6 +244,10 @@
         {
           ratio = 110;
         }
+        else if (urls[i].endsWith("aspectjrt.jar"))
+        {
+          ratio = 10;
+        }
         else
         {
           ratio = (100 / urls.length);
diff --git a/opendj-sdk/opends/src/quicksetup/org/opends/quicksetup/installer/webstart/WebStartInstaller.java b/opendj-sdk/opends/src/quicksetup/org/opends/quicksetup/installer/webstart/WebStartInstaller.java
index 8f16bb6..4424e1c 100644
--- a/opendj-sdk/opends/src/quicksetup/org/opends/quicksetup/installer/webstart/WebStartInstaller.java
+++ b/opendj-sdk/opends/src/quicksetup/org/opends/quicksetup/installer/webstart/WebStartInstaller.java
@@ -180,6 +180,13 @@
         startServer();
       }
 
+      if (Utils.isWindows())
+      {
+          notifyListeners(getTaskSeparator());
+          status = InstallProgressStep.ENABLING_WINDOWS_SERVICE;
+          enableWindowsService();
+      }
+
       status = InstallProgressStep.FINISHED_SUCCESSFULLY;
       notifyListeners(null);
 
@@ -240,6 +247,7 @@
     hmTime.put(InstallProgressStep.IMPORTING_LDIF, 20);
     hmTime.put(InstallProgressStep.IMPORTING_AUTOMATICALLY_GENERATED,
         20);
+    hmTime.put(InstallProgressStep.ENABLING_WINDOWS_SERVICE, 5);
     hmTime.put(InstallProgressStep.STARTING_SERVER, 10);
 
     int totalTime = 0;
@@ -267,6 +275,11 @@
               InstallProgressStep.IMPORTING_AUTOMATICALLY_GENERATED);
       break;
     }
+    if (Utils.isWindows())
+    {
+        totalTime += hmTime.get(InstallProgressStep.ENABLING_WINDOWS_SERVICE);
+        steps.add(InstallProgressStep.ENABLING_WINDOWS_SERVICE);
+    }
     if (getUserData().getStartServer())
     {
       totalTime += hmTime.get(InstallProgressStep.STARTING_SERVER);
diff --git a/opendj-sdk/opends/src/quicksetup/org/opends/quicksetup/resources/Resources.properties b/opendj-sdk/opends/src/quicksetup/org/opends/quicksetup/resources/Resources.properties
index f1d1900..4c9d7eb 100644
--- a/opendj-sdk/opends/src/quicksetup/org/opends/quicksetup/resources/Resources.properties
+++ b/opendj-sdk/opends/src/quicksetup/org/opends/quicksetup/resources/Resources.properties
@@ -31,8 +31,8 @@
 #
 # Setup command line messages
 #
-setup-launcher-usage=This utility may be used to setup the Directory Server.\n\
-Usage:  {0} {options}\n        where {options} include:\n\
+setup-launcher-usage-unix=This utility may be used to setup the Directory \
+Server.\n\Usage:  {0} {options}\n        where {options} include:\n\
 --cli\n\    Specifies to use the command line setup.  If not specified the \
 graphical\n\    interface will be launched.\n\
 -H  or   --help\n    Displays usage information for this program.\n\n\
@@ -64,6 +64,41 @@
 -W {filename}  or   --rootUserPasswordFile {filename}\n    Specifies the path \
 to a file containing the password for the initial Administrative\n\    User \
 for the Directory Server.
+setup-launcher-usage-windows=This utility may be used to setup the Directory \
+Server.\n\Usage:  {0} {options}\n        where {options} include:\n\
+--cli\n\    Specifies to use the command line setup.  If not specified the \
+graphical\n\    interface will be launched.\n\
+-H  or   --help\n    Displays usage information for this program.\n\n\
+The following options will only be taken into account if the option --cli \n\
+(command line) is specified\n\
+-s  or   --silentInstall\n    Perform a silent installation.\n\
+-b {baseDN}  or   --baseDN {baseDN}\n\    Specifies the base DN for user \
+information in the Directory Server.\n    Multiple base DNs may be provided by \
+using this option multiple times.\n\
+-a  or   --addBaseEntry\n    Indicates whether to create the base entry in the \
+Directory Server\n    database.\n\
+-i {ldifFile}  or   --importLDIF {ldifFile}\n    Specifies the path to an LDIF \
+file containing data that should be added to\n    the Directory Server \
+database.  Multiple LDIF files may be provided by\n    using this option \
+multiple times.\n\
+-d {numEntries}  or   --sampleData {numEntries}\n    Specifies that the \
+database should be populated with the specified number\n\    of sample \
+entries.\n\
+-p {port}  or   --ldapPort {port}\n    Specifies the port on which the \
+Directory Server should listen for LDAP\n    communication.\n\
+-j {jmxPort}  or   --jmxPort {jmxPort}\n    Specifies the port on which the \
+Directory Server should listen for JMX\n    communication.\n\
+-S  or   --skipPortCheck\n    Skip the check to determine whether the \
+specified LDAP port is usable.\n\
+-D {rootDN}  or   --rootUserDN {rootDN}\n    Specifies the DN for the initial \
+Administrative User for the Directory Server.\n\
+-w {password}  or   --rootUserPassword {password}\n    Specifies the password \
+for the initial Administrative User for the Directory Server.\n\
+-W {filename}  or   --rootUserPasswordFile {filename}\n    Specifies the path \
+to a file containing the password for the initial Administrative\n\    User \
+for the Directory Server.\n\
+-n or --noWindowsService\n    Do not enable OpenDS to run as a Windows \
+Service.
 setup-launcher-launching-gui=Launching graphical setup...
 setup-launcher-gui-launched-failed=\n\nThe graphical Setup launch failed.\n\n\
 Launching command line Setup...
@@ -489,6 +524,7 @@
 summary-importing-automatically-generated=Importing Automatically-Generated \
 Data...
 summary-starting=Starting Directory Server...
+summary-enabling-windows-service=Enabling Windows Service...
 summary-install-finished-successfully=<b>OpenDS QuickSetup Completed \
 Successfully.</b><br>OpenDS is now installed in {0}.<br><br>Visit the \
 <a href="https://opends.dev.java.net/public/docs/user-docs/OpenDS-QuickReference.html"> \
@@ -499,6 +535,7 @@
 summary-install-finished-with-error=An error occurred.  Check 'Details' text \
 area for more information.
 summary-stopping=Stopping Directory Server...
+summary-disabling-windows-service=Disabling Windows Service...
 summary-deleting-external-db-files=Deleting Database Files outside the \
 Installation Path...
 summary-deleting-external-log-files=Deleting Log Files outside the \
@@ -508,12 +545,12 @@
 Path...
 summary-uninstall-finished-successfully-remove-jarfiles=<b>OpenDS Uninstall \
 Completed Successfully.</b><br><br>To complete the uninstallation, you must \
-delete manually the following files:<br>{0}
+delete manually the following files and directories:\n{0}
 summary-uninstall-finished-successfully=<b>OpenDS Uninstall Completed \
 Successfully.</b>
 summary-uninstall-finished-successfully-remove-jarfiles-cli=OpenDS Uninstall \
 Completed Successfully.\nTo complete the uninstallation, you must \
-delete manually the following files:\n{0}
+delete manually the following files and directories:\n{0}
 summary-uninstall-finished-successfully-cli=OpenDS Uninstall Completed \
 Successfully.
 summary-uninstall-finished-with-error=An error occurred.  Check 'Details' text \
@@ -536,6 +573,8 @@
 ({0} Entries):
 progress-starting=Starting Directory Server:
 progress-stopping=Stopping Directory Server:
+progress-enabling-windows-service=Enabling Windows Service...
+progress-disabling-windows-service=Disabling Windows Service...
 progress-deleting-external-db-files=Deleting Database Files outside the \
 Installation Path:
 progress-deleting-external-log-files=Deleting Log Files outside the \
@@ -563,6 +602,8 @@
 error-creating-temp-file=An error occurred creating the temporary file.
 error-writing-to-temp-file=An error occurred writing to temporary file {0}.
 error-configuring=Error Configuring Directory Server.
+error-enabling-windows-service=Error Enabling Windows service.
+error-disabling-windows-service=Error Disabling Windows service.
 error-creating-base-entry=Error Creating Base Entry.
 error-importing-ldif=Error Importing LDIF File.
 error-import-automatically-generated=Error Importing Automatically- Generated \
diff --git a/opendj-sdk/opends/src/quicksetup/org/opends/quicksetup/uninstaller/UninstallException.java b/opendj-sdk/opends/src/quicksetup/org/opends/quicksetup/uninstaller/UninstallException.java
index ea72225..5b77db0 100644
--- a/opendj-sdk/opends/src/quicksetup/org/opends/quicksetup/uninstaller/UninstallException.java
+++ b/opendj-sdk/opends/src/quicksetup/org/opends/quicksetup/uninstaller/UninstallException.java
@@ -56,6 +56,10 @@
      */
     STOP_ERROR,
     /**
+     * Error disabling the Windows service.
+     */
+    WINDOWS_SERVICE_ERROR,
+    /**
      * A bug (for instance when we throw an IllegalStateException).
      */
     BUG
diff --git a/opendj-sdk/opends/src/quicksetup/org/opends/quicksetup/uninstaller/UninstallProgressStep.java b/opendj-sdk/opends/src/quicksetup/org/opends/quicksetup/uninstaller/UninstallProgressStep.java
index 0fc2ee7..3fcd5a1 100644
--- a/opendj-sdk/opends/src/quicksetup/org/opends/quicksetup/uninstaller/UninstallProgressStep.java
+++ b/opendj-sdk/opends/src/quicksetup/org/opends/quicksetup/uninstaller/UninstallProgressStep.java
@@ -43,6 +43,10 @@
    */
   STOPPING_SERVER,
   /**
+   * Disabling Windows Service.
+   */
+  DISABLING_WINDOWS_SERVICE,
+  /**
    * Removing External Database files.
    */
   DELETING_EXTERNAL_DATABASE_FILES,
diff --git a/opendj-sdk/opends/src/quicksetup/org/opends/quicksetup/uninstaller/Uninstaller.java b/opendj-sdk/opends/src/quicksetup/org/opends/quicksetup/uninstaller/Uninstaller.java
index 10787f8..53ea429 100644
--- a/opendj-sdk/opends/src/quicksetup/org/opends/quicksetup/uninstaller/Uninstaller.java
+++ b/opendj-sdk/opends/src/quicksetup/org/opends/quicksetup/uninstaller/Uninstaller.java
@@ -28,10 +28,12 @@
 package org.opends.quicksetup.uninstaller;
 
 import java.io.BufferedReader;
+import java.io.ByteArrayOutputStream;
 import java.io.File;
 import java.io.FileFilter;
 import java.io.IOException;
 import java.io.InputStreamReader;
+import java.io.PrintStream;
 import java.util.ArrayList;
 import java.util.HashMap;
 import java.util.HashSet;
@@ -46,6 +48,8 @@
 import org.opends.quicksetup.util.ProgressMessageFormatter;
 import org.opends.quicksetup.util.Utils;
 
+import org.opends.server.tools.ConfigureWindowsService;
+
 /**
  * This class is in charge of performing the uninstallation of Open DS.
  *
@@ -66,6 +70,8 @@
 
   private UninstallException ue;
 
+  private Boolean isWindowsServiceEnabled;
+
   /**
    * Uninstaller constructor.
    * @param userData the object containing the information provided by the user
@@ -149,6 +155,8 @@
         getFormattedSummary(getMsg("summary-uninstall-not-started")));
     hmSummary.put(UninstallProgressStep.STOPPING_SERVER,
         getFormattedSummary(getMsg("summary-stopping")));
+    hmSummary.put(UninstallProgressStep.DISABLING_WINDOWS_SERVICE,
+        getFormattedSummary(getMsg("summary-disabling-windows-service")));
     hmSummary.put(UninstallProgressStep.DELETING_EXTERNAL_DATABASE_FILES,
         getFormattedSummary(getMsg("summary-deleting-external-db-files")));
     hmSummary.put(UninstallProgressStep.DELETING_EXTERNAL_LOG_FILES,
@@ -163,7 +171,16 @@
     {
       if (userData.getRemoveLibrariesAndTools())
       {
-        String[] arg = {getLibrariesPath()};
+        String[] arg = new String[1];
+        if (Utils.isWindows())
+        {
+            arg[0] = getUninstallBatFile()+getLineBreak()+
+            getTab()+getLibrariesPath();
+        }
+        else
+        {
+            arg[0] = getLibrariesPath();
+        }
         successMsg = getMsg(
             "summary-uninstall-finished-successfully-remove-jarfiles-cli",
             arg);
@@ -201,6 +218,7 @@
     HashMap<UninstallProgressStep, Integer> hmTime =
         new HashMap<UninstallProgressStep, Integer>();
     hmTime.put(UninstallProgressStep.STOPPING_SERVER, 15);
+    hmTime.put(UninstallProgressStep.DISABLING_WINDOWS_SERVICE, 5);
     hmTime.put(UninstallProgressStep.DELETING_EXTERNAL_DATABASE_FILES, 30);
     hmTime.put(UninstallProgressStep.DELETING_EXTERNAL_LOG_FILES, 5);
     hmTime.put(UninstallProgressStep.REMOVING_EXTERNAL_REFERENCES, 5);
@@ -214,6 +232,11 @@
       totalTime += hmTime.get(UninstallProgressStep.STOPPING_SERVER);
       steps.add(UninstallProgressStep.STOPPING_SERVER);
     }
+    if (isWindowsServiceEnabled())
+    {
+      totalTime += hmTime.get(UninstallProgressStep.DISABLING_WINDOWS_SERVICE);
+      steps.add(UninstallProgressStep.DISABLING_WINDOWS_SERVICE);
+    }
     totalTime += hmTime.get(UninstallProgressStep.DELETING_INSTALLATION_FILES);
     steps.add(UninstallProgressStep.DELETING_INSTALLATION_FILES);
 
@@ -482,8 +505,18 @@
    */
   private void doUninstall()
   {
+    PrintStream origErr = System.err;
+    PrintStream origOut = System.out;
     try
     {
+      PrintStream err = new ErrorPrintStream();
+      PrintStream out = new OutputPrintStream();
+      if (!Utils.isCli())
+      {
+          System.setErr(err);
+          System.setOut(out);
+      }
+
       boolean displaySeparator = false;
       if (getUserData().getStopServer())
       {
@@ -491,6 +524,12 @@
         stopServer();
         displaySeparator = true;
       }
+      if (isWindowsServiceEnabled())
+      {
+        status = UninstallProgressStep.DISABLING_WINDOWS_SERVICE;
+        disableWindowsService();
+        displaySeparator = true;
+      }
 
       Set<String> dbsToDelete = getUserData().getExternalDbsToRemove();
       if (dbsToDelete.size() > 0)
@@ -562,6 +601,11 @@
       String msg = getFormattedError(ue, true);
       notifyListeners(msg);
     }
+    if (!Utils.isCli())
+    {
+        System.setErr(origErr);
+        System.setOut(origOut);
+    }
   }
 
   /**
@@ -882,6 +926,43 @@
   }
 
   /**
+   * Returns the path to the quicksetup jar file.
+   * @return the path to the quicksetup jar file.
+   */
+  private String getQuicksetupJarPath()
+  {
+    return Utils.getPath(getLibrariesPath(), "quicksetup.jar");
+  }
+
+  /**
+   * Returns the path to the opends jar file.
+   * @return the path to the opends jar file.
+   */
+  private String getOpenDSJarPath()
+  {
+    return Utils.getPath(getLibrariesPath(), "OpenDS.jar");
+  }
+
+  /**
+   * Returns the path to the aspectj jar file.
+   * @return the path to the aspectj jar file.
+   */
+  private String getAspectJJarPath()
+  {
+    return Utils.getPath(getLibrariesPath(), "aspectjrt.jar");
+  }
+
+
+  /**
+   * Returns the path to the uninstall.bat file.
+   * @return the path to the uninstall.bat file.
+   */
+  private String getUninstallBatFile()
+  {
+    return Utils.getPath(Utils.getInstallPathFromClasspath(), "uninstall.bat");
+  }
+
+  /**
    * Returns the path to the backup files under the install path.
    * @return the path to the backup files under the install path.
    */
@@ -1142,8 +1223,12 @@
    */
   class InstallationFilesToDeleteFilter implements FileFilter
   {
+    File quicksetupFile = new File(getQuicksetupJarPath());
+    File openDSFile = new File(getOpenDSJarPath());
     File librariesFile = new File(getLibrariesPath());
 
+    File uninstallBatFile = new File(getUninstallBatFile());
+
     File installationPath = new File(Utils.getInstallPathFromClasspath());
     /**
      * {@inheritDoc}
@@ -1171,8 +1256,15 @@
       };
 
      boolean accept =
-          !installationPath.equals(file)&&
-          !equalsOrDescendant(file, librariesFile);
+          !installationPath.equals(file)
+              && !librariesFile.equals(file)
+              && !quicksetupFile.equals(file)
+              && !openDSFile.equals(file);
+
+     if (accept && Utils.isWindows() && Utils.isCli())
+     {
+         accept = !uninstallBatFile.equals(file);
+     }
 
      for (int i=0; i<uData.length && accept; i++)
      {
@@ -1183,4 +1275,162 @@
      return accept;
     }
   }
+
+  private boolean isWindowsServiceEnabled()
+  {
+    if (isWindowsServiceEnabled == null)
+    {
+      if (ConfigureWindowsService.serviceState(null, null) ==
+          ConfigureWindowsService.SERVICE_STATE_ENABLED)
+      {
+        isWindowsServiceEnabled = Boolean.TRUE;
+      }
+      else
+      {
+        isWindowsServiceEnabled = Boolean.FALSE;
+      }
+    }
+    return isWindowsServiceEnabled.booleanValue();
+  }
+
+  /**
+   * This methods disables this server as a Windows service.
+   * @throws UninstallException if something goes wrong.
+   */
+  protected void disableWindowsService() throws UninstallException
+  {
+    notifyListeners(getFormattedProgress(
+      getMsg("progress-disabling-windows-service")));
+    int code = ConfigureWindowsService.disableService(System.out, System.err);
+
+    String errorMessage = getMsg("error-disabling-windows-service");
+
+    switch (code)
+    {
+      case ConfigureWindowsService.SERVICE_DISABLE_SUCCESS:
+      break;
+      case ConfigureWindowsService.SERVICE_ALREADY_DISABLED:
+      break;
+      default:
+      throw new UninstallException(
+      UninstallException.Type.WINDOWS_SERVICE_ERROR, errorMessage, null);
+    }
+  }
+
+  /**
+   * This class is used to notify the UninstallProgressUpdateListeners of events
+   * that are written to the standard error.  These classes just create an
+   * ErrorPrintStream and then they do a call to System.err with it.
+   *
+   * The class just reads what is written to the standard error, obtains an
+   * formatted representation of it and then notifies the
+   * UninstallProgressUpdateListeners with the formatted messages.
+   *
+   */
+  protected class ErrorPrintStream extends PrintStream
+  {
+    private boolean isFirstLine;
+
+    /**
+     * Default constructor.
+     *
+     */
+    public ErrorPrintStream()
+    {
+      super(new ByteArrayOutputStream(), true);
+      isFirstLine = true;
+    }
+
+    /**
+     * {@inheritDoc}
+     */
+    public void println(String msg)
+    {
+      if (isFirstLine)
+      {
+        notifyListeners(getFormattedLogError(msg));
+      } else
+      {
+        notifyListeners(formatter.getLineBreak() + getFormattedLogError(msg));
+      }
+      isFirstLine = false;
+    }
+
+    /**
+     * {@inheritDoc}
+     */
+    public void write(byte[] b, int off, int len)
+    {
+      if (b == null)
+      {
+        throw new NullPointerException("b is null");
+      }
+
+      if (off + len > b.length)
+      {
+        throw new IndexOutOfBoundsException(
+            "len + off are bigger than the length of the byte array");
+      }
+      println(new String(b, off, len));
+    }
+  }
+
+  /**
+   * This class is used to notify the UninstallProgressUpdateListeners of events
+   * that are written to the standard output.  These classes just create an
+   * OutputPrintStream and then they do a call to System.out with it.
+   *
+   * The class just reads what is written to the standard output, obtains an
+   * formatted representation of it and then notifies the
+   * UninstallProgressUpdateListeners with the formatted messages.
+   *
+   */
+  protected class OutputPrintStream extends PrintStream
+  {
+    private boolean isFirstLine;
+
+    /**
+     * Default constructor.
+     *
+     */
+    public OutputPrintStream()
+    {
+      super(new ByteArrayOutputStream(), true);
+      isFirstLine = true;
+    }
+
+    /**
+     * {@inheritDoc}
+     */
+    public void println(String msg)
+    {
+      if (isFirstLine)
+      {
+        notifyListeners(getFormattedLog(msg));
+      } else
+      {
+        notifyListeners(formatter.getLineBreak() + getFormattedLog(msg));
+      }
+      isFirstLine = false;
+    }
+
+    /**
+     * {@inheritDoc}
+     */
+    public void write(byte[] b, int off, int len)
+    {
+      if (b == null)
+      {
+        throw new NullPointerException("b is null");
+      }
+
+      if (off + len > b.length)
+      {
+        throw new IndexOutOfBoundsException(
+            "len + off are bigger than the length of the byte array");
+      }
+
+      println(new String(b, off, len));
+    }
+  }
 }
diff --git a/opendj-sdk/opends/src/server/org/opends/server/core/DirectoryServer.java b/opendj-sdk/opends/src/server/org/opends/server/core/DirectoryServer.java
index 7ee531b..bb0b5a8 100644
--- a/opendj-sdk/opends/src/server/org/opends/server/core/DirectoryServer.java
+++ b/opendj-sdk/opends/src/server/org/opends/server/core/DirectoryServer.java
@@ -127,6 +127,7 @@
 import org.opends.server.schema.TelephoneNumberEqualityMatchingRule;
 import org.opends.server.schema.TelephoneNumberSubstringMatchingRule;
 import org.opends.server.schema.TelephoneNumberSyntax;
+import org.opends.server.tools.ConfigureWindowsService;
 import org.opends.server.types.AcceptRejectWarn;
 import org.opends.server.types.AttributeType;
 import org.opends.server.types.AttributeUsage;
@@ -154,6 +155,7 @@
 import org.opends.server.types.Schema;
 import org.opends.server.types.WritabilityMode;
 import org.opends.server.util.MultiOutputStream;
+import org.opends.server.util.SetupUtils;
 import org.opends.server.util.TimeThread;
 import org.opends.server.util.Validator;
 import org.opends.server.util.args.ArgumentException;
@@ -205,6 +207,43 @@
   private static boolean serverLocked = false;
 
 
+  /**
+   * Return codes used when the hidden option --checkStartability is used.
+   * NOTE: when checkstartability is specified is recommended not to allocate
+   * a lot of memory for the JVM (Using -Xms and -Xmx options) as there might
+   * be calls to Runtime.exec.
+   */
+  /**
+   * Returned when the user specified the --checkStartability option with other
+   * options like printing the usage, dumping messages, displaying version, etc.
+   */
+  private static int NOTHING_TO_DO = 0;
+  /**
+   * Returned when the user specified the --checkStartability option with
+   * some incompatible arguments.
+   */
+  private static int CHECK_ERROR = 1;
+  /**
+   * The server is already started.
+   */
+  private static int SERVER_ALREADY_STARTED = 98;
+  /**
+   * The server must be started as detached process.
+   */
+  private static int START_AS_DETACH = 99;
+  /**
+   * The server must be started as a non-detached process.
+   */
+  private static int START_AS_NON_DETACH = 100;
+  /**
+   * The server must be started as a window service.
+   */
+  private static int START_AS_WINDOWS_SERVICE = 101;
+  /**
+   * The server must be started as detached and it is being called from the
+   * Windows Service.
+   */
+  private static int START_AS_DETACH_CALLED_FROM_WINDOWS_SERVICE = 102;
 
   // The policy to use regarding single structural objectclass enforcement.
   private AcceptRejectWarn singleStructuralClassPolicy;
@@ -2539,8 +2578,6 @@
     }
   }
 
-
-
   /**
    * Retrieves the time that the Directory Server was started, in milliseconds
    * since the epoch.
@@ -7662,6 +7699,7 @@
   {
     // Define the arguments that may be provided to the server.
     BooleanArgument checkStartability = null;
+    BooleanArgument windowsNetStart   = null;
     BooleanArgument displayUsage      = null;
     BooleanArgument dumpMessages      = null;
     BooleanArgument fullVersion       = null;
@@ -7705,6 +7743,12 @@
       checkStartability.setHidden(true);
       argParser.addArgument(checkStartability);
 
+      windowsNetStart = new BooleanArgument("windowsnetstart", null,
+                              "windowsNetStart",
+                              MSGID_DSCORE_DESCRIPTION_WINDOWS_NET_START);
+      windowsNetStart.setHidden(true);
+      argParser.addArgument(windowsNetStart);
+
 
       version = new BooleanArgument("version", 'v', "version",
                                     MSGID_DSCORE_DESCRIPTION_VERSION);
@@ -7782,14 +7826,15 @@
       //   something else like display the version number.  In that case, we
       //   don't need to write the PID file at all and can just execute the
       //   intended command.  If that command was successful, then we'll have an
-      //   exit code of 0.  Otherwise, it will have an exit code that is
-      //   something other than 0, 98, or 99 to indicate that a problem
-      // occurred.
+      //   exit code of NOTHING_TO_DO (0).  Otherwise, it will have an exit code
+      //   that is something other than NOTHING_TO_DO, SERVER_ALREADY_STARTED,
+      //   START_AS_DETACH, START_AS_NON_DETACH, START_AS_WINDOWS_SERVICE to
+      //   indicate that a problem occurred.
       if (argParser.usageDisplayed())
       {
         // We're just trying to display usage, and that's already been done so
         // exit with a code of zero.
-        System.exit(0);
+        System.exit(NOTHING_TO_DO);
       }
       else if (fullVersion.isPresent() || version.isPresent() ||
                systemInfo.isPresent() || dumpMessages.isPresent())
@@ -7808,44 +7853,11 @@
         String[] newArgs = new String[newArgList.size()];
         newArgList.toArray(newArgs);
         main(newArgs);
-        System.exit(0);
+        System.exit(NOTHING_TO_DO);
       }
       else
       {
-        // We're trying to start the server, so see if it's already running by
-        // trying to grab an exclusive lock on the server lock file.  If it
-        // succeeds, then the server isn't running and we can try to start.
-        // Otherwise, the server is running and this attempt should fail.
-        String lockFile = LockFileManager.getServerLockFileName();
-        try
-        {
-          StringBuilder failureReason = new StringBuilder();
-          if (LockFileManager.acquireExclusiveLock(lockFile, failureReason))
-          {
-            // The server isn't running, so it can be started.
-            LockFileManager.releaseLock(lockFile, failureReason);
-            System.exit(99);
-          }
-          else
-          {
-            // The server's already running.
-            int    msgID   = MSGID_CANNOT_ACQUIRE_EXCLUSIVE_SERVER_LOCK;
-            String message = getMessage(msgID, lockFile,
-                                        String.valueOf(failureReason));
-            System.err.println(message);
-            System.exit(98);
-          }
-        }
-        catch (Exception e)
-        {
-          // We'll treat this as if the server is running because we won't
-          // be able to start it anyway.
-          int    msgID   = MSGID_CANNOT_ACQUIRE_EXCLUSIVE_SERVER_LOCK;
-          String message = getMessage(msgID, lockFile,
-                                      stackTraceToSingleLineString(e));
-          System.err.println(message);
-          System.exit(98);
-        }
+        System.exit(checkStartability(argParser));
       }
     }
     else if (argParser.usageDisplayed())
@@ -8159,5 +8171,134 @@
     RDN rdn = RDN.create(cnType, new AttributeValue(cnType, monitorName));
     return monitorRootDN.concat(rdn);
   }
+
+  /**
+   * Returns the error code that we return when we are checking the startability
+   * of the server.
+   * If there are conflicting arguments (like asking to run the server in non
+   * detach mode when the server is configured to run as a window service) it
+   * returns CHECK_ERROR (1).
+   * @param argParser the ArgumentParser with the arguments already parsed.
+   * @return the error code that we return when we are checking the startability
+   * of the server.
+   */
+  private static int checkStartability(ArgumentParser argParser)
+  {
+    int returnValue;
+    boolean isServerRunning;
+
+    BooleanArgument noDetach =
+      (BooleanArgument)argParser.getArgumentForLongID("nodetach");
+    BooleanArgument windowsNetStart =
+      (BooleanArgument)argParser.getArgumentForLongID("windowsnetstart");
+
+    boolean noDetachPresent = noDetach.isPresent();
+    boolean windowsNetStartPresent = windowsNetStart.isPresent();
+
+    // We're trying to start the server, so see if it's already running by
+    // trying to grab an exclusive lock on the server lock file.  If it
+    // succeeds, then the server isn't running and we can try to start.
+    // Otherwise, the server is running and this attempt should fail.
+    String lockFile = LockFileManager.getServerLockFileName();
+    try
+    {
+      StringBuilder failureReason = new StringBuilder();
+      if (LockFileManager.acquireExclusiveLock(lockFile, failureReason))
+      {
+        // The server isn't running, so it can be started.
+        LockFileManager.releaseLock(lockFile, failureReason);
+        isServerRunning = false;
+      }
+      else
+      {
+        // The server's already running.
+        int msgID = MSGID_CANNOT_ACQUIRE_EXCLUSIVE_SERVER_LOCK;
+        String message = getMessage(msgID, lockFile,
+            String.valueOf(failureReason));
+        System.err.println(message);
+        isServerRunning = true;
+      }
+    }
+    catch (Exception e)
+    {
+      // We'll treat this as if the server is running because we won't
+      // be able to start it anyway.
+      int msgID = MSGID_CANNOT_ACQUIRE_EXCLUSIVE_SERVER_LOCK;
+      String message = getMessage(msgID, lockFile,
+          stackTraceToSingleLineString(e));
+      System.err.println(message);
+      isServerRunning = true;
+    }
+
+    if (isServerRunning)
+    {
+      returnValue = SERVER_ALREADY_STARTED;
+    }
+    else
+    {
+      boolean configuredAsService = isRunningAsWindowsService();
+
+      if (configuredAsService)
+      {
+        if (noDetachPresent)
+        {
+          // Conflicting arguments
+          returnValue = CHECK_ERROR;
+          int    msgID   = MSGID_DSCORE_ERROR_NODETACH_AND_WINDOW_SERVICE;
+          String message = getMessage(msgID, (Object[])null);
+
+          System.err.println(message);
+
+        }
+        else
+        {
+          if (windowsNetStartPresent)
+          {
+            // start-ds.bat is being called through net start, so return
+            // START_AS_DETACH_CALLED_FROM_WINDOWS_SERVICE so that the batch
+            // file actually starts the server.
+            returnValue = START_AS_DETACH_CALLED_FROM_WINDOWS_SERVICE;
+          }
+          else
+          {
+            returnValue = START_AS_WINDOWS_SERVICE;
+          }
+        }
+      }
+      else
+      {
+        if (noDetachPresent)
+        {
+          returnValue = START_AS_NON_DETACH;
+        }
+        else
+        {
+          returnValue = START_AS_DETACH;
+        }
+      }
+    }
+    return returnValue;
+  }
+
+  /**
+   * Returns true if this server is configured to run as a windows service.
+   * @return <CODE>true</CODE> if this server is configured to run as a windows
+   * service and <CODE>false</CODE> otherwise.
+   */
+  public static boolean isRunningAsWindowsService()
+  {
+    boolean isRunningAsWindowsService;
+    if (SetupUtils.isWindows())
+    {
+      isRunningAsWindowsService = ConfigureWindowsService.serviceState(null,
+      null) == ConfigureWindowsService.SERVICE_STATE_ENABLED;
+    }
+    else
+    {
+      isRunningAsWindowsService = false;
+    }
+    return isRunningAsWindowsService;
+  }
+
 }
 
diff --git a/opendj-sdk/opends/src/server/org/opends/server/messages/CoreMessages.java b/opendj-sdk/opends/src/server/org/opends/server/messages/CoreMessages.java
index f90d343..6229ac3 100644
--- a/opendj-sdk/opends/src/server/org/opends/server/messages/CoreMessages.java
+++ b/opendj-sdk/opends/src/server/org/opends/server/messages/CoreMessages.java
@@ -5984,8 +5984,6 @@
   public static final int MSGID_DSCORE_DESCRIPTION_CHECK_STARTABILITY =
        CATEGORY_MASK_CORE | SEVERITY_MASK_INFORMATIONAL | 596;
 
-
-
   /**
    * The message ID for the message that will be used if an entry includes an
    * attribute with no values.  This takes two arguments, which are the DN of
@@ -5995,6 +5993,20 @@
        CATEGORY_MASK_CORE | SEVERITY_MASK_MILD_ERROR | 597;
 
 
+  /**
+   * The message ID for the message that will be used when the user asks to run
+   * the server in no-detach mode and the server is configured to run as a
+   * service.  This message does not take arguments.
+   */
+  public static final int MSGID_DSCORE_ERROR_NODETACH_AND_WINDOW_SERVICE =
+       CATEGORY_MASK_CORE | SEVERITY_MASK_FATAL_ERROR | 598;
+
+  /**
+   * The message ID for the message that will be used as the description for the
+   * windowsNetStart command-line argument.  This does not take any arguments.
+   */
+  public static final int MSGID_DSCORE_DESCRIPTION_WINDOWS_NET_START =
+       CATEGORY_MASK_CORE | SEVERITY_MASK_INFORMATIONAL | 599;
 
   /**
    * Associates a set of generic messages with the message IDs defined
@@ -7269,8 +7281,12 @@
                     "information needed by the configuration handler to " +
                     "obtain the Directory Server configuration.");
     registerMessage(MSGID_DSCORE_DESCRIPTION_CHECK_STARTABILITY,
-                    "Used to determine whether to write a server PID file " +
-                    "and attempt to start the server.");
+                    "Used to determine whether a server can be started or not" +
+                    "and the mode to be used to start it.");
+    registerMessage(MSGID_DSCORE_DESCRIPTION_WINDOWS_NET_START,
+                    "Used by the window service code to inform that start-ds "+
+                    "is being called from the window services after a call "+
+                    "to net start");
     registerMessage(MSGID_DSCORE_DESCRIPTION_VERSION,
                     "Display Directory Server version information");
     registerMessage(MSGID_DSCORE_DESCRIPTION_FULLVERSION,
@@ -7290,6 +7306,9 @@
     registerMessage(MSGID_DSCORE_ERROR_PARSING_ARGS,
                     "An error occurred while attempting to parse the " +
                     "provided set of command line arguments:  %s.");
+    registerMessage(MSGID_DSCORE_ERROR_NODETACH_AND_WINDOW_SERVICE,
+                    "OpenDS is configured to run as a window service and it "+
+                    "cannot run in no-detach mode.");
     registerMessage(MSGID_DSCORE_CANNOT_BOOTSTRAP,
                     "An error occurred while attempting to bootstrap the " +
                     "Directory Server:  %s.");
@@ -8154,6 +8173,10 @@
     registerMessage(MSGID_PROXYAUTH_INSUFFICIENT_PRIVILEGES,
                     "You do not have sufficient privileges to use the " +
                     "proxied authorization control.");
+
+    registerMessage(MSGID_PROXYAUTH_INSUFFICIENT_PRIVILEGES,
+                    "You do not have sufficient privileges to use the " +
+                    "proxied authorization control.");
   }
 }
 
diff --git a/opendj-sdk/opends/src/server/org/opends/server/messages/ToolMessages.java b/opendj-sdk/opends/src/server/org/opends/server/messages/ToolMessages.java
index 17bb407..de101c5 100644
--- a/opendj-sdk/opends/src/server/org/opends/server/messages/ToolMessages.java
+++ b/opendj-sdk/opends/src/server/org/opends/server/messages/ToolMessages.java
@@ -7608,7 +7608,6 @@
        CATEGORY_MASK_TOOLS | SEVERITY_MASK_INFORMATIONAL | 799;
 
 
-
   /**
    * The message ID for the message that will be used to prompt the user to
    * enter "yes" or "no".  This does not take any arguments.
@@ -7685,6 +7684,7 @@
   public static final int MSGID_INSTALLDS_PROMPT_JMXPORT =
        CATEGORY_MASK_TOOLS | SEVERITY_MASK_INFORMATIONAL | 809;
 
+
   /**
    * The message ID for the message that will be used to print the result code
    * for an error encountered in a client tool.  This takes two arguments,
@@ -7711,6 +7711,232 @@
   public static final int MSGID_TOOL_MATCHED_DN =
        CATEGORY_MASK_TOOLS | SEVERITY_MASK_SEVERE_ERROR | 812;
 
+  /**
+   * The message ID for the message that will be used to inform that the windows
+   * service name for the OpenDS could not be found. This message takes no
+   * arguments.
+   */
+  public static final int MSGID_WINDOWS_SERVICE_NOT_FOUND =
+       CATEGORY_MASK_TOOLS | SEVERITY_MASK_SEVERE_ERROR | 813;
+
+  /**
+   * The message ID for the message that will be used to inform that the windows
+   * service for OpenDS could not be started. This message takes no arguments.
+   */
+  public static final int MSGID_WINDOWS_SERVICE_START_ERROR =
+       CATEGORY_MASK_TOOLS | SEVERITY_MASK_SEVERE_ERROR | 814;
+
+  /**
+   * The message ID for the message that will be used to inform that the windows
+   * service for OpenDS could not be stopped. This message takes no arguments.
+   */
+  public static final int MSGID_WINDOWS_SERVICE_STOP_ERROR =
+       CATEGORY_MASK_TOOLS | SEVERITY_MASK_SEVERE_ERROR | 815;
+
+  /**
+   * The message ID for the message that will be used as the description for the
+   * configure windows service tool.  This does not take any arguments.
+   */
+  public static final int MSGID_CONFIGURE_WINDOWS_SERVICE_TOOL_DESCRIPTION =
+        CATEGORY_MASK_TOOLS | SEVERITY_MASK_INFORMATIONAL | 816;
+
+  /**
+   * The message ID for the message that will be used as the description of the
+   * showUsage argument.  This does not take any arguments.
+   */
+  public static final int
+        MSGID_CONFIGURE_WINDOWS_SERVICE_DESCRIPTION_SHOWUSAGE =
+        CATEGORY_MASK_TOOLS | SEVERITY_MASK_INFORMATIONAL | 817;
+
+  /**
+   * The message ID for the message that will be used as the description of the
+   * enableService argument.  This does not take any arguments.
+   */
+  public static final int MSGID_CONFIGURE_WINDOWS_SERVICE_DESCRIPTION_ENABLE =
+        CATEGORY_MASK_TOOLS | SEVERITY_MASK_INFORMATIONAL | 818;
+
+  /**
+   * The message ID for the message that will be used as the description of the
+   * disableService argument.  This does not take any arguments.
+   */
+  public static final int MSGID_CONFIGURE_WINDOWS_SERVICE_DESCRIPTION_DISABLE =
+        CATEGORY_MASK_TOOLS | SEVERITY_MASK_INFORMATIONAL | 819;
+
+  /**
+   * The message ID for the message that will be used as the description of the
+   * serviceState argument.  This does not take any arguments.
+   */
+  public static final int MSGID_CONFIGURE_WINDOWS_SERVICE_DESCRIPTION_STATE =
+        CATEGORY_MASK_TOOLS | SEVERITY_MASK_INFORMATIONAL | 820;
+
+  /**
+   * The message ID for the message that will be used if an error occurs while
+   * initializing the command-line arguments.  This takes a single argument,
+   * which is an explanation of the problem that occurred.
+   */
+  public static final int
+        MSGID_CONFIGURE_WINDOWS_SERVICE_CANNOT_INITIALIZE_ARGS =
+        CATEGORY_MASK_TOOLS | SEVERITY_MASK_SEVERE_ERROR | 821;
+
+  /**
+   * The message ID for the message that will be used if an error occurs while
+   * parsing the command-line arguments.  This takes a single argument, which is
+   * an explanation of the problem that occurred.
+   */
+  public static final int MSGID_CONFIGURE_WINDOWS_SERVICE_ERROR_PARSING_ARGS =
+        CATEGORY_MASK_TOOLS | SEVERITY_MASK_SEVERE_ERROR | 822;
+
+  /**
+   * The message ID for the message that will be used if an error occurs if
+   * the user provided too many arguments.  This does not take any argument.
+   */
+  public static final int MSGID_CONFIGURE_WINDOWS_SERVICE_TOO_MANY_ARGS =
+        CATEGORY_MASK_TOOLS | SEVERITY_MASK_SEVERE_ERROR | 823;
+
+  /**
+   * The message ID for the message that will be used if an error occurs if
+   * the user provided too few arguments.  This does not take any argument.
+   */
+  public static final int MSGID_CONFIGURE_WINDOWS_SERVICE_TOO_FEW_ARGS =
+        CATEGORY_MASK_TOOLS | SEVERITY_MASK_SEVERE_ERROR | 824;
+
+  /**
+   * The message ID for the message for the name of the Windows service.
+   * This does not take any argument.
+   */
+  public static final int MSGID_WINDOWS_SERVICE_NAME =
+        CATEGORY_MASK_TOOLS | SEVERITY_MASK_INFORMATIONAL | 825;
+
+  /**
+   * The message ID for the message for the description of the Windows service.
+   * This does take the server path installation as argument.
+   */
+  public static final int MSGID_WINDOWS_SERVICE_DESCRIPTION =
+        CATEGORY_MASK_TOOLS | SEVERITY_MASK_INFORMATIONAL | 826;
+
+  /**
+   * The message ID for the message to inform that the Windows service was
+   * successfully enabled.  This does not take any argument.
+   */
+  public static final int MSGID_WINDOWS_SERVICE_SUCCESSULLY_ENABLED =
+        CATEGORY_MASK_TOOLS | SEVERITY_MASK_INFORMATIONAL | 827;
+
+  /**
+   * The message ID for the message to inform that the Windows service was
+   * already enabled.  This does not take any argument.
+   */
+  public static final int MSGID_WINDOWS_SERVICE_ALREADY_ENABLED =
+        CATEGORY_MASK_TOOLS | SEVERITY_MASK_INFORMATIONAL | 828;
+
+  /**
+   * The message ID for the message to inform that the Windows service name was
+   * already in use.  This does not take any argument.
+   */
+  public static final int MSGID_WINDOWS_SERVICE_NAME_ALREADY_IN_USE =
+        CATEGORY_MASK_TOOLS | SEVERITY_MASK_SEVERE_ERROR | 829;
+
+  /**
+   * The message ID for the message to inform that the Windows service could not
+   * be enabled.  This does not take any argument.
+   */
+  public static final int MSGID_WINDOWS_SERVICE_ENABLE_ERROR =
+        CATEGORY_MASK_TOOLS | SEVERITY_MASK_SEVERE_ERROR | 830;
+
+  /**
+   * The message ID for the message to inform that the Windows service was
+   * successfully disabled.  This does not take any argument.
+   */
+  public static final int MSGID_WINDOWS_SERVICE_SUCCESSULLY_DISABLED =
+        CATEGORY_MASK_TOOLS | SEVERITY_MASK_INFORMATIONAL | 831;
+
+  /**
+   * The message ID for the message to inform that the Windows service was
+   * already disabled.  This does not take any argument.
+   */
+  public static final int MSGID_WINDOWS_SERVICE_ALREADY_DISABLED =
+        CATEGORY_MASK_TOOLS | SEVERITY_MASK_INFORMATIONAL | 832;
+
+  /**
+   * The message ID for the message to inform that the Windows service name was
+   * marked for deletion.  This does not take any argument.
+   */
+  public static final int MSGID_WINDOWS_SERVICE_MARKED_FOR_DELETION =
+        CATEGORY_MASK_TOOLS | SEVERITY_MASK_SEVERE_WARNING | 833;
+
+  /**
+   * The message ID for the message to inform that the Windows service could not
+   * be disabled.  This does not take any argument.
+   */
+  public static final int MSGID_WINDOWS_SERVICE_DISABLE_ERROR =
+        CATEGORY_MASK_TOOLS | SEVERITY_MASK_SEVERE_ERROR | 834;
+
+
+        /**
+   * The message ID for the message to inform that the Windows service is
+   * enabled.  This does take the name of the service as argument.
+   */
+  public static final int MSGID_WINDOWS_SERVICE_ENABLED =
+        CATEGORY_MASK_TOOLS | SEVERITY_MASK_INFORMATIONAL | 835;
+
+  /**
+   * The message ID for the message to inform that the Windows service is
+   * disabled.  This does not take any argument.
+   */
+  public static final int MSGID_WINDOWS_SERVICE_DISABLED =
+        CATEGORY_MASK_TOOLS | SEVERITY_MASK_INFORMATIONAL | 836;
+
+  /**
+   * The message ID for the message to inform that the Windows service state
+   * could not be retrieved.  This does not take any argument.
+   */
+  public static final int MSGID_WINDOWS_SERVICE_STATE_ERROR =
+        CATEGORY_MASK_TOOLS | SEVERITY_MASK_SEVERE_ERROR | 837;
+
+  /**
+   * The message ID for the message that will be used as the description for the
+   * windowsNetStop command-line argument.  This does not take any arguments.
+   */
+  public static final int MSGID_STOPDS_DESCRIPTION_WINDOWS_NET_STOP =
+       CATEGORY_MASK_CORE | SEVERITY_MASK_INFORMATIONAL | 838;
+
+  /**
+   * The message ID for the message that will be used as the description for the
+   * outputFile argument.  It does not take any arguments.
+   */
+  public static final int MSGID_WAIT4DEL_DESCRIPTION_OUTPUT_FILE =
+       CATEGORY_MASK_TOOLS | SEVERITY_MASK_INFORMATIONAL | 839;
+
+  /**
+   * The message ID for the message that will be used if an error occurs while
+   * trying to open the output file for reading.  This takes two arguments,
+   * which are the path to the log file and a message explaining the problem
+   * that occurred.
+   */
+  public static final int MSGID_WAIT4DEL_CANNOT_OPEN_OUTPUT_FILE =
+       CATEGORY_MASK_TOOLS | SEVERITY_MASK_SEVERE_WARNING | 840;
+
+  /**
+   * The message ID for the message that will be used to tell that we are
+   * enabling OpenDS as a Windows service.
+   */
+  public static final int MSGID_INSTALLDS_ENABLING_WINDOWS_SERVICE =
+       CATEGORY_MASK_TOOLS | SEVERITY_MASK_INFORMATIONAL | 841;
+
+
+  /**
+   * The message ID for the message that will be used to ask the user whether to
+   * enable OpenDS as a Windows service or not.  This does not take any
+   * argument.
+   */
+  public static final int MSGID_INSTALLDS_PROMPT_ENABLE_SERVICE =
+       CATEGORY_MASK_TOOLS | SEVERITY_MASK_INFORMATIONAL | 842;
+
+  /**
+   * The message ID for the message for the description of the No Windows
+   * service.  This does not take any argument.
+   */
+  public static final int MSGID_INSTALLDS_DESCRIPTION_NO_WINDOWS_SERVICE =
+      CATEGORY_MASK_TOOLS | SEVERITY_MASK_INFORMATIONAL | 843;
 
 
   /**
@@ -8922,7 +9148,12 @@
                     "Attempt to automatically restart the server once it has " +
                     "stopped");
     registerMessage(MSGID_STOPDS_CHECK_STOPPABILITY,
-                    "Used to determine whether the server is stopped or not.");
+                    "Used to determine whether the server can be stopped "+
+                    "or not and the mode to be used to stop it.");
+    registerMessage(MSGID_STOPDS_DESCRIPTION_WINDOWS_NET_STOP,
+                    "Used by the window service code to inform that stop-ds "+
+                    "is being called from the window services after a call "+
+                    "to net stop");
     registerMessage(MSGID_STOPDS_DESCRIPTION_STOP_TIME,
                     "Time to begin the shutdown in YYYYMMDDhhmmss format " +
                     "(local time)");
@@ -9288,6 +9519,8 @@
     registerMessage(MSGID_INSTALLDS_DESCRIPTION_ROOTPWFILE,
                     "Specifies the path to a file containing the password " +
                     "for the initial root user for the Directory Server.");
+    registerMessage(MSGID_INSTALLDS_DESCRIPTION_NO_WINDOWS_SERVICE,
+                    "Do not enable OpenDS to run as a Windows Service.");
     registerMessage(MSGID_INSTALLDS_DESCRIPTION_HELP,
                     "Displays usage information for this program.");
     registerMessage(MSGID_INSTALLDS_NO_CONFIG_FILE,
@@ -9330,6 +9563,8 @@
     registerMessage(MSGID_INSTALLDS_PROMPT_JMXPORT,
                     "On which port would you like the Directory Server to " +
                     "accept connections from JMX clients?");
+    registerMessage(MSGID_INSTALLDS_PROMPT_ENABLE_SERVICE,
+                    "Enable OpenDS to run as a Windows Service?");
     registerMessage(MSGID_INSTALLDS_CANNOT_BIND_TO_PRIVILEGED_PORT,
                     "ERROR:  Unable to bind to port %d.  This port may " +
                     "already be in use, or you may not have permission to " +
@@ -9418,6 +9653,8 @@
     registerMessage(MSGID_INSTALLDS_CANNOT_CREATE_TEMPLATE_FILE,
                     "ERROR:  Cannot create the template file for generating " +
                     "sample data:  %s.");
+    registerMessage(MSGID_INSTALLDS_ENABLING_WINDOWS_SERVICE,
+                    "Enabling OpenDS as a Windows service....");
 
 
     registerMessage(MSGID_MAKELDIF_TAG_INVALID_ARGUMENT_COUNT,
@@ -9844,6 +10081,9 @@
     registerMessage(MSGID_WAIT4DEL_DESCRIPTION_LOG_FILE,
                     "Specifies the path to a file containing log output to " +
                     "monitor.");
+    registerMessage(MSGID_WAIT4DEL_DESCRIPTION_OUTPUT_FILE,
+                    "Specifies the path to a file to which the command will " +
+                    "write the output.");
     registerMessage(MSGID_WAIT4DEL_DESCRIPTION_TIMEOUT,
                     "The maximum length of time in seconds to wait for the " +
                     "target file to be deleted before exiting.");
@@ -9857,6 +10097,9 @@
                     "arguments:  %s.");
     registerMessage(MSGID_WAIT4DEL_CANNOT_OPEN_LOG_FILE,
                     "WARNING:  Unable to open log file %s for reading:  %s.");
+    registerMessage(MSGID_WAIT4DEL_CANNOT_OPEN_OUTPUT_FILE,
+                    "WARNING:  Unable to open output file %s for writing:  "+
+                    "%s.");
 
 
     registerMessage(MSGID_LDAPCOMPARE_NO_DNS,
@@ -10081,6 +10324,97 @@
                     "Please enter \"yes\" or \"no\":  ");
     registerMessage(MSGID_PROMPTTM_USER_REJECTED,
                     "The server certificate has been rejected by the user.");
+
+    registerMessage(MSGID_WINDOWS_SERVICE_NOT_FOUND,
+                    "Could not find the service name for OpenDS.");
+
+    registerMessage(MSGID_WINDOWS_SERVICE_START_ERROR,
+                    "An unexpected error occurred starting OpenDS as a "+
+                    "windows service");
+
+    registerMessage(MSGID_WINDOWS_SERVICE_STOP_ERROR,
+                    "An unexpected error occurred stopping the OpenDS "+
+                    "windows service");
+
+    registerMessage(MSGID_CONFIGURE_WINDOWS_SERVICE_TOOL_DESCRIPTION,
+                    "This utility may be used to configure OpenDS as a "+
+                    "Windows service.");
+
+    registerMessage(MSGID_CONFIGURE_WINDOWS_SERVICE_DESCRIPTION_SHOWUSAGE,
+                    "Display this usage information.");
+
+    registerMessage(MSGID_CONFIGURE_WINDOWS_SERVICE_DESCRIPTION_ENABLE,
+                    "Enables OpenDS as a Windows service.");
+
+    registerMessage(MSGID_CONFIGURE_WINDOWS_SERVICE_DESCRIPTION_DISABLE,
+                    "Disables OpenDS as a Windows service and stops the "+
+                    "server");
+
+    registerMessage(MSGID_CONFIGURE_WINDOWS_SERVICE_DESCRIPTION_STATE,
+                    "Provides information about the state of OpenDS as a "+
+                    "Windows service.");
+
+    registerMessage(MSGID_CONFIGURE_WINDOWS_SERVICE_CANNOT_INITIALIZE_ARGS,
+                    "An unexpected error occurred while attempting to " +
+                    "initialize the command-line arguments:  %s.");
+
+    registerMessage(MSGID_CONFIGURE_WINDOWS_SERVICE_ERROR_PARSING_ARGS,
+                    "An error occurred while parsing the command-line " +
+                    "arguments:  %s.");
+
+    registerMessage(MSGID_CONFIGURE_WINDOWS_SERVICE_TOO_MANY_ARGS,
+                    "You can only provide one of the following arguments:"+
+                    EOL+"enableService, disableService or serviceState.");
+
+    registerMessage(MSGID_CONFIGURE_WINDOWS_SERVICE_TOO_FEW_ARGS,
+                    "You must provide at least one of the following arguments:"+
+                    EOL+"enableService, disableService or serviceState.");
+
+    registerMessage(MSGID_WINDOWS_SERVICE_NAME,
+                    "OpenDS");
+
+    registerMessage(MSGID_WINDOWS_SERVICE_DESCRIPTION,
+                    "Open source Next Generation Directory Server.  "+
+                    "Installation path: %s");
+
+    registerMessage(MSGID_WINDOWS_SERVICE_SUCCESSULLY_ENABLED,
+                    "OpenDS was successfully enabled as a Windows service.");
+
+    registerMessage(MSGID_WINDOWS_SERVICE_ALREADY_ENABLED,
+                    "OpenDS was already enabled as a Windows service.");
+
+    registerMessage(MSGID_WINDOWS_SERVICE_NAME_ALREADY_IN_USE,
+                    "OpenDS could not enabled as a Windows service.  The "+
+                    "service name is already in use.");
+
+    registerMessage(MSGID_WINDOWS_SERVICE_ENABLE_ERROR,
+                    "An unexpected error occurred trying to enable OpenDS as "+
+                    "a Windows service.");
+
+    registerMessage(MSGID_WINDOWS_SERVICE_SUCCESSULLY_DISABLED,
+                    "OpenDS was successfully disabled as a Windows service.");
+
+    registerMessage(MSGID_WINDOWS_SERVICE_ALREADY_DISABLED,
+                    "OpenDS was already disabled as a Windows service.");
+
+    registerMessage(MSGID_WINDOWS_SERVICE_MARKED_FOR_DELETION,
+                    "OpenDS has been marked for deletion as a Windows "+
+                    "Service.");
+
+    registerMessage(MSGID_WINDOWS_SERVICE_DISABLE_ERROR,
+                    "An unexpected error occurred trying to disable OpenDS as "+
+                    "a Windows service.");
+
+    registerMessage(MSGID_WINDOWS_SERVICE_ENABLED,
+                    "OpenDS is enabled as a Windows service.  The service "+
+                    "name for OpenDS is: %s");
+
+    registerMessage(MSGID_WINDOWS_SERVICE_DISABLED,
+                    "OpenDS is disabled as a Windows service.");
+
+    registerMessage(MSGID_WINDOWS_SERVICE_STATE_ERROR,
+                    "An unexpected error occurred trying to retrieve the "+
+                    "state of OpenDS as a Windows service.");
   }
 }
 
diff --git a/opendj-sdk/opends/src/server/org/opends/server/tools/ConfigureWindowsService.java b/opendj-sdk/opends/src/server/org/opends/server/tools/ConfigureWindowsService.java
new file mode 100644
index 0000000..fd16026
--- /dev/null
+++ b/opendj-sdk/opends/src/server/org/opends/server/tools/ConfigureWindowsService.java
@@ -0,0 +1,612 @@
+/*
+ * CDDL HEADER START
+ *
+ * The contents of this file are subject to the terms of the
+ * Common Development and Distribution License, Version 1.0 only
+ * (the "License").  You may not use this file except in compliance
+ * with the License.
+ *
+ * You can obtain a copy of the license at
+ * trunk/opends/resource/legal-notices/OpenDS.LICENSE
+ * or https://OpenDS.dev.java.net/OpenDS.LICENSE.
+ * See the License for the specific language governing permissions
+ * and limitations under the License.
+ *
+ * When distributing Covered Code, include this CDDL HEADER in each
+ * file and include the License file at
+ * trunk/opends/resource/legal-notices/OpenDS.LICENSE.  If applicable,
+ * add the following below this CDDL HEADER, with the fields enclosed
+ * by brackets "[]" replaced with your own identifying information:
+ *      Portions Copyright [yyyy] [name of copyright owner]
+ *
+ * CDDL HEADER END
+ *
+ *
+ *      Portions Copyright 2007 Sun Microsystems, Inc.
+ */
+
+package org.opends.server.tools;
+
+import java.io.BufferedReader;
+import java.io.File;
+import java.io.InputStreamReader;
+import java.io.IOException;
+import java.io.OutputStream;
+import java.io.PrintStream;
+
+import org.opends.server.core.DirectoryServer;
+import org.opends.server.types.NullOutputStream;
+import org.opends.server.util.args.ArgumentException;
+import org.opends.server.util.args.ArgumentParser;
+import org.opends.server.util.args.BooleanArgument;
+
+import static org.opends.server.messages.MessageHandler.getMessage;
+import static org.opends.server.messages.ToolMessages.*;
+import static org.opends.server.util.ServerConstants.MAX_LINE_WIDTH;
+import static org.opends.server.util.StaticUtils.wrapText;
+
+/**
+  * This class is used to configure the Windows service for this instance on
+  * this machine.
+  * This tool allows to enable and disable OpenDS to run as a Windows service
+  * and allows to know if OpenDS is running as a Windows service or not.
+  */
+public class ConfigureWindowsService
+{
+  /**
+   * The fully-qualified name of this class.
+   */
+  private static final String CLASS_NAME =
+    "org.opends.server.tools.ConfigureWindowsService";
+
+  private static int ERROR = 1;
+
+  /**
+   * Return codes for the method enableService.
+   */
+  /**
+   * The service was successfully enabled.
+   */
+  public static final int SERVICE_ENABLE_SUCCESS = 0;
+  /**
+   * The service was already enabled.
+   */
+  public static final int SERVICE_ALREADY_ENABLED = 1;
+  /**
+   * The service name was already in use.
+   */
+  public static final int SERVICE_NAME_ALREADY_IN_USE = 2;
+  /**
+   * An error occurred enabling the service.
+   */
+  public static final int SERVICE_ENABLE_ERROR = 3;
+
+  /**
+   * Return codes for the method disableService.
+   */
+  /**
+   * The service was successfully disabled.
+   */
+  public static final int SERVICE_DISABLE_SUCCESS = 0;
+  /**
+   * The service was already disabled.
+   */
+  public static final int SERVICE_ALREADY_DISABLED = 1;
+  /**
+   * The service is marked for deletion.
+   */
+  public static final int SERVICE_MARKED_FOR_DELETION = 2;
+  /**
+   * An error occurred disabling the service.
+   */
+  public static final int SERVICE_DISABLE_ERROR = 3;
+
+  /**
+   * Return codes for the method serviceState.
+   */
+  /**
+   * The service is enabled.
+   */
+  public static final int SERVICE_STATE_ENABLED = 0;
+  /**
+   * The service is disabled.
+   */
+  public static final int SERVICE_STATE_DISABLED = 1;
+  /**
+   * An error occurred checking the service state.
+   */
+  public static final int SERVICE_STATE_ERROR = 2;
+
+  /**
+   * Configures the Windows service for this instance on this machine.
+   * This tool allows to enable and disable OpenDS to run as a Windows service
+   * and allows to know if OpenDS is running as a Windows service or not.
+   *
+   * @param  args  The command-line arguments provided to this program.
+   */
+  public static void main(String[] args)
+  {
+    int result = configureWindowsService(args, System.out, System.err);
+
+    System.exit(result);
+  }
+
+  /**
+   * Configures the Windows service for this instance on this machine.
+   * This tool allows to enable and disable OpenDS to run as a Windows service
+   * and allows to know if OpenDS is running as a Windows service or not.
+   *
+   * @param  args  The command-line arguments provided to this program.
+   * @param outStream the stream used to write the standard output.
+   * @param errStream the stream used to write the error output.
+   * @return the integer code describing if the operation could be completed or
+   * not.
+   */
+  public static int configureWindowsService(String[] args,
+      OutputStream outStream, OutputStream errStream)
+  {
+    int returnValue = 0;
+    PrintStream out;
+    if (outStream == null)
+    {
+      out = NullOutputStream.printStream();
+    }
+    else
+    {
+      out = new PrintStream(outStream);
+    }
+
+    PrintStream err;
+    if (errStream == null)
+    {
+      err = NullOutputStream.printStream();
+    }
+    else
+    {
+      err = new PrintStream(errStream);
+    }
+
+//  Define all the arguments that may be used with this program.
+    String toolDescription =
+      getMessage(MSGID_CONFIGURE_WINDOWS_SERVICE_TOOL_DESCRIPTION);
+    ArgumentParser argParser = new ArgumentParser(CLASS_NAME,
+        toolDescription, false);
+    BooleanArgument enableService = null;
+    BooleanArgument disableService = null;
+    BooleanArgument serviceState = null;
+    BooleanArgument showUsage = null;
+
+    try
+    {
+      enableService = new BooleanArgument("enableservice", 'e', "enableService",
+          MSGID_CONFIGURE_WINDOWS_SERVICE_DESCRIPTION_ENABLE);
+      argParser.addArgument(enableService);
+
+      disableService = new BooleanArgument("disableservice", 'd',
+          "disableService",
+          MSGID_CONFIGURE_WINDOWS_SERVICE_DESCRIPTION_DISABLE);
+      argParser.addArgument(disableService);
+
+      serviceState = new BooleanArgument("servicestate", 's',
+          "serviceState",
+          MSGID_CONFIGURE_WINDOWS_SERVICE_DESCRIPTION_STATE);
+      argParser.addArgument(serviceState);
+
+      showUsage = new BooleanArgument("showusage", 'H', "help",
+          MSGID_CONFIGURE_WINDOWS_SERVICE_DESCRIPTION_SHOWUSAGE);
+      argParser.addArgument(showUsage);
+      argParser.setUsageArgument(showUsage, out);
+    }
+    catch (ArgumentException ae)
+    {
+      int msgID   = MSGID_CONFIGURE_WINDOWS_SERVICE_CANNOT_INITIALIZE_ARGS;
+      String message = getMessage(msgID, ae.getMessage());
+
+      err.println(wrapText(message, MAX_LINE_WIDTH));
+      returnValue = ERROR;
+    }
+
+    // Parse the command-line arguments provided to this program.
+    if (returnValue == 0)
+    {
+      try
+      {
+        argParser.parseArguments(args);
+      }
+      catch (ArgumentException ae)
+      {
+        int msgID = MSGID_CONFIGURE_WINDOWS_SERVICE_ERROR_PARSING_ARGS;
+        String message = getMessage(msgID, ae.getMessage());
+
+        err.println(wrapText(message, MAX_LINE_WIDTH));
+        err.println(argParser.getUsage());
+        returnValue = ERROR;
+      }
+    }
+
+    // If we should just display usage information, then it is already done
+    if ((returnValue == 0) && !argParser.usageDisplayed())
+    {
+      /* Check that the user only asked for one argument */
+      int nArgs = 0;
+      if (enableService.isPresent())
+      {
+        nArgs++;
+      }
+      if (disableService.isPresent())
+      {
+        nArgs++;
+      }
+      if (serviceState.isPresent())
+      {
+        nArgs++;
+      }
+      if (nArgs > 1)
+      {
+        int msgID = MSGID_CONFIGURE_WINDOWS_SERVICE_TOO_MANY_ARGS;
+        String message = getMessage(msgID, (Object[])null);
+        err.println(wrapText(message, MAX_LINE_WIDTH));
+        err.println(argParser.getUsage());
+        returnValue = ERROR;
+      }
+      if (nArgs == 0)
+      {
+        int msgID = MSGID_CONFIGURE_WINDOWS_SERVICE_TOO_FEW_ARGS;
+        String message = getMessage(msgID, (Object[])null);
+        err.println(wrapText(message, MAX_LINE_WIDTH));
+        err.println(argParser.getUsage());
+        returnValue = ERROR;
+      }
+    }
+
+    if ((returnValue == 0) && !argParser.usageDisplayed())
+    {
+      if (enableService.isPresent())
+      {
+        returnValue = enableService(out, err);
+      }
+      else if (disableService.isPresent())
+      {
+        returnValue = disableService(out, err);
+      }
+      else
+      {
+        returnValue = serviceState(out, err);
+      }
+    }
+
+    return returnValue;
+  }
+
+  /**
+   * Returns the service name associated with OpenDS or null if no service name
+   * could be found.
+   * @return the service name associated with OpenDS or null if no service name
+   * could be found.
+   */
+  static String getServiceName()
+  {
+    String serviceName = null;
+    String serverRoot = getServerRoot();
+    String[] cmd = {
+        getBinaryFullPath(),
+        "state",
+        serverRoot
+        };
+    try
+    {
+      Process p = Runtime.getRuntime().exec(cmd);
+      BufferedReader stdout = new BufferedReader(
+          new InputStreamReader(p.getInputStream()));
+      boolean processDone = false;
+      String s;
+      while (!processDone)
+      {
+        try
+        {
+          p.exitValue();
+          processDone = true;
+        }
+        catch (Throwable t)
+        {
+        }
+        while ((s = stdout.readLine()) != null)
+        {
+          serviceName = s;
+          if (serviceName.trim().length() == 0)
+          {
+            serviceName = null;
+          }
+        }
+      }
+    }
+    catch (Throwable t)
+    {
+      serviceName = null;
+    }
+
+    return serviceName;
+  }
+
+  /**
+   * Enables OpenDS to run as a windows service.
+   * @param out the stream used to write the standard output.
+   * @param err the stream used to write the error output.
+   * @return <CODE>SERVICE_ENABLE_SUCCESS</CODE>,
+   * <CODE>SERVICE_ENABLE_ERROR</CODE>,
+   * <CODE>SERVICE_NAME_ALREADY_IN_USE</CODE> or
+   * <CODE>SERVICE_ALREADY_ENABLED</CODE> depending on whether the service could
+   * be enabled or not.
+   */
+  public static int enableService(PrintStream out, PrintStream err)
+  {
+    int returnValue;
+    String msg;
+    String serverRoot = getServerRoot();
+
+    String[] cmd = {
+        getBinaryFullPath(),
+        "create",
+        serverRoot,
+        getMessage(MSGID_WINDOWS_SERVICE_NAME, (Object[]) null),
+        getMessage(MSGID_WINDOWS_SERVICE_DESCRIPTION, serverRoot)
+        };
+    try
+    {
+      int resultCode = Runtime.getRuntime().exec(cmd).waitFor();
+      switch (resultCode)
+      {
+      case 0:
+        returnValue = SERVICE_ENABLE_SUCCESS;
+        msg = getMessage(MSGID_WINDOWS_SERVICE_SUCCESSULLY_ENABLED,
+            (Object[])null);
+        out.println(wrapText(msg, MAX_LINE_WIDTH));
+        break;
+      case 1:
+        returnValue = SERVICE_ALREADY_ENABLED;
+        msg = getMessage(MSGID_WINDOWS_SERVICE_ALREADY_ENABLED,
+            (Object[])null);
+        out.println(wrapText(msg, MAX_LINE_WIDTH));
+        break;
+      case 2:
+        returnValue = SERVICE_NAME_ALREADY_IN_USE;
+        msg = getMessage(MSGID_WINDOWS_SERVICE_NAME_ALREADY_IN_USE,
+            (Object[])null);
+        err.println(wrapText(msg, MAX_LINE_WIDTH));
+        break;
+      case 3:
+        returnValue = SERVICE_ENABLE_ERROR;
+        msg = getMessage(MSGID_WINDOWS_SERVICE_ENABLE_ERROR,
+            (Object[])null);
+        err.println(wrapText(msg, MAX_LINE_WIDTH));
+        break;
+      default:
+        returnValue = SERVICE_ENABLE_ERROR;
+        msg = getMessage(MSGID_WINDOWS_SERVICE_ENABLE_ERROR,
+            (Object[])null);
+        err.println(wrapText(msg, MAX_LINE_WIDTH));
+      }
+    }
+    catch (Throwable t)
+    {
+      returnValue = SERVICE_ENABLE_ERROR;
+      msg = getMessage(MSGID_WINDOWS_SERVICE_ENABLE_ERROR,
+          (Object[])null);
+      err.println(wrapText(msg, MAX_LINE_WIDTH));
+    }
+    return returnValue;
+  }
+
+  /**
+   * Disables OpenDS to run as a windows service.
+   * @param out the stream used to write the standard output.
+   * @param err the stream used to write the error output.
+   * @return <CODE>SERVICE_DISABLE_SUCCESS</CODE>,
+   * <CODE>SERVICE_DISABLE_ERROR</CODE>,
+   * <CODE>SERVICE_MARKED_FOR_DELETION</CODE> or
+   * <CODE>SERVICE_ALREADY_DISABLED</CODE> depending on whether the service
+   * could be disabled or not.
+   */
+  public static int disableService(PrintStream out, PrintStream err)
+  {
+    int returnValue;
+    String msg;
+    String serverRoot = getServerRoot();
+    String[] cmd = {
+        getBinaryFullPath(),
+        "remove",
+        serverRoot
+        };
+    try
+    {
+      int resultCode = Runtime.getRuntime().exec(cmd).waitFor();
+      switch (resultCode)
+      {
+      case 0:
+        returnValue = SERVICE_DISABLE_SUCCESS;
+        msg = getMessage(MSGID_WINDOWS_SERVICE_SUCCESSULLY_DISABLED,
+            (Object[])null);
+        out.println(msg);
+        break;
+      case 1:
+        returnValue = SERVICE_ALREADY_DISABLED;
+        msg = getMessage(MSGID_WINDOWS_SERVICE_ALREADY_DISABLED,
+            (Object[])null);
+        out.println(msg);
+        break;
+      case 2:
+        returnValue = SERVICE_MARKED_FOR_DELETION;
+        msg = getMessage(MSGID_WINDOWS_SERVICE_MARKED_FOR_DELETION,
+            (Object[])null);
+        out.println(msg);
+        break;
+      case 3:
+        returnValue = SERVICE_DISABLE_ERROR;
+        msg = getMessage(MSGID_WINDOWS_SERVICE_DISABLE_ERROR,
+            (Object[])null);
+        err.println(msg);
+        break;
+      default:
+        returnValue = SERVICE_DISABLE_ERROR;
+        msg = getMessage(MSGID_WINDOWS_SERVICE_DISABLE_ERROR,
+            (Object[])null);
+        err.println(msg);
+      }
+    }
+    catch (Throwable t)
+    {
+      returnValue = SERVICE_DISABLE_ERROR;
+      msg = getMessage(MSGID_WINDOWS_SERVICE_DISABLE_ERROR,
+          (Object[])null);
+      err.println(msg);
+    }
+    return returnValue;
+  }
+
+  /**
+    * Checks if OpenDS is enabled as a windows service and if it is
+    * write the serviceName in the output stream (if it is not null).
+    * @param out the stream used to write the standard output.
+    * @param err the stream used to write the error output.
+    * @return <CODE>SERVICE_STATE_ENABLED</CODE>,
+    * <CODE>SERVICE_STATE_DISABLED</CODE> or <CODE>SERVICE_STATE_ERROR</CODE>
+    * depending on the state of the service.
+    */
+  public static int serviceState(PrintStream out, PrintStream err)
+  {
+    int returnValue;
+    String msg;
+    String serviceName = null;
+
+    String serverRoot = getServerRoot();
+    String[] cmd = {
+        getBinaryFullPath(),
+        "state",
+        serverRoot
+        };
+    try
+    {
+      int resultCode = -1;
+      ProcessBuilder pb = new ProcessBuilder(cmd);
+      Process process = pb.start();
+
+      BufferedReader stdout =
+          new BufferedReader(new InputStreamReader(process.getInputStream()));
+
+      boolean processDone = false;
+      String s;
+      while (!processDone)
+      {
+        try
+        {
+          resultCode = process.exitValue();
+          processDone = true;
+        }
+        catch (Throwable t)
+        {
+        }
+        while ((s = stdout.readLine()) != null)
+        {
+          if (s.trim().length() != 0)
+          {
+            serviceName = s;
+          }
+        }
+      }
+
+      switch (resultCode)
+      {
+      case 0:
+        returnValue = SERVICE_STATE_ENABLED;
+        if (out != null)
+        {
+          msg = getMessage(MSGID_WINDOWS_SERVICE_ENABLED,
+            serviceName);
+          out.println(msg);
+        }
+        break;
+      case 1:
+        returnValue = SERVICE_STATE_DISABLED;
+        if (out != null)
+        {
+          msg = getMessage(MSGID_WINDOWS_SERVICE_DISABLED,
+            (Object[])null);
+          out.println(msg);
+        }
+        break;
+      case 2:
+        returnValue = SERVICE_STATE_ERROR;
+        if (out != null)
+        {
+          msg = getMessage(MSGID_WINDOWS_SERVICE_STATE_ERROR,
+            (Object[])null);
+          out.println(msg);
+        }
+        break;
+      default:
+        returnValue = SERVICE_STATE_ERROR;
+        if (err != null)
+        {
+          msg = getMessage(MSGID_WINDOWS_SERVICE_STATE_ERROR,
+            (Object[])null);
+          err.println(msg);
+        }
+      }
+    }
+    catch (Throwable t)
+    {
+      returnValue = SERVICE_STATE_ERROR;
+      if (err != null)
+      {
+        msg = getMessage(MSGID_WINDOWS_SERVICE_STATE_ERROR,
+          (Object[])null);
+        err.println(wrapText(msg, MAX_LINE_WIDTH));
+      }
+    }
+    return returnValue;
+  }
+
+  /**
+   * Returns the Directory Server installation path in a user friendly
+   * representation.
+   * @return the Directory Server installation path in a user friendly
+   * representation.
+   */
+  private static String getServerRoot()
+  {
+    String serverRoot = DirectoryServer.getServerRoot();
+    File f = new File(serverRoot);
+    try
+    {
+      /*
+       * Do a best effort to avoid having a relative representation (for
+       * instance to avoid having ../../../).
+       */
+      File canonical = f.getCanonicalFile();
+      f = canonical;
+    }
+    catch (IOException ioe)
+    {
+      /* This is a best effort to get the best possible representation of the
+       * file: reporting the error is not necessary.
+       */
+    }
+    serverRoot = f.toString();
+    if (serverRoot.endsWith(File.separator))
+    {
+      serverRoot = serverRoot.substring(0, serverRoot.length() - 1);
+    }
+    return serverRoot;
+  }
+
+  /**
+   * Returns the full path of the executable used by this class to perform
+   * operations related to the service.
+   * @return the full path of the executable used by this class to perform
+   * operations related to the service.
+   */
+  private static String getBinaryFullPath()
+  {
+    return getServerRoot()+"\\lib\\opends_service.exe";
+  }
+}
diff --git a/opendj-sdk/opends/src/server/org/opends/server/tools/InstallDS.java b/opendj-sdk/opends/src/server/org/opends/server/tools/InstallDS.java
index 5399c19..86b1314 100644
--- a/opendj-sdk/opends/src/server/org/opends/server/tools/InstallDS.java
+++ b/opendj-sdk/opends/src/server/org/opends/server/tools/InstallDS.java
@@ -177,6 +177,7 @@
     BooleanArgument   showUsage;
     BooleanArgument   silentInstall;
     BooleanArgument   skipPortCheck;
+    BooleanArgument   noWindowsService;
     FileBasedArgument rootPWFile;
     IntegerArgument   ldapPort;
     IntegerArgument   jmxPort;
@@ -278,6 +279,14 @@
                             null, null, MSGID_INSTALLDS_DESCRIPTION_ROOTPWFILE);
       argParser.addArgument(rootPWFile);
 
+      noWindowsService = new BooleanArgument("nowindowsservice", 'n',
+                                "noWindowsService",
+                                MSGID_INSTALLDS_DESCRIPTION_NO_WINDOWS_SERVICE);
+      if (SetupUtils.isWindows())
+      {
+        argParser.addArgument(noWindowsService);
+      }
+
       showUsage = new BooleanArgument("help", 'H', "help",
                                       MSGID_INSTALLDS_DESCRIPTION_HELP);
       argParser.addArgument(showUsage);
@@ -790,6 +799,24 @@
       }
     }
 
+    boolean enableService = false;
+    // If we are in Windows ask if the server must run as a windows service.
+    if (SetupUtils.isWindows())
+    {
+      if (silentInstall.isPresent())
+      {
+        enableService = !noWindowsService.isPresent();
+      }
+      else if (noWindowsService.isPresent())
+      {
+        enableService = false;
+      }
+      else
+      {
+        String message = getMessage(MSGID_INSTALLDS_PROMPT_ENABLE_SERVICE);
+        enableService = promptForBoolean(message, Boolean.TRUE);
+      }
+    }
 
     // At this point, we should be able to invoke the ConfigureDS utility to
     // apply the requested configuration.
@@ -976,6 +1003,24 @@
       SetupUtils.writeSetJavaHome(serverRoot);
     } catch (Exception e) {}
 
+    if (enableService)
+    {
+      String message = getMessage(MSGID_INSTALLDS_ENABLING_WINDOWS_SERVICE);
+      System.out.println(wrapText(message, MAX_LINE_WIDTH));
+      int code = ConfigureWindowsService.enableService(System.out,
+          System.err);
+
+      switch (code)
+      {
+      case ConfigureWindowsService.SERVICE_ENABLE_SUCCESS:
+        break;
+      case ConfigureWindowsService.SERVICE_ALREADY_ENABLED:
+        break;
+      default:
+        // It did not work.
+        return code;
+      }
+    }
 
     // If we've gotten here, then everything seems to have gone smoothly.
     if (! silentInstall.isPresent())
diff --git a/opendj-sdk/opends/src/server/org/opends/server/tools/StartWindowsService.java b/opendj-sdk/opends/src/server/org/opends/server/tools/StartWindowsService.java
new file mode 100644
index 0000000..043f704
--- /dev/null
+++ b/opendj-sdk/opends/src/server/org/opends/server/tools/StartWindowsService.java
@@ -0,0 +1,142 @@
+/*
+ * CDDL HEADER START
+ *
+ * The contents of this file are subject to the terms of the
+ * Common Development and Distribution License, Version 1.0 only
+ * (the "License").  You may not use this file except in compliance
+ * with the License.
+ *
+ * You can obtain a copy of the license at
+ * trunk/opends/resource/legal-notices/OpenDS.LICENSE
+ * or https://OpenDS.dev.java.net/OpenDS.LICENSE.
+ * See the License for the specific language governing permissions
+ * and limitations under the License.
+ *
+ * When distributing Covered Code, include this CDDL HEADER in each
+ * file and include the License file at
+ * trunk/opends/resource/legal-notices/OpenDS.LICENSE.  If applicable,
+ * add the following below this CDDL HEADER, with the fields enclosed
+ * by brackets "[]" replaced with your own identifying information:
+ *      Portions Copyright [yyyy] [name of copyright owner]
+ *
+ * CDDL HEADER END
+ *
+ *
+ *      Portions Copyright 2007 Sun Microsystems, Inc.
+ */
+
+package org.opends.server.tools;
+
+import java.io.OutputStream;
+import java.io.PrintStream;
+
+import org.opends.server.types.NullOutputStream;
+
+import static org.opends.server.messages.MessageHandler.getMessage;
+import static org.opends.server.messages.ToolMessages.*;
+
+/**
+  * This class is used to start the Windows service associated with this
+  * instance on this machine.
+  * This tool allows to start OpenDS and to make it run as a Windows service.
+  */
+public class StartWindowsService
+{
+  /**
+    * The service was successfully started.
+    */
+  private static int SERVICE_START_SUCCESSFUL = 0;
+  /**
+    * The service could not be found.
+    */
+  private static int SERVICE_NOT_FOUND = 1;
+
+  /**
+    * The service could not be started.
+    */
+  private static int SERVICE_START_ERROR = 2;
+
+  /**
+   * Invokes the net start on the service corresponding to this server.
+   *
+   * @param  args  The command-line arguments provided to this program.
+   */
+  public static void main(String[] args)
+  {
+    int result = startWindowsService(System.out, System.err);
+
+    System.exit(result);
+  }
+
+  /**
+   * Invokes the net start on the service corresponding to this server, it
+   * writes information and error messages in the provided streams.
+   * @return <CODE>SERVICE_START_SUCCESSFUL</CODE>,
+   * <CODE>SERVICE_NOT_FOUND</CODE>, <CODE>SERVICE_ALREADY_STARTED</CODE> or
+   * <CODE>SERVICE_START_ERROR</CODE> depending on whether the service could be
+   * stopped or not.
+   * @param  outStream  The stream to write standard output messages.
+   * @param  errStream  The stream to write error messages.
+   */
+  public static int startWindowsService(OutputStream outStream,
+                           OutputStream errStream)
+  {
+    int returnValue;
+    PrintStream out;
+    if (outStream == null)
+    {
+      out = NullOutputStream.printStream();
+    }
+    else
+    {
+      out = new PrintStream(outStream);
+    }
+
+    PrintStream err;
+    if (errStream == null)
+    {
+      err = NullOutputStream.printStream();
+    }
+    else
+    {
+      err = new PrintStream(errStream);
+    }
+
+    String serviceName = ConfigureWindowsService.getServiceName();
+    if (serviceName == null)
+    {
+      int msgID = MSGID_WINDOWS_SERVICE_NOT_FOUND;
+      String message = getMessage(msgID, (Object[])null);
+      err.println(message);
+      returnValue = SERVICE_NOT_FOUND;
+    }
+    else
+    {
+      String[] cmd = {
+          "net",
+          "start",
+          serviceName
+          };
+      /* Check if is a running service */
+      try
+      {
+        if (Runtime.getRuntime().exec(cmd).waitFor() == 0)
+        {
+          returnValue = SERVICE_START_SUCCESSFUL;
+        }
+        else
+        {
+          returnValue = SERVICE_START_ERROR;
+        }
+      }
+      catch (Throwable t)
+      {
+        int msgID = MSGID_WINDOWS_SERVICE_START_ERROR;
+        String message = getMessage(msgID, (Object[])null);
+        out.println(message);
+        returnValue = SERVICE_START_ERROR;
+      }
+    }
+    return returnValue;
+  }
+}
diff --git a/opendj-sdk/opends/src/server/org/opends/server/tools/StopDS.java b/opendj-sdk/opends/src/server/org/opends/server/tools/StopDS.java
index 1f06a81..598cf35 100644
--- a/opendj-sdk/opends/src/server/org/opends/server/tools/StopDS.java
+++ b/opendj-sdk/opends/src/server/org/opends/server/tools/StopDS.java
@@ -40,6 +40,7 @@
 import java.util.concurrent.atomic.AtomicInteger;
 
 import org.opends.server.controls.ProxiedAuthV2Control;
+import org.opends.server.core.DirectoryServer;
 import org.opends.server.core.LockFileManager;
 import org.opends.server.protocols.asn1.ASN1Element;
 import org.opends.server.protocols.asn1.ASN1Exception;
@@ -58,6 +59,7 @@
 import org.opends.server.tasks.ShutdownTask;
 import org.opends.server.types.Control;
 import org.opends.server.types.NullOutputStream;
+import org.opends.server.util.args.Argument;
 import org.opends.server.util.args.ArgumentException;
 import org.opends.server.util.args.ArgumentParser;
 import org.opends.server.util.args.BooleanArgument;
@@ -84,7 +86,40 @@
    */
   private static final String CLASS_NAME = "org.opends.server.tools.StopDS";
 
-
+  /**
+   * Return codes used when the hidden option --checkStoppability is used.
+   * NOTE: when checkStoppability is specified is recommended not to allocate
+   * a lot of memory for the JVM (Using -Xms and -Xmx options) as there might
+   * be calls to Runtime.exec.
+   */
+  /**
+   * The server is already stopped.
+   */
+  private static int SERVER_ALREADY_STOPPED = 98;
+  /**
+   * The server must be started.
+   */
+  private static int START_SERVER = 99;
+  /**
+   * The server must be stopped using a system call.
+   */
+  private static int STOP_USING_SYSTEM_CALL = 100;
+  /**
+   * The server must be restarted using system calls.
+   */
+  private static int RESTART_USING_SYSTEM_CALL = 101;
+  /**
+   * The server must be stopped using protocol.
+   */
+  private static int STOP_USING_PROTOCOL = 102;
+  /**
+   * The server must be stopped as a window service.
+   */
+  private static int STOP_AS_WINDOW_SERVICE = 103;
+  /**
+   * The server must be restarted as a window service.
+   */
+  private static int RESTART_AS_WINDOW_SERVICE = 104;
 
   /**
    * Invokes the <CODE>stopDS</CODE> method, passing it the provided command
@@ -165,6 +200,7 @@
     ArgumentParser    argParser = new ArgumentParser(CLASS_NAME,
                                                      toolDescription, false);
     BooleanArgument   checkStoppability;
+    BooleanArgument   windowsNetStop;
     BooleanArgument   restart;
     BooleanArgument   showUsage;
     BooleanArgument   trustAll;
@@ -245,6 +281,11 @@
       checkStoppability.setHidden(true);
       argParser.addArgument(checkStoppability);
 
+      windowsNetStop = new BooleanArgument("windowsnetstop", null,
+          "windowsNetStop", MSGID_STOPDS_DESCRIPTION_WINDOWS_NET_STOP);
+      windowsNetStop.setHidden(true);
+      argParser.addArgument(windowsNetStop);
+
       restart = new BooleanArgument("restart", 'R', "restart",
                                     MSGID_STOPDS_DESCRIPTION_RESTART);
       argParser.addArgument(restart);
@@ -340,44 +381,8 @@
 
     if (checkStoppability.isPresent())
     {
-      // This option should only be used if we want to check if the local
-      // server is running or not. If the server is running result code is 98.
-      // If the server is stopped the return code is 99.
-      String lockFile = LockFileManager.getServerLockFileName();
-      try
-        {
-          StringBuilder failureReason = new StringBuilder();
-          if (LockFileManager.acquireExclusiveLock(lockFile, failureReason))
-          {
-            // The server is not running: write a message informing of that
-            // in the standard out (this is not an error message).
-            int    msgID   = MSGID_STOPDS_SERVER_ALREADY_STOPPED;
-            String message = getMessage(msgID, null, null);
-            System.out.println(message);
-            LockFileManager.releaseLock(lockFile, failureReason);
-            System.exit(99);
-          }
-          else
-          {
-            // Display a message informing that we are going to the server.
-            int    msgID   = MSGID_STOPDS_GOING_TO_STOP;
-            String message = getMessage(msgID, null, null);
-            System.out.println(message);
-            // The server is running.
-            System.exit(98);
-          }
-        }
-        catch (Exception e)
-        {
-          // Display a message informing that we are going to the server.
-          int    msgID   = MSGID_STOPDS_GOING_TO_STOP;
-          String message = getMessage(msgID, null, null);
-          System.out.println(message);
-          // Assume that if we cannot acquire the lock file the server is
-          // running.
-          System.exit(98);
-        }
-      }
+      System.exit(checkStoppability(argParser));
+    }
 
     // If both a bind password and bind password file were provided, then return
     // an error.
@@ -750,5 +755,141 @@
 
     return addResponse.getResultCode();
   }
+
+  /**
+   * Returns the error code that we return when we are checking the stoppability
+   * of the server.  This basically tells the invoker what must be done based
+   * on the different parameters passed.
+   * @param argParser the ArgumentParser with the arguments already parsed.
+   * @return the error code that we return when we are checking the stoppability
+   * of the server.
+   */
+  private static int checkStoppability(ArgumentParser argParser)
+  {
+    int returnValue;
+    boolean isServerRunning;
+
+    BooleanArgument restart =
+      (BooleanArgument)argParser.getArgumentForLongID("restart");
+    boolean restartPresent = restart.isPresent();
+    BooleanArgument windowsNetStop =
+      (BooleanArgument)argParser.getArgumentForLongID("windowsnetstop");
+    boolean windowsNetStopPresent = windowsNetStop.isPresent();
+
+    // Check if this is a stop through protocol.
+    LinkedList<Argument> list = argParser.getArgumentList();
+    boolean stopThroughProtocol = false;
+    for (Argument arg: list)
+    {
+      if (!"restart".equals(arg.getName()) &&
+          !"showusage".equals(arg.getName()) &&
+          !"checkstoppability".equals(arg.getName()) &&
+          !"windowsnetstop".equals(arg.getName()))
+      {
+        stopThroughProtocol |= arg.isPresent();
+      }
+    }
+
+    if (stopThroughProtocol)
+    {
+      // Assume that this is done on a remote server and do no more checks.
+      returnValue = STOP_USING_PROTOCOL;
+    }
+    else
+    {
+      String lockFile = LockFileManager.getServerLockFileName();
+      try
+      {
+        StringBuilder failureReason = new StringBuilder();
+        if (LockFileManager.acquireExclusiveLock(lockFile, failureReason))
+        {
+          // The server is not running: write a message informing of that
+          // in the standard out (this is not an error message).
+          int    msgID   = MSGID_STOPDS_SERVER_ALREADY_STOPPED;
+          String message = getMessage(msgID, null, null);
+          System.out.println(message);
+          LockFileManager.releaseLock(lockFile, failureReason);
+          isServerRunning = false;
+        }
+        else
+        {
+          isServerRunning = true;
+        }
+      }
+      catch (Exception e)
+      {
+        // Assume that if we cannot acquire the lock file the server is
+        // running.
+        isServerRunning = true;
+      }
+
+      if (!isServerRunning)
+      {
+        if (restartPresent)
+        {
+          returnValue = START_SERVER;
+        }
+        else
+        {
+          returnValue = SERVER_ALREADY_STOPPED;
+        }
+      }
+      else
+      {
+        boolean configuredAsService =
+          DirectoryServer.isRunningAsWindowsService();
+
+        if (configuredAsService)
+        {
+          if (windowsNetStopPresent)
+          {
+            // stop-ds.bat is being called through net stop, so return
+            // STOP_USING_SYSTEM_CALL or RESTART_USING_SYSTEM_CALL so that the
+            // batch file actually stops the server.
+            if (restartPresent)
+            {
+              returnValue = RESTART_USING_SYSTEM_CALL;
+            }
+            else
+            {
+              returnValue = STOP_USING_SYSTEM_CALL;
+            }
+          }
+          else
+          {
+            if (restartPresent)
+            {
+              returnValue = RESTART_AS_WINDOW_SERVICE;
+            }
+            else
+            {
+              returnValue = STOP_AS_WINDOW_SERVICE;
+            }
+            // Display a message informing that we are going to the server.
+            int    msgID   = MSGID_STOPDS_GOING_TO_STOP;
+            String message = getMessage(msgID, null, null);
+            System.out.println(message);
+          }
+        }
+        else
+        {
+          // Display a message informing that we are going to the server.
+          int    msgID   = MSGID_STOPDS_GOING_TO_STOP;
+          String message = getMessage(msgID, null, null);
+          System.out.println(message);
+
+          if (restartPresent)
+          {
+            returnValue = RESTART_USING_SYSTEM_CALL;
+          }
+          else
+          {
+            returnValue = STOP_USING_SYSTEM_CALL;
+          }
+        }
+      }
+    }
+    return returnValue;
+  }
 }
 
diff --git a/opendj-sdk/opends/src/server/org/opends/server/tools/StopWindowsService.java b/opendj-sdk/opends/src/server/org/opends/server/tools/StopWindowsService.java
new file mode 100644
index 0000000..7ef7aca
--- /dev/null
+++ b/opendj-sdk/opends/src/server/org/opends/server/tools/StopWindowsService.java
@@ -0,0 +1,147 @@
+/*
+ * CDDL HEADER START
+ *
+ * The contents of this file are subject to the terms of the
+ * Common Development and Distribution License, Version 1.0 only
+ * (the "License").  You may not use this file except in compliance
+ * with the License.
+ *
+ * You can obtain a copy of the license at
+ * trunk/opends/resource/legal-notices/OpenDS.LICENSE
+ * or https://OpenDS.dev.java.net/OpenDS.LICENSE.
+ * See the License for the specific language governing permissions
+ * and limitations under the License.
+ *
+ * When distributing Covered Code, include this CDDL HEADER in each
+ * file and include the License file at
+ * trunk/opends/resource/legal-notices/OpenDS.LICENSE.  If applicable,
+ * add the following below this CDDL HEADER, with the fields enclosed
+ * by brackets "[]" replaced with your own identifying information:
+ *      Portions Copyright [yyyy] [name of copyright owner]
+ *
+ * CDDL HEADER END
+ *
+ *
+ *      Portions Copyright 2007 Sun Microsystems, Inc.
+ */
+
+package org.opends.server.tools;
+
+import java.io.OutputStream;
+import java.io.PrintStream;
+
+import org.opends.server.types.NullOutputStream;
+
+import static org.opends.server.messages.MessageHandler.getMessage;
+import static org.opends.server.messages.ToolMessages.*;
+
+
+/**
+  * This class is used to stop the Windows service associated with this
+  * instance on this machine.
+  * This tool allows to stop OpenDS as a Windows service.
+  */
+public class StopWindowsService
+{
+  /**
+    * The service was successfully stopped.
+    */
+  public static int SERVICE_STOP_SUCCESSFUL = 0;
+  /**
+    * The service could not be found.
+    */
+  public static int SERVICE_NOT_FOUND = 1;
+  /**
+    * The service was already stopped.
+    */
+  public static int SERVICE_ALREADY_STOPPED = 2;
+  /**
+    * The service could not be stopped.
+    */
+  public static int SERVICE_STOP_ERROR = 3;
+
+  /**
+   * Invokes the net stop on the service corresponding to this server.
+   *
+   * @param  args  The command-line arguments provided to this program.
+   */
+  public static void main(String[] args)
+  {
+    int result = stopWindowsService(System.out, System.err);
+
+    System.exit(result);
+  }
+
+  /**
+   * Invokes the net stop on the service corresponding to this server, it writes
+   * information and error messages in the provided streams.
+   * @return <CODE>SERVICE_STOP_SUCCESSFUL</CODE>,
+   * <CODE>SERVICE_NOT_FOUND</CODE>, <CODE>SERVICE_ALREADY_STOPPED</CODE> or
+   * <CODE>SERVICE_STOP_ERROR</CODE> depending on whether the service could be
+   * stopped or not.
+   * @param  outStream  The stream to write standard output messages.
+   * @param  errStream  The stream to write error messages.
+   */
+  public static int stopWindowsService(OutputStream outStream,
+                           OutputStream errStream)
+  {
+    int returnValue;
+    PrintStream out;
+    if (outStream == null)
+    {
+      out = NullOutputStream.printStream();
+    }
+    else
+    {
+      out = new PrintStream(outStream);
+    }
+
+    PrintStream err;
+    if (errStream == null)
+    {
+      err = NullOutputStream.printStream();
+    }
+    else
+    {
+      err = new PrintStream(errStream);
+    }
+
+    String serviceName = ConfigureWindowsService.getServiceName();
+    if (serviceName == null)
+    {
+      int msgID = MSGID_WINDOWS_SERVICE_NOT_FOUND;
+      String message = getMessage(msgID, (Object[])null);
+      err.println(message);
+      returnValue = SERVICE_NOT_FOUND;
+    }
+    else
+    {
+      String[] cmd = {
+          "net",
+          "stop",
+          serviceName
+          };
+      /* Check if is a running service */
+      try
+      {
+        if (Runtime.getRuntime().exec(cmd).waitFor() == 0)
+        {
+          returnValue = SERVICE_STOP_SUCCESSFUL;
+        }
+        else
+        {
+          returnValue = SERVICE_STOP_ERROR;
+        }
+      }
+      catch (Throwable t)
+      {
+        int msgID = MSGID_WINDOWS_SERVICE_STOP_ERROR;
+        String message = getMessage(msgID, (Object[])null);
+        out.println(message);
+        returnValue = SERVICE_STOP_ERROR;
+      }
+    }
+    return returnValue;
+  }
+}
+
diff --git a/opendj-sdk/opends/src/server/org/opends/server/tools/WaitForFileDelete.java b/opendj-sdk/opends/src/server/org/opends/server/tools/WaitForFileDelete.java
index 111b11b..a9d9bc4 100644
--- a/opendj-sdk/opends/src/server/org/opends/server/tools/WaitForFileDelete.java
+++ b/opendj-sdk/opends/src/server/org/opends/server/tools/WaitForFileDelete.java
@@ -124,6 +124,7 @@
     IntegerArgument timeout        = null;
     StringArgument  logFilePath    = null;
     StringArgument  targetFilePath = null;
+    StringArgument  outputFilePath = null;
 
     String toolDescription = getMessage(MSGID_WAIT4DEL_TOOL_DESCRIPTION);
     ArgumentParser argParser = new ArgumentParser(CLASS_NAME, toolDescription,
@@ -144,6 +145,13 @@
       argParser.addArgument(logFilePath);
 
 
+      outputFilePath = new StringArgument("outputfile", 'o', "outputFile",
+                                        false, false,
+                                        true, "{path}", null, null,
+                                        MSGID_WAIT4DEL_DESCRIPTION_OUTPUT_FILE);
+      argParser.addArgument(outputFilePath);
+
+
       timeout = new IntegerArgument("timeout", 't', "timeout", true, false,
                                     true, "{seconds}", 60, null, true, 0, false,
                                     0, MSGID_WAIT4DEL_DESCRIPTION_TIMEOUT);
@@ -222,6 +230,35 @@
     }
 
 
+    // If an output file was specified and we could open the log file, open it
+    // and append data to it.
+    RandomAccessFile outputFile = null;
+    long outputFileOffset = 0L;
+    if (logFile != null)
+    {
+      if (outputFilePath.isPresent())
+      {
+        try
+        {
+          File f = new File(outputFilePath.getValue());
+          if (f.exists())
+          {
+            outputFile = new RandomAccessFile(f, "rw");
+            outputFileOffset = outputFile.length();
+            outputFile.seek(outputFileOffset);
+          }
+        }
+        catch (Exception e)
+        {
+          int    msgID   = MSGID_WAIT4DEL_CANNOT_OPEN_OUTPUT_FILE;
+          String message = getMessage(msgID, outputFilePath.getValue(),
+                                    String.valueOf(e));
+          System.err.println(wrapText(message, MAX_LINE_WIDTH));
+
+          outputFile = null;
+        }
+      }
+    }
     // Figure out when to stop waiting.
     long stopWaitingTime;
     try
@@ -257,8 +294,18 @@
             int bytesRead = logFile.read(logBuffer);
             if (bytesRead > 0)
             {
-              System.out.write(logBuffer, 0, bytesRead);
-              System.out.flush();
+              if (outputFile == null)
+              {
+                System.out.write(logBuffer, 0, bytesRead);
+                System.out.flush();
+              }
+              else
+              {
+                // Write on the file.
+                // TODO
+                outputFile.write(logBuffer, 0, bytesRead);
+
+              }
               logFileOffset += bytesRead;
             }
           }
@@ -283,6 +330,14 @@
       }
     }
 
+    if (outputFile != null)
+    {
+      try
+      {
+        outputFile.close();
+      }
+      catch (Throwable t) {}
+    }
 
     if (targetFile.exists())
     {

--
Gitblit v1.10.0