├── .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 | Windows 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 | --------------------------------------------------------------------------------