views:

34

answers:

2

I have an ATL ActiveX control that raises three events (Connected, Authenticated, Disconnected) which need to be handled in IE/JavaScript. So far as I can tell, I'm doing everything right, specifically:

(1) I've told ATL to implement the IProviderClassInfo2 interface, as described here.

(2) I've implemented connection points within my ATL project by following the directions here. I now have a CProxy_IMyControlEvents class, with the appropriate Fire_Authenticated(), Fire_Connected() and Fire_Disconnected() implementations. They look more-or-less like this:

template<class T>
class CProxy_IVncServerControlEvents :
 public ATL::IConnectionPointImpl<T, &__uuidof(_IVncServerControlEvents)>
{
public:
HRESULT Fire_Connected()
 {
  HRESULT hr = S_OK;
  T * pThis = static_cast<T *>(this);
  int cConnections = m_vec.GetSize();

  for (int iConnection = 0; iConnection < cConnections; iConnection++)
  {
   pThis->Lock();
   CComPtr<IUnknown> punkConnection = m_vec.GetAt(iConnection);
   pThis->Unlock();

   IDispatch * pConnection = static_cast<IDispatch *>(punkConnection.p);

   if (pConnection)
   {
    CComVariant varResult;

    DISPPARAMS params = { NULL, NULL, 0, 0 };
    hr = pConnection->Invoke(1, IID_NULL, LOCALE_USER_DEFAULT, DISPATCH_METHOD,  &params, &varResult, NULL, NULL);
   }
  }
  return hr;
 }
};

(3) I'm calling Fire_Connected() et al at the appropriate points in my code (on the main UI thread), and the debugger confirms that they're firing.

(4) I'm instantiating the resulting control in an HTML page, and am able to call methods on it. These methods do what they're supposed to do and return successfully.

<object id="MyControl" classid="CLSID:42832F4C-3480-4450-A6B5-156B2EFC408F" codebase="http://localhost:51150/Resources/MyControlInstaller.CAB" />

<script language="javascript">
var myControl = document.getElementById("MyControl");
myControl.connect();
</script>

(5) I'm wiring up the events to JavaScript function handlers. This seems to be where I'm running into trouble. I've seen three different ways of doing it referenced, and none of them seem to be working for me.

<!-- Method #1 -->
<script language="javascript">
myControl.attachEvent('Connected', onConnected);
myControl.attachEvent('Disconnected', onDisconnected);
myControl.attachEvent('Authenticated', onAuthenticated);
</script>

<!-- Method #2 -->
<script language="javascript">
myControl.Connected = onConnected;
myControl.Disconnected = onDisconnected;
myControl.Authenticated = onAuthenticated;
</script>

<!-- Method #3 -->
<script for="MyControl" language="javascript">
function MyControl::Connected()
{
    onConnected();
}

function MyControl::Disconnected()
{
    onDisconnected();
}

function MyControl::Authenticated()
{
    onAuthenticated();
}
</script>

I've ready up on everything I can find on the Internet about how to do this, and it doesn't seem like I'm leaving anything out. So I must be doing something stupid. Any suggestions about what I might be doing wrong or how to troubleshoot it?

A: 

First, all the examples I see from MSDN use "JScript" as the language, not "javascript", but I don't know if that makes a difference (perhaps both are accepted, but technically MS's implementation of ECMA is JScript, I believe).

As a variation on your method 3, maybe try specifying the EVENT attribute to the script:

<script for="MyControl" EVENT="Connected()" language="JScript">
  onConnected();
</script>

<script for="MyControl" EVENT="Disconnected()" language="JScript">
  onDisconnected();
</script>

<script for="MyControl" EVENT="Authenticated()" language="JScript">
  onAuthenticated();
</script>
Mike Ellery
Thanks for the suggestions. Unfortunately, I tried them out, and the events still aren't firing. Continuing to look around...
Ken Smith
+1  A: 

I figured it out by looking at the Circ sample project that comes with VS2010. Turns out that (at least in my case) the ATL event wizard didn't update the IDL for the dispatch interface. Life was good once I updated the dispinterface section of the IDL file from this:

dispinterface _IMyControlEvents
{
    properties:
    methods:
};

To this:

dispinterface _IMyControlEvents
{
    properties:
    methods:
        [id(1)] void Connected();
        [id(2)] void Disconnected();
        [id(3)] void Authenticated();
};

Once I did that, I was able to get the various different event handling syntaxes to work.

Ken Smith