- win32-api
- windows-api
require 'windows/com' require 'windows/unicode' require 'windows/error' require 'windows/national' require 'windows/window/message' require 'windows/msvcrt/buffer' require 'watir/win32ole' include Windows::COM include Windows::Unicode include Windows::National include Windows::Error include Windows::Window::Message include Windows::MSVCRT::Buffer VariantInit = Win32::API.new('VariantInit', 'P', 'V', 'oleaut32') OleUninitialize = Win32::API.new('OleUninitialize', 'V', 'V', 'ole32') DISPID_UNKNOWN = -1 DISPID_VALUE = 0 DISPID_PROPERTYPUT = -3 DISPID_NEWENUM = -4 DISPID_EVALUATE = -5 DISPID_CONSTRUCTOR = -6 DISPID_DESTRUCTOR = -7 DISPID_COLLECT = -8 DISPATCH_METHOD = 0x1 DISPATCH_PROPERTYGET = 0x2 DISPATCH_PROPERTYPUT = 0x4 DISPATCH_PROPERTYPUTREF = 0x8 # Initialize OLE Libraries. OleInitialize() SMTO_ABORTIFHUNG = 0x0002 ObjectFromLresult = Win32::API.new('ObjectFromLresult', 'LPIP', 'L', 'oleacc') IID_NULL = [0x00000000,0x0000,0x0000,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00].pack('LSSC8') def get_control_from_hwnd(hnd) CoInitialize(0) reg_msg = RegisterWindowMessage("WM_HTML_GETOBJECT") puts "msg: " + reg_msg.to_s iid =[0x626FC520,0xA41E,0x11CF,0xA7,0x31,0x00,0xA0,0xC9,0x08,0x26,0x37].pack('LSSC8') result = 0.chr*4 SendMessageTimeout(hnd.hex, reg_msg, 0, 0, SMTO_ABORTIFHUNG,1000, result) puts "result unpacked: " + result.unpack("L").to_s result = result.unpack('L')[0] idisp = 0.chr * 4 r = ObjectFromLresult.call(result, iid, 0, idisp) if r == 0 idisp = idisp.unpack('L').first puts "idisp: " + idisp.to_s end pDisp = idisp ucPtr = multi_to_wide("Script") lpVtbl = 0.chr * 4 table = 0.chr * 28 memcpy(lpVtbl,pDisp,4) memcpy(table,lpVtbl.unpack('L').first,28) table = table.unpack('L*') getIDsOfNames = Win32::API::Function.new(table[5],'PPPLLP','L') dispID = 0.chr * 4 getIDsOfNames.call(pDisp,IID_NULL,[ucPtr].pack('P'),1,LOCALE_USER_DEFAULT,dispID) dispID = dispID.unpack('L').first dispParams = [0,0,0,0].pack('LLLL') res = 0.chr * 16 invoke = Win32::API::Function.new(table[6],'PLPLLPPPP','L') hr = invoke.call(pDisp, dispID, IID_NULL, LOCALE_SYSTEM_DEFAULT, DISPATCH_PROPERTYGET | DISPATCH_METHOD, dispParams, res, nil, nil) if hr != S_OK raise StandardError, "IDispatch::Invoke() failed with %08x" % hr end res = res.unpack('SSSSLL') if res[0] == VT_DISPATCH pDisp = res[4] ucPtr = multi_to_wide("Document") lpVtbl = 0.chr * 4 table = 0.chr * 28 memcpy(lpVtbl,pDisp,4) memcpy(table,lpVtbl.unpack('L').first,28) table = table.unpack('L*') getIDsOfNames = Win32::API::Function.new(table[5],'PPPLLP','L') dispID = 0.chr * 4 getIDsOfNames.call(pDisp,IID_NULL,[ucPtr].pack('P'),1,LOCALE_USER_DEFAULT,dispID) dispID = dispID.unpack('L').first dispParams = [0,0,0,0].pack('LLLL') res = 0.chr * 16 invoke = Win32::API::Function.new(table[6],'PLPLLPPPP','L') hr = invoke.call(pDisp, dispID, IID_NULL, LOCALE_SYSTEM_DEFAULT, DISPATCH_PROPERTYGET | DISPATCH_METHOD, dispParams, res, nil, nil) if hr != S_OK raise StandardError, "IDispatch::Invoke() failed with %08x" % hr end res = res.unpack('SSSSLL') if res[0] == VT_DISPATCH pDisp = res[4] ucPtr = multi_to_wide("parentWindow") lpVtbl = 0.chr * 4 table = 0.chr * 28 memcpy(lpVtbl,pDisp,4) memcpy(table,lpVtbl.unpack('L').first,28) table = table.unpack('L*') getIDsOfNames = Win32::API::Function.new(table[5],'PPPLLP','L') dispID = 0.chr * 4 getIDsOfNames.call(pDisp,IID_NULL,[ucPtr].pack('P'),1,LOCALE_USER_DEFAULT,dispID) dispID = dispID.unpack('L').first dispParams = [0,0,0,0].pack('LLLL') res = 0.chr * 16 invoke = Win32::API::Function.new(table[6],'PLPLLPPPP','L') hr = invoke.call(pDisp, dispID, IID_NULL, LOCALE_SYSTEM_DEFAULT, DISPATCH_PROPERTYGET | DISPATCH_METHOD, dispParams, res, nil, nil) if hr != S_OK raise StandardError, "IDispatch::Invoke() failed with %08x" % hr end res = res.unpack('SSSSLL') if res[0] == VT_DISPATCH puts "#{res}" return res[4] end end end 0 endMaybe the time will come and I'll dig into this code deeper to get an idea what exactly is going on here but for now it's enough for me to know that this code returns the Dispatch pointer to the OLE object corresponding to the window with specified HWND (passed as parameter). The only thing left here is to connect to OLE object and use it methods and properties. It looks like:
obj = get_control_from_hwnd(handle) ie = WIN32OLE.connect_unknown( obj )Where handle variable contains previously found HWND of our OLE object. After that we are free to use OLE object. So, I can write something like:
handle = "00C40180" obj = get_control_from_hwnd(handle) ie = WIN32OLE.connect_unknown( obj ) puts ie.window.document.body.innerHTMLOf course, handle should be initialized with the proper HWND value of existing object. In order to get more details about document objects and methods we just have to dig into MSDN here.
That's it and current problem no longer disturbs me, so let's look for other challenges.
No comments:
Post a Comment