-
-
Save bsommardahl/8605208 to your computer and use it in GitHub Desktop.
public interface IRtdClient | |
{ | |
object GetValue(params object[] args); | |
} | |
public class RtdClient : IRtdClient | |
{ | |
readonly string _rtdProgId; | |
static IRtdServer _rtdServer; | |
public RtdClient(string rtdProgId) | |
{ | |
_rtdProgId = rtdProgId; | |
} | |
public object GetValue(params object[] args) | |
{ | |
const int topicCount = 1; | |
var rnd = new Random(); | |
var topicId = rnd.Next(int.MaxValue); | |
var rtdServer = GetRtdServer(); | |
rtdServer.ConnectData(topicId, args, true); | |
object val = null; | |
while (val == null) | |
{ | |
var alive = rtdServer.Heartbeat(); | |
if (alive != 1) | |
GetRtdServer(); | |
else | |
{ | |
var refresh = rtdServer.RefreshData(topicCount); | |
if (refresh.Length <= 0) continue; | |
if (refresh[0, 0].ToString() == topicId.ToString()) | |
{ | |
val = refresh[1, 0]; | |
} | |
} | |
} | |
rtdServer.DisconnectData(topicId); | |
return val; | |
} | |
IRtdServer GetRtdServer() | |
{ | |
if(_rtdServer==null) | |
{ | |
Type rtd = Type.GetTypeFromProgID(_rtdProgId); | |
_rtdServer = (IRtdServer)Activator.CreateInstance(rtd); | |
} | |
return _rtdServer; | |
} | |
} | |
[ComImport, | |
TypeLibType((short)0x1040), | |
Guid("EC0E6191-DB51-11D3-8F3E-00C04F3651B8")] | |
public interface IRtdServer | |
{ | |
[MethodImpl(MethodImplOptions.InternalCall, MethodCodeType = MethodCodeType.Runtime), DispId(10)] | |
int ServerStart([In, MarshalAs(UnmanagedType.Interface)] IRTDUpdateEvent callback); | |
[return: MarshalAs(UnmanagedType.Struct)] | |
[MethodImpl(MethodImplOptions.InternalCall, MethodCodeType = MethodCodeType.Runtime), DispId(11)] | |
object ConnectData([In] int topicId, [In, MarshalAs(UnmanagedType.SafeArray, | |
SafeArraySubType = VarEnum.VT_VARIANT)] ref object[] parameters, [In, Out] ref bool newValue); | |
[return: MarshalAs(UnmanagedType.SafeArray, SafeArraySubType = VarEnum.VT_VARIANT)] | |
[MethodImpl(MethodImplOptions.InternalCall, MethodCodeType = MethodCodeType.Runtime), DispId(12)] | |
object[,] RefreshData([In, Out] ref int topicCount); | |
[MethodImpl(MethodImplOptions.InternalCall, MethodCodeType = MethodCodeType.Runtime), DispId(13)] | |
void DisconnectData([In] int topicId); | |
[MethodImpl(MethodImplOptions.InternalCall, MethodCodeType = MethodCodeType.Runtime), DispId(14)] | |
int Heartbeat(); | |
[MethodImpl(MethodImplOptions.InternalCall, MethodCodeType = MethodCodeType.Runtime), DispId(15)] | |
void ServerTerminate(); | |
} | |
[ComImport, | |
TypeLibType((short) 0x1040), | |
Guid("A43788C1-D91B-11D3-8F39-00C04F3651B8")] | |
public interface IRTDUpdateEvent | |
{ | |
[MethodImpl(MethodImplOptions.InternalCall, MethodCodeType = MethodCodeType.Runtime), DispId(10), | |
PreserveSig] | |
void UpdateNotify(); | |
[DispId(11)] | |
int HeartbeatInterval { [MethodImpl(MethodImplOptions.InternalCall, MethodCodeType = MethodCodeType.Runtime), DispId(11)] | |
get; [param: In] | |
[MethodImpl(MethodImplOptions.InternalCall, MethodCodeType = MethodCodeType.Runtime), DispId(11)] | |
set; } | |
[MethodImpl(MethodImplOptions.InternalCall, MethodCodeType = MethodCodeType.Runtime), DispId(12)] | |
void Disconnect(); | |
} |
It my case of server (TwsRtdServer) I couldn't understand for a long time,
why data isn't going, response is empty array...
And explicit starting of server helped me,
I added that line:
IRtdServer GetRtdServer()
{
if(_rtdServer==null)
{
Type rtd = Type.GetTypeFromProgID(_rtdProgId);
_rtdServer = (IRtdServer)Activator.CreateInstance(rtd);
// ++
_rtdServer.startServer(/*Define class with dummy IRTDUpdateEvent implementation and pass it HERE */);
// ++
}
return _rtdServer;
}
Only after that everything worked. Good if you have access to sources of the server.
It my case of server (TwsRtdServer) I couldn't understand for a long time,
why data isn't going, response is empty array...And explicit starting of server helped me,
I added that line:IRtdServer GetRtdServer() { if(_rtdServer==null) { Type rtd = Type.GetTypeFromProgID(_rtdProgId); _rtdServer = (IRtdServer)Activator.CreateInstance(rtd); // ++ _rtdServer.startServer(/*Define class with dummy IRTDUpdateEvent implementation and pass it HERE */); // ++ } return _rtdServer; }
Only after that everything worked. Good if you have access to sources of the server.
@Neznakomec
I could demonstrate what your RTD client looks like, I'm facing the same problem with the exception of calling IRtdServer.ConnectData(Int32
This looks like the best I can find on the web about code to do this. But for some reason I cannot pass the topics
args
at all.Having this on MS-Excel:
=RTD("rtdtrading.rtdserver",, "WINZ20_F_0", "HOR")
This formula works on Excel and pulls fresh data.I then tried to instantiate the object with:
var handler = new RtdClient("rtdtrading.rtdserver");
So far, so good. But then, when I try to
var valList = handler.GetValue(new object[] { "WINZ20_G_0", "HOR" });
I get a big Catastrophic failure (0x8000FFFF (E_UNEXPECTED)) from
IRtdServer.ConnectData(Int32 topicId, Object[]& parameters, Boolean& newValue)
, line 24 in the code above.If I try to use
new string[] { "WINZ20_G_0", "HOR" });
, then the error changes to Specified array was not of the expected type, happening a bit deeper, but I believe still beforeConnectData()
is actually run, as the call stack suggestes:at System.StubHelpers.MngdSafeArrayMarshaler.ConvertSpaceToNative(IntPtr pMarshalState, Object& pManagedHome, IntPtr pNativeHome) at ProfitRTDAnalyzer.Program.IRtdServer.ConnectData(Int32 topicId, Object[]& parameters, Boolean& newValue)
Hi @avengerx, to solve this problem, I do the follwing:
Create a a new class to implement UpdateEvent:
public class UpdateEvent : IRTDUpdateEvent
{
public long Count { get; set; }
public int HeartbeatInterval { get; set; }
public UpdateEvent()
{
// Do not call the RTD Heartbeat()
// method.
HeartbeatInterval = -1;
}
public void Disconnect()
{
// Do nothing.
}
public void UpdateNotify()
{
Count++;
}
and then, replace it into GetRtdServer function
IRtdServer GetRtdServer()
{
if (_rtdServer == null)
{
Type rtd = Type.GetTypeFromProgID(_rtdProgId);
_rtdServer = (IRtdServer)Activator.CreateInstance(rtd);
// Create the updateEvent.
UpdateEvent updateEvent = new UpdateEvent();
_rtdServer.ServerStart(updateEvent);
}
return _rtdServer;
}
Now it's working for me.
@julianozucatti I can give my dirty sandbox application
where I tried to make RTD Client for "TWS RTD Server API".
What is good here, you can see the sources of this API and what is going
with your requests.
This looks like the best I can find on the web about code to do this. But for some reason I cannot pass the topics
args
at all.Having this on MS-Excel:
=RTD("rtdtrading.rtdserver",, "WINZ20_F_0", "HOR")
This formula works on Excel and pulls fresh data.I then tried to instantiate the object with:
var handler = new RtdClient("rtdtrading.rtdserver");
So far, so good. But then, when I try to
var valList = handler.GetValue(new object[] { "WINZ20_G_0", "HOR" });
I get a big Catastrophic failure (0x8000FFFF (E_UNEXPECTED)) from
IRtdServer.ConnectData(Int32 topicId, Object[]& parameters, Boolean& newValue)
, line 24 in the code above.If I try to use
new string[] { "WINZ20_G_0", "HOR" });
, then the error changes to Specified array was not of the expected type, happening a bit deeper, but I believe still beforeConnectData()
is actually run, as the call stack suggestes: