Netzscan mit Quellcode [gelöst]
-
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