123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104 |
- from win32com.server.util import wrap
- import pythoncom, sys, os, time, win32api, win32event, tempfile
- from win32com.bits import bits
- TIMEOUT = 200 # ms
- StopEvent = win32event.CreateEvent(None, 0, 0, None)
- job_name = 'bits-pywin32-test'
- states = dict([(val, (name[13:]))
- for name, val in vars(bits).items()
- if name.startswith('BG_JOB_STATE_')])
- bcm = pythoncom.CoCreateInstance(bits.CLSID_BackgroundCopyManager,
- None,
- pythoncom.CLSCTX_LOCAL_SERVER,
- bits.IID_IBackgroundCopyManager)
- class BackgroundJobCallback:
- _com_interfaces_ = [bits.IID_IBackgroundCopyCallback]
- _public_methods_ = ["JobTransferred", "JobError", "JobModification"]
-
- def JobTransferred(self, job):
- print('Job Transferred', job)
- job.Complete()
- win32event.SetEvent(StopEvent) # exit msg pump
- def JobError(self, job, error):
- print('Job Error', job, error)
- f = error.GetFile()
- print('While downloading', f.GetRemoteName())
- print('To', f.GetLocalName())
- print('The following error happened:')
- self._print_error(error)
- if f.GetRemoteName().endswith('missing-favicon.ico'):
- print('Changing to point to correct file')
- f2 = f.QueryInterface(bits.IID_IBackgroundCopyFile2)
- favicon = 'http://www.python.org/favicon.ico'
- print('Changing RemoteName from', f2.GetRemoteName(), 'to', favicon)
- f2.SetRemoteName(favicon)
- job.Resume()
- else:
- job.Cancel()
- def _print_error(self, err):
- ctx, hresult = err.GetError()
- try:
- hresult_msg = win32api.FormatMessage(hresult)
- except win32api.error:
- hresult_msg = ""
- print("Context=0x%x, hresult=0x%x (%s)" % (ctx, hresult, hresult_msg))
- print(err.GetErrorDescription())
- def JobModification(self, job, reserved):
- state = job.GetState()
- print('Job Modification', job.GetDisplayName(), states.get(state))
- # Need to catch TRANSIENT_ERROR here, as JobError doesn't get
- # called (apparently) when the error is transient.
- if state == bits.BG_JOB_STATE_TRANSIENT_ERROR:
- print("Error details:")
- err = job.GetError()
- self._print_error(err)
- job = bcm.CreateJob(job_name, bits.BG_JOB_TYPE_DOWNLOAD)
- job.SetNotifyInterface(wrap(BackgroundJobCallback()))
- job.SetNotifyFlags(bits.BG_NOTIFY_JOB_TRANSFERRED |
- bits.BG_NOTIFY_JOB_ERROR |
- bits.BG_NOTIFY_JOB_MODIFICATION)
- # The idea here is to intentionally make one of the files fail to be
- # downloaded. Then the JobError notification will be triggered, where
- # we do fix the failing file by calling SetRemoteName to a valid URL
- # and call Resume() on the job, making the job finish successfully.
- #
- # Note to self: A domain that cannot be resolved will cause
- # TRANSIENT_ERROR instead of ERROR, and the JobError notification will
- # not be triggered! This can bite you during testing depending on how
- # your DNS is configured. For example, if you use OpenDNS.org's DNS
- # servers, an invalid hostname will *always* be resolved (they
- # redirect you to a search page), so be careful when testing.
- job.AddFile('http://www.python.org/favicon.ico', os.path.join(tempfile.gettempdir(), 'bits-favicon.ico'))
- job.AddFile('http://www.python.org/missing-favicon.ico', os.path.join(tempfile.gettempdir(), 'bits-missing-favicon.ico'))
- for f in job.EnumFiles():
- print('Downloading', f.GetRemoteName())
- print('To', f.GetLocalName())
- job.Resume()
- while True:
- rc = win32event.MsgWaitForMultipleObjects(
- (StopEvent,),
- 0,
- TIMEOUT,
- win32event.QS_ALLEVENTS)
- if rc == win32event.WAIT_OBJECT_0:
- break
- elif rc == win32event.WAIT_OBJECT_0+1:
- if pythoncom.PumpWaitingMessages():
- break # wm_quit
|