Neu in .NET 7.0 [28]: Source-Generator fĂĽr Platform Invoke
Neben dem Source-Generator für reguläre Ausdrücke führt .NET 7.0 auch einen für den Zugriff auf native Betriebssystemfunktionen ein.

(Bild: zekkoukyo/Shutterstock.com)
- Dr. Holger Schwichtenberg
Neben dem in den vorherigen beiden Teilen dieser Serie behandelten Source-Generator für reguläre Ausdrücke gibt es in .NET 7.0 auch einen neuen Source-Generator für den Zugriff auf native Betriebssystemfunktionen (.NET-Fachbegriff: Platform Invoke, abgekürzt P/Invoke).
Der neue Source-Generator heiĂźt Microsoft.Interop.LibraryImportGenerator. Er wird verwendet ĂĽber die Annotation [LibraryImport]
alternativ zu der bisherigen Annotation [DllImport]
, die eine Codegenerierung eines Intermediate Language Stub (IL Stub) zur Laufzeit auslöste. Die Laufzeitcodegenerierung ist aber nicht möglich in Verbindung mit dem in Teil 17 dieser Serie behandelten Ahead-of-Time-Compiler (AOT).
Das folgende Listing zeigt drei Beispiele fĂĽr Windows-API-Aufrufe mit dem bisherigen [DllImport]
:
/// <summary>
/// <summary>
/// Altes Verfahren
/// [DllImport] erfordert static und extern!
/// </summary>
public static class Win32APIohneSG
{
[DllImport("User32.dll")]
public static extern bool MessageBeep(UInt32 beepType);
[DllImport("user32.dll", CharSet = CharSet.Unicode, ExactSpelling = true)]
public static extern IntPtr MessageBoxW(int hWnd, string text, string caption, uint type);
// funktioniert auch ohne Zusatz "W" (W steht fĂĽr Unicode)
[DllImport("shell32.dll")]
public static extern int ShellAbout(IntPtr hWnd, string szApp, string szOtherStuff, IntPtr hIcon);
}
In der neuen Variante mit Source-Generator mĂĽssen die Methoden weiterhin static
sein, an die Stelle von extern
tritt aber partial
. Die Parameter bei [LibraryImport]
sind anders als bei [DllImport]
.
/// <summary>
/// Neu ab .NET 7.0
/// [LibraryImport] erfordert static und partial!
/// </summary>
public static partial class Win32APIMmitSG
{
[LibraryImport("User32.dll")]
[return: MarshalAs(UnmanagedType.Bool)]
public static partial bool MessageBeep(UInt32 beepType);
[LibraryImport("user32.dll", StringMarshalling = StringMarshalling.Utf16)]
public static partial IntPtr MessageBoxW(int hWnd, string text, string caption, uint type);
// ohne Zusatz "W": System.EntryPointNotFoundException: 'Unable to find an entry point named 'MessageBox' in DLL 'user32.dll'.', weil im generierten Code: ExactSpelling = true
[LibraryImport("shell32.dll", StringMarshalling = StringMarshalling.Utf16)]
public static partial int ShellAboutW(IntPtr hWnd, string szApp, string szOtherStuff, IntPtr hIcon);
}
Der Source-Generator erzeugt dann Programmcode beim Kompilieren. Den generierten Code sieht man im Projekt unter Dependencies/Analyzers/Microsoft.Interop.LibraryImportGenerator (siehe Abbildung 1):
Der Aufruf ist jeweils identisch:
Console.WriteLine("Beep...");
Win32APIohneSG.MessageBeep(0x00000010);
Win32APIMmitSG.MessageBeep(0x00000010);
Console.WriteLine("MessageBox...");
Win32APIohneSG.MessageBoxW(0, "Hallo von " + System.Runtime.InteropServices.RuntimeInformation.FrameworkDescription, "Platform Invoke Sample", 0);
Win32APIMmitSG.MessageBoxW(0, "Hallo von " + System.Runtime.InteropServices.RuntimeInformation.FrameworkDescription, "Platform Invoke Sample", 0);
Console.WriteLine("ShellAbout...");
Win32APIohneSG.ShellAbout(Process.GetCurrentProcess().MainWindowHandle, "AppName " + Assembly.GetExecutingAssembly()!.GetName()!.Version!.ToString(), "", IntPtr.Zero);
Win32APIMmitSG.ShellAboutW(Process.GetCurrentProcess().MainWindowHandle, "AppName " + Assembly.GetExecutingAssembly()!.GetName()!.Version!.ToString(), "", IntPtr.Zero);
Details zu diesem Source-Generator, insbesondere zur Umwandlung bestehender [DllImport]
-Annotationen, finden sich in der Dokumentation.
(map)