This fixes a bug where games like "Don't Starve Together" wouldn't
capture because their actual render window is a completely different
window than their actual window on the screen.
So, because we already have the hook info by this point with the last
known window handle available, instead of using 0 here, we can just use
the window handle provided by the shared memory. And we didn't even
have to change the hook! That's nice.
Certain UWP programs can't obtain a normal window handle from their API
for whatever reason (this was observed with minecraft win10 edition), so
if the normal window handle on the map fails, try window handle 0
instead.
Checks the hook version to ensure compatibility with hook DLL. It's
unlikely it'll ever be necessary to increment the hook version, but this
is just a precautionary thing that allows a hook DLL to make sure it's
rejected by an older OBS version if needed. Again however, very
unlikely that the major version will ever be incremented.
The inject helper should be able to specify the full path rather than
assume the path of the hook DLL. This change allows us to modify the
hook's location. This needs to be done because the hook needs to be
relocated to ProgramData to prevent the possibility of multiple Vulkan
capture hooks.
This re-uses the game capture code for checking whether the original
window still exists or not. If it doesn't or the name changed, it'll
insert the value at the top of the list so it doesn't automatically
select another when the user opens properties.
Basically, this fixes an issue where opening properties could sometimes
cause it to instantly capture whatever window was at the top of the
list, which is undesirable.
Closesobsproject/obs-studio#2421
Before this change, after a game capture source would send a signal to
init or restart a graphics hook, it would respond to any and all hook
ready signals.
With multiple game capture sources in the same scene, a source could
receive the signal intended for another source, and show the wrong
texture.
This change adds the window handle to the name for shared data with the
hook, resulting in hooks for other sources being ignored.
Code submissions have continually suffered from formatting
inconsistencies that constantly have to be addressed. Using
clang-format simplifies this by making code formatting more consistent,
and allows automation of the code formatting so that maintainers can
focus more on the code itself instead of code formatting.
The GDI+ based Text Source actually uses Premultiplied Alpha. The edges
of the fonts are therefore incorrectly blended, causing ugly artifacts
especially if bright text above a bright background is used. Here's an
image comparing the new text blending (left) to before (right):
![https://i.imgur.com/VhhkQcZ.png](https://i.imgur.com/VhhkQcZ.png)
Additionally, the game capture has the same problem, so premultiplied
alpha is used there as well now.
Occasionally users accidentally select the following applications built
into Windows 10 using game capture, which cannot be captured.
This PR simply hides them from the game capture list.
The latter takes up 6 entries in the dropdown.
LockApp.exe - the lock screen which doesn't run in user space
WindowsInternal.ComposableShell.Experiences.TextInput.InputApp
Makes it a bit more clear this option shouldn't be used unless you're on
SLI/crossfire.
In the future, something should be put in to the program that detects
laptops and warns on how to set up their adapter for efficient capture.
Closesjp9000/obs-studio#1138
If the target process re-creates its D3D context, the game capture tick
can trigger before the capture is setup, in which case OBS gets a
CAPTURE_RETRY message. However with the memory capture method, it
continues to try and copy from the shared memory pointer which is no
longer valid, resulting in a crash. The fix uses the old texture until
the next tick at which point the new capture should be ready for use.
Using and creating a window can use issues in game capture if multiple
game captures are active, so revert back to using a mutex, and just
ignore the keepalive check failure if injected inside a UWP program
(only check to see if GetLastError reports that it's not found -- if it
returns access denied or any other error, assume it's in a UWP program,
and ignore the keepalive check).
Because the hook cannot get the window handle of UWP windows, fall back
to using the window handle stored in the game capture source itself if
it's unavailable from the hook.
Under certain circumstances, the program may not be able to acquire the
window thread ID for a UWP process, but will be able to acquire the
process ID. In this case, it should soft fail and retry, rather than
assume it's unacquirable and stop trying to reacquire.
The "attempting to hook [executable]" message would not display the
correct executable if it's fallen back to a different window with the
same window class.
Now that the game capture hook creates and controls all the
synchronization objects, it's no longer possible to expect that the hook
is fully loaded by the time game capture tries to initialize it. In
that case, allow game capture to retry the hook for a few frames before
assuming something failed.
This detects whether the target process is a UWP process, and then uses
the open_app_* functions for mutexes/events/mapping. Also slightly
refactors named object open functions.
All named objects (including file mapped shared memory) need to be
created within the hook itself due to the fact that UWP programs cannot
access named objects outside of the UWP process.
Because shared memory needs to be created within the hook, the capture
loop cannot start until the shared memory has been filled with valid
data. Creating an additional "initialize" event fixes this issue.
Additionally, changed the way that named kernel objects are
opened/created. Before, there were functions that would first try to
open named objects and then implicitly create them if opening failed
(assuming that if the hook didn't create it first, game capture would),
now it's been changed so that you can only either explicitly open or
create.
To check to make sure game capture is still active in the capture
program, it currently uses a named event, and then it checks to see if
that named event exists. However with UWP programs, you can't open a
named event outside of the UWP process. FindWindow on the other hand
does work, so instead of checking to see if a named kernel object
exists, create a window and check to see if that window exists.
The "main" windows detected for UWP programs are basically to help
sandbox the programs -- they run in the ApplicationFrameHost process and
help reduce the possibility of other programs trying to access the
actual process window, which is a child window.
To bypass this, go through the list of child windows for the
ApplicationFrameHost window, and then find the one that's attached to
a different process; that different process will always be the target,
and will allows us to open the actual process of the UWP program.