quickwin 2.3.1 → 3.0.1
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/README.en.md +1 -2
- package/README.md +1 -2
- package/constants.ts +15 -0
- package/enum_map.d.ts +3 -0
- package/examples/PdfCanvas.js +1 -1
- package/examples/PdfCanvas.tsx +2 -2
- package/examples/execd/main.js +334 -188
- package/examples/pdf_preview2.js +76 -67
- package/examples/pdf_preview2.ts +84 -64
- package/examples/pdf_viewer.js +4932 -1029
- package/examples/pdf_viewer.tsx +11 -22
- package/examples/test_gallery.js +308 -143
- package/examples/test_gallery.tsx +12 -7
- package/examples/test_react_lazy.js +295 -133
- package/examples/test_react_lazy.tsx +4 -3
- package/examples/test_react_listbox.js +293 -132
- package/examples/test_react_listbox.tsx +3 -2
- package/examples/test_root_window.js +283 -126
- package/examples/test_tab.js +295 -133
- package/examples/test_tab.tsx +4 -3
- package/examples/tray_demo.js +37 -30
- package/examples/tray_demo.tsx +39 -32
- package/lib/abort.d.ts +21 -0
- package/lib/assert.d.ts +2 -0
- package/lib/bitmap.d.ts +7 -0
- package/lib/bitmap.js +40 -0
- package/lib/cache-utils.d.ts +6 -0
- package/lib/certs.d.ts +1 -0
- package/lib/certs.js +31 -3
- package/lib/dpi.d.ts +9 -0
- package/lib/dpi.js +30 -0
- package/lib/dumpRects.d.ts +2 -0
- package/lib/dumpRects.js +14 -7
- package/lib/exec-log.d.ts +23 -0
- package/lib/fetch.d.ts +4 -0
- package/lib/ffi/bind.d.ts +70 -0
- package/lib/ffi/bind.js +5 -4
- package/lib/ffi/ctype.d.ts +117 -0
- package/lib/ffi/index.d.ts +2 -0
- package/lib/ffi/struct.d.ts +174 -0
- package/lib/http-common.d.ts +143 -0
- package/lib/http-server.d.ts +59 -0
- package/lib/polyfill.d.ts +22 -0
- package/lib/react-qw/components/Button.d.ts +9 -0
- package/lib/react-qw/components/CheckBox.d.ts +11 -0
- package/lib/react-qw/components/ComboBox.d.ts +11 -0
- package/lib/react-qw/components/DateTimePicker.d.ts +15 -0
- package/lib/react-qw/components/DateTimePicker.js +6 -7
- package/lib/react-qw/components/Input.d.ts +15 -0
- package/lib/react-qw/components/Input.js +5 -1
- package/lib/react-qw/components/Link.d.ts +12 -0
- package/lib/react-qw/components/ListBox.d.ts +13 -0
- package/lib/react-qw/components/ListView.d.ts +37 -0
- package/lib/react-qw/components/ListView.js +8 -6
- package/lib/react-qw/components/PathPicker.d.ts +23 -0
- package/lib/react-qw/components/ProgressBar.d.ts +9 -0
- package/lib/react-qw/components/RadioButton.d.ts +11 -0
- package/lib/react-qw/components/ScrollView.d.ts +9 -0
- package/lib/react-qw/components/ScrollView.js +28 -22
- package/lib/react-qw/components/Slider.d.ts +12 -0
- package/lib/react-qw/components/Tab.d.ts +14 -0
- package/lib/react-qw/components/Tooltip.d.ts +7 -0
- package/lib/react-qw/components/TreeView.d.ts +18 -0
- package/lib/react-qw/components/index.d.ts +16 -0
- package/lib/react-qw/index.d.ts +24 -0
- package/lib/react-qw/index.js +7 -5
- package/lib/react-qw/layout.d.ts +29 -0
- package/lib/react-qw/nmhdr.d.ts +1 -0
- package/lib/react-qw/props.d.ts +2 -0
- package/lib/react-qw/props.js +3 -3
- package/lib/react-qw/reconciler.d.ts +21 -0
- package/lib/react-qw/reconciler.js +12 -17
- package/lib/stream.d.ts +20 -0
- package/lib/text-codec.d.ts +39 -0
- package/lib/text-measure.d.ts +14 -0
- package/lib/text-measure.js +9 -6
- package/lib/url.d.ts +54 -0
- package/lib/websocket.d.ts +73 -0
- package/lib/windows/{advapi32.ts → advapi32.d.ts} +6 -21
- package/lib/windows/comctl32.d.ts +14 -0
- package/lib/windows/comctl32.js +3 -2
- package/lib/windows/comdlg32.d.ts +4 -0
- package/lib/windows/{gdi32.ts → gdi32.d.ts} +184 -97
- package/lib/windows/gdi32.js +28 -6
- package/lib/windows/{kernel32.ts → kernel32.d.ts} +145 -113
- package/lib/windows/kernel32.js +9 -0
- package/lib/windows/{msimg32.ts → msimg32.d.ts} +11 -14
- package/lib/windows/ntdll.d.ts +5 -0
- package/lib/windows/ole32.d.ts +3 -0
- package/lib/windows/{psapi.ts → psapi.d.ts} +9 -18
- package/lib/windows/shell32.d.ts +51 -0
- package/lib/windows/shell32.js +11 -2
- package/lib/windows/structs.d.ts +3141 -0
- package/lib/windows/structs.js +51 -0
- package/lib/windows/user32.d.ts +623 -0
- package/lib/windows/user32.js +6 -5
- package/lib/windows/version.d.ts +27 -0
- package/lib/windows/{winspool.ts → winspool.d.ts} +18 -32
- package/main.js +13 -5
- package/package.json +16 -7
- package/quickwin.d.ts +13 -115
- package/qwin-nowasm-x86.exe +0 -0
- package/qwin-nowasm.exe +0 -0
- package/qwin-x86.exe +0 -0
- package/qwin.exe +0 -0
- package/test/bench_ffi_callraw.js +3 -4
- package/test/bench_ffi_callraw.ts +3 -4
- package/test/debug/mupdf_debug.js +4 -22
- package/test/debug/wasm_export_debug.js +2 -12
- package/test/debug/wasm_names.js +3 -13
- package/test/example.pdf +0 -0
- package/test/mupdf-cdn.js +40 -0
- package/test/mupdf-cdn.ts +43 -0
- package/test/test_ffi.js +8 -9
- package/test/test_ffi.ts +8 -9
- package/test/test_ffi_abi.js +6 -6
- package/test/test_ffi_abi.ts +8 -8
- package/test/test_ffi_windows.js +82 -11
- package/test/test_ffi_windows.ts +85 -11
- package/test/test_gdi_draw.js +3 -3
- package/test/test_gdi_draw.ts +4 -4
- package/test/test_mupdf_render.js +4 -22
- package/test/test_mupdf_render.ts +4 -23
- package/test/test_mupdf_twice.js +4 -19
- package/test/test_mupdf_twice.ts +4 -20
- package/test/test_mupdf_wasm.js +10 -4
- package/test/test_mupdf_wasm.ts +6 -4
- package/test/test_react_complex.js +316 -140
- package/test/test_react_counter.js +295 -133
- package/test/test_react_flex.js +297 -138
- package/test/test_react_hidden.js +296 -134
- package/test/test_react_listview_link.js +288 -131
- package/test/test_react_notify.js +290 -133
- package/test/test_react_render.js +295 -133
- package/lib/abort.ts +0 -69
- package/lib/assert.ts +0 -7
- package/lib/cache-utils.ts +0 -40
- package/lib/certs.ts +0 -229
- package/lib/dumpRects.ts +0 -26
- package/lib/exec-log.ts +0 -30
- package/lib/fetch.ts +0 -589
- package/lib/ffi/bind.ts +0 -539
- package/lib/ffi/ctype.ts +0 -371
- package/lib/ffi/index.ts +0 -6
- package/lib/ffi/struct.ts +0 -780
- package/lib/http-common.ts +0 -441
- package/lib/http-server.ts +0 -604
- package/lib/polyfill.ts +0 -171
- package/lib/react-qw/components/index.ts +0 -17
- package/lib/react-qw/index.ts +0 -96
- package/lib/react-qw/layout.ts +0 -111
- package/lib/react-qw/nmhdr.ts +0 -7
- package/lib/react-qw/props.ts +0 -41
- package/lib/react-qw/reconciler.ts +0 -383
- package/lib/stream.ts +0 -22
- package/lib/text-codec.ts +0 -171
- package/lib/text-measure.ts +0 -41
- package/lib/url.ts +0 -201
- package/lib/websocket.ts +0 -600
- package/lib/windows/comctl32.ts +0 -19
- package/lib/windows/comdlg32.ts +0 -10
- package/lib/windows/ntdll.ts +0 -11
- package/lib/windows/ole32.ts +0 -9
- package/lib/windows/shell32.ts +0 -39
- package/lib/windows/structs.ts +0 -752
- package/lib/windows/user32.ts +0 -619
- package/lib/windows/version.ts +0 -35
- package/vendor/mupdf-wasm/mupdf-wasm.d.ts +0 -571
- package/vendor/mupdf-wasm/mupdf-wasm.js +0 -2749
- package/vendor/mupdf-wasm/mupdf-wasm.wasm +0 -0
- package/vendor/mupdf-wasm/mupdf.d.ts +0 -939
- package/vendor/mupdf-wasm/mupdf.js +0 -3317
package/examples/test_tab.tsx
CHANGED
|
@@ -2,12 +2,13 @@ import '../lib/polyfill.js'
|
|
|
2
2
|
import * as gui from 'gui'
|
|
3
3
|
import { useState } from 'react'
|
|
4
4
|
import { render, Button, Tab } from '../lib/react-qw/index.js'
|
|
5
|
-
import { WindowStyle, WmMsg } from '../constants'
|
|
5
|
+
import { ShowWindowCmd, WindowStyle, WmMsg } from '../constants'
|
|
6
|
+
import { PostQuitMessage, ShowWindow } from '../lib/windows/user32.js'
|
|
6
7
|
|
|
7
8
|
gui.RegisterClass('TabDemo', (hwnd, msg, wParam, lParam) => {
|
|
8
9
|
if (!hwnd) return gui.DefWindowProc(hwnd, msg, wParam, lParam)
|
|
9
10
|
if (msg === WmMsg.DESTROY) {
|
|
10
|
-
|
|
11
|
+
PostQuitMessage(0)
|
|
11
12
|
return 0
|
|
12
13
|
}
|
|
13
14
|
return gui.DefWindowProc(hwnd, msg, wParam, lParam)
|
|
@@ -71,6 +72,6 @@ const hwnd = gui.CreateWindow(
|
|
|
71
72
|
)
|
|
72
73
|
|
|
73
74
|
if (hwnd) {
|
|
74
|
-
|
|
75
|
+
ShowWindow(hwnd, ShowWindowCmd.SHOWNORMAL)
|
|
75
76
|
render(<App />, hwnd)
|
|
76
77
|
}
|
package/examples/tray_demo.js
CHANGED
|
@@ -1,73 +1,80 @@
|
|
|
1
1
|
import * as gui from 'gui';
|
|
2
2
|
import * as std from 'std';
|
|
3
|
+
import { NULL } from '../lib/ffi/ctype.js';
|
|
4
|
+
import { GetCursorPos, CreatePopupMenu, AppendMenu, TrackPopupMenu, DestroyMenu, GetSystemMetrics, LoadImageOrdinal, PostQuitMessage, SetForegroundWindow, ShowWindow } from '../lib/windows/user32.js';
|
|
5
|
+
import { NOTIFYICONDATAW, POINT } from '../lib/windows/structs.js';
|
|
6
|
+
import { ShellNotifyIcon } from '../lib/windows/shell32.js';
|
|
7
|
+
import { createSystemDpiFont } from '../lib/dpi.js';
|
|
3
8
|
const WM_TRAY = 0x8001;
|
|
4
9
|
gui.RegisterClass('TrayApp', (hwnd, msg, wParam, lParam) => {
|
|
5
10
|
if (msg === WM_TRAY) {
|
|
6
11
|
const evt = lParam;
|
|
7
|
-
if (evt ===
|
|
8
|
-
|
|
9
|
-
|
|
12
|
+
if (evt === 513 /* WmMsg.LBUTTONDOWN */) {
|
|
13
|
+
ShowWindow(hwnd, 5 /* ShowWindowCmd.SHOW */);
|
|
14
|
+
SetForegroundWindow(hwnd);
|
|
10
15
|
}
|
|
11
|
-
else if (evt ===
|
|
12
|
-
|
|
13
|
-
const
|
|
14
|
-
const
|
|
15
|
-
const
|
|
16
|
-
const
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
16
|
+
else if (evt === 516 /* WmMsg.RBUTTONDOWN */ || evt === 123 /* WmMsg.CONTEXTMENU */) {
|
|
17
|
+
SetForegroundWindow(hwnd);
|
|
18
|
+
const pt = POINT.alloc();
|
|
19
|
+
const pos = GetCursorPos(pt.ptr) ? POINT.decode(pt) : null;
|
|
20
|
+
const x = pos ? pos.x : 0;
|
|
21
|
+
const y = pos ? pos.y : 0;
|
|
22
|
+
const hMenu = CreatePopupMenu();
|
|
23
|
+
if (hMenu !== NULL) {
|
|
24
|
+
AppendMenu(hMenu, 0, 1, '显示窗口');
|
|
25
|
+
AppendMenu(hMenu, 2048 /* MenuFlag.SEPARATOR */, 0, NULL);
|
|
26
|
+
AppendMenu(hMenu, 0, 2, '退出');
|
|
27
|
+
const cmd = TrackPopupMenu(hMenu, 256 /* TrackPopupMenuFlag.RETURNCMD */ | 2 /* TrackPopupMenuFlag.RIGHTBUTTON */, x, y, 0, hwnd, NULL);
|
|
28
|
+
DestroyMenu(hMenu);
|
|
23
29
|
if (cmd === 1) {
|
|
24
|
-
|
|
30
|
+
ShowWindow(hwnd, 5 /* ShowWindowCmd.SHOW */);
|
|
25
31
|
}
|
|
26
32
|
else if (cmd === 2) {
|
|
27
|
-
|
|
28
|
-
|
|
33
|
+
ShellNotifyIcon(2 /* NotifyIconCmd.DELETE */, { cbSize: NOTIFYICONDATAW.size, hWnd: hwnd, uID: 1 });
|
|
34
|
+
PostQuitMessage(0);
|
|
29
35
|
}
|
|
30
36
|
}
|
|
31
37
|
}
|
|
32
38
|
return 0;
|
|
33
39
|
}
|
|
34
40
|
if (msg === 16 /* WmMsg.CLOSE */) {
|
|
35
|
-
|
|
41
|
+
ShowWindow(hwnd, 0 /* ShowWindowCmd.HIDE */);
|
|
36
42
|
return 0;
|
|
37
43
|
}
|
|
38
44
|
return gui.DefWindowProc(hwnd, msg, wParam, lParam);
|
|
39
45
|
});
|
|
40
46
|
// 创建窗口
|
|
41
47
|
const W = 500, H = 400;
|
|
42
|
-
const scr =
|
|
48
|
+
const scr = [GetSystemMetrics(0 /* SysMetrics.CXSCREEN */), GetSystemMetrics(1 /* SysMetrics.CYSCREEN */)];
|
|
43
49
|
const x = (scr[0] - W) >> 1;
|
|
44
50
|
const y = (scr[1] - H) >> 1;
|
|
45
51
|
const hwnd = gui.CreateWindow('TrayApp', '系统托盘示例', 13565952 /* WindowStyle.OVERLAPPEDWINDOW */, x, y, W, H, null, null);
|
|
46
52
|
if (!hwnd)
|
|
47
53
|
std.exit(0);
|
|
48
|
-
|
|
54
|
+
ShowWindow(hwnd, 1 /* ShowWindowCmd.SHOWNORMAL */);
|
|
49
55
|
// 添加说明文字
|
|
50
|
-
const
|
|
51
|
-
const ES_READONLY = 0x0800;
|
|
52
|
-
const style = 1073741824 /* WindowStyle.CHILD */ | 268435456 /* WindowStyle.VISIBLE */ | ES_MULTILINE | ES_READONLY;
|
|
56
|
+
const style = 1073741824 /* WindowStyle.CHILD */ | 268435456 /* WindowStyle.VISIBLE */ | 4 /* EditStyle.MULTILINE */ | 2048 /* EditStyle.READONLY */;
|
|
53
57
|
const text = gui.CreateWindow('EDIT', 'QuickWin 系统托盘示例\r\n'
|
|
54
58
|
+ '\r\n'
|
|
55
59
|
+ '右键点击托盘图标打开上下文菜单。\r\n'
|
|
56
60
|
+ '关闭此窗口将隐藏到托盘。\r\n'
|
|
57
61
|
+ '从菜单中选择"显示窗口"恢复窗口,"退出"结束程序。', style, 15, 15, W - 30, H - 70, hwnd, null);
|
|
58
62
|
if (text) {
|
|
59
|
-
const font =
|
|
63
|
+
const font = createSystemDpiFont();
|
|
60
64
|
if (font)
|
|
61
65
|
gui.SendMessage(text, 48 /* WmMsg.SETFONT */, font, 1);
|
|
62
66
|
}
|
|
67
|
+
// LoadImageW 返回的句柄随 uType 变(HICON/HCURSOR/HBITMAP),绑定只能给裸地址档;
|
|
68
|
+
// LoadAppIcon 的 HICON 是同一档的品牌子型,故变量按裸地址声明
|
|
63
69
|
let hIcon = gui.LoadAppIcon();
|
|
64
70
|
if (!hIcon)
|
|
65
|
-
hIcon =
|
|
71
|
+
hIcon = LoadImageOrdinal(NULL, 32512 /* IDI.APPLICATION */, 1 /* ImageType.ICON */, 0, 0, 32768 /* LoadImageFlag.SHARED */);
|
|
66
72
|
if (hIcon) {
|
|
67
|
-
const ok =
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
73
|
+
const ok = ShellNotifyIcon(0 /* NotifyIconCmd.ADD */, {
|
|
74
|
+
cbSize: NOTIFYICONDATAW.size,
|
|
75
|
+
hWnd: hwnd, uID: 1,
|
|
76
|
+
uFlags: 1 /* NotifyIconFlag.MESSAGE */ | 2 /* NotifyIconFlag.ICON */,
|
|
77
|
+
uCallbackMessage: WM_TRAY,
|
|
71
78
|
hIcon,
|
|
72
79
|
});
|
|
73
80
|
std.out.printf('tray icon %s\n', ok ? 'added' : 'FAILED');
|
package/examples/tray_demo.tsx
CHANGED
|
@@ -1,39 +1,45 @@
|
|
|
1
1
|
import * as gui from 'gui'
|
|
2
2
|
import * as std from 'std'
|
|
3
|
-
import {
|
|
3
|
+
import { NULL, type MaybePtr } from '../lib/ffi/ctype.js'
|
|
4
|
+
import { GetCursorPos, CreatePopupMenu, AppendMenu, TrackPopupMenu, DestroyMenu, GetSystemMetrics, LoadImageOrdinal, PostQuitMessage, SetForegroundWindow, ShowWindow } from '../lib/windows/user32.js'
|
|
5
|
+
import { NOTIFYICONDATAW, POINT } from '../lib/windows/structs.js'
|
|
6
|
+
import { ShellNotifyIcon } from '../lib/windows/shell32.js'
|
|
7
|
+
import { createSystemDpiFont } from '../lib/dpi.js'
|
|
8
|
+
import { EditStyle, IDI, ImageType, LoadImageFlag, MenuFlag, NotifyIconCmd, NotifyIconFlag, ShowWindowCmd, SysMetrics, TrackPopupMenuFlag, WindowStyle, WmMsg } from '../constants'
|
|
4
9
|
|
|
5
10
|
const WM_TRAY = 0x8001
|
|
6
11
|
|
|
7
12
|
gui.RegisterClass('TrayApp', (hwnd, msg, wParam, lParam) => {
|
|
8
13
|
if (msg === WM_TRAY) {
|
|
9
14
|
const evt = lParam
|
|
10
|
-
if (evt ===
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
} else if (evt ===
|
|
14
|
-
|
|
15
|
-
const
|
|
16
|
-
const
|
|
17
|
-
const
|
|
18
|
-
const
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
15
|
+
if (evt === WmMsg.LBUTTONDOWN) {
|
|
16
|
+
ShowWindow(hwnd, ShowWindowCmd.SHOW)
|
|
17
|
+
SetForegroundWindow(hwnd)
|
|
18
|
+
} else if (evt === WmMsg.RBUTTONDOWN || evt === WmMsg.CONTEXTMENU) {
|
|
19
|
+
SetForegroundWindow(hwnd)
|
|
20
|
+
const pt = POINT.alloc()
|
|
21
|
+
const pos = GetCursorPos(pt.ptr) ? POINT.decode(pt) : null
|
|
22
|
+
const x = pos ? pos.x : 0
|
|
23
|
+
const y = pos ? pos.y : 0
|
|
24
|
+
const hMenu = CreatePopupMenu()
|
|
25
|
+
if (hMenu !== NULL) {
|
|
26
|
+
AppendMenu(hMenu, 0, 1, '显示窗口')
|
|
27
|
+
AppendMenu(hMenu, MenuFlag.SEPARATOR, 0, NULL)
|
|
28
|
+
AppendMenu(hMenu, 0, 2, '退出')
|
|
29
|
+
const cmd = TrackPopupMenu(hMenu, TrackPopupMenuFlag.RETURNCMD | TrackPopupMenuFlag.RIGHTBUTTON, x, y, 0, hwnd, NULL)
|
|
30
|
+
DestroyMenu(hMenu)
|
|
25
31
|
if (cmd === 1) {
|
|
26
|
-
|
|
32
|
+
ShowWindow(hwnd, ShowWindowCmd.SHOW)
|
|
27
33
|
} else if (cmd === 2) {
|
|
28
|
-
|
|
29
|
-
|
|
34
|
+
ShellNotifyIcon(NotifyIconCmd.DELETE, { cbSize: NOTIFYICONDATAW.size, hWnd: hwnd, uID: 1 })
|
|
35
|
+
PostQuitMessage(0)
|
|
30
36
|
}
|
|
31
37
|
}
|
|
32
38
|
}
|
|
33
39
|
return 0
|
|
34
40
|
}
|
|
35
41
|
if (msg === WmMsg.CLOSE) {
|
|
36
|
-
|
|
42
|
+
ShowWindow(hwnd, ShowWindowCmd.HIDE)
|
|
37
43
|
return 0
|
|
38
44
|
}
|
|
39
45
|
return gui.DefWindowProc(hwnd, msg, wParam, lParam)
|
|
@@ -41,17 +47,15 @@ gui.RegisterClass('TrayApp', (hwnd, msg, wParam, lParam) => {
|
|
|
41
47
|
|
|
42
48
|
// 创建窗口
|
|
43
49
|
const W = 500, H = 400
|
|
44
|
-
const scr =
|
|
50
|
+
const scr: [number, number] = [GetSystemMetrics(SysMetrics.CXSCREEN), GetSystemMetrics(SysMetrics.CYSCREEN)]
|
|
45
51
|
const x = (scr[0] - W) >> 1
|
|
46
52
|
const y = (scr[1] - H) >> 1
|
|
47
53
|
const hwnd = gui.CreateWindow('TrayApp', '系统托盘示例', WindowStyle.OVERLAPPEDWINDOW, x, y, W, H, null, null)
|
|
48
54
|
if (!hwnd) std.exit(0)
|
|
49
|
-
|
|
55
|
+
ShowWindow(hwnd, ShowWindowCmd.SHOWNORMAL)
|
|
50
56
|
|
|
51
57
|
// 添加说明文字
|
|
52
|
-
const
|
|
53
|
-
const ES_READONLY = 0x0800
|
|
54
|
-
const style = WindowStyle.CHILD | WindowStyle.VISIBLE | ES_MULTILINE | ES_READONLY
|
|
58
|
+
const style = WindowStyle.CHILD | WindowStyle.VISIBLE | EditStyle.MULTILINE | EditStyle.READONLY
|
|
55
59
|
const text = gui.CreateWindow('EDIT',
|
|
56
60
|
'QuickWin 系统托盘示例\r\n'
|
|
57
61
|
+ '\r\n'
|
|
@@ -60,18 +64,21 @@ const text = gui.CreateWindow('EDIT',
|
|
|
60
64
|
+ '从菜单中选择"显示窗口"恢复窗口,"退出"结束程序。',
|
|
61
65
|
style, 15, 15, W - 30, H - 70, hwnd, null)
|
|
62
66
|
if (text) {
|
|
63
|
-
const font =
|
|
67
|
+
const font = createSystemDpiFont()
|
|
64
68
|
if (font)
|
|
65
69
|
gui.SendMessage(text, WmMsg.SETFONT, font, 1)
|
|
66
70
|
}
|
|
67
71
|
|
|
68
|
-
|
|
69
|
-
|
|
72
|
+
// LoadImageW 返回的句柄随 uType 变(HICON/HCURSOR/HBITMAP),绑定只能给裸地址档;
|
|
73
|
+
// LoadAppIcon 的 HICON 是同一档的品牌子型,故变量按裸地址声明
|
|
74
|
+
let hIcon: MaybePtr<''> | null = gui.LoadAppIcon()
|
|
75
|
+
if (!hIcon) hIcon = LoadImageOrdinal(NULL, IDI.APPLICATION, ImageType.ICON, 0, 0, LoadImageFlag.SHARED)
|
|
70
76
|
if (hIcon) {
|
|
71
|
-
const ok =
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
77
|
+
const ok = ShellNotifyIcon(NotifyIconCmd.ADD, {
|
|
78
|
+
cbSize: NOTIFYICONDATAW.size,
|
|
79
|
+
hWnd: hwnd, uID: 1,
|
|
80
|
+
uFlags: NotifyIconFlag.MESSAGE | NotifyIconFlag.ICON,
|
|
81
|
+
uCallbackMessage: WM_TRAY,
|
|
75
82
|
hIcon,
|
|
76
83
|
})
|
|
77
84
|
std.out.printf('tray icon %s\n', ok ? 'added' : 'FAILED')
|
package/lib/abort.d.ts
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
export interface AbortEvent {
|
|
2
|
+
readonly type: 'abort';
|
|
3
|
+
readonly target: unknown;
|
|
4
|
+
}
|
|
5
|
+
export declare class AbortSignal {
|
|
6
|
+
private _aborted;
|
|
7
|
+
private _reason;
|
|
8
|
+
private _listeners;
|
|
9
|
+
onabort: ((e: AbortEvent) => void) | null;
|
|
10
|
+
get aborted(): boolean;
|
|
11
|
+
get reason(): unknown;
|
|
12
|
+
addEventListener(type: string, listener: (e: AbortEvent) => void): void;
|
|
13
|
+
removeEventListener(type: string, listener: (e: AbortEvent) => void): void;
|
|
14
|
+
/** @internal fired by AbortController.abort() */
|
|
15
|
+
_fire(reason: unknown): void;
|
|
16
|
+
throwIfAborted(): void;
|
|
17
|
+
}
|
|
18
|
+
export declare class AbortController {
|
|
19
|
+
readonly signal: AbortSignal;
|
|
20
|
+
abort(reason?: unknown): void;
|
|
21
|
+
}
|
package/lib/assert.d.ts
ADDED
package/lib/bitmap.d.ts
ADDED
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
import { type MaybePtr } from './ffi/ctype.js';
|
|
2
|
+
/** 建 32bpp 自顶向下 DIB 段位图(像素为 BGRA,[B,G,R,A] 字节序,alpha 保留 —— 可喂
|
|
3
|
+
* ImageListAdd(ILC_COLOR32) 等)。width/height ≤ 0 或像素缓冲不足 width*height*4 →
|
|
4
|
+
* NULL(同旧 gui.CreateBitmapFromPixels 语义:非法入参静默返空,由调用方按「无图」处理);
|
|
5
|
+
* GDI 失败同样返 NULL(已建的位图当场回收)。
|
|
6
|
+
* 位图归调用方所有:用完 DeleteObject。 */
|
|
7
|
+
export declare function createBitmapFromPixels(width: number, height: number, pixels: ArrayBuffer): MaybePtr<'HGDIOBJ'>;
|
package/lib/bitmap.js
ADDED
|
@@ -0,0 +1,40 @@
|
|
|
1
|
+
// 按像素建位图 —— gui 模块下沉到 JS 层的复合逻辑(原 js_createBitmapFromPixels)。
|
|
2
|
+
// 旧 C 体是 CreateDIBSection + memcpy 直写位数据;FFI 侧没有「JS 缓冲 → 原生地址」的
|
|
3
|
+
// 批量写原语(ffi 只导出 readBytes / writeByte,逐字节循环不值当),改用 GDI 自带的
|
|
4
|
+
// SetDIBits 把调用方缓冲装进 DIB 段:ColorUse.RGB_COLORS 下 hdc 被忽略(MSDN:
|
|
5
|
+
// "used only if the DIB_PAL_COLORS constant is set ... otherwise it is ignored"),
|
|
6
|
+
// 双机实测传 NULL 可用、GetDIBits 读回逐字节一致(含 alpha),与旧 C 的 memcpy 等价。
|
|
7
|
+
import { NULL, PtrArrayBuffer } from './ffi/ctype.js';
|
|
8
|
+
import { CreateDIBSection, DeleteObject, SetDIBits } from './windows/gdi32.js';
|
|
9
|
+
import { BITMAPINFOHEADER } from './windows/structs.js';
|
|
10
|
+
/** 建 32bpp 自顶向下 DIB 段位图(像素为 BGRA,[B,G,R,A] 字节序,alpha 保留 —— 可喂
|
|
11
|
+
* ImageListAdd(ILC_COLOR32) 等)。width/height ≤ 0 或像素缓冲不足 width*height*4 →
|
|
12
|
+
* NULL(同旧 gui.CreateBitmapFromPixels 语义:非法入参静默返空,由调用方按「无图」处理);
|
|
13
|
+
* GDI 失败同样返 NULL(已建的位图当场回收)。
|
|
14
|
+
* 位图归调用方所有:用完 DeleteObject。 */
|
|
15
|
+
export function createBitmapFromPixels(width, height, pixels) {
|
|
16
|
+
if (width <= 0 || height <= 0)
|
|
17
|
+
return NULL;
|
|
18
|
+
const len = width * height * 4;
|
|
19
|
+
if (pixels.byteLength < len)
|
|
20
|
+
return NULL;
|
|
21
|
+
// 32bpp BI_RGB:头部即全部(无颜色表);负 biHeight = 自顶向下,与 JS 缓冲行序一致
|
|
22
|
+
const bi = BITMAPINFOHEADER.encode({
|
|
23
|
+
biSize: BITMAPINFOHEADER.size,
|
|
24
|
+
biWidth: width,
|
|
25
|
+
biHeight: -height,
|
|
26
|
+
biPlanes: 1,
|
|
27
|
+
biBitCount: 32,
|
|
28
|
+
});
|
|
29
|
+
const hbm = CreateDIBSection(NULL, bi.ptr, 0 /* ColorUse.RGB_COLORS */, NULL, NULL, 0);
|
|
30
|
+
if (!hbm)
|
|
31
|
+
return NULL;
|
|
32
|
+
// 像素先落自有原生缓冲(BYTE.encode 需带 .ptr 的缓冲),再让 GDI 装进 DIB 段
|
|
33
|
+
const src = new PtrArrayBuffer(len);
|
|
34
|
+
new Uint8Array(src).set(new Uint8Array(pixels, 0, len));
|
|
35
|
+
if (SetDIBits(NULL, hbm, 0, height, src, bi.ptr, 0 /* ColorUse.RGB_COLORS */) !== height) {
|
|
36
|
+
DeleteObject(hbm);
|
|
37
|
+
return NULL;
|
|
38
|
+
}
|
|
39
|
+
return hbm;
|
|
40
|
+
}
|
package/lib/certs.d.ts
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export declare const TRUSTED_CA_COUNT = 8;
|
package/lib/certs.js
CHANGED
|
@@ -6,8 +6,10 @@
|
|
|
6
6
|
// bundle and are pushed into wolfSSL's process-wide trust store as soon
|
|
7
7
|
// as this module is imported.
|
|
8
8
|
//
|
|
9
|
-
// The process-wide store has a fixed QW_CA_SLOTS (
|
|
10
|
-
// bundle uses
|
|
9
|
+
// The process-wide store has a fixed QW_CA_SLOTS (16) capacity; this
|
|
10
|
+
// bundle uses 8, leaving headroom for future anchors. If the bundle
|
|
11
|
+
// ever outgrows it, raise QW_CA_SLOTS in src/quickjs-wolfssl.c first —
|
|
12
|
+
// a full store throws at import time.
|
|
11
13
|
//
|
|
12
14
|
// Each anchor covers a different root hierarchy, and none is
|
|
13
15
|
// interchangeable: wolfSSL resolves a CA by AKID/SKID and does not walk
|
|
@@ -25,6 +27,10 @@
|
|
|
25
27
|
// G2 (bing.com), RSA 2048.
|
|
26
28
|
// * GLOBALSIGN_R46, ISRG_X1, ISRG_X2 — the newer GlobalSign R46 and
|
|
27
29
|
// Let's Encrypt hierarchies (taobao.com, qq.com).
|
|
30
|
+
// * GTS_R4 — cross-signed GTS Root R4 (issued by GlobalSign Root CA,
|
|
31
|
+
// notAfter 2028-01-28, EC P-256). unpkg.com and other properties
|
|
32
|
+
// whose chains terminate at Google Trust Services (WE1/E5/E6
|
|
33
|
+
// intermediates).
|
|
28
34
|
//
|
|
29
35
|
// Known limitation (wolfSSL, not the bundle): GLOBALSIGN_R46 and ISRG_X1
|
|
30
36
|
// are RSA 4096, and this wolfSSL build compiles the SP bignum with
|
|
@@ -202,6 +208,27 @@ zj0EAwMDaAAwZQIwe3lORlCEwkSHRhtFcP9Ymd70/aTSVaYgLXTWNLxBo1BfASdW
|
|
|
202
208
|
tL4ndQavEi51mI38AjEAi/V3bNTIZargCyzuFJ0nN6T5U6VR5CmD1/iQMVtCnwr1
|
|
203
209
|
/q4AaOeMSQ+2b1tbFfLn
|
|
204
210
|
-----END CERTIFICATE-----`;
|
|
211
|
+
const GTS_R4 = `-----BEGIN CERTIFICATE-----
|
|
212
|
+
MIIDejCCAmKgAwIBAgIQf+UwvzMTQ77dghYQST2KGzANBgkqhkiG9w0BAQsFADBX
|
|
213
|
+
MQswCQYDVQQGEwJCRTEZMBcGA1UEChMQR2xvYmFsU2lnbiBudi1zYTEQMA4GA1UE
|
|
214
|
+
CxMHUm9vdCBDQTEbMBkGA1UEAxMSR2xvYmFsU2lnbiBSb290IENBMB4XDTIzMTEx
|
|
215
|
+
NTAzNDMyMVoXDTI4MDEyODAwMDA0MlowRzELMAkGA1UEBhMCVVMxIjAgBgNVBAoT
|
|
216
|
+
GUdvb2dsZSBUcnVzdCBTZXJ2aWNlcyBMTEMxFDASBgNVBAMTC0dUUyBSb290IFI0
|
|
217
|
+
MHYwEAYHKoZIzj0CAQYFK4EEACIDYgAE83Rzp2iLYK5DuDXFgTB7S0md+8Fhzube
|
|
218
|
+
Rr1r1WEYNa5A3XP3iZEwWus87oV8okB2O6nGuEfYKueSkWpz6bFyOZ8pn6KY019e
|
|
219
|
+
WIZlD6GEZQbR3IvJx3PIjGov5cSr0R2Ko4H/MIH8MA4GA1UdDwEB/wQEAwIBhjAd
|
|
220
|
+
BgNVHSUEFjAUBggrBgEFBQcDAQYIKwYBBQUHAwIwDwYDVR0TAQH/BAUwAwEB/zAd
|
|
221
|
+
BgNVHQ4EFgQUgEzW63T/STaj1dj8tT7FavCUHYwwHwYDVR0jBBgwFoAUYHtmGkUN
|
|
222
|
+
l8qJUC99BM00qP/8/UswNgYIKwYBBQUHAQEEKjAoMCYGCCsGAQUFBzAChhpodHRw
|
|
223
|
+
Oi8vaS5wa2kuZ29vZy9nc3IxLmNydDAtBgNVHR8EJjAkMCKgIKAehhxodHRwOi8v
|
|
224
|
+
Yy5wa2kuZ29vZy9yL2dzcjEuY3JsMBMGA1UdIAQMMAowCAYGZ4EMAQIBMA0GCSqG
|
|
225
|
+
SIb3DQEBCwUAA4IBAQAYQrsPBtYDh5bjP2OBDwmkoWhIDDkic574y04tfzHpn+cJ
|
|
226
|
+
odI2D4SseesQ6bDrarZ7C30ddLibZatoKiws3UL9xnELz4ct92vID24FfVbiI1hY
|
|
227
|
+
+SW6FoVHkNeWIP0GCbaM4C6uVdF5dTUsMVs/ZbzNnIdCp5Gxmx5ejvEau8otR/Cs
|
|
228
|
+
kGN+hr/W5GvT1tMBjgWKZ1i4//emhA1JG1BbPzoLJQvyEotc03lXjTaCzv8mEbep
|
|
229
|
+
8RqZ7a2CPsgRbuvTPBwcOMBBmuFeU88+FSBX6+7iP0il8b4Z0QFqIwwMHfs/L6K1
|
|
230
|
+
vepuoxtGzi4CZ68zJpiq1UvSqTbFJjtbD4seiMHl
|
|
231
|
+
-----END CERTIFICATE-----`;
|
|
205
232
|
// Register at import time. Importers of this module get the anchors
|
|
206
233
|
// without writing any code themselves. addTrustedCA only returns the
|
|
207
234
|
// slot count (-1 when full/empty); the fatal-vs-not decision is ours.
|
|
@@ -216,4 +243,5 @@ trust(DIGICERT_GLOBAL_G2);
|
|
|
216
243
|
trust(GLOBALSIGN_R46);
|
|
217
244
|
trust(ISRG_X1);
|
|
218
245
|
trust(ISRG_X2);
|
|
219
|
-
|
|
246
|
+
trust(GTS_R4);
|
|
247
|
+
export const TRUSTED_CA_COUNT = 8;
|
package/lib/dpi.d.ts
ADDED
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
import { NULL, type Ptr } from './ffi/ctype.js';
|
|
2
|
+
/** 屏幕缩放系数(96 DPI = 1):GetDC(NULL) → GetDeviceCaps(LOGPIXELSX) → ReleaseDC 成对释放 */
|
|
3
|
+
export declare function getScaleFactor(): number;
|
|
4
|
+
/** 系统消息字体(CreateFontIndirectW(NONCLIENTMETRICS.lfMessageFont))——界面控件的默认字体;
|
|
5
|
+
* 出参位不注册 encoder:encode({cbSize}) 建缓冲带初值 → 传 .ptr → decode 读回。
|
|
6
|
+
* cbSize/uiParam 必须与系统认知的结构尺寸一致:Vista+ 为 504(含尾部 iPaddedBorderWidth)、
|
|
7
|
+
* XP/2003 为 500 —— 先按 504 试,失败退回 500(lfMessageFont 落在前 500 字节内,尾部留 0);
|
|
8
|
+
* 两次都失败 → NULL,调用方按「无字体」处理(控件回落系统默认字体)。 */
|
|
9
|
+
export declare function createSystemDpiFont(): Ptr<'HGDIOBJ'> | NULL;
|
package/lib/dpi.js
ADDED
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
// DPI 与系统字体 —— gui 模块下沉到 JS 层的两处复合逻辑(原 js_getScaleFactor /
|
|
2
|
+
// js_createSystemDpiFont)。两者都只按「一次操作一次」调用,FFI 的固定溢价无感;
|
|
3
|
+
// 留在 C 只会与 lib/windows 的绑定重复一层,遂收在此处单点实现。
|
|
4
|
+
import { NULL } from './ffi/ctype.js';
|
|
5
|
+
import { GetDC, ReleaseDC, SystemParametersInfo } from './windows/user32.js';
|
|
6
|
+
import { GetDeviceCaps, CreateFontIndirect } from './windows/gdi32.js';
|
|
7
|
+
import { NONCLIENTMETRICSW } from './windows/structs.js';
|
|
8
|
+
/** 屏幕缩放系数(96 DPI = 1):GetDC(NULL) → GetDeviceCaps(LOGPIXELSX) → ReleaseDC 成对释放 */
|
|
9
|
+
export function getScaleFactor() {
|
|
10
|
+
const hdc = GetDC(NULL);
|
|
11
|
+
const dpi = hdc ? GetDeviceCaps(hdc, 88 /* DeviceCap.LOGPIXELSX */) : 96;
|
|
12
|
+
if (hdc)
|
|
13
|
+
ReleaseDC(NULL, hdc);
|
|
14
|
+
return dpi / 96;
|
|
15
|
+
}
|
|
16
|
+
/** 系统消息字体(CreateFontIndirectW(NONCLIENTMETRICS.lfMessageFont))——界面控件的默认字体;
|
|
17
|
+
* 出参位不注册 encoder:encode({cbSize}) 建缓冲带初值 → 传 .ptr → decode 读回。
|
|
18
|
+
* cbSize/uiParam 必须与系统认知的结构尺寸一致:Vista+ 为 504(含尾部 iPaddedBorderWidth)、
|
|
19
|
+
* XP/2003 为 500 —— 先按 504 试,失败退回 500(lfMessageFont 落在前 500 字节内,尾部留 0);
|
|
20
|
+
* 两次都失败 → NULL,调用方按「无字体」处理(控件回落系统默认字体)。 */
|
|
21
|
+
export function createSystemDpiFont() {
|
|
22
|
+
const ncm = NONCLIENTMETRICSW.encode({ cbSize: NONCLIENTMETRICSW.size });
|
|
23
|
+
if (!SystemParametersInfo(41 /* Spi.GETNONCLIENTMETRICS */, NONCLIENTMETRICSW.size, ncm, 0)) {
|
|
24
|
+
const legacySize = NONCLIENTMETRICSW.size - 4;
|
|
25
|
+
NONCLIENTMETRICSW.encode({ cbSize: legacySize }, ncm);
|
|
26
|
+
if (!SystemParametersInfo(41 /* Spi.GETNONCLIENTMETRICS */, legacySize, ncm, 0))
|
|
27
|
+
return NULL;
|
|
28
|
+
}
|
|
29
|
+
return CreateFontIndirect(NONCLIENTMETRICSW.decode(ncm).lfMessageFont);
|
|
30
|
+
}
|
package/lib/dumpRects.js
CHANGED
|
@@ -1,17 +1,24 @@
|
|
|
1
1
|
import * as os from 'os';
|
|
2
|
-
import
|
|
2
|
+
import { GetClientRect, GetWindow, GetWindowRect, GetWindowText, GetWindowTextLength } from '../lib/windows/user32.js';
|
|
3
|
+
import { WCHAR } from '../lib/ffi/bind.js';
|
|
4
|
+
import { RECT } from '../lib/windows/structs.js';
|
|
3
5
|
export function startDumpRects(rootHwnd, intervalMs = 3000) {
|
|
4
6
|
function dumpChild(parent, indent) {
|
|
5
|
-
var ch =
|
|
7
|
+
var ch = GetWindow(parent, 5 /* GetWindowCmd.CHILD */);
|
|
6
8
|
var n = 0;
|
|
7
9
|
while (ch) {
|
|
8
10
|
n++;
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
11
|
+
const wr = RECT.alloc();
|
|
12
|
+
const cr = RECT.alloc();
|
|
13
|
+
GetWindowRect(ch, wr.ptr);
|
|
14
|
+
GetClientRect(ch, cr.ptr);
|
|
15
|
+
const cap = GetWindowTextLength(ch) + 1;
|
|
16
|
+
const textBuf = WCHAR.alloc(cap);
|
|
17
|
+
GetWindowText(ch, textBuf, cap);
|
|
18
|
+
var txt = WCHAR.decode(textBuf).slice(0, 16);
|
|
19
|
+
console.log(indent + '[' + n + '] hwnd=' + String(ch) + ' txt="' + txt + '" wr=' + JSON.stringify(RECT.decode(wr)) + ' cr=' + JSON.stringify(RECT.decode(cr)));
|
|
13
20
|
dumpChild(ch, indent + ' ');
|
|
14
|
-
ch =
|
|
21
|
+
ch = GetWindow(ch, 2 /* GetWindowCmd.NEXT */);
|
|
15
22
|
}
|
|
16
23
|
if (n === 0)
|
|
17
24
|
console.log(indent + '(no children)');
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
export interface LogEntry {
|
|
2
|
+
/** epoch 秒 */
|
|
3
|
+
ts: number;
|
|
4
|
+
/** 展示用命令/请求描述 */
|
|
5
|
+
cmd: string;
|
|
6
|
+
/** HTTP 状态码(401/404/500/504 等);异常终止用 -1 */
|
|
7
|
+
status: number;
|
|
8
|
+
/** X-Exit-Code(子进程退出码);无则 null */
|
|
9
|
+
exit: number | null;
|
|
10
|
+
/** 耗时 ms */
|
|
11
|
+
durMs: number;
|
|
12
|
+
/** 附加说明(如超时/拒绝原因) */
|
|
13
|
+
note?: string;
|
|
14
|
+
}
|
|
15
|
+
/** 请求日志:固定容量环形缓冲,GUI ListBox 每行一条。 */
|
|
16
|
+
export declare class RequestLog {
|
|
17
|
+
private readonly cap;
|
|
18
|
+
private buf;
|
|
19
|
+
constructor(cap?: number);
|
|
20
|
+
get size(): number;
|
|
21
|
+
push(e: LogEntry): void;
|
|
22
|
+
list(): LogEntry[];
|
|
23
|
+
}
|
package/lib/fetch.d.ts
ADDED
|
@@ -0,0 +1,70 @@
|
|
|
1
|
+
import '../text-codec.js';
|
|
2
|
+
import { ArgJsTypeOfToken, RetJsTypeOfToken, type Ptr, PtrArrayBuffer } from './ctype.js';
|
|
3
|
+
type Codec<N extends string = string, V = unknown, T = unknown> = {
|
|
4
|
+
encode?(v: V, buf?: PtrArrayBuffer<any>): PtrArrayBuffer<any>;
|
|
5
|
+
decode?(p: Ptr<N> | ArrayBuffer): V;
|
|
6
|
+
alloc?(a: T): PtrArrayBuffer<N>;
|
|
7
|
+
};
|
|
8
|
+
export type CodecMap = Record<string, {
|
|
9
|
+
encode?(v: any, buf?: PtrArrayBuffer<any>): PtrArrayBuffer<any>;
|
|
10
|
+
decode?(p: any): any;
|
|
11
|
+
alloc?(a: any): PtrArrayBuffer<any>;
|
|
12
|
+
}>;
|
|
13
|
+
type ParseArgStr<S extends string, L, Acc extends unknown[] = []> = S extends `${infer F} ${infer R}` ? ParseArgStr<R, L, [...Acc, ArgJsTypeOfToken<F, L>]> : S extends '' ? Acc : [...Acc, ArgJsTypeOfToken<S, L>];
|
|
14
|
+
type EncodeValue<T> = 'encode' extends keyof T ? (T extends {
|
|
15
|
+
encode?: (v: infer V, ...r: any[]) => ArrayBuffer;
|
|
16
|
+
} ? V : never) : never;
|
|
17
|
+
type DecodeValue<T> = 'decode' extends keyof T ? (T extends {
|
|
18
|
+
decode?: (p: any, ...r: any[]) => infer V;
|
|
19
|
+
} ? V : never) : never;
|
|
20
|
+
type BindEncoders<M> = {
|
|
21
|
+
[K in keyof M]: EncodeValue<M[K]>;
|
|
22
|
+
} & {
|
|
23
|
+
WCHAR: string;
|
|
24
|
+
BYTE: PtrArrayBuffer<any>;
|
|
25
|
+
};
|
|
26
|
+
type BindDecoders<M> = {
|
|
27
|
+
[K in keyof M]: DecodeValue<M[K]>;
|
|
28
|
+
} & {
|
|
29
|
+
WCHAR: string;
|
|
30
|
+
};
|
|
31
|
+
type BindFn<S extends string, E, D> = S extends `${infer ArgStr} -> ${infer RetStr}` ? ((...args: ParseArgStr<ArgStr, E>) => RetJsTypeOfToken<RetStr, D>) : never;
|
|
32
|
+
/** 内建 UTF-16 编解码:encode 入参序列化(UTF-16LE + NUL);decode 双态单参——
|
|
33
|
+
* 品牌指针逐字节读到 NUL(野指针无终止 4MiB 上限 fail-fast)、ArrayBuffer 直读到
|
|
34
|
+
* NUL 或末尾(out 参数未写 NUL 时按读满处理);alloc 预分配返回带 .ptr 的
|
|
35
|
+
* PtrArrayBuffer(a = 字符数,缺省 256)。类型取必需形态——
|
|
36
|
+
* 内建三件齐备,调用无需空断言。刻意 Pick 而非 Required<Codec>:只声明消费的
|
|
37
|
+
* 三件(encode/decode/alloc),新增可选能力位不被拉成必填。 */
|
|
38
|
+
export declare const WCHAR: Required<Pick<Codec<'WCHAR', string, number>, 'encode' | 'decode' | 'alloc'>>;
|
|
39
|
+
/** 内建字节缓冲:encode identity 直通(收 PtrArrayBuffer、原地存活,native 写回同一
|
|
40
|
+
* buffer);alloc 预分配返回带 .ptr 的 PtrArrayBuffer(a = 字节数)。无 decode——
|
|
41
|
+
* 地址不携带长度(无终止符),读回直接在 buffer 上 DataView / TypedArray 取。 */
|
|
42
|
+
export declare const BYTE: Required<Pick<Codec<'BYTE', PtrArrayBuffer<any>, number>, 'encode' | 'alloc'>>;
|
|
43
|
+
/** 绑定单个函数。encoders/decoders 是两张可选布局表(结构上是 Codec):
|
|
44
|
+
* encoders 喂入参位(encode 值域 → 形参类型),decoders 喂返回位(decode 值域
|
|
45
|
+
* → 返回 V | null,替代 Ptr | null)。decoders 缺省时回退到 encoders——双向 codec
|
|
46
|
+
* 只需传一次(与运行时 `decoders ?? encoders` 同构:都只在实参缺省时生效,
|
|
47
|
+
* 显式传空对象不 fallback)。内建 WCHAR/BYTE 无条件参与两张表。 */
|
|
48
|
+
export declare function bind<const S extends string, const LE extends CodecMap = {}, const LD extends CodecMap = LE>(dll: string, name: string, sig: S, encoders?: LE, decoders?: LD): BindFn<S, BindEncoders<LE>, BindDecoders<LD>>;
|
|
49
|
+
/** 批量绑定(map = 函数名 → 签名串)。encoders/decoders 语义同 bind()。 */
|
|
50
|
+
export declare function bindLib<const M extends Record<string, string>, const LE extends CodecMap = {}, const LD extends CodecMap = LE>(dll: string, map: M, encoders?: LE, decoders?: LD): { [K in keyof M]: BindFn<M[K], BindEncoders<LE>, BindDecoders<LD>>; };
|
|
51
|
+
/** 把 JS 函数变成可传给 Win32 API 的函数指针(同步同线程回调)。
|
|
52
|
+
* sig 为回调签名:实参只许 BasicKind(ptr 槽 0 保真读回 NULL | Ptr),
|
|
53
|
+
* 返回只许 void|u8..u64|i8..i64|f32|f64|ptr(u64/i64 走 EDX:EAX,x64 走 RAX)。
|
|
54
|
+
* '!' 标记位运行时校验(与 bind 调用位同语义,见 dispatchClosure):参数位 C 传入 0
|
|
55
|
+
* → 打印诊断并跳过回调;返回位 fn 返回 0 → 保持结果槽 0。
|
|
56
|
+
* opts.stdcall 仅 ia32 有效(默认 true,Win32 回调标准 CALLBACK);msvcrt 等
|
|
57
|
+
* cdecl 库回调传 { stdcall: false }。x64 恒由调用方清栈,无需指定。
|
|
58
|
+
* 参数上限:x64 至多 16 个、ia32 栈区至多 64 字节(C 桩定长捕获窗),超限抛错。
|
|
59
|
+
* 返回 { ptr, dispose }:ptr 即函数指针(传给 API 的 ptr 参数);dispose 注销
|
|
60
|
+
* 并释放回调函数,幂等;闭包期间回调被强引用,不会被 GC 回收。
|
|
61
|
+
* 注意:dispose 后 ptr 不得再被任何 native 方引用。
|
|
62
|
+
* 从未 dispose 就丢弃通道(整个返回对象或解构出来的 dispose 均算)
|
|
63
|
+
* → 打印泄漏警告(只警告、不自动释放,见 leakRegistry)。 */
|
|
64
|
+
export declare function closure<S extends string>(sig: S, fn: BindFn<S, {}, {}>, opts?: {
|
|
65
|
+
stdcall?: boolean;
|
|
66
|
+
}): {
|
|
67
|
+
ptr: number;
|
|
68
|
+
dispose(): void;
|
|
69
|
+
};
|
|
70
|
+
export {};
|
package/lib/ffi/bind.js
CHANGED
|
@@ -1,7 +1,6 @@
|
|
|
1
1
|
import * as ffi from 'ffi';
|
|
2
2
|
import * as os from 'os';
|
|
3
3
|
import * as std from 'std';
|
|
4
|
-
import * as win from 'win';
|
|
5
4
|
import '../text-codec.js';
|
|
6
5
|
import { cTokenToType, isCPtrToken, isCValToken, valName, normToken, PTR_SIZE, ptrName, readScalar, writeSlot, PtrArrayBuffer } from './ctype.js';
|
|
7
6
|
// CodecMap 的值是结构形(size 只在 StructDef 上、不属 Codec 契约),统一走 unknown
|
|
@@ -14,7 +13,7 @@ function loadDll(dll) {
|
|
|
14
13
|
const cached = _dllCache.get(dll);
|
|
15
14
|
if (cached !== undefined)
|
|
16
15
|
return cached;
|
|
17
|
-
const loaded =
|
|
16
|
+
const loaded = ffi.LoadLibrary(dll);
|
|
18
17
|
if (!loaded)
|
|
19
18
|
throw new Error(`ffi-bind: LoadLibrary("${dll}") failed`);
|
|
20
19
|
_dllCache.set(dll, loaded);
|
|
@@ -55,6 +54,8 @@ function parseSig(sig) {
|
|
|
55
54
|
sig,
|
|
56
55
|
};
|
|
57
56
|
}
|
|
57
|
+
/** proc 是 GetProcAddress 拿到的函数地址(<FARPROC>ptr):调用方已校验非空,故收窄后的
|
|
58
|
+
* Ptr 而非 MaybePtr;品牌只在绑定层内部走,落到 ffiCall 的 uintptr 槽(number)时脱落。 */
|
|
58
59
|
function makeFn(proc, sig, encoders, decoders) {
|
|
59
60
|
const ps = parseSig(sig);
|
|
60
61
|
// 按值位的能力校验前移到绑定期(模块加载即炸,不留到首个调用):布局缺位 / 非结构
|
|
@@ -296,7 +297,7 @@ const builtinCodecs = { WCHAR, BYTE };
|
|
|
296
297
|
* 只需传一次(与运行时 `decoders ?? encoders` 同构:都只在实参缺省时生效,
|
|
297
298
|
* 显式传空对象不 fallback)。内建 WCHAR/BYTE 无条件参与两张表。 */
|
|
298
299
|
export function bind(dll, name, sig, encoders, decoders) {
|
|
299
|
-
const proc =
|
|
300
|
+
const proc = ffi.GetProcAddress(loadDll(dll), name);
|
|
300
301
|
if (!proc)
|
|
301
302
|
throw new Error(`ffi-bind: proc "${name}" not found in ${dll}`);
|
|
302
303
|
const effDec = decoders ?? encoders;
|
|
@@ -310,7 +311,7 @@ export function bindLib(dll, map, encoders, decoders) {
|
|
|
310
311
|
const encTable = { ...builtinCodecs, ...encoders };
|
|
311
312
|
const decTable = { ...builtinCodecs, ...(effDec ?? {}) };
|
|
312
313
|
for (const [name, sig] of Object.entries(map)) {
|
|
313
|
-
const proc =
|
|
314
|
+
const proc = ffi.GetProcAddress(h, name);
|
|
314
315
|
if (!proc)
|
|
315
316
|
throw new Error(`ffi-bind: proc "${name}" not found in ${dll}`);
|
|
316
317
|
out[name] = makeFn(proc, sig, encTable, decTable);
|