## Summary of the Pull Request
This PR is a light cleanup on Window Walker built-in extension:
- Removes unused types
- Removes redundant code
- Fixes inconsistent naming conventions
- De-LINQ-ify
- Fixes XML doc
- Updates language constructs to the latest (use of
System.Threading.Lock, Collection expressions)
- Updates types and members visibility and makes static classes static
⚠️ Trickiest part are 44ac1c1 and 26c946c that removes redundant null
checks.
## Summary of the Pull Request
This fixes a race condition in the WindowWalker component in both
**Command Palette** and **Run**. The lack of a lock around a cache
update could potentially lead to inaccurate information about UWP
applications being returned.
<!-- Please review the items on the PR checklist before submitting-->
## PR Checklist
- [x] Closes: #45600
<!-- - [ ] Closes: #yyy (add separate lines for additional resolved
issues) -->
- [ ] **Communication:** I've discussed this with core contributors
already. If the work hasn't been agreed, this work might be rejected
- [ ] **Tests:** Added/updated and all pass
- [ ] **Localization:** All end-user-facing strings can be localized
- [ ] **Dev docs:** Added/updated
- [ ] **New binaries:** Added on the required places
- [ ] [JSON for
signing](https://github.com/microsoft/PowerToys/blob/main/.pipelines/ESRPSigning_core.json)
for new binaries
- [ ] [WXS for
installer](https://github.com/microsoft/PowerToys/blob/main/installer/PowerToysSetup/Product.wxs)
for new binaries and localization folder
- [ ] [YML for CI
pipeline](https://github.com/microsoft/PowerToys/blob/main/.pipelines/ci/templates/build-powertoys-steps.yml)
for new test projects
- [ ] [YML for signed
pipeline](https://github.com/microsoft/PowerToys/blob/main/.pipelines/release.yml)
- [ ] **Documentation updated:** If checked, please file a pull request
on [our docs
repo](https://github.com/MicrosoftDocs/windows-uwp/tree/docs/hub/powertoys)
and link it here: #xxx
<!-- Provide a more detailed description of the PR, other things fixed,
or any additional comments/features here -->
## Detailed Description of the Pull Request / Additional comments
More details about the root cause can be found in the original issue:
#45600.
In summary, a `Task` is created and started as part of the
`CreateWindowProcessInstance()` code. The creation is inside a lock, but
there is no lock around access to the `_handlesToProcessCache` cache
within the Task itself, which will run on a different thread.
<!-- Describe how you validated the behavior. Add automated tests
wherever possible, but list manual validation steps taken as well -->
## Validation Steps Performed
- Ensured unit tests still pass (NB: I cannot currently run CmdPal UI
tests for some reason)
- Manually ran the applications, testing the Window Walker component in
both
<!-- Enter a brief description/summary of your PR here. What does it
fix/what does it change/how was it tested (even manually, if necessary)?
-->
<img width="629" height="767" alt="image"
src="https://github.com/user-attachments/assets/bc093640-db9d-4bc8-bc33-53729e692850"
/>
## Summary of the Pull Request
This is a PR for issue **#42260**.
It targets **CmdPal’s WindowWalker** and changes the icon retrieval to
use **SendMessage** to obtain the window’s actual icon, instead of using
the **process icon**.
To support this, I added a new configuration option.
<img width="400" height="401" alt="image"
src="https://github.com/user-attachments/assets/1a2d97a8-ff95-40b0-be42-746c2b1409d4"
/>
<!-- Please review the items on the PR checklist before submitting-->
## PR Checklist
- [ ] Closes: #42260
- [ ] **Communication:** @jiripolasek
- [ ] **Tests:** Added/updated and all pass
- [ ] **Localization:** All end-user-facing strings can be localized
- [ ] **Dev docs:** Added/updated
- [ ] **New binaries:** Added on the required places
- [ ] [JSON for
signing](https://github.com/microsoft/PowerToys/blob/main/.pipelines/ESRPSigning_core.json)
for new binaries
- [ ] [WXS for
installer](https://github.com/microsoft/PowerToys/blob/main/installer/PowerToysSetup/Product.wxs)
for new binaries and localization folder
- [ ] [YML for CI
pipeline](https://github.com/microsoft/PowerToys/blob/main/.pipelines/ci/templates/build-powertoys-steps.yml)
for new test projects
- [ ] [YML for signed
pipeline](https://github.com/microsoft/PowerToys/blob/main/.pipelines/release.yml)
- [ ] **Documentation updated:** If checked, please file a pull request
on [our docs
repo](https://github.com/MicrosoftDocs/windows-uwp/tree/docs/hub/powertoys)
and link it here: #xxx
<!-- Provide a more detailed description of the PR, other things fixed,
or any additional comments/features here -->
## Detailed Description of the Pull Request / Additional comments
Actully, The `ThumbnailHelper` already contains code that converts an
`IntPtr` `hIcon` into an `IRandomAccessStream`, as shown below:
```
private static MemoryStream GetMemoryStreamFromIcon(IntPtr hIcon)
{
var memoryStream = new MemoryStream();
// Ensure disposing the icon before freeing the handle
using (var icon = Icon.FromHandle(hIcon))
{
icon.ToBitmap().Save(memoryStream, System.Drawing.Imaging.ImageFormat.Png);
}
// Clean up the unmanaged handle without risking a use-after-free.
NativeMethods.DestroyIcon(hIcon);
memoryStream.Position = 0;
return memoryStream;
}
private static async Task<IRandomAccessStream?> FromHIconToStream(IntPtr hIcon)
{
var stream = new InMemoryRandomAccessStream();
using var memoryStream = GetMemoryStreamFromIcon(hIcon); // this will DestroyIcon hIcon
using var outputStream = stream.GetOutputStreamAt(0);
using var dataWriter = new DataWriter(outputStream);
dataWriter.WriteBytes(memoryStream.ToArray());
await dataWriter.StoreAsync();
await dataWriter.FlushAsync();
return stream;
}
```
Without modifying (or using) this code, I implemented the almost same
logic directly in `SwitchToWindowCommand` (calling the async code with
`Wait` to block synchronously). The reasons are:
1. I wanted to limit changes to the **WindowWalker** project area. I
don’t expect other extensions to need this behavior.
2. Because this is resource-related work, exposing a public helper that
pulls memory from an `hIcon` pointer seems risky—especially in a class
like `ThumbnailHelper`.
Therefore, I implemented behavior that is nearly identical to the
snippet above.
I did use `using`/`Dispose` where appropriate, but the
`InMemoryRandomAccessStream` created for `IconInfo.FromStream` appears
to use internal referencing; disposing it would be incorrect. For that
reason I didn’t wrap it in a `using`. I’m not entirely sure whether GC
will handle this cleanly.
However, based on the implementation of `FromStream` itself and its
usage elsewhere (e.g., in `ThumbnailHelper`), this seems to be the
correct usage pattern, though I’m not entirely sure.
<!-- Describe how you validated the behavior. Add automated tests
wherever possible, but list manual validation steps taken as well -->
## Validation Steps Performed
---------
Co-authored-by: Jiří Polášek <me@jiripolasek.com>
**WARNING:** This PR will probably blow up all in-flight PRs
at some point in the early days of CmdPal, two of us created seperate
`Exts` and `exts` dirs. Depending on what the casing was on the branch
that you checked one of those out from, it'd get stuck like that on your
PC forever.
Windows didn't care, so we never noticed.
But GitHub does care, and now browsing the source on GitHub is basically
impossible.
Closes#38081