embedding ActiveX controls in Common Graphics windows

"Thomas R. Hinrichs" <[email protected]>
Newsgroups gmane.lisp.allegro
Message-ID <[email protected]>
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
lmpx.com only provides a reader for public news (NNTP) servers. It is not affiliated with the servers or forums shown here and is not responsible for the content of articles, which is written by their respective authors.