Entwickler-Ecke
Basistechnologien - Marshalen von einem Array der Strukturen enthält, gut so?
MCPC10 - So 02.08.20 15:36
Titel: Marshalen von einem Array der Strukturen enthält, gut so?
Hallo liebe Community,
Ich hätte wieder mal eine Frage ;).
Ich wollte mal von euch wissen ob dieser Code den so gut ist oder ob dieser noch verbessert werden kann/es eine bessere Methode gibt.
Ich danke für jede konstruktive Antwort :).
C#-Quelltext
1: 2: 3: 4: 5: 6: 7: 8: 9: 10: 11: 12: 13: 14: 15: 16: 17: 18: 19: 20: 21: 22: 23: 24: 25: 26: 27: 28: 29: 30: 31: 32: 33: 34: 35: 36: 37: 38: 39: 40: 41: 42: 43: 44: 45: 46: 47: 48: 49: 50:
| public unsafe void ChangeFailureActions(TimeSpan resetPeriod, string rebootMessage, string command, IReadOnlyList<Win32ScAction> actions) { int size = 0; Win32ScAction** ptr = null; if (actions != null) { size = actions.Count; ptr = (Win32ScAction**) Marshal.AllocHGlobal(Marshal.SizeOf<Win32ScAction>() * size); }
try { if (ptr != null) { for (int i = 0; i < actions.Count; i++) Marshal.StructureToPtr(actions[i], (IntPtr)ptr[i], false); }
Win32ServiceFailureActions serviceFailureActions = new Win32ServiceFailureActions(resetPeriod, rebootMessage, command, size, ptr != null ? (IntPtr)ptr : IntPtr.Zero); IntPtr ptrServiceFailureActions = Marshal.AllocHGlobal(Marshal.SizeOf(serviceFailureActions)); try { Marshal.StructureToPtr(serviceFailureActions, ptrServiceFailureActions, false); try { if (!ChangeServiceConfig2W(this, Win32ServiceConfigInfoLevel.SERVICE_CONFIG_FAILURE_ACTIONS, ptrServiceFailureActions)) throw new Win32Exception(Marshal.GetLastWin32Error()); } finally { Marshal.DestroyStructure<Win32ServiceFailureActions>(ptrServiceFailureActions); } } finally { Marshal.FreeHGlobal(ptrServiceFailureActions); } } finally { if (ptr != null) { for (int i = 0; i < actions.Count; i++) Marshal.DestroyStructure<Win32ScAction>((IntPtr)ptr[i]);
Marshal.FreeHGlobal((IntPtr)ptr); } } } |
Mit freundlichen Grüßen
MCPC10
Moderiert von Th69: Topic aus C# - Die Sprache verschoben am Mo 03.08.2020 um 08:47
Th69 - Mo 03.08.20 08:46
So ganz verstehe ich deinen Code und die verwendeten Datentypen nicht.
Welchen Datentyp verlangt denn die
ChangeServiceConfig2W-Funktion:
Win32ScAction* (Zeiger auf Strukturen) oder
Win32ScAction** (Zeiger auf Zeiger auf Struktur)?
Bei
C#-Quelltext
1:
| ptr = (Win32ScAction**) Marshal.AllocHGlobal(Marshal.SizeOf<Win32ScAction>() * size); |
müßte doch als Datentyp
Win32ScAction* verwendet werden (da du die Größe der Struktur und nicht eines Zeigers angibst).
Funktioniert denn dein Code so zur Laufzeit oder erhältst du einen Laufzeitfehler?
Für das Marshallen eines Arrays schau dir auch mal die letzten Beispiele "
TestArrayOfStructs/2" in
Marshallen verschiedener Typen von Arrays [
https://docs.microsoft.com/de-de/dotnet/framework/interop/marshaling-different-types-of-arrays] an.
MCPC10 - Mo 03.08.20 20:52
Hallo,
Erstmal Danke für deine Antwort.
Hast natürlich völlig Recht ;) aber gibt es ne schönere Methode direkt die richtige menge Speicher zu zuweisen ohne mehrfach Marshal.AllocHGlobal aufzurufen (außer dieser hier xD)?
Hier ist der verbessert Code (funktioniert so auch, hab den Code etwas geändert da ich ihn zum testen in meine bestehende App eingebaut habe):
C#-Quelltext
1: 2: 3: 4: 5: 6: 7: 8: 9: 10: 11: 12: 13: 14: 15: 16: 17: 18: 19: 20: 21: 22: 23: 24: 25: 26: 27: 28: 29: 30: 31: 32: 33: 34: 35: 36: 37: 38: 39: 40: 41: 42: 43: 44: 45: 46: 47: 48: 49: 50: 51: 52: 53: 54: 55: 56: 57: 58: 59: 60:
| public unsafe void ChangeFailureActions2(Advapi32.ServiceFailureActions failureActions) { int size = 0; Advapi32.ScAction* ptr = null; if (failureActions.Actions != null) { size = failureActions.Actions.Count; ptr = (Advapi32.ScAction*) Marshal.AllocHGlobal(Marshal.SizeOf<Advapi32.ScAction>() * size); }
try { if (ptr != null) { for (int i = 0; i < size; i++) Marshal.StructureToPtr(failureActions.Actions[i], new IntPtr(&ptr[i]), false); }
Advapi32.ServiceConfigFailureActions serviceConfigFailureActions = new Advapi32.ServiceConfigFailureActions { resetPeriode = (uint)Math.Round(failureActions.ResetPeriode.TotalSeconds), rebootMessage = failureActions.RebootMessage, command = failureActions.Command, actionsLength = (uint)size, actions = (IntPtr)ptr };
IntPtr ptrServiceFailureActions = Marshal.AllocHGlobal(Marshal.SizeOf<Advapi32.ServiceConfigFailureActions>()); try { Marshal.StructureToPtr(serviceConfigFailureActions, ptrServiceFailureActions, false); try { if (!Advapi32.ChangeServiceConfig2(this, Advapi32.ServiceInfoLevel.FailureActions, ptrServiceFailureActions)) throw new Win32Exception(Marshal.GetLastWin32Error()); } finally { Marshal.DestroyStructure<Advapi32.ServiceConfigFailureActions>(ptrServiceFailureActions); } } finally { Marshal.FreeHGlobal(ptrServiceFailureActions); } } finally { if (ptr != null) { for (int i = 0; i < size; i++) Marshal.DestroyStructure<Advapi32.ScAction>(new IntPtr(&ptr[i]));
Marshal.FreeHGlobal((IntPtr)ptr); } } } |
jfheins - Mo 03.08.20 22:36
Ich habe schon lange nichts mehr mit P/invoke gemacht, aber müsste man nicht auch das Array so anlegen und dann pinnen können?
Also statt ein neues Array aufzumachen, einfach das vorhandene nehmen?
MCPC10 - Di 04.08.20 19:39
Hallo,
Werden Strukturen nicht mit
GCHandle.Alloc kopiert?
Moderiert von Th69: C#-Tags hinzugefügt
jfheins - Mi 05.08.20 08:33
MCPC10 hat folgendes geschrieben : |
Werden Strukturen nicht mit GCHandle.Alloc kopiert? |
Also soweit ich weiß (/gelesen habe), erzeugt
GCHandle.Alloc ein neues Handle, sodass der GC den struct nicht abräumt. Der struct selbst bleibt aber an der Stelle und wird nicht kopiert.
Ich glaube das Problem wird eher, dass du kein Array hast sondern nur eine IReadOnlyList, die ihr Array nicht offen legt.
MCPC10 - Fr 07.08.20 20:35
In diesem Fall würde es funktionieren (wenn es ein Array wäre), weil hier keine Non-Blittable typen zum Einsatz kommen oder lieg ich falsch?
jfheins - So 09.08.20 19:55
MCPC10 hat folgendes geschrieben : |
In diesem Fall würde es funktionieren (wenn es ein Array wäre), weil hier keine Non-Blittable typen zum Einsatz kommen oder lieg ich falsch? |
Das klingt plausibel, aber letztlich musst du es ausprobieren und gucken, ob es geht ;-)
Entwickler-Ecke.de based on phpBB
Copyright 2002 - 2011 by Tino Teuber, Copyright 2011 - 2024 by Christian Stelzmann Alle Rechte vorbehalten.
Alle Beiträge stammen von dritten Personen und dürfen geltendes Recht nicht verletzen.
Entwickler-Ecke und die zugehörigen Webseiten distanzieren sich ausdrücklich von Fremdinhalten jeglicher Art!