| allegro-cl archives 2003-8-22 | home index prev H thread prev K thread-next J next L |
|
From: Thomas R. Hinrichs Subject: embedding ActiveX controls in Common Graphics windows Date: 2003-8-22 17:06
I'm getting stuck trying to embed a web browser control in a Lisp window (in Franz Allegro 6.2, Common Graphics). Has anybody successfully embedded an ActiveX control in a Common Graphics window?
Franz has a nice example of using OLE to control Internet Explorer, but I would really like it embedded in the window so I can control its size and location and eliminate the navbar and so forth. (My main goal is to display equations in MathML, so I don't want user controls & etc)
I've gotten reasonably far, but the documentation is a bit vague about a few things that should be simple.
The first thing I realized is that I don't want to embed I.E. itself, since that's an application. I want to embed the reusable Web Browser Control, which is contained in shodocvw.dll. Spelunking the registry, I discovered the VersionIndependentProgID is "Shell.Explorer" and its classid is "{8856F961-340A-11D0-A96B-00C04FD705A2}".
Now it's going to need to be an inproc server and the autotool should be a subclass of control, so we want to require :ocx-container and define the client interface :IViewObject2, since this is a visible control.
Here I ran into some problems with ACL: When you call (require :ocx-container) it barfs because it tries to require :olewin, a module that doesn't exist. I can only assume that this is a typo and work around it by explicitly providing :olewin.
Next, it complains because it tries to load autotool.fasl, but somebody left off the ".fasl" so it can't find it. I worked around that by manually loading it beforehand.
Based on these workarounds, I'm starting to think nobody's done this before...
I managed to make an autotool that seems like it should be the right thing (I can query it & etc), but I'm stuck trying to figure out what should be the site object, what should be the container of the site object & etc.
My test code below dies when it gets to ole:install-control because it calls ole:get-Container with a clos instance and a number. Something isn't right there and I have no clue if it's how I set it up or if it's a bug in the ole code. Does anybody have any insight into this? It would be *really* nice to be able to embed ActiveX controls in Lisp windows.
Thanks,
Tom Hinrichs
Computer Science Department
Northwestern University
(in-package :cg-user)
(eval-when (compile eval)
(require :ole-dev))
(eval-when (load eval)
(require :ole)
(load "sys:;ole;client;autotool.fasl") ;; workaround bug in Franz' ole
(provide :olewin) ;; workaround another bug in Franz' ole
(ole:require-modules :ocx-container) ;; now this should work
(ole:def-client-interface :IViewObject2) ;; we need this interface for visible activeX controls
)
(defparameter ie-classid
(ole:unique-guid "{0002DF01-0000-0000-C000-000000000046}"))
(defun get-autotool ()
(setf (sys:gsgc-switch :print) nil)
;; Check the registry to be sure the explorer is out there
(ole:with-open-registry-key (ie-reg ole:rkey-classes-root
`("CLSID" ,(ole:guid-name ie-classid))
:error-return nil)
(when (null ie-reg)
(format t "Sorry, no explorer on this system~2%")
(return-from get-autotool nil)))
(ole:start-ole) ; in case ole not yet started
(ole:ask-for-autotool
"Shell.Explorer"
ole:CLSCTX_INPROC_SERVER
'ole:control ; make the autotool a subclass of control
:ole-classid "{8856F961-340A-11D0-A96B-00C04FD705A2}"))
(defun close-autotool (autotool)
(ole:auto-method autotool :quit)
(ole:release autotool))
(defmacro net-wait (tool)
`(do () ((not (ole::auto-getf ,tool :Busy)))))
(defun do-query (tool)
(ole::query-interface tool :IViewObject2))
(defun go-to-url (tool where)
(cond ((symbolp where)
(setq where (symbol-name where)))
((not (stringp where))
(format t "destination must be entered as a symbol or string~%")
(return-from go-to-url)))
(ole:auto-method tool :navigate2
where ; url
0 ; flags
"IE Window" ; target frame name
0 ; postdata
0) ; extra headers
(net-wait tool))
;;;
;;; Define the container & control classes
;;; (Is windows-widget a reasonable thing to subclass?)
(defclass activex-pane (cg::widget-window ole:container-mixin) ())
(defclass activex-control (cg::windows-widget ole:site-mixin) ())
(defmethod widget-device ((item activex-control) dialog)
(declare (ignore dialog))
'activex-pane)
(defmethod device-open ((widget-window activex-pane) options)
(apply #'cg::open-widget-window widget-window options))
(defmethod cg::widget-set-value ((widget-window activex-pane)
item new-value old-value recursive-p)
(declare (ignore item new-value old-value recursive-p))
(and (component widget-window)
(cg::InvalidateRect (cg::handle! widget-window) ct::hnull cg::FALSE))
t)
(defun make-ie-control ()
(make-instance 'activex-control
:name :my-activeX-control
:left 50
:top 100
:height 300
:width 500))
(defun make-parent-window ()
"Make a plain window to hold the ActiveX control"
(make-window :test-window
:owner (screen *system*)
:class 'dialog
:exterior (make-box 107 139 932 666)
:close-button t
:state :normal))
;;;
;;; Testing
;;;
(defparameter *autotool* nil "The ole autotool")
(defparameter *activex-site* nil "The site object")
(defparameter *browserwin* nil "The toplevel window")
(defun test-embedded-browser ()
(setf *autotool* (get-autotool))
(setf (ole::auto-getf *autotool* :visible) t)
(setf *activex-site* (make-ie-control))
(setf *browserwin* (make-parent-window))
(add-component *activex-site* *browserwin*)
(ole:install-control *autotool* *activex-site*)
(go-to-url *autotool* "http://www.google.com"))
;;; End
|