Commit 80d1d087 authored by Rémi Bernon's avatar Rémi Bernon Committed by Alexandre Julliard

dinput: Keep track of input thread users using public refcounts.

And start the input thread when first user is created, then stop it when last user is destroyed. The thread will not need to enter the hook critical section on stop, as no public reference are held and devices are already unacquired.
parent 5119753a
......@@ -734,6 +734,7 @@ static ULONG WINAPI dinput_device_Release( IDirectInputDevice8W *iface )
if (!ref)
{
IDirectInputDevice_Unacquire( iface );
input_thread_remove_user();
dinput_device_internal_release( impl );
}
......@@ -2127,6 +2128,8 @@ void dinput_device_init( struct dinput_device *device, const struct dinput_devic
InitializeCriticalSection( &device->crit );
dinput_internal_addref( (device->dinput = dinput) );
device->vtbl = vtbl;
input_thread_add_user();
}
static const GUID *object_instance_guid( const DIDEVICEOBJECTINSTANCEW *instance )
......
......@@ -146,6 +146,7 @@ static ULONG WINAPI dinput7_Release( IDirectInput7W *iface )
if (!ref)
{
input_thread_remove_user();
dinput_internal_release( impl );
}
......@@ -819,6 +820,8 @@ static HRESULT dinput_create( IUnknown **out )
#else
*out = (IUnknown *)&impl->IDirectInput8W_iface;
#endif
input_thread_add_user();
return DI_OK;
}
......
......@@ -69,6 +69,7 @@ static HWND di_em_win;
static HANDLE dinput_thread;
static DWORD dinput_thread_id;
static UINT input_thread_user_count;
static CRITICAL_SECTION dinput_hook_crit;
static CRITICAL_SECTION_DEBUG dinput_critsect_debug =
......@@ -347,34 +348,39 @@ done:
return 0;
}
static BOOL WINAPI dinput_thread_start_once( INIT_ONCE *once, void *param, void **context )
void input_thread_add_user(void)
{
EnterCriticalSection( &dinput_hook_crit );
if (!input_thread_user_count++)
{
HANDLE start_event;
start_event = CreateEventW( NULL, FALSE, FALSE, NULL );
if (!start_event) ERR( "failed to create start event, error %lu\n", GetLastError() );
dinput_thread = CreateThread( NULL, 0, dinput_thread_proc, start_event, 0, &dinput_thread_id );
if (!dinput_thread) ERR( "failed to create internal thread, error %lu\n", GetLastError() );
TRACE( "Starting input thread.\n" );
if (!(start_event = CreateEventW( NULL, FALSE, FALSE, NULL )))
ERR( "Failed to create start event, error %lu\n", GetLastError() );
else if (!(dinput_thread = CreateThread( NULL, 0, dinput_thread_proc, start_event, 0, &dinput_thread_id )))
ERR( "Failed to create internal thread, error %lu\n", GetLastError() );
else
WaitForSingleObject( start_event, INFINITE );
CloseHandle( start_event );
return TRUE;
CloseHandle( start_event );
}
LeaveCriticalSection( &dinput_hook_crit );
}
static void dinput_thread_start(void)
void input_thread_remove_user(void)
{
static INIT_ONCE init_once = INIT_ONCE_STATIC_INIT;
InitOnceExecuteOnce( &init_once, dinput_thread_start_once, NULL, NULL );
}
EnterCriticalSection( &dinput_hook_crit );
if (!--input_thread_user_count)
{
TRACE( "Stopping input thread.\n" );
static void dinput_thread_stop(void)
{
PostThreadMessageW( dinput_thread_id, WM_USER + 0x10, 0, 0 );
if (WaitForSingleObject( dinput_thread, 500 ) == WAIT_TIMEOUT)
WARN("Timeout while waiting for internal thread\n");
WaitForSingleObject( dinput_thread, INFINITE );
CloseHandle( dinput_thread );
}
LeaveCriticalSection( &dinput_hook_crit );
}
void check_dinput_hooks( IDirectInputDevice8W *iface, BOOL acquired )
......@@ -384,8 +390,6 @@ void check_dinput_hooks( IDirectInputDevice8W *iface, BOOL acquired )
struct dinput_device *impl = impl_from_IDirectInputDevice8W( iface );
HANDLE hook_change_finished_event = NULL;
dinput_thread_start();
EnterCriticalSection(&dinput_hook_crit);
if (impl->dwCoopLevel & DISCL_FOREGROUND)
......@@ -468,7 +472,6 @@ BOOL WINAPI DllMain( HINSTANCE inst, DWORD reason, void *reserved )
break;
case DLL_PROCESS_DETACH:
if (reserved) break;
dinput_thread_stop();
unregister_di_em_win_class();
break;
}
......
......@@ -63,6 +63,9 @@ struct DevicePlayer {
struct list entry;
};
extern void input_thread_add_user(void);
extern void input_thread_remove_user(void);
extern void dinput_hooks_acquire_device( IDirectInputDevice8W *iface );
extern void dinput_hooks_unacquire_device( IDirectInputDevice8W *iface );
extern int dinput_mouse_hook( IDirectInputDevice8W *iface, WPARAM wparam, LPARAM lparam );
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment