🎮 示例代码

pull/4/head
林选臣 1 year ago
parent d80e2a6a36
commit 478f03ca45

@ -0,0 +1,38 @@
namespace MinimalWinFormiumApp;
partial class Form1
{
/// <summary>
/// Required designer variable.
/// </summary>
private System.ComponentModel.IContainer components = null;
/// <summary>
/// Clean up any resources being used.
/// </summary>
/// <param name="disposing">true if managed resources should be disposed; otherwise, false.</param>
protected override void Dispose(bool disposing)
{
if (disposing && (components != null))
{
components.Dispose();
}
base.Dispose(disposing);
}
#region Windows Form Designer generated code
/// <summary>
/// Required method for Designer support - do not modify
/// the contents of this method with the code editor.
/// </summary>
private void InitializeComponent()
{
this.components = new System.ComponentModel.Container();
this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font;
this.ClientSize = new System.Drawing.Size(800, 450);
this.Text = "Form1";
}
#endregion
}

@ -0,0 +1,32 @@
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows.Forms;
namespace MinimalWinFormiumApp;
public partial class Form1 : Form
{
public Form1()
{
InitializeComponent();
Label label = new (){
Text = "Click to open WinFormium",
};
label.Click += (_, _) =>
{
var window = new MyWindow();
window.Show();
};
Controls.Add(label);
}
}

@ -0,0 +1,120 @@
<?xml version="1.0" encoding="utf-8"?>
<root>
<!--
Microsoft ResX Schema
Version 2.0
The primary goals of this format is to allow a simple XML format
that is mostly human readable. The generation and parsing of the
various data types are done through the TypeConverter classes
associated with the data types.
Example:
... ado.net/XML headers & schema ...
<resheader name="resmimetype">text/microsoft-resx</resheader>
<resheader name="version">2.0</resheader>
<resheader name="reader">System.Resources.ResXResourceReader, System.Windows.Forms, ...</resheader>
<resheader name="writer">System.Resources.ResXResourceWriter, System.Windows.Forms, ...</resheader>
<data name="Name1"><value>this is my long string</value><comment>this is a comment</comment></data>
<data name="Color1" type="System.Drawing.Color, System.Drawing">Blue</data>
<data name="Bitmap1" mimetype="application/x-microsoft.net.object.binary.base64">
<value>[base64 mime encoded serialized .NET Framework object]</value>
</data>
<data name="Icon1" type="System.Drawing.Icon, System.Drawing" mimetype="application/x-microsoft.net.object.bytearray.base64">
<value>[base64 mime encoded string representing a byte array form of the .NET Framework object]</value>
<comment>This is a comment</comment>
</data>
There are any number of "resheader" rows that contain simple
name/value pairs.
Each data row contains a name, and value. The row also contains a
type or mimetype. Type corresponds to a .NET class that support
text/value conversion through the TypeConverter architecture.
Classes that don't support this are serialized and stored with the
mimetype set.
The mimetype is used for serialized objects, and tells the
ResXResourceReader how to depersist the object. This is currently not
extensible. For a given mimetype the value must be set accordingly:
Note - application/x-microsoft.net.object.binary.base64 is the format
that the ResXResourceWriter will generate, however the reader can
read any of the formats listed below.
mimetype: application/x-microsoft.net.object.binary.base64
value : The object must be serialized with
: System.Runtime.Serialization.Formatters.Binary.BinaryFormatter
: and then encoded with base64 encoding.
mimetype: application/x-microsoft.net.object.soap.base64
value : The object must be serialized with
: System.Runtime.Serialization.Formatters.Soap.SoapFormatter
: and then encoded with base64 encoding.
mimetype: application/x-microsoft.net.object.bytearray.base64
value : The object must be serialized into a byte array
: using a System.ComponentModel.TypeConverter
: and then encoded with base64 encoding.
-->
<xsd:schema id="root" xmlns="" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:msdata="urn:schemas-microsoft-com:xml-msdata">
<xsd:import namespace="http://www.w3.org/XML/1998/namespace" />
<xsd:element name="root" msdata:IsDataSet="true">
<xsd:complexType>
<xsd:choice maxOccurs="unbounded">
<xsd:element name="metadata">
<xsd:complexType>
<xsd:sequence>
<xsd:element name="value" type="xsd:string" minOccurs="0" />
</xsd:sequence>
<xsd:attribute name="name" use="required" type="xsd:string" />
<xsd:attribute name="type" type="xsd:string" />
<xsd:attribute name="mimetype" type="xsd:string" />
<xsd:attribute ref="xml:space" />
</xsd:complexType>
</xsd:element>
<xsd:element name="assembly">
<xsd:complexType>
<xsd:attribute name="alias" type="xsd:string" />
<xsd:attribute name="name" type="xsd:string" />
</xsd:complexType>
</xsd:element>
<xsd:element name="data">
<xsd:complexType>
<xsd:sequence>
<xsd:element name="value" type="xsd:string" minOccurs="0" msdata:Ordinal="1" />
<xsd:element name="comment" type="xsd:string" minOccurs="0" msdata:Ordinal="2" />
</xsd:sequence>
<xsd:attribute name="name" type="xsd:string" use="required" msdata:Ordinal="1" />
<xsd:attribute name="type" type="xsd:string" msdata:Ordinal="3" />
<xsd:attribute name="mimetype" type="xsd:string" msdata:Ordinal="4" />
<xsd:attribute ref="xml:space" />
</xsd:complexType>
</xsd:element>
<xsd:element name="resheader">
<xsd:complexType>
<xsd:sequence>
<xsd:element name="value" type="xsd:string" minOccurs="0" msdata:Ordinal="1" />
</xsd:sequence>
<xsd:attribute name="name" type="xsd:string" use="required" />
</xsd:complexType>
</xsd:element>
</xsd:choice>
</xsd:complexType>
</xsd:element>
</xsd:schema>
<resheader name="resmimetype">
<value>text/microsoft-resx</value>
</resheader>
<resheader name="version">
<value>2.0</value>
</resheader>
<resheader name="reader">
<value>System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
</resheader>
<resheader name="writer">
<value>System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
</resheader>
</root>

@ -0,0 +1,67 @@
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<OutputType>WinExe</OutputType>
<TargetFrameworks>net6.0-windows;net481;</TargetFrameworks>
<Nullable>enable</Nullable>
<UseWindowsForms>true</UseWindowsForms>
<ImplicitUsings>enable</ImplicitUsings>
<StartupObject>MinimalWinFormiumApp.Program</StartupObject>
<AssemblyTitle>WinFormium Example App</AssemblyTitle>
<ApplicationVisualStyles>true</ApplicationVisualStyles>
<ApplicationUseCompatibleTextRendering>true</ApplicationUseCompatibleTextRendering>
<ApplicationHighDpiMode>PerMonitorV2</ApplicationHighDpiMode>
<ApplicationDefaultFont>Microsoft Yahei, 8.25pt</ApplicationDefaultFont>
<ApplicationManifest>app.manifest</ApplicationManifest>
<AllowUnsafeBlocks>False</AllowUnsafeBlocks>
<BaseOutputPath>$(BinDir)\$(MSBuildProjectName)\</BaseOutputPath>
<RunPostBuildEvent>OnBuildSuccess</RunPostBuildEvent>
<PlatformTarget>AnyCPU</PlatformTarget>
<ApplicationIcon>Resources\WinFormiumIcon.ico</ApplicationIcon>
<AutoGenerateBindingRedirects>True</AutoGenerateBindingRedirects>
</PropertyGroup>
<ItemGroup>
<None Remove="wwwroot\index.html" />
</ItemGroup>
<ItemGroup>
<EmbeddedResource Include="wwwroot\**\*" />
</ItemGroup>
<ItemGroup>
<Content Include="Resources\WinFormiumIcon.ico" />
<Content Include="Resources\DefaultIcon.ico" />
</ItemGroup>
<ItemGroup>
<ProjectReference Include="..\..\src\WinFormium\WinFormium.csproj" />
</ItemGroup>
<ItemGroup>
<EmbeddedResource Update="wwwroot\**\*">
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
</EmbeddedResource>
</ItemGroup>
<ItemGroup>
<Compile Update="Properties\Resources.Designer.cs">
<DesignTime>True</DesignTime>
<AutoGen>True</AutoGen>
<DependentUpon>Resources.resx</DependentUpon>
</Compile>
</ItemGroup>
<ItemGroup>
<EmbeddedResource Update="Properties\Resources.resx">
<Generator>ResXFileCodeGenerator</Generator>
<LastGenOutput>Resources.Designer.cs</LastGenOutput>
</EmbeddedResource>
</ItemGroup>
<Target Name="PostBuild" AfterTargets="PostBuildEvent">
<Exec Command="if not $(PlatformName) == x64 (&#xD;&#xA;if exist &quot;$(DevEnvDir)..\tools\vsdevcmd.bat&quot; (&#xD;&#xA;call &quot;$(DevEnvDir)..\tools\vsdevcmd.bat&quot; &gt; nul&#xD;&#xA;echo Setting largeaddressaware on [$(OutDir)$(TargetName).exe] to get 4gb access in 32bit&#xD;&#xA;editbin /largeaddressaware /stacksize:4194304 &quot;$(OutDir)$(TargetName).exe&quot; &gt; nul&#xD;&#xA;)&#xD;&#xA;)" />
</Target>
</Project>

@ -0,0 +1,105 @@
using Microsoft.Extensions.DependencyInjection;
using WinFormium;
using WinFormium.WebResource;
using WinFormium.JavaScript;
namespace MinimalWinFormiumApp;
internal class MyApp : WinFormiumStartup
{
public MyApp(ChromiumEnvironment env)
{
}
protected override MainWindowCreationAction? UseMainWindow(MainWindowOptions opts)
{
return opts.UseMainFormium<MyWindow>();
// 可以指定 Formium 为主窗体,也可以使用原生的 WinForm 窗体。
// You can specify Formium as the main form, or you can use the native WinForm form.
//return opts.UseMainForm<Form1>();
}
protected override void WinFormiumMain(string[] args)
{
// 现在把 Main 函数搬到这里来。避免用户搞不清主进程和渲染进程的区别,在 Program.cs 里面写太多代码导致子进程内部出现问题。
// Now move the Main function here. To avoid users not knowing the difference between the main process and the rendering process, write too much code in Program.cs, which causes problems in the sub-process.
#if NETCOREAPP3_1_OR_GREATER
// To customize application configuration such as set high DPI settings or default font,
// see https://aka.ms/applicationconfiguration.
ApplicationConfiguration.Initialize();
#else
Application.EnableVisualStyles();
Application.SetCompatibleTextRenderingDefault(false);
#endif
}
// CEF 的配置可以在Program.cs里面写也可以在这里写在这里写更集中更简洁。
// CEF configuration can be written in Program.cs or here, which is more centralized and concise here.
protected override void ConfigurationChromiumEmbedded(ChromiumEnvironmentBuiler cef)
{
//cef.UseInMemoryUserData();
cef.ConfigureCommandLineArguments(cl =>
{
//cl.AppendArgument("disable-web-security");
//cl.AppendSwitch("no-proxy-server");
cl.AppendSwitch("enable-gpu");
//cl.AppendSwitch("disable-gpu");
});
cef.ConfigureDefaultSettings(settings =>
{
settings.WindowlessRenderingEnabled = true;
});
cef.ConfigureDefaultBrowserSettings(settings =>
{
});
// 启用子进程的示例。
// Example of enabling sub-process.
//cef.ConfigureSubprocess(sub =>
//{
// sub.SubprocessFilePath = "WinFormiumSubProcess.exe";
//});
}
protected override void ConfigureServices(IServiceCollection services)
{
// 注册嵌入资源
// Register embedded resources to specific domain.
services.AddEmbeddedFileResource(new EmbeddedFileResourceOptions
{
Scheme = "http",
DomainName = "embedded.app.local",
ResourceAssembly = typeof(Program).Assembly,
EmbeddedResourceDirectoryName = "wwwroot",
});
// 注册本地资源
// Register local resources to specific domain.
services.AddLocalFileResource(new LocalFileResourceOptions
{
Scheme = "http",
DomainName = "files.app.local",
PhysicalFilePath = Path.Combine(AppContext.BaseDirectory, "wwwroot"),
});
// 注册 JavaScript Window Binding Object
// Register JavaScript Window Binding Object
services.AddWindowBindingObject<TestWindowBindingObject>();
}
}

@ -0,0 +1,259 @@
using WinFormium;
using WinFormium.Browser;
using WinFormium.CefGlue;
using WinFormium.Forms;
using WinFormium.JavaScript;
namespace MinimalWinFormiumApp;
internal class MyWindow : Formium
{
public MyWindow() { }
public MyWindow(ChromiumEnvironment env) // 依赖注入测试; Dependency Injection Testing;
{
//默认测试,加载普通网页
//Default test, load web page
//Url = "https://www.bing.com";
//测试加载本地资源
//Test loading local resources
//Url = "http://static.app.local/";
//测试嵌入资源
//Test loading embedded resources
//Url = "http://embedded.app.local/";
//错误地址测试指定了错误页面的地址如果页面加载失败将会自动显示WinFormium内置的错误页面。
//Error address test specifies the address of the error page. If the page fails to load, WinFormium's built-in error page will be automatically displayed.
//Url = "http://static1.app.local/";
//注意默认没有指定任何Url新版WinFormium将会自动加载一个欢迎页面。
//If no URL is specified, WinFormium will automatically load a welcome page.
//这个事件对应WinForm的Load事件对应NanUI的OnReady抽象方法
//OnReady of old version NanUI
Loaded += MyWindow_Loaded;
PageLoadEnd += MyWindow_PageLoadEnd;
}
private void MyWindow_Loaded(object? sender, BrowserEventArgs e)
{
var frame = e.Browser.GetMainFrame();
// 测试JS对象映射
// Test JS object mapping
TestJSObjectMapping(frame);
// 注册前端消息处理器比如这里注册bbb那么在前端调用 formium.postMessage("bbb", "[任意数据类型/字符/数字/数组/对象]")来向这个处理器发送消息。
// Register front-end message handler. For example, by registering “bbb” here, you can send messages to this handler from the front-end using the formium.postMessage("bbb", "[any data type/string/number/array/object]") method.
RegisterJavaScriptMessagDispatcher("bbb", args =>
{
});
// 注册前端请求处理器,请求处理和消息处理器的不同在于,消息处理器不需要返回结果,而请求处理器需要返回结果。
// Register front-end request handler. The difference between a request handler and a message handler is that a request handler needs to return a result.
// 请求处理器提供了2中不同的接口返回数据一种是同步接口一种是异步接口。
// The request handler provides two different interfaces for returning data: synchronous and asynchronous.
// 这是同步接口,前端使用 formium.sendHostWindowRequest("rrr", "[任意数据类型/字符/数字/数组/对象]") 来向这个处理器发送请求,这个请求会阻塞前端线程,直到这个处理器返回结果。
// This is the synchronous interface. The front-end can send a request to this handler using formium.sendHostWindowRequest("rrr", "[any data type/string/number/array/object]"), and this request will block the front-end thread until the handler returns a result.
RegisterJavaScriptSynchronousRequestDispatcher("rrr", args => "OK sync");
// 这是异步接口,前端使用 formium.sendHostWindowRequestAsync("aaa", "[任意数据类型/字符/数字/数组/对象]") 来向这个处理器发送请求这个请求不会阻塞前端线程前端线程会继续执行使用promise参数的resolve([data: any])或者reject([reason: string])方法来指定这个异步是否成功执行。
// This is the asynchronous interface. The front-end can send a request to this handler using formium.sendHostWindowRequestAsync("aaa", "[any data type/string/number/array/object]"), and this request will not block the front-end thread. The front-end thread will continue executing, and you can use the resolve([data: any]) or reject([reason: string]) methods of the promise parameter to specify whether this asynchronous operation is successfully executed.
// 前端的formium.sendHostWindowRequestAsync()方法将返回一个可等待的promise对象可以使用await关键字来等待这个promise对象的执行结果。当然使用传统的then/catch方法也可以。
// The front-end's formium.sendHostWindowRequestAsync() method will return a awaitable promise object. You can use the await keyword to wait for the execution result of this promise object. Alternatively, you can also use the traditional then/catch methods.
RegisterJavaScriptAsynchronousRequestDispatcher("aaa", async (args, promise) => {
await Task.Delay(3000);
promise.Resolve("OK async");
});
}
private void MyWindow_PageLoadEnd(object? sender, PageLoadEndEventArgs e)
{
//测试JS引擎
//Test JS engine
TestJSEngine();
//测试从后端Post消息到前端前端需要使用formium.addMessageDispatcher("test", msg=>{})方法来接收消息。
//Test post message from back-end to front-end, the front-end needs to use the formium.addMessageDispatcher("test", msg=>{}) method to receive the message.
Task.Run(async () =>
{
while (true)
{
await Task.Delay(5000);
PostBrowserJavaScriptMessage("test", DateTime.Now);
}
});
}
// 使用对象映射的方式来为WinFormium提供可前后端交互的JavaScript对象。
// Use object mapping to provide JavaScript objects that can interact with the front and back ends for WinFormium.
private void TestJSObjectMapping(CefFrame frame)
{
var obj = new JavaScriptObject
{
{ "name", "linxuanchen" },
{ "age", 38 }
};
obj.DefineProperty("now", () => DateTime.Now);
obj.DefineProperty("title", () => AppTitle, v => AppTitle = ((string?)v ?? string.Empty));
obj.Add("sync", (args) =>
{
var retval = string.Join(",", args.Select(x => x.GetString()));
InvokeOnUIThread(() =>
{
MessageBox.Show(this, $"Caller arguments:{retval}", "JavaScriptSyncFunction");
});
return null;
});
obj.Add("exit", args =>
{
WinFormiumApp.Shutdown();
return null;
});
obj.Add("async", async (args, promise) =>
{
var retval = string.Join(",", args.Select(x => x.GetString()));
var rnd = new Random();
var x = rnd.Next(1, 6);
await Task.Delay(x * 500);
if (x == 5)
{
promise.Reject("Rejected by random.");
}
else
{
promise.Resolve(new string(retval.Reverse().ToArray()) ?? "No argument.");
}
});
// 与0.9相比注册对象前需要先调用BeginRegisterJavaScriptObject()方法注册完毕后需要调用EndRegisterJavaScriptObject()方法这样可以确保EndRegisterJavaScriptObject时才像渲染进程发送注册对象的消息。
// Compared with 0.9, you need to call the BeginRegisterJavaScriptObject() method before registering the object, and call the EndRegisterJavaScriptObject() method after the registration is completed. This ensures that the registration object is sent to the rendering process when EndRegisterJavaScriptObject is called.
var hbrjso = BeginRegisterJavaScriptObject(frame);
RegisterJavaScriptObject(hbrjso, "test", obj);
EndRegisterJavaScriptObject(hbrjso);
}
private async void TestJSEngine()
{
// 执行带结果的JavaScript表达式如果不需要返回结果可以使用ExecuteJavaScript方法。
// Execute JavaScript expressions with results. If you don't need to return results, you can use the ExecuteJavaScript method.
var retval = await EvaluateJavaScriptAsync("3+4");
// 获取返回结果类型为JavaScriptValue可以使用JavaScriptValue的各种方法来获取返回结果的值。
// Retrieve the return result, which is of type JavaScriptValue. You can use various methods of JavaScriptValue to access the value of the return result.
// 这个版本为JavaScriptValue提供了各类显式、隐式转换操作符可以直接将JavaScriptValue转换为各种基本类型。
// This version provides various explicit and implicit conversion operators for JavaScriptValue, allowing direct conversion of JavaScriptValue to various primitive types.
// 例如下面的代码将JavaScriptValue转换为int类型。
// For example, the following code converts JavaScriptValue to int type.
int value1 = retval.ReturnValue;
// 获取页面标题
// Get the page title.
var retval2 = await EvaluateJavaScriptAsync("document.title");
// 显式转换为可空string类型
// Explicitly convert to nullable string type.
string? value2 = retval2.ReturnValue;
// 返回一个函数对象
// Return a function object.
var retval3 = await EvaluateJavaScriptAsync("(a)=>{ const v = a.apply(); console.log(`value:${v}`); }");
// 获取函数对象的Invoker可以通过该Invoker类型的ExecuteAsync调用这个函数对象。这里使用了JavaScriptSynchronousFunction表示这个函数对象是同步执行的如果是异步执行的可以使用JavaScriptAsynchronousFunction根据函数对象的参数类型来选择。
// Get the Invoker of the function object, which can be used to invoke the function object using the ExecuteAsync method of the Invoker type. Here, we are using JavaScriptSynchronousFunction, which indicates that the function object is executed synchronously. If it is executed asynchronously, you can use JavaScriptAsynchronousFunction and choose based on the parameter types of the function object.
var retval4 = await ((JavaScriptFunctionInvoker)retval3.ReturnValue).ExecuteAsync(new JavaScriptSynchronousFunction((a) => "Callback function for retval3."));
// 函数对象的返回结果这里是string类型
// The return result of the function object is of string type.
string? value3 = retval4.ReturnValue;
// 返回一个函数对象这个函数对象是异步执行的所以使用JavaScriptAsynchronousFunction
// Return a function object that is executed asynchronously, using JavaScriptAsynchronousFunction.
var retval5 = await EvaluateJavaScriptAsync("(callback)=>{ callback().then(x=>console.log(`success:${x}`)).catch(err=>console.log(`success:${err}`)); }");
// 在JavaScriptAsynchronousFunction中提供了一个Promise参数可以使用这个参数的Resolve方法来返回结果也可以使用Reject方法来返回错误。因为是异步的所以这里使用了await关键字来等待这个异步函数的执行结果。
// In JavaScriptAsynchronousFunction, a Promise parameter is provided. You can use the Resolve method of this parameter to return the result, or use the Reject method to return an error. Since it is asynchronous, the await keyword is used here to wait for the execution result of this asynchronous function.
// promise resovle
var retval6 = await ((JavaScriptFunctionInvoker)retval5.ReturnValue).ExecuteAsync(new JavaScriptAsynchronousFunction(async (args, promise) =>
{
await Task.Delay(5000);
promise.Resolve("Resolved for retval5.");
}));
// promise reject
var retval7 = await ((JavaScriptFunctionInvoker)retval5.ReturnValue).ExecuteAsync(new JavaScriptAsynchronousFunction(async (args, promise) =>
{
await Task.Delay(1000);
promise.Reject("Rejected for retval5.");
}));
InvokeOnUIThread(() => { MessageBox.Show(this, $"value1={value1} value2={value2}"); });
}
protected override FormStyle ConfigureWindowStyle(WindowStyleBuilder builder)
{
var style = builder.UseSystemForm();
// 移除系统窗体的标题栏
// To remove the title bar of a system window and achieve a borderless form
style.TitleBar = false;
// 指定系统深浅色主题模式,默认将自动检测当前系统的深浅色主题模式。也可以手动指定
// Specify the system's light or dark theme mode. By default, it will automatically detect the current system's theme mode. It can also be manually specified.
//style.ColorMode = FormiumColorMode.Dark;
// 是否启用网页的页面标题
// Whether to enable the page title of the webpage.
//style.UsePageTitle = true;
//style.StartCentered = true;
// 是否启用Kiosk模式启用后将禁用任务栏
// Whether to enable Kiosk mode, which disables the taskbar when enabled.
//var style = builder.UseKisokForm();
//style.DisableTaskBar = true;
return style;
}
}

@ -0,0 +1,46 @@
using WinFormium;
using WinFormium.JavaScript;
using WinFormium.WebResource;
namespace MinimalWinFormiumApp;
internal static class Program
{
/// <summary>
/// The main entry point for the application.
/// </summary>
[STAThread]
static void Main(string[] args)
{
var builder = WinFormiumApp.CreateBuilder();
var app = builder
// 使用WinFormiumStartup的子类来启动应用程序这个子类必须继承自WinFormiumStartup类这个类提供了一些方法来配置应用程序。
// Use a subclass of WinFormiumStartup to start the application. This subclass must inherit from the WinFormiumStartup class, which provides some methods to configure the application.
.UseWinFormiumApp<MyApp>()
// 启用内部浏览器这个版本默认外部Url打开方式是调用系统默认浏览器需要手动开启内部浏览器后才能使用内部浏览器打开外部Url。
// Enable the internal browser. In this version, the default external URL opening method is to call the system default browser. You need to manually enable the internal browser before you can use the internal browser to open the external URL.
.UseEmbeddedBrowser()
// 演示单例模式如果你的应用需要单例模式那么可以使用这个方法来启用单例模式。新版本可以使用ActiveRunningInstance方法来激活已经运行实例的主窗体。
// Demonstrate singleton mode. If your application requires singleton mode, you can use this method to enable singleton mode. The new version can use the ActiveRunningInstance method to activate the main form of the running instance.
.UseSingleApplicationInstanceMode(handler =>
{
var retval = MessageBox.Show($"已经有一个实例在运行了:{handler.ProcessId}。\r\n是否打开其主窗体", "单例模式已启用", MessageBoxButtons.YesNo, MessageBoxIcon.Warning);
if (retval == DialogResult.Yes)
{
handler.ActiveRunningInstance();
}
})
// 在这里指定culture字符传来模拟多语言环境这个版本的多语言环境还不完善只提供zh-CN和en-US两种语言环境。欢迎提交PR来增加更多语言环境。
// Specify the culture string here to simulate the multilingual environment. The multilingual environment of this version is not perfect, and only provides two language environments: zh-CN and en-US. Welcome to submit PR to add more language environments.
//.UseCulture("en-US")
// 是否启用开发者工具菜单,这个菜单可以在主窗体的右键菜单中找到。
// Whether to enable the developer tool menu, this menu can be found in the right-click menu of the main form.
.UseDevToolsMenu()
.Build();
app.Run();
}
}

@ -0,0 +1,83 @@
//------------------------------------------------------------------------------
// <auto-generated>
// 此代码由工具生成。
// 运行时版本:4.0.30319.42000
//
// 对此文件的更改可能会导致不正确的行为,并且如果
// 重新生成代码,这些更改将会丢失。
// </auto-generated>
//------------------------------------------------------------------------------
namespace MinimalWinFormiumApp.Properties {
using System;
/// <summary>
/// 一个强类型的资源类,用于查找本地化的字符串等。
/// </summary>
// 此类是由 StronglyTypedResourceBuilder
// 类通过类似于 ResGen 或 Visual Studio 的工具自动生成的。
// 若要添加或移除成员,请编辑 .ResX 文件,然后重新运行 ResGen
// (以 /str 作为命令选项),或重新生成 VS 项目。
[global::System.CodeDom.Compiler.GeneratedCodeAttribute("System.Resources.Tools.StronglyTypedResourceBuilder", "17.0.0.0")]
[global::System.Diagnostics.DebuggerNonUserCodeAttribute()]
[global::System.Runtime.CompilerServices.CompilerGeneratedAttribute()]
internal class Resources {
private static global::System.Resources.ResourceManager resourceMan;
private static global::System.Globalization.CultureInfo resourceCulture;
[global::System.Diagnostics.CodeAnalysis.SuppressMessageAttribute("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")]
internal Resources() {
}
/// <summary>
/// 返回此类使用的缓存的 ResourceManager 实例。
/// </summary>
[global::System.ComponentModel.EditorBrowsableAttribute(global::System.ComponentModel.EditorBrowsableState.Advanced)]
internal static global::System.Resources.ResourceManager ResourceManager {
get {
if (object.ReferenceEquals(resourceMan, null)) {
global::System.Resources.ResourceManager temp = new global::System.Resources.ResourceManager("MinimalWinFormiumApp.Properties.Resources", typeof(Resources).Assembly);
resourceMan = temp;
}
return resourceMan;
}
}
/// <summary>
/// 重写当前线程的 CurrentUICulture 属性,对
/// 使用此强类型资源类的所有资源查找执行重写。
/// </summary>
[global::System.ComponentModel.EditorBrowsableAttribute(global::System.ComponentModel.EditorBrowsableState.Advanced)]
internal static global::System.Globalization.CultureInfo Culture {
get {
return resourceCulture;
}
set {
resourceCulture = value;
}
}
/// <summary>
/// 查找类似于 (图标) 的 System.Drawing.Icon 类型的本地化资源。
/// </summary>
internal static System.Drawing.Icon DefaultIcon {
get {
object obj = ResourceManager.GetObject("DefaultIcon", resourceCulture);
return ((System.Drawing.Icon)(obj));
}
}
/// <summary>
/// 查找类似于 (图标) 的 System.Drawing.Icon 类型的本地化资源。
/// </summary>
internal static System.Drawing.Icon WinFormiumIcon {
get {
object obj = ResourceManager.GetObject("WinFormiumIcon", resourceCulture);
return ((System.Drawing.Icon)(obj));
}
}
}
}

@ -0,0 +1,127 @@
<?xml version="1.0" encoding="utf-8"?>
<root>
<!--
Microsoft ResX Schema
Version 2.0
The primary goals of this format is to allow a simple XML format
that is mostly human readable. The generation and parsing of the
various data types are done through the TypeConverter classes
associated with the data types.
Example:
... ado.net/XML headers & schema ...
<resheader name="resmimetype">text/microsoft-resx</resheader>
<resheader name="version">2.0</resheader>
<resheader name="reader">System.Resources.ResXResourceReader, System.Windows.Forms, ...</resheader>
<resheader name="writer">System.Resources.ResXResourceWriter, System.Windows.Forms, ...</resheader>
<data name="Name1"><value>this is my long string</value><comment>this is a comment</comment></data>
<data name="Color1" type="System.Drawing.Color, System.Drawing">Blue</data>
<data name="Bitmap1" mimetype="application/x-microsoft.net.object.binary.base64">
<value>[base64 mime encoded serialized .NET Framework object]</value>
</data>
<data name="Icon1" type="System.Drawing.Icon, System.Drawing" mimetype="application/x-microsoft.net.object.bytearray.base64">
<value>[base64 mime encoded string representing a byte array form of the .NET Framework object]</value>
<comment>This is a comment</comment>
</data>
There are any number of "resheader" rows that contain simple
name/value pairs.
Each data row contains a name, and value. The row also contains a
type or mimetype. Type corresponds to a .NET class that support
text/value conversion through the TypeConverter architecture.
Classes that don't support this are serialized and stored with the
mimetype set.
The mimetype is used for serialized objects, and tells the
ResXResourceReader how to depersist the object. This is currently not
extensible. For a given mimetype the value must be set accordingly:
Note - application/x-microsoft.net.object.binary.base64 is the format
that the ResXResourceWriter will generate, however the reader can
read any of the formats listed below.
mimetype: application/x-microsoft.net.object.binary.base64
value : The object must be serialized with
: System.Runtime.Serialization.Formatters.Binary.BinaryFormatter
: and then encoded with base64 encoding.
mimetype: application/x-microsoft.net.object.soap.base64
value : The object must be serialized with
: System.Runtime.Serialization.Formatters.Soap.SoapFormatter
: and then encoded with base64 encoding.
mimetype: application/x-microsoft.net.object.bytearray.base64
value : The object must be serialized into a byte array
: using a System.ComponentModel.TypeConverter
: and then encoded with base64 encoding.
-->
<xsd:schema id="root" xmlns="" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:msdata="urn:schemas-microsoft-com:xml-msdata">
<xsd:import namespace="http://www.w3.org/XML/1998/namespace" />
<xsd:element name="root" msdata:IsDataSet="true">
<xsd:complexType>
<xsd:choice maxOccurs="unbounded">
<xsd:element name="metadata">
<xsd:complexType>
<xsd:sequence>
<xsd:element name="value" type="xsd:string" minOccurs="0" />
</xsd:sequence>
<xsd:attribute name="name" use="required" type="xsd:string" />
<xsd:attribute name="type" type="xsd:string" />
<xsd:attribute name="mimetype" type="xsd:string" />
<xsd:attribute ref="xml:space" />
</xsd:complexType>
</xsd:element>
<xsd:element name="assembly">
<xsd:complexType>
<xsd:attribute name="alias" type="xsd:string" />
<xsd:attribute name="name" type="xsd:string" />
</xsd:complexType>
</xsd:element>
<xsd:element name="data">
<xsd:complexType>
<xsd:sequence>
<xsd:element name="value" type="xsd:string" minOccurs="0" msdata:Ordinal="1" />
<xsd:element name="comment" type="xsd:string" minOccurs="0" msdata:Ordinal="2" />
</xsd:sequence>
<xsd:attribute name="name" type="xsd:string" use="required" msdata:Ordinal="1" />
<xsd:attribute name="type" type="xsd:string" msdata:Ordinal="3" />
<xsd:attribute name="mimetype" type="xsd:string" msdata:Ordinal="4" />
<xsd:attribute ref="xml:space" />
</xsd:complexType>
</xsd:element>
<xsd:element name="resheader">
<xsd:complexType>
<xsd:sequence>
<xsd:element name="value" type="xsd:string" minOccurs="0" msdata:Ordinal="1" />
</xsd:sequence>
<xsd:attribute name="name" type="xsd:string" use="required" />
</xsd:complexType>
</xsd:element>
</xsd:choice>
</xsd:complexType>
</xsd:element>
</xsd:schema>
<resheader name="resmimetype">
<value>text/microsoft-resx</value>
</resheader>
<resheader name="version">
<value>2.0</value>
</resheader>
<resheader name="reader">
<value>System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
</resheader>
<resheader name="writer">
<value>System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
</resheader>
<assembly alias="System.Windows.Forms" name="System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089" />
<data name="DefaultIcon" type="System.Resources.ResXFileRef, System.Windows.Forms">
<value>..\Resources\DefaultIcon.ico;System.Drawing.Icon, System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a</value>
</data>
<data name="WinFormiumIcon" type="System.Resources.ResXFileRef, System.Windows.Forms">
<value>..\Resources\WinFormiumIcon.ico;System.Drawing.Icon, System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a</value>
</data>
</root>

Binary file not shown.

After

Width:  |  Height:  |  Size: 212 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 272 KiB

@ -0,0 +1,73 @@
using WinFormium;
using WinFormium.JavaScript;
namespace MinimalWinFormiumApp;
// 演示 JavaScript Window Binding Object 的使用需要在Builder中通过RegsiterWindowBindingObject<TestWindowBindingObject>()方法注册这个对象。使用RegsiterWindowBindingObject<T>方法来注册JavaScript Window Binding Object这个方法会自动创建一个T类型的实例并将这个实例自动注册到主进程和渲染进程的JavaScript环境中。
// Demonstrates the usage of JavaScript Window Binding Object. It is required to register this object in the Builder using the RegisterWindowBindingObject<TestWindowBindingObject>() method. The RegisterWindowBindingObject<T> method is used to register the JavaScript Window Binding Object. This method automatically creates an instance of type T and registers it in the JavaScript environment of both the main process and the rendering process.
// 使用RegsiterWindowBindingObject还提供了另外一种方式就是直接传入代理来注册对象实例这个对象实例必须继承自JavaScriptWindowBindingObject类如果你的应用使用了独立的Subprocess那么在Subprocess中也需要注册这个对象实例。(类型0.9版本的那种方式)
// The RegisterWindowBindingObject also provides another way to register object instances by directly passing a proxy. The object instance must inherit from the JavaScriptWindowBindingObject class. If your application uses a separate subprocess, you also need to register this object instance in the subprocess. (This is the approach used in version 0.9 of the library.)
// 所以建议使用RegsiterWindowBindingObject<T>方法来注册。
// Therefore, it is recommended to use the RegsiterWindowBindingObject<T> method to register.
internal class TestWindowBindingObject : JavaScriptWindowBindingObject
{
public override string Name => "TestWindowBindingObject";
// Window Binding Object的JavaScript代码这个代码会被注入到JavaScript环境中。这个根据实际情况进行编写具体内容请自行参考CEF的JavaScript Window Binding Object的相关文档。
// JavaScript code for the Window Binding Object, which will be injected into the JavaScript environment. This code should be written based on your specific requirements. Please refer to the relevant documentation of CEF's JavaScript Window Binding Object for specific details.
public override string JavaScriptWindowBindingCode => """"
var TestWindowBindingObject = {
a: 1,
b: function (a, b) {
return a + b;
},
test: function(message){
native function TestMethod();
return TestMethod(message);
},
testAsync: function(message, num){
native function TestMethodAsync();
return TestMethodAsync(message,num);
}
};
"""";
public TestWindowBindingObject()
{
// 注册同步方法带有Formium参数的方法表示这个方法行在主进程中不带Formium参数的方法表示这个方法运行在渲染进程中。
// Registering synchronous methods. Methods with the Formium parameter indicate that they run in the main process, while methods without the Formium parameter indicate that they run in the rendering process.
RegisterSynchronousNativeFunction(TestMethod);
// 注册异步方法带有Formium参数的方法表示这个方法行在主进程中不带Formium参数的方法表示这个方法运行在渲染进程中。
// Registering asynchronous methods. Methods with the Formium parameter indicate that they run in the main process, while methods without the Formium parameter indicate that they run in the rendering process.
RegisterAsynchronousNativeFunction(TestMethodAsync);
}
public JavaScriptValue? TestMethod(Formium sender, JavaScriptArray arguments)
{
var stringArg = arguments.FirstOrDefault(x => x.ValueType == JavaScriptValueType.String)?.GetString()??string.Empty;
MessageBox.Show(sender, $"JS Say:{stringArg}");
return null;
}
public async void TestMethodAsync(Formium sender, JavaScriptArray arguments, JavaScriptPromise promise)
{
var stringArg = arguments.FirstOrDefault(x => x.ValueType == JavaScriptValueType.String)?.GetString() ?? string.Empty;
var intArg = arguments.FirstOrDefault(x => x.ValueType == JavaScriptValueType.Number)?.GetInt() ?? 0;
System.Diagnostics.Debug.WriteLine($"JS Say:{stringArg}");
var rnd = new Random(DateTime.Now.Millisecond);
var delayed = rnd.Next(1, 5000);
// 模拟一个异步操作
// Simulating an asynchronous operation
await Task.Delay(delayed);
promise.Resolve($"Hello from C# with value:{intArg} and delayed:{delayed}ms.");
}
}

@ -0,0 +1,80 @@
<?xml version="1.0" encoding="utf-8"?>
<assembly manifestVersion="1.0" xmlns="urn:schemas-microsoft-com:asm.v1">
<assemblyIdentity version="1.0.0.0" name="MyApplication.app"/>
<trustInfo xmlns="urn:schemas-microsoft-com:asm.v2">
<security>
<requestedPrivileges xmlns="urn:schemas-microsoft-com:asm.v3">
<!-- UAC 清单选项
如果想要更改 Windows 用户帐户控制级别,请使用
以下节点之一替换 requestedExecutionLevel 节点。
<requestedExecutionLevel level="asInvoker" uiAccess="false" />
<requestedExecutionLevel level="requireAdministrator" uiAccess="false" />
<requestedExecutionLevel level="highestAvailable" uiAccess="false" />
指定 requestedExecutionLevel 元素将禁用文件和注册表虚拟化。
如果你的应用程序需要此虚拟化来实现向后兼容性,则移除此
元素。
-->
<requestedExecutionLevel level="asInvoker" uiAccess="false" />
</requestedPrivileges>
</security>
</trustInfo>
<compatibility xmlns="urn:schemas-microsoft-com:compatibility.v1">
<application>
<!-- 设计此应用程序与其一起工作且已针对此应用程序进行测试的
Windows 版本的列表。取消评论适当的元素,
Windows 将自动选择最兼容的环境。 -->
<!-- Windows Vista -->
<!--<supportedOS Id="{e2011457-1546-43c5-a5fe-008deee3d3f0}" />-->
<!-- Windows 7 -->
<supportedOS Id="{35138b9a-5d96-4fbd-8e2d-a2440225f93a}" />
<!-- Windows 8 -->
<supportedOS Id="{4a2f28e3-53b9-4441-ba9c-d69d4a4a6e38}" />
<!-- Windows 8.1 -->
<supportedOS Id="{1f676c76-80e1-4239-95bb-83d0f6d0da78}" />
<!-- Windows 10 -->
<supportedOS Id="{8e0f7a12-bfb3-4fe8-b9a5-48fd50a15a9a}" />
</application>
</compatibility>
<!-- 指示该应用程序可感知 DPI 且 Windows 在 DPI 较高时将不会对其进行
自动缩放。Windows Presentation Foundation (WPF)应用程序自动感知 DPI无需
选择加入。选择加入此设置的 Windows 窗体应用程序(面向 .NET Framework 4.6)还应
在其 app.config 中将 "EnableWindowsFormsHighDpiAutoResizing" 设置设置为 "true"。
将应用程序设为感知长路径。请参阅 https://docs.microsoft.com/windows/win32/fileio/maximum-file-path-limitation -->
<application xmlns="urn:schemas-microsoft-com:asm.v3">
<windowsSettings>
<dpiAware xmlns="http://schemas.microsoft.com/SMI/2005/WindowsSettings">true</dpiAware>
<dpiAwareness xmlns="http://schemas.microsoft.com/SMI/2016/WindowsSettings">PerMonitorV2</dpiAwareness>
<longPathAware xmlns="http://schemas.microsoft.com/SMI/2016/WindowsSettings">true</longPathAware>
</windowsSettings>
</application>
<!-- 启用 Windows 公共控件和对话框的主题(Windows XP 和更高版本) -->
<dependency>
<dependentAssembly>
<assemblyIdentity
type="win32"
name="Microsoft.Windows.Common-Controls"
version="6.0.0.0"
processorArchitecture="*"
publicKeyToken="6595b64144ccf1df"
language="*"
/>
</dependentAssembly>
</dependency>
</assembly>

@ -0,0 +1,25 @@
<!DOCTYPE html>
<html lang="en" xmlns="http://www.w3.org/1999/xhtml">
<head>
<meta charset="utf-8" />
<title>doc</title>
<script src="jq^&~`u%@,e!ry-(2.4.4)-中文测试/jq@ue$r&y-(2.2.4).js?myname=yourdaddy"></script>
</head>
<body>
<h1 title="Hint Test">Hello!</h1>
<a href="https://cn.bing.com" target="_blank">打开外链测试</a>
<hr />
<p>新版本改进了对嵌入资源特殊文件名查找的逻辑,理论上不会再出现前端文件名带特殊字符导致文件无法加载的问题了。</p>
<p>例如“jq^&~`u%@,e!ry-(2.4.4)-中文测试\jq@ue$r&y-(2.2.4).js” 这个文件,已经可以正常访问了。</p>
<hr />
<h2>窗体内部指令测试</h2>
<p formium-command="maximize">Maximize测试</p>
<p formium-command="minimize">Minimize测试</p>
<p formium-command="restore">Restore测试</p>
<p formium-command="close">Close测试</p>
</body>
</html>

@ -0,0 +1,34 @@
// THIS FILE IS PART OF WinFormium PROJECT
// THE WinFormium PROJECT IS AN OPENSOURCE LIBRARY LICENSED UNDER THE MIT License.
// COPYRIGHTS (C) Xuanchen Lin. ALL RIGHTS RESERVED.
// GITHUB: https://github.com/XuanchenLin/NanUI
using WinFormium;
namespace WinFormiumSubProcess;
internal static class Program
{
/// <summary>
/// The main entry point for the application.
/// </summary>
[STAThread]
static void Main()
{
// To customize application configuration such as set high DPI settings or default font,
// see https://aka.ms/applicationconfiguration.
#if NETCOREAPP3_0_OR_GREATER
ApplicationConfiguration.Initialize();
#else
Application.EnableVisualStyles();
Application.SetCompatibleTextRenderingDefault(false);
#endif
var builder = WinFormiumApp.CreateBuilder();
var app = builder.Build();
app.RunAsSubprocess();
}
}

@ -0,0 +1,73 @@
//------------------------------------------------------------------------------
// <auto-generated>
// 此代码由工具生成。
// 运行时版本:4.0.30319.42000
//
// 对此文件的更改可能会导致不正确的行为,并且如果
// 重新生成代码,这些更改将会丢失。
// </auto-generated>
//------------------------------------------------------------------------------
namespace WinFormiumSubProcess.Properties {
using System;
/// <summary>
/// 一个强类型的资源类,用于查找本地化的字符串等。
/// </summary>
// 此类是由 StronglyTypedResourceBuilder
// 类通过类似于 ResGen 或 Visual Studio 的工具自动生成的。
// 若要添加或移除成员,请编辑 .ResX 文件,然后重新运行 ResGen
// (以 /str 作为命令选项),或重新生成 VS 项目。
[global::System.CodeDom.Compiler.GeneratedCodeAttribute("System.Resources.Tools.StronglyTypedResourceBuilder", "17.0.0.0")]
[global::System.Diagnostics.DebuggerNonUserCodeAttribute()]
[global::System.Runtime.CompilerServices.CompilerGeneratedAttribute()]
internal class Resources {
private static global::System.Resources.ResourceManager resourceMan;
private static global::System.Globalization.CultureInfo resourceCulture;
[global::System.Diagnostics.CodeAnalysis.SuppressMessageAttribute("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")]
internal Resources() {
}
/// <summary>
/// 返回此类使用的缓存的 ResourceManager 实例。
/// </summary>
[global::System.ComponentModel.EditorBrowsableAttribute(global::System.ComponentModel.EditorBrowsableState.Advanced)]
internal static global::System.Resources.ResourceManager ResourceManager {
get {
if (object.ReferenceEquals(resourceMan, null)) {
global::System.Resources.ResourceManager temp = new global::System.Resources.ResourceManager("WinFormiumSubProcess.Properties.Resources", typeof(Resources).Assembly);
resourceMan = temp;
}
return resourceMan;
}
}
/// <summary>
/// 重写当前线程的 CurrentUICulture 属性,对
/// 使用此强类型资源类的所有资源查找执行重写。
/// </summary>
[global::System.ComponentModel.EditorBrowsableAttribute(global::System.ComponentModel.EditorBrowsableState.Advanced)]
internal static global::System.Globalization.CultureInfo Culture {
get {
return resourceCulture;
}
set {
resourceCulture = value;
}
}
/// <summary>
/// 查找类似于 (图标) 的 System.Drawing.Icon 类型的本地化资源。
/// </summary>
internal static System.Drawing.Icon SubprocessIcon {
get {
object obj = ResourceManager.GetObject("SubprocessIcon", resourceCulture);
return ((System.Drawing.Icon)(obj));
}
}
}
}

@ -0,0 +1,124 @@
<?xml version="1.0" encoding="utf-8"?>
<root>
<!--
Microsoft ResX Schema
Version 2.0
The primary goals of this format is to allow a simple XML format
that is mostly human readable. The generation and parsing of the
various data types are done through the TypeConverter classes
associated with the data types.
Example:
... ado.net/XML headers & schema ...
<resheader name="resmimetype">text/microsoft-resx</resheader>
<resheader name="version">2.0</resheader>
<resheader name="reader">System.Resources.ResXResourceReader, System.Windows.Forms, ...</resheader>
<resheader name="writer">System.Resources.ResXResourceWriter, System.Windows.Forms, ...</resheader>
<data name="Name1"><value>this is my long string</value><comment>this is a comment</comment></data>
<data name="Color1" type="System.Drawing.Color, System.Drawing">Blue</data>
<data name="Bitmap1" mimetype="application/x-microsoft.net.object.binary.base64">
<value>[base64 mime encoded serialized .NET Framework object]</value>
</data>
<data name="Icon1" type="System.Drawing.Icon, System.Drawing" mimetype="application/x-microsoft.net.object.bytearray.base64">
<value>[base64 mime encoded string representing a byte array form of the .NET Framework object]</value>
<comment>This is a comment</comment>
</data>
There are any number of "resheader" rows that contain simple
name/value pairs.
Each data row contains a name, and value. The row also contains a
type or mimetype. Type corresponds to a .NET class that support
text/value conversion through the TypeConverter architecture.
Classes that don't support this are serialized and stored with the
mimetype set.
The mimetype is used for serialized objects, and tells the
ResXResourceReader how to depersist the object. This is currently not
extensible. For a given mimetype the value must be set accordingly:
Note - application/x-microsoft.net.object.binary.base64 is the format
that the ResXResourceWriter will generate, however the reader can
read any of the formats listed below.
mimetype: application/x-microsoft.net.object.binary.base64
value : The object must be serialized with
: System.Runtime.Serialization.Formatters.Binary.BinaryFormatter
: and then encoded with base64 encoding.
mimetype: application/x-microsoft.net.object.soap.base64
value : The object must be serialized with
: System.Runtime.Serialization.Formatters.Soap.SoapFormatter
: and then encoded with base64 encoding.
mimetype: application/x-microsoft.net.object.bytearray.base64
value : The object must be serialized into a byte array
: using a System.ComponentModel.TypeConverter
: and then encoded with base64 encoding.
-->
<xsd:schema id="root" xmlns="" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:msdata="urn:schemas-microsoft-com:xml-msdata">
<xsd:import namespace="http://www.w3.org/XML/1998/namespace" />
<xsd:element name="root" msdata:IsDataSet="true">
<xsd:complexType>
<xsd:choice maxOccurs="unbounded">
<xsd:element name="metadata">
<xsd:complexType>
<xsd:sequence>
<xsd:element name="value" type="xsd:string" minOccurs="0" />
</xsd:sequence>
<xsd:attribute name="name" use="required" type="xsd:string" />
<xsd:attribute name="type" type="xsd:string" />
<xsd:attribute name="mimetype" type="xsd:string" />
<xsd:attribute ref="xml:space" />
</xsd:complexType>
</xsd:element>
<xsd:element name="assembly">
<xsd:complexType>
<xsd:attribute name="alias" type="xsd:string" />
<xsd:attribute name="name" type="xsd:string" />
</xsd:complexType>
</xsd:element>
<xsd:element name="data">
<xsd:complexType>
<xsd:sequence>
<xsd:element name="value" type="xsd:string" minOccurs="0" msdata:Ordinal="1" />
<xsd:element name="comment" type="xsd:string" minOccurs="0" msdata:Ordinal="2" />
</xsd:sequence>
<xsd:attribute name="name" type="xsd:string" use="required" msdata:Ordinal="1" />
<xsd:attribute name="type" type="xsd:string" msdata:Ordinal="3" />
<xsd:attribute name="mimetype" type="xsd:string" msdata:Ordinal="4" />
<xsd:attribute ref="xml:space" />
</xsd:complexType>
</xsd:element>
<xsd:element name="resheader">
<xsd:complexType>
<xsd:sequence>
<xsd:element name="value" type="xsd:string" minOccurs="0" msdata:Ordinal="1" />
</xsd:sequence>
<xsd:attribute name="name" type="xsd:string" use="required" />
</xsd:complexType>
</xsd:element>
</xsd:choice>
</xsd:complexType>
</xsd:element>
</xsd:schema>
<resheader name="resmimetype">
<value>text/microsoft-resx</value>
</resheader>
<resheader name="version">
<value>2.0</value>
</resheader>
<resheader name="reader">
<value>System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
</resheader>
<resheader name="writer">
<value>System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
</resheader>
<assembly alias="System.Windows.Forms" name="System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089" />
<data name="SubprocessIcon" type="System.Resources.ResXFileRef, System.Windows.Forms">
<value>..\Resources\SubprocessIcon.ico;System.Drawing.Icon, System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a</value>
</data>
</root>

Binary file not shown.

After

Width:  |  Height:  |  Size: 334 KiB

@ -0,0 +1,42 @@
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<OutputType>WinExe</OutputType>
<TargetFrameworks>net6.0-windows;net481;</TargetFrameworks>
<Nullable>enable</Nullable>
<UseWindowsForms>true</UseWindowsForms>
<ImplicitUsings>enable</ImplicitUsings>
<AssemblyTitle>WinFormium Subprocee App</AssemblyTitle>
<ApplicationVisualStyles>true</ApplicationVisualStyles>
<ApplicationUseCompatibleTextRendering>true</ApplicationUseCompatibleTextRendering>
<ApplicationHighDpiMode>PerMonitorV2</ApplicationHighDpiMode>
<ApplicationDefaultFont>Microsoft Yahei, 8.25pt</ApplicationDefaultFont>
<BaseOutputPath>$(BinDir)\$(MSBuildProjectName)\..\MinimalWinFormiumApp\</BaseOutputPath>
<ApplicationIcon>Resources\SubprocessIcon.ico</ApplicationIcon>
<ApplicationManifest>app.manifest</ApplicationManifest>
</PropertyGroup>
<ItemGroup>
<Content Include="Resources\SubprocessIcon.ico" />
</ItemGroup>
<ItemGroup>
<ProjectReference Include="..\..\src\WinFormium\WinFormium.csproj" />
</ItemGroup>
<ItemGroup>
<Compile Update="Properties\Resources.Designer.cs">
<DesignTime>True</DesignTime>
<AutoGen>True</AutoGen>
<DependentUpon>Resources.resx</DependentUpon>
</Compile>
</ItemGroup>
<ItemGroup>
<EmbeddedResource Update="Properties\Resources.resx">
<Generator>ResXFileCodeGenerator</Generator>
<LastGenOutput>Resources.Designer.cs</LastGenOutput>
</EmbeddedResource>
</ItemGroup>
</Project>

@ -0,0 +1,80 @@
<?xml version="1.0" encoding="utf-8"?>
<assembly manifestVersion="1.0" xmlns="urn:schemas-microsoft-com:asm.v1">
<assemblyIdentity version="1.0.0.0" name="MyApplication.app"/>
<trustInfo xmlns="urn:schemas-microsoft-com:asm.v2">
<security>
<requestedPrivileges xmlns="urn:schemas-microsoft-com:asm.v3">
<!-- UAC 清单选项
如果想要更改 Windows 用户帐户控制级别,请使用
以下节点之一替换 requestedExecutionLevel 节点。
<requestedExecutionLevel level="asInvoker" uiAccess="false" />
<requestedExecutionLevel level="requireAdministrator" uiAccess="false" />
<requestedExecutionLevel level="highestAvailable" uiAccess="false" />
指定 requestedExecutionLevel 元素将禁用文件和注册表虚拟化。
如果你的应用程序需要此虚拟化来实现向后兼容性,则移除此
元素。
-->
<requestedExecutionLevel level="asInvoker" uiAccess="false" />
</requestedPrivileges>
</security>
</trustInfo>
<compatibility xmlns="urn:schemas-microsoft-com:compatibility.v1">
<application>
<!-- 设计此应用程序与其一起工作且已针对此应用程序进行测试的
Windows 版本的列表。取消评论适当的元素,
Windows 将自动选择最兼容的环境。 -->
<!-- Windows Vista -->
<!--<supportedOS Id="{e2011457-1546-43c5-a5fe-008deee3d3f0}" />-->
<!-- Windows 7 -->
<supportedOS Id="{35138b9a-5d96-4fbd-8e2d-a2440225f93a}" />
<!-- Windows 8 -->
<supportedOS Id="{4a2f28e3-53b9-4441-ba9c-d69d4a4a6e38}" />
<!-- Windows 8.1 -->
<supportedOS Id="{1f676c76-80e1-4239-95bb-83d0f6d0da78}" />
<!-- Windows 10 -->
<supportedOS Id="{8e0f7a12-bfb3-4fe8-b9a5-48fd50a15a9a}" />
</application>
</compatibility>
<!-- 指示该应用程序可感知 DPI 且 Windows 在 DPI 较高时将不会对其进行
自动缩放。Windows Presentation Foundation (WPF)应用程序自动感知 DPI无需
选择加入。选择加入此设置的 Windows 窗体应用程序(面向 .NET Framework 4.6)还应
在其 app.config 中将 "EnableWindowsFormsHighDpiAutoResizing" 设置设置为 "true"。
将应用程序设为感知长路径。请参阅 https://docs.microsoft.com/windows/win32/fileio/maximum-file-path-limitation -->
<application xmlns="urn:schemas-microsoft-com:asm.v3">
<windowsSettings>
<dpiAware xmlns="http://schemas.microsoft.com/SMI/2005/WindowsSettings">true</dpiAware>
<dpiAwareness xmlns="http://schemas.microsoft.com/SMI/2016/WindowsSettings">PerMonitorV2</dpiAwareness>
<longPathAware xmlns="http://schemas.microsoft.com/SMI/2016/WindowsSettings">true</longPathAware>
</windowsSettings>
</application>
<!-- 启用 Windows 公共控件和对话框的主题(Windows XP 和更高版本) -->
<dependency>
<dependentAssembly>
<assemblyIdentity
type="win32"
name="Microsoft.Windows.Common-Controls"
version="6.0.0.0"
processorArchitecture="*"
publicKeyToken="6595b64144ccf1df"
language="*"
/>
</dependentAssembly>
</dependency>
</assembly>
Loading…
Cancel
Save