ole32: Remove redundant NULL check (Coverity).
[wine] / dlls / setupapi / queue.c
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., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
19  */
20
21 #include <stdarg.h>
22
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"
36
37 WINE_DEFAULT_DEBUG_CHANNEL(setupapi);
38
39 /* context structure for the default queue callback */
40 struct default_callback_context
41 {
42     HWND owner;
43     HWND progress;
44     UINT message;
45 };
46
47 struct file_op
48 {
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;
58 };
59
60 struct file_op_queue
61 {
62     struct file_op *head;
63     struct file_op *tail;
64     unsigned int count;
65 };
66
67 struct file_queue
68 {
69     struct file_op_queue copy_queue;
70     struct file_op_queue delete_queue;
71     struct file_op_queue rename_queue;
72     DWORD                flags;
73 };
74
75
76 inline static WCHAR *strdupW( const WCHAR *str )
77 {
78     WCHAR *ret = NULL;
79     if (str)
80     {
81         int len = (strlenW(str) + 1) * sizeof(WCHAR);
82         if ((ret = HeapAlloc( GetProcessHeap(), 0, len ))) memcpy( ret, str, len );
83     }
84     return ret;
85 }
86
87 inline static char *strdupWtoA( const WCHAR *str )
88 {
89     char *ret = NULL;
90     if (str)
91     {
92         DWORD len = WideCharToMultiByte( CP_ACP, 0, str, -1, NULL, 0, NULL, NULL );
93         if ((ret = HeapAlloc( GetProcessHeap(), 0, len )))
94             WideCharToMultiByte( CP_ACP, 0, str, -1, ret, len, NULL, NULL );
95     }
96     return ret;
97 }
98
99 /* append a file operation to a queue */
100 inline static void queue_file_op( struct file_op_queue *queue, struct file_op *op )
101 {
102     op->next = NULL;
103     if (queue->tail) queue->tail->next = op;
104     else queue->head = op;
105     queue->tail = op;
106     queue->count++;
107 }
108
109 /* free all the file operations on a given queue */
110 static void free_file_op_queue( struct file_op_queue *queue )
111 {
112     struct file_op *t, *op = queue->head;
113
114     while( op )
115     {
116         HeapFree( GetProcessHeap(), 0, op->src_root );
117         HeapFree( GetProcessHeap(), 0, op->src_path );
118         HeapFree( GetProcessHeap(), 0, op->src_file );
119         HeapFree( GetProcessHeap(), 0, op->src_descr );
120         HeapFree( GetProcessHeap(), 0, op->src_tag );
121         HeapFree( GetProcessHeap(), 0, op->dst_path );
122         if (op->dst_file != op->src_file) HeapFree( GetProcessHeap(), 0, op->dst_file );
123         t = op;
124         op = op->next;
125         HeapFree( GetProcessHeap(), 0, t );
126     }
127 }
128
129 /* concat 3 strings to make a path, handling separators correctly */
130 static void concat_W( WCHAR *buffer, const WCHAR *src1, const WCHAR *src2, const WCHAR *src3 )
131 {
132     *buffer = 0;
133     if (src1 && *src1)
134     {
135         strcpyW( buffer, src1 );
136         buffer += strlenW(buffer );
137         if (buffer[-1] != '\\') *buffer++ = '\\';
138         if (src2) while (*src2 == '\\') src2++;
139     }
140
141     if (src2)
142     {
143         strcpyW( buffer, src2 );
144         buffer += strlenW(buffer );
145         if (buffer[-1] != '\\') *buffer++ = '\\';
146         if (src3) while (*src3 == '\\') src3++;
147     }
148     if (src3)
149     {
150         strcpyW( buffer, src3 );
151         buffer += strlenW(buffer );
152     }
153 }
154
155
156 /***********************************************************************
157  *            build_filepathsW
158  *
159  * Build a FILEPATHS_W structure for a given file operation.
160  */
161 static BOOL build_filepathsW( const struct file_op *op, FILEPATHS_W *paths )
162 {
163     unsigned int src_len = 1, dst_len = 1;
164     WCHAR *source = (PWSTR)paths->Source, *target = (PWSTR)paths->Target;
165
166     if (op->src_root) src_len += strlenW(op->src_root) + 1;
167     if (op->src_path) src_len += strlenW(op->src_path) + 1;
168     if (op->src_file) src_len += strlenW(op->src_file) + 1;
169     if (op->dst_path) dst_len += strlenW(op->dst_path) + 1;
170     if (op->dst_file) dst_len += strlenW(op->dst_file) + 1;
171     src_len *= sizeof(WCHAR);
172     dst_len *= sizeof(WCHAR);
173
174     if (!source || HeapSize( GetProcessHeap(), 0, source ) < src_len )
175     {
176         HeapFree( GetProcessHeap(), 0, source );
177         paths->Source = source = HeapAlloc( GetProcessHeap(), 0, src_len );
178     }
179     if (!target || HeapSize( GetProcessHeap(), 0, target ) < dst_len )
180     {
181         HeapFree( GetProcessHeap(), 0, target );
182         paths->Target = target = HeapAlloc( GetProcessHeap(), 0, dst_len );
183     }
184     if (!source || !target) return FALSE;
185     concat_W( source, op->src_root, op->src_path, op->src_file );
186     concat_W( target, NULL, op->dst_path, op->dst_file );
187     paths->Win32Error = 0;
188     paths->Flags      = 0;
189     return TRUE;
190 }
191
192
193 /***********************************************************************
194  *            QUEUE_callback_WtoA
195  *
196  * Map a file callback parameters from W to A and call the A callback.
197  */
198 UINT CALLBACK QUEUE_callback_WtoA( void *context, UINT notification,
199                                    UINT_PTR param1, UINT_PTR param2 )
200 {
201     struct callback_WtoA_context *callback_ctx = context;
202     char buffer[MAX_PATH];
203     UINT ret;
204     UINT_PTR old_param2 = param2;
205
206     switch(notification)
207     {
208     case SPFILENOTIFY_COPYERROR:
209         param2 = (UINT_PTR)&buffer;
210         /* fall through */
211     case SPFILENOTIFY_STARTDELETE:
212     case SPFILENOTIFY_ENDDELETE:
213     case SPFILENOTIFY_DELETEERROR:
214     case SPFILENOTIFY_STARTRENAME:
215     case SPFILENOTIFY_ENDRENAME:
216     case SPFILENOTIFY_RENAMEERROR:
217     case SPFILENOTIFY_STARTCOPY:
218     case SPFILENOTIFY_ENDCOPY:
219         {
220             FILEPATHS_W *pathsW = (FILEPATHS_W *)param1;
221             FILEPATHS_A pathsA;
222
223             pathsA.Source     = strdupWtoA( pathsW->Source );
224             pathsA.Target     = strdupWtoA( pathsW->Target );
225             pathsA.Win32Error = pathsW->Win32Error;
226             pathsA.Flags      = pathsW->Flags;
227             ret = callback_ctx->orig_handler( callback_ctx->orig_context, notification,
228                                               (UINT_PTR)&pathsA, param2 );
229             HeapFree( GetProcessHeap(), 0, (void *)pathsA.Source );
230             HeapFree( GetProcessHeap(), 0, (void *)pathsA.Target );
231         }
232         if (notification == SPFILENOTIFY_COPYERROR)
233             MultiByteToWideChar( CP_ACP, 0, buffer, -1, (WCHAR *)old_param2, MAX_PATH );
234         break;
235
236     case SPFILENOTIFY_STARTREGISTRATION:
237     case SPFILENOTIFY_ENDREGISTRATION:
238         {
239             SP_REGISTER_CONTROL_STATUSW *statusW = (SP_REGISTER_CONTROL_STATUSW *)param1;
240             SP_REGISTER_CONTROL_STATUSA statusA;
241
242             statusA.cbSize = sizeof(statusA);
243             statusA.FileName = strdupWtoA( statusW->FileName );
244             statusA.Win32Error  = statusW->Win32Error;
245             statusA.FailureCode = statusW->FailureCode;
246             ret = callback_ctx->orig_handler( callback_ctx->orig_context, notification,
247                                               (UINT_PTR)&statusA, param2 );
248             HeapFree( GetProcessHeap(), 0, (LPSTR)statusA.FileName );
249         }
250         break;
251
252     case SPFILENOTIFY_NEEDMEDIA:
253     case SPFILENOTIFY_QUEUESCAN:
254         FIXME("mapping for %d not implemented\n",notification);
255     case SPFILENOTIFY_STARTQUEUE:
256     case SPFILENOTIFY_ENDQUEUE:
257     case SPFILENOTIFY_STARTSUBQUEUE:
258     case SPFILENOTIFY_ENDSUBQUEUE:
259     default:
260         ret = callback_ctx->orig_handler( callback_ctx->orig_context, notification, param1, param2 );
261         break;
262     }
263     return ret;
264 }
265
266
267 /***********************************************************************
268  *            get_src_file_info
269  *
270  * Retrieve the source file information for a given file.
271  */
272 static void get_src_file_info( HINF hinf, struct file_op *op )
273 {
274     static const WCHAR SourceDisksNames[] =
275         {'S','o','u','r','c','e','D','i','s','k','s','N','a','m','e','s',0};
276     static const WCHAR SourceDisksFiles[] =
277         {'S','o','u','r','c','e','D','i','s','k','s','F','i','l','e','s',0};
278
279     INFCONTEXT file_ctx, disk_ctx;
280     INT id, diskid;
281     DWORD len, len2;
282
283     /* find the SourceDisksFiles entry */
284     if (!SetupFindFirstLineW( hinf, SourceDisksFiles, op->src_file, &file_ctx ))
285     {
286         if ((op->style & (SP_COPY_SOURCE_ABSOLUTE|SP_COPY_SOURCEPATH_ABSOLUTE))) return;
287         /* no specific info, use .inf file source directory */
288         if (!op->src_root) op->src_root = PARSER_get_src_root( hinf );
289         return;
290     }
291     if (!SetupGetIntField( &file_ctx, 1, &diskid )) return;
292
293     /* now find the diskid in the SourceDisksNames section */
294     if (!SetupFindFirstLineW( hinf, SourceDisksNames, NULL, &disk_ctx )) return;
295     for (;;)
296     {
297         if (SetupGetIntField( &disk_ctx, 0, &id ) && (id == diskid)) break;
298         if (!SetupFindNextLine( &disk_ctx, &disk_ctx )) return;
299     }
300
301     /* and fill in the missing info */
302
303     if (!op->src_descr)
304     {
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 );
308     }
309     if (!op->src_tag)
310     {
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 );
314     }
315     if (!op->src_path && !(op->style & SP_COPY_SOURCE_ABSOLUTE))
316     {
317         len = len2 = 0;
318         if (!(op->style & SP_COPY_SOURCEPATH_ABSOLUTE))
319         {
320             /* retrieve relative path for this disk */
321             if (!SetupGetStringFieldW( &disk_ctx, 4, NULL, 0, &len )) len = 0;
322         }
323         /* retrieve relative path for this file */
324         if (!SetupGetStringFieldW( &file_ctx, 2, NULL, 0, &len2 )) len2 = 0;
325
326         if ((len || len2) &&
327             (op->src_path = HeapAlloc( GetProcessHeap(), 0, (len+len2)*sizeof(WCHAR) )))
328         {
329             WCHAR *ptr = op->src_path;
330             if (len)
331             {
332                 SetupGetStringFieldW( &disk_ctx, 4, op->src_path, len, NULL );
333                 ptr = op->src_path + strlenW(op->src_path);
334                 if (len2 && ptr > op->src_path && ptr[-1] != '\\') *ptr++ = '\\';
335             }
336             if (!SetupGetStringFieldW( &file_ctx, 2, ptr, len2, NULL )) *ptr = 0;
337         }
338     }
339     if (!op->src_root) op->src_root = PARSER_get_src_root(hinf);
340 }
341
342
343 /***********************************************************************
344  *            get_destination_dir
345  *
346  * Retrieve the destination dir for a given section.
347  */
348 static WCHAR *get_destination_dir( HINF hinf, const WCHAR *section )
349 {
350     static const WCHAR Dest[] = {'D','e','s','t','i','n','a','t','i','o','n','D','i','r','s',0};
351     static const WCHAR Def[]  = {'D','e','f','a','u','l','t','D','e','s','t','D','i','r',0};
352     INFCONTEXT context;
353
354     if (!SetupFindFirstLineW( hinf, Dest, section, &context ) &&
355         !SetupFindFirstLineW( hinf, Dest, Def, &context )) return NULL;
356     return PARSER_get_dest_dir( &context );
357 }
358
359
360 static void (WINAPI *pExtractFiles)( LPSTR, LPSTR, DWORD, DWORD, DWORD, DWORD );
361
362 /***********************************************************************
363  *            extract_cabinet_file
364  *
365  * Extract a file from a .cab file.
366  */
367 static BOOL extract_cabinet_file( const WCHAR *cabinet, const WCHAR *root,
368                                   const WCHAR *src, const WCHAR *dst )
369 {
370     static const WCHAR extW[] = {'.','c','a','b',0};
371     static HMODULE advpack;
372
373     char *cab_path, *cab_file;
374     int len = strlenW( cabinet );
375
376     /* make sure the cabinet file has a .cab extension */
377     if (len <= 4 || strcmpiW( cabinet + len - 4, extW )) return FALSE;
378     if (!pExtractFiles)
379     {
380         if (!advpack && !(advpack = LoadLibraryA( "advpack.dll" )))
381         {
382             ERR( "could not load advpack.dll\n" );
383             return FALSE;
384         }
385         if (!(pExtractFiles = (void *)GetProcAddress( advpack, "ExtractFiles" )))
386         {
387             ERR( "could not find ExtractFiles in advpack.dll\n" );
388             return FALSE;
389         }
390     }
391
392     if (!(cab_path = strdupWtoA( root ))) return FALSE;
393     len = WideCharToMultiByte( CP_ACP, 0, cabinet, -1, NULL, 0, NULL, NULL );
394     if (!(cab_file = HeapAlloc( GetProcessHeap(), 0, strlen(cab_path) + len + 1 )))
395     {
396         HeapFree( GetProcessHeap(), 0, cab_path );
397         return FALSE;
398     }
399     strcpy( cab_file, cab_path );
400     if (cab_file[0] && cab_file[strlen(cab_file)-1] != '\\') strcat( cab_file, "\\" );
401     WideCharToMultiByte( CP_ACP, 0, cabinet, -1, cab_file + strlen(cab_file), len, NULL, NULL );
402     FIXME( "awful hack: extracting cabinet %s\n", debugstr_a(cab_file) );
403     pExtractFiles( cab_file, cab_path, 0, 0, 0, 0 );
404     HeapFree( GetProcessHeap(), 0, cab_file );
405     HeapFree( GetProcessHeap(), 0, cab_path );
406     return CopyFileW( src, dst, FALSE /*FIXME*/ );
407 }
408
409
410 /***********************************************************************
411  *            SetupOpenFileQueue   (SETUPAPI.@)
412  */
413 HSPFILEQ WINAPI SetupOpenFileQueue(void)
414 {
415     struct file_queue *queue;
416
417     if (!(queue = HeapAlloc( GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*queue))))
418         return (HSPFILEQ)INVALID_HANDLE_VALUE;
419     return queue;
420 }
421
422
423 /***********************************************************************
424  *            SetupCloseFileQueue   (SETUPAPI.@)
425  */
426 BOOL WINAPI SetupCloseFileQueue( HSPFILEQ handle )
427 {
428     struct file_queue *queue = handle;
429
430     free_file_op_queue( &queue->copy_queue );
431     free_file_op_queue( &queue->rename_queue );
432     free_file_op_queue( &queue->delete_queue );
433     HeapFree( GetProcessHeap(), 0, queue );
434     return TRUE;
435 }
436
437
438 /***********************************************************************
439  *            SetupQueueCopyIndirectA   (SETUPAPI.@)
440  */
441 BOOL WINAPI SetupQueueCopyIndirectA( PSP_FILE_COPY_PARAMS_A params )
442 {
443     struct file_queue *queue = params->QueueHandle;
444     struct file_op *op;
445
446     if (!(op = HeapAlloc( GetProcessHeap(), 0, sizeof(*op) ))) return FALSE;
447     op->style      = params->CopyStyle;
448     op->src_root   = strdupAtoW( params->SourceRootPath );
449     op->src_path   = strdupAtoW( params->SourcePath );
450     op->src_file   = strdupAtoW( params->SourceFilename );
451     op->src_descr  = strdupAtoW( params->SourceDescription );
452     op->src_tag    = strdupAtoW( params->SourceTagfile );
453     op->dst_path   = strdupAtoW( params->TargetDirectory );
454     op->dst_file   = strdupAtoW( params->TargetFilename );
455
456     /* some defaults */
457     if (!op->src_file) op->src_file = op->dst_file;
458     if (params->LayoutInf)
459     {
460         get_src_file_info( params->LayoutInf, op );
461         if (!op->dst_path) op->dst_path = get_destination_dir( params->LayoutInf, op->dst_file );
462     }
463
464     TRACE( "root=%s path=%s file=%s -> dir=%s file=%s  descr=%s tag=%s\n",
465            debugstr_w(op->src_root), debugstr_w(op->src_path), debugstr_w(op->src_file),
466            debugstr_w(op->dst_path), debugstr_w(op->dst_file),
467            debugstr_w(op->src_descr), debugstr_w(op->src_tag) );
468
469     queue_file_op( &queue->copy_queue, op );
470     return TRUE;
471 }
472
473
474 /***********************************************************************
475  *            SetupQueueCopyIndirectW   (SETUPAPI.@)
476  */
477 BOOL WINAPI SetupQueueCopyIndirectW( PSP_FILE_COPY_PARAMS_W params )
478 {
479     struct file_queue *queue = params->QueueHandle;
480     struct file_op *op;
481
482     if (!(op = HeapAlloc( GetProcessHeap(), 0, sizeof(*op) ))) return FALSE;
483     op->style      = params->CopyStyle;
484     op->src_root   = strdupW( params->SourceRootPath );
485     op->src_path   = strdupW( params->SourcePath );
486     op->src_file   = strdupW( params->SourceFilename );
487     op->src_descr  = strdupW( params->SourceDescription );
488     op->src_tag    = strdupW( params->SourceTagfile );
489     op->dst_path   = strdupW( params->TargetDirectory );
490     op->dst_file   = strdupW( params->TargetFilename );
491
492     /* some defaults */
493     if (!op->src_file) op->src_file = op->dst_file;
494     if (params->LayoutInf)
495     {
496         get_src_file_info( params->LayoutInf, op );
497         if (!op->dst_path) op->dst_path = get_destination_dir( params->LayoutInf, op->dst_file );
498     }
499
500     TRACE( "root=%s path=%s file=%s -> dir=%s file=%s  descr=%s tag=%s\n",
501            debugstr_w(op->src_root), debugstr_w(op->src_path), debugstr_w(op->src_file),
502            debugstr_w(op->dst_path), debugstr_w(op->dst_file),
503            debugstr_w(op->src_descr), debugstr_w(op->src_tag) );
504
505     queue_file_op( &queue->copy_queue, op );
506     return TRUE;
507 }
508
509
510 /***********************************************************************
511  *            SetupQueueCopyA   (SETUPAPI.@)
512  */
513 BOOL WINAPI SetupQueueCopyA( HSPFILEQ queue, PCSTR src_root, PCSTR src_path, PCSTR src_file,
514                              PCSTR src_descr, PCSTR src_tag, PCSTR dst_dir, PCSTR dst_file,
515                              DWORD style )
516 {
517     SP_FILE_COPY_PARAMS_A params;
518
519     params.cbSize             = sizeof(params);
520     params.QueueHandle        = queue;
521     params.SourceRootPath     = src_root;
522     params.SourcePath         = src_path;
523     params.SourceFilename     = src_file;
524     params.SourceDescription  = src_descr;
525     params.SourceTagfile      = src_tag;
526     params.TargetDirectory    = dst_dir;
527     params.TargetFilename     = dst_file;
528     params.CopyStyle          = style;
529     params.LayoutInf          = 0;
530     params.SecurityDescriptor = NULL;
531     return SetupQueueCopyIndirectA( &params );
532 }
533
534
535 /***********************************************************************
536  *            SetupQueueCopyW   (SETUPAPI.@)
537  */
538 BOOL WINAPI SetupQueueCopyW( HSPFILEQ queue, PCWSTR src_root, PCWSTR src_path, PCWSTR src_file,
539                              PCWSTR src_descr, PCWSTR src_tag, PCWSTR dst_dir, PCWSTR dst_file,
540                              DWORD style )
541 {
542     SP_FILE_COPY_PARAMS_W params;
543
544     params.cbSize             = sizeof(params);
545     params.QueueHandle        = queue;
546     params.SourceRootPath     = src_root;
547     params.SourcePath         = src_path;
548     params.SourceFilename     = src_file;
549     params.SourceDescription  = src_descr;
550     params.SourceTagfile      = src_tag;
551     params.TargetDirectory    = dst_dir;
552     params.TargetFilename     = dst_file;
553     params.CopyStyle          = style;
554     params.LayoutInf          = 0;
555     params.SecurityDescriptor = NULL;
556     return SetupQueueCopyIndirectW( &params );
557 }
558
559
560 /***********************************************************************
561  *            SetupQueueDefaultCopyA   (SETUPAPI.@)
562  */
563 BOOL WINAPI SetupQueueDefaultCopyA( HSPFILEQ queue, HINF hinf, PCSTR src_root, PCSTR src_file,
564                                     PCSTR dst_file, DWORD style )
565 {
566     SP_FILE_COPY_PARAMS_A params;
567
568     params.cbSize             = sizeof(params);
569     params.QueueHandle        = queue;
570     params.SourceRootPath     = src_root;
571     params.SourcePath         = NULL;
572     params.SourceFilename     = src_file;
573     params.SourceDescription  = NULL;
574     params.SourceTagfile      = NULL;
575     params.TargetDirectory    = NULL;
576     params.TargetFilename     = dst_file;
577     params.CopyStyle          = style;
578     params.LayoutInf          = hinf;
579     params.SecurityDescriptor = NULL;
580     return SetupQueueCopyIndirectA( &params );
581 }
582
583
584 /***********************************************************************
585  *            SetupQueueDefaultCopyW   (SETUPAPI.@)
586  */
587 BOOL WINAPI SetupQueueDefaultCopyW( HSPFILEQ queue, HINF hinf, PCWSTR src_root, PCWSTR src_file,
588                                     PCWSTR dst_file, DWORD style )
589 {
590     SP_FILE_COPY_PARAMS_W params;
591
592     params.cbSize             = sizeof(params);
593     params.QueueHandle        = queue;
594     params.SourceRootPath     = src_root;
595     params.SourcePath         = NULL;
596     params.SourceFilename     = src_file;
597     params.SourceDescription  = NULL;
598     params.SourceTagfile      = NULL;
599     params.TargetDirectory    = NULL;
600     params.TargetFilename     = dst_file;
601     params.CopyStyle          = style;
602     params.LayoutInf          = hinf;
603     params.SecurityDescriptor = NULL;
604     return SetupQueueCopyIndirectW( &params );
605 }
606
607
608 /***********************************************************************
609  *            SetupQueueDeleteA   (SETUPAPI.@)
610  */
611 BOOL WINAPI SetupQueueDeleteA( HSPFILEQ handle, PCSTR part1, PCSTR part2 )
612 {
613     struct file_queue *queue = handle;
614     struct file_op *op;
615
616     if (!(op = HeapAlloc( GetProcessHeap(), 0, sizeof(*op) ))) return FALSE;
617     op->style      = 0;
618     op->src_root   = NULL;
619     op->src_path   = NULL;
620     op->src_file   = NULL;
621     op->src_descr  = NULL;
622     op->src_tag    = NULL;
623     op->dst_path   = strdupAtoW( part1 );
624     op->dst_file   = strdupAtoW( part2 );
625     queue_file_op( &queue->delete_queue, op );
626     return TRUE;
627 }
628
629
630 /***********************************************************************
631  *            SetupQueueDeleteW   (SETUPAPI.@)
632  */
633 BOOL WINAPI SetupQueueDeleteW( HSPFILEQ handle, PCWSTR part1, PCWSTR part2 )
634 {
635     struct file_queue *queue = handle;
636     struct file_op *op;
637
638     if (!(op = HeapAlloc( GetProcessHeap(), 0, sizeof(*op) ))) return FALSE;
639     op->style      = 0;
640     op->src_root   = NULL;
641     op->src_path   = NULL;
642     op->src_file   = NULL;
643     op->src_descr  = NULL;
644     op->src_tag    = NULL;
645     op->dst_path   = strdupW( part1 );
646     op->dst_file   = strdupW( part2 );
647     queue_file_op( &queue->delete_queue, op );
648     return TRUE;
649 }
650
651
652 /***********************************************************************
653  *            SetupQueueRenameA   (SETUPAPI.@)
654  */
655 BOOL WINAPI SetupQueueRenameA( HSPFILEQ handle, PCSTR SourcePath, PCSTR SourceFilename,
656                                PCSTR TargetPath, PCSTR TargetFilename )
657 {
658     struct file_queue *queue = handle;
659     struct file_op *op;
660
661     if (!(op = HeapAlloc( GetProcessHeap(), 0, sizeof(*op) ))) return FALSE;
662     op->style      = 0;
663     op->src_root   = NULL;
664     op->src_path   = strdupAtoW( SourcePath );
665     op->src_file   = strdupAtoW( SourceFilename );
666     op->src_descr  = NULL;
667     op->src_tag    = NULL;
668     op->dst_path   = strdupAtoW( TargetPath );
669     op->dst_file   = strdupAtoW( TargetFilename );
670     queue_file_op( &queue->rename_queue, op );
671     return TRUE;
672 }
673
674
675 /***********************************************************************
676  *            SetupQueueRenameW   (SETUPAPI.@)
677  */
678 BOOL WINAPI SetupQueueRenameW( HSPFILEQ handle, PCWSTR SourcePath, PCWSTR SourceFilename,
679                                PCWSTR TargetPath, PCWSTR TargetFilename )
680 {
681     struct file_queue *queue = handle;
682     struct file_op *op;
683
684     if (!(op = HeapAlloc( GetProcessHeap(), 0, sizeof(*op) ))) return FALSE;
685     op->style      = 0;
686     op->src_root   = NULL;
687     op->src_path   = strdupW( SourcePath );
688     op->src_file   = strdupW( SourceFilename );
689     op->src_descr  = NULL;
690     op->src_tag    = NULL;
691     op->dst_path   = strdupW( TargetPath );
692     op->dst_file   = strdupW( TargetFilename );
693     queue_file_op( &queue->rename_queue, op );
694     return TRUE;
695 }
696
697
698 /***********************************************************************
699  *            SetupQueueCopySectionA   (SETUPAPI.@)
700  */
701 BOOL WINAPI SetupQueueCopySectionA( HSPFILEQ queue, PCSTR src_root, HINF hinf, HINF hlist,
702                                     PCSTR section, DWORD style )
703 {
704     UNICODE_STRING sectionW;
705     BOOL ret = FALSE;
706
707     if (!RtlCreateUnicodeStringFromAsciiz( &sectionW, section ))
708     {
709         SetLastError( ERROR_NOT_ENOUGH_MEMORY );
710         return FALSE;
711     }
712     if (!src_root)
713         ret = SetupQueueCopySectionW( queue, NULL, hinf, hlist, sectionW.Buffer, style );
714     else
715     {
716         UNICODE_STRING srcW;
717         if (RtlCreateUnicodeStringFromAsciiz( &srcW, src_root ))
718         {
719             ret = SetupQueueCopySectionW( queue, srcW.Buffer, hinf, hlist, sectionW.Buffer, style );
720             RtlFreeUnicodeString( &srcW );
721         }
722         else SetLastError( ERROR_NOT_ENOUGH_MEMORY );
723     }
724     RtlFreeUnicodeString( &sectionW );
725     return ret;
726 }
727
728
729 /***********************************************************************
730  *            SetupQueueCopySectionW   (SETUPAPI.@)
731  */
732 BOOL WINAPI SetupQueueCopySectionW( HSPFILEQ queue, PCWSTR src_root, HINF hinf, HINF hlist,
733                                     PCWSTR section, DWORD style )
734 {
735     SP_FILE_COPY_PARAMS_W params;
736     INFCONTEXT context;
737     WCHAR dest[MAX_PATH], src[MAX_PATH];
738     INT flags;
739
740     TRACE( "hinf=%p/%p section=%s root=%s\n",
741            hinf, hlist, debugstr_w(section), debugstr_w(src_root) );
742
743     params.cbSize             = sizeof(params);
744     params.QueueHandle        = queue;
745     params.SourceRootPath     = src_root;
746     params.SourcePath         = NULL;
747     params.SourceDescription  = NULL;
748     params.SourceTagfile      = NULL;
749     params.TargetFilename     = dest;
750     params.CopyStyle          = style;
751     params.LayoutInf          = hinf;
752     params.SecurityDescriptor = NULL;
753
754     if (!hlist) hlist = hinf;
755     if (!hinf) hinf = hlist;
756     if (!SetupFindFirstLineW( hlist, section, NULL, &context )) return FALSE;
757     if (!(params.TargetDirectory = get_destination_dir( hinf, section ))) return FALSE;
758     do
759     {
760         if (!SetupGetStringFieldW( &context, 1, dest, sizeof(dest)/sizeof(WCHAR), NULL ))
761             return FALSE;
762         if (!SetupGetStringFieldW( &context, 2, src, sizeof(src)/sizeof(WCHAR), NULL )) *src = 0;
763         if (!SetupGetIntField( &context, 4, &flags )) flags = 0;  /* FIXME */
764
765         params.SourceFilename = *src ? src : NULL;
766         if (!SetupQueueCopyIndirectW( &params )) return FALSE;
767     } while (SetupFindNextLine( &context, &context ));
768     return TRUE;
769 }
770
771
772 /***********************************************************************
773  *            SetupQueueDeleteSectionA   (SETUPAPI.@)
774  */
775 BOOL WINAPI SetupQueueDeleteSectionA( HSPFILEQ queue, HINF hinf, HINF hlist, PCSTR section )
776 {
777     UNICODE_STRING sectionW;
778     BOOL ret = FALSE;
779
780     if (RtlCreateUnicodeStringFromAsciiz( &sectionW, section ))
781     {
782         ret = SetupQueueDeleteSectionW( queue, hinf, hlist, sectionW.Buffer );
783         RtlFreeUnicodeString( &sectionW );
784     }
785     else SetLastError( ERROR_NOT_ENOUGH_MEMORY );
786     return ret;
787 }
788
789
790 /***********************************************************************
791  *            SetupQueueDeleteSectionW   (SETUPAPI.@)
792  */
793 BOOL WINAPI SetupQueueDeleteSectionW( HSPFILEQ queue, HINF hinf, HINF hlist, PCWSTR section )
794 {
795     INFCONTEXT context;
796     WCHAR *dest_dir;
797     WCHAR buffer[MAX_PATH];
798     BOOL ret = FALSE;
799     INT flags;
800
801     TRACE( "hinf=%p/%p section=%s\n", hinf, hlist, debugstr_w(section) );
802
803     if (!hlist) hlist = hinf;
804     if (!SetupFindFirstLineW( hlist, section, NULL, &context )) return FALSE;
805     if (!(dest_dir = get_destination_dir( hinf, section ))) return FALSE;
806     do
807     {
808         if (!SetupGetStringFieldW( &context, 1, buffer, sizeof(buffer)/sizeof(WCHAR), NULL ))
809             goto done;
810         if (!SetupGetIntField( &context, 4, &flags )) flags = 0;
811         if (!SetupQueueDeleteW( queue, dest_dir, buffer )) goto done;
812     } while (SetupFindNextLine( &context, &context ));
813
814     ret = TRUE;
815  done:
816     HeapFree( GetProcessHeap(), 0, dest_dir );
817     return ret;
818 }
819
820
821 /***********************************************************************
822  *            SetupQueueRenameSectionA   (SETUPAPI.@)
823  */
824 BOOL WINAPI SetupQueueRenameSectionA( HSPFILEQ queue, HINF hinf, HINF hlist, PCSTR section )
825 {
826     UNICODE_STRING sectionW;
827     BOOL ret = FALSE;
828
829     if (RtlCreateUnicodeStringFromAsciiz( &sectionW, section ))
830     {
831         ret = SetupQueueRenameSectionW( queue, hinf, hlist, sectionW.Buffer );
832         RtlFreeUnicodeString( &sectionW );
833     }
834     else SetLastError( ERROR_NOT_ENOUGH_MEMORY );
835     return ret;
836 }
837
838
839 /***********************************************************************
840  *            SetupQueueRenameSectionW   (SETUPAPI.@)
841  */
842 BOOL WINAPI SetupQueueRenameSectionW( HSPFILEQ queue, HINF hinf, HINF hlist, PCWSTR section )
843 {
844     INFCONTEXT context;
845     WCHAR *dest_dir;
846     WCHAR src[MAX_PATH], dst[MAX_PATH];
847     BOOL ret = FALSE;
848
849     TRACE( "hinf=%p/%p section=%s\n", hinf, hlist, debugstr_w(section) );
850
851     if (!hlist) hlist = hinf;
852     if (!SetupFindFirstLineW( hlist, section, NULL, &context )) return FALSE;
853     if (!(dest_dir = get_destination_dir( hinf, section ))) return FALSE;
854     do
855     {
856         if (!SetupGetStringFieldW( &context, 1, dst, sizeof(dst)/sizeof(WCHAR), NULL ))
857             goto done;
858         if (!SetupGetStringFieldW( &context, 2, src, sizeof(src)/sizeof(WCHAR), NULL ))
859             goto done;
860         if (!SetupQueueRenameW( queue, dest_dir, src, NULL, dst )) goto done;
861     } while (SetupFindNextLine( &context, &context ));
862
863     ret = TRUE;
864  done:
865     HeapFree( GetProcessHeap(), 0, dest_dir );
866     return ret;
867 }
868
869
870 /***********************************************************************
871  *            SetupCommitFileQueueA   (SETUPAPI.@)
872  */
873 BOOL WINAPI SetupCommitFileQueueA( HWND owner, HSPFILEQ queue, PSP_FILE_CALLBACK_A handler,
874                                    PVOID context )
875 {
876     struct callback_WtoA_context ctx;
877
878     ctx.orig_context = context;
879     ctx.orig_handler = handler;
880     return SetupCommitFileQueueW( owner, queue, QUEUE_callback_WtoA, &ctx );
881 }
882
883
884 /***********************************************************************
885  *            create_full_pathW
886  *
887  * Recursively create all directories in the path.
888  */
889 static BOOL create_full_pathW(const WCHAR *path)
890 {
891     BOOL ret = TRUE;
892     int len;
893     WCHAR *new_path;
894
895     new_path = HeapAlloc(GetProcessHeap(), 0, (strlenW(path) + 1) * sizeof(WCHAR));
896     strcpyW(new_path, path);
897
898     while((len = strlenW(new_path)) && new_path[len - 1] == '\\')
899         new_path[len - 1] = 0;
900
901     while(!CreateDirectoryW(new_path, NULL))
902     {
903         WCHAR *slash;
904         DWORD last_error = GetLastError();
905
906         if(last_error == ERROR_ALREADY_EXISTS)
907             break;
908
909         if(last_error != ERROR_PATH_NOT_FOUND)
910         {
911             ret = FALSE;
912             break;
913         }
914
915         if(!(slash = strrchrW(new_path, '\\')))
916         {
917             ret = FALSE;
918             break;
919         }
920
921         len = slash - new_path;
922         new_path[len] = 0;
923         if(!create_full_pathW(new_path))
924         {
925             ret = FALSE;
926             break;
927         }
928         new_path[len] = '\\';
929     }
930
931     HeapFree(GetProcessHeap(), 0, new_path);
932     return ret;
933 }
934
935 static BOOL do_file_copyW( LPCWSTR source, LPCWSTR target, DWORD style, 
936                            PSP_FILE_CALLBACK_W handler, PVOID context )
937 {
938     BOOL rc = FALSE;
939     BOOL docopy = TRUE;
940
941     TRACE("copy %s to %s style 0x%x\n",debugstr_w(source),debugstr_w(target),style);
942
943     /* before copy processing */
944     if (style & SP_COPY_REPLACEONLY)
945     {
946         if (GetFileAttributesW(target) == INVALID_FILE_ATTRIBUTES)
947             docopy = FALSE;
948     }
949     if (style & (SP_COPY_NEWER_OR_SAME | SP_COPY_NEWER_ONLY | SP_COPY_FORCE_NEWER))
950     {
951         DWORD VersionSizeSource=0;
952         DWORD VersionSizeTarget=0;
953         DWORD zero=0;
954
955         /*
956          * This is sort of an interesting workaround. You see, calling
957          * GetVersionInfoSize on a builtin dll loads that dll into memory
958          * and we do not properly unload builtin dlls.. so we effectively
959          * lock into memory all the targets we are replacing. This leads
960          * to problems when we try to register the replaced dlls.
961          *
962          * So I will test for the existence of the files first so that
963          * we just basically unconditionally replace the builtin versions.
964          */
965         if ((GetFileAttributesW(target) != INVALID_FILE_ATTRIBUTES) &&
966             (GetFileAttributesW(source) != INVALID_FILE_ATTRIBUTES))
967         {
968             VersionSizeSource = GetFileVersionInfoSizeW(source,&zero);
969             VersionSizeTarget = GetFileVersionInfoSizeW(target,&zero);
970         }
971
972         TRACE("SizeTarget %i ... SizeSource %i\n",VersionSizeTarget,
973                 VersionSizeSource);
974
975         if (VersionSizeSource && VersionSizeTarget)
976         {
977             LPVOID VersionSource;
978             LPVOID VersionTarget;
979             VS_FIXEDFILEINFO *TargetInfo;
980             VS_FIXEDFILEINFO *SourceInfo;
981             UINT length;
982             WCHAR  SubBlock[2]={'\\',0};
983             DWORD  ret;
984
985             VersionSource = HeapAlloc(GetProcessHeap(),0,VersionSizeSource);
986             VersionTarget = HeapAlloc(GetProcessHeap(),0,VersionSizeTarget);
987
988             ret = GetFileVersionInfoW(source,0,VersionSizeSource,VersionSource);
989             if (ret)
990               ret = GetFileVersionInfoW(target, 0, VersionSizeTarget,
991                     VersionTarget);
992
993             if (ret)
994             {
995                 ret = VerQueryValueW(VersionSource, SubBlock,
996                                     (LPVOID*)&SourceInfo, &length);
997                 if (ret)
998                     ret = VerQueryValueW(VersionTarget, SubBlock,
999                                          (LPVOID*)&TargetInfo, &length);
1000
1001                 if (ret)
1002                 {
1003                     FILEPATHS_W filepaths;
1004
1005                     TRACE("Versions: Source %i.%i target %i.%i\n",
1006                       SourceInfo->dwFileVersionMS, SourceInfo->dwFileVersionLS,
1007                       TargetInfo->dwFileVersionMS, TargetInfo->dwFileVersionLS);
1008
1009                     /* used in case of notification */
1010                     filepaths.Target = target;
1011                     filepaths.Source = source;
1012                     filepaths.Win32Error = 0;
1013                     filepaths.Flags = 0;
1014
1015                     if (TargetInfo->dwFileVersionMS > SourceInfo->dwFileVersionMS)
1016                     {
1017                         if (handler)
1018                             docopy = handler (context, SPFILENOTIFY_TARGETNEWER, (UINT_PTR)&filepaths, 0);
1019                         else
1020                             docopy = FALSE;
1021                     }
1022                     else if ((TargetInfo->dwFileVersionMS == SourceInfo->dwFileVersionMS)
1023                              && (TargetInfo->dwFileVersionLS > SourceInfo->dwFileVersionLS))
1024                     {
1025                         if (handler)
1026                             docopy = handler (context, SPFILENOTIFY_TARGETNEWER, (UINT_PTR)&filepaths, 0);
1027                         else
1028                             docopy = FALSE;
1029                     }
1030                     else if ((style & SP_COPY_NEWER_ONLY) &&
1031                         (TargetInfo->dwFileVersionMS ==
1032                          SourceInfo->dwFileVersionMS)
1033                         &&(TargetInfo->dwFileVersionLS ==
1034                         SourceInfo->dwFileVersionLS))
1035                     {
1036                         if (handler)
1037                             docopy = handler (context, SPFILENOTIFY_TARGETNEWER, (UINT_PTR)&filepaths, 0);
1038                         else
1039                             docopy = FALSE;
1040                     }
1041                 }
1042             }
1043             HeapFree(GetProcessHeap(),0,VersionSource);
1044             HeapFree(GetProcessHeap(),0,VersionTarget);
1045         }
1046     }
1047     if (style & (SP_COPY_NOOVERWRITE | SP_COPY_FORCE_NOOVERWRITE))
1048     {
1049         if (GetFileAttributesW(target) != INVALID_FILE_ATTRIBUTES)
1050         {
1051             FIXME("Notify user target file exists\n");
1052             docopy = FALSE;
1053         }
1054     }
1055     if (style & (SP_COPY_NODECOMP | SP_COPY_LANGUAGEAWARE | SP_COPY_FORCE_IN_USE |
1056                  SP_COPY_IN_USE_NEEDS_REBOOT | SP_COPY_NOSKIP | SP_COPY_WARNIFSKIP))
1057     {
1058         ERR("Unsupported style(s) 0x%x\n",style);
1059     }
1060
1061     if (docopy)
1062     {
1063         rc = CopyFileW(source,target,FALSE);
1064         TRACE("Did copy... rc was %i\n",rc);
1065     }
1066
1067     /* after copy processing */
1068     if (style & SP_COPY_DELETESOURCE)
1069     {
1070        if (rc)
1071             DeleteFileW(source);
1072     }
1073
1074     return rc;
1075 }
1076
1077 /***********************************************************************
1078  *            SetupCommitFileQueueW   (SETUPAPI.@)
1079  */
1080 BOOL WINAPI SetupCommitFileQueueW( HWND owner, HSPFILEQ handle, PSP_FILE_CALLBACK_W handler,
1081                                    PVOID context )
1082 {
1083     struct file_queue *queue = handle;
1084     struct file_op *op;
1085     BOOL result = FALSE;
1086     FILEPATHS_W paths;
1087     UINT op_result;
1088
1089     paths.Source = paths.Target = NULL;
1090
1091     if (!queue->copy_queue.count && !queue->delete_queue.count && !queue->rename_queue.count)
1092         return TRUE;  /* nothing to do */
1093
1094     if (!handler( context, SPFILENOTIFY_STARTQUEUE, (UINT_PTR)owner, 0 )) return FALSE;
1095
1096     /* perform deletes */
1097
1098     if (queue->delete_queue.count)
1099     {
1100         if (!(handler( context, SPFILENOTIFY_STARTSUBQUEUE, FILEOP_DELETE,
1101                        queue->delete_queue.count ))) goto done;
1102         for (op = queue->delete_queue.head; op; op = op->next)
1103         {
1104             build_filepathsW( op, &paths );
1105             op_result = handler( context, SPFILENOTIFY_STARTDELETE, (UINT_PTR)&paths, FILEOP_DELETE);
1106             if (op_result == FILEOP_ABORT) goto done;
1107             while (op_result == FILEOP_DOIT)
1108             {
1109                 TRACE( "deleting file %s\n", debugstr_w(paths.Target) );
1110                 if (DeleteFileW( paths.Target )) break;  /* success */
1111                 paths.Win32Error = GetLastError();
1112                 op_result = handler( context, SPFILENOTIFY_DELETEERROR, (UINT_PTR)&paths, 0 );
1113                 if (op_result == FILEOP_ABORT) goto done;
1114             }
1115             handler( context, SPFILENOTIFY_ENDDELETE, (UINT_PTR)&paths, 0 );
1116         }
1117         handler( context, SPFILENOTIFY_ENDSUBQUEUE, FILEOP_DELETE, 0 );
1118     }
1119
1120     /* perform renames */
1121
1122     if (queue->rename_queue.count)
1123     {
1124         if (!(handler( context, SPFILENOTIFY_STARTSUBQUEUE, FILEOP_RENAME,
1125                        queue->rename_queue.count ))) goto done;
1126         for (op = queue->rename_queue.head; op; op = op->next)
1127         {
1128             build_filepathsW( op, &paths );
1129             op_result = handler( context, SPFILENOTIFY_STARTRENAME, (UINT_PTR)&paths, FILEOP_RENAME);
1130             if (op_result == FILEOP_ABORT) goto done;
1131             while (op_result == FILEOP_DOIT)
1132             {
1133                 TRACE( "renaming file %s -> %s\n",
1134                        debugstr_w(paths.Source), debugstr_w(paths.Target) );
1135                 if (MoveFileW( paths.Source, paths.Target )) break;  /* success */
1136                 paths.Win32Error = GetLastError();
1137                 op_result = handler( context, SPFILENOTIFY_RENAMEERROR, (UINT_PTR)&paths, 0 );
1138                 if (op_result == FILEOP_ABORT) goto done;
1139             }
1140             handler( context, SPFILENOTIFY_ENDRENAME, (UINT_PTR)&paths, 0 );
1141         }
1142         handler( context, SPFILENOTIFY_ENDSUBQUEUE, FILEOP_RENAME, 0 );
1143     }
1144
1145     /* perform copies */
1146
1147     if (queue->copy_queue.count)
1148     {
1149         if (!(handler( context, SPFILENOTIFY_STARTSUBQUEUE, FILEOP_COPY,
1150                        queue->copy_queue.count ))) goto done;
1151         for (op = queue->copy_queue.head; op; op = op->next)
1152         {
1153             WCHAR newpath[MAX_PATH];
1154
1155             build_filepathsW( op, &paths );
1156             op_result = handler( context, SPFILENOTIFY_STARTCOPY, (UINT_PTR)&paths, FILEOP_COPY );
1157             if (op_result == FILEOP_ABORT) goto done;
1158             if (op_result == FILEOP_NEWPATH) op_result = FILEOP_DOIT;
1159             while (op_result == FILEOP_DOIT || op_result == FILEOP_NEWPATH)
1160             {
1161                 TRACE( "copying file %s -> %s\n",
1162                        debugstr_w( op_result == FILEOP_NEWPATH ? newpath : paths.Source ),
1163                        debugstr_w(paths.Target) );
1164                 if (op->dst_path)
1165                 {
1166                     if (!create_full_pathW( op->dst_path ))
1167                     {
1168                         paths.Win32Error = GetLastError();
1169                         op_result = handler( context, SPFILENOTIFY_COPYERROR,
1170                                              (UINT_PTR)&paths, (UINT_PTR)newpath );
1171                         if (op_result == FILEOP_ABORT) goto done;
1172                     }
1173                 }
1174                 if (do_file_copyW( op_result == FILEOP_NEWPATH ? newpath : paths.Source,
1175                                paths.Target, op->style, handler, context )) break;  /* success */
1176                 /* try to extract it from the cabinet file */
1177                 if (op->src_tag)
1178                 {
1179                     if (extract_cabinet_file( op->src_tag, op->src_root,
1180                                               paths.Source, paths.Target )) break;
1181                 }
1182                 paths.Win32Error = GetLastError();
1183                 op_result = handler( context, SPFILENOTIFY_COPYERROR,
1184                                      (UINT_PTR)&paths, (UINT_PTR)newpath );
1185                 if (op_result == FILEOP_ABORT) goto done;
1186             }
1187             handler( context, SPFILENOTIFY_ENDCOPY, (UINT_PTR)&paths, 0 );
1188         }
1189         handler( context, SPFILENOTIFY_ENDSUBQUEUE, FILEOP_COPY, 0 );
1190     }
1191
1192
1193     result = TRUE;
1194
1195  done:
1196     handler( context, SPFILENOTIFY_ENDQUEUE, result, 0 );
1197     HeapFree( GetProcessHeap(), 0, (void *)paths.Source );
1198     HeapFree( GetProcessHeap(), 0, (void *)paths.Target );
1199     return result;
1200 }
1201
1202
1203 /***********************************************************************
1204  *            SetupScanFileQueueA   (SETUPAPI.@)
1205  */
1206 BOOL WINAPI SetupScanFileQueueA( HSPFILEQ queue, DWORD flags, HWND window,
1207                                  PSP_FILE_CALLBACK_A callback, PVOID context, PDWORD result )
1208 {
1209     FIXME("stub\n");
1210     return FALSE;
1211 }
1212
1213
1214 /***********************************************************************
1215  *            SetupScanFileQueueW   (SETUPAPI.@)
1216  */
1217 BOOL WINAPI SetupScanFileQueueW( HSPFILEQ queue, DWORD flags, HWND window,
1218                                  PSP_FILE_CALLBACK_W callback, PVOID context, PDWORD result )
1219 {
1220     FIXME("stub\n");
1221     return FALSE;
1222 }
1223
1224
1225 /***********************************************************************
1226  *            SetupGetFileQueueCount   (SETUPAPI.@)
1227  */
1228 BOOL WINAPI SetupGetFileQueueCount( HSPFILEQ handle, UINT op, PUINT result )
1229 {
1230     struct file_queue *queue = handle;
1231
1232     switch(op)
1233     {
1234     case FILEOP_COPY:
1235         *result = queue->copy_queue.count;
1236         return TRUE;
1237     case FILEOP_RENAME:
1238         *result = queue->rename_queue.count;
1239         return TRUE;
1240     case FILEOP_DELETE:
1241         *result = queue->delete_queue.count;
1242         return TRUE;
1243     }
1244     return FALSE;
1245 }
1246
1247
1248 /***********************************************************************
1249  *            SetupGetFileQueueFlags   (SETUPAPI.@)
1250  */
1251 BOOL WINAPI SetupGetFileQueueFlags( HSPFILEQ handle, PDWORD flags )
1252 {
1253     struct file_queue *queue = handle;
1254     *flags = queue->flags;
1255     return TRUE;
1256 }
1257
1258
1259 /***********************************************************************
1260  *            SetupSetFileQueueFlags   (SETUPAPI.@)
1261  */
1262 BOOL WINAPI SetupSetFileQueueFlags( HSPFILEQ handle, DWORD mask, DWORD flags )
1263 {
1264     struct file_queue *queue = handle;
1265     queue->flags = (queue->flags & ~mask) | flags;
1266     return TRUE;
1267 }
1268
1269
1270 /***********************************************************************
1271  *   SetupSetFileQueueAlternatePlatformA  (SETUPAPI.@)
1272  */
1273 BOOL WINAPI SetupSetFileQueueAlternatePlatformA(HSPFILEQ handle, PSP_ALTPLATFORM_INFO platform, PCSTR catalogfile)
1274 {
1275     FIXME("(%p, %p, %s) stub!\n", handle, platform, debugstr_a(catalogfile));
1276     return FALSE;
1277 }
1278
1279
1280 /***********************************************************************
1281  *   SetupSetFileQueueAlternatePlatformW  (SETUPAPI.@)
1282  */
1283 BOOL WINAPI SetupSetFileQueueAlternatePlatformW(HSPFILEQ handle, PSP_ALTPLATFORM_INFO platform, PCWSTR catalogfile)
1284 {
1285     FIXME("(%p, %p, %s) stub!\n", handle, platform, debugstr_w(catalogfile));
1286     return FALSE;
1287 }
1288
1289
1290 /***********************************************************************
1291  *            SetupInitDefaultQueueCallback   (SETUPAPI.@)
1292  */
1293 PVOID WINAPI SetupInitDefaultQueueCallback( HWND owner )
1294 {
1295     return SetupInitDefaultQueueCallbackEx( owner, 0, 0, 0, NULL );
1296 }
1297
1298
1299 /***********************************************************************
1300  *            SetupInitDefaultQueueCallbackEx   (SETUPAPI.@)
1301  */
1302 PVOID WINAPI SetupInitDefaultQueueCallbackEx( HWND owner, HWND progress, UINT msg,
1303                                               DWORD reserved1, PVOID reserved2 )
1304 {
1305     struct default_callback_context *context;
1306
1307     if ((context = HeapAlloc( GetProcessHeap(), 0, sizeof(*context) )))
1308     {
1309         context->owner    = owner;
1310         context->progress = progress;
1311         context->message  = msg;
1312     }
1313     return context;
1314 }
1315
1316
1317 /***********************************************************************
1318  *            SetupTermDefaultQueueCallback   (SETUPAPI.@)
1319  */
1320 void WINAPI SetupTermDefaultQueueCallback( PVOID context )
1321 {
1322     HeapFree( GetProcessHeap(), 0, context );
1323 }
1324
1325
1326 /***********************************************************************
1327  *            SetupDefaultQueueCallbackA   (SETUPAPI.@)
1328  */
1329 UINT WINAPI SetupDefaultQueueCallbackA( PVOID context, UINT notification,
1330                                         UINT_PTR param1, UINT_PTR param2 )
1331 {
1332     FILEPATHS_A *paths = (FILEPATHS_A *)param1;
1333     struct default_callback_context *ctx = (struct default_callback_context *)context;
1334
1335     switch(notification)
1336     {
1337     case SPFILENOTIFY_STARTQUEUE:
1338         TRACE( "start queue\n" );
1339         return TRUE;
1340     case SPFILENOTIFY_ENDQUEUE:
1341         TRACE( "end queue\n" );
1342         return 0;
1343     case SPFILENOTIFY_STARTSUBQUEUE:
1344         TRACE( "start subqueue %d count %d\n", param1, param2 );
1345         return TRUE;
1346     case SPFILENOTIFY_ENDSUBQUEUE:
1347         TRACE( "end subqueue %d\n", param1 );
1348         return 0;
1349     case SPFILENOTIFY_STARTDELETE:
1350         TRACE( "start delete %s\n", debugstr_a(paths->Target) );
1351         return FILEOP_DOIT;
1352     case SPFILENOTIFY_ENDDELETE:
1353         TRACE( "end delete %s\n", debugstr_a(paths->Target) );
1354         return 0;
1355     case SPFILENOTIFY_DELETEERROR:
1356         /*Windows Ignores attempts to delete files / folders which do not exist*/
1357         if ((paths->Win32Error != ERROR_FILE_NOT_FOUND) && (paths->Win32Error != ERROR_PATH_NOT_FOUND))
1358         SetupDeleteErrorA(ctx->owner, NULL, paths->Target, paths->Win32Error, 0);
1359         return FILEOP_SKIP;
1360     case SPFILENOTIFY_STARTRENAME:
1361         TRACE( "start rename %s -> %s\n", debugstr_a(paths->Source), debugstr_a(paths->Target) );
1362         return FILEOP_DOIT;
1363     case SPFILENOTIFY_ENDRENAME:
1364         TRACE( "end rename %s -> %s\n", debugstr_a(paths->Source), debugstr_a(paths->Target) );
1365         return 0;
1366     case SPFILENOTIFY_RENAMEERROR:
1367         SetupRenameErrorA(ctx->owner, NULL, paths->Source, paths->Target, paths->Win32Error, 0);
1368         return FILEOP_SKIP;
1369     case SPFILENOTIFY_STARTCOPY:
1370         TRACE( "start copy %s -> %s\n", debugstr_a(paths->Source), debugstr_a(paths->Target) );
1371         return FILEOP_DOIT;
1372     case SPFILENOTIFY_ENDCOPY:
1373         TRACE( "end copy %s -> %s\n", debugstr_a(paths->Source), debugstr_a(paths->Target) );
1374         return 0;
1375     case SPFILENOTIFY_COPYERROR:
1376         ERR( "copy error %d %s -> %s\n", paths->Win32Error,
1377              debugstr_a(paths->Source), debugstr_a(paths->Target) );
1378         return FILEOP_SKIP;
1379     case SPFILENOTIFY_NEEDMEDIA:
1380         TRACE( "need media\n" );
1381         return FILEOP_SKIP;
1382     default:
1383         FIXME( "notification %d params %x,%x\n", notification, param1, param2 );
1384         break;
1385     }
1386     return 0;
1387 }
1388
1389
1390 /***********************************************************************
1391  *            SetupDefaultQueueCallbackW   (SETUPAPI.@)
1392  */
1393 UINT WINAPI SetupDefaultQueueCallbackW( PVOID context, UINT notification,
1394                                         UINT_PTR param1, UINT_PTR param2 )
1395 {
1396     FILEPATHS_W *paths = (FILEPATHS_W *)param1;
1397     struct default_callback_context *ctx = (struct default_callback_context *)context;
1398
1399     switch(notification)
1400     {
1401     case SPFILENOTIFY_STARTQUEUE:
1402         TRACE( "start queue\n" );
1403         return TRUE;
1404     case SPFILENOTIFY_ENDQUEUE:
1405         TRACE( "end queue\n" );
1406         return 0;
1407     case SPFILENOTIFY_STARTSUBQUEUE:
1408         TRACE( "start subqueue %d count %d\n", param1, param2 );
1409         return TRUE;
1410     case SPFILENOTIFY_ENDSUBQUEUE:
1411         TRACE( "end subqueue %d\n", param1 );
1412         return 0;
1413     case SPFILENOTIFY_STARTDELETE:
1414         TRACE( "start delete %s\n", debugstr_w(paths->Target) );
1415         return FILEOP_DOIT;
1416     case SPFILENOTIFY_ENDDELETE:
1417         TRACE( "end delete %s\n", debugstr_w(paths->Target) );
1418         return 0;
1419     case SPFILENOTIFY_DELETEERROR:
1420         /*Windows Ignores attempts to delete files / folders which do not exist*/
1421         if ((paths->Win32Error != ERROR_FILE_NOT_FOUND) && (paths->Win32Error != ERROR_PATH_NOT_FOUND))
1422             SetupDeleteErrorW(ctx->owner, NULL, paths->Target, paths->Win32Error, 0);
1423         return FILEOP_SKIP;
1424     case SPFILENOTIFY_STARTRENAME:
1425         SetupRenameErrorW(ctx->owner, NULL, paths->Source, paths->Target, paths->Win32Error, 0);
1426         return FILEOP_DOIT;
1427     case SPFILENOTIFY_ENDRENAME:
1428         TRACE( "end rename %s -> %s\n", debugstr_w(paths->Source), debugstr_w(paths->Target) );
1429         return 0;
1430     case SPFILENOTIFY_RENAMEERROR:
1431         ERR( "rename error %d %s -> %s\n", paths->Win32Error,
1432              debugstr_w(paths->Source), debugstr_w(paths->Target) );
1433         return FILEOP_SKIP;
1434     case SPFILENOTIFY_STARTCOPY:
1435         TRACE( "start copy %s -> %s\n", debugstr_w(paths->Source), debugstr_w(paths->Target) );
1436         return FILEOP_DOIT;
1437     case SPFILENOTIFY_ENDCOPY:
1438         TRACE( "end copy %s -> %s\n", debugstr_w(paths->Source), debugstr_w(paths->Target) );
1439         return 0;
1440     case SPFILENOTIFY_COPYERROR:
1441         ERR( "copy error %d %s -> %s\n", paths->Win32Error,
1442              debugstr_w(paths->Source), debugstr_w(paths->Target) );
1443         return FILEOP_SKIP;
1444     case SPFILENOTIFY_NEEDMEDIA:
1445         TRACE( "need media\n" );
1446         return FILEOP_SKIP;
1447     default:
1448         FIXME( "notification %d params %x,%x\n", notification, param1, param2 );
1449         break;
1450     }
1451     return 0;
1452 }
1453
1454 /***********************************************************************
1455  *            SetupDeleteErrorA   (SETUPAPI.@)
1456  */
1457
1458 UINT WINAPI SetupDeleteErrorA( HWND parent, PCSTR dialogTitle, PCSTR file,
1459                                UINT w32error, DWORD style)
1460 {
1461     FIXME( "stub: (Error Number %d when attempting to delete %s)\n",
1462            w32error, debugstr_a(file) );
1463     return DPROMPT_SKIPFILE;
1464 }
1465
1466 /***********************************************************************
1467  *            SetupDeleteErrorW   (SETUPAPI.@)
1468  */
1469
1470 UINT WINAPI SetupDeleteErrorW( HWND parent, PCWSTR dialogTitle, PCWSTR file,
1471                                UINT w32error, DWORD style)
1472 {
1473     FIXME( "stub: (Error Number %d when attempting to delete %s)\n",
1474            w32error, debugstr_w(file) );
1475     return DPROMPT_SKIPFILE;
1476 }
1477
1478 /***********************************************************************
1479  *            SetupRenameErrorA   (SETUPAPI.@)
1480  */
1481
1482 UINT WINAPI SetupRenameErrorA( HWND parent, PCSTR dialogTitle, PCSTR source,
1483                                PCSTR target, UINT w32error, DWORD style)
1484 {
1485     FIXME( "stub: (Error Number %d when attempting to rename %s to %s)\n",
1486            w32error, debugstr_a(source), debugstr_a(target));
1487     return DPROMPT_SKIPFILE;
1488 }
1489
1490 /***********************************************************************
1491  *            SetupRenameErrorW   (SETUPAPI.@)
1492  */
1493
1494 UINT WINAPI SetupRenameErrorW( HWND parent, PCWSTR dialogTitle, PCWSTR source,
1495                                PCWSTR target, UINT w32error, DWORD style)
1496 {
1497     FIXME( "stub: (Error Number %d when attempting to rename %s to %s)\n",
1498            w32error, debugstr_w(source), debugstr_w(target));
1499     return DPROMPT_SKIPFILE;
1500 }
1501
1502
1503 /***********************************************************************
1504  *            SetupCopyErrorA   (SETUPAPI.@)
1505  */
1506
1507 UINT WINAPI SetupCopyErrorA( HWND parent, PCSTR dialogTitle, PCSTR diskname, 
1508                              PCSTR sourcepath, PCSTR sourcefile, PCSTR targetpath,
1509                              UINT w32error, DWORD style, PSTR pathbuffer, 
1510                              DWORD buffersize, PDWORD requiredsize)
1511 {
1512     FIXME( "stub: (Error Number %d when attempting to copy file %s from %s to %s)\n",
1513            w32error, debugstr_a(sourcefile), debugstr_a(sourcepath) ,debugstr_a(targetpath));
1514     return DPROMPT_SKIPFILE;
1515 }
1516
1517 /***********************************************************************
1518  *            SetupCopyErrorW   (SETUPAPI.@)
1519  */
1520
1521 UINT WINAPI SetupCopyErrorW( HWND parent, PCWSTR dialogTitle, PCWSTR diskname, 
1522                              PCWSTR sourcepath, PCWSTR sourcefile, PCWSTR targetpath,
1523                              UINT w32error, DWORD style, PWSTR pathbuffer, 
1524                              DWORD buffersize, PDWORD requiredsize)
1525 {
1526     FIXME( "stub: (Error Number %d when attempting to copy file %s from %s to %s)\n",
1527            w32error, debugstr_w(sourcefile), debugstr_w(sourcepath) ,debugstr_w(targetpath));
1528     return DPROMPT_SKIPFILE;
1529 }