Entwickler-Ecke

Basistechnologien - Allgemeiner Typ für struct


Delete - Do 13.09.18 07:30
Titel: Allgemeiner Typ für struct
- Nachträglich durch die Entwickler-Ecke gelöscht -


OlafSt - Do 13.09.18 07:42

Ein Generic geht nicht ?


Th69 - Do 13.09.18 08:07

Und diese Generic-Methode könntest du dann mittels where T : struct passend einschränken (s.a. Einschränkungen für Typparameter [https://docs.microsoft.com/de-de/dotnet/csharp/programming-guide/generics/constraints-on-type-parameters]).


Delete - Do 13.09.18 08:45

- Nachträglich durch die Entwickler-Ecke gelöscht -


Th69 - Do 13.09.18 09:16

Nein, die Klasse muß nicht zwangsläufig generisch sein.

Was meinst du aber jetzt mit "untypisierter Zeiger (void*)"? Zeige mal am besten ein Beispiel.


OlafSt - Do 13.09.18 09:26

Eine generische Klasse braucht es nicht. Eine List<T>, später als List<integer> instanziiert, hat auch keinen generischen Integer ;)


Delete - Do 13.09.18 13:36

- Nachträglich durch die Entwickler-Ecke gelöscht -


Th69 - Do 13.09.18 14:48

Einfach so:

C#-Quelltext
1:
2:
[DllImport("User32.dll", EntryPoint = "SendMessage")]
private static extern bool SendMsgB<T>(IntPtr hWnd, int Msg, int wParam, ref T lParam) where T : struct;

Und der Aufruf dazu:

C#-Quelltext
1:
2:
3:
4:
public static bool capDriverGetCaps(IntPtr hwnd, ref CAPDRIVERCAPS psCaps, int wSize)
{
  return SendMsgB(hwnd, WM_CAP_DRIVER_GET_CAPS, wSize, ref psCaps);
}

s.a. Ideone-Code [https://ideone.com/5YhQVK] (wobei dabei DllImportAttribute sowie CAPDRIVERCAPS nur Fakes sind).


Delete - Fr 14.09.18 00:10

- Nachträglich durch die Entwickler-Ecke gelöscht -


Th69 - Fr 14.09.18 08:17

Puh, da scheint wohl P/Invoke nicht mit generischen Methoden umgehen zu können.

Dann bleibt wohl nur (ohne unsafe zu benutzen):

C#-Quelltext
1:
2:
[DllImport("User32.dll", EntryPoint = "SendMessage")]
private static extern bool SendMsgB(IntPtr hWnd, int Msg, int wParam, IntPtr lParam);

Und dann eine generische Methode erstellen, welche mittels Marshal.AllocHGlobal [https://docs.microsoft.com/de-de/dotnet/api/system.runtime.interopservices.marshal.allochglobal?view=netframework-4.7.2] diesen IntPtr erstellt und nach dem Aufruf von SendMsgB dann Marshal.PtrToStructure [https://docs.microsoft.com/de-de/dotnet/api/system.runtime.interopservices.marshal.ptrtostructure?view=netframework-4.7.2] aufruft (s.a. die Beispiele)

PS: Laß dich nicht verwirren von "This API is now obsolete.": dies bezieht sich nur auf die Methoden-Überladung mittels object (je nachdem also welche Framework-Version du nutzt, wird die passende Methode verwendet).

PPS: Die Größe der Struktur würde ich direkt in capDriverGetCaps vornehmen (und nicht wie du es bisher machst, jedesmal als Parameter übergeben).


Delete - Fr 14.09.18 20:38

- Nachträglich durch die Entwickler-Ecke gelöscht -


Th69 - Sa 15.09.18 07:53

Ja stimmt, zumindestens wenn es auch ein Input-Parameter sein soll. Bei capDriverGetCaps bin ich jedoch von einem reinen Output(out)-Parameter ausgegangen.
Aber als generelle Methode sicherlich empfehlenswert.

Du könntest aber jetzt einfach 2 verschiedene generische Methoden anbieten, einmal mit ref und einmal mit out:

C#-Quelltext
1:
2:
3:
4:
5:
6:
7:
8:
9:
10:
11:
12:
13:
14:
15:
16:
17:
18:
19:
public static bool SendMsgRef<T>(IntPtr hwnd, int msg, ref T param) where T : struct
{
    int wSize = Marshal.SizeOf(param);
    IntPtr hMem = Marshal.AllocHGlobal(wSize);
    // ZeroMemory(hMem, wSize); // sehe ich nicht als notwendig hier an (wegen anschließendem StructureToPtr)

    Marshal.StructureToPtr(param, hMem, true);
    bool result = SendMsgB(hwnd, msg, wSize, hMem);
    param = (T)Marshal.PtrToStructure(hMem, typeof(T));

    Marshal.FreeHGlobal(hMem);

    return result;
}

public static bool SendMsgOut<T>(IntPtr hwnd, int msg, out T param) where T : struct
{
  // wie oben, nur ohne StructureToPtr
}


Delete - Sa 15.09.18 21:11

- Nachträglich durch die Entwickler-Ecke gelöscht -