Forms - Fenster aus Dll werden nicht angezeigt.



  • Hi,
    ich weiß nicht ob ich dass besser im WinAPI Forum posten sollte, aber ich denke dass es ein VCL-Speziefisches Problem ist.
    Also, in einer Dll habe ich eine TForm, diese enthält ein Panel. Ein Programm nun ruft eine funktion der Dll auf und diese liefert das Handle des Panels. Und nun wird mit der WinAPI-Funktion SetParent das Panel der Dll in ein Panel der Anwendung eingefügt. Zumindest sollte es das tun, aber ich bekomme nichts zu sehen.

    Ungefähr so sieht das ausprogrammiert aus:
    (Das ganze ist in Delphi programmiert, deswegen habe ich vielleicht irgendwelche Fehler eingebaut als ich die Funktionen hier umgewandelt habe. (ist schließlich ein C++-Forum 😉 )
    Funktion der Dll:

    HWND TTestPlugin::getPanel()
    {
       if (Form1 == nil){
          app_->raiseException("Das Plugin wurde nicht initialisiert");
          return INVALID_HANDLE_VALUE;
       } else{
          return Form1->Panel1->Handle;
       }
    }
    
    //Erstellt wird das Fenster so:
    void TTestPlugin::initialize()
    {
       if (Form1 == NULL){
          Form1 := TForm1(NULL);
       }
    }
    

    Die Funktion der Anwendung die das Plugin einfügt:

    [...]
    IMETCPlugin* plugin = pluginMgr->getPlugin(
                           pluginMgr->indexByName(item->Caption));
    IMETCPanel* panel = NULL;
    
    if (plugin->QueryInterface(IMETCPanel, panel) == S_OK){
       if (item == __prefSelectedListItem_){ // Das Element erhält den Fokus
          if (panel->getPanel() != INVALID_HANDLE_VALUE){
             Windows::SetParent(panel->getPanel(), pnlContainer.Handle);
             ShowWindow(panel->getPanel(), SW_SHOWNORMAL); // das nützt nichts
             pnlContainer->UpdateControlState();           // das auch nicht
          }else{   // Das Element verliert den Fokus
             panel->hidePanel();
          }
       }
    }
    [...]
    


  • Hab jetzt hingekriegt, man musste noch die Position des Panels setzten

    TRect r;
    [...]
    ::SetParent(panel->getPanel(), pnlContainer->Handle);
    ::GetClientRect(pnlContainer->Handle, r);
    MoveWindow(panel->getPanel(), r.Left, r.Top, r.Right, r.Bottom, true); ////
    ShowWindow(child, SW_SHOWNORMAL);
    [...]
    

    Das Problem jetzt ist, dass die Child-Elemente des Panels nicht angezeigt werden
    (außer TLabel - wahrscheinlich alle TGraphicControls). Wie kann man sie denn alle zum Anzeigen bringen. Gibt es da etwas besseres als EnumChildWindows()?.
    Und gibt es eigentlich eine Align-Funktion (TControl::Align) in der Winapi, oder muss ich diese selbst programmieren?



  • Ich hab versucht mit EnumChildWindows() alle Steuerelemente des eingefügten Panels anzuzeigen, aber irgendwie wird die callback-funktion nicht aufgerufen. Und auch WinSight zeigt nur das Panel aber ohne Steuerelemente. Ich komme einfach nicht weiter. 😞



  • mit einem reinen WinAPI-Fenster (genauergesagt Dialog) kommt das Programm zurecht,
    (alle Steuerelemente werden angezeigt). Aber alle Fenster in WinAPI zu erstellen ist irgendwie nicht der Sinn der Sache. Ich hab einerseits keinen gescheiten Resourcen-Editor, andererseits sollte es auch mit VCL Zeug funktionieren, nur wie?

    (Irgendwie sieht der Thread nach einem Monolog aus. Weiß niemand was über das Thema oder schreibe ich unverständlich?)



  • Um Deinen Monolog zu beenden:

    Schaul mal auf meine Seite unter BCB->DLLs.



  • Endlich erste Antwort!!!

    aber leider finde ich nichts passendes auf deiner Homepage, weder in http://fatman98.funpic.de/delphi_dlls.php noch in http://fatman98.funpic.de/builder_dll.php. Irgendwo steht zwar etwas über Fenster aber nichts das mich weiterbringt, oder ich bin irgendwie blind, dass ich nichts finden kann.



  • u.U. "Verwenden von Datenbankkomponenten in einer DLL"?

    Da habe ich eine Form verwendet. Vielleicht hilft das ja weiter.



  • F98 schrieb:

    u.U. "Verwenden von Datenbankkomponenten in einer DLL"?

    Da habe ich eine Form verwendet. Vielleicht hilft das ja weiter.

    Erstmal danke für die Mühe.
    Ein Fenster aus der Dll modal anzuzeigen klappt schon, aber nicht, wenn das Fenster (genauergesagt ein Panel, das sich im Fenster befindet), in meiner Anwendung eingebettet wird. Sozusagen wie ein TFrame. Aber das Problem ist, dass es mit Frames nicht funktioniert, mit Panels alleine auch nicht. Wenn ich aber das Panel mit Komponenten in eine TForm einfüge, als Dll kompiliere, dann werden im Programm selbst nur das Panel mit den Graphischen Komponenten angezeigt, aber Buttons zum Beispiel nicht. Wenn ich aber ein Fenster mit der reinen WinAPI erstelle, so wird scheinbar alles richtig angezeigt. Wieso das mit VCL nicht funktioniert, das verstehe ich nicht. Schließlich wird nur das Handle übergeben und keine Komponenten. Aber auch wenn ich im WinSigh die Fenster durchgehe, dann wird zwar das eingefügte Panel gefunden, aber nicht die Komponenten, die sich darauf befinden.

    * Ich hab zwar in den Newsgroups irgendwo gelesen, dass das mit Packages funktionieren sollte, aber ich will keine Packages verwenden, da sie einerseits mit genauderselben Version des BCB/Delphi kompiliert sein müssen, andererseits sich auf BCB bzw. Delphi beschränken. Aber ich möchte es davon unabhängig halten, damit die Dlls auch mit anderen Compilern erzeugt werden können.
    * Das mit der reinen WinAPI ist auch schlecht, da ich viele umfangreiche Komponenten wie SynEdit in die Dlls auslagern möchte, und Neuentwicklungen bzw. Erweiterungen von RichEdit gehen gewaltig über mein Wissen hinaus.
    * Vielleicht kann man das aber auch mit ActiveForms lösen. Hab aber wenig Erfahrung damit.



  • Hallo,

    ich hab zur Zeit ein ähnliches Problem und zwar mit Delphi. Ist ja die selbe VCL. Ich möchte das Fenster aus der Dll in das aufrufende Programm einbetten. Dazu übergebe ich das Handle des Parent-Fensters in das ich das Dll-Fenster einbetten möchte.

    Zuerst hab ich das Dll-Fenster als Form eingebettet mit der Api-Funktion SetParent(). Dazu hab ich noch BorderStyle auf bsNone geschaltet. Das hatte noch am besten geklappt. Aber ich habe in diesem Dll-Fenster SpeedButtons mit Flat=true. Wenn man nun mit der Maus das Control verlies, senkten sich die Buttons nicht mehr.

    In den Borland NewsGroups hieß es, dass bei Fenstern in Dll's, die nicht Modal angezeigt werden, die CM_MOUSELEAVE Message nicht richtig abgearbeitet wird. Ich habs dann ausprobiert: bei Modaler Anzeige war das Problem weg. Die einzigste Lösung sollen Packages sein. Wie auch du möchte, ich das aber nicht - aus ähnlichen Gründen.

    Dann hab ich es noch als TFrame versucht. Ich bekam dann zur Laufzeit eine Zugriffsverletzung ("TFont kann nicht an TFont zugewiesen werden" 😮 ), es wurde dann aber dennoch angezeigt. Allerdings wurden die Controls nicht richtig gezeichnet. Sie hatten einen flachen Rahmen, wie bei Ctl3D=true.

    Ich hab zur Zeit auch keine Ahnung, wie ich das jetzt in den Griff kriege. 😞
    Nur eines steht fest: Keine Packages.

    MfG
    tuküe



  • Hallo Leidensgenosse 😉
    Ich programmiere auch in Delphi, weil mein BCB schon seit längerem Streikt.
    Was ich nicht so ganz verstanden habe ist, wie Du das Fenster mit Komponenten zum Anzeigen gebracht hast. Werden bei Dir alle TWinControls angezeigt? Schließlich ist TSpeedButton ein TGraphicControl.

    Das Workaround für den TFont-Fehler ist, das ParentFont auf false zu setzen.

    Außer mit Packages sollte es eigentlich auch mit ActiveForms funktionieren, zumindest werden VCL-ActiveForms in VB-Anwendungen und VB-ActiveX-Controls in VCL-Forms ohne Probleme angezeigt (außer bei TDateTimePicker). Aber wie man das "richig" einsetzt weiß ich nicht, muss mich damit etwas auseinandersetzten.

    Eine andere Alternative ist, wie ich schon oben schrieb, die WinAPI.



  • Hallo,

    wenn ich dich richtig verstanden habe, gibt deine Dll-Funktion das Handle des Panels zurück. Und damit rufst du SetParent() auf.

    Ich mache es umgedreht. Ich übergebe der Dll das Handle des Container-Fensters(Parent) und rufe dann in der Dll SetParent() auf. Ich hab es auch nun mit einem Panel hinbekommen. Es werden alle Controls angezeigt, allerdings bleibt der Fehler mit den SpeedButtons, weil das Fenster nicht Modal angezeigt wird. Wenn ich hierfür noch einen Workaround finde, hab ich es geschafft.

    Aber momentan arbeit ich wieder an einem anderem Projekt und komme erst nächste Woche dazu.

    MfG
    tuküe



  • tuküe schrieb:

    Ich mache es umgedreht. Ich übergebe der Dll das Handle des Container-Fensters(Parent) und rufe dann in der Dll SetParent() auf.

    Hab gerade ausprobiert, geht auch nicht. Rufst Du vielleicht noch irgendwelche zusätzlichen Funktionen auf?

    Bei mir sieht es in etwa so aus:

    // Dll
    HWND TMyPlugin::createWindow(HWND parent)
    {
       Form1 = new TForm1(NULL);
       ::SetParent(Form1->Panel1->Handle, parent);  
       return Form1->Panel1->Handle;
    }
    
    // Programm
    void placeWindow(HWND child, HWND parent)
    {
       TRect r;
    
       ::GetClientRect(parent, r);
       ::MoveWindow(child, r.Left, r.Top,
                            r.Right, r.Bottom, true);
       ::ShowWindow(child, SW_SHOWNORMAL);
    }
    
    void TForm1::Button1Click(TObject *Sender )
    {
       TFRegisterPlugin proc; 
       THandle handle;
       hDll_ = LoadLibrary('testPlugin.dll');
       if (hDll_ != NULL) {
          proc = ::GetProcAddress(hDll_, c_regFunc);
          if (proc != NULL){
             plugin = proc_();
             handle = plugin_->createWindow(pnlContainer->Handle);
             placeWindow(handle, pnlContainer->Handle);
             plugin_->ShowWindow();
          }
       }
    }
    

    EDIT: War kein C++



  • Hallo,

    so mache ich es momentan. Aber zufrieden bin ich damit nicht 😞 . Ich werde es auf jeden Fall noch überarbeiten. Habe ja noch Hoffnung einen sauberen Weg zu finden 🕶.

    // in der DLL
    HWND LoadFTPModule(HWND hParent)
    {
       TRect R;
    
       frmMain = new TfrmMain(NULL);
    
       GetClientRect(hParent, &R);
       SetParent(frmMain->pnlFTP->Handle, hParent);
       MoveWindow(frmMain->Handle, 0, 0, R.Right, R.Bottom, true);
    
       // so wird nur der SpeedButton angezeigt
       // ShowWindow(frmMain->pnlFTP->Handle, SW_SHOWNORMAL);
    
       // nicht schön, aber so gehts, allerdings bleibt der Fehler mit SpeedButton
       frmMain->Show();
       frmMain->Hide();
    
       return frmMain->Handle;
    }
    

    MfG
    tuküe



  • Wow, es funktioniert. Danke!!!!!!!

    EDIT:
    Vielleicht ist es was für die FAQ. Zumindest in den Newsgroups wird es oft gefragt, aber keine vernünftige Lösung.


Anmelden zum Antworten