Autor Beitrag
MCPC10
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starontopic star
Beiträge: 35

Win 10, Win Server 2016
C# (VS 2015, VS2017, VS2019), Assembler (Atmel Studio 7.0)
BeitragVerfasst: So 02.08.20 15:36 
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 :).

ausblenden volle Höhe 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
                {
                    //Copy struct to unmanaged memory 
                    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 user profile iconTh69: Topic aus C# - Die Sprache verschoben am Mo 03.08.2020 um 08:47
Th69
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starontopic star
Moderator
Beiträge: 4282
Erhaltene Danke: 919

Win10
C#, C++ (VS 2015/17)
BeitragVerfasst: 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
ausblenden 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 an.

Für diesen Beitrag haben gedankt: MCPC10
MCPC10 Threadstarter
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starontopic star
Beiträge: 35

Win 10, Win Server 2016
C# (VS 2015, VS2017, VS2019), Assembler (Atmel Studio 7.0)
BeitragVerfasst: 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):
ausblenden volle Höhe 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);
                }

                //Create the unmanaged struct
                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
                {
                    //Copy struct to unmanaged memory 
                    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);
                }
            }
        }

_________________
Mit freundlichen Grüßen
MCPC10
jfheins
ontopic starontopic starontopic starontopic starontopic starontopic starofftopic starofftopic star
Beiträge: 888
Erhaltene Danke: 149

Win7
VS 2013, VS2015
BeitragVerfasst: 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 Threadstarter
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starontopic star
Beiträge: 35

Win 10, Win Server 2016
C# (VS 2015, VS2017, VS2019), Assembler (Atmel Studio 7.0)
BeitragVerfasst: Di 04.08.20 19:39 
Hallo,
Werden Strukturen nicht mit GCHandle.Alloc kopiert?

Moderiert von user profile iconTh69: C#-Tags hinzugefügt

_________________
Mit freundlichen Grüßen
MCPC10
jfheins
ontopic starontopic starontopic starontopic starontopic starontopic starofftopic starofftopic star
Beiträge: 888
Erhaltene Danke: 149

Win7
VS 2013, VS2015
BeitragVerfasst: Mi 05.08.20 08:33 
user profile iconMCPC10 hat folgendes geschrieben Zum zitierten Posting springen:
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 Threadstarter
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starontopic star
Beiträge: 35

Win 10, Win Server 2016
C# (VS 2015, VS2017, VS2019), Assembler (Atmel Studio 7.0)
BeitragVerfasst: 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?

_________________
Mit freundlichen Grüßen
MCPC10
jfheins
ontopic starontopic starontopic starontopic starontopic starontopic starofftopic starofftopic star
Beiträge: 888
Erhaltene Danke: 149

Win7
VS 2013, VS2015
BeitragVerfasst: So 09.08.20 19:55 
user profile iconMCPC10 hat folgendes geschrieben Zum zitierten Posting springen:
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 ;-)