![]() Last edit: 05-03-17 Graham Wideman |
Delphi |
Delphi ActiveX Controls: Unusable in MS Office
Document Pages Article created: 2000-03-26 |
Puzzler regarding VCL notification and design/run modes?
Delphi 5 ActiveX components (generated from VCL components using the wizard) appear to work OK in the VBA "UserForm" environment associated with MS Office products . However when inserted into a document page their behavior is missing a few aspects.In particular:
1. Painting doesn't work properly in "designing" mode
2. In "run" mode the VCL control fails to pass the Click event up to
the wizard-generated Delphi ActiveX control, from where it would be passed
"up" to the containing document environment (where you might handle it
with VBA).
These basic symptoms have been kindly verified by Eric Harmon (author of "Delphi COM Programming"), who has suggested running this by the Borland newsgroups. This page details the problem, in the hopes that fellow developers may have some insight into the problem.
The expertise most pressingly needed (it appears) is in how the VCL dispatches notification messages (or possibly how the VCL does this differently depending on design/run mode, or on some other initialization.)
The symptoms are very easy to generate. Basically the steps are:
Test Section | Step | Details |
Create ActiveX Control in Delphi | Create the ActiveX control | In Delphi, File > New > ActiveX Control. I chose TButton and selected all wizard defaults to create ButtonX. Then register it. (Run > Register). |
Verify in UserForm Environment | Verify Normal Functions in UserForm | You can use any Office product to try this, these are the directions for Word 97, others will be similar. |
Open Word and create new document. | ||
Invoke VBA environment. | Hit Alt-F11, or put doc into design mode using Control Toolbox toolbar "Design Mode" button, then hit "View Code" button.) If VBA offers a bunch of open code windows, close them as they aren't of interest. (This can happen if some previous installation installed some start-up VBA to be added to all new docs. Acrobat does this for example.) | |
Insert UserForm. | In VBA environment, Insert > UserForm. If it's not already showing, also View > Project Explorer. Use Project Explorer to open the new Form into a design window. | |
Insert MS Command Button as a sample: | Select a Command Button from VBA's Toolbox and draw it on the form. | |
Attach Event Code: | Right-click the
CommandButton1 and View Code. This should open the code window and present
you with a Click event procedure. Stick something in there like
Beep: Private Sub CommandButton1_Click() Beep End Sub |
|
Test MS Button | Put Form in Run mode (Hit the Run arrow on the VBA Standard toolbar). Click the button and hear beep. | |
Install DAX ButtonX on VBA Toolbox | Right-click on the Toolbox, and select Additional Controls. If your contol was properly registered, then you can select it from the list. | |
Insert and test DAX ButtonX | Same as for MS Command Button. Place ButtonX on UserForm, View Code, add Beep to Click procedure. Test. Should work OK. | |
Test in Document | Insert MS Command Button in document page. | In Word, view Control Toolbox (if not already), and place doc in Design Mode. Select Command Button (this should drop button on page). |
Add event code for CommandButton1 and test. | RIght-click CommandButton1 and View Code. Add Beep to skeleton. Put document in Run mode, click button and note that this works. | |
Insert ButtonX into document page. | On Control Toolbox,
select Mode Controls button, and select ButtonX.
Bug: I observed that ButtonX doesn't paint properly in Design mode (I see blank white rectangle.). Strangely, if you copy and paste that ButtonX to create a second one, that one does paint OK. |
|
Add event code for ButtonX | Follow same procedure
as above.
Bug: ButtonX1_Click is never called. |
Eric Harmon observed that while Click didn't work from ButtonX in a document, KeyPressed does! (This happens to be doable in Word because you can get ButtonX to receive keypresses -- in other environments you may not be able to) This led me to try the following tests. You can readily imagine similar variants for other base controls.
Test | Result/Conclusion |
Check OnClick wiring
to container: Call OnClick from KeyPressEvent:
procedure TButtonX.KeyPressEvent( Sender: TObject; var Key: Char); var TempKey: Smallint; begin TempKey := Smallint(Key); if FEvents <> nil then FEvents.OnKeyPress(TempKey); Key := Char(TempKey); if FEvents <> nil then FEvents.OnClick; end; |
Successfully calls VBA ButtonX1_Click proc. This indicates that the problem is not with some screw-up in event IDs or other issues to do with wiring the ActiveX events to the container (Word). |
Check whether
ClickEvent is ever called.
procedure TButtonX.ClickEvent(Sender: TObject); begin Beep; if FEvents <> nil then FEvents.OnClick; end; |
ClickEvent gets called when ButtonX is on a UserForm, but not when ButtonX is inserted in a document page. |
Attempt to trace
what's happening (or not) in VCL
procedure TButton.CNCommand(var Message: TWMCommand); begin if Message.NotifyCode = BN_CLICKED then Click; end; |
This is as far back as
I can figure out the difference. CNCommand gets called when ButtonX is on a UserForm, but not when ButtonX is inserted in a document page. Unfortunately, I don't understand the mechanism that Delphi uses to call CNCommand, hence I'm stumped when it comes to figuring out what preparatory state is different between the two cases. |
Other Misbehaviors noted for ButtonX on Word 97 document page. | 1. Iimproper painting
in Design mode 2. In Run mode, once ButtonX is selected, you can't change the focus to the document text by clicking the text. Ie: the ButtonX won't "relinquish focus". You can only escape by doing something more extreme, like changing back to Design mode, or changing Word's viewing mode from "Page Layout" to "Normal". |
1. DAX-control-to-container wiring is OK. Ie: this is not an issue with event IDs, or basic failure to connect container event procs to DAX control.
2. Delphi VCL Click Handling: The main symptom shows up as a problem with how the VCL is handling Click. But this is probably due to some other VCL state that is causing Click not to propagate, an impression reinforced by the other misbehaviors noted.
As best I can conceive, what needs to be reasoned out is:
1. Review what preceding initialization or state normally causes TButton.CNCommand to get called (say in the UserForm "good" case).
2. Observe what aspects of this state are failing to be prepared in the document-page case.
3. Determine what code is supposed to do that preparation, and how it is called in the "good" case.
4. Determine what ActiveX interface calls are activating that preparation code in the "good" case, and why they are not being called in the "bad" case.
This may uncover that the DAX designers made some assumptions about which ActiveX interfaces would be invoked by containers to switch between component states, and a new understanding that in Office docs this is handled some other way.
To email me about this: graham@wideman-one.com
Logged as Borland Bug 433150
I found the following map helpful in figuring out how the DAX wrapper functions. It shows:
The tests above indicate that all of this works as intended. Instead, the non-Click problem is with TButton.Click never being called from the bowels of the TButton VCL code (following a Left-Mouse-Button message).
Note the color codes indicate which lines of initializing code hook up which connections.