Netzscan mit Quellcode [gelöst]



  • Hallo DocShoe,

    bin mit dem Debugger leider nicht sehr fit;
    wenn ich mir aber die ermittelten Daten bei
    meinem Kommentar in der FunktionNetzscanner.hpp
    ausgeben lasse, dann ist der Servername immer
    der korrekt übergebene. Aber das Ergebnis in
    der Map dic ist immer die gleiche. Das das
    Netscanner sich selbst rekursiv aufruft, vermute
    ich hier ein Problem. Wenn ich nämlich diese Stelle
    in der FunktionNetzscanner.hpp so verändere:

    bool NetworkBase::NetScan(StringToString *dic,void *obj,func eh,string resource,DWORD displaytype,DWORD type,LPNETRESOURCE lpnr)
    {Integer iPos; AnsiString zData,zTxt,zTyp;					// Vars definieren
     DWORD dwResult,dwResultEnum; 							// für die Rückgaben der API-Funktionen
     HANDLE hEnum;									// ein Handle auf die Enumeration
     DWORD cbBuffer=16384;      							// eine Buffergröße
     DWORD cEntries=-1;            							// für die Anzahl der zurückgegebenen Objekte
     LPNETRESOURCE lpnrLocal;      							// ein Zeiger auf eine NETRESOURCE-Struktur (für die Methode intern)
    
     if(lpnr==NULL && !resource.empty()) {						// wenn Resource übergeben wird, dann erstellen wir eine NETRESOURCE Struktur
      NETRESOURCE rec;								// vorbereiten
      rec.dwScope	     = RESOURCE_GLOBALNET;					// globale Netzerk durchsuchen (nicht Internet)
      rec.dwType	     = type;							//
      rec.dwDisplayType  = displaytype;                                             //
    
      if(type==RESOURCETYPE_DISK || type==RESOURCETYPE_PRINT) {			// wenn wir nach einer Freigabe oder nach einem Netzwerkdrucker suchen
       rec.dwUsage       = RESOURCEUSAGE_CONNECTABLE;                               // Laufwerke oder Freigaben usw.
    
    // ================================   
    // ANFANG NEU EINGEFÜGT ZUM TESTEN:
       rec.lpLocalName   = NULL;							//
       rec.lpComment     = NULL;                                                    //
       rec.lpProvider    = NULL;                                                    //
       rec.lpRemoteName  = (char *)resource.c_str();				//
       lpnr 	     = &rec;                                                    //
    // ENDE NEU
    // ================================
    
      }                                                                             // ende if(type==
      else {								        // alle anderen Suchen (Domains, Workgroups...)
       rec.dwUsage       = RESOURCEUSAGE_CONTAINER;                                 // Domains, Server, Workgroups usw.
       rec.lpLocalName   = NULL;							//
       rec.lpComment     = NULL;                                                    //
       rec.lpProvider    = NULL;                                                    //
       rec.lpRemoteName  = (char *)resource.c_str();				//
       lpnr 	     = &rec;                                                    //
      }										// ende else(
     }										// ende if(lpnr==NULL
    

    ..dann bekomme ich die richtigen Ergebnisse,
    allerdings hört die Schleife dann nicht mehr auf.

    Ich kann auch gerne mal das ganze Projekt zukommen
    lassen, wenn damit jemand was ausprobieren möchte.
    Verstehe leider zuwenig von diesen Strukturen, Iteratoren usw.

    Danke und Gruss, Stefan



  • Läuft deine Anwendung in den ersten if-Block an Zeile 9?
    Wenn das so sein sollte handelst du dir ein undefiniertes Verhalten ein, denn du definierst in dem if-Block eine lokale Variable rec, die nur in diesem Block gültig ist, weist dann aber lpnr deren Adresse zu. Damit zeigt lpnr nach dem if-Block auf bereits freigegebenen Speicher.

    PS:
    (1) Du solltest Variablen erst dann deklarieren, wenn sie tatsächlich benötigt werden. Also bitte nicht alle am Kopf der Methode deklarieren.

    (2) Falls die while-Schleife mit dwResultEnum!=ERROR_NO_MORE_ITEMS abbricht gibst du lpnrLocal 2x frei (1x im if-Block, 1x nach der while-Schleife)

    (3) Fast alle Win32 API Funktionen, die einen Speicherblock zum Füllen erwarten, haben die Eigenschaft, dass sie bei einem Aufruf mit der Pufferlänge 0 die benötigte Puffergrösse zurückgeben.

    DWORD dwBufferSize = 0;
    DWORD dwEntryCount = -1;
    
    // 1. Aufruf: Puffergrösse bestimmen
    ::WNetEnumResource( hHandle, &dwEntryCount, 0, &dwBufferSize );
    
    // Speicher anfordern (als vector)
    vector<char> ResourceBuffer( dwBufferSize );
    
    // 2. Aufruf: tatsächliche Daten abholen
    ::WNetEnumResource( hHandle, &dwEntryCount, reinterpret_cast<LPVOID>( &ResourceBuffer[0] ), &dwBufferSize );
    
    NETRESOURCE* pRes = reinterpret_cast<NETRESOURCE*>( ResourceBuffer[0] );
    ...
    


  • Hallo

    Hier kannst du nachlesen wie du mit dem Debugger arbeiten kannst. Ist sehr wichtig für halbwegs komplexe Programme wie deins.

    bis bald
    akari



  • Hallo an alle,
    so funktioniert es, wenn die FunktionNetzwerk.cpp so geschrieben wird:

    //---------------------------------------------------------------------------
    #pragma hdrstop
    
    #include "FunktionenNetzwerk.h"							// Netzwerkfunktionen
    #include "FunktionenAllgemein.h"						// Funktionsaufrufe allgemein
    #include "Main_Netzscanner.h"							// Form1
    
    //---------------------------------------------------------------------------
    
    #pragma package(smart_init)
    
    bool NetworkBase::NetScan(StringToString *dic,void *obj,func eh,string resource,DWORD displaytype,DWORD type,LPNETRESOURCE lpnr)
    {Integer iPos; AnsiString z1,zData,zTxt,zTyp; 					// Vars definieren
     DWORD  dwResult,dwResultEnum; 							// für die Rückgaben der API-Funktionen
     HANDLE hEnum;									// ein Handle auf die Enumeration
     DWORD  cbBuffer=16384;      							// eine Buffergröße
     DWORD  cEntries=-1;            						// für die Anzahl der zurückgegebenen Objekte
     LPNETRESOURCE lpnrLocal;      							// ein Zeiger auf eine NETRESOURCE-Struktur (für die Methode intern)
     NETRESOURCE rec;								// vorbereiten
    
     if(lpnr==NULL && !resource.empty()) {						// wenn Resource übergeben wird, dann erstellen wir eine NETRESOURCE Struktur
      rec.dwScope	   =RESOURCE_GLOBALNET;					        // globale Netzerk durchsuchen (nicht Internet)
      rec.dwType	   =type;							// übergebenen Suchtyp übertragen in REC Strukt
      rec.dwDisplayType=displaytype;                                                //
      rec.lpLocalName  =NULL;							//
      rec.lpComment    =NULL;                                                       //
      rec.lpProvider   =NULL;                                                       //
      rec.lpRemoteName =(char *)resource.c_str();					//
      rec.dwUsage      =RESOURCEUSAGE_CONTAINER;                                    // Voreinstellung für Domains, Server, Workgroups usw.
      if(type==RESOURCETYPE_DISK || type==RESOURCETYPE_PRINT) { rec.dwUsage=RESOURCEUSAGE_CONNECTABLE; } // wenn wir nach einer Freigabe oder nach einem Netzwerkdrucker suchen
      lpnr 	           =&rec;                                                    	//
     }										// ende if(lpnr==NULL
    
     dwResult=WNetOpenEnum(RESOURCE_GLOBALNET,type,0,lpnr,&hEnum );			// WNet öffnen (Netzwerk Enumeration)
     if(dwResult!=NO_ERROR) {							// Fehlermeldung zurück erhalten
      eh(obj,dwResult,"");								// Fehlermeldung auslösen
      return false;									// und Rücksprung negativ
     }                                                                              // ende if(dwResult
    
     do {										// Verarbeitungsschleife der gelesenen Daten
      lpnrLocal=new NETRESOURCE[cbBuffer];						// Speicher für das struct-array allokieren
    
      if(!lpnrLocal) {								// es konnte kein Speicher allokiert werden
       eh(obj,0,"Speicher allocieren fehlgeschlagen");				// Fehler anzeigen
       return false;								// Rücksprung negativ
      }										// ende if(!lpnrLocal
      ZeroMemory(lpnrLocal, cbBuffer);						// den Speicher auf 0 setzen
    
    										// Das Netzwerk enumieren und die Ressourcen raus holen
      dwResultEnum=WNetEnumResource(hEnum,&cEntries,lpnrLocal,&cbBuffer);		// resource handle/auf -1 vorbelegt/Zeiger auf unser Array/Puffergröße
      if(dwResultEnum==NO_ERROR) {							// kein Fehler erhalten (es wurden Ressourcen gefunden)
       for(DWORD i=0;i<cEntries;i++) { 						// Die Ressourcen iterieren, die in dieser Ebene gefunden wurden
        string name    ="";                                                         // vorbereiten leerstring
        string comment ="";                                                         // vorbereiten leerstring
        string provider="";                                                         // vorbereiten leerstring
        string localtxt="";                                                         // vorbereiten leerstring
    
        if(lpnrLocal[i].lpRemoteName) { name    =(char*)lpnrLocal[i].lpRemoteName; }
        if(lpnrLocal[i].lpComment)    { comment =(char*)lpnrLocal[i].lpComment;    }
        if(lpnrLocal[i].lpProvider)   { provider=(char*)lpnrLocal[i].lpProvider;   }
        if(lpnrLocal[i].lpLocalName)  { localtxt=(char*)lpnrLocal[i].lpLocalName;  }
    
        if(RESOURCEUSAGE_CONTAINER==(lpnrLocal[i].dwUsage & RESOURCEUSAGE_CONTAINER)) { // Überprüfen, ob die Resource ein Container ist
         if(displaytype==lpnrLocal[i].dwDisplayType) { 				// jetzt überprüfen wir ob die Ressource der angegebenen Ebene von <displaytype> entspricht
          while(name.find("\\")!=string::npos) { 				        // ersetzen
           name.replace(name.find("\\"),strlen("\\"),"");				// aller Backslashes durch nichts
          }										// ende while(
          zTxt=String(name.c_str());
          dic->insert(StringToString::value_type(name,comment));			// jetzt fügen wir die gefundene Resource in unsere map ein
         }                                                             		// ende if(displaytype
         else {       						                // wenn die Resource nicht unserer ebene entspricht, aber trotzdem ein Container ist (s.o.)
          if(!NetScan(dic,obj,eh,name,displaytype,type,&lpnrLocal[i])) {		// dann rufen wir die NetScan-Funktion rekursiv auf
           eh(obj,0,"NetScan fehlgeschlagen");                                      // Fehler anzeigen
          }										// ende if(!NetScan
         }   									// ende else(
        }										// ende if(RESOURCE
        else {    									// Wenn die Resource kein Container ist (evtl. eine Datenfreigabe oder Drucker, dann überprüfen wir trotzdem, ob sie der angegebenen Ebene enspricht, denn dann können wir sie in die map einfügen
         if(displaytype==lpnrLocal[i].dwDisplayType) {				// wir entfernen zunächst den Rechnernamen
          zTxt=String(name.c_str()); iPos=zTxt.LastDelimiter("\\");			// hinten letztes Zeichen suchen
          zTxt=Trim(zTxt.SubString(iPos+1,zTxt.Length()-iPos));			// vorne Pfad abschneiden
          dic->insert(StringToString::value_type(name,comment));			// Schließlich können wir die Resource doch noch in die map einfügen
         }										// ende if(name.find
        }										// ende else()
    
        switch(lpnrLocal[i].dwDisplayType) {                                        // welcher Type wurde ermittelt?
        case RESOURCEDISPLAYTYPE_DIRECTORY:  zTyp="Directory";  break;              //
        case RESOURCEDISPLAYTYPE_DOMAIN:     zTyp="Domäne";     break;              //
        case RESOURCEDISPLAYTYPE_FILE:       zTyp="Datei";      break;              //
        case RESOURCEDISPLAYTYPE_GENERIC:    zTyp="Generic";    break;              //
        case RESOURCEDISPLAYTYPE_GROUP:      zTyp="Group";      break;              //
        case RESOURCEDISPLAYTYPE_NETWORK:    zTyp="Netzwerk";   break;              //
        case RESOURCEDISPLAYTYPE_ROOT:       zTyp="Root";       break;              //
        case RESOURCEDISPLAYTYPE_SERVER:     zTyp="Server";     break;              //
        case RESOURCEDISPLAYTYPE_SHARE:      zTyp="Share";      break;              //
        case RESOURCEDISPLAYTYPE_SHAREADMIN: zTyp="ShareAdmin"; break;              //
        default:                             zTyp="?";          break;              //
        }										// ende switch(lpnrLocal[i].dwDisplayType
    
        zData=  "|"+zTxt		        +"|";                                   //
        zData=zData+String(comment.c_str()) +"|";                                   //
        zData=zData+String(provider.c_str())+"|";                                   //
        zData=zData+String(localtxt.c_str())+"|";                                   //
        zData=zData+String(name.c_str())    +"|";                                   //
        zData=zData+zTyp                    +"|";                                   //
        zData=zData+"||||";                                                         //
        Form1->Scan->Add(zData);							// in Scanstringliste ablegen
       }										// ende for(i1
      }										// ende if(dwResultEnum
      else if(dwResultEnum!=ERROR_NO_MORE_ITEMS) {					// keine weiteren Items mehr als Fehlermeldung
       eh(obj,dwResultEnum,"");							// Fehler anzeigen
       break;  									// Schleife abbrechen
      }										// ende else if()
    
     }										// ende do
     while(dwResultEnum!=ERROR_NO_MORE_ITEMS);					// Abbruchbedingung der Schleife
    
     delete[] lpnrLocal; 								// löschen des arrays, falls nicht bereits geschehen
    
     dwResult=WNetCloseEnum(hEnum);							// schließen der Enumeration
     if(dwResult!=NO_ERROR) {							// Fehlermeldung vorhanden
      eh(obj,dwResult,"");								// Fehler anzeigen
      return false;									// Rücksprung nicht ok
     }										// ende if(dwResult
    
     return true;									// Rücksprung ok
    }
    
    void ErrorHandling(void*,DWORD error,string errortext)
    {if(error && !errortext.empty()) {  						// Fehlernummer und Fehlertext vorhanden
      ShowMessage("NetworkBase::NetScan\r\rFehlertext: "+String(errortext.c_str()));// Fehler anzeigen
     }										// ende if(error
    }
    

    @Akari: Wie der Debugger genutzt wird, weiss ich einigermaßen.
    Es nützt halt nicht viel, wenn man das angezeigte nicht versteht.
    Das liegt aber schlicht an mir, da ich in solche komplexen Strukturen
    usw. einfach nicht fit genug bin.

    @DocShoe:
    Dein Hinweis 2 habe ich korrigiert; der Hinweis 1 war der Entscheidende.
    Vielen, vielen Dank dafür. 😋 Musste zwar noch einiges durchtüfteln, aber jetzt
    funktioniert es und auch richtig schön schnell. 👍

    Den Aufruf aus dem Button OnClick setze ich auch nochmal rein,
    falls das hier ein Thema für die FAQ ist:

    // BUTTON S
    void __fastcall TForm1::frm1_btn1_ScannenClick(TObject *Sender)
    {try {                                                                          // Fehlerroutine Start
     Integer iAnz,iScan,iAnzS; AnsiString z1,zFile,zScan,zDom; Boolean o1; 		// Vars definieren
     string firstDomain,firstServer;						// Vars definieren
     Boolean ret;                                                                   // Vars definieren
     TStringGrid *Grid;								// vorbereiten
     TRichEdit *RTF; 								// vorbereiten
     StringToString dic;   		  						// Maps vorbereiten
     StringToString::iterator iter;                             			// Iterator für die Maps
     NetworkBase net;                                                               //
     TStringList *Domain,*Server,*Drives,*Drucker;					// vorbereiten
    
     Domain =new TStringList();							// Stringliste neu erzeugen
     Server =new TStringList();                                                     // Stringliste neu erzeugen
     Drives =new TStringList();                                                     // Stringliste neu erzeugen
     Drucker=new TStringList();                                                     // Stringliste neu erzeugen
    
     Scan->Clear();									// für Debugmdous löschen
    
     RTF  =frm1_rtf1_Info;								// zuordnen
     Grid =frm1_grd3_GListe;      							// zuordnen
     zScan=frm1_cb1_Auswahl->Text;							// Auswahl Scandurchgang?
     iScan=StrToIntDef(Trim(zScan.SubString(1,2)),0);	     			// als Index ermitteln
    
     RTF->Lines->Clear();								// Zeilen löschen
     RTF->PlainText=false;								// Richttext aktivieren
     RTF->Paragraph->TabCount=5;							// Anzahl Tabs
     RTF->Paragraph->Tab[0]  =30;							// Spalte Nummerierung
     RTF->Paragraph->Tab[1]  =125;                                                  // Spalte Bezeichnung
     RTF->Paragraph->Tab[2]  =250;                                                  // Spalte Kommentar
     RTF->Paragraph->Tab[3]  =170;                                                  // Spalte ID
     RTF->Paragraph->Tab[4]  =210;                                                  // Spalte Typ
     RTF->Enabled            =false;						// Control sperren/freigeben
    
     TextRTF(1,clRed ,8,"Arial",-1,RTF,"Scanvorgang gestartet - "+ZeitStempel(12,"")+": "+zScan+" (Index: "+IntToStr(iScan)+")");   // Kopfzeile
     //TextRTF(0,clBlue,8,"Arial",-1,RTF,"Nr.\tGerät/Name\tKommentar\tTyp\tID\tVersion");  // Kopfzeile
    
     Screen->Cursor=crHourGlass; Application->ProcessMessages();			// Sanduhr
     frm1_pan1_Info->Visible       =true;						// Control zeigen/verbergen
     frm1_pan3_Info->Visible       =true;						// Control zeigen/verbergen
     frm1_btn1_Scannen->Enabled    =false;						// Control sperren/freigeben
     frm1_btn3_EintragInfo->Enabled=false;						// Control sperren/freigeben
     frm1_lbl3_Titel10->Caption    ="Eintragsliste (0):";			 	// Label aktualisieren
     Grid->Visible                 =false;						// Control zeigen/verbergen
     Grid->RowCount                =2;						// Voreinstellung 1. Leerzeile
     Grid->Cells[0][1]             ="";						// 2. Zeile löschen
     frm1_stbStatus->Panels->Items[1]->Text="Einträge: 0";				 // Statusbar aktualisieren
     Application->ProcessMessages();						// events abarbeiten
    
     //-----------------------------------------------------------------------------//
     //--- NETZWERK SCANNEN - START ---                                             //
     //-----------------------------------------------------------------------------//
    
     //-----------------------------------------------------------------------------// DOMAINS SUCHEN
     TextRTF(0,clBlue,8,"Arial",-1,RTF," "); 					// Leerzeile
     TextRTF(0,clBlue,8,"Arial",-1,RTF,"Folgende Domains/Workgroups gefunden:");  	// Kopfzeile
     ret =net.NetScan(&dic,NULL,&ErrorHandling,"",RESOURCEDISPLAYTYPE_DOMAIN);	// domains suchen
     //if(ret==true && dic.size()>0) {						// Scan durchgeführt und mind.1 Eintrag vorhanden...
     if(ret==true) {								// Scan durchgeführt
      iter=dic.begin();								// jetzt iterieren der domains und ausgeben
      while(iter!=dic.end()) {							// aller Iteratoren (Einträge) abarbeiten
       TextRTF(0,clNavy,8,"Arial",-1,RTF,"Domain/Workgroup: \t"+String(iter->first.c_str())+"\tKommentar: "+String(iter->second.c_str())); // Eintragszeile
       Domain->Add("|"+String(iter->first.c_str())+"|"+String(firstDomain.c_str())+"|"); // und in Stringliste ablegen
       iter++;									// Iteriem +1
      }										// ende while(iter!
      Application->ProcessMessages();						// events abarbeiten
      dic.clear();									// map jetzt löschen
     }										// ende if(ret==true
     else {										// sonst Fehler...
      TextRTF(1,clRed,8,"Arial",-1,RTF,"=> Fehler beim Scan der Domains/Workgroups!?");// Infozeile
     }										// ende else(
    
     //-----------------------------------------------------------------------------// SERVER/PC SUCHEN
     TextRTF(0,clRed,8,"Arial",-1,RTF," "); 					// Leerzeile
     TextRTF(0,clRed,8,"Arial",-1,RTF,"Folgende Server/Computer gefunden:"); 	// Kopfzeile
     iAnz=Domain->Count;								// Anzahl Server
     for(int i1=0;i1<iAnz;i1++) {							// alle abscannen
      zDom=DatenPipe(1,1,Domain->Strings[i1],"!!");					// Domainname ausschneiden
      ret=net.NetScan(&dic,NULL,&ErrorHandling,zDom.c_str(),RESOURCEDISPLAYTYPE_SERVER); // Server/PC in Domäne/Workgroup zDom suchen
      //if(ret==true && dic.size()>0) {						// Scan durchgeführt und mind.1 Eintrag vorhanden...
      if(ret==true) {								// Scan durchgeführt
       iter=dic.begin();								// jetzt iterieren der domains und ausgeben
       while(iter!=dic.end()) {							// aller Iteratoren (Einträge) abarbeiten
        TextRTF(0,clMaroon,8,"Arial",-1,RTF,"Domäne/WG: "+zDom+"\t"+String(iter->first.c_str())+"\tKommentar: "+String(iter->second.c_str())); // Eintragszeile
        Server->Add("|Domäne: "+zDom+"|"+String(iter->first.c_str())+"|"+String(iter->second.c_str())+"|"); // und in Stringliste ablegen
        iter++;									// Iteriem +1
       } 										// ende while(iter!
       Application->ProcessMessages();						// events abarbeiten
       dic.clear();									// map jetzt löschen
      }										// ende if(ret==true
      else {									// sonst Fehler...
       TextRTF(1,clRed,8,"Arial",-1,RTF,"=> Fehler beim Scan der Server/PC's!?");	// Infozeile
      }										// ende else(
     }										// ende for(i1
    
     //-----------------------------------------------------------------------------// LAUFWERKE/FREIGABEN SUCHEN
     TextRTF(0,clFuchsia,8,"Arial",-1,RTF," "); 					// Leerzeile
     TextRTF(0,clFuchsia,8,"Arial",-1,RTF,"Folgende Freigaben/Laufwerke gefunden:");// Kopfzeile
     iAnz=Server->Count;								// Anzahl Server
     for(int i1=0;i1<iAnz;i1++) {							// alle abscannen
      zDom=DatenPipe(1,1,Server->Strings[i1],"!!");					// Domainname ausschneiden
      z1  ="\\\\"+DatenPipe(1,2,Server->Strings[i1],"!!");				// Servername ausschneiden
      ret =net.NetScan(&dic,NULL,&ErrorHandling,z1.c_str(),RESOURCEDISPLAYTYPE_SHARE,RESOURCETYPE_DISK); // Laufwerke/Freigaben suchen
      //if(ret==true && dic.size()>0) {						// Scan durchgeführt und mind.1 Eintrag vorhanden...
      if(ret==true) {								// Scan durchgeführt
       iter=dic.begin();								// jetzt iterieren der Laufwerke und ausgeben
       while(iter!=dic.end()) {							// aller Iteratoren (Einträge) abarbeiten
        TextRTF(0,clPurple,8,"Arial",-1,RTF,"Laufwerk/Freigabe: \t"+String(iter->first.c_str())+"\tKommentar: "+String(iter->second.c_str())); // Eintragszeile
        Drives->Add("Domaine: "+zDom+"|Server: "+z1+"|"+String(iter->first.c_str())+"|"+String(iter->second.c_str())+"|"); // und in Stringliste ablegen
        iter++;									// Iteriem +1
       }										// ende while(iter!
       Application->ProcessMessages();						// events abarbeiten
       dic.clear();									// map jetzt löschen
      }										// ende if(ret==true
      else {							  		// sonst Fehler...
       TextRTF(1,clRed,8,"Arial",-1,RTF,"=> Fehler beim Scan der Laufwerke/Freigaben!?"); // Infozeile
      }										// ende else(
      TextRTF(0,clPurple,8,"Arial",-1,RTF," "); 					// Leerzeile
     }										// ende for(i1
    
     //-----------------------------------------------------------------------------// DRUCKERN SUCHEN
     TextRTF(0,clBlack,8,"Arial",-1,RTF," "); 					// Leerzeile
     TextRTF(0,clBlack,8,"Arial",-1,RTF,"Folgende Drucker/Freigaben gefunden:"); 	// Kopfzeile
    
     //ret=net.NetScan(&dic,NULL,&ErrorHandling,"\\\\"+firstServer,RESOURCEDISPLAYTYPE_SHARE,RESOURCETYPE_PRINT); // Drucker suchen
    
     iAnz=Server->Count;								// Anzahl Server
     for(int i1=0;i1<iAnz;i1++) {							// alle abscannen
      zDom=DatenPipe(1,1,Server->Strings[i1],"!!");					// Domainname ausschneiden
      z1  ="\\\\"+DatenPipe(1,2,Server->Strings[i1],"!!");				// Servername ausschneiden
      ret =net.NetScan(&dic,NULL,&ErrorHandling,z1.c_str(),RESOURCEDISPLAYTYPE_SHARE,RESOURCETYPE_PRINT); // Drucker suchen
      //if(ret==true && dic.size()>0) {						// Scan durchgeführt und mind.1 Eintrag vorhanden...
      if(ret==true) {								// Scan durchgeführt
       iter=dic.begin();								// jetzt iterieren der Printer und ausgeben
       while(iter!=dic.end()) {							// aller Iteratoren (Einträge) abarbeiten
        TextRTF(0,clGray,8,"Arial",-1,RTF,"Drucker/Freigabe: \t"+String(iter->first.c_str())+"\tKommentar: "+String(iter->second.c_str())); // Eintragszeile
        Drucker->Add("|"+z1+"|"+String(iter->first.c_str())+"|"+String(iter->second.c_str())+"|"); // und in Stringliste ablegen
        iter++;									// Iteriem +1
       }										// ende while(iter!
       Application->ProcessMessages();						// events abarbeiten
       dic.clear();									// map jetzt löschen
      }										// ende if(ret==true
      else {										// sonst Fehler...
       TextRTF(1,clRed,8,"Arial",-1,RTF,"=> Fehler beim Scan der Drucker!?"); 	// Infozeile
      }										// ende else(
      TextRTF(0,clGray,8,"Arial",-1,RTF," "); 					// Leerzeile
     }										// ende for(i1
    
     //-----------------------------------------------------------------------------//
     //--- NETZWERK SCANNEN - ENDE ---                                              //
     //-----------------------------------------------------------------------------//
    
     iAnzS=Scan->Count;                             				// ermittelte Datensätze?
     if(iAnzS==0) {									// keine Daten vorhanden
      Scan->Add("|<keine Daten ermittelt!?|||||");					// Grundeintrag vorhanden
      iAnz=1;									// Anzahl korrigieren
     }										// ende if(iAnzS
     Grid->RowCount=iAnzS+1;							// Anzahl Zeilen anpassen
     Grid->Cells[0][1]="";								// 2. Zeile löschen
     for(int i1=0;i1<iAnzS;i1++) {							// alle Datensätze übertragen
      Grid->Cells[0][i1+1]=Scan->Strings[i1];					// Daten eintragen
     }										// ende for(i1
     Grid->Repaint();								// neu zeichnen
     Grid->Visible =true;								// Control zeigen/verbergen
    
     if(oScanFile==true || oPrgComp) {						// Stringlisten noch sichern in TEMP Ordner
      zFile=PfadTemp; if(oScanTime==true) { zFile=zFile+ZeitStempel(7,""); } 	// Filevorgabe
      Domain ->SaveToFile(zFile+" Domainliste.txt");				// in Datei sichern
      Server ->SaveToFile(zFile+" Serverliste.txt");                                // in Datei sichern
      Drives ->SaveToFile(zFile+" Drivesliste.txt");                                // in Datei sichern
      Drucker->SaveToFile(zFile+" Printerliste.txt");                               // in Datei sichern
      Scan   ->SaveToFile(zFile+" Debugscanliste.txt");                             // in Datei sichern
      frm1_menuDatei_OrdnerTEMPClick(0);						// und Ordner anzeigen
     }										// ende if(oScanFile
     delete Domain;									// Stringliste löschen
     delete Server;									// Stringliste löschen
     delete Drives;									// Stringliste löschen
     delete Drucker;	   							// Stringliste löschen
    
     Screen->Cursor=crDefault; Application->ProcessMessages();			// Pfeil
    
     frm1_proBalken->Position      =0; 						// Balken auf Pos x setzen
     frm1_btn1_Scannen->Enabled    =true;						// Control sperren/freigeben
     frm1_btn3_EintragInfo->Enabled=iAnz>0;						// Control sperren/freigeben
     frm1_lbl3_Titel10->Caption    ="Eintragsliste ("+IntToStr(iAnz)+"):";		// Label aktualisieren
     frm1_pan3_Info->Visible       =iAnz==0;					// Control zeigen/verbergen
     frm1_pan1_Info->Visible       =false;						// Control zeigen/verbergen
     frm1_stbStatus->Panels->Items[1]->Text="Einträge: "+IntToStr(iAnz);		 // Statusbar aktualisieren
     RTF->Enabled                  =true;						// Control sperren/freigeben
    
     if(iAnz>0) {               							// mind.1 Eintrag wurde gescannt
      o1=false;									// wg. Aufruf
      frm1_grd3_GListe->TopRow=1;							// Tabelle nach oben verschieben
      frm1_grd3_GListeSelectCell(Grid,0,1,o1);					// und 1.Zeile selektieren
     }										// ende if(iAnz>0
    
     //RTF->Lines->Strings[0]="Scanvorgang beendet - "+ZeitStempel(12,"");		// erste Zeile aktualisieren
     TextRTF(2,clGreen,8,"Arial",-1,RTF," ");  					// Leerzeilen
     TextRTF(1,clGreen,8,"Arial",-1,RTF,"Scanvorgang beendet - "+ZeitStempel(12,"")+": "+zScan);  // Kopfzeile
     frm1_stbStatus->Panels->Items[0]->Text=" Letzter Scan (Anzahl: "+IntToStr(iAnz)+"): "+ZeitStempel(12,""); //
    
     } catch(Exception& e) {                               				// Fehler anzeigen
      MessageBox(NULL,e.Message.c_str()," TForm1::frm1_btn1_ScannenClick()",MB_OK);	// Info anzeigen
     }										// ende catch()
    }
    

    Die Funktion TextRTF setzt einfach formatierten Text in ein RichEdit Control
    rein; hier kann man also auch z.B. eine Ablage in ein StringGrid oder ähnliches vornehmen. Der eigentliche Aufruf finden zwischen den kommentierten Zeilen
    Netzwerk Scannen - Start und Netzwerk scannen - Ende statt.

    Viele Grüsse, Stefan



  • Das solltest du dir wirklich noch einmal genau ansehen, der folgende Schnipsel ist bestimmt auch nicht das, was du eigentlich tun wolltest:

    lpnrLocal=new NETRESOURCE[cbBuffer];
    ...
    ZeroMemory(lpnrLocal, cbBuffer);
    

    Hab mir den Quelltext nicht genauer angeguckt, aber da waren bisher mindestens 2 grobe Böcke drin. Der Weg in die FAQ ist noch lang 😉



  • Hallo DocShoe

    welche beiden Blöcke meinst Du denn?
    Mit dem ZeroMemory kann ich keinen Fehler erkennen;
    bin allerdings auch mit diesen Befehlen nicht superfit.

    Die Anspielung auf die FAQ war damit gemeint, daß ja viele
    das Scannen eines Netzwerkes interessiert und ein Forum wie
    dieses ja auch gemeinschaftlich einen FAQ Beitrag entstehen
    lassen kann. 😉

    Grüsse, Stefan



  • Stefan7124 schrieb:

    Mit dem ZeroMemory kann ich keinen Fehler erkennen;
    bin allerdings auch mit diesen Befehlen nicht superfit.

    deshalb gibts dafür auch ne Doku:
    http://msdn.microsoft.com/en-us/library/aa366920(VS.85).aspx

    Ich denk mal folgendes hat DocShoe gemeint

    MSDN schrieb:

    Length [in]
    The size of the block of memory to fill with zeros, in bytes.

    ergo

    ZeroMemory(lpnrLocal, sizeof(NETRESOUCE)*cbBuffer);
    


  • *Morris: Danke für diesen Hinweis; wird die Länge aber nicht automatisch
    durch deie Übergabe des *cbBuffer in der API ermittelt? Sonst müsste ich
    ja eigentlich dauernd Fehler damit haben...? Ist jetzt eine reine
    Verständnisfrage.

    Gruss, Stefan



  • Kurz: Nein. Ja.

    Lang: ZeroMemory erwartet als zweiten Parameter die Länge des zu bearbeitenden Speicherbereichs in Byte, so wie in der Dokumentation auch beschrieben ist. Da wird nichts automatisch ermittelt. "Fehler" sind nicht unbedingt gleich "Fehler". Das 0-Initialisieren von Speicher ist zwar löblich (?) aber in vielen Fällen nicht notwendig, weil sowieso vor dem Lesen reingeschrieben wird. Deshalb verursacht die falsche Verwendung von ZeroMemory hier möglicherweise kein Problem, ist aber trotzdem ein Fehler.



  • Es ist eine Ungenauigkeit, die Fehler hervorrufen kann, aber nicht unbedingt muss. Sie führt deshalb nicht sofort zum Absturz, da jeder Datentyp eine Mindestgrösse von 1 Byte hat. Damit kann ZeroMemory den Puffer nicht überschreiben, löscht ihn aber nicht zwingend vollständing, sondern nur die ersten 1 / sizeof( Typ ) * Puffergrösse Elemente. Nehmen wir an, du möchtest ein Array aus 20 int (4 Byte Grösse) löschen und rufst ZeroMemory( &arr, 20 ) auf, dann löscht ZeroMemory nur die ersten 20 Byte. Da das Array aber insgesamt 80 Byte gross ist (20 int á 4 Byte) stehen in den letzten 60 Byte Zufallszahlen (die letzten 15 int).

    Stell dir folgendes Szenario vor:

    double Offset[1000];
    double Array[1000];
    
    // füllt die ersten 1000 Bytes des Offset mit 0
    ::ZeroMemory( Array, 1000 );
    
    // fülle das komplette Array mit 100.0 the STL way
    std::fill( Array, Array +1000, 100.0 );
    
    // addiere Offset zu Array elementweise
    for( int i = 0; i < 1000; ++i )
    {
       Array[i] += Offset[i];
    }
    

    Da nur die ersten 125 Elemente (1000 Bytes / sizeof( double ) = 125, da sizeof( double ) 😎 mit 0 besetzt sind stehen in den übrigen 875 Zufallswerte. Damit stehen nach der for Schleife im Ergebnisarray auch Zufallswerte an den letzten 875 Positionen.

    Der fill Algorithmus aus der STL erkennt die Grösse des Datentyps automatisch anhand des Template Parameters, da musst du tatsächlich nur die Anzahl der zu schreibenden Elemente angeben.



  • Hallo,

    vielen Dank für die lehrreichen Informationen. Das habe ich
    jetzt begriffen.

    @Morris:
    Was ist denn der zweite grobe Bock?

    Gruss Stefan


Anmelden zum Antworten