diff --git a/jhbuild/monkeypatch.py b/jhbuild/monkeypatch.py
index b0bded1..ddd1928 100644
--- a/jhbuild/monkeypatch.py
+++ b/jhbuild/monkeypatch.py
@@ -21,6 +21,11 @@ from __future__ import generators
 
 import sys
 
+# Windows lacks all sorts of subprocess features that we need to kludge around
+if sys.platform.startswith('win'):
+    from jhbuild.utils import subprocess_win32
+    sys.modules['subprocess'] = subprocess_win32
+
 # Python < 2.2.1 lacks  True and False constants
 import __builtin__
 if not hasattr(__builtin__, 'True'):
diff --git a/jhbuild/utils/subprocess_win32.py b/jhbuild/utils/subprocess_win32.py
new file mode 100644
index 0000000..3bc4dd5
--- /dev/null
+++ b/jhbuild/utils/subprocess_win32.py
@@ -0,0 +1,124 @@
+# jhbuild - a build script for GNOME 1.x and 2.x
+# Copyright (C) 2001-2006  James Henstridge
+#
+#   subprocess_win32: monkeypatch to make jhbuild work on win32
+#
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 2 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program; if not, write to the Free Software
+# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+
+import os
+import sys
+import subprocess as real_subprocess
+
+PIPE = real_subprocess.PIPE
+STDOUT = real_subprocess.STDOUT
+
+def cmdline2list(cmd_string):
+    """
+    Translate a command line string into a sequence of arguments, with
+    the same rules as subprocess.list2cmdline:
+
+    1) Arguments are delimited by white space, which is either a
+       space or a tab.
+
+    2) A string surrounded by double quotation marks is
+       interpreted as a single argument, regardless of white space
+       or pipe characters contained within.  A quoted string can be
+       embedded in an argument.
+
+    3) A double quotation mark preceded by a backslash is
+       interpreted as a literal double quotation mark.
+
+    4) Backslashes are interpreted literally, unless they
+       immediately precede a double quotation mark.
+
+    5) If backslashes immediately precede a double quotation mark,
+       every pair of backslashes is interpreted as a literal
+       backslash.  If the number of backslashes is odd, the last
+       backslash escapes the next double quotation mark as
+       described in rule 3.
+    """
+
+    cmd_string = cmd_string.strip()
+
+    result = []
+    current_element = ""
+    escape = False
+    in_quotes = False
+    for character in cmd_string:
+        if escape:
+            current_element += character
+            escape = False
+        else:
+            if character=='\\':
+                escape = True
+            elif character=='"':
+                if in_quotes: in_quotes = False
+                else:         in_quotes = True
+            elif (character==' ' or character==9) and not in_quotes:
+                result.append(current_element)
+                current_element = ""
+            else:
+                current_element += character
+    result.append(current_element)
+    return result
+
+list2cmdline = real_subprocess.list2cmdline
+
+class Popen(real_subprocess.Popen):
+    __emulate_close_fds = False
+
+    def __init__(self, command, **kws):
+        #print "monkeypopen IN: ", command, kws
+
+        # command could be string or list - our kludges require list. subprocess 
+        # converts the list back to a string using list2cmdline.
+        if not isinstance(command, list):
+            command = cmdline2list(command)
+
+        # shell executes command using cmd.exe, which is a waste of time. We use sh.exe
+        # to execute programs which look like shell scripts.
+        if 'shell' in kws and kws['shell']:
+            kws['shell'] = False
+
+        # ./ confuses windows, and these are normally shell scripts so use sh.exe
+        if command[0].startswith('./'):
+            command = ['sh', command[0].replace('./','')] + command[1:]
+        else:
+            # check if program has no extension or has .sh extension - it probably 
+            # needs executing by sh rather than by Windows directly
+            for path in os.environ['PATH'].split(os.pathsep):
+                prog = os.path.abspath(os.path.join(path, command[0]))
+                if os.path.exists(prog) or os.path.exists(prog+".sh"):
+                    command = ['sh', '-c', ' '.join([command[0]] + command[1:])]
+                    break
+
+        # close_fds is useless in default subprocess under windows
+        if 'close_fds' in kws and kws['close_fds']:
+            kws['close_fds'] = False
+            self.__emulate_close_fds = True
+
+        #print "monkeypopen OUT: ", command, kws
+
+        real_subprocess.Popen.__init__(self, command, **kws)
+
+    def __del__(self):
+        if self.__emulate_close_fds:
+            for f in self.stdin, self.stdout, self.stderr:
+                # This somehow tells us if we are dealing with a pipe.
+                if isinstance(f, file) and f.name=='<fdopen>':
+                    # Not that it actually matters.
+                    f.close()
+            sys.stdout.flush()
+        real_subprocess.Popen.__del__(self)    
diff --git a/tests/tests.py b/tests/tests.py
index 0a8b009..3375d81 100644
--- a/tests/tests.py
+++ b/tests/tests.py
@@ -64,6 +64,15 @@ __builtin__.__dict__['uencode'] = uencode
 
 import mock
 
+if sys.platform.startswith('win'):
+    import subprocess
+
+    class WindowsTestCase(unittest.TestCase):
+        '''Tests for Windows kludges.'''
+        def testCmdline2List(self):
+            cmd_list = subprocess.cmdline2list('test "no quotes" != \\"no\\ quotes\\"')
+            self.assertEqual (cmd_list, ['test', 'no quotes', '!=', '"no quotes"'])
+
 class ModuleOrderingTestCase(unittest.TestCase):
     '''Module Ordering'''
 
