HitTest and InkEdit Control

AlexanderBB

Well-known Member
Joined
Jul 1, 2009
Messages
2,148
Office Version
  1. 2019
  2. 2010
Platform
  1. Windows
Does anyone know if the hittest function will work with an Inkedit control?
 
The InkEdit library provides a number of very useful interfaces such as IStream, IRunningObjectTable, IMoniker etc that could potentially be used instead of using low level api com calls hence making the code much easier and shorter. Unfortunately, some of these interfaces are not compatible with VB(A) clients as they use unsupported data types in VB(A). I guess one could still work around this limitation by using light object versions of the interfaces and the IDispatch interface. I would be curious if this could be done.


View attachment 119193
I did know that InkEdit had a few additional interfaces after stumbling across a thread written by wqweto on the topic: COM interfaces in system supplied type libraries-VBForums

I seem to see IStream all the time these days.
 
Upvote 0
I did know that InkEdit had a few additional interfaces after stumbling across a thread written by wqweto on the topic: COM interfaces in system supplied type libraries-VBForums
Exactly. I too stumbled on that post by wqweto a few months ago which drew my attention to the potential of using the interfaces that come with the InkEdit lib. It is a shame the tlbs define various functions whose parameters are unsigned longs, not comptaible with VB(A).
 
Upvote 0
Found this when trying the workbook on a 2nd machine. Inkedit still had to be (re)applied from Additional Controls. Maybe that's normal. it would also be nice but I think not possible to vary the font used. Do you also get a Active X prompt on startup that won't go away, even when turned off in trust settings?
@AlexanderBB I am very sorry, I completely missed these points/question. In terms of the ActiveX prompt, yes I do get that when I load a workbook. This is unforunate, but I may have come up with a workaround, to this and to your points about changing the properties to the InkEdit control. I will pull some code together for you.
 
Upvote 0
Ok, I may need to do this in stages.

The ActiveX warning

This is annoying, but I'm just so used to it these days that I barely notice it. I can see that it would be frustrating if you planned on using it in solutions that you had to circulate to other people. But the only 'solution' that I've come up with for this is to dynamically generate the control. It seems to me that Office/Excel scans the workbook/document/file for the the references for certain things (here, a reference to the InkEdit and doubtless the InkPicture libraries/controls), and then produces the warning message accordingly. It does not appear to check the code, so the line of code works for me:

VBA Code:
Set IE = Me.Controls.Add("Inked.Inkedit.1")

I have put some code below which dynamically generates this (And shows how to programmatically undo changes to the InkEdit because I needed to have something fo the commandbutton to do):
1734882958038.png


An 'uneventful' solution?

The point I want to make from all of this is that I've only managed to accomplish this by declaraing the dynamically generated InkEdit control as an Object data type is that you then lose access to the control's events. There may be a workaround for this, but I haven't thought about it too much.

Also, in order to avoid the warning message, I think that you need to make sure that you don't have an explicit reference to either the InkEdit control or the InkEd.dll file in the references section, but this may need double checking.

1734883289809.png


[Side note]BTW, adding a reference to the InkEd.dll here is how I managed to get access to the TextObjectModel (tom). I think it would be possible to do so without having to make an explicit reference, but that would likely require use of DispCallFunc (? Jaafra can confirm?), which I still can't use without my code crashing Excel half the time.
[Caveat]I am so used to clicking on the 'ok' button when that warning appears that I don't know if my proposed 'solution' indeed actually works, or if my 'ok' in relation to another/earlier workbook just carries over and I'm just not seeing it, so it would be useful to check this when/if you try the code above.

The code below goes into the UserForm:

VBA Code:
Option Explicit
#If VBA7 Then
  Private Declare PtrSafe Function SendMessage Lib "user32.dll" Alias "SendMessageA" (ByVal hWnd As LongPtr, _
                                                                                      ByVal wMsg As Long, _
                                                                                      ByVal wParam As LongPtr, _
                                                                                      lParam As Any) As Long
#Else
  Private Enum LongPtr
  [_]
  End Enum
  Private Declare Function SendMessage Lib "user32.dll" Alias "SendMessageA" (ByVal hWnd As Long, _
                                                                              ByVal wMsg As Long, _
                                                                              ByVal wParam As Long, _
                                                                              lParam As Any) As Long
#End If

Private IE As Object        ' Cannot use the Object data type with WithEvents
Private WithEvents btnUndo As MSForms.CommandButton
Private ControlsInstalled As Boolean

Private Sub btnUndo_Click()
  Call DoUndo(IE.hWnd)
End Sub

Private Sub UserForm_Activate()
  If Not ControlsInstalled Then
    SetupControls
    IE.SetFocus
    IE.SelStart = Len(IE.Text)  ' Puts the cursor at the end of the text
  End If
End Sub

Private Sub UserForm_QueryClose(Cancel As Integer, CloseMode As Integer)
  If ControlsInstalled Then
    Me.Controls.Remove IE.Name
    Me.Controls.Remove btnUndo.Name
  End If
End Sub

Private Sub SetupControls()
  Set IE = Me.Controls.Add("Inked.Inkedit.1")
  With IE
    .MousePointer = 3 ' IMP_Ibeam = this sets the Mouse Point to the
                      ' IBeam you normally get when hovering over the textbox, etc
    .Left = 2
    .Top = 2
    .Height = Me.InsideHeight - 35
    .Width = Me.InsideWidth - 4
    .BackColor = RGB(10, 20, 30)
    .Text = "Some sample text"
    .SelStart = 0
    .SelLength = Len(.Text)
    .SelFontSize = 11
    .SelColor = vbGreen
    .SelFontName = "Consolas"
    .SelLength = 0
  End With
  
  Set btnUndo = Me.Controls.Add("Forms.CommandButton.1", "btnUndo")
  With btnUndo
    .Width = 55
    .Height = 25
    .Left = IE.Left + IE.Width - .Width
    .Top = IE.Top + IE.Height + 5
    .Caption = "Undo"
    .Accelerator = "U"
    .Default = True
  End With
  ControlsInstalled = True
End Sub

Sub DoUndo(ByVal TargethWnd As LongPtr)
  Const EM_CANUNDO = &HC6
  Const EM_UNDO = &HC7
  Const EM_EMPTYUNDOBUFFER = &HCD
  Dim Result As Long
  Result = SendMessage(TargethWnd, EM_CANUNDO, 0&, ByVal 0&)
  If Result Then
    Call SendMessage(TargethWnd, EM_UNDO, 0&, ByVal 0&)
    Call SendMessage(TargethWnd, EM_EMPTYUNDOBUFFER, 0&, ByVal 0&)
  Else
    MsgBox "There is nothing to undo.", vbInformation, "Undo Queue is empty"
  End If
End Sub
 
Upvote 0
I had read your comment above about reapplying properties to refer to the problem commonly experienced about changing the propety at runtime (to which I wrote a response and set out a solution below), but I think now that you're referring to changing the default settings of the control when it needs to be added on the destination machine? That, I do not think you can do when you add it as an aadditional control. However, if you do opt for the above dynamically generated solution, you (a) won't need the end user to add it as an additional control, and (b) may encounter the problems below when you try and change the properties programatically at runtime. For that reasons, I decided I'd nonetheless post this reply on the off-chance you might use the dynamically generation method above (probably unlikely), or it might be of use to someone else.

Changing InkEdit's properties

A common problem with the InkEdit control is that it won't let you change it's certain of its properties at runtime. If you do try to change them at runtime, you will get an error message (incorrectly) explaining that the property is read-only. Spoiler: It isn't.

1734885012944.png


This problem becomes even more pronounced if, as above, you're generating the control dynamically, and can't actually do anything at design time.

Solution = Now you see me, now you don't ... it's magic! 🧙‍♂️

My solution to this is to (and bear with me here):
  1. hide the control
  2. change the problematic property
  3. show the control again
I dunno ... it seems to work...

So two properties that I've always had problems with was the Appearance and the ScrollBars property. Piggybacking off the code above that dynamically generates the InkEdit control, if you add:

VBA Code:
Sub FixInkEditSettings()
  IE.Visible = False
  IE.Appearance = 0 ' rtfFlat = 0
  IE.ScrollBars = 2 ' rtfVertical = 2
  IE.Visible = True
End Sub

And then call it wherever you like (but only after you've made the control, obviously). I had put all the control generation and setup code in the Activate event out of habit and a mistaken belief that it wouldn't work in the Initialize event. Not only does it appear to work in the Initialize event, it works better - I've noticed a quick flicker/delay from the Activate event, which you don't get from the Init event.

VBA Code:
Private Sub UserForm_Initialize()
    SetupControls
    FixInkEditSettings
    IE.SetFocus
    IE.SelStart = Len(IE.Text)  ' Puts the cursor at the end of the text
End Sub

(But now I've noticed that the SetFocus method is ignored... sigh... )
Anyway, now there is flat control with a vertical scrollbar.

1734885639180.png



Final point
I had to rewrite this post slightly because I was under the impression that these were problems at design time too. The problem manifested itself differently in that you could make the change in the properties window, but that the change would then promply be ignored by the InkEdit control at runtime, which is what I had orginally understood your point to be. But when I tried it just now (with vertical scrollbars, for example), it surprisingly worked fine (?!?!). To be honest, I think the InkEdit control can be a little janky, at times.
 
Upvote 0
I'm into some other Forms (in the same project) and will get back to one with the Inkedit control. You've given me a lot to look at/try out etc. I hope to end up with a working solution without too many pitfalls. Thanks for the reply/code, I'll let you know how I get on. No-one else commented on the ActiveX warning so at least I know now it's not just me, and thus I Googled further and found a Reg hack that stops it. But still can't figure out why there's a setting in Trust Center that appears to suggest it will suppress it, but doesn't. And yes it's distribution to others where the prompt is a nuisance. But at least I can offer a reg file and they decide. I presume it disables the warning for everything which may be hazardous.

To Avoid ActiveX Control Warning when initializing a UserForm that contains ActiveX controls: http://support.microsoft.com/default.aspx?scid=kb;en-us;827742

1) Click Start, click Run, type regedit, and then click OK.
2) Expand the following registry subkey:HKEY_CURRENT_USER\SOFTWARE\Microsoft\Office\Common
3) Right-click Common, point to New, and then click Key.
4) Type Security, and then press ENTER to name the new subkey.
5) Right-click Security, point to New, and then click DWORD Value.
6) Type UFIControls, and then press ENTER to name the value.
7) Double-click UFIControls.
8) In the Value data box, type 1, and then click OK.
9) Expand the following registry subkey: HKEY_CURRENT_USER\Software\Microsoft\VBA\
10) Right-click VBA, point to New, and then click Key.
11) Type Security, and then press ENTER to name the new subkey.
12) Right-click Security, point to New, and then click DWORD Value.
13) Type LoadControlsInForms, and then press ENTER to name the value.
14) Double-click LoadControlsInForms
15) In the Value data box, type 1, and then click OK.
16) Quit Registry Editor.
 
Upvote 0
I blame you for all this, Alexander. I have you to thank for all this, Alexander.

I am well and truly down the rabbithole now.

So it turns out that not only do we have access to a kind of RichTextBox control (InkEdit), but that is an ever better version of it available to those with Office installed. It's even better than the InkEdit control, and it allows us to do things like...
1736551891522.png


full color renderable emojis! I haven't quite got to the bottom of what those darn black and white ones are doing, but lets ignore them for now.

And, somewhat connected to this, I've found a way of accessing the MouseWheel event without subclassing or anything complicated. It's all very exciting. For me, at least!
 
Upvote 0
That sounds great Dan! What a control... what else might it do I wonder?
In my project I'm still finishing a few Forms - then will be implementing InkEdit, Text only, but making use of colours and bold, so far. Pretty basic compared to your research!
 
Upvote 0

Forum statistics

Threads
1,226,772
Messages
6,192,928
Members
453,767
Latest member
922aloose

We've detected that you are using an adblocker.

We have a great community of people providing Excel help here, but the hosting costs are enormous. You can help keep this site running by allowing ads on MrExcel.com.
Allow Ads at MrExcel

Which adblocker are you using?

Disable AdBlock

Follow these easy steps to disable AdBlock

1)Click on the icon in the browser’s toolbar.
2)Click on the icon in the browser’s toolbar.
2)Click on the "Pause on this site" option.
Go back

Disable AdBlock Plus

Follow these easy steps to disable AdBlock Plus

1)Click on the icon in the browser’s toolbar.
2)Click on the toggle to disable it for "mrexcel.com".
Go back

Disable uBlock Origin

Follow these easy steps to disable uBlock Origin

1)Click on the icon in the browser’s toolbar.
2)Click on the "Power" button.
3)Click on the "Refresh" button.
Go back

Disable uBlock

Follow these easy steps to disable uBlock

1)Click on the icon in the browser’s toolbar.
2)Click on the "Power" button.
3)Click on the "Refresh" button.
Go back
Back
Top