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
package/lib/ffi/bind.ts 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 { type C_BasicType, C_BasicType_No_Void, C_BasicType_Token, C_BasicType_Token_No_Void, cTokenToType, isCPtrToken, isCValToken, valName, ArgJsTypeOfToken, RetJsTypeOfToken, normToken, PTR_SIZE, ptrName, type Ptr, readScalar, writeSlot, PtrArrayBuffer } from './ctype.js'
7
6
 
@@ -47,12 +46,12 @@ function valCodec(name: string, encoders: CodecMap): StructValCodec | undefined
47
46
  return encoders[name] as unknown as StructValCodec | undefined
48
47
  }
49
48
 
50
- const _dllCache: Map<string, win.HMODULE> = new Map()
49
+ const _dllCache: Map<string, ffi.HMODULE> = new Map()
51
50
 
52
- function loadDll(dll: string): win.HMODULE {
51
+ function loadDll(dll: string): ffi.HMODULE {
53
52
  const cached = _dllCache.get(dll)
54
53
  if (cached !== undefined) return cached
55
- const loaded = win.LoadLibrary(dll)
54
+ const loaded = ffi.LoadLibrary(dll)
56
55
  if (!loaded) throw new Error(`ffi-bind: LoadLibrary("${dll}") failed`)
57
56
  _dllCache.set(dll, loaded)
58
57
  return loaded
@@ -105,7 +104,9 @@ function parseSig(sig: string): ParsedSig {
105
104
  }
106
105
  }
107
106
 
108
- function makeFn(proc: number, sig: string, encoders: CodecMap, decoders: CodecMap): (...a: unknown[]) => unknown {
107
+ /** proc 是 GetProcAddress 拿到的函数地址(<FARPROC>ptr):调用方已校验非空,故收窄后的
108
+ * Ptr 而非 MaybePtr;品牌只在绑定层内部走,落到 ffiCall 的 uintptr 槽(number)时脱落。 */
109
+ function makeFn(proc: Ptr<'FARPROC'>, sig: string, encoders: CodecMap, decoders: CodecMap): (...a: unknown[]) => unknown {
109
110
  const ps = parseSig(sig)
110
111
  // 按值位的能力校验前移到绑定期(模块加载即炸,不留到首个调用):布局缺位 / 非结构
111
112
  // 布局(无 size)/ 退化 size 都是签名层面的错误,报错指向具体位与可用布局清单。
@@ -134,7 +135,7 @@ const IA32_ARG_SIZE: Record<C_BasicType_No_Void, number> = {
134
135
  // x64 桩无条件双读 slots[0..3],故 argFrame 至少 4 个槽(32 字节)
135
136
  const X64_MIN_SLOTS = 4
136
137
 
137
- function callPacked(proc: number, { argTokens, retToken, sig }: ParsedSig, args: any[], encoders: CodecMap, decoders: CodecMap): unknown {
138
+ function callPacked(proc: Ptr<'FARPROC'>, { argTokens, retToken, sig }: ParsedSig, args: any[], encoders: CodecMap, decoders: CodecMap): unknown {
138
139
  const is64 = os.arch === 'x64'
139
140
 
140
141
  const getWidth = (t: C_BasicType_Token_No_Void, is64: boolean): number => {
@@ -381,7 +382,7 @@ export function bind<const S extends string,
381
382
  const LE extends CodecMap = {},
382
383
  const LD extends CodecMap = LE>(
383
384
  dll: string, name: string, sig: S, encoders?: LE, decoders?: LD) {
384
- const proc = win.GetProcAddress(loadDll(dll), name)
385
+ const proc = ffi.GetProcAddress(loadDll(dll), name)
385
386
  if (!proc) throw new Error(`ffi-bind: proc "${name}" not found in ${dll}`)
386
387
  const effDec = decoders ?? encoders
387
388
  return makeFn(proc, sig,
@@ -401,7 +402,7 @@ export function bindLib<const M extends Record<string, string>,
401
402
  const encTable = { ...builtinCodecs, ...encoders }
402
403
  const decTable = { ...builtinCodecs, ...(effDec ?? {}) }
403
404
  for (const [name, sig] of Object.entries(map)) {
404
- const proc = win.GetProcAddress(h, name)
405
+ const proc = ffi.GetProcAddress(h, name)
405
406
  if (!proc) throw new Error(`ffi-bind: proc "${name}" not found in ${dll}`)
406
407
  out[name] = makeFn(proc, sig, encTable, decTable)
407
408
  }
@@ -1,9 +1,9 @@
1
1
  import { jsx as _jsx } from "react/jsx-runtime";
2
2
  import { forwardRef, useRef, useEffect, useState } from 'react';
3
3
  import * as gui from 'gui';
4
- import { InvalidateRect } from '../../windows/user32.js';
4
+ import { GetClientRect, InvalidateRect } from '../../windows/user32.js';
5
5
  import { NULL } from '../../ffi/ctype.js';
6
- import { SYSTEMTIME, NMDATETIMECHANGE } from '../../windows/structs.js';
6
+ import { RECT, SYSTEMTIME, NMDATETIMECHANGE } from '../../windows/structs.js';
7
7
  import { nmCode } from '../nmhdr.js';
8
8
  function dateToSysTimeBuf(d) {
9
9
  // wDayOfWeek 设置时被忽略,缺省跳过 = 0
@@ -52,11 +52,10 @@ const DateTimePicker = forwardRef(function DateTimePicker({ value, onChange, def
52
52
  return;
53
53
  InvalidateRect(h, NULL, 1);
54
54
  // 发送 WM_SIZE 让控件(尤其是 DTS_UPDOWN)重新布局内部子窗口
55
- const cr = gui.GetClientRect(h);
56
- if (cr) {
57
- const w = cr.right - cr.left;
58
- const hh = cr.bottom - cr.top;
59
- gui.SendMessage(h, 5 /* WmMsg.SIZE */, 0, (hh << 16) | w);
55
+ const cr = RECT.alloc();
56
+ if (GetClientRect(h, cr.ptr)) {
57
+ const { left, top, right, bottom } = RECT.decode(cr);
58
+ gui.SendMessage(h, 5 /* WmMsg.SIZE */, 0, ((bottom - top) << 16) | (right - left));
60
59
  }
61
60
  }, []);
62
61
  return (_jsx("w", { type: "STATIC", ws: 268435456 /* WindowStyle.VISIBLE */ | 33554432 /* WindowStyle.CLIPCHILDREN */, style: { ...style, flexDirection: 'column', alignItems: 'stretch' }, ref: ref, onEvent: (e) => {
@@ -2,6 +2,7 @@ import { jsx as _jsx } from "react/jsx-runtime";
2
2
  import { forwardRef, useState, useRef, useEffect } from 'react';
3
3
  import * as gui from 'gui';
4
4
  import { WCHAR } from '../../ffi/bind.js';
5
+ import { GetWindowText, GetWindowTextLength } from '../../windows/user32.js';
5
6
  export const Input = forwardRef(({ value: controlledValue, defaultValue = '', onChange, placeholder, password, multiline, readonly, number, disabled, style }, ref) => {
6
7
  const [internalValue, setInternalValue] = useState(defaultValue);
7
8
  const isControlled = controlledValue !== undefined;
@@ -34,7 +35,10 @@ export const Input = forwardRef(({ value: controlledValue, defaultValue = '', on
34
35
  const h = inputRef.current;
35
36
  if (!h)
36
37
  return;
37
- const newText = gui.GetWindowText(h);
38
+ const cap = GetWindowTextLength(h) + 1;
39
+ const buf = WCHAR.alloc(cap);
40
+ GetWindowText(h, buf, cap);
41
+ const newText = WCHAR.decode(buf);
38
42
  if (!isControlled)
39
43
  setInternalValue(newText);
40
44
  onChange?.(newText);
@@ -7,6 +7,8 @@ import { WCHAR } from '../../ffi/bind.js';
7
7
  import { nmCode } from '../nmhdr.js';
8
8
  import { LoadCursor, SetCursor, ScreenToClient, GetCursorPos } from '../../windows/user32.js';
9
9
  import { CreateFontIndirect, DeleteObject, GetObject, SelectObject } from '../../windows/gdi32.js';
10
+ import { createBitmapFromPixels } from '../../bitmap.js';
11
+ import { ImageListCreate, ImageListAdd, ImageListDestroy } from '../../windows/comctl32.js';
10
12
  import { LOGFONTW, POINT, NMCUSTOMDRAW, NMLVCUSTOMDRAW, NMLISTVIEW, LVHITTESTINFO, LVITEMW, LVCOLUMNW, } from '../../windows/structs.js';
11
13
  export function makeColorBlock(size, bgra) {
12
14
  const n = size * size;
@@ -134,27 +136,27 @@ function makeLVItem(i, sub, text, image) {
134
136
  }
135
137
  const ListView = forwardRef(function ListViewInner({ columns, data, style, icons, iconSize, getIcon }, ref) {
136
138
  const lvRef = useRef(null);
137
- const iconListRef = useRef(0);
139
+ const iconListRef = useRef(NULL);
138
140
  useEffect(() => {
139
141
  const h = lvRef.current;
140
142
  if (!h)
141
143
  return;
142
144
  const il = iconListRef.current;
143
- iconListRef.current = 0;
145
+ iconListRef.current = NULL;
144
146
  if (il) {
145
147
  gui.SendMessage(h, 4099 /* LvMsg.SETIMAGELIST */, 1 /* LvImageList.SMALL */, 0);
146
- gui.ImageListDestroy(il);
148
+ ImageListDestroy(il);
147
149
  }
148
150
  if (!icons || icons.length === 0)
149
151
  return;
150
152
  const size = iconSize ?? 32;
151
- const img = gui.ImageListCreate(size, size, 32 /* ImageListFlag.COLOR32 */, icons.length, 1);
153
+ const img = ImageListCreate(size, size, 32 /* ImageListFlag.COLOR32 */, icons.length, 1);
152
154
  if (!img)
153
155
  return;
154
156
  for (const p of icons) {
155
- const hbm = gui.CreateBitmapFromPixels(size, size, p);
157
+ const hbm = createBitmapFromPixels(size, size, p);
156
158
  if (hbm) {
157
- gui.ImageListAdd(img, hbm);
159
+ ImageListAdd(img, hbm, NULL);
158
160
  DeleteObject(hbm);
159
161
  }
160
162
  }
@@ -1,10 +1,9 @@
1
1
  import { jsx as _jsx } from "react/jsx-runtime";
2
2
  import { forwardRef, useLayoutEffect, useRef } from 'react';
3
- import * as gui from 'gui';
4
- import { DefWindowProc, SetWindowPos, ShowScrollBar, GetDC, ReleaseDC } from '../../windows/user32.js';
5
- import { NULL } from '../../ffi/ctype.js';
6
- import { GetDeviceCaps } from '../../windows/gdi32.js';
3
+ import { DefWindowProc, GetClientRect, GetScrollInfo, SetScrollInfo, SetWindowPos, ShowScrollBar } from '../../windows/user32.js';
4
+ import { RECT, SCROLLINFO } from '../../windows/structs.js';
7
5
  import { forceFlexLayout } from '../reconciler.js';
6
+ import { getScaleFactor } from '../../dpi.js';
8
7
  export const ScrollView = forwardRef(({ children, style, contentWidth, contentHeight }, ref) => {
9
8
  const svRef = useRef(null);
10
9
  const contentRef = useRef(null);
@@ -16,16 +15,13 @@ export const ScrollView = forwardRef(({ children, style, contentWidth, contentHe
16
15
  // page = viewportSize(可见行数)
17
16
  // nPos = 0 … max - page + 1(即 0 … contentSize - viewportSize)
18
17
  function updateScroll(sv, content) {
19
- const svRect = gui.GetClientRect(sv);
20
- if (!svRect)
18
+ const svBuf = RECT.alloc();
19
+ if (!GetClientRect(sv, svBuf.ptr))
21
20
  return;
22
- const svW = svRect.right - svRect.left;
23
- const svH = svRect.bottom - svRect.top;
24
- // GetScaleFactor 等价内联:GetDC → GetDeviceCaps(LOGPIXELSX=88) → ReleaseDC 配对
25
- const hdc = GetDC(NULL);
26
- const scale = hdc ? GetDeviceCaps(hdc, 88) / 96 : 1;
27
- if (hdc)
28
- ReleaseDC(NULL, hdc);
21
+ const { left, top, right, bottom } = RECT.decode(svBuf);
22
+ const svW = right - left;
23
+ const svH = bottom - top;
24
+ const scale = getScaleFactor();
29
25
  const natW = Math.round((contentWidth ?? (svW / scale)) * scale);
30
26
  const natH = Math.round((contentHeight ?? (svH / scale)) * scale);
31
27
  scrollXRef.current = Math.max(0, Math.min(scrollXRef.current, natW - svW));
@@ -33,7 +29,10 @@ export const ScrollView = forwardRef(({ children, style, contentWidth, contentHe
33
29
  SetWindowPos(content, 0 /* SetWindowPosHwnd.TOP */, -scrollXRef.current, -scrollYRef.current, natW, natH, 4 /* SetWindowPosFlag.SWP_NOZORDER */);
34
30
  forceFlexLayout(content);
35
31
  if (natW > svW) {
36
- gui.SetScrollInfo(sv, 0 /* ScrollBar.HORZ */, { min: 0, max: natW - 1, page: svW, pos: scrollXRef.current }, true);
32
+ SetScrollInfo(sv, 0 /* ScrollBar.HORZ */, {
33
+ cbSize: SCROLLINFO.size, fMask: 1 /* ScrollInfoFlag.RANGE */ | 2 /* ScrollInfoFlag.PAGE */ | 4 /* ScrollInfoFlag.POS */,
34
+ nMin: 0, nMax: natW - 1, nPage: svW, nPos: scrollXRef.current,
35
+ }, 1);
37
36
  ShowScrollBar(sv, 0 /* ScrollBar.HORZ */, 1);
38
37
  }
39
38
  else {
@@ -41,7 +40,10 @@ export const ScrollView = forwardRef(({ children, style, contentWidth, contentHe
41
40
  ShowScrollBar(sv, 0 /* ScrollBar.HORZ */, 0);
42
41
  }
43
42
  if (natH > svH) {
44
- gui.SetScrollInfo(sv, 1 /* ScrollBar.VERT */, { min: 0, max: natH - 1, page: svH, pos: scrollYRef.current }, true);
43
+ SetScrollInfo(sv, 1 /* ScrollBar.VERT */, {
44
+ cbSize: SCROLLINFO.size, fMask: 1 /* ScrollInfoFlag.RANGE */ | 2 /* ScrollInfoFlag.PAGE */ | 4 /* ScrollInfoFlag.POS */,
45
+ nMin: 0, nMax: natH - 1, nPage: svH, nPos: scrollYRef.current,
46
+ }, 1);
45
47
  ShowScrollBar(sv, 1 /* ScrollBar.VERT */, 1);
46
48
  }
47
49
  else {
@@ -64,15 +66,17 @@ export const ScrollView = forwardRef(({ children, style, contentWidth, contentHe
64
66
  scrollXRef.current = newPos;
65
67
  }
66
68
  SetWindowPos(content, 0 /* SetWindowPosHwnd.TOP */, -scrollXRef.current, -scrollYRef.current, 0, 0, 1 /* SetWindowPosFlag.SWP_NOSIZE */ | 4 /* SetWindowPosFlag.SWP_NOZORDER */);
67
- gui.SetScrollInfo(sv, bar, { pos: newPos }, true);
69
+ SetScrollInfo(sv, bar, { cbSize: SCROLLINFO.size, fMask: 4 /* ScrollInfoFlag.POS */, nPos: newPos }, 1);
68
70
  }
69
71
  function handleScroll(e, bar) {
70
72
  const sv = svRef.current;
71
73
  const content = contentRef.current;
72
74
  if (!sv || !content)
73
75
  return;
74
- const info = gui.GetScrollInfo(sv, bar);
75
- const maxPos = info.max - info.page + 1;
76
+ const si = SCROLLINFO.encode({ cbSize: SCROLLINFO.size, fMask: 23 /* ScrollInfoFlag.ALL */ });
77
+ GetScrollInfo(sv, bar, si.ptr);
78
+ const info = SCROLLINFO.decode(si);
79
+ const maxPos = info.nMax - info.nPage + 1;
76
80
  const code = e.wParam & 0xFFFF;
77
81
  const ref_ = bar === 1 /* ScrollBar.VERT */ ? scrollYRef : scrollXRef;
78
82
  let newPos = ref_.current;
@@ -84,9 +88,9 @@ export const ScrollView = forwardRef(({ children, style, contentWidth, contentHe
84
88
  else if (code === 1 /* ScrollCmd.LINEDOWN */)
85
89
  newPos += 20;
86
90
  else if (code === 2 /* ScrollCmd.PAGEUP */)
87
- newPos -= info.page;
91
+ newPos -= info.nPage;
88
92
  else if (code === 3 /* ScrollCmd.PAGEDOWN */)
89
- newPos += info.page;
93
+ newPos += info.nPage;
90
94
  else
91
95
  return;
92
96
  newPos = Math.max(0, Math.min(maxPos, newPos));
@@ -106,8 +110,10 @@ export const ScrollView = forwardRef(({ children, style, contentWidth, contentHe
106
110
  if (!isHorz && contentHeight === undefined)
107
111
  return;
108
112
  const bar = isHorz ? 0 /* ScrollBar.HORZ */ : 1 /* ScrollBar.VERT */;
109
- const info = gui.GetScrollInfo(sv, bar);
110
- const maxPos = info.max - info.page + 1;
113
+ const si = SCROLLINFO.encode({ cbSize: SCROLLINFO.size, fMask: 23 /* ScrollInfoFlag.ALL */ });
114
+ GetScrollInfo(sv, bar, si.ptr);
115
+ const info = SCROLLINFO.decode(si);
116
+ const maxPos = info.nMax - info.nPage + 1;
111
117
  const ref_ = isHorz ? scrollXRef : scrollYRef;
112
118
  let newPos = ref_.current + dy;
113
119
  newPos = Math.max(0, Math.min(maxPos, newPos));
@@ -1,5 +1,5 @@
1
1
  import * as gui from 'gui';
2
- import { DefWindowProc, GetSystemMetrics } from '../windows/user32.js';
2
+ import { DefWindowProc, GetSystemMetrics, ShowWindow, UpdateWindow } from '../windows/user32.js';
3
3
  import reconciler, { scaleFactor, instancesByHwnd, forceFlexLayout } from './reconciler.js';
4
4
  const noop = () => { };
5
5
  let defaultClassRegistered = false;
@@ -34,8 +34,7 @@ export function createRoot(container) {
34
34
  const ws = (cfg.ws ?? 0) | 13565952 /* WindowStyle.OVERLAPPEDWINDOW */;
35
35
  const w = (cfg.width ?? 800) * scaleFactor;
36
36
  const h = (cfg.height ?? 600) * scaleFactor;
37
- // GetScreenSize 等价内联:SM_CXSCREEN=0 / SM_CYSCREEN=1
38
- const [sw, sh] = [GetSystemMetrics(0), GetSystemMetrics(1)];
37
+ const [sw, sh] = [GetSystemMetrics(0 /* SysMetrics.CXSCREEN */), GetSystemMetrics(1 /* SysMetrics.CYSCREEN */)];
39
38
  const x = cfg.x === undefined ? ((sw - w) / 2) | 0
40
39
  : cfg.x === -2147483648 /* CreatePos.USEDEFAULT */ ? -2147483648 /* CreatePos.USEDEFAULT */ : cfg.x * scaleFactor;
41
40
  const y = cfg.y === undefined ? ((sh - h) / 2) | 0
@@ -44,8 +43,11 @@ export function createRoot(container) {
44
43
  if (!hwin)
45
44
  throw new Error('CreateWindow failed');
46
45
  hwnd = hwin;
47
- if (!cfg.noShowWindow)
48
- gui.ShowWindow(hwnd);
46
+ // 启动首帧:ShowWindow 后立即 WM_PAINT,不留白(原 gui.ShowWindow 复合语义)
47
+ if (!cfg.noShowWindow) {
48
+ ShowWindow(hwnd, 1 /* ShowWindowCmd.SHOWNORMAL */);
49
+ UpdateWindow(hwnd);
50
+ }
49
51
  }
50
52
  else {
51
53
  hwnd = container;
@@ -1,8 +1,8 @@
1
1
  import * as gui from 'gui'
2
2
  import React from 'react'
3
- import { DefWindowProc, GetSystemMetrics } from '../windows/user32.js'
3
+ import { DefWindowProc, GetSystemMetrics, ShowWindow, UpdateWindow } from '../windows/user32.js'
4
4
  import reconciler, { scaleFactor, instancesByHwnd, forceFlexLayout, type Instance } from './reconciler.js'
5
- import { CreatePos, WindowStyle, WmMsg } from '../../constants'
5
+ import { CreatePos, ShowWindowCmd, SysMetrics, WindowStyle, WmMsg } from '../../constants'
6
6
 
7
7
  const noop = () => { }
8
8
 
@@ -48,8 +48,7 @@ export function createRoot(container: gui.HWND | RootWindowConfig) {
48
48
  const ws = (cfg.ws ?? 0) | WindowStyle.OVERLAPPEDWINDOW
49
49
  const w = (cfg.width ?? 800) * scaleFactor
50
50
  const h = (cfg.height ?? 600) * scaleFactor
51
- // GetScreenSize 等价内联:SM_CXSCREEN=0 / SM_CYSCREEN=1
52
- const [sw, sh] = [GetSystemMetrics(0), GetSystemMetrics(1)]
51
+ const [sw, sh] = [GetSystemMetrics(SysMetrics.CXSCREEN), GetSystemMetrics(SysMetrics.CYSCREEN)]
53
52
  const x = cfg.x === undefined ? ((sw - w) / 2) | 0
54
53
  : cfg.x === CreatePos.USEDEFAULT ? CreatePos.USEDEFAULT
55
54
  : cfg.x * scaleFactor
@@ -59,7 +58,8 @@ export function createRoot(container: gui.HWND | RootWindowConfig) {
59
58
  const hwin = gui.CreateWindow(className, cfg.text || '', ws, x, y, w, h, null, null)
60
59
  if (!hwin) throw new Error('CreateWindow failed')
61
60
  hwnd = hwin
62
- if (!cfg.noShowWindow) gui.ShowWindow(hwnd)
61
+ // 启动首帧:ShowWindow 后立即 WM_PAINT,不留白(原 gui.ShowWindow 复合语义)
62
+ if (!cfg.noShowWindow) { ShowWindow(hwnd, ShowWindowCmd.SHOWNORMAL); UpdateWindow(hwnd) }
63
63
  } else {
64
64
  hwnd = container
65
65
  }
@@ -1,5 +1,5 @@
1
1
  import * as gui from 'gui';
2
- import { SetWindowText, EnableWindow } from '../windows/user32.js';
2
+ import { SetWindowText, EnableWindow, ShowWindow } from '../windows/user32.js';
3
3
  export function applyProps(instance, newProps, _oldProps) {
4
4
  const hwnd = instance.hwnd;
5
5
  instance.props = newProps;
@@ -24,9 +24,9 @@ export function applyProps(instance, newProps, _oldProps) {
24
24
  EnableWindow(hwnd, !newProps.disabled ? 1 : 0);
25
25
  }
26
26
  if ('hidden' in newProps) {
27
- gui.ShowWindow(hwnd, newProps.hidden ? 0 /* ShowWindowCmd.HIDE */ : 5 /* ShowWindowCmd.SHOW */);
27
+ ShowWindow(hwnd, newProps.hidden ? 0 /* ShowWindowCmd.HIDE */ : 5 /* ShowWindowCmd.SHOW */);
28
28
  }
29
29
  if ('visible' in newProps) {
30
- gui.ShowWindow(hwnd, newProps.visible ? 5 /* ShowWindowCmd.SHOW */ : 0 /* ShowWindowCmd.HIDE */);
30
+ ShowWindow(hwnd, newProps.visible ? 5 /* ShowWindowCmd.SHOW */ : 0 /* ShowWindowCmd.HIDE */);
31
31
  }
32
32
  }
@@ -1,5 +1,5 @@
1
1
  import * as gui from 'gui'
2
- import { SetWindowText, EnableWindow } from '../windows/user32.js'
2
+ import { SetWindowText, EnableWindow, ShowWindow } from '../windows/user32.js'
3
3
  import type { Instance, Props } from './reconciler.js'
4
4
  import { EditMsg, ShowWindowCmd } from '../../constants'
5
5
 
@@ -33,9 +33,9 @@ export function applyProps(
33
33
  EnableWindow(hwnd, !newProps.disabled ? 1 : 0)
34
34
  }
35
35
  if ('hidden' in newProps) {
36
- gui.ShowWindow(hwnd, newProps.hidden ? ShowWindowCmd.HIDE : ShowWindowCmd.SHOW)
36
+ ShowWindow(hwnd, newProps.hidden ? ShowWindowCmd.HIDE : ShowWindowCmd.SHOW)
37
37
  }
38
38
  if ('visible' in newProps) {
39
- gui.ShowWindow(hwnd, newProps.visible ? ShowWindowCmd.SHOW : ShowWindowCmd.HIDE)
39
+ ShowWindow(hwnd, newProps.visible ? ShowWindowCmd.SHOW : ShowWindowCmd.HIDE)
40
40
  }
41
41
  }
@@ -3,21 +3,15 @@ import { createContext } from 'react';
3
3
  import { DefaultEventPriority, NoEventPriority } from 'react-reconciler/constants';
4
4
  import * as gui from 'gui';
5
5
  import * as os from 'os';
6
- import { GetDC, ReleaseDC, GetWindowLongPtr, CallWindowProc, SetWindowPos, InvalidateRect, SetParent, SetWindowText } from '../windows/user32.js';
7
- import { GetDeviceCaps } from '../windows/gdi32.js';
6
+ import { GetClientRect, GetWindowLongPtr, CallWindowProc, SetWindowPos, ShowWindow, InvalidateRect, SetParent, SetWindowText } from '../windows/user32.js';
7
+ import { createSystemDpiFont, getScaleFactor } from '../dpi.js';
8
+ import { RECT } from '../windows/structs.js';
8
9
  import { NULL } from '../ffi/ctype.js';
9
10
  import { applyProps } from './props.js';
10
11
  import { calculateFlexLayout } from './layout.js';
11
12
  import { getButtonIdealSize, measureTextForHwnd } from '../text-measure.js';
12
- const dpiFont = gui.CreateSystemDpiFont();
13
- // GetScaleFactor 等价内联:GetDC → GetDeviceCaps(LOGPIXELSX=88) → ReleaseDC 配对
14
- export const scaleFactor = (() => {
15
- const hdc = GetDC(NULL);
16
- const dpi = hdc ? GetDeviceCaps(hdc, 88) : 96;
17
- if (hdc)
18
- ReleaseDC(NULL, hdc);
19
- return dpi / 96;
20
- })();
13
+ const dpiFont = createSystemDpiFont();
14
+ export const scaleFactor = getScaleFactor();
21
15
  const DELAYED_CONTROLS = new Set(['SysListView32', 'SysTreeView32', 'LISTBOX', 'COMBOBOX', 'msctls_trackbar32', 'SysDateTimePick32', 'SysLink']);
22
16
  function isDelayedControl(winClass) {
23
17
  return DELAYED_CONTROLS.has(winClass);
@@ -59,11 +53,12 @@ function runFlexLayout(inst) {
59
53
  const visible = children.filter(c => !c.props.hidden);
60
54
  if (visible.length === 0)
61
55
  return;
62
- const rect = gui.GetClientRect(inst.hwnd);
63
- if (!rect) {
56
+ const rcBuf = RECT.alloc();
57
+ if (!GetClientRect(inst.hwnd, rcBuf.ptr)) {
64
58
  console.log('flex: no rect for', inst.hwnd, inst.type);
65
59
  return;
66
60
  }
61
+ const rect = RECT.decode(rcBuf);
67
62
  const pw = (rect.right - rect.left) / scaleFactor;
68
63
  const ph = (rect.bottom - rect.top) / scaleFactor;
69
64
  if (pw <= 0 || ph <= 0) {
@@ -260,19 +255,19 @@ const hostConfig = {
260
255
  },
261
256
  hideInstance(instance) {
262
257
  if (instance.hwnd !== null)
263
- gui.ShowWindow(instance.hwnd, 0 /* ShowWindowCmd.HIDE */);
258
+ ShowWindow(instance.hwnd, 0 /* ShowWindowCmd.HIDE */);
264
259
  },
265
260
  hideTextInstance(instance) {
266
261
  if (instance.hwnd !== null)
267
- gui.ShowWindow(instance.hwnd, 0 /* ShowWindowCmd.HIDE */);
262
+ ShowWindow(instance.hwnd, 0 /* ShowWindowCmd.HIDE */);
268
263
  },
269
264
  unhideInstance(instance, _props) {
270
265
  if (instance.hwnd !== null)
271
- gui.ShowWindow(instance.hwnd, 5 /* ShowWindowCmd.SHOW */);
266
+ ShowWindow(instance.hwnd, 5 /* ShowWindowCmd.SHOW */);
272
267
  },
273
268
  unhideTextInstance(instance, _text) {
274
269
  if (instance.hwnd !== null)
275
- gui.ShowWindow(instance.hwnd, 5 /* ShowWindowCmd.SHOW */);
270
+ ShowWindow(instance.hwnd, 5 /* ShowWindowCmd.SHOW */);
276
271
  },
277
272
  shouldSetTextContent(_type, props) {
278
273
  return typeof props.children === 'string' || typeof props.children === 'number';
@@ -3,8 +3,9 @@ import { createContext } from 'react'
3
3
  import { DefaultEventPriority, NoEventPriority } from 'react-reconciler/constants'
4
4
  import * as gui from 'gui'
5
5
  import * as os from 'os'
6
- import { GetDC, ReleaseDC, GetWindowLongPtr, CallWindowProc, SetWindowPos, InvalidateRect, SetParent, SetWindowText } from '../windows/user32.js'
7
- import { GetDeviceCaps } from '../windows/gdi32.js'
6
+ import { GetClientRect, GetWindowLongPtr, CallWindowProc, SetWindowPos, ShowWindow, InvalidateRect, SetParent, SetWindowText } from '../windows/user32.js'
7
+ import { createSystemDpiFont, getScaleFactor } from '../dpi.js'
8
+ import { RECT } from '../windows/structs.js'
8
9
  import { NULL } from '../ffi/ctype.js'
9
10
  import { applyProps } from './props.js'
10
11
  import { calculateFlexLayout, type FlexStyle } from './layout.js'
@@ -15,14 +16,8 @@ import { Gwlp, SetWindowPosFlag, SetWindowPosHwnd, ShowWindowCmd, WindowStyle, W
15
16
  // DEBUG 由 esbuild --define 在 bundle 时替换(见 build.ts),生产环境为 false
16
17
  declare const DEBUG: boolean
17
18
 
18
- const dpiFont = gui.CreateSystemDpiFont()
19
- // GetScaleFactor 等价内联:GetDC → GetDeviceCaps(LOGPIXELSX=88) → ReleaseDC 配对
20
- export const scaleFactor = (() => {
21
- const hdc = GetDC(NULL)
22
- const dpi = hdc ? GetDeviceCaps(hdc, 88) : 96
23
- if (hdc) ReleaseDC(NULL, hdc)
24
- return dpi / 96
25
- })()
19
+ const dpiFont = createSystemDpiFont()
20
+ export const scaleFactor = getScaleFactor()
26
21
 
27
22
  type Container = gui.HWND
28
23
  export type Props = WIntrinsicProps
@@ -83,8 +78,9 @@ function runFlexLayout(inst: Instance) {
83
78
  const flex: FlexStyle = s || {}
84
79
  const visible = children.filter(c => !c.props.hidden)
85
80
  if (visible.length === 0) return
86
- const rect = gui.GetClientRect(inst.hwnd!)
87
- if (!rect) { console.log('flex: no rect for', inst.hwnd, inst.type); return }
81
+ const rcBuf = RECT.alloc()
82
+ if (!GetClientRect(inst.hwnd!, rcBuf.ptr)) { console.log('flex: no rect for', inst.hwnd, inst.type); return }
83
+ const rect = RECT.decode(rcBuf)
88
84
  const pw = (rect.right - rect.left) / scaleFactor
89
85
  const ph = (rect.bottom - rect.top) / scaleFactor
90
86
  if (pw <= 0 || ph <= 0) { console.log('flex: zero size for', inst.hwnd, inst.type, pw, ph); return }
@@ -284,19 +280,19 @@ const hostConfig: QuickWinHostConfig = {
284
280
  },
285
281
 
286
282
  hideInstance(instance: Instance) {
287
- if (instance.hwnd !== null) gui.ShowWindow(instance.hwnd, ShowWindowCmd.HIDE)
283
+ if (instance.hwnd !== null) ShowWindow(instance.hwnd, ShowWindowCmd.HIDE)
288
284
  },
289
285
 
290
286
  hideTextInstance(instance: Instance) {
291
- if (instance.hwnd !== null) gui.ShowWindow(instance.hwnd, ShowWindowCmd.HIDE)
287
+ if (instance.hwnd !== null) ShowWindow(instance.hwnd, ShowWindowCmd.HIDE)
292
288
  },
293
289
 
294
290
  unhideInstance(instance: Instance, _props: Props) {
295
- if (instance.hwnd !== null) gui.ShowWindow(instance.hwnd, ShowWindowCmd.SHOW)
291
+ if (instance.hwnd !== null) ShowWindow(instance.hwnd, ShowWindowCmd.SHOW)
296
292
  },
297
293
 
298
294
  unhideTextInstance(instance: Instance, _text: string) {
299
- if (instance.hwnd !== null) gui.ShowWindow(instance.hwnd, ShowWindowCmd.SHOW)
295
+ if (instance.hwnd !== null) ShowWindow(instance.hwnd, ShowWindowCmd.SHOW)
300
296
  },
301
297
 
302
298
  shouldSetTextContent(_type: string, props: Props) {
@@ -1,6 +1,6 @@
1
1
  import { NULL } from './ffi/ctype.js';
2
2
  import * as gui from 'gui';
3
- import { DrawText, GetDC, ReleaseDC } from './windows/user32.js';
3
+ import { DrawText, GetDC, GetClientRect, GetWindowRect, ReleaseDC } from './windows/user32.js';
4
4
  import { SelectObject } from './windows/gdi32.js';
5
5
  import { RECT, SIZE } from './windows/structs.js';
6
6
  export function measureText(hdc, text, maxWidth) {
@@ -29,11 +29,14 @@ export function measureTextForHwnd(hwnd, text) {
29
29
  if (hFont)
30
30
  SelectObject(hdc, oldFont);
31
31
  ReleaseDC(hwnd, hdc);
32
- const wr = gui.GetWindowRect(hwnd);
33
- const cr = gui.GetClientRect(hwnd);
34
- if (wr && cr) {
35
- result.width += (wr.right - wr.left) - (cr.right - cr.left);
36
- result.height += (wr.bottom - wr.top) - (cr.bottom - cr.top);
32
+ const wr = RECT.alloc();
33
+ const cr = RECT.alloc();
34
+ const okWr = GetWindowRect(hwnd, wr.ptr);
35
+ const okCr = GetClientRect(hwnd, cr.ptr);
36
+ if (okWr && okCr) {
37
+ const w = RECT.decode(wr), c = RECT.decode(cr);
38
+ result.width += (w.right - w.left) - (c.right - c.left);
39
+ result.height += (w.bottom - w.top) - (c.bottom - c.top);
37
40
  }
38
41
  return result;
39
42
  }
@@ -1,6 +1,6 @@
1
1
  import { NULL, type Ptr } from './ffi/ctype.js'
2
2
  import * as gui from 'gui'
3
- import { DrawText, GetDC, ReleaseDC } from './windows/user32.js'
3
+ import { DrawText, GetDC, GetClientRect, GetWindowRect, ReleaseDC } from './windows/user32.js'
4
4
  import { SelectObject } from './windows/gdi32.js'
5
5
  import { RECT, SIZE } from './windows/structs.js'
6
6
  import { ButtonExtMsg, DrawTextFlag, WmMsg } from '../constants'
@@ -31,11 +31,14 @@ export function measureTextForHwnd(hwnd: gui.HWND, text: string): { width: numbe
31
31
  const result = measureText(hdc, text, 0)
32
32
  if (hFont) SelectObject(hdc, oldFont)
33
33
  ReleaseDC(hwnd, hdc)
34
- const wr = gui.GetWindowRect(hwnd)
35
- const cr = gui.GetClientRect(hwnd)
36
- if (wr && cr) {
37
- result.width += (wr.right - wr.left) - (cr.right - cr.left)
38
- result.height += (wr.bottom - wr.top) - (cr.bottom - cr.top)
34
+ const wr = RECT.alloc()
35
+ const cr = RECT.alloc()
36
+ const okWr = GetWindowRect(hwnd, wr.ptr)
37
+ const okCr = GetClientRect(hwnd, cr.ptr)
38
+ if (okWr && okCr) {
39
+ const w = RECT.decode(wr), c = RECT.decode(cr)
40
+ result.width += (w.right - w.left) - (c.right - c.left)
41
+ result.height += (w.bottom - w.top) - (c.bottom - c.top)
39
42
  }
40
43
  return result
41
44
  }
@@ -11,8 +11,9 @@ export const ImageListCreate = /*@__PURE__*/ b('ImageList_Create', 'i32 i32 u32
11
11
  /** 加位图进图像列表
12
12
  * @returns 新索引(-1 失败)
13
13
  * @param args_0 himl 图像列表句柄
14
- * @param args_1 hbm 位图句柄(gdi32 <HGDIOBJ>ptr 产物,如 CreateCompatibleBitmap) */
15
- export const ImageListAdd = /*@__PURE__*/ b('ImageList_Add', '<HIMAGELIST>ptr <HGDIOBJ>ptr -> i32');
14
+ * @param args_1 hbmImage 位图句柄(gdi32 <HGDIOBJ>ptr 产物,如 CreateCompatibleBitmap)
15
+ * @param args_2 hbmMask 掩码位图;32bpp 图像传 NULL */
16
+ export const ImageListAdd = /*@__PURE__*/ b('ImageList_Add', '<HIMAGELIST>ptr <HGDIOBJ>ptr <HGDIOBJ>ptr -> i32');
16
17
  /** 销毁图像列表
17
18
  * @returns 成功 → 非 0 */
18
19
  export const ImageListDestroy = /*@__PURE__*/ b('ImageList_Destroy', '<HIMAGELIST>ptr -> i32');
@@ -12,8 +12,9 @@ export const ImageListCreate = /*@__PURE__*/ b('ImageList_Create', 'i32 i32 u32
12
12
  /** 加位图进图像列表
13
13
  * @returns 新索引(-1 失败)
14
14
  * @param args_0 himl 图像列表句柄
15
- * @param args_1 hbm 位图句柄(gdi32 <HGDIOBJ>ptr 产物,如 CreateCompatibleBitmap) */
16
- export const ImageListAdd = /*@__PURE__*/ b('ImageList_Add', '<HIMAGELIST>ptr <HGDIOBJ>ptr -> i32')
15
+ * @param args_1 hbmImage 位图句柄(gdi32 <HGDIOBJ>ptr 产物,如 CreateCompatibleBitmap)
16
+ * @param args_2 hbmMask 掩码位图;32bpp 图像传 NULL */
17
+ export const ImageListAdd = /*@__PURE__*/ b('ImageList_Add', '<HIMAGELIST>ptr <HGDIOBJ>ptr <HGDIOBJ>ptr -> i32')
17
18
  /** 销毁图像列表
18
19
  * @returns 成功 → 非 0 */
19
20
  export const ImageListDestroy = /*@__PURE__*/ b('ImageList_Destroy', '<HIMAGELIST>ptr -> i32')
@@ -80,8 +80,30 @@ export const BitBlt = /*@__PURE__*/ b('BitBlt', '<HDC>ptr! i32 i32 i32 i32 <HDC>
80
80
  * @param args_3 cLines 扫描行数
81
81
  * @param args_4 lpvBits 像素接收缓冲(ArrayBuffer)
82
82
  * @param args_5 lpbmi BITMAPINFO 缓冲(BITMAPINFOHEADER.encode({...}).ptr)
83
- * @param args_6 uUsage DIB_RGB_COLORS(0) */
84
- export const GetDIBits = /*@__PURE__*/ b('GetDIBits', '<HDC>ptr! <HGDIOBJ>ptr u32 u32 <BYTE>ptr <>ptr u32 -> i32');
83
+ * @param args_6 uUsage ColorUse.RGB_COLORS */
84
+ export const GetDIBits = /*@__PURE__*/ b('GetDIBits', '<HDC>ptr! <HGDIOBJ>ptr u32 u32 <BYTE>ptr <>ptr u32@ColorUse -> i32');
85
+ /** 建 32bpp DIB 段位图(biHeight 负 = 自顶向下,像素内存由系统分配)——像素内容靠
86
+ * SetDIBits 从调用方缓冲装入,故 ppvBits 出参槽可传 NULL 不取位地址(要直写像素
87
+ * 才需要非空槽)
88
+ * @returns 位图句柄;失败 → 0(用完 DeleteObject)
89
+ * @param args_0 hdc 参考 DC(NULL 即可,只取 DIB 格式)
90
+ * @param args_1 pbmi BITMAPINFO 缓冲(BITMAPINFOHEADER.encode({...}).ptr,同 GetDIBits)
91
+ * @param args_2 iUsage ColorUse.RGB_COLORS
92
+ * @param args_3 ppvBits 收位地址的出参槽(NULL = 不取)
93
+ * @param args_4 hSection NULL(无文件映射区)
94
+ * @param args_5 offset 位数据在映射区内的偏移(无映射区恒 0) */
95
+ export const CreateDIBSection = /*@__PURE__*/ b('CreateDIBSection', '<HDC>ptr <>ptr u32@ColorUse <>ptr <>ptr u32 -> <HGDIOBJ>ptr');
96
+ /** 把 lpvBits 的像素装进位图(lpbmi 描述源的格式;ColorUse.RGB_COLORS 时 hdc 只定
97
+ * 目标格式,本仓传 NULL 实测可用——MSDN:仅 DIB_PAL_COLORS 才用 hdc)
98
+ * @returns 成功复制的扫描行数;失败 → 0
99
+ * @param args_0 hdc 参考 DC(NULL 即可,见上)
100
+ * @param args_1 hbm 目标位图(DIB 段同可用)
101
+ * @param args_2 uStartScan 起始扫描行
102
+ * @param args_3 cLines 扫描行数
103
+ * @param args_4 lpvBits 像素源缓冲(ArrayBuffer)
104
+ * @param args_5 lpbmi BITMAPINFO 缓冲(同 GetDIBits)
105
+ * @param args_6 iUsage ColorUse.RGB_COLORS */
106
+ export const SetDIBits = /*@__PURE__*/ b('SetDIBits', '<HDC>ptr <HGDIOBJ>ptr! u32 u32 <BYTE>ptr <>ptr u32@ColorUse -> i32');
85
107
  /** 取 GDI 对象信息到 lpv(hFont → LOGFONTW 等)
86
108
  * @returns 写入的字节数;失败 → 0
87
109
  * @param args_0 h GDI 对象句柄(字体/画笔/位图等)
@@ -171,8 +193,8 @@ export const MaskBlt = /*@__PURE__*/ b('MaskBlt', '<HDC>ptr! i32 i32 i32 i32 <HD
171
193
  * @param args_8 uNumScans 扫描行数
172
194
  * @param args_9 lpvBits 像素缓冲(ArrayBuffer)
173
195
  * @param args_10 lpbmi BITMAPINFO 缓冲
174
- * @param args_11 iUsage DIB_RGB_COLORS(0) */
175
- export const SetDIBitsToDevice = /*@__PURE__*/ b('SetDIBitsToDevice', '<HDC>ptr! i32 i32 u32 u32 i32 i32 u32 u32 <BYTE>ptr <BYTE>ptr u32 -> i32');
196
+ * @param args_11 iUsage ColorUse.RGB_COLORS */
197
+ export const SetDIBitsToDevice = /*@__PURE__*/ b('SetDIBitsToDevice', '<HDC>ptr! i32 i32 u32 u32 i32 i32 u32 u32 <BYTE>ptr <BYTE>ptr u32@ColorUse -> i32');
176
198
  /** 拉伸 DIB 传送(内存像素缓冲直接放/缩到目标,免创建 HBITMAP 中转);
177
199
  * DestWidth/DestHeight 传 0 = 源自然尺寸;SrcWidth/SrcHeight 负 = 翻转
178
200
  * @returns 成功 → 扫描行数;失败 → 0
@@ -186,9 +208,9 @@ export const SetDIBitsToDevice = /*@__PURE__*/ b('SetDIBitsToDevice', '<HDC>ptr!
186
208
  * @param args_8 SrcHeight 源区高
187
209
  * @param args_9 lpvBits 像素缓冲(ArrayBuffer)
188
210
  * @param args_10 lpbmi BITMAPINFO 缓冲(BITMAPINFOHEADER.encode({...}).ptr)
189
- * @param args_11 iUsage DIB_RGB_COLORS(0)
211
+ * @param args_11 iUsage ColorUse.RGB_COLORS
190
212
  * @param args_12 rop RasterOp.SRCCOPY 等互斥单选光栅操作码 */
191
- export const StretchDIBits = /*@__PURE__*/ b('StretchDIBits', '<HDC>ptr! i32 i32 i32 i32 i32 i32 i32 i32 <BYTE>ptr <BYTE>ptr u32 u32@RasterOp -> i32');
213
+ export const StretchDIBits = /*@__PURE__*/ b('StretchDIBits', '<HDC>ptr! i32 i32 i32 i32 i32 i32 i32 i32 <BYTE>ptr <BYTE>ptr u32@ColorUse u32@RasterOp -> i32');
192
214
  // ============ 画图原语(笔 / 线 / 形状 / 文字) ============
193
215
  /** 取系统共享对象(笔/刷/字体/调色板);共享句柄不要 DeleteObject——
194
216
  * SelectObject 选入 hdc 生效(如 NULL_BRUSH 让形状只描边不填充)