@devscholar/node-ps1-dotnet 0.0.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/EnsureBom.ps1 +27 -0
- package/LICENSE.md +22 -0
- package/README.md +65 -0
- package/examples/console/await-delay/await-delay.ts +14 -0
- package/examples/console/console-input/console-input.ts +18 -0
- package/examples/winforms/counter/counter.ts +47 -0
- package/examples/winforms/drag-box/drag-box.ts +62 -0
- package/examples/wpf/counter/counter.ts +55 -0
- package/examples/wpf/drag-box/drag-box.ts +84 -0
- package/examples/wpf/webview2-browser/WebView2Libs/Microsoft.Web.WebView2.Core.dll +0 -0
- package/examples/wpf/webview2-browser/WebView2Libs/Microsoft.Web.WebView2.Core.dll.backup +0 -0
- package/examples/wpf/webview2-browser/WebView2Libs/Microsoft.Web.WebView2.Wpf.dll +0 -0
- package/examples/wpf/webview2-browser/WebView2Libs/Microsoft.Web.WebView2.Wpf.dll.backup +0 -0
- package/examples/wpf/webview2-browser/WebView2Libs/WebView2License.txt +27 -0
- package/examples/wpf/webview2-browser/counter.html +31 -0
- package/examples/wpf/webview2-browser/webview2-browser.ts +90 -0
- package/package.json +19 -0
- package/scripts/PsBridge/BridgeState.cs +39 -0
- package/scripts/PsBridge/Protocol.cs +222 -0
- package/scripts/PsBridge/PsBridge.psd1 +10 -0
- package/scripts/PsBridge/PsBridge.psm1 +22 -0
- package/scripts/PsBridge/PsHost.cs +393 -0
- package/scripts/PsBridge/PsHostEntry.cs +23 -0
- package/scripts/PsBridge/Reflection.cs +830 -0
- package/scripts/PsHost.ps1 +11 -0
- package/src/index.ts +510 -0
- package/src/ipc.ts +182 -0
- package/src/types.ts +21 -0
- package/src/utils.ts +13 -0
- package/start.js +67 -0
- package/tsconfig.json +14 -0
package/EnsureBom.ps1
ADDED
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
$ErrorActionPreference = 'Stop'
|
|
2
|
+
|
|
3
|
+
$extensions = @('.c', '.cpp', '.ps1')
|
|
4
|
+
$rootPath = (Get-Location).Path
|
|
5
|
+
$scriptPath = $MyInvocation.MyCommand.Path
|
|
6
|
+
|
|
7
|
+
$files = Get-ChildItem -Path $rootPath -Recurse -File | Where-Object { $extensions -contains $_.Extension }
|
|
8
|
+
|
|
9
|
+
foreach ($file in $files) {
|
|
10
|
+
if ($file.FullName -eq $scriptPath) {
|
|
11
|
+
continue
|
|
12
|
+
}
|
|
13
|
+
|
|
14
|
+
$bytes = [System.IO.File]::ReadAllBytes($file.FullName)
|
|
15
|
+
$hasBom = $bytes.Length -ge 3 -and $bytes[0] -eq 0xEF -and $bytes[1] -eq 0xBB -and $bytes[2] -eq 0xBF
|
|
16
|
+
|
|
17
|
+
if ($hasBom) {
|
|
18
|
+
Write-Host "Skipped (already BOM): $($file.FullName)"
|
|
19
|
+
continue
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
$content = [System.Text.Encoding]::UTF8.GetString($bytes)
|
|
23
|
+
[System.IO.File]::WriteAllText($file.FullName, $content, [System.Text.UTF8Encoding]::new($true))
|
|
24
|
+
Write-Host "Converted: $($file.FullName)"
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
Write-Host "Done."
|
package/LICENSE.md
ADDED
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) DevScholar
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
|
22
|
+
|
package/README.md
ADDED
|
@@ -0,0 +1,65 @@
|
|
|
1
|
+
# Node PS1 for .NET
|
|
2
|
+
|
|
3
|
+
⚠️ This project is still in pre-alpha stage, and API is subject to change.
|
|
4
|
+
|
|
5
|
+
This is a project that mimics the [Node API for .NET](https://github.com/microsoft/node-api-dotnet), aiming to utilize the built-in PowerShell 5.1 in Windows to replace the full high-version .NET runtime, thereby reducing the program's size. Since this project uses IPC instead of C++ Addon, it is compatible not only with Node but also with Deno and Bun. You can run its example programs in the examples folder.
|
|
6
|
+
|
|
7
|
+
# Requirements
|
|
8
|
+
|
|
9
|
+
- **Node.js** 22+ (uses `--experimental-transform-types` for native TypeScript support)
|
|
10
|
+
- **PowerShell** 5.1 (built-in on Windows 10/11)
|
|
11
|
+
- **.NET Framework** 4.5+ (required by PowerShell 5.1, pre-installed on Windows 10/11)
|
|
12
|
+
|
|
13
|
+
> Note: This project is Windows-only due to its dependency on PowerShell 5.1.
|
|
14
|
+
|
|
15
|
+
# Examples
|
|
16
|
+
|
|
17
|
+
You can use the `--runtime=[node|deno|bun]` option to specify the runtime. For example:
|
|
18
|
+
|
|
19
|
+
```bat
|
|
20
|
+
node start.js examples/console/console-input/console-input.ts --runtime=deno
|
|
21
|
+
```
|
|
22
|
+
|
|
23
|
+
## Console Apps
|
|
24
|
+
|
|
25
|
+
### Console Input App
|
|
26
|
+
|
|
27
|
+
```bat
|
|
28
|
+
node start.js examples/console/console-input/console-input.ts
|
|
29
|
+
```
|
|
30
|
+
### Await Delay App
|
|
31
|
+
|
|
32
|
+
```bat
|
|
33
|
+
node start.js examples/console/await-delay/await-delay.ts
|
|
34
|
+
```
|
|
35
|
+
|
|
36
|
+
## GUI Apps
|
|
37
|
+
|
|
38
|
+
### WinForms Counter App
|
|
39
|
+
|
|
40
|
+
```bat
|
|
41
|
+
node start.js examples/winforms/counter/counter.ts
|
|
42
|
+
```
|
|
43
|
+
### WinForms Drag Box App
|
|
44
|
+
|
|
45
|
+
```bat
|
|
46
|
+
node start.js examples/winforms/drag-box/drag-box.ts
|
|
47
|
+
```
|
|
48
|
+
### WPF Counter App
|
|
49
|
+
|
|
50
|
+
```bat
|
|
51
|
+
node start.js examples/wpf/counter/counter.ts
|
|
52
|
+
```
|
|
53
|
+
### WPF Drag Box App
|
|
54
|
+
|
|
55
|
+
```bat
|
|
56
|
+
node start.js examples/wpf/drag-box/drag-box.ts
|
|
57
|
+
```
|
|
58
|
+
### WPF WebView2 Browser
|
|
59
|
+
|
|
60
|
+
```bat
|
|
61
|
+
node start.js examples/wpf/webview2-browser/webview2-browser.ts
|
|
62
|
+
```
|
|
63
|
+
# License
|
|
64
|
+
|
|
65
|
+
This project is licensed under the MIT License. See the [LICENSE](LICENSE.md) file for details.
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
// examples/console/await-delay/await-delay.ts
|
|
2
|
+
import dotnet from '../../../src/index.ts';
|
|
3
|
+
|
|
4
|
+
const System = dotnet.System as any;
|
|
5
|
+
const Console = System.Console;
|
|
6
|
+
const Task = System.Threading.Tasks.Task;
|
|
7
|
+
const Path = System.IO.Path;
|
|
8
|
+
|
|
9
|
+
Console.WriteLine('0s');
|
|
10
|
+
await Task.Delay(1000);
|
|
11
|
+
await Console.Out.WriteLineAsync("1s");
|
|
12
|
+
await Task.Delay(1000);
|
|
13
|
+
await Console.Out.WriteLineAsync("2s");
|
|
14
|
+
await Task.Delay(1000);
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
// examples/console/console-input/console-input.ts
|
|
2
|
+
import dotnet from '../../../src/index.ts';
|
|
3
|
+
|
|
4
|
+
const System = dotnet.System as any;
|
|
5
|
+
const Console = System.Console;
|
|
6
|
+
|
|
7
|
+
Console.WriteLine("=== Greeting Program ===");
|
|
8
|
+
Console.Write("Please enter your name: ");
|
|
9
|
+
|
|
10
|
+
const name = Console.ReadLine();
|
|
11
|
+
|
|
12
|
+
if (name && name.trim() !== "") {
|
|
13
|
+
Console.WriteLine(`Hello, ${name}! Welcome to this program!`);
|
|
14
|
+
} else {
|
|
15
|
+
Console.WriteLine("Hello, friend! Welcome to this program!");
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
Console.WriteLine("Program ended.");
|
|
@@ -0,0 +1,47 @@
|
|
|
1
|
+
// examples/winforms/counter/counter.ts
|
|
2
|
+
import dotnet from '../../../src/index.ts';
|
|
3
|
+
|
|
4
|
+
dotnet.load('System.Windows.Forms');
|
|
5
|
+
dotnet.load('System.Drawing');
|
|
6
|
+
|
|
7
|
+
const System = dotnet.System as any;
|
|
8
|
+
const Forms = System.Windows.Forms;
|
|
9
|
+
const Drawing = System.Drawing;
|
|
10
|
+
|
|
11
|
+
let clickCount = 0;
|
|
12
|
+
|
|
13
|
+
console.log("--- WinForms Counter (XP Style) ---");
|
|
14
|
+
|
|
15
|
+
Forms.Application.EnableVisualStyles();
|
|
16
|
+
Forms.Application.SetCompatibleTextRenderingDefault(false);
|
|
17
|
+
|
|
18
|
+
const form = new Forms.Form();
|
|
19
|
+
form.Text = "Counter App";
|
|
20
|
+
form.Width = 640;
|
|
21
|
+
form.Height = 480;
|
|
22
|
+
form.StartPosition = 1;
|
|
23
|
+
|
|
24
|
+
const label = new Forms.Label();
|
|
25
|
+
label.Text = "Clicks: 0";
|
|
26
|
+
label.Font = new Drawing.Font("Arial", 24);
|
|
27
|
+
label.AutoSize = true;
|
|
28
|
+
label.Location = new Drawing.Point(90, 30);
|
|
29
|
+
form.Controls.Add(label);
|
|
30
|
+
|
|
31
|
+
const button = new Forms.Button();
|
|
32
|
+
button.Text = "Click to Add";
|
|
33
|
+
button.Font = new Drawing.Font("Arial", 14);
|
|
34
|
+
button.AutoSize = true;
|
|
35
|
+
button.Location = new Drawing.Point(100, 90);
|
|
36
|
+
|
|
37
|
+
button.add_Click(() => {
|
|
38
|
+
clickCount++;
|
|
39
|
+
const message = `Clicked ${clickCount} times`;
|
|
40
|
+
label.Text = message;
|
|
41
|
+
console.log(message);
|
|
42
|
+
});
|
|
43
|
+
|
|
44
|
+
form.Controls.Add(button);
|
|
45
|
+
|
|
46
|
+
console.log("Click the button to increase the counter...");
|
|
47
|
+
Forms.Application.Run(form);
|
|
@@ -0,0 +1,62 @@
|
|
|
1
|
+
// examples/winforms/drag-box/drag-box.ts
|
|
2
|
+
import dotnet from '../../../src/index.ts';
|
|
3
|
+
|
|
4
|
+
dotnet.load('System.Windows.Forms');
|
|
5
|
+
dotnet.load('System.Drawing');
|
|
6
|
+
|
|
7
|
+
const System = dotnet.System as any;
|
|
8
|
+
const Forms = System.Windows.Forms;
|
|
9
|
+
const Drawing = System.Drawing;
|
|
10
|
+
|
|
11
|
+
console.log("--- WinForms Draggable Box ---");
|
|
12
|
+
|
|
13
|
+
Forms.Application.EnableVisualStyles();
|
|
14
|
+
Forms.Application.SetCompatibleTextRenderingDefault(false);
|
|
15
|
+
|
|
16
|
+
const form = new Forms.Form();
|
|
17
|
+
form.Text = "Draggable Box Example (High Frequency IPC)";
|
|
18
|
+
form.Width = 800;
|
|
19
|
+
form.Height = 600;
|
|
20
|
+
form.StartPosition = 1; // CenterScreen
|
|
21
|
+
|
|
22
|
+
const box = new Forms.Panel();
|
|
23
|
+
box.BackColor = Drawing.Color.Red;
|
|
24
|
+
box.Width = 100;
|
|
25
|
+
box.Height = 100;
|
|
26
|
+
|
|
27
|
+
// Track position locally to avoid synchronous read overhead over IPC
|
|
28
|
+
let currentX = 350;
|
|
29
|
+
let currentY = 250;
|
|
30
|
+
box.Location = new Drawing.Point(currentX, currentY);
|
|
31
|
+
|
|
32
|
+
form.Controls.Add(box);
|
|
33
|
+
|
|
34
|
+
// State tracking for drag and drop
|
|
35
|
+
let isDragging = false;
|
|
36
|
+
let startDragOffsetX = 0;
|
|
37
|
+
let startDragOffsetY = 0;
|
|
38
|
+
|
|
39
|
+
box.add_MouseDown((sender: any, e: any) => {
|
|
40
|
+
isDragging = true;
|
|
41
|
+
startDragOffsetX = e.X;
|
|
42
|
+
startDragOffsetY = e.Y;
|
|
43
|
+
box.BackColor = Drawing.Color.DarkRed; // Visual feedback
|
|
44
|
+
});
|
|
45
|
+
|
|
46
|
+
box.add_MouseUp((sender: any, e: any) => {
|
|
47
|
+
isDragging = false;
|
|
48
|
+
box.BackColor = Drawing.Color.Red;
|
|
49
|
+
});
|
|
50
|
+
|
|
51
|
+
box.add_MouseMove((sender: any, e: any) => {
|
|
52
|
+
if (isDragging) {
|
|
53
|
+
currentX = currentX + e.X - startDragOffsetX;
|
|
54
|
+
currentY = currentY + e.Y - startDragOffsetY;
|
|
55
|
+
|
|
56
|
+
box.Left = currentX;
|
|
57
|
+
box.Top = currentY;
|
|
58
|
+
}
|
|
59
|
+
});
|
|
60
|
+
|
|
61
|
+
console.log("Initialization complete. Try dragging the red box!");
|
|
62
|
+
Forms.Application.Run(form);
|
|
@@ -0,0 +1,55 @@
|
|
|
1
|
+
import dotnet from '../../../src/index.ts';
|
|
2
|
+
|
|
3
|
+
dotnet.load('PresentationFramework');
|
|
4
|
+
dotnet.load('PresentationCore');
|
|
5
|
+
dotnet.load('WindowsBase');
|
|
6
|
+
|
|
7
|
+
const System = dotnet.System as any;
|
|
8
|
+
const Windows = System.Windows;
|
|
9
|
+
const Controls = System.Windows.Controls;
|
|
10
|
+
const Media = System.Windows.Media;
|
|
11
|
+
|
|
12
|
+
let clickCount = 0;
|
|
13
|
+
|
|
14
|
+
console.log("--- WPF Counter ---");
|
|
15
|
+
|
|
16
|
+
const mainWindow = new Windows.Window();
|
|
17
|
+
mainWindow.Title = "WPF Counter App";
|
|
18
|
+
mainWindow.Width = 400;
|
|
19
|
+
mainWindow.Height = 300;
|
|
20
|
+
mainWindow.WindowStartupLocation = Windows.WindowStartupLocation.CenterScreen;
|
|
21
|
+
|
|
22
|
+
const stackPanel = new Controls.StackPanel();
|
|
23
|
+
stackPanel.Margin = new Windows.Thickness(20);
|
|
24
|
+
stackPanel.HorizontalAlignment = Windows.HorizontalAlignment.Center;
|
|
25
|
+
stackPanel.VerticalAlignment = Windows.VerticalAlignment.Center;
|
|
26
|
+
|
|
27
|
+
const label = new Controls.Label();
|
|
28
|
+
label.Content = "Clicks: 0";
|
|
29
|
+
label.FontSize = 32;
|
|
30
|
+
label.FontFamily = new Media.FontFamily("Arial");
|
|
31
|
+
label.HorizontalContentAlignment = Windows.HorizontalAlignment.Center;
|
|
32
|
+
label.Margin = new Windows.Thickness(0, 0, 0, 20);
|
|
33
|
+
stackPanel.Children.Add(label);
|
|
34
|
+
|
|
35
|
+
const button = new Controls.Button();
|
|
36
|
+
button.Content = "Click to Add";
|
|
37
|
+
button.FontSize = 18;
|
|
38
|
+
button.Padding = new Windows.Thickness(20, 10, 20, 10);
|
|
39
|
+
button.HorizontalAlignment = Windows.HorizontalAlignment.Center;
|
|
40
|
+
|
|
41
|
+
button.add_Click((sender: any, e: any) => {
|
|
42
|
+
clickCount++;
|
|
43
|
+
const message = `Clicked ${clickCount} times`;
|
|
44
|
+
label.Content = message;
|
|
45
|
+
console.log(message);
|
|
46
|
+
});
|
|
47
|
+
|
|
48
|
+
stackPanel.Children.Add(button);
|
|
49
|
+
|
|
50
|
+
mainWindow.Content = stackPanel;
|
|
51
|
+
|
|
52
|
+
console.log("Click the button to increase the counter...");
|
|
53
|
+
|
|
54
|
+
const app = new Windows.Application();
|
|
55
|
+
app.Run(mainWindow);
|
|
@@ -0,0 +1,84 @@
|
|
|
1
|
+
// examples/wpf/drag-box/drag-box.ts
|
|
2
|
+
import dotnet from '../../../src/index.ts';
|
|
3
|
+
|
|
4
|
+
dotnet.load('PresentationFramework');
|
|
5
|
+
dotnet.load('PresentationCore');
|
|
6
|
+
dotnet.load('WindowsBase');
|
|
7
|
+
|
|
8
|
+
const System = dotnet.System as any;
|
|
9
|
+
const Windows = System.Windows;
|
|
10
|
+
const Controls = System.Windows.Controls;
|
|
11
|
+
const Media = System.Windows.Media;
|
|
12
|
+
const Input = System.Windows.Input;
|
|
13
|
+
|
|
14
|
+
console.log("--- WPF Draggable Box ---");
|
|
15
|
+
|
|
16
|
+
const mainWindow = new Windows.Window();
|
|
17
|
+
mainWindow.Title = "WPF Draggable Box Example (High Frequency IPC)";
|
|
18
|
+
mainWindow.Width = 800;
|
|
19
|
+
mainWindow.Height = 600;
|
|
20
|
+
mainWindow.WindowStartupLocation = Windows.WindowStartupLocation.CenterScreen;
|
|
21
|
+
|
|
22
|
+
// Create a canvas for absolute positioning
|
|
23
|
+
const canvas = new Controls.Canvas();
|
|
24
|
+
canvas.Background = Media.Brushes.LightGray;
|
|
25
|
+
|
|
26
|
+
// Create the draggable box
|
|
27
|
+
const box = new Controls.Border();
|
|
28
|
+
box.Width = 100;
|
|
29
|
+
box.Height = 100;
|
|
30
|
+
box.Background = Media.Brushes.Red;
|
|
31
|
+
box.BorderBrush = Media.Brushes.DarkRed;
|
|
32
|
+
box.BorderThickness = new Windows.Thickness(2);
|
|
33
|
+
|
|
34
|
+
const transform = new Media.TranslateTransform();
|
|
35
|
+
box.RenderTransform = transform;
|
|
36
|
+
|
|
37
|
+
transform.X = 350;
|
|
38
|
+
transform.Y = 250;
|
|
39
|
+
|
|
40
|
+
canvas.Children.Add(box);
|
|
41
|
+
|
|
42
|
+
// State tracking for drag and drop
|
|
43
|
+
let isDragging = false;
|
|
44
|
+
let startMouseX = 0;
|
|
45
|
+
let startMouseY = 0;
|
|
46
|
+
let startBoxX = 0;
|
|
47
|
+
let startBoxY = 0;
|
|
48
|
+
|
|
49
|
+
box.add_MouseDown((sender: any, e: any) => {
|
|
50
|
+
console.log('[DEBUG] MouseDown');
|
|
51
|
+
isDragging = true;
|
|
52
|
+
const pos = e.GetPosition(canvas);
|
|
53
|
+
startMouseX = pos.X;
|
|
54
|
+
startMouseY = pos.Y;
|
|
55
|
+
startBoxX = transform.X;
|
|
56
|
+
startBoxY = transform.Y;
|
|
57
|
+
box.Background = Media.Brushes.DarkRed;
|
|
58
|
+
box.CaptureMouse();
|
|
59
|
+
});
|
|
60
|
+
|
|
61
|
+
// Mouse up event - stop dragging
|
|
62
|
+
box.add_MouseUp((sender: any, e: any) => {
|
|
63
|
+
console.log('[DEBUG] MouseUp');
|
|
64
|
+
isDragging = false;
|
|
65
|
+
box.Background = Media.Brushes.Red;
|
|
66
|
+
box.ReleaseMouseCapture();
|
|
67
|
+
});
|
|
68
|
+
|
|
69
|
+
// Mouse move event - handle dragging
|
|
70
|
+
box.add_MouseMove((sender: any, e: any) => {
|
|
71
|
+
if (isDragging) {
|
|
72
|
+
const currentPos = e.GetPosition(canvas);
|
|
73
|
+
|
|
74
|
+
transform.X = startBoxX + (currentPos.X - startMouseX);
|
|
75
|
+
transform.Y = startBoxY + (currentPos.Y - startMouseY);
|
|
76
|
+
}
|
|
77
|
+
});
|
|
78
|
+
|
|
79
|
+
mainWindow.Content = canvas;
|
|
80
|
+
|
|
81
|
+
console.log("Initialization complete. Try dragging the red box!");
|
|
82
|
+
|
|
83
|
+
const app = new Windows.Application();
|
|
84
|
+
app.Run(mainWindow);
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
Copyright (C) Microsoft Corporation. All rights reserved.
|
|
2
|
+
|
|
3
|
+
Redistribution and use in source and binary forms, with or without
|
|
4
|
+
modification, are permitted provided that the following conditions are
|
|
5
|
+
met:
|
|
6
|
+
|
|
7
|
+
* Redistributions of source code must retain the above copyright
|
|
8
|
+
notice, this list of conditions and the following disclaimer.
|
|
9
|
+
* Redistributions in binary form must reproduce the above
|
|
10
|
+
copyright notice, this list of conditions and the following disclaimer
|
|
11
|
+
in the documentation and/or other materials provided with the
|
|
12
|
+
distribution.
|
|
13
|
+
* The name of Microsoft Corporation, or the names of its contributors
|
|
14
|
+
may not be used to endorse or promote products derived from this
|
|
15
|
+
software without specific prior written permission.
|
|
16
|
+
|
|
17
|
+
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
|
18
|
+
"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
|
19
|
+
LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
|
20
|
+
A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
|
21
|
+
OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
|
22
|
+
SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
|
23
|
+
LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
|
24
|
+
DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
|
25
|
+
THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
|
26
|
+
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
|
27
|
+
OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
<!DOCTYPE html>
|
|
2
|
+
<html lang="en">
|
|
3
|
+
<head>
|
|
4
|
+
<title>Counter</title>
|
|
5
|
+
<meta charset="UTF-8">
|
|
6
|
+
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
|
7
|
+
</head>
|
|
8
|
+
<body>
|
|
9
|
+
<h1>Counter App</h1>
|
|
10
|
+
<p id="display">Clicks: 0</p>
|
|
11
|
+
<button id="btn">Click to Add</button>
|
|
12
|
+
|
|
13
|
+
<script>
|
|
14
|
+
let clickCount = 0;
|
|
15
|
+
const display = document.getElementById('display');
|
|
16
|
+
const button = document.getElementById('btn');
|
|
17
|
+
|
|
18
|
+
button.addEventListener('click', function() {
|
|
19
|
+
clickCount++;
|
|
20
|
+
const message = 'Button clicked ' + clickCount + ' times';
|
|
21
|
+
display.textContent = message;
|
|
22
|
+
|
|
23
|
+
if (window.chrome && window.chrome.webview) {
|
|
24
|
+
window.chrome.webview.postMessage(message);
|
|
25
|
+
} else {
|
|
26
|
+
alert('chrome.webview not available! Click: ' + message);
|
|
27
|
+
}
|
|
28
|
+
});
|
|
29
|
+
</script>
|
|
30
|
+
</body>
|
|
31
|
+
</html>
|
|
@@ -0,0 +1,90 @@
|
|
|
1
|
+
import dotnet from '../../../src/index.ts';
|
|
2
|
+
import * as fs from 'node:fs';
|
|
3
|
+
import * as path from 'node:path';
|
|
4
|
+
import { fileURLToPath } from 'node:url';
|
|
5
|
+
|
|
6
|
+
const __filename = fileURLToPath(import.meta.url);
|
|
7
|
+
const __dirname = path.dirname(__filename);
|
|
8
|
+
|
|
9
|
+
const System = dotnet.System as any;
|
|
10
|
+
const Windows = System.Windows;
|
|
11
|
+
const Controls = System.Windows.Controls;
|
|
12
|
+
|
|
13
|
+
const webview2LibPath = path.join(__dirname, 'WebView2Libs');
|
|
14
|
+
|
|
15
|
+
try {
|
|
16
|
+
System.Reflection.Assembly.LoadFrom(path.join(webview2LibPath, 'Microsoft.Web.WebView2.Core.dll'));
|
|
17
|
+
System.Reflection.Assembly.LoadFrom(path.join(webview2LibPath, 'Microsoft.Web.WebView2.Wpf.dll'));
|
|
18
|
+
} catch (e) {
|
|
19
|
+
console.error("Core Dll Load Failed:", e);
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
const WebView2WpfAssembly = System.Reflection.Assembly.LoadFrom(path.join(webview2LibPath, 'Microsoft.Web.WebView2.Wpf.dll'));
|
|
23
|
+
|
|
24
|
+
const USER_DATA_FOLDER = path.join(__dirname, 'WebView2_Data');
|
|
25
|
+
const COUNTER_HTML_PATH = path.join(__dirname, 'counter.html');
|
|
26
|
+
|
|
27
|
+
console.log('--- Initializing WebView2 (Counter App) ---');
|
|
28
|
+
|
|
29
|
+
const WebView2Type = WebView2WpfAssembly.GetType('Microsoft.Web.WebView2.Wpf.WebView2');
|
|
30
|
+
const webView = new WebView2Type();
|
|
31
|
+
|
|
32
|
+
const CreationPropertiesType = WebView2WpfAssembly.GetType('Microsoft.Web.WebView2.Wpf.CoreWebView2CreationProperties');
|
|
33
|
+
const props = new CreationPropertiesType();
|
|
34
|
+
if (!fs.existsSync(USER_DATA_FOLDER)) fs.mkdirSync(USER_DATA_FOLDER, { recursive: true });
|
|
35
|
+
props.UserDataFolder = USER_DATA_FOLDER;
|
|
36
|
+
props.Language = "zh-CN";
|
|
37
|
+
webView.CreationProperties = props;
|
|
38
|
+
|
|
39
|
+
const browserWindow = new Windows.Window();
|
|
40
|
+
browserWindow.Title = 'Counter App - WebView2';
|
|
41
|
+
browserWindow.Width = 500;
|
|
42
|
+
browserWindow.Height = 400;
|
|
43
|
+
browserWindow.WindowStartupLocation = Windows.WindowStartupLocation.CenterScreen;
|
|
44
|
+
|
|
45
|
+
const grid = new Controls.Grid();
|
|
46
|
+
browserWindow.Content = grid;
|
|
47
|
+
grid.Children.Add(webView);
|
|
48
|
+
|
|
49
|
+
webView.add_CoreWebView2InitializationCompleted((sender: any, e: any) => {
|
|
50
|
+
if (e.IsSuccess) {
|
|
51
|
+
console.log('WebView2 Initialized Successfully');
|
|
52
|
+
|
|
53
|
+
const coreWebView2 = webView.CoreWebView2;
|
|
54
|
+
|
|
55
|
+
coreWebView2.add_WebMessageReceived((sender2: any, e2: any) => {
|
|
56
|
+
const message = e2.TryGetWebMessageAsString();
|
|
57
|
+
if (message) {
|
|
58
|
+
console.log('[WebView2] ' + message);
|
|
59
|
+
}
|
|
60
|
+
});
|
|
61
|
+
|
|
62
|
+
const script = `
|
|
63
|
+
(function() {
|
|
64
|
+
var originalLog = console.log;
|
|
65
|
+
console.log = function(msg) {
|
|
66
|
+
originalLog(msg);
|
|
67
|
+
if (window.chrome && window.chrome.webview) {
|
|
68
|
+
window.chrome.webview.postMessage(msg);
|
|
69
|
+
}
|
|
70
|
+
};
|
|
71
|
+
})();
|
|
72
|
+
`;
|
|
73
|
+
coreWebView2.ExecuteJavaScript(script);
|
|
74
|
+
} else {
|
|
75
|
+
console.error('FAILURE: Init failed', e.InitializationException?.Message);
|
|
76
|
+
}
|
|
77
|
+
});
|
|
78
|
+
|
|
79
|
+
webView.add_NavigationCompleted((sender: any, e: any) => {
|
|
80
|
+
console.log('Page Loaded Successfully');
|
|
81
|
+
});
|
|
82
|
+
|
|
83
|
+
webView.Source = new System.Uri(COUNTER_HTML_PATH);
|
|
84
|
+
|
|
85
|
+
browserWindow.add_Closed((sender: any, e: any) => {
|
|
86
|
+
process.exit(0);
|
|
87
|
+
});
|
|
88
|
+
|
|
89
|
+
const app = new Windows.Application();
|
|
90
|
+
app.Run(browserWindow);
|
package/package.json
ADDED
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@devscholar/node-ps1-dotnet",
|
|
3
|
+
"version": "0.0.0",
|
|
4
|
+
"description": "Node.js to .NET interop via IPC",
|
|
5
|
+
"main": "dist/index.js",
|
|
6
|
+
"type": "module",
|
|
7
|
+
"scripts": {
|
|
8
|
+
"test": "echo \"Error: no test specified\" && exit 1",
|
|
9
|
+
"start": "node start.js examples/winforms/counter/counter.ts",
|
|
10
|
+
"build": "tsc"
|
|
11
|
+
},
|
|
12
|
+
"keywords": ["dotnet", "winforms", "interop", "bridge", "ipc"],
|
|
13
|
+
"author": "",
|
|
14
|
+
"license": "ISC",
|
|
15
|
+
"devDependencies": {
|
|
16
|
+
"@types/node": "^25.0.10",
|
|
17
|
+
"typescript": "^5.9.3"
|
|
18
|
+
}
|
|
19
|
+
}
|
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
// scripts/PsBridge/BridgeState.cs
|
|
2
|
+
using System;
|
|
3
|
+
using System.Collections.Concurrent;
|
|
4
|
+
using System.Collections.Generic;
|
|
5
|
+
using System.IO;
|
|
6
|
+
using System.IO.Pipes;
|
|
7
|
+
using System.Threading;
|
|
8
|
+
|
|
9
|
+
public static class BridgeState
|
|
10
|
+
{
|
|
11
|
+
private static Dictionary<string, object> _objectStore;
|
|
12
|
+
public static Dictionary<string, object> ObjectStore
|
|
13
|
+
{
|
|
14
|
+
get { return _objectStore; }
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
public static StreamReader Reader { get; set; }
|
|
18
|
+
public static StreamWriter Writer { get; set; }
|
|
19
|
+
public static NamedPipeServerStream PipeServer { get; set; }
|
|
20
|
+
public static string PipeName { get; set; }
|
|
21
|
+
|
|
22
|
+
// SynchronizationContext for UI framework dispatching
|
|
23
|
+
public static SynchronizationContext MainSyncContext { get; set; }
|
|
24
|
+
|
|
25
|
+
// Flag to indicate the bridge is closing
|
|
26
|
+
public static bool IsClosing { get; set; }
|
|
27
|
+
|
|
28
|
+
// Command queue for thread-safe communication
|
|
29
|
+
public static BlockingCollection<Dictionary<string, object>> CommandQueue { get; set; }
|
|
30
|
+
public static BlockingCollection<Dictionary<string, object>> ReplyQueue { get; set; }
|
|
31
|
+
|
|
32
|
+
static BridgeState()
|
|
33
|
+
{
|
|
34
|
+
_objectStore = new Dictionary<string, object>();
|
|
35
|
+
CommandQueue = new BlockingCollection<Dictionary<string, object>>();
|
|
36
|
+
ReplyQueue = new BlockingCollection<Dictionary<string, object>>();
|
|
37
|
+
IsClosing = false;
|
|
38
|
+
}
|
|
39
|
+
}
|