quickwin 1.3.0 → 2.1.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 (167) hide show
  1. package/README.en.md +18 -24
  2. package/README.md +17 -23
  3. package/examples/PdfCanvas.js +8 -37
  4. package/examples/PdfCanvas.tsx +11 -41
  5. package/examples/exec_server.js +20155 -1420
  6. package/examples/exec_server.tsx +489 -0
  7. package/examples/exec_server_worker.js +383 -33
  8. package/examples/exec_server_worker.ts +408 -30
  9. package/examples/pdf_preview2.js +25 -82
  10. package/examples/pdf_preview2.ts +27 -84
  11. package/examples/pdf_viewer.js +1424 -1180
  12. package/examples/pdf_viewer.tsx +16 -67
  13. package/examples/setres.js +22 -47
  14. package/examples/setres.ts +23 -57
  15. package/examples/test_gallery.js +1418 -1075
  16. package/examples/test_react_lazy.js +1391 -1059
  17. package/examples/test_react_listbox.js +1390 -1058
  18. package/examples/test_root_window.js +1384 -1052
  19. package/examples/test_tab.js +1391 -1059
  20. package/lib/abort.js +70 -0
  21. package/lib/abort.ts +69 -0
  22. package/lib/certs.js +219 -0
  23. package/lib/certs.ts +229 -0
  24. package/lib/exec-log.js +15 -0
  25. package/lib/exec-log.ts +30 -0
  26. package/lib/fetch.js +88 -7
  27. package/lib/fetch.ts +73 -7
  28. package/lib/ffi/bind.js +441 -0
  29. package/lib/ffi/bind.ts +539 -0
  30. package/lib/ffi/ctype.js +194 -0
  31. package/lib/ffi/ctype.ts +369 -0
  32. package/lib/ffi/index.js +6 -0
  33. package/lib/ffi/index.ts +6 -0
  34. package/lib/ffi/struct.js +490 -0
  35. package/lib/ffi/struct.ts +753 -0
  36. package/lib/http-common.js +43 -5
  37. package/lib/http-common.ts +48 -6
  38. package/lib/http-server.js +187 -29
  39. package/lib/http-server.ts +177 -26
  40. package/lib/react-qw/components/DateTimePicker.js +18 -37
  41. package/lib/react-qw/components/Input.js +3 -10
  42. package/lib/react-qw/components/Link.js +6 -19
  43. package/lib/react-qw/components/ListView.js +50 -154
  44. package/lib/react-qw/components/PathPicker.js +28 -88
  45. package/lib/react-qw/components/ScrollView.js +15 -8
  46. package/lib/react-qw/components/Slider.js +2 -1
  47. package/lib/react-qw/components/Tab.js +6 -22
  48. package/lib/react-qw/components/Tooltip.js +10 -21
  49. package/lib/react-qw/components/TreeView.js +8 -31
  50. package/lib/react-qw/index.js +5 -3
  51. package/lib/react-qw/index.ts +8 -3
  52. package/lib/react-qw/nmhdr.js +3 -24
  53. package/lib/react-qw/nmhdr.ts +5 -30
  54. package/lib/react-qw/props.js +7 -2
  55. package/lib/react-qw/props.ts +7 -3
  56. package/lib/react-qw/reconciler.js +23 -13
  57. package/lib/react-qw/reconciler.ts +22 -13
  58. package/lib/text-measure.js +20 -23
  59. package/lib/text-measure.ts +22 -26
  60. package/lib/websocket.js +44 -4
  61. package/lib/websocket.ts +40 -4
  62. package/lib/windows/advapi32.js +53 -0
  63. package/lib/windows/advapi32.ts +64 -0
  64. package/lib/windows/comctl32.js +18 -0
  65. package/lib/windows/comctl32.ts +19 -0
  66. package/lib/windows/comdlg32.js +8 -0
  67. package/lib/windows/comdlg32.ts +10 -0
  68. package/lib/windows/gdi32.js +392 -0
  69. package/lib/windows/gdi32.ts +420 -0
  70. package/lib/windows/kernel32.js +262 -0
  71. package/lib/windows/kernel32.ts +291 -0
  72. package/lib/windows/msimg32.js +38 -0
  73. package/lib/windows/msimg32.ts +45 -0
  74. package/lib/windows/ntdll.js +9 -0
  75. package/lib/windows/ntdll.ts +11 -0
  76. package/lib/windows/ole32.js +7 -0
  77. package/lib/windows/ole32.ts +9 -0
  78. package/lib/windows/psapi.js +32 -0
  79. package/lib/windows/psapi.ts +37 -0
  80. package/lib/windows/shell32.js +13 -0
  81. package/lib/windows/shell32.ts +16 -0
  82. package/lib/windows/structs.js +519 -0
  83. package/lib/windows/structs.ts +566 -0
  84. package/lib/windows/user32.js +572 -0
  85. package/lib/windows/user32.ts +607 -0
  86. package/lib/windows/version.js +29 -0
  87. package/lib/windows/version.ts +35 -0
  88. package/lib/windows/winspool.js +71 -0
  89. package/lib/windows/winspool.ts +80 -0
  90. package/package.json +1 -1
  91. package/quickwin.d.ts +31 -40
  92. package/quickwin_const.d.ts +137 -0
  93. package/qwin-nowasm-x86.exe +0 -0
  94. package/qwin-nowasm.exe +0 -0
  95. package/qwin-x86.exe +0 -0
  96. package/qwin.exe +0 -0
  97. package/test/bench_ffi_callraw.js +236 -0
  98. package/test/bench_ffi_callraw.ts +236 -0
  99. package/test/bench_ffi_overhead.js +139 -0
  100. package/test/bench_ffi_overhead.ts +141 -0
  101. package/test/bench_sendmessage.js +104 -0
  102. package/test/bench_sendmessage.ts +100 -0
  103. package/test/bench_sendmessage_nonnull.js +187 -0
  104. package/test/bench_sendmessage_nonnull.ts +188 -0
  105. package/test/run.js +19 -4
  106. package/test/run.ts +20 -5
  107. package/test/test_basic_fetch.js +29 -0
  108. package/test/test_basic_fetch.ts +26 -0
  109. package/test/test_ffi.js +27 -45
  110. package/test/test_ffi.ts +35 -54
  111. package/test/test_ffi_abi.js +290 -0
  112. package/test/test_ffi_abi.ts +274 -0
  113. package/test/test_ffi_array.js +116 -0
  114. package/test/test_ffi_array.ts +141 -0
  115. package/test/test_ffi_bind.js +620 -8
  116. package/test/test_ffi_bind.ts +630 -8
  117. package/test/test_ffi_struct.js +632 -88
  118. package/test/test_ffi_struct.ts +666 -91
  119. package/test/test_ffi_struct_layout.js +495 -0
  120. package/test/test_ffi_struct_layout.ts +543 -0
  121. package/test/test_ffi_user32.js +103 -0
  122. package/test/test_ffi_user32.ts +113 -0
  123. package/test/test_ffi_windows.js +101 -0
  124. package/test/test_ffi_windows.ts +113 -0
  125. package/test/test_files.js +102 -0
  126. package/test/test_files.ts +121 -0
  127. package/test/test_gdi_draw.js +681 -0
  128. package/test/test_gdi_draw.ts +725 -0
  129. package/test/test_helper.js +8 -1
  130. package/test/test_helper.ts +9 -1
  131. package/test/test_http_import.js +18 -0
  132. package/test/test_http_import.ts +19 -0
  133. package/test/test_http_server.js +73 -1
  134. package/test/test_http_server.ts +75 -1
  135. package/test/test_ipv6.js +2 -2
  136. package/test/test_ipv6.ts +2 -2
  137. package/test/test_net_fetch.js +74 -11
  138. package/test/test_net_fetch.ts +73 -10
  139. package/test/test_net_websocket.js +1 -1
  140. package/test/test_net_websocket.ts +1 -1
  141. package/test/test_printer.js +137 -0
  142. package/test/test_printer.ts +148 -0
  143. package/test/test_proc.js +141 -0
  144. package/test/test_proc.ts +163 -0
  145. package/test/test_react_complex.js +1401 -1069
  146. package/test/test_react_counter.js +1391 -1059
  147. package/test/test_react_flex.js +1411 -1072
  148. package/test/test_react_hidden.js +1394 -1062
  149. package/test/test_react_listview_link.js +1391 -1059
  150. package/test/test_react_notify.js +18638 -0
  151. package/test/test_react_render.js +1391 -1059
  152. package/test/test_registry.js +74 -0
  153. package/test/test_registry.ts +95 -0
  154. package/test/test_sysinfo.js +122 -0
  155. package/test/test_sysinfo.ts +141 -0
  156. package/test/test_wolfssl_read.js +45 -43
  157. package/test/test_wolfssl_read.ts +42 -40
  158. package/test/test_worker_net.js +35 -17
  159. package/test/test_worker_net.ts +27 -15
  160. package/tsconfig.json +1 -1
  161. package/examples/exec_server.ts +0 -80
  162. package/lib/ffi-bind.js +0 -85
  163. package/lib/ffi-bind.ts +0 -170
  164. package/lib/ffi-struct.js +0 -224
  165. package/lib/ffi-struct.ts +0 -239
  166. package/lib/win-common-structs.js +0 -39
  167. package/lib/win-common-structs.ts +0 -41
@@ -1,86 +1,35 @@
1
+ import { MaybePtr, PtrArrayBuffer } from '../lib/ffi/ctype.js'
1
2
  import '../lib/polyfill.js'
2
3
  import * as std from 'std'
3
4
  import * as gui from 'gui'
4
- import * as win from 'win'
5
- import * as ffi from 'ffi'
6
5
  import type { Document, Page, Pixmap } from '../vendor/mupdf-wasm/mupdf.js'
7
6
  import { useState } from 'react'
8
7
  import { render, Button, Input, ScrollView } from '../lib/react-qw/index.js'
8
+ import { WCHAR } from '../lib/ffi/bind.js'
9
9
  import { PdfCanvas } from './PdfCanvas.js'
10
- import { OPENFILENAMEW } from '../lib/win-common-structs.js'
10
+ import { OPENFILENAMEW } from '../lib/windows/structs.js'
11
+ import { GetOpenFileName } from '../lib/windows/comdlg32.js'
11
12
 
12
13
  type MuPdf = typeof import('../vendor/mupdf-wasm/mupdf.js')
13
14
 
14
- const _user32 = win.LoadLibrary('user32.dll')
15
- const _gdi32 = win.LoadLibrary('gdi32.dll')
16
- const _comdlg32 = win.LoadLibrary('comdlg32.dll')
17
- if (!_user32 || !_gdi32 || !_comdlg32) {
18
- gui.MessageBox('Failed to load system libraries')
19
- std.exit(0)
20
- }
21
-
22
- function loadProc(lib: win.HMODULE, name: string): number {
23
- const ptr = win.GetProcAddress(lib, name)
24
- if (!ptr) throw new Error('Failed to load ' + name)
25
- return ptr
26
- }
27
-
28
- const GetOpenFileNameW_ = loadProc(_comdlg32, 'GetOpenFileNameW')
29
- const FFI_PTR = ffi.FFI_TYPE_POINTER
30
- const FFI_U32 = ffi.FFI_TYPE_UINT32
31
-
32
- function strToWide(str: string): ArrayBuffer {
33
- const buf = new ArrayBuffer((str.length + 1) * 2)
34
- const dv = new DataView(buf)
35
- for (let i = 0; i < str.length; i++) dv.setUint16(i * 2, str.charCodeAt(i), true)
36
- return buf
37
- }
38
-
39
- function wideToStr(buf: ArrayBuffer): string {
40
- const dv = new DataView(buf)
41
- const chars: number[] = []
42
- for (let i = 0; i < buf.byteLength; i += 2) {
43
- const c = dv.getUint16(i, true)
44
- if (c === 0) break
45
- chars.push(c)
46
- }
47
- return String.fromCharCode(...chars)
48
- }
49
-
50
- function openPdfFileDialog(owner: number): string | null {
51
- const fileBuf = new ArrayBuffer(260 * 2)
52
- const filterWide = strToWide('PDF Files\0*.pdf\0All Files\0*.*\0\0')
53
- const ofn: ArrayBuffer & { __keep?: ArrayBuffer[] } = OPENFILENAMEW.write({
15
+ function openPdfFileDialog(owner: MaybePtr<'HWND'>): string | null {
16
+ const fileBuf = WCHAR.alloc(260)
17
+ const filterWide = WCHAR.encode('PDF Files\0*.pdf\0All Files\0*.*\0\0')
18
+ // 缺省字段跳过 = fresh buffer 上留 0
19
+ const ofn: PtrArrayBuffer<'OPENFILENAMEW'> & { __keep?: ArrayBuffer[] } = OPENFILENAMEW.encode({
54
20
  lStructSize: OPENFILENAMEW.size,
55
21
  hwndOwner: owner,
56
- hInstance: 0,
57
- lpstrFilter: ffi.bufferPtr(filterWide),
58
- lpstrCustomFilter: 0,
59
- nMaxCustFilter: 0,
60
- nFilterIndex: 0,
61
- lpstrFile: ffi.bufferPtr(fileBuf),
22
+ lpstrFilter: filterWide.ptr,
23
+ lpstrFile: fileBuf.ptr,
62
24
  nMaxFile: 260,
63
- lpstrFileTitle: 0,
64
- nMaxFileTitle: 0,
65
- lpstrInitialDir: 0,
66
- lpstrTitle: 0,
67
25
  Flags: 0x1000 | 0x0800 | 0x0004,
68
- nFileOffset: 0,
69
- nFileExtension: 0,
70
- lpstrDefExt: 0,
71
- lCustData: 0,
72
- lpfnHook: 0,
73
- lpTemplateName: 0,
74
- pvReserved: 0,
75
- dwReserved: 0,
76
- FlagsEx: 0,
77
26
  })
78
27
  ofn.__keep = [fileBuf, filterWide]
79
28
 
80
- const ret = ffi.ffiCall(GetOpenFileNameW_, [FFI_PTR], [ofn], FFI_U32)
29
+ const ret = GetOpenFileName(ofn.ptr)
81
30
  if (!ret) return null
82
31
 
83
- const path = wideToStr(fileBuf)
32
+ const path = WCHAR.decode(fileBuf)
84
33
  return path.length > 0 ? path : null
85
34
  }
86
35
 
@@ -108,7 +57,7 @@ async function loadMupdf(): Promise<MuPdf | null> {
108
57
  }
109
58
 
110
59
  interface PixmapInfo {
111
- data: ArrayBuffer
60
+ data: PtrArrayBuffer<string>
112
61
  w: number
113
62
  h: number
114
63
  }
@@ -169,7 +118,7 @@ function renderPdfPage(mupdf: MuPdf, filePath: string, pageIndex: number): Pixma
169
118
  const dibStride = Math.floor((w * 3 + 3) / 4) * 4
170
119
 
171
120
  const dibSize = h * dibStride
172
- const dibBuffer = new ArrayBuffer(dibSize)
121
+ const dibBuffer = new PtrArrayBuffer(dibSize)
173
122
  const dib = new Uint8Array(dibBuffer)
174
123
 
175
124
  for (let y = 0; y < h; y++) {
@@ -196,7 +145,7 @@ function renderPdfPage(mupdf: MuPdf, filePath: string, pageIndex: number): Pixma
196
145
  }
197
146
  }
198
147
 
199
- function App({ mupdf, mainHwnd: hwnd }: { mupdf: MuPdf; mainHwnd: number }) {
148
+ function App({ mupdf, mainHwnd: hwnd }: { mupdf: MuPdf; mainHwnd: gui.HWND }) {
200
149
  const [filePath, setFilePath] = useState('')
201
150
  const [currentPage, setCurrentPage] = useState(0)
202
151
  const [pixmap, setPixmap] = useState<PixmapInfo | undefined>(undefined)
@@ -1,24 +1,8 @@
1
1
  import * as std from 'std';
2
2
  import * as gui from 'gui';
3
- import * as win from 'win';
4
- import * as ffi from 'ffi';
5
- const user32 = win.LoadLibrary('user32.dll');
6
- if (!user32) {
7
- print('LoadLibrary user32 failed');
8
- std.exit(1);
9
- }
10
- function loadProc(lib, name) {
11
- const ptr = win.GetProcAddress(lib, name);
12
- if (!ptr) {
13
- print('GetProcAddress ' + name + ' failed');
14
- std.exit(1);
15
- }
16
- return ptr;
17
- }
18
- const EnumDisplaySettingsA = loadProc(user32, 'EnumDisplaySettingsA');
19
- const ChangeDisplaySettingsA = loadProc(user32, 'ChangeDisplaySettingsA');
20
- /** DEVMODEA used by EnumDisplaySettings; driver reports actual dmSize (often 124). */
21
- const DEVMODE_SIZE = 220;
3
+ import { NULL } from '../lib/ffi/ctype.js';
4
+ import { ChangeDisplaySettings, EnumDisplaySettings } from '../lib/windows/user32.js';
5
+ import { DEVMODEW } from '../lib/windows/structs.js';
22
6
  const DM_PELSWIDTH = 0x00800000;
23
7
  const DM_PELSHEIGHT = 0x01000000;
24
8
  const ENUM_CURRENT_SETTINGS = -1;
@@ -35,35 +19,27 @@ const DISP_CHANGE = {
35
19
  [-6]: 'BADDUALVIEW',
36
20
  };
37
21
  function newDevMode() {
38
- const buf = new ArrayBuffer(DEVMODE_SIZE);
39
- new DataView(buf).setUint16(36, DEVMODE_SIZE, true);
40
- return buf;
41
- }
42
- function enumMode(modeNum, buf) {
43
- return ffi.ffiCall(EnumDisplaySettingsA, [ffi.FFI_TYPE_POINTER, ffi.FFI_TYPE_SINT32, ffi.FFI_TYPE_POINTER], [null, modeNum, buf], ffi.FFI_TYPE_SINT32);
44
- }
45
- function getPels(dv) {
46
- return [dv.getUint32(108, true), dv.getUint32(112, true), dv.getUint32(120, true)];
22
+ // dmSize = 结构自身大小是 Win32 要求(否则 API 拒绝);其余字段由 Enum 就地填充
23
+ return DEVMODEW.encode({ dmSize: DEVMODEW.size });
47
24
  }
48
25
  function applyFromCurrent(w, h, flags, label) {
49
26
  const dm = newDevMode();
50
- if (!enumMode(ENUM_CURRENT_SETTINGS, dm)) {
27
+ if (!EnumDisplaySettings(NULL, ENUM_CURRENT_SETTINGS, dm.ptr)) {
51
28
  print(label + ': EnumDisplaySettings CURRENT failed');
52
29
  return null;
53
30
  }
54
- const dv = new DataView(dm);
55
- const before = getPels(dv);
56
- const size = dv.getUint16(36, true);
57
- const extra = dv.getUint16(38, true);
58
- const fields = dv.getUint32(40, true);
59
- const bpp = dv.getUint32(104, true);
60
- const freq = dv.getUint32(120, true);
61
- print(label + ': base size=' + size + ' extra=' + extra + ' fields=0x' + fields.toString(16) +
62
- ' ' + before[0] + 'x' + before[1] + '@' + freq + ' bpp=' + bpp);
63
- dv.setUint32(40, fields | DM_PELSWIDTH | DM_PELSHEIGHT, true);
64
- dv.setUint32(108, w, true);
65
- dv.setUint32(112, h, true);
66
- const ret = ffi.ffiCall(ChangeDisplaySettingsA, [ffi.FFI_TYPE_POINTER, ffi.FFI_TYPE_UINT32], [dm, flags], ffi.FFI_TYPE_SINT32);
31
+ const cur = DEVMODEW.decode(dm);
32
+ print(label + ': base size=' + cur.dmSize + ' extra=' + cur.dmDriverExtra +
33
+ ' fields=0x' + cur.dmFields.toString(16) +
34
+ ' ' + cur.dmPelsWidth + 'x' + cur.dmPelsHeight +
35
+ '@' + cur.dmDisplayFrequency + ' bpp=' + cur.dmBitsPerPel);
36
+ // 复用同一 buffer 原地改三项(encode 缺省字段跳过 = 保留 Enum 填的其余项)
37
+ DEVMODEW.encode({
38
+ dmFields: cur.dmFields | DM_PELSWIDTH | DM_PELSHEIGHT,
39
+ dmPelsWidth: w,
40
+ dmPelsHeight: h,
41
+ }, dm);
42
+ const ret = ChangeDisplaySettings(dm.ptr, flags);
67
43
  print(label + ': ChangeDisplaySettings ' + w + 'x' + h +
68
44
  ' flags=0x' + flags.toString(16) + ' ret=' + ret + ' (' + (DISP_CHANGE[ret] ?? '?') + ')');
69
45
  return ret;
@@ -78,13 +54,12 @@ print('before GetScreenSize: ' + JSON.stringify(gui.GetScreenSize()));
78
54
  const probe = newDevMode();
79
55
  const modes32 = [];
80
56
  for (let i = 0; i < 200; i++) {
81
- if (!enumMode(i, probe))
57
+ if (!EnumDisplaySettings(NULL, i, probe.ptr))
82
58
  break;
83
- const dv = new DataView(probe);
84
- if (dv.getUint32(104, true) !== 32)
59
+ const dm = DEVMODEW.decode(probe);
60
+ if (dm.dmBitsPerPel !== 32)
85
61
  continue;
86
- const p = getPels(dv);
87
- modes32.push(p[0] + 'x' + p[1] + '@' + p[2]);
62
+ modes32.push(dm.dmPelsWidth + 'x' + dm.dmPelsHeight + '@' + dm.dmDisplayFrequency);
88
63
  }
89
64
  print('32bpp modes sample: ' + modes32.slice(0, 25).join(', ') + (modes32.length > 25 ? ' ...' : ''));
90
65
  const testRet = applyFromCurrent(targetW, targetH, CDS_TEST, 'TEST');
@@ -1,22 +1,9 @@
1
1
  import * as std from 'std'
2
2
  import * as gui from 'gui'
3
- import * as win from 'win'
4
- import * as ffi from 'ffi'
3
+ import { NULL } from '../lib/ffi/ctype.js'
4
+ import { ChangeDisplaySettings, EnumDisplaySettings } from '../lib/windows/user32.js'
5
+ import { DEVMODEW } from '../lib/windows/structs.js'
5
6
 
6
- const user32 = win.LoadLibrary('user32.dll')
7
- if (!user32) { print('LoadLibrary user32 failed'); std.exit(1) }
8
-
9
- function loadProc(lib: win.HMODULE, name: string): number {
10
- const ptr = win.GetProcAddress(lib, name)
11
- if (!ptr) { print('GetProcAddress ' + name + ' failed'); std.exit(1) }
12
- return ptr
13
- }
14
-
15
- const EnumDisplaySettingsA = loadProc(user32, 'EnumDisplaySettingsA')
16
- const ChangeDisplaySettingsA = loadProc(user32, 'ChangeDisplaySettingsA')
17
-
18
- /** DEVMODEA used by EnumDisplaySettings; driver reports actual dmSize (often 124). */
19
- const DEVMODE_SIZE = 220
20
7
  const DM_PELSWIDTH = 0x00800000
21
8
  const DM_PELSHEIGHT = 0x01000000
22
9
  const ENUM_CURRENT_SETTINGS = -1
@@ -34,51 +21,31 @@ const DISP_CHANGE: Record<number, string> = {
34
21
  [-6]: 'BADDUALVIEW',
35
22
  }
36
23
 
37
- function newDevMode(): ArrayBuffer {
38
- const buf = new ArrayBuffer(DEVMODE_SIZE)
39
- new DataView(buf).setUint16(36, DEVMODE_SIZE, true)
40
- return buf
41
- }
42
-
43
- function enumMode(modeNum: number, buf: ArrayBuffer): number {
44
- return ffi.ffiCall(
45
- EnumDisplaySettingsA,
46
- [ffi.FFI_TYPE_POINTER, ffi.FFI_TYPE_SINT32, ffi.FFI_TYPE_POINTER],
47
- [null, modeNum, buf],
48
- ffi.FFI_TYPE_SINT32,
49
- )
50
- }
51
-
52
- function getPels(dv: DataView): [number, number, number] {
53
- return [dv.getUint32(108, true), dv.getUint32(112, true), dv.getUint32(120, true)]
24
+ function newDevMode() {
25
+ // dmSize = 结构自身大小是 Win32 要求(否则 API 拒绝);其余字段由 Enum 就地填充
26
+ return DEVMODEW.encode({ dmSize: DEVMODEW.size })
54
27
  }
55
28
 
56
29
  function applyFromCurrent(w: number, h: number, flags: number, label: string): number | null {
57
30
  const dm = newDevMode()
58
- if (!enumMode(ENUM_CURRENT_SETTINGS, dm)) {
31
+ if (!EnumDisplaySettings(NULL, ENUM_CURRENT_SETTINGS, dm.ptr)) {
59
32
  print(label + ': EnumDisplaySettings CURRENT failed')
60
33
  return null
61
34
  }
62
- const dv = new DataView(dm)
63
- const before = getPels(dv)
64
- const size = dv.getUint16(36, true)
65
- const extra = dv.getUint16(38, true)
66
- const fields = dv.getUint32(40, true)
67
- const bpp = dv.getUint32(104, true)
68
- const freq = dv.getUint32(120, true)
69
- print(label + ': base size=' + size + ' extra=' + extra + ' fields=0x' + fields.toString(16) +
70
- ' ' + before[0] + 'x' + before[1] + '@' + freq + ' bpp=' + bpp)
35
+ const cur = DEVMODEW.decode(dm)
36
+ print(label + ': base size=' + cur.dmSize + ' extra=' + cur.dmDriverExtra +
37
+ ' fields=0x' + cur.dmFields.toString(16) +
38
+ ' ' + cur.dmPelsWidth + 'x' + cur.dmPelsHeight +
39
+ '@' + cur.dmDisplayFrequency + ' bpp=' + cur.dmBitsPerPel)
71
40
 
72
- dv.setUint32(40, fields | DM_PELSWIDTH | DM_PELSHEIGHT, true)
73
- dv.setUint32(108, w, true)
74
- dv.setUint32(112, h, true)
41
+ // 复用同一 buffer 原地改三项(encode 缺省字段跳过 = 保留 Enum 填的其余项)
42
+ DEVMODEW.encode({
43
+ dmFields: cur.dmFields | DM_PELSWIDTH | DM_PELSHEIGHT,
44
+ dmPelsWidth: w,
45
+ dmPelsHeight: h,
46
+ }, dm)
75
47
 
76
- const ret = ffi.ffiCall(
77
- ChangeDisplaySettingsA,
78
- [ffi.FFI_TYPE_POINTER, ffi.FFI_TYPE_UINT32],
79
- [dm, flags],
80
- ffi.FFI_TYPE_SINT32,
81
- )
48
+ const ret = ChangeDisplaySettings(dm.ptr, flags)
82
49
  print(label + ': ChangeDisplaySettings ' + w + 'x' + h +
83
50
  ' flags=0x' + flags.toString(16) + ' ret=' + ret + ' (' + (DISP_CHANGE[ret] ?? '?') + ')')
84
51
  return ret
@@ -96,11 +63,10 @@ print('before GetScreenSize: ' + JSON.stringify(gui.GetScreenSize()))
96
63
  const probe = newDevMode()
97
64
  const modes32: string[] = []
98
65
  for (let i = 0; i < 200; i++) {
99
- if (!enumMode(i, probe)) break
100
- const dv = new DataView(probe)
101
- if (dv.getUint32(104, true) !== 32) continue
102
- const p = getPels(dv)
103
- modes32.push(p[0] + 'x' + p[1] + '@' + p[2])
66
+ if (!EnumDisplaySettings(NULL, i, probe.ptr)) break
67
+ const dm = DEVMODEW.decode(probe)
68
+ if (dm.dmBitsPerPel !== 32) continue
69
+ modes32.push(dm.dmPelsWidth + 'x' + dm.dmPelsHeight + '@' + dm.dmDisplayFrequency)
104
70
  }
105
71
  print('32bpp modes sample: ' + modes32.slice(0, 25).join(', ') + (modes32.length > 25 ? ' ...' : ''))
106
72