Mit CB2010 dll auf BCB6 TPanel zeichenen



  • Hallo zusammen

    Um eine ältere Anwendung zu erweitern habe ich mir vorgestellt, daß eine neue DLL (BCB2010) Steuerelemente (Button, Labels, ...) auf ein TPanel der BCB6 Anwendung zeichnet.
    Ist dies möglich und welche Probleme sind zu erwarten?

    MfG Stephan



  • Stephan schrieb:

    Um eine ältere Anwendung zu erweitern habe ich mir vorgestellt, daß eine neue DLL (BCB2010) Steuerelemente (Button, Labels, ...) auf ein TPanel der BCB6 Anwendung zeichnet.
    Ist dies möglich

    Klar. Ich würde ein Frame erstellen und dessen ParentWindow-Eigenschaft das Fensterhandle des Panels zuweisen. (Wenn's so nicht klappt, sieh hier nach.)

    Stephan schrieb:

    und welche Probleme sind zu erwarten?

    Du darfst zwischen den beiden Modulen nur über ein C-Interface Daten austauschen. Der Austausch komplexer Datentypen (std::string, std::vector<>, AnsiString, DynamicArray<>, von TObject abgeleitete Klassen etc.) ist nicht möglich. Einzig WideString kannst du für den Austausch verwenden, weil es ein Wrapper für den COM-Datentyp BSTR ist.



  • Habe nun meine Steuerelemente auf ein TPanel in der DLL gepackt.
    Dieses TPanel wird dann direkt im Form der BCB6 Anwendung angezeigt.

    BCB6 Anwendung:

    HWND hPnl1 = Form1->Handle;
        Test(&hPnl1);
    

    CB2010 DLL:

    _DLL_EXPORT void Test(HWND *handle)
    {
        Gui.pnl = new TPanel(*handle);
        Gui.pnl->Parent = NULL;
        Gui.pnl->Top = 50;
        Gui.pnl->Left = 10;
        Gui.pnl->Height = 230;
        Gui.pnl->Width = 333;
        Gui.pnl->Visible = true;
    
        Gui.b2 = new TButton(Gui.pnl->Handle);
        Gui.b2->Parent = Gui.pnl;
        Gui.b2->Visible = true;
        Gui.b2->Top = 3;
        Gui.b2->Left = 3;
        Gui.b2->Caption = L"DynDllButton";
        Gui.b2->OnClick = Gui.b2Click;
        Gui.b2->Cursor = crHandPoint;
    
        Gui.memo = new TMemo(Gui.pnl->Handle);
        Gui.memo->Parent = Gui.pnl;
        Gui.memo->Visible = true;
        Gui.memo->Top = 3;
        Gui.memo->Left = 100;
        Gui.memo->ScrollBars = ssBoth;
    
    }
    

    audacia schrieb:

    Du darfst zwischen den beiden Modulen nur über ein C-Interface Daten austauschen. Der Austausch komplexer Datentypen (std::string, std::vector<>, AnsiString, DynamicArray<>, von TObject abgeleitete Klassen etc.) ist nicht möglich. Einzig WideString kannst du für den Austausch verwenden, weil es ein Wrapper für den COM-Datentyp BSTR ist.

    Das mit dem C-Interface ist soweit klar.
    Vermutlich wird eh nur das Fenster Handle übergeben.
    Deine Lösung werde ich mir mal anschauen, eventuell bringt dies noch Vorteile für mich.

    Ob mit oder ohne Laufzeitpackages sollte hier keinen Einfluß haben, oder?



  • Stephan schrieb:

    Habe nun meine Steuerelemente auf ein TPanel in der DLL gepackt.
    Dieses TPanel wird dann direkt im Form der BCB6 Anwendung angezeigt.

    So gehts auch. Der Vorteil beim Frame ist eben, daß du den Form-Designer nutzen kannst.

    Stephan schrieb:

    Ob mit oder ohne Laufzeitpackages sollte hier keinen Einfluß haben, oder?

    Vermutlich geht beides. Natürlich können die beiden Module nicht dieselben Packages teilen, so daß du sowohl vcl60.bpl/rtl60.bpl/... als auch vcl140.bpl/rtl140.bpl/... im Arbeitsspeicher hättest. Aber da du keine komplexen Datentypen austauschst, ist es egal.

    Einzig mit der dynamischen RTL könntest du Probleme bekommen; ich meine mich dunkel erinnern zu können, daß sie es nicht mag, wenn zwei verschiedene Instanzen ihrer selbst in eine Anwendung geladen werden. Aber ich kann da auch irren. Probiere es einfach aus; wenn die RTL das nicht will, wird sie sich schon melden.



  • Also irgendwie bekomm ich das mit den Frames nicht hin.

    In der BCB6 Anwendung hab ich mein TPanel.
    Dieses Fenster-Handle gebe ich an die DLL weiter.

    Test1(pnl1->Handle);
    

    In der DLL Funktion versuche ich den Frame zu erstellen:

    _DLL_EXPORT void Test(HWND handle)
    {
        Frame1 = new TFrame1(NULL);
    //    Frame1->Parent = NULL;
        Frame1->ParentWindow = handle;
        Frame1->Show();
        Frame1->Top = 50;
        Frame1->Left = 0;
        Frame1->Visible = true;
    }
    

    Jedoch irgend etwas mache ich falsch, da nichts angezeigt wird.
    Die CreateParams Methode habe ich in die Frame-Klasse eingefügt.

    Irgendjemand gute Ideen?



  • Ich habs jetzt mal probiert mit C++Builder 6 (Host-Anwendung) und C++Builder XE (Client-DLL).

    In der Klassendeklaration von TFrame in Forms.hpp siehst du, daß es einen zweiten Konstruktor gibt, der ein HWND akzeptiert. Du mußt also für dein Frame auch einen solchen Konstruktor erstellen:

    __fastcall TFrmChild::TFrmChild(HWND parentWindow)
     : TFrame (parentWindow)
    {
    }
    //---------------------------------------------------------------------------
    void __fastcall TFrmChild::CreateParams(Controls::TCreateParams &Params)
    {
        inherited::CreateParams (Params);
        if (Params.WndParent == NULL)
            Params.WndParent = ParentWindow;
    }
    //---------------------------------------------------------------------------
    extern "C" __declspec (dllexport) void* __stdcall DisplayChildWindow (HWND hParentWnd)
    {
        TFrame* frame = new TFrmChild (hParentWnd);
        frame->Show ();
        return frame;
    }
    

    Dann geht es bei mir. Etwas hübscher wird es, wenn du die ganzen Parent*-Eigenschaften (ParentFont, ParentCtl3D, ...) des Frames deaktivierst. Die Navigation durch die Steuerelemente mit Tab funktioniert allerdings nicht.

    Frame->Show(); und Frame->Visible = true; ist übrigens redundant; die Anweisungen tun exakt dasselbe.

    Was du übrigens auch tun könntest: in der DLL eine ActiveForm erstellen und in einem ActiveX-Container in C++Builder 6 anzeigen. Ich könnte mir vorstellen, daß da die Unterstützung für Tab-Navigation, Control-Fokus, Alignment und dergleichen besser ist. Außerdem ist es sehr einfach, aus der Host-Anwendung auf Eigenschaften der ActiveForm zuzugreifen, weil die IDE automatisch COM-Wrappermethoden dafür erstellt.



  • audacia schrieb:

    Was du übrigens auch tun könntest: in der DLL eine ActiveForm erstellen und in einem ActiveX-Container in C++Builder 6 anzeigen. Ich könnte mir vorstellen, daß da die Unterstützung für Tab-Navigation, Control-Fokus, Alignment und dergleichen besser ist. Außerdem ist es sehr einfach, aus der Host-Anwendung auf Eigenschaften der ActiveForm zuzugreifen, weil die IDE automatisch COM-Wrappermethoden dafür erstellt.

    Das hört sich für mich am sinnvollsten an.
    Bisher ist zwar nicht geplant das die Host Anwendung auf die DLL Form zugreift, jedoch wer weiß was noch kommt.
    Das muß ich mal etwas genauer anschauen.
    Audacia, ich fürchte jedoch, daß da noch ein paar Fragen auf dich zukommen 😉


Anmelden zum Antworten