probleme beim einbinden von netapi32.lib



  • die netapi32.dll musst du explizit von hand laden

    Blödsinn! Man kann aus dieser DLL per Borlands Tool "ImpLib" eine LIB generieren. Die bindet man dann ein. Ganz einfach.



  • falsch... nicht auf jedem system ist die richtige netapi32.dll vorhanden, die die funktionen exportiert! ergo kannst du nichts importieren was nicht da ist!



  • @Aoeke: welches Betriebssystem hast du denn?
    Ich frage deshalb, weil die meisten Funktionen nur unter WinNT zur Verfügung stehen. Unter WIndows 9x/ME bzw. auch Win3.x funktionieren diese nicht (wie auch schon Sunday meinte, dass die netapi32.dll auf den verschiedenen Systemen unterschiedlich ist)



  • hi..
    @sunday: ist das jetzt für 'ne Konsolenanwendung oder für eine ganz normale anwendung mit dem builder??? weil bei letzteres kommen dann fehlermeldung wie:

    typedef NET_API_STATUS (WINAPI *NETQUERYINFO)  (LPWSTR ServerName, DWORD Level, DWORD Index,
    

    -> [C++ Fehler] Unit1.cpp(26): E2257, erwartet
    und:

    static NETQUERYINFO  pNetQueryDisplayInformation = NULL;
    

    -> [C++ Fehler] Unit1.cpp(32): E2141 Fehler in der Deklarationssyntax ...
    und:

    pNetQueryDisplayInformation = (NETQUERYINFO)  GetProcAddress(hLib, "NetQueryDisplayInformation");
    

    -> [C++ Fehler] Unit1.cpp(72): E2541 Undefiniertes Symbol 'pNetQueryDisplayInformation' ... und noch 'nen paar mehr???
    also was habe ich jetzt schon wieder falsch gemacht??? bin ich so blöd???

    @JeGr: Windows 98 Second Edition...

    ich kriege das einfach nicht hin... 😞 das ist zum verzweifeln...



  • Lt. Windows SDK-Hilfe geht das mit Win9x nicht!

    Tipp mal "NetQueryDisplayInformation" in der Windows SDK-Hilfe ein.
    Dann wählst du den Eintrag aus und klickst links oben auf "Overview".
    Dort steht, dass die Funktion nur unter WinNT/2K/XP zur Verfügung steht.

    Also brauchst du nicht an deinen Programmierkenntnissen zweifeln, sondern du kannst das mit deinem BS einfach nicht entwickeln.

    Entweder stellst du dein BS um, oder du versuchst einen Wirkaround zu finden!



  • hast du ne idee wie ich das anders machen könnte??? also mein programm soll folgendermaßen funktionieren: also das soll nen programm werden, mit dem man im netzwerk mit den anderen rechnern chatten / sich textnachrichten senden kann... wenn man das programm öffnet soll ein fenster erscheinen, in dem alle gerade im netzwerk befindlichen rechner in irgendeiner form aufgelistet werden... wenn dann ein rechner ausgewählt wird, öffnet sich das chatfenster... und dann soll man eben mit dem chatten können!
    ich weiß allerdings nicht, ob ich dass so hinkriege, aber ich würds eben versuchen...
    hast du irgendeine idee die mir helfen könnte, dass alle rechner aufgelistet werden, und man auch die ip zu jedem rechner damit herausbekommt???



  • Also, eine Möglichkeit wäre, dass du die ganze Sache über Sockets regelst.
    Ich würde dann einen Rechner als Server deklarieren. An diesem Rechner müssen sich nun alle Clients anmelden. Bei der Anmeldung wird dann die IP bzw der NetBIOS-Name an den Server übergeben. Dieser wiederum "verwaltet" quasi die ganzen angemeldeten Clients in einer Liste, die dann jeder verbundene Client bei Bedarf erfragen kann.
    Somit hättest du dann eine Möglichkeit, wie du die anderen Clients sehen könntest.

    Ich habe mal mit Linux und dem Samba-Server ein paar Versuche gemacht, Ich wollte mich z.B. an einer Win2K-Domäne anschliessen. Dabei ist mir u.a. der Befehl "net view" aufgefallen. Dieser listet auch alle Rechner der aktuellen Domäne / Arbeitsgruppe auf.
    Vielleicht kannst du ja auch diesem Weg über ShellExecute() eine Liste erzeugen.



  • bei mir funktioniert der code den ich gepostet habe, auch unter win9x nur das man halt kein ergebnis bekommt, da die funktionen nicht in netapi32.dll enthalten sind!

    hast du schon mal ne konsolenanwendung mit buttons, edits und listviews gesehen?

    // die zeile ist doch nur umgebrochen, damit es hier nicht zu breit ist
    typedef NET_API_STATUS (WINAPI *NETQUERYINFO)  (LPWSTR ServerName, DWORD Level, DWORD Index, 
                                                    DWORD EntriesRequested, DWORD PreferredMaximumLength, 
                                                    LPDWORD ReturnedEntryCount,
    PVOID *SortedBuffer);
    

    der code behört in die cpp-datei!!!

    //---------------------------------------------------------------------------
    // Net-API (Prototypen)
    //---------------------------------------------------------------------------
    typedef NET_API_STATUS (WINAPI *NETQUERYINFO)  (LPWSTR ServerName, DWORD Level, DWORD Index, 
                                                    DWORD EntriesRequested, DWORD PreferredMaximumLength, 
                                                    LPDWORD ReturnedEntryCount,PVOID *SortedBuffer);
    typedef NET_API_STATUS (WINAPI *NETBUFFERFREE) (LPVOID Buffer);
    //---------------------------------------------------------------------------
    static NETQUERYINFO  pNetQueryDisplayInformation = NULL;
    static NETBUFFERFREE pNetApiBufferFree           = NULL;
    

    ich hab den code direkt aus meine anwendung entnommen. es fehlt auch nichts. prüf noch mal ob du alles richtig hast!

    pNetQueryDisplayInformation und pNetApiBufferFree sind nur Zeiger auf eine Funktionsadresse in der DLL. beim dynamischen Laden der DLL ist es daher völlig egal ob die Funktionen unter Win9x verfügbar sind oder nicht. Deswegen macht man das ja über LoadLibrary damit man zur Designer-Zeit keine Fehlermeldung bekommt, falls die Funktion nicht zur Verfügung steht.

    [ Dieser Beitrag wurde am 03.02.2003 um 15:35 Uhr von Sunday editiert. ]

    Edit:
    Code umgebrochen.

    [ Dieser Beitrag wurde am 04.02.2003 um 08:41 Uhr von Jansen editiert. ]



  • Original erstellt von Sunday:
    falsch... nicht auf jedem system ist die richtige netapi32.dll vorhanden, die die funktionen exportiert! ergo kannst du nichts importieren was nicht da ist!

    Ich habe keine Peilung, was du meinst. 😕 In der LIB steht doch nur, wo sich die DLL befindet und was für Funktionen darin deklariert sind. Wenn ich also ein LIB zu meiner DLL generiere, die auf meinem Windows drauf ist, und die dann in mein Projekt mit einbinde, dann kann ich doch alle Funktionen der DLL benutzen. Oder etwa nicht???



  • naja ok, die frage mit der konsolenanwendung war wohl nen bissl überflüssig... ich hab jetzt aber auch noch ein anderes problem: ich habe das programm jetzt erstmal so geschrieben, dass ich die beiden computer / ip-adressen schon gleich eingegeben habe. jetzt hab ich aber nen problem mit dem textaustausch... wenn ich das programm auf beiden computern starte, kann der rechner, auf dem das programm zuerst gestartet wurde, die daten senden, empfängt aber nichts. der andere rechner empfängt den text, sendet aber wohl nicht korrekt...
    ich weiß nicht, kann das daran liegen, dass die beiden programme eigentlich diesselben sind, in denen bloß die ip-adresse (an die der text gesendet wird) anders ist. also dass beide einen serversocket und einen clientsocket haben??? das ist mein erstes programm mit diesen komponenten, so dass ich mich da noch nicht so auskenne...
    kann mir (mal wieder) jemand bei dem problem helfen??? 😕
    danke schonmal im vorraus und auch mal für alle vorherigen antworten!!!



  • Ich habe eine Lösung, um alle Rechnernamen im Netzwerk aufzulisten, die auch mit Win9x funktionieren müsste gefunden:

    Benötigt wird ein Button und ein RichEdit

    Hier der Code:

    void __fastcall::TForm1::Button2Click(TObject *Sender)
    {
      // leere Inhalt von RichEdit
      RichEdit1->Clear();
    
      try
      {
        // setze Maus-Cursor auf "Warten"
        Screen->Cursor = crAppStart;
    
        // Zeiger auf NETRESOURCE-Struktur
        NETRESOURCE *NetResource = NULL;
        // Handle von WNetOpenEnum für WNetEnumResource und WNetCloseEnum
        HANDLE hEnum;
    
        // starte Aufzählung von Netzwerk-Ressourcen
        WNetOpenEnum(RESOURCE_CONTEXT, NULL, NULL, NULL, &hEnum);
    
        // wenn gültiges Handle
        if(hEnum)
        {
          // Anzahl der Einträge (0xFFFFFFFF bedeutet alle Möglichen)
          DWORD Count = 0xFFFFFFFF;
          // Grösse für den Puffer
          // (grosser Puffer, falls viele Rechner im Netzwerk)
          DWORD BufferSize = 131072;
          // Void-Zeiger
          // Zeigt später auf NETRESOURCE-Struktur
          LPVOID Buffer = new char[BufferSize];
    
          // setze Aufzählung der Netzwerk-Ressourcen fort,
          // die durch WNetOpenEnum begonnen wurde
          WNetEnumResource(hEnum, &Count, Buffer, &BufferSize);
          // biege Void-Zeiger auf NETRESOURCE-Struktur
          NetResource = (NETRESOURCE*)Buffer;
    
          // ermittle die Namen der Rechner im Netzwerk
          for(DWORD i=0; i<Count; i++, NetResource++)
          {
            // wenn die Ressource ein Container-Objekt ist
            // und der Typ der Ressource beliebig ist
            // (Computer, Drucker, Verzeichnis)
            if(NetResource->dwUsage == RESOURCEUSAGE_CONTAINER &&
               NetResource->dwType == RESOURCETYPE_ANY )
            {
                // wenn Name vorhanden ist
                if(NetResource->lpRemoteName)
                {
                    // füge Namen dem RichEdit hinzu
                    RichEdit1->Lines->Add(NetResource->lpRemoteName);
                }
            }
          }
          // gib Speicher wieder frei
          delete Buffer;
          // beende die Aufzählung der Netzwerk-Ressourcen
          WNetCloseEnum(hEnum);
        }
      }
      __finally
      {
        // setze Maus-Cursor wieder auf "Standard"
        Screen->Cursor = crDefault;
      }
    
      // gib die Anzahl der ermittelten Rechner in Titelleiste aus
      Caption = "Computer: "+IntToStr(RichEdit1->Lines->Count);
    }
    


  • @JeGr : danke das du dich damit beschäftigst hast... das gute ist jetzt bei dem quelltext, dass das programm läuft. das schlechte, er findet keinen computer...
    hast du das mal unter win9x probiert??? und müsste das programm auch den eigenen computer finden???
    ach und kennst du irgendeine gute hilfe zu den ganzen sachen??? also winapi programmierung mit dem BCB zum beispiel??? ich weiß jetzt nämlich z.b. nicht, was eine netresource ist...



  • Also zur WinAPI kann ich auch nur sagen, dass ich die Sachen in der Windows SDK Hilfe bzw auf MSDN-Website nachgeschlagen habe.
    Unter Win2k funktioniert der Code auf jeden Fall einandfrei.
    Ich habe alle Rechner der Domäne (ca. 400 St.) in meinem RichEdit aufgelistet.

    Ich habe momentan hier nur Win2k, aber ich kann's heute Abend mal auf meinem Win98 Rechner ausprobieren.

    Falls du die WinAPI Sachen nicht ganz verstehst, dann kann ich dir nur noch einmal die entsprechenden Hilfeseiten ans Herz legen.
    Ich habe mich damit am Anfang auch sehr schwer getan, aber wenn man einmal den Trick raus hat, dann findet man sich ganz gut zurecht.
    Ansonsten kannst du auch ein bisschen googeln, da findet man auch immer wieder ein paar interessante Schnippsel und Anregungen

    [ Dieser Beitrag wurde am 04.02.2003 um 12:47 Uhr von JeGr editiert. ]



  • Hi,
    ja teste den Code ma auf Win9x! Und noch ne Frage, wie bekomme ich aus dem Rechnernamen die IP heraus!

    Danke

    Alexander Sulrian

    [edit] Hi,
    hab gerade eine Delphi-Komponente gefunden, die genau das macht: http://overbyte.delphicenter.com/frame_index.html und dann runter scrollen zu

    Name:
    ICS_NetFind.zip
    Size:
    7 KB
    Author:
    Sven Schmidts
    Use this component to make a broadcast and find all PC's, on wich this component is running. You can send your own data to the PC's and receive the data, that is send back within addional strings.

    Ich hab's noch nicht getestet und weiß nicht obs auf Win9x läuft! Drauf gekommen bin ich durch: http://www.delphipraxis.net/viewtopic.php?t=1872 !
    Werde noch weiter suchen!

    Danke

    Alexander Sulfrian
    [/edit]

    [ Dieser Beitrag wurde am 04.02.2003 um 17:52 Uhr von Alexander Sulfrian editiert. ]



  • So, ich habe die ganze Sache noch einmal überarbeitet.
    Hab das Beispiel aus der Windows SDK Hilfe so modifiziert, dass nun die Rechnernamen des lokalen Netzerks in ein RichEdit geschrieben werden.

    Habe es unter Win98 und Win2k getestet und bei beiden habe ich das gleiche Resultat erhalten.

    Hier der neue Code:

    //---------------------------------------------------------------------------
    #include <vcl.h>
    #pragma hdrstop
    
    #include "Unit1.h"
    //---------------------------------------------------------------------------
    #pragma package(smart_init)
    #pragma resource "*.dfm"
    TForm1 *Form1;
    
    //===========================================================================
    // Funktion ListNetworkComputer
    //---------------------------------------------------------------------------
    //
    // Ermittelt die Rechnernamen im lokalen Netzwerk.
    // Ist Win9x kompatibel.
    //---------------------------------------------------------------------------
    //
    // Erstellt 04/02/2003 by Jens Gross mit Borland C++ Builder 6
    //===========================================================================
    BOOL WINAPI ListNetworkComputer(HWND hwnd, HDC hdc, LPNETRESOURCE lpnr)
    { 
        // Variablendeklaration
        HANDLE        hEnum;                   // Handle von WNetOpenEnum
        DWORD         Result;                  // Rückgabewert für WNetXXX
        DWORD         Buffer = 16384;          // 16K als Startgrösse
        DWORD         Entries = 0xFFFFFFFF;    // liste alle möglichen Einträge
        LPNETRESOURCE NetResource;             // Pointer auf NETRESOURCE
                                               // (enthält die gelisteten Einträge)
    
        // führe WNetOpenEnum aus, um Auflistung der Netzwerkressourcen
        // zu beginnen und ermittle den Rückgabewert
        Result = WNetOpenEnum(RESOURCE_GLOBALNET, RESOURCETYPE_ANY, 0, lpnr, &hEnum);
    
        // wenn Rückgabewert Fehler
        if(Result != NO_ERROR)
        {
          // gib Flag zurück, dass Funktion fehlerhaft
          return FALSE;
        } 
    
        // solange noch Daten vorhanden sind
        do
        {
          // allokiere Speicher für NETRESOURCE-Struktur
          NetResource = (LPNETRESOURCE)GlobalAlloc(GPTR, Buffer);
    
          // führe WNetEnumResource aus, um Auflistung fortzusetzen,
          // die mit WNetOpenEnum begonnen wurde und ermittle Rückgabewert
          Result = WNetEnumResource(hEnum, &Entries, NetResource, &Buffer);
    
          // wenn Rückgabewert in Ordnung
          if(Result == NO_ERROR)
          {
            // ermittle für alle ermittelten Einträge die Namen
            for(DWORD i=0; i<Entries; i++)
            {
              // wenn ermittelter Eintrag ein Container ist
              // (z.B. Domäne, Arbeitsgruppe etc)
              if(RESOURCEUSAGE_CONTAINER ==
                            (NetResource[i].dwUsage & RESOURCEUSAGE_CONTAINER))
              {
                // wenn List-Funktion FALSE liefert
                if(!ListNetworkComputer(hwnd, hdc, &NetResource[i]))
                {
                  // gib Fehlermeldung aus
                  ShowMessage("Fehler bei der weiteren Auflistung!");
                }
                // List-Funktion hat TRUE geliefert
                else
                {
                  // ermittle den Remotenamen
                  AnsiString RemoteName = AnsiString(NetResource[i].lpRemoteName);
    
                  // wenn Remotename vorhanden und der Name mit \\ beginnt
                  // (\\ deshalb, damit nur Rechner aufgelistet werden und nicht
                  // auch noch die Domänen, Arbeitsgruppen etc)
                  if(RemoteName != "" && RemoteName.SubString(1,2) == "\\\\")
                  {
                    // schreibe Namen in RichEdit von Formular
                    Form1->RichEdit1->Lines->Add(RemoteName);
                  }
                }
              }
            }
          }
          // wenn keine weiteren Daten mehr vorliegen
          else if(Result != ERROR_NO_MORE_ITEMS)
          {
            // beende die Schleife
            break;
          }
        } 
        while(Result != ERROR_NO_MORE_ITEMS);
    
        // gib den allokierten Speicher wieder frei
        GlobalFree((HGLOBAL)NetResource);
    
        // führe WNetCloseEnum aus, um die Auflistung zu beenden
        // und ermittle den Rückgabewert
        Result = WNetCloseEnum(hEnum);
    
        // wenn Rückgabewert Fehler
        if(Result != NO_ERROR)
        {
          // gib Flag zurück, dass Funktion fehlerhaft
          return FALSE;
        }
        // gib Flag zurück, dass Funktion erfolgreich
        return TRUE;
    }
    
    //---------------------------------------------------------------------------
    __fastcall TForm1::TForm1(TComponent* Owner)
            : TForm(Owner)
    {
    }
    
    //---------------------------------------------------------------------------
    void __fastcall TForm1::Button2Click(TObject *Sender)
    {
      // leere Inhalt von RichEdit
      RichEdit1->Clear();
      // führe List-Funktion aus
      ListNetworkComputer(Application->Handle, NULL, NULL);
    }
    //---------------------------------------------------------------------------
    

    Zum Theme IP-Adressen:

    Du kannst dir zu einem Rechnernamen über Winsock mit gethostby...() und einer hostent-Struktur die IP-Adressen ermitteln.
    Wie das genau geht, kann man in der FAQ bzw. bei Bytes&More nachlesen.



  • juhu es funktioniert!!!!!! danke JeGr!!!!! 🙂 es taucht dann, nachdem er die rechner aufgelistet hat, zwar die meldung "Fehler bei der weiteren Auflistung!" auf, aber das ist mir egal. wenns nichts schimmes ist, kann ich die zeile aus dem code ja auch einfach entfernen oder??? ist ja eigentlich bloß eine info für den benutzer...
    ach JeGr, wo findet man die windows sdk hilfe eigentlich??? die ist kommt nicht gleich bei der windows installation auf den computer rauf, oder? danke...



  • Bei mir ist die SDK Hilfe jedenfalls installiert.
    Wenn du im BCB unter dem Menü Hilfe nachschaust, dann befindet sich dort ein entsprechender Eintrag.
    Auf der Festplatte müsste es die folgende Datei sein:
    C:\Programme\Gemeinsame Dateien\Borland Shared\MSHelp\guide.hlp

    Wenn die nicht da ist, dann musst du halt nochmal bei der BCB-Installation nachschauen.

    Ansonsten findest du das ganze auch Online unter: http://msdn.microsoft.com/library/default.asp

    Die Meldung kannst du natürlich unterdrücken. Kannst statt dessen auch eine andere Fehlerbehandlung machen bzw. es auch einfach ignorieren.
    Die Hauptsache ist doch, dass die Rechner erscheinen 😉

    [ Dieser Beitrag wurde am 05.02.2003 um 08:15 Uhr von JeGr editiert. ]



  • @JeGr: schon ganz gut, nur noch ein paar anmerkungen

    1. wozu brauchst Du das Handle der Anwendung und ein Handle auf nen Device Context?

    [cpp]
    BOOL WINAPI ListNetworkComputer(HWND hwnd, HDC hdc, LPNETRESOURCE lpnr)[/cpp]

    2. warum erst umständlich mit GlobalAlloc Speicher reservieren?

    eine einfache Variablen deklaration reicht da vollkommen aus

    if (RESOURCEUSAGE_CONTAINER == (NetResource[i].dwUsage & RESOURCEUSAGE_CONTAINER))
    

    ist identisch mit:

    if (NetResource[i].dwUsage & RESOURCEUSAGE_CONTAINER)
    
    beispiel:
    
       dezimal:   2 ==   3 &   2 
       binär:   010 == 011 & 010 -> 010 == 010 => true doppelt gemoppelt :) 
    
       dezimal:          3 &   2 
       binär:          011 & 010 -> 010        => true
    


  • @sunday

    Danke für die Hinweise!
    Das meiste ist hier aber nicht auf meinem Mist gewachsen.
    Ich habe den Grossteil (vor allem das mit dem Speicher allokieren) aus der Windows SDK-Hilfe übernommen. Dort wurde das eben so gemacht.

    Ansonsten war ich froh, dass die Funktion soweit funktioniert hat und da hab ich mich nicht mehr darum gekümmert, das Ganze noch zu optimieren.

    Aber falls hier jemand Zeit und sonst nichts bessers vor hat, dann darf er gerne die ganze Sache überarbeiten.
    Vielleicht könnte man dies dann auch in die FAQ stellen 🙄



  • Ausserdem hat bei einer universellen Lösung eine Zeile wie Form1->RichEdit1->Lines->Add(RemoteName); auch nichts zu suchen. Statt dessen sollte zB. einfach ein Zeiger auf eine StringList als Funktionsparameter übergeben werden:

    ListNetworkComputer(TStrings *ResList)
    {
      ...
      ResList->Add(NetResource->lpRemoteName);
      ...
    }
    
    ...
    ListNetworkComputer(Memo1->Lines);
    

    Ihr merkt schon, ich suche wieder Freiwillige für einen hübschen FAQ-Beitrag. 😉


Anmelden zum Antworten