Last active
January 28, 2024 21:31
-
-
Save UweKeim/038cbcdc6299030eb672663d2169dfd4 to your computer and use it in GitHub Desktop.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
namespace ZetaProducer.RuntimeGui.ExtendedWebBrowser | |
{ | |
using JetBrains.Annotations; | |
using System; | |
using System.Collections.Generic; | |
using System.Linq; | |
using System.Text; | |
using System.Text.RegularExpressions; | |
using System.Windows.Forms; | |
using Zeta.VoyagerLibrary.Common.IO; | |
using ZetaLongPaths; | |
public static class HtmlClipboardHelper | |
{ | |
public static string GetClipboardHtmlText() | |
{ | |
if (Clipboard.ContainsText(TextDataFormat.Html)) | |
{ | |
getHtmlFromClipboard(out var htmlCode, out var originalBuffer); | |
if (string.IsNullOrEmpty(htmlCode)) return null; | |
//split Html to htmlInfo (and htmlSource) | |
var htmlInfo = htmlCode.Substring(0, htmlCode.IndexOf('<') - 1); | |
const string startFragmentText = @"StartFragment:"; | |
const string endFragmentText = @"EndFragment:"; | |
//get Fragment positions | |
var tmp = htmlInfo.Substring(htmlInfo.IndexOf(startFragmentText, StringComparison.Ordinal) + | |
startFragmentText.Length); | |
var ir = tmp.IndexOf('\r'); | |
if (ir < 0) return null; | |
tmp = tmp.Substring(0, ir); | |
var posStartSelection = Convert.ToInt32(tmp); | |
tmp = htmlInfo.Substring(htmlInfo.IndexOf(endFragmentText, StringComparison.Ordinal) + | |
endFragmentText.Length); | |
ir = tmp.IndexOf('\r'); | |
if (ir < 0) return null; | |
tmp = tmp.Substring(0, ir); | |
var posEndSelection = Convert.ToInt32(tmp); | |
// Get Fragment. Always UTF-8 as of spec. | |
return Encoding.UTF8.GetString( | |
originalBuffer, | |
posStartSelection, | |
posEndSelection - posStartSelection); | |
} | |
else if (Clipboard.ContainsText(TextDataFormat.Text) || | |
Clipboard.ContainsText(TextDataFormat.UnicodeText)) | |
{ | |
var text = Clipboard.GetText(); | |
// https://trello.com/c/2T5k5ivG | |
return ConvertPlainTextToHtml(text); | |
} | |
else | |
{ | |
return null; | |
} | |
} | |
public static string GetClipboardHtmlTextBody() | |
{ | |
var htmlCode = GetClipboardHtmlText(); | |
if (string.IsNullOrEmpty(htmlCode) || !htmlCode.ContainsNoCase(@"<body")) | |
{ | |
return htmlCode; | |
} | |
else | |
{ | |
// TODO (2014-12-18, Uwe Keim): Das hier war im Profiler BRECHEND langsam. | |
var regex = new Regex( | |
@".*?<body[^>]*>(.*?)</body>", | |
RegexOptions.Singleline | | |
RegexOptions.IgnoreCase); | |
var m = regex.Match(htmlCode); | |
if (m.Success) | |
{ | |
var groups = GetEffectiveMatchGroups(m); | |
return groups[1].Value; | |
} | |
else | |
{ | |
return htmlCode; | |
} | |
} | |
} | |
public static string GetClipboardHtmlTextComplete() | |
{ | |
if (Clipboard.ContainsText(TextDataFormat.Html)) | |
{ | |
getHtmlFromClipboard(out var htmlCode, out _); | |
return htmlCode; | |
} | |
else | |
{ | |
return null; | |
} | |
} | |
[UsedImplicitly] | |
public static string ConvertPlainTextToHtml(string text) | |
{ | |
if (string.IsNullOrWhiteSpace(text)) return text?.Trim(); | |
text = text.Trim(); | |
// Blanks aus komplett leeren Zeilen weg. | |
text = Regex.Replace(text, @"^\s+$", string.Empty, RegexOptions.Multiline); | |
text = text.Replace("\r\n", "\r"); | |
text = text.Replace("\n", "\r"); | |
text = text.Replace("\r", "\r\n"); | |
// Mehrfache Leerzeilen weg. | |
text = Regex.Replace(text, "\n{3,}", Environment.NewLine + Environment.NewLine); | |
text = PathHelper.HtmlEncode(text); | |
text = text.Replace("\r\n", "\r"); | |
text = text.Replace("\n", "\r"); | |
text = text.Replace("\r\r", @"</p><p>"); | |
text = text.Replace("\r", @"<br>"); | |
text = @"<p>" + text + @"</p>"; | |
return text; | |
} | |
internal static List<Group> GetEffectiveMatchGroups( | |
Match match) | |
{ | |
var result = new List<Group>(); | |
if (match != null && match.Success) | |
{ | |
result.AddRange(match.Groups.Cast<Group>().Where(group => group.Success)); | |
} | |
return result; | |
} | |
private static void getHtmlFromClipboard( | |
out string htmlCode, | |
out byte[] originalBuffer) | |
{ | |
htmlCode = HtmlClipboardHelperInternal.GetHTMLWin32Native(out originalBuffer); | |
} | |
} | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
namespace ZetaProducer.RuntimeGui.ExtendedWebBrowser | |
{ | |
using System; | |
using System.Runtime.InteropServices; | |
using System.Text; | |
/// <summary> | |
/// Von https://metadataconsulting.blogspot.com/2019/06/How-to-get-HTML-from-the-Windows-system-clipboard-directly-using-PInvoke-Win32-Native-methods-avoiding-bad-funny-characters.html | |
/// </summary> | |
internal static class HtmlClipboardHelperInternal | |
{ | |
#region Win32 Native PInvoke | |
[DllImport(@"User32.dll", SetLastError = true)] | |
[return: MarshalAs(UnmanagedType.Bool)] | |
private static extern bool IsClipboardFormatAvailable(uint format); | |
[DllImport(@"User32.dll", SetLastError = true)] | |
private static extern IntPtr GetClipboardData(uint uFormat); | |
[DllImport(@"User32.dll", SetLastError = true)] | |
[return: MarshalAs(UnmanagedType.Bool)] | |
private static extern bool OpenClipboard(IntPtr hWndNewOwner); | |
[DllImport(@"User32.dll", SetLastError = true)] | |
[return: MarshalAs(UnmanagedType.Bool)] | |
private static extern bool CloseClipboard(); | |
[DllImport(@"Kernel32.dll", SetLastError = true)] | |
private static extern IntPtr GlobalLock(IntPtr hMem); | |
[DllImport(@"Kernel32.dll", SetLastError = true)] | |
[return: MarshalAs(UnmanagedType.Bool)] | |
private static extern bool GlobalUnlock(IntPtr hMem); | |
[DllImport(@"Kernel32.dll", SetLastError = true)] | |
private static extern uint GlobalSize(IntPtr hMem); | |
[DllImport(@"user32.dll", SetLastError = true)] | |
private static extern uint RegisterClipboardFormatA(string lpszFormat); | |
#endregion | |
public static string GetHTMLWin32Native(out byte[] rawBytes) | |
{ | |
rawBytes = null; | |
var CF_HTML = RegisterClipboardFormatA(@"HTML Format"); | |
if (/*CF_HTML != null ||*/ CF_HTML == 0) | |
return null; | |
if (!IsClipboardFormatAvailable(CF_HTML)) | |
return null; | |
try | |
{ | |
if (!OpenClipboard(IntPtr.Zero)) return null; | |
var handle = GetClipboardData(CF_HTML); | |
if (handle == IntPtr.Zero) return null; | |
var pointer = IntPtr.Zero; | |
try | |
{ | |
pointer = GlobalLock(handle); | |
if (pointer == IntPtr.Zero) return null; | |
var size = GlobalSize(handle); | |
var buff = new byte[size]; | |
Marshal.Copy(pointer, buff, 0, (int)size); | |
rawBytes = buff; | |
return Encoding.UTF8.GetString(buff); | |
} | |
finally | |
{ | |
if (pointer != IntPtr.Zero) GlobalUnlock(handle); | |
} | |
} | |
finally | |
{ | |
CloseClipboard(); | |
} | |
} | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment