Avdump GUI: Difference between revisions
Jump to navigation
Jump to search
m (→Introduction) |
No edit summary |
||
Line 13: | Line 13: | ||
==Changelog== | ==Changelog== | ||
<pre> | <pre> | ||
v2.00 - 03.06.2011 | |||
Avdump2 Build 4260 added | |||
rewrote the whole lot and simplified it | |||
v1.07 - 06.04.2008 | v1.07 - 06.04.2008 | ||
Avdump 0.34 added | Avdump 0.34 added | ||
Line 49: | Line 53: | ||
<pre style="font-size: 60%;"> | <pre style="font-size: 60%;"> | ||
import | import sys, os, platform, subprocessw, ConfigParser, string, unicodedata | ||
from time import time | |||
# Import Qt modules | |||
from PyQt4 import QtCore, QtGui | |||
# Import the compiled UI module | |||
from gui import Ui_MainWindow | |||
# Create a class for our main window | |||
class Main(QtGui.QMainWindow): | |||
def __init__(self): | |||
QtGui.QMainWindow.__init__(self) | |||
self._ui = Ui_MainWindow() | |||
self._ui.setupUi(self) | |||
self._filelist = {} | |||
self._paths = {} | |||
self._done_files = [] | |||
self._worker = None | |||
self._export_filename = 'exports/export_' + str(int(time())) + '.txt' | |||
self._allowed_extensions = ('avi', 'mpg', 'mpeg', 'ts', 'm2ts', 'rm', 'rmvb', 'asf', 'wmv', 'mov', 'qt', 'ogm', | |||
'mp4', 'mkv', 'swf', 'flv', 'ogv', 'webm', 'mk3d', 'srt', 'sub', 'ssa', 'smi', 'idx', 'ass', | |||
'txt', 'mks', 'lrc', 'rt', 'tmp', 'js', 'pjs', 'tts', 'xss', 'mp3', 'aac', 'ac3', 'dts', 'wav', | |||
'flac', 'wma', 'mka', 'ra', 'ogg', 'm4a', 'dtshd', 'thd', 'rar', 'zip', 'ace', '7z', 'smil') | |||
tmp = [] | |||
for ext in self._allowed_extensions: | |||
tmp.append('*.' + ext) | |||
self._allowed_extensions_str = "; ".join(tmp) | |||
self._ui.datatable.setSelectionBehavior(QtGui.QAbstractItemView.SelectRows) | |||
self._ui.datatable.setColumnWidth(0, 90) | |||
self._ui.datatable.setColumnWidth(1, 250) | |||
self._ui.datatable.setColumnWidth(2, 40) | |||
self.connect(self._ui.files_button, QtCore.SIGNAL("clicked()"), self._slotFile) | |||
self.connect(self._ui.folder_button, QtCore.SIGNAL("clicked()"), self._slotFolder) | |||
self.connect(self._ui.start_button, QtCore.SIGNAL("clicked()"), self._run) | |||
self.connect(self._ui.stop_button, QtCore.SIGNAL("clicked()"), self._stop) | |||
self.connect(QtGui.QAction(self), QtCore.SIGNAL('triggered()'), QtCore.SLOT('close()')) | |||
self._enable_elements() | |||
self._read_config() | |||
self._read_done() | |||
################################################# | |||
# # | |||
# GUI FUNCTIONS # | |||
# # | |||
################################################# | |||
def _disable_elements(self): | |||
self._ui.username.setDisabled(True) | |||
self._ui.apikey.setDisabled(True) | |||
self._ui.files_button.setDisabled(True) | |||
self._ui.folder_button.setDisabled(True) | |||
self._ui.done.setDisabled(True) | |||
self._ui.exp.setDisabled(True) | |||
self._ui.start_button.setDisabled(True) | |||
self._ui.stop_button.setEnabled(True) | |||
def _enable_elements(self): | |||
self._ui.username.setEnabled(True) | |||
self._ui.apikey.setEnabled(True) | |||
self._ui.files_button.setEnabled(True) | |||
self._ui.folder_button.setEnabled(True) | |||
self._ui.done.setEnabled(True) | |||
self._ui.exp.setEnabled(True) | |||
self._ui.start_button.setEnabled(True) | |||
self._ui.stop_button.setDisabled(True) | |||
def _output_export(self): | |||
self._ui.ed2k_export.setText("".join(file(self._export_filename).readlines())) | |||
def _calculate_progress(self): | |||
if self._ui.datatable.rowCount() == 0: | |||
return 0 | |||
done = 0 | |||
for i in range(self._ui.datatable.rowCount()): | |||
if unicode(self._ui.datatable.item(i,2).text()) == 'done': | |||
done += 1 | |||
return done*100/self._ui.datatable.rowCount() | |||
################################################# | |||
# # | |||
# EVENT HANDLER # | |||
# # | |||
################################################# | |||
def _closeEvent(self,event): | |||
self._stop() | |||
self._write_config() | |||
event.accept() | |||
def _done(self, path): | |||
i = self._paths[path] | |||
item = QtGui.QTableWidgetItem('done') | |||
self._ui.datatable.setItem(i, 2, item) | |||
if self._ui.exp.isChecked(): | |||
self._output_export() | |||
self._ui.progressBar.setValue(self._calculate_progress()) | |||
def _finished(self): | |||
self._paths = {} | |||
self._ui.progressBar.setValue(self._calculate_progress()) | |||
self._worker = None | |||
self._enable_elements() | |||
if self._ui.exp.isChecked(): | |||
self._output_export() | |||
def _stop(self): | |||
if self._worker is not None: | |||
self._worker.stop() | |||
self._output_export() | |||
self._enable_elements() | |||
def _slotFile(self): | |||
files = QtGui.QFileDialog.getOpenFileNames(self, 'File select', os.getcwd(), self._allowed_extensions_str) | |||
for path in files: | |||
self._add_file(unicode(path)) | |||
def | def _slotFolder(self): | ||
path = unicode(QtGui.QFileDialog.getExistingDirectory(self, "Select Directory")) | |||
if path != '': | |||
for root, dir, files in os.walk(path): | |||
for filename in files: | |||
self._add_file(os.path.join(root, filename)) | |||
self. | |||
def | def _add_file(self, fileloc): | ||
if len(fileloc) == 0: | |||
return | |||
elif unicodedata.normalize('NFKC', fileloc) in self._done_files: | |||
return | |||
no = self._ui.datatable.rowCount() | |||
if platform.system().lower() == 'windows': | |||
fileloc = fileloc.replace("/", "\\") | |||
filepath, filename = fileloc.rsplit("\\", 1) | |||
else: | else: | ||
filepath, filename = fileloc.rsplit("/", 1) | |||
tmp, ext = filename.rsplit('.', 1) | |||
self. | if ext not in self._allowed_extensions: | ||
return | |||
if fileloc not in self._filelist.keys(): | |||
self._filelist[fileloc] = 1 | |||
self._ui.datatable.insertRow(no) | |||
item = QtGui.QTableWidgetItem(filepath) | |||
self._ui.datatable.setItem(no, 0, item) | |||
self. | |||
item = QtGui.QTableWidgetItem(filename) | |||
self._ui.datatable.setItem(no, 1, item) | |||
item = QtGui.QTableWidgetItem('new') | |||
self._ui.datatable.setItem(no, 2, item) | |||
self._ui.progressBar.setValue(self._calculate_progress()) | |||
def | def _run(self): | ||
if | if self._ui.datatable.rowCount() == 0: | ||
QtGui.QMessageBox.information(self, "Error!", "No files to scan in list.", QtGui.QMessageBox.Ok) | |||
return | |||
elif not os.path.exists('avdump2cl.exe'): | |||
QtGui.QMessageBox.information(self, "Error!", "Avdump2cl.exe not found.", QtGui.QMessageBox.Ok) | |||
return | |||
paths = [] | |||
for i in range(self._ui.datatable.rowCount()): | |||
if unicode(self._ui.datatable.item(i,2).text()) == 'new': | |||
path = os.path.join(unicode(self._ui.datatable.item(i,0).text()), unicode(self._ui.datatable.item(i,1).text())) | |||
paths.append(path) | |||
self._paths[path] = i | |||
if len(paths) > 0: | |||
self._ui.progressBar.setValue(self._calculate_progress()) | |||
self._disable_elements() | |||
self. | username = unicode(self._ui.username.text()) | ||
self. | apikey = unicode(self._ui.apikey.text()) | ||
done = '' | |||
if self._ui.done.isChecked() is True: | |||
done = '-done:done.txt' | |||
exp = '' | |||
if self._ui.exp.isChecked() is True: | |||
exp = '-exp:' + self._export_filename | |||
self. | |||
self. | self._worker = avdump_worker(username, apikey, done, exp, paths) | ||
self.connect(self._worker, QtCore.SIGNAL("done"), self._done) | |||
self.connect(self._worker, QtCore.SIGNAL("finished"), self._finished) | |||
self._worker.start() | |||
def | ################################################# | ||
# # | |||
# CONFIG READ/WRITE # | |||
# # | |||
self. | ################################################# | ||
def _read_config(self): | |||
if os.path.exists('options.ini'): | |||
config = ConfigParser.ConfigParser() | |||
config.read('options.ini') | |||
self._ui.username.setText(config.get('DEFAULT', 'username')) | |||
self._ui.apikey.setText(config.get('DEFAULT', 'apikey')) | |||
if config.get('DEFAULT', 'done') == '1': | |||
self._ui.done.setChecked(True) | |||
else: | |||
self._ui.done.setChecked(False) | |||
if config.get('DEFAULT', 'exp') == '1': | |||
self._ui.exp.setChecked(True) | |||
else: | |||
self._ui.exp.setChecked(False) | |||
self. | |||
def | def _write_config(self): | ||
self. | config = ConfigParser.ConfigParser() | ||
if self. | config.set("DEFAULT", "username", str(self._ui.username.text())) | ||
config.set("DEFAULT", "apikey", str(self._ui.apikey.text())) | |||
if self._ui.done.isChecked(): | |||
config.set("DEFAULT", "done", 1) | |||
else: | |||
config.set("DEFAULT", "done", 0) | |||
if self._ui.exp.isChecked(): | |||
config.set("DEFAULT", "exp", 1) | |||
else: | else: | ||
config.set("DEFAULT", "exp", 0) | |||
config.write(file("options.ini", "w")) | |||
def | def _read_done(self): | ||
if os.path.exists("done.txt"): | |||
for line in file("done.txt"): | |||
self._done_files.append(unicodedata.normalize('NFKC', line.decode("utf8").strip())) | |||
def | class avdump_worker(QtCore.QThread): | ||
self. | def __init__(self, username, apikey, done, exp, paths): | ||
QtCore.QThread.__init__(self, parent=None) | |||
self._username = username | |||
self._apikey = apikey | |||
self._done = done | |||
self._exp = exp | |||
self._paths = paths | |||
self._was_stopped = False | |||
self._avdump = None | |||
def | def stop(self): | ||
self. | self._was_stopped = True | ||
self._avdump.terminate() | |||
self. | |||
def | def run(self): | ||
self. | for path in self._paths: | ||
if self._was_stopped is True: | |||
break | |||
self._avdump = subprocessw.Popen((u'avdump2cl.exe -ac:%s:%s %s %s "%s"') %(self._username, self._apikey, self._done, self._exp, path)) | |||
self._avdump.communicate() | |||
if self._was_stopped is False: | |||
self.emit(QtCore.SIGNAL('done'), path) | |||
self. | |||
if self._was_stopped is False: | |||
self.emit(QtCore.SIGNAL('finished')) | |||
def main(): | |||
app = QtGui.QApplication(sys.argv) | |||
window=Main() | |||
window.show() | |||
sys.exit(app.exec_()) | |||
if __name__ == | if __name__ == "__main__": | ||
main() | |||
</pre> | </pre> | ||
Line 446: | Line 384: | ||
if startupinfo == None: | if startupinfo == None: | ||
startupinfo = STARTUPINFOW() | startupinfo = STARTUPINFOW() | ||
startupinfo.dwFlags |= subprocess._subprocess.STARTF_USESHOWWINDOW | |||
startupinfo.wShowWindow = subprocess._subprocess.SW_HIDE | |||
else: | else: | ||
raise NotImplementedError("Can't pass startup stuff") | raise NotImplementedError("Can't pass startup stuff") |
Revision as of 13:32, 3 June 2011
Introduction
Note | You have to set an API key in your profile before auto-creqing with Avdump GUI. |
For Vista and Windows 7 permission issues on installation:
- Create a blank .bat file.
- Insert this text into it and modify it to your situation:
"C:\Windows\System32\msiExec.exe" -i "C:\Directory\Where\Located\avdump-gui.msi" - Right click and run the .bat file as administrator.
Changelog
v2.00 - 03.06.2011 Avdump2 Build 4260 added rewrote the whole lot and simplified it v1.07 - 06.04.2008 Avdump 0.34 added fixed a bug with the bufferfield not allowing 16 buffer while that being the default made option o default when no profile exists v1.06 - 12.02.2008 Avdump 0.33 added v1.05 - 13.11.2007 thx to rar for fixing dumping of files with characters in non local codepage v1.04 - 10.11.2007 fix for not being able to dump files with Japanese characters in the filename Avdump 0.32 added and changes implemented v1.03 - 13.05.2007 added the console again fix for log, export and done paths with spaces added parents for the dialogues so they die with the program and can't stay open any more option 9 added (experimental mp3 hashing for ostdb) v1.02 - 13.05.2007 added error and warning dialogue boxes to prevent a couple problems added some exception handling for a few fields v1.01 - 12.05.2007 killed a nasty bug with trailing \ in the scanpath v1.00 - 12.05.2007 Initial release
Source
This GUI was coded purely in python using wxpython for the framework.
import sys, os, platform, subprocessw, ConfigParser, string, unicodedata from time import time # Import Qt modules from PyQt4 import QtCore, QtGui # Import the compiled UI module from gui import Ui_MainWindow # Create a class for our main window class Main(QtGui.QMainWindow): def __init__(self): QtGui.QMainWindow.__init__(self) self._ui = Ui_MainWindow() self._ui.setupUi(self) self._filelist = {} self._paths = {} self._done_files = [] self._worker = None self._export_filename = 'exports/export_' + str(int(time())) + '.txt' self._allowed_extensions = ('avi', 'mpg', 'mpeg', 'ts', 'm2ts', 'rm', 'rmvb', 'asf', 'wmv', 'mov', 'qt', 'ogm', 'mp4', 'mkv', 'swf', 'flv', 'ogv', 'webm', 'mk3d', 'srt', 'sub', 'ssa', 'smi', 'idx', 'ass', 'txt', 'mks', 'lrc', 'rt', 'tmp', 'js', 'pjs', 'tts', 'xss', 'mp3', 'aac', 'ac3', 'dts', 'wav', 'flac', 'wma', 'mka', 'ra', 'ogg', 'm4a', 'dtshd', 'thd', 'rar', 'zip', 'ace', '7z', 'smil') tmp = [] for ext in self._allowed_extensions: tmp.append('*.' + ext) self._allowed_extensions_str = "; ".join(tmp) self._ui.datatable.setSelectionBehavior(QtGui.QAbstractItemView.SelectRows) self._ui.datatable.setColumnWidth(0, 90) self._ui.datatable.setColumnWidth(1, 250) self._ui.datatable.setColumnWidth(2, 40) self.connect(self._ui.files_button, QtCore.SIGNAL("clicked()"), self._slotFile) self.connect(self._ui.folder_button, QtCore.SIGNAL("clicked()"), self._slotFolder) self.connect(self._ui.start_button, QtCore.SIGNAL("clicked()"), self._run) self.connect(self._ui.stop_button, QtCore.SIGNAL("clicked()"), self._stop) self.connect(QtGui.QAction(self), QtCore.SIGNAL('triggered()'), QtCore.SLOT('close()')) self._enable_elements() self._read_config() self._read_done() ################################################# # # # GUI FUNCTIONS # # # ################################################# def _disable_elements(self): self._ui.username.setDisabled(True) self._ui.apikey.setDisabled(True) self._ui.files_button.setDisabled(True) self._ui.folder_button.setDisabled(True) self._ui.done.setDisabled(True) self._ui.exp.setDisabled(True) self._ui.start_button.setDisabled(True) self._ui.stop_button.setEnabled(True) def _enable_elements(self): self._ui.username.setEnabled(True) self._ui.apikey.setEnabled(True) self._ui.files_button.setEnabled(True) self._ui.folder_button.setEnabled(True) self._ui.done.setEnabled(True) self._ui.exp.setEnabled(True) self._ui.start_button.setEnabled(True) self._ui.stop_button.setDisabled(True) def _output_export(self): self._ui.ed2k_export.setText("".join(file(self._export_filename).readlines())) def _calculate_progress(self): if self._ui.datatable.rowCount() == 0: return 0 done = 0 for i in range(self._ui.datatable.rowCount()): if unicode(self._ui.datatable.item(i,2).text()) == 'done': done += 1 return done*100/self._ui.datatable.rowCount() ################################################# # # # EVENT HANDLER # # # ################################################# def _closeEvent(self,event): self._stop() self._write_config() event.accept() def _done(self, path): i = self._paths[path] item = QtGui.QTableWidgetItem('done') self._ui.datatable.setItem(i, 2, item) if self._ui.exp.isChecked(): self._output_export() self._ui.progressBar.setValue(self._calculate_progress()) def _finished(self): self._paths = {} self._ui.progressBar.setValue(self._calculate_progress()) self._worker = None self._enable_elements() if self._ui.exp.isChecked(): self._output_export() def _stop(self): if self._worker is not None: self._worker.stop() self._output_export() self._enable_elements() def _slotFile(self): files = QtGui.QFileDialog.getOpenFileNames(self, 'File select', os.getcwd(), self._allowed_extensions_str) for path in files: self._add_file(unicode(path)) def _slotFolder(self): path = unicode(QtGui.QFileDialog.getExistingDirectory(self, "Select Directory")) if path != '': for root, dir, files in os.walk(path): for filename in files: self._add_file(os.path.join(root, filename)) def _add_file(self, fileloc): if len(fileloc) == 0: return elif unicodedata.normalize('NFKC', fileloc) in self._done_files: return no = self._ui.datatable.rowCount() if platform.system().lower() == 'windows': fileloc = fileloc.replace("/", "\\") filepath, filename = fileloc.rsplit("\\", 1) else: filepath, filename = fileloc.rsplit("/", 1) tmp, ext = filename.rsplit('.', 1) if ext not in self._allowed_extensions: return if fileloc not in self._filelist.keys(): self._filelist[fileloc] = 1 self._ui.datatable.insertRow(no) item = QtGui.QTableWidgetItem(filepath) self._ui.datatable.setItem(no, 0, item) item = QtGui.QTableWidgetItem(filename) self._ui.datatable.setItem(no, 1, item) item = QtGui.QTableWidgetItem('new') self._ui.datatable.setItem(no, 2, item) self._ui.progressBar.setValue(self._calculate_progress()) def _run(self): if self._ui.datatable.rowCount() == 0: QtGui.QMessageBox.information(self, "Error!", "No files to scan in list.", QtGui.QMessageBox.Ok) return elif not os.path.exists('avdump2cl.exe'): QtGui.QMessageBox.information(self, "Error!", "Avdump2cl.exe not found.", QtGui.QMessageBox.Ok) return paths = [] for i in range(self._ui.datatable.rowCount()): if unicode(self._ui.datatable.item(i,2).text()) == 'new': path = os.path.join(unicode(self._ui.datatable.item(i,0).text()), unicode(self._ui.datatable.item(i,1).text())) paths.append(path) self._paths[path] = i if len(paths) > 0: self._ui.progressBar.setValue(self._calculate_progress()) self._disable_elements() username = unicode(self._ui.username.text()) apikey = unicode(self._ui.apikey.text()) done = '' if self._ui.done.isChecked() is True: done = '-done:done.txt' exp = '' if self._ui.exp.isChecked() is True: exp = '-exp:' + self._export_filename self._worker = avdump_worker(username, apikey, done, exp, paths) self.connect(self._worker, QtCore.SIGNAL("done"), self._done) self.connect(self._worker, QtCore.SIGNAL("finished"), self._finished) self._worker.start() ################################################# # # # CONFIG READ/WRITE # # # ################################################# def _read_config(self): if os.path.exists('options.ini'): config = ConfigParser.ConfigParser() config.read('options.ini') self._ui.username.setText(config.get('DEFAULT', 'username')) self._ui.apikey.setText(config.get('DEFAULT', 'apikey')) if config.get('DEFAULT', 'done') == '1': self._ui.done.setChecked(True) else: self._ui.done.setChecked(False) if config.get('DEFAULT', 'exp') == '1': self._ui.exp.setChecked(True) else: self._ui.exp.setChecked(False) def _write_config(self): config = ConfigParser.ConfigParser() config.set("DEFAULT", "username", str(self._ui.username.text())) config.set("DEFAULT", "apikey", str(self._ui.apikey.text())) if self._ui.done.isChecked(): config.set("DEFAULT", "done", 1) else: config.set("DEFAULT", "done", 0) if self._ui.exp.isChecked(): config.set("DEFAULT", "exp", 1) else: config.set("DEFAULT", "exp", 0) config.write(file("options.ini", "w")) def _read_done(self): if os.path.exists("done.txt"): for line in file("done.txt"): self._done_files.append(unicodedata.normalize('NFKC', line.decode("utf8").strip())) class avdump_worker(QtCore.QThread): def __init__(self, username, apikey, done, exp, paths): QtCore.QThread.__init__(self, parent=None) self._username = username self._apikey = apikey self._done = done self._exp = exp self._paths = paths self._was_stopped = False self._avdump = None def stop(self): self._was_stopped = True self._avdump.terminate() def run(self): for path in self._paths: if self._was_stopped is True: break self._avdump = subprocessw.Popen((u'avdump2cl.exe -ac:%s:%s %s %s "%s"') %(self._username, self._apikey, self._done, self._exp, path)) self._avdump.communicate() if self._was_stopped is False: self.emit(QtCore.SIGNAL('done'), path) if self._was_stopped is False: self.emit(QtCore.SIGNAL('finished')) def main(): app = QtGui.QApplication(sys.argv) window=Main() window.show() sys.exit(app.exec_()) if __name__ == "__main__": main()
Wrapper module for subprocess by rar
import subprocess from subprocess import call, PIPE, STDOUT, list2cmdline, mswindows import ctypes import ctypes.wintypes CreateProcessW = ctypes.windll.kernel32.CreateProcessW CloseHandle = ctypes.windll.kernel32.CloseHandle __all__ = ["Popen", "PIPE", "STDOUT", "call"] class STARTUPINFOW(ctypes.Structure): _fields_ = (("cb", ctypes.wintypes.DWORD), # should init to 17*4 maybe? ("lpReserved", ctypes.wintypes.LPWSTR), ("lpDesktop", ctypes.wintypes.LPWSTR), ("lpTitle", ctypes.wintypes.LPWSTR), ("dwX", ctypes.wintypes.DWORD), ("dwY", ctypes.wintypes.DWORD), ("dwXSize", ctypes.wintypes.DWORD), ("dwYSize", ctypes.wintypes.DWORD), ("dwXCountChars", ctypes.wintypes.DWORD), ("dwYCountChars", ctypes.wintypes.DWORD), ("dwFillAttribute", ctypes.wintypes.DWORD), ("dwFlags", ctypes.wintypes.DWORD), ("wShowWindow", ctypes.wintypes.WORD), ("cbReserved2", ctypes.wintypes.WORD), ("lpReserved2", ctypes.wintypes.LPSTR), # actually LPBYTE ("hStdInput", ctypes.wintypes.HANDLE), ("hStdOutput", ctypes.wintypes.HANDLE), ("hStdError", ctypes.wintypes.HANDLE)) class PROCESS_INFORMATION(ctypes.Structure): _fields_ = (("hProcess", ctypes.wintypes.HANDLE), ("hThread", ctypes.wintypes.HANDLE), ("dwProcessId", ctypes.wintypes.DWORD), ("dwThreadId", ctypes.wintypes.DWORD)) if mswindows: class Popen(subprocess.Popen): def _execute_child(self, args, executable, preexec_fn, close_fds, cwd, env, universal_newlines, startupinfo, creationflags, shell, p2cread, p2cwrite, c2pread, c2pwrite, errread, errwrite): if not isinstance(args, basestring): args = list2cmdline(args) if not isinstance(args, unicode): subprocess.Popen._execute_child(self, args, executable, preexec_fn, close_fds, cwd, env, universal_newlines, startupinfo, creationflags, shell, p2cread, p2cwrite, c2pread, c2pwrite, errread, errwrite) return if startupinfo == None: startupinfo = STARTUPINFOW() startupinfo.dwFlags |= subprocess._subprocess.STARTF_USESHOWWINDOW startupinfo.wShowWindow = subprocess._subprocess.SW_HIDE else: raise NotImplementedError("Can't pass startup stuff") if not None in (p2cread, c2pwrite, errwrite): raise NotImplementedError("Can't pass file object bits") if shell: raise NotImplementedError("Can't pick your own shell for unicode args") margs = ctypes.create_unicode_buffer(args) processinfo = PROCESS_INFORMATION() CreateProcessW(executable, margs, None, None, 1, creationflags, env, cwd, ctypes.byref(startupinfo), ctypes.byref(processinfo)) hp, ht, pid, tid = (processinfo.hProcess, processinfo.hThread, processinfo.dwProcessId, processinfo.dwThreadId) # can't wrap this as a _subprocess_handle so scuppered, need sp_handle_new() self._handle = hp self.pid = pid CloseHandle(ht) # ht.Close() else: Popen = subprocess.Popen