AcceptLoopAsync(_cts.Token));
+ return port;
+ }
+
+ public void Stop()
+ {
+ try { _cts?.Cancel(); } catch { }
+ try { _listener?.Stop(); } catch { }
+ }
+
+ private async Task AcceptLoopAsync(CancellationToken ct)
+ {
+ if (_listener == null) return;
+ while (!ct.IsCancellationRequested)
+ {
+ HttpListenerContext? ctx = null;
+ try { ctx = await _listener.GetContextAsync(); }
+ catch { if (ct.IsCancellationRequested) break; }
+ if (ctx == null) continue;
+ _ = Task.Run(() => HandleRequestAsync(ctx));
+ }
+ }
+
+ private async Task HandleRequestAsync(HttpListenerContext ctx)
+ {
+ try
+ {
+ var req = ctx.Request;
+ var relPath = req.Url?.AbsolutePath ?? "/";
+ relPath = WebUtility.UrlDecode(relPath).TrimStart('/');
+ if (string.IsNullOrEmpty(relPath)) relPath = "index.html";
+
+ // 防止越权访问
+ var fullPath = Path.GetFullPath(Path.Combine(_root, relPath.Replace('/', Path.DirectorySeparatorChar)));
+ if (!fullPath.StartsWith(Path.GetFullPath(_root), StringComparison.OrdinalIgnoreCase))
+ {
+ ctx.Response.StatusCode = 403;
+ ctx.Response.Close();
+ return;
+ }
+
+ if (!File.Exists(fullPath))
+ {
+ ctx.Response.StatusCode = 404;
+ ctx.Response.Close();
+ return;
+ }
+
+ var bytes = await File.ReadAllBytesAsync(fullPath);
+ ctx.Response.ContentType = GetContentType(fullPath);
+ ctx.Response.ContentLength64 = bytes.LongLength;
+ await ctx.Response.OutputStream.WriteAsync(bytes, 0, bytes.Length);
+ ctx.Response.OutputStream.Close();
+ }
+ catch
+ {
+ try { ctx.Response.StatusCode = 500; ctx.Response.Close(); } catch { }
+ }
+ }
+
+ private static string GetContentType(string path)
+ {
+ var ext = Path.GetExtension(path).ToLowerInvariant();
+ return ext switch
+ {
+ ".html" or ".htm" => "text/html; charset=utf-8",
+ ".js" => "application/javascript; charset=utf-8",
+ ".css" => "text/css; charset=utf-8",
+ ".json" => "application/json; charset=utf-8",
+ ".png" => "image/png",
+ ".jpg" or ".jpeg" => "image/jpeg",
+ ".gif" => "image/gif",
+ ".svg" => "image/svg+xml",
+ ".ico" => "image/x-icon",
+ ".txt" => "text/plain; charset=utf-8",
+ _ => "application/octet-stream"
+ };
+ }
+
+ private static int FindAvailablePort(int start)
+ {
+ for (var p = start; p < 65535; p++)
+ {
+ try
+ {
+ var l = new HttpListener();
+ l.Prefixes.Add($"http://127.0.0.1:" + p + "/");
+ l.Start();
+ l.Stop();
+ return p;
+ }
+ catch { /* try next */ }
+ }
+ throw new InvalidOperationException("无法找到可用的端口");
+ }
+ }
+}
\ No newline at end of file
diff --git a/README.md b/README.md
new file mode 100644
index 0000000..be1f9a6
--- /dev/null
+++ b/README.md
@@ -0,0 +1,183 @@
+# WebToApp
+
+一个基于 WPF 和 WebView2 的网页转桌面应用工具,可以将在线网页或本地网页打包成 Windows 桌面应用程序。
+
+## 功能特性
+
+- 🌐 **支持在线网页**:直接加载远程网页地址
+- 📁 **支持本地网页**:支持本地 HTML 文件,可通过 HTTP 服务器或直接文件方式加载
+- 🎨 **自定义窗口设置**:可配置窗口大小、置顶、全屏等属性
+- 🖱️ **自定义右键菜单**:提供返回、刷新、关于等快捷操作
+- 📥 **下载拦截**:智能拦截下载链接,使用系统保存对话框
+- 🎯 **滚动条隐藏**:可隐藏网页滚动条,提供更沉浸的体验
+- 🖼️ **自定义图标和标题**:支持自定义应用图标和窗口标题
+
+## 技术栈
+
+- **.NET 8.0** - 跨平台开发框架
+- **WPF** - Windows Presentation Foundation
+- **WebView2** - 基于 Chromium 的 WebView 控件
+
+## 系统要求
+
+- Windows 10/11
+- .NET 8.0 Runtime(如果使用独立部署则不需要)
+- WebView2 Runtime(通常已预装或会自动下载)
+
+## 快速开始
+
+### 1. 克隆项目
+
+```bash
+git clone https://github.com/yourusername/WebToApp.git
+cd WebToApp
+```
+
+### 2. 配置应用
+
+编辑 `config/config.json` 文件来配置你的应用:
+
+#### 在线网页配置示例
+
+```json
+{
+ "软件名称": "我的应用",
+ "软件logo": "config/logo.png",
+ "网页类型": "在线网页",
+ "在线网页": {
+ "链接地址": "https://example.com"
+ },
+ "注入设置": {
+ "隐藏网页滚动条": true,
+ "自定义右键菜单": true,
+ "拦截下载链接": true
+ },
+ "窗口设置": {
+ "窗口宽度": 1200,
+ "窗口高度": 800,
+ "窗口可调整大小": true,
+ "窗口置顶": false,
+ "窗口阴影": true,
+ "全屏": false
+ }
+}
+```
+
+#### 本地网页配置示例
+
+```json
+{
+ "软件名称": "我的应用",
+ "软件logo": "config/logo.png",
+ "网页类型": "本地网页",
+ "本地网页": {
+ "网页目录": "config/web",
+ "网页入口": "index.html",
+ "展示模式": "http服务器"
+ },
+ "注入设置": {
+ "隐藏网页滚动条": true,
+ "自定义右键菜单": true,
+ "拦截下载链接": true
+ },
+ "窗口设置": {
+ "窗口宽度": 1200,
+ "窗口高度": 800,
+ "窗口可调整大小": true,
+ "窗口置顶": false,
+ "窗口阴影": true,
+ "全屏": false
+ }
+}
+```
+
+### 3. 构建项目
+
+使用 Visual Studio 或命令行构建:
+
+```bash
+dotnet build
+```
+
+### 4. 运行应用
+
+```bash
+dotnet run
+```
+
+或者直接运行编译后的可执行文件。
+
+### 5. 发布应用
+
+发布为独立可执行文件:
+
+```bash
+dotnet publish -c Release -r win-x64 --self-contained true
+```
+
+发布后的文件在 `bin/Release/net8.0-windows/win-x64/publish/` 目录下。
+
+## 配置说明
+
+### 窗口设置
+
+- `窗口宽度` / `窗口高度`:设置窗口的初始大小(像素)
+- `窗口可调整大小`:是否允许用户调整窗口大小
+- `窗口置顶`:窗口是否始终显示在其他窗口之上
+- `窗口阴影`:是否显示窗口阴影效果
+- `全屏`:是否以全屏模式启动
+
+### 注入设置
+
+- `隐藏网页滚动条`:隐藏网页内的滚动条
+- `自定义右键菜单`:启用自定义右键菜单(包含返回、刷新、关于等功能)
+- `拦截下载链接`:拦截网页中的下载链接,使用系统保存对话框
+
+### 本地网页展示模式
+
+- `http服务器`:使用内置 HTTP 服务器提供网页服务(推荐)
+- `直接本地`:直接使用 `file://` 协议加载本地文件
+
+## 项目结构
+
+```
+WebToApp/
+├── config/ # 配置文件目录
+│ ├── config.json # 主配置文件
+│ ├── logo.png # 应用图标
+│ └── aboutpage/ # 关于页面
+│ └── about.html
+├── MainWindow.xaml # 主窗口 XAML
+├── MainWindow.xaml.cs # 主窗口代码
+├── App.xaml # 应用程序 XAML
+├── App.xaml.cs # 应用程序代码
+└── WebToApp.csproj # 项目文件
+```
+
+## 开发
+
+### 环境要求
+
+- Visual Studio 2022 或更高版本
+- .NET 8.0 SDK
+
+### 依赖项
+
+- Microsoft.Web.WebView2 (1.0.3595.46)
+
+## 许可证
+
+本项目采用 MIT 许可证。
+
+## 贡献
+
+欢迎提交 Issue 和 Pull Request!
+
+## 作者
+
+[你的名字]
+
+---
+
+如果这个项目对你有帮助,请给个 ⭐ Star 支持一下!
+
diff --git a/WebToApp.csproj b/WebToApp.csproj
new file mode 100644
index 0000000..4df0708
--- /dev/null
+++ b/WebToApp.csproj
@@ -0,0 +1,45 @@
+
+
+
+ WinExe
+ net8.0-windows
+ enable
+ enable
+ true
+
+
+
+
+
+ win-x64
+
+
+ false
+
+
+ false
+
+
+ true
+
+
+ none
+ false
+ false
+
+
+ false
+
+
+
+
+
+
+
+
+
+ PreserveNewest
+
+
+
+
diff --git a/WebToApp.sln b/WebToApp.sln
new file mode 100644
index 0000000..58d84fd
--- /dev/null
+++ b/WebToApp.sln
@@ -0,0 +1,22 @@
+
+Microsoft Visual Studio Solution File, Format Version 12.00
+# Visual Studio Version 17
+VisualStudioVersion = 17.12.35527.113 d17.12
+MinimumVisualStudioVersion = 10.0.40219.1
+Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "WebToApp", "WebToApp.csproj", "{ED8C8E3D-BAB9-4937-A38B-E937B87F5CB3}"
+EndProject
+Global
+ GlobalSection(SolutionConfigurationPlatforms) = preSolution
+ Debug|Any CPU = Debug|Any CPU
+ Release|Any CPU = Release|Any CPU
+ EndGlobalSection
+ GlobalSection(ProjectConfigurationPlatforms) = postSolution
+ {ED8C8E3D-BAB9-4937-A38B-E937B87F5CB3}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+ {ED8C8E3D-BAB9-4937-A38B-E937B87F5CB3}.Debug|Any CPU.Build.0 = Debug|Any CPU
+ {ED8C8E3D-BAB9-4937-A38B-E937B87F5CB3}.Release|Any CPU.ActiveCfg = Release|Any CPU
+ {ED8C8E3D-BAB9-4937-A38B-E937B87F5CB3}.Release|Any CPU.Build.0 = Release|Any CPU
+ EndGlobalSection
+ GlobalSection(SolutionProperties) = preSolution
+ HideSolutionNode = FALSE
+ EndGlobalSection
+EndGlobal
diff --git a/config/aboutpage/about.html b/config/aboutpage/about.html
new file mode 100644
index 0000000..4a3adab
--- /dev/null
+++ b/config/aboutpage/about.html
@@ -0,0 +1,26 @@
+
+
+
+
+
+ 关于 - WebToApp 示例
+
+
+
+ 关于
+ 这是用于演示的关于页面,展示从应用内打开本地 HTML 的能力。
+
+
本应用由 WPF + WebView2 构建,支持:
+
+ - 加载在线或本地网页
+ - 自定义右键菜单
+ - 拦截并保存 data/blob/同域下载
+
+
+
+
diff --git a/config/config.json b/config/config.json
new file mode 100644
index 0000000..4aa257c
--- /dev/null
+++ b/config/config.json
@@ -0,0 +1,27 @@
+{
+ "软件名称": "灵创盘",
+ "软件logo": "config/logo.png",
+ "网页类型": "在线网页",
+ "在线网页": {
+ "链接地址": "https://pan.lcxm.site"
+ },
+ "本地网页": {
+ "网页目录": "config/web",
+ "网页入口": "index.html",
+ "展示模式": "http服务器"
+ },
+ "注入设置":{
+ "隐藏网页滚动条": true,
+ "自定义右键菜单":true,
+ "拦截下载链接":true
+ },
+ "窗口设置": {
+ "窗口宽度": 1200,
+ "窗口高度": 800,
+ "窗口可调整大小": true,
+ "窗口置顶": true,
+ "窗口阴影": true,
+ "全屏": false
+ }
+}
+
\ No newline at end of file
diff --git a/config/logo.png b/config/logo.png
new file mode 100644
index 0000000..d6dbf1e
Binary files /dev/null and b/config/logo.png differ
diff --git a/dotnet b/dotnet
new file mode 100644
index 0000000..e69de29
diff --git a/在线网页配置示例/aboutpage/about.html b/在线网页配置示例/aboutpage/about.html
new file mode 100644
index 0000000..4a3adab
--- /dev/null
+++ b/在线网页配置示例/aboutpage/about.html
@@ -0,0 +1,26 @@
+
+
+
+
+
+ 关于 - WebToApp 示例
+
+
+
+ 关于
+ 这是用于演示的关于页面,展示从应用内打开本地 HTML 的能力。
+
+
本应用由 WPF + WebView2 构建,支持:
+
+ - 加载在线或本地网页
+ - 自定义右键菜单
+ - 拦截并保存 data/blob/同域下载
+
+
+
+
diff --git a/在线网页配置示例/config.json b/在线网页配置示例/config.json
new file mode 100644
index 0000000..4aa257c
--- /dev/null
+++ b/在线网页配置示例/config.json
@@ -0,0 +1,27 @@
+{
+ "软件名称": "灵创盘",
+ "软件logo": "config/logo.png",
+ "网页类型": "在线网页",
+ "在线网页": {
+ "链接地址": "https://pan.lcxm.site"
+ },
+ "本地网页": {
+ "网页目录": "config/web",
+ "网页入口": "index.html",
+ "展示模式": "http服务器"
+ },
+ "注入设置":{
+ "隐藏网页滚动条": true,
+ "自定义右键菜单":true,
+ "拦截下载链接":true
+ },
+ "窗口设置": {
+ "窗口宽度": 1200,
+ "窗口高度": 800,
+ "窗口可调整大小": true,
+ "窗口置顶": true,
+ "窗口阴影": true,
+ "全屏": false
+ }
+}
+
\ No newline at end of file
diff --git a/本地网页配置示例/aboutpage/about.html b/本地网页配置示例/aboutpage/about.html
new file mode 100644
index 0000000..4a3adab
--- /dev/null
+++ b/本地网页配置示例/aboutpage/about.html
@@ -0,0 +1,26 @@
+
+
+
+
+
+ 关于 - WebToApp 示例
+
+
+
+ 关于
+ 这是用于演示的关于页面,展示从应用内打开本地 HTML 的能力。
+
+
本应用由 WPF + WebView2 构建,支持:
+
+ - 加载在线或本地网页
+ - 自定义右键菜单
+ - 拦截并保存 data/blob/同域下载
+
+
+
+
diff --git a/本地网页配置示例/config.json b/本地网页配置示例/config.json
new file mode 100644
index 0000000..d2fbf5b
--- /dev/null
+++ b/本地网页配置示例/config.json
@@ -0,0 +1,27 @@
+{
+ "软件名称": "灵创盘",
+ "软件logo": "config/logo.png",
+ "网页类型": "本地网页",
+ "在线网页": {
+ "链接地址": "https://pan.lcxm.site"
+ },
+ "本地网页": {
+ "网页目录": "config/web",
+ "网页入口": "index.html",
+ "展示模式": "http服务器"
+ },
+ "注入设置":{
+ "隐藏网页滚动条": true,
+ "自定义右键菜单":true,
+ "拦截下载链接":true
+ },
+ "窗口设置": {
+ "窗口宽度": 1200,
+ "窗口高度": 800,
+ "窗口可调整大小": true,
+ "窗口置顶": true,
+ "窗口阴影": true,
+ "全屏": false
+ }
+}
+
\ No newline at end of file
diff --git a/本地网页配置示例/web/images/sample.png b/本地网页配置示例/web/images/sample.png
new file mode 100644
index 0000000..77d4e45
--- /dev/null
+++ b/本地网页配置示例/web/images/sample.png
@@ -0,0 +1 @@
+iVBORw0KGgoAAAANSUhEUgAAAEAAAABACAYAAACqaXHeAAAAGXRFWHRTb2Z0d2FyZQBBZG9iZSBJbWFnZVJlYWR5ccllPAAAABh0RVh0Q3JlYXRpb24gVGltZQAyMDI1LTAxLTAxVDEyOjAwOjAwW7vWJQAAAQ1JREFUeNrs1kENgDAMQ9G9/5+S0YF4pG3lI1oIuJmYQ8NwJdC0xgq7r9q+3QAAACcWcH9yJwAAABgqY7tJwAAABgqY7tJwAAABgqY7tJwAAABgqY7tJwAAABgqY7tJwAAABgqY7tJwAAABgqY7tJwAAABgqY7tJwAAABgqY7tJwAAABi8BfC8YwAAAOw3oQIAAAD8fV8AAAAAANoYAwAAAPx9XwAAAADaGAMAAAD8fV8AAAAA2hgDAAAA/H1fAAAAANoYAwAAAPx9XwAAAADaGAMAAAD8fV8AAAAA2vgCkHfXfVQyAAAAAElFTkSuQmCC
\ No newline at end of file
diff --git a/本地网页配置示例/web/index.html b/本地网页配置示例/web/index.html
new file mode 100644
index 0000000..5c220fe
--- /dev/null
+++ b/本地网页配置示例/web/index.html
@@ -0,0 +1,83 @@
+
+
+
+
+
+ 本地网页示例
+
+
+
+ 本地网页示例
+ 用于演示:右键菜单、下载拦截(data/blob/同域)、关于页面。
+
+
+
+
+
Data URL 下载(内联文本)
+
+
+
+
+
+
Blob URL 下载(运行时生成)
+
+
+
+
+
+
右键菜单测试
+
在页面空白处点击右键,弹出自定义菜单(返回/刷新/关于)。
+
+
+
+
+
+
示例文件内容
+
+sample.txt 将在同目录下提供。
+images/sample.png 将作为占位图片。
+
+
+
+
diff --git a/本地网页配置示例/web/sample.txt b/本地网页配置示例/web/sample.txt
new file mode 100644
index 0000000..ac151b2
--- /dev/null
+++ b/本地网页配置示例/web/sample.txt
@@ -0,0 +1,2 @@
+这是一个用于同域下载的示例文本文件。
+Hello from WebToApp (WPF + WebView2).
diff --git a/构建命令.txt b/构建命令.txt
new file mode 100644
index 0000000..fedd1e5
--- /dev/null
+++ b/构建命令.txt
@@ -0,0 +1,6 @@
+
+dotnet publish -c Release -r win-x64 --self-contained false
+
+dotnet publish -c Release -r win-x64 --self-contained true
+
+dotnet build -c Debug
\ No newline at end of file
diff --git a/网页转Windows应用-CSharp b/网页转Windows应用-CSharp
new file mode 100644
index 0000000..e69de29