text: #A part of NonVisual Desktop Access (NVDA)
  #Copyright (C) 2009-2016 NV Access Limited
  #This file is covered by the GNU General Public License.
  #See the file COPYING for more details.
  
  from logHandler import log
  
  from comtypes import COMError
  from comtypes.hresult import *
  
  #Monkey patch comtypes to support byref in variants
  from comtypes.automation import VARIANT, VT_BYREF, IDispatch
  from ctypes import cast, c_void_p
  from _ctypes import _Pointer
  oldVARIANT_value_fset=VARIANT.value.fset
  def newVARIANT_value_fset(self,value):
  	realValue=value
  	if isinstance(value,_Pointer):
  		try:
  			value=value.contents
  		except (NameError,AttributeError):
  			pass
  	oldVARIANT_value_fset(self,value)
  	if realValue is not value:
  		self.vt|=VT_BYREF
  		self._.c_void_p=cast(realValue,c_void_p)
  VARIANT.value=property(VARIANT.value.fget,newVARIANT_value_fset,VARIANT.value.fdel)
  
  #Monkeypatch comtypes lazybind dynamic IDispatch support to fallback to the more basic dynamic IDispatch support if the former does not work
  #Example: ITypeComp.bind gives back a vardesc, which comtypes does not yet support
  import comtypes.client.lazybind
  old__getattr__=comtypes.client.lazybind.Dispatch.__getattr__
  def new__getattr__(self,name):
  	try:
  		return old__getattr__(self,name)
  	except (NameError, AttributeError):
  		return getattr(comtypes.client.dynamic._Dispatch(self._comobj),name)
  comtypes.client.lazybind.Dispatch.__getattr__=new__getattr__
  
  #Monkeypatch comtypes to allow its basic dynamic Dispatch support to  support invoke 0 (calling the actual IDispatch object itself)
  def new__call__(self,*args,**kwargs):
  	return comtypes.client.dynamic.MethodCaller(0,self)(*args,**kwargs)
  comtypes.client.dynamic._Dispatch.__call__=new__call__
  
  # Work around an issue with comtypes where __del__ seems to be called twice on COM pointers.
  # This causes Release() to be called more than it should, which is very nasty and will eventually cause us to access pointers which have been freed.
  from comtypes import _compointer_base
  _cpbDel = _compointer_base.__del__
  def newCpbDel(self):
  	if hasattr(self, "_deleted"):
  		# Don't allow this to be called more than once.
  		log.debugWarning("COM pointer %r already deleted" % self)
  		return
  	_cpbDel(self)
  	self._deleted = True
  newCpbDel.__name__ = "__del__"
  _compointer_base.__del__ = newCpbDel
  del _compointer_base
  
  #Monkey patch to force dynamic Dispatch on all vt_dispatch variant values.
  #Certainly needed for comtypes COM servers, but currently very fiddly to do just for that case 
  oldVARIANT_value_fget=VARIANT.value.fget
  def newVARIANT_value_fget(self):
  	return self._get_value(dynamic=True)
  VARIANT.value=property(newVARIANT_value_fget,VARIANT.value.fset,VARIANT.value.fdel)
  
  # #4258: monkeypatch to better handle error where IDispatch's GetTypeInfo can return a NULL pointer. Affects QT5
  oldGetTypeInfo=IDispatch._GetTypeInfo
  def newGetTypeInfo(self,index,lcid=0):
  	res=oldGetTypeInfo(self,index,lcid)
  	if not res:
  		raise COMError(E_NOTIMPL,None,None)
  	return res
  IDispatch._GetTypeInfo=newGetTypeInfo
  
  # Windows updates often include newer versions of dlls/typelibs we use.
  # The typelib being newer than the comtypes generated module doesn't hurt us,
  # so kill the "Typelib newer than module" ImportError.
  # comtypes doesn't let us disable this when running from source, so we need to monkey patch.
  # This is just the code from the original comtypes._check_version excluding the time check.
  import comtypes
  def _check_version(actual):
  	from comtypes.tools.codegenerator import version as required
  	if actual != required:
  		raise ImportError("Wrong version")
  comtypes._check_version = _check_version
  