Fantastic, thanks for sharing this code.  I will definitely have a look.  If it turns out to<br>work for us, would you mind releasing this under a BSD license so we can include<br>it in IPython (BSD open source project)?  In either case, the ideas will be <br>
very helpful to us.<br><br>Cheers,<br><br>Brian<br><div class="h5"><br>
</div><div class="gmail_quote"><blockquote class="gmail_quote" style="border-left: 1px solid rgb(204, 204, 204); margin: 0pt 0pt 0pt 0.8ex; padding-left: 1ex;">It is possible to daemonize a process on Windows. I experimented with<br>

adding that support to the twistd script, but got swamped with other<br>
work and couldn&#39;t finish it. Below is the code that I have so far. You<br>
can save it in a module and call the daemonize() function from your script.<br>
<br>
The process of daemonization is similar to the one on UNIX -- you have<br>
to spawn a child process twice, the first child is responsible for<br>
breaking away from any job objects (somewhat similar to becoming a<br>
session leader on UNIX), becoming a new process group leader and closing<br>
all handles (file descriptors) that might have been inherited.<br>
<br>
The second child has to open dummy std* files and a new (hidden)<br>
console, otherwise the signals stop working. There is a slight<br>
complication with window stations and desktops. Each console creates at<br>
least one window and some other user objects, so we have to create<br>
a separate desktop, or other processes would be able to manipulate them<br>
  and send us arbitrary (Windows) messages.<br>
<br>
Regards,<br>
Ziga<br>
<br>
<br>
<br>
import os<br>
import sys<br>
import msvcrt<br>
<br>
import win32con<br>
import win32process<br>
import win32security<br>
import win32service<br>
<br>
from twisted.python import win32<br>
<br>
<br>
<br>
def getPythonArgs():<br>
     &quot;&quot;&quot;<br>
     Return the list of command line args that were used to start<br>
     the current Python interpreter and were not stored in C{sys.argv}.<br>
<br>
     These are the options that control the Python interpreter itself,<br>
     like the Python executable, optimization level, warning filters,<br>
     division behaviour and literal string handling.<br>
     &quot;&quot;&quot;<br>
     args = [sys.executable]<br>
     for warnoption in sys.warnoptions:<br>
         args.append(&quot;-W&quot;)<br>
         args.append(warnoption)<br>
     if type(1 / 2) is not int:<br>
         args.append(&quot;-Qnew&quot;)<br>
     if type(&quot;&quot;) is not str:<br>
         args.append(&quot;-U&quot;)<br>
     if not __debug__:<br>
         if getPythonArgs.__doc__ is None:<br>
             args.append(&quot;-OO&quot;)<br>
         else:<br>
             args.append(&quot;-O&quot;)<br>
     return args<br>
<br>
<br>
<br>
def daemonize():<br>
     args = [os.path.abspath(__file__)] + sys.argv<br>
     executable = sys.executable<br>
     cmdline = win32.quoteArguments(getPythonArgs() + args)<br>
     inherit = False<br>
<br>
     flags = (win32process.CREATE_BREAKAWAY_FROM_JOB | # session leader<br>
              win32process.CREATE_NEW_PROCESS_GROUP |  # group leader<br>
              win32process.DETACHED_PROCESS) # no controlling terminal<br>
<br>
     info = win32process.STARTUPINFO()<br>
     win32process.CreateProcess(executable, cmdline, None, None,<br>
                                inherit, flags, None, None, info)<br>
     # Do what exec* functions do, let the OS do the cleanup.<br>
     os._exit(0)<br>
<br>
<br>
<br>
def daemonize2():<br>
     args = [sys.argv[1], &quot;--nodaemon&quot;] + sys.argv[2:]<br>
     executable = sys.executable<br>
     cmdline = win32.quoteArguments(getPythonArgs() + args)<br>
     inherit = True<br>
     # create an invisible console<br>
     flags = (win32process.CREATE_NO_WINDOW<br>
     attributes = win32security.SECURITY_ATTRIBUTES()<br>
     attributes.bInheritHandle = True<br>
     station = win32service.CreateWindowStation(None, 0,<br>
                                                win32con.GENERIC_READ |<br>
                                                win32con.GENERIC_WRITE,<br>
                                                attributes)<br>
     station.SetProcessWindowStation()<br>
     sname = win32service.GetUserObjectInformation(station,<br>
                                                   win32service.UOI_NAME)<br>
     dname = str(os.getpid())<br>
     desktop = win32service.CreateDesktop(dname, 0,<br>
                                          win32con.GENERIC_READ |<br>
                                          win32con.GENERIC_WRITE,<br>
                                          attributes)<br>
     desktop.SetThreadDesktop()<br>
     null = os.open(&quot;NUL&quot;, os.O_RDWR)<br>
     handle = msvcrt.get_osfhandle(null)<br>
     info = win32process.STARTUPINFO()<br>
     info.lpDesktop = &quot;%s\\%s&quot; % (sname, dname)<br>
     info.dwFlags = win32process.STARTF_USESTDHANDLES<br>
     info.hStdInput = info.hStdOutput = info.hStdError = handle<br>
     win32process.CreateProcess(executable, cmdline, None, None,<br>
                                inherit, flags, None, None, info)<br>
     # Same as above, exit as fast as possible.<br>
     os._exit(0)<br>
<br>
<br>
<br>
if __name__ == &quot;__main__&quot;:<br>
     daemonize2()<br>
<div><div></div><div class="h5"><br>
_______________________________________________<br>
Twisted-Python mailing list<br>
<a href="mailto:Twisted-Python@twistedmatrix.com">Twisted-Python@twistedmatrix.com</a><br>
<a href="http://twistedmatrix.com/cgi-bin/mailman/listinfo/twisted-python" target="_blank">http://twistedmatrix.com/cgi-bin/mailman/listinfo/twisted-python</a><br>
</div></div></blockquote></div><br>