I did some more investigation tonight, using a different Windows system hooked up to my Raspberry Pi 3B+ INDI server (using the telescope/CCD simulators and remote plate solving to eliminate any extra variables,) and I'm now thoroughly confident I've isolated the root cause. I won't go into the story of how I figured this all out, because it's pretty boring, but it has to do with the behavior of Qt's handling of temp files. There is a relevant bug report
here
which was marked as invalid due to "security concerns," since apparently introducing strange and overtly misleading platform-specific behavior is A-OK in Qt Land as long as it's marginally "safer" for one person somewhere in the world on at least one occasion.
Anyway, long story short, Qt maintains a chokehold on any temp files it creates, and will absolutely never, under any circumstances, close its file handle until the file is removed or the reference to it destroyed,
even if you explicitly call close(). The worst part is that I'm not even joking. This is actually a real thing that somebody thought was a good idea, and then wrote
this comment explaining why the method silently refuses to do the one thing that is literally the name of the method, and then returns success anyway.
Unbelievable. On Mac/Linux, this doesn't matter, because UNIX-based systems will happily allow two simultaneously-active file handles to point to the same file, but Windows will refuse cfitsio access to the file since Qt still "owns" it, hence the Windows-only nature of the bug.
I suppose you could call remove() on the file rather than close(), but it seems to me like you'd be giving up any benefits that using Qt to manage the file would have offered (such as removing it when the process ends? Does Qt do that?) At that point it seems like it would just be a plain old vanilla temp file, and you might as well just use std::tmpnam() or something like that rather than jumping through the "create a file, then remove it, then create it again" hoops. I'll leave the implementation details to the maintainers, but hopefully with this information you'll be able to get the PA utility working for Windows users in 2.9.7. Cheers!
EDIT: The relevant code in KStars is at the top of
Align::processPAHStage().