quickwin 2.0.0 → 2.1.1

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 (103) hide show
  1. package/README.en.md +21 -26
  2. package/README.md +3 -6
  3. package/examples/exec_server.js +139 -31
  4. package/examples/exec_server.tsx +7 -8
  5. package/examples/exec_server_worker.js +1 -1
  6. package/examples/exec_server_worker.ts +2 -2
  7. package/examples/pdf_preview2.js +1 -1
  8. package/examples/pdf_preview2.ts +1 -1
  9. package/examples/pdf_viewer.js +132 -28
  10. package/examples/pdf_viewer.tsx +1 -1
  11. package/examples/test_gallery.js +131 -27
  12. package/examples/test_react_lazy.js +131 -27
  13. package/examples/test_react_listbox.js +131 -27
  14. package/examples/test_root_window.js +131 -27
  15. package/examples/test_tab.js +131 -27
  16. package/lib/certs.js +13 -8
  17. package/lib/certs.ts +13 -8
  18. package/lib/fetch.js +51 -3
  19. package/lib/fetch.ts +38 -3
  20. package/lib/ffi/bind.js +94 -5
  21. package/lib/ffi/bind.ts +107 -10
  22. package/lib/ffi/ctype.js +33 -7
  23. package/lib/ffi/ctype.ts +48 -10
  24. package/lib/ffi/struct.js +92 -14
  25. package/lib/ffi/struct.ts +108 -19
  26. package/lib/react-qw/components/ListView.js +1 -0
  27. package/lib/react-qw/components/PathPicker.js +2 -2
  28. package/lib/react-qw/index.js +1 -1
  29. package/lib/react-qw/index.ts +4 -1
  30. package/lib/text-measure.js +3 -1
  31. package/lib/text-measure.ts +4 -3
  32. package/lib/websocket.js +32 -2
  33. package/lib/websocket.ts +25 -2
  34. package/lib/windows/advapi32.js +53 -0
  35. package/lib/windows/advapi32.ts +64 -0
  36. package/lib/windows/comctl32.js +15 -15
  37. package/lib/windows/comctl32.ts +15 -16
  38. package/lib/windows/comdlg32.js +3 -2
  39. package/lib/windows/comdlg32.ts +3 -2
  40. package/lib/windows/gdi32.js +328 -26
  41. package/lib/windows/gdi32.ts +349 -26
  42. package/lib/windows/kernel32.js +206 -10
  43. package/lib/windows/kernel32.ts +225 -10
  44. package/lib/windows/msimg32.js +38 -0
  45. package/lib/windows/msimg32.ts +45 -0
  46. package/lib/windows/ntdll.js +3 -2
  47. package/lib/windows/ntdll.ts +3 -2
  48. package/lib/windows/ole32.js +1 -1
  49. package/lib/windows/ole32.ts +1 -1
  50. package/lib/windows/psapi.js +32 -0
  51. package/lib/windows/psapi.ts +37 -0
  52. package/lib/windows/shell32.js +5 -3
  53. package/lib/windows/shell32.ts +5 -3
  54. package/lib/windows/structs.js +135 -0
  55. package/lib/windows/structs.ts +144 -0
  56. package/lib/windows/user32.js +202 -99
  57. package/lib/windows/user32.ts +204 -99
  58. package/lib/windows/version.js +29 -0
  59. package/lib/windows/version.ts +35 -0
  60. package/lib/windows/winspool.js +71 -0
  61. package/lib/windows/winspool.ts +80 -0
  62. package/package.json +1 -1
  63. package/quickwin.d.ts +11 -5
  64. package/quickwin_const.d.ts +136 -0
  65. package/qwin-nowasm-x86.exe +0 -0
  66. package/qwin-nowasm.exe +0 -0
  67. package/qwin-x86.exe +0 -0
  68. package/qwin.exe +0 -0
  69. package/test/run.js +7 -0
  70. package/test/run.ts +7 -0
  71. package/test/test_basic_fetch.js +21 -0
  72. package/test/test_basic_fetch.ts +17 -0
  73. package/test/test_ffi.js +6 -6
  74. package/test/test_ffi.ts +6 -6
  75. package/test/test_ffi_abi.js +55 -0
  76. package/test/test_ffi_abi.ts +56 -0
  77. package/test/test_ffi_array.js +116 -0
  78. package/test/test_ffi_array.ts +141 -0
  79. package/test/test_ffi_bind.js +82 -0
  80. package/test/test_ffi_bind.ts +71 -0
  81. package/test/test_files.js +102 -0
  82. package/test/test_files.ts +121 -0
  83. package/test/test_gdi_draw.js +681 -0
  84. package/test/test_gdi_draw.ts +725 -0
  85. package/test/test_net_fetch.js +4 -3
  86. package/test/test_net_fetch.ts +4 -3
  87. package/test/test_printer.js +137 -0
  88. package/test/test_printer.ts +148 -0
  89. package/test/test_proc.js +141 -0
  90. package/test/test_proc.ts +163 -0
  91. package/test/test_react_complex.js +131 -27
  92. package/test/test_react_counter.js +131 -27
  93. package/test/test_react_flex.js +131 -27
  94. package/test/test_react_hidden.js +131 -27
  95. package/test/test_react_listview_link.js +131 -27
  96. package/test/test_react_notify.js +131 -27
  97. package/test/test_react_render.js +131 -27
  98. package/test/test_registry.js +74 -0
  99. package/test/test_registry.ts +95 -0
  100. package/test/test_sysinfo.js +122 -0
  101. package/test/test_sysinfo.ts +141 -0
  102. package/test/test_wolfssl_read.js +45 -44
  103. package/test/test_wolfssl_read.ts +42 -42
@@ -0,0 +1,102 @@
1
+ import { WCHAR } from '../lib/ffi/bind.js';
2
+ import { NULL, PtrArrayBuffer } from '../lib/ffi/ctype.js';
3
+ import { CloseHandle, CopyFile, CreateDirectory, CreateFile, DeleteFile, FindClose, FindFirstFile, FindNextFile, GetFileAttributes, GetFileSize, GetTempPath, MoveFileEx, ReadFile, RemoveDirectory, SetFilePointer, WriteFile, } from '../lib/windows/kernel32.js';
4
+ import { WIN32_FIND_DATAW } from '../lib/windows/structs.js';
5
+ const GENERIC_READ = 0x80000000;
6
+ const GENERIC_WRITE = 0x40000000;
7
+ const FILE_ATTRIBUTE_DIRECTORY = 0x10;
8
+ const INVALID32 = 0xffffffff;
9
+ // ASCII payload ↔ UTF-16LE 缓冲互转(REG_SZ 同型,测试内联)
10
+ function toWide(s) {
11
+ const p = new PtrArrayBuffer(s.length * 2);
12
+ const dv = new DataView(p);
13
+ for (let i = 0; i < s.length; i++)
14
+ dv.setUint16(i * 2, s.charCodeAt(i), true);
15
+ return p;
16
+ }
17
+ function fromWide(p, chars) {
18
+ const dv = new DataView(p);
19
+ let out = '';
20
+ for (let i = 0; i < chars; i++)
21
+ out += String.fromCharCode(dv.getUint16(i * 2, true));
22
+ return out;
23
+ }
24
+ export const suite = {
25
+ name: 'files',
26
+ run: (t) => {
27
+ t.section('GetTempPath + CreateDirectory');
28
+ const tmpW = WCHAR.alloc(260);
29
+ const tmpLen = GetTempPath(260, tmpW);
30
+ t.checkTrue(`temp path non-empty (${tmpLen})`, tmpLen > 0);
31
+ const dir = `${WCHAR.decode(tmpW)}QuickWinTest`; // GetTempPath 尾带反斜杠
32
+ // 目录可能残留自上次中断的 run:已存在(且是目录)则静默复用
33
+ if (CreateDirectory(dir, NULL) === 0 &&
34
+ (GetFileAttributes(dir) & FILE_ATTRIBUTE_DIRECTORY) === 0) {
35
+ t.checkTrue('CreateDirectory', false);
36
+ return;
37
+ }
38
+ const pathA = `${dir}\\a.txt`;
39
+ const pathB = `${dir}\\b.txt`;
40
+ const pathC = `${dir}\\c.txt`;
41
+ const pathCn = `${dir}\\中文文件.txt`;
42
+ t.section('CreateFile + WriteFile: write payload');
43
+ const hW = CreateFile(pathA, GENERIC_WRITE, 0, NULL, 2 /* gui.FileCreation.CREATE_ALWAYS */, 0x80 /* FILE_ATTRIBUTE_NORMAL */, NULL);
44
+ t.checkTrue(`write handle valid (${hW})`, hW !== -1); // 失败 = INVALID_HANDLE_VALUE(-1)
45
+ const payload = 'hello files';
46
+ const wData = toWide(payload);
47
+ const pWr = new PtrArrayBuffer(4);
48
+ t.checkTrue('WriteFile ok', WriteFile(hW, wData, payload.length * 2, pWr, NULL) !== 0);
49
+ t.check('bytes written', payload.length * 2, new DataView(pWr).getUint32(0, true));
50
+ t.checkTrue('CloseHandle (writer)', CloseHandle(hW) !== 0);
51
+ t.section('CreateFile(READ) + GetFileSize + SetFilePointer + ReadFile');
52
+ const hR = CreateFile(pathA, GENERIC_READ, 0, NULL, 3 /* gui.FileCreation.OPEN_EXISTING */, 0x80, NULL);
53
+ t.checkTrue(`read handle valid (${hR})`, hR !== -1);
54
+ t.check('GetFileSize', payload.length * 2, GetFileSize(hR, NULL));
55
+ t.check('SetFilePointer BEGIN → 0', 0, SetFilePointer(hR, 0, NULL, 0 /* gui.FileSeekFrom.BEGIN */));
56
+ const rData = new PtrArrayBuffer(payload.length * 2);
57
+ const pRd = new PtrArrayBuffer(4);
58
+ t.checkTrue('ReadFile ok', ReadFile(hR, rData, payload.length * 2, pRd, NULL) !== 0);
59
+ t.check('read roundtrip', payload, fromWide(rData, payload.length));
60
+ // seek 到 END-4 验证负偏移 + 读尾 4 字节
61
+ t.check('SetFilePointer END-4', payload.length * 2 - 4, SetFilePointer(hR, -4, NULL, 2 /* gui.FileSeekFrom.END */));
62
+ const rTail = new PtrArrayBuffer(8);
63
+ ReadFile(hR, rTail, 4, pRd, NULL);
64
+ t.check('seeked tail', payload.slice(-2), fromWide(rTail, 2));
65
+ CloseHandle(hR);
66
+ t.section('CopyFile + MoveFileEx + GetFileAttributes');
67
+ const hB = CreateFile(pathB, GENERIC_WRITE, 0, NULL, 2 /* gui.FileCreation.CREATE_ALWAYS */, 0x80, NULL);
68
+ const bData = toWide('bb');
69
+ WriteFile(hB, bData, 4, pWr, NULL);
70
+ CloseHandle(hB);
71
+ t.checkTrue('CopyFile ok', CopyFile(pathB, pathC, 0) !== 0);
72
+ const hC = CreateFile(pathC, GENERIC_READ, 0, NULL, 3 /* gui.FileCreation.OPEN_EXISTING */, 0x80, NULL);
73
+ t.check('copied size', 4, GetFileSize(hC, NULL));
74
+ t.checkTrue('CloseHandle (copy reader)', CloseHandle(hC) !== 0);
75
+ t.checkTrue('MoveFileEx replace ok', MoveFileEx(pathB, pathC, 0x1 /* MOVEFILE_REPLACE_EXISTING */) !== 0);
76
+ t.check('moved: source gone', INVALID32, GetFileAttributes(pathB));
77
+ t.checkTrue('dest is file (not dir)', (GetFileAttributes(pathC) & FILE_ATTRIBUTE_DIRECTORY) === 0);
78
+ t.section('FindFirstFile/FindNextFile: enumerate *.txt incl. CJK name');
79
+ const hCn = CreateFile(pathCn, GENERIC_WRITE, 0, NULL, 2 /* gui.FileCreation.CREATE_ALWAYS */, 0x80, NULL);
80
+ CloseHandle(hCn); // 0 字节中文名文件
81
+ const fd = WIN32_FIND_DATAW.alloc();
82
+ const hFind = FindFirstFile(`${dir}\\a.txt`, fd.ptr);
83
+ t.checkTrue(`FindFirstFile ok (${hFind})`, hFind !== -1);
84
+ t.check('found name', 'a.txt', WIN32_FIND_DATAW.decode(fd).cFileName);
85
+ t.checkTrue('FindNextFile exhausted = 0', FindNextFile(hFind, fd.ptr) === 0);
86
+ t.checkTrue('FindClose', FindClose(hFind) !== 0);
87
+ let count = 0;
88
+ const hEnum = FindFirstFile(`${dir}\\*.txt`, fd.ptr);
89
+ if (hEnum !== -1) {
90
+ count = 1;
91
+ while (FindNextFile(hEnum, fd.ptr) !== 0)
92
+ count++;
93
+ FindClose(hEnum);
94
+ }
95
+ t.check('enum *.txt count (a/c/CJK)', 3, count);
96
+ t.section('DeleteFile + RemoveDirectory: cleanup');
97
+ t.checkTrue('DeleteFile ×3', DeleteFile(pathA) !== 0 && DeleteFile(pathC) !== 0
98
+ && DeleteFile(pathCn) !== 0);
99
+ t.checkTrue('RemoveDirectory', RemoveDirectory(dir) !== 0);
100
+ t.check('dir gone', INVALID32, GetFileAttributes(dir));
101
+ },
102
+ };
@@ -0,0 +1,121 @@
1
+ import * as gui from 'gui'
2
+ import { WCHAR } from '../lib/ffi/bind.js'
3
+ import { NULL, PtrArrayBuffer } from '../lib/ffi/ctype.js'
4
+ import {
5
+ CloseHandle, CopyFile, CreateDirectory, CreateFile, DeleteFile,
6
+ FindClose, FindFirstFile, FindNextFile, GetFileAttributes, GetFileSize,
7
+ GetTempPath, MoveFileEx, ReadFile, RemoveDirectory, SetFilePointer, WriteFile,
8
+ } from '../lib/windows/kernel32.js'
9
+ import { WIN32_FIND_DATAW } from '../lib/windows/structs.js'
10
+ import { Tester } from './test_helper.js'
11
+
12
+ const GENERIC_READ = 0x80000000
13
+ const GENERIC_WRITE = 0x40000000
14
+ const FILE_ATTRIBUTE_DIRECTORY = 0x10
15
+ const INVALID32 = 0xffffffff
16
+
17
+ // ASCII payload ↔ UTF-16LE 缓冲互转(REG_SZ 同型,测试内联)
18
+ function toWide(s: string): PtrArrayBuffer<string> {
19
+ const p = new PtrArrayBuffer(s.length * 2)
20
+ const dv = new DataView(p)
21
+ for (let i = 0; i < s.length; i++) dv.setUint16(i * 2, s.charCodeAt(i), true)
22
+ return p
23
+ }
24
+ function fromWide(p: PtrArrayBuffer<string>, chars: number): string {
25
+ const dv = new DataView(p)
26
+ let out = ''
27
+ for (let i = 0; i < chars; i++) out += String.fromCharCode(dv.getUint16(i * 2, true))
28
+ return out
29
+ }
30
+
31
+ export const suite = {
32
+ name: 'files',
33
+ run: (t: Tester) => {
34
+ t.section('GetTempPath + CreateDirectory')
35
+ const tmpW = WCHAR.alloc(260)
36
+ const tmpLen = GetTempPath(260, tmpW)
37
+ t.checkTrue(`temp path non-empty (${tmpLen})`, tmpLen > 0)
38
+ const dir = `${WCHAR.decode(tmpW)}QuickWinTest` // GetTempPath 尾带反斜杠
39
+ // 目录可能残留自上次中断的 run:已存在(且是目录)则静默复用
40
+ if (CreateDirectory(dir, NULL) === 0 &&
41
+ (GetFileAttributes(dir) & FILE_ATTRIBUTE_DIRECTORY) === 0) {
42
+ t.checkTrue('CreateDirectory', false)
43
+ return
44
+ }
45
+ const pathA = `${dir}\\a.txt`
46
+ const pathB = `${dir}\\b.txt`
47
+ const pathC = `${dir}\\c.txt`
48
+ const pathCn = `${dir}\\中文文件.txt`
49
+
50
+ t.section('CreateFile + WriteFile: write payload')
51
+ const hW = CreateFile(pathA, GENERIC_WRITE, 0, NULL,
52
+ gui.FileCreation.CREATE_ALWAYS, 0x80 /* FILE_ATTRIBUTE_NORMAL */, NULL)
53
+ t.checkTrue(`write handle valid (${hW})`, hW !== -1) // 失败 = INVALID_HANDLE_VALUE(-1)
54
+ const payload = 'hello files'
55
+ const wData = toWide(payload)
56
+ const pWr = new PtrArrayBuffer(4)
57
+ t.checkTrue('WriteFile ok', WriteFile(hW, wData, payload.length * 2, pWr, NULL) !== 0)
58
+ t.check('bytes written', payload.length * 2, new DataView(pWr).getUint32(0, true))
59
+ t.checkTrue('CloseHandle (writer)', CloseHandle(hW) !== 0)
60
+
61
+ t.section('CreateFile(READ) + GetFileSize + SetFilePointer + ReadFile')
62
+ const hR = CreateFile(pathA, GENERIC_READ, 0, NULL,
63
+ gui.FileCreation.OPEN_EXISTING, 0x80, NULL)
64
+ t.checkTrue(`read handle valid (${hR})`, hR !== -1)
65
+ t.check('GetFileSize', payload.length * 2, GetFileSize(hR, NULL))
66
+ t.check('SetFilePointer BEGIN → 0', 0, SetFilePointer(hR, 0, NULL, gui.FileSeekFrom.BEGIN))
67
+ const rData = new PtrArrayBuffer(payload.length * 2)
68
+ const pRd = new PtrArrayBuffer(4)
69
+ t.checkTrue('ReadFile ok', ReadFile(hR, rData, payload.length * 2, pRd, NULL) !== 0)
70
+ t.check('read roundtrip', payload, fromWide(rData, payload.length))
71
+ // seek 到 END-4 验证负偏移 + 读尾 4 字节
72
+ t.check('SetFilePointer END-4', payload.length * 2 - 4,
73
+ SetFilePointer(hR, -4, NULL, gui.FileSeekFrom.END))
74
+ const rTail = new PtrArrayBuffer(8)
75
+ ReadFile(hR, rTail, 4, pRd, NULL)
76
+ t.check('seeked tail', payload.slice(-2), fromWide(rTail, 2))
77
+ CloseHandle(hR)
78
+
79
+ t.section('CopyFile + MoveFileEx + GetFileAttributes')
80
+ const hB = CreateFile(pathB, GENERIC_WRITE, 0, NULL,
81
+ gui.FileCreation.CREATE_ALWAYS, 0x80, NULL)
82
+ const bData = toWide('bb')
83
+ WriteFile(hB, bData, 4, pWr, NULL)
84
+ CloseHandle(hB)
85
+ t.checkTrue('CopyFile ok', CopyFile(pathB, pathC, 0) !== 0)
86
+ const hC = CreateFile(pathC, GENERIC_READ, 0, NULL,
87
+ gui.FileCreation.OPEN_EXISTING, 0x80, NULL)
88
+ t.check('copied size', 4, GetFileSize(hC, NULL))
89
+ t.checkTrue('CloseHandle (copy reader)', CloseHandle(hC) !== 0)
90
+ t.checkTrue('MoveFileEx replace ok',
91
+ MoveFileEx(pathB, pathC, 0x1 /* MOVEFILE_REPLACE_EXISTING */) !== 0)
92
+ t.check('moved: source gone', INVALID32, GetFileAttributes(pathB))
93
+ t.checkTrue('dest is file (not dir)',
94
+ (GetFileAttributes(pathC) & FILE_ATTRIBUTE_DIRECTORY) === 0)
95
+
96
+ t.section('FindFirstFile/FindNextFile: enumerate *.txt incl. CJK name')
97
+ const hCn = CreateFile(pathCn, GENERIC_WRITE, 0, NULL,
98
+ gui.FileCreation.CREATE_ALWAYS, 0x80, NULL)
99
+ CloseHandle(hCn) // 0 字节中文名文件
100
+ const fd = WIN32_FIND_DATAW.alloc()
101
+ const hFind = FindFirstFile(`${dir}\\a.txt`, fd.ptr)
102
+ t.checkTrue(`FindFirstFile ok (${hFind})`, hFind !== -1)
103
+ t.check('found name', 'a.txt', WIN32_FIND_DATAW.decode(fd).cFileName)
104
+ t.checkTrue('FindNextFile exhausted = 0', FindNextFile(hFind, fd.ptr) === 0)
105
+ t.checkTrue('FindClose', FindClose(hFind) !== 0)
106
+ let count = 0
107
+ const hEnum = FindFirstFile(`${dir}\\*.txt`, fd.ptr)
108
+ if (hEnum !== -1) {
109
+ count = 1
110
+ while (FindNextFile(hEnum, fd.ptr) !== 0) count++
111
+ FindClose(hEnum)
112
+ }
113
+ t.check('enum *.txt count (a/c/CJK)', 3, count)
114
+
115
+ t.section('DeleteFile + RemoveDirectory: cleanup')
116
+ t.checkTrue('DeleteFile ×3', DeleteFile(pathA) !== 0 && DeleteFile(pathC) !== 0
117
+ && DeleteFile(pathCn) !== 0)
118
+ t.checkTrue('RemoveDirectory', RemoveDirectory(dir) !== 0)
119
+ t.check('dir gone', INVALID32, GetFileAttributes(dir))
120
+ },
121
+ }