Autor Beitrag
Asmodeus
Hält's aus hier
Beiträge: 8



BeitragVerfasst: Mi 22.09.10 23:46 
Hallo liebe Community,

ich muss sagen, dass ich Dank der Hilfe dieses Forums schon sehr weit mit meinem Programm gekommen bin. Zu fast jedem Problem oder Frage die ich hatte war bereits eine Antwort hier im Forum verfügbar. Jetzt hänge ich aber leider schon seit einiger Zeit fest und komme nicht weiter.

Ich habe eine Vertragsdatenbank programmiert. Die Datenbank selber wurde erstellt mit Access 2003 und beinhaltet nur die Daten. Abfragen werden via SQL aus dem Programm heraus gesteuert. Nun habe ich eine Möglichkeit implementiert Dateianhänge als Link in der Datenbank zu speichern und über Shellapi wieder auszuführen. Bei Dateien, die auf dem lokalen PC abgespeichert sind klappt das wunderbar, bei Dateien auf dem Netzwerk klappt es nicht. Dort stürzt er ab in Bereich Zeile 628 in der Unit kundendatenverwalten. Den Bugreport füge ich separat noch hinzu. Er gibt dabei eine Eaccessviolation aus und einen Fehler beim ERstellen einer neuen SQL Query. Ich verstehe absolut nicht, warum das Problem nur bei Dateianhängen auftritt die sich auf dem Server befinden. Danach ist das Programm auch in einer Fehler-Endlosschleife und muss über den Task Manager beendet werden.

Zu dem Hintergrundsystem kann ich sagen, dass lokal Windows XP SP3 genutzt wird. Das Programm ist als Client lokal bei jedem Nutzer gespeichert. Die Datenbank sowie auch die Dateianhänge sind auf einem Server gespeichert. Entwickelt wird das System auf einem Windows 7 Rechner.

Ich hatte schon versucht mit einer Abfangroutine dieses Fehler zu elminieren und habe die unit sharemem eingebunden, aber nichts hilft davon.
Es wäre echt super nett, wenn jemand einen Anhaltspunkt hätte wo das Problem liegen könnte...

Vielen Dank!

Grüße
Jens


-------------------------------
04.10.2010 UPDATE
Soooo ich habe herausgefunden, dass meine Probleme immer dann stattfinden, wenn ich eine zu große Datei mit Shellexecute aufgerufen habe. Kleinere Dateien funktionen problemlos, aber wenn diese eine bestimmte Anzahl MB überschritten haben, werde Fehler verursacht. Dies geschieht nicht nur im Netzwerk sondern auch lokal, womit ich nun sicher bin, dass der Fehler dort zu suchen ist.

Das Projekt habe ich komplett angehangen und hier ist die entsprechende Prozedur:
ausblenden volle Höhe Delphi-Quelltext
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:
88:
89:
90:
91:
92:
93:
94:
95:
96:
97:
98:
99:
100:
101:
102:
103:
104:
105:
106:
107:
108:
109:
110:
111:
112:
113:
114:
115:
procedure TKundendaten_verwalten_form.GridattachKeyDown(Sender: TObject;
  var Key: Word; Shift: TShiftState);
Var Antwort,i : Integer;
    Pfad :String;
    Name: String;
    PfadChar, Pfadchar2 : PWidechar;
    searchResult : TSearchRec;
    weiter : Boolean;
    ReturnValue : THandle;
begin
If (Key = VK_RETURN) Then
begin

   //Attachment wird geöffnet
 if DataModule2.QueryAttach.Eof = TRUE then
 begin
   exit;
 end
 else
 begin

    Antwort := Application.MessageBox ('Do you really want to open attached file?''Question',
      MB_YesNo+MB_IconQuestion+MB_DefButton2);

    if antwort = IDYes then
    begin
     TRY
     //Dateipfad wird ermittelt
     Pfad:= '';
     Name:= '';
     if datamodule2.QueryAttach.Active = TRUE then
         begin
           Name:= datamodule2.QueryAttach.FieldByName('Filename').AsString;
           datamodule2.QueryAttach.Active:= FALSE;
           datamodule2.QueryAttach.Close;
         end;
         //Query filtert nach allen benötigten Datenfeldern
         datamodule2.QueryAttach.SQL.Clear;
         datamodule2.QueryAttach.SQL.Text:= 'SELECT * FROM Attachments WHERE VertragID = '+inttostr(VertragID)+' AND Dateiname = '+quotedstr(Name);
         datamodule2.QueryAttach.Open;
         datamodule2.QueryAttach.Active:= TRUE;
         gridattach.DataSource.DataSet:= datamodule2.QueryAttach;

         pfad:= Pfad + datamodule2.QueryAttach.FieldByName('Dateipfad').AsString;
         pfad:= Pfad + datamodule2.QueryAttach.FieldByName('Dateiname').AsString;
         name:= datamodule2.QueryAttach.FieldByName('Dateiname').AsString;
         FINALLY
         //Ursprüngliche Anzeige wird wieder hergestellt
         if datamodule2.QueryAttach.Active = TRUE then
         begin
           datamodule2.QueryAttach.Active:= FALSE;
           datamodule2.QueryAttach.Close;
         end;
         datamodule2.QueryAttach.SQL.Clear;
         datamodule2.QueryAttach.SQL.Text:= 'SELECT Dateiname as Filename, VertragID as ID FROM Attachments WHERE VertragID = '+inttostr(VertragID);
         datamodule2.QueryAttach.Open;
         datamodule2.QueryAttach.Active:= TRUE;
         gridattach.DataSource.DataSet:= datamodule2.QueryAttach;
         gridattach.DataSource.DataSet.Filtered:= TRUE;


         try
       <span style="color: red">  getmem(Pfadchar, 256);
         StringToWideChar(pfad, pfadchar, 256);
         if fileexists(pfad) then
         begin


         ReturnValue := 0;
         ReturnValue := ShellExecute(Application.Handle, 'open', Pfadchar, nilnil, SW_SHOW);
     


        if ReturnValue <= 32 then
           showmessage(SysErrorMessage(ReturnValue)+ ' '+ IntToStr(ReturnValue));
</span>
         end
         else
         BEGIN
             Antwort := Application.MessageBox ('Cannot load assigned program or Path is invalid! Do you want to use the Quickfind-Function?''Question',
                  MB_YesNo+MB_IconQuestion+MB_DefButton2);
             if antwort = IDYes then //Quickfind
             begin
               pfad:= '';
               GetFilesInDirectory(datamodule2.DBPfad,name , Boxresult.Items, TRUE, True);

               if boxresult.Count = 0 then
               begin
                 Showmessage('Couldn''t find your requested file with Quickfind!');
               end
               else  //ES wurde eine Datei gefunden Datei kann gestartet werden
               begin
                  pfad:= boxresult.Items.Strings[0];
                  freemem(pfadchar);
                  getmem(Pfadchar, 256);
                  StringToWideChar(pfad, pfadchar, 256);
                  boxresult.Items.Clear;
                    try
                       ShellExecute(Application.Handle, 'open', Pfadchar, nilnil, SW_SHOW);
                    except
                      Showmessage('Cannot load assigned program!');
                    end;

               end;
             end;   // STOP Quickfind
         END;

         finally
            freemem(pfadchar);
         end;
     END;
  end;
 end;
end;
end;
Einloggen, um Attachments anzusehen!


Zuletzt bearbeitet von Asmodeus am Mo 04.10.10 20:34, insgesamt 2-mal bearbeitet
Asmodeus Threadstarter
Hält's aus hier
Beiträge: 8



BeitragVerfasst: Mi 22.09.10 23:49 
Part 2
Einloggen, um Attachments anzusehen!
Asmodeus Threadstarter
Hält's aus hier
Beiträge: 8



BeitragVerfasst: Mi 22.09.10 23:50 
Part 3
Einloggen, um Attachments anzusehen!
Asmodeus Threadstarter
Hält's aus hier
Beiträge: 8



BeitragVerfasst: Mi 22.09.10 23:51 
Bug Report (madexcept V 3)
Einloggen, um Attachments anzusehen!
Asmodeus Threadstarter
Hält's aus hier
Beiträge: 8



BeitragVerfasst: Mo 04.10.10 19:28 
schade, scheint keiner eine LÖsung zu haben :(
Muck
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starhalf ontopic star
Beiträge: 98
Erhaltene Danke: 8

Win 8, Win 7, Vista, Win XP
Delphi XE3, Delphi 2009, Delphi 2007, Delphi 5
BeitragVerfasst: Mo 04.10.10 20:19 
Hallo,

in Deinem "COM PRGL" Abschnitt greifst Du auf query zu, jedoch hast Du vorher "datamodule2.DelQuery" aufgerufen.
In Deiner Procedure DelQuery machst Du ein Free auf das TAdoQuery Object.
Daher Access Violation.
Davon abgesehen: TAdoQuery.Free ruft automatisch ein Close auf. Also kein Grund vorher auf Active=TRUE zu pruefen,
dann Active=false zu setzen und dann noch ein Close. Das ist dreimal das Gleiche.
Ausserdem, suche mal im Forum weshalb man nicht "If Query.Active=TRUE" bunutzen sollte, gleiches fuer
"while query.eof = false"! Besser nutze "while not query.eof"

Statt innerhalb Deiner Procedure die TAdoQuery staendig zu erzeugen und wieder freizugeben, besser nur einmal erzeugen am Anfang,
dann einen Schutzblock und einmal freigeben am Ende.
Innerhalb der Procedure dann die Query schliessen und dann einfach SQL.Text ein neues Kommando zuweisen und die Query wieder oeffnen.

Markus


ausblenden volle Höhe Delphi-Quelltext
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:
procedure TKundendaten_verwalten_form.comboboxaktualisieren;
Var i, index : Integer;
    query : TAdoquery;
begin
//*************************COM LAND*******************************************
 for i := 0 to comland.Items.Count do
 begin
   comland.Items.Delete(0);
 end;
 query:= datamodule2.CreateQuery('SELECT * FROM Länder',0);
 query.First;
 while query.Eof = FALSE do
 begin
   comland.Items.Add(query.FieldByName('Kennzeichen').AsString);
   query.Next;
 end;
 datamodule2.Delquery(query);
 index:= comland.Items.IndexOf(datamodule2.QueryKunden.FieldByName('Land').AsString);
 comland.ItemIndex:= index;
//*************************COM PRGL*******************************************
 for i := 0 to comPRGL.items.Count do
 begin
   comPRGL.Items.Delete(0);
 end;
 if query.Active = TRUE then
 begin
   query.Active:= FALSE;
   query.Close;
 end;

 query:= datamodule2.CreateQuery('SELECT * FROM Preisgleitklauseln',0);
 //query.First;
 while query.Eof = FALSE do  //Fügt alle PRGL zur Auswahl hinzu
 begin
   comprgl.Items.Add(query.FieldByName('PRC').AsString);
   query.Next;
 end;
 datamodule2.Delquery(query);

 query:= datamodule2.CreateQuery('SELECT * FROM KD_PRGL_List WHERE ContractID = '+inttostr(VertragID),0);
 index:= comprgl.Items.IndexOf('Dummy');
 comprgl.Items.Delete(index);
 while query.Eof = FALSE do //Löscht die PRGL, die bereits ausgewählt wurden
 begin
   index:= comprgl.Items.IndexOf(query.FieldByName('PRGL').AsString);
   comprgl.Items.Delete(index);
   query.Next;
 end;
 datamodule2.Delquery(query);
//*************************COM PRC*******************************************
 for i := 0 to comPRC.items.Count do
 begin
   comPRC.Items.Delete(0);
 end;
 comprc.Items.Add('Dummy');
 query:= datamodule2.CreateQuery('SELECT * FROM KD_PRGL_List WHERE ContractID = '+inttostr(vertragid),0);
 query.First;
 while query.Eof = FALSE do  //Fügt alle PRGL zur Auswahl hinzu
 begin
   comPRC.Items.Add(query.FieldByName('PRGL').AsString);
   query.Next;
 end;
 datamodule2.Delquery(query);


end;
Asmodeus Threadstarter
Hält's aus hier
Beiträge: 8



BeitragVerfasst: Mo 04.10.10 20:39 
Hallo Markus,

danke, dass du dir meinen Code angetan hast. Soweit ich erkennen kann, erzeugt dies nicht das Problem, trotzdem vielen Dank für deine Tipps. Ich hatte wirklich versucht alles ziemlich ordentlich zu coden und dachte es wäre ganz gute die Query immer wieder neu zu machen und dann wirder zu löschen, aber war dann scheinbar doch nicht die beste Idee. Werde auf jeden Fall deine Hinweise versuchen umzusetzen, vielen Dank!

Mittlerweile bin ich aber fest davon überzeugt, dass das Problem an der Dateigröße liegt. Kannst du dir vorstellen ob Shellexecute so ein Problem verursachen kann?

Danke!

Grüße
Jens
Muck
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starhalf ontopic star
Beiträge: 98
Erhaltene Danke: 8

Win 8, Win 7, Vista, Win XP
Delphi XE3, Delphi 2009, Delphi 2007, Delphi 5
BeitragVerfasst: Mo 04.10.10 20:59 
Jens,

man kann natuerlich auch immer ein Create und Free aus ein TAdoObject machen. Nach einem Free (oder bei Dir DelQuery) kannst Du jedoch das TAdoObject nicht mehr benutzen und das ist was Du tust, ungefaehr in Zeilte 628.

Ausserdem noch ein Tip:
ausblenden Delphi-Quelltext
1:
2:
3:
4:
 for i := 0 to comPRGL.items.Count do
 begin
   comPRGL.Items.Delete(0);
 end;

Fuer eine Liste mit 10 items rufst Du Delete(0) 11 mal auf.

Besser:
ausblenden Delphi-Quelltext
1:
comPRGL.Items.Clear;					


loescht alles in einem Rutsch.

Und:
Waehrend du Items einer ComboBox mit dem Inhalt einer Tabelle fuellst solltest du BeginUpdate und Endupdate aufrufen, besonders beim Fuellen groesserer Tablellen oder das ganze wird ewig dauern, da die ComboBox immer wieder neu gezeichnet wird.

Zu der Frage, groesse der Datei:
Ich glaube nicht, dass ShellExecute ein Problem mit Dateien hat, die ein paar MB groesser sind. Wenn das der Fall waere, koennest Du die Dateien ja auch nicht mehr mit Doppelklick direkt vom Explorer oeffnen. Ich glaube viel mehr, dass Du vorher bereits Speicherbreiche ueberschrieben hast und das fuehrt dann spaeter zu diesen Fehlern.

Pruefe Dein Programm mal komplette auf Schutzbloecke und ob Du irgendwo anders noch auf Objecte zugreifst, die breits freigegeben sind. Schalte auch mal die Bereichspruefung in den Compiler optionen an.

Markus
Asmodeus Threadstarter
Hält's aus hier
Beiträge: 8



BeitragVerfasst: Do 07.10.10 06:14 
Hallo Markus,

vielen Dank für deine Hilfe. Ich arbeite gerade daran den Code zu verbessern gemäß deinen Ausführungen. Kannst du mir bitte nur sagen wie ich am besten die Objekte oder Speicherbereiche überprüfen kann? Das übersteigt irgendwie komplett meinen Kenntnisstand...arbeite sonst immer nur mit dem Fehlern, die der Compiler immer direkt anzeigt.

Danke!

Grüße
Jens
jaenicke
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starofftopic star
Beiträge: 19339
Erhaltene Danke: 1752

W11 x64 (Chrome, Edge)
Delphi 12 Pro, C# (VS 2022), JS/HTML, Java (NB), PHP, Lazarus
BeitragVerfasst: Do 07.10.10 06:16 
In den Projektoptionen unter Compiler gibt es die Bereichsüberprüfung.

Im Projektquelltext kannst du ReportMemoryLeaksOnShutdown als erstes auf True setzen, dann werden dir die beim Programmende angezeigt.
Asmodeus Threadstarter
Hält's aus hier
Beiträge: 8



BeitragVerfasst: Di 19.10.10 14:25 
Hi Sebastian,

vielen Dank!
MIr ist aufgefallen, dass ich bei Getmem auch zu wenig Speicher zuweise. Dazu habe ich noch einige weitere Schutzblöcke eingebaut. Mittlerweile läuft das Programm schon ganz stabil, werde aber weiter testen um zu sehen, ob es doch noch Probleme gibt.

Schon mal vielen Dank bis jetzt!

Grüße
Jens