C# - A LAN gépein telepített SQL Server példányok lekérdezése

forráskód letöltése
A Windows NT 4-es verziójától kezdődően rendelkezésünkre áll egy dinamikus könyvtár, a Netapi32.dll, mely számtalan hasznos függvényt tartalmaz egyrészt ahhoz, hogy a lokális számítógépről információkat kérdezzünk le, illetve jellemzőket állítsunk be, másrészt hogy a helyi hálózat számítógépeiről kapjunk hasznos adatokat. Cikkünkben az utóbbi függvénycsoport egyik tagját használjuk fel arra, hogy a LAN számítógépeit feltérképezve lekérdezzük az egyes számítógépeken telepített SQL Server példányokat.
A mellékelt példában a program indulásakor lefuttatjuk a számítógépek pásztázását elvégző függvényt, az eredményt – az SQL Server példányok neveit – a program űrlapján elhelyezett ComboBox kontrolban helyezzük el. Több szerver esetén az aktuálisan kiválasztott elemről töltődik be információ a ListBox kontrolba. A program hálózatba nem kapcsolt számítógépen is kipróbálható.
A Netapi32.dll dinamikus könyvtár NetServerEnum metódusát használjuk fel a cél elérése érdekében. Minden, a függvényhíváshoz szükséges objektum deklarációját a Win32 osztályban helyeztünk el.
A függvénydeklaráció a következő:
[DllImport("netapi32.dll")]
unsafe private static extern uint NetServerEnum(
  [MarshalAs(UnmanagedType.LPWStr)]
  string ServerName, 
  uint level,
  out IntPtr bufptr,
  uint prefmaxlen,
  ref uint entriesread,
  ref uint totalentries,
  uint servertype,
  [MarshalAs(UnmanagedType.LPWStr)]
  string domain, 
  uint resume_handle);
A függvény paraméterei a következő szerepet töltik be:
  • ServerName: a feltérképezendő szerver neve. Jelen esetben NULL, mivel a hálózat valamennyi gépét feltérképezzük.
  • level: a szám értéke függ attól, hogy milyen jellegű információt kérünk az adott szerverről. Jelen esetben ez 101, mert a SERVER_INFO_101 struktúrában tároljuk el a visszakapott adatokat.
  • bufptr: a kapott információra mutató pointer, melyet majd feldolgozunk a függvény meghívása után.
  • prefmaxlen: a kapott információ maximális mérete bájtban. A függvény ezt a memóriaterületet foglalja le a memóriában a kapott információ számára.
  • entriesread: az összes specifikált szerver számát adja vissza.
  • totalentries: a hálózat valamennyi számítógépének (szerverek, munkaállomások) számát adja vissza.
  • servertype: itt adhatjuk meg, hogy milyen szerver, vagy szoftvertípussal rendelkező számítógépet keressen a függvény.
  • domain: a domain neve, melybe a hálózat számítógépei tartoznak. NULL esetén az elsődleges domain kerül átvizsgálásra.
  • resume_handle: nem használt érték, nulla értéket kell megadnunk.
A kapott információra egy pointer mutat. A pointer-t értelmezve meghatározzuk, hogy hány SQL Server példányról kaptunk információkat. Minden információ egy-egy struktúrában lesz megtalálható. Ez a struktúra a SERVER_INFO_101, melynek menedzselt megfelelője a következő:
[System.Runtime.InteropServices.StructLayoutAttribute (LayoutKind.Sequential, CharSet=CharSet.Auto)]
private struct SERVER_INFO_101 
{ 
Mezőinek értéke a következő információkat hordozza:
A szervert tartalmazó platform azonosítója, mely NT kliens esetén a PLATFORM_ID_NT konstans értéke.
  public int dwPlatformID;
Az SQL Server neve.
  public System.IntPtr lpszServerName;
A szerver verziószámára vonatkozó információ első, és második jegye.
  public int dwVersionMajor;
  public int dwVersionMinor;
A szerver típusa, mely jelen esetben a SV_TYPE_SQLSERVER nevű konstans.
  public int dwType;
Esetleges szerverrel kapcsolatos megjegyzések.
  public int lpszComment;
}
A Win32 osztályunk GetServers() metódusában hívjuk meg a függvényt. Első lépésben deklarálunk egy pointert, mely a kapott struktúrára mutat.
IntPtr ptr = IntPtr.Zero;
A lekérdezendő szervertípusként az említett SV_TYPE_SQLSERVER konstanst adjuk át.
uint nRes = NetServerEnum(null, level, out ptr, prefmaxlen, ref entriesread, ref totalentries, SQLSERVER, null, resume_handle);
A függvény visszatérési értéke sikeres lekérdezés esetén nulla. Ha a művelet sikeres volt, és a visszakapott szerverszám nem nulla, akkor a mutatót értelmezzük. Elsőként deklarálunk egy tömböt a szerverek nevei számára.
string[] servers = new string[entriesread];
Deklarálunk egy másik, két-dimenziós tömböt az egyes szerverek tulajdonságai számára. Ez egy osztályszinten deklarált tömb, hogy a ListBox feltöltésekor is elérjük.
serverinfos = new string[entriesread,5];
Példányosítjuk a struktúrát.
SERVER_INFO_101 serverinfo = new SERVER_INFO_101();
És deklarálunk egy újabb pointert, mely végighalad a – több szerver esetén - több struktúrára mutató pointeren.
SERVER_INFO_101* temp;
Az utóbbi pointerbe átmásoljuk a függvény által visszaadott pointert.
temp = (SERVER_INFO_101*)ptr;
Majd a FOR ciklus segítségével végigmegyünk a pointer által mutatott tömbön.
A csak a szerverneveket tároló tömbben elhelyezzük a struktúra első mezőjének értékét.
servers[i] = Marshal.PtrToStringAuto(temp->lpszServerName);
A másik tömbben pedig minden adatot a struktúrából.
serverinfos[i,0] = "Szerver neve: " + Marshal.PtrToStringAuto(temp->lpszServerName);
...
Majd léptetjük a mutatót a következő struktúra memóriaterületének kezdőcímére.
temp++;
A művelet végén fontos, hogy a pointer által lefoglalt memóriaterületet felszabadítsuk. Erre a NetApiBufferFree metódust használjuk, paraméterében a mutatóval.
NetApiBufferFree(ptr);
A program űrlapjának konstruktorában egyszerűen átadjuk adatforrásként a kapott tömböt a ComboBox kontrolnak.
comboBox1.DataSource = Win32.GetServers();