Netzscan mit Quellcode [gelöst]
-
Hallo zusammen,
nach intensiven Recherchen im Web konnte ich folgenden Quellcoe erstellen,
der alle Domains und Server/PC auflistet. Zuzsätzlich werden alle Freigaben
(Laufwerke) und Drucker aufgelistet; da allerdings nur immer vom letzten
Server/PC, obwohl ich als Parameter an die FunktioneNetzwerk.hpp den ent-
sprechenden Server-/PC-Namen übergebe. Wäre echt toll, wenn hier einer einen
Tipp hätte, warum ich immer nur bei dem Aufruf von net.NetScan(...) für die
Laufwerke/Freigaben und Drucker immer nur die letzten Daten erhalte.Der komplette Quellcode ist hier (die Funktion TextRTF ist auskommentiert und
setzt mit einer Unterfunktion Text formatiert in ein RichEdit ein, wird hier
aber nicht benötigt).Es gibt eine Form1 mit einem Button (Form1_Button1) in der
MainNetzscanner.hpp. Die eigentliche Scanfunktion ist in der Unit
FunktionNetzscanner.hpp und eine benötigte Unterfunktion (DatenPipe)
in der FunktionAllgemein.hpp. Habe die ganze Routine schon mit StringGrid
und Richedit umfangreich aufgebaut, so das statt das reine Ablegen in den
StringGrids eine Tabelle aufgebaut wird. Sieht auch gut aus, bis eben auf
das Problem vom Scannen der Laufwerke und Drucker auf allen ermittelten
Servern/PCs:FunktionenNetzscanner.h: //--------------------------------------------------------------------------- #include <windows.h> // wird für die API-Funktionen benötigt #include <string> // benötigen wir für Strings #include <map> // für ein Dictonary #include <winerror.h> // für die evtl. Fehlerauswertung //#include <stdio.h> // Standard In/Out #ifndef FunktionenNetzwerkH #define FunktionenNetzwerkH //--------------------------------------------------------------------------- #include <Dialogs.hpp> //--------------------------------------------------------------------------- using namespace std; //typedef map<string,string,string> StringToString; typedef map<string,string> StringToString; typedef void (*func)(void *, DWORD, string); class NetworkBase { public: bool NetScan(StringToString* dic,void* obj,func eh,string resource="",DWORD displaytype = RESOURCEDISPLAYTYPE_GENERIC,DWORD type = RESOURCETYPE_ANY,LPNETRESOURCE lpnr=NULL); }; //--------------------------------------------------------------------------- #endif FuntkionenNetzscanner.hpp: //--------------------------------------------------------------------------- #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 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. } // 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 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( 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 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 //hier könnte man jetzt alle gesammelten Daten z.B. zTyp auch in einer Stringliste ablegen.... //.... } // ende for(i1 } // ende if(dwResultEnum else if(dwResultEnum!=ERROR_NO_MORE_ITEMS) { // keine weiteren Items mehr als Fehlermeldung delete[] lpnrLocal; // löschen des arrays 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 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 } ================================================================================// FunktionenAllgemein.h: //--------------------------------------------------------------------------- #ifndef FunktionenAllgemeinH #define FunktionenAllgemeinH //--------------------------------------------------------------------------- AnsiString DatenPipe(int p1, int p2, AnsiString pt1, AnsiString pt2); // //--------------------------------------------------------------------------- #endif FunktionenAllgemein.hpp: //---------------------------------------------------------------------------- //----- DATENPIPE ----- //---------------------------------------------------------------------------- AnsiString DatenPipe(int p1, int p2, AnsiString pt1, AnsiString pt2) {try { // Fehlerroutine Start Integer iAnz,iPos,iInd; AnsiString z1,zData,zTxt,zVorn,zInh; // Vars definieren zData=pt1; // Parameter übergeben |Text1|Text2|Text3|... zInh =pt2; // neuen Inhalt TextNeu iInd =p2; // Index Feld |1|2|3|4|... switch(p1) { // was machen? case 1: // AUSLESEN STRING case 3: // AUSLESEN INTEGER if(zData.Length()==0) { zTxt=""; goto LesenEnde; } // keine Vorgabe, also fertig for(int i1=1;i1<=p2;i1++) { // x. Pipe suchen iPos =zData.AnsiPos("|"); // Pipe suchen if(iPos==0) { zTxt=""; goto LesenEnde; } // keines gefunden, beenden zData=zData.SubString(iPos+1,99999); // String ab Pipe+1 abschneiden } // ende for(i1 iPos=zData.AnsiPos("|"); // noch nächstes Pipe suchen zTxt=zData.SubString(1,iPos-1); // und bis nächstes Pipe den Inhalt ausschneiden if(zInh=="!!") { zTxt=zTxt.Trim(); } // ohne Leerstellen zurückgeben LesenEnde: // Sprungmarke if(p1==3 & zTxt.Length()==0) { zTxt="0"; } // Rückgabe für Integer (leerer String gibt Fehlermeldung!) break; // und fertig case 2: // SCHREIBEN zVorn=""; // vorbereiten for(int i1=1;i1<=iInd;i1++) { // x. Pipe suchen iPos=zData.AnsiPos("|"); // Pipe suchen if(iPos==0) { // keines gefunden zData=zData+"|"; // also eines anhängen iPos =zData.AnsiPos("|"); // und neu suchen } // ende if(iPos zVorn=zVorn+zData.SubString(1,iPos); // und vorne merken zData=zData.SubString(iPos+1,99999); // und ab da abschneiden } // ende for(i1 iPos=zData.AnsiPos("|"); // noch nächstes Pipe suchen if(iPos==0) { // keines gefunden zData=zData+"|"; // also eines anhängen iPos =zData.AnsiPos("|"); // und neu suchen } // ende if(iPos zTxt=zVorn+zInh+zData.SubString(iPos,zData.Length()); // und pt2 einsetzen und ab nächstem Pipe anhängen break; // und fertig } // ende switch(p1 return zTxt; // Rückgabe Werte } catch(Exception& e) { MessageBox(NULL, e.Message.c_str(), "FunktionAllgemein.h: DateiPipe()", MB_OK); return "ERROR"; } // Fehler anzeigen } ================================================================================// MainNetzscanner.hpp: #include "FunktionenNetzwerk.h" // Netzwerkfunktionen #include "FunktionenAllgemein.h" // Funktionsaufrufe allgemein #include "Main_Netzscanner.h" // Form1 void __fastcall TForm1::Form1_Button1Click(TObject *Sender) {try { // Fehlerroutine Start AnsiString z1,zFile; // Vars definieren string firstDomain,firstServer; // Vars definieren Boolean ret; // Vars definieren StringToString dic; // Maps vorbereiten StringToString::iterator iter; // Iterator für die Maps NetworkBase net; // TStringList *Domain,*Server,*Drives,*Printer; // vorbereiten Domain =new TStringList(); // Stringliste neu erzeugen Server =new TStringList(); // Stringliste neu erzeugen Drives =new TStringList(); // Stringliste neu erzeugen Printer=new TStringList(); // Stringliste neu erzeugen Screen->Cursor=crHourGlass; Application->ProcessMessages(); // Sanduhr //-----------------------------------------------------------------------------// //--- NETZWERK SCANNEN - START --- // //-----------------------------------------------------------------------------// DOMAINS SUCHEN ret=net.NetScan(&dic,NULL,&ErrorHandling,"",RESOURCEDISPLAYTYPE_DOMAIN); // domains suchen if(!ret) { return; } // Ergebnis negativ! Kein Scan durchgeführt... if(!dic.size()) { return; } // Wurden denn Domains gefunden ? iter=dic.begin(); // jetzt iterieren der domains und ausgeben //TextRTF(0,clRed,8,"Arial",-1,RTF,"Folgende Domäns/Workgroups gefunden:"); // Kopfzeile while(iter!=dic.end()) { // aller Iteratoren (Einträge) abarbeiten //TextRTF(0,clMaroon,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! //-----------------------------------------------------------------------------// SERVER/PC SUCHEN iAnz=Domain->Count; // Anzahl Domäns/Workgroups ermitteln for(int i1=0;i1<iAnz;i1++) { // alle scannen dic.clear(); // map jetzt löschen z1 =DatenPipe(1,1,Domain->Strings[i1],"!!"); // Domän-/Workgroupname ausschneiden ret=net.NetScan(&dic,NULL,&ErrorHandling,z1.c_str(),RESOURCEDISPLAYTYPE_SERVER); // domains suchen if(!ret) { return; } // Ergebnis negativ! Kein Scan durchgeführt... if(!dic.size()) { return; } // Wurden denn Domains gefunden ? iter=dic.begin(); // jetzt iterieren der domains und ausgeben //TextRTF(0,clRed,8,"Arial",-1,RTF,"Folgende Server/Computer in Domän/Workgroup >"+z1+"< gefunden:"); // Kopfzeile while(iter!=dic.end()) { // aller Iteratoren (Einträge) abarbeiten //TextRTF(0,clMaroon,8,"Arial",-1,RTF,"Server/PC: \t"+String(iter->first.c_str())+"\tKommentar: "+String(iter->second.c_str())); // Eintragszeile Server->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 } // ende for(i1 //-----------------------------------------------------------------------------// LAUFWERKE/FREIGABEN SUCHEN // AB HIER bekomme ich "nur" die Laufwerke und Drucker vom jeweils zuletzt // // erfassten Server/PC: // //-----------------------------------------------------------------------------// LAUFWERKE/FREIGABEN SUCHEN iAnz=Server->Count; // Anzahl Server/PC ermitteln for(int i1=0;i1<iAnz;i1++) { // alle scannen dic.clear(); // map jetzt löschen z1 =DatenPipe(1,2,Server->Strings[i1],"!!"); // Server-/PC Name ausschneiden ret=net.NetScan(&dic,NULL,&ErrorHandling,z1.c_str(),RESOURCEDISPLAYTYPE_SHARE,RESOURCETYPE_DISK); // Laufwerke/Freigaben suchen if(!ret) { return; } // Ergebnis negativ! Kein Scan durchgeführt... if(!dic.size()) { return; } // Wurden denn Laufwerke gefunden ? iter=dic.begin(); // jetzt iterieren der Laufwerke und ausgeben //TextRTF(0,clFuchsia,8,"Arial",-1,RTF,"Folgende Freigaben/Laufwerke auf Server/PC >"+z1+"< gefunden:"); // Kopfzeile 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("|"+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 } // ende for(i1 dic.clear(); // map Freigaben jetzt löschen //-----------------------------------------------------------------------------// DRUCKERN SUCHEN iAnz=Server->Count; // Anzahl Server/PC ermitteln for(int i1=0;i1<iAnz;i1++) { // alle scannen dic.clear(); // map jetzt löschen z1 =DatenPipe(1,2,Server->Strings[i1],"!!"); // Server-/PC Name ausschneiden ret=net.NetScan(&dic,NULL,&ErrorHandling,z1.c_str(),RESOURCEDISPLAYTYPE_SHARE,RESOURCETYPE_PRINT); // Drucker suchen if(!ret) { return; } // Ergebnis negativ! Kein Scan durchgeführt... if(!dic.size()) { return; } // Wurden denn Printer gefunden ? iter=dic.begin(); // jetzt iterieren der Printer und ausgeben //TextRTF(0,clBlack,8,"Arial",-1,RTF,"Folgende Drucker/Freigaben auf Server/PC >"+z1+"< gefunden:"); // Kopfzeile 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 Printer->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 } // ende for(i1 dic.clear(); // map Printer jetzt löschen //-----------------------------------------------------------------------------// //--- NETZWERK SCANNEN - ENDE --- // //-----------------------------------------------------------------------------// zFile=ExtractFilePath(Application->ExeName); // aktueller Programmpfad Domain ->SaveToFile(zFile+" Domainliste.txt"); // in Datei sichern Server ->SaveToFile(zFile+" Serverliste.txt"); // in Datei sichern Drives ->SaveToFile(zFile+" Drivesliste.txt"); // in Datei sichern Printer->SaveToFile(zFile+" Printerliste.txt"); // in Datei sichern z1 ="explorer.exe "+zFile; // Befehl zusammenstellen WinExec(z1.c_str(),SW_NORMAL); // Programmordner zeigen delete Domain; // Stringliste löschen delete Server; // Stringliste löschen delete Drives; // Stringliste löschen delete Printer; // Stringliste löschen Screen->Cursor=crDefault; Application->ProcessMessages(); // Pfeil } catch(Exception& e) { // Fehler anzeigen MessageBox(NULL,e.Message.c_str()," TForm1::Form1_Button1Click()",MB_OK); // Info anzeigen } // ende catch() }
Habe schon alles mögliche probiert, komme aber einfach nicht mehr weiter.
Denke mal, daß das Thema einige interessiert und hoffe auf einen entscheidenen
TippGrüsse, Stefan
-
Schonmal mit dem Debugger step-by-step reingeguckt?
-
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).aspxIch 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