Alaska Software Inc. - Return variable by reference in Event method
Username: Password:
AuthorTopic: Return variable by reference in Event method
R.M. MeijerReturn variable by reference in Event method
on Fri, 13 Jan 2017 11:19:07 +0100
Hi,

I am not able to return a variable by reference within a event callback 
method of an ActiveX component (TextControl).

Sample Visual Basic code:

[Visual Basic]
Private Sub TXTextControl1_SpellCheckText(ByVal Text As String, 
MisspelledWordPositions As Variant)
     TXSpell1.Check (Text)
     MisspelledWordPositions = TXSpell1.MisspelledWordPositions
End Sub

My implementation looks like this:

METHOD OwnActiveX:SpellCheckText(cText, aMisspelledWordPositions)
   ::oSpell:Check(cText)
   aMisspelledWordPositions := ::oSpell:MisspelledWordPositions
RETURN aMisspelledWordPositions

Unfortunately this approach does not work.

::oSpell:MisspelledWordPositions does contain an Array of misspelled 
word positions, but assigning this value to parameter
aMisspelledWordPositions has no effect at all.

The problem seems to be that there is no way to return a value (by 
reference) for this second parameter in Xbase++?

Does anyone know a solution or workaround for this problem?


With kind regards,
Rens Zwanenburg
rens[at]rmdata[dot]com
Jonathan LeemingRe: Return variable by reference in Event method
on Fri, 13 Jan 2017 08:15:20 -0700
Hi,

I belive if you make the following changes to your code it will
resolve your issue...

METHOD OwnActiveX:SpellCheckText(cText, aMisspelledWordPositions)
   ::oSpell:Check(cText)

 ASIZE(aMisspelledWordPositions,LEN(::oSpell:MisspelledWordPositions))
ACOPY(::oSpell:MisspelledWordPositions,aMisspelledWordPositions)	

   * aMisspelledWordPositions := ::oSpell:MisspelledWordPositions

RETURN aMisspelledWordPositions

When your method is called it is passing the memory address of the
array aMissspelledWordPositions but when the line
"aMisspelledWordPositions := ::oSpell:MisspelledWordPositions" is
executed it changes the memory address of aMisspelledWordPositions as
referenced in the METHOD but the function from which it was called is
still referrencing the old memory address.  Using the ASIZE / ACOPY
lines will preserve the memory address and populate the array with the
values from ::oSpell:MisspelledWordPositions.

Assuming I'm understanding your issue correctly this should resolve
your issue.

Regards... Jonathan


On Fri, 13 Jan 2017 11:19:07 +0100, R.M. Meijer wrote:

>Hi,
>
>I am not able to return a variable by reference within a event callback 
>method of an ActiveX component (TextControl).
>
>Sample Visual Basic code:
>
>[Visual Basic]
>Private Sub TXTextControl1_SpellCheckText(ByVal Text As String, 
>MisspelledWordPositions As Variant)
>     TXSpell1.Check (Text)
>     MisspelledWordPositions = TXSpell1.MisspelledWordPositions
>End Sub
>
>My implementation looks like this:
>
>METHOD OwnActiveX:SpellCheckText(cText, aMisspelledWordPositions)
>   ::oSpell:Check(cText)
>   aMisspelledWordPositions := ::oSpell:MisspelledWordPositions
>RETURN aMisspelledWordPositions
>
>Unfortunately this approach does not work.
>
>::oSpell:MisspelledWordPositions does contain an Array of misspelled 
>word positions, but assigning this value to parameter
>aMisspelledWordPositions has no effect at all.
>
>The problem seems to be that there is no way to return a value (by 
>reference) for this second parameter in Xbase++?
>
>Does anyone know a solution or workaround for this problem?
R.M. MeijerRe: Return variable by reference in Event method
on Mon, 16 Jan 2017 14:49:11 +0100
Hi Jonathan,

Thanks for your reply.

Unfortunately it does not work.

The argument "aMisspelledWordPositions" is not an Array, it is NIL. So I 
cannot use ASize() to change it.

I tried cloning the array like this:

   aMisspelledWordPositions := AClone(::oSpell:MisspelledWordPositions)

No errors, but also no result.

Maybe XBase++ (1.9.355) does not allow ActiveX object to pass arguments 
by reference?

Or it is a problem with the type of the argument, the documentation 
talks about an array of 'long' values. And according to Microsoft, a 
long value in Visual Basic is a 64 bit signed integer.

As far as I know XBase integers are 32 bit, so maybe this is a problem 
for the component?

Met vriendelijke groet,
With kind regards,

Rens Zwanenburg

Op 13-1-2017 om 16:15 schreef Jonathan Leeming:
> Hi,
>
> I belive if you make the following changes to your code it will
> resolve your issue...
>
> METHOD OwnActiveX:SpellCheckText(cText, aMisspelledWordPositions)
>     ::oSpell:Check(cText)
>
>   ASIZE(aMisspelledWordPositions,LEN(::oSpell:MisspelledWordPositions))
> ACOPY(::oSpell:MisspelledWordPositions,aMisspelledWordPositions)	
>
>     * aMisspelledWordPositions := ::oSpell:MisspelledWordPositions
>
> RETURN aMisspelledWordPositions
>
> When your method is called it is passing the memory address of the
> array aMissspelledWordPositions but when the line
> "aMisspelledWordPositions := ::oSpell:MisspelledWordPositions" is
> executed it changes the memory address of aMisspelledWordPositions as
> referenced in the METHOD but the function from which it was called is
> still referrencing the old memory address.  Using the ASIZE / ACOPY
> lines will preserve the memory address and populate the array with the
> values from ::oSpell:MisspelledWordPositions.
>
> Assuming I'm understanding your issue correctly this should resolve
> your issue.
>
> Regards... Jonathan
>
>
> On Fri, 13 Jan 2017 11:19:07 +0100, R.M. Meijer wrote:
>
>> Hi,
>>
>> I am not able to return a variable by reference within a event callback
>> method of an ActiveX component (TextControl).
>>
>> Sample Visual Basic code:
>>
>> [Visual Basic]
>> Private Sub TXTextControl1_SpellCheckText(ByVal Text As String,
>> MisspelledWordPositions As Variant)
>>      TXSpell1.Check (Text)
>>      MisspelledWordPositions = TXSpell1.MisspelledWordPositions
>> End Sub
>>
>> My implementation looks like this:
>>
>> METHOD OwnActiveX:SpellCheckText(cText, aMisspelledWordPositions)
>>    ::oSpell:Check(cText)
>>    aMisspelledWordPositions := ::oSpell:MisspelledWordPositions
>> RETURN aMisspelledWordPositions
>>
>> Unfortunately this approach does not work.
>>
>> ::oSpell:MisspelledWordPositions does contain an Array of misspelled
>> word positions, but assigning this value to parameter
>> aMisspelledWordPositions has no effect at all.
>>
>> The problem seems to be that there is no way to return a value (by
>> reference) for this second parameter in Xbase++?
>>
>> Does anyone know a solution or workaround for this problem?
Jonathan LeemingRe: Return variable by reference in Event method
on Mon, 16 Jan 2017 16:36:25 -0700
Hi Rens,

I must be missing something...

When you are calling your OwnActiveX:SpellCheckText(cText,
aMisspelledWordPositions) can you not declare aMisspelledWordPositions
:= {} within the procedure/function before calling the method?

On another note I created a spell check for my MLEs based upon a
sample that Alaska provided...

My Documents\Xbase++\source\samples\activex\spellchecker\spellchk.prg
(for Xbase++ 2.0)

C:\Program Files
(x86)\ALASKA\XPPW32\source\samples\activex\spellchecker\spellchk.prg
(for Xbase++ 1.9)

It uses the spell checker engine from MS Word... I don't know if that
will help... obviously MS Word needs to be installed on the
workstation.

Regards... Jonathan



On Mon, 16 Jan 2017 14:49:11 +0100, R.M. Meijer wrote:

>Hi Jonathan,
>
>Thanks for your reply.
>
>Unfortunately it does not work.
>
>The argument "aMisspelledWordPositions" is not an Array, it is NIL. So I 
>cannot use ASize() to change it.
>
>I tried cloning the array like this:
>
>   aMisspelledWordPositions := AClone(::oSpell:MisspelledWordPositions)
>
>No errors, but also no result.
>
>Maybe XBase++ (1.9.355) does not allow ActiveX object to pass arguments 
>by reference?
>
>Or it is a problem with the type of the argument, the documentation 
>talks about an array of 'long' values. And according to Microsoft, a 
>long value in Visual Basic is a 64 bit signed integer.
>
>As far as I know XBase integers are 32 bit, so maybe this is a problem 
>for the component?
R.M. MeijerRe: Return variable by reference in Event method
on Thu, 19 Jan 2017 13:17:54 +0100
Hi Jonathan,

The method "spellCheckText" is called automatically by the control 
(event), every time something in the document changes.
But I am starting to think it is possibly some kind of data type miss match.

Alaska is also looking into this, hopefully they will find the solution.

Met vriendelijke groet,
With kind regards,

Rens Zwanenburg

Op 17-1-2017 om 0:36 schreef Jonathan Leeming:
> Hi Rens,
>
> I must be missing something...
>
> When you are calling your OwnActiveX:SpellCheckText(cText,
> aMisspelledWordPositions) can you not declare aMisspelledWordPositions
> := {} within the procedure/function before calling the method?
>
> On another note I created a spell check for my MLEs based upon a
> sample that Alaska provided...
>
> My Documents\Xbase++\source\samples\activex\spellchecker\spellchk.prg
> (for Xbase++ 2.0)
>
> C:\Program Files
> (x86)\ALASKA\XPPW32\source\samples\activex\spellchecker\spellchk.prg
> (for Xbase++ 1.9)
>
> It uses the spell checker engine from MS Word... I don't know if that
> will help... obviously MS Word needs to be installed on the
> workstation.
>
> Regards... Jonathan
>
>
>
> On Mon, 16 Jan 2017 14:49:11 +0100, R.M. Meijer wrote:
>
>> Hi Jonathan,
>>
>> Thanks for your reply.
>>
>> Unfortunately it does not work.
>>
>> The argument "aMisspelledWordPositions" is not an Array, it is NIL. So I
>> cannot use ASize() to change it.
>>
>> I tried cloning the array like this:
>>
>>    aMisspelledWordPositions := AClone(::oSpell:MisspelledWordPositions)
>>
>> No errors, but also no result.
>>
>> Maybe XBase++ (1.9.355) does not allow ActiveX object to pass arguments
>> by reference?
>>
>> Or it is a problem with the type of the argument, the documentation
>> talks about an array of 'long' values. And according to Microsoft, a
>> long value in Visual Basic is a 64 bit signed integer.
>>
>> As far as I know XBase integers are 32 bit, so maybe this is a problem
>> for the component?
Jim LeeRe: Return variable by reference in Event method
on Wed, 18 Jan 2017 05:16:49 +0100
hi,

i did not use TX-Control so i have no Solution but perhaps a Tip

as i see Type is "Variant" ...
try to use o:callMethod() and different VT_* Constante.

Note : \XPPW32\INCLUDE\activex.ch have more Constante than Help File

search in Alaska Newsgroup for "VTType" or just "VT_" e.g. using with 
OpenOffice

    xParam := VTType():new( xValue, VT_ARRAY + VT_VARIANT )
    xParam := VTType():new( xValue, VT_ARRAY + VT_UI1  )

if nothing help ask Pablo at www.xbwin.com if he know a solution.
R.M. MeijerRe: Return variable by reference in Event method
on Thu, 19 Jan 2017 14:05:44 +0100
Hi Jim,

Thanks for the suggestion!

As the spellCheckText event is automatically called by the component 
itself (whenever something changes in the document), I am not able to 
change the way it is being called.

But you might be right about the data type miss match.

Have been experimenting with different VT_ settings, but no result yet...

Will post a question on the xbwin forum!

Met vriendelijke groet,
With kind regards,

Rens Zwanenburg

Op 18-1-2017 om 5:16 schreef Jim Lee:
> hi,
>
> i did not use TX-Control so i have no Solution but perhaps a Tip
>
> as i see Type is "Variant" ...
> try to use o:callMethod() and different VT_* Constante.
>
> Note : \XPPW32\INCLUDE\activex.ch have more Constante than Help File
>
> search in Alaska Newsgroup for "VTType" or just "VT_" e.g. using with
> OpenOffice
>
>      xParam := VTType():new( xValue, VT_ARRAY + VT_VARIANT )
>      xParam := VTType():new( xValue, VT_ARRAY + VT_UI1  )
>
> if nothing help ask Pablo at www.xbwin.com if he know a solution.
>
>
Jim LeeRe: Return variable by reference in Event method
on Fri, 20 Jan 2017 07:36:06 +0100
ok ... back to Start
how does your "Create" look like

oTxControl                    := XbpActiveXControl():new( )
oTxControl:CLSID              := cTxTextControll
oTxControl:license            := 'TP-XXXXXXXXXXX'
oTxControl:Userevents         := .F.
oTxControl:ReCreateHandle     := .T.
R.M. MeijerRe: Return variable by reference in Event method
on Fri, 20 Jan 2017 16:47:15 +0100
This is my little test procedure:

   oSpell      := createObject("AxTXSpell.AxTXSpellChecker")

   oTx         := xbpActiveXControl():new()
   oTx:CLSID   := cCLSID
   oTx:license := cLicense
   oTx:create(oParent, NIL, {100,100}, {500, 500})
   oTx:show()

   oTx:enableSpellChecking := .T.
   oTx:SpellCheckText      := {|cText, aMisspelledWordPositions| 
oSpell:Check(cText), aMisspelledWordPositions := 
oSpell:MisspelledWordPositions}

Met vriendelijke groet,
With kind regards,

Rens Zwanenburg

Op 20-1-2017 om 7:36 schreef Jim Lee:
> ok ... back to Start
> how does your "Create" look like
>
> oTxControl                    := XbpActiveXControl():new( )
> oTxControl:CLSID              := cTxTextControll
> oTxControl:license            := 'TP-XXXXXXXXXXX'
> oTxControl:Userevents         := .F.
> oTxControl:ReCreateHandle     := .T.
>
>
Jim LeeRe: Return variable by reference in Event method
on Sat, 21 Jan 2017 04:37:09 +0100
hi,

i was told, by a Man how use TXControl, that the Documentation about 
Spellchecker is not what you think.
he use a external Spellchecker within TXControl after try internal 
Spellchecker Version.

neverless back to the Problem :

> This is my little test procedure:

as it is send as Event you need to o:subscribeEvent() and use a Codeblock to 
pass Parameter to that VB Function.

   cEventName := "Name_of_Event_Constant"
   xVar := oActiveX:isEventPublished( cEventName )
   IF xVar <> Nil
      lSuccess := oActiveX:SubscribeEvent( xVar, { |a,b,c ... ,z| 
MyFunc(a,b,c ... ,z) } )
   ENDIF

Parameter a,b,c,d are "send" from ActiveX which you pass to your Codeblock.
you need as much Parameter in "| |" as Event send but it can be more than 
need.

this Work have to be done to each Event you want to recive in your Xbase++ 
App

... and do not forget to o:unsubscribeEvent() all and oActiveX:Destroy() all 
Connection you have made.
R.M. MeijerRe: Return variable by reference in Event method
on Mon, 23 Jan 2017 09:08:55 +0100
Hi Jim,

Actually, the spell checker component (txSpell.NET) works perfectly 
fine, after calling "oSpell:check(cText)" the variable 
oSpell:aMisspelledWordPositions contains an Array with the correct word 
positions.

It is the SpellCheckText event method of txTextControl that just seems 
to ignore any value I put into the argument "aMisspelledWordPositions" 
(no red zigzag lines appear inside the textControl).

Even if I manually set the Array (like aMisspelledWordPositions := {1, 
3, 10, 14}), nothing happens.

I tried your suggestion of subscribing to the event, but there is no 
difference. As far as I know (and the XBase++ manual says), you do not 
need to manually subscribe to these events, this is done automatically 
by XBase++.

Thanks for you help!

Met vriendelijke groet,
With kind regards,

Rens Zwanenburg

Op 21-1-2017 om 4:37 schreef Jim Lee:
> hi,
>
> i was told, by a Man how use TXControl, that the Documentation about
> Spellchecker is not what you think.
> he use a external Spellchecker within TXControl after try internal
> Spellchecker Version.
>
> neverless back to the Problem :
>
>> This is my little test procedure:
> as it is send as Event you need to o:subscribeEvent() and use a Codeblock to
> pass Parameter to that VB Function.
>
>     cEventName := "Name_of_Event_Constant"
>     xVar := oActiveX:isEventPublished( cEventName )
>     IF xVar <> Nil
>        lSuccess := oActiveX:SubscribeEvent( xVar, { |a,b,c ... ,z|
> MyFunc(a,b,c ... ,z) } )
>     ENDIF
>
> Parameter a,b,c,d are "send" from ActiveX which you pass to your Codeblock.
> you need as much Parameter in "| |" as Event send but it can be more than
> need.
>
> this Work have to be done to each Event you want to recive in your Xbase++
> App
>
> ... and do not forget to o:unsubscribeEvent() all and oActiveX:Destroy() all
> Connection you have made.
>
>
Jim LeeRe: Return variable by reference in Event method
on Mon, 23 Jan 2017 22:40:08 +0100
> I tried your suggestion of subscribing to the event, but there is no 
> difference. As far as I know (and the XBase++ manual says), you do not 
> need to manually subscribe to these events, this is done automatically by 
> XBase++.

so what is o:subscribeEvent() for if you think you do not need it ?
remember Windows Apps are send Event via Windows Queue but Xbase++ do not 
pass "all" to User.

Question : how do you o:subscribeEvent() ? ( Syntax )

> Even if I manually set the Array

that will not work while Event, after something "happend", is not send.
normal Windows App will "fill" a Windows Structure and send a Event with a 
Pointer to that Structure.
no Event -> no Structure -> no Result

have you try undokumented o:Userevents / o :UseGuiThread / o:ReCreateHandle 
?
R.M. MeijerRe: Return variable by reference in Event method
on Tue, 24 Jan 2017 12:08:30 +0100
> so what is o:subscribeEvent() for if you think you do not need it ?
> remember Windows Apps are send Event via Windows Queue but Xbase++ do not
> pass "all" to User.
Well, that is because the callback slot is correctly being called when I 
set it like this:

   oTx:SpellCheckText      := {|cText, aMisspelledWordPositions| 
SpellCheckText(cText, aMisspelledWordPositions) }

> Question : how do you o:subscribeEvent() ? ( Syntax )

This is the source I used when manually subscribing to the event:

   ...
   nId := oTx:isEventPublished("SpellCheckText")
   If nId <> NIL
     oTx:subscribeEvent(nId, {|cText, aMisspelledWordPositions| 
SpellCheckText(cText, aMisspelledWordPositions) } )
   Endif
   ...

After this, the function 'SpellCheckText' is called correctly.

>> Even if I manually set the Array
> that will not work while Event, after something "happend", is not send.
> normal Windows App will "fill" a Windows Structure and send a Event with a
> Pointer to that Structure.
> no Event -> no Structure -> no Result
I meant: setting the argument 'aMisspelledWordPositions' inside the 
event callback "spellCheckText" with a mock-up value, see sample program 
below.

> have you try undokumented o:Userevents / o :UseGuiThread / o:ReCreateHandle
> ?
Yes, it makes no difference.

Here is a simple test program (without spell checking component, as that 
is not required to provoke this problem).
In this program the method 'spellCheckText' is being called 
automatically by the control (event) whenever the text in side the 
control is changed.
I simply tell the control the first word is always wrong, but again, no 
red zig-zag line.

Alaska is also investigating this issue.

PROCEDURE Main()
   Local nEvent, mp1, mp2, oXbp
   Local oDlg, oTx

    Create dialog window hidden
   oDlg          := XbpDialog():new( ,,{100,100}, {600,400},, .F. )
   oDlg:taskList := .T.
   oDlg:create()

   oDlg:drawingArea:resize := {|mp1, mp2, obj| 
obj:childList()[1]:setSize({mp2[1]-20, mp2[2]-20}) }

    create txTextControl
   oTx := MyTxControl():new(oDlg:drawingArea, NIL, {10,10}, 
{oDlg:drawingArea:currentSize()[1]-20, 
oDlg:drawingArea:currentSize()[2]-20})
   oTx:CLSID   := "TIS.TX.TextControl.24"
   oTx:license := ""  no license = demo
   oTx:Create()

    enable spell checking
   oTx:EnableSpellChecking := .T.  causes the 'spellCheckText' event 
to be fired when the text in the control changes

    show dialog and txControl
   oTx:show()
   oDlg:show()

   SetAppFocus(oTx)

   Do While nEvent <> xbeP_Close
     nEvent := AppEvent( @mp1, @mp2, @oXbp )
     oXbp:handleEvent( nEvent, mp1, mp2 )

     Do Case
     Case nEvent == xbeP_Keyboard .And. mp1 == xbeK_ESC
       nEvent := xbeP_Close
     EndCase
   Enddo

   oTx:destroy()
   oDlg:destroy()
RETURN

CLASS MyTxControl FROM xbpActiveXControl

EXPORTED:
   METHOD Init
   METHOD SpellCheckText
ENDCLASS

METHOD MyTxControl:Init(oParent, oOwner, aPos, aSize, aPP, lShow)
RETURN ::XbpActiveXControl:Init(oParent, oOwner, aPos, aSize, aPP, lShow)

/*
[Visual Basic]
Private Sub TXTextControl1_SpellCheckText(ByVal Text As String, 
MisspelledWordPositions As Variant)
     TXSpell1.Check (Text)
     MisspelledWordPositions = TXSpell1.MisspelledWordPositions
End Sub
*/
METHOD MyTxControl:SpellCheckText(cText, aMisspelledWordPositions)
   Local nWordLen
   If !Empty(cText)
      TODO: call spell checking engine to determine wrong word positions
      For now, just force the first word to be wrong...
     nWordLen := At(" ", cText)  find first space characterto 
determine length of first word in 'cText'
     If nWordLen == 0  no space > use full length of 'cText'
       nWordLen := Len(cText)
     Endif
     aMisspelledWordPositions := {1, nWordLen}
   Endif
RETURN Self

Met vriendelijke groet,
With kind regards,

Rens Zwanenburg

Op 23-1-2017 om 22:40 schreef Jim Lee:
>> I tried your suggestion of subscribing to the event, but there is no
>> difference. As far as I know (and the XBase++ manual says), you do not
>> need to manually subscribe to these events, this is done automatically by
>> XBase++.
> so what is o:subscribeEvent() for if you think you do not need it ?
> remember Windows Apps are send Event via Windows Queue but Xbase++ do not
> pass "all" to User.
>
> Question : how do you o:subscribeEvent() ? ( Syntax )
>
>> Even if I manually set the Array
> that will not work while Event, after something "happend", is not send.
> normal Windows App will "fill" a Windows Structure and send a Event with a
> Pointer to that Structure.
> no Event -> no Structure -> no Result
>
> have you try undokumented o:Userevents / o :UseGuiThread / o:ReCreateHandle
> ?
>
>
Jim LeeRe: Return variable by reference in Event method
on Wed, 25 Jan 2017 07:59:14 +0100
>I simply tell the control the first word is always wrong, but again, no red
>zig-zag line.

i did not see that you are calling

     TXSpell1.Check (Text)

in your Method MyTxControl:SpellCheckText()
R.M. MeijerRe: Return variable by reference in Event method
on Mon, 30 Jan 2017 10:33:47 +0100
That's because the Spell checking component (txSpell) is not required to 
provoke this problem. You can use whatever spell cheking component you 
like, as long as you return an Array of misspelled word positions within 
the spellCheckText event.

I simply tried to get a red zig-zag line somewhere inside the control...

Alaska support looked into it and now created PDR 6853 for this problem. 
The dev team will now look into this.

I also submitted the issue at TextControl support.

Meanwhile, I will try a different approach as suggested by Mark Sergent, 
using wSpell without the spellCheckText event.


Met vriendelijke groet,
With kind regards,

Rens Zwanenburg

Op 25-1-2017 om 7:59 schreef Jim Lee:
>> I simply tell the control the first word is always wrong, but again, no red
>> zig-zag line.
> i did not see that you are calling
>
>       TXSpell1.Check (Text)
>
> in your Method MyTxControl:SpellCheckText()
>
>
>
>
Jim LeeRe: Return variable by reference in Event method
on Fri, 27 Jan 2017 23:29:07 +0100
have download TxControl Trail Version and try to make Demo.

Question : did you have any *.VTD on your PC ?

these are the Dictionary Files which you need to check