quickwin 1.2.1 → 1.3.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (50) hide show
  1. package/README.en.md +2 -1
  2. package/README.md +2 -1
  3. package/examples/PdfCanvas.js +3 -3
  4. package/examples/PdfCanvas.tsx +3 -3
  5. package/examples/pdf_preview2.js +34 -19
  6. package/examples/pdf_preview2.ts +34 -20
  7. package/examples/pdf_viewer.js +959 -219
  8. package/examples/pdf_viewer.tsx +29 -19
  9. package/examples/test_gallery.js +925 -198
  10. package/examples/test_react_lazy.js +908 -181
  11. package/examples/test_react_listbox.js +908 -181
  12. package/examples/test_root_window.js +908 -181
  13. package/examples/test_tab.js +908 -181
  14. package/lib/ffi-bind.js +85 -0
  15. package/lib/ffi-bind.ts +170 -0
  16. package/lib/ffi-struct.js +224 -0
  17. package/lib/ffi-struct.ts +239 -0
  18. package/lib/react-qw/components/DateTimePicker.js +21 -15
  19. package/lib/react-qw/components/Link.js +4 -6
  20. package/lib/react-qw/components/ListView.js +84 -40
  21. package/lib/react-qw/components/PathPicker.js +40 -24
  22. package/lib/react-qw/components/Tab.js +21 -10
  23. package/lib/react-qw/components/Tooltip.js +27 -15
  24. package/lib/react-qw/components/TreeView.js +23 -33
  25. package/lib/react-qw/nmhdr.js +26 -0
  26. package/lib/react-qw/nmhdr.ts +32 -0
  27. package/lib/text-measure.js +14 -26
  28. package/lib/text-measure.ts +14 -26
  29. package/lib/win-common-structs.js +39 -0
  30. package/lib/win-common-structs.ts +41 -0
  31. package/package.json +1 -1
  32. package/quickwin.d.ts +6 -2
  33. package/qwin-nowasm-x86.exe +0 -0
  34. package/qwin-nowasm.exe +0 -0
  35. package/qwin-x86.exe +0 -0
  36. package/qwin.exe +0 -0
  37. package/test/run.js +2 -0
  38. package/test/run.ts +2 -0
  39. package/test/test_ffi.js +12 -8
  40. package/test/test_ffi.ts +12 -12
  41. package/test/test_ffi_bind.js +42 -0
  42. package/test/test_ffi_bind.ts +46 -0
  43. package/test/test_ffi_struct.js +201 -0
  44. package/test/test_ffi_struct.ts +223 -0
  45. package/test/test_react_complex.js +911 -184
  46. package/test/test_react_counter.js +908 -181
  47. package/test/test_react_flex.js +908 -181
  48. package/test/test_react_hidden.js +910 -183
  49. package/test/test_react_listview_link.js +908 -181
  50. package/test/test_react_render.js +908 -181
package/README.en.md CHANGED
@@ -13,10 +13,11 @@ Install:
13
13
  ```bash
14
14
  # Option 1: npm local install (recommended)
15
15
  npm install quickwin
16
- npx quickwin script.js
16
+ npx quickwin node_modules/quickwin/main.js # bundled main.js demo; use npx quickwin script.js for your own scripts
17
17
 
18
18
  # Option 2: download directly from GitHub Release
19
19
  iwr https://github.com/xna00/quickwin/releases/latest/download/qwin.exe -OutFile qwin.exe
20
+ iwr https://github.com/xna00/quickwin/releases/latest/download/main.js -OutFile main.js
20
21
  .\qwin.exe main.js
21
22
  ```
22
23
 
package/README.md CHANGED
@@ -13,10 +13,11 @@ Windows 平台上的 QuickJS 运行时,支持原生 GUI、网络、WASM、FFI
13
13
  ```bash
14
14
  # 方式一:npm 本地安装(推荐)
15
15
  npm install quickwin
16
- npx quickwin script.js
16
+ npx quickwin node_modules/quickwin/main.js # 包自带 main.js 示例;用 npx quickwin script.js 运行你自己的脚本
17
17
 
18
18
  # 方式二:直接从 GitHub Release 下载
19
19
  iwr https://github.com/xna00/quickwin/releases/latest/download/qwin.exe -OutFile qwin.exe
20
+ iwr https://github.com/xna00/quickwin/releases/latest/download/main.js -OutFile main.js
20
21
  .\qwin.exe main.js
21
22
  ```
22
23
 
@@ -46,11 +46,11 @@ export const PdfCanvas = forwardRef(({ pixmap, style }, ref) => {
46
46
  const pm = pixmapRef.current;
47
47
  if (!pm)
48
48
  return 0;
49
- const hdc = ffi.ffiCall(GetDC_, [ffi.FFI_TYPE_UINT64], [hwnd], ffi.FFI_TYPE_UINT64);
49
+ const hdc = ffi.ffiCall(GetDC_, [ffi.FFI_TYPE_POINTER], [hwnd], ffi.FFI_TYPE_POINTER);
50
50
  if (hdc) {
51
51
  const bmi = makeBitmapInfo(pm.w, pm.h);
52
52
  ffi.ffiCall(SetDIBitsToDevice_, [
53
- ffi.FFI_TYPE_UINT64, FFI_S32, FFI_S32, FFI_U32, FFI_U32,
53
+ ffi.FFI_TYPE_POINTER, FFI_S32, FFI_S32, FFI_U32, FFI_U32,
54
54
  FFI_S32, FFI_S32, FFI_U32, FFI_U32,
55
55
  FFI_PTR, FFI_PTR, FFI_U32
56
56
  ], [
@@ -58,7 +58,7 @@ export const PdfCanvas = forwardRef(({ pixmap, style }, ref) => {
58
58
  0, 0, 0, pm.h,
59
59
  pm.data, bmi, 0
60
60
  ], FFI_S32);
61
- ffi.ffiCall(ReleaseDC_, [ffi.FFI_TYPE_UINT64, ffi.FFI_TYPE_UINT64], [hwnd, hdc], FFI_S32);
61
+ ffi.ffiCall(ReleaseDC_, [ffi.FFI_TYPE_POINTER, ffi.FFI_TYPE_POINTER], [hwnd, hdc], FFI_S32);
62
62
  }
63
63
  return 0;
64
64
  }
@@ -59,11 +59,11 @@ export const PdfCanvas = forwardRef<gui.HWND, PdfCanvasProps>(
59
59
  if (e.msg === gui.WmMsg.PAINT) {
60
60
  const pm = pixmapRef.current
61
61
  if (!pm) return 0
62
- const hdc = ffi.ffiCall(GetDC_, [ffi.FFI_TYPE_UINT64], [hwnd], ffi.FFI_TYPE_UINT64)
62
+ const hdc = ffi.ffiCall(GetDC_, [ffi.FFI_TYPE_POINTER], [hwnd], ffi.FFI_TYPE_POINTER)
63
63
  if (hdc) {
64
64
  const bmi = makeBitmapInfo(pm.w, pm.h)
65
65
  ffi.ffiCall(SetDIBitsToDevice_, [
66
- ffi.FFI_TYPE_UINT64, FFI_S32, FFI_S32, FFI_U32, FFI_U32,
66
+ ffi.FFI_TYPE_POINTER, FFI_S32, FFI_S32, FFI_U32, FFI_U32,
67
67
  FFI_S32, FFI_S32, FFI_U32, FFI_U32,
68
68
  FFI_PTR, FFI_PTR, FFI_U32
69
69
  ], [
@@ -71,7 +71,7 @@ export const PdfCanvas = forwardRef<gui.HWND, PdfCanvasProps>(
71
71
  0, 0, 0, pm.h,
72
72
  pm.data, bmi, 0
73
73
  ], FFI_S32)
74
- ffi.ffiCall(ReleaseDC_, [ffi.FFI_TYPE_UINT64, ffi.FFI_TYPE_UINT64], [hwnd, hdc], FFI_S32)
74
+ ffi.ffiCall(ReleaseDC_, [ffi.FFI_TYPE_POINTER, ffi.FFI_TYPE_POINTER], [hwnd, hdc], FFI_S32)
75
75
  }
76
76
  return 0
77
77
  }
@@ -4,6 +4,7 @@ import * as gui from 'gui';
4
4
  import * as win from 'win';
5
5
  import * as ffi from 'ffi';
6
6
  import { assertNonNullable } from '../lib/assert.js';
7
+ import { OPENFILENAMEW } from '../lib/win-common-structs.js';
7
8
  const FFI_PTR = ffi.FFI_TYPE_POINTER;
8
9
  const FFI_U32 = ffi.FFI_TYPE_UINT32;
9
10
  const FFI_S32 = ffi.FFI_TYPE_SINT32;
@@ -50,10 +51,6 @@ function wideToStr(buf) {
50
51
  }
51
52
  return String.fromCharCode(...chars);
52
53
  }
53
- function setPtr(dv, off, ptr) {
54
- dv.setUint32(off, ptr & 0xFFFFFFFF, true);
55
- dv.setUint32(off + 4, Math.floor(ptr / 0x100000000), true);
56
- }
57
54
  let hwndMain = null;
58
55
  let hwndEdit = null;
59
56
  let hwndCanvas = null;
@@ -172,17 +169,35 @@ function renderPdfPage(mupdf, filePath, pageIndex) {
172
169
  }
173
170
  function openPdfFileDialog() {
174
171
  assertNonNullable(hwndMain);
175
- const structBuf = new ArrayBuffer(152), sv = new DataView(structBuf);
176
172
  const fileBuf = new ArrayBuffer(260 * 2);
177
173
  const filterWide = strToWide('PDF Files\0*.pdf\0All Files\0*.*\0\0');
178
- sv.setUint32(0, 152, true);
179
- sv.setUint32(8, hwndMain & 0xFFFFFFFF, true);
180
- sv.setUint32(12, Math.floor(hwndMain / 0x100000000), true);
181
- setPtr(sv, 24, ffi.bufferPtr(filterWide));
182
- setPtr(sv, 48, ffi.bufferPtr(fileBuf));
183
- sv.setUint32(56, 260, true);
184
- sv.setUint32(96, 0x1000 | 0x0800 | 0x0004, true);
185
- const ret = ffi.ffiCall(GetOpenFileNameW, [FFI_PTR], [structBuf], FFI_U32);
174
+ const ofn = OPENFILENAMEW.write({
175
+ lStructSize: OPENFILENAMEW.size,
176
+ hwndOwner: hwndMain,
177
+ hInstance: 0,
178
+ lpstrFilter: ffi.bufferPtr(filterWide),
179
+ lpstrCustomFilter: 0,
180
+ nMaxCustFilter: 0,
181
+ nFilterIndex: 0,
182
+ lpstrFile: ffi.bufferPtr(fileBuf),
183
+ nMaxFile: 260,
184
+ lpstrFileTitle: 0,
185
+ nMaxFileTitle: 0,
186
+ lpstrInitialDir: 0,
187
+ lpstrTitle: 0,
188
+ Flags: 0x1000 | 0x0800 | 0x0004,
189
+ nFileOffset: 0,
190
+ nFileExtension: 0,
191
+ lpstrDefExt: 0,
192
+ lCustData: 0,
193
+ lpfnHook: 0,
194
+ lpTemplateName: 0,
195
+ pvReserved: 0,
196
+ dwReserved: 0,
197
+ FlagsEx: 0,
198
+ });
199
+ ofn.__keep = [fileBuf, filterWide];
200
+ const ret = ffi.ffiCall(GetOpenFileNameW, [FFI_PTR], [ofn], FFI_U32);
186
201
  return ret ? wideToStr(fileBuf) : null;
187
202
  }
188
203
  function updateScrollRange() {
@@ -344,15 +359,15 @@ async function main() {
344
359
  const pm = currentPixmap;
345
360
  if (!pm)
346
361
  return 0;
347
- const hdc = ffi.ffiCall(GetDC, [ffi.FFI_TYPE_UINT64], [hwnd], ffi.FFI_TYPE_UINT64);
362
+ const hdc = ffi.ffiCall(GetDC, [ffi.FFI_TYPE_POINTER], [hwnd], ffi.FFI_TYPE_POINTER);
348
363
  if (hdc) {
349
364
  const bmi = makeBitmapInfo(pm.w, pm.h);
350
365
  ffi.ffiCall(SetDIBitsToDevice, [
351
- ffi.FFI_TYPE_UINT64, FFI_S32, FFI_S32, FFI_U32, FFI_U32,
366
+ ffi.FFI_TYPE_POINTER, FFI_S32, FFI_S32, FFI_U32, FFI_U32,
352
367
  FFI_S32, FFI_S32, FFI_U32, FFI_U32,
353
368
  FFI_PTR, FFI_PTR, FFI_U32
354
369
  ], [hdc, 0, 0, pm.w, pm.h, 0, 0, 0, pm.h, pm.data, bmi, 0], FFI_S32);
355
- ffi.ffiCall(ReleaseDC, [ffi.FFI_TYPE_UINT64, ffi.FFI_TYPE_UINT64], [hwnd, hdc], FFI_S32);
370
+ ffi.ffiCall(ReleaseDC, [ffi.FFI_TYPE_POINTER, ffi.FFI_TYPE_POINTER], [hwnd, hdc], FFI_S32);
356
371
  }
357
372
  return 0;
358
373
  }
@@ -366,10 +381,10 @@ async function main() {
366
381
  const cr = gui.GetClientRect(hwnd);
367
382
  if (cr) {
368
383
  const cw = cr.right - cr.left, ch = cr.bottom - cr.top;
369
- const hdc = ffi.ffiCall(GetDC, [ffi.FFI_TYPE_UINT64], [hwnd], ffi.FFI_TYPE_UINT64);
384
+ const hdc = ffi.ffiCall(GetDC, [ffi.FFI_TYPE_POINTER], [hwnd], ffi.FFI_TYPE_POINTER);
370
385
  if (hdc) {
371
- ffi.ffiCall(PatBlt, [ffi.FFI_TYPE_UINT64, FFI_S32, FFI_S32, FFI_S32, FFI_S32, FFI_U32], [hdc, 0, 0, cw, ch, WHITENESS], FFI_U32);
372
- ffi.ffiCall(ReleaseDC, [ffi.FFI_TYPE_UINT64, ffi.FFI_TYPE_UINT64], [hwnd, hdc], FFI_S32);
386
+ ffi.ffiCall(PatBlt, [ffi.FFI_TYPE_POINTER, FFI_S32, FFI_S32, FFI_S32, FFI_S32, FFI_U32], [hdc, 0, 0, cw, ch, WHITENESS], FFI_U32);
387
+ ffi.ffiCall(ReleaseDC, [ffi.FFI_TYPE_POINTER, ffi.FFI_TYPE_POINTER], [hwnd, hdc], FFI_S32);
373
388
  }
374
389
  }
375
390
  gui.DefWindowProc(hwnd, msg, wParam, lParam);
@@ -5,6 +5,7 @@ import * as win from 'win'
5
5
  import * as ffi from 'ffi'
6
6
  import type { Document, Page, Pixmap } from '../vendor/mupdf-wasm/mupdf.js'
7
7
  import { assertNonNullable } from '../lib/assert.js'
8
+ import { OPENFILENAMEW } from '../lib/win-common-structs.js'
8
9
 
9
10
  const FFI_PTR = ffi.FFI_TYPE_POINTER
10
11
  const FFI_U32 = ffi.FFI_TYPE_UINT32
@@ -55,11 +56,6 @@ function wideToStr(buf: ArrayBuffer): string {
55
56
  return String.fromCharCode(...chars)
56
57
  }
57
58
 
58
- function setPtr(dv: DataView, off: number, ptr: number): void {
59
- dv.setUint32(off, ptr & 0xFFFFFFFF, true)
60
- dv.setUint32(off + 4, Math.floor(ptr / 0x100000000), true)
61
- }
62
-
63
59
  interface PixmapInfo {
64
60
  data: ArrayBuffer; w: number; h: number
65
61
  }
@@ -133,17 +129,35 @@ function renderPdfPage(mupdf: MuPdf, filePath: string, pageIndex: number): Pixma
133
129
 
134
130
  function openPdfFileDialog(): string | null {
135
131
  assertNonNullable(hwndMain)
136
- const structBuf = new ArrayBuffer(152), sv = new DataView(structBuf)
137
132
  const fileBuf = new ArrayBuffer(260 * 2)
138
133
  const filterWide = strToWide('PDF Files\0*.pdf\0All Files\0*.*\0\0')
139
- sv.setUint32(0, 152, true)
140
- sv.setUint32(8, hwndMain & 0xFFFFFFFF, true)
141
- sv.setUint32(12, Math.floor(hwndMain / 0x100000000), true)
142
- setPtr(sv, 24, ffi.bufferPtr(filterWide))
143
- setPtr(sv, 48, ffi.bufferPtr(fileBuf))
144
- sv.setUint32(56, 260, true)
145
- sv.setUint32(96, 0x1000 | 0x0800 | 0x0004, true)
146
- const ret = ffi.ffiCall(GetOpenFileNameW, [FFI_PTR], [structBuf], FFI_U32)
134
+ const ofn: ArrayBuffer & { __keep?: ArrayBuffer[] } = OPENFILENAMEW.write({
135
+ lStructSize: OPENFILENAMEW.size,
136
+ hwndOwner: hwndMain,
137
+ hInstance: 0,
138
+ lpstrFilter: ffi.bufferPtr(filterWide),
139
+ lpstrCustomFilter: 0,
140
+ nMaxCustFilter: 0,
141
+ nFilterIndex: 0,
142
+ lpstrFile: ffi.bufferPtr(fileBuf),
143
+ nMaxFile: 260,
144
+ lpstrFileTitle: 0,
145
+ nMaxFileTitle: 0,
146
+ lpstrInitialDir: 0,
147
+ lpstrTitle: 0,
148
+ Flags: 0x1000 | 0x0800 | 0x0004,
149
+ nFileOffset: 0,
150
+ nFileExtension: 0,
151
+ lpstrDefExt: 0,
152
+ lCustData: 0,
153
+ lpfnHook: 0,
154
+ lpTemplateName: 0,
155
+ pvReserved: 0,
156
+ dwReserved: 0,
157
+ FlagsEx: 0,
158
+ })
159
+ ofn.__keep = [fileBuf, filterWide]
160
+ const ret = ffi.ffiCall(GetOpenFileNameW, [FFI_PTR], [ofn], FFI_U32)
147
161
  return ret ? wideToStr(fileBuf) : null
148
162
  }
149
163
 
@@ -299,15 +313,15 @@ let hwndBtnNext: gui.HWND | null = null
299
313
  gui.DefWindowProc(hwnd, msg, wParam, lParam)
300
314
  const pm = currentPixmap
301
315
  if (!pm) return 0
302
- const hdc = ffi.ffiCall(GetDC, [ffi.FFI_TYPE_UINT64], [hwnd], ffi.FFI_TYPE_UINT64)
316
+ const hdc = ffi.ffiCall(GetDC, [ffi.FFI_TYPE_POINTER], [hwnd], ffi.FFI_TYPE_POINTER)
303
317
  if (hdc) {
304
318
  const bmi = makeBitmapInfo(pm.w, pm.h)
305
319
  ffi.ffiCall(SetDIBitsToDevice, [
306
- ffi.FFI_TYPE_UINT64, FFI_S32, FFI_S32, FFI_U32, FFI_U32,
320
+ ffi.FFI_TYPE_POINTER, FFI_S32, FFI_S32, FFI_U32, FFI_U32,
307
321
  FFI_S32, FFI_S32, FFI_U32, FFI_U32,
308
322
  FFI_PTR, FFI_PTR, FFI_U32
309
323
  ], [hdc, 0, 0, pm.w, pm.h, 0, 0, 0, pm.h, pm.data, bmi, 0], FFI_S32)
310
- ffi.ffiCall(ReleaseDC, [ffi.FFI_TYPE_UINT64, ffi.FFI_TYPE_UINT64], [hwnd, hdc], FFI_S32)
324
+ ffi.ffiCall(ReleaseDC, [ffi.FFI_TYPE_POINTER, ffi.FFI_TYPE_POINTER], [hwnd, hdc], FFI_S32)
311
325
  }
312
326
  return 0
313
327
  }
@@ -321,11 +335,11 @@ let hwndBtnNext: gui.HWND | null = null
321
335
  const cr = gui.GetClientRect(hwnd)
322
336
  if (cr) {
323
337
  const cw = cr.right - cr.left, ch = cr.bottom - cr.top
324
- const hdc = ffi.ffiCall(GetDC, [ffi.FFI_TYPE_UINT64], [hwnd], ffi.FFI_TYPE_UINT64)
338
+ const hdc = ffi.ffiCall(GetDC, [ffi.FFI_TYPE_POINTER], [hwnd], ffi.FFI_TYPE_POINTER)
325
339
  if (hdc) {
326
- ffi.ffiCall(PatBlt, [ffi.FFI_TYPE_UINT64, FFI_S32, FFI_S32, FFI_S32, FFI_S32, FFI_U32],
340
+ ffi.ffiCall(PatBlt, [ffi.FFI_TYPE_POINTER, FFI_S32, FFI_S32, FFI_S32, FFI_S32, FFI_U32],
327
341
  [hdc, 0, 0, cw, ch, WHITENESS], FFI_U32)
328
- ffi.ffiCall(ReleaseDC, [ffi.FFI_TYPE_UINT64, ffi.FFI_TYPE_UINT64], [hwnd, hdc], FFI_S32)
342
+ ffi.ffiCall(ReleaseDC, [ffi.FFI_TYPE_POINTER, ffi.FFI_TYPE_POINTER], [hwnd, hdc], FFI_S32)
329
343
  }
330
344
  }
331
345
  gui.DefWindowProc(hwnd, msg, wParam, lParam)