Initialize Xlib threading support to see what it breaks...
[wine.git] / dlls / setupapi / queue.c
blobb40f3047a04cdf48196be9901dd3ad1e557d3687
1 /*
2 * Setupapi file queue routines
4 * Copyright 2002 Alexandre Julliard for CodeWeavers
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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
21 #include <stdarg.h>
23 #include "windef.h"
24 #include "winbase.h"
25 #include "winreg.h"
26 #include "winternl.h"
27 #include "winerror.h"
28 #include "wingdi.h"
29 #include "winuser.h"
30 #include "winnls.h"
31 #include "setupapi.h"
32 #include "wine/unicode.h"
33 #include "setupapi_private.h"
34 #include "winver.h"
35 #include "wine/debug.h"
37 WINE_DEFAULT_DEBUG_CHANNEL(setupapi);
39 /* context structure for the default queue callback */
40 struct default_callback_context
42 HWND owner;
43 HWND progress;
44 UINT message;
47 struct file_op
49 struct file_op *next;
50 UINT style;
51 WCHAR *src_root;
52 WCHAR *src_path;
53 WCHAR *src_file;
54 WCHAR *src_descr;
55 WCHAR *src_tag;
56 WCHAR *dst_path;
57 WCHAR *dst_file;
60 struct file_op_queue
62 struct file_op *head;
63 struct file_op *tail;
64 unsigned int count;
67 struct file_queue
69 struct file_op_queue copy_queue;
70 struct file_op_queue delete_queue;
71 struct file_op_queue rename_queue;
72 DWORD flags;
76 inline static WCHAR *strdupW( const WCHAR *str )
78 WCHAR *ret = NULL;
79 if (str)
81 int len = (strlenW(str) + 1) * sizeof(WCHAR);
82 if ((ret = HeapAlloc( GetProcessHeap(), 0, len ))) memcpy( ret, str, len );
84 return ret;
88 inline static WCHAR *strdupAtoW( const char *str )
90 WCHAR *ret = NULL;
91 if (str)
93 DWORD len = MultiByteToWideChar( CP_ACP, 0, str, -1, NULL, 0 );
94 if ((ret = HeapAlloc( GetProcessHeap(), 0, len * sizeof(WCHAR) )))
95 MultiByteToWideChar( CP_ACP, 0, str, -1, ret, len );
97 return ret;
100 inline static char *strdupWtoA( const WCHAR *str )
102 char *ret = NULL;
103 if (str)
105 DWORD len = WideCharToMultiByte( CP_ACP, 0, str, -1, NULL, 0, NULL, NULL );
106 if ((ret = HeapAlloc( GetProcessHeap(), 0, len )))
107 WideCharToMultiByte( CP_ACP, 0, str, -1, ret, len, NULL, NULL );
109 return ret;
112 /* append a file operation to a queue */
113 inline static void queue_file_op( struct file_op_queue *queue, struct file_op *op )
115 op->next = NULL;
116 if (queue->tail) queue->tail->next = op;
117 else queue->head = op;
118 queue->tail = op;
119 queue->count++;
122 /* free all the file operations on a given queue */
123 static void free_file_op_queue( struct file_op_queue *queue )
125 struct file_op *t, *op = queue->head;
127 while( op )
129 HeapFree( GetProcessHeap(), 0, op->src_root );
130 HeapFree( GetProcessHeap(), 0, op->src_path );
131 HeapFree( GetProcessHeap(), 0, op->src_file );
132 HeapFree( GetProcessHeap(), 0, op->src_descr );
133 HeapFree( GetProcessHeap(), 0, op->src_tag );
134 HeapFree( GetProcessHeap(), 0, op->dst_path );
135 if (op->dst_file != op->src_file) HeapFree( GetProcessHeap(), 0, op->dst_file );
136 t = op;
137 op = op->next;
138 HeapFree( GetProcessHeap(), 0, t );
142 /* concat 3 strings to make a path, handling separators correctly */
143 static void concat_W( WCHAR *buffer, const WCHAR *src1, const WCHAR *src2, const WCHAR *src3 )
145 *buffer = 0;
146 if (src1 && *src1)
148 strcpyW( buffer, src1 );
149 buffer += strlenW(buffer );
150 if (buffer[-1] != '\\') *buffer++ = '\\';
151 if (src2) while (*src2 == '\\') src2++;
154 if (src2)
156 strcpyW( buffer, src2 );
157 buffer += strlenW(buffer );
158 if (buffer[-1] != '\\') *buffer++ = '\\';
159 if (src3) while (*src3 == '\\') src3++;
161 if (src3)
163 strcpyW( buffer, src3 );
164 buffer += strlenW(buffer );
169 /***********************************************************************
170 * build_filepathsW
172 * Build a FILEPATHS_W structure for a given file operation.
174 static BOOL build_filepathsW( const struct file_op *op, FILEPATHS_W *paths )
176 int src_len = 1, dst_len = 1;
177 WCHAR *source = (PWSTR)paths->Source, *target = (PWSTR)paths->Target;
179 if (op->src_root) src_len += strlenW(op->src_root) + 1;
180 if (op->src_path) src_len += strlenW(op->src_path) + 1;
181 if (op->src_file) src_len += strlenW(op->src_file) + 1;
182 if (op->dst_path) dst_len += strlenW(op->dst_path) + 1;
183 if (op->dst_file) dst_len += strlenW(op->dst_file) + 1;
184 src_len *= sizeof(WCHAR);
185 dst_len *= sizeof(WCHAR);
187 if (!source || HeapSize( GetProcessHeap(), 0, source ) < src_len )
189 HeapFree( GetProcessHeap(), 0, source );
190 paths->Source = source = HeapAlloc( GetProcessHeap(), 0, src_len );
192 if (!target || HeapSize( GetProcessHeap(), 0, target ) < dst_len )
194 HeapFree( GetProcessHeap(), 0, target );
195 paths->Target = target = HeapAlloc( GetProcessHeap(), 0, dst_len );
197 if (!source || !target) return FALSE;
198 concat_W( source, op->src_root, op->src_path, op->src_file );
199 concat_W( target, NULL, op->dst_path, op->dst_file );
200 paths->Win32Error = 0;
201 paths->Flags = 0;
202 return TRUE;
206 /***********************************************************************
207 * QUEUE_callback_WtoA
209 * Map a file callback parameters from W to A and call the A callback.
211 UINT CALLBACK QUEUE_callback_WtoA( void *context, UINT notification,
212 UINT_PTR param1, UINT_PTR param2 )
214 struct callback_WtoA_context *callback_ctx = context;
215 char buffer[MAX_PATH];
216 UINT ret;
217 UINT_PTR old_param2 = param2;
219 switch(notification)
221 case SPFILENOTIFY_COPYERROR:
222 param2 = (UINT_PTR)&buffer;
223 /* fall through */
224 case SPFILENOTIFY_STARTDELETE:
225 case SPFILENOTIFY_ENDDELETE:
226 case SPFILENOTIFY_DELETEERROR:
227 case SPFILENOTIFY_STARTRENAME:
228 case SPFILENOTIFY_ENDRENAME:
229 case SPFILENOTIFY_RENAMEERROR:
230 case SPFILENOTIFY_STARTCOPY:
231 case SPFILENOTIFY_ENDCOPY:
233 FILEPATHS_W *pathsW = (FILEPATHS_W *)param1;
234 FILEPATHS_A pathsA;
236 pathsA.Source = strdupWtoA( pathsW->Source );
237 pathsA.Target = strdupWtoA( pathsW->Target );
238 pathsA.Win32Error = pathsW->Win32Error;
239 pathsA.Flags = pathsW->Flags;
240 ret = callback_ctx->orig_handler( callback_ctx->orig_context, notification,
241 (UINT_PTR)&pathsA, param2 );
242 HeapFree( GetProcessHeap(), 0, (void *)pathsA.Source );
243 HeapFree( GetProcessHeap(), 0, (void *)pathsA.Target );
245 if (notification == SPFILENOTIFY_COPYERROR)
246 MultiByteToWideChar( CP_ACP, 0, buffer, -1, (WCHAR *)old_param2, MAX_PATH );
247 break;
249 case SPFILENOTIFY_NEEDMEDIA:
250 case SPFILENOTIFY_QUEUESCAN:
251 FIXME("mapping for %d not implemented\n",notification);
252 case SPFILENOTIFY_STARTQUEUE:
253 case SPFILENOTIFY_ENDQUEUE:
254 case SPFILENOTIFY_STARTSUBQUEUE:
255 case SPFILENOTIFY_ENDSUBQUEUE:
256 default:
257 ret = callback_ctx->orig_handler( callback_ctx->orig_context, notification, param1, param2 );
258 break;
260 return ret;
264 /***********************************************************************
265 * get_src_file_info
267 * Retrieve the source file information for a given file.
269 static void get_src_file_info( HINF hinf, struct file_op *op )
271 static const WCHAR SourceDisksNames[] =
272 {'S','o','u','r','c','e','D','i','s','k','s','N','a','m','e','s',0};
273 static const WCHAR SourceDisksFiles[] =
274 {'S','o','u','r','c','e','D','i','s','k','s','F','i','l','e','s',0};
276 INFCONTEXT file_ctx, disk_ctx;
277 INT id, diskid;
278 DWORD len, len2;
280 /* find the SourceDisksFiles entry */
281 if (!SetupFindFirstLineW( hinf, SourceDisksFiles, op->src_file, &file_ctx ))
283 const WCHAR *dir;
285 if ((op->style & (SP_COPY_SOURCE_ABSOLUTE|SP_COPY_SOURCEPATH_ABSOLUTE))) return;
286 /* no specific info, use .inf file source directory */
287 if (!op->src_root && (dir = DIRID_get_string( hinf, DIRID_SRCPATH )))
288 op->src_root = strdupW( dir );
289 return;
291 if (!SetupGetIntField( &file_ctx, 1, &diskid )) return;
293 /* now find the diskid in the SourceDisksNames section */
294 if (!SetupFindFirstLineW( hinf, SourceDisksNames, NULL, &disk_ctx )) return;
295 for (;;)
297 if (SetupGetIntField( &disk_ctx, 0, &id ) && (id == diskid)) break;
298 if (!SetupFindNextLine( &disk_ctx, &disk_ctx )) return;
301 /* and fill in the missing info */
303 if (!op->src_descr)
305 if (SetupGetStringFieldW( &disk_ctx, 1, NULL, 0, &len ) &&
306 (op->src_descr = HeapAlloc( GetProcessHeap(), 0, len*sizeof(WCHAR) )))
307 SetupGetStringFieldW( &disk_ctx, 1, op->src_descr, len, NULL );
309 if (!op->src_tag)
311 if (SetupGetStringFieldW( &disk_ctx, 2, NULL, 0, &len ) &&
312 (op->src_tag = HeapAlloc( GetProcessHeap(), 0, len*sizeof(WCHAR) )))
313 SetupGetStringFieldW( &disk_ctx, 2, op->src_tag, len, NULL );
315 if (!op->src_path && !(op->style & SP_COPY_SOURCE_ABSOLUTE))
317 if (!(op->style & SP_COPY_SOURCEPATH_ABSOLUTE))
319 /* retrieve relative path for this disk */
320 if (!SetupGetStringFieldW( &disk_ctx, 4, NULL, 0, &len )) len = 0;
322 /* retrieve relative path for this file */
323 if (!SetupGetStringFieldW( &file_ctx, 2, NULL, 0, &len2 )) len2 = 0;
325 if ((len || len2) &&
326 (op->src_path = HeapAlloc( GetProcessHeap(), 0, (len+len2)*sizeof(WCHAR) )))
328 WCHAR *ptr = op->src_path;
329 if (len)
331 SetupGetStringFieldW( &disk_ctx, 4, op->src_path, len, NULL );
332 ptr = op->src_path + strlenW(op->src_path);
333 if (len2 && ptr > op->src_path && ptr[-1] != '\\') *ptr++ = '\\';
335 if (!SetupGetStringFieldW( &disk_ctx, 4, ptr, len2, NULL )) *ptr = 0;
338 if (!op->src_root) op->src_root = strdupW( PARSER_get_src_root(hinf) );
342 /***********************************************************************
343 * get_destination_dir
345 * Retrieve the destination dir for a given section.
347 static WCHAR *get_destination_dir( HINF hinf, const WCHAR *section )
349 static const WCHAR Dest[] = {'D','e','s','t','i','n','a','t','i','o','n','D','i','r','s',0};
350 static const WCHAR Def[] = {'D','e','f','a','u','l','t','D','e','s','t','D','i','r',0};
352 const WCHAR *dir;
353 WCHAR *ptr, *ret;
354 INFCONTEXT context;
355 INT dirid;
356 DWORD len1, len2;
358 if (!SetupFindFirstLineW( hinf, Dest, section, &context ) &&
359 !SetupFindFirstLineW( hinf, Dest, Def, &context )) return NULL;
360 if (!SetupGetIntField( &context, 1, &dirid )) return NULL;
361 if (!(dir = DIRID_get_string( hinf, dirid ))) return NULL;
362 len1 = strlenW(dir) + 1;
363 if (!SetupGetStringFieldW( &context, 2, NULL, 0, &len2 )) len2 = 0;
364 if (!(ret = HeapAlloc( GetProcessHeap(), 0, (len1+len2) * sizeof(WCHAR) ))) return NULL;
365 strcpyW( ret, dir );
366 ptr = ret + strlenW(ret);
367 if (len2 && ptr > ret && ptr[-1] != '\\') *ptr++ = '\\';
368 if (!SetupGetStringFieldW( &context, 2, ptr, len2, NULL )) *ptr = 0;
369 return ret;
373 static void (WINAPI *pExtractFiles)( LPSTR, LPSTR, DWORD, DWORD, DWORD, DWORD );
375 /***********************************************************************
376 * extract_cabinet_file
378 * Extract a file from a .cab file.
380 static BOOL extract_cabinet_file( const WCHAR *cabinet, const WCHAR *root,
381 const WCHAR *src, const WCHAR *dst )
383 static const WCHAR extW[] = {'.','c','a','b',0};
384 static HMODULE advpack;
386 char *cab_path, *cab_file;
387 int len = strlenW( cabinet );
389 /* make sure the cabinet file has a .cab extension */
390 if (len <= 4 || strcmpiW( cabinet + len - 4, extW )) return FALSE;
391 if (!pExtractFiles)
393 if (!advpack && !(advpack = LoadLibraryA( "advpack.dll" )))
395 ERR( "could not load advpack.dll\n" );
396 return FALSE;
398 if (!(pExtractFiles = (void *)GetProcAddress( advpack, "ExtractFiles" )))
400 ERR( "could not find ExtractFiles in advpack.dll\n" );
401 return FALSE;
405 if (!(cab_path = strdupWtoA( root ))) return FALSE;
406 len = WideCharToMultiByte( CP_ACP, 0, cabinet, -1, NULL, 0, NULL, NULL );
407 if (!(cab_file = HeapAlloc( GetProcessHeap(), 0, strlen(cab_path) + len + 1 )))
409 HeapFree( GetProcessHeap(), 0, cab_path );
410 return FALSE;
412 strcpy( cab_file, cab_path );
413 if (cab_file[0] && cab_file[strlen(cab_file)-1] != '\\') strcat( cab_file, "\\" );
414 WideCharToMultiByte( CP_ACP, 0, cabinet, -1, cab_file + strlen(cab_file), len, NULL, NULL );
415 FIXME( "awful hack: extracting cabinet %s\n", debugstr_a(cab_file) );
416 pExtractFiles( cab_file, cab_path, 0, 0, 0, 0 );
417 HeapFree( GetProcessHeap(), 0, cab_file );
418 HeapFree( GetProcessHeap(), 0, cab_path );
419 return CopyFileW( src, dst, FALSE /*FIXME*/ );
423 /***********************************************************************
424 * SetupOpenFileQueue (SETUPAPI.@)
426 HSPFILEQ WINAPI SetupOpenFileQueue(void)
428 struct file_queue *queue;
430 if (!(queue = HeapAlloc( GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*queue))))
431 return (HSPFILEQ)INVALID_HANDLE_VALUE;
432 return queue;
436 /***********************************************************************
437 * SetupCloseFileQueue (SETUPAPI.@)
439 BOOL WINAPI SetupCloseFileQueue( HSPFILEQ handle )
441 struct file_queue *queue = handle;
443 free_file_op_queue( &queue->copy_queue );
444 free_file_op_queue( &queue->rename_queue );
445 free_file_op_queue( &queue->delete_queue );
446 HeapFree( GetProcessHeap(), 0, queue );
447 return TRUE;
451 /***********************************************************************
452 * SetupQueueCopyIndirectA (SETUPAPI.@)
454 BOOL WINAPI SetupQueueCopyIndirectA( PSP_FILE_COPY_PARAMS_A params )
456 struct file_queue *queue = params->QueueHandle;
457 struct file_op *op;
459 if (!(op = HeapAlloc( GetProcessHeap(), 0, sizeof(*op) ))) return FALSE;
460 op->style = params->CopyStyle;
461 op->src_root = strdupAtoW( params->SourceRootPath );
462 op->src_path = strdupAtoW( params->SourcePath );
463 op->src_file = strdupAtoW( params->SourceFilename );
464 op->src_descr = strdupAtoW( params->SourceDescription );
465 op->src_tag = strdupAtoW( params->SourceTagfile );
466 op->dst_path = strdupAtoW( params->TargetDirectory );
467 op->dst_file = strdupAtoW( params->TargetFilename );
469 /* some defaults */
470 if (!op->src_file) op->src_file = op->dst_file;
471 if (params->LayoutInf)
473 get_src_file_info( params->LayoutInf, op );
474 if (!op->dst_path) op->dst_path = get_destination_dir( params->LayoutInf, op->dst_file );
477 TRACE( "root=%s path=%s file=%s -> dir=%s file=%s descr=%s tag=%s\n",
478 debugstr_w(op->src_root), debugstr_w(op->src_path), debugstr_w(op->src_file),
479 debugstr_w(op->dst_path), debugstr_w(op->dst_file),
480 debugstr_w(op->src_descr), debugstr_w(op->src_tag) );
482 queue_file_op( &queue->copy_queue, op );
483 return TRUE;
487 /***********************************************************************
488 * SetupQueueCopyIndirectW (SETUPAPI.@)
490 BOOL WINAPI SetupQueueCopyIndirectW( PSP_FILE_COPY_PARAMS_W params )
492 struct file_queue *queue = params->QueueHandle;
493 struct file_op *op;
495 if (!(op = HeapAlloc( GetProcessHeap(), 0, sizeof(*op) ))) return FALSE;
496 op->style = params->CopyStyle;
497 op->src_root = strdupW( params->SourceRootPath );
498 op->src_path = strdupW( params->SourcePath );
499 op->src_file = strdupW( params->SourceFilename );
500 op->src_descr = strdupW( params->SourceDescription );
501 op->src_tag = strdupW( params->SourceTagfile );
502 op->dst_path = strdupW( params->TargetDirectory );
503 op->dst_file = strdupW( params->TargetFilename );
505 /* some defaults */
506 if (!op->src_file) op->src_file = op->dst_file;
507 if (params->LayoutInf)
509 get_src_file_info( params->LayoutInf, op );
510 if (!op->dst_path) op->dst_path = get_destination_dir( params->LayoutInf, op->dst_file );
513 TRACE( "root=%s path=%s file=%s -> dir=%s file=%s descr=%s tag=%s\n",
514 debugstr_w(op->src_root), debugstr_w(op->src_path), debugstr_w(op->src_file),
515 debugstr_w(op->dst_path), debugstr_w(op->dst_file),
516 debugstr_w(op->src_descr), debugstr_w(op->src_tag) );
518 queue_file_op( &queue->copy_queue, op );
519 return TRUE;
523 /***********************************************************************
524 * SetupQueueCopyA (SETUPAPI.@)
526 BOOL WINAPI SetupQueueCopyA( HSPFILEQ queue, PCSTR src_root, PCSTR src_path, PCSTR src_file,
527 PCSTR src_descr, PCSTR src_tag, PCSTR dst_dir, PCSTR dst_file,
528 DWORD style )
530 SP_FILE_COPY_PARAMS_A params;
532 params.cbSize = sizeof(params);
533 params.QueueHandle = queue;
534 params.SourceRootPath = src_root;
535 params.SourcePath = src_path;
536 params.SourceFilename = src_file;
537 params.SourceDescription = src_descr;
538 params.SourceTagfile = src_tag;
539 params.TargetDirectory = dst_dir;
540 params.TargetFilename = dst_file;
541 params.CopyStyle = style;
542 params.LayoutInf = 0;
543 params.SecurityDescriptor = NULL;
544 return SetupQueueCopyIndirectA( &params );
548 /***********************************************************************
549 * SetupQueueCopyW (SETUPAPI.@)
551 BOOL WINAPI SetupQueueCopyW( HSPFILEQ queue, PCWSTR src_root, PCWSTR src_path, PCWSTR src_file,
552 PCWSTR src_descr, PCWSTR src_tag, PCWSTR dst_dir, PCWSTR dst_file,
553 DWORD style )
555 SP_FILE_COPY_PARAMS_W params;
557 params.cbSize = sizeof(params);
558 params.QueueHandle = queue;
559 params.SourceRootPath = src_root;
560 params.SourcePath = src_path;
561 params.SourceFilename = src_file;
562 params.SourceDescription = src_descr;
563 params.SourceTagfile = src_tag;
564 params.TargetDirectory = dst_dir;
565 params.TargetFilename = dst_file;
566 params.CopyStyle = style;
567 params.LayoutInf = 0;
568 params.SecurityDescriptor = NULL;
569 return SetupQueueCopyIndirectW( &params );
573 /***********************************************************************
574 * SetupQueueDefaultCopyA (SETUPAPI.@)
576 BOOL WINAPI SetupQueueDefaultCopyA( HSPFILEQ queue, HINF hinf, PCSTR src_root, PCSTR src_file,
577 PCSTR dst_file, DWORD style )
579 SP_FILE_COPY_PARAMS_A params;
581 params.cbSize = sizeof(params);
582 params.QueueHandle = queue;
583 params.SourceRootPath = src_root;
584 params.SourcePath = NULL;
585 params.SourceFilename = src_file;
586 params.SourceDescription = NULL;
587 params.SourceTagfile = NULL;
588 params.TargetDirectory = NULL;
589 params.TargetFilename = dst_file;
590 params.CopyStyle = style;
591 params.LayoutInf = hinf;
592 params.SecurityDescriptor = NULL;
593 return SetupQueueCopyIndirectA( &params );
597 /***********************************************************************
598 * SetupQueueDefaultCopyW (SETUPAPI.@)
600 BOOL WINAPI SetupQueueDefaultCopyW( HSPFILEQ queue, HINF hinf, PCWSTR src_root, PCWSTR src_file,
601 PCWSTR dst_file, DWORD style )
603 SP_FILE_COPY_PARAMS_W params;
605 params.cbSize = sizeof(params);
606 params.QueueHandle = queue;
607 params.SourceRootPath = src_root;
608 params.SourcePath = NULL;
609 params.SourceFilename = src_file;
610 params.SourceDescription = NULL;
611 params.SourceTagfile = NULL;
612 params.TargetDirectory = NULL;
613 params.TargetFilename = dst_file;
614 params.CopyStyle = style;
615 params.LayoutInf = hinf;
616 params.SecurityDescriptor = NULL;
617 return SetupQueueCopyIndirectW( &params );
621 /***********************************************************************
622 * SetupQueueDeleteA (SETUPAPI.@)
624 BOOL WINAPI SetupQueueDeleteA( HSPFILEQ handle, PCSTR part1, PCSTR part2 )
626 struct file_queue *queue = handle;
627 struct file_op *op;
629 if (!(op = HeapAlloc( GetProcessHeap(), 0, sizeof(*op) ))) return FALSE;
630 op->style = 0;
631 op->src_root = NULL;
632 op->src_path = NULL;
633 op->src_file = NULL;
634 op->src_descr = NULL;
635 op->src_tag = NULL;
636 op->dst_path = strdupAtoW( part1 );
637 op->dst_file = strdupAtoW( part2 );
638 queue_file_op( &queue->delete_queue, op );
639 return TRUE;
643 /***********************************************************************
644 * SetupQueueDeleteW (SETUPAPI.@)
646 BOOL WINAPI SetupQueueDeleteW( HSPFILEQ handle, PCWSTR part1, PCWSTR part2 )
648 struct file_queue *queue = handle;
649 struct file_op *op;
651 if (!(op = HeapAlloc( GetProcessHeap(), 0, sizeof(*op) ))) return FALSE;
652 op->style = 0;
653 op->src_root = NULL;
654 op->src_path = NULL;
655 op->src_file = NULL;
656 op->src_descr = NULL;
657 op->src_tag = NULL;
658 op->dst_path = strdupW( part1 );
659 op->dst_file = strdupW( part2 );
660 queue_file_op( &queue->delete_queue, op );
661 return TRUE;
665 /***********************************************************************
666 * SetupQueueRenameA (SETUPAPI.@)
668 BOOL WINAPI SetupQueueRenameA( HSPFILEQ handle, PCSTR SourcePath, PCSTR SourceFilename,
669 PCSTR TargetPath, PCSTR TargetFilename )
671 struct file_queue *queue = handle;
672 struct file_op *op;
674 if (!(op = HeapAlloc( GetProcessHeap(), 0, sizeof(*op) ))) return FALSE;
675 op->style = 0;
676 op->src_root = NULL;
677 op->src_path = strdupAtoW( SourcePath );
678 op->src_file = strdupAtoW( SourceFilename );
679 op->src_descr = NULL;
680 op->src_tag = NULL;
681 op->dst_path = strdupAtoW( TargetPath );
682 op->dst_file = strdupAtoW( TargetFilename );
683 queue_file_op( &queue->rename_queue, op );
684 return TRUE;
688 /***********************************************************************
689 * SetupQueueRenameW (SETUPAPI.@)
691 BOOL WINAPI SetupQueueRenameW( HSPFILEQ handle, PCWSTR SourcePath, PCWSTR SourceFilename,
692 PCWSTR TargetPath, PCWSTR TargetFilename )
694 struct file_queue *queue = handle;
695 struct file_op *op;
697 if (!(op = HeapAlloc( GetProcessHeap(), 0, sizeof(*op) ))) return FALSE;
698 op->style = 0;
699 op->src_root = NULL;
700 op->src_path = strdupW( SourcePath );
701 op->src_file = strdupW( SourceFilename );
702 op->src_descr = NULL;
703 op->src_tag = NULL;
704 op->dst_path = strdupW( TargetPath );
705 op->dst_file = strdupW( TargetFilename );
706 queue_file_op( &queue->rename_queue, op );
707 return TRUE;
711 /***********************************************************************
712 * SetupQueueCopySectionA (SETUPAPI.@)
714 BOOL WINAPI SetupQueueCopySectionA( HSPFILEQ queue, PCSTR src_root, HINF hinf, HINF hlist,
715 PCSTR section, DWORD style )
717 UNICODE_STRING sectionW;
718 BOOL ret = FALSE;
720 if (!RtlCreateUnicodeStringFromAsciiz( &sectionW, section ))
722 SetLastError( ERROR_NOT_ENOUGH_MEMORY );
723 return FALSE;
725 if (!src_root)
726 ret = SetupQueueCopySectionW( queue, NULL, hinf, hlist, sectionW.Buffer, style );
727 else
729 UNICODE_STRING srcW;
730 if (RtlCreateUnicodeStringFromAsciiz( &srcW, src_root ))
732 ret = SetupQueueCopySectionW( queue, srcW.Buffer, hinf, hlist, sectionW.Buffer, style );
733 RtlFreeUnicodeString( &srcW );
735 else SetLastError( ERROR_NOT_ENOUGH_MEMORY );
737 RtlFreeUnicodeString( &sectionW );
738 return ret;
742 /***********************************************************************
743 * SetupQueueCopySectionW (SETUPAPI.@)
745 BOOL WINAPI SetupQueueCopySectionW( HSPFILEQ queue, PCWSTR src_root, HINF hinf, HINF hlist,
746 PCWSTR section, DWORD style )
748 SP_FILE_COPY_PARAMS_W params;
749 INFCONTEXT context;
750 WCHAR dest[MAX_PATH], src[MAX_PATH];
751 INT flags;
753 TRACE( "hinf=%p/%p section=%s root=%s\n",
754 hinf, hlist, debugstr_w(section), debugstr_w(src_root) );
756 params.cbSize = sizeof(params);
757 params.QueueHandle = queue;
758 params.SourceRootPath = src_root;
759 params.SourcePath = NULL;
760 params.SourceDescription = NULL;
761 params.SourceTagfile = NULL;
762 params.TargetFilename = dest;
763 params.CopyStyle = style;
764 params.LayoutInf = hinf;
765 params.SecurityDescriptor = NULL;
767 if (!hlist) hlist = hinf;
768 if (!SetupFindFirstLineW( hlist, section, NULL, &context )) return FALSE;
769 if (!(params.TargetDirectory = get_destination_dir( hinf, section ))) return FALSE;
772 if (!SetupGetStringFieldW( &context, 1, dest, sizeof(dest)/sizeof(WCHAR), NULL ))
773 return FALSE;
774 if (!SetupGetStringFieldW( &context, 2, src, sizeof(src)/sizeof(WCHAR), NULL )) *src = 0;
775 if (!SetupGetIntField( &context, 4, &flags )) flags = 0; /* FIXME */
777 params.SourceFilename = *src ? src : NULL;
778 if (!SetupQueueCopyIndirectW( &params )) return FALSE;
779 } while (SetupFindNextLine( &context, &context ));
780 return TRUE;
784 /***********************************************************************
785 * SetupQueueDeleteSectionA (SETUPAPI.@)
787 BOOL WINAPI SetupQueueDeleteSectionA( HSPFILEQ queue, HINF hinf, HINF hlist, PCSTR section )
789 UNICODE_STRING sectionW;
790 BOOL ret = FALSE;
792 if (RtlCreateUnicodeStringFromAsciiz( &sectionW, section ))
794 ret = SetupQueueDeleteSectionW( queue, hinf, hlist, sectionW.Buffer );
795 RtlFreeUnicodeString( &sectionW );
797 else SetLastError( ERROR_NOT_ENOUGH_MEMORY );
798 return ret;
802 /***********************************************************************
803 * SetupQueueDeleteSectionW (SETUPAPI.@)
805 BOOL WINAPI SetupQueueDeleteSectionW( HSPFILEQ queue, HINF hinf, HINF hlist, PCWSTR section )
807 INFCONTEXT context;
808 WCHAR *dest_dir;
809 WCHAR buffer[MAX_PATH];
810 BOOL ret = FALSE;
811 INT flags;
813 TRACE( "hinf=%p/%p section=%s\n", hinf, hlist, debugstr_w(section) );
815 if (!hlist) hlist = hinf;
816 if (!SetupFindFirstLineW( hlist, section, NULL, &context )) return FALSE;
817 if (!(dest_dir = get_destination_dir( hinf, section ))) return FALSE;
820 if (!SetupGetStringFieldW( &context, 1, buffer, sizeof(buffer)/sizeof(WCHAR), NULL ))
821 goto done;
822 if (!SetupGetIntField( &context, 4, &flags )) flags = 0;
823 if (!SetupQueueDeleteW( queue, dest_dir, buffer )) goto done;
824 } while (SetupFindNextLine( &context, &context ));
826 ret = TRUE;
827 done:
828 HeapFree( GetProcessHeap(), 0, dest_dir );
829 return ret;
833 /***********************************************************************
834 * SetupQueueRenameSectionA (SETUPAPI.@)
836 BOOL WINAPI SetupQueueRenameSectionA( HSPFILEQ queue, HINF hinf, HINF hlist, PCSTR section )
838 UNICODE_STRING sectionW;
839 BOOL ret = FALSE;
841 if (RtlCreateUnicodeStringFromAsciiz( &sectionW, section ))
843 ret = SetupQueueRenameSectionW( queue, hinf, hlist, sectionW.Buffer );
844 RtlFreeUnicodeString( &sectionW );
846 else SetLastError( ERROR_NOT_ENOUGH_MEMORY );
847 return ret;
851 /***********************************************************************
852 * SetupQueueRenameSectionW (SETUPAPI.@)
854 BOOL WINAPI SetupQueueRenameSectionW( HSPFILEQ queue, HINF hinf, HINF hlist, PCWSTR section )
856 INFCONTEXT context;
857 WCHAR *dest_dir;
858 WCHAR src[MAX_PATH], dst[MAX_PATH];
859 BOOL ret = FALSE;
861 TRACE( "hinf=%p/%p section=%s\n", hinf, hlist, debugstr_w(section) );
863 if (!hlist) hlist = hinf;
864 if (!SetupFindFirstLineW( hlist, section, NULL, &context )) return FALSE;
865 if (!(dest_dir = get_destination_dir( hinf, section ))) return FALSE;
868 if (!SetupGetStringFieldW( &context, 1, dst, sizeof(dst)/sizeof(WCHAR), NULL ))
869 goto done;
870 if (!SetupGetStringFieldW( &context, 2, src, sizeof(src)/sizeof(WCHAR), NULL ))
871 goto done;
872 if (!SetupQueueRenameW( queue, dest_dir, src, NULL, dst )) goto done;
873 } while (SetupFindNextLine( &context, &context ));
875 ret = TRUE;
876 done:
877 HeapFree( GetProcessHeap(), 0, dest_dir );
878 return ret;
882 /***********************************************************************
883 * SetupCommitFileQueueA (SETUPAPI.@)
885 BOOL WINAPI SetupCommitFileQueueA( HWND owner, HSPFILEQ queue, PSP_FILE_CALLBACK_A handler,
886 PVOID context )
888 struct callback_WtoA_context ctx;
890 ctx.orig_context = context;
891 ctx.orig_handler = handler;
892 return SetupCommitFileQueueW( owner, queue, QUEUE_callback_WtoA, &ctx );
896 /***********************************************************************
897 * create_full_pathW
899 * Recursively create all directories in the path.
901 static BOOL create_full_pathW(const WCHAR *path)
903 BOOL ret = TRUE;
904 int len;
905 WCHAR *new_path;
907 new_path = HeapAlloc(GetProcessHeap(), 0, (strlenW(path) + 1) * sizeof(WCHAR));
908 strcpyW(new_path, path);
910 while((len = strlenW(new_path)) && new_path[len - 1] == '\\')
911 new_path[len - 1] = 0;
913 while(!CreateDirectoryW(new_path, NULL))
915 WCHAR *slash;
916 DWORD last_error = GetLastError();
918 if(last_error == ERROR_ALREADY_EXISTS)
919 break;
921 if(last_error != ERROR_PATH_NOT_FOUND)
923 ret = FALSE;
924 break;
927 if(!(slash = strrchrW(new_path, '\\')))
929 ret = FALSE;
930 break;
933 len = slash - new_path;
934 new_path[len] = 0;
935 if(!create_full_pathW(new_path))
937 ret = FALSE;
938 break;
940 new_path[len] = '\\';
943 HeapFree(GetProcessHeap(), 0, new_path);
944 return ret;
947 BOOL static do_file_copyW( LPCWSTR source, LPCWSTR target, DWORD style)
949 BOOL rc = FALSE;
950 BOOL docopy = TRUE;
952 TRACE("copy %s to %s style 0x%lx\n",debugstr_w(source),debugstr_w(target),style);
954 /* before copy processing */
955 if (style & SP_COPY_REPLACEONLY)
957 if (GetFileAttributesW(target) == INVALID_FILE_ATTRIBUTES)
958 docopy = FALSE;
960 if (style & (SP_COPY_NEWER_OR_SAME | SP_COPY_NEWER_ONLY | SP_COPY_FORCE_NEWER))
962 DWORD VersionSizeSource=0;
963 DWORD VersionSizeTarget=0;
964 DWORD zero=0;
967 * This is sort of an interesting workaround. You see, calling
968 * GetVersionInfoSize on a builtin dll loads that dll into memory
969 * and we do not properly unload builtin dlls.. so we effectively
970 * lock into memory all the targets we are replacing. This leads
971 * to problems when we try to register the replaced dlls.
973 * So I will test for the existence of the files first so that
974 * we just basically unconditionally replace the builtin versions.
976 if ((GetFileAttributesW(target) != INVALID_FILE_ATTRIBUTES) &&
977 (GetFileAttributesW(source) != INVALID_FILE_ATTRIBUTES))
979 VersionSizeSource = GetFileVersionInfoSizeW(source,&zero);
980 VersionSizeTarget = GetFileVersionInfoSizeW(target,&zero);
983 TRACE("SizeTarget %li ... SizeSource %li\n",VersionSizeTarget,
984 VersionSizeSource);
986 if (VersionSizeSource && VersionSizeTarget)
988 LPVOID VersionSource;
989 LPVOID VersionTarget;
990 VS_FIXEDFILEINFO *TargetInfo;
991 VS_FIXEDFILEINFO *SourceInfo;
992 INT length;
993 WCHAR SubBlock[2]={'\\',0};
994 DWORD ret;
996 VersionSource = HeapAlloc(GetProcessHeap(),0,VersionSizeSource);
997 VersionTarget = HeapAlloc(GetProcessHeap(),0,VersionSizeTarget);
999 ret = GetFileVersionInfoW(source,0,VersionSizeSource,VersionSource);
1000 if (ret)
1001 ret = GetFileVersionInfoW(target, 0, VersionSizeTarget,
1002 VersionTarget);
1004 if (ret)
1006 ret = VerQueryValueW(VersionSource, SubBlock,
1007 (LPVOID*)&SourceInfo, &length);
1008 if (ret)
1009 ret = VerQueryValueW(VersionTarget, SubBlock,
1010 (LPVOID*)&TargetInfo, &length);
1012 if (ret)
1014 TRACE("Versions: Source %li.%li target %li.%li\n",
1015 SourceInfo->dwFileVersionMS, SourceInfo->dwFileVersionLS,
1016 TargetInfo->dwFileVersionMS, TargetInfo->dwFileVersionLS);
1018 if (TargetInfo->dwFileVersionMS > SourceInfo->dwFileVersionMS)
1020 FIXME("Notify that target version is greater..\n");
1021 docopy = FALSE;
1023 else if ((TargetInfo->dwFileVersionMS == SourceInfo->dwFileVersionMS)
1024 && (TargetInfo->dwFileVersionLS > SourceInfo->dwFileVersionLS))
1026 FIXME("Notify that target version is greater..\n");
1027 docopy = FALSE;
1029 else if ((style & SP_COPY_NEWER_ONLY) &&
1030 (TargetInfo->dwFileVersionMS ==
1031 SourceInfo->dwFileVersionMS)
1032 &&(TargetInfo->dwFileVersionLS ==
1033 SourceInfo->dwFileVersionLS))
1035 FIXME("Notify that target version is greater..\n");
1036 docopy = FALSE;
1040 HeapFree(GetProcessHeap(),0,VersionSource);
1041 HeapFree(GetProcessHeap(),0,VersionTarget);
1044 if (style & (SP_COPY_NOOVERWRITE | SP_COPY_FORCE_NOOVERWRITE))
1046 if (GetFileAttributesW(target) != INVALID_FILE_ATTRIBUTES)
1048 FIXME("Notify user target file exists\n");
1049 docopy = FALSE;
1052 if (style & (SP_COPY_NODECOMP | SP_COPY_LANGUAGEAWARE | SP_COPY_FORCE_IN_USE |
1053 SP_COPY_IN_USE_NEEDS_REBOOT | SP_COPY_NOSKIP | SP_COPY_WARNIFSKIP))
1055 ERR("Unsupported style(s) 0x%lx\n",style);
1058 if (docopy)
1060 rc = CopyFileW(source,target,FALSE);
1061 TRACE("Did copy... rc was %i\n",rc);
1064 /* after copy processing */
1065 if (style & SP_COPY_DELETESOURCE)
1067 if (rc)
1068 DeleteFileW(source);
1071 return rc;
1074 /***********************************************************************
1075 * SetupCommitFileQueueW (SETUPAPI.@)
1077 BOOL WINAPI SetupCommitFileQueueW( HWND owner, HSPFILEQ handle, PSP_FILE_CALLBACK_W handler,
1078 PVOID context )
1080 struct file_queue *queue = handle;
1081 struct file_op *op;
1082 BOOL result = FALSE;
1083 FILEPATHS_W paths;
1084 UINT op_result;
1086 paths.Source = paths.Target = NULL;
1088 if (!queue->copy_queue.count && !queue->delete_queue.count && !queue->rename_queue.count)
1089 return TRUE; /* nothing to do */
1091 if (!handler( context, SPFILENOTIFY_STARTQUEUE, (UINT)owner, 0 )) return FALSE;
1093 /* perform deletes */
1095 if (queue->delete_queue.count)
1097 if (!(handler( context, SPFILENOTIFY_STARTSUBQUEUE, FILEOP_DELETE,
1098 queue->delete_queue.count ))) goto done;
1099 for (op = queue->delete_queue.head; op; op = op->next)
1101 build_filepathsW( op, &paths );
1102 op_result = handler( context, SPFILENOTIFY_STARTDELETE, (UINT_PTR)&paths, FILEOP_DELETE);
1103 if (op_result == FILEOP_ABORT) goto done;
1104 while (op_result == FILEOP_DOIT)
1106 TRACE( "deleting file %s\n", debugstr_w(paths.Target) );
1107 if (DeleteFileW( paths.Target )) break; /* success */
1108 paths.Win32Error = GetLastError();
1109 op_result = handler( context, SPFILENOTIFY_DELETEERROR, (UINT_PTR)&paths, 0 );
1110 if (op_result == FILEOP_ABORT) goto done;
1112 handler( context, SPFILENOTIFY_ENDDELETE, (UINT_PTR)&paths, 0 );
1114 handler( context, SPFILENOTIFY_ENDSUBQUEUE, FILEOP_DELETE, 0 );
1117 /* perform renames */
1119 if (queue->rename_queue.count)
1121 if (!(handler( context, SPFILENOTIFY_STARTSUBQUEUE, FILEOP_RENAME,
1122 queue->rename_queue.count ))) goto done;
1123 for (op = queue->rename_queue.head; op; op = op->next)
1125 build_filepathsW( op, &paths );
1126 op_result = handler( context, SPFILENOTIFY_STARTRENAME, (UINT_PTR)&paths, FILEOP_RENAME);
1127 if (op_result == FILEOP_ABORT) goto done;
1128 while (op_result == FILEOP_DOIT)
1130 TRACE( "renaming file %s -> %s\n",
1131 debugstr_w(paths.Source), debugstr_w(paths.Target) );
1132 if (MoveFileW( paths.Source, paths.Target )) break; /* success */
1133 paths.Win32Error = GetLastError();
1134 op_result = handler( context, SPFILENOTIFY_RENAMEERROR, (UINT_PTR)&paths, 0 );
1135 if (op_result == FILEOP_ABORT) goto done;
1137 handler( context, SPFILENOTIFY_ENDRENAME, (UINT_PTR)&paths, 0 );
1139 handler( context, SPFILENOTIFY_ENDSUBQUEUE, FILEOP_RENAME, 0 );
1142 /* perform copies */
1144 if (queue->copy_queue.count)
1146 if (!(handler( context, SPFILENOTIFY_STARTSUBQUEUE, FILEOP_COPY,
1147 queue->copy_queue.count ))) goto done;
1148 for (op = queue->copy_queue.head; op; op = op->next)
1150 WCHAR newpath[MAX_PATH];
1152 build_filepathsW( op, &paths );
1153 op_result = handler( context, SPFILENOTIFY_STARTCOPY, (UINT_PTR)&paths, FILEOP_COPY );
1154 if (op_result == FILEOP_ABORT) goto done;
1155 if (op_result == FILEOP_NEWPATH) op_result = FILEOP_DOIT;
1156 while (op_result == FILEOP_DOIT || op_result == FILEOP_NEWPATH)
1158 TRACE( "copying file %s -> %s\n",
1159 debugstr_w( op_result == FILEOP_NEWPATH ? newpath : paths.Source ),
1160 debugstr_w(paths.Target) );
1161 if (op->dst_path)
1163 if (!create_full_pathW( op->dst_path ))
1165 paths.Win32Error = GetLastError();
1166 op_result = handler( context, SPFILENOTIFY_COPYERROR,
1167 (UINT_PTR)&paths, (UINT_PTR)newpath );
1168 if (op_result == FILEOP_ABORT) goto done;
1171 if (do_file_copyW( op_result == FILEOP_NEWPATH ? newpath : paths.Source,
1172 paths.Target, op->style )) break; /* success */
1173 /* try to extract it from the cabinet file */
1174 if (op->src_tag)
1176 if (extract_cabinet_file( op->src_tag, op->src_root,
1177 paths.Source, paths.Target )) break;
1179 paths.Win32Error = GetLastError();
1180 op_result = handler( context, SPFILENOTIFY_COPYERROR,
1181 (UINT_PTR)&paths, (UINT_PTR)newpath );
1182 if (op_result == FILEOP_ABORT) goto done;
1184 handler( context, SPFILENOTIFY_ENDCOPY, (UINT_PTR)&paths, 0 );
1186 handler( context, SPFILENOTIFY_ENDSUBQUEUE, FILEOP_COPY, 0 );
1190 result = TRUE;
1192 done:
1193 handler( context, SPFILENOTIFY_ENDQUEUE, result, 0 );
1194 HeapFree( GetProcessHeap(), 0, (void *)paths.Source );
1195 HeapFree( GetProcessHeap(), 0, (void *)paths.Target );
1196 return result;
1200 /***********************************************************************
1201 * SetupScanFileQueueA (SETUPAPI.@)
1203 BOOL WINAPI SetupScanFileQueueA( HSPFILEQ queue, DWORD flags, HWND window,
1204 PSP_FILE_CALLBACK_A callback, PVOID context, PDWORD result )
1206 FIXME("stub\n");
1207 return FALSE;
1211 /***********************************************************************
1212 * SetupScanFileQueueW (SETUPAPI.@)
1214 BOOL WINAPI SetupScanFileQueueW( HSPFILEQ queue, DWORD flags, HWND window,
1215 PSP_FILE_CALLBACK_W callback, PVOID context, PDWORD result )
1217 FIXME("stub\n");
1218 return FALSE;
1222 /***********************************************************************
1223 * SetupGetFileQueueCount (SETUPAPI.@)
1225 BOOL WINAPI SetupGetFileQueueCount( HSPFILEQ handle, UINT op, PUINT result )
1227 struct file_queue *queue = handle;
1229 switch(op)
1231 case FILEOP_COPY:
1232 *result = queue->copy_queue.count;
1233 return TRUE;
1234 case FILEOP_RENAME:
1235 *result = queue->rename_queue.count;
1236 return TRUE;
1237 case FILEOP_DELETE:
1238 *result = queue->delete_queue.count;
1239 return TRUE;
1241 return FALSE;
1245 /***********************************************************************
1246 * SetupGetFileQueueFlags (SETUPAPI.@)
1248 BOOL WINAPI SetupGetFileQueueFlags( HSPFILEQ handle, PDWORD flags )
1250 struct file_queue *queue = handle;
1251 *flags = queue->flags;
1252 return TRUE;
1256 /***********************************************************************
1257 * SetupSetFileQueueFlags (SETUPAPI.@)
1259 BOOL WINAPI SetupSetFileQueueFlags( HSPFILEQ handle, DWORD mask, DWORD flags )
1261 struct file_queue *queue = handle;
1262 queue->flags = (queue->flags & ~mask) | flags;
1263 return TRUE;
1267 /***********************************************************************
1268 * SetupInitDefaultQueueCallback (SETUPAPI.@)
1270 PVOID WINAPI SetupInitDefaultQueueCallback( HWND owner )
1272 return SetupInitDefaultQueueCallbackEx( owner, 0, 0, 0, NULL );
1276 /***********************************************************************
1277 * SetupInitDefaultQueueCallbackEx (SETUPAPI.@)
1279 PVOID WINAPI SetupInitDefaultQueueCallbackEx( HWND owner, HWND progress, UINT msg,
1280 DWORD reserved1, PVOID reserved2 )
1282 struct default_callback_context *context;
1284 if ((context = HeapAlloc( GetProcessHeap(), 0, sizeof(*context) )))
1286 context->owner = owner;
1287 context->progress = progress;
1288 context->message = msg;
1290 return context;
1294 /***********************************************************************
1295 * SetupTermDefaultQueueCallback (SETUPAPI.@)
1297 void WINAPI SetupTermDefaultQueueCallback( PVOID context )
1299 HeapFree( GetProcessHeap(), 0, context );
1303 /***********************************************************************
1304 * SetupDefaultQueueCallbackA (SETUPAPI.@)
1306 UINT WINAPI SetupDefaultQueueCallbackA( PVOID context, UINT notification,
1307 UINT_PTR param1, UINT_PTR param2 )
1309 FILEPATHS_A *paths = (FILEPATHS_A *)param1;
1311 switch(notification)
1313 case SPFILENOTIFY_STARTQUEUE:
1314 TRACE( "start queue\n" );
1315 return TRUE;
1316 case SPFILENOTIFY_ENDQUEUE:
1317 TRACE( "end queue\n" );
1318 return 0;
1319 case SPFILENOTIFY_STARTSUBQUEUE:
1320 TRACE( "start subqueue %d count %d\n", param1, param2 );
1321 return TRUE;
1322 case SPFILENOTIFY_ENDSUBQUEUE:
1323 TRACE( "end subqueue %d\n", param1 );
1324 return 0;
1325 case SPFILENOTIFY_STARTDELETE:
1326 TRACE( "start delete %s\n", debugstr_a(paths->Target) );
1327 return FILEOP_DOIT;
1328 case SPFILENOTIFY_ENDDELETE:
1329 TRACE( "end delete %s\n", debugstr_a(paths->Target) );
1330 return 0;
1331 case SPFILENOTIFY_DELETEERROR:
1332 ERR( "delete error %d %s\n", paths->Win32Error, debugstr_a(paths->Target) );
1333 return FILEOP_SKIP;
1334 case SPFILENOTIFY_STARTRENAME:
1335 TRACE( "start rename %s -> %s\n", debugstr_a(paths->Source), debugstr_a(paths->Target) );
1336 return FILEOP_DOIT;
1337 case SPFILENOTIFY_ENDRENAME:
1338 TRACE( "end rename %s -> %s\n", debugstr_a(paths->Source), debugstr_a(paths->Target) );
1339 return 0;
1340 case SPFILENOTIFY_RENAMEERROR:
1341 ERR( "rename error %d %s -> %s\n", paths->Win32Error,
1342 debugstr_a(paths->Source), debugstr_a(paths->Target) );
1343 return FILEOP_SKIP;
1344 case SPFILENOTIFY_STARTCOPY:
1345 TRACE( "start copy %s -> %s\n", debugstr_a(paths->Source), debugstr_a(paths->Target) );
1346 return FILEOP_DOIT;
1347 case SPFILENOTIFY_ENDCOPY:
1348 TRACE( "end copy %s -> %s\n", debugstr_a(paths->Source), debugstr_a(paths->Target) );
1349 return 0;
1350 case SPFILENOTIFY_COPYERROR:
1351 ERR( "copy error %d %s -> %s\n", paths->Win32Error,
1352 debugstr_a(paths->Source), debugstr_a(paths->Target) );
1353 return FILEOP_SKIP;
1354 case SPFILENOTIFY_NEEDMEDIA:
1355 TRACE( "need media\n" );
1356 return FILEOP_SKIP;
1357 default:
1358 FIXME( "notification %d params %x,%x\n", notification, param1, param2 );
1359 break;
1361 return 0;
1365 /***********************************************************************
1366 * SetupDefaultQueueCallbackW (SETUPAPI.@)
1368 UINT WINAPI SetupDefaultQueueCallbackW( PVOID context, UINT notification,
1369 UINT_PTR param1, UINT_PTR param2 )
1371 FIXME( "notification %d params %x,%x\n", notification, param1, param2 );
1372 return FILEOP_SKIP;