Jump to content

Sky Slate Blueberry Blackcurrant Watermelon Strawberry Orange Banana Apple Emerald Chocolate
Photo

Problem with COM: Adapting a VB example to AHK


  • Please log in to reply
8 replies to this topic
dadepp
  • Members
  • 27 posts
  • Last active: Feb 28 2012 08:33 PM
  • Joined: 12 Jun 2008
Hi,

hope someone with COM knowledge can help me out here.
I'm trying to access the TOM implementation of a Richedit via COM.

I already have tried to adapt an example from VB, but failed on something simple: COM_CreateObject !

; requires corrupts richedit implementation:
; http://www.autohotkey.com/forum/ntopic49028.html
;
; Example VB Code that I tried to adapt:
; http://www.tech-archive.net/Archive/VB/microsoft.public.vb.general.discussion/2009-01/msg01380.html
;
; Msdn docu on EM_GETOLEINTERFACE
; http://msdn.microsoft.com/en-us/library/bb788041(VS.85).aspx

Gui Add, Button, ym gtest1, test1
Gui Show, +hide w500 h500, RichEdit demo
If A_OSVersion = WIN_95
  cGUI("Add", REdit1, 10, 40, 480, 450, "RICHEDIT")
Else
  cGUI("Add", REdit1, 10, 40, 480, 450, "RichEdit20A")
cRichEdit(REdit1, "Text", "Test string to illustrate how to use the `nText Object Model")
COM_Init()
Gui Show
Return

test1:
ptobj := COM_CreateObject("IRichEditOle")        ; cant find any references on what to put here !!!
SendMessage, 0x43C,0,&ptobj,, ahk_id %REdit1%
pito := COM_QueryInterface(ptobj, "{8CC497C0-A1DF-11CE-8098-00AA0047BE5D}")
; {8CC497C0-A1DF-11CE-8098-00AA0047BE5D} = ITextDocument ???
ptr := COM_Invoke(pito, "SetRange", 1, 3)
ptf := COM_CreateObject("ITextFont")             ; cant find any references on what to put here !!!

COM_Invoke(ptr, "GetFont", &ptf)
COM_Invoke(ptf, "SetForeColor", "0x00FF0000")
COM_Invoke(ptr, "SetColor", &ptf)

COM_Release(ptf)
COM_Release(ptr)
COM_Release(ptobj)
Return

GuiClose:
COM_Term()
If (REdit1)
  cRichEdit(REdit1, "Destroy")
Gui, %A_Gui%:Destroy
cGUI("FreeDlls", NULL)
ExitApp
Return

#Include cGUI.ahk
#Include cRichEdit.ahk

Then the next problem will probably be the EM_GETOLEINTERFACE message since the lparam is "Pointer to a pointer that receives the IRichEditOle object". No idea how to implement this double pointer system.
Hope someone has some more insight into this.

jethrow
  • Moderators
  • 2854 posts
  • Last active: May 17 2017 01:57 AM
  • Joined: 24 May 2009
Perhaps supplying the VBScript might help.

dadepp
  • Members
  • 27 posts
  • Last active: Feb 28 2012 08:33 PM
  • Joined: 12 Jun 2008

Perhaps supplying the VBScript might help.

; Example VB Code that I tried to adapt:
; http://www.tech-archive.net/Archive/VB/microsoft.public.vb.general.discussion/2009-01/msg01380.html

I wrote it into the code. sry if it was not obvious.

dadepp
  • Members
  • 27 posts
  • Last active: Feb 28 2012 08:33 PM
  • Joined: 12 Jun 2008
Bump!

After a few hours on google, i came up with something that might work:
(but its probally just wishfull thinking on my part :( )
ptobj := COM_CreateObject("IID_IUnknown")
SendMessage, 0x43C,0,&ptobj,, ahk_id %REdit1%
pito := COM_QueryInterface(&ptobj, "IID_ITextDocument")

But still got the COM error:

Function Name: "SetRange"
ERROR: The COM Object may not be a valid Dispatch Object!
First ensure that COM Library has been initialized through COM_Init().
()

Will continue?


I hope someone with COM knowledge can help here!
Or maybe someone can point me in the rigth direction, on where to get needed infos, or maybe even an ahk script that has the same "pointer to a pointer to an object" problem, so I can try to adapt it.

Below is the VB code (note I only tried the first part, not the searching for a word part):
Option Explicit

Private Const WM_USER As Long = &H400
Private Const EM_GETOLEINTERFACE As Long = (WM_USER + 60)
Private Declare Function SendMessage Lib "user32" Alias "SendMessageA" ( _
ByVal hwnd As Long, ByVal wMsg As Long, ByVal wParam As Long, _
lParam As Any) As Long

Dim oUnknown As stdole.IUnknown
Dim oTextDocument As ITextDocument
Dim oTextRange1 As ITextRange
Dim oTextFont1 As ITextFont
Dim oTextPara1 As ITextPara
Dim oTextSelection1 As ITextSelection

Private Sub Command1_Click()
Dim ret As Long

ret = SendMessage(RichTextBox1.hwnd, EM_GETOLEINTERFACE, 0, oUnknown)
Debug.Print "EM_GETOLEINTERFACE returned " & ret & _
", LastDllError = " & Err.LastDllError
Set oTextDocument = oUnknown
If oTextDocument Is Nothing Then
Debug.Print "oTextDocument Is Nothing"
Exit Sub
End If

Debug.Print "StoryCount = " & oTextDocument.StoryCount

' Specify range char 5 to 11
Set oTextRange1 = oTextDocument.Range(5, 11)
Debug.Print "TextRange1: '" & oTextRange1.Text & "'"
' Change its color
Set oTextFont1 = oTextRange1.Font
oTextFont1.ForeColor = RGB(255, 0, 0)

' Find "Object"
oTextRange1.FindText "Object", tomForward, tomMatchWord
' Change its color
oTextFont1.ForeColor = RGB(0, 255, 0)

Set oTextPara1 = oTextRange1.Para

Set oTextSelection1 = oTextDocument.Selection

' Done
Set oTextSelection1 = Nothing
Set oTextPara1 = Nothing
Set oTextFont1 = Nothing
Set oTextRange1 = Nothing
Set oTextDocument = Nothing
End Sub

Private Sub Form_Load()
RichTextBox1.HideSelection = False
RichTextBox1.Text = "Test string to illustrate how to use the " & _
"Text Object Model"
End Sub

I hope someone can help/ shed some light on things.

Sean
  • Members
  • 2462 posts
  • Last active: Feb 07 2012 04:00 AM
  • Joined: 12 Feb 2007
You did it completely wrong. It's a great mystery how you reached the posted code from the mentioned VB code. Do you understand the VB code? Anyway, there exist two ways to obtain IRichEidtOle/ITextDocument interface.

Only for RichEdit controls in the same AHK/thread,
COM_Init()
VarSetCapacity(lp,4,0)
SendMessage, 1084,, &lp,, ahk_id %hwndRichEdit%
preo := NumGet(lp) ; IRichEditOle
; ptom := COM_QueryInterface(preo, "{8CC497C0-A1DF-11CE-8098-00AA0047BE5D}"), COM_Release(preo)
or, also for RichEdit controls in other apps,
COM_AccInit()
ptom := COM_AccessibleObjectFromWindow(hwndRichEdit, -16) ; ITextDocument


dadepp
  • Members
  • 27 posts
  • Last active: Feb 28 2012 08:33 PM
  • Joined: 12 Jun 2008
First off many thanks for taking the time to help the idiotic me.

You did it completely wrong. It's a great mystery how you reached the posted code from the mentioned VB code. Do you understand the VB code?


...... Owned :!: ..... That was the first thought that crossed my mind after reading your post, and i deserve it. No excuses for me (except maybe the standard ones like "it was late" and so on ...).

To answer your question if I understood the VB code I can honsetly say Yes/No, since I never worked with VB, except when adapting vb scripts to ahk (sucessfully till now i might add!), and concerning COM, well that was my first try into the field, that I didn't touch, even with a 10 foot pole, till now.

Believe it or not, but your solution was the first thing i tried, minus the VarSetCapacity and the NumGet part of course. Since that didn't work I came up with that piece of code. It went down something like this:
- They create the Com objects before using them, so lets do it like this too --> COM_CreateObject
- send EM_GETOLEINTERFACE --> ok the same
- hm setting one object to the recieved lparam pointer and then using it like an ITextDocument object --> msdn says the sendmsg returns a IRichEditOle and to get ITextDocument use QueryInterface --> total mess
- and so on ..

After I got that it didnt work, and I thought i adapted it right and the only thing wrong here was the params of COM_CreateObject, and thats how this mess came to be.

Anyway, there exist two ways to obtain IRichEidtOle/ITextDocument interface.

Only for RichEdit controls in the same AHK/thread,

COM_Init()
VarSetCapacity(lp,4,0)
SendMessage, 1084,, &lp,, ahk_id %hwndRichEdit%
preo := NumGet(lp) ; IRichEditOle
; ptom := COM_QueryInterface(preo, "{8CC497C0-A1DF-11CE-8098-00AA0047BE5D}"), COM_Release(preo)


With your solution I managed to make it work, so heres the working code with many thanks to Sean:
Just run this, select some part of the text then press button!
; requires corrupts richedit implementation:
; http://www.autohotkey.com/forum/ntopic49028.html
;
Gui Add, Button, ym gtest1, test1
Gui Show, +hide w500 h500, RichEdit demo
If A_OSVersion = WIN_95
  cGUI("Add", REdit1, 10, 40, 480, 450, "RICHEDIT")
Else
  cGUI("Add", REdit1, 10, 40, 480, 450, "RichEdit20A")
cRichEdit(REdit1, "Text", "Test string to illustrate how to use the `nText Object Model")
COM_Init()
Gui Show
Return

test1:
VarSetCapacity(lp,4,0)
SendMessage, 1084,, &lp,, ahk_id %REdit1%
preo := NumGet(lp)
ptom := COM_QueryInterface(preo, "{8CC497C0-A1DF-11CE-8098-00AA0047BE5D}")
COM_Release(preo)

ptr := COM_Invoke(ptom, "Range", 5, 11)
ptf := COM_Invoke(ptr, "Font")
COM_Invoke(ptf, "ForeColor", "0x000000FF")

COM_Invoke(ptr, "FindText", "object", "1073741823", "2")
COM_Invoke(ptf, "ForeColor", "0x0000FF00")

COM_Release(ptf)
COM_Release(ptr)

COM_Release(ptom)
Return

GuiClose:
COM_Term()
If (REdit1)
  cRichEdit(REdit1, "Destroy")
Gui, %A_Gui%:Destroy
cGUI("FreeDlls", NULL)
ExitApp
Return

#Include cGUI.ahk
#Include cRichEdit.ahk


tank
  • Administrators
  • 4345 posts
  • AutoHotkey Foundation
  • Last active: May 02 2019 09:16 PM
  • Joined: 21 Dec 2007
care to share these?
#Include cGUI.ahk
#Include cRichEdit.ahk
Never lose.
WIN or LEARN.

dadepp
  • Members
  • 27 posts
  • Last active: Feb 28 2012 08:33 PM
  • Joined: 12 Jun 2008

care to share these?
#Include cGUI.ahk
#Include cRichEdit.ahk


; requires corrupts richedit implementation:
; http://www.autohotkey.com/forum/ntopic49028.html
;
.....
........


It is an include from corrupt:
http://www.autohotke...topic49028.html

tank
  • Administrators
  • 4345 posts
  • AutoHotkey Foundation
  • Last active: May 02 2019 09:16 PM
  • Joined: 21 Dec 2007
doh :!: :oops:
Never lose.
WIN or LEARN.