managed Methode von "not managed" Funktion aus aufrufen



  • Hallo,

    hoffe ihr könnt mir weiterhelfen:
    ein Reduziertes Beispiel:

    public ref class traceDialog : public System::Windows::Forms::Form
    {
    public:
        void addFrame(const CanFrame & Frame)
        {...}
    };
    
    #ifdef _MANAGED
    #pragma unmanaged
    #endif
    
    class receiver
    {
    public:
        receiver(gcroot<traceDialog^> TraceDialog):
          m_traceDialog(TraceDialog)
        {}
    
    protected:
        void onReceivedFrame(const CanFrame & Frame)
        {m_traceDialog->addFrame(Frame);}   // <---- Fehler
    
    private:
       gcroot<traceDialog^> m_traceDialog;
    };
    

    Beim kompilieren kommt folgende Fehlermeldung:
    error C3642: 'traceDialog gcroot<T>::operator ->(void) const' : cannot call a function with __clrcall calling convention from native code

    Das ganze läuft unter VC++ 2005 Express.

    Die receiver-Klasse lässt sich leider nicht in "managed" verwandeln, da auf
    diverse Treiber zurückgegriffen wird, welche dann ihren Dienst verweigern...

    Bin für jede Anregung dankbar.

    Martin



  • Das geht nicht. Du kannst in "unmanaged" code keine Managed Klasse verwende, auch nicht mit "gcroot"!
    Du bringst da was durcheinander:
    1. Es gibt C++ Klassen, die nicht managed sind (also kein ref), aber trotzdem in IL übersetzt werden; hier kannst Du gcroot verwenden
    2. Es gibt wirklich native-C++-Klassen, diese können aber keine Verweise auf managed Objekte enthalten (bis auf void* via GCHandle).



  • erstmal danke für die schnelle Antwort.

    Heisst das, ich hab keine Chance, meiner gemanagedten GUI irgendwie
    mitzuteilen, dass in einer nicht gemanagedten Klasse ein neuer Frame
    empfangen wurde?

    Langsam fang ich an, das CLR - Zeug abgrundtief zu hassen...

    zu 2)
    laut http://msdn2.microsoft.com/en-us/library/aeb4be4k.aspx ist
    gcroot<T> bloss ein Wrapper für GCHandle.
    Und das Halten an sich macht auch keine Probleme.
    Erst wenn ich damit was anstellen will, dann krachts.

    thx
    Martin



  • ein dirty workaround:

    ///////////////////////////////////////////////////////
    // hpp
    ///////////////////////////////////////////////////////
    class receiver
    {
    public:
        receiver(gcroot<traceDialog^> TraceDialog);
    
    protected:
        void onReceivedFrame(const CanFrame & Frame);
    
    private:
       gcroot<traceDialog^> m_traceDialog;
    }; 
    
    ///////////////////////////////////////////////////////
    // cpp
    ///////////////////////////////////////////////////////
    #ifdef _MANAGED
    #pragma unmanaged
    #endif
    
    receiver::receiver(gcroot<traceDialog^> TraceDialog):
      m_traceDialog(TraceDialog)
    {}
    
    #pragma managed
    
    gcroot<traceDialog ^> dlg;
    CanFrame frm;
    void test()
    {
    dlg->addFrame(Frame);
    }
    
    #pragma unmanaged
    
    void receiver::onReceivedFrame(const CanFrame & Frame)
    {
    dlg = m_traceDialog;
    frm = Frame;
    test();
    }
    

    Jetzt kompiliert er's.
    Allerdings kommt jetzt zur Laufzeit eine Exception, dass auf den dialog von einem anderen Thread aus zugegriffen worden ist, als von dem, wo er erzeugt
    worden ist...

    Aber dazu mach ich evtl. später nen neuen Thread auf...

    Martin



  • anonymus schrieb:

    Jetzt kompiliert er's.
    Allerdings kommt jetzt zur Laufzeit eine Exception, dass auf den dialog von einem anderen Thread aus zugegriffen worden ist, als von dem, wo er erzeugt
    worden ist...

    Aber dazu mach ich evtl. später nen neuen Thread auf...

    Martin

    Tust du ja auch, dann musst du mit (Begin)Invoke und Delegates auf die GUI zugreifen.



  • Auf GUI-Elemente darf man nur aus dem Thread zugreifen, welcher das Element erstellt hat! Und wenn Du es doch willst, so musst Du es, wie Talla sagt, mittels Invok/Begin/EndInvoke machen.



  • anonymus schrieb:

    erstmal danke für die schnelle Antwort.

    Heisst das, ich hab keine Chance, meiner gemanagedten GUI irgendwie
    mitzuteilen, dass in einer nicht gemanagedten Klasse ein neuer Frame
    empfangen wurde?

    Langsam fang ich an, das CLR - Zeug abgrundtief zu hassen...

    Die binaries sind halt nicht kompatibel. Das eine wird vom Standard C++ Compiler erzeugt, das andere vom JIT-Compiler der VM. Ich würde nicht mal auf die Idee kommen, dass da irgendwas kompatibel sein könnte.

    Wenn du auf bestimmte Module angewiesen bist, musst du deren Objekt-Modell benutzen und zwischen ihnen übersetzen. Unter Windows ist das eigentlich fast immer COM oder .Net oder C-DLLs, war schon immer so, dass man irgendeinen Anhaltspunkt braucht. Von .Net aus kannst du alles nutzen, von COM aus kannst du COM und .Net nutzen. Wenn dir der Sourcecode vorliegt, kannst du alles auch einfach zu IL-Code compilieren, das sollte am wenigsten stressen.



  • ok, also jetzt läufts:

    #pragma managed
    void receiver::onReceivedFrame(const CanFrame & Frame)
    {
    m_traceDialog->addFrame(Frame);
    }
    #pragma unmanaged
    

    und die addFrame Methode:

    delegate void InvokeDelegate(System::Object ^ Line);
    
    void traceDialog::test(System::Object ^ Line)
    {
    m_listBoxTrace->Items->Add(Line);
    m_listBoxTrace->SetSelected(m_listBoxTrace->Items->Count - 1, true);
    }
    
    void traceDialog::addFrame(const CanFrame & Frame)
    {
    System::Object item;
    
    // hier das item befüllen
    	if (this->InvokeRequired == true)
    	{
    	this->BeginInvoke(gcnew InvokeDelegate(this, &traceDialog::test), item);
    	return;
    	}
    }
    

    Also nochmal danke


Anmelden zum Antworten