[Delphi] geheugen alloceren, kopieren en vrijmaken

Pagina: 1
Acties:
  • 111 views sinds 30-01-2008
  • Reageer

  • FendtVario
  • Registratie: Januari 2002
  • Laatst online: 12-05-2025

FendtVario

The leader drives Vario!

Topicstarter
Ik bezig met een programmatje dat bestandjes moet gaan zoeken over het netwerk in alle beschikbare werkgroepen die er zijn. Hiervoor zijn (uiteraard) een paaar handige functies opgenomen in delphi te weten: WNetOpenEnum, WNetEnumResource en WNetCloseEnum. Ook te vinden in de Win32 SDK.

De drie maken gebruik van een structure dat gedefinieerd is al packed record onder de naam TNetResourceA en is te bereiken met een pointer PNetResourceA. Het zoeken duurt echter verschrikkelijk lang, de werkgroepen en pc zijn zo gevonden maar de shares duurt echt verschrikkelijk lang.

Daarom wou ik de structures bewaren en in een thread op de achtergrond de shares opzoeken. Dit lukt echter maar gedeeltelijk. Op naar het probleem:

Als je een nieuwe variabele als pointer wil maken gebruikte je vroeger GetMem( pointer, size ), nu doen we dat met New. De pointer weggooien gebeurt vervolgens met Dispose( pointer ).


Maar nu, het kopieren van geheugen doen we met CopyMemory( destination, source, size), hier kom ik echter in de problemen. Het gekopieerde structure is niet altijd correct. Hier mijn code:
code:
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
procedure TSearchGroups.GetGroups(const Parent: TTreeNode;
   NetNode: PNetResourceA);
{ recurse through the network and find all available workgroups }
const
   INITIALSIZE = $1;
var
   tmpHEnum: THandle;
   tmpCount, tmpBufSize: DWORD;
   tmpNetResource, tmpBuf, tmpNRTree: PNetResourceA;
   tmpNRE: Integer; // network-resource enumerator
   tmpChildNode: TTreeNode;

   tmpShrSearch: TSearchShares;
begin
   { open the net resources, search for containers only }
   tmpNRE := WNetOpenEnum( RESOURCE_GLOBALNET, RESOURCETYPE_DISK,
    RESOURCEUSAGE_CONTAINER, NetNode, tmpHEnum);

   if tmpNRE <> NO_ERROR then
   begin
    Exit;
   end;

   tmpBufSize := $1;
   GetMem(tmpBuf, tmpBufSize);
   try
    while True do
    begin
       tmpCount := $FFFFFFFF;   // read all items
       tmpNRE := WNetEnumResource(tmpHEnum, tmpCount, tmpBuf, tmpBufSize);

       if tmpNRE = ERROR_MORE_DATA then
       begin
        { the initial size is to smal }
        tmpCount := $FFFFFFFF;   // read all items
        FreeMem(tmpBuf);
        GetMem(tmpBuf, tmpBufSize);
        tmpNRE := WNetEnumResource(tmpHEnum, tmpCount, tmpBuf, tmpBufSize);
       end;

       if tmpNRE = ERROR_NO_MORE_ITEMS then Break;
       if tmpNRE <> NO_ERROR then
       begin
        { if there's an error abort the search }
        Abort;
       end;

       tmpNetResource := tmpBuf;
       while tmpCount > 0 do
       begin
        //tmpChildNode := frmMain.tvNetwork.Items.AddChild(Parent,
        //   tmpNetResource.lpRemoteName);

        //we need to save the structure, copy it
        New(tmpNRTree);
        CopyMemory(tmpNRTree, tmpNetResource, SizeOf(tmpNetResource^) );

        tmpChildNode := frmMain.tvNetwork.Items.AddChildObject(Parent,
           tmpNetResource.lpRemoteName, tmpNRTree);

        GetGroups(tmpChildNode, tmpNetResource);

        Inc( tmpNetResource );
        Dec( tmpCount );
       end; // while tmpCount > 0

    end; // while R <> ERROR_NO_MORE_ITEMS
   finally
    WNetCloseEnum( tmpHEnum );
    FreeMem( tmpBuf );
   end; // try
end;

De structures worden in een TreeView opgeslagen. De const RESOURCEUSAGE_CONTAINER geeft aan dat we alleen zoeken naar groepen en pc's.

De structures in de tree zijn af en toe goed, dat is het vervelende. Ook als ik met de debugger step->run doe gaat het fout.

Please help.

www.fendt.com | Nikon D7100 | PS5


  • FendtVario
  • Registratie: Januari 2002
  • Laatst online: 12-05-2025

FendtVario

The leader drives Vario!

Topicstarter
Op zaterdag 15 juni 2002 20:01 schreef FendtVario het volgende:
Ik bezig met een programmatje dat bestandjes moet gaan zoeken over het netwerk in alle beschikbare werkgroepen die er zijn. Hiervoor zijn (uiteraard) een paaar handige functies opgenomen in delphi te weten: WNetOpenEnum, WNetEnumResource en WNetCloseEnum. Ook te vinden in de Win32 SDK.

De drie maken gebruik van een structure dat gedefinieerd is al packed record onder de naam TNetResourceA en is te bereiken met een pointer PNetResourceA. Het zoeken duurt echter verschrikkelijk lang, de werkgroepen en pc zijn zo gevonden maar de shares duurt echt verschrikkelijk lang.

Daarom wou ik de structures bewaren en in een thread op de achtergrond de shares opzoeken. Dit lukt echter maar gedeeltelijk. Op naar het probleem:

Als je een nieuwe variabele als pointer wil maken gebruikte je vroeger GetMem( pointer, size ), nu doen we dat met New. De pointer weggooien gebeurt vervolgens met Dispose( pointer ).


Maar nu, het kopieren van geheugen doen we met CopyMemory( destination, source, size), hier kom ik echter in de problemen. Het gekopieerde structure is niet altijd correct. Hier mijn code:
code:
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
procedure TSearchGroups.GetShares(const Parent: TTreeNode;
   NetNode: PNetResourceA);
{ recurse through the network and find all available workgroups }
const
   INITIALSIZE = $1;
var
   tmpHEnum: THandle;
   tmpCount, tmpBufSize: DWORD;
   tmpNetResource, tmpBuf, tmpNRTree: PNetResourceA;
   tmpNRE: Integer; // network-resource enumerator
   tmpChildNode: TTreeNode;

   tmpShrSearch: TSearchShares;
begin
   { open the net resources, search for containers only }
   tmpNRE := WNetOpenEnum( RESOURCE_GLOBALNET, RESOURCETYPE_DISK,
    RESOURCEUSAGE_CONTAINER, NetNode, tmpHEnum);

   if tmpNRE <> NO_ERROR then
   begin
    Exit;
   end;

   tmpBufSize := $1;
   GetMem(tmpBuf, tmpBufSize);
   try
    while True do
    begin
       tmpCount := $FFFFFFFF;   // read all items
       tmpNRE := WNetEnumResource(tmpHEnum, tmpCount, tmpBuf, tmpBufSize);

       if tmpNRE = ERROR_MORE_DATA then
       begin
        { the initial size is to smal }
        tmpCount := $FFFFFFFF;   // read all items
        FreeMem(tmpBuf);
        GetMem(tmpBuf, tmpBufSize);
        tmpNRE := WNetEnumResource(tmpHEnum, tmpCount, tmpBuf, tmpBufSize);
       end;

       if tmpNRE = ERROR_NO_MORE_ITEMS then Break;
       if tmpNRE <> NO_ERROR then
       begin
        { if there's an error abort the search }
        Abort;
       end;

       tmpNetResource := tmpBuf;
       while tmpCount > 0 do
       begin
        //tmpChildNode := frmMain.tvNetwork.Items.AddChild(Parent,
        //   tmpNetResource.lpRemoteName);

        //we need to save the structure, copy it
        New(tmpNRTree);
        CopyMemory(tmpNRTree, tmpNetResource, SizeOf(tmpNetResource^) );

        tmpChildNode := frmMain.tvNetwork.Items.AddChildObject(Parent,
           tmpNetResource.lpRemoteName, tmpNRTree);

        GetShares(tmpChildNode, tmpNetResource);

        Inc( tmpNetResource );
        Dec( tmpCount );
       end; // while tmpCount > 0

    end; // while R <> ERROR_NO_MORE_ITEMS
   finally
    WNetCloseEnum( tmpHEnum );
    FreeMem( tmpBuf );
   end; // try
end;

De structures worden in een TreeView opgeslagen. De const RESOURCEUSAGE_CONTAINER geeft aan dat we alleen zoeken naar groepen en pc's.

De structures in de tree zijn af en toe goed, dat is het vervelende. Ook als ik met de debugger step->run doe gaat het fout.

[edit]
de functie roep je aan met GetShares(nil,nil)

Please help.

www.fendt.com | Nikon D7100 | PS5


Verwijderd

Gebruik je de BeginUpdate, EndUpdate van de Tree?

Misschien is het makkelijker om een array of TNetResource te gebruiken. Hiervan kun je de lengte setten dmv SetLength.

Bij WNetEnumResource, als je BufferSize op 0 zet krijg je de benodigde groootte van de buffer.

De aanroep wordt dan zoiets:
code:
1
2
3
4
5
  BufferSize := 0;
  WNetEnumResource(NetHandle, Count, nil, BufferSize);
  Count := BufferSize div SizeOf(TNetResource) + 1;
  SetLength(Buffer, Count);
  Error := WNetEnumResource(NetHandle, Count, @Buffer[0], BufferSize);

Ik zie geen fouten mbt geheugengebruik; maar ik zal maandag wel eens op het werk testen.

  • FendtVario
  • Registratie: Januari 2002
  • Laatst online: 12-05-2025

FendtVario

The leader drives Vario!

Topicstarter
Dat kan ook ja, maar dan verlies je boomstructuur, wat je dan krijgt is gewoon een lijst van alle groepen, pc's en shares. Ik wil juist de boomstructuur bewaren.

In mijn code word de PNetResourceA gekopieerd en in de boom opgeslagen, ik heb een onDblClick event op de TTreeView gemaakt dat van het item de PNetResourceA^.lpRemoteName en lpComment laat zien. Maar het lijkt af en toe wel als of deze gereset worden en de waarden gewist worden.

www.fendt.com | Nikon D7100 | PS5


Verwijderd

Oke je hebt een pointer naar een TNetResource record; dit record heb je zelf gealloceerd, dus hier geen probleem. Deze pointer zet je in de boom. In deze records staan pointers naar geheugenlocaties waar strings staan.

Je hebt geen geheugen gealloceerd voor die strings, dus het lijkt me logisch dat windows die in beheer heeft; waarschijnlijk [lees: zeker] worden die strings weggegegooid na de WNetCloseEnum.

Dus wat moet je doen: Een eigen record maken net als TNetResource, dus bv:
code:
1
2
3
4
5
6
7
8
9
10
11
  PMyNetResource = ^TMyNetResource;
  TMyNetResource = record
   RScope: DWORD;
   RType: DWORD;
   RDisplayType: DWORD;
   RUsage: DWORD;
   RLocalName: string;
   RRemoteName: string;
   RComment: string;
   RProvider: string;
 end;

[Ik prefix record-fields met R :)]

Je alloceert een TMyNetResource record met New; zet de pointer hiernaar toe in de tree; ook kopieer je de TNetResource record hier in; nu heb jij controle over het geheugenbeheer van de strings..

  • FendtVario
  • Registratie: Januari 2002
  • Laatst online: 12-05-2025

FendtVario

The leader drives Vario!

Topicstarter
ok, een idee. Ik heb het geprobeerd en de CopyMemory functie kan dan dus niet meer omdat _NETRESOURCEA in de System.pas van Delphi een packed record is. Maar nu het volgende:

als de eerste thread alle werkgroepen en pc's gevonden heeft moet een tweede thread de shares gaan zoeken. Dan geef je het _NETRESOURCEA record dus weer aan de WNetOpenEnum en moet je het dus ook weer terugzetten op de juiste manier. NIet echt problematisch, ff twee functies toevoegen en klaar is kees.

Raar vindt ik het dan alleen nog waarom het probleem er niet altijd is maar dan soms de strings niet aanwezig zijn. En af en toe werkt het de eerste keer wel (de onclick op een tree-item die de waarden laat zien) en een tweede of derde keer niet meer. Zal inderdaad wel aan dat geheugenbeheer liggen.

www.fendt.com | Nikon D7100 | PS5


Verwijderd

Met WNetCloseEnum geef je het geheugen vrij; het staat er dan nog wel, maar iedereen mag erover heen schrijven.

Hoe langer je wacht, hoe groter de kans is dat het ook daadwerkelijk is overschreven.

  • FendtVario
  • Registratie: Januari 2002
  • Laatst online: 12-05-2025

FendtVario

The leader drives Vario!

Topicstarter
aha, op die fiets. Ik geloof dat ik nu steeds beter die pointers ga begrijpen. Klinkt inderdaad logisch. Ik ben nu twee procedures aan het maken die het geheel dan maar converten van de Windows NetResource naar de eigen.

Dank voor de hulp. heb ik morgen op school ook weer wat te doen. Ik wil dit gebruiken in een programmatje dan alle shares op het laptop-netwerk doorzoekt op een aantal extensies. Dit omdat de windows zoekfunctie (Windowstoest + F) je niet door het hele netwerk laat zoeken.

www.fendt.com | Nikon D7100 | PS5

Pagina: 1