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