Upload via GUI (37 Dateien)
This commit is contained in:
31
webview2/MyStart.csproj
Normal file
31
webview2/MyStart.csproj
Normal file
@@ -0,0 +1,31 @@
|
||||
<Project Sdk="Microsoft.NET.Sdk">
|
||||
|
||||
<PropertyGroup>
|
||||
<OutputType>WinExe</OutputType>
|
||||
<TargetFramework>net10.0-windows</TargetFramework>
|
||||
<UseWindowsForms>true</UseWindowsForms>
|
||||
<Nullable>enable</Nullable>
|
||||
<ImplicitUsings>enable</ImplicitUsings>
|
||||
<AssemblyName>MyStart</AssemblyName>
|
||||
<RootNamespace>MyStart</RootNamespace>
|
||||
<ApplicationIcon>app.ico</ApplicationIcon>
|
||||
<RuntimeIdentifier>win-x64</RuntimeIdentifier>
|
||||
<PublishSingleFile>true</PublishSingleFile>
|
||||
<SelfContained>true</SelfContained>
|
||||
<IncludeNativeLibrariesForSelfExtract>true</IncludeNativeLibrariesForSelfExtract>
|
||||
<EnableCompressionInSingleFile>true</EnableCompressionInSingleFile>
|
||||
<DebugType>none</DebugType>
|
||||
<DebugSymbols>false</DebugSymbols>
|
||||
<SatelliteResourceLanguages>en</SatelliteResourceLanguages>
|
||||
</PropertyGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<PackageReference Include="Microsoft.Web.WebView2" Version="1.0.3485.44" />
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<EmbeddedResource Include="app-index.html" />
|
||||
<EmbeddedResource Include="app.ico" />
|
||||
</ItemGroup>
|
||||
|
||||
</Project>
|
||||
239
webview2/Program.cs
Normal file
239
webview2/Program.cs
Normal file
@@ -0,0 +1,239 @@
|
||||
using System.Reflection;
|
||||
using System.Text.Json;
|
||||
using Microsoft.Win32;
|
||||
using Microsoft.Web.WebView2.Core;
|
||||
using Microsoft.Web.WebView2.WinForms;
|
||||
|
||||
namespace MyStart;
|
||||
|
||||
static class Program
|
||||
{
|
||||
[STAThread]
|
||||
static void Main(string[] args)
|
||||
{
|
||||
Application.EnableVisualStyles();
|
||||
Application.SetCompatibleTextRenderingDefault(false);
|
||||
Application.SetHighDpiMode(HighDpiMode.PerMonitorV2);
|
||||
bool minimized = args.Any(a =>
|
||||
a.Equals("--minimized", StringComparison.OrdinalIgnoreCase) ||
|
||||
a.Equals("--min", StringComparison.OrdinalIgnoreCase) ||
|
||||
a.Equals("--autostart", StringComparison.OrdinalIgnoreCase));
|
||||
Application.Run(new MainForm(minimized));
|
||||
}
|
||||
}
|
||||
|
||||
class MainForm : Form
|
||||
{
|
||||
private readonly WebView2 _web = new() { Dock = DockStyle.Fill };
|
||||
private const string Host = "mystart.local";
|
||||
private bool _pendingMaximize;
|
||||
|
||||
public MainForm(bool startMinimized = false)
|
||||
{
|
||||
Text = "MyStart";
|
||||
StartPosition = FormStartPosition.CenterScreen;
|
||||
Width = 1280;
|
||||
Height = 800;
|
||||
ShowInTaskbar = true;
|
||||
BackColor = System.Drawing.Color.Black;
|
||||
// No title bar / border. Close with Alt+F4, minimize via the taskbar button.
|
||||
FormBorderStyle = FormBorderStyle.None;
|
||||
|
||||
if (startMinimized)
|
||||
{
|
||||
// Autostart: sit minimized on the taskbar; maximize on first open.
|
||||
WindowState = FormWindowState.Minimized;
|
||||
_pendingMaximize = true;
|
||||
Resize += (_, _) =>
|
||||
{
|
||||
if (_pendingMaximize && WindowState != FormWindowState.Minimized)
|
||||
{
|
||||
_pendingMaximize = false;
|
||||
WindowState = FormWindowState.Maximized;
|
||||
}
|
||||
};
|
||||
}
|
||||
else
|
||||
{
|
||||
WindowState = FormWindowState.Maximized;
|
||||
}
|
||||
|
||||
try
|
||||
{
|
||||
var asm = Assembly.GetExecutingAssembly();
|
||||
var icoName = asm.GetManifestResourceNames()
|
||||
.FirstOrDefault(n => n.EndsWith("app.ico", StringComparison.OrdinalIgnoreCase));
|
||||
if (icoName != null)
|
||||
{
|
||||
using var s = asm.GetManifestResourceStream(icoName);
|
||||
if (s != null) Icon = new Icon(s);
|
||||
}
|
||||
}
|
||||
catch { /* icon optional */ }
|
||||
|
||||
Controls.Add(_web);
|
||||
Shown += async (_, _) => await InitAsync();
|
||||
}
|
||||
|
||||
// Keep a borderless maximized window from covering the taskbar.
|
||||
protected override void OnHandleCreated(EventArgs e)
|
||||
{
|
||||
base.OnHandleCreated(e);
|
||||
MaximizedBounds = Screen.FromHandle(Handle).WorkingArea;
|
||||
}
|
||||
|
||||
private async Task InitAsync()
|
||||
{
|
||||
// Persistent data dir -> localStorage (settings/bookmarks) survive across runs
|
||||
// and independent of where the .exe lives.
|
||||
string dataDir = Path.Combine(
|
||||
Environment.GetFolderPath(Environment.SpecialFolder.LocalApplicationData),
|
||||
"MyStart");
|
||||
Directory.CreateDirectory(dataDir);
|
||||
|
||||
var env = await CoreWebView2Environment.CreateAsync(null, dataDir);
|
||||
await _web.EnsureCoreWebView2Async(env);
|
||||
|
||||
// Extract the embedded app to a fixed folder, served via a stable origin.
|
||||
string appDir = Path.Combine(dataDir, "app");
|
||||
Directory.CreateDirectory(appDir);
|
||||
string htmlPath = Path.Combine(appDir, "index.html");
|
||||
var asm = Assembly.GetExecutingAssembly();
|
||||
string resName = asm.GetManifestResourceNames()
|
||||
.First(n => n.EndsWith("app-index.html", StringComparison.OrdinalIgnoreCase));
|
||||
await using (var res = asm.GetManifestResourceStream(resName)!)
|
||||
await using (var file = File.Create(htmlPath))
|
||||
await res.CopyToAsync(file);
|
||||
|
||||
var core = _web.CoreWebView2;
|
||||
core.SetVirtualHostNameToFolderMapping(Host, appDir, CoreWebView2HostResourceAccessKind.Allow);
|
||||
core.Settings.IsStatusBarEnabled = false;
|
||||
core.Settings.AreDefaultContextMenusEnabled = true;
|
||||
core.Settings.IsWebMessageEnabled = true;
|
||||
|
||||
// Autostart toggle from the in-app "MyStart" info page.
|
||||
core.WebMessageReceived += (_, e) =>
|
||||
{
|
||||
try
|
||||
{
|
||||
using var doc = JsonDocument.Parse(e.WebMessageAsJson);
|
||||
var root = doc.RootElement;
|
||||
if (!root.TryGetProperty("type", out var t)) return;
|
||||
switch (t.GetString())
|
||||
{
|
||||
case "autostart-get":
|
||||
PostAutostartState();
|
||||
break;
|
||||
case "autostart-set":
|
||||
bool on = root.TryGetProperty("value", out var v) &&
|
||||
v.ValueKind == JsonValueKind.True;
|
||||
SetAutostart(on);
|
||||
PostAutostartState();
|
||||
break;
|
||||
case "window-drag":
|
||||
StartWindowDrag();
|
||||
break;
|
||||
case "window-min":
|
||||
WindowState = FormWindowState.Minimized;
|
||||
break;
|
||||
case "window-max":
|
||||
WindowState = WindowState == FormWindowState.Maximized
|
||||
? FormWindowState.Normal : FormWindowState.Maximized;
|
||||
break;
|
||||
case "window-close":
|
||||
Close();
|
||||
break;
|
||||
}
|
||||
}
|
||||
catch { /* ignore malformed messages */ }
|
||||
};
|
||||
|
||||
// Bookmark links that open a new window -> user's default browser.
|
||||
core.NewWindowRequested += (_, e) =>
|
||||
{
|
||||
e.Handled = true;
|
||||
OpenExternal(e.Uri);
|
||||
};
|
||||
|
||||
// Same-tab clicks to external sites -> default browser, keep the app loaded.
|
||||
core.NavigationStarting += (_, e) =>
|
||||
{
|
||||
var uri = e.Uri ?? string.Empty;
|
||||
if (uri.StartsWith("https://" + Host, StringComparison.OrdinalIgnoreCase)) return; // internal
|
||||
if (uri.StartsWith("http://", StringComparison.OrdinalIgnoreCase) ||
|
||||
uri.StartsWith("https://", StringComparison.OrdinalIgnoreCase))
|
||||
{
|
||||
e.Cancel = true;
|
||||
OpenExternal(uri);
|
||||
}
|
||||
};
|
||||
|
||||
core.Navigate("https://" + Host + "/index.html");
|
||||
}
|
||||
|
||||
// --- Autostart (per-user HKCU Run key, points at THIS exe with --minimized) ---
|
||||
private const string RunKeyPath = @"Software\Microsoft\Windows\CurrentVersion\Run";
|
||||
private const string RunValueName = "MyStart";
|
||||
private static string ExePath => Environment.ProcessPath ?? Application.ExecutablePath;
|
||||
|
||||
private static bool IsAutostartEnabled()
|
||||
{
|
||||
try
|
||||
{
|
||||
using var k = Registry.CurrentUser.OpenSubKey(RunKeyPath, false);
|
||||
return k?.GetValue(RunValueName) is string v && v.Length > 0;
|
||||
}
|
||||
catch { return false; }
|
||||
}
|
||||
|
||||
private static void SetAutostart(bool on)
|
||||
{
|
||||
try
|
||||
{
|
||||
using var k = Registry.CurrentUser.OpenSubKey(RunKeyPath, true)
|
||||
?? Registry.CurrentUser.CreateSubKey(RunKeyPath, true);
|
||||
if (k == null) return;
|
||||
if (on) k.SetValue(RunValueName, "\"" + ExePath + "\" --minimized");
|
||||
else if (k.GetValue(RunValueName) != null) k.DeleteValue(RunValueName, false);
|
||||
}
|
||||
catch { /* ignore */ }
|
||||
}
|
||||
|
||||
private void PostAutostartState()
|
||||
{
|
||||
var json = "{\"type\":\"autostart\",\"enabled\":" +
|
||||
(IsAutostartEnabled() ? "true" : "false") + "}";
|
||||
try { _web.CoreWebView2.PostWebMessageAsJson(json); } catch { }
|
||||
}
|
||||
|
||||
// --- Free window drag for the borderless window (page sends "window-drag"
|
||||
// on grip mousedown / Alt+drag; we hand off to the native move loop). ---
|
||||
[System.Runtime.InteropServices.DllImport("user32.dll")]
|
||||
private static extern bool ReleaseCapture();
|
||||
[System.Runtime.InteropServices.DllImport("user32.dll")]
|
||||
private static extern IntPtr SendMessage(IntPtr hWnd, int msg, IntPtr wParam, IntPtr lParam);
|
||||
private const int WM_NCLBUTTONDOWN = 0xA1;
|
||||
private const int HTCAPTION = 0x2;
|
||||
|
||||
private void StartWindowDrag()
|
||||
{
|
||||
// A maximized window can't be moved -> restore first, centred under cursor-ish.
|
||||
if (WindowState == FormWindowState.Maximized)
|
||||
WindowState = FormWindowState.Normal;
|
||||
ReleaseCapture();
|
||||
SendMessage(Handle, WM_NCLBUTTONDOWN, (IntPtr)HTCAPTION, IntPtr.Zero);
|
||||
}
|
||||
|
||||
private static void OpenExternal(string uri)
|
||||
{
|
||||
try
|
||||
{
|
||||
System.Diagnostics.Process.Start(new System.Diagnostics.ProcessStartInfo
|
||||
{
|
||||
FileName = uri,
|
||||
UseShellExecute = true
|
||||
});
|
||||
}
|
||||
catch { /* ignore */ }
|
||||
}
|
||||
}
|
||||
95
webview2/app-index.html
Normal file
95
webview2/app-index.html
Normal file
File diff suppressed because one or more lines are too long
BIN
webview2/app.ico
Normal file
BIN
webview2/app.ico
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 9.3 KiB |
BIN
webview2/build/icon.ico
Normal file
BIN
webview2/build/icon.ico
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 9.3 KiB |
Reference in New Issue
Block a user