diff --git a/common/src/workarounds/java/net/caffeinemc/mods/sodium/client/platform/MessageBox.java b/common/src/workarounds/java/net/caffeinemc/mods/sodium/client/platform/MessageBox.java index bf0cfb47cb..fe80d7a501 100644 --- a/common/src/workarounds/java/net/caffeinemc/mods/sodium/client/platform/MessageBox.java +++ b/common/src/workarounds/java/net/caffeinemc/mods/sodium/client/platform/MessageBox.java @@ -1,6 +1,7 @@ package net.caffeinemc.mods.sodium.client.platform; import net.caffeinemc.mods.sodium.client.compatibility.environment.OsUtils; +import net.caffeinemc.mods.sodium.client.platform.windows.api.Shell32; import net.caffeinemc.mods.sodium.client.platform.windows.api.User32; import net.caffeinemc.mods.sodium.client.platform.windows.api.msgbox.MsgBoxCallback; import net.caffeinemc.mods.sodium.client.platform.windows.api.msgbox.MsgBoxParamSw; @@ -58,11 +59,7 @@ public void showMessageBox(NativeWindowHandle window, if (helpUrl != null) { msgBoxCallback = MsgBoxCallback.create(lpHelpInfo -> { - try { - Desktop.getDesktop().browse(URI.create(helpUrl)); - } catch (IOException e) { - System.out.println("Failed to open! Giving up."); - } + Shell32.browseUrl(window, helpUrl); }); } else { msgBoxCallback = null; diff --git a/common/src/workarounds/java/net/caffeinemc/mods/sodium/client/platform/windows/api/Shell32.java b/common/src/workarounds/java/net/caffeinemc/mods/sodium/client/platform/windows/api/Shell32.java new file mode 100644 index 0000000000..5409b7fcea --- /dev/null +++ b/common/src/workarounds/java/net/caffeinemc/mods/sodium/client/platform/windows/api/Shell32.java @@ -0,0 +1,57 @@ +package net.caffeinemc.mods.sodium.client.platform.windows.api; + +import net.caffeinemc.mods.sodium.client.platform.NativeWindowHandle; +import org.jetbrains.annotations.Nullable; +import org.lwjgl.system.JNI; +import org.lwjgl.system.MemoryStack; +import org.lwjgl.system.SharedLibrary; + +import java.util.Objects; + +import static org.lwjgl.system.APIUtil.apiCreateLibrary; +import static org.lwjgl.system.APIUtil.apiGetFunctionAddressOptional; +import static org.lwjgl.system.MemoryUtil.NULL; + +public class Shell32 { + private static final SharedLibrary LIBRARY = apiCreateLibrary("shell32"); + + private static final long PFN_ShellExecuteW = apiGetFunctionAddressOptional(LIBRARY, "ShellExecuteW"); + + public static void browseUrl(@Nullable NativeWindowHandle window, String url) { + Objects.requireNonNull(url, "URL parameter must be non-null"); + + try (var stack = MemoryStack.stackPush()) { + stack.nUTF16("open", true); + var lpOperation = stack.getPointerAddress(); + + stack.nUTF16(url, true); + var lpFile = stack.getPointerAddress(); + + nShellExecuteW(window != null ? window.getWin32Handle() : NULL, + lpOperation, + lpFile, + NULL, + NULL, + 0x1 /* SW_NORMAL */); + } + } + + public static long nShellExecuteW( + /* HWND */ long hwnd, + /* LPCWSTR */ long lpOperation, + /* LPCWSTR */ long lpFile, + /* LPCWSTR */ long lpParameters, + /* LPCWSTR */ long lpDirectory, + /* INT */ int nShowCmd + ) { + return JNI.invokePPPPPP(hwnd, lpOperation, lpFile, lpParameters, lpDirectory, nShowCmd, checkPfn(PFN_ShellExecuteW)); + } + + private static long checkPfn(long pfn) { + if (pfn == NULL) { + throw new NullPointerException("Function pointer not available"); + } + + return pfn; + } +}