views:

32

answers:

1

Hello All

This issue is related to a blog post by Kenny Kerr on "Excel RTD Servers: C# Interfaces", which can be found here, that should allow you to build an Excel RTD server without including a reference to any specific Excel type library; having to include a reference makes your RTD server Excel version specific (forwards compatible, but not backwards compatible, I believe). Not having any dependency on an Excel type library simplifies deployment of your RTD to machines with different versions of Excel (XP, 2003, 2007, and 2010).

Now, not having an RTD reference a specific Excel type library to obtain the interfaces IRtdServer and IRTDUpdateEvent is very nice. But I am having the devil of a time making Kenny's suggestion work.

Here's what I have done:

1) Added IRtdServer.cs and IRTDUpdateEvent.cs to my RTD project and put the interface definitions from your blog into those files (not changing the GUIDs).
2) Removed any reference to an Excel type library.
3) Build and regasm OK.

I have small test harnesses in VBA and VBScript that tests my MyRTD.dll RTD server by emulating the calls made by Excel to the RTD. Here are the relevant snippets of code:

First VBA:

Const RTDProgID As String = "MyRTD.RTD"
Const UpdateEventProgID As String = "MyRTD.UpdateEvent"

' Create the RTD server object.
Dim rtd As Object
Set rtd = CreateObject(RTDProgID)

' Start the RTD server, passing in a callback object.
Dim callback As Object
Set callback = CreateObject(UpdateEventProgID)
Dim status As Long
status = rtd.ServerStart(callback)    <----    Fails here.

This code fails on the last line with the message along the lines of "Cannot cast MyRTD.UpdateEvent to MyRTD.IRTDUpdateEvent". Though class UpdateEvent implements the interface IRTDUpdateEvent.

Second VBScript:

' ProgIDs for COM components.
Const RTDProgID = "MyRTD.RTD"
Const UpdateEventProgID = "MyRTD.UpdateEvent"

' Real-time data (RTD) object
Dim rtd
Set rtd = CreateObject(rtdID)

' Callback object. This is how
' the RTD would notify Excel of
' new data updates.
Dim callback
Set callback = CreateObject(UpdateEventProgID)

' Start the RTD server, passing in
' the callback object.
Dim status
status = rtd.ServerStart(callback)    <----    Fails here.

This code fails on the last line with the message along the lines of "Invalid procedure call or argument" (which I assume results from callback being of the wrong type/interface).

Any help would be appreciated.

             Best regards, Andrew Sheppard
A: 

After doing some more work on this and exchanging some e-mails with Kenny Kerr it became clear that the problem arose because interfaces with the same GUID and using ComImport are not treated as the same thing if they are defined in different assemblies, even if defined identically.

I have both an in-process (DLL) and out-of-process (EXE) real-time data (RTD) server that shares the exact same code base; that is, same RTD, different execution model. I had taken IRTDUpdateEvent and put it in an assembly of its own. IRTDUpdateEvent is, of course, implemented by the Excel object library; but I define it myself so I don't have to make my RTD depend on a specific version of Excel (2002, 2003, 2007, 2010) making deployment simpler.

This would not be a problem if I were using C# 4.0 because of the new feature of "type equivalence". You can make classes/interfaces with the same GUID behave as though there are the same (which makes more sense), regardless of where they are defined. But my target platform is versions prior to 4.0.

The fix was to move IRTDUpdateEvent from its own assembly back into the DLL and EXE assemblies. That done, both DLL and EXE RTD servers work with Excel and VBA and VBScript and C# clients.

Shep