サーバレス練習帳

着眼大局着手小局

【python】MSHTMLイベント受信

Eternal Windowsの次の記事のC++コードをpythonに変換しようと思いました。
http://eternalwindows.jp/browser/mshtml/mshtml07.html

これでコンパイルを通すところまではできましたが、ボタンクリックしてもメッセージを出してくれない。。。 うーむ。

この方式は、一旦、諦めるか。

ただ、少なくともIHTMLDocument3やIHTMLDocument2を使えるようになった効果は大きい!

### iecontrol4.py ###
__author__ = "w.y"
__version__ = "0.0.0.4"

# Win32モジュール
import win32gui
from comtypes.gen.MSHTML import IHTMLWindow2,IHTMLDocument2,IHTMLDocument3,IHTMLElement
from comtypes.gen.MSHTML import BSTR,IDispatch
from comtypes.automation import VARIANT,VT_DISPATCH
from ctypes import windll,c_ulong,byref,POINTER
from time import sleep



class __clsIETabs(object):
	lsHandle = []
	lsHandlePrev = []
	lsTitle = []
	lsTitlePrev = []
	lsUrl = []
	lsUrlPrev = []
	lsHandleChange = []
	lsHandleClose = []

	def setHandle(self, value):
		self.lsHandle.append(value)
		return True

	def removeHandle(self, value):
		self.lsHandle.remove(value)
		return True

	def setTitle(self, value):
		self.lsTitle.append(value)
		return True

	def setUrl(self, value):
		self.lsUrl.append(value)
		return True

	def resetIETabs(self):
		self.lsHandlePrev.clear()
		self.lsTitlePrev.clear()
		self.lsUrlPrev.clear()
		for index, handle in enumerate(self.lsHandle):
			self.lsHandlePrev.append(handle);
			self.lsTitlePrev.append(self.lsTitle[index]);
			self.lsUrlPrev.append(self.lsUrl[index]);
		self.lsHandle.clear()
		self.lsTitle.clear()
		self.lsUrl.clear()
		return True

	def getIETabsChange(self):
		self.lsHandleChange.clear()
		for indexNow, hWndNow in enumerate(self.lsHandle) :
			flChange = True 
			for indexPrev,hWndPrev in enumerate(self.lsHandlePrev) :
				if ((hWndNow == hWndPrev) 
					and (self.lsTitle[indexNow] == self.lsTitlePrev[indexPrev]) 
					and (self.lsUrl[indexNow] == self.lsUrlPrev[indexPrev])):
					flChange = False
			if flChange :
				self.lsHandleChange.append(hWndNow)
		return self.lsHandleChange

	def getIETabsClose(self):
		self.lsHandleClose.clear()
		self.lsHandleClose = list(set(self.lsHandlePrev)-set(self.lsHandle))
		return self.lsHandleClose

def __checkIETab(hWnd,IETabs):
	if (win32gui.GetClassName(hWnd) == 'Internet Explorer_Server'):
		#print(str(hWnd)+' : '+win32gui.GetClassName(hWnd)+' : '+win32gui.GetWindowText(hWnd))
		IETabs.setHandle(hWnd);

class clsEventHandler(IDispatch):
	m_pWin2 = POINTER(IHTMLWindow2)()
	def __init__(self,pWin2):
		super().__init__()
		m_pWin2 = pWin2
		windll.user32.MessageBoxW(None, u'生成されました!', u'メッセージボックス!', 0x00000040)

	def _IDispatch__com_Invoke():
		super()._IDispatch__com_Invoke()
		print('ボタンが押されましたっ!')
		windll.user32.MessageBoxW(None, u'メッセージぼっくす!', u'メッセージボックス!', 0x00000040)

	def _Invoke():
		super()._Invoke()
		print('ボタンが押されましたっ!')
		windll.user32.MessageBoxW(None, u'メッセージぼっくす!', u'メッセージボックス!', 0x00000040)


	def _invoke():
		super()._invoke()
		print('ボタンが押されましたっ!')
		windll.user32.MessageBoxW(None, u'メッセージぼっくす!', u'メッセージボックス!', 0x00000040)


	def Invoke():
		super().Invoke()
		print('ボタンが押されましたっ!')
		windll.user32.MessageBoxW(None, u'メッセージぼっくす!', u'メッセージボックス!', 0x00000040)

def run():

	#初期化:IEタブのクラスを生成、無限ループフラグをセット
	IETabs = __clsIETabs()
	flContinue = True
	user32 = windll.user32
	
	#無限ループIEタブを監視
	while(flContinue):
		#古いIEタブリストの削除
		IETabs.resetIETabs()

		#IEタブリスト(ウインドウハンドル)の取得
		win32gui.EnumChildWindows(win32gui.FindWindow(u'IEFrame',None),lambda hWnd, _: __checkIETab(hWnd,IETabs), None)

		#IEタブリスト(タイトルとUrl)の取得
		uMsg = user32.RegisterWindowMessageW(u'WM_HTML_GETOBJECT')	
		for hIETab in IETabs.lsHandle:
			try : 
				lRes2 = c_ulong(0)
				pLRes2 = byref(lRes2)
				user32.SendMessageTimeoutW(hWnd, uMsg, 0, 0,2, 1000, pLRes2) # 2 == SMTO_ABORTIFHUNG 
				pDoc2 = POINTER(IHTMLDocument2)()			
				windll.oleacc.ObjectFromLresult(lRes2, IHTMLDocument2._iid_, 0, byref(pDoc2))
				IETabs.setTitle(pDoc2.title)
				IETabs.setUrl(pDoc2.url)
			except :
				IETabs.setTitle('no title')
				IETabs.setUrl('no url')
				print('IETabError!')

		#変化したIEタブ、閉じたIEタブの検出
		print('Change : ',IETabs.getIETabsChange())
		for hWnd in IETabs.getIETabsChange():
			# タイトル/URL/エレメントの取得
			lRes2 = c_ulong(0)
			pLRes2 = byref(lRes2)
			user32.SendMessageTimeoutW(hWnd, uMsg, 0, 0,2, 1000, pLRes2) # 2 == SMTO_ABORTIFHUNG 
			pDoc2 = POINTER(IHTMLDocument2)()			
			windll.oleacc.ObjectFromLresult(lRes2, IHTMLDocument2._iid_, 0, byref(pDoc2))

			lRes3 = c_ulong(0)
			pLRes3 = byref(lRes3)
			user32.SendMessageTimeoutW(hWnd, uMsg, 0, 0,2, 1000, pLRes3) # 2 == SMTO_ABORTIFHUNG 
			pDoc3 = POINTER(IHTMLDocument3)()			
			windll.oleacc.ObjectFromLresult(lRes3, IHTMLDocument3._iid_, 0, byref(pDoc3))

			pElementItem01 = POINTER(IHTMLElement)()
			pElementItem02 = POINTER(IHTMLElement)()
			strBstr = BSTR()	
			pDoc3._IHTMLDocument3__com_getElementById('btn01',byref(pElementItem01))
			pDoc3._IHTMLDocument3__com_getElementById('str_Value009',byref(pElementItem02))
			#pElementItem02._IHTMLElement__com__get_innerHTML(byref(strBstr))
			#print(strBstr)
			
			pWin2 = POINTER(IHTMLWindow2)()
			pDoc2._IHTMLDocument2__com__get_parentWindow(byref(pWin2));
			
			var = VARIANT()
			var.vt = VT_DISPATCH;
			var.pdispVal = clsEventHandler(byref(pWin2));
			try:
				pElementItem01._IHTMLElement__com__set_onclick(var);
				pElementItem02._IHTMLElement__com__set_onclick(var);
				print('set!')
			except:
				print('except!')
			
		print('Close  : ',IETabs.getIETabsClose())
		sleep(1)

if __name__ == '__main__':
	run()

でも、ここまで良くやったと思う。大幅なレベルアップ!