Jump to content
Tom Next - Daytrading Community

IEasyLanguageObject, Zugriff via C#


Recommended Posts

MC8.8

 

Ich bin dabei meine Algorithmen in eine C#-DLL auszulagern und habe mir entsprechend eine Interop-DLL in C++ geschrieben, die quasi als Wrapper für die C#-DLL agiert. In MC kann ich {self} als Referenz via IEasyLanguageObject übergeben und auch in C++ verwerten, nur scheitert es an der Weitergabe an C#.

 

Die wichtigsten Punkte dazu folgend im Code. Lediglich die Übergabe von IEasyLanguageObject an C# ist so noch verkehrt. Möglicherweise ist die Lösung relativ einfach. Der MC-Support lieferte keine wirklich hilfreichen Informationen. Es wurde sogar die grundsätzliche Möglichkeit der objektorientierten Nutzung in den DLLs verneint. Ich habe dann auf das MC-Forum verwiesen, wo diesbezueglich die ersten Fragen bereits 2007 beantwortet und mit Support unterstüzt wurden. Wichtig ist die CLR-Unterstützung in der Interop-DLL. Das ist bei den Projekteigenschaften mit /clr konfiguriert.

 

// ----- C++ Interop-DLL

#include "stdafx.h"
#include "TSLib_Interop.h"
#include <comdef.h>

#import "C:\Program Files\TS Support\MultiCharts64\PLKit.dll" no_namespace

double __clrcall TestR(IEasyLanguageObject* pELObj, double _2) {
  return TS::Class1::TestR(pELObj, _2);
}

// ------ C# DLL
using PLKit;

public class Class1
{
    public static double TestR(ref IEasyLanguageObject elRef, double len)
    {
        return 2;
    }
}
Link to comment
Share on other sites

Mittlerweile hat sich einiges getan. Um in C# die Schnittstelle IEasyLanguageObject zu erreichen muss man diese via QueryInterface in Erfahrung bringen. Bis auf die auskommentierte C#-Methode Calc ist die Kommunikation so praktizierbar. Die restlichen Schritte in Calc konnte ich so nicht klären. Es liessen sich auch Mittel umsetzen in der C++-Schicht bestimmte Bar-Werte auslesen und diese dann auf einfache Weise zu übertragen. Das wäre aber keine elegante Art und Weise. Ein Zugriff auf den Indikator-Kontext auf C#-Ebene ist aber mehr als wichtig, da die C#-Lib umfangreicher wird und auch zur Weiterleitung bestimmter Informationen an eine C#-GUI genutzt werden soll, quasi eine bidirektionale Verbindung von EL C#-GUI mit einem Service als Dispatcher. Der offene Knackpunkt war noch das Weiterleiten der Referenz nach C#.

 

Ein paar Gedanken weiter und ich habe mir MC.Net gezogen, ein bisschen eingelesen und meine Lib eingebunden, debugged, etc. Was mir neu war ist die Möglichkeit der License-Conversion für 199$, das Migrieren des EL-Codes ist einfacher als ich vermutet hatte und die ganze Infrastruktur, die ich mir aufbauen minimiert sich enorm.

 

Der Vollständigkeit wegen habe ich den Code komplettiert, falls also jemand aus EL heraus auf C++ oder C# zugreifen möchte:

 

// ----- Powerlanguage - Code
...
EXTERNAL: "TSLib_Interop.dll", string, "StringExample", string ;
EXTERNAL: "TSLib_Interop.dll", string, "Calc", IEasyLanguageObject, string, int ;
...
resultCalc = Calc( self, "value9", BarNumber);
Plot1(value9, "Calc", Blue);
commentary("ResultCalc: " + resultCalc + newline + "Sponsored by: " + StringExample("-Next"));


// ----- C++ TSLib_Interop.def
// This file declares the functions to be exported from this C++-Interop-DLL
// MC can call all functions exported here

LIBRARY    "TSLib_Interop"
EXPORTS
    Calc
    StringExample
    
// ----- C++ Interop-DLL
#include "stdafx.h"
#include "TSLib_Interop.h"
#include <comdef.h>

#import "C:\Program Files\TS Support\MultiCharts64\PLKit.dll" no_namespace

// ---  Two helper methods when dealing with <string> in C#-Method signature -----------

System::String^ bstr2string(const _bstr_t& _str){
    if (!_str.length())
        return System::String::Empty;
    return System::Runtime::InteropServices::Marshal::PtrToStringBSTR((System::IntPtr)(BSTR)_str);
}

const _bstr_t string2bstr(System::String^const _str){
    if (System::String::IsNullOrEmpty(_str))
        return "";
    _bstr_t _result;
    _result.Attach( (BSTR)(void*)System::Runtime::InteropServices::Marshal::StringToBSTR(_str) );
    return _result;
}

LPCSTR __stdcall Calc( IEasyLanguageObject* pEL, LPCSTR varName, int barnum )
{
   static _bstr_t s_result;

   // Example of accessing IEasyLanguageObject from within C++
   IEasyLanguageVariable *pVar = pEL->Variables[ varName ] ;
   if ( pVar ) pVar->AsDouble[0] = (double) barnum;

   // Calling C#, the ref is handled by using IntPtr
   s_result = string2bstr(TS::Class1::Calc((System::IntPtr)pEL, barnum));
   return s_result;
}

LPCSTR __stdcall StringExample(LPCSTR _input_str){
    static _bstr_t s_result;
    s_result = string2bstr(TS::Class1::StringExample(bstr2string(_input_str)));
    return s_result;
}

// ------ C# DLL
using PLKit;
using System;
using System.Runtime.InteropServices;

namespace TS
{
 public class Class1
 {

  public static string StringExample(string _1){
           return "Tom-" + _1;
  }

   public static string Calc(IntPtr elRef, double barnum)
   {
        // Bis hierher funktionieren die Aufrufe. Lediglich das Extrahieren der
        // Schnittstelle IEasyLanguageObject in C# fehlt. COM ist wirklich nicht meine Welt
        // aber so in etwa könnte es aussehen. Ich habe zwei Varianten aufgeführt, um an
        // die Schnittstelle zu gelangen. Welche davon die eigentliche ist
        // und wie das im Detail aussehen wuerde, die Frage bleibt im Raum, ist mir aber mittlerweile
        // unwichtig geworden ;)
      
        //    IEasyLanguageObject mcObj;
        //    Guid myGuid;
        //    string infoTxt = ":";

        //  Variante 1
        //    IntPtr ptr = Marshal.GetIUnknownForObject(elRef);
        //    result = Marshal.QueryInterface(ptr, ref iid, out finalIntPtr);

        //  Variante 2
        //    ptr = Marshal.GetComInterfaceForObject(elRef, typeof(IEasyLanguageObject));
        //    ... Marshal.ReadIntPtr(ptr);
        //    mcRef = (IEasyLanguageObject)Convert.ChangeType(ptr2, typeof(IEasyLanguageObject));


        //        Marshal.Release(ptr);
        //        Marshal.Release(...);

        //    return ...;
  }  
 }
}
  • Upvote 2
Link to comment
Share on other sites

Join the conversation

You can post now and register later. If you have an account, sign in now to post with your account.

Guest
Reply to this topic...

×   Pasted as rich text.   Paste as plain text instead

  Only 75 emoji are allowed.

×   Your link has been automatically embedded.   Display as a link instead

×   Your previous content has been restored.   Clear editor

×   You cannot paste images directly. Upload or insert images from URL.

Loading...
×
×
  • Create New...