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.
Files changed (172) hide show
  1. package/README.en.md +1 -2
  2. package/README.md +1 -2
  3. package/constants.ts +15 -0
  4. package/enum_map.d.ts +3 -0
  5. package/examples/PdfCanvas.js +1 -1
  6. package/examples/PdfCanvas.tsx +2 -2
  7. package/examples/execd/main.js +334 -188
  8. package/examples/pdf_preview2.js +76 -67
  9. package/examples/pdf_preview2.ts +84 -64
  10. package/examples/pdf_viewer.js +4932 -1029
  11. package/examples/pdf_viewer.tsx +11 -22
  12. package/examples/test_gallery.js +308 -143
  13. package/examples/test_gallery.tsx +12 -7
  14. package/examples/test_react_lazy.js +295 -133
  15. package/examples/test_react_lazy.tsx +4 -3
  16. package/examples/test_react_listbox.js +293 -132
  17. package/examples/test_react_listbox.tsx +3 -2
  18. package/examples/test_root_window.js +283 -126
  19. package/examples/test_tab.js +295 -133
  20. package/examples/test_tab.tsx +4 -3
  21. package/examples/tray_demo.js +37 -30
  22. package/examples/tray_demo.tsx +39 -32
  23. package/lib/abort.d.ts +21 -0
  24. package/lib/assert.d.ts +2 -0
  25. package/lib/bitmap.d.ts +7 -0
  26. package/lib/bitmap.js +40 -0
  27. package/lib/cache-utils.d.ts +6 -0
  28. package/lib/certs.d.ts +1 -0
  29. package/lib/certs.js +31 -3
  30. package/lib/dpi.d.ts +9 -0
  31. package/lib/dpi.js +30 -0
  32. package/lib/dumpRects.d.ts +2 -0
  33. package/lib/dumpRects.js +14 -7
  34. package/lib/exec-log.d.ts +23 -0
  35. package/lib/fetch.d.ts +4 -0
  36. package/lib/ffi/bind.d.ts +70 -0
  37. package/lib/ffi/bind.js +5 -4
  38. package/lib/ffi/ctype.d.ts +117 -0
  39. package/lib/ffi/index.d.ts +2 -0
  40. package/lib/ffi/struct.d.ts +174 -0
  41. package/lib/http-common.d.ts +143 -0
  42. package/lib/http-server.d.ts +59 -0
  43. package/lib/polyfill.d.ts +22 -0
  44. package/lib/react-qw/components/Button.d.ts +9 -0
  45. package/lib/react-qw/components/CheckBox.d.ts +11 -0
  46. package/lib/react-qw/components/ComboBox.d.ts +11 -0
  47. package/lib/react-qw/components/DateTimePicker.d.ts +15 -0
  48. package/lib/react-qw/components/DateTimePicker.js +6 -7
  49. package/lib/react-qw/components/Input.d.ts +15 -0
  50. package/lib/react-qw/components/Input.js +5 -1
  51. package/lib/react-qw/components/Link.d.ts +12 -0
  52. package/lib/react-qw/components/ListBox.d.ts +13 -0
  53. package/lib/react-qw/components/ListView.d.ts +37 -0
  54. package/lib/react-qw/components/ListView.js +8 -6
  55. package/lib/react-qw/components/PathPicker.d.ts +23 -0
  56. package/lib/react-qw/components/ProgressBar.d.ts +9 -0
  57. package/lib/react-qw/components/RadioButton.d.ts +11 -0
  58. package/lib/react-qw/components/ScrollView.d.ts +9 -0
  59. package/lib/react-qw/components/ScrollView.js +28 -22
  60. package/lib/react-qw/components/Slider.d.ts +12 -0
  61. package/lib/react-qw/components/Tab.d.ts +14 -0
  62. package/lib/react-qw/components/Tooltip.d.ts +7 -0
  63. package/lib/react-qw/components/TreeView.d.ts +18 -0
  64. package/lib/react-qw/components/index.d.ts +16 -0
  65. package/lib/react-qw/index.d.ts +24 -0
  66. package/lib/react-qw/index.js +7 -5
  67. package/lib/react-qw/layout.d.ts +29 -0
  68. package/lib/react-qw/nmhdr.d.ts +1 -0
  69. package/lib/react-qw/props.d.ts +2 -0
  70. package/lib/react-qw/props.js +3 -3
  71. package/lib/react-qw/reconciler.d.ts +21 -0
  72. package/lib/react-qw/reconciler.js +12 -17
  73. package/lib/stream.d.ts +20 -0
  74. package/lib/text-codec.d.ts +39 -0
  75. package/lib/text-measure.d.ts +14 -0
  76. package/lib/text-measure.js +9 -6
  77. package/lib/url.d.ts +54 -0
  78. package/lib/websocket.d.ts +73 -0
  79. package/lib/windows/{advapi32.ts → advapi32.d.ts} +6 -21
  80. package/lib/windows/comctl32.d.ts +14 -0
  81. package/lib/windows/comctl32.js +3 -2
  82. package/lib/windows/comdlg32.d.ts +4 -0
  83. package/lib/windows/{gdi32.ts → gdi32.d.ts} +184 -97
  84. package/lib/windows/gdi32.js +28 -6
  85. package/lib/windows/{kernel32.ts → kernel32.d.ts} +145 -113
  86. package/lib/windows/kernel32.js +9 -0
  87. package/lib/windows/{msimg32.ts → msimg32.d.ts} +11 -14
  88. package/lib/windows/ntdll.d.ts +5 -0
  89. package/lib/windows/ole32.d.ts +3 -0
  90. package/lib/windows/{psapi.ts → psapi.d.ts} +9 -18
  91. package/lib/windows/shell32.d.ts +51 -0
  92. package/lib/windows/shell32.js +11 -2
  93. package/lib/windows/structs.d.ts +3141 -0
  94. package/lib/windows/structs.js +51 -0
  95. package/lib/windows/user32.d.ts +623 -0
  96. package/lib/windows/user32.js +6 -5
  97. package/lib/windows/version.d.ts +27 -0
  98. package/lib/windows/{winspool.ts → winspool.d.ts} +18 -32
  99. package/main.js +13 -5
  100. package/package.json +16 -7
  101. package/quickwin.d.ts +13 -115
  102. package/qwin-nowasm-x86.exe +0 -0
  103. package/qwin-nowasm.exe +0 -0
  104. package/qwin-x86.exe +0 -0
  105. package/qwin.exe +0 -0
  106. package/test/bench_ffi_callraw.js +3 -4
  107. package/test/bench_ffi_callraw.ts +3 -4
  108. package/test/debug/mupdf_debug.js +4 -22
  109. package/test/debug/wasm_export_debug.js +2 -12
  110. package/test/debug/wasm_names.js +3 -13
  111. package/test/example.pdf +0 -0
  112. package/test/mupdf-cdn.js +40 -0
  113. package/test/mupdf-cdn.ts +43 -0
  114. package/test/test_ffi.js +8 -9
  115. package/test/test_ffi.ts +8 -9
  116. package/test/test_ffi_abi.js +6 -6
  117. package/test/test_ffi_abi.ts +8 -8
  118. package/test/test_ffi_windows.js +82 -11
  119. package/test/test_ffi_windows.ts +85 -11
  120. package/test/test_gdi_draw.js +3 -3
  121. package/test/test_gdi_draw.ts +4 -4
  122. package/test/test_mupdf_render.js +4 -22
  123. package/test/test_mupdf_render.ts +4 -23
  124. package/test/test_mupdf_twice.js +4 -19
  125. package/test/test_mupdf_twice.ts +4 -20
  126. package/test/test_mupdf_wasm.js +10 -4
  127. package/test/test_mupdf_wasm.ts +6 -4
  128. package/test/test_react_complex.js +316 -140
  129. package/test/test_react_counter.js +295 -133
  130. package/test/test_react_flex.js +297 -138
  131. package/test/test_react_hidden.js +296 -134
  132. package/test/test_react_listview_link.js +288 -131
  133. package/test/test_react_notify.js +290 -133
  134. package/test/test_react_render.js +295 -133
  135. package/lib/abort.ts +0 -69
  136. package/lib/assert.ts +0 -7
  137. package/lib/cache-utils.ts +0 -40
  138. package/lib/certs.ts +0 -229
  139. package/lib/dumpRects.ts +0 -26
  140. package/lib/exec-log.ts +0 -30
  141. package/lib/fetch.ts +0 -589
  142. package/lib/ffi/bind.ts +0 -539
  143. package/lib/ffi/ctype.ts +0 -371
  144. package/lib/ffi/index.ts +0 -6
  145. package/lib/ffi/struct.ts +0 -780
  146. package/lib/http-common.ts +0 -441
  147. package/lib/http-server.ts +0 -604
  148. package/lib/polyfill.ts +0 -171
  149. package/lib/react-qw/components/index.ts +0 -17
  150. package/lib/react-qw/index.ts +0 -96
  151. package/lib/react-qw/layout.ts +0 -111
  152. package/lib/react-qw/nmhdr.ts +0 -7
  153. package/lib/react-qw/props.ts +0 -41
  154. package/lib/react-qw/reconciler.ts +0 -383
  155. package/lib/stream.ts +0 -22
  156. package/lib/text-codec.ts +0 -171
  157. package/lib/text-measure.ts +0 -41
  158. package/lib/url.ts +0 -201
  159. package/lib/websocket.ts +0 -600
  160. package/lib/windows/comctl32.ts +0 -19
  161. package/lib/windows/comdlg32.ts +0 -10
  162. package/lib/windows/ntdll.ts +0 -11
  163. package/lib/windows/ole32.ts +0 -9
  164. package/lib/windows/shell32.ts +0 -39
  165. package/lib/windows/structs.ts +0 -752
  166. package/lib/windows/user32.ts +0 -619
  167. package/lib/windows/version.ts +0 -35
  168. package/vendor/mupdf-wasm/mupdf-wasm.d.ts +0 -571
  169. package/vendor/mupdf-wasm/mupdf-wasm.js +0 -2749
  170. package/vendor/mupdf-wasm/mupdf-wasm.wasm +0 -0
  171. package/vendor/mupdf-wasm/mupdf.d.ts +0 -939
  172. package/vendor/mupdf-wasm/mupdf.js +0 -3317
@@ -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
- gui.PostQuitMessage(0)
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
- gui.ShowWindow(hwnd)
75
+ ShowWindow(hwnd, ShowWindowCmd.SHOWNORMAL)
75
76
  render(<App />, hwnd)
76
77
  }
@@ -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 === 0x0201) { // WM_LBUTTONDOWN
8
- gui.ShowWindow(hwnd, 5); // SW_SHOW
9
- gui.SetForegroundWindow(hwnd);
12
+ if (evt === 513 /* WmMsg.LBUTTONDOWN */) {
13
+ ShowWindow(hwnd, 5 /* ShowWindowCmd.SHOW */);
14
+ SetForegroundWindow(hwnd);
10
15
  }
11
- else if (evt === 0x0204 || evt === 0x007B) { // WM_RBUTTONDOWN or WM_CONTEXTMENU
12
- gui.SetForegroundWindow(hwnd);
13
- const pos = gui.GetCursorPos();
14
- const x = pos ? pos[0] : 0;
15
- const y = pos ? pos[1] : 0;
16
- const hMenu = gui.CreatePopupMenu();
17
- if (hMenu) {
18
- gui.AppendMenu(hMenu, 0, 1, '显示窗口');
19
- gui.AppendMenu(hMenu, 0x0800, 0, '');
20
- gui.AppendMenu(hMenu, 0, 2, '退出');
21
- const cmd = gui.TrackPopupMenu(hMenu, x, y, undefined, hwnd);
22
- gui.DestroyMenu(hMenu);
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
- gui.ShowWindow(hwnd, 5); // SW_SHOW
30
+ ShowWindow(hwnd, 5 /* ShowWindowCmd.SHOW */);
25
31
  }
26
32
  else if (cmd === 2) {
27
- gui.ShellNotifyIcon(2 /* NotifyIconCmd.DELETE */, { hwnd, uID: 1 });
28
- gui.PostQuitMessage(0);
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
- gui.ShowWindow(hwnd, 0); // SW_HIDE
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 = gui.GetScreenSize();
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
- gui.ShowWindow(hwnd);
54
+ ShowWindow(hwnd, 1 /* ShowWindowCmd.SHOWNORMAL */);
49
55
  // 添加说明文字
50
- const ES_MULTILINE = 0x0004;
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 = gui.CreateSystemDpiFont();
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 = gui.LoadImage(null, 32512 /* IDI.APPLICATION */, 1 /* ImageType.ICON */, 0, 0, 32768 /* LoadImageFlag.SHARED */);
71
+ hIcon = LoadImageOrdinal(NULL, 32512 /* IDI.APPLICATION */, 1 /* ImageType.ICON */, 0, 0, 32768 /* LoadImageFlag.SHARED */);
66
72
  if (hIcon) {
67
- const ok = gui.ShellNotifyIcon(0 /* NotifyIconCmd.ADD */, {
68
- hwnd: hwnd, uID: 1,
69
- flags: 1 /* NotifyIconFlag.MESSAGE */ | 2 /* NotifyIconFlag.ICON */,
70
- callbackMessage: WM_TRAY,
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');
@@ -1,39 +1,45 @@
1
1
  import * as gui from 'gui'
2
2
  import * as std from 'std'
3
- import { IDI, ImageType, LoadImageFlag, NotifyIconCmd, NotifyIconFlag, WindowStyle, WmMsg } from '../constants'
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 === 0x0201) { // WM_LBUTTONDOWN
11
- gui.ShowWindow(hwnd, 5) // SW_SHOW
12
- gui.SetForegroundWindow(hwnd)
13
- } else if (evt === 0x0204 || evt === 0x007B) { // WM_RBUTTONDOWN or WM_CONTEXTMENU
14
- gui.SetForegroundWindow(hwnd)
15
- const pos = gui.GetCursorPos()
16
- const x = pos ? pos[0] : 0
17
- const y = pos ? pos[1] : 0
18
- const hMenu = gui.CreatePopupMenu()
19
- if (hMenu) {
20
- gui.AppendMenu(hMenu, 0, 1, '显示窗口')
21
- gui.AppendMenu(hMenu, 0x0800, 0, '')
22
- gui.AppendMenu(hMenu, 0, 2, '退出')
23
- const cmd = gui.TrackPopupMenu(hMenu, x, y, undefined, hwnd)
24
- gui.DestroyMenu(hMenu)
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
- gui.ShowWindow(hwnd, 5) // SW_SHOW
32
+ ShowWindow(hwnd, ShowWindowCmd.SHOW)
27
33
  } else if (cmd === 2) {
28
- gui.ShellNotifyIcon(NotifyIconCmd.DELETE, { hwnd, uID: 1 })
29
- gui.PostQuitMessage(0)
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
- gui.ShowWindow(hwnd, 0) // SW_HIDE
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 = gui.GetScreenSize()
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
- gui.ShowWindow(hwnd)
55
+ ShowWindow(hwnd, ShowWindowCmd.SHOWNORMAL)
50
56
 
51
57
  // 添加说明文字
52
- const ES_MULTILINE = 0x0004
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 = gui.CreateSystemDpiFont()
67
+ const font = createSystemDpiFont()
64
68
  if (font)
65
69
  gui.SendMessage(text, WmMsg.SETFONT, font, 1)
66
70
  }
67
71
 
68
- let hIcon = gui.LoadAppIcon()
69
- if (!hIcon) hIcon = gui.LoadImage(null, IDI.APPLICATION, ImageType.ICON, 0, 0, LoadImageFlag.SHARED)
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 = gui.ShellNotifyIcon(NotifyIconCmd.ADD, {
72
- hwnd: hwnd, uID: 1,
73
- flags: NotifyIconFlag.MESSAGE | NotifyIconFlag.ICON,
74
- callbackMessage: WM_TRAY,
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
+ }
@@ -0,0 +1,2 @@
1
+ export declare function assertNonNullable<T>(v: T, msg?: string): asserts v is NonNullable<T>;
2
+ export declare function assertArrayBuffer(v: ArrayBufferLike): asserts v is ArrayBuffer;
@@ -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
+ }
@@ -0,0 +1,6 @@
1
+ export interface IniCache {
2
+ headers: Record<string, string>;
3
+ meta: Record<string, string>;
4
+ }
5
+ export declare function parseIni(text: string): IniCache;
6
+ export declare function toIni(headers: Record<string, string>, meta: Record<string, string>): string;
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 (8) capacity; this
10
- // bundle uses 7, leaving headroom for run-time registrations.
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
- export const TRUSTED_CA_COUNT = 7;
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
+ }
@@ -0,0 +1,2 @@
1
+ import * as gui from 'gui';
2
+ export declare function startDumpRects(rootHwnd: gui.HWND, intervalMs?: number): void;
package/lib/dumpRects.js CHANGED
@@ -1,17 +1,24 @@
1
1
  import * as os from 'os';
2
- import * as gui from 'gui';
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 = gui.GetWindow(parent, 5 /* GetWindowCmd.CHILD */);
7
+ var ch = GetWindow(parent, 5 /* GetWindowCmd.CHILD */);
6
8
  var n = 0;
7
9
  while (ch) {
8
10
  n++;
9
- var wr = gui.GetWindowRect(ch);
10
- var cr = gui.GetClientRect(ch);
11
- var txt = String(gui.GetWindowText(ch) || '').slice(0, 16);
12
- console.log(indent + '[' + n + '] hwnd=' + String(ch) + ' txt="' + txt + '" wr=' + JSON.stringify(wr) + ' cr=' + JSON.stringify(cr));
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 = gui.GetWindow(ch, 2 /* GetWindowCmd.NEXT */);
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,4 @@
1
+ declare global {
2
+ var fetch: (url: string | Request, init?: RequestInit) => Promise<Response>;
3
+ }
4
+ export {};
@@ -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 = win.LoadLibrary(dll);
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 = win.GetProcAddress(loadDll(dll), name);
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 = win.GetProcAddress(h, name);
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);