Hallo zusammen,
Crosspost
wir versuchen hier zur Zeit, eine alte C++-
DLL zu C# zu migrieren, die für den
SQL-Server 2008 Stored Procedures bereitstellt. Diese Prozeduren werden genutzt, um Gruppen und Benutzer des Servers auszulesen. (Bevor entsprechende Hinweise kommen: Mir ist bewusst, dass man in C# die Gruppen auch anders auslesen kann, aufgrund der Verknüpfung mit dem
SQL-Server scheinen wir aber auf die Verwendung der NetAPI32.dll festgelegt zu sein)
Teilweise klappt das ganz gut, so konnten wir schon den LogIn von Usern verifizieren oder auch alle Gruppen eines angegebenen Users auslesen. Vor ein Problem stellt uns jetzt allerdings das Auslesen aller User einer bestimmten Gruppe. Auf unserem Entwicklungsrechner bekommen wir das korrekte Ergebnis, sobald wir dann die Prozedur aber auf dem Server ausführen, führt das nicht nur zu einem Fehler, nein, der
SQL-Server schmiert einfach jedes Mal unaufhaltbar ab. Selbst try...catch zeigt keinerlei Wirkung.
Zu Testzwecken haben wir anschließend den entsprechenden Code mal in eine Applikation (siehe Anhang) gepackt. Selbige liefert wieder auf dem Entwicklungsrechner das erwartete Ergebnis, auf dem Server allerdings stürzt das Programm jedes Mal ab, sobald man eine Gruppe eingibt, die tatsächlich existiert (und User besitzt). Unsere Vermutung ist nun, dass das wohl etwas mit dem Betriebssystem zu tun hat, denn der Entwicklungsrechner hat 32bit, unser neuer Server 64bit (Windows Server 2008). Auch ein Test bei mir daheim hat ergeben, dass die Testanwendung weder auf Windows 7 64bit noch unter Vista 64bit funktioniert. ("Anwendung wurde geschlossen" oder so ähnlich, ohne Angabe einer Fehlermeldung)
Erstmal hier der entsprechende Code. Dabei wurde einfach nur ein Button, eine Textbox und eine Listbox auf die Form gezogen. Die Textbox dient zur Eingabe der Gruppenname, die Listbox zur Ausgabe der gefundenen User. Button sollte klar sein
Code:
using System.Runtime.InteropServices;
//...
[DllImport("NetAPI32.dll", CharSet = CharSet.Unicode)]
public extern static int NetLocalGroupGetMembers(
[MarshalAs(UnmanagedType.LPWStr)] string servername,
[MarshalAs(UnmanagedType.LPWStr)] string localgroupname,
int level,
out IntPtr bufptr,
int prefmaxlen,
out int entriesread,
out int totalentries,
ref int resume_handle);
[StructLayout(LayoutKind.Sequential, CharSet = CharSet.Unicode)]
internal struct LOCALGROUP_MEMBERS_INFO_1
{
public int lgrmi1_sid;
public int lgrmi1_sidusage;
public string lgrmi1_name;
}
[DllImport("Netapi32.dll", SetLastError = true)]
static extern int NetApiBufferFree(IntPtr Buffer);
//...
private void button1_Click(object sender, EventArgs e)
{
listBox1.Items.Clear();
int EntriesRead = 0;
int TotalEntries = 0;
int Resume = 0;
IntPtr bufPtr;
IntPtr iter;
NetLocalGroupGetMembers(null, textBox1.Text, 1, out bufPtr, -1, out EntriesRead, out TotalEntries, ref Resume);
try
{
iter = bufPtr;
for (int i = 0; i < EntriesRead; i++)
{
LOCALGROUP_MEMBERS_INFO_1 lgi = new LOCALGROUP_MEMBERS_INFO_1();
lgi = (LOCALGROUP_MEMBERS_INFO_1)Marshal.PtrToStructure(iter, typeof(LOCALGROUP_MEMBERS_INFO_1));
iter = (IntPtr)((int)iter + Marshal.SizeOf(typeof(LOCALGROUP_MEMBERS_INFO_1)));
listBox1.Items.Add(lgi.lgrmi1_name);
}
}
catch (
Exception ex)
{
listBox1.Items.Add("/!\\ :: " + ex.ToString());
}
}
Soooo, was passiert hier? Wir rufen die Funktion NetLocalGroupGetMembers aus der NetAPI32.dll auf. Den entsprechenden Code findet man mehrfach online, und an die entsprechende Vorgehensweise haben wir uns im Großen und Ganzen auch gehalten. Wir rufen also die Funktion mit den entsprechenden Parametern auf und sollten anschließend im out-Parameter
bufPtr die Daten zurückbekommen. Anschließend wird daraus dann mittels Marshall.PtrToStructure eine lesbare Struktur erstellt.
Unser Problem konnten wir nach einigen Versuchen dann genau auf diese Umwandlung eingrenzen:
Code:
lgi = (LOCALGROUP_MEMBERS_INFO_1)Marshal.PtrToStructure(iter, typeof(LOCALGROUP_MEMBERS_INFO_1));
Genau dabei fällt alles zusammen. Offensichtlich stimmt bei einem 64bit-Betriebssystem in dem Speicherbereich, auf den bufPtr zeigt, etwas nicht.
Seltsamerweise (keine Ahnung, ob das etwas zur Sache beiträgt, ich erwähne es aber trotzdem mal) wird beim Aufruf von NetLocalGroupGetMembers auch der Wert
TotalEntries nur beim 32bit-System gesetzt. Dort steht dann z.B., dass insgesamt (TotalEntries) 12 Datensätze gefunden wurden, von denen 12 gelesen (EntriesRead) wurden. Auf der 64bit-Maschine wird uns aber ausgegeben, es wurden 12 Datensätze gelesen, obwohl keiner gefunden wurde (TotalEntries = 0)...
Wir stehen hier vor einem absoluten Rätsel... Wir haben erfolglos mehrere Varianten ausprobiert und auch Tante Google schweigt leider eisern zu dem Thema. Darum habe ich die Hoffnung, dass vielleicht hier jemand bereits ähnliches versucht hat und eventuell einen kleinen Workaround hat. Auf die Verwendung der hier verwendeten Strukturen sind wir wie gesagt aber wohl leider festgelegt.
Danke schonmal im Voraus,
Axel