unoplatform/uno · critical · InvalidOperationException
PInvoke.RegisterClassEx failed: {Win32Helper.GetErrorMessage
Error message
PInvoke.RegisterClassEx failed: {Win32Helper.GetErrorMessage()} What it means
InvalidOperationException thrown in the static constructor of Win32MediaPlayerPresenterExtension when the Win32 RegisterClassEx call returns a 0 atom, meaning the window class 'UnoPlatformVLCWindow' could not be registered. This class is needed to host the LibVLC media player surface on the Skia/Win32 desktop target. A static-constructor failure type-initializes the extension and prevents any media player window from being created.
Source
Thrown at src/AddIns/Uno.UI.MediaPlayer.Skia.Win32/Win32MediaPlayerPresenterExtension.cs:59
private readonly HWND _hwnd;
static unsafe Win32MediaPlayerPresenterExtension()
{
using var lpClassName = new Win32Helper.NativeNulTerminatedUtf16String(WindowClassName);
_windowClass = new WNDCLASSEXW
{
cbSize = (uint)Marshal.SizeOf<WNDCLASSEXW>(),
lpfnWndProc = &WndProc,
hInstance = Win32Helper.GetHInstance(),
lpszClassName = lpClassName,
style = WNDCLASS_STYLES.CS_HREDRAW | WNDCLASS_STYLES.CS_VREDRAW // https://learn.microsoft.com/en-us/windows/win32/winmsg/window-class-styles
};
var classAtom = PInvoke.RegisterClassEx(_windowClass);
if (classAtom is 0)
{
throw new InvalidOperationException($"{nameof(PInvoke.RegisterClassEx)} failed: {Win32Helper.GetErrorMessage()}");
}
}
public unsafe Win32MediaPlayerPresenterExtension(MediaPlayerPresenter presenter)
{
_presenter = presenter;
using var lpClassName = new Win32Helper.NativeNulTerminatedUtf16String(WindowClassName);
_extForNextCreateWindow = new WeakReference<Win32MediaPlayerPresenterExtension>(this);
_hwnd = PInvoke.CreateWindowEx(
0,
lpClassName,
new PCWSTR(),
0,
PInvoke.CW_USEDEFAULT,
PInvoke.CW_USEDEFAULT,
PInvoke.CW_USEDEFAULT,View on GitHub (pinned to 0418340488)
Solutions
- Read Win32Helper.GetErrorMessage() in the exception text — ERROR_CLASS_ALREADY_EXISTS (1410) means a duplicate registration; ensure only one Skia Win32 host registers the class.
- Confirm LibVLC native dependencies are present and the process has a usable window station/desktop.
- Avoid instantiating MediaPlayerPresenter in a non-interactive session (services, headless tests).
- If hosting multiple Skia windows in one process, verify the static class is initialized once (it is, by design — duplicate calls shouldn't happen, so a 1410 implies a different component already took the name).
- Update the Uno.UI.MediaPlayer.Skia.Win32 add-in; class-registration robustness has been improved across versions.
Example fix
// The class is registered once in a static ctor; you cannot easily change it.
// Guard usage: only create the presenter in an interactive desktop session.
if (OperatingSystem.IsWindows() && Environment.UserInteractive)
{
_presenter = new Win32MediaPlayerPresenterExtension(mediaPresenter);
} Defensive patterns
Strategy: validation
Validate before calling
// Only construct the Win32 media extension in an interactive Windows session
if (OperatingSystem.IsWindows() && Environment.UserInteractive && !System.Windows.Forms.SystemInformation.TerminalServerSession)
_presenter = new Win32MediaPlayerPresenterExtension(mediaPresenter); Type guard
bool CanHostWin32MediaPlayer()
=> OperatingSystem.IsWindows() && Environment.UserInteractive; Try / catch
try { _presenter = new Win32MediaPlayerPresenterExtension(mediaPresenter); }
catch (InvalidOperationException ex) when (ex.Message.Contains("RegisterClassEx"))
{ Log.Error($"Win32 window class registration failed: {ex.Message}"); } Prevention
- Run the Skia Win32 host in an interactive desktop session only.
- Ensure only one host registers the 'UnoPlatformVLCWindow' class per process.
- Keep LibVLC native deps and Uno.UI.MediaPlayer.Skia.Win32 versions aligned.
When it happens
Trigger: Type initialization of Win32MediaPlayerPresenterExtension (first use of MediaPlayerPresenter on Skia.Win32) when RegisterClassEx fails: the class name already exists (duplicate registration), hInstance is wrong, or the lpfnWndProc delegate was collected. Because _windowClass is static and holds the WndProc function pointer, GC collection of the delegate is mitigated, but a duplicate class name across processes/instances or a corrupt process state can still return 0.
Common situations: Running two Uno hosts in the same process that both register 'UnoPlatformVLCWindow'; a LibVLC initialization ordering issue; running under a constrained session (e.g. service/session-0) where window class registration is blocked; DLL/HINSTANCE corruption. The formatted Win32Helper.GetErrorMessage() reveals the OS reason (e.g. ERROR_CLASS_ALREADY_EXISTS).
Related errors
- PInvoke.CreateWindowEx failed: {Win32Helper.GetErrorMessage(
- XLIB ERROR: Cannot connect to X server
- MediaPlayerPresenterExtension must be initialized with a Med
- Playlist Items could not be set
- Unsupported media source type
AI-assisted analysis of unoplatform/uno@0418340488 (2026-08-13).
Data as JSON: /api/errors/c6d3fe7be3311ea6.
Report an issue: GitHub.