News:

Masm32 SDK description, downloads and other helpful links
Message to All Guests

Main Menu

Contextual help project

Started by mywan, July 18, 2012, 07:31:02 AM

Previous topic - Next topic

mywan

Thanks for the code, I'll play with it, but I succeeded in retrieving the selected text from within IEContainer.exe using another app. I still have to dig in and figure out what APIs were being used. The relevant code snippet (AutoIt) was as simple as:

#include <IE.au3>
$oIE = _IEAttach("MasmBasic", "embedded")
Local $sText = $oIE.document.selection.createRange().text
MsgBox(0, "Selected Text:", $sText)


This popped up a message box with whatever text was select in the IEContainer window.

jj2007

Post the executable :biggrin:

#include <IE.au3>
Local MyInt = 1/0 ; let's see if Olly likes the error handler :icon_mrgreen:
$oIE = _IEAttach("MasmBasic", "embedded")

mywan

Quote from: jj2007 on July 31, 2012, 03:44:46 AM
Post the executable :biggrin:

#include <IE.au3>
Local MyInt = 1/0 ; let's see if Olly likes the error handler :icon_mrgreen:
$oIE = _IEAttach("MasmBasic", "embedded")

:badgrin:

What the above demonstrates is that IEContainer.exe is fine as is. The issue could be handled just as well from within xHelp.exe but it doesn't really matter which side it's implemented on.

Looking at the internals of the AutoIt code what is indicated is that you need to create access to an IDispatch object. This is done first by calling the CoInitialize API.
http://msdn.microsoft.com/en-us/library/windows/desktop/ms678543(v=vs.85).aspx

In AutoIt this is:
DllCall("ole32.dll", "long", "CoInitialize", "ptr", 0)

In asm it should look something like:
invoke  CoInitialize,NULL

Then to get a pointer to this interface you need to call the ObjectFromLresult API.

In AutoIt this looks like:
Local $lResult
Local $typUUID = DllStructCreate("int;short;short;byte[8]")
DllStructSetData($typUUID, 1, 0x626FC520)
DllStructSetData($typUUID, 2, 0xA41E)
DllStructSetData($typUUID, 3, 0x11CF)
DllStructSetData($typUUID, 4, 0xA7, 1)
DllStructSetData($typUUID, 4, 0x31, 2)
DllStructSetData($typUUID, 4, 0x0, 3)
DllStructSetData($typUUID, 4, 0xA0, 4)
DllStructSetData($typUUID, 4, 0xC9, 5)
DllStructSetData($typUUID, 4, 0x8, 6)
DllStructSetData($typUUID, 4, 0x26, 7)
DllStructSetData($typUUID, 4, 0x37, 8)

Local $aRet = DllCall("oleacc.dll", "long", "ObjectFromLresult", "lresult", $lResult, "struct*", $typUUID, "wparam", 0, "idispatch*", 0)


You'll need a SendMessageTimeOut to prevent a hang if retrieving the object fails. In asm the includes should contain the DllStructCreate construct, so should look something like:
invoke ObjectFromLresult, var1, addr IID_IHTMLDocument2, 0, addr var2

var1 is defined by the SendMessageTimeout API. I'm at the edge of what I understand in assembly, but this is as far as I've gotten so far.

mywan

Attached is the executable.
Note: This does no error checking and will bomb out if the page IE page is not found. Simple run IEContainer.exe leaving it on the default "MasmBasic - a fast and easy-to-use library", select some text, then run ctrl.exe. The IEContainer does not have to be active to read the text that is selected on it.

I also found a sample script implementing what I described in assembly:
http://files.codes-sources.com/fichier.aspx?id=52594&f=html%2Fhtml.asm

Edit: I didn't pay attention when I compiled that, it might be 64 bit.. Let me know.

Ryan

Japheth has implemented macros to streamline the function calls.  I've been trying to get through his Excel automation example.  I don't have it here at work.  It's on my home computer.  Since mywan has nailed down the properties needed to go through to get the selected text, I should be able to put something together for assembly.

jj2007

#65
Here's the structure and some code for testing:

include \masm32\MasmBasic\MasmBasic.inc   ; download
uselib oleacc      ; thread
REFIID STRUCT
muInt   dd ?
muSh1   dw ?
muSh2   dw ?
muB8   db 8 dup(?)
REFIID ENDS

.data
typUUID REFIID <0626FC520h, 0A41Eh, 011CFh, <0A7h, 31h, 0, 0a0h, 0c9h, 8, 26h, 37h>>
IID_IAccessible REFIID <618736E0h, 3C3Dh, 11CFh, <81h, 0Ch, 0, 0AAh, 0, 38h, 9Bh, 71h>>

   Init
   invoke CoInitialize, NULL
   Inkey "ok"
   invoke CoUninitialize
   Exit
   invoke ObjectFromLresult, 1, 2, 3, 4   ; behind Exit - just to test if it assembles...
   invoke LresultFromObject, offset IID_IAccessible, 2, 3   ; is that a pointer to RIID, or RIID itself??
end start

Local $aRet = DllCall("oleacc.dll", "long", "ObjectFromLresult", "lresult", $lResult, "struct*", $typUUID, "wparam", 0, "idispatch*", 0)

ObjectFromLresult function
Retrieves a requested interface pointer for an accessible object based on a previously generated object reference.

STDAPI ObjectFromLresult(
  __in   LRESULT lResult,
  __in   REFIID riid,
  __in   WPARAM wParam,
  __out  void **ppvObject
);

LresultFromObject function

Returns a reference, similar to a handle, to the specified object. Servers return this reference when handling WM_GETOBJECT.
LRESULT LresultFromObject(
  __in  REFIID riid,
  __in  WPARAM wParam,
  __in  LPUNKNOWN pAcc
);

jj2007

Quote from: mywan on July 31, 2012, 04:18:44 AM
Edit: I didn't pay attention when I compiled that, it might be 64 bit.. Let me know.

It's 32-bit code. However, it's packed - a bit more difficult to debug :(

mywan

Wait, I could make it some easier. I forgot that AutoIt uses a UPX packer even when you choose zero compression. I can swap in a dummy UPX.exe to get around that. However, it is still an interpreted script packed inside the interpreter. So poor Olly will still think your on drugs. Anyway, here's one without the upx packer.

This piece of AutoIt script runs in the tray and give me copy access through Ctrl-x. Need a better title match though:
#include <IE.au3>
HotKeySet("^x","cpy")
Sleep(2147483647) ; No reason to run it longer than 24 days :)
Func cpy()
   $oIE = _IEAttach("MasmBasic", "embedded")
   If @error Then Return
   Local $sText = $oIE.document.selection.createRange().text
   If $sText="" Then Return
   ClipPut($sText)
EndFunc


jj2007

#68
Quote from: mywan on July 31, 2012, 05:20:28 AMSo poor Olly will still think your on drugs. Anyway, here's one without the upx packer.

Well, somehow ::)

P.S.: See Basil Yercin on IID_IAccessible in Masm syntax. Looks horrific :biggrin:

qWord

Hi,
you can solve the Copy&Paste problem by replacing CoInitialize(NULL) with OleInitialize(NULL) in the WinMain.
There is note about it here.

EDIT: do not forget OleUninitialize()
MREAL macros - when you need floating point arithmetic while assembling!

mywan

Nice, looks like qWord has found the easy solution while I was typing.

::) I just read about how that was put into later versions of AutoIt. Basically, because a compiled AutIt scipt is essentially the interpreter, which the EULA doesn't allow decompilation of, with a script packed inside of it they decided that decompilation of scripts with a debugger was essentially a decompilation of the interpreter. Apparently they have a back door available for AV companies. This was news to me before today. However, I have source code to earlier version of AutoIt (yes legally obtained, not reversed). I also have earlier AutoIt versions. I could try compiling with one of those earlier AutoIt versions if your really interested, but I would need to unpack them and do some experimenting and checking version histories for DllCall. Not sure how much good it would do. Even many of the APIs are wrapped in DllCall and implemented in script. I could also send you IE.au3 which implements the Dll calls.

This page has essentially a full implementation of what is relevant anyway:
http://files.codes-sources.com/fichier.aspx?id=52594&f=html%2Fhtml.asm

jj2007

Quote from: mywan on July 31, 2012, 07:32:59 AM
Nice, looks like qWord has found the easy solution while I was typing.

Sometimes he is really useful 8)
Japheth reacted also, with a new zip.

QuoteI have source code to earlier version of AutoIt (yes legally obtained, not reversed).

I guess we can stop here - although your ObjectFromLresult etc approach looks feasible in Masm, I add that as a second OleTest zipfile below :biggrin:

By the way:
invoke LresultFromObject, offset IID_IAccessible, 2, 3   ; is that a pointer to RIID, or RIID itself??

xHelp3107.zip contains the new version of xHelp, with Copy enabled, and lots of credits to mywan, ryan and qWord :t

To the proud owners of \masm32\help\WIN32.HLP: Type SendMessage, press TAB, then < and tell me if it works ;)

Ryan

I was not able to do what I wanted to do.

I've been using COMView http://www.japheth.de/COMView.html to look at the available functions within a file.  For some reason when I look at "Microsoft Internet Controls", I see the Document property but not the Selection or CreateRange that mywan indicated that we need for getting the selected text.

mywan

Quote from: Ryan on July 31, 2012, 09:51:05 AM
I was not able to do what I wanted to do.

I've been using COMView http://www.japheth.de/COMView.html to look at the available functions within a file.  For some reason when I look at "Microsoft Internet Controls", I see the Document property but not the Selection or CreateRange that mywan indicated that we need for getting the selected text.
COM is more like a messaging system between objects in other applications to expose methods to external programs. CreateRange is actually a method, not object, in Microsoft's version of JavaScript. JavaScript doesn't expose itself the way MS does theirs. So basically it was in effect JavaScript code, not AutoIt or asm code, that I was implementing. This is allowed because OLE provides the messaging for the methods to be called from external apps. Expecting to see it with COMView is a bit like expecting to see the internal variables defined by MSPaint while looking at notepad. COMView only tells you about the objects that will send the messages for you, not what messages you can send. That is determined by the application you send the message to.

mywan

Ok, that was probably the most difficult issue and it turned out quiet trivial. That leaves some rather basic stuff. Perhaps it's time for a punch list, like when finishing up a construction project. I have one more easy one since my last set list. The list is very short at this point though  :t

1) Pass command line into the search box. Duh..
2) Activate the IEContainer, if open, when the search box is maximized (gains focus) or navigation occurs.

After starting to use xHelp a lot for my own study of MASM the need for 2) became obvious. It has already saved me lots of hours even unfinished. I often click xHelp on the taskbar to minimize/maximize it so it doesn't close the container or interfere with my text editor. Then when I do a new search the container navigates but remains under the other windows. Also activating the container when xHelp is activated is just a little extra convenience for when I keep switching back and forth between my editor and the same htm page. Icing would be if the container was also minimized whenever you minimize xHelp. Basically make them activate and deactivate in tandem for the most part.

I guess the easiest way to implement command line searches when xHelp was already open would be to have xHelp kill any prior instances of itself. There's less hackish ways to do it so that's up to you. Other than that you have an app usable enough I will not waste my time trying to reinvent it in the foreseeable future. Too many other things I also want to accomplish, and better suited to my skill level while still offering a learning experience.

Nice job, very little left to do  :bgrin: