Casting von Managed -> Unmanaged -> Managed



  • Moin,

    ich habe hier eine API mit einer unvollständigen .NET Unterstützung ... daher versuche ich das ganze in einer Mischung aus Managed und Unmanaged zu machen

    ich habe eine Klasse VoiceRecorder ... diese enthält die unmanaged Klasse streamer

    ref class VoiceRecorder
    {
      public:
        rcpplus::RtpStreamer *__streamer;
        rPROPERTY(Streamer, rcpplus::RtpStreamer*, __streamer);
    }
    

    ich erzeuge die Klasse VoiceRecorder und im Konstruktor erzeuge ich dann passend auch eine Instanz von RtpStreamer

    VoiceRecorder ^vr = gcnew VoiceRecorder(xn);
    vr->Streamer->registerReceiverCallback(false, Dispatcher::RtpCallback, &vr);
    

    die Callback-Funktion sieht wie folgt aus und ist unmanaged

    void Dispatcher::RtpCallback(void *ptr, rcpplus::RtpPayloadType payloadType, const unsigned char *data, int len)
    {
      // String ^ip = gcnew String((char*)ptr);
      // VoiceRecorder ^vr = dynamic_cast<VoiceRecorder^>(ptr);
      // VoiceRecorder ^vr = reinterpret_cast<VoiceRecorder^>(ptr);
      // VoiceRecorder ^vr = static_cast<VoiceRecorder^>(ptr);
    }
    

    mit String hat es beim Testen funktioniert ... der Compiler meckert das er void* und Voicerecorder^ nicht in Einklang bringen kann ... wie bekomme ich jetzt aus ptr wieder einen VoiceRecorder?

    hand, mogel



  • Hier wirst Du nicht drum rum kommen, das GCHandle zu verwenden... hier ein Beispiel:

    #include <windows.h>
    #include <tchar.h>
    #pragma comment(lib, "user32.lib")
    
    using namespace System;
    using namespace System::Runtime::InteropServices;
    
    ref class Foo
    {
    public:
      void DisplayWindow(String^ text)
      {
        Console::WriteLine(text);
      }
    };
    
    BOOL __stdcall MyEnumWindowsCallback(HWND hWnd, LPARAM lParam)
    {
      IntPtr lp(lParam);
      GCHandle gch = GCHandle::FromIntPtr(lp);
    
      Foo^ f = (Foo^) gch.Target;
    
      TCHAR szBuffer[1024];
      GetWindowText(hWnd, szBuffer, 1024);
    
      String^ text = String::Format("hWnd: {0}, Caption: {1}", IntPtr(hWnd), gcnew String(szBuffer));
      f->DisplayWindow(text);
    
      return TRUE;
    }
    
    int main()
    {
      Foo^ f = gcnew Foo();
    
      GCHandle handle = GCHandle::Alloc(f);
    
      EnumWindows(&MyEnumWindowsCallback, (LPARAM)GCHandle::ToIntPtr(handle).ToPointer());
    
      handle.Free();
    }
    


  • Moin,

    Jochen Kalmbach schrieb:

    Hier wirst Du nicht drum rum kommen, das GCHandle zu verwenden...

    da habe ich wohl die Glaskugel mit den falschen Werte gefüttert

    hier ein Beispiel:

    welche geholfen hat - Danke

    hand, mogel



  • Theoretisch kannst Du das ganze auch noch mit Delegates machen... aber da diese gepinnt sein müssen und es so aussieht, als ob dies länger der Fall sein würde, ist dies nicht zu empfehlen...



  • Jochen Kalmbach schrieb:

    Theoretisch kannst Du das ganze auch noch mit Delegates machen... aber da diese gepinnt sein müssen und es so aussieht, als ob dies länger der Fall sein würde, ist dies nicht zu empfehlen...

    AFAIK muss man delegates nie pinnen, nur eine Referenz garantieren.



  • Ja, es sieht so aus... da hab ich was durcheinander gebrwacht.. sorry...



  • Das einfachste ist aber trotzdem noch pinnen, da man hier nichts falsch machen kannn 😉 Sonst muss man teilweise explizit GC::KeepAlive aufrufen...

    Hier ein Beispiel mit dem Delegate

    #include <windows.h>
    #pragma comment(lib, "user32.lib")
    
    using namespace System;
    using namespace System::Runtime::InteropServices;
    
    delegate bool EnumWindowsDelegateProc(IntPtr hWnd, IntPtr lParam);
    
    ref class Foo
    {
    public:
      bool MyCallback(IntPtr hWnd, IntPtr lParam)
      {
        Console::WriteLine(hWnd);
        return true;
      }
    
      void DoEnumWindows()
      {
        EnumWindowsDelegateProc^ del = gcnew EnumWindowsDelegateProc(this, &Foo::MyCallback);
        //pin_ptr<EnumWindowsDelegateProc^> gepinnt = &del;  // Nicht nötig, wenn die Referenz nicht verloren geht!
    
        EnumWindows((WNDENUMPROC) Marshal::GetFunctionPointerForDelegate(del).ToPointer(), NULL);
        System::GC::KeepAlive(del);  // DIES ist nötig, sonst wird der Delegate aufgeräumt, obwohl er noch in native Code verwendet wird!
      }
    };
    
    int main()
    {
      Foo^ f = gcnew Foo();
    
      f->DoEnumWindows();
    }
    

Anmelden zum Antworten