diff --git a/src/System.Windows.Forms.Primitives/src/Interop/Hhctrl/Interop.HH.cs b/src/System.Windows.Forms.Primitives/src/Interop/Hhctrl/Interop.HH.cs new file mode 100644 index 00000000000..d4cf871dcaf --- /dev/null +++ b/src/System.Windows.Forms.Primitives/src/Interop/Hhctrl/Interop.HH.cs @@ -0,0 +1,44 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. + +internal partial class Interop +{ + internal static partial class Hhctl + { + public enum HH : uint + { + DISPLAY_TOPIC = 0x00, + HELP_FINDER = 0x00, + DISPLAY_TOC = 0x01, + DISPLAY_INDEX = 0x02, + DISPLAY_SEARCH = 0x03, + SET_WIN_TYPE = 0x04, + GET_WIN_TYPE = 0x05, + GET_WIN_HANDLE = 0x06, + ENUM_INFO_TYPE = 0x07, + SET_INFO_TYPE = 0x08, + SYNC = 0x09, + RESERVED1 = 0x0A, + RESERVED2 = 0x0B, + RESERVED3 = 0x0C, + KEYWORD_LOOKUP = 0x0D, + DISPLAY_TEXT_POPUP = 0x0E, + HELP_CONTEXT = 0x0F, + TP_HELP_CONTEXTMENU = 0x10, + TP_HELP_WM_HELP = 0x11, + CLOSE_ALL = 0x12, + ALINK_LOOKUP = 0x13, + GET_LAST_ERROR = 0x14, + ENUM_CATEGORY = 0x15, + ENUM_CATEGORY_IT = 0x16, + RESET_IT_FILTER = 0x17, + SET_INCLUSIVE_FILTER = 0x18, + SET_EXCLUSIVE_FILTER = 0x19, + INITIALIZE = 0x1C, + UNINITIALIZE = 0x1D, + SAFE_DISPLAY_TOPIC = 0x20, + PRETRANSLATEMESSAGE = 0xFD, + SET_GLOBAL_PROPERTY = 0xFC + } + } +} diff --git a/src/System.Windows.Forms.Primitives/src/Interop/Hhctrl/Interop.HH_ALINKW.cs b/src/System.Windows.Forms.Primitives/src/Interop/Hhctrl/Interop.HH_ALINKW.cs new file mode 100644 index 00000000000..5f025ad4ff8 --- /dev/null +++ b/src/System.Windows.Forms.Primitives/src/Interop/Hhctrl/Interop.HH_ALINKW.cs @@ -0,0 +1,20 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. + +internal partial class Interop +{ + internal static partial class Hhctl + { + public unsafe struct HH_ALINKW + { + public int cbStruct; + public BOOL fReserved; + public char* pszKeywords; + public char* pszUrl; + public char* pszMsgText; + public char* pszMsgTitle; + public char* pszWindow; + public BOOL fIndexOnFail; + } + } +} diff --git a/src/System.Windows.Forms.Primitives/src/Interop/Hhctrl/Interop.HH_FTS_QUERYW.cs b/src/System.Windows.Forms.Primitives/src/Interop/Hhctrl/Interop.HH_FTS_QUERYW.cs new file mode 100644 index 00000000000..47d7a332b1f --- /dev/null +++ b/src/System.Windows.Forms.Primitives/src/Interop/Hhctrl/Interop.HH_FTS_QUERYW.cs @@ -0,0 +1,22 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. + +internal partial class Interop +{ + internal static partial class Hhctl + { + public unsafe struct HH_FTS_QUERYW + { + public const int DEFAULT_PROXIMITY = -1; + + public int cbStruct; + public BOOL fUniCodeStrings; + public char* pszSearchQuery; + public int iProximity; + public BOOL fStemmedSearch; + public BOOL fTitleOnly; + public BOOL fExecute; + public char* pszWindow; + } + } +} diff --git a/src/System.Windows.Forms.Primitives/src/Interop/Hhctrl/Interop.HH_POPUPW.cs b/src/System.Windows.Forms.Primitives/src/Interop/Hhctrl/Interop.HH_POPUPW.cs new file mode 100644 index 00000000000..193af309ff6 --- /dev/null +++ b/src/System.Windows.Forms.Primitives/src/Interop/Hhctrl/Interop.HH_POPUPW.cs @@ -0,0 +1,23 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. + +using System.Drawing; + +internal partial class Interop +{ + internal static partial class Hhctl + { + public unsafe struct HH_POPUPW + { + public int cbStruct; + public IntPtr hinst; + public uint idString; + public char* pszText; + public Point pt; + public COLORREF clrForeground; + public COLORREF clrBackground; + public RECT rcMargins; + public char* pszFont; + } + } +} diff --git a/src/System.Windows.Forms.Primitives/src/Interop/Hhctrl/Interop.HtmlHelpW.cs b/src/System.Windows.Forms.Primitives/src/Interop/Hhctrl/Interop.HtmlHelpW.cs new file mode 100644 index 00000000000..8ef7e2fcf37 --- /dev/null +++ b/src/System.Windows.Forms.Primitives/src/Interop/Hhctrl/Interop.HtmlHelpW.cs @@ -0,0 +1,36 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. + +using System.Runtime.InteropServices; + +internal partial class Interop +{ + internal static partial class Hhctl + { + [DllImport(Libraries.Hhctrl, CharSet = CharSet.Unicode, ExactSpelling = true)] + public static extern int HtmlHelpW(IntPtr hwndCaller, string? pszFile, HH uCommand, IntPtr dwData); + + public static int HtmlHelpW(HandleRef hwndCaller, string? pszFile, HH uCommand, IntPtr dwData) + { + int result = HtmlHelpW(hwndCaller.Handle, pszFile, uCommand, dwData); + GC.KeepAlive(hwndCaller.Wrapper); + return result; + } + + public static unsafe int HtmlHelpW(HandleRef hwndCaller, string? pszFile, HH uCommand, string data) + { + fixed (char* dwData = data) + { + return HtmlHelpW(hwndCaller, pszFile, uCommand, (IntPtr)(void*)dwData); + } + } + + public static unsafe int HtmlHelpW(HandleRef hwndCaller, string? pszFile, HH uCommand, ref T data) where T : unmanaged + { + fixed (void* dwData = &data) + { + return HtmlHelpW(hwndCaller, pszFile, uCommand, (IntPtr)dwData); + } + } + } +} diff --git a/src/System.Windows.Forms.Primitives/src/NativeMethods.txt b/src/System.Windows.Forms.Primitives/src/NativeMethods.txt index bd2af7c7c26..48fdc6e09d6 100644 --- a/src/System.Windows.Forms.Primitives/src/NativeMethods.txt +++ b/src/System.Windows.Forms.Primitives/src/NativeMethods.txt @@ -346,11 +346,6 @@ HIGHCONTRASTW HitTestThemeBackground HT* HTREEITEM -HTML_HELP_COMMAND -HtmlHelpW -HH_AKLINK -HH_FTS_QUERY -HH_POPUP HWND_* IAccessible IAutoComplete2 diff --git a/src/System.Windows.Forms.Primitives/src/Windows/Win32/PInvoke.HtmlHelp.cs b/src/System.Windows.Forms.Primitives/src/Windows/Win32/PInvoke.HtmlHelp.cs deleted file mode 100644 index 618bdac7d71..00000000000 --- a/src/System.Windows.Forms.Primitives/src/Windows/Win32/PInvoke.HtmlHelp.cs +++ /dev/null @@ -1,25 +0,0 @@ -// Licensed to the .NET Foundation under one or more agreements. -// The .NET Foundation licenses this file to you under the MIT license. - -using Windows.Win32.Data.HtmlHelp; - -namespace Windows.Win32 -{ - internal static partial class PInvoke - { - public static HWND HtmlHelp(HandleRef hwndCaller, string? pszFile, HTML_HELP_COMMAND uCommand, nuint dwData) - { - HWND result = HtmlHelp(hwndCaller.Handle, pszFile, uCommand, dwData); - GC.KeepAlive(hwndCaller.Wrapper); - return result; - } - - public static unsafe HWND HtmlHelp(HandleRef hwndCaller, string? pszFile, HTML_HELP_COMMAND uCommand, string data) - { - fixed (char* dwData = data) - { - return HtmlHelp(hwndCaller, pszFile, uCommand, (nuint)dwData); - } - } - } -} diff --git a/src/System.Windows.Forms/src/System/Windows/Forms/Help/Help.cs b/src/System.Windows.Forms/src/System/Windows/Forms/Help/Help.cs index 78d2993a730..e71728b267a 100644 --- a/src/System.Windows.Forms/src/System/Windows/Forms/Help/Help.cs +++ b/src/System.Windows.Forms/src/System/Windows/Forms/Help/Help.cs @@ -3,7 +3,7 @@ using System.Drawing; using System.Globalization; -using Windows.Win32.Data.HtmlHelp; +using static Interop.Hhctl; namespace System.Windows.Forms; @@ -95,9 +95,9 @@ public static unsafe void ShowPopup(Control? parent, string caption, Point locat { s_windowsFormsHelpTrace.TraceVerbose("Help:: ShowPopup"); - HH_POPUP pop = new() + HH_POPUPW pop = new() { - cbStruct = sizeof(HH_POPUP), + cbStruct = sizeof(HH_POPUPW), pt = location, rcMargins = new RECT(-1, -1, -1, -1), // Ignore clrForeground = new COLORREF(unchecked((uint)-1)), // Ignore @@ -109,8 +109,8 @@ public static unsafe void ShowPopup(Control? parent, string caption, Point locat fixed (char* pszText = caption, pszFont = captionFont) { - pop.pszText = (sbyte*)pszText; - pop.pszFont = (sbyte*)pszFont; + pop.pszText = pszText; + pop.pszFont = pszFont; ShowHTML10Help(parent, null, HelpNavigator.Topic, pop); } } @@ -160,51 +160,48 @@ private static unsafe void ShowHTML10Help(Control? parent, string? url, HelpNavi object? htmlParam; if (param is string stringParam) { - HTML_HELP_COMMAND htmlCommand = MapCommandToHTMLCommand(command, stringParam, out htmlParam); + HH htmlCommand = MapCommandToHTMLCommand(command, stringParam, out htmlParam); if (htmlParam is string stringHtmlParam) { - PInvoke.HtmlHelp(handle, pathAndFileName, htmlCommand, stringHtmlParam); + HtmlHelpW(handle, pathAndFileName, htmlCommand, stringHtmlParam); } else if (htmlParam is int intParam) { - PInvoke.HtmlHelp(handle, pathAndFileName, htmlCommand, (nuint)intParam); + HtmlHelpW(handle, pathAndFileName, htmlCommand, intParam); } - else if (htmlParam is HH_FTS_QUERY query) + else if (htmlParam is HH_FTS_QUERYW query) { - HH_FTS_QUERY* dwData = &query; fixed (char* pszSearchQuery = stringParam) { - query.pszSearchQuery = (sbyte*)pszSearchQuery; - PInvoke.HtmlHelp(handle, pathAndFileName, htmlCommand, (nuint)dwData); + query.pszSearchQuery = pszSearchQuery; + HtmlHelpW(handle, pathAndFileName, htmlCommand, ref query); } } - else if (htmlParam is HH_AKLINK aLink) + else if (htmlParam is HH_ALINKW aLink) { // According to MSDN documentation, we have to ensure that the help window is up // before we call ALINK lookup. - PInvoke.HtmlHelp(HWND.Null, pathAndFileName, HTML_HELP_COMMAND.HH_DISPLAY_TOPIC, nuint.Zero); + HtmlHelpW(IntPtr.Zero, pathAndFileName, HH.DISPLAY_TOPIC, IntPtr.Zero); - HH_AKLINK* dwData = &aLink; fixed (char* pszKeywords = stringParam) { - aLink.pszKeywords = (sbyte*)pszKeywords; - PInvoke.HtmlHelp(handle, pathAndFileName, htmlCommand, (nuint)dwData); + aLink.pszKeywords = pszKeywords; + HtmlHelpW(handle, pathAndFileName, htmlCommand, ref aLink); } } else { Debug.Fail($"Cannot handle HTML parameter of type: {htmlParam!.GetType()}"); - PInvoke.HtmlHelp(handle, pathAndFileName, htmlCommand, (string)param); + HtmlHelpW(handle, pathAndFileName, htmlCommand, (string)param); } } else if (param is null) { - PInvoke.HtmlHelp(handle, pathAndFileName, MapCommandToHTMLCommand(command, null, out htmlParam), nuint.Zero); + HtmlHelpW(handle, pathAndFileName, MapCommandToHTMLCommand(command, null, out htmlParam), IntPtr.Zero); } - else if (param is HH_POPUP popup) + else if (param is HH_POPUPW popup) { - HH_POPUP* dwData = &popup; - PInvoke.HtmlHelp(handle, pathAndFileName, HTML_HELP_COMMAND.HH_DISPLAY_TEXT_POPUP, (nuint)dwData); + HtmlHelpW(handle, pathAndFileName, HH.DISPLAY_TEXT_POPUP, ref popup); } else if (param.GetType() == typeof(int)) { @@ -353,37 +350,37 @@ private static int GetHelpFileType(string? url) /// /// Maps one of the COMMAND_* constants to the HTML 1.0 Help equivalent. /// - private static unsafe HTML_HELP_COMMAND MapCommandToHTMLCommand(HelpNavigator command, string? param, out object? htmlParam) + private static unsafe HH MapCommandToHTMLCommand(HelpNavigator command, string? param, out object? htmlParam) { htmlParam = param; if (string.IsNullOrEmpty(param) && (command == HelpNavigator.AssociateIndex || command == HelpNavigator.KeywordIndex)) { - return HTML_HELP_COMMAND.HH_DISPLAY_INDEX; + return HH.DISPLAY_INDEX; } switch (command) { case HelpNavigator.Topic: - return HTML_HELP_COMMAND.HH_DISPLAY_TOPIC; + return HH.DISPLAY_TOPIC; case HelpNavigator.TableOfContents: - return HTML_HELP_COMMAND.HH_DISPLAY_TOC; + return HH.DISPLAY_TOC; case HelpNavigator.Index: - return HTML_HELP_COMMAND.HH_DISPLAY_INDEX; + return HH.DISPLAY_INDEX; case HelpNavigator.Find: { - HH_FTS_QUERY ftsQuery = new() + HH_FTS_QUERYW ftsQuery = new() { - cbStruct = sizeof(HH_FTS_QUERY), - iProximity = (int)HTML_HELP_COMMAND.HH_FTS_DEFAULT_PROXIMITY, + cbStruct = sizeof(HH_FTS_QUERYW), + iProximity = HH_FTS_QUERYW.DEFAULT_PROXIMITY, fExecute = true, fUniCodeStrings = true }; htmlParam = ftsQuery; - return HTML_HELP_COMMAND.HH_DISPLAY_SEARCH; + return HH.DISPLAY_SEARCH; } case HelpNavigator.TopicId: @@ -391,28 +388,28 @@ private static unsafe HTML_HELP_COMMAND MapCommandToHTMLCommand(HelpNavigator co if (int.TryParse(param, out int htmlParamAsInt)) { htmlParam = htmlParamAsInt; - return HTML_HELP_COMMAND.HH_HELP_CONTEXT; + return HH.HELP_CONTEXT; } // default to just showing the index - return HTML_HELP_COMMAND.HH_DISPLAY_INDEX; + return HH.DISPLAY_INDEX; } case HelpNavigator.KeywordIndex: case HelpNavigator.AssociateIndex: { - HH_AKLINK alink = new() + HH_ALINKW alink = new() { - cbStruct = sizeof(HH_AKLINK), + cbStruct = sizeof(HH_ALINKW), fIndexOnFail = true, fReserved = false }; htmlParam = alink; - return command == HelpNavigator.KeywordIndex ? HTML_HELP_COMMAND.HH_KEYWORD_LOOKUP : HTML_HELP_COMMAND.HH_ALINK_LOOKUP; + return command == HelpNavigator.KeywordIndex ? HH.KEYWORD_LOOKUP : HH.ALINK_LOOKUP; } default: - return (HTML_HELP_COMMAND)command; + return (HH)command; } } } diff --git a/src/System.Windows.Forms/tests/UnitTests/System/Windows/Forms/Help/HelpTests.cs b/src/System.Windows.Forms/tests/UnitTests/System/Windows/Forms/Help/HelpTests.cs new file mode 100644 index 00000000000..f9eaad96095 --- /dev/null +++ b/src/System.Windows.Forms/tests/UnitTests/System/Windows/Forms/Help/HelpTests.cs @@ -0,0 +1,15 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. + +using System.Drawing; + +namespace System.Windows.Forms.Tests; + +public class HelpTests +{ + [Fact] + public void ShowPopupTest() + { + Help.ShowPopup(null, "Popup", Point.Empty); + } +}