tutorials.de Buch-Aktion 05/2012
ERLEDIGT
NEIN
ANTWORTEN
7
ZUGRIFFE
1458
EMPFEHLEN
  • An Twitter übertragen
  • An Facebook übertragen
AUF DIESES THEMA
ANTWORTEN
  1. #1
    Avatar von jokey2
    jokey2 jokey2 ist offline Mitglied Smaragd
    Registriert seit
    Nov 2004
    Beiträge
    1.235
    Hallo Gemeinde!

    Folgendes Problem:
    Wenn ich meine MFC-Applikation starte und als Programmargument einen Dateinamen angebe, dann versucht das MFC-Framework die Datei in ProcessShellCommand zu öffnen. Wenn das allerdings fehlschlägt, z.B. weil es die angegebene Datei nicht gibt, dann beendet sich die Anwendung wieder kommentarlos und das mit IMPLEMENT_DYNCREATE erzeugte CDocument wird nicht wieder zerstört. Die Folge: ein Speicherleck!
    Das kann ja eigentlich nicht sein, oder? Ich erzeuge das Dokument ja nicht selber, sondern es wird vom Framewürg erzeugt. Dann sollte das Framewürg es doch auch wieder zerstören, oder?
    Ich habe mir jetzt erstmal so beholfen, daß ich sowohl das CDocument als auch den MainFrame vor dem Aufruf von ProcessShellCommand selber erzeuge. Dadurch habe ich einen Zeiger auf das Dokument, den ich deleten kann, wenn das ProcessShellCommand FALSE zurückliefert, bzw. setze ich dann den 'm_nShellCommand' Parameter von 'CCommandLineInfo' auf 'FileNew' und lasse ProcessShellCommand so nochmal laufen. Dadurch wird die Applikation eben nicht einfach kommentarlos geschlossen sondern sie wird mit einem leeren Dokument geöffnet. So kann ich auch noch eine Meldung ausgeben, daß die Datei nicht gefunden wurde.
    So sieht das ganze dann aus:
    Code :
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    
        // Dokument und MainWnd erzeugen, um eventuelles Speicherleck zu vermeiden,
        // falls die Datei im Aufrufparameter nicht existiert
        CVDMIDEDoc * pDoc = (CVDMIDEDoc *)pDocTemplate->CreateNewDocument();
        m_pMainWnd = pDocTemplate->CreateNewFrame(pDoc, NULL);
        // Verteilung der in der Befehlszeile angegebenen Befehle
        if (!ProcessShellCommand(cmdInfo))
        {
            cmdInfo.m_nShellCommand = CCommandLineInfo::FileNew;
            cmdInfo.m_strFileName.Empty();
            if (!ProcessShellCommand(cmdInfo))
            {
                delete pDoc;
                return FALSE;
            }
        }
    Aber, wie gesagt, das kann's ja eigentlich nicht sein, daß man die MFC derartig austricksen muß, um kein Speicherleck zu bekommen. Hab' ich da irgendwas falsch gemacht? Hat jemand hier ähnliche Erfahrungen gemacht?

    Über Kommentare dazu würde ich mich sehr freuen.
     

  2. #2
    Avatar von Endurion
    Endurion Endurion ist offline Mitglied Diamant
    Registriert seit
    Apr 2004
    Beiträge
    2.151
    Blöde Frage, wie siehst du, dass du ein Speicherleck hast?

    Bekommst du einen Eintrag im Ausgabe-Fenster dazu?

    Ich habe das mal bei mir ausprobiert (VS 2003) und ich bekomme zwar eine Fehlermeldung, dass Datei xxx nicht geöffnet werden kann. Ein Leck bekomme ich am Ende aber nicht angezeigt?
     

  3. #3
    Avatar von jokey2
    jokey2 jokey2 ist offline Mitglied Smaragd
    Registriert seit
    Nov 2004
    Beiträge
    1.235
    wie siehst du, dass du ein Speicherleck hast?
    Nach dem Beenden im DevStudio kommt die übliche Anzeige von nicht freigegebenem Speicher:
    Document::OnOpenDocument returned FALSE.
    Warning: destroying CSingleDocTemplate with live document.
    Detected memory leaks!
    Dumping objects ->
    {680} normal block at 0x00D163F0, 48 bytes long.
    Data: < K b K > 10 4B D1 00 A8 62 D1 00 10 4B D1 00 CC CD CD CD
    {679} normal block at 0x00D16388, 33 bytes long.
    Data: < encoding > 00 65 6E 63 6F 64 69 6E 67 00 CD CD CD CD CD CD
    {678} normal block at 0x00D16320, 33 bytes long.
    Data: < ISO-8859-1 > 00 49 53 4F 2D 38 38 35 39 2D 31 00 CD CD CD CD
    {677} normal block at 0x00D162A8, 48 bytes long.
    Data: < c @X K > F0 63 D1 00 40 58 D1 00 10 4B D1 00 CC CD CD CD
    {676} normal block at 0x00D1BDD8, 33 bytes long.
    Data: < version > 00 76 65 72 73 69 6F 6E 00 CD CD CD CD CD CD CD
    {675} normal block at 0x00D1BD70, 33 bytes long.
    Data: < 1.0 > 00 31 2E 30 00 CD CD CD CD CD CD CD CD CD CD CD
    {674} normal block at 0x00D16240, 33 bytes long.
    Data: < xml > FF 78 6D 6C 00 CD CD CD CD CD CD CD CD CD CD CD
    {671} normal block at 0x00D15840, 48 bytes long.
    Data: < c b b > F0 63 D1 00 A8 62 D1 00 A8 62 D1 00 CD CD CD CD
    {670} normal block at 0x00D14B10, 48 bytes long.
    Data: < > 00 00 00 00 00 00 00 00 00 00 00 00 CD CD CD CD
    {669} normal block at 0x00D12D48, 12 bytes long.
    Data: <H- H- > 48 2D D1 00 48 2D D1 00 CD CD CD CD
    {668} normal block at 0x00D14C00, 44 bytes long.
    Data: < L L > 00 4C D1 00 00 4C D1 00 CD CD CD CD CD CD CD CD
    c:\projekte\vc++\vdmide\vdmidedoc.cpp(36) : {667} client block at 0x00D15FA8, subtype 0, 592 bytes long.
    a CVDMIDEDoc object at $00D15FA8, 592 bytes long
    Das ist meine InitInstance:
    Code cpp:
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    49
    50
    51
    52
    53
    54
    55
    56
    57
    58
    59
    60
    61
    62
    63
    64
    65
    66
    67
    68
    69
    70
    71
    72
    73
    74
    75
    76
    77
    78
    79
    80
    81
    82
    83
    84
    85
    86
    87
    
    // OLE-Bibliotheken initialisieren
        if (!AfxOleInit())
        {
            AfxMessageBox(IDP_OLE_INIT_FAILED);
            return FALSE;
        }
     
        AfxEnableControlContainer();
     
        // Standardinitialisierung
        // Wenn Sie diese Funktionen nicht nutzen und die Größe Ihrer fertigen 
        //  ausführbaren Datei reduzieren wollen, sollten Sie die nachfolgenden
        //  spezifischen Initialisierungsroutinen, die Sie nicht benötigen, entfernen.
     
    #ifdef _AFXDLL
        Enable3dControls();            // Diese Funktion bei Verwendung von MFC in gemeinsam genutzten DLLs aufrufen
    #else
        Enable3dControlsStatic();    // Diese Funktion bei statischen MFC-Anbindungen aufrufen
    #endif
     
        AfxInitRichEdit( );
     
        // Ändern des Registrierungsschlüssels, unter dem unsere Einstellungen gespeichert sind.
        // ZU ERLEDIGEN: Sie sollten dieser Zeichenfolge einen geeigneten Inhalt geben
        // wie z.B. den Namen Ihrer Firma oder Organisation.
        SetRegistryKey(_T("Firmenname"));
     
        LoadStdProfileSettings();  // Standard INI-Dateioptionen laden (einschließlich MRU)
     
        // Dokumentvorlagen der Anwendung registrieren. Dokumentvorlagen
        //  dienen als Verbindung zwischen Dokumenten, Rahmenfenstern und Ansichten.
     
        CSingleDocTemplate* pDocTemplate;
        pDocTemplate = new CSingleDocTemplate(
            IDR_MAINFRAME,
            RUNTIME_CLASS(CMyDoc),
            RUNTIME_CLASS(CMainFrame),       // Haupt-SDI-Rahmenfenster
            RUNTIME_CLASS(CLeftView));
        AddDocTemplate(pDocTemplate);
     
        // Verbinden des COleTemplateServer mit der Dokumentvorlage.
        //  Der COleTemplateServer legt auf Basis der Informationen in der
        //  Dokumentvorlage bei der Anforderung von OLE-Containern
        //  neue Dokumente an.
        m_server.ConnectTemplate(clsid, pDocTemplate, TRUE);
            // Hinweis: SDI-Anwendungen registrieren Server-Objekte nur dann, wenn /Embedding
            //   oder /Automation in der Befehlszeile enthalten ist.
     
        //Konfiguration laden
        m_Config.Load();
     
        // Befehlszeile parsen, um zu prüfen auf Standard-Umgebungsbefehle DDE, Datei offen
        CCommandLineInfo cmdInfo;
        ParseCommandLine(cmdInfo);
     
     
        // Testen, ob Ausführung als OLE-Server
        if (cmdInfo.m_bRunEmbedded || cmdInfo.m_bRunAutomated)
        {
            // Alle OLE-Server (-fabriken) als aktiv registrieren. Dies aktiviert die
            //  OLE-Bibliotheken, um Objekte von anderen Anwendungen zu erstellen.
            COleTemplateServer::RegisterAll();
     
            // Anwendung mit /Embedding oder /Automation gestartet. In diesem Fall
            //  kein Hauptfenster anzeigen.
            return TRUE;
        }
     
        // Wird eine Server-Anwendung im Standalone-Modus betrieben, ist es ratsam,
        //  die Systemregistrierung zu aktualisieren, falls diese beschädigt wurde.
        m_server.UpdateRegistry(OAT_DISPATCH_OBJECT);
        COleObjectFactory::UpdateRegistryAll();
     
        //Standard-Dateierweiterung registrieren
        RegisterFileExtension();
     
        // Verteilung der in der Befehlszeile angegebenen Befehle
        if (!ProcessShellCommand(cmdInfo))
            return FALSE;
     
        // Öffnen per DragDrop aktivieren
        m_pMainWnd->DragAcceptFiles();
        // Das einzige Fenster ist initialisiert und kann jetzt angezeigt und aktualisiert werden.
        m_pMainWnd->ShowWindow(SW_SHOW);
        m_pMainWnd->UpdateWindow();
     
        return TRUE;
    Geändert von jokey2 (10.07.06 um 12:16 Uhr)
     

  4. #4
    Avatar von Endurion
    Endurion Endurion ist offline Mitglied Diamant
    Registriert seit
    Apr 2004
    Beiträge
    2.151
    Das einzige, das mir da direkt auffällt, ist der COleTemplateServer. Ich könnte mir vorstellen, dass der COleTemplateServer als Object Factory da einen CDocTemplate-Klon von deinem Dokument erstellt und das wird nicht freigegeben.

    Rufst du denn da Unregister mit auf?
     

  5. #5
    Avatar von jokey2
    jokey2 jokey2 ist offline Mitglied Smaragd
    Registriert seit
    Nov 2004
    Beiträge
    1.235
    Rufst du denn da Unregister mit auf?
    Nö, sollte ich das?

    Das wurde vom VS hinzugefügt, ehrlich gesagt weiß ich gar nicht, ob ich das überhaupt brauche. Eigentlich habe ich keine besondere OLE-Unterstützung implementiert.
     

  6. #6
    Avatar von Endurion
    Endurion Endurion ist offline Mitglied Diamant
    Registriert seit
    Apr 2004
    Beiträge
    2.151
    Also MFC räumt normalerweise seine Templates auf.

    Jetzt muss ich allerdings gestehen, dass ich diese OLE-Server-Geschichte da noch nie gesehen habe (habe ich wohl beim Erstellen immer abgeschaltet? Oder hast du da VS 2005, ich habe nur 2003).
     

  7. #7
    Avatar von jokey2
    jokey2 jokey2 ist offline Mitglied Smaragd
    Registriert seit
    Nov 2004
    Beiträge
    1.235
    Ne, ich habe hier VS6.
    Ich hab's gerade mal ausprobiert. Ich habe eine neue Applikation mit dem Wizard erstellt und eine nicht existierende Datei als Parameter angegeben. Da kommt dann, wie es sein soll, die MessageBox, daß die datei nicht geöffnet werden konnte und die Anwendung schließt sich ohne Speicherleck.
    Warum das bei meiner App nicht so ist, weiß ich leider nicht!
     

  8. #8
    Avatar von Endurion
    Endurion Endurion ist offline Mitglied Diamant
    Registriert seit
    Apr 2004
    Beiträge
    2.151
    In dem Fall hilft nur Hardcore:

    Du bekommst ja bei dem Speicherleck eine Nummer angezeigt:

    c:\projekte\vc++\vdmide\vdmidedoc.cpp(36) : {667} client block

    Du kannst mit _CrtSetBreakAlloc jetzt die Nummer angeben. Das muss im Sourcecode passieren, am besten so früh wie möglich (im Constructor von der App zum Bleistift):

    _CtrSetBreakAlloc( 667 );

    Die Funktion benötigt das Include <crtdbg.h>.

    Dann müsste beim Erzeugen ein Breakpoint aufgerufen werden und du kannst am CallStack prüfen, ob das jetzt dein CDocTemplate ist (das in InitInstance angelegt wird) oder ein anderes. Ich setze hier auf die Annahme auf, dass ein DocTemplate, das mit AddDocTemplate angemeldet wird, auf jeden Fall aufgeräumt wird; und das evtl. irgendwo ein zweites Doc-Template erzeugt wird.
     

Ähnliche Themen

  1. dynamischen tree erzeugen
    Von worst_case im Forum XML Technologien
    Antworten: 14
    Letzter Beitrag: 07.01.11, 00:10
  2. Druck eines Dynamischen Inhaltes
    Von crsakawolf im Forum CSS
    Antworten: 5
    Letzter Beitrag: 28.10.10, 07:09
  3. Problem beim Erzeugen eines Images aus byte[]
    Von Kai008 im Forum Java Grundlagen
    Antworten: 8
    Letzter Beitrag: 08.07.10, 17:59
  4. Antworten: 2
    Letzter Beitrag: 27.08.09, 20:05
  5. Value eines Dynamischen Droptdownfeldes
    Von Peace-Maker im Forum Javascript & Ajax
    Antworten: 1
    Letzter Beitrag: 07.11.08, 11:06