2 * Network Store Interface
4 * Copyright 2021 Huw Davies
6 * This library is free software; you can redistribute it and/or
7 * modify it under the terms of the GNU Lesser General Public
8 * License as published by the Free Software Foundation; either
9 * version 2.1 of the License, or (at your option) any later version.
11 * This library is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14 * Lesser General Public License for more details.
16 * You should have received a copy of the GNU Lesser General Public
17 * License along with this library; if not, write to the Free Software
18 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
28 #include "wine/heap.h"
29 #include "wine/debug.h"
31 WINE_DEFAULT_DEBUG_CHANNEL(nsi
);
33 static HANDLE nsi_device
= INVALID_HANDLE_VALUE
;
34 static HANDLE nsi_device_async
= INVALID_HANDLE_VALUE
;
36 BOOL WINAPI
DllMain(HINSTANCE hinst
, DWORD reason
, void *reserved
)
40 case DLL_PROCESS_ATTACH
:
41 DisableThreadLibraryCalls( hinst
);
43 case DLL_PROCESS_DETACH
:
44 if (nsi_device
!= INVALID_HANDLE_VALUE
) CloseHandle( nsi_device
);
45 if (nsi_device_async
!= INVALID_HANDLE_VALUE
) CloseHandle( nsi_device_async
);
51 static inline HANDLE
get_nsi_device( BOOL async
)
53 HANDLE
*cached_device
= async
? &nsi_device_async
: &nsi_device
;
56 if (*cached_device
== INVALID_HANDLE_VALUE
)
58 device
= CreateFileW( L
"\\\\.\\Nsi", 0, FILE_SHARE_READ
| FILE_SHARE_WRITE
, NULL
, OPEN_EXISTING
,
59 async
? FILE_FLAG_OVERLAPPED
: 0, NULL
);
60 if (device
!= INVALID_HANDLE_VALUE
61 && InterlockedCompareExchangePointer( cached_device
, device
, INVALID_HANDLE_VALUE
) != INVALID_HANDLE_VALUE
)
62 CloseHandle( device
);
64 return *cached_device
;
67 DWORD WINAPI
NsiAllocateAndGetTable( DWORD unk
, const NPI_MODULEID
*module
, DWORD table
, void **key_data
, DWORD key_size
,
68 void **rw_data
, DWORD rw_size
, void **dynamic_data
, DWORD dynamic_size
,
69 void **static_data
, DWORD static_size
, DWORD
*count
, DWORD unk2
)
72 void *data
[4] = { NULL
};
73 DWORD sizes
[4] = { key_size
, rw_size
, dynamic_size
, static_size
};
76 TRACE( "%ld %p %ld %p %ld %p %ld %p %ld %p %ld %p %ld\n", unk
, module
, table
, key_data
, key_size
,
77 rw_data
, rw_size
, dynamic_data
, dynamic_size
, static_data
, static_size
, count
, unk2
);
79 for (attempt
= 0; attempt
< 5; attempt
++)
81 for (i
= 0; i
< ARRAY_SIZE(data
); i
++)
85 data
[i
] = heap_alloc( sizes
[i
] * num
);
88 err
= ERROR_OUTOFMEMORY
;
94 err
= NsiEnumerateObjectsAllParameters( unk
, 0, module
, table
, data
[0], sizes
[0], data
[1], sizes
[1],
95 data
[2], sizes
[2], data
[3], sizes
[3], &num
);
96 if (err
!= ERROR_MORE_DATA
) break;
97 TRACE( "Short buffer, attempt %d.\n", attempt
);
98 NsiFreeTable( data
[0], data
[1], data
[2], data
[3] );
99 memset( data
, 0, sizeof(data
) );
100 err
= NsiEnumerateObjectsAllParameters( unk
, 0, module
, table
, NULL
, 0, NULL
, 0, NULL
, 0, NULL
, 0, &num
);
102 err
= ERROR_OUTOFMEMORY
; /* fail if this is the last attempt */
103 num
+= num
>> 4; /* the tables may grow before the next iteration; get ahead */
108 if (sizes
[0]) *key_data
= data
[0];
109 if (sizes
[1]) *rw_data
= data
[1];
110 if (sizes
[2]) *dynamic_data
= data
[2];
111 if (sizes
[3]) *static_data
= data
[3];
116 if (err
) NsiFreeTable( data
[0], data
[1], data
[2], data
[3] );
120 DWORD WINAPI
NsiCancelChangeNotification( OVERLAPPED
*ovr
)
122 DWORD err
= ERROR_SUCCESS
;
124 TRACE( "%p.\n", ovr
);
126 if (!ovr
) return ERROR_NOT_FOUND
;
127 if (!CancelIoEx( get_nsi_device( TRUE
), ovr
))
128 err
= GetLastError();
133 DWORD WINAPI
NsiEnumerateObjectsAllParameters( DWORD unk
, DWORD unk2
, const NPI_MODULEID
*module
, DWORD table
,
134 void *key_data
, DWORD key_size
, void *rw_data
, DWORD rw_size
,
135 void *dynamic_data
, DWORD dynamic_size
, void *static_data
, DWORD static_size
,
138 struct nsi_enumerate_all_ex params
;
141 TRACE( "%ld %ld %p %ld %p %ld %p %ld %p %ld %p %ld %p\n", unk
, unk2
, module
, table
, key_data
, key_size
,
142 rw_data
, rw_size
, dynamic_data
, dynamic_size
, static_data
, static_size
, count
);
144 params
.unknown
[0] = 0;
145 params
.unknown
[1] = 0;
146 params
.module
= module
;
147 params
.table
= table
;
148 params
.first_arg
= unk
;
149 params
.second_arg
= unk2
;
150 params
.key_data
= key_data
;
151 params
.key_size
= key_size
;
152 params
.rw_data
= rw_data
;
153 params
.rw_size
= rw_size
;
154 params
.dynamic_data
= dynamic_data
;
155 params
.dynamic_size
= dynamic_size
;
156 params
.static_data
= static_data
;
157 params
.static_size
= static_size
;
158 params
.count
= *count
;
160 err
= NsiEnumerateObjectsAllParametersEx( ¶ms
);
161 *count
= params
.count
;
165 DWORD WINAPI
NsiEnumerateObjectsAllParametersEx( struct nsi_enumerate_all_ex
*params
)
167 DWORD out_size
, received
, err
= ERROR_SUCCESS
;
168 HANDLE device
= get_nsi_device( FALSE
);
169 struct nsiproxy_enumerate_all in
;
172 if (device
== INVALID_HANDLE_VALUE
) return GetLastError();
174 out_size
= sizeof(DWORD
) +
175 (params
->key_size
+ params
->rw_size
+ params
->dynamic_size
+ params
->static_size
) * params
->count
;
177 out
= malloc( out_size
);
178 if (!out
) return ERROR_OUTOFMEMORY
;
180 in
.module
= *params
->module
;
181 in
.first_arg
= params
->first_arg
;
182 in
.second_arg
= params
->second_arg
;
183 in
.table
= params
->table
;
184 in
.key_size
= params
->key_size
;
185 in
.rw_size
= params
->rw_size
;
186 in
.dynamic_size
= params
->dynamic_size
;
187 in
.static_size
= params
->static_size
;
188 in
.count
= params
->count
;
190 if (!DeviceIoControl( device
, IOCTL_NSIPROXY_WINE_ENUMERATE_ALL
, &in
, sizeof(in
), out
, out_size
, &received
, NULL
))
191 err
= GetLastError();
192 if (err
== ERROR_SUCCESS
|| err
== ERROR_MORE_DATA
)
194 params
->count
= *(DWORD
*)out
;
195 ptr
= out
+ sizeof(DWORD
);
196 if (params
->key_size
) memcpy( params
->key_data
, ptr
, params
->key_size
* params
->count
);
197 ptr
+= params
->key_size
* in
.count
;
198 if (params
->rw_size
) memcpy( params
->rw_data
, ptr
, params
->rw_size
* params
->count
);
199 ptr
+= params
->rw_size
* in
.count
;
200 if (params
->dynamic_size
) memcpy( params
->dynamic_data
, ptr
, params
->dynamic_size
* params
->count
);
201 ptr
+= params
->dynamic_size
* in
.count
;
202 if (params
->static_size
) memcpy( params
->static_data
, ptr
, params
->static_size
* params
->count
);
210 void WINAPI
NsiFreeTable( void *key_data
, void *rw_data
, void *dynamic_data
, void *static_data
)
212 TRACE( "%p %p %p %p\n", key_data
, rw_data
, dynamic_data
, static_data
);
213 heap_free( key_data
);
214 heap_free( rw_data
);
215 heap_free( dynamic_data
);
216 heap_free( static_data
);
219 DWORD WINAPI
NsiGetAllParameters( DWORD unk
, const NPI_MODULEID
*module
, DWORD table
, const void *key
, DWORD key_size
,
220 void *rw_data
, DWORD rw_size
, void *dynamic_data
, DWORD dynamic_size
,
221 void *static_data
, DWORD static_size
)
223 struct nsi_get_all_parameters_ex params
;
225 TRACE( "%ld %p %ld %p %ld %p %ld %p %ld %p %ld\n", unk
, module
, table
, key
, key_size
,
226 rw_data
, rw_size
, dynamic_data
, dynamic_size
, static_data
, static_size
);
228 params
.unknown
[0] = 0;
229 params
.unknown
[1] = 0;
230 params
.module
= module
;
231 params
.table
= table
;
232 params
.first_arg
= unk
;
235 params
.key_size
= key_size
;
236 params
.rw_data
= rw_data
;
237 params
.rw_size
= rw_size
;
238 params
.dynamic_data
= dynamic_data
;
239 params
.dynamic_size
= dynamic_size
;
240 params
.static_data
= static_data
;
241 params
.static_size
= static_size
;
243 return NsiGetAllParametersEx( ¶ms
);
246 DWORD WINAPI
NsiGetAllParametersEx( struct nsi_get_all_parameters_ex
*params
)
248 HANDLE device
= get_nsi_device( FALSE
);
249 struct nsiproxy_get_all_parameters
*in
;
250 ULONG in_size
= FIELD_OFFSET( struct nsiproxy_get_all_parameters
, key
[params
->key_size
] ), received
;
251 ULONG out_size
= params
->rw_size
+ params
->dynamic_size
+ params
->static_size
;
252 DWORD err
= ERROR_SUCCESS
;
255 if (device
== INVALID_HANDLE_VALUE
) return GetLastError();
257 in
= malloc( in_size
);
258 out
= malloc( out_size
);
261 err
= ERROR_OUTOFMEMORY
;
265 in
->module
= *params
->module
;
266 in
->first_arg
= params
->first_arg
;
267 in
->table
= params
->table
;
268 in
->key_size
= params
->key_size
;
269 in
->rw_size
= params
->rw_size
;
270 in
->dynamic_size
= params
->dynamic_size
;
271 in
->static_size
= params
->static_size
;
272 memcpy( in
->key
, params
->key
, params
->key_size
);
274 if (!DeviceIoControl( device
, IOCTL_NSIPROXY_WINE_GET_ALL_PARAMETERS
, in
, in_size
, out
, out_size
, &received
, NULL
))
275 err
= GetLastError();
276 if (err
== ERROR_SUCCESS
)
279 if (params
->rw_size
) memcpy( params
->rw_data
, ptr
, params
->rw_size
);
280 ptr
+= params
->rw_size
;
281 if (params
->dynamic_size
) memcpy( params
->dynamic_data
, ptr
, params
->dynamic_size
);
282 ptr
+= params
->dynamic_size
;
283 if (params
->static_size
) memcpy( params
->static_data
, ptr
, params
->static_size
);
292 DWORD WINAPI
NsiGetParameter( DWORD unk
, const NPI_MODULEID
*module
, DWORD table
, const void *key
, DWORD key_size
,
293 DWORD param_type
, void *data
, DWORD data_size
, DWORD data_offset
)
295 struct nsi_get_parameter_ex params
;
297 TRACE( "%ld %p %ld %p %ld %ld %p %ld %ld\n", unk
, module
, table
, key
, key_size
,
298 param_type
, data
, data_size
, data_offset
);
300 params
.unknown
[0] = 0;
301 params
.unknown
[1] = 0;
302 params
.module
= module
;
303 params
.table
= table
;
304 params
.first_arg
= unk
;
307 params
.key_size
= key_size
;
308 params
.param_type
= param_type
;
310 params
.data_size
= data_size
;
311 params
.data_offset
= data_offset
;
312 return NsiGetParameterEx( ¶ms
);
315 DWORD WINAPI
NsiGetParameterEx( struct nsi_get_parameter_ex
*params
)
317 HANDLE device
= get_nsi_device( FALSE
);
318 struct nsiproxy_get_parameter
*in
;
319 ULONG in_size
= FIELD_OFFSET( struct nsiproxy_get_parameter
, key
[params
->key_size
] ), received
;
320 DWORD err
= ERROR_SUCCESS
;
322 if (device
== INVALID_HANDLE_VALUE
) return GetLastError();
324 in
= malloc( in_size
);
325 if (!in
) return ERROR_OUTOFMEMORY
;
326 in
->module
= *params
->module
;
327 in
->first_arg
= params
->first_arg
;
328 in
->table
= params
->table
;
329 in
->key_size
= params
->key_size
;
330 in
->param_type
= params
->param_type
;
331 in
->data_offset
= params
->data_offset
;
332 memcpy( in
->key
, params
->key
, params
->key_size
);
334 if (!DeviceIoControl( device
, IOCTL_NSIPROXY_WINE_GET_PARAMETER
, in
, in_size
, params
->data
, params
->data_size
, &received
, NULL
))
335 err
= GetLastError();
341 DWORD WINAPI
NsiRequestChangeNotification( DWORD unk
, const NPI_MODULEID
*module
, DWORD table
, OVERLAPPED
*ovr
,
344 struct nsi_request_change_notification_ex params
;
346 TRACE( "%lu %p %lu %p %p stub.\n", unk
, module
, table
, ovr
, handle
);
349 params
.module
= module
;
350 params
.table
= table
;
352 params
.handle
= handle
;
353 return NsiRequestChangeNotificationEx( ¶ms
);
356 DWORD WINAPI
NsiRequestChangeNotificationEx( struct nsi_request_change_notification_ex
*params
)
358 HANDLE device
= get_nsi_device( TRUE
);
359 struct nsiproxy_request_notification
*in
;
360 ULONG in_size
= sizeof(struct nsiproxy_get_parameter
), received
;
361 OVERLAPPED overlapped
, *ovr
;
362 DWORD err
= ERROR_SUCCESS
;
365 TRACE( "%p.\n", params
);
367 if (params
->unk
) FIXME( "unknown parameter %#lx.\n", params
->unk
);
369 if (device
== INVALID_HANDLE_VALUE
) return GetLastError();
371 in
= malloc( in_size
);
372 if (!in
) return ERROR_OUTOFMEMORY
;
373 in
->module
= *params
->module
;
374 in
->table
= params
->table
;
376 if (!(ovr
= params
->ovr
))
378 overlapped
.hEvent
= CreateEventW( NULL
, FALSE
, FALSE
, NULL
);
381 if (!DeviceIoControl( device
, IOCTL_NSIPROXY_WINE_CHANGE_NOTIFICATION
, in
, in_size
, NULL
, 0, &received
, ovr
))
382 err
= GetLastError();
383 if (ovr
== &overlapped
)
385 if (err
== ERROR_IO_PENDING
)
386 err
= GetOverlappedResult( device
, ovr
, &len
, TRUE
) ? 0 : GetLastError();
387 CloseHandle( overlapped
.hEvent
);
389 else if (params
->handle
&& ovr
&& err
== ERROR_IO_PENDING
)
390 *params
->handle
= device
;