quickwin 3.0.0 → 3.0.2

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 (253) hide show
  1. package/README.en.md +3 -0
  2. package/README.md +2 -0
  3. package/lib/abort.d.ts +21 -0
  4. package/lib/assert.d.ts +2 -0
  5. package/lib/bitmap.d.ts +7 -0
  6. package/lib/cache-utils.d.ts +6 -0
  7. package/lib/certs.d.ts +1 -0
  8. package/lib/dpi.d.ts +9 -0
  9. package/lib/dumpRects.d.ts +2 -0
  10. package/lib/exec-log.d.ts +23 -0
  11. package/lib/fetch.d.ts +4 -0
  12. package/lib/ffi/bind.d.ts +70 -0
  13. package/lib/ffi/ctype.d.ts +117 -0
  14. package/lib/ffi/index.d.ts +2 -0
  15. package/lib/ffi/struct.d.ts +174 -0
  16. package/lib/http-common.d.ts +143 -0
  17. package/lib/http-server.d.ts +59 -0
  18. package/lib/polyfill.d.ts +22 -0
  19. package/lib/react-qw/components/Button.d.ts +9 -0
  20. package/lib/react-qw/components/CheckBox.d.ts +11 -0
  21. package/lib/react-qw/components/ComboBox.d.ts +11 -0
  22. package/lib/react-qw/components/DateTimePicker.d.ts +15 -0
  23. package/lib/react-qw/components/Input.d.ts +15 -0
  24. package/lib/react-qw/components/Link.d.ts +12 -0
  25. package/lib/react-qw/components/ListBox.d.ts +13 -0
  26. package/lib/react-qw/components/ListView.d.ts +37 -0
  27. package/lib/react-qw/components/PathPicker.d.ts +23 -0
  28. package/lib/react-qw/components/ProgressBar.d.ts +9 -0
  29. package/lib/react-qw/components/RadioButton.d.ts +11 -0
  30. package/lib/react-qw/components/ScrollView.d.ts +9 -0
  31. package/lib/react-qw/components/Slider.d.ts +12 -0
  32. package/lib/react-qw/components/Tab.d.ts +14 -0
  33. package/lib/react-qw/components/Tooltip.d.ts +7 -0
  34. package/lib/react-qw/components/TreeView.d.ts +18 -0
  35. package/lib/react-qw/components/index.d.ts +16 -0
  36. package/lib/react-qw/index.d.ts +24 -0
  37. package/lib/react-qw/layout.d.ts +29 -0
  38. package/lib/react-qw/nmhdr.d.ts +1 -0
  39. package/lib/react-qw/props.d.ts +2 -0
  40. package/lib/react-qw/reconciler.d.ts +21 -0
  41. package/lib/stream.d.ts +20 -0
  42. package/lib/text-codec.d.ts +39 -0
  43. package/lib/text-measure.d.ts +14 -0
  44. package/lib/url.d.ts +54 -0
  45. package/lib/websocket.d.ts +73 -0
  46. package/lib/windows/{advapi32.ts → advapi32.d.ts} +6 -21
  47. package/lib/windows/comctl32.d.ts +14 -0
  48. package/lib/windows/comdlg32.d.ts +4 -0
  49. package/lib/windows/{gdi32.ts → gdi32.d.ts} +161 -98
  50. package/lib/windows/{kernel32.ts → kernel32.d.ts} +138 -115
  51. package/lib/windows/{msimg32.ts → msimg32.d.ts} +11 -14
  52. package/lib/windows/ntdll.d.ts +5 -0
  53. package/lib/windows/ole32.d.ts +3 -0
  54. package/lib/windows/{psapi.ts → psapi.d.ts} +9 -18
  55. package/lib/windows/{shell32.ts → shell32.d.ts} +25 -24
  56. package/lib/windows/structs.d.ts +3141 -0
  57. package/lib/windows/{user32.ts → user32.d.ts} +196 -193
  58. package/lib/windows/version.d.ts +27 -0
  59. package/lib/windows/{winspool.ts → winspool.d.ts} +18 -32
  60. package/package.json +15 -8
  61. package/qwin-nowasm-x86.exe +0 -0
  62. package/qwin-nowasm.exe +0 -0
  63. package/qwin-x86.exe +0 -0
  64. package/qwin.exe +0 -0
  65. package/examples/PdfCanvas.js +0 -38
  66. package/examples/PdfCanvas.tsx +0 -54
  67. package/examples/execd/main.js +0 -23379
  68. package/examples/execd/tray.js +0 -192
  69. package/examples/execd/worker.js +0 -122
  70. package/examples/pdf_preview2.js +0 -398
  71. package/examples/pdf_preview2.ts +0 -353
  72. package/examples/pdf_viewer.js +0 -22515
  73. package/examples/pdf_viewer.tsx +0 -228
  74. package/examples/test_gallery.js +0 -18692
  75. package/examples/test_gallery.tsx +0 -291
  76. package/examples/test_react_lazy.js +0 -18560
  77. package/examples/test_react_lazy.tsx +0 -65
  78. package/examples/test_react_listbox.js +0 -18562
  79. package/examples/test_react_listbox.tsx +0 -73
  80. package/examples/test_root_window.js +0 -18532
  81. package/examples/test_root_window.tsx +0 -41
  82. package/examples/test_tab.js +0 -18563
  83. package/examples/test_tab.tsx +0 -77
  84. package/examples/tray_demo.js +0 -86
  85. package/examples/tray_demo.tsx +0 -89
  86. package/lib/abort.ts +0 -69
  87. package/lib/assert.ts +0 -7
  88. package/lib/bitmap.ts +0 -39
  89. package/lib/cache-utils.ts +0 -40
  90. package/lib/certs.ts +0 -258
  91. package/lib/dpi.ts +0 -31
  92. package/lib/dumpRects.ts +0 -34
  93. package/lib/exec-log.ts +0 -30
  94. package/lib/fetch.ts +0 -589
  95. package/lib/ffi/bind.ts +0 -540
  96. package/lib/ffi/ctype.ts +0 -371
  97. package/lib/ffi/index.ts +0 -6
  98. package/lib/ffi/struct.ts +0 -780
  99. package/lib/http-common.ts +0 -441
  100. package/lib/http-server.ts +0 -604
  101. package/lib/polyfill.ts +0 -171
  102. package/lib/react-qw/components/index.ts +0 -17
  103. package/lib/react-qw/index.ts +0 -96
  104. package/lib/react-qw/layout.ts +0 -111
  105. package/lib/react-qw/nmhdr.ts +0 -7
  106. package/lib/react-qw/props.ts +0 -41
  107. package/lib/react-qw/reconciler.ts +0 -379
  108. package/lib/stream.ts +0 -22
  109. package/lib/text-codec.ts +0 -171
  110. package/lib/text-measure.ts +0 -44
  111. package/lib/url.ts +0 -201
  112. package/lib/websocket.ts +0 -600
  113. package/lib/windows/comctl32.ts +0 -20
  114. package/lib/windows/comdlg32.ts +0 -10
  115. package/lib/windows/ntdll.ts +0 -11
  116. package/lib/windows/ole32.ts +0 -9
  117. package/lib/windows/structs.ts +0 -807
  118. package/lib/windows/version.ts +0 -35
  119. package/test/add.wasm +0 -0
  120. package/test/bench_ffi_callraw.js +0 -235
  121. package/test/bench_ffi_callraw.ts +0 -235
  122. package/test/bench_ffi_overhead.js +0 -139
  123. package/test/bench_ffi_overhead.ts +0 -141
  124. package/test/bench_sendmessage.js +0 -104
  125. package/test/bench_sendmessage.ts +0 -100
  126. package/test/bench_sendmessage_nonnull.js +0 -187
  127. package/test/bench_sendmessage_nonnull.ts +0 -188
  128. package/test/complex.wasm +0 -0
  129. package/test/complex_imports.wasm +0 -0
  130. package/test/debug/http_server_e2e.js +0 -31
  131. package/test/debug/minwasm.js +0 -52
  132. package/test/debug/mupdf_debug.js +0 -86
  133. package/test/debug/wasm.js +0 -122
  134. package/test/debug/wasm_export_debug.js +0 -54
  135. package/test/debug/wasm_names.js +0 -36
  136. package/test/example.pdf +0 -0
  137. package/test/global_imports.wasm +0 -0
  138. package/test/import_func.wasm +0 -0
  139. package/test/imports.wasm +0 -0
  140. package/test/mupdf-cdn.js +0 -40
  141. package/test/mupdf-cdn.ts +0 -43
  142. package/test/run.js +0 -111
  143. package/test/run.ts +0 -116
  144. package/test/sjlj.wasm +0 -0
  145. package/test/test_basic.js +0 -7
  146. package/test/test_basic.ts +0 -9
  147. package/test/test_basic_fetch.js +0 -63
  148. package/test/test_basic_fetch.ts +0 -59
  149. package/test/test_brotli.js +0 -48
  150. package/test/test_brotli.ts +0 -52
  151. package/test/test_fetch_cache.js +0 -169
  152. package/test/test_fetch_cache.ts +0 -187
  153. package/test/test_ffi.js +0 -157
  154. package/test/test_ffi.ts +0 -170
  155. package/test/test_ffi_abi.js +0 -290
  156. package/test/test_ffi_abi.ts +0 -274
  157. package/test/test_ffi_array.js +0 -116
  158. package/test/test_ffi_array.ts +0 -141
  159. package/test/test_ffi_bind.js +0 -656
  160. package/test/test_ffi_bind.ts +0 -670
  161. package/test/test_ffi_struct.js +0 -779
  162. package/test/test_ffi_struct.ts +0 -828
  163. package/test/test_ffi_struct_layout.js +0 -495
  164. package/test/test_ffi_struct_layout.ts +0 -543
  165. package/test/test_ffi_user32.js +0 -103
  166. package/test/test_ffi_user32.ts +0 -113
  167. package/test/test_ffi_windows.js +0 -172
  168. package/test/test_ffi_windows.ts +0 -187
  169. package/test/test_files.js +0 -102
  170. package/test/test_files.ts +0 -121
  171. package/test/test_frame_encoding.js +0 -128
  172. package/test/test_frame_encoding.ts +0 -132
  173. package/test/test_gdi_draw.js +0 -681
  174. package/test/test_gdi_draw.ts +0 -725
  175. package/test/test_helper.js +0 -91
  176. package/test/test_helper.ts +0 -88
  177. package/test/test_http_import.js +0 -96
  178. package/test/test_http_import.ts +0 -93
  179. package/test/test_http_server.js +0 -214
  180. package/test/test_http_server.ts +0 -211
  181. package/test/test_import_dir.js +0 -4
  182. package/test/test_import_dir.ts +0 -5
  183. package/test/test_ipv6.js +0 -134
  184. package/test/test_ipv6.ts +0 -130
  185. package/test/test_jsx.js +0 -1314
  186. package/test/test_meta_url.js +0 -3
  187. package/test/test_meta_url.ts +0 -4
  188. package/test/test_mupdf_render.js +0 -51
  189. package/test/test_mupdf_render.ts +0 -55
  190. package/test/test_mupdf_twice.js +0 -62
  191. package/test/test_mupdf_twice.ts +0 -65
  192. package/test/test_mupdf_wasm.js +0 -39
  193. package/test/test_mupdf_wasm.ts +0 -32
  194. package/test/test_net_event.js +0 -57
  195. package/test/test_net_event.ts +0 -56
  196. package/test/test_net_fetch.js +0 -384
  197. package/test/test_net_fetch.ts +0 -373
  198. package/test/test_net_websocket.js +0 -180
  199. package/test/test_net_websocket.ts +0 -164
  200. package/test/test_polyfill.js +0 -144
  201. package/test/test_polyfill.ts +0 -159
  202. package/test/test_printer.js +0 -137
  203. package/test/test_printer.ts +0 -148
  204. package/test/test_proc.js +0 -141
  205. package/test/test_proc.ts +0 -163
  206. package/test/test_react_complex.js +0 -18678
  207. package/test/test_react_counter.js +0 -18555
  208. package/test/test_react_flex.js +0 -18871
  209. package/test/test_react_hidden.js +0 -18560
  210. package/test/test_react_listview_link.js +0 -18590
  211. package/test/test_react_notify.js +0 -18797
  212. package/test/test_react_render.js +0 -18550
  213. package/test/test_registry.js +0 -74
  214. package/test/test_registry.ts +0 -95
  215. package/test/test_sysinfo.js +0 -122
  216. package/test/test_sysinfo.ts +0 -141
  217. package/test/test_url.js +0 -173
  218. package/test/test_url.ts +0 -183
  219. package/test/test_wasm_basic.js +0 -85
  220. package/test/test_wasm_basic.ts +0 -73
  221. package/test/test_wasm_import_global.js +0 -41
  222. package/test/test_wasm_import_global.ts +0 -45
  223. package/test/test_wasm_sjlj.js +0 -145
  224. package/test/test_wasm_sjlj.ts +0 -125
  225. package/test/test_wasm_types.js +0 -97
  226. package/test/test_wasm_types.ts +0 -124
  227. package/test/test_wolfssl_read.js +0 -203
  228. package/test/test_wolfssl_read.ts +0 -184
  229. package/test/test_worker.js +0 -21
  230. package/test/test_worker.ts +0 -24
  231. package/test/test_worker_concurrent.js +0 -45
  232. package/test/test_worker_concurrent.ts +0 -56
  233. package/test/test_worker_data_url.js +0 -46
  234. package/test/test_worker_data_url.ts +0 -51
  235. package/test/test_worker_fetch.js +0 -26
  236. package/test/test_worker_fetch.ts +0 -27
  237. package/test/test_worker_net.js +0 -69
  238. package/test/test_worker_net.ts +0 -66
  239. package/test/test_worker_wasm_concurrent.js +0 -44
  240. package/test/test_worker_wasm_concurrent.ts +0 -45
  241. package/test/types.wasm +0 -0
  242. package/test/worker_fetch.js +0 -13
  243. package/test/worker_fetch.ts +0 -13
  244. package/test/worker_helper.js +0 -1
  245. package/test/worker_helper.ts +0 -1
  246. package/test/worker_http.js +0 -18
  247. package/test/worker_http.ts +0 -20
  248. package/test/worker_import_lib.js +0 -12
  249. package/test/worker_import_lib.ts +0 -13
  250. package/test/worker_module.js +0 -16
  251. package/test/worker_module.ts +0 -17
  252. package/test/worker_wasm_concurrent.js +0 -22
  253. package/test/worker_wasm_concurrent.ts +0 -22
@@ -1,148 +0,0 @@
1
- import * as ffi from 'ffi'
2
- import * as os from 'os'
3
- import { WCHAR } from '../lib/ffi/bind.js'
4
- import { structArray } from '../lib/ffi/struct.js'
5
- import { NULL, PtrArrayBuffer } from '../lib/ffi/ctype.js'
6
- import { CloseHandle, CreateFile, DeleteFile, GetLastError, GetTempPath, GetFileSize, ReadFile } from '../lib/windows/kernel32.js'
7
- import {
8
- ClosePrinter, DeviceCapabilities, EnumPrinters, EndDocPrinter, EndPagePrinter,
9
- GetDefaultPrinter, OpenPrinter, StartDocPrinter, StartPagePrinter, WritePrinter,
10
- } from '../lib/windows/winspool.js'
11
- import { PRINTER_INFO_2W } from '../lib/windows/structs.js'
12
- import { Tester } from './test_helper.js'
13
- import { DeviceCap, FileCreation } from '../constants'
14
-
15
- // PrinterEnum.LOCAL(0x2) | CONNECTIONS(0x4):可组合 flags 组合 OR 裸传
16
- const LOCAL_OR_CONNECTIONS = 0x6
17
- const MAX_WCHARS = 4096
18
-
19
- // 指针字段跟进读宽字符串 / 跨架构读指针(test_ffi.ts 同型)
20
- function decodeWideAtPtr(ptr: number): string {
21
- if (!ptr) return ''
22
- const chars: number[] = []
23
- let pos = ptr
24
- while (chars.length < MAX_WCHARS) {
25
- const ch = ffi.readByte(pos) + ffi.readByte(pos + 1) * 256
26
- if (ch === 0) break
27
- chars.push(ch)
28
- pos += 2
29
- }
30
- return String.fromCharCode(...chars)
31
- }
32
- function readPtr(dv: DataView, offset: number): number {
33
- if (os.arch === 'ia32') return dv.getUint32(offset, true)
34
- return dv.getUint32(offset, true) + dv.getUint32(offset + 4, true) * 4294967296
35
- }
36
-
37
- export const suite = {
38
- name: 'printer',
39
- run: (t: Tester) => {
40
- t.section('EnumPrinters: two-pass LOCAL|CONNECTIONS')
41
- const neededB = new PtrArrayBuffer(4)
42
- const returnedB = new PtrArrayBuffer(4)
43
- const neededU = new Uint32Array(neededB)
44
- const returnedU = new Uint32Array(returnedB)
45
- EnumPrinters(LOCAL_OR_CONNECTIONS, NULL, 2, NULL, 0, neededB, returnedB)
46
- if (neededU[0]! === 0) {
47
- // 无打印机环境(XP VM):整段优雅跳过——属环境差异非缺陷(test_ffi 先例)
48
- t.skipCase('printer suite (no printers on this VM)')
49
- return
50
- }
51
- t.checkTrue(`pcbNeeded > 0 (${neededU[0]!})`, neededU[0]! > 0)
52
- const buf = new PtrArrayBuffer(neededU[0]!)
53
- t.checkTrue('EnumPrinters full buffer',
54
- EnumPrinters(LOCAL_OR_CONNECTIONS, NULL, 2, buf, neededU[0]!, neededB, returnedB) !== 0)
55
- const count = returnedU[0]!
56
- t.checkTrue(`found printers (${count})`, count > 0)
57
-
58
- // 出参数组读回:结构数组区 = 前 count*size 字节,尾部是字符串数据
59
- // (byteLength 非 size 整数倍)→ 必须显式 count;指针字段跟进读字符串
60
- const infos = structArray(PRINTER_INFO_2W).decode(buf, count)
61
- t.check('decode count == pcReturned', count, infos.length)
62
- // 单值 decode 与数组 decode 首元素一致(布局单一来源互证,无硬编码 offset)
63
- t.checkTrue('array/single decode agree',
64
- PRINTER_INFO_2W.decode(buf).pPrinterName === infos[0]!.pPrinterName)
65
- const names: string[] = []
66
- const ports: Record<string, string> = {}
67
- for (const inf of infos) {
68
- const name = decodeWideAtPtr(inf.pPrinterName)
69
- names.push(name)
70
- ports[name] = decodeWideAtPtr(inf.pPortName)
71
- }
72
-
73
- t.section('GetDefaultPrinter')
74
- const defW = WCHAR.alloc(260)
75
- const lenB = new PtrArrayBuffer(4)
76
- new Uint32Array(lenB)[0] = 260
77
- t.checkTrue('GetDefaultPrinter ok', GetDefaultPrinter(defW, lenB) !== 0)
78
- const defName = WCHAR.decode(defW)
79
- t.checkTrue(`default in enum list (${defName})`, names.includes(defName))
80
-
81
- t.section('DeviceCapabilities: numeric caps on default printer')
82
- const defPort = ports[defName] ?? NULL
83
- const horz = DeviceCapabilities(defName, defPort, DeviceCap.HORZRES, NULL, NULL)
84
- t.checkTrue(`HORZRES sane (${horz})`, horz > 0)
85
- const vert = DeviceCapabilities(defName, defPort, DeviceCap.VERTRES, NULL, NULL)
86
- t.checkTrue(`VERTRES sane (${vert})`, vert > 0)
87
-
88
- t.section('raw job chain on default printer (FILE: port -> .prn file, no UI)')
89
- // 输出文件放系统 temp(GetTempPath 尾带反斜杠)——FILE: 端口把作业写到 pOutputFile
90
- const tmpW = WCHAR.alloc(260)
91
- GetTempPath(260, tmpW)
92
- const outPrn = `${WCHAR.decode(tmpW)}qw_job.prn`
93
- const slot = new PtrArrayBuffer(8)
94
- t.checkTrue('OpenPrinter ok', OpenPrinter(defName, slot, NULL) !== 0)
95
- const hPrinter = readPtr(new DataView(slot), 0)
96
- t.checkTrue(`hPrinter valid (${hPrinter})`, hPrinter !== 0)
97
- // pDatatype 省略(NULL)→ spooler 用打印机默认 datatype;显式传 RAW/XPS_PASS 反而
98
- // 可能被驱动拒——1804 = ERROR_INVALID_DATATYPE(官方错误码表;注意 StartDocPrinter
99
- // 不设置 last error,GetLastError 读到的常是残留值)
100
- const jobId = StartDocPrinter(hPrinter, 1, {
101
- pDocName: WCHAR.encode('QuickWin Raw Job').ptr, // <>ptr 字段收裸地址(number 子类型)
102
- pOutputFile: WCHAR.encode(outPrn).ptr,
103
- })
104
- if (jobId === 0) {
105
- // 失败即暴露(1804 = ERROR_INVALID_DATATYPE——datatype 显式 RAW/XPS_PASS 会被
106
- // XPS 驱动拒,NULL 让 spooler 用默认即通;StartDocPrinter 不设置 last error,
107
- // 下方诊断值常是残留)
108
- t.checkTrue(`StartDocPrinter job id > 0 (lastError=${GetLastError()})`, false)
109
- ClosePrinter(hPrinter)
110
- return
111
- }
112
- t.checkTrue(`StartDocPrinter job id > 0`, jobId > 0)
113
- const sp = StartPagePrinter(hPrinter)
114
- t.checkTrue(`StartPagePrinter (lastError=${GetLastError()})`, sp !== 0)
115
- const job = 'hello printer'
116
- const jBuf = new PtrArrayBuffer(job.length)
117
- const jDv = new DataView(jBuf)
118
- for (let i = 0; i < job.length; i++) jDv.setUint8(i, job.charCodeAt(i))
119
- const pWr = new PtrArrayBuffer(4)
120
- const wr = WritePrinter(hPrinter, jBuf, job.length, pWr)
121
- t.checkTrue(`WritePrinter ok (lastError=${GetLastError()})`, wr !== 0)
122
- t.check('bytes written', job.length, new Uint32Array(pWr)[0])
123
- const ep = EndPagePrinter(hPrinter)
124
- t.checkTrue(`EndPagePrinter (lastError=${GetLastError()})`, ep !== 0)
125
- const ed = EndDocPrinter(hPrinter)
126
- t.checkTrue(`EndDocPrinter (lastError=${GetLastError()})`, ed !== 0)
127
- t.checkTrue('ClosePrinter', ClosePrinter(hPrinter) !== 0)
128
-
129
- // 作业落盘断言:FILE: 端口把 RAW 数据写到 pOutputFile
130
- const hOut = CreateFile(outPrn, 0x80000000 /* GENERIC_READ */, 0, NULL,
131
- FileCreation.OPEN_EXISTING, 0, NULL)
132
- t.checkTrue(`job file exists (${outPrn})`, hOut !== -1)
133
- if (hOut !== -1) {
134
- const fSize = GetFileSize(hOut, NULL)
135
- t.checkTrue(`job file size > 0 (${fSize})`, fSize > 0)
136
- const fBuf = new PtrArrayBuffer(Math.max(fSize, 1))
137
- const pRd = new PtrArrayBuffer(4)
138
- ReadFile(hOut, fBuf, fSize, pRd, NULL)
139
- // RAW 通道(winprint + RAW)应原样落盘——若 XPS 驱动重渲染则 FAIL 揭示实际内容头
140
- let back = ''
141
- const fDv = new DataView(fBuf)
142
- for (let i = 0; i < Math.min(fSize, job.length); i++) back += String.fromCharCode(fDv.getUint8(i))
143
- t.check('job data roundtrip (RAW passthrough)', job, back)
144
- CloseHandle(hOut)
145
- }
146
- DeleteFile(outPrn)
147
- },
148
- }
package/test/test_proc.js DELETED
@@ -1,141 +0,0 @@
1
- import { WCHAR } from '../lib/ffi/bind.js';
2
- import { NULL, PtrArrayBuffer } from '../lib/ffi/ctype.js';
3
- import { CloseHandle, CreateProcess, CreateToolhelp32Snapshot, GetCurrentProcessId, GetExitCodeProcess, GetLastError, GetModuleFileName, GetSystemDirectory, Module32First, Module32Next, OpenProcess, Process32First, Process32Next, Sleep, TerminateProcess, WaitForSingleObject, } from '../lib/windows/kernel32.js';
4
- import { EnumProcesses, GetModuleFileNameEx, GetProcessMemoryInfo } from '../lib/windows/psapi.js';
5
- import { MODULEENTRY32W, PROCESSENTRY32W, PROCESS_INFORMATION, PROCESS_MEMORY_COUNTERS, STARTUPINFOW, } from '../lib/windows/structs.js';
6
- // STILL_ACTIVE:GetExitCodeProcess 对存活进程的保留返回值(杀进程退出码避开 259)
7
- const STILL_ACTIVE = 259;
8
- export const suite = {
9
- name: 'proc',
10
- run: (t) => {
11
- const selfPid = GetCurrentProcessId();
12
- t.checkTrue(`GetCurrentProcessId > 0 (${selfPid})`, selfPid > 0);
13
- // PID 数组扫描(每次刷新:EnumProcesses 出参 needed 字节 /4 = PID 数)
14
- const pidBuf = new PtrArrayBuffer(4096); // 1024 个 PID 槽
15
- const needed = new PtrArrayBuffer(4);
16
- const listPids = () => {
17
- const out = new Set();
18
- if (!EnumProcesses(pidBuf, 4096, needed))
19
- return out;
20
- const n = new Uint32Array(needed)[0] >>> 2; // 字节 /4 = 条数
21
- const arr = new Uint32Array(pidBuf);
22
- for (let i = 0; i < n; i++)
23
- out.add(arr[i]);
24
- return out;
25
- };
26
- t.section('EnumProcesses: pid array contains self');
27
- t.checkTrue('EnumProcesses', EnumProcesses(pidBuf, 4096, needed) !== 0);
28
- const nPid = new Uint32Array(needed)[0] >>> 2;
29
- t.checkTrue(`pid count sane (${nPid})`, nPid > 0);
30
- t.checkTrue('self pid present', listPids().has(selfPid));
31
- t.section('toolhelp Process32 walk: self entry + exe name');
32
- const snapP = CreateToolhelp32Snapshot(0x2 /* TH32CS_SNAPPROCESS */, 0);
33
- t.checkTrue(`snapshot handle (${snapP})`, snapP > 0);
34
- const pe = PROCESSENTRY32W.alloc();
35
- new Uint32Array(pe)[0] = PROCESSENTRY32W.size; // 预写 dwSize(MSDN 要求)
36
- let nProc = 0;
37
- let selfName = '';
38
- let parentOfSelf = -1;
39
- let selfThreads = -1;
40
- if (Process32First(snapP, pe.ptr)) {
41
- do {
42
- const e = PROCESSENTRY32W.decode(pe);
43
- nProc++;
44
- if (e.th32ProcessID === selfPid) {
45
- selfName = e.szExeFile;
46
- parentOfSelf = e.th32ParentProcessID;
47
- selfThreads = e.cntThreads;
48
- }
49
- } while (Process32Next(snapP, pe.ptr));
50
- }
51
- const firstRd = PROCESSENTRY32W.decode(pe);
52
- CloseHandle(snapP);
53
- t.checkTrue(`process entries (${nProc}) >= 3`, nProc >= 3);
54
- t.checkTrue('self found in walk', selfName.length > 0);
55
- t.check('dwSize readback stays size', PROCESSENTRY32W.size, firstRd.dwSize);
56
- t.checkTrue(`parent pid sane (${parentOfSelf})`, parentOfSelf > 0);
57
- t.checkTrue(`cntThreads sane (${selfThreads})`, selfThreads >= 1);
58
- // exe 名与 GetModuleFileName(NULL) 的 basename 互证(批 8 同源锚点)
59
- const exeW = WCHAR.alloc(520);
60
- GetModuleFileName(NULL, exeW, 520);
61
- const exePath = WCHAR.decode(exeW);
62
- const exeBase = exePath.slice(exePath.lastIndexOf('\\') + 1).toLowerCase();
63
- t.check('szExeFile === basename(GetModuleFileName)', exeBase, selfName.toLowerCase());
64
- t.section('OpenProcess + GetProcessMemoryInfo');
65
- const hSelf = OpenProcess(0x400 /* QUERY_INFORMATION */ | 0x10 /* VM_READ */, 0, selfPid);
66
- t.checkTrue(`OpenProcess(self) (${hSelf})`, hSelf !== NULL);
67
- // 上行已判定非 NULL;断言进 ! 消费位(真 NULL → bind 运行时 throw 兜底)
68
- const hQ = hSelf;
69
- const pmc = PROCESS_MEMORY_COUNTERS.alloc();
70
- new Uint32Array(pmc)[0] = PROCESS_MEMORY_COUNTERS.size; // 预写 cb
71
- t.checkTrue('GetProcessMemoryInfo', GetProcessMemoryInfo(hQ, pmc.ptr, PROCESS_MEMORY_COUNTERS.size) !== 0);
72
- const mem = PROCESS_MEMORY_COUNTERS.decode(pmc);
73
- t.check('cb readback stays size', PROCESS_MEMORY_COUNTERS.size, mem.cb);
74
- t.checkTrue(`WorkingSetSize > 0 (${mem.WorkingSetSize})`, mem.WorkingSetSize > 0);
75
- t.checkTrue(`PeakWorkingSet >= WorkingSet (${mem.PeakWorkingSetSize})`, mem.PeakWorkingSetSize >= mem.WorkingSetSize);
76
- t.checkTrue(`PagefileUsage > 0 (${mem.PagefileUsage})`, mem.PagefileUsage > 0);
77
- t.checkTrue(`PageFaultCount >= 0 (${mem.PageFaultCount})`, mem.PageFaultCount >= 0);
78
- const codeB = new PtrArrayBuffer(4);
79
- t.checkTrue('GetExitCodeProcess(self)', GetExitCodeProcess(hQ, codeB) !== 0);
80
- t.check('self is STILL_ACTIVE', STILL_ACTIVE, new Int32Array(codeB)[0]);
81
- CloseHandle(hSelf);
82
- t.checkTrue('OpenProcess(nonexistent pid) -> NULL', OpenProcess(0x400, 0, 0xfffffffe) === NULL);
83
- t.section('toolhelp Module32 walk + GetModuleFileNameEx');
84
- const snapM = CreateToolhelp32Snapshot(0x8 /* TH32CS_SNAPMODULE */, selfPid);
85
- t.checkTrue(`module snapshot (${snapM})`, snapM > 0);
86
- const me = MODULEENTRY32W.alloc();
87
- new Uint32Array(me)[0] = MODULEENTRY32W.size; // 预写 dwSize
88
- let modCount = 0;
89
- let k32Base = 0;
90
- let hasK32 = false;
91
- if (Module32First(snapM, me.ptr)) {
92
- do {
93
- const m = MODULEENTRY32W.decode(me);
94
- modCount++;
95
- if (m.szModule.toLowerCase() === 'kernel32.dll') {
96
- hasK32 = true;
97
- k32Base = m.modBaseAddr;
98
- }
99
- } while (Module32Next(snapM, me.ptr));
100
- }
101
- CloseHandle(snapM);
102
- t.checkTrue(`module count (${modCount}) > 0`, modCount > 0);
103
- t.checkTrue('kernel32.dll in module walk + base sane', hasK32 && k32Base > 0x10000);
104
- // psapi 主模块路径 === kernel32 GetModuleFileName(NULL)(同进程同源互证)
105
- const hSelf2 = OpenProcess(0x400 | 0x10, 0, selfPid);
106
- t.checkTrue(`OpenProcess(self) second (${hSelf2})`, hSelf2 !== NULL);
107
- const exW = WCHAR.alloc(520);
108
- const exLen = GetModuleFileNameEx(hSelf2, NULL, exW, 520);
109
- CloseHandle(hSelf2);
110
- t.checkTrue(`GetModuleFileNameEx len (${exLen})`, exLen > 0);
111
- t.check('exe path psapi === kernel32', exePath.toLowerCase(), WCHAR.decode(exW).toLowerCase());
112
- t.section('CreateProcess -> pid visible -> TerminateProcess');
113
- const sysW = WCHAR.alloc(300);
114
- GetSystemDirectory(sysW, 300); // 尾不带反斜杠
115
- // 首 token 全路径(worker 探针:裸名 PATH 解析在本环境失败 err 267/123)
116
- const cmdline = `${WCHAR.decode(sysW)}\\ping.exe -n 60 127.0.0.1`;
117
- const pi = PROCESS_INFORMATION.alloc();
118
- const created = CreateProcess(NULL, cmdline, NULL, NULL, 0, 0x08000000 /* CREATE_NO_WINDOW */, NULL, NULL, { cb: STARTUPINFOW.size }, pi.ptr);
119
- t.checkTrue(`CreateProcess(ping) ${created ? '' : `err=${GetLastError()}`}`, created !== 0);
120
- if (created) {
121
- const { hProcess, hThread, dwProcessId, dwThreadId } = PROCESS_INFORMATION.decode(pi);
122
- t.checkTrue(`child pid (${dwProcessId}) valid`, dwProcessId > 0 && dwProcessId !== selfPid);
123
- t.checkTrue(`child tid sane (${dwThreadId})`, dwThreadId > 0);
124
- t.checkTrue('child pid in EnumProcesses', listPids().has(dwProcessId));
125
- const codeB2 = new PtrArrayBuffer(4);
126
- GetExitCodeProcess(hProcess, codeB2);
127
- t.check('child alive (STILL_ACTIVE)', STILL_ACTIVE, new Int32Array(codeB2)[0]);
128
- // XP 怪癖:进程初始化未完成时 TerminateProcess,exit code 不保留读回 0
129
- // (win7 立即杀读 42 正常;探针实测 XP 立即杀=0、等 3s 后杀=42)——先等初始化
130
- Sleep(1000);
131
- t.checkTrue('TerminateProcess', TerminateProcess(hProcess, 42) !== 0);
132
- const waited = WaitForSingleObject(hProcess, 5000);
133
- t.checkTrue(`child exited (wait=${waited})`, waited === 0 /* WAIT_OBJECT_0 */);
134
- GetExitCodeProcess(hProcess, codeB2);
135
- t.check('child exit code 42', 42, new Int32Array(codeB2)[0]);
136
- t.checkTrue('child pid gone', !listPids().has(dwProcessId));
137
- CloseHandle(hProcess);
138
- CloseHandle(hThread);
139
- }
140
- },
141
- };
package/test/test_proc.ts DELETED
@@ -1,163 +0,0 @@
1
- import { WCHAR } from '../lib/ffi/bind.js'
2
- import { NULL, PtrArrayBuffer, type Ptr } from '../lib/ffi/ctype.js'
3
- import {
4
- CloseHandle, CreateProcess, CreateToolhelp32Snapshot, GetCurrentProcessId,
5
- GetExitCodeProcess, GetLastError, GetModuleFileName, GetSystemDirectory,
6
- Module32First, Module32Next, OpenProcess, Process32First, Process32Next, Sleep,
7
- TerminateProcess, WaitForSingleObject,
8
- } from '../lib/windows/kernel32.js'
9
- import { EnumProcesses, GetModuleFileNameEx, GetProcessMemoryInfo } from '../lib/windows/psapi.js'
10
- import {
11
- MODULEENTRY32W, PROCESSENTRY32W, PROCESS_INFORMATION,
12
- PROCESS_MEMORY_COUNTERS, STARTUPINFOW,
13
- } from '../lib/windows/structs.js'
14
- import { Tester } from './test_helper.js'
15
-
16
- // STILL_ACTIVE:GetExitCodeProcess 对存活进程的保留返回值(杀进程退出码避开 259)
17
- const STILL_ACTIVE = 259
18
-
19
- export const suite = {
20
- name: 'proc',
21
- run: (t: Tester) => {
22
- const selfPid = GetCurrentProcessId()
23
- t.checkTrue(`GetCurrentProcessId > 0 (${selfPid})`, selfPid > 0)
24
-
25
- // PID 数组扫描(每次刷新:EnumProcesses 出参 needed 字节 /4 = PID 数)
26
- const pidBuf = new PtrArrayBuffer(4096) // 1024 个 PID 槽
27
- const needed = new PtrArrayBuffer(4)
28
- const listPids = (): Set<number> => {
29
- const out = new Set<number>()
30
- if (!EnumProcesses(pidBuf, 4096, needed)) return out
31
- const n = new Uint32Array(needed)[0]! >>> 2 // 字节 /4 = 条数
32
- const arr = new Uint32Array(pidBuf)
33
- for (let i = 0; i < n; i++) out.add(arr[i]!)
34
- return out
35
- }
36
-
37
- t.section('EnumProcesses: pid array contains self')
38
- t.checkTrue('EnumProcesses', EnumProcesses(pidBuf, 4096, needed) !== 0)
39
- const nPid = new Uint32Array(needed)[0]! >>> 2
40
- t.checkTrue(`pid count sane (${nPid})`, nPid > 0)
41
- t.checkTrue('self pid present', listPids().has(selfPid))
42
-
43
- t.section('toolhelp Process32 walk: self entry + exe name')
44
- const snapP = CreateToolhelp32Snapshot(0x2 /* TH32CS_SNAPPROCESS */, 0)
45
- t.checkTrue(`snapshot handle (${snapP})`, snapP > 0)
46
- const pe = PROCESSENTRY32W.alloc()
47
- new Uint32Array(pe)[0] = PROCESSENTRY32W.size // 预写 dwSize(MSDN 要求)
48
- let nProc = 0
49
- let selfName = ''
50
- let parentOfSelf = -1
51
- let selfThreads = -1
52
- if (Process32First(snapP, pe.ptr)) {
53
- do {
54
- const e = PROCESSENTRY32W.decode(pe)
55
- nProc++
56
- if (e.th32ProcessID === selfPid) {
57
- selfName = e.szExeFile
58
- parentOfSelf = e.th32ParentProcessID
59
- selfThreads = e.cntThreads
60
- }
61
- } while (Process32Next(snapP, pe.ptr))
62
- }
63
- const firstRd = PROCESSENTRY32W.decode(pe)
64
- CloseHandle(snapP)
65
- t.checkTrue(`process entries (${nProc}) >= 3`, nProc >= 3)
66
- t.checkTrue('self found in walk', selfName.length > 0)
67
- t.check('dwSize readback stays size', PROCESSENTRY32W.size, firstRd.dwSize)
68
- t.checkTrue(`parent pid sane (${parentOfSelf})`, parentOfSelf > 0)
69
- t.checkTrue(`cntThreads sane (${selfThreads})`, selfThreads >= 1)
70
- // exe 名与 GetModuleFileName(NULL) 的 basename 互证(批 8 同源锚点)
71
- const exeW = WCHAR.alloc(520)
72
- GetModuleFileName(NULL, exeW, 520)
73
- const exePath = WCHAR.decode(exeW)
74
- const exeBase = exePath.slice(exePath.lastIndexOf('\\') + 1).toLowerCase()
75
- t.check('szExeFile === basename(GetModuleFileName)', exeBase, selfName.toLowerCase())
76
-
77
- t.section('OpenProcess + GetProcessMemoryInfo')
78
- const hSelf = OpenProcess(0x400 /* QUERY_INFORMATION */ | 0x10 /* VM_READ */, 0, selfPid)
79
- t.checkTrue(`OpenProcess(self) (${hSelf})`, hSelf !== NULL)
80
- // 上行已判定非 NULL;断言进 ! 消费位(真 NULL → bind 运行时 throw 兜底)
81
- const hQ = hSelf as Ptr<'HPROCESS'>
82
- const pmc = PROCESS_MEMORY_COUNTERS.alloc()
83
- new Uint32Array(pmc)[0] = PROCESS_MEMORY_COUNTERS.size // 预写 cb
84
- t.checkTrue('GetProcessMemoryInfo',
85
- GetProcessMemoryInfo(hQ, pmc.ptr, PROCESS_MEMORY_COUNTERS.size) !== 0)
86
- const mem = PROCESS_MEMORY_COUNTERS.decode(pmc)
87
- t.check('cb readback stays size', PROCESS_MEMORY_COUNTERS.size, mem.cb)
88
- t.checkTrue(`WorkingSetSize > 0 (${mem.WorkingSetSize})`, mem.WorkingSetSize > 0)
89
- t.checkTrue(`PeakWorkingSet >= WorkingSet (${mem.PeakWorkingSetSize})`,
90
- mem.PeakWorkingSetSize >= mem.WorkingSetSize)
91
- t.checkTrue(`PagefileUsage > 0 (${mem.PagefileUsage})`, mem.PagefileUsage > 0)
92
- t.checkTrue(`PageFaultCount >= 0 (${mem.PageFaultCount})`, mem.PageFaultCount >= 0)
93
- const codeB = new PtrArrayBuffer(4)
94
- t.checkTrue('GetExitCodeProcess(self)', GetExitCodeProcess(hQ, codeB) !== 0)
95
- t.check('self is STILL_ACTIVE', STILL_ACTIVE, new Int32Array(codeB)[0])
96
- CloseHandle(hSelf)
97
- t.checkTrue('OpenProcess(nonexistent pid) -> NULL',
98
- OpenProcess(0x400, 0, 0xfffffffe) === NULL)
99
-
100
- t.section('toolhelp Module32 walk + GetModuleFileNameEx')
101
- const snapM = CreateToolhelp32Snapshot(0x8 /* TH32CS_SNAPMODULE */, selfPid)
102
- t.checkTrue(`module snapshot (${snapM})`, snapM > 0)
103
- const me = MODULEENTRY32W.alloc()
104
- new Uint32Array(me)[0] = MODULEENTRY32W.size // 预写 dwSize
105
- let modCount = 0
106
- let k32Base = 0
107
- let hasK32 = false
108
- if (Module32First(snapM, me.ptr)) {
109
- do {
110
- const m = MODULEENTRY32W.decode(me)
111
- modCount++
112
- if (m.szModule.toLowerCase() === 'kernel32.dll') {
113
- hasK32 = true
114
- k32Base = m.modBaseAddr
115
- }
116
- } while (Module32Next(snapM, me.ptr))
117
- }
118
- CloseHandle(snapM)
119
- t.checkTrue(`module count (${modCount}) > 0`, modCount > 0)
120
- t.checkTrue('kernel32.dll in module walk + base sane', hasK32 && k32Base > 0x10000)
121
- // psapi 主模块路径 === kernel32 GetModuleFileName(NULL)(同进程同源互证)
122
- const hSelf2 = OpenProcess(0x400 | 0x10, 0, selfPid)
123
- t.checkTrue(`OpenProcess(self) second (${hSelf2})`, hSelf2 !== NULL)
124
- const exW = WCHAR.alloc(520)
125
- const exLen = GetModuleFileNameEx(hSelf2 as Ptr<'HPROCESS'>, NULL, exW, 520)
126
- CloseHandle(hSelf2)
127
- t.checkTrue(`GetModuleFileNameEx len (${exLen})`, exLen > 0)
128
- t.check('exe path psapi === kernel32',
129
- exePath.toLowerCase(), WCHAR.decode(exW).toLowerCase())
130
-
131
- t.section('CreateProcess -> pid visible -> TerminateProcess')
132
- const sysW = WCHAR.alloc(300)
133
- GetSystemDirectory(sysW, 300) // 尾不带反斜杠
134
- // 首 token 全路径(worker 探针:裸名 PATH 解析在本环境失败 err 267/123)
135
- const cmdline = `${WCHAR.decode(sysW)}\\ping.exe -n 60 127.0.0.1`
136
- const pi = PROCESS_INFORMATION.alloc()
137
- const created = CreateProcess(NULL, cmdline, NULL, NULL, 0,
138
- 0x08000000 /* CREATE_NO_WINDOW */, NULL, NULL,
139
- { cb: STARTUPINFOW.size }, pi.ptr)
140
- t.checkTrue(`CreateProcess(ping) ${created ? '' : `err=${GetLastError()}`}`, created !== 0)
141
- if (created) {
142
- const { hProcess, hThread, dwProcessId, dwThreadId } = PROCESS_INFORMATION.decode(pi)
143
- t.checkTrue(`child pid (${dwProcessId}) valid`,
144
- dwProcessId > 0 && dwProcessId !== selfPid)
145
- t.checkTrue(`child tid sane (${dwThreadId})`, dwThreadId > 0)
146
- t.checkTrue('child pid in EnumProcesses', listPids().has(dwProcessId))
147
- const codeB2 = new PtrArrayBuffer(4)
148
- GetExitCodeProcess(hProcess, codeB2)
149
- t.check('child alive (STILL_ACTIVE)', STILL_ACTIVE, new Int32Array(codeB2)[0])
150
- // XP 怪癖:进程初始化未完成时 TerminateProcess,exit code 不保留读回 0
151
- // (win7 立即杀读 42 正常;探针实测 XP 立即杀=0、等 3s 后杀=42)——先等初始化
152
- Sleep(1000)
153
- t.checkTrue('TerminateProcess', TerminateProcess(hProcess, 42) !== 0)
154
- const waited = WaitForSingleObject(hProcess, 5000)
155
- t.checkTrue(`child exited (wait=${waited})`, waited === 0 /* WAIT_OBJECT_0 */)
156
- GetExitCodeProcess(hProcess, codeB2)
157
- t.check('child exit code 42', 42, new Int32Array(codeB2)[0])
158
- t.checkTrue('child pid gone', !listPids().has(dwProcessId))
159
- CloseHandle(hProcess)
160
- CloseHandle(hThread)
161
- }
162
- },
163
- }