sechost: Implement I_ScRegisterDeviceNotification().
Based on a patch by Micah N Gorrell. Signed-off-by: Zebediah Figura <zfigura@codeweavers.com> Signed-off-by: Alexandre Julliard <julliard@winehq.org>
This commit is contained in:
parent
d70d1cda38
commit
6cf777ebd5
|
@ -11,4 +11,5 @@ C_SRCS = \
|
||||||
trace.c
|
trace.c
|
||||||
|
|
||||||
IDL_SRCS = \
|
IDL_SRCS = \
|
||||||
|
plugplay.idl \
|
||||||
svcctl.idl
|
svcctl.idl
|
||||||
|
|
|
@ -0,0 +1,2 @@
|
||||||
|
#pragma makedep client
|
||||||
|
#include "wine/plugplay.idl"
|
|
@ -108,14 +108,14 @@
|
||||||
@ stub I_ScIsSecurityProcess
|
@ stub I_ScIsSecurityProcess
|
||||||
@ stub I_ScPnPGetServiceName
|
@ stub I_ScPnPGetServiceName
|
||||||
@ stub I_ScQueryServiceConfig
|
@ stub I_ScQueryServiceConfig
|
||||||
@ stub I_ScRegisterDeviceNotification
|
@ stdcall I_ScRegisterDeviceNotification(ptr ptr long)
|
||||||
@ stub I_ScRegisterPreshutdownRestart
|
@ stub I_ScRegisterPreshutdownRestart
|
||||||
@ stub I_ScReparseServiceDatabase
|
@ stub I_ScReparseServiceDatabase
|
||||||
@ stub I_ScRpcBindA
|
@ stub I_ScRpcBindA
|
||||||
@ stub I_ScRpcBindW
|
@ stub I_ScRpcBindW
|
||||||
@ stub I_ScSendPnPMessage
|
@ stub I_ScSendPnPMessage
|
||||||
@ stub I_ScSendTSMessage
|
@ stub I_ScSendTSMessage
|
||||||
@ stub I_ScUnregisterDeviceNotification
|
@ stdcall I_ScUnregisterDeviceNotification(ptr)
|
||||||
@ stub I_ScValidatePnPService
|
@ stub I_ScValidatePnPService
|
||||||
@ stub LocalGetConditionForString
|
@ stub LocalGetConditionForString
|
||||||
@ stub LocalGetReferencedTokenTypesForCondition
|
@ stub LocalGetReferencedTokenTypesForCondition
|
||||||
|
|
|
@ -26,6 +26,8 @@
|
||||||
#include "winbase.h"
|
#include "winbase.h"
|
||||||
#include "winsvc.h"
|
#include "winsvc.h"
|
||||||
#include "winternl.h"
|
#include "winternl.h"
|
||||||
|
#include "winuser.h"
|
||||||
|
#include "dbt.h"
|
||||||
|
|
||||||
#include "wine/debug.h"
|
#include "wine/debug.h"
|
||||||
#include "wine/exception.h"
|
#include "wine/exception.h"
|
||||||
|
@ -33,6 +35,7 @@
|
||||||
#include "wine/list.h"
|
#include "wine/list.h"
|
||||||
|
|
||||||
#include "svcctl.h"
|
#include "svcctl.h"
|
||||||
|
#include "plugplay.h"
|
||||||
|
|
||||||
WINE_DEFAULT_DEBUG_CHANNEL(service);
|
WINE_DEFAULT_DEBUG_CHANNEL(service);
|
||||||
|
|
||||||
|
@ -1967,3 +1970,148 @@ BOOL WINAPI DECLSPEC_HOTPATCH StartServiceCtrlDispatcherW( const SERVICE_TABLE_E
|
||||||
|
|
||||||
return service_run_main_thread();
|
return service_run_main_thread();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
struct device_notification_details
|
||||||
|
{
|
||||||
|
DWORD (CALLBACK *cb)(HANDLE handle, DWORD flags, DEV_BROADCAST_HDR *header);
|
||||||
|
HANDLE handle;
|
||||||
|
};
|
||||||
|
|
||||||
|
static HANDLE device_notify_thread;
|
||||||
|
static struct list device_notify_list = LIST_INIT(device_notify_list);
|
||||||
|
|
||||||
|
struct device_notify_registration
|
||||||
|
{
|
||||||
|
struct list entry;
|
||||||
|
struct device_notification_details details;
|
||||||
|
};
|
||||||
|
|
||||||
|
static DWORD WINAPI device_notify_proc( void *arg )
|
||||||
|
{
|
||||||
|
WCHAR endpoint[] = L"\\pipe\\wine_plugplay";
|
||||||
|
WCHAR protseq[] = L"ncalrpc";
|
||||||
|
RPC_WSTR binding_str;
|
||||||
|
DWORD err = ERROR_SUCCESS;
|
||||||
|
struct device_notify_registration *registration;
|
||||||
|
plugplay_rpc_handle handle = NULL;
|
||||||
|
DWORD code = 0;
|
||||||
|
unsigned int size;
|
||||||
|
BYTE *buf;
|
||||||
|
|
||||||
|
if ((err = RpcStringBindingComposeW( NULL, protseq, NULL, endpoint, NULL, &binding_str )))
|
||||||
|
{
|
||||||
|
ERR("RpcStringBindingCompose() failed, error %#x\n", err);
|
||||||
|
return err;
|
||||||
|
}
|
||||||
|
err = RpcBindingFromStringBindingW( binding_str, &plugplay_binding_handle );
|
||||||
|
RpcStringFreeW( &binding_str );
|
||||||
|
if (err)
|
||||||
|
{
|
||||||
|
ERR("RpcBindingFromStringBinding() failed, error %#x\n", err);
|
||||||
|
return err;
|
||||||
|
}
|
||||||
|
|
||||||
|
__TRY
|
||||||
|
{
|
||||||
|
handle = plugplay_register_listener();
|
||||||
|
}
|
||||||
|
__EXCEPT(rpc_filter)
|
||||||
|
{
|
||||||
|
err = map_exception_code( GetExceptionCode() );
|
||||||
|
}
|
||||||
|
__ENDTRY
|
||||||
|
|
||||||
|
if (!handle)
|
||||||
|
{
|
||||||
|
ERR("failed to open RPC handle, error %u\n", err);
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
for (;;)
|
||||||
|
{
|
||||||
|
buf = NULL;
|
||||||
|
__TRY
|
||||||
|
{
|
||||||
|
code = plugplay_get_event( handle, &buf, &size );
|
||||||
|
err = ERROR_SUCCESS;
|
||||||
|
}
|
||||||
|
__EXCEPT(rpc_filter)
|
||||||
|
{
|
||||||
|
err = map_exception_code( GetExceptionCode() );
|
||||||
|
}
|
||||||
|
__ENDTRY
|
||||||
|
|
||||||
|
if (err)
|
||||||
|
{
|
||||||
|
ERR("failed to get event, error %u\n", err);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
EnterCriticalSection( &service_cs );
|
||||||
|
LIST_FOR_EACH_ENTRY(registration, &device_notify_list, struct device_notify_registration, entry)
|
||||||
|
{
|
||||||
|
registration->details.cb( registration->details.handle, code, (DEV_BROADCAST_HDR *)buf );
|
||||||
|
}
|
||||||
|
LeaveCriticalSection(&service_cs);
|
||||||
|
MIDL_user_free(buf);
|
||||||
|
}
|
||||||
|
|
||||||
|
__TRY
|
||||||
|
{
|
||||||
|
plugplay_unregister_listener( handle );
|
||||||
|
}
|
||||||
|
__EXCEPT(rpc_filter)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
__ENDTRY
|
||||||
|
|
||||||
|
RpcBindingFree( &plugplay_binding_handle );
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
/******************************************************************************
|
||||||
|
* I_ScRegisterDeviceNotification (sechost.@)
|
||||||
|
*/
|
||||||
|
HDEVNOTIFY WINAPI I_ScRegisterDeviceNotification( struct device_notification_details *details,
|
||||||
|
void *filter, DWORD flags )
|
||||||
|
{
|
||||||
|
struct device_notify_registration *registration;
|
||||||
|
|
||||||
|
TRACE("callback %p, handle %p, filter %p, flags %#x\n", details->cb, details->handle, filter, flags);
|
||||||
|
|
||||||
|
if (filter) FIXME("Notification filters are not yet implemented.\n");
|
||||||
|
|
||||||
|
if (!(registration = heap_alloc(sizeof(struct device_notify_registration))))
|
||||||
|
{
|
||||||
|
SetLastError(ERROR_NOT_ENOUGH_MEMORY);
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
registration->details = *details;
|
||||||
|
|
||||||
|
EnterCriticalSection( &service_cs );
|
||||||
|
list_add_tail( &device_notify_list, ®istration->entry );
|
||||||
|
|
||||||
|
if (!device_notify_thread)
|
||||||
|
device_notify_thread = CreateThread( NULL, 0, device_notify_proc, NULL, 0, NULL );
|
||||||
|
|
||||||
|
LeaveCriticalSection( &service_cs );
|
||||||
|
|
||||||
|
return registration;
|
||||||
|
}
|
||||||
|
|
||||||
|
/******************************************************************************
|
||||||
|
* I_ScUnregisterDeviceNotification (sechost.@)
|
||||||
|
*/
|
||||||
|
BOOL WINAPI I_ScUnregisterDeviceNotification( HDEVNOTIFY handle )
|
||||||
|
{
|
||||||
|
struct device_notify_registration *registration = handle;
|
||||||
|
|
||||||
|
TRACE("%p\n", handle);
|
||||||
|
|
||||||
|
EnterCriticalSection( &service_cs );
|
||||||
|
list_remove( ®istration->entry );
|
||||||
|
LeaveCriticalSection(&service_cs);
|
||||||
|
heap_free( registration );
|
||||||
|
return TRUE;
|
||||||
|
}
|
||||||
|
|
|
@ -0,0 +1,32 @@
|
||||||
|
/*
|
||||||
|
* Copyright (C) 2020 Zebediah Figura for CodeWeavers
|
||||||
|
*
|
||||||
|
* This library is free software; you can redistribute it and/or
|
||||||
|
* modify it under the terms of the GNU Lesser General Public
|
||||||
|
* License as published by the Free Software Foundation; either
|
||||||
|
* version 2.1 of the License, or (at your option) any later version.
|
||||||
|
*
|
||||||
|
* This library is distributed in the hope that it will be useful,
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||||
|
* Lesser General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU Lesser General Public
|
||||||
|
* License along with this library; if not, write to the Free Software
|
||||||
|
* Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
|
||||||
|
*/
|
||||||
|
|
||||||
|
import "wtypes.idl";
|
||||||
|
|
||||||
|
[
|
||||||
|
uuid(57c680ac-7bce-4f39-97fd-ffea566754d5),
|
||||||
|
implicit_handle(handle_t plugplay_binding_handle)
|
||||||
|
]
|
||||||
|
interface plugplay
|
||||||
|
{
|
||||||
|
typedef [context_handle] void *plugplay_rpc_handle;
|
||||||
|
|
||||||
|
plugplay_rpc_handle plugplay_register_listener();
|
||||||
|
DWORD plugplay_get_event([in] plugplay_rpc_handle handle, [out, size_is(,*size)] BYTE **data, [out] unsigned int *size);
|
||||||
|
void plugplay_unregister_listener([in] plugplay_rpc_handle handle);
|
||||||
|
}
|
|
@ -1,7 +1,10 @@
|
||||||
MODULE = plugplay.exe
|
MODULE = plugplay.exe
|
||||||
IMPORTS = advapi32
|
IMPORTS = advapi32 rpcrt4
|
||||||
|
|
||||||
EXTRADLLFLAGS = -mconsole -municode -mno-cygwin
|
EXTRADLLFLAGS = -mconsole -municode -mno-cygwin
|
||||||
|
|
||||||
C_SRCS = \
|
C_SRCS = \
|
||||||
main.c
|
main.c
|
||||||
|
|
||||||
|
IDL_SRCS = \
|
||||||
|
plugplay.idl
|
||||||
|
|
|
@ -21,6 +21,8 @@
|
||||||
#include <windows.h>
|
#include <windows.h>
|
||||||
#include "winsvc.h"
|
#include "winsvc.h"
|
||||||
#include "wine/debug.h"
|
#include "wine/debug.h"
|
||||||
|
#include "wine/list.h"
|
||||||
|
#include "plugplay.h"
|
||||||
|
|
||||||
WINE_DEFAULT_DEBUG_CHANNEL(plugplay);
|
WINE_DEFAULT_DEBUG_CHANNEL(plugplay);
|
||||||
|
|
||||||
|
@ -29,6 +31,111 @@ static WCHAR plugplayW[] = {'P','l','u','g','P','l','a','y',0};
|
||||||
static SERVICE_STATUS_HANDLE service_handle;
|
static SERVICE_STATUS_HANDLE service_handle;
|
||||||
static HANDLE stop_event;
|
static HANDLE stop_event;
|
||||||
|
|
||||||
|
void __RPC_FAR * __RPC_USER MIDL_user_allocate( SIZE_T len )
|
||||||
|
{
|
||||||
|
return malloc( len );
|
||||||
|
}
|
||||||
|
|
||||||
|
void __RPC_USER MIDL_user_free( void __RPC_FAR *ptr )
|
||||||
|
{
|
||||||
|
free( ptr );
|
||||||
|
}
|
||||||
|
|
||||||
|
static CRITICAL_SECTION plugplay_cs;
|
||||||
|
static CRITICAL_SECTION_DEBUG plugplay_cs_debug =
|
||||||
|
{
|
||||||
|
0, 0, &plugplay_cs,
|
||||||
|
{ &plugplay_cs_debug.ProcessLocksList, &plugplay_cs_debug.ProcessLocksList },
|
||||||
|
0, 0, { (DWORD_PTR)(__FILE__ ": plugplay_cs") }
|
||||||
|
};
|
||||||
|
static CRITICAL_SECTION plugplay_cs = { &plugplay_cs_debug, -1, 0, 0, 0, 0 };
|
||||||
|
|
||||||
|
static struct list listener_list = LIST_INIT(listener_list);
|
||||||
|
|
||||||
|
struct listener
|
||||||
|
{
|
||||||
|
struct list entry;
|
||||||
|
struct list events;
|
||||||
|
CONDITION_VARIABLE cv;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct event
|
||||||
|
{
|
||||||
|
struct list entry;
|
||||||
|
DWORD code;
|
||||||
|
BYTE *data;
|
||||||
|
unsigned int size;
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
static void destroy_listener( struct listener *listener )
|
||||||
|
{
|
||||||
|
struct event *event, *next;
|
||||||
|
|
||||||
|
EnterCriticalSection( &plugplay_cs );
|
||||||
|
list_remove( &listener->entry );
|
||||||
|
LeaveCriticalSection( &plugplay_cs );
|
||||||
|
|
||||||
|
LIST_FOR_EACH_ENTRY_SAFE(event, next, &listener->events, struct event, entry)
|
||||||
|
{
|
||||||
|
MIDL_user_free( event->data );
|
||||||
|
list_remove( &event->entry );
|
||||||
|
free( event );
|
||||||
|
}
|
||||||
|
free( listener );
|
||||||
|
}
|
||||||
|
|
||||||
|
void __RPC_USER plugplay_rpc_handle_rundown( plugplay_rpc_handle handle )
|
||||||
|
{
|
||||||
|
destroy_listener( handle );
|
||||||
|
}
|
||||||
|
|
||||||
|
plugplay_rpc_handle __cdecl plugplay_register_listener(void)
|
||||||
|
{
|
||||||
|
struct listener *listener;
|
||||||
|
|
||||||
|
if (!(listener = calloc( 1, sizeof(*listener) )))
|
||||||
|
return NULL;
|
||||||
|
|
||||||
|
list_init( &listener->events );
|
||||||
|
InitializeConditionVariable( &listener->cv );
|
||||||
|
|
||||||
|
EnterCriticalSection( &plugplay_cs );
|
||||||
|
list_add_tail( &listener_list, &listener->entry );
|
||||||
|
LeaveCriticalSection( &plugplay_cs );
|
||||||
|
|
||||||
|
return listener;
|
||||||
|
}
|
||||||
|
|
||||||
|
DWORD __cdecl plugplay_get_event( plugplay_rpc_handle handle, BYTE **data, unsigned int *size )
|
||||||
|
{
|
||||||
|
struct listener *listener = handle;
|
||||||
|
struct event *event;
|
||||||
|
struct list *entry;
|
||||||
|
DWORD ret;
|
||||||
|
|
||||||
|
EnterCriticalSection( &plugplay_cs );
|
||||||
|
|
||||||
|
while (!(entry = list_head( &listener->events )))
|
||||||
|
SleepConditionVariableCS( &listener->cv, &plugplay_cs, INFINITE );
|
||||||
|
|
||||||
|
event = LIST_ENTRY(entry, struct event, entry);
|
||||||
|
list_remove( &event->entry );
|
||||||
|
|
||||||
|
LeaveCriticalSection( &plugplay_cs );
|
||||||
|
|
||||||
|
ret = event->code;
|
||||||
|
*data = event->data;
|
||||||
|
*size = event->size;
|
||||||
|
free( event );
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
void __cdecl plugplay_unregister_listener( plugplay_rpc_handle handle )
|
||||||
|
{
|
||||||
|
destroy_listener( handle );
|
||||||
|
}
|
||||||
|
|
||||||
static DWORD WINAPI service_handler( DWORD ctrl, DWORD event_type, LPVOID event_data, LPVOID context )
|
static DWORD WINAPI service_handler( DWORD ctrl, DWORD event_type, LPVOID event_data, LPVOID context )
|
||||||
{
|
{
|
||||||
SERVICE_STATUS status;
|
SERVICE_STATUS status;
|
||||||
|
@ -60,10 +167,29 @@ static DWORD WINAPI service_handler( DWORD ctrl, DWORD event_type, LPVOID event_
|
||||||
|
|
||||||
static void WINAPI ServiceMain( DWORD argc, LPWSTR *argv )
|
static void WINAPI ServiceMain( DWORD argc, LPWSTR *argv )
|
||||||
{
|
{
|
||||||
|
unsigned char endpoint[] = "\\pipe\\wine_plugplay";
|
||||||
|
unsigned char protseq[] = "ncalrpc";
|
||||||
SERVICE_STATUS status;
|
SERVICE_STATUS status;
|
||||||
|
RPC_STATUS err;
|
||||||
|
|
||||||
WINE_TRACE( "starting service\n" );
|
WINE_TRACE( "starting service\n" );
|
||||||
|
|
||||||
|
if ((err = RpcServerUseProtseqEpA( protseq, 0, endpoint, NULL )))
|
||||||
|
{
|
||||||
|
ERR("RpcServerUseProtseqEp() failed, error %u\n", err);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if ((err = RpcServerRegisterIf( plugplay_v0_0_s_ifspec, NULL, NULL )))
|
||||||
|
{
|
||||||
|
ERR("RpcServerRegisterIf() failed, error %u\n", err);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if ((err = RpcServerListen( 1, RPC_C_LISTEN_MAX_CALLS_DEFAULT, TRUE )))
|
||||||
|
{
|
||||||
|
ERR("RpcServerListen() failed, error %u\n", err);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
stop_event = CreateEventW( NULL, TRUE, FALSE, NULL );
|
stop_event = CreateEventW( NULL, TRUE, FALSE, NULL );
|
||||||
|
|
||||||
service_handle = RegisterServiceCtrlHandlerExW( plugplayW, service_handler, NULL );
|
service_handle = RegisterServiceCtrlHandlerExW( plugplayW, service_handler, NULL );
|
||||||
|
@ -81,6 +207,10 @@ static void WINAPI ServiceMain( DWORD argc, LPWSTR *argv )
|
||||||
|
|
||||||
WaitForSingleObject( stop_event, INFINITE );
|
WaitForSingleObject( stop_event, INFINITE );
|
||||||
|
|
||||||
|
RpcMgmtStopServerListening( NULL );
|
||||||
|
RpcServerUnregisterIf( plugplay_v0_0_s_ifspec, NULL, TRUE );
|
||||||
|
RpcMgmtWaitServerListen();
|
||||||
|
|
||||||
status.dwCurrentState = SERVICE_STOPPED;
|
status.dwCurrentState = SERVICE_STOPPED;
|
||||||
status.dwControlsAccepted = 0;
|
status.dwControlsAccepted = 0;
|
||||||
SetServiceStatus( service_handle, &status );
|
SetServiceStatus( service_handle, &status );
|
||||||
|
|
|
@ -0,0 +1,2 @@
|
||||||
|
#pragma makedep server
|
||||||
|
#include "wine/plugplay.idl"
|
Loading…
Reference in New Issue