Problem with RTD Server

Add-in Express™ Support Service
That's what is more important than anything else

Problem with RTD Server
code returning "Unrecognized" in Excel 
Subscribe
Mike Ianni




Posts: 4
Joined: 2025-01-12
I'm a new programmer trying to create my own RTD Server that has two data sources (stock data). I was able to register a DLL that implemented IRTDServer directly however my code returns "Unrecognized" in Excel. Not sure what I'm doing wrong. I set up the data sources with similar topics that I would actually use but then inserted some random data which should appear with the following formulas: =RTD("MyRTDServer.RTDServerModule",, "NxCore2", "E", "IBM","", "QUOTE", "", "", "LAST") and =RTD("MyRTDServer.RTDServerModule",, "ExcelMD", "someWorkbook.xlsm", "Sheet1", "TSLA", "LAST")here is the code I'm using (C#) using[CODE]using System;
using System.Collections.Generic;
using System.Runtime.InteropServices;
using AddinExpress.RTD;

namespace MyRTDServer
{
[Guid("11111111-2222-3333-4444-555555555555")]
[ProgId("MyRTDServer.RTDServerModule")]
public partial class RTDServerModule : ADXRTDServerModule, IRtdServer
{
// Store RTD topics by topicId
private readonly Dictionary<int, object[]> _topics = new Dictionary<int, object[]>();

public RTDServerModule()
{
// Designer partial likely defines InitializeComponent(), components, etc.
InitializeComponent();
}

// ------------------------------------------------------------
// IRtdServer #1: ConnectData
// ------------------------------------------------------------
public object ConnectData(int topicId, System.Array strings, ref bool newValues)
{
// Convert System.Array -> object[]
object[] parameters = new object[strings.Length];
for (int i = 0; i < strings.Length; i++)
parameters[i] = strings.GetValue(i);

_topics[topicId] = parameters;
// Indicate immediate new data
newValues = true;

// Return initial string
return $"Initial data for topic {topicId}";
}

// ------------------------------------------------------------
// IRtdServer #2: DisconnectData
// ------------------------------------------------------------
public void DisconnectData(int topicId)
{
_topics.Remove(topicId);
}

// ------------------------------------------------------------
// IRtdServer #3: Heartbeat
// ------------------------------------------------------------
public int Heartbeat()
{
// Return 0 => still alive
return 0;
}

// ------------------------------------------------------------
// IRtdServer #4: RefreshData
// Excel calls this with a single integer "topicCount" in your library
// We'll interpret that as "the topicId to refresh"
// ------------------------------------------------------------
public object RefreshData(int topicId)
{
if (_topics.TryGetValue(topicId, out object[] pars))
{
if (pars.Length == 0)
return "#NO_PARAMETERS";

// The first argument should be NxCore2 or ExcelMD
string dataSource = pars[0]?.ToString();

switch (dataSource)
{
case "NxCore2":
return NxCoreHelper.GetValue(pars);
case "ExcelMD":
return ExcelMDHelper.GetValue(pars);
default:
return $"#UNKNOWN_SOURCE_{dataSource}";
}
}
return "#UNKNOWN_TOPIC";
}

// ------------------------------------------------------------
// IRtdServer #5: ServerStart
// ------------------------------------------------------------
public void ServerStart(IRTDUpdateEvent callback)
{
// NxCore or ExcelMD init if needed
}

// ------------------------------------------------------------
// IRtdServer #6: ServerTerminate
// ------------------------------------------------------------
public void ServerTerminate()
{
// NxCore or ExcelMD cleanup if needed
}

// -------------------------------------------------------------------
// NxCoreHelper: parse NxCore’s placeholders and return random "LAST"
// -------------------------------------------------------------------
private static class NxCoreHelper
{
public static object GetValue(object[] pars)
{
// NxCore formula example:
// "NxCore2", "E", "IBM", "", "QUOTE", "", "", "LAST"
// indices: 0 1 2 3 4 5 6 7

if (pars.Length < 8)
return "#INSUFFICIENT_ARGS_NXCORE";

// parse them
string eqOrOpt = pars[1]?.ToString(); // e.g. "E"
string symbol = pars[2]?.ToString(); // e.g. "IBM"
// pars[3] might be blank
string dataType = pars[4]?.ToString(); // "QUOTE"
// pars[5], pars[6] might be blank
string field = pars[7]?.ToString(); // "LAST"

if (field?.ToUpper() == "LAST")
{
// Return a random last price for demonstration
Random rnd = new Random();
double lastPrice = 50 + rnd.NextDouble() * 150; // 50-200
return $"NxCore {symbol} {field} = {lastPrice:F2}";
}
// If not "LAST", return placeholder
return $"NxCore {symbol} {field} not implemented";
}
}

// -------------------------------------------------------------------
// ExcelMDHelper: parse minimal arguments and return random "LAST"
// -------------------------------------------------------------------
private static class ExcelMDHelper
{
public static object GetValue(object[] pars)
{
// ExcelMD formula example:
// "ExcelMD", "someWorkbook.xlsm", "Sheet1", "TSLA", "LAST"
// indices: 0 1 2 3 4

if (pars.Length < 5)
return "#INSUFFICIENT_ARGS_EXCELMD";

string workbook = pars[1]?.ToString(); // "someWorkbook.xlsm"
string sheet = pars[2]?.ToString(); // "Sheet1"
string symbol = pars[3]?.ToString(); // "TSLA"
string field = pars[4]?.ToString(); // "LAST"

if (field?.ToUpper() == "LAST")
{
// Return a random last price
Random rnd = new Random();
double lastPrice = 100 + rnd.NextDouble() * 50; // 100-150
return $"ExcelMD {symbol} {field} = {lastPrice:F2}";
}
return $"ExcelMD {symbol} {field} not implemented";
}
}
}
}
Posted 12 Jan, 2025 15:19:07 Top
Andrei Smolin


Add-in Express team


Posts: 19048
Joined: 2006-05-11
Hello Mike,

You can find a working example at https://www.add-in-express.com/creating-addins-blog/sample-com-addin-projects-outlook-excel-powerpoint-word/.

Check section Your first Excel RTD server in the Add-in Express manual; find the PDF file in folder {Add-in Express}\Docs on your development PC.

Regards from Poland (GMT+1),

Andrei Smolin
Add-in Express Team Leader
Posted 13 Jan, 2025 11:22:14 Top
Mike Ianni




Posts: 4
Joined: 2025-01-12
I think I see my issue - I was mixing a IRTDServer approach with the ADXRTDServerModule. Anyhow, can I still use your Module if I require unlimited symbols. Could I create a ADXRTDTopic for each symbol programmatically at runtime for each new symbol (could be 100,000) or would you use a single dynamic ADXRTDTopic and override OnRefreshData? Or should I simply go to a Full IRtdServer approach??
Posted 14 Jan, 2025 00:55:11 Top
Andrei Smolin


Add-in Express team


Posts: 19048
Joined: 2006-05-11
Hello Mike,

I suppose you are looking for using an asterisk in the ADXRTDTopic.StringsNN property. Note that behind the scene, Add-in Express creates an ADXRTDTopic for every given combination of strings (the strings identify the topic) so that when Add-in Express calls e.g. MyTopic_RefreshData, it passes it the exact ADXRTDTopic that caused this event; see the Sender parameter of the event handler method.

It is possible to enter an asterisk (*) in any of the String## properties. When there is no ADXRTDTopic corresponding to the identifying strings entered by the user, Add-in Express creates a new ADXRTDTopic and passes it to the RefreshData event handler of the topic containing an asterisk (*). In that event, you can cast the Sender argument to ADXRTDTopic and get actual strings from its String## properties.


Regards from Poland (GMT+1),

Andrei Smolin
Add-in Express Team Leader
Posted 14 Jan, 2025 10:02:59 Top
Mike Ianni




Posts: 4
Joined: 2025-01-12
I think I see my issue - I was mixing a IRTDServer approach with the ADXRTDServerModule. Anyhow, can I still use your Module if I require unlimited symbols. Could I create a ADXRTDTopic for each symbol programmatically at runtime for each new symbol (could be 100,000) or would you use a single dynamic ADXRTDTopic and override OnRefreshData? Or should I simply go to a Full IRtdServer approach??
Posted 14 Jan, 2025 18:23:46 Top
Mike Ianni




Posts: 4
Joined: 2025-01-12
Andrei: thanks that worked well. I actually had a server running using this * method with 10,000 rtd formulas and it performed really well.

So a single data source works fine (with 5 parameters). However, when I add a second data source (with 8 parameters)—either as a separate wildcard topic or by parsing both formats in one wildcard—I get #N/A or ‘unrecognized’ errors in Excel. The goal is to have two separate data sources that work with the RTD server.

I’ve verified the ProgID, registry, bitness, and formula syntax (two commas after the RTD server name). The single-source version works perfectly, so the basics are right. But mixing two different parameter counts consistently fails.

Has anyone successfully run two data sources (with different parameter counts) under a single Add-in Express RTD module? If so, how did you configure the wildcard topics (or a single catch-all wildcard) to avoid #N/A errors?”
Posted 14 Jan, 2025 18:36:31 Top
Andrei Smolin


Add-in Express team


Posts: 19048
Joined: 2006-05-11
Hello Mike,

I've overlooked your question somehow; really sorry for this.

I don't understand your configuration. I believe, you should debug your code that handles parameters supplied and produces a result.

Regards from Poland (GMT+1),

Andrei Smolin
Add-in Express Team Leader
Posted 31 Jan, 2025 12:27:15 Top