source: trunk/src/setupapi/queue.c@ 8553

Last change on this file since 8553 was 8421, checked in by sandervl, 23 years ago

wine resync

File size: 41.0 KB
Line 
1/*
2 * Setupapi file queue routines
3 *
4 * Copyright 2002 Alexandre Julliard for CodeWeavers
5 *
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.
10 *
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.
15 *
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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
19 */
20
21#include "windef.h"
22#include "winbase.h"
23#include "ntddk.h"
24#include "winerror.h"
25#include "setupapi.h"
26#include "wine/unicode.h"
27#include "setupapi_private.h"
28#include "wine/debug.h"
29
30WINE_DEFAULT_DEBUG_CHANNEL(setupapi);
31
32/* context structure for the default queue callback */
33struct default_callback_context
34{
35 HWND owner;
36 HWND progress;
37 UINT message;
38};
39
40struct file_op
41{
42 struct file_op *next;
43 UINT style;
44 WCHAR *src_root;
45 WCHAR *src_path;
46 WCHAR *src_file;
47 WCHAR *src_descr;
48 WCHAR *src_tag;
49 WCHAR *dst_path;
50 WCHAR *dst_file;
51};
52
53struct file_op_queue
54{
55 struct file_op *head;
56 struct file_op *tail;
57 unsigned int count;
58};
59
60struct file_queue
61{
62 struct file_op_queue copy_queue;
63 struct file_op_queue delete_queue;
64 struct file_op_queue rename_queue;
65 DWORD flags;
66};
67
68
69inline static WCHAR *strdupW( const WCHAR *str )
70{
71 WCHAR *ret = NULL;
72 if (str)
73 {
74 int len = (strlenW(str) + 1) * sizeof(WCHAR);
75 if ((ret = HeapAlloc( GetProcessHeap(), 0, len ))) memcpy( ret, str, len );
76 }
77 return ret;
78}
79
80
81inline static WCHAR *strdupAtoW( const char *str )
82{
83 WCHAR *ret = NULL;
84 if (str)
85 {
86 DWORD len = MultiByteToWideChar( CP_ACP, 0, str, -1, NULL, 0 );
87 if ((ret = HeapAlloc( GetProcessHeap(), 0, len * sizeof(WCHAR) )))
88 MultiByteToWideChar( CP_ACP, 0, str, -1, ret, len );
89 }
90 return ret;
91}
92
93inline static char *strdupWtoA( const WCHAR *str )
94{
95 char *ret = NULL;
96 if (str)
97 {
98 DWORD len = WideCharToMultiByte( CP_ACP, 0, str, -1, NULL, 0, NULL, NULL );
99 if ((ret = HeapAlloc( GetProcessHeap(), 0, len )))
100 WideCharToMultiByte( CP_ACP, 0, str, -1, ret, len, NULL, NULL );
101 }
102 return ret;
103}
104
105/* append a file operation to a queue */
106inline static void queue_file_op( struct file_op_queue *queue, struct file_op *op )
107{
108 op->next = NULL;
109 if (queue->tail) queue->tail->next = op;
110 else queue->head = op;
111 queue->tail = op;
112 queue->count++;
113}
114
115/* free all the file operations on a given queue */
116static void free_file_op_queue( struct file_op_queue *queue )
117{
118 struct file_op *op;
119
120 for (op = queue->head; op; op = op->next)
121 {
122 HeapFree( GetProcessHeap(), 0, op->src_root );
123 HeapFree( GetProcessHeap(), 0, op->src_path );
124 HeapFree( GetProcessHeap(), 0, op->src_file );
125 HeapFree( GetProcessHeap(), 0, op->src_descr );
126 HeapFree( GetProcessHeap(), 0, op->src_tag );
127 HeapFree( GetProcessHeap(), 0, op->dst_path );
128 if (op->dst_file != op->src_file) HeapFree( GetProcessHeap(), 0, op->dst_file );
129 }
130}
131
132/* concat 3 strings to make a path, handling separators correctly */
133static void concat_W( WCHAR *buffer, const WCHAR *src1, const WCHAR *src2, const WCHAR *src3 )
134{
135 *buffer = 0;
136 if (src1 && *src1)
137 {
138 strcpyW( buffer, src1 );
139 buffer += strlenW(buffer );
140 if (buffer[-1] != '\\') *buffer++ = '\\';
141 if (src2) while (*src2 == '\\') src2++;
142 }
143
144 if (src2)
145 {
146 strcpyW( buffer, src2 );
147 buffer += strlenW(buffer );
148 if (buffer[-1] != '\\') *buffer++ = '\\';
149 if (src3) while (*src3 == '\\') src3++;
150 }
151 if (src3)
152 {
153 strcpyW( buffer, src3 );
154 buffer += strlenW(buffer );
155 }
156}
157
158
159/***********************************************************************
160 * build_filepathsW
161 *
162 * Build a FILEPATHS_W structure for a given file operation.
163 */
164static BOOL build_filepathsW( const struct file_op *op, FILEPATHS_W *paths )
165{
166 int src_len = 1, dst_len = 1;
167 WCHAR *source = (PWSTR)paths->Source, *target = (PWSTR)paths->Target;
168
169 if (op->src_root) src_len += strlenW(op->src_root) + 1;
170 if (op->src_path) src_len += strlenW(op->src_path) + 1;
171 if (op->src_file) src_len += strlenW(op->src_file) + 1;
172 if (op->dst_path) dst_len += strlenW(op->dst_path) + 1;
173 if (op->dst_file) dst_len += strlenW(op->dst_file) + 1;
174 src_len *= sizeof(WCHAR);
175 dst_len *= sizeof(WCHAR);
176
177 if (!source || HeapSize( GetProcessHeap(), 0, source ) < src_len )
178 {
179 HeapFree( GetProcessHeap(), 0, source );
180 paths->Source = source = HeapAlloc( GetProcessHeap(), 0, src_len );
181 }
182 if (!target || HeapSize( GetProcessHeap(), 0, target ) < dst_len )
183 {
184 HeapFree( GetProcessHeap(), 0, target );
185 paths->Target = target = HeapAlloc( GetProcessHeap(), 0, dst_len );
186 }
187 if (!source || !target) return FALSE;
188 concat_W( source, op->src_root, op->src_path, op->src_file );
189 concat_W( target, NULL, op->dst_path, op->dst_file );
190 paths->Win32Error = 0;
191 paths->Flags = 0;
192 return TRUE;
193}
194
195
196/***********************************************************************
197 * QUEUE_callback_WtoA
198 *
199 * Map a file callback parameters from W to A and call the A callback.
200 */
201UINT CALLBACK QUEUE_callback_WtoA( void *context, UINT notification,
202 UINT_PTR param1, UINT_PTR param2 )
203{
204 struct callback_WtoA_context *callback_ctx = context;
205 char buffer[MAX_PATH];
206 UINT ret;
207 UINT_PTR old_param2 = param2;
208
209 switch(notification)
210 {
211 case SPFILENOTIFY_COPYERROR:
212 param2 = (UINT_PTR)&buffer;
213 /* fall through */
214 case SPFILENOTIFY_STARTDELETE:
215 case SPFILENOTIFY_ENDDELETE:
216 case SPFILENOTIFY_DELETEERROR:
217 case SPFILENOTIFY_STARTRENAME:
218 case SPFILENOTIFY_ENDRENAME:
219 case SPFILENOTIFY_RENAMEERROR:
220 case SPFILENOTIFY_STARTCOPY:
221 case SPFILENOTIFY_ENDCOPY:
222 {
223 FILEPATHS_W *pathsW = (FILEPATHS_W *)param1;
224 FILEPATHS_A pathsA;
225
226 pathsA.Source = strdupWtoA( pathsW->Source );
227 pathsA.Target = strdupWtoA( pathsW->Target );
228 pathsA.Win32Error = pathsW->Win32Error;
229 pathsA.Flags = pathsW->Flags;
230 ret = callback_ctx->orig_handler( callback_ctx->orig_context, notification,
231 (UINT_PTR)&pathsA, param2 );
232 HeapFree( GetProcessHeap(), 0, (void *)pathsA.Source );
233 HeapFree( GetProcessHeap(), 0, (void *)pathsA.Target );
234 }
235 if (notification == SPFILENOTIFY_COPYERROR)
236 MultiByteToWideChar( CP_ACP, 0, buffer, -1, (WCHAR *)old_param2, MAX_PATH );
237 break;
238
239 case SPFILENOTIFY_NEEDMEDIA:
240 case SPFILENOTIFY_QUEUESCAN:
241 FIXME("mapping for %d not implemented\n",notification);
242 case SPFILENOTIFY_STARTQUEUE:
243 case SPFILENOTIFY_ENDQUEUE:
244 case SPFILENOTIFY_STARTSUBQUEUE:
245 case SPFILENOTIFY_ENDSUBQUEUE:
246 default:
247 ret = callback_ctx->orig_handler( callback_ctx->orig_context, notification, param1, param2 );
248 break;
249 }
250 return ret;
251}
252
253
254/***********************************************************************
255 * get_src_file_info
256 *
257 * Retrieve the source file information for a given file.
258 */
259static void get_src_file_info( HINF hinf, struct file_op *op )
260{
261 static const WCHAR SourceDisksNames[] =
262 {'S','o','u','r','c','e','D','i','s','k','s','N','a','m','e','s',0};
263 static const WCHAR SourceDisksFiles[] =
264 {'S','o','u','r','c','e','D','i','s','k','s','F','i','l','e','s',0};
265
266 INFCONTEXT file_ctx, disk_ctx;
267 INT id, diskid;
268 DWORD len, len2;
269
270 /* find the SourceDisksFiles entry */
271 if (!SetupFindFirstLineW( hinf, SourceDisksFiles, op->src_file, &file_ctx ))
272 {
273 const WCHAR *dir;
274
275 if ((op->style & (SP_COPY_SOURCE_ABSOLUTE|SP_COPY_SOURCEPATH_ABSOLUTE))) return;
276 /* no specific info, use .inf file source directory */
277 if (!op->src_root && (dir = DIRID_get_string( hinf, DIRID_SRCPATH )))
278 op->src_root = strdupW( dir );
279 return;
280 }
281 if (!SetupGetIntField( &file_ctx, 1, &diskid )) return;
282
283 /* now find the diskid in the SourceDisksNames section */
284 if (!SetupFindFirstLineW( hinf, SourceDisksNames, NULL, &disk_ctx )) return;
285 for (;;)
286 {
287 if (SetupGetIntField( &disk_ctx, 0, &id ) && (id == diskid)) break;
288 if (!SetupFindNextLine( &disk_ctx, &disk_ctx )) return;
289 }
290
291 /* and fill in the missing info */
292
293 if (!op->src_descr)
294 {
295 if (SetupGetStringFieldW( &disk_ctx, 1, NULL, 0, &len ) &&
296 (op->src_descr = HeapAlloc( GetProcessHeap(), 0, len*sizeof(WCHAR) )))
297 SetupGetStringFieldW( &disk_ctx, 1, op->src_descr, len, NULL );
298 }
299 if (!op->src_tag)
300 {
301 if (SetupGetStringFieldW( &disk_ctx, 2, NULL, 0, &len ) &&
302 (op->src_tag = HeapAlloc( GetProcessHeap(), 0, len*sizeof(WCHAR) )))
303 SetupGetStringFieldW( &disk_ctx, 2, op->src_tag, len, NULL );
304 }
305 if (!op->src_path && !(op->style & SP_COPY_SOURCE_ABSOLUTE))
306 {
307 if (!(op->style & SP_COPY_SOURCEPATH_ABSOLUTE))
308 {
309 /* retrieve relative path for this disk */
310 if (!SetupGetStringFieldW( &disk_ctx, 4, NULL, 0, &len )) len = 0;
311 }
312 /* retrieve relative path for this file */
313 if (!SetupGetStringFieldW( &file_ctx, 2, NULL, 0, &len2 )) len2 = 0;
314
315 if ((len || len2) &&
316 (op->src_path = HeapAlloc( GetProcessHeap(), 0, (len+len2)*sizeof(WCHAR) )))
317 {
318 WCHAR *ptr = op->src_path;
319 if (len)
320 {
321 SetupGetStringFieldW( &disk_ctx, 4, op->src_path, len, NULL );
322 ptr = op->src_path + strlenW(op->src_path);
323 if (len2 && ptr > op->src_path && ptr[-1] != '\\') *ptr++ = '\\';
324 }
325 if (!SetupGetStringFieldW( &disk_ctx, 4, ptr, len2, NULL )) *ptr = 0;
326 }
327 }
328 if (!op->src_root) op->src_root = strdupW( PARSER_get_src_root(hinf) );
329}
330
331
332/***********************************************************************
333 * get_destination_dir
334 *
335 * Retrieve the destination dir for a given section.
336 */
337static WCHAR *get_destination_dir( HINF hinf, const WCHAR *section )
338{
339 static const WCHAR Dest[] = {'D','e','s','t','i','n','a','t','i','o','n','D','i','r','s',0};
340 static const WCHAR Def[] = {'D','e','f','a','u','l','t','D','e','s','t','D','i','r',0};
341
342 const WCHAR *dir;
343 WCHAR *ptr, *ret;
344 INFCONTEXT context;
345 INT dirid;
346 DWORD len1, len2;
347
348 if (!SetupFindFirstLineW( hinf, Dest, section, &context ) &&
349 !SetupFindFirstLineW( hinf, Dest, Def, &context )) return NULL;
350 if (!SetupGetIntField( &context, 1, &dirid )) return NULL;
351 if (!(dir = DIRID_get_string( hinf, dirid ))) return NULL;
352 len1 = strlenW(dir) + 1;
353 if (!SetupGetStringFieldW( &context, 2, NULL, 0, &len2 )) len2 = 0;
354 if (!(ret = HeapAlloc( GetProcessHeap(), 0, (len1+len2) * sizeof(WCHAR) ))) return NULL;
355 strcpyW( ret, dir );
356 ptr = ret + strlenW(ret);
357 if (len2 && ptr > ret && ptr[-1] != '\\') *ptr++ = '\\';
358 if (!SetupGetStringFieldW( &context, 2, ptr, len2, NULL )) *ptr = 0;
359 return ret;
360}
361
362
363#ifdef __WIN32OS2__
364static void (* WINAPI pExtractFiles)( LPSTR, LPSTR, DWORD, DWORD, DWORD, DWORD );
365#else
366static void (WINAPI *pExtractFiles)( LPSTR, LPSTR, DWORD, DWORD, DWORD, DWORD );
367#endif
368
369/***********************************************************************
370 * extract_cabinet_file
371 *
372 * Extract a file from a .cab file.
373 */
374static BOOL extract_cabinet_file( const WCHAR *cabinet, const WCHAR *root,
375 const WCHAR *src, const WCHAR *dst )
376{
377 static const WCHAR extW[] = {'.','c','a','b',0};
378 static HMODULE advpack;
379
380 char *cab_path, *cab_file;
381 int len = strlenW( cabinet );
382
383 /* make sure the cabinet file has a .cab extension */
384 if (len <= 4 || strcmpiW( cabinet + len - 4, extW )) return FALSE;
385 if (!pExtractFiles)
386 {
387 if (!advpack && !(advpack = LoadLibraryA( "advpack.dll" )))
388 {
389 ERR( "could not load advpack.dll\n" );
390 return FALSE;
391 }
392 if (!(pExtractFiles = (void *)GetProcAddress( advpack, "ExtractFiles" )))
393 {
394 ERR( "could not find ExtractFiles in advpack.dll\n" );
395 return FALSE;
396 }
397 }
398
399 if (!(cab_path = strdupWtoA( root ))) return FALSE;
400 len = WideCharToMultiByte( CP_ACP, 0, cabinet, -1, NULL, 0, NULL, NULL );
401 if (!(cab_file = HeapAlloc( GetProcessHeap(), 0, strlen(cab_path) + len + 1 )))
402 {
403 HeapFree( GetProcessHeap(), 0, cab_path );
404 return FALSE;
405 }
406 strcpy( cab_file, cab_path );
407 if (cab_file[0] && cab_file[strlen(cab_file)-1] != '\\') strcat( cab_file, "\\" );
408 WideCharToMultiByte( CP_ACP, 0, cabinet, -1, cab_file + strlen(cab_file), len, NULL, NULL );
409 FIXME( "awful hack: extracting cabinet %s\n", debugstr_a(cab_file) );
410 pExtractFiles( cab_file, cab_path, 0, 0, 0, 0 );
411 HeapFree( GetProcessHeap(), 0, cab_file );
412 HeapFree( GetProcessHeap(), 0, cab_path );
413 return CopyFileW( src, dst, FALSE /*FIXME*/ );
414}
415
416
417/***********************************************************************
418 * SetupOpenFileQueue (SETUPAPI.@)
419 */
420HSPFILEQ WINAPI SetupOpenFileQueue(void)
421{
422 struct file_queue *queue;
423
424 if (!(queue = HeapAlloc( GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*queue))))
425 return (HSPFILEQ)INVALID_HANDLE_VALUE;
426 return queue;
427}
428
429
430/***********************************************************************
431 * SetupCloseFileQueue (SETUPAPI.@)
432 */
433BOOL WINAPI SetupCloseFileQueue( HSPFILEQ handle )
434{
435 struct file_queue *queue = handle;
436
437 free_file_op_queue( &queue->copy_queue );
438 free_file_op_queue( &queue->rename_queue );
439 free_file_op_queue( &queue->delete_queue );
440 HeapFree( GetProcessHeap(), 0, queue );
441 return TRUE;
442}
443
444
445/***********************************************************************
446 * SetupQueueCopyIndirectA (SETUPAPI.@)
447 */
448BOOL WINAPI SetupQueueCopyIndirectA( PSP_FILE_COPY_PARAMS_A params )
449{
450 struct file_queue *queue = params->QueueHandle;
451 struct file_op *op;
452
453 if (!(op = HeapAlloc( GetProcessHeap(), 0, sizeof(*op) ))) return FALSE;
454 op->style = params->CopyStyle;
455 op->src_root = strdupAtoW( params->SourceRootPath );
456 op->src_path = strdupAtoW( params->SourcePath );
457 op->src_file = strdupAtoW( params->SourceFilename );
458 op->src_descr = strdupAtoW( params->SourceDescription );
459 op->src_tag = strdupAtoW( params->SourceTagfile );
460 op->dst_path = strdupAtoW( params->TargetDirectory );
461 op->dst_file = strdupAtoW( params->TargetFilename );
462
463 /* some defaults */
464 if (!op->src_file) op->src_file = op->dst_file;
465 if (params->LayoutInf)
466 {
467 get_src_file_info( params->LayoutInf, op );
468 if (!op->dst_path) op->dst_path = get_destination_dir( params->LayoutInf, op->dst_file );
469 }
470
471 TRACE( "root=%s path=%s file=%s -> dir=%s file=%s descr=%s tag=%s\n",
472 debugstr_w(op->src_root), debugstr_w(op->src_path), debugstr_w(op->src_file),
473 debugstr_w(op->dst_path), debugstr_w(op->dst_file),
474 debugstr_w(op->src_descr), debugstr_w(op->src_tag) );
475
476 queue_file_op( &queue->copy_queue, op );
477 return TRUE;
478}
479
480
481/***********************************************************************
482 * SetupQueueCopyIndirectW (SETUPAPI.@)
483 */
484BOOL WINAPI SetupQueueCopyIndirectW( PSP_FILE_COPY_PARAMS_W params )
485{
486 struct file_queue *queue = params->QueueHandle;
487 struct file_op *op;
488
489 if (!(op = HeapAlloc( GetProcessHeap(), 0, sizeof(*op) ))) return FALSE;
490 op->style = params->CopyStyle;
491 op->src_root = strdupW( params->SourceRootPath );
492 op->src_path = strdupW( params->SourcePath );
493 op->src_file = strdupW( params->SourceFilename );
494 op->src_descr = strdupW( params->SourceDescription );
495 op->src_tag = strdupW( params->SourceTagfile );
496 op->dst_path = strdupW( params->TargetDirectory );
497 op->dst_file = strdupW( params->TargetFilename );
498
499 /* some defaults */
500 if (!op->src_file) op->src_file = op->dst_file;
501 if (params->LayoutInf)
502 {
503 get_src_file_info( params->LayoutInf, op );
504 if (!op->dst_path) op->dst_path = get_destination_dir( params->LayoutInf, op->dst_file );
505 }
506
507 TRACE( "root=%s path=%s file=%s -> dir=%s file=%s descr=%s tag=%s\n",
508 debugstr_w(op->src_root), debugstr_w(op->src_path), debugstr_w(op->src_file),
509 debugstr_w(op->dst_path), debugstr_w(op->dst_file),
510 debugstr_w(op->src_descr), debugstr_w(op->src_tag) );
511
512 queue_file_op( &queue->copy_queue, op );
513 return TRUE;
514}
515
516
517/***********************************************************************
518 * SetupQueueCopyA (SETUPAPI.@)
519 */
520BOOL WINAPI SetupQueueCopyA( HSPFILEQ queue, PCSTR src_root, PCSTR src_path, PCSTR src_file,
521 PCSTR src_descr, PCSTR src_tag, PCSTR dst_dir, PCSTR dst_file,
522 DWORD style )
523{
524 SP_FILE_COPY_PARAMS_A params;
525
526 params.cbSize = sizeof(params);
527 params.QueueHandle = queue;
528 params.SourceRootPath = src_root;
529 params.SourcePath = src_path;
530 params.SourceFilename = src_file;
531 params.SourceDescription = src_descr;
532 params.SourceTagfile = src_tag;
533 params.TargetDirectory = dst_dir;
534 params.TargetFilename = dst_file;
535 params.CopyStyle = style;
536 params.LayoutInf = 0;
537 params.SecurityDescriptor = NULL;
538 return SetupQueueCopyIndirectA( &params );
539}
540
541
542/***********************************************************************
543 * SetupQueueCopyW (SETUPAPI.@)
544 */
545BOOL WINAPI SetupQueueCopyW( HSPFILEQ queue, PCWSTR src_root, PCWSTR src_path, PCWSTR src_file,
546 PCWSTR src_descr, PCWSTR src_tag, PCWSTR dst_dir, PCWSTR dst_file,
547 DWORD style )
548{
549 SP_FILE_COPY_PARAMS_W params;
550
551 params.cbSize = sizeof(params);
552 params.QueueHandle = queue;
553 params.SourceRootPath = src_root;
554 params.SourcePath = src_path;
555 params.SourceFilename = src_file;
556 params.SourceDescription = src_descr;
557 params.SourceTagfile = src_tag;
558 params.TargetDirectory = dst_dir;
559 params.TargetFilename = dst_file;
560 params.CopyStyle = style;
561 params.LayoutInf = 0;
562 params.SecurityDescriptor = NULL;
563 return SetupQueueCopyIndirectW( &params );
564}
565
566
567/***********************************************************************
568 * SetupQueueDefaultCopyA (SETUPAPI.@)
569 */
570BOOL WINAPI SetupQueueDefaultCopyA( HSPFILEQ queue, HINF hinf, PCSTR src_root, PCSTR src_file,
571 PCSTR dst_file, DWORD style )
572{
573 SP_FILE_COPY_PARAMS_A params;
574
575 params.cbSize = sizeof(params);
576 params.QueueHandle = queue;
577 params.SourceRootPath = src_root;
578 params.SourcePath = NULL;
579 params.SourceFilename = src_file;
580 params.SourceDescription = NULL;
581 params.SourceTagfile = NULL;
582 params.TargetDirectory = NULL;
583 params.TargetFilename = dst_file;
584 params.CopyStyle = style;
585 params.LayoutInf = hinf;
586 params.SecurityDescriptor = NULL;
587 return SetupQueueCopyIndirectA( &params );
588}
589
590
591/***********************************************************************
592 * SetupQueueDefaultCopyW (SETUPAPI.@)
593 */
594BOOL WINAPI SetupQueueDefaultCopyW( HSPFILEQ queue, HINF hinf, PCWSTR src_root, PCWSTR src_file,
595 PCWSTR dst_file, DWORD style )
596{
597 SP_FILE_COPY_PARAMS_W params;
598
599 params.cbSize = sizeof(params);
600 params.QueueHandle = queue;
601 params.SourceRootPath = src_root;
602 params.SourcePath = NULL;
603 params.SourceFilename = src_file;
604 params.SourceDescription = NULL;
605 params.SourceTagfile = NULL;
606 params.TargetDirectory = NULL;
607 params.TargetFilename = dst_file;
608 params.CopyStyle = style;
609 params.LayoutInf = hinf;
610 params.SecurityDescriptor = NULL;
611 return SetupQueueCopyIndirectW( &params );
612}
613
614
615/***********************************************************************
616 * SetupQueueDeleteA (SETUPAPI.@)
617 */
618BOOL WINAPI SetupQueueDeleteA( HSPFILEQ handle, PCSTR part1, PCSTR part2 )
619{
620 struct file_queue *queue = handle;
621 struct file_op *op;
622
623 if (!(op = HeapAlloc( GetProcessHeap(), 0, sizeof(*op) ))) return FALSE;
624 op->style = 0;
625 op->src_root = NULL;
626 op->src_path = NULL;
627 op->src_file = NULL;
628 op->src_descr = NULL;
629 op->src_tag = NULL;
630 op->dst_path = strdupAtoW( part1 );
631 op->dst_file = strdupAtoW( part2 );
632 queue_file_op( &queue->delete_queue, op );
633 return TRUE;
634}
635
636
637/***********************************************************************
638 * SetupQueueDeleteW (SETUPAPI.@)
639 */
640BOOL WINAPI SetupQueueDeleteW( HSPFILEQ handle, PCWSTR part1, PCWSTR part2 )
641{
642 struct file_queue *queue = handle;
643 struct file_op *op;
644
645 if (!(op = HeapAlloc( GetProcessHeap(), 0, sizeof(*op) ))) return FALSE;
646 op->style = 0;
647 op->src_root = NULL;
648 op->src_path = NULL;
649 op->src_file = NULL;
650 op->src_descr = NULL;
651 op->src_tag = NULL;
652 op->dst_path = strdupW( part1 );
653 op->dst_file = strdupW( part2 );
654 queue_file_op( &queue->delete_queue, op );
655 return TRUE;
656}
657
658
659/***********************************************************************
660 * SetupQueueRenameA (SETUPAPI.@)
661 */
662BOOL WINAPI SetupQueueRenameA( HSPFILEQ handle, PCSTR SourcePath, PCSTR SourceFilename,
663 PCSTR TargetPath, PCSTR TargetFilename )
664{
665 struct file_queue *queue = handle;
666 struct file_op *op;
667
668 if (!(op = HeapAlloc( GetProcessHeap(), 0, sizeof(*op) ))) return FALSE;
669 op->style = 0;
670 op->src_root = NULL;
671 op->src_path = strdupAtoW( SourcePath );
672 op->src_file = strdupAtoW( SourceFilename );
673 op->src_descr = NULL;
674 op->src_tag = NULL;
675 op->dst_path = strdupAtoW( TargetPath );
676 op->dst_file = strdupAtoW( TargetFilename );
677 queue_file_op( &queue->rename_queue, op );
678 return TRUE;
679}
680
681
682/***********************************************************************
683 * SetupQueueRenameW (SETUPAPI.@)
684 */
685BOOL WINAPI SetupQueueRenameW( HSPFILEQ handle, PCWSTR SourcePath, PCWSTR SourceFilename,
686 PCWSTR TargetPath, PCWSTR TargetFilename )
687{
688 struct file_queue *queue = handle;
689 struct file_op *op;
690
691 if (!(op = HeapAlloc( GetProcessHeap(), 0, sizeof(*op) ))) return FALSE;
692 op->style = 0;
693 op->src_root = NULL;
694 op->src_path = strdupW( SourcePath );
695 op->src_file = strdupW( SourceFilename );
696 op->src_descr = NULL;
697 op->src_tag = NULL;
698 op->dst_path = strdupW( TargetPath );
699 op->dst_file = strdupW( TargetFilename );
700 queue_file_op( &queue->rename_queue, op );
701 return TRUE;
702}
703
704
705/***********************************************************************
706 * SetupQueueCopySectionA (SETUPAPI.@)
707 */
708BOOL WINAPI SetupQueueCopySectionA( HSPFILEQ queue, PCSTR src_root, HINF hinf, HINF hlist,
709 PCSTR section, DWORD style )
710{
711 UNICODE_STRING sectionW;
712 BOOL ret = FALSE;
713
714 if (!RtlCreateUnicodeStringFromAsciiz( &sectionW, section ))
715 {
716 SetLastError( ERROR_NOT_ENOUGH_MEMORY );
717 return FALSE;
718 }
719 if (!src_root)
720 ret = SetupQueueCopySectionW( queue, NULL, hinf, hlist, sectionW.Buffer, style );
721 else
722 {
723 UNICODE_STRING srcW;
724 if (RtlCreateUnicodeStringFromAsciiz( &srcW, src_root ))
725 {
726 ret = SetupQueueCopySectionW( queue, srcW.Buffer, hinf, hlist, sectionW.Buffer, style );
727 RtlFreeUnicodeString( &srcW );
728 }
729 else SetLastError( ERROR_NOT_ENOUGH_MEMORY );
730 }
731 RtlFreeUnicodeString( &sectionW );
732 return ret;
733}
734
735
736/***********************************************************************
737 * SetupQueueCopySectionW (SETUPAPI.@)
738 */
739BOOL WINAPI SetupQueueCopySectionW( HSPFILEQ queue, PCWSTR src_root, HINF hinf, HINF hlist,
740 PCWSTR section, DWORD style )
741{
742 SP_FILE_COPY_PARAMS_W params;
743 INFCONTEXT context;
744 WCHAR dest[MAX_PATH], src[MAX_PATH];
745 INT flags;
746
747 TRACE( "hinf=%p/%p section=%s root=%s\n",
748 hinf, hlist, debugstr_w(section), debugstr_w(src_root) );
749
750 params.cbSize = sizeof(params);
751 params.QueueHandle = queue;
752 params.SourceRootPath = src_root;
753 params.SourcePath = NULL;
754 params.SourceDescription = NULL;
755 params.SourceTagfile = NULL;
756 params.TargetFilename = dest;
757 params.CopyStyle = style;
758 params.LayoutInf = hinf;
759 params.SecurityDescriptor = NULL;
760
761 if (!hlist) hlist = hinf;
762 if (!SetupFindFirstLineW( hlist, section, NULL, &context )) return FALSE;
763 if (!(params.TargetDirectory = get_destination_dir( hinf, section ))) return FALSE;
764 do
765 {
766 if (!SetupGetStringFieldW( &context, 1, dest, sizeof(dest)/sizeof(WCHAR), NULL ))
767 return FALSE;
768 if (!SetupGetStringFieldW( &context, 2, src, sizeof(src)/sizeof(WCHAR), NULL )) *src = 0;
769 if (!SetupGetIntField( &context, 4, &flags )) flags = 0; /* FIXME */
770
771 params.SourceFilename = *src ? src : NULL;
772 if (!SetupQueueCopyIndirectW( &params )) return FALSE;
773 } while (SetupFindNextLine( &context, &context ));
774 return TRUE;
775}
776
777
778/***********************************************************************
779 * SetupQueueDeleteSectionA (SETUPAPI.@)
780 */
781BOOL WINAPI SetupQueueDeleteSectionA( HSPFILEQ queue, HINF hinf, HINF hlist, PCSTR section )
782{
783 UNICODE_STRING sectionW;
784 BOOL ret = FALSE;
785
786 if (RtlCreateUnicodeStringFromAsciiz( &sectionW, section ))
787 {
788 ret = SetupQueueDeleteSectionW( queue, hinf, hlist, sectionW.Buffer );
789 RtlFreeUnicodeString( &sectionW );
790 }
791 else SetLastError( ERROR_NOT_ENOUGH_MEMORY );
792 return ret;
793}
794
795
796/***********************************************************************
797 * SetupQueueDeleteSectionW (SETUPAPI.@)
798 */
799BOOL WINAPI SetupQueueDeleteSectionW( HSPFILEQ queue, HINF hinf, HINF hlist, PCWSTR section )
800{
801 INFCONTEXT context;
802 WCHAR *dest_dir;
803 WCHAR buffer[MAX_PATH];
804 BOOL ret = FALSE;
805 INT flags;
806
807 TRACE( "hinf=%p/%p section=%s\n", hinf, hlist, debugstr_w(section) );
808
809 if (!hlist) hlist = hinf;
810 if (!SetupFindFirstLineW( hlist, section, NULL, &context )) return FALSE;
811 if (!(dest_dir = get_destination_dir( hinf, section ))) return FALSE;
812 do
813 {
814 if (!SetupGetStringFieldW( &context, 1, buffer, sizeof(buffer)/sizeof(WCHAR), NULL ))
815 goto done;
816 if (!SetupGetIntField( &context, 4, &flags )) flags = 0;
817 if (!SetupQueueDeleteW( queue, dest_dir, buffer )) goto done;
818 } while (SetupFindNextLine( &context, &context ));
819
820 ret = TRUE;
821 done:
822 HeapFree( GetProcessHeap(), 0, dest_dir );
823 return ret;
824}
825
826
827/***********************************************************************
828 * SetupQueueRenameSectionA (SETUPAPI.@)
829 */
830BOOL WINAPI SetupQueueRenameSectionA( HSPFILEQ queue, HINF hinf, HINF hlist, PCSTR section )
831{
832 UNICODE_STRING sectionW;
833 BOOL ret = FALSE;
834
835 if (RtlCreateUnicodeStringFromAsciiz( &sectionW, section ))
836 {
837 ret = SetupQueueRenameSectionW( queue, hinf, hlist, sectionW.Buffer );
838 RtlFreeUnicodeString( &sectionW );
839 }
840 else SetLastError( ERROR_NOT_ENOUGH_MEMORY );
841 return ret;
842}
843
844
845/***********************************************************************
846 * SetupQueueRenameSectionW (SETUPAPI.@)
847 */
848BOOL WINAPI SetupQueueRenameSectionW( HSPFILEQ queue, HINF hinf, HINF hlist, PCWSTR section )
849{
850 INFCONTEXT context;
851 WCHAR *dest_dir;
852 WCHAR src[MAX_PATH], dst[MAX_PATH];
853 BOOL ret = FALSE;
854
855 TRACE( "hinf=%p/%p section=%s\n", hinf, hlist, debugstr_w(section) );
856
857 if (!hlist) hlist = hinf;
858 if (!SetupFindFirstLineW( hlist, section, NULL, &context )) return FALSE;
859 if (!(dest_dir = get_destination_dir( hinf, section ))) return FALSE;
860 do
861 {
862 if (!SetupGetStringFieldW( &context, 1, dst, sizeof(dst)/sizeof(WCHAR), NULL ))
863 goto done;
864 if (!SetupGetStringFieldW( &context, 2, src, sizeof(src)/sizeof(WCHAR), NULL ))
865 goto done;
866 if (!SetupQueueRenameW( queue, dest_dir, src, NULL, dst )) goto done;
867 } while (SetupFindNextLine( &context, &context ));
868
869 ret = TRUE;
870 done:
871 HeapFree( GetProcessHeap(), 0, dest_dir );
872 return ret;
873}
874
875
876/***********************************************************************
877 * SetupCommitFileQueueA (SETUPAPI.@)
878 */
879BOOL WINAPI SetupCommitFileQueueA( HWND owner, HSPFILEQ queue, PSP_FILE_CALLBACK_A handler,
880 PVOID context )
881{
882 struct callback_WtoA_context ctx;
883
884 ctx.orig_context = context;
885 ctx.orig_handler = handler;
886 return SetupCommitFileQueueW( owner, queue, QUEUE_callback_WtoA, &ctx );
887}
888
889
890/***********************************************************************
891 * create_full_pathW
892 *
893 * Recursively create all directories in the path.
894 */
895static BOOL create_full_pathW(const WCHAR *path)
896{
897 BOOL ret = TRUE;
898 int len;
899 WCHAR *new_path;
900
901 new_path = HeapAlloc(GetProcessHeap(), 0, (strlenW(path) + 1) * sizeof(WCHAR));
902 strcpyW(new_path, path);
903
904 while((len = strlenW(new_path)) && new_path[len - 1] == '\\')
905 new_path[len - 1] = 0;
906
907 while(!CreateDirectoryW(new_path, NULL))
908 {
909 WCHAR *slash;
910 DWORD last_error = GetLastError();
911
912 if(last_error == ERROR_ALREADY_EXISTS)
913 break;
914
915 if(last_error != ERROR_PATH_NOT_FOUND)
916 {
917 ret = FALSE;
918 break;
919 }
920
921 if(!(slash = strrchrW(new_path, '\\')))
922 {
923 ret = FALSE;
924 break;
925 }
926
927 len = slash - new_path;
928 new_path[len] = 0;
929 if(!create_full_pathW(new_path))
930 {
931 ret = FALSE;
932 break;
933 }
934 new_path[len] = '\\';
935 }
936
937 HeapFree(GetProcessHeap(), 0, new_path);
938 return ret;
939}
940
941
942/***********************************************************************
943 * SetupCommitFileQueueW (SETUPAPI.@)
944 */
945BOOL WINAPI SetupCommitFileQueueW( HWND owner, HSPFILEQ handle, PSP_FILE_CALLBACK_W handler,
946 PVOID context )
947{
948 struct file_queue *queue = handle;
949 struct file_op *op;
950 BOOL result = FALSE;
951 FILEPATHS_W paths;
952 UINT op_result;
953
954 paths.Source = paths.Target = NULL;
955
956 if (!queue->copy_queue.count && !queue->delete_queue.count && !queue->rename_queue.count)
957 return TRUE; /* nothing to do */
958
959 if (!handler( context, SPFILENOTIFY_STARTQUEUE, owner, 0 )) return FALSE;
960
961 /* perform deletes */
962
963 if (queue->delete_queue.count)
964 {
965 if (!(handler( context, SPFILENOTIFY_STARTSUBQUEUE, FILEOP_DELETE,
966 queue->delete_queue.count ))) goto done;
967 for (op = queue->delete_queue.head; op; op = op->next)
968 {
969 build_filepathsW( op, &paths );
970 op_result = handler( context, SPFILENOTIFY_STARTDELETE, (UINT_PTR)&paths, FILEOP_DELETE);
971 if (op_result == FILEOP_ABORT) goto done;
972 while (op_result == FILEOP_DOIT)
973 {
974 TRACE( "deleting file %s\n", debugstr_w(paths.Target) );
975 if (DeleteFileW( paths.Target )) break; /* success */
976 paths.Win32Error = GetLastError();
977 op_result = handler( context, SPFILENOTIFY_DELETEERROR, (UINT_PTR)&paths, 0 );
978 if (op_result == FILEOP_ABORT) goto done;
979 }
980 handler( context, SPFILENOTIFY_ENDDELETE, (UINT_PTR)&paths, 0 );
981 }
982 handler( context, SPFILENOTIFY_ENDSUBQUEUE, FILEOP_DELETE, 0 );
983 }
984
985 /* perform renames */
986
987 if (queue->rename_queue.count)
988 {
989 if (!(handler( context, SPFILENOTIFY_STARTSUBQUEUE, FILEOP_RENAME,
990 queue->rename_queue.count ))) goto done;
991 for (op = queue->rename_queue.head; op; op = op->next)
992 {
993 build_filepathsW( op, &paths );
994 op_result = handler( context, SPFILENOTIFY_STARTRENAME, (UINT_PTR)&paths, FILEOP_RENAME);
995 if (op_result == FILEOP_ABORT) goto done;
996 while (op_result == FILEOP_DOIT)
997 {
998 TRACE( "renaming file %s -> %s\n",
999 debugstr_w(paths.Source), debugstr_w(paths.Target) );
1000 if (MoveFileW( paths.Source, paths.Target )) break; /* success */
1001 paths.Win32Error = GetLastError();
1002 op_result = handler( context, SPFILENOTIFY_RENAMEERROR, (UINT_PTR)&paths, 0 );
1003 if (op_result == FILEOP_ABORT) goto done;
1004 }
1005 handler( context, SPFILENOTIFY_ENDRENAME, (UINT_PTR)&paths, 0 );
1006 }
1007 handler( context, SPFILENOTIFY_ENDSUBQUEUE, FILEOP_RENAME, 0 );
1008 }
1009
1010 /* perform copies */
1011
1012 if (queue->copy_queue.count)
1013 {
1014 if (!(handler( context, SPFILENOTIFY_STARTSUBQUEUE, FILEOP_COPY,
1015 queue->copy_queue.count ))) goto done;
1016 for (op = queue->copy_queue.head; op; op = op->next)
1017 {
1018 WCHAR newpath[MAX_PATH];
1019
1020 build_filepathsW( op, &paths );
1021 op_result = handler( context, SPFILENOTIFY_STARTCOPY, (UINT_PTR)&paths, FILEOP_COPY );
1022 if (op_result == FILEOP_ABORT) goto done;
1023 if (op_result == FILEOP_NEWPATH) op_result = FILEOP_DOIT;
1024 while (op_result == FILEOP_DOIT || op_result == FILEOP_NEWPATH)
1025 {
1026 TRACE( "copying file %s -> %s\n",
1027 debugstr_w( op_result == FILEOP_NEWPATH ? newpath : paths.Source ),
1028 debugstr_w(paths.Target) );
1029 if (op->dst_path)
1030 {
1031 if (!create_full_pathW( op->dst_path ))
1032 {
1033 paths.Win32Error = GetLastError();
1034 op_result = handler( context, SPFILENOTIFY_COPYERROR,
1035 (UINT_PTR)&paths, (UINT_PTR)newpath );
1036 if (op_result == FILEOP_ABORT) goto done;
1037 }
1038 }
1039 if (CopyFileW( op_result == FILEOP_NEWPATH ? newpath : paths.Source,
1040 paths.Target, FALSE /*FIXME*/ )) break; /* success */
1041 /* try to extract it from the cabinet file */
1042 if (op->src_tag)
1043 {
1044 if (extract_cabinet_file( op->src_tag, op->src_root,
1045 paths.Source, paths.Target )) break;
1046 }
1047 paths.Win32Error = GetLastError();
1048 op_result = handler( context, SPFILENOTIFY_COPYERROR,
1049 (UINT_PTR)&paths, (UINT_PTR)newpath );
1050 if (op_result == FILEOP_ABORT) goto done;
1051 }
1052 handler( context, SPFILENOTIFY_ENDCOPY, (UINT_PTR)&paths, 0 );
1053 }
1054 handler( context, SPFILENOTIFY_ENDSUBQUEUE, FILEOP_COPY, 0 );
1055 }
1056
1057
1058 result = TRUE;
1059
1060 done:
1061 handler( context, SPFILENOTIFY_ENDQUEUE, result, 0 );
1062 HeapFree( GetProcessHeap(), 0, (void *)paths.Source );
1063 HeapFree( GetProcessHeap(), 0, (void *)paths.Target );
1064 return result;
1065}
1066
1067
1068/***********************************************************************
1069 * SetupScanFileQueueA (SETUPAPI.@)
1070 */
1071BOOL WINAPI SetupScanFileQueueA( HSPFILEQ queue, DWORD flags, HWND window,
1072 PSP_FILE_CALLBACK_A callback, PVOID context, PDWORD result )
1073{
1074 FIXME("stub\n");
1075 return FALSE;
1076}
1077
1078
1079/***********************************************************************
1080 * SetupScanFileQueueW (SETUPAPI.@)
1081 */
1082BOOL WINAPI SetupScanFileQueueW( HSPFILEQ queue, DWORD flags, HWND window,
1083 PSP_FILE_CALLBACK_W callback, PVOID context, PDWORD result )
1084{
1085 FIXME("stub\n");
1086 return FALSE;
1087}
1088
1089
1090/***********************************************************************
1091 * SetupGetFileQueueCount (SETUPAPI.@)
1092 */
1093BOOL WINAPI SetupGetFileQueueCount( HSPFILEQ handle, UINT op, PUINT result )
1094{
1095 struct file_queue *queue = handle;
1096
1097 switch(op)
1098 {
1099 case FILEOP_COPY:
1100 *result = queue->copy_queue.count;
1101 return TRUE;
1102 case FILEOP_RENAME:
1103 *result = queue->rename_queue.count;
1104 return TRUE;
1105 case FILEOP_DELETE:
1106 *result = queue->delete_queue.count;
1107 return TRUE;
1108 }
1109 return FALSE;
1110}
1111
1112
1113/***********************************************************************
1114 * SetupGetFileQueueFlags (SETUPAPI.@)
1115 */
1116BOOL WINAPI SetupGetFileQueueFlags( HSPFILEQ handle, PDWORD flags )
1117{
1118 struct file_queue *queue = handle;
1119 *flags = queue->flags;
1120 return TRUE;
1121}
1122
1123
1124/***********************************************************************
1125 * SetupSetFileQueueFlags (SETUPAPI.@)
1126 */
1127BOOL WINAPI SetupSetFileQueueFlags( HSPFILEQ handle, DWORD mask, DWORD flags )
1128{
1129 struct file_queue *queue = handle;
1130 queue->flags = (queue->flags & ~mask) | flags;
1131 return TRUE;
1132}
1133
1134
1135/***********************************************************************
1136 * SetupInitDefaultQueueCallback (SETUPAPI.@)
1137 */
1138PVOID WINAPI SetupInitDefaultQueueCallback( HWND owner )
1139{
1140 return SetupInitDefaultQueueCallbackEx( owner, 0, 0, 0, NULL );
1141}
1142
1143
1144/***********************************************************************
1145 * SetupInitDefaultQueueCallbackEx (SETUPAPI.@)
1146 */
1147PVOID WINAPI SetupInitDefaultQueueCallbackEx( HWND owner, HWND progress, UINT msg,
1148 DWORD reserved1, PVOID reserved2 )
1149{
1150 struct default_callback_context *context;
1151
1152 if ((context = HeapAlloc( GetProcessHeap(), 0, sizeof(*context) )))
1153 {
1154 context->owner = owner;
1155 context->progress = progress;
1156 context->message = msg;
1157 }
1158 return context;
1159}
1160
1161
1162/***********************************************************************
1163 * SetupTermDefaultQueueCallback (SETUPAPI.@)
1164 */
1165void WINAPI SetupTermDefaultQueueCallback( PVOID context )
1166{
1167 HeapFree( GetProcessHeap(), 0, context );
1168}
1169
1170
1171/***********************************************************************
1172 * SetupDefaultQueueCallbackA (SETUPAPI.@)
1173 */
1174UINT WINAPI SetupDefaultQueueCallbackA( PVOID context, UINT notification,
1175 UINT_PTR param1, UINT_PTR param2 )
1176{
1177 FILEPATHS_A *paths = (FILEPATHS_A *)param1;
1178
1179 switch(notification)
1180 {
1181 case SPFILENOTIFY_STARTQUEUE:
1182 TRACE( "start queue\n" );
1183 return TRUE;
1184 case SPFILENOTIFY_ENDQUEUE:
1185 TRACE( "end queue\n" );
1186 return 0;
1187 case SPFILENOTIFY_STARTSUBQUEUE:
1188 TRACE( "start subqueue %d count %d\n", param1, param2 );
1189 return TRUE;
1190 case SPFILENOTIFY_ENDSUBQUEUE:
1191 TRACE( "end subqueue %d\n", param1 );
1192 return 0;
1193 case SPFILENOTIFY_STARTDELETE:
1194 TRACE( "start delete %s\n", debugstr_a(paths->Target) );
1195 return FILEOP_DOIT;
1196 case SPFILENOTIFY_ENDDELETE:
1197 TRACE( "end delete %s\n", debugstr_a(paths->Target) );
1198 return 0;
1199 case SPFILENOTIFY_DELETEERROR:
1200 ERR( "delete error %d %s\n", paths->Win32Error, debugstr_a(paths->Target) );
1201 return FILEOP_SKIP;
1202 case SPFILENOTIFY_STARTRENAME:
1203 TRACE( "start rename %s -> %s\n", debugstr_a(paths->Source), debugstr_a(paths->Target) );
1204 return FILEOP_DOIT;
1205 case SPFILENOTIFY_ENDRENAME:
1206 TRACE( "end rename %s -> %s\n", debugstr_a(paths->Source), debugstr_a(paths->Target) );
1207 return 0;
1208 case SPFILENOTIFY_RENAMEERROR:
1209 ERR( "rename error %d %s -> %s\n", paths->Win32Error,
1210 debugstr_a(paths->Source), debugstr_a(paths->Target) );
1211 return FILEOP_SKIP;
1212 case SPFILENOTIFY_STARTCOPY:
1213 TRACE( "start copy %s -> %s\n", debugstr_a(paths->Source), debugstr_a(paths->Target) );
1214 return FILEOP_DOIT;
1215 case SPFILENOTIFY_ENDCOPY:
1216 TRACE( "end copy %s -> %s\n", debugstr_a(paths->Source), debugstr_a(paths->Target) );
1217 return 0;
1218 case SPFILENOTIFY_COPYERROR:
1219 ERR( "copy error %d %s -> %s\n", paths->Win32Error,
1220 debugstr_a(paths->Source), debugstr_a(paths->Target) );
1221 return FILEOP_SKIP;
1222 case SPFILENOTIFY_NEEDMEDIA:
1223 TRACE( "need media\n" );
1224 return FILEOP_SKIP;
1225 default:
1226 FIXME( "notification %d params %x,%x\n", notification, param1, param2 );
1227 break;
1228 }
1229 return 0;
1230}
1231
1232
1233/***********************************************************************
1234 * SetupDefaultQueueCallbackW (SETUPAPI.@)
1235 */
1236UINT WINAPI SetupDefaultQueueCallbackW( PVOID context, UINT notification,
1237 UINT_PTR param1, UINT_PTR param2 )
1238{
1239 FIXME( "notification %d params %x,%x\n", notification, param1, param2 );
1240 return FILEOP_SKIP;
1241}
Note: See TracBrowser for help on using the repository browser.