Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
wine-mirror
GitHub Repository: wine-mirror/wine
Path: blob/master/dlls/cfgmgr32/notification.c
12343 views
1
/*
2
* Copyright (C) 2023 Mohamad Al-Jaf
3
* Copyright (C) 2025 Vibhav Pant
4
*
5
* This library is free software; you can redistribute it and/or
6
* modify it under the terms of the GNU Lesser General Public
7
* License as published by the Free Software Foundation; either
8
* version 2.1 of the License, or (at your option) any later version.
9
*
10
* This library is distributed in the hope that it will be useful,
11
* but WITHOUT ANY WARRANTY; without even the implied warranty of
12
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13
* Lesser General Public License for more details.
14
*
15
* You should have received a copy of the GNU Lesser General Public
16
* License along with this library; if not, write to the Free Software
17
* Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
18
*/
19
20
#include "cfgmgr32_private.h"
21
22
WINE_DEFAULT_DEBUG_CHANNEL(setupapi);
23
24
static const char *debugstr_CM_NOTIFY_FILTER( const CM_NOTIFY_FILTER *filter )
25
{
26
if (!filter) return "(null)";
27
switch (filter->FilterType)
28
{
29
case CM_NOTIFY_FILTER_TYPE_DEVICEINTERFACE:
30
return wine_dbg_sprintf( "{%#lx %lx CM_NOTIFY_FILTER_TYPE_DEVICEINTERFACE %lu {{%s}}}", filter->cbSize,
31
filter->Flags, filter->Reserved, debugstr_guid( &filter->u.DeviceInterface.ClassGuid ) );
32
case CM_NOTIFY_FILTER_TYPE_DEVICEHANDLE:
33
return wine_dbg_sprintf( "{%#lx %lx CM_NOTIFY_FILTER_TYPE_DEVICEHANDLE %lu {{%p}}}", filter->cbSize,
34
filter->Flags, filter->Reserved, filter->u.DeviceHandle.hTarget );
35
case CM_NOTIFY_FILTER_TYPE_DEVICEINSTANCE:
36
return wine_dbg_sprintf( "{%#lx %lx CM_NOTIFY_FILTER_TYPE_DEVICEINSTANCE %lu {{%s}}}", filter->cbSize,
37
filter->Flags, filter->Reserved, debugstr_w( filter->u.DeviceInstance.InstanceId ) );
38
default:
39
return wine_dbg_sprintf( "{%#lx %lx (unknown FilterType %d) %lu}", filter->cbSize, filter->Flags,
40
filter->FilterType, filter->Reserved );
41
}
42
}
43
44
struct cm_notify_context
45
{
46
HDEVNOTIFY notify;
47
void *user_data;
48
PCM_NOTIFY_CALLBACK callback;
49
};
50
51
CALLBACK DWORD devnotify_callback( HANDLE handle, DWORD flags, DEV_BROADCAST_HDR *header )
52
{
53
struct cm_notify_context *ctx = handle;
54
CM_NOTIFY_EVENT_DATA *event_data;
55
CM_NOTIFY_ACTION action;
56
DWORD size, ret;
57
58
TRACE( "(%p, %#lx, %p)\n", handle, flags, header );
59
60
switch (flags)
61
{
62
case DBT_DEVICEARRIVAL:
63
action = CM_NOTIFY_ACTION_DEVICEINTERFACEARRIVAL;
64
break;
65
case DBT_DEVICEREMOVECOMPLETE:
66
FIXME( "CM_NOTIFY_ACTION_DEVICEREMOVECOMPLETE not implemented\n" );
67
action = CM_NOTIFY_ACTION_DEVICEINTERFACEREMOVAL;
68
break;
69
case DBT_CUSTOMEVENT:
70
action = CM_NOTIFY_ACTION_DEVICECUSTOMEVENT;
71
break;
72
default:
73
FIXME( "Unexpected flags value: %#lx\n", flags );
74
return 0;
75
}
76
77
switch (header->dbch_devicetype)
78
{
79
case DBT_DEVTYP_DEVICEINTERFACE:
80
{
81
const DEV_BROADCAST_DEVICEINTERFACE_W *iface = (DEV_BROADCAST_DEVICEINTERFACE_W *)header;
82
UINT data_size = wcslen( iface->dbcc_name ) + 1;
83
84
size = offsetof( CM_NOTIFY_EVENT_DATA, u.DeviceInterface.SymbolicLink[data_size] );
85
if (!(event_data = calloc( 1, size ))) return 0;
86
87
event_data->FilterType = CM_NOTIFY_FILTER_TYPE_DEVICEINTERFACE;
88
event_data->u.DeviceInterface.ClassGuid = iface->dbcc_classguid;
89
memcpy( event_data->u.DeviceInterface.SymbolicLink, iface->dbcc_name, data_size * sizeof(WCHAR) );
90
break;
91
}
92
case DBT_DEVTYP_HANDLE:
93
{
94
const DEV_BROADCAST_HANDLE *handle = (DEV_BROADCAST_HANDLE *)header;
95
UINT data_size = handle->dbch_size - 2 * sizeof(WCHAR) - offsetof( DEV_BROADCAST_HANDLE, dbch_data );
96
97
size = offsetof( CM_NOTIFY_EVENT_DATA, u.DeviceHandle.Data[data_size] );
98
if (!(event_data = calloc( 1, size ))) return 0;
99
100
event_data->FilterType = CM_NOTIFY_FILTER_TYPE_DEVICEHANDLE;
101
event_data->u.DeviceHandle.EventGuid = handle->dbch_eventguid;
102
event_data->u.DeviceHandle.NameOffset = handle->dbch_nameoffset;
103
event_data->u.DeviceHandle.DataSize = data_size;
104
memcpy( event_data->u.DeviceHandle.Data, handle->dbch_data, data_size );
105
break;
106
}
107
default:
108
FIXME( "Unexpected devicetype value: %#lx\n", header->dbch_devicetype );
109
return 0;
110
}
111
112
ret = ctx->callback( ctx, ctx->user_data, action, event_data, size );
113
free( event_data );
114
return ret;
115
}
116
117
static CONFIGRET create_notify_context( const CM_NOTIFY_FILTER *filter, HCMNOTIFICATION *notify_handle,
118
PCM_NOTIFY_CALLBACK callback, void *user_data )
119
{
120
union
121
{
122
DEV_BROADCAST_HDR header;
123
DEV_BROADCAST_DEVICEINTERFACE_W iface;
124
DEV_BROADCAST_HANDLE handle;
125
} notify_filter = {0};
126
struct cm_notify_context *ctx;
127
static const GUID GUID_NULL;
128
129
switch (filter->FilterType)
130
{
131
case CM_NOTIFY_FILTER_TYPE_DEVICEINTERFACE:
132
notify_filter.iface.dbcc_devicetype = DBT_DEVTYP_DEVICEINTERFACE;
133
if (filter->Flags & CM_NOTIFY_FILTER_FLAG_ALL_INTERFACE_CLASSES)
134
{
135
if (!IsEqualGUID( &filter->u.DeviceInterface.ClassGuid, &GUID_NULL )) return CR_INVALID_DATA;
136
notify_filter.iface.dbcc_size = offsetof( DEV_BROADCAST_DEVICEINTERFACE_W, dbcc_classguid );
137
}
138
else
139
{
140
notify_filter.iface.dbcc_size = offsetof( DEV_BROADCAST_DEVICEINTERFACE_W, dbcc_name );
141
notify_filter.iface.dbcc_classguid = filter->u.DeviceInterface.ClassGuid;
142
}
143
break;
144
case CM_NOTIFY_FILTER_TYPE_DEVICEHANDLE:
145
notify_filter.handle.dbch_devicetype = DBT_DEVTYP_HANDLE;
146
notify_filter.handle.dbch_size = sizeof(notify_filter.handle);
147
notify_filter.handle.dbch_handle = filter->u.DeviceHandle.hTarget;
148
break;
149
case CM_NOTIFY_FILTER_TYPE_DEVICEINSTANCE:
150
FIXME( "CM_NOTIFY_FILTER_TYPE_DEVICEINSTANCE is not supported!\n" );
151
return CR_CALL_NOT_IMPLEMENTED;
152
default:
153
return CR_INVALID_DATA;
154
}
155
156
if (!(ctx = calloc( 1, sizeof(*ctx) ))) return CR_OUT_OF_MEMORY;
157
158
ctx->user_data = user_data;
159
ctx->callback = callback;
160
if (!(ctx->notify = I_ScRegisterDeviceNotification( ctx, &notify_filter.header, devnotify_callback )))
161
{
162
free( ctx );
163
switch (GetLastError())
164
{
165
case ERROR_NOT_ENOUGH_MEMORY: return CR_OUT_OF_MEMORY;
166
case ERROR_INVALID_PARAMETER: return CR_INVALID_DATA;
167
default: return CR_FAILURE;
168
}
169
}
170
*notify_handle = ctx;
171
return CR_SUCCESS;
172
}
173
174
/***********************************************************************
175
* CM_Register_Notification (cfgmgr32.@)
176
*/
177
CONFIGRET WINAPI CM_Register_Notification( CM_NOTIFY_FILTER *filter, void *context,
178
PCM_NOTIFY_CALLBACK callback, HCMNOTIFICATION *notify_context )
179
{
180
TRACE( "(%s %p %p %p)\n", debugstr_CM_NOTIFY_FILTER( filter ), context, callback, notify_context );
181
182
if (!notify_context) return CR_FAILURE;
183
if (!filter || !callback || filter->cbSize != sizeof(*filter)) return CR_INVALID_DATA;
184
185
return create_notify_context( filter, notify_context, callback, context );
186
}
187
188
/***********************************************************************
189
* CM_Unregister_Notification (cfgmgr32.@)
190
*/
191
CONFIGRET WINAPI CM_Unregister_Notification( HCMNOTIFICATION notify )
192
{
193
struct cm_notify_context *ctx = notify;
194
195
TRACE( "(%p)\n", notify );
196
197
if (!notify) return CR_INVALID_DATA;
198
199
I_ScUnregisterDeviceNotification( ctx->notify );
200
free( ctx );
201
202
return CR_SUCCESS;
203
}
204
205