├── .gitignore
├── AntiWindowSnap.png
├── Cargo.lock
├── Cargo.toml
├── Icon18.ico
├── Icon19.ico
├── LICENSE
├── README.md
├── build.rs
├── cursor20.cur
├── resource.rc
└── src
├── helper.rs
├── lib.rs
└── main.rs
/.gitignore:
--------------------------------------------------------------------------------
1 | /target
2 | .vscode/settings.json
3 | config2.txt
4 | config.txt
5 |
--------------------------------------------------------------------------------
/AntiWindowSnap.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/pkptzx/AntiWindowSnap/c91fa8eee77f12072e3624a1b86463cb864d63ce/AntiWindowSnap.png
--------------------------------------------------------------------------------
/Cargo.lock:
--------------------------------------------------------------------------------
1 | # This file is automatically @generated by Cargo.
2 | # It is not intended for manual editing.
3 | version = 3
4 |
5 | [[package]]
6 | name = "AntiWindowSnap"
7 | version = "1.3.0"
8 | dependencies = [
9 | "dashmap",
10 | "embed-resource",
11 | "fltk",
12 | "image",
13 | "once_cell",
14 | "scopeguard",
15 | "windows",
16 | ]
17 |
18 | [[package]]
19 | name = "adler"
20 | version = "1.0.2"
21 | source = "registry+https://github.com/rust-lang/crates.io-index"
22 | checksum = "f26201604c87b1e01bd3d98f8d5d9a8fcbb815e8cedb41ffccbeb4bf593a35fe"
23 |
24 | [[package]]
25 | name = "aligned-vec"
26 | version = "0.5.0"
27 | source = "registry+https://github.com/rust-lang/crates.io-index"
28 | checksum = "4aa90d7ce82d4be67b64039a3d588d38dbcc6736577de4a847025ce5b0c468d1"
29 |
30 | [[package]]
31 | name = "anyhow"
32 | version = "1.0.86"
33 | source = "registry+https://github.com/rust-lang/crates.io-index"
34 | checksum = "b3d1d046238990b9cf5bcde22a3fb3584ee5cf65fb2765f454ed428c7a0063da"
35 |
36 | [[package]]
37 | name = "arbitrary"
38 | version = "1.3.2"
39 | source = "registry+https://github.com/rust-lang/crates.io-index"
40 | checksum = "7d5a26814d8dcb93b0e5a0ff3c6d80a8843bafb21b39e8e18a6f05471870e110"
41 |
42 | [[package]]
43 | name = "arg_enum_proc_macro"
44 | version = "0.3.4"
45 | source = "registry+https://github.com/rust-lang/crates.io-index"
46 | checksum = "0ae92a5119aa49cdbcf6b9f893fe4e1d98b04ccbf82ee0584ad948a44a734dea"
47 | dependencies = [
48 | "proc-macro2",
49 | "quote",
50 | "syn",
51 | ]
52 |
53 | [[package]]
54 | name = "arrayvec"
55 | version = "0.7.4"
56 | source = "registry+https://github.com/rust-lang/crates.io-index"
57 | checksum = "96d30a06541fbafbc7f82ed10c06164cfbd2c401138f6addd8404629c4b16711"
58 |
59 | [[package]]
60 | name = "autocfg"
61 | version = "1.3.0"
62 | source = "registry+https://github.com/rust-lang/crates.io-index"
63 | checksum = "0c4b4d0bd25bd0b74681c0ad21497610ce1b7c91b1022cd21c80c6fbdd9476b0"
64 |
65 | [[package]]
66 | name = "av1-grain"
67 | version = "0.2.3"
68 | source = "registry+https://github.com/rust-lang/crates.io-index"
69 | checksum = "6678909d8c5d46a42abcf571271e15fdbc0a225e3646cf23762cd415046c78bf"
70 | dependencies = [
71 | "anyhow",
72 | "arrayvec",
73 | "log",
74 | "nom",
75 | "num-rational",
76 | "v_frame",
77 | ]
78 |
79 | [[package]]
80 | name = "avif-serialize"
81 | version = "0.8.1"
82 | source = "registry+https://github.com/rust-lang/crates.io-index"
83 | checksum = "876c75a42f6364451a033496a14c44bffe41f5f4a8236f697391f11024e596d2"
84 | dependencies = [
85 | "arrayvec",
86 | ]
87 |
88 | [[package]]
89 | name = "bit_field"
90 | version = "0.10.2"
91 | source = "registry+https://github.com/rust-lang/crates.io-index"
92 | checksum = "dc827186963e592360843fb5ba4b973e145841266c1357f7180c43526f2e5b61"
93 |
94 | [[package]]
95 | name = "bitflags"
96 | version = "1.3.2"
97 | source = "registry+https://github.com/rust-lang/crates.io-index"
98 | checksum = "bef38d45163c2f1dde094a7dfd33ccf595c92905c8f8f4fdc18d06fb1037718a"
99 |
100 | [[package]]
101 | name = "bitflags"
102 | version = "2.6.0"
103 | source = "registry+https://github.com/rust-lang/crates.io-index"
104 | checksum = "b048fb63fd8b5923fc5aa7b340d8e156aec7ec02f0c78fa8a6ddc2613f6f71de"
105 |
106 | [[package]]
107 | name = "bitstream-io"
108 | version = "2.5.0"
109 | source = "registry+https://github.com/rust-lang/crates.io-index"
110 | checksum = "3dcde5f311c85b8ca30c2e4198d4326bc342c76541590106f5fa4a50946ea499"
111 |
112 | [[package]]
113 | name = "built"
114 | version = "0.7.4"
115 | source = "registry+https://github.com/rust-lang/crates.io-index"
116 | checksum = "236e6289eda5a812bc6b53c3b024039382a2895fbbeef2d748b2931546d392c4"
117 |
118 | [[package]]
119 | name = "bumpalo"
120 | version = "3.16.0"
121 | source = "registry+https://github.com/rust-lang/crates.io-index"
122 | checksum = "79296716171880943b8470b5f8d03aa55eb2e645a4874bdbb28adb49162e012c"
123 |
124 | [[package]]
125 | name = "bytemuck"
126 | version = "1.16.1"
127 | source = "registry+https://github.com/rust-lang/crates.io-index"
128 | checksum = "b236fc92302c97ed75b38da1f4917b5cdda4984745740f153a5d3059e48d725e"
129 |
130 | [[package]]
131 | name = "byteorder"
132 | version = "1.5.0"
133 | source = "registry+https://github.com/rust-lang/crates.io-index"
134 | checksum = "1fd0f2584146f6f2ef48085050886acf353beff7305ebd1ae69500e27c67f64b"
135 |
136 | [[package]]
137 | name = "byteorder-lite"
138 | version = "0.1.0"
139 | source = "registry+https://github.com/rust-lang/crates.io-index"
140 | checksum = "8f1fe948ff07f4bd06c30984e69f5b4899c516a3ef74f34df92a2df2ab535495"
141 |
142 | [[package]]
143 | name = "cc"
144 | version = "1.1.0"
145 | source = "registry+https://github.com/rust-lang/crates.io-index"
146 | checksum = "eaff6f8ce506b9773fa786672d63fc7a191ffea1be33f72bbd4aeacefca9ffc8"
147 | dependencies = [
148 | "jobserver",
149 | "libc",
150 | "once_cell",
151 | ]
152 |
153 | [[package]]
154 | name = "cfg-expr"
155 | version = "0.15.8"
156 | source = "registry+https://github.com/rust-lang/crates.io-index"
157 | checksum = "d067ad48b8650848b989a59a86c6c36a995d02d2bf778d45c3c5d57bc2718f02"
158 | dependencies = [
159 | "smallvec",
160 | "target-lexicon",
161 | ]
162 |
163 | [[package]]
164 | name = "cfg-if"
165 | version = "1.0.0"
166 | source = "registry+https://github.com/rust-lang/crates.io-index"
167 | checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd"
168 |
169 | [[package]]
170 | name = "cmake"
171 | version = "0.1.50"
172 | source = "registry+https://github.com/rust-lang/crates.io-index"
173 | checksum = "a31c789563b815f77f4250caee12365734369f942439b7defd71e18a48197130"
174 | dependencies = [
175 | "cc",
176 | ]
177 |
178 | [[package]]
179 | name = "color_quant"
180 | version = "1.1.0"
181 | source = "registry+https://github.com/rust-lang/crates.io-index"
182 | checksum = "3d7b894f5411737b7867f4827955924d7c254fc9f4d91a6aad6b097804b1018b"
183 |
184 | [[package]]
185 | name = "crc32fast"
186 | version = "1.4.2"
187 | source = "registry+https://github.com/rust-lang/crates.io-index"
188 | checksum = "a97769d94ddab943e4510d138150169a2758b5ef3eb191a9ee688de3e23ef7b3"
189 | dependencies = [
190 | "cfg-if",
191 | ]
192 |
193 | [[package]]
194 | name = "crossbeam-channel"
195 | version = "0.5.13"
196 | source = "registry+https://github.com/rust-lang/crates.io-index"
197 | checksum = "33480d6946193aa8033910124896ca395333cae7e2d1113d1fef6c3272217df2"
198 | dependencies = [
199 | "crossbeam-utils",
200 | ]
201 |
202 | [[package]]
203 | name = "crossbeam-deque"
204 | version = "0.8.5"
205 | source = "registry+https://github.com/rust-lang/crates.io-index"
206 | checksum = "613f8cc01fe9cf1a3eb3d7f488fd2fa8388403e97039e2f73692932e291a770d"
207 | dependencies = [
208 | "crossbeam-epoch",
209 | "crossbeam-utils",
210 | ]
211 |
212 | [[package]]
213 | name = "crossbeam-epoch"
214 | version = "0.9.18"
215 | source = "registry+https://github.com/rust-lang/crates.io-index"
216 | checksum = "5b82ac4a3c2ca9c3460964f020e1402edd5753411d7737aa39c3714ad1b5420e"
217 | dependencies = [
218 | "crossbeam-utils",
219 | ]
220 |
221 | [[package]]
222 | name = "crossbeam-utils"
223 | version = "0.8.20"
224 | source = "registry+https://github.com/rust-lang/crates.io-index"
225 | checksum = "22ec99545bb0ed0ea7bb9b8e1e9122ea386ff8a48c0922e43f36d45ab09e0e80"
226 |
227 | [[package]]
228 | name = "crunchy"
229 | version = "0.2.2"
230 | source = "registry+https://github.com/rust-lang/crates.io-index"
231 | checksum = "7a81dae078cea95a014a339291cec439d2f232ebe854a9d672b796c6afafa9b7"
232 |
233 | [[package]]
234 | name = "dashmap"
235 | version = "6.0.1"
236 | source = "registry+https://github.com/rust-lang/crates.io-index"
237 | checksum = "804c8821570c3f8b70230c2ba75ffa5c0f9a4189b9a432b6656c536712acae28"
238 | dependencies = [
239 | "cfg-if",
240 | "crossbeam-utils",
241 | "hashbrown",
242 | "lock_api",
243 | "once_cell",
244 | "parking_lot_core",
245 | ]
246 |
247 | [[package]]
248 | name = "either"
249 | version = "1.13.0"
250 | source = "registry+https://github.com/rust-lang/crates.io-index"
251 | checksum = "60b1af1c220855b6ceac025d3f6ecdd2b7c4894bfe9cd9bda4fbb4bc7c0d4cf0"
252 |
253 | [[package]]
254 | name = "embed-resource"
255 | version = "2.4.2"
256 | source = "registry+https://github.com/rust-lang/crates.io-index"
257 | checksum = "c6985554d0688b687c5cb73898a34fbe3ad6c24c58c238a4d91d5e840670ee9d"
258 | dependencies = [
259 | "cc",
260 | "memchr",
261 | "rustc_version",
262 | "toml",
263 | "vswhom",
264 | "winreg",
265 | ]
266 |
267 | [[package]]
268 | name = "equivalent"
269 | version = "1.0.1"
270 | source = "registry+https://github.com/rust-lang/crates.io-index"
271 | checksum = "5443807d6dff69373d433ab9ef5378ad8df50ca6298caf15de6e52e24aaf54d5"
272 |
273 | [[package]]
274 | name = "exr"
275 | version = "1.72.0"
276 | source = "registry+https://github.com/rust-lang/crates.io-index"
277 | checksum = "887d93f60543e9a9362ef8a21beedd0a833c5d9610e18c67abe15a5963dcb1a4"
278 | dependencies = [
279 | "bit_field",
280 | "flume",
281 | "half",
282 | "lebe",
283 | "miniz_oxide",
284 | "rayon-core",
285 | "smallvec",
286 | "zune-inflate",
287 | ]
288 |
289 | [[package]]
290 | name = "fdeflate"
291 | version = "0.3.4"
292 | source = "registry+https://github.com/rust-lang/crates.io-index"
293 | checksum = "4f9bfee30e4dedf0ab8b422f03af778d9612b63f502710fc500a334ebe2de645"
294 | dependencies = [
295 | "simd-adler32",
296 | ]
297 |
298 | [[package]]
299 | name = "flate2"
300 | version = "1.0.30"
301 | source = "registry+https://github.com/rust-lang/crates.io-index"
302 | checksum = "5f54427cfd1c7829e2a139fcefea601bf088ebca651d2bf53ebc600eac295dae"
303 | dependencies = [
304 | "crc32fast",
305 | "miniz_oxide",
306 | ]
307 |
308 | [[package]]
309 | name = "fltk"
310 | version = "1.4.32"
311 | source = "registry+https://github.com/rust-lang/crates.io-index"
312 | checksum = "e13e98701200fb73f4fac8f07a73cb2adcb4758599727e5d758ec3961e4b54d1"
313 | dependencies = [
314 | "bitflags 2.6.0",
315 | "crossbeam-channel",
316 | "fltk-sys",
317 | "once_cell",
318 | "paste",
319 | "ttf-parser",
320 | ]
321 |
322 | [[package]]
323 | name = "fltk-sys"
324 | version = "1.4.32"
325 | source = "registry+https://github.com/rust-lang/crates.io-index"
326 | checksum = "28e102f461c6701a1fdb745421693ad68fe19ad80734ad4d5941d9325207bd13"
327 | dependencies = [
328 | "cmake",
329 | ]
330 |
331 | [[package]]
332 | name = "flume"
333 | version = "0.11.0"
334 | source = "registry+https://github.com/rust-lang/crates.io-index"
335 | checksum = "55ac459de2512911e4b674ce33cf20befaba382d05b62b008afc1c8b57cbf181"
336 | dependencies = [
337 | "spin",
338 | ]
339 |
340 | [[package]]
341 | name = "getrandom"
342 | version = "0.2.15"
343 | source = "registry+https://github.com/rust-lang/crates.io-index"
344 | checksum = "c4567c8db10ae91089c99af84c68c38da3ec2f087c3f82960bcdbf3656b6f4d7"
345 | dependencies = [
346 | "cfg-if",
347 | "libc",
348 | "wasi",
349 | ]
350 |
351 | [[package]]
352 | name = "gif"
353 | version = "0.13.1"
354 | source = "registry+https://github.com/rust-lang/crates.io-index"
355 | checksum = "3fb2d69b19215e18bb912fa30f7ce15846e301408695e44e0ef719f1da9e19f2"
356 | dependencies = [
357 | "color_quant",
358 | "weezl",
359 | ]
360 |
361 | [[package]]
362 | name = "half"
363 | version = "2.4.1"
364 | source = "registry+https://github.com/rust-lang/crates.io-index"
365 | checksum = "6dd08c532ae367adf81c312a4580bc67f1d0fe8bc9c460520283f4c0ff277888"
366 | dependencies = [
367 | "cfg-if",
368 | "crunchy",
369 | ]
370 |
371 | [[package]]
372 | name = "hashbrown"
373 | version = "0.14.5"
374 | source = "registry+https://github.com/rust-lang/crates.io-index"
375 | checksum = "e5274423e17b7c9fc20b6e7e208532f9b19825d82dfd615708b70edd83df41f1"
376 |
377 | [[package]]
378 | name = "heck"
379 | version = "0.5.0"
380 | source = "registry+https://github.com/rust-lang/crates.io-index"
381 | checksum = "2304e00983f87ffb38b55b444b5e3b60a884b5d30c0fca7d82fe33449bbe55ea"
382 |
383 | [[package]]
384 | name = "image"
385 | version = "0.25.1"
386 | source = "registry+https://github.com/rust-lang/crates.io-index"
387 | checksum = "fd54d660e773627692c524beaad361aca785a4f9f5730ce91f42aabe5bce3d11"
388 | dependencies = [
389 | "bytemuck",
390 | "byteorder",
391 | "color_quant",
392 | "exr",
393 | "gif",
394 | "image-webp",
395 | "num-traits",
396 | "png",
397 | "qoi",
398 | "ravif",
399 | "rayon",
400 | "rgb",
401 | "tiff",
402 | "zune-core",
403 | "zune-jpeg",
404 | ]
405 |
406 | [[package]]
407 | name = "image-webp"
408 | version = "0.1.2"
409 | source = "registry+https://github.com/rust-lang/crates.io-index"
410 | checksum = "d730b085583c4d789dfd07fdcf185be59501666a90c97c40162b37e4fdad272d"
411 | dependencies = [
412 | "byteorder-lite",
413 | "thiserror",
414 | ]
415 |
416 | [[package]]
417 | name = "imgref"
418 | version = "1.10.1"
419 | source = "registry+https://github.com/rust-lang/crates.io-index"
420 | checksum = "44feda355f4159a7c757171a77de25daf6411e217b4cabd03bd6650690468126"
421 |
422 | [[package]]
423 | name = "indexmap"
424 | version = "2.2.6"
425 | source = "registry+https://github.com/rust-lang/crates.io-index"
426 | checksum = "168fb715dda47215e360912c096649d23d58bf392ac62f73919e831745e40f26"
427 | dependencies = [
428 | "equivalent",
429 | "hashbrown",
430 | ]
431 |
432 | [[package]]
433 | name = "interpolate_name"
434 | version = "0.2.4"
435 | source = "registry+https://github.com/rust-lang/crates.io-index"
436 | checksum = "c34819042dc3d3971c46c2190835914dfbe0c3c13f61449b2997f4e9722dfa60"
437 | dependencies = [
438 | "proc-macro2",
439 | "quote",
440 | "syn",
441 | ]
442 |
443 | [[package]]
444 | name = "itertools"
445 | version = "0.12.1"
446 | source = "registry+https://github.com/rust-lang/crates.io-index"
447 | checksum = "ba291022dbbd398a455acf126c1e341954079855bc60dfdda641363bd6922569"
448 | dependencies = [
449 | "either",
450 | ]
451 |
452 | [[package]]
453 | name = "jobserver"
454 | version = "0.1.31"
455 | source = "registry+https://github.com/rust-lang/crates.io-index"
456 | checksum = "d2b099aaa34a9751c5bf0878add70444e1ed2dd73f347be99003d4577277de6e"
457 | dependencies = [
458 | "libc",
459 | ]
460 |
461 | [[package]]
462 | name = "jpeg-decoder"
463 | version = "0.3.1"
464 | source = "registry+https://github.com/rust-lang/crates.io-index"
465 | checksum = "f5d4a7da358eff58addd2877a45865158f0d78c911d43a5784ceb7bbf52833b0"
466 |
467 | [[package]]
468 | name = "lebe"
469 | version = "0.5.2"
470 | source = "registry+https://github.com/rust-lang/crates.io-index"
471 | checksum = "03087c2bad5e1034e8cace5926dec053fb3790248370865f5117a7d0213354c8"
472 |
473 | [[package]]
474 | name = "libc"
475 | version = "0.2.155"
476 | source = "registry+https://github.com/rust-lang/crates.io-index"
477 | checksum = "97b3888a4aecf77e811145cadf6eef5901f4782c53886191b2f693f24761847c"
478 |
479 | [[package]]
480 | name = "libfuzzer-sys"
481 | version = "0.4.7"
482 | source = "registry+https://github.com/rust-lang/crates.io-index"
483 | checksum = "a96cfd5557eb82f2b83fed4955246c988d331975a002961b07c81584d107e7f7"
484 | dependencies = [
485 | "arbitrary",
486 | "cc",
487 | "once_cell",
488 | ]
489 |
490 | [[package]]
491 | name = "lock_api"
492 | version = "0.4.12"
493 | source = "registry+https://github.com/rust-lang/crates.io-index"
494 | checksum = "07af8b9cdd281b7915f413fa73f29ebd5d55d0d3f0155584dade1ff18cea1b17"
495 | dependencies = [
496 | "autocfg",
497 | "scopeguard",
498 | ]
499 |
500 | [[package]]
501 | name = "log"
502 | version = "0.4.22"
503 | source = "registry+https://github.com/rust-lang/crates.io-index"
504 | checksum = "a7a70ba024b9dc04c27ea2f0c0548feb474ec5c54bba33a7f72f873a39d07b24"
505 |
506 | [[package]]
507 | name = "loop9"
508 | version = "0.1.5"
509 | source = "registry+https://github.com/rust-lang/crates.io-index"
510 | checksum = "0fae87c125b03c1d2c0150c90365d7d6bcc53fb73a9acaef207d2d065860f062"
511 | dependencies = [
512 | "imgref",
513 | ]
514 |
515 | [[package]]
516 | name = "maybe-rayon"
517 | version = "0.1.1"
518 | source = "registry+https://github.com/rust-lang/crates.io-index"
519 | checksum = "8ea1f30cedd69f0a2954655f7188c6a834246d2bcf1e315e2ac40c4b24dc9519"
520 | dependencies = [
521 | "cfg-if",
522 | "rayon",
523 | ]
524 |
525 | [[package]]
526 | name = "memchr"
527 | version = "2.7.4"
528 | source = "registry+https://github.com/rust-lang/crates.io-index"
529 | checksum = "78ca9ab1a0babb1e7d5695e3530886289c18cf2f87ec19a575a0abdce112e3a3"
530 |
531 | [[package]]
532 | name = "minimal-lexical"
533 | version = "0.2.1"
534 | source = "registry+https://github.com/rust-lang/crates.io-index"
535 | checksum = "68354c5c6bd36d73ff3feceb05efa59b6acb7626617f4962be322a825e61f79a"
536 |
537 | [[package]]
538 | name = "miniz_oxide"
539 | version = "0.7.4"
540 | source = "registry+https://github.com/rust-lang/crates.io-index"
541 | checksum = "b8a240ddb74feaf34a79a7add65a741f3167852fba007066dcac1ca548d89c08"
542 | dependencies = [
543 | "adler",
544 | "simd-adler32",
545 | ]
546 |
547 | [[package]]
548 | name = "new_debug_unreachable"
549 | version = "1.0.6"
550 | source = "registry+https://github.com/rust-lang/crates.io-index"
551 | checksum = "650eef8c711430f1a879fdd01d4745a7deea475becfb90269c06775983bbf086"
552 |
553 | [[package]]
554 | name = "nom"
555 | version = "7.1.3"
556 | source = "registry+https://github.com/rust-lang/crates.io-index"
557 | checksum = "d273983c5a657a70a3e8f2a01329822f3b8c8172b73826411a55751e404a0a4a"
558 | dependencies = [
559 | "memchr",
560 | "minimal-lexical",
561 | ]
562 |
563 | [[package]]
564 | name = "noop_proc_macro"
565 | version = "0.3.0"
566 | source = "registry+https://github.com/rust-lang/crates.io-index"
567 | checksum = "0676bb32a98c1a483ce53e500a81ad9c3d5b3f7c920c28c24e9cb0980d0b5bc8"
568 |
569 | [[package]]
570 | name = "num-bigint"
571 | version = "0.4.6"
572 | source = "registry+https://github.com/rust-lang/crates.io-index"
573 | checksum = "a5e44f723f1133c9deac646763579fdb3ac745e418f2a7af9cd0c431da1f20b9"
574 | dependencies = [
575 | "num-integer",
576 | "num-traits",
577 | ]
578 |
579 | [[package]]
580 | name = "num-derive"
581 | version = "0.4.2"
582 | source = "registry+https://github.com/rust-lang/crates.io-index"
583 | checksum = "ed3955f1a9c7c0c15e092f9c887db08b1fc683305fdf6eb6684f22555355e202"
584 | dependencies = [
585 | "proc-macro2",
586 | "quote",
587 | "syn",
588 | ]
589 |
590 | [[package]]
591 | name = "num-integer"
592 | version = "0.1.46"
593 | source = "registry+https://github.com/rust-lang/crates.io-index"
594 | checksum = "7969661fd2958a5cb096e56c8e1ad0444ac2bbcd0061bd28660485a44879858f"
595 | dependencies = [
596 | "num-traits",
597 | ]
598 |
599 | [[package]]
600 | name = "num-rational"
601 | version = "0.4.2"
602 | source = "registry+https://github.com/rust-lang/crates.io-index"
603 | checksum = "f83d14da390562dca69fc84082e73e548e1ad308d24accdedd2720017cb37824"
604 | dependencies = [
605 | "num-bigint",
606 | "num-integer",
607 | "num-traits",
608 | ]
609 |
610 | [[package]]
611 | name = "num-traits"
612 | version = "0.2.19"
613 | source = "registry+https://github.com/rust-lang/crates.io-index"
614 | checksum = "071dfc062690e90b734c0b2273ce72ad0ffa95f0c74596bc250dcfd960262841"
615 | dependencies = [
616 | "autocfg",
617 | ]
618 |
619 | [[package]]
620 | name = "once_cell"
621 | version = "1.19.0"
622 | source = "registry+https://github.com/rust-lang/crates.io-index"
623 | checksum = "3fdb12b2476b595f9358c5161aa467c2438859caa136dec86c26fdd2efe17b92"
624 |
625 | [[package]]
626 | name = "parking_lot_core"
627 | version = "0.9.10"
628 | source = "registry+https://github.com/rust-lang/crates.io-index"
629 | checksum = "1e401f977ab385c9e4e3ab30627d6f26d00e2c73eef317493c4ec6d468726cf8"
630 | dependencies = [
631 | "cfg-if",
632 | "libc",
633 | "redox_syscall",
634 | "smallvec",
635 | "windows-targets 0.52.6",
636 | ]
637 |
638 | [[package]]
639 | name = "paste"
640 | version = "1.0.15"
641 | source = "registry+https://github.com/rust-lang/crates.io-index"
642 | checksum = "57c0d7b74b563b49d38dae00a0c37d4d6de9b432382b2892f0574ddcae73fd0a"
643 |
644 | [[package]]
645 | name = "pkg-config"
646 | version = "0.3.30"
647 | source = "registry+https://github.com/rust-lang/crates.io-index"
648 | checksum = "d231b230927b5e4ad203db57bbcbee2802f6bce620b1e4a9024a07d94e2907ec"
649 |
650 | [[package]]
651 | name = "png"
652 | version = "0.17.13"
653 | source = "registry+https://github.com/rust-lang/crates.io-index"
654 | checksum = "06e4b0d3d1312775e782c86c91a111aa1f910cbb65e1337f9975b5f9a554b5e1"
655 | dependencies = [
656 | "bitflags 1.3.2",
657 | "crc32fast",
658 | "fdeflate",
659 | "flate2",
660 | "miniz_oxide",
661 | ]
662 |
663 | [[package]]
664 | name = "ppv-lite86"
665 | version = "0.2.17"
666 | source = "registry+https://github.com/rust-lang/crates.io-index"
667 | checksum = "5b40af805b3121feab8a3c29f04d8ad262fa8e0561883e7653e024ae4479e6de"
668 |
669 | [[package]]
670 | name = "proc-macro2"
671 | version = "1.0.86"
672 | source = "registry+https://github.com/rust-lang/crates.io-index"
673 | checksum = "5e719e8df665df0d1c8fbfd238015744736151d4445ec0836b8e628aae103b77"
674 | dependencies = [
675 | "unicode-ident",
676 | ]
677 |
678 | [[package]]
679 | name = "profiling"
680 | version = "1.0.15"
681 | source = "registry+https://github.com/rust-lang/crates.io-index"
682 | checksum = "43d84d1d7a6ac92673717f9f6d1518374ef257669c24ebc5ac25d5033828be58"
683 | dependencies = [
684 | "profiling-procmacros",
685 | ]
686 |
687 | [[package]]
688 | name = "profiling-procmacros"
689 | version = "1.0.15"
690 | source = "registry+https://github.com/rust-lang/crates.io-index"
691 | checksum = "8021cf59c8ec9c432cfc2526ac6b8aa508ecaf29cd415f271b8406c1b851c3fd"
692 | dependencies = [
693 | "quote",
694 | "syn",
695 | ]
696 |
697 | [[package]]
698 | name = "qoi"
699 | version = "0.4.1"
700 | source = "registry+https://github.com/rust-lang/crates.io-index"
701 | checksum = "7f6d64c71eb498fe9eae14ce4ec935c555749aef511cca85b5568910d6e48001"
702 | dependencies = [
703 | "bytemuck",
704 | ]
705 |
706 | [[package]]
707 | name = "quick-error"
708 | version = "2.0.1"
709 | source = "registry+https://github.com/rust-lang/crates.io-index"
710 | checksum = "a993555f31e5a609f617c12db6250dedcac1b0a85076912c436e6fc9b2c8e6a3"
711 |
712 | [[package]]
713 | name = "quote"
714 | version = "1.0.36"
715 | source = "registry+https://github.com/rust-lang/crates.io-index"
716 | checksum = "0fa76aaf39101c457836aec0ce2316dbdc3ab723cdda1c6bd4e6ad4208acaca7"
717 | dependencies = [
718 | "proc-macro2",
719 | ]
720 |
721 | [[package]]
722 | name = "rand"
723 | version = "0.8.5"
724 | source = "registry+https://github.com/rust-lang/crates.io-index"
725 | checksum = "34af8d1a0e25924bc5b7c43c079c942339d8f0a8b57c39049bef581b46327404"
726 | dependencies = [
727 | "libc",
728 | "rand_chacha",
729 | "rand_core",
730 | ]
731 |
732 | [[package]]
733 | name = "rand_chacha"
734 | version = "0.3.1"
735 | source = "registry+https://github.com/rust-lang/crates.io-index"
736 | checksum = "e6c10a63a0fa32252be49d21e7709d4d4baf8d231c2dbce1eaa8141b9b127d88"
737 | dependencies = [
738 | "ppv-lite86",
739 | "rand_core",
740 | ]
741 |
742 | [[package]]
743 | name = "rand_core"
744 | version = "0.6.4"
745 | source = "registry+https://github.com/rust-lang/crates.io-index"
746 | checksum = "ec0be4795e2f6a28069bec0b5ff3e2ac9bafc99e6a9a7dc3547996c5c816922c"
747 | dependencies = [
748 | "getrandom",
749 | ]
750 |
751 | [[package]]
752 | name = "rav1e"
753 | version = "0.7.1"
754 | source = "registry+https://github.com/rust-lang/crates.io-index"
755 | checksum = "cd87ce80a7665b1cce111f8a16c1f3929f6547ce91ade6addf4ec86a8dda5ce9"
756 | dependencies = [
757 | "arbitrary",
758 | "arg_enum_proc_macro",
759 | "arrayvec",
760 | "av1-grain",
761 | "bitstream-io",
762 | "built",
763 | "cfg-if",
764 | "interpolate_name",
765 | "itertools",
766 | "libc",
767 | "libfuzzer-sys",
768 | "log",
769 | "maybe-rayon",
770 | "new_debug_unreachable",
771 | "noop_proc_macro",
772 | "num-derive",
773 | "num-traits",
774 | "once_cell",
775 | "paste",
776 | "profiling",
777 | "rand",
778 | "rand_chacha",
779 | "simd_helpers",
780 | "system-deps",
781 | "thiserror",
782 | "v_frame",
783 | "wasm-bindgen",
784 | ]
785 |
786 | [[package]]
787 | name = "ravif"
788 | version = "0.11.8"
789 | source = "registry+https://github.com/rust-lang/crates.io-index"
790 | checksum = "c6ba61c28ba24c0cf8406e025cb29a742637e3f70776e61c27a8a8b72a042d12"
791 | dependencies = [
792 | "avif-serialize",
793 | "imgref",
794 | "loop9",
795 | "quick-error",
796 | "rav1e",
797 | "rayon",
798 | "rgb",
799 | ]
800 |
801 | [[package]]
802 | name = "rayon"
803 | version = "1.10.0"
804 | source = "registry+https://github.com/rust-lang/crates.io-index"
805 | checksum = "b418a60154510ca1a002a752ca9714984e21e4241e804d32555251faf8b78ffa"
806 | dependencies = [
807 | "either",
808 | "rayon-core",
809 | ]
810 |
811 | [[package]]
812 | name = "rayon-core"
813 | version = "1.12.1"
814 | source = "registry+https://github.com/rust-lang/crates.io-index"
815 | checksum = "1465873a3dfdaa8ae7cb14b4383657caab0b3e8a0aa9ae8e04b044854c8dfce2"
816 | dependencies = [
817 | "crossbeam-deque",
818 | "crossbeam-utils",
819 | ]
820 |
821 | [[package]]
822 | name = "redox_syscall"
823 | version = "0.5.2"
824 | source = "registry+https://github.com/rust-lang/crates.io-index"
825 | checksum = "c82cf8cff14456045f55ec4241383baeff27af886adb72ffb2162f99911de0fd"
826 | dependencies = [
827 | "bitflags 2.6.0",
828 | ]
829 |
830 | [[package]]
831 | name = "rgb"
832 | version = "0.8.44"
833 | source = "registry+https://github.com/rust-lang/crates.io-index"
834 | checksum = "1aee83dc281d5a3200d37b299acd13b81066ea126a7f16f0eae70fc9aed241d9"
835 | dependencies = [
836 | "bytemuck",
837 | ]
838 |
839 | [[package]]
840 | name = "rustc_version"
841 | version = "0.4.0"
842 | source = "registry+https://github.com/rust-lang/crates.io-index"
843 | checksum = "bfa0f585226d2e68097d4f95d113b15b83a82e819ab25717ec0590d9584ef366"
844 | dependencies = [
845 | "semver",
846 | ]
847 |
848 | [[package]]
849 | name = "scopeguard"
850 | version = "1.2.0"
851 | source = "registry+https://github.com/rust-lang/crates.io-index"
852 | checksum = "94143f37725109f92c262ed2cf5e59bce7498c01bcc1502d7b9afe439a4e9f49"
853 |
854 | [[package]]
855 | name = "semver"
856 | version = "1.0.23"
857 | source = "registry+https://github.com/rust-lang/crates.io-index"
858 | checksum = "61697e0a1c7e512e84a621326239844a24d8207b4669b41bc18b32ea5cbf988b"
859 |
860 | [[package]]
861 | name = "serde"
862 | version = "1.0.204"
863 | source = "registry+https://github.com/rust-lang/crates.io-index"
864 | checksum = "bc76f558e0cbb2a839d37354c575f1dc3fdc6546b5be373ba43d95f231bf7c12"
865 | dependencies = [
866 | "serde_derive",
867 | ]
868 |
869 | [[package]]
870 | name = "serde_derive"
871 | version = "1.0.204"
872 | source = "registry+https://github.com/rust-lang/crates.io-index"
873 | checksum = "e0cd7e117be63d3c3678776753929474f3b04a43a080c744d6b0ae2a8c28e222"
874 | dependencies = [
875 | "proc-macro2",
876 | "quote",
877 | "syn",
878 | ]
879 |
880 | [[package]]
881 | name = "serde_spanned"
882 | version = "0.6.6"
883 | source = "registry+https://github.com/rust-lang/crates.io-index"
884 | checksum = "79e674e01f999af37c49f70a6ede167a8a60b2503e56c5599532a65baa5969a0"
885 | dependencies = [
886 | "serde",
887 | ]
888 |
889 | [[package]]
890 | name = "simd-adler32"
891 | version = "0.3.7"
892 | source = "registry+https://github.com/rust-lang/crates.io-index"
893 | checksum = "d66dc143e6b11c1eddc06d5c423cfc97062865baf299914ab64caa38182078fe"
894 |
895 | [[package]]
896 | name = "simd_helpers"
897 | version = "0.1.0"
898 | source = "registry+https://github.com/rust-lang/crates.io-index"
899 | checksum = "95890f873bec569a0362c235787f3aca6e1e887302ba4840839bcc6459c42da6"
900 | dependencies = [
901 | "quote",
902 | ]
903 |
904 | [[package]]
905 | name = "smallvec"
906 | version = "1.13.2"
907 | source = "registry+https://github.com/rust-lang/crates.io-index"
908 | checksum = "3c5e1a9a646d36c3599cd173a41282daf47c44583ad367b8e6837255952e5c67"
909 |
910 | [[package]]
911 | name = "spin"
912 | version = "0.9.8"
913 | source = "registry+https://github.com/rust-lang/crates.io-index"
914 | checksum = "6980e8d7511241f8acf4aebddbb1ff938df5eebe98691418c4468d0b72a96a67"
915 | dependencies = [
916 | "lock_api",
917 | ]
918 |
919 | [[package]]
920 | name = "syn"
921 | version = "2.0.69"
922 | source = "registry+https://github.com/rust-lang/crates.io-index"
923 | checksum = "201fcda3845c23e8212cd466bfebf0bd20694490fc0356ae8e428e0824a915a6"
924 | dependencies = [
925 | "proc-macro2",
926 | "quote",
927 | "unicode-ident",
928 | ]
929 |
930 | [[package]]
931 | name = "system-deps"
932 | version = "6.2.2"
933 | source = "registry+https://github.com/rust-lang/crates.io-index"
934 | checksum = "a3e535eb8dded36d55ec13eddacd30dec501792ff23a0b1682c38601b8cf2349"
935 | dependencies = [
936 | "cfg-expr",
937 | "heck",
938 | "pkg-config",
939 | "toml",
940 | "version-compare",
941 | ]
942 |
943 | [[package]]
944 | name = "target-lexicon"
945 | version = "0.12.15"
946 | source = "registry+https://github.com/rust-lang/crates.io-index"
947 | checksum = "4873307b7c257eddcb50c9bedf158eb669578359fb28428bef438fec8e6ba7c2"
948 |
949 | [[package]]
950 | name = "thiserror"
951 | version = "1.0.61"
952 | source = "registry+https://github.com/rust-lang/crates.io-index"
953 | checksum = "c546c80d6be4bc6a00c0f01730c08df82eaa7a7a61f11d656526506112cc1709"
954 | dependencies = [
955 | "thiserror-impl",
956 | ]
957 |
958 | [[package]]
959 | name = "thiserror-impl"
960 | version = "1.0.61"
961 | source = "registry+https://github.com/rust-lang/crates.io-index"
962 | checksum = "46c3384250002a6d5af4d114f2845d37b57521033f30d5c3f46c4d70e1197533"
963 | dependencies = [
964 | "proc-macro2",
965 | "quote",
966 | "syn",
967 | ]
968 |
969 | [[package]]
970 | name = "tiff"
971 | version = "0.9.1"
972 | source = "registry+https://github.com/rust-lang/crates.io-index"
973 | checksum = "ba1310fcea54c6a9a4fd1aad794ecc02c31682f6bfbecdf460bf19533eed1e3e"
974 | dependencies = [
975 | "flate2",
976 | "jpeg-decoder",
977 | "weezl",
978 | ]
979 |
980 | [[package]]
981 | name = "toml"
982 | version = "0.8.14"
983 | source = "registry+https://github.com/rust-lang/crates.io-index"
984 | checksum = "6f49eb2ab21d2f26bd6db7bf383edc527a7ebaee412d17af4d40fdccd442f335"
985 | dependencies = [
986 | "serde",
987 | "serde_spanned",
988 | "toml_datetime",
989 | "toml_edit",
990 | ]
991 |
992 | [[package]]
993 | name = "toml_datetime"
994 | version = "0.6.6"
995 | source = "registry+https://github.com/rust-lang/crates.io-index"
996 | checksum = "4badfd56924ae69bcc9039335b2e017639ce3f9b001c393c1b2d1ef846ce2cbf"
997 | dependencies = [
998 | "serde",
999 | ]
1000 |
1001 | [[package]]
1002 | name = "toml_edit"
1003 | version = "0.22.15"
1004 | source = "registry+https://github.com/rust-lang/crates.io-index"
1005 | checksum = "d59a3a72298453f564e2b111fa896f8d07fabb36f51f06d7e875fc5e0b5a3ef1"
1006 | dependencies = [
1007 | "indexmap",
1008 | "serde",
1009 | "serde_spanned",
1010 | "toml_datetime",
1011 | "winnow",
1012 | ]
1013 |
1014 | [[package]]
1015 | name = "ttf-parser"
1016 | version = "0.21.1"
1017 | source = "registry+https://github.com/rust-lang/crates.io-index"
1018 | checksum = "2c591d83f69777866b9126b24c6dd9a18351f177e49d625920d19f989fd31cf8"
1019 |
1020 | [[package]]
1021 | name = "unicode-ident"
1022 | version = "1.0.12"
1023 | source = "registry+https://github.com/rust-lang/crates.io-index"
1024 | checksum = "3354b9ac3fae1ff6755cb6db53683adb661634f67557942dea4facebec0fee4b"
1025 |
1026 | [[package]]
1027 | name = "v_frame"
1028 | version = "0.3.8"
1029 | source = "registry+https://github.com/rust-lang/crates.io-index"
1030 | checksum = "d6f32aaa24bacd11e488aa9ba66369c7cd514885742c9fe08cfe85884db3e92b"
1031 | dependencies = [
1032 | "aligned-vec",
1033 | "num-traits",
1034 | "wasm-bindgen",
1035 | ]
1036 |
1037 | [[package]]
1038 | name = "version-compare"
1039 | version = "0.2.0"
1040 | source = "registry+https://github.com/rust-lang/crates.io-index"
1041 | checksum = "852e951cb7832cb45cb1169900d19760cfa39b82bc0ea9c0e5a14ae88411c98b"
1042 |
1043 | [[package]]
1044 | name = "vswhom"
1045 | version = "0.1.0"
1046 | source = "registry+https://github.com/rust-lang/crates.io-index"
1047 | checksum = "be979b7f07507105799e854203b470ff7c78a1639e330a58f183b5fea574608b"
1048 | dependencies = [
1049 | "libc",
1050 | "vswhom-sys",
1051 | ]
1052 |
1053 | [[package]]
1054 | name = "vswhom-sys"
1055 | version = "0.1.2"
1056 | source = "registry+https://github.com/rust-lang/crates.io-index"
1057 | checksum = "d3b17ae1f6c8a2b28506cd96d412eebf83b4a0ff2cbefeeb952f2f9dfa44ba18"
1058 | dependencies = [
1059 | "cc",
1060 | "libc",
1061 | ]
1062 |
1063 | [[package]]
1064 | name = "wasi"
1065 | version = "0.11.0+wasi-snapshot-preview1"
1066 | source = "registry+https://github.com/rust-lang/crates.io-index"
1067 | checksum = "9c8d87e72b64a3b4db28d11ce29237c246188f4f51057d65a7eab63b7987e423"
1068 |
1069 | [[package]]
1070 | name = "wasm-bindgen"
1071 | version = "0.2.92"
1072 | source = "registry+https://github.com/rust-lang/crates.io-index"
1073 | checksum = "4be2531df63900aeb2bca0daaaddec08491ee64ceecbee5076636a3b026795a8"
1074 | dependencies = [
1075 | "cfg-if",
1076 | "wasm-bindgen-macro",
1077 | ]
1078 |
1079 | [[package]]
1080 | name = "wasm-bindgen-backend"
1081 | version = "0.2.92"
1082 | source = "registry+https://github.com/rust-lang/crates.io-index"
1083 | checksum = "614d787b966d3989fa7bb98a654e369c762374fd3213d212cfc0251257e747da"
1084 | dependencies = [
1085 | "bumpalo",
1086 | "log",
1087 | "once_cell",
1088 | "proc-macro2",
1089 | "quote",
1090 | "syn",
1091 | "wasm-bindgen-shared",
1092 | ]
1093 |
1094 | [[package]]
1095 | name = "wasm-bindgen-macro"
1096 | version = "0.2.92"
1097 | source = "registry+https://github.com/rust-lang/crates.io-index"
1098 | checksum = "a1f8823de937b71b9460c0c34e25f3da88250760bec0ebac694b49997550d726"
1099 | dependencies = [
1100 | "quote",
1101 | "wasm-bindgen-macro-support",
1102 | ]
1103 |
1104 | [[package]]
1105 | name = "wasm-bindgen-macro-support"
1106 | version = "0.2.92"
1107 | source = "registry+https://github.com/rust-lang/crates.io-index"
1108 | checksum = "e94f17b526d0a461a191c78ea52bbce64071ed5c04c9ffe424dcb38f74171bb7"
1109 | dependencies = [
1110 | "proc-macro2",
1111 | "quote",
1112 | "syn",
1113 | "wasm-bindgen-backend",
1114 | "wasm-bindgen-shared",
1115 | ]
1116 |
1117 | [[package]]
1118 | name = "wasm-bindgen-shared"
1119 | version = "0.2.92"
1120 | source = "registry+https://github.com/rust-lang/crates.io-index"
1121 | checksum = "af190c94f2773fdb3729c55b007a722abb5384da03bc0986df4c289bf5567e96"
1122 |
1123 | [[package]]
1124 | name = "weezl"
1125 | version = "0.1.8"
1126 | source = "registry+https://github.com/rust-lang/crates.io-index"
1127 | checksum = "53a85b86a771b1c87058196170769dd264f66c0782acf1ae6cc51bfd64b39082"
1128 |
1129 | [[package]]
1130 | name = "windows"
1131 | version = "0.58.0"
1132 | source = "registry+https://github.com/rust-lang/crates.io-index"
1133 | checksum = "dd04d41d93c4992d421894c18c8b43496aa748dd4c081bac0dc93eb0489272b6"
1134 | dependencies = [
1135 | "windows-core",
1136 | "windows-targets 0.52.6",
1137 | ]
1138 |
1139 | [[package]]
1140 | name = "windows-core"
1141 | version = "0.58.0"
1142 | source = "registry+https://github.com/rust-lang/crates.io-index"
1143 | checksum = "6ba6d44ec8c2591c134257ce647b7ea6b20335bf6379a27dac5f1641fcf59f99"
1144 | dependencies = [
1145 | "windows-implement",
1146 | "windows-interface",
1147 | "windows-result",
1148 | "windows-strings",
1149 | "windows-targets 0.52.6",
1150 | ]
1151 |
1152 | [[package]]
1153 | name = "windows-implement"
1154 | version = "0.58.0"
1155 | source = "registry+https://github.com/rust-lang/crates.io-index"
1156 | checksum = "2bbd5b46c938e506ecbce286b6628a02171d56153ba733b6c741fc627ec9579b"
1157 | dependencies = [
1158 | "proc-macro2",
1159 | "quote",
1160 | "syn",
1161 | ]
1162 |
1163 | [[package]]
1164 | name = "windows-interface"
1165 | version = "0.58.0"
1166 | source = "registry+https://github.com/rust-lang/crates.io-index"
1167 | checksum = "053c4c462dc91d3b1504c6fe5a726dd15e216ba718e84a0e46a88fbe5ded3515"
1168 | dependencies = [
1169 | "proc-macro2",
1170 | "quote",
1171 | "syn",
1172 | ]
1173 |
1174 | [[package]]
1175 | name = "windows-result"
1176 | version = "0.2.0"
1177 | source = "registry+https://github.com/rust-lang/crates.io-index"
1178 | checksum = "1d1043d8214f791817bab27572aaa8af63732e11bf84aa21a45a78d6c317ae0e"
1179 | dependencies = [
1180 | "windows-targets 0.52.6",
1181 | ]
1182 |
1183 | [[package]]
1184 | name = "windows-strings"
1185 | version = "0.1.0"
1186 | source = "registry+https://github.com/rust-lang/crates.io-index"
1187 | checksum = "4cd9b125c486025df0eabcb585e62173c6c9eddcec5d117d3b6e8c30e2ee4d10"
1188 | dependencies = [
1189 | "windows-result",
1190 | "windows-targets 0.52.6",
1191 | ]
1192 |
1193 | [[package]]
1194 | name = "windows-sys"
1195 | version = "0.48.0"
1196 | source = "registry+https://github.com/rust-lang/crates.io-index"
1197 | checksum = "677d2418bec65e3338edb076e806bc1ec15693c5d0104683f2efe857f61056a9"
1198 | dependencies = [
1199 | "windows-targets 0.48.5",
1200 | ]
1201 |
1202 | [[package]]
1203 | name = "windows-targets"
1204 | version = "0.48.5"
1205 | source = "registry+https://github.com/rust-lang/crates.io-index"
1206 | checksum = "9a2fa6e2155d7247be68c096456083145c183cbbbc2764150dda45a87197940c"
1207 | dependencies = [
1208 | "windows_aarch64_gnullvm 0.48.5",
1209 | "windows_aarch64_msvc 0.48.5",
1210 | "windows_i686_gnu 0.48.5",
1211 | "windows_i686_msvc 0.48.5",
1212 | "windows_x86_64_gnu 0.48.5",
1213 | "windows_x86_64_gnullvm 0.48.5",
1214 | "windows_x86_64_msvc 0.48.5",
1215 | ]
1216 |
1217 | [[package]]
1218 | name = "windows-targets"
1219 | version = "0.52.6"
1220 | source = "registry+https://github.com/rust-lang/crates.io-index"
1221 | checksum = "9b724f72796e036ab90c1021d4780d4d3d648aca59e491e6b98e725b84e99973"
1222 | dependencies = [
1223 | "windows_aarch64_gnullvm 0.52.6",
1224 | "windows_aarch64_msvc 0.52.6",
1225 | "windows_i686_gnu 0.52.6",
1226 | "windows_i686_gnullvm",
1227 | "windows_i686_msvc 0.52.6",
1228 | "windows_x86_64_gnu 0.52.6",
1229 | "windows_x86_64_gnullvm 0.52.6",
1230 | "windows_x86_64_msvc 0.52.6",
1231 | ]
1232 |
1233 | [[package]]
1234 | name = "windows_aarch64_gnullvm"
1235 | version = "0.48.5"
1236 | source = "registry+https://github.com/rust-lang/crates.io-index"
1237 | checksum = "2b38e32f0abccf9987a4e3079dfb67dcd799fb61361e53e2882c3cbaf0d905d8"
1238 |
1239 | [[package]]
1240 | name = "windows_aarch64_gnullvm"
1241 | version = "0.52.6"
1242 | source = "registry+https://github.com/rust-lang/crates.io-index"
1243 | checksum = "32a4622180e7a0ec044bb555404c800bc9fd9ec262ec147edd5989ccd0c02cd3"
1244 |
1245 | [[package]]
1246 | name = "windows_aarch64_msvc"
1247 | version = "0.48.5"
1248 | source = "registry+https://github.com/rust-lang/crates.io-index"
1249 | checksum = "dc35310971f3b2dbbf3f0690a219f40e2d9afcf64f9ab7cc1be722937c26b4bc"
1250 |
1251 | [[package]]
1252 | name = "windows_aarch64_msvc"
1253 | version = "0.52.6"
1254 | source = "registry+https://github.com/rust-lang/crates.io-index"
1255 | checksum = "09ec2a7bb152e2252b53fa7803150007879548bc709c039df7627cabbd05d469"
1256 |
1257 | [[package]]
1258 | name = "windows_i686_gnu"
1259 | version = "0.48.5"
1260 | source = "registry+https://github.com/rust-lang/crates.io-index"
1261 | checksum = "a75915e7def60c94dcef72200b9a8e58e5091744960da64ec734a6c6e9b3743e"
1262 |
1263 | [[package]]
1264 | name = "windows_i686_gnu"
1265 | version = "0.52.6"
1266 | source = "registry+https://github.com/rust-lang/crates.io-index"
1267 | checksum = "8e9b5ad5ab802e97eb8e295ac6720e509ee4c243f69d781394014ebfe8bbfa0b"
1268 |
1269 | [[package]]
1270 | name = "windows_i686_gnullvm"
1271 | version = "0.52.6"
1272 | source = "registry+https://github.com/rust-lang/crates.io-index"
1273 | checksum = "0eee52d38c090b3caa76c563b86c3a4bd71ef1a819287c19d586d7334ae8ed66"
1274 |
1275 | [[package]]
1276 | name = "windows_i686_msvc"
1277 | version = "0.48.5"
1278 | source = "registry+https://github.com/rust-lang/crates.io-index"
1279 | checksum = "8f55c233f70c4b27f66c523580f78f1004e8b5a8b659e05a4eb49d4166cca406"
1280 |
1281 | [[package]]
1282 | name = "windows_i686_msvc"
1283 | version = "0.52.6"
1284 | source = "registry+https://github.com/rust-lang/crates.io-index"
1285 | checksum = "240948bc05c5e7c6dabba28bf89d89ffce3e303022809e73deaefe4f6ec56c66"
1286 |
1287 | [[package]]
1288 | name = "windows_x86_64_gnu"
1289 | version = "0.48.5"
1290 | source = "registry+https://github.com/rust-lang/crates.io-index"
1291 | checksum = "53d40abd2583d23e4718fddf1ebec84dbff8381c07cae67ff7768bbf19c6718e"
1292 |
1293 | [[package]]
1294 | name = "windows_x86_64_gnu"
1295 | version = "0.52.6"
1296 | source = "registry+https://github.com/rust-lang/crates.io-index"
1297 | checksum = "147a5c80aabfbf0c7d901cb5895d1de30ef2907eb21fbbab29ca94c5b08b1a78"
1298 |
1299 | [[package]]
1300 | name = "windows_x86_64_gnullvm"
1301 | version = "0.48.5"
1302 | source = "registry+https://github.com/rust-lang/crates.io-index"
1303 | checksum = "0b7b52767868a23d5bab768e390dc5f5c55825b6d30b86c844ff2dc7414044cc"
1304 |
1305 | [[package]]
1306 | name = "windows_x86_64_gnullvm"
1307 | version = "0.52.6"
1308 | source = "registry+https://github.com/rust-lang/crates.io-index"
1309 | checksum = "24d5b23dc417412679681396f2b49f3de8c1473deb516bd34410872eff51ed0d"
1310 |
1311 | [[package]]
1312 | name = "windows_x86_64_msvc"
1313 | version = "0.48.5"
1314 | source = "registry+https://github.com/rust-lang/crates.io-index"
1315 | checksum = "ed94fce61571a4006852b7389a063ab983c02eb1bb37b47f8272ce92d06d9538"
1316 |
1317 | [[package]]
1318 | name = "windows_x86_64_msvc"
1319 | version = "0.52.6"
1320 | source = "registry+https://github.com/rust-lang/crates.io-index"
1321 | checksum = "589f6da84c646204747d1270a2a5661ea66ed1cced2631d546fdfb155959f9ec"
1322 |
1323 | [[package]]
1324 | name = "winnow"
1325 | version = "0.6.13"
1326 | source = "registry+https://github.com/rust-lang/crates.io-index"
1327 | checksum = "59b5e5f6c299a3c7890b876a2a587f3115162487e704907d9b6cd29473052ba1"
1328 | dependencies = [
1329 | "memchr",
1330 | ]
1331 |
1332 | [[package]]
1333 | name = "winreg"
1334 | version = "0.52.0"
1335 | source = "registry+https://github.com/rust-lang/crates.io-index"
1336 | checksum = "a277a57398d4bfa075df44f501a17cfdf8542d224f0d36095a2adc7aee4ef0a5"
1337 | dependencies = [
1338 | "cfg-if",
1339 | "windows-sys",
1340 | ]
1341 |
1342 | [[package]]
1343 | name = "zune-core"
1344 | version = "0.4.12"
1345 | source = "registry+https://github.com/rust-lang/crates.io-index"
1346 | checksum = "3f423a2c17029964870cfaabb1f13dfab7d092a62a29a89264f4d36990ca414a"
1347 |
1348 | [[package]]
1349 | name = "zune-inflate"
1350 | version = "0.2.54"
1351 | source = "registry+https://github.com/rust-lang/crates.io-index"
1352 | checksum = "73ab332fe2f6680068f3582b16a24f90ad7096d5d39b974d1c0aff0125116f02"
1353 | dependencies = [
1354 | "simd-adler32",
1355 | ]
1356 |
1357 | [[package]]
1358 | name = "zune-jpeg"
1359 | version = "0.4.11"
1360 | source = "registry+https://github.com/rust-lang/crates.io-index"
1361 | checksum = "ec866b44a2a1fd6133d363f073ca1b179f438f99e7e5bfb1e33f7181facfe448"
1362 | dependencies = [
1363 | "zune-core",
1364 | ]
1365 |
--------------------------------------------------------------------------------
/Cargo.toml:
--------------------------------------------------------------------------------
1 | [package]
2 | name = "AntiWindowSnap"
3 | version = "1.3.0"
4 | edition = "2021"
5 | description = "Prevent screenshotting and screen recording for the window with the specified title."
6 | repository = "https://github.com/pkptzx/AntiWindowSnap"
7 |
8 | [lib]
9 | name = "anti_window_snap"
10 |
11 | [dependencies]
12 | dashmap = "6.0.1"
13 | once_cell = "1.19.0"
14 | fltk = { version = "^1.4", features = ["fltk-bundled"] }
15 | image = "0.25.1"
16 | scopeguard = "1.2.0"
17 | windows = { version = "0.58.0", features = [
18 | "Win32_Foundation",
19 | "Win32_UI_Accessibility",
20 | "Win32_UI_WindowsAndMessaging",
21 | "Win32_Security",
22 | "Win32_System_Threading",
23 | "Win32_System_Memory",
24 | "Win32_System_LibraryLoader",
25 | "Win32_System_Diagnostics_Debug",
26 | "Win32_System_Diagnostics_ToolHelp",
27 | "Win32_Graphics_Gdi",
28 | ] }
29 |
30 | [build-dependencies]
31 | embed-resource = "2.4"
32 |
33 | [profile.release]
34 | panic = "abort"
35 | codegen-units = 1
36 | lto = true
37 | opt-level = "s"
38 | strip = true
39 |
--------------------------------------------------------------------------------
/Icon18.ico:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/pkptzx/AntiWindowSnap/c91fa8eee77f12072e3624a1b86463cb864d63ce/Icon18.ico
--------------------------------------------------------------------------------
/Icon19.ico:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/pkptzx/AntiWindowSnap/c91fa8eee77f12072e3624a1b86463cb864d63ce/Icon19.ico
--------------------------------------------------------------------------------
/LICENSE:
--------------------------------------------------------------------------------
1 | MIT License
2 |
3 | Copyright (c) 2024 码魂
4 |
5 | Permission is hereby granted, free of charge, to any person obtaining a copy
6 | of this software and associated documentation files (the "Software"), to deal
7 | in the Software without restriction, including without limitation the rights
8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9 | copies of the Software, and to permit persons to whom the Software is
10 | furnished to do so, subject to the following conditions:
11 |
12 | The above copyright notice and this permission notice shall be included in all
13 | copies or substantial portions of the Software.
14 |
15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21 | SOFTWARE.
22 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 |
2 | AntiWindowSnap
3 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 | `AntiWindowSnap` Prevent screenshotting and screen recording for the window with the specified title.
17 |
18 |
19 |
20 | ## Usage
21 | 1. Create a config.txt file next to AntiWindowSnap.exe.
22 | 2. In config.txt, list one window title per line.
23 | 3. Double-click to run AntiWindowSnap.exe.
24 |
25 |
26 |
27 |
28 |
29 | ## Why AntiWindowSnap?
30 | - No DLL injection, no administrator rights are required, and only code injection is used to implement anti-screenshot api calls
31 | - It detects new windows and changes to window titles in real-time, and also prevents screenshotting of previously opened windows.
32 |
33 | ### Download Prebuilt Binaries
34 | [Release download](https://github.com/pkptzx/AntiWindowSnap/releases/latest)
35 |
36 |
37 |
38 | ## Build from source
39 | ```shell
40 | cargo build --release
41 | ```
42 |
43 | # License
44 | MIT
45 |
--------------------------------------------------------------------------------
/build.rs:
--------------------------------------------------------------------------------
1 | extern crate embed_resource;
2 | fn main() {
3 | println!("cargo:rerun-if-changed=resource.rc");
4 | embed_resource::compile("resource.rc", embed_resource::NONE);
5 | }
--------------------------------------------------------------------------------
/cursor20.cur:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/pkptzx/AntiWindowSnap/c91fa8eee77f12072e3624a1b86463cb864d63ce/cursor20.cur
--------------------------------------------------------------------------------
/resource.rc:
--------------------------------------------------------------------------------
1 | IDC_C_CURSOR CURSOR "cursor20.cur"
2 | IDI_1 ICON "Icon18.ico"
3 | IDI_2 ICON "Icon19.ico"
--------------------------------------------------------------------------------
/src/helper.rs:
--------------------------------------------------------------------------------
1 | use std::ffi::c_void;
2 | use std::io::Cursor;
3 |
4 | use image::{ImageBuffer, Rgba};
5 | use scopeguard::defer;
6 | use windows::core::HSTRING;
7 | use windows::core::PCWSTR;
8 | use windows::Win32::Foundation::{GetLastError, HWND, RECT};
9 |
10 | use windows::Win32::Graphics::Gdi::{
11 | CreateCompatibleDC, DeleteDC, GetBitmapBits,
12 | };
13 | use windows::Win32::System::LibraryLoader::GetModuleHandleW;
14 | use windows::Win32::UI::WindowsAndMessaging::{
15 | DestroyIcon, GetClassNameW, GetIconInfo, GetParent, GetWindowInfo, GetWindowTextW, LoadIconW, SetWindowDisplayAffinity, ICONINFO,
16 | WDA_EXCLUDEFROMCAPTURE, WDA_NONE, WINDOWINFO,
17 | };
18 |
19 | #[allow(dead_code)]
20 | #[derive(Default, Debug)]
21 | pub struct WindowInfo {
22 | pub hwnd: u64,
23 | pub text: String,
24 | pub class_name: String,
25 | pub style: u32,
26 | pub ex_style: u32,
27 | pub rect: RECT,
28 | pub parent_hwnd: u64,
29 | pub parent_text: String,
30 | pub parent_class_name: String,
31 | }
32 |
33 | pub fn get_parent_window(hwnd: u64) -> u64 {
34 | unsafe {
35 | let hwnd = GetParent(HWND(hwnd as _));
36 | match hwnd {
37 | Ok(hwnd) => hwnd.0 as _,
38 | Err(_) => 0,
39 | }
40 | }
41 | }
42 | pub fn get_window_info(hwnd: u64) -> WindowInfo {
43 | unsafe {
44 | let info = &mut WINDOWINFO::default();
45 | GetWindowInfo(HWND(hwnd as _), info).unwrap();
46 | let p_hwnd = get_parent_window(hwnd);
47 | WindowInfo {
48 | hwnd: hwnd,
49 | text: get_window_text(hwnd),
50 | class_name: get_class_name(hwnd),
51 | style: info.dwStyle.0,
52 | ex_style: info.dwExStyle.0,
53 | rect: info.rcWindow,
54 | parent_hwnd: p_hwnd,
55 | parent_text: if p_hwnd != 0 {
56 | get_window_text(p_hwnd)
57 | } else {
58 | String::new()
59 | },
60 | parent_class_name: if p_hwnd != 0 {
61 | get_class_name(p_hwnd)
62 | } else {
63 | String::new()
64 | },
65 | }
66 | }
67 | }
68 |
69 | pub fn get_window_text(hwnd: u64) -> String {
70 | unsafe {
71 | let text: &mut [u16] = &mut [0; 255];
72 | let size = GetWindowTextW(HWND(hwnd as _), text);
73 | let text = &text[0..size as usize];
74 | String::from_utf16_lossy(text)
75 | }
76 | }
77 | pub fn get_class_name(hwnd: u64) -> String {
78 | unsafe {
79 | let text: &mut [u16] = &mut [0; 255];
80 | let size = GetClassNameW(HWND(hwnd as _), text);
81 | let text = &text[0..size as usize];
82 | String::from_utf16_lossy(text)
83 | }
84 | }
85 |
86 | pub fn set_window_deny_capture(hwnd: u64, flag: bool) -> bool {
87 | let show = if flag {
88 | WDA_EXCLUDEFROMCAPTURE
89 | } else {
90 | WDA_NONE
91 | };
92 | unsafe { SetWindowDisplayAffinity(HWND(hwnd as _), show).is_ok() }
93 | }
94 |
95 |
96 | pub fn load_icon_to_png(resource_name: &str) -> Result, String> {
97 | unsafe {
98 | let h_module = GetModuleHandleW(None).unwrap();
99 | let resource_name = PCWSTR(HSTRING::from(resource_name).as_ptr());
100 | let icon = LoadIconW(h_module, resource_name);
101 | if icon.is_err() {
102 | return Err(format!("LoadIconW failed: {}", GetLastError().0));
103 | }
104 | let icon = icon.unwrap();
105 | let mut info = ICONINFO::default();
106 | if GetIconInfo(icon, &mut info).is_err() {
107 | return Err(format!("GetIconInfo failed: {}", GetLastError().0));
108 | }
109 |
110 | let hdc = CreateCompatibleDC(None);
111 | if hdc.is_invalid() {
112 | return Err("CreateCompatibleDC failed".to_string());
113 | }
114 | defer! {DeleteDC(hdc).as_bool();}
115 |
116 | let width = info.xHotspot * 2; // icon width is twice the hotspot x coordinate
117 | let height = info.yHotspot * 2; // icon height is twice the hotspot y coordinate
118 |
119 | // 获取掩码位图
120 | let hbm_mask = info.hbmMask;
121 |
122 | let mut mask_pixels = vec![0u8; (width * height) as usize];
123 | let _bytes_written = GetBitmapBits(
124 | hbm_mask,
125 | mask_pixels.len() as i32,
126 | mask_pixels.as_mut_ptr() as *mut c_void,
127 | );
128 |
129 | // 获取颜色位图
130 | let hbm_color = info.hbmColor;
131 | // println!("hbmColor: {}", hbm_color.is_invalid());
132 | let mut color_pixels = vec![0u8; (width * height * 4) as usize];
133 | let _bytes_written = GetBitmapBits(
134 | hbm_color,
135 | color_pixels.len() as i32,
136 | color_pixels.as_mut_ptr() as *mut c_void,
137 | );
138 |
139 | // 合并掩码和颜色位图
140 | let mut pixels = vec![0u8; (width * height * 4) as usize];
141 | for y in 0..height {
142 | for x in 0..width {
143 | let color_index = (y * width * 4 + x * 4) as usize;
144 | let mask_index = (y * width + x) as usize;
145 | let inner_mask_index = mask_index / 8;
146 | let inner_mask_bit_index = 8 - (mask_index % 8 + 1);
147 | let mask_value = mask_pixels[inner_mask_index];
148 | let alpha = (mask_value & (1 << inner_mask_bit_index)) >> inner_mask_bit_index;
149 |
150 | pixels[color_index] = color_pixels[color_index + 2]; // 红R
151 | pixels[color_index + 1] = color_pixels[color_index + 1]; // 绿G
152 | pixels[color_index + 2] = color_pixels[color_index + 0]; // 蓝B
153 | pixels[color_index + 3] = (1 - alpha) * 255; // alpha
154 | }
155 | }
156 |
157 | DestroyIcon(icon).unwrap();
158 |
159 | let img = ImageBuffer::, _>::from_raw(width, height, &*pixels).unwrap();
160 | let png_data = Vec::new();
161 | let mut cursor = Cursor::new(png_data);
162 | // img.save_with_format("f:/tmp/testicon9.png", image::ImageFormat::Png)
163 | // .unwrap();
164 | img.write_to(&mut cursor, image::ImageFormat::Png).unwrap();
165 | let data = cursor.get_mut().to_owned();
166 | // println!("data len: {}", data.len());
167 | Ok(data)
168 | }
169 | }
170 |
171 |
--------------------------------------------------------------------------------
/src/lib.rs:
--------------------------------------------------------------------------------
1 | use std::{
2 | ffi::c_void,
3 | mem::{size_of, transmute},
4 | };
5 |
6 | use windows::{
7 | core::s,
8 | Win32::{
9 | Foundation::{CloseHandle, GetLastError, BOOL, FARPROC, HANDLE, HMODULE, HWND},
10 | System::{
11 | Diagnostics::{
12 | Debug::WriteProcessMemory,
13 | ToolHelp::{
14 | CreateToolhelp32Snapshot, Module32FirstW, Module32NextW, MODULEENTRY32W,
15 | TH32CS_SNAPMODULE, TH32CS_SNAPMODULE32,
16 | },
17 | },
18 | LibraryLoader::GetProcAddress,
19 | Memory::{
20 | VirtualAllocEx, VirtualFreeEx, MEM_COMMIT, MEM_DECOMMIT, MEM_RELEASE, MEM_RESERVE, PAGE_EXECUTE_READWRITE
21 | },
22 | Threading::{
23 | CreateRemoteThread, GetExitCodeThread, IsWow64Process, OpenProcess,
24 | WaitForSingleObject, INFINITE, LPTHREAD_START_ROUTINE, PROCESS_ALL_ACCESS,
25 | },
26 | },
27 | UI::WindowsAndMessaging::{GetWindowThreadProcessId, WDA_EXCLUDEFROMCAPTURE, WDA_NONE},
28 | },
29 | };
30 |
31 | const CODE_GET_FUNC_ADDRESS_X86: [u8; 124] = [
32 | 0x64u8, 0xA1, 0x30, 0x00, 0x00, 0x00, /* mov eax,dword ptr fs:[00000030h] */
33 | 0x53, /* push ebx */
34 | 0x56, /* push esi */
35 | 0x57, /* push edi */
36 | 0x8B, 0x40, 0x0C, /* mov eax,dword ptr [eax+0Ch] */
37 | 0x8B, 0x40, 0x14, /* mov eax,dword ptr [eax+14h] */
38 | 0x8B, 0x00, /* mov eax,dword ptr [eax] */
39 | 0x8B, 0x00, /* mov eax,dword ptr [eax] */
40 | 0x8B, 0x78, 0x10, /* mov edi,dword ptr [eax+10h] */
41 | 0x8B, 0x47, 0x3C, /* mov eax,dword ptr [edi+3Ch] */
42 | 0x8B, 0x44, 0x38, 0x78, /* mov eax,dword ptr [eax+edi+78h] */
43 | 0x8B, 0x4C, 0x38, 0x20, /* mov ecx,dword ptr [eax+edi+20h] */
44 | 0x8B, 0x74, 0x38, 0x24, /* mov esi,dword ptr [eax+edi+24h] */
45 | 0x03, 0xCF, /* add ecx,edi */
46 | 0x8B, 0x5C, 0x38, 0x1C, /* mov ebx,dword ptr [eax+edi+1Ch] */
47 | 0x03, 0xF7, /* add esi,edi */
48 | 0x03, 0xDF, /* add ebx,edi */
49 | 0x33, 0xD2, /* xor edx,edx */
50 | /* label1: */
51 | 0x8B, 0x01, /* mov eax,dword ptr [ecx] */
52 | 0x81, 0x3C, 0x38, 0x47, 0x65, 0x74, 0x50, /* cmp dword ptr [eax+edi],50746547h */
53 | 0x75, 0x14, /* jne */
54 | 0x81, 0x7C, 0x38, 0x04, 0x72, 0x6F, 0x63, 0x41, /* cmp dword ptr [eax+edi+4],41636F72h */
55 | 0x75, 0x0A, /* jne */
56 | 0x81, 0x7C, 0x38, 0x08, 0x64, 0x64, 0x72, 0x65, /* cmp dword ptr [eax+edi+8],65726464h */
57 | 0x74, 0x06, /* je */
58 | /* label2: */
59 | 0x83, 0xC1, 0x04, /* add ecx,4 */
60 | 0x42, /* inc edx */
61 | 0xEB, 0xDB, /* jmp */
62 | /* label3: */
63 | 0x0F, 0xB7, 0x04, 0x56, /* movzx eax,word ptr [esi+edx*2] */
64 | 0x68, 0x00, 0x00, 0x00, 0x00, /* push offset string "GetModuleHandleA" */
65 | 0x57, /* push edi */
66 | 0x8B, 0x34, 0x83, /* mov esi,dword ptr [ebx+eax*4] */
67 | 0x03, 0xF7, /* add esi,edi */
68 | 0xFF, 0xD6, /* call esi */
69 | 0x68, 0x00, 0x00, 0x00, 0x00, /* push offset string "SetWindowDisplayAffinity" */
70 | 0x68, 0x00, 0x00, 0x00, 0x00, /* push offset string "user32" */
71 | 0xFF, 0xD0, /* call eax */
72 | 0x50, /* push eax */
73 | 0xFF, 0xD6, /* call esi */
74 | 0x5F, /* pop edi */
75 | 0x5E, /* pop esi */
76 | 0x5B, /* pop ebx */
77 | 0xC2, 0x04, 0x00, /* ret 4 */
78 | ];
79 |
80 | const CODE_GET_FUNC_ADDRESS_X86_DATA_GMH: [u8; 17] = *b"GetModuleHandleA\0";
81 | const CODE_GET_FUNC_ADDRESS_X86_DATA_USER32: [u8; 7] = *b"user32\0";
82 | const CODE_GET_FUNC_ADDRESS_X86_DATA_SWDF: [u8; 25] = *b"SetWindowDisplayAffinity\0";
83 |
84 | const CODE_GET_FUNC_ADDRESS_X86_SIZE: usize = CODE_GET_FUNC_ADDRESS_X86.len();
85 | const CODE_GET_FUNC_ADDRESS_X86_DATA_GMH_SIZE: usize = CODE_GET_FUNC_ADDRESS_X86_DATA_GMH.len();
86 | const CODE_GET_FUNC_ADDRESS_X86_DATA_USER32_SIZE: usize =
87 | CODE_GET_FUNC_ADDRESS_X86_DATA_USER32.len();
88 | const CODE_GET_FUNC_ADDRESS_X86_DATA_SWDF_SIZE: usize = CODE_GET_FUNC_ADDRESS_X86_DATA_SWDF.len();
89 |
90 | const CODE_GET_FUNC_ADDRESS_X86_SIZE_ALL: usize = CODE_GET_FUNC_ADDRESS_X86_SIZE
91 | + CODE_GET_FUNC_ADDRESS_X86_DATA_GMH_SIZE
92 | + CODE_GET_FUNC_ADDRESS_X86_DATA_USER32_SIZE
93 | + CODE_GET_FUNC_ADDRESS_X86_DATA_SWDF_SIZE;
94 |
95 | const CODE_X86: [u8; 11] = [
96 | 0x58u8, /* pop eax */
97 | 0x59, /* pop ecx */
98 | 0x6A, 0x00, /* push */
99 | 0x51, /* push ecx */
100 | 0x50, /* push eax */
101 | 0xE9, 0x00, 0x00, 0x00, 0x00,
102 | ];
103 |
104 | const CODE_X86_SIZE: usize = CODE_X86.len();
105 |
106 | pub fn anti_window(hwnd: u64, hide: bool) -> bool {
107 | let mask: u32 = if hide {
108 | WDA_EXCLUDEFROMCAPTURE.0
109 | } else {
110 | WDA_NONE.0
111 | }; // WDA_NONE WDA_EXCLUDEFROMCAPTURE
112 | unsafe {
113 | let mut pid = 0u32;
114 | let pid_ptr = Some(&mut pid as *mut u32);
115 |
116 | let _tid = GetWindowThreadProcessId(HWND(hwnd as *mut c_void), pid_ptr);
117 |
118 | let process_handle = OpenProcess(PROCESS_ALL_ACCESS, false, pid).unwrap();
119 |
120 | let is_x86_process = &mut BOOL::default();
121 | IsWow64Process(process_handle, is_x86_process).unwrap();
122 | let is_x86_process = is_x86_process.as_bool();
123 |
124 | if !is_x86_process {
125 | let mut shellcode_x64: Vec = "48 89 4C 24 08 48 89 54 24 10 4C 89 44 24 18 4C 89 4C 24 20 48 83 EC 38 48 B9 ED FE AD DE ED FE 00 00 48 C7 C2 AD DE 00 00 48 B8 AD DE ED FE AD DE 00 00 FF D0 48 83 C4 38 48 8B 4C 24 08 48 8B 54 24 10 4C 8B 44 24 18 4C 8B 4C 24 20 C3".split_whitespace().map(|v|{
126 | u8::from_str_radix(v, 16).unwrap()
127 | }).collect();
128 |
129 | let mod_info = get_mod_info(pid, "User32.dll").unwrap();
130 |
131 | let mod_handle = mod_info.hModule.0;
132 | let fn_set_window_display_affinity_address = GetProcAddress(
133 | HMODULE(mod_handle as *mut std::ffi::c_void),
134 | s!("SetWindowDisplayAffinity"),
135 | )
136 | .unwrap();
137 |
138 | let address: u64 = fn_set_window_display_affinity_address as u64;
139 |
140 | let hwnd_bytes = hwnd.to_ne_bytes();
141 | let mask_bytes = mask.to_ne_bytes();
142 | let address_bytes = address.to_ne_bytes();
143 | //26 37 43
144 | shellcode_x64.splice(26..26 + hwnd_bytes.len(), hwnd_bytes.iter().cloned());
145 | shellcode_x64.splice(37..37 + mask_bytes.len(), mask_bytes.iter().cloned());
146 | shellcode_x64.splice(43..43 + address_bytes.len(), address_bytes.iter().cloned());
147 | // println!("pat_bytes: {:02X?}", shellcode);
148 |
149 | let address = VirtualAllocEx(
150 | process_handle,
151 | None,
152 | shellcode_x64.len(),
153 | MEM_COMMIT | MEM_RESERVE,
154 | PAGE_EXECUTE_READWRITE,
155 | );
156 | // println!("address: {:?}", address);
157 |
158 | WriteProcessMemory(
159 | process_handle,
160 | address as *mut c_void,
161 | shellcode_x64.as_ptr() as *const c_void,
162 | shellcode_x64.len(),
163 | None,
164 | )
165 | .unwrap();
166 | let addr = transmute(address);
167 | let address = transmute::(Some(addr));
168 | let mut tid = 0u32;
169 | let tid_ptr = &mut tid as *mut u32;
170 |
171 | let t_handle =
172 | CreateRemoteThread(process_handle, None, 0, address, None, 0, Some(tid_ptr))
173 | .unwrap();
174 | let _last_error = GetLastError();
175 | // println!("last_error: {:?}", _last_error);
176 |
177 | // println!("t_handle: {:?}", t_handle);
178 | // println!("tid: {:?}", tid);
179 | WaitForSingleObject(t_handle, INFINITE);
180 |
181 | VirtualFreeEx(
182 | process_handle,
183 | addr as *mut std::os::raw::c_void,
184 | 0,
185 | MEM_RELEASE,
186 | )
187 | .unwrap();
188 | CloseHandle(t_handle).unwrap();
189 | } else {
190 | let func_addr = get_func_address_x86(process_handle);
191 | let code_address = VirtualAllocEx(
192 | process_handle,
193 | None,
194 | CODE_X86_SIZE,
195 | MEM_COMMIT,
196 | PAGE_EXECUTE_READWRITE,
197 | );
198 | let code = build_x86_code(
199 | func_addr as _,
200 | mask as u8,
201 | code_address as _,
202 | );
203 | let retval = write_and_execute_code_wait(
204 | process_handle,
205 | code_address,
206 | code.as_ptr() as *const std::os::raw::c_void,
207 | CODE_X86_SIZE,
208 | Some(hwnd as *mut c_void),
209 | INFINITE,
210 | );
211 | println!("成功?: {:?}", retval);
212 | VirtualFreeEx(process_handle, code_address, CODE_X86_SIZE, MEM_DECOMMIT).unwrap();
213 | }
214 | CloseHandle(process_handle).unwrap();
215 | }
216 | return true;
217 | }
218 | pub fn get_mod_info(
219 | pid: u32,
220 | mod_name: &str,
221 | ) -> Result> {
222 | unsafe {
223 | let snapshot_handle =
224 | CreateToolhelp32Snapshot(TH32CS_SNAPMODULE | TH32CS_SNAPMODULE32, pid)?;
225 |
226 | let mut mod_info = MODULEENTRY32W::default();
227 | mod_info.dwSize = size_of::() as u32;
228 |
229 | Module32FirstW(snapshot_handle, &mut mod_info)
230 | .inspect_err(|err| {
231 | println!("{:?}", err);
232 | CloseHandle(snapshot_handle).unwrap();
233 | })
234 | .unwrap();
235 | let mod_name_ = String::from_utf16(&mod_info.szModule)
236 | .unwrap()
237 | .trim_end_matches("\0")
238 | .to_string();
239 |
240 | if mod_name_.eq_ignore_ascii_case(mod_name) {
241 | CloseHandle(snapshot_handle)?;
242 | return Ok(mod_info.clone());
243 | }
244 |
245 | while Module32NextW(snapshot_handle, &mut mod_info).is_ok() {
246 | let mod_name_ = String::from_utf16(&mod_info.szModule)
247 | .unwrap()
248 | .trim_end_matches("\0")
249 | .to_string();
250 |
251 | if mod_name_.eq_ignore_ascii_case(mod_name) {
252 | CloseHandle(snapshot_handle)?;
253 | return Ok(mod_info.clone());
254 | }
255 | }
256 |
257 | CloseHandle(snapshot_handle)?;
258 |
259 | Err(format!("{} not found", mod_name).into())
260 | }
261 | }
262 |
263 | fn get_func_address_x86(h_process: HANDLE) -> u32 {
264 | unsafe {
265 | let mut retval = 0u32;
266 | let code_address = VirtualAllocEx(
267 | h_process,
268 | None,
269 | CODE_GET_FUNC_ADDRESS_X86_SIZE_ALL,
270 | MEM_COMMIT,
271 | PAGE_EXECUTE_READWRITE,
272 | );
273 | println!("code_address: {:?}", code_address);
274 | if code_address as u32 != 0 {
275 | let code = build_x86_get_func_code(code_address as _);
276 | let exit_code = &mut 0u32;
277 | // DWORD exit_code;
278 | if write_and_execute_code_wait_return(
279 | h_process,
280 | code_address,
281 | code.as_ptr() as *const std::os::raw::c_void,
282 | CODE_GET_FUNC_ADDRESS_X86_SIZE_ALL,
283 | exit_code,
284 | None,
285 | INFINITE,
286 | ) {
287 | retval = *exit_code;
288 | VirtualFreeEx(
289 | h_process,
290 | code_address,
291 | CODE_GET_FUNC_ADDRESS_X86_SIZE_ALL,
292 | MEM_DECOMMIT,
293 | )
294 | .unwrap();
295 | }
296 | }
297 | return retval;
298 | }
299 | }
300 | fn build_x86_code(func_addr: usize, affinity: u8, base_address: usize) -> [u8; 11] {
301 | // affinity 是 WWDA_NONE / DA_MONITOR 虽然定义是u32但实际上只是0,1,17.u8就够了
302 | let mut code = [0u8; 11];
303 | code.copy_from_slice(&CODE_X86);
304 | code[3] = affinity;
305 | code[7..11].copy_from_slice(&((func_addr - (base_address + 6) - 5) as u32).to_ne_bytes());
306 | code
307 | }
308 | fn build_x86_get_func_code(base_address: usize) -> [u8; CODE_GET_FUNC_ADDRESS_X86_SIZE_ALL] {
309 | let mut code = [0; CODE_GET_FUNC_ADDRESS_X86_SIZE_ALL];
310 | let mut start = 0usize;
311 | let mut end = CODE_GET_FUNC_ADDRESS_X86_SIZE;
312 | code[start..end].copy_from_slice(&CODE_GET_FUNC_ADDRESS_X86);
313 | start = end;
314 | end += CODE_GET_FUNC_ADDRESS_X86_DATA_GMH_SIZE;
315 | code[start..end].copy_from_slice(&CODE_GET_FUNC_ADDRESS_X86_DATA_GMH);
316 | start = end;
317 | end += CODE_GET_FUNC_ADDRESS_X86_DATA_USER32_SIZE;
318 | code[start..end].copy_from_slice(&CODE_GET_FUNC_ADDRESS_X86_DATA_USER32);
319 | start = end;
320 | end += CODE_GET_FUNC_ADDRESS_X86_DATA_SWDF_SIZE;
321 | code[start..end].copy_from_slice(&CODE_GET_FUNC_ADDRESS_X86_DATA_SWDF);
322 |
323 | code[91..95]
324 | .copy_from_slice(&((base_address + CODE_GET_FUNC_ADDRESS_X86_SIZE) as u32).to_ne_bytes());
325 | code[104..108].copy_from_slice(
326 | &((base_address
327 | + CODE_GET_FUNC_ADDRESS_X86_SIZE
328 | + CODE_GET_FUNC_ADDRESS_X86_DATA_GMH_SIZE
329 | + CODE_GET_FUNC_ADDRESS_X86_DATA_USER32_SIZE) as u32)
330 | .to_ne_bytes(),
331 | );
332 | code[109..113].copy_from_slice(
333 | &((base_address + CODE_GET_FUNC_ADDRESS_X86_SIZE + CODE_GET_FUNC_ADDRESS_X86_DATA_GMH_SIZE)
334 | as u32)
335 | .to_ne_bytes(),
336 | );
337 | println!("BuildGetFuncCode:\n{:02X?}", code);
338 | code
339 | }
340 |
341 | fn write_and_execute_code(
342 | h_process: HANDLE,
343 | code_address: *const c_void,
344 | code: *const core::ffi::c_void,
345 | code_size: usize,
346 | parameter: Option<*const c_void>,
347 | ) -> HANDLE {
348 | unsafe {
349 | WriteProcessMemory(h_process, code_address, code, code_size, None).unwrap();
350 | // let addr = transmute(code_address);
351 | let address = transmute::<*const c_void, LPTHREAD_START_ROUTINE>(code_address);
352 | return CreateRemoteThread(h_process, None, 0, address, parameter, 0, None).unwrap();
353 | }
354 | }
355 |
356 | fn write_and_execute_code_wait(
357 | h_process: HANDLE,
358 | code_address: *const c_void,
359 | code: *const c_void,
360 | code_size: usize,
361 | parameter: Option<*const c_void>,
362 | timeout: u32,
363 | ) -> bool {
364 | unsafe {
365 | let h_thread = write_and_execute_code(h_process, code_address, code, code_size, parameter);
366 | if !h_thread.is_invalid() {
367 | WaitForSingleObject(h_thread, timeout); //INFINITE
368 | CloseHandle(h_thread).unwrap();
369 | return true;
370 | }
371 | return false;
372 | }
373 | }
374 |
375 | fn write_and_execute_code_wait_return(
376 | h_process: HANDLE,
377 | code_address: *const c_void,
378 | code: *const c_void,
379 | code_size: usize,
380 | exit_code: *mut u32,
381 | parameter: Option<*const c_void>,
382 | timeout: u32,
383 | ) -> bool {
384 | unsafe {
385 | let h_thread = write_and_execute_code(h_process, code_address, code, code_size, parameter);
386 | if !h_thread.is_invalid() {
387 | WaitForSingleObject(h_thread, timeout);
388 | GetExitCodeThread(h_thread, exit_code).unwrap();
389 | CloseHandle(h_thread).unwrap();
390 | return true;
391 | }
392 | return false;
393 | }
394 | }
395 |
--------------------------------------------------------------------------------
/src/main.rs:
--------------------------------------------------------------------------------
1 | #![cfg_attr(not(debug_assertions), windows_subsystem = "windows")]
2 | use std::{
3 | ffi::{c_void, OsStr, OsString},
4 | fs::File,
5 | io::{BufRead, BufReader},
6 | os::windows::process::CommandExt,
7 | };
8 |
9 | use anti_window_snap::anti_window;
10 | use dashmap::DashMap;
11 | use fltk::enums::{Color, Event};
12 | use fltk::image::PngImage;
13 | use fltk::input::Input;
14 | use fltk::{app, enums, prelude::*, window::Window};
15 | use fltk::{app::Scheme, enums::Align};
16 | use fltk::{button, dialog, frame, group, input, text};
17 | use once_cell::sync::Lazy;
18 | use windows::{
19 | core::w,
20 | Win32::{
21 | Foundation::{BOOL, COLORREF, HWND, POINT, RECT},
22 | Graphics::Gdi::{
23 | ClientToScreen, CombineRgn, CreateRectRgn, CreateRectRgnIndirect, CreateSolidBrush, FillRgn, GetDC, GetWindowDC, InflateRect, InvertRect,
24 | OffsetRect, RedrawWindow, ReleaseDC, SetRect, RDW_FRAME, RDW_INTERNALPAINT, RDW_INVALIDATE,
25 | RDW_UPDATENOW, RGN_DIFF,
26 | },
27 | System::LibraryLoader::GetModuleHandleW,
28 | UI::{
29 | Accessibility::{SetWinEventHook, UnhookWinEvent, HWINEVENTHOOK},
30 | WindowsAndMessaging::{
31 | EnumWindows, GetClientRect, GetParent, GetPhysicalCursorPos, GetWindowLongPtrW,
32 | GetWindowRect, GetWindowTextW, LoadCursorW, SetCursor, WindowFromPhysicalPoint,
33 | CHILDID_SELF, EVENT_OBJECT_CREATE, EVENT_OBJECT_NAMECHANGE, GWL_STYLE,
34 | OBJID_WINDOW, WINDOW_STYLE, WINEVENT_OUTOFCONTEXT, WINEVENT_SKIPOWNTHREAD,
35 | WS_CHILD,
36 | },
37 | },
38 | },
39 | };
40 | mod helper;
41 |
42 | #[derive(Debug, PartialEq, Eq)]
43 | enum STATE {
44 | UnProcessed,
45 | Processing,
46 | Processed,
47 | Completed,
48 | }
49 |
50 | static mut WINDOW_CACHE: Lazy> = Lazy::new(|| initialize_map());
51 | static mut ROOT_WINDOW_CACHE: Lazy> = Lazy::new(|| initialize_root_window_map());
52 | static mut CONFIG_WINDOW_TITLES: Vec = Vec::new();
53 | static mut LABELS_CACHE: Lazy> = Lazy::new(|| initialize_tips_map());
54 |
55 | fn initialize_map() -> DashMap {
56 | DashMap::new()
57 | }
58 | fn initialize_root_window_map() -> DashMap {
59 | DashMap::new()
60 | }
61 |
62 | fn initialize_tips_map() -> DashMap {
63 | DashMap::new()
64 | }
65 |
66 | fn main() {
67 | let path = std::env::current_dir()
68 | .unwrap_or_default()
69 | .join("config.txt");
70 | let mut txt_buf = text::TextBuffer::default();
71 | if path.exists() {
72 | let file = File::open(path).unwrap();
73 | let reader = BufReader::new(file);
74 |
75 | for line_result in reader.lines() {
76 | let line = line_result.unwrap();
77 | if !line.trim().is_empty() {
78 | unsafe {
79 | // println!("已加载配置:{}", line);
80 | CONFIG_WINDOW_TITLES.push(line.clone());
81 | txt_buf.append((line + "\n").as_str());
82 | }
83 | };
84 | }
85 | }
86 |
87 | let app = app::App::default().with_scheme(Scheme::Gtk);
88 | let mut wind = Window::default().with_size(640, 380).center_screen();
89 |
90 | let mut col = group::Flex::default_fill().column();
91 | let mut mp = group::Flex::default().row();
92 | frame::Frame::default();
93 |
94 | let mut left_panel_layout = group::Flex::default().column();
95 |
96 | let mut tip1_label = frame::Frame::default()
97 | .with_label("窗口标题一行一个")
98 | .with_align(enums::Align::Inside | enums::Align::Left);
99 | tip1_label.set_label_color(Color::Red);
100 | let mut txt = text::TextEditor::default().with_size(190, 290);
101 | txt.set_buffer(txt_buf.clone());
102 | txt.set_text_color(Color::DarkGreen);
103 | txt.set_scrollbar_align(Align::Right);
104 |
105 | let mut brow = group::Flex::default().row();
106 | {
107 | frame::Frame::default();
108 | let tip2_label = frame::Frame::default()
109 | .with_label("保存位置config.txt")
110 | .with_align(enums::Align::Inside | enums::Align::Left);
111 | let mut save = create_button("保存");
112 | save.set_callback(move |_| {
113 | let path = std::env::current_dir()
114 | .unwrap_or_default()
115 | .join("config.txt");
116 | match txt_buf.clone().save_file(path) {
117 | Ok(_) => {
118 | unsafe {
119 | CONFIG_WINDOW_TITLES.clear();
120 | }
121 | let content = txt_buf.text();
122 | for line in content.lines() {
123 | if !line.trim().is_empty() {
124 | unsafe {
125 | CONFIG_WINDOW_TITLES.push(line.to_string());
126 | }
127 | };
128 | }
129 | do_allwindow();
130 | }
131 | Err(_) => {
132 | dialog::message_default("保存失败");
133 | }
134 | }
135 | });
136 | brow.fixed(&tip2_label, 120);
137 | brow.fixed(&save, 60);
138 | brow.end();
139 | }
140 | left_panel_layout.fixed(&tip1_label, 30);
141 | left_panel_layout.fixed(&txt, 300);
142 | left_panel_layout.fixed(&brow, 30);
143 | left_panel_layout.end();
144 |
145 | let spacer = frame::Frame::default();
146 |
147 | let mut right_panel_layout = group::Flex::default().column();
148 | right_panel(&mut right_panel_layout);
149 | right_panel_layout.end();
150 |
151 | frame::Frame::default();
152 | mp.fixed(&left_panel_layout, 300);
153 | mp.fixed(&spacer, 10);
154 | mp.fixed(&right_panel_layout, 300);
155 | frame::Frame::default();
156 | mp.end();
157 | frame::Frame::default();
158 | col.fixed(&mp, 500);
159 |
160 | col.end();
161 | // wind.resizable(&col);
162 | wind.set_color(enums::Color::from_rgb(250, 250, 250));
163 | wind.end();
164 |
165 | // wind.size_range(600, 400, 1024, 768);
166 |
167 | wind.show();
168 | helper::set_window_deny_capture(wind.raw_handle() as _, true);
169 | let image = PngImage::from_data(&helper::load_icon_to_png("IDI_1").unwrap()).unwrap();
170 | wind.set_icon(Some(image));
171 | wind.set_label(
172 | format!(
173 | "{} {}",
174 | wind.raw_handle() as u64,
175 | " 开源地址:github.com/pkptzx/AntiWindowSnap"
176 | )
177 | .as_str(),
178 | );
179 |
180 | do_allwindow();
181 |
182 | let hook = unsafe {
183 | SetWinEventHook(
184 | EVENT_OBJECT_CREATE,
185 | EVENT_OBJECT_NAMECHANGE,
186 | None,
187 | Some(win_event_hook_callback),
188 | 0,
189 | 0,
190 | WINEVENT_OUTOFCONTEXT | WINEVENT_SKIPOWNTHREAD,
191 | )
192 | };
193 | assert!(!hook.is_invalid(), "Failed to install hook");
194 |
195 | wind.set_callback(move |_| {
196 | if fltk::app::event() == fltk::enums::Event::Close {
197 | dialog::message_title("想好了?");
198 | let choice = dialog::choice2_default(
199 | "退出是不会取消已经设置过防截屏的窗口状态",
200 | "取消",
201 | "臣退了",
202 | "开源地址:github.com/pkptzx/AntiWindowSnap",
203 | );
204 | if !choice.is_none() && choice.unwrap() == 1 {
205 | unsafe {
206 | let _ = UnhookWinEvent(hook);
207 | }
208 | app::quit();
209 | } else if !choice.is_none() && choice.unwrap() == 2 {
210 | let mut cmd = std::process::Command::new("cmd");
211 | cmd.arg("/c")
212 | .arg("start")
213 | .raw_arg("\"\"")
214 | // .raw_arg(wrap_in_quotes(app.into()))
215 | .raw_arg(wrap_in_quotes("https://github.com/pkptzx/AntiWindowSnap"))
216 | .creation_flags(0x08000000);
217 | cmd.status().unwrap();
218 | }
219 | }
220 | });
221 | app.run().unwrap();
222 |
223 | unsafe {
224 | let _ = UnhookWinEvent(hook);
225 | }
226 | }
227 | fn wrap_in_quotes>(path: T) -> OsString {
228 | let mut result = OsString::from("\"");
229 | result.push(path);
230 | result.push("\"");
231 |
232 | result
233 | }
234 | unsafe extern "system" fn win_event_hook_callback(
235 | _hook_handle: HWINEVENTHOOK,
236 | _event_id: u32,
237 | _window_handle: HWND,
238 | _object_id: i32,
239 | _child_id: i32,
240 | _thread_id: u32,
241 | _timestamp: u32,
242 | ) {
243 | let hwnd = _window_handle.0 as u64;
244 | if _event_id == EVENT_OBJECT_CREATE
245 | && _object_id == OBJID_WINDOW.0
246 | && _child_id as u32 == CHILDID_SELF
247 | {
248 | if !is_root_window_by_cache(hwnd) {
249 | return;
250 | }
251 |
252 | // println!(
253 | // "创建窗体事件: _hook_handle:{:?} _event_id:{} _window_handle:{:?} _object_id:{} _child_id:{} _thread_id:{} _timestamp:{}",
254 | // _hook_handle, _event_id, _window_handle, _object_id, _child_id, _thread_id, _timestamp
255 | // );
256 | // println!("{:?}窗口名称: {}",_window_handle, get_window_title(hwnd));
257 | // 接受到创建窗体的事件
258 | if !WINDOW_CACHE.contains_key(&hwnd) {
259 | WINDOW_CACHE.insert(hwnd, (STATE::Processing, STATE::UnProcessed));
260 | std::thread::spawn(move || unsafe {
261 | let title = get_window_title(hwnd);
262 | if CONFIG_WINDOW_TITLES.contains(&title) {
263 | if anti_window(hwnd, true) {
264 | println!("************************已经设置窗口防截屏:{}", title);
265 | set_tip(format!("已经设置窗口防截屏:{}", title));
266 | } else {
267 | println!("设置窗口防截屏失败:{}", title);
268 | set_tip(format!("设置窗口防截屏失败:{}", title));
269 | }
270 | }
271 | let mut val = WINDOW_CACHE.get_mut(&hwnd).unwrap();
272 | val.0 = STATE::Processed;
273 | });
274 | }
275 | } else if _event_id == EVENT_OBJECT_NAMECHANGE
276 | && _object_id == OBJID_WINDOW.0
277 | && _child_id as u32 == CHILDID_SELF
278 | {
279 | if !is_root_window_by_cache(hwnd) {
280 | return;
281 | }
282 | // println!(
283 | // "对象名称改变事件: _hook_handle:{:?} _event_id:{} _window_handle:{:?} _object_id:{} _child_id:{} _thread_id:{} _timestamp:{}",
284 | // _hook_handle, _event_id, _window_handle, _object_id, _child_id, _thread_id, _timestamp
285 | // );
286 | // println!("{:?}窗口名称: {}",_window_handle, get_window_title(hwnd));
287 | // 接受到名称改变的事件
288 | if !WINDOW_CACHE.contains_key(&hwnd) {
289 | WINDOW_CACHE.insert(hwnd, (STATE::UnProcessed, STATE::Processing));
290 | std::thread::spawn(move || unsafe {
291 | let title = get_window_title(hwnd);
292 | let mut val = WINDOW_CACHE.get_mut(&hwnd).unwrap();
293 | if CONFIG_WINDOW_TITLES.contains(&title) {
294 | if anti_window(hwnd, true) {
295 | println!("************************已经设置窗口防截屏:{}", title);
296 | set_tip(format!("已经设置窗口防截屏:{}", title));
297 | } else {
298 | println!("设置窗口防截屏失败:{}", title);
299 | }
300 | val.1 = STATE::Completed;
301 | } else {
302 | val.1 = STATE::Processed;
303 | }
304 | });
305 | } else {
306 | let val = WINDOW_CACHE.get_mut(&hwnd).unwrap();
307 | if val.1 == STATE::UnProcessed || val.1 == STATE::Processed {
308 | std::thread::spawn(move || unsafe {
309 | let title = get_window_title(hwnd);
310 | let mut val = WINDOW_CACHE.get_mut(&hwnd).unwrap();
311 | if CONFIG_WINDOW_TITLES.contains(&title) {
312 | if anti_window(hwnd, true) {
313 | println!("************************已经设置窗口防截屏:{}", title);
314 | set_tip(format!("已经设置窗口防截屏:{}", title));
315 | } else {
316 | println!("设置窗口防截屏失败:{}", title);
317 | set_tip(format!("设置窗口防截屏失败:{}", title));
318 | }
319 | val.1 = STATE::Completed;
320 | } else {
321 | val.1 = STATE::Processed;
322 | }
323 | });
324 | }
325 | }
326 | }
327 | // CHILDID_SELF;
328 | }
329 |
330 | fn get_window_title(hwnd: u64) -> String {
331 | unsafe {
332 | let title: &mut [u16] = &mut [0; 255];
333 | let size = GetWindowTextW(HWND(hwnd as *mut c_void), title);
334 | let title = &title[0..size as usize];
335 | String::from_utf16_lossy(title)
336 | }
337 | }
338 |
339 | fn is_root_window(hwnd: u64) -> bool {
340 | unsafe {
341 | if GetParent(HWND(hwnd as *mut c_void)).is_err() {
342 | // 没有父窗口,可能是顶级窗口,进一步检查样式
343 | let style = GetWindowLongPtrW(HWND(hwnd as *mut c_void), GWL_STYLE);
344 | let style = WINDOW_STYLE(style as u32);
345 | // 如果没有WS_CHILD标志,则是顶级窗口
346 | return (style & WS_CHILD).0 == 0;
347 | }
348 | return false;
349 | }
350 | }
351 |
352 | fn is_root_window_by_cache(hwnd: u64) -> bool {
353 | unsafe {
354 | let root_window = ROOT_WINDOW_CACHE.get(&hwnd);
355 | if let Some(root_window) = root_window {
356 | root_window.to_owned()
357 | } else {
358 | let root_window = is_root_window(hwnd);
359 | ROOT_WINDOW_CACHE.insert(hwnd, root_window);
360 | root_window
361 | }
362 | }
363 | }
364 |
365 | unsafe extern "system" fn enum_window_callback(
366 | hwnd: HWND,
367 | _lparam: windows::Win32::Foundation::LPARAM,
368 | ) -> windows::Win32::Foundation::BOOL {
369 | // println!("hwnd:{:?} title:{} lparam: {}", hwnd,get_window_title(hwnd.0 as u64),lparam.0);
370 | let hwnd = hwnd.0 as u64;
371 | WINDOW_CACHE.insert(hwnd, (STATE::Processing, STATE::UnProcessed));
372 | std::thread::spawn(move || unsafe {
373 | let title = get_window_title(hwnd);
374 | if CONFIG_WINDOW_TITLES.contains(&title) {
375 | if anti_window(hwnd, true) {
376 | println!("************************已经设置窗口防截屏:{}", title);
377 | set_tip(format!("已经设置窗口防截屏:{}", title));
378 | } else {
379 | println!("设置窗口防截屏失败:{}", title);
380 | set_tip(format!("设置窗口防截屏失败:{}", title));
381 | }
382 | }
383 | let mut val = WINDOW_CACHE.get_mut(&hwnd).unwrap();
384 | val.0 = STATE::Processed;
385 | });
386 | BOOL(1)
387 | }
388 | fn do_allwindow() {
389 | unsafe {
390 | WINDOW_CACHE.clear();
391 | let lparam = windows::Win32::Foundation::LPARAM(8888);
392 | EnumWindows(Some(enum_window_callback), lparam).unwrap();
393 | }
394 | }
395 | fn set_tip(txt: String) {
396 | let mut tip = unsafe { LABELS_CACHE.get_mut("tips").unwrap() };
397 | let tip_lab = tip.label();
398 | let lines: Vec<&str> = tip_lab.split("\n").collect();
399 | let last_line = lines.last().unwrap();
400 | let last_line = if last_line.is_empty() { "" } else { last_line };
401 | let tips = format!("{}\n{}", last_line, txt);
402 | tip.set_label(tips.as_str());
403 | tip.redraw_label();
404 | tip.parent().unwrap().redraw();
405 | }
406 | fn right_panel(parent: &mut group::Flex) {
407 | // frame::Frame::default();
408 | let mut sqq = group::Flex::default().row();
409 | {
410 | frame::Frame::default()
411 | .with_label("窗口拾取器:")
412 | .with_align(enums::Align::Inside | enums::Align::Right);
413 |
414 | let mut img = frame::Frame::default().with_size(42, 42);
415 | // img.set_frame(FrameType::EngravedBox);
416 |
417 | let image = PngImage::from_data(&helper::load_icon_to_png("IDI_1").unwrap()).unwrap();
418 | println!("image: {} {}", image.width(), image.height());
419 | // image.scale(42, 42, true, false);
420 |
421 | img.set_image(Some(image));
422 | img.handle({
423 | let mut last_hwnd = 0u64;
424 | move |me, event| match event {
425 | Event::Push => {
426 | last_hwnd = 0;
427 | let image =
428 | PngImage::from_data(&helper::load_icon_to_png("IDI_2").unwrap()).unwrap();
429 | // image.scale(42, 42, true, true);
430 | me.set_image(Some(image));
431 | me.redraw();
432 | unsafe {
433 | let h_module = GetModuleHandleW(None).unwrap();
434 | let hcursor = LoadCursorW(h_module, w!("IDC_C_CURSOR")).unwrap();
435 | // println!("hcursor: {:?}", hcursor);
436 | SetCursor(hcursor);
437 | }
438 | true
439 | }
440 | Event::Released => {
441 | if last_hwnd != 0 {
442 | // highlight_border(HWND(last_hwnd as _),false);
443 | invert_window(HWND(last_hwnd as _), false);
444 | }
445 | let image =
446 | PngImage::from_data(&helper::load_icon_to_png("IDI_1").unwrap()).unwrap();
447 | // image.scale(42, 42, true, true);
448 | me.set_image(Some(image));
449 | me.redraw();
450 | true
451 | }
452 | Event::Drag => {
453 | unsafe {
454 | let mut point2 = POINT::default();
455 | GetPhysicalCursorPos(&mut point2).unwrap();
456 | // println!("GetPhysicalCursorPos: {:?}", point2);
457 |
458 | let hwnd = WindowFromPhysicalPoint(point2);
459 | // println!("hwnd: {:?}", hwnd);
460 | if !hwnd.is_invalid() {
461 | let window_info = helper::get_window_info(hwnd.0 as _);
462 | // println!("hwnd: {:?} window_info: {:?}", hwnd, window_info);
463 | // let hdc = GetWindowDC(hwnd);
464 | // let oldRop2 = SetROP2(hdc, windows::Win32::Graphics::Gdi::R2_NOTXORPEN); // 返回0失败 R2_NOT R2_MASKPEN R2_NOTXORPEN
465 | // let pen = CreatePen(PS_INSIDEFRAME, 3, COLORREF(0x000000FF));// red 0x000000FF
466 | // let h_old_pen = SelectObject(hdc, pen);
467 | // let h_old_brush = SelectObject(hdc, GetStockObject(NULL_BRUSH));
468 | // let width = window_info.rect.right - window_info.rect.left;
469 | // let height = window_info.rect.bottom - window_info.rect.top;
470 | // Rectangle(hdc, 0, 0, width, height).as_bool();
471 |
472 | // SetROP2(hdc, windows::Win32::Graphics::Gdi::R2_MODE(oldRop2));
473 |
474 | // SelectObject(hdc, h_old_brush);
475 | // SelectObject(hdc, h_old_pen);
476 | // ReleaseDC(hwnd, hdc);
477 | // DeleteObject(pen).as_bool();
478 | if last_hwnd != hwnd.0 as _ {
479 | if last_hwnd != 0 {
480 | // highlight_border(HWND(last_hwnd as _),false);
481 | invert_window(HWND(last_hwnd as _), false);
482 | }
483 | // highlight_border(hwnd,true);
484 | invert_window(hwnd, false);
485 | }
486 |
487 | let group = me.parent().unwrap().parent().unwrap();
488 | let mut win_title: Input = group
489 | .child(1)
490 | .unwrap()
491 | .as_group()
492 | .unwrap()
493 | .child(1)
494 | .unwrap()
495 | .into_widget();
496 | win_title.set_value(&window_info.text);
497 |
498 | let mut win_hwnd: Input = group
499 | .child(2)
500 | .unwrap()
501 | .as_group()
502 | .unwrap()
503 | .child(1)
504 | .unwrap()
505 | .into_widget();
506 | win_hwnd.set_value(&window_info.hwnd.to_string());
507 |
508 | let mut win_class_name: Input = group
509 | .child(3)
510 | .unwrap()
511 | .as_group()
512 | .unwrap()
513 | .child(1)
514 | .unwrap()
515 | .into_widget();
516 | win_class_name.set_value(&window_info.class_name);
517 |
518 | let mut win_style: Input = group
519 | .child(4)
520 | .unwrap()
521 | .as_group()
522 | .unwrap()
523 | .child(1)
524 | .unwrap()
525 | .into_widget();
526 | win_style.set_value(&window_info.style.to_string());
527 |
528 | let mut win_exstyle: Input = group
529 | .child(5)
530 | .unwrap()
531 | .as_group()
532 | .unwrap()
533 | .child(1)
534 | .unwrap()
535 | .into_widget();
536 | win_exstyle.set_value(&window_info.ex_style.to_string());
537 |
538 | let mut win_parent_title: Input = group
539 | .child(6)
540 | .unwrap()
541 | .as_group()
542 | .unwrap()
543 | .child(1)
544 | .unwrap()
545 | .into_widget();
546 | win_parent_title.set_value(&window_info.parent_text);
547 |
548 | let mut win_parent_hwnd: Input = group
549 | .child(7)
550 | .unwrap()
551 | .as_group()
552 | .unwrap()
553 | .child(1)
554 | .unwrap()
555 | .into_widget();
556 | win_parent_hwnd.set_value(&window_info.parent_hwnd.to_string());
557 |
558 | let mut win_parent_class_name: Input = group
559 | .child(8)
560 | .unwrap()
561 | .as_group()
562 | .unwrap()
563 | .child(1)
564 | .unwrap()
565 | .into_widget();
566 | win_parent_class_name.set_value(&window_info.parent_class_name);
567 |
568 | last_hwnd = hwnd.0 as _;
569 | }
570 | }
571 | true
572 | }
573 | _ => false,
574 | }
575 | });
576 | sqq.fixed(&img, 43);
577 | sqq.end();
578 | }
579 |
580 | let mut urow = group::Flex::default().row();
581 | {
582 | frame::Frame::default()
583 | .with_label("窗口标题:")
584 | .with_align(enums::Align::Inside | enums::Align::Right);
585 | let mut inp_win_title = input::Input::default();
586 | inp_win_title.set_readonly(true);
587 | urow.fixed(&inp_win_title, 180);
588 | urow.end();
589 | }
590 |
591 | let mut prow = group::Flex::default().row();
592 | {
593 | frame::Frame::default()
594 | .with_label("窗口句柄:")
595 | .with_align(enums::Align::Inside | enums::Align::Right);
596 | let mut inp_win_hwnd = input::Input::default();
597 | inp_win_hwnd.set_readonly(true);
598 | prow.fixed(&inp_win_hwnd, 180);
599 | prow.end();
600 | }
601 | let mut row3 = group::Flex::default().row();
602 | {
603 | frame::Frame::default()
604 | .with_label("窗口类名:")
605 | .with_align(enums::Align::Inside | enums::Align::Right);
606 | let mut inp_win_class_name = input::Input::default();
607 | inp_win_class_name.set_readonly(true);
608 |
609 | row3.fixed(&inp_win_class_name, 180);
610 | row3.end();
611 | }
612 | let mut row4 = group::Flex::default().row();
613 | {
614 | frame::Frame::default()
615 | .with_label("窗口样式:")
616 | .with_align(enums::Align::Inside | enums::Align::Right);
617 | let mut inp_win_style = input::Input::default();
618 | inp_win_style.set_readonly(true);
619 |
620 | row4.fixed(&inp_win_style, 180);
621 | row4.end();
622 | }
623 | let mut row5 = group::Flex::default().row();
624 | {
625 | frame::Frame::default()
626 | .with_label("扩展样式:")
627 | .with_align(enums::Align::Inside | enums::Align::Right);
628 | let mut inp_win_exstyle = input::Input::default();
629 | inp_win_exstyle.set_readonly(true);
630 |
631 | row5.fixed(&inp_win_exstyle, 180);
632 | row5.end();
633 | }
634 | let mut row6 = group::Flex::default().row();
635 | {
636 | frame::Frame::default()
637 | .with_label("父窗口标题:")
638 | .with_align(enums::Align::Inside | enums::Align::Right);
639 | let mut inp_parent_win_title = input::Input::default();
640 | inp_parent_win_title.set_readonly(true);
641 |
642 | row6.fixed(&inp_parent_win_title, 180);
643 | row6.end();
644 | }
645 | let mut row7 = group::Flex::default().row();
646 | {
647 | frame::Frame::default()
648 | .with_label("父窗口句柄:")
649 | .with_align(enums::Align::Inside | enums::Align::Right);
650 | let mut inp_parent_win_hwnd = input::Input::default();
651 | inp_parent_win_hwnd.set_readonly(true);
652 |
653 | row7.fixed(&inp_parent_win_hwnd, 180);
654 | row7.end();
655 | }
656 | let mut row8 = group::Flex::default().row();
657 | {
658 | frame::Frame::default()
659 | .with_label("父窗口类名:")
660 | .with_align(enums::Align::Inside | enums::Align::Right);
661 |
662 | let mut inp_parent_win_class_name = input::Input::default();
663 | inp_parent_win_class_name.set_readonly(true);
664 |
665 | row8.fixed(&inp_parent_win_class_name, 180);
666 | row8.end();
667 | }
668 | let mut row9 = group::Flex::default().row();
669 | {
670 | let mut tip = frame::Frame::default()
671 | .with_label("https://github.com/pkptzx/AntiWindowSnap")
672 | .with_align(enums::Align::Inside | enums::Align::Left);
673 | tip.set_label_color(Color::Blue);
674 | row9.fixed(&tip, 180);
675 | unsafe {
676 | LABELS_CACHE.insert("tips".to_string(), tip);
677 | }
678 | row9.end();
679 | }
680 |
681 | let pad = frame::Frame::default();
682 |
683 | frame::Frame::default();
684 |
685 | parent.fixed(&sqq, 43);
686 | parent.fixed(&urow, 30);
687 | parent.fixed(&prow, 30);
688 | parent.fixed(&row3, 30);
689 | parent.fixed(&row4, 30);
690 | parent.fixed(&row5, 30);
691 | parent.fixed(&row6, 30);
692 | parent.fixed(&row7, 30);
693 | parent.fixed(&row8, 30);
694 | parent.fixed(&row9, 60);
695 |
696 | parent.fixed(&pad, 1); //空
697 | // parent.fixed(&brow, 30); //按钮
698 | // parent.fixed(&b, 30); //底部
699 | }
700 |
701 | fn create_button(caption: &str) -> button::Button {
702 | let mut btn = button::Button::default().with_label(caption);
703 | btn.set_color(enums::Color::from_rgb(225, 225, 225));
704 | btn
705 | }
706 |
707 | //from https://github.com/zodiacon/WinSpy/blob/master/WinSpy/WindowHelper.cpp#L101
708 | pub fn highlight_border(hwnd: HWND, highlight: bool) {
709 | let mut rc = RECT {
710 | left: 0,
711 | top: 0,
712 | right: 0,
713 | bottom: 0,
714 | };
715 |
716 | unsafe {
717 | GetWindowRect(hwnd, &mut rc).unwrap();
718 | // rc.OffsetRect(-rc.left, -rc.top); // 偏移
719 | OffsetRect(&mut rc, -rc.left, -rc.top).unwrap();
720 | // rc.InflateRect(2, 2); //增大 CRect 的宽度和高度。
721 | InflateRect(&mut rc, 2, 2).unwrap();
722 | }
723 | let rgn1 = unsafe { CreateRectRgnIndirect(&rc) };
724 | unsafe {
725 | // rc.DeflateRect(5, 5); //减小 CRect 的宽度和高度。
726 | InflateRect(&mut rc, -5, -5).unwrap();
727 | }
728 | let rgn2 = unsafe { CreateRectRgnIndirect(&rc) };
729 |
730 | let rgn = unsafe { CreateRectRgn(0, 0, 1, 1) };
731 | unsafe { CombineRgn(rgn, rgn1, rgn2, RGN_DIFF) }; // RGN_DIFF = 2 RGN_OR(2) RGN_DIFF(4)
732 |
733 | if !highlight {
734 | unsafe {
735 | RedrawWindow(
736 | hwnd,
737 | None,
738 | rgn,
739 | RDW_INTERNALPAINT | RDW_INVALIDATE | RDW_UPDATENOW | RDW_FRAME,
740 | )
741 | .as_bool()
742 | };
743 | return;
744 | }
745 |
746 | let dc = unsafe { GetDC(hwnd) };
747 | let brush = unsafe { CreateSolidBrush(rgb(255, 0, 0)) };
748 | let _result = unsafe { FillRgn(dc, rgn, brush).as_bool() };
749 | }
750 |
751 | fn rgb(r: u8, g: u8, b: u8) -> COLORREF {
752 | let color: u32 = (b as u32) << 16 | (g as u32) << 8 | r as u32;
753 | COLORREF(color)
754 | }
755 |
756 | // from https://github.com/strobejb/winspy/blob/master/src/FindTool.c#L91
757 | fn invert_window(hwnd: HWND, f_show_hidden: bool) {
758 | let mut hwnd = hwnd;
759 | let mut rect = RECT::default();
760 | let mut rect2 = RECT::default();
761 | let mut rectc = RECT::default();
762 |
763 | let mut border = 3; //INVERT_BORDER
764 |
765 | if hwnd.is_invalid() {
766 | return;
767 | }
768 |
769 | //window rectangle (screen coords)
770 | unsafe {
771 | GetWindowRect(hwnd, &mut rect).unwrap();
772 |
773 | //client rectangle (screen coords)
774 | GetClientRect(hwnd, &mut rectc).unwrap();
775 | let mut point: POINT = POINT {
776 | x: rectc.left,
777 | y: rectc.top,
778 | };
779 | ClientToScreen(hwnd, &mut point).as_bool();
780 | rectc.left = point.x;
781 | rectc.top = point.y;
782 |
783 | let mut point: POINT = POINT {
784 | x: rectc.right,
785 | y: rectc.bottom,
786 | };
787 | ClientToScreen(hwnd, &mut point).as_bool();
788 | rectc.right = point.x;
789 | rectc.bottom = point.y;
790 | //MapWindowPoints(hwnd, 0, (POINT *)&rectc, 2);
791 |
792 | let x1 = rect.left;
793 | let y1 = rect.top;
794 | OffsetRect(&mut rect, -x1, -y1).as_bool();
795 | OffsetRect(&mut rectc, -x1, -y1).as_bool();
796 |
797 | if rect.bottom - border * 2 < 0 {
798 | border = 1;
799 | }
800 |
801 | if rect.right - border * 2 < 0 {
802 | border = 1;
803 | }
804 |
805 | if f_show_hidden == true {
806 | hwnd.0 = 0 as _;
807 | }
808 |
809 | let hdc = GetWindowDC(hwnd);
810 |
811 | if hdc.is_invalid() {
812 | return;
813 | }
814 |
815 | //top edge
816 | //border = rectc.top-rect.top;
817 | SetRect(&mut rect2, 0, 0, rect.right, border).as_bool();
818 | if f_show_hidden == true {
819 | OffsetRect(&mut rect2, x1, y1).as_bool();
820 | }
821 | InvertRect(hdc, &rect2).as_bool();
822 |
823 | //left edge
824 | //border = rectc.left-rect.left;
825 | SetRect(&mut rect2, 0, border, border, rect.bottom).as_bool();
826 | if f_show_hidden == true {
827 | OffsetRect(&mut rect2, x1, y1).as_bool();
828 | }
829 | InvertRect(hdc, &rect2).as_bool();
830 |
831 | //right edge
832 | //border = rect.right-rectc.right;
833 | SetRect(
834 | &mut rect2,
835 | border,
836 | rect.bottom - border,
837 | rect.right,
838 | rect.bottom,
839 | )
840 | .as_bool();
841 | if f_show_hidden == true {
842 | OffsetRect(&mut rect2, x1, y1).as_bool();
843 | }
844 | InvertRect(hdc, &rect2).as_bool();
845 |
846 | //bottom edge
847 | //border = rect.bottom-rectc.bottom;
848 | SetRect(
849 | &mut rect2,
850 | rect.right - border,
851 | border,
852 | rect.right,
853 | rect.bottom - border,
854 | )
855 | .as_bool();
856 | if f_show_hidden == true {
857 | OffsetRect(&mut rect2, x1, y1).as_bool();
858 | }
859 | InvertRect(hdc, &rect2).as_bool();
860 |
861 | ReleaseDC(hwnd, hdc);
862 | };
863 | }
864 |
--------------------------------------------------------------------------------