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 |