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