From 032de6a848007023836d73fd5c7c05551c9ceba2 Mon Sep 17 00:00:00 2001 From: hakril Date: Mon, 5 Aug 2019 22:32:10 +0200 Subject: [PATCH] Moved bits.py to winobject/ + added windows.system.bits as entrypoint --- windows/bits.py | 107 --------------- windows/winobject/bits.py | 264 ++++++++++++++++++++++++++++++++++++ windows/winobject/system.py | 5 + 3 files changed, 269 insertions(+), 107 deletions(-) delete mode 100644 windows/bits.py create mode 100644 windows/winobject/bits.py diff --git a/windows/bits.py b/windows/bits.py deleted file mode 100644 index 7f8ebb3..0000000 --- a/windows/bits.py +++ /dev/null @@ -1,107 +0,0 @@ -import threading - -import windows -import windows.com -from windows.generated_def.interfaces import (IBackgroundCopyManager, IEnumBackgroundCopyJobs, IBackgroundCopyJob, - IBackgroundCopyCallback, COMImplementation, IUnknown, IBackgroundCopyError) -from windows.generated_def import DWORD, BG_JOB_TYPE_UPLOAD, BG_JOB_STATE_SUSPENDED, BG_ERROR_CONTEXT, HRESULT - -BackgroundCopyManager = windows.com.IID.from_string("4991d34b-80a1-4291-83b6-3328366b9097") -BackgroundCopyManager1_5 = windows.com.IID.from_string("f087771f-d74f-4c1a-bb8a-e16aca9124ea") -BackgroundCopyManager2_0 = windows.com.IID.from_string("6d18ad12-bde3-4393-b311-099c346e6df9s") -BackgroundCopyManager2_5 = windows.com.IID.from_string("03ca98d6-ff5d-49b8-abc6-03dd84127020") -BackgroundCopyManager3_0 = windows.com.IID.from_string("659cdea7-489e-11d9-a9cd-000d56965251") - - -class BitsCopyCallback(COMImplementation): - IMPLEMENT = IBackgroundCopyCallback - - def JobError(self, this, job, error): - return True - - def JobTransferred(self, this, job): - #copy_terminated.set() - return True - - def JobModification(self, job, reserved): - return True - -class BitsCopyCallbackSetEvent(BitsCopyCallback): - def __init__(self, event): - super(BitsCopyCallbackSetEvent, self).__init__() - self.event = event - - # With the current generated_def.interface design, the current - # prototype is: - # ctypes.WINFUNCTYPE(HRESULT, PVOID, PVOID)(4, "JobError") - # How should I address that ? - def JobError(self, this, job, error): - job = BitsCopyJob(job) - error = BitsCopyError(error) - errcode, errctx = error.error - print("Copy failed with error code <{0:#x}> (ctx={1})".format(errcode, errctx)) - print("see ") - self.event.set() - return True - - def JobTransferred(self, this, job): - self.event.set() - return True - -class BitsCopyManager(IBackgroundCopyManager): - @property - def jobs(self): - jobsenum = IEnumBackgroundCopyJobs() - self.EnumJobs(0, jobsenum) - res = [] - nbretrieved = DWORD() - while True: - current = BitsCopyJob() - jobsenum.Next(1, current, nbretrieved) - if not nbretrieved.value: - break - res.append(current) - return res - - def create(self, name, jobtype): - myjob_uuid = windows.com.IID() - newjob = BitsCopyJob() - self.CreateJob(name, jobtype, myjob_uuid, newjob) - return newjob - -class BitsCopyJob(IBackgroundCopyJob): - @property - def iid(self): - res = windows.com.IID() - self.GetId(res) - res.update_strid() - return res - - @property - def state(self): - x = windows.generated_def.BG_JOB_STATE() - self.GetState(x) - return x - - def wait(self): - if self.state.value == BG_JOB_STATE_SUSPENDED: - raise ValueError("Cannot wait a BG_JOB_STATE_SUSPENDED job") - event = threading.Event() - callback_event = BitsCopyCallbackSetEvent(event) - self.SetNotifyInterface(callback_event) - self.SetNotifyFlags(1 | 2) # BG_NOTIFY_JOB_TRANSFERRED | BG_NOTIFY_JOB_ERROR - event.wait() - return True - - - def __repr__(self): - return '<{0} iid="{1}" at {2:#08x}>'.format(type(self).__name__, self.iid.to_string(), id(self)) - - -class BitsCopyError(IBackgroundCopyError): - @property - def error(self): - err_ctx = BG_ERROR_CONTEXT() - err = HRESULT() - self.GetError(err_ctx, err) - return (err.value & 0xffffffff, err_ctx) \ No newline at end of file diff --git a/windows/winobject/bits.py b/windows/winobject/bits.py new file mode 100644 index 0000000..9f77ac4 --- /dev/null +++ b/windows/winobject/bits.py @@ -0,0 +1,264 @@ +import threading + +import windows +import windows.com +from windows.com import COMImplementation +from windows.generated_def.interfaces import (IBackgroundCopyManager, IEnumBackgroundCopyJobs, IBackgroundCopyJob, + IBackgroundCopyCallback, IUnknown, IBackgroundCopyError, IEnumBackgroundCopyFiles, + IBackgroundCopyFile) +import windows.generated_def as gdef + +BackgroundCopyManager = windows.com.IID.from_string("4991d34b-80a1-4291-83b6-3328366b9097") +BackgroundCopyManager1_5 = windows.com.IID.from_string("f087771f-d74f-4c1a-bb8a-e16aca9124ea") +BackgroundCopyManager2_0 = windows.com.IID.from_string("6d18ad12-bde3-4393-b311-099c346e6df9s") +BackgroundCopyManager2_5 = windows.com.IID.from_string("03ca98d6-ff5d-49b8-abc6-03dd84127020") +BackgroundCopyManager3_0 = windows.com.IID.from_string("659cdea7-489e-11d9-a9cd-000d56965251") + +BITS_CLS_BY_VERSION = { + (1,0): BackgroundCopyManager, + (1,5): BackgroundCopyManager1_5, + (2,0): BackgroundCopyManager2_0, + (2,5): BackgroundCopyManager2_5, + (3,0): BackgroundCopyManager3_0, +} + + +class BitsCopyCallback(COMImplementation): + IMPLEMENT = IBackgroundCopyCallback + + def JobError(self, this, job, error): + return True + + def JobTransferred(self, this, job): + #copy_terminated.set() + return True + + def JobModification(self, job, reserved): + return True + +class BitsCopyCallbackSetEvent(BitsCopyCallback): + def __init__(self, event): + super(BitsCopyCallbackSetEvent, self).__init__() + self.event = event + + # With the current generated_def.interface design, the current + # prototype is: + # ctypes.WINFUNCTYPE(HRESULT, PVOID, PVOID)(4, "JobError") + # How should I address that ? + def JobError(self, this, job, error): + job = BitsCopyJob(job) + error = BitsCopyError(error) + errcode, errctx = error.error + print("Copy failed with error code <{0:#x}> (ctx={1})".format(errcode, errctx)) + print("see ") + self.event.set() + return True + + def JobTransferred(self, this, job): + self.event.set() + return True + +class BitsCopyManager(IBackgroundCopyManager): + def get_jobs(self, flags=0): + jobsenum = IEnumBackgroundCopyJobs() + self.EnumJobs(flags, jobsenum) + res = [] + nbretrieved = gdef.DWORD() + while True: + current = BitsCopyJob() + jobsenum.Next(1, current, nbretrieved) + if not nbretrieved.value: + break + res.append(current.promote()) + jobsenum.Release() + return res + + @property + def jobs(self): + return self.get_jobs() + + def create(self, name, jobtype): + myjob_uuid = windows.com.IID() + newjob = BitsCopyJob() + self.CreateJob(name, jobtype, myjob_uuid, newjob) + return newjob.promote() + +class BitsCopyJob(IBackgroundCopyJob): + version = 1 + @property + def owner(self): + owner = gdef.LPWSTR() + self.GetOwner(owner) + data = owner.value + windows.winproxy.CoTaskMemFree(owner) + return data + + + @property + def iid(self): + res = windows.com.IID() + self.GetId(res) + res.update_strid() + return res + + @property + def state(self): + x = gdef.BG_JOB_STATE() + self.GetState(x) + return x.value + + @property + def name(self): + descr = gdef.LPWSTR() + self.GetDisplayName(descr) + data = descr.value + windows.winproxy.CoTaskMemFree(descr) + return data + + @property + def description(self): + descr = gdef.LPWSTR() + self.GetDescription(descr) + data = descr.value + windows.winproxy.CoTaskMemFree(descr) + return data + + @property + def files(self): + enum = IEnumBackgroundCopyFiles() + self.EnumFiles(enum) + count = gdef.ULONG() + enum.GetCount(count) + if not count: + return [] + res_size = gdef.ULONG() + array = (BitsFile * count.value)() + enum.Next(count.value, array, res_size) + return array[:res_size.value] + + @property + def type(self): + res = gdef.BG_JOB_TYPE() + self.GetType(res) + return res.value + + @property + def priority(self): + priority = gdef.BG_JOB_PRIORITY() + self.GetPriority(priority) + return priority.value + + @property + def minimum_retry_delay(self): + retry_delay = gdef.ULONG() + self.GetMinimumRetryDelay(retry_delay) + return retry_delay.value + + @property + def proxy_settings(self): + ProxyUsage = gdef.BG_JOB_PROXY_USAGE() + ProxyList = gdef.LPWSTR() + ProxyBypassList = gdef.LPWSTR() + self.GetProxySettings(ProxyUsage, ProxyList, ProxyBypassList) + result = ProxyUsage.value, ProxyList.value, ProxyBypassList.value + windows.winproxy.CoTaskMemFree(ProxyList) + windows.winproxy.CoTaskMemFree(ProxyBypassList) + return result + + @property + def times(self): + res = gdef.BG_JOB_TIMES() + self.GetTimes(res) + return res + + + def wait(self): + if self.state.value == gdef.BG_JOB_STATE_SUSPENDED: + raise ValueError("Cannot wait a BG_JOB_STATE_SUSPENDED job") + event = threading.Event() + callback_event = BitsCopyCallbackSetEvent(event) + self.SetNotifyInterface(callback_event) + self.SetNotifyFlags(1 | 2) # BG_NOTIFY_JOB_TRANSFERRED | BG_NOTIFY_JOB_ERROR + event.wait() + return True + + + def promote(self): + try: + return self.query(BitsCopyJob2) + except WindowsError as e: + return self + + + def __repr__(self): + return '<{0} iid="{1}" at {2:#08x}>'.format(type(self).__name__, self.iid.to_string(), id(self)) + + +class BitsCopyJob2(gdef.IBackgroundCopyJob2, BitsCopyJob): + version = 2 + @property + def notify_cmdline(self): + path = gdef.LPWSTR() + params = gdef.LPWSTR() + self.GetNotifyCmdLine(path, params) + strpath, strparams = path.value, params.value + windows.winproxy.CoTaskMemFree(path) + windows.winproxy.CoTaskMemFree(params) + return strpath, strparams + + +class BitsFile(IBackgroundCopyFile): + version = 1 + @property + def local_name(self): + name = gdef.LPWSTR() + self.GetLocalName(name) + data = name.value + windows.winproxy.CoTaskMemFree(name) + return data + + @property + def remote_name(self): + name = gdef.LPWSTR() + self.GetRemoteName(name) + data = name.value + windows.winproxy.CoTaskMemFree(name) + return data + + @property + def progress(self): + progress = gdef.BG_FILE_PROGRESS() + self.GetProgress(progress) + return progress + + def promote(self): + try: + return self.query(BitsFile3) + except WindowsError as e: + return self + +class BitsFile3(gdef.IBackgroundCopyFile3, BitsFile): + version = 3 + @property + def temporary_name(self): + name = gdef.LPWSTR() + self.GetTemporaryName(name) + data = name.value + windows.winproxy.CoTaskMemFree(name) + return data + +class BitsCopyError(IBackgroundCopyError): + @property + def error(self): + err_ctx = gdef.BG_ERROR_CONTEXT() + err = gdef.HRESULT() + self.GetError(err_ctx, err) + return (err.value & 0xffffffff, err_ctx) + + +def create_manager(version=(3,0)): + windows.com.init() + clsid = BITS_CLS_BY_VERSION[version] + manager = BitsCopyManager() + windows.com.create_instance(clsid, manager) + return manager \ No newline at end of file diff --git a/windows/winobject/system.py b/windows/winobject/system.py index fad3114..62ef7d5 100644 --- a/windows/winobject/system.py +++ b/windows/winobject/system.py @@ -24,6 +24,7 @@ from windows.winobject import event_log from windows.winobject import event_trace from windows.winobject import task_scheduler from windows.winobject import system_module +from windows.winobject import bits from windows.dbgprint import dbgprint @@ -134,6 +135,10 @@ class System(object): """ return windows.winobject.object_manager.ObjectManager() + @utils.fixedpropety + def bits(self): + return bits.create_manager() + #TODO: use GetComputerNameExA ? and recover other names ? @utils.fixedpropety def computer_name(self):