quickwin 2.3.1 → 3.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (97) 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/bitmap.js +40 -0
  24. package/lib/bitmap.ts +39 -0
  25. package/lib/certs.js +31 -3
  26. package/lib/certs.ts +32 -3
  27. package/lib/dpi.js +30 -0
  28. package/lib/dpi.ts +31 -0
  29. package/lib/dumpRects.js +14 -7
  30. package/lib/dumpRects.ts +14 -6
  31. package/lib/ffi/bind.js +5 -4
  32. package/lib/ffi/bind.ts +9 -8
  33. package/lib/react-qw/components/DateTimePicker.js +6 -7
  34. package/lib/react-qw/components/Input.js +5 -1
  35. package/lib/react-qw/components/ListView.js +8 -6
  36. package/lib/react-qw/components/ScrollView.js +28 -22
  37. package/lib/react-qw/index.js +7 -5
  38. package/lib/react-qw/index.ts +5 -5
  39. package/lib/react-qw/props.js +3 -3
  40. package/lib/react-qw/props.ts +3 -3
  41. package/lib/react-qw/reconciler.js +12 -17
  42. package/lib/react-qw/reconciler.ts +12 -16
  43. package/lib/text-measure.js +9 -6
  44. package/lib/text-measure.ts +9 -6
  45. package/lib/windows/comctl32.js +3 -2
  46. package/lib/windows/comctl32.ts +3 -2
  47. package/lib/windows/gdi32.js +28 -6
  48. package/lib/windows/gdi32.ts +30 -6
  49. package/lib/windows/kernel32.js +9 -0
  50. package/lib/windows/kernel32.ts +9 -0
  51. package/lib/windows/shell32.js +11 -2
  52. package/lib/windows/shell32.ts +13 -2
  53. package/lib/windows/structs.js +51 -0
  54. package/lib/windows/structs.ts +55 -0
  55. package/lib/windows/user32.js +6 -5
  56. package/lib/windows/user32.ts +6 -5
  57. package/main.js +13 -5
  58. package/package.json +2 -2
  59. package/quickwin.d.ts +13 -115
  60. package/qwin-nowasm-x86.exe +0 -0
  61. package/qwin-nowasm.exe +0 -0
  62. package/qwin-x86.exe +0 -0
  63. package/qwin.exe +0 -0
  64. package/test/bench_ffi_callraw.js +3 -4
  65. package/test/bench_ffi_callraw.ts +3 -4
  66. package/test/debug/mupdf_debug.js +4 -22
  67. package/test/debug/wasm_export_debug.js +2 -12
  68. package/test/debug/wasm_names.js +3 -13
  69. package/test/example.pdf +0 -0
  70. package/test/mupdf-cdn.js +40 -0
  71. package/test/mupdf-cdn.ts +43 -0
  72. package/test/test_ffi.js +8 -9
  73. package/test/test_ffi.ts +8 -9
  74. package/test/test_ffi_abi.js +6 -6
  75. package/test/test_ffi_abi.ts +8 -8
  76. package/test/test_ffi_windows.js +82 -11
  77. package/test/test_ffi_windows.ts +85 -11
  78. package/test/test_gdi_draw.js +3 -3
  79. package/test/test_gdi_draw.ts +4 -4
  80. package/test/test_mupdf_render.js +4 -22
  81. package/test/test_mupdf_render.ts +4 -23
  82. package/test/test_mupdf_twice.js +4 -19
  83. package/test/test_mupdf_twice.ts +4 -20
  84. package/test/test_mupdf_wasm.js +10 -4
  85. package/test/test_mupdf_wasm.ts +6 -4
  86. package/test/test_react_complex.js +316 -140
  87. package/test/test_react_counter.js +295 -133
  88. package/test/test_react_flex.js +297 -138
  89. package/test/test_react_hidden.js +296 -134
  90. package/test/test_react_listview_link.js +288 -131
  91. package/test/test_react_notify.js +290 -133
  92. package/test/test_react_render.js +295 -133
  93. package/vendor/mupdf-wasm/mupdf-wasm.d.ts +0 -571
  94. package/vendor/mupdf-wasm/mupdf-wasm.js +0 -2749
  95. package/vendor/mupdf-wasm/mupdf-wasm.wasm +0 -0
  96. package/vendor/mupdf-wasm/mupdf.d.ts +0 -939
  97. package/vendor/mupdf-wasm/mupdf.js +0 -3317
@@ -1,12 +1,13 @@
1
- import { PtrArrayBuffer } from '../lib/ffi/ctype.js';
1
+ import { PtrArrayBuffer, NULL } from '../lib/ffi/ctype.js';
2
2
  import '../lib/polyfill.js';
3
3
  import * as std from 'std';
4
4
  import * as gui from 'gui';
5
+ import { MUPDF_JS_URL, preloadMupdfWasm } from '../test/mupdf-cdn.js';
5
6
  import { assertNonNullable } from '../lib/assert.js';
6
7
  import { WCHAR } from '../lib/ffi/bind.js';
7
- import { BITMAPINFOHEADER, OPENFILENAMEW } from '../lib/windows/structs.js';
8
+ import { BITMAPINFOHEADER, OPENFILENAMEW, RECT, SCROLLINFO } from '../lib/windows/structs.js';
8
9
  import { GetOpenFileName } from '../lib/windows/comdlg32.js';
9
- import { GetDC, ReleaseDC } from '../lib/windows/user32.js';
10
+ import { GetClientRect, GetDC, GetScrollInfo, GetWindowLongPtr, GetWindowText, GetWindowTextLength, InvalidateRect, MessageBox, PostQuitMessage, ReleaseDC, SetScrollInfo, SetWindowPos, SetWindowLongPtr, SetWindowText, ShowScrollBar, ShowWindow } from '../lib/windows/user32.js';
10
11
  import { PatBlt, SetDIBitsToDevice } from '../lib/windows/gdi32.js';
11
12
  const WHITENESS = 0x00FF0062;
12
13
  function makeBitmapInfo(w, h) {
@@ -33,21 +34,9 @@ function clearCachedDoc() {
33
34
  cachedPath = '';
34
35
  }
35
36
  async function loadMupdf() {
36
- const wasmPath = './vendor/mupdf-wasm/mupdf-wasm.wasm';
37
- const fp = std.open(wasmPath, 'rb');
38
- if (!fp) {
39
- std.printf('Error: cannot open %s\n', wasmPath);
40
- return null;
41
- }
42
- fp.seek(0, 2);
43
- const size = fp.tell();
44
- fp.seek(0, 0);
45
- const buf = new ArrayBuffer(size);
46
- fp.read(buf, 0, size);
47
- fp.close();
48
- (globalThis).$libmupdf_wasm_Module = { wasmBinary: buf, locateFile: (p) => p };
49
37
  try {
50
- return await import('../vendor/mupdf-wasm/mupdf.js');
38
+ await preloadMupdfWasm();
39
+ return await import(MUPDF_JS_URL);
51
40
  }
52
41
  catch (e) {
53
42
  std.printf('Error: mupdf load failed: %s\n', String(e));
@@ -152,79 +141,87 @@ function updateScrollRange() {
152
141
  assertNonNullable(hwndContent);
153
142
  if (!currentPixmap)
154
143
  return;
155
- const cr = gui.GetClientRect(hwndCanvas);
156
- if (!cr)
144
+ const crBuf = RECT.alloc();
145
+ if (!GetClientRect(hwndCanvas, crBuf.ptr))
157
146
  return;
158
- const cw = cr.right - cr.left, ch = cr.bottom - cr.top;
147
+ const { left, top, right, bottom } = RECT.decode(crBuf);
148
+ const cw = right - left, ch = bottom - top;
159
149
  const maxX = Math.max(0, currentPixmap.w - cw);
160
150
  const maxY = Math.max(0, currentPixmap.h - ch);
161
151
  scrollX = Math.min(scrollX, maxX);
162
152
  scrollY = Math.min(scrollY, maxY);
163
153
  if (currentPixmap.w > cw) {
164
- const style = gui.GetWindowLongPtr(hwndCanvas, -16 /* Gwlp.STYLE */) | 0;
154
+ const style = GetWindowLongPtr(hwndCanvas, -16 /* Gwlp.STYLE */);
165
155
  if (!(style & 1048576 /* WindowStyle.HSCROLL */)) {
166
- gui.SetWindowLongPtr(hwndCanvas, -16 /* Gwlp.STYLE */, style | 1048576 /* WindowStyle.HSCROLL */);
167
- gui.SetWindowPos(hwndCanvas, 0 /* SetWindowPosHwnd.TOP */, 0, 0, 0, 0, 2 /* SetWindowPosFlag.SWP_NOMOVE */ | 1 /* SetWindowPosFlag.SWP_NOSIZE */ | 4 /* SetWindowPosFlag.SWP_NOZORDER */ | 32 /* SetWindowPosFlag.SWP_FRAMECHANGED */);
156
+ SetWindowLongPtr(hwndCanvas, -16 /* Gwlp.STYLE */, style | 1048576 /* WindowStyle.HSCROLL */);
157
+ SetWindowPos(hwndCanvas, 0 /* SetWindowPosHwnd.TOP */, 0, 0, 0, 0, 2 /* SetWindowPosFlag.SWP_NOMOVE */ | 1 /* SetWindowPosFlag.SWP_NOSIZE */ | 4 /* SetWindowPosFlag.SWP_NOZORDER */ | 32 /* SetWindowPosFlag.SWP_FRAMECHANGED */);
168
158
  }
169
- gui.SetScrollInfo(hwndCanvas, 0 /* ScrollBar.HORZ */, { min: 0, max: currentPixmap.w - 1, page: cw, pos: scrollX }, true);
170
- gui.ShowScrollBar(hwndCanvas, 0 /* ScrollBar.HORZ */, true);
159
+ SetScrollInfo(hwndCanvas, 0 /* ScrollBar.HORZ */, {
160
+ cbSize: SCROLLINFO.size, fMask: 1 /* ScrollInfoFlag.RANGE */ | 2 /* ScrollInfoFlag.PAGE */ | 4 /* ScrollInfoFlag.POS */,
161
+ nMin: 0, nMax: currentPixmap.w - 1, nPage: cw, nPos: scrollX,
162
+ }, 1);
163
+ ShowScrollBar(hwndCanvas, 0 /* ScrollBar.HORZ */, 1);
171
164
  }
172
165
  else {
173
166
  scrollX = 0;
174
- const style = gui.GetWindowLongPtr(hwndCanvas, -16 /* Gwlp.STYLE */) | 0;
167
+ const style = GetWindowLongPtr(hwndCanvas, -16 /* Gwlp.STYLE */);
175
168
  if (style & 1048576 /* WindowStyle.HSCROLL */) {
176
- gui.SetWindowLongPtr(hwndCanvas, -16 /* Gwlp.STYLE */, style & ~1048576 /* WindowStyle.HSCROLL */);
177
- gui.SetWindowPos(hwndCanvas, 0 /* SetWindowPosHwnd.TOP */, 0, 0, 0, 0, 2 /* SetWindowPosFlag.SWP_NOMOVE */ | 1 /* SetWindowPosFlag.SWP_NOSIZE */ | 4 /* SetWindowPosFlag.SWP_NOZORDER */ | 32 /* SetWindowPosFlag.SWP_FRAMECHANGED */);
169
+ SetWindowLongPtr(hwndCanvas, -16 /* Gwlp.STYLE */, style & ~1048576 /* WindowStyle.HSCROLL */);
170
+ SetWindowPos(hwndCanvas, 0 /* SetWindowPosHwnd.TOP */, 0, 0, 0, 0, 2 /* SetWindowPosFlag.SWP_NOMOVE */ | 1 /* SetWindowPosFlag.SWP_NOSIZE */ | 4 /* SetWindowPosFlag.SWP_NOZORDER */ | 32 /* SetWindowPosFlag.SWP_FRAMECHANGED */);
178
171
  }
179
- gui.ShowScrollBar(hwndCanvas, 0 /* ScrollBar.HORZ */, false);
172
+ ShowScrollBar(hwndCanvas, 0 /* ScrollBar.HORZ */, 0);
180
173
  }
181
174
  if (currentPixmap.h > ch) {
182
- gui.SetScrollInfo(hwndCanvas, 1 /* ScrollBar.VERT */, { min: 0, max: currentPixmap.h - 1, page: ch, pos: scrollY }, true);
183
- gui.ShowScrollBar(hwndCanvas, 1 /* ScrollBar.VERT */, true);
175
+ SetScrollInfo(hwndCanvas, 1 /* ScrollBar.VERT */, {
176
+ cbSize: SCROLLINFO.size, fMask: 1 /* ScrollInfoFlag.RANGE */ | 2 /* ScrollInfoFlag.PAGE */ | 4 /* ScrollInfoFlag.POS */,
177
+ nMin: 0, nMax: currentPixmap.h - 1, nPage: ch, nPos: scrollY,
178
+ }, 1);
179
+ ShowScrollBar(hwndCanvas, 1 /* ScrollBar.VERT */, 1);
184
180
  }
185
181
  else {
186
182
  scrollY = 0;
187
- gui.ShowScrollBar(hwndCanvas, 1 /* ScrollBar.VERT */, false);
183
+ ShowScrollBar(hwndCanvas, 1 /* ScrollBar.VERT */, 0);
188
184
  }
189
- gui.SetWindowPos(hwndContent, 0 /* SetWindowPosHwnd.TOP */, -scrollX, -scrollY, 0, 0, 1 /* SetWindowPosFlag.SWP_NOSIZE */ | 4 /* SetWindowPosFlag.SWP_NOZORDER */);
185
+ SetWindowPos(hwndContent, 0 /* SetWindowPosHwnd.TOP */, -scrollX, -scrollY, 0, 0, 1 /* SetWindowPosFlag.SWP_NOSIZE */ | 4 /* SetWindowPosFlag.SWP_NOZORDER */);
190
186
  }
191
187
  function showPdf(mupdf, path, pageIdx) {
192
188
  assertNonNullable(hwndMain);
193
189
  assertNonNullable(hwndContent);
194
190
  const pix = renderPdfPage(mupdf, path, pageIdx);
195
191
  if (!pix) {
196
- gui.MessageBox('渲染 PDF 失败');
192
+ MessageBox(NULL, '渲染 PDF 失败', 'JS Alert', 0);
197
193
  return;
198
194
  }
199
195
  currentPixmap = pix;
200
196
  currentPage = pageIdx;
201
197
  totalPages = pix.totalPages;
202
- gui.SetWindowText(hwndMain, 'PDF 预览 - 第 ' + (pageIdx + 1) + '/' + totalPages + ' 页');
198
+ SetWindowText(hwndMain, 'PDF 预览 - 第 ' + (pageIdx + 1) + '/' + totalPages + ' 页');
203
199
  scrollX = 0;
204
200
  scrollY = 0;
205
- gui.SetWindowPos(hwndContent, 0 /* SetWindowPosHwnd.TOP */, 0, 0, pix.w, pix.h, 4 /* SetWindowPosFlag.SWP_NOZORDER */ | 2 /* SetWindowPosFlag.SWP_NOMOVE */);
201
+ SetWindowPos(hwndContent, 0 /* SetWindowPosHwnd.TOP */, 0, 0, pix.w, pix.h, 4 /* SetWindowPosFlag.SWP_NOZORDER */ | 2 /* SetWindowPosFlag.SWP_NOMOVE */);
206
202
  updateScrollRange();
207
- gui.InvalidateRect(hwndContent, null, true);
203
+ InvalidateRect(hwndContent, NULL, 1);
208
204
  }
209
205
  function doScroll(dx, dy) {
210
206
  assertNonNullable(hwndCanvas);
211
207
  assertNonNullable(hwndContent);
212
- const cr = gui.GetClientRect(hwndCanvas);
213
- if (!cr || !currentPixmap)
208
+ const crBuf = RECT.alloc();
209
+ if (!GetClientRect(hwndCanvas, crBuf.ptr) || !currentPixmap)
214
210
  return;
215
- const cw = cr.right - cr.left, ch = cr.bottom - cr.top;
211
+ const { left, top, right, bottom } = RECT.decode(crBuf);
212
+ const cw = right - left, ch = bottom - top;
216
213
  const maxX = Math.max(0, currentPixmap.w - cw);
217
214
  const maxY = Math.max(0, currentPixmap.h - ch);
218
215
  scrollX = Math.max(0, Math.min(maxX, scrollX + dx));
219
216
  scrollY = Math.max(0, Math.min(maxY, scrollY + dy));
220
- gui.SetWindowPos(hwndContent, 0 /* SetWindowPosHwnd.TOP */, -scrollX, -scrollY, 0, 0, 1 /* SetWindowPosFlag.SWP_NOSIZE */ | 4 /* SetWindowPosFlag.SWP_NOZORDER */);
221
- gui.SetScrollInfo(hwndCanvas, 0 /* ScrollBar.HORZ */, { pos: scrollX }, true);
222
- gui.SetScrollInfo(hwndCanvas, 1 /* ScrollBar.VERT */, { pos: scrollY }, true);
217
+ SetWindowPos(hwndContent, 0 /* SetWindowPosHwnd.TOP */, -scrollX, -scrollY, 0, 0, 1 /* SetWindowPosFlag.SWP_NOSIZE */ | 4 /* SetWindowPosFlag.SWP_NOZORDER */);
218
+ SetScrollInfo(hwndCanvas, 0 /* ScrollBar.HORZ */, { cbSize: SCROLLINFO.size, fMask: 4 /* ScrollInfoFlag.POS */, nPos: scrollX }, 1);
219
+ SetScrollInfo(hwndCanvas, 1 /* ScrollBar.VERT */, { cbSize: SCROLLINFO.size, fMask: 4 /* ScrollInfoFlag.POS */, nPos: scrollY }, 1);
223
220
  }
224
221
  async function main() {
225
222
  const mupdf = await loadMupdf();
226
223
  if (!mupdf) {
227
- gui.MessageBox('加载 mupdf WASM 失败');
224
+ MessageBox(NULL, '加载 mupdf WASM 失败', 'JS Alert', 0);
228
225
  return;
229
226
  }
230
227
  const WS_CHILD = 1073741824 /* WindowStyle.CHILD */;
@@ -241,15 +238,16 @@ async function main() {
241
238
  assertNonNullable(hwndBtnPrev);
242
239
  assertNonNullable(hwndBtnNext);
243
240
  if (msg === 2 /* WmMsg.DESTROY */) {
244
- gui.PostQuitMessage(0);
241
+ PostQuitMessage(0);
245
242
  return 0;
246
243
  }
247
244
  if (msg === 5 /* WmMsg.SIZE */) {
248
- const cr = gui.GetClientRect(hwnd);
249
- if (cr) {
250
- const cw = cr.right - cr.left, ch = cr.bottom - cr.top;
251
- gui.SetWindowPos(hwndCanvas, 0 /* SetWindowPosHwnd.TOP */, 0, 50, cw, Math.max(1, ch - 50), 4 /* SetWindowPosFlag.SWP_NOZORDER */);
252
- gui.SetWindowPos(hwndEdit, 0 /* SetWindowPosHwnd.TOP */, 0, 0, Math.max(100, cw - 320), 0, 2 /* SetWindowPosFlag.SWP_NOMOVE */ | 4 /* SetWindowPosFlag.SWP_NOZORDER */);
245
+ const crBuf = RECT.alloc();
246
+ if (GetClientRect(hwnd, crBuf.ptr)) {
247
+ const { left, top, right, bottom } = RECT.decode(crBuf);
248
+ const cw = right - left, ch = bottom - top;
249
+ SetWindowPos(hwndCanvas, 0 /* SetWindowPosHwnd.TOP */, 0, 50, cw, Math.max(1, ch - 50), 4 /* SetWindowPosFlag.SWP_NOZORDER */);
250
+ SetWindowPos(hwndEdit, 0 /* SetWindowPosHwnd.TOP */, 0, 0, Math.max(100, cw - 320), 0, 2 /* SetWindowPosFlag.SWP_NOMOVE */ | 4 /* SetWindowPosFlag.SWP_NOZORDER */);
253
251
  }
254
252
  return gui.DefWindowProc(hwnd, msg, wParam, lParam);
255
253
  }
@@ -258,17 +256,23 @@ async function main() {
258
256
  if (hCtrl === hwndBtnOpen) {
259
257
  const path = openPdfFileDialog();
260
258
  if (path) {
261
- gui.SetWindowText(hwndEdit, path);
259
+ SetWindowText(hwndEdit, path);
262
260
  showPdf(mupdf, path, 0);
263
261
  }
264
262
  }
265
263
  else if (hCtrl === hwndBtnPrev) {
266
- const path = gui.GetWindowText(hwndEdit);
264
+ const cap = GetWindowTextLength(hwndEdit) + 1;
265
+ const buf = WCHAR.alloc(cap);
266
+ GetWindowText(hwndEdit, buf, cap);
267
+ const path = WCHAR.decode(buf);
267
268
  if (path && currentPage > 0)
268
269
  showPdf(mupdf, path, currentPage - 1);
269
270
  }
270
271
  else if (hCtrl === hwndBtnNext) {
271
- const path = gui.GetWindowText(hwndEdit);
272
+ const cap = GetWindowTextLength(hwndEdit) + 1;
273
+ const buf = WCHAR.alloc(cap);
274
+ GetWindowText(hwndEdit, buf, cap);
275
+ const path = WCHAR.decode(buf);
272
276
  if (path && currentPage < totalPages - 1)
273
277
  showPdf(mupdf, path, currentPage + 1);
274
278
  }
@@ -278,7 +282,7 @@ async function main() {
278
282
  });
279
283
  hwndMain = gui.CreateWindow('PdfViewer2', 'PDF 预览 2', 13565952 /* WindowStyle.OVERLAPPEDWINDOW */ | 33554432 /* WindowStyle.CLIPCHILDREN */, 100, 100, 1100, 800, null, null);
280
284
  if (!hwndMain) {
281
- gui.MessageBox('创建主窗口失败');
285
+ MessageBox(NULL, '创建主窗口失败', 'JS Alert', 0);
282
286
  return;
283
287
  }
284
288
  // 控件直接挂在主窗口上
@@ -309,7 +313,7 @@ async function main() {
309
313
  const hdc = GetDC(hwnd);
310
314
  if (hdc) {
311
315
  const bmi = makeBitmapInfo(pm.w, pm.h);
312
- SetDIBitsToDevice(hdc, 0, 0, pm.w, pm.h, 0, 0, 0, pm.h, pm.data, bmi, 0);
316
+ SetDIBitsToDevice(hdc, 0, 0, pm.w, pm.h, 0, 0, 0, pm.h, pm.data, bmi, 0 /* ColorUse.RGB_COLORS */);
313
317
  ReleaseDC(hwnd, hdc);
314
318
  }
315
319
  return 0;
@@ -321,9 +325,10 @@ async function main() {
321
325
  if (msg === 20 /* WmMsg.ERASEBKGND */)
322
326
  return 1;
323
327
  if (msg === 15 /* WmMsg.PAINT */) {
324
- const cr = gui.GetClientRect(hwnd);
325
- if (cr) {
326
- const cw = cr.right - cr.left, ch = cr.bottom - cr.top;
328
+ const crBuf = RECT.alloc();
329
+ if (GetClientRect(hwnd, crBuf.ptr)) {
330
+ const { left, top, right, bottom } = RECT.decode(crBuf);
331
+ const cw = right - left, ch = bottom - top;
327
332
  const hdc = GetDC(hwnd);
328
333
  if (hdc) {
329
334
  PatBlt(hdc, 0, 0, cw, ch, WHITENESS);
@@ -335,8 +340,10 @@ async function main() {
335
340
  }
336
341
  if (msg === 277 /* WmMsg.VSCROLL */ || msg === 276 /* WmMsg.HSCROLL */) {
337
342
  const bar = msg === 277 /* WmMsg.VSCROLL */ ? 1 /* ScrollBar.VERT */ : 0 /* ScrollBar.HORZ */;
338
- const info = gui.GetScrollInfo(hwnd, bar);
339
- const maxPos = info.max - info.page + 1;
343
+ const si = SCROLLINFO.encode({ cbSize: SCROLLINFO.size, fMask: 23 /* ScrollInfoFlag.ALL */ });
344
+ GetScrollInfo(hwnd, bar, si.ptr);
345
+ const info = SCROLLINFO.decode(si);
346
+ const maxPos = info.nMax - info.nPage + 1;
340
347
  const code = wParam & 0xFFFF;
341
348
  let newPos = bar === 1 /* ScrollBar.VERT */ ? scrollY : scrollX;
342
349
  if (code === 5 /* ScrollCmd.THUMBTRACK */ || code === 4 /* ScrollCmd.THUMBPOSITION */)
@@ -346,9 +353,9 @@ async function main() {
346
353
  else if (code === 1 /* ScrollCmd.LINEDOWN */)
347
354
  newPos += 20;
348
355
  else if (code === 2 /* ScrollCmd.PAGEUP */)
349
- newPos -= info.page;
356
+ newPos -= info.nPage;
350
357
  else if (code === 3 /* ScrollCmd.PAGEDOWN */)
351
- newPos += info.page;
358
+ newPos += info.nPage;
352
359
  else
353
360
  return 0;
354
361
  newPos = Math.max(0, Math.min(maxPos, newPos));
@@ -363,8 +370,10 @@ async function main() {
363
370
  const wheel = raw >= 0x8000 ? raw - 0x10000 : raw;
364
371
  const isHorz = (wParam & 4 /* MouseKeyFlag.MK_SHIFT */) !== 0;
365
372
  const bar = isHorz ? 0 /* ScrollBar.HORZ */ : 1 /* ScrollBar.VERT */;
366
- const info = gui.GetScrollInfo(hwnd, bar);
367
- const maxPos = info.max - info.page + 1;
373
+ const si = SCROLLINFO.encode({ cbSize: SCROLLINFO.size, fMask: 23 /* ScrollInfoFlag.ALL */ });
374
+ GetScrollInfo(hwnd, bar, si.ptr);
375
+ const info = SCROLLINFO.decode(si);
376
+ const maxPos = info.nMax - info.nPage + 1;
368
377
  let newPos = (isHorz ? scrollX : scrollY) - Math.round(wheel * 40 / 120);
369
378
  newPos = Math.max(0, Math.min(maxPos, newPos));
370
379
  if (isHorz)
@@ -379,11 +388,11 @@ async function main() {
379
388
  }
380
389
  return gui.DefWindowProc(hwnd, msg, wParam, lParam);
381
390
  });
382
- gui.ShowWindow(hwndMain);
383
- const test = std.open('example.pdf', 'rb');
391
+ ShowWindow(hwndMain, 1 /* ShowWindowCmd.SHOWNORMAL */);
392
+ const test = std.open('test/example.pdf', 'rb');
384
393
  if (test) {
385
394
  test.close();
386
- showPdf(mupdf, 'example.pdf', 0);
395
+ showPdf(mupdf, 'test/example.pdf', 0);
387
396
  }
388
397
  }
389
398
  main();
@@ -1,17 +1,18 @@
1
- import { PtrArrayBuffer } from '../lib/ffi/ctype.js'
1
+ import { PtrArrayBuffer, NULL } from '../lib/ffi/ctype.js'
2
2
  import '../lib/polyfill.js'
3
3
  import * as std from 'std'
4
4
  import * as gui from 'gui'
5
- import type { Document, Page, Pixmap } from '../vendor/mupdf-wasm/mupdf.js'
5
+ import type { Document, Page, Pixmap } from '@quickwinlabs/mupdf-wasm'
6
+ import { MUPDF_JS_URL, preloadMupdfWasm } from '../test/mupdf-cdn.js'
6
7
  import { assertNonNullable } from '../lib/assert.js'
7
8
  import { WCHAR } from '../lib/ffi/bind.js'
8
- import { BITMAPINFOHEADER, OPENFILENAMEW } from '../lib/windows/structs.js'
9
+ import { BITMAPINFOHEADER, OPENFILENAMEW, RECT, SCROLLINFO } from '../lib/windows/structs.js'
9
10
  import { GetOpenFileName } from '../lib/windows/comdlg32.js'
10
- import { GetDC, ReleaseDC } from '../lib/windows/user32.js'
11
+ import { GetClientRect, GetDC, GetScrollInfo, GetWindowLongPtr, GetWindowText, GetWindowTextLength, InvalidateRect, MessageBox, PostQuitMessage, ReleaseDC, SetScrollInfo, SetWindowPos, SetWindowLongPtr, SetWindowText, ShowScrollBar, ShowWindow } from '../lib/windows/user32.js'
11
12
  import { PatBlt, SetDIBitsToDevice } from '../lib/windows/gdi32.js'
12
- import { Gwlp, MouseKeyFlag, ScrollBar, ScrollCmd, SetWindowPosFlag, SetWindowPosHwnd, WindowStyle, WmMsg } from '../constants'
13
+ import { ColorUse, Gwlp, MouseKeyFlag, ScrollBar, ScrollCmd, ScrollInfoFlag, SetWindowPosFlag, SetWindowPosHwnd, ShowWindowCmd, WindowStyle, WmMsg } from '../constants'
13
14
 
14
- type MuPdf = typeof import('../vendor/mupdf-wasm/mupdf.js')
15
+ type MuPdf = typeof import('@quickwinlabs/mupdf-wasm')
15
16
 
16
17
  const WHITENESS = 0x00FF0062
17
18
 
@@ -41,14 +42,13 @@ function clearCachedDoc(): void {
41
42
  }
42
43
 
43
44
  async function loadMupdf(): Promise<MuPdf | null> {
44
- const wasmPath = './vendor/mupdf-wasm/mupdf-wasm.wasm'
45
- const fp = std.open(wasmPath, 'rb')
46
- if (!fp) { std.printf('Error: cannot open %s\n', wasmPath); return null }
47
- fp.seek(0, 2); const size = fp.tell(); fp.seek(0, 0)
48
- const buf = new ArrayBuffer(size); fp.read(buf, 0, size); fp.close()
49
- ;(globalThis).$libmupdf_wasm_Module = { wasmBinary: buf, locateFile: (p: string) => p }
50
- try { return await import('../vendor/mupdf-wasm/mupdf.js') }
51
- catch (e) { std.printf('Error: mupdf load failed: %s\n', String(e)); return null }
45
+ try {
46
+ await preloadMupdfWasm()
47
+ return await import(MUPDF_JS_URL)
48
+ } catch (e) {
49
+ std.printf('Error: mupdf load failed: %s\n', String(e))
50
+ return null
51
+ }
52
52
  }
53
53
 
54
54
  function renderPdfPage(mupdf: MuPdf, filePath: string, pageIndex: number): PixmapInfo & { totalPages: number } | null {
@@ -113,73 +113,81 @@ function openPdfFileDialog(): string | null {
113
113
  function updateScrollRange(): void {
114
114
  assertNonNullable(hwndCanvas); assertNonNullable(hwndContent)
115
115
  if (!currentPixmap) return
116
- const cr = gui.GetClientRect(hwndCanvas)
117
- if (!cr) return
118
- const cw = cr.right - cr.left, ch = cr.bottom - cr.top
116
+ const crBuf = RECT.alloc()
117
+ if (!GetClientRect(hwndCanvas, crBuf.ptr)) return
118
+ const { left, top, right, bottom } = RECT.decode(crBuf)
119
+ const cw = right - left, ch = bottom - top
119
120
  const maxX = Math.max(0, currentPixmap.w - cw)
120
121
  const maxY = Math.max(0, currentPixmap.h - ch)
121
122
  scrollX = Math.min(scrollX, maxX)
122
123
  scrollY = Math.min(scrollY, maxY)
123
124
  if (currentPixmap.w > cw) {
124
- const style = gui.GetWindowLongPtr(hwndCanvas, Gwlp.STYLE) | 0
125
+ const style = GetWindowLongPtr(hwndCanvas, Gwlp.STYLE)
125
126
  if (!(style & WindowStyle.HSCROLL)) {
126
- gui.SetWindowLongPtr(hwndCanvas, Gwlp.STYLE, style | WindowStyle.HSCROLL)
127
- gui.SetWindowPos(hwndCanvas, SetWindowPosHwnd.TOP, 0, 0, 0, 0,
127
+ SetWindowLongPtr(hwndCanvas, Gwlp.STYLE, style | WindowStyle.HSCROLL)
128
+ SetWindowPos(hwndCanvas, SetWindowPosHwnd.TOP, 0, 0, 0, 0,
128
129
  SetWindowPosFlag.SWP_NOMOVE | SetWindowPosFlag.SWP_NOSIZE |
129
130
  SetWindowPosFlag.SWP_NOZORDER | SetWindowPosFlag.SWP_FRAMECHANGED)
130
131
  }
131
- gui.SetScrollInfo(hwndCanvas, ScrollBar.HORZ, { min: 0, max: currentPixmap.w - 1, page: cw, pos: scrollX }, true)
132
- gui.ShowScrollBar(hwndCanvas, ScrollBar.HORZ, true)
132
+ SetScrollInfo(hwndCanvas, ScrollBar.HORZ, {
133
+ cbSize: SCROLLINFO.size, fMask: ScrollInfoFlag.RANGE | ScrollInfoFlag.PAGE | ScrollInfoFlag.POS,
134
+ nMin: 0, nMax: currentPixmap.w - 1, nPage: cw, nPos: scrollX,
135
+ }, 1)
136
+ ShowScrollBar(hwndCanvas, ScrollBar.HORZ, 1)
133
137
  } else {
134
138
  scrollX = 0
135
- const style = gui.GetWindowLongPtr(hwndCanvas, Gwlp.STYLE) | 0
139
+ const style = GetWindowLongPtr(hwndCanvas, Gwlp.STYLE)
136
140
  if (style & WindowStyle.HSCROLL) {
137
- gui.SetWindowLongPtr(hwndCanvas, Gwlp.STYLE, style & ~WindowStyle.HSCROLL)
138
- gui.SetWindowPos(hwndCanvas, SetWindowPosHwnd.TOP, 0, 0, 0, 0,
141
+ SetWindowLongPtr(hwndCanvas, Gwlp.STYLE, style & ~WindowStyle.HSCROLL)
142
+ SetWindowPos(hwndCanvas, SetWindowPosHwnd.TOP, 0, 0, 0, 0,
139
143
  SetWindowPosFlag.SWP_NOMOVE | SetWindowPosFlag.SWP_NOSIZE |
140
144
  SetWindowPosFlag.SWP_NOZORDER | SetWindowPosFlag.SWP_FRAMECHANGED)
141
145
  }
142
- gui.ShowScrollBar(hwndCanvas, ScrollBar.HORZ, false)
146
+ ShowScrollBar(hwndCanvas, ScrollBar.HORZ, 0)
143
147
  }
144
148
  if (currentPixmap.h > ch) {
145
- gui.SetScrollInfo(hwndCanvas, ScrollBar.VERT, { min: 0, max: currentPixmap.h - 1, page: ch, pos: scrollY }, true)
146
- gui.ShowScrollBar(hwndCanvas, ScrollBar.VERT, true)
147
- } else { scrollY = 0; gui.ShowScrollBar(hwndCanvas, ScrollBar.VERT, false) }
148
- gui.SetWindowPos(hwndContent, SetWindowPosHwnd.TOP, -scrollX, -scrollY, 0, 0,
149
+ SetScrollInfo(hwndCanvas, ScrollBar.VERT, {
150
+ cbSize: SCROLLINFO.size, fMask: ScrollInfoFlag.RANGE | ScrollInfoFlag.PAGE | ScrollInfoFlag.POS,
151
+ nMin: 0, nMax: currentPixmap.h - 1, nPage: ch, nPos: scrollY,
152
+ }, 1)
153
+ ShowScrollBar(hwndCanvas, ScrollBar.VERT, 1)
154
+ } else { scrollY = 0; ShowScrollBar(hwndCanvas, ScrollBar.VERT, 0) }
155
+ SetWindowPos(hwndContent, SetWindowPosHwnd.TOP, -scrollX, -scrollY, 0, 0,
149
156
  SetWindowPosFlag.SWP_NOSIZE | SetWindowPosFlag.SWP_NOZORDER)
150
157
  }
151
158
 
152
159
  function showPdf(mupdf: MuPdf, path: string, pageIdx: number): void {
153
160
  assertNonNullable(hwndMain); assertNonNullable(hwndContent)
154
161
  const pix = renderPdfPage(mupdf, path, pageIdx)
155
- if (!pix) { gui.MessageBox('渲染 PDF 失败'); return }
162
+ if (!pix) { MessageBox(NULL, '渲染 PDF 失败', 'JS Alert', 0); return }
156
163
  currentPixmap = pix; currentPage = pageIdx; totalPages = pix.totalPages
157
- gui.SetWindowText(hwndMain, 'PDF 预览 - 第 ' + (pageIdx + 1) + '/' + totalPages + ' 页')
164
+ SetWindowText(hwndMain, 'PDF 预览 - 第 ' + (pageIdx + 1) + '/' + totalPages + ' 页')
158
165
  scrollX = 0; scrollY = 0
159
- gui.SetWindowPos(hwndContent, SetWindowPosHwnd.TOP, 0, 0, pix.w, pix.h,
166
+ SetWindowPos(hwndContent, SetWindowPosHwnd.TOP, 0, 0, pix.w, pix.h,
160
167
  SetWindowPosFlag.SWP_NOZORDER | SetWindowPosFlag.SWP_NOMOVE)
161
168
  updateScrollRange()
162
- gui.InvalidateRect(hwndContent, null, true)
169
+ InvalidateRect(hwndContent, NULL, 1)
163
170
  }
164
171
 
165
172
  function doScroll(dx: number, dy: number): void {
166
173
  assertNonNullable(hwndCanvas); assertNonNullable(hwndContent)
167
- const cr = gui.GetClientRect(hwndCanvas)
168
- if (!cr || !currentPixmap) return
169
- const cw = cr.right - cr.left, ch = cr.bottom - cr.top
174
+ const crBuf = RECT.alloc()
175
+ if (!GetClientRect(hwndCanvas, crBuf.ptr) || !currentPixmap) return
176
+ const { left, top, right, bottom } = RECT.decode(crBuf)
177
+ const cw = right - left, ch = bottom - top
170
178
  const maxX = Math.max(0, currentPixmap.w - cw)
171
179
  const maxY = Math.max(0, currentPixmap.h - ch)
172
180
  scrollX = Math.max(0, Math.min(maxX, scrollX + dx))
173
181
  scrollY = Math.max(0, Math.min(maxY, scrollY + dy))
174
- gui.SetWindowPos(hwndContent, SetWindowPosHwnd.TOP, -scrollX, -scrollY, 0, 0,
182
+ SetWindowPos(hwndContent, SetWindowPosHwnd.TOP, -scrollX, -scrollY, 0, 0,
175
183
  SetWindowPosFlag.SWP_NOSIZE | SetWindowPosFlag.SWP_NOZORDER)
176
- gui.SetScrollInfo(hwndCanvas, ScrollBar.HORZ, { pos: scrollX }, true)
177
- gui.SetScrollInfo(hwndCanvas, ScrollBar.VERT, { pos: scrollY }, true)
184
+ SetScrollInfo(hwndCanvas, ScrollBar.HORZ, { cbSize: SCROLLINFO.size, fMask: ScrollInfoFlag.POS, nPos: scrollX }, 1)
185
+ SetScrollInfo(hwndCanvas, ScrollBar.VERT, { cbSize: SCROLLINFO.size, fMask: ScrollInfoFlag.POS, nPos: scrollY }, 1)
178
186
  }
179
187
 
180
188
  async function main(): Promise<void> {
181
189
  const mupdf = await loadMupdf()
182
- if (!mupdf) { gui.MessageBox('加载 mupdf WASM 失败'); return }
190
+ if (!mupdf) { MessageBox(NULL, '加载 mupdf WASM 失败', 'JS Alert', 0); return }
183
191
 
184
192
  const WS_CHILD = WindowStyle.CHILD
185
193
  const WS_VIS = WindowStyle.VISIBLE
@@ -192,13 +200,14 @@ let hwndBtnNext: gui.HWND | null = null
192
200
 
193
201
  gui.RegisterClass('PdfViewer2', (hwnd, msg, wParam, lParam) => {
194
202
  assertNonNullable(hwndCanvas); assertNonNullable(hwndEdit); assertNonNullable(hwndBtnOpen); assertNonNullable(hwndBtnPrev); assertNonNullable(hwndBtnNext)
195
- if (msg === WmMsg.DESTROY) { gui.PostQuitMessage(0); return 0 }
203
+ if (msg === WmMsg.DESTROY) { PostQuitMessage(0); return 0 }
196
204
  if (msg === WmMsg.SIZE) {
197
- const cr = gui.GetClientRect(hwnd)
198
- if (cr) {
199
- const cw = cr.right - cr.left, ch = cr.bottom - cr.top
200
- gui.SetWindowPos(hwndCanvas, SetWindowPosHwnd.TOP, 0, 50, cw, Math.max(1, ch - 50), SetWindowPosFlag.SWP_NOZORDER)
201
- gui.SetWindowPos(hwndEdit, SetWindowPosHwnd.TOP, 0, 0, Math.max(100, cw - 320), 0,
205
+ const crBuf = RECT.alloc()
206
+ if (GetClientRect(hwnd, crBuf.ptr)) {
207
+ const { left, top, right, bottom } = RECT.decode(crBuf)
208
+ const cw = right - left, ch = bottom - top
209
+ SetWindowPos(hwndCanvas, SetWindowPosHwnd.TOP, 0, 50, cw, Math.max(1, ch - 50), SetWindowPosFlag.SWP_NOZORDER)
210
+ SetWindowPos(hwndEdit, SetWindowPosHwnd.TOP, 0, 0, Math.max(100, cw - 320), 0,
202
211
  SetWindowPosFlag.SWP_NOMOVE | SetWindowPosFlag.SWP_NOZORDER)
203
212
  }
204
213
  return gui.DefWindowProc(hwnd, msg, wParam, lParam)
@@ -207,12 +216,18 @@ let hwndBtnNext: gui.HWND | null = null
207
216
  const hCtrl = lParam
208
217
  if (hCtrl === hwndBtnOpen) {
209
218
  const path = openPdfFileDialog()
210
- if (path) { gui.SetWindowText(hwndEdit, path); showPdf(mupdf, path, 0) }
219
+ if (path) { SetWindowText(hwndEdit, path); showPdf(mupdf, path, 0) }
211
220
  } else if (hCtrl === hwndBtnPrev) {
212
- const path = gui.GetWindowText(hwndEdit)
221
+ const cap = GetWindowTextLength(hwndEdit) + 1
222
+ const buf = WCHAR.alloc(cap)
223
+ GetWindowText(hwndEdit, buf, cap)
224
+ const path = WCHAR.decode(buf)
213
225
  if (path && currentPage > 0) showPdf(mupdf, path, currentPage - 1)
214
226
  } else if (hCtrl === hwndBtnNext) {
215
- const path = gui.GetWindowText(hwndEdit)
227
+ const cap = GetWindowTextLength(hwndEdit) + 1
228
+ const buf = WCHAR.alloc(cap)
229
+ GetWindowText(hwndEdit, buf, cap)
230
+ const path = WCHAR.decode(buf)
216
231
  if (path && currentPage < totalPages - 1) showPdf(mupdf, path, currentPage + 1)
217
232
  }
218
233
  return 0
@@ -222,7 +237,7 @@ let hwndBtnNext: gui.HWND | null = null
222
237
  hwndMain = gui.CreateWindow('PdfViewer2', 'PDF 预览 2',
223
238
  WindowStyle.OVERLAPPEDWINDOW | WindowStyle.CLIPCHILDREN,
224
239
  100, 100, 1100, 800, null, null)!
225
- if (!hwndMain) { gui.MessageBox('创建主窗口失败'); return }
240
+ if (!hwndMain) { MessageBox(NULL, '创建主窗口失败', 'JS Alert', 0); return }
226
241
 
227
242
  // 控件直接挂在主窗口上
228
243
  hwndEdit = gui.CreateWindow('EDIT', '',
@@ -265,7 +280,7 @@ let hwndBtnNext: gui.HWND | null = null
265
280
  const hdc = GetDC(hwnd)
266
281
  if (hdc) {
267
282
  const bmi = makeBitmapInfo(pm.w, pm.h)
268
- SetDIBitsToDevice(hdc, 0, 0, pm.w, pm.h, 0, 0, 0, pm.h, pm.data, bmi, 0)
283
+ SetDIBitsToDevice(hdc, 0, 0, pm.w, pm.h, 0, 0, 0, pm.h, pm.data, bmi, ColorUse.RGB_COLORS)
269
284
  ReleaseDC(hwnd, hdc)
270
285
  }
271
286
  return 0
@@ -277,9 +292,10 @@ let hwndBtnNext: gui.HWND | null = null
277
292
  gui.SetWindowProc(hwndCanvas, (hwnd: gui.HWND, msg: number, wParam: number, lParam: number): number => {
278
293
  if (msg === WmMsg.ERASEBKGND) return 1
279
294
  if (msg === WmMsg.PAINT) {
280
- const cr = gui.GetClientRect(hwnd)
281
- if (cr) {
282
- const cw = cr.right - cr.left, ch = cr.bottom - cr.top
295
+ const crBuf = RECT.alloc()
296
+ if (GetClientRect(hwnd, crBuf.ptr)) {
297
+ const { left, top, right, bottom } = RECT.decode(crBuf)
298
+ const cw = right - left, ch = bottom - top
283
299
  const hdc = GetDC(hwnd)
284
300
  if (hdc) {
285
301
  PatBlt(hdc, 0, 0, cw, ch, WHITENESS)
@@ -291,16 +307,18 @@ let hwndBtnNext: gui.HWND | null = null
291
307
  }
292
308
  if (msg === WmMsg.VSCROLL || msg === WmMsg.HSCROLL) {
293
309
  const bar = msg === WmMsg.VSCROLL ? ScrollBar.VERT : ScrollBar.HORZ
294
- const info = gui.GetScrollInfo(hwnd, bar)
295
- const maxPos = info.max - info.page + 1
310
+ const si = SCROLLINFO.encode({ cbSize: SCROLLINFO.size, fMask: ScrollInfoFlag.ALL })
311
+ GetScrollInfo(hwnd, bar, si.ptr)
312
+ const info = SCROLLINFO.decode(si)
313
+ const maxPos = info.nMax - info.nPage + 1
296
314
  const code = wParam & 0xFFFF
297
315
  let newPos = bar === ScrollBar.VERT ? scrollY : scrollX
298
316
  if (code === ScrollCmd.THUMBTRACK || code === ScrollCmd.THUMBPOSITION)
299
317
  newPos = Math.max(0, Math.min(maxPos, (wParam >> 16) & 0xFFFF))
300
318
  else if (code === ScrollCmd.LINEUP) newPos -= 20
301
319
  else if (code === ScrollCmd.LINEDOWN) newPos += 20
302
- else if (code === ScrollCmd.PAGEUP) newPos -= info.page
303
- else if (code === ScrollCmd.PAGEDOWN) newPos += info.page
320
+ else if (code === ScrollCmd.PAGEUP) newPos -= info.nPage
321
+ else if (code === ScrollCmd.PAGEDOWN) newPos += info.nPage
304
322
  else return 0
305
323
  newPos = Math.max(0, Math.min(maxPos, newPos))
306
324
  if (bar === ScrollBar.VERT) doScroll(0, newPos - scrollY)
@@ -312,8 +330,10 @@ let hwndBtnNext: gui.HWND | null = null
312
330
  const wheel = raw >= 0x8000 ? raw - 0x10000 : raw
313
331
  const isHorz = (wParam & MouseKeyFlag.MK_SHIFT) !== 0
314
332
  const bar = isHorz ? ScrollBar.HORZ : ScrollBar.VERT
315
- const info = gui.GetScrollInfo(hwnd, bar)
316
- const maxPos = info.max - info.page + 1
333
+ const si = SCROLLINFO.encode({ cbSize: SCROLLINFO.size, fMask: ScrollInfoFlag.ALL })
334
+ GetScrollInfo(hwnd, bar, si.ptr)
335
+ const info = SCROLLINFO.decode(si)
336
+ const maxPos = info.nMax - info.nPage + 1
317
337
  let newPos = (isHorz ? scrollX : scrollY) - Math.round(wheel * 40 / 120)
318
338
  newPos = Math.max(0, Math.min(maxPos, newPos))
319
339
  if (isHorz) doScroll(newPos - scrollX, 0)
@@ -324,10 +344,10 @@ let hwndBtnNext: gui.HWND | null = null
324
344
  return gui.DefWindowProc(hwnd, msg, wParam, lParam)
325
345
  })
326
346
 
327
- gui.ShowWindow(hwndMain)
347
+ ShowWindow(hwndMain, ShowWindowCmd.SHOWNORMAL)
328
348
 
329
- const test = std.open('example.pdf', 'rb')
330
- if (test) { test.close(); showPdf(mupdf, 'example.pdf', 0) }
349
+ const test = std.open('test/example.pdf', 'rb')
350
+ if (test) { test.close(); showPdf(mupdf, 'test/example.pdf', 0) }
331
351
  }
332
352
 
333
353
  main()