Funktionsmarshalling generieren, um Funktionen und Parameter durch dumme Schnittstelle zu tunneln



  • Ganz einfach wenn eine Dritte Bedingung erfüllt währe:

    -Beide Komponenten laufen im gleichen virtuellen Speicherbereich 
    -Die Wortbreite ist immer 32bit und der Byte-Order immer Intel 
    --> - Beide Module die Identische Code Basis benutzen
    

    Ist das so, dann könnte ich eine Lösung anbieten!

    Lichtlein



  • Puuuh, danke für die Mühe erstmal.

    Das Interface sieht garnicht blöd aus. Ich müsste tatsächlich nur unter alle betroffenen Klassen ein pure-virtual Interface drunterbasteln.

    Was mir aber nicht klar ist, wie in dem Zusammenhang überhaupt Objekte erzeugt werden sollen. In deinem Beispiel hält Komponente B ein globale SomeObject-Instanz.
    In meinem Fall muss aber Komponente A beliebig viele Instanzen erzeugen können, und auf jeder Instanz die Funktionen aufrufen.

    Der invoker bekäme dadurch einen weiteren Parameter, nämlich die Instanz, auf der überhaupt was invoked werden soll. Stellt sich die Frage, wen diese Instanzen gehören sollen.

    Philipp



  • Lichtlein schrieb:

    Ganz einfach wenn eine Dritte Bedingung erfüllt währe:

    --> - Beide Module die Identische Code Basis benutzen

    Du meinst, dass sie die selben Header inkludieren?
    Ja, das tun sie.

    Philipp



  • Nein ich dachte da an eine Binäre Datei in der mehr als 1 Core unterwegs sind.
    (Multiprozessor System).
    Es geht um den void Pointer, wenn es möglich ist diesen Pointer als Funktionspointer zu benutzen dann geht das was Du vorhast ganz einfach und sehr Flexibel.

    Lichtlein



  • Achso.

    Nein, by design ist das alles single-Threaded. Da kann kein anderer drin herumfummeln.
    Immer her mit der Idee!

    Philipp



  • PhilippM schrieb:

    Was mir aber nicht klar ist, wie in dem Zusammenhang überhaupt Objekte erzeugt werden sollen. In deinem Beispiel hält Komponente B ein globale SomeObject-Instanz.
    In meinem Fall muss aber Komponente A beliebig viele Instanzen erzeugen können, und auf jeder Instanz die Funktionen aufrufen.

    Der invoker bekäme dadurch einen weiteren Parameter, nämlich die Instanz, auf der überhaupt was invoked werden soll. Stellt sich die Frage, wen diese Instanzen gehören sollen.

    Dazu kann ich dir nun wirklich nichts sagen, da ich das Design von eurer sendMessage-Schnittstelle nicht kenne - ich hatte angenommen dass der "receiver" Wert in Wirklichkeit für ein Objekt steht, und nicht für ein "Modul".

    Ist aber auch egal, genau so wie in meinem Beispielcode kannst du ein "statisches" Interface mit Factory-Funktionen abfragen. Über diese Factory-Funktionen können dann direkt Objekte erzeugt werden - von denen muss man sich dann nichtmal die Interfaces über sendMessage holen, da man ja schon Zeiger hat.



  • Ich gebe Dir mal meine Idee, vielleicht hilft sie Dir ja weiter.
    Wie gesagt funktioniert das nur wenn Module A und Module B einen
    Funktionspointer an der gleichen Stelle haben und den gleichen Logischen Speicher benutzen.

    Also, Module A will, das Module B Type C anlegt und mit Werten x,y,z bestückt.

    Packen wir die Initial Werte in eine Struktur.

    struct TypeCInitValues
    {
        int x, y, z;
    };
    

    Als nächstes braucht man eine Fabrik Funktion die aus den Initialwerten Type C anlegt.

    TypeC* fabrikTypeC(const TypeCInitValue &init_values)
    {
        return new cTypeC(init_values.x, init_values.y, init_values.z);
    }
    

    Über Deine send und receive funktionen wollen wir nur einen Defenierten Type schicken.
    Der sieht so aus.

    struct SendData
    {
        virtual void receive();
    };
    

    Jetzt die Klasse die alles Verpackt und Sendet, und auch der empfänger der
    alles dann wieder entschlüsselt.

    struct SendHelper
    {
    
        template< typename data_tmp, typename fabik_funktion, typename generated_class>
        struct SendDataTmp : public SendData
        {
            virtual void receive()
            {
                generated_class *pGeneratetClass = (FabrikFunktion)(*pData);
    
                // MACH WAS MIT DER ERZEUGTEN CLASSE
            }
    
            data_tmp            *pData;
            fabrik_funktion     FabikFunktion;
        };
    
        template< typename init_data, typename generated_class >
        static void send(const INIT_DATA &init_data, generated_class* (*pfunc) (init_data &InitData))
        {
            typedef generated_class* (*tFunc) (init_data &InitData)     tFabikFunc;
    
            SendDataTmp<init_data, tFabikFunc, generated_class>  Sdt;
            Sdt.pData = &init_data;
            Sdt.FabrikFunktion = pfunc;
    
            sendMessage(0, 0, &Sdt)
        }
    
    };
    

    So und hier nun der Aufruf des ganzen.

    TypeCInitValues init_values;
    
    init_values.x = 1;
    init_values.y = 2;
    init_values.z = 3;
    
    SendHelper< TypeCInitValues >::send(init_values, fabrikTypeC);
    

    Habe ich jetzt aus den Kopf geschrieben, kann also sein das es nicht Compiliert.

    Hoffe Du erkennst was ich da gemeint habe, und das Du es benutzen kann oder wenigstens einen
    anregung.

    Lichtlein



  • Sieht mir jetzt ganz nach Visitor-Pattern aus.

    Ist auch nicht doof, bloss (ohne Lambda-Expressions) sehr umständlich, da man ziemlich viel tippen/kopieren muss wenn man unterschiedliche "MACH WAS MIT DER ERZEUGTEN CLASSE" (Klasse schreibt man mit K) braucht.

    Falls Lambda-Expressions zur Verfügung stehen finde ich die Idee allerdings sehr gut.



  • Hey, richtig klasse wieviele gute Ideen hier aufschlagen. Danke an alle Antworter 🙂

    Lambda-Funktionen habe ich keine. Noch ist kein boost im Projekt, und ich denke dabei bleibts auch.
    C++0x fällt auch flach, da der aktuellste Compiler auf dem Mac, den ich nutzen kann, 4.2 ist, und da ist noch nix mit C++0x.

    Aber:
    Ich habe an meinem Design nochmal ein bißchen gefeilt und siehe da - es gibt nur eine einzige Klasse, dere Methoden so getunnelt werden müssen, und - Überraschung - die ist auch noch ein Singleton.

    Daher passt Hustbaer's Lösung eigentlich wie angegossen. Das globale Objekt wird durch das Singleton ersetzt und voila! Funktioniert prächtig!

    Aber leider nur auf dem GCC.
    Wenn ich das durch Visual C++ 2010 jagen will, bekomme ich folgenden Fehler:

    enum Function {
        FSystem,
        // ...
    };
    
    enum FMSInterfaces {
        FMSSystemInterface,
        // ...
    };
    
    struct InterfaceQuery
    {
        explicit InterfaceQuery(FMSInterfaces iid) : interfaceId(iid), interface(0) {} // <--- das ist Zeile 25
    
        FMSInterfaces interfaceId;
        void* interface;  // <--- das ist Zeile 28
    };
    
    (28) : error C2332: 'struct': Fehlender Tagname
    (28) : error C2226: Syntaxfehler: Typ 'InterfaceQuery::<unnamed-tag>' nicht erwartet
    (28) : error C2238: Unerwartete(s) Token vor ';'
    (25) : error C2332: 'struct': Fehlender Tagname
    (25) : error C2011: '<unnamed-tag>': 'enum' Typneudefinition
    : Siehe Deklaration von '<unnamed-tag>'
    (25) : error C2059: Syntaxfehler: 'Typ'
    

    Und nu?
    GCC 4.4 und 4.5 kompilieren das wie gesagt prächitg.

    Gruß,
    Philipp

    EDITH hat festgestellt, dass wenn ich

    void* interface;
    

    in

    void* interface_;
    

    umbennene, es tadellos kompiliert.
    Hä?
    Ist "interface" bei msvc ein Schlüsselwort?

    Gruß,
    Philipp



  • PhilippM schrieb:

    Ist "interface" bei msvc ein Schlüsselwort?

    Nö, ist kein Schlüsselwort (obwohl das Syntax-Highlighting von VS 2010 es in Schlüsselwort-Farbe einfärbt).

    Aber irgendwo in den Untiefen der Windows-Header gibt's ein

    #define interface struct
    

    Hatte ich nicht dran gedacht. (Ich hatte den Code sogar mit MSVC geschrieben und probe-compiliert, bloss hatte ich da kein #include <windows.h> drinnen gehabt...)


Anmelden zum Antworten