views:

2026

answers:

2

I admit I know enough about COM and IE architecture only to be dangerous. I have a working C# .NET ActiveX control similar to this:

using System;
using System.Runtime.InteropServices;
using BrowseUI;
using mshtml;
using SHDocVw;
using Microsoft.Win32;

    namespace CTI
    {
        public interface CTIActiveXInterface
        {
            [DispId(1)]
            string GetMsg();
        }

        [ComVisible(true), ClassInterface(ClassInterfaceType.AutoDual)]
        public class CTIActiveX : CTIActiveXInterface
        {

            /*** Where can I get a reference to SHDocVw.WebBrowser? *****/
            SHDocVw.WebBrowser browser;

            public string GetMsg()
            {
                return "foo";
            }
        }
    }

I registered and created a type library using regasm:

regasm CTIActiveX.dll /tlb:CTIActiveXNet.dll /codebase

And can successfully instantiate this in javascript:

var CTIAX = new ActiveXObject("CTI.CTIActiveX");
alert(CTIAX.GetMsg());

How can I get a reference to the client site (browser window) within CTIActiveX? I have done this in a BHO by implementing IObjectWithSite, but I don't think this is the correct approach for an ActiveX control. If I implement any interface (I mean COM interface like IObjectWithSite) on CTIActiveX when I try to instantiate in Javascript I get an error that the object does not support automation.

+2  A: 

First, your interface needs ComVisible(true) in order to be seen by the calling script (this is probably causing the error).

Second, add a .NETreference in your project to "Microsoft.mshtml". This will import the COM interfaces for various IE-related things (windows, HTML documents, etc.)

Then, you need to add a property of type IHtmlDocument2 to your interface:

IHtmlDocument2 Document { set; }

...implement it in your class:

public IHtmlDocument2 Document
{
  set { _doc = value;}
}

...call it from script

CTIAX.Document = document;

...once you have stored a reference to the document, you can use it at will to get to the window, other frames, or any part of the HTML DOM that you wish.

jlew
Good answer that helps me with another problem; however it isn't exaclty what I'm looking for.IHTMLDocument2.parentWindow returns an mshtml.IHTMLWindow2, not SHDocVw.WebBrowser.I'm looking for SHDocVw.WebBrowser so I can get to the GetProperty and PutProperty methods to communicate with a BHO.
Also, to be clear, the example in the question does work. ComVisible(true) does not appear to be needed if the implementing class specifies ComVisible as in my example. It only breaks if I explicitly implement a COM interface such as IObjectWithSite.
+1  A: 

I have found a workable solution. It's not ideal because it relies on matching the location URL of the IE window to get the correct container, but it does work. In my case I'm using a special value on the query string to make sure I get the right window.

This gets a reference to SHDocVw.InternetExplorer, which exposes the same GetProperty and PutProperty that SHDocVw.WebBrowser does:

private InternetExplorer GetIEWindow(string url)
{
    SHDocVw.ShellWindowsClass sh = new ShellWindowsClass();
    InternetExplorer IE;

    for (int i = 1; i <= sh.Count; i++)
    {
        IE = (InternetExplorer)sh.Item(i);
        if (IE != null)
        {
            if (IE.LocationURL.Contains(url))
            {
                return IE;
            }
        }
    }

    return null;
}
How did you get that url in the first place?
Rick Minerich