riched20: Pass the run to the text drawing routine.
[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     WCHAR systemdir[MAX_PATH], *dir;
342     BOOL ret;
343
344     if (!(ret = SetupFindFirstLineW( hinf, Dest, section, &context )))
345         ret = SetupFindFirstLineW( hinf, Dest, Def, &context );
346
347     if (ret && (dir = PARSER_get_dest_dir( &context )))
348         return dir;
349
350     GetSystemDirectoryW( systemdir, MAX_PATH );
351     return strdupW( systemdir );
352 }
353
354
355 static void (WINAPI *pExtractFiles)( LPSTR, LPSTR, DWORD, DWORD, DWORD, DWORD );
356
357 /***********************************************************************
358  *            extract_cabinet_file
359  *
360  * Extract a file from a .cab file.
361  */
362 static BOOL extract_cabinet_file( const WCHAR *cabinet, const WCHAR *root,
363                                   const WCHAR *src, const WCHAR *dst )
364 {
365     static const WCHAR extW[] = {'.','c','a','b',0};
366     static HMODULE advpack;
367
368     char *cab_path, *cab_file;
369     int len = strlenW( cabinet );
370
371     /* make sure the cabinet file has a .cab extension */
372     if (len <= 4 || strcmpiW( cabinet + len - 4, extW )) return FALSE;
373     if (!pExtractFiles)
374     {
375         if (!advpack && !(advpack = LoadLibraryA( "advpack.dll" )))
376         {
377             ERR( "could not load advpack.dll\n" );
378             return FALSE;
379         }
380         if (!(pExtractFiles = (void *)GetProcAddress( advpack, "ExtractFiles" )))
381         {
382             ERR( "could not find ExtractFiles in advpack.dll\n" );
383             return FALSE;
384         }
385     }
386
387     if (!(cab_path = strdupWtoA( root ))) return FALSE;
388     len = WideCharToMultiByte( CP_ACP, 0, cabinet, -1, NULL, 0, NULL, NULL );
389     if (!(cab_file = HeapAlloc( GetProcessHeap(), 0, strlen(cab_path) + len + 1 )))
390     {
391         HeapFree( GetProcessHeap(), 0, cab_path );
392         return FALSE;
393     }
394     strcpy( cab_file, cab_path );
395     if (cab_file[0] && cab_file[strlen(cab_file)-1] != '\\') strcat( cab_file, "\\" );
396     WideCharToMultiByte( CP_ACP, 0, cabinet, -1, cab_file + strlen(cab_file), len, NULL, NULL );
397     FIXME( "awful hack: extracting cabinet %s\n", debugstr_a(cab_file) );
398     pExtractFiles( cab_file, cab_path, 0, 0, 0, 0 );
399     HeapFree( GetProcessHeap(), 0, cab_file );
400     HeapFree( GetProcessHeap(), 0, cab_path );
401     return CopyFileW( src, dst, FALSE /*FIXME*/ );
402 }
403
404
405 /***********************************************************************
406  *            SetupOpenFileQueue   (SETUPAPI.@)
407  */
408 HSPFILEQ WINAPI SetupOpenFileQueue(void)
409 {
410     struct file_queue *queue;
411
412     if (!(queue = HeapAlloc( GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*queue))))
413         return INVALID_HANDLE_VALUE;
414     return queue;
415 }
416
417
418 /***********************************************************************
419  *            SetupCloseFileQueue   (SETUPAPI.@)
420  */
421 BOOL WINAPI SetupCloseFileQueue( HSPFILEQ handle )
422 {
423     struct file_queue *queue = handle;
424
425     free_file_op_queue( &queue->copy_queue );
426     free_file_op_queue( &queue->rename_queue );
427     free_file_op_queue( &queue->delete_queue );
428     HeapFree( GetProcessHeap(), 0, queue );
429     return TRUE;
430 }
431
432
433 /***********************************************************************
434  *            SetupQueueCopyIndirectA   (SETUPAPI.@)
435  */
436 BOOL WINAPI SetupQueueCopyIndirectA( PSP_FILE_COPY_PARAMS_A params )
437 {
438     struct file_queue *queue = params->QueueHandle;
439     struct file_op *op;
440
441     if (!(op = HeapAlloc( GetProcessHeap(), 0, sizeof(*op) ))) return FALSE;
442     op->style      = params->CopyStyle;
443     op->src_root   = strdupAtoW( params->SourceRootPath );
444     op->src_path   = strdupAtoW( params->SourcePath );
445     op->src_file   = strdupAtoW( params->SourceFilename );
446     op->src_descr  = strdupAtoW( params->SourceDescription );
447     op->src_tag    = strdupAtoW( params->SourceTagfile );
448     op->dst_path   = strdupAtoW( params->TargetDirectory );
449     op->dst_file   = strdupAtoW( params->TargetFilename );
450
451     /* some defaults */
452     if (!op->src_file) op->src_file = op->dst_file;
453     if (params->LayoutInf)
454     {
455         get_src_file_info( params->LayoutInf, op );
456         if (!op->dst_path) op->dst_path = get_destination_dir( params->LayoutInf, op->dst_file );
457     }
458
459     TRACE( "root=%s path=%s file=%s -> dir=%s file=%s  descr=%s tag=%s\n",
460            debugstr_w(op->src_root), debugstr_w(op->src_path), debugstr_w(op->src_file),
461            debugstr_w(op->dst_path), debugstr_w(op->dst_file),
462            debugstr_w(op->src_descr), debugstr_w(op->src_tag) );
463
464     queue_file_op( &queue->copy_queue, op );
465     return TRUE;
466 }
467
468
469 /***********************************************************************
470  *            SetupQueueCopyIndirectW   (SETUPAPI.@)
471  */
472 BOOL WINAPI SetupQueueCopyIndirectW( PSP_FILE_COPY_PARAMS_W params )
473 {
474     struct file_queue *queue = params->QueueHandle;
475     struct file_op *op;
476
477     if (!(op = HeapAlloc( GetProcessHeap(), 0, sizeof(*op) ))) return FALSE;
478     op->style      = params->CopyStyle;
479     op->src_root   = strdupW( params->SourceRootPath );
480     op->src_path   = strdupW( params->SourcePath );
481     op->src_file   = strdupW( params->SourceFilename );
482     op->src_descr  = strdupW( params->SourceDescription );
483     op->src_tag    = strdupW( params->SourceTagfile );
484     op->dst_path   = strdupW( params->TargetDirectory );
485     op->dst_file   = strdupW( params->TargetFilename );
486
487     /* some defaults */
488     if (!op->src_file) op->src_file = op->dst_file;
489     if (params->LayoutInf)
490     {
491         get_src_file_info( params->LayoutInf, op );
492         if (!op->dst_path) op->dst_path = get_destination_dir( params->LayoutInf, op->dst_file );
493     }
494
495     TRACE( "root=%s path=%s file=%s -> dir=%s file=%s  descr=%s tag=%s\n",
496            debugstr_w(op->src_root), debugstr_w(op->src_path), debugstr_w(op->src_file),
497            debugstr_w(op->dst_path), debugstr_w(op->dst_file),
498            debugstr_w(op->src_descr), debugstr_w(op->src_tag) );
499
500     queue_file_op( &queue->copy_queue, op );
501     return TRUE;
502 }
503
504
505 /***********************************************************************
506  *            SetupQueueCopyA   (SETUPAPI.@)
507  */
508 BOOL WINAPI SetupQueueCopyA( HSPFILEQ queue, PCSTR src_root, PCSTR src_path, PCSTR src_file,
509                              PCSTR src_descr, PCSTR src_tag, PCSTR dst_dir, PCSTR dst_file,
510                              DWORD style )
511 {
512     SP_FILE_COPY_PARAMS_A params;
513
514     params.cbSize             = sizeof(params);
515     params.QueueHandle        = queue;
516     params.SourceRootPath     = src_root;
517     params.SourcePath         = src_path;
518     params.SourceFilename     = src_file;
519     params.SourceDescription  = src_descr;
520     params.SourceTagfile      = src_tag;
521     params.TargetDirectory    = dst_dir;
522     params.TargetFilename     = dst_file;
523     params.CopyStyle          = style;
524     params.LayoutInf          = 0;
525     params.SecurityDescriptor = NULL;
526     return SetupQueueCopyIndirectA( &params );
527 }
528
529
530 /***********************************************************************
531  *            SetupQueueCopyW   (SETUPAPI.@)
532  */
533 BOOL WINAPI SetupQueueCopyW( HSPFILEQ queue, PCWSTR src_root, PCWSTR src_path, PCWSTR src_file,
534                              PCWSTR src_descr, PCWSTR src_tag, PCWSTR dst_dir, PCWSTR dst_file,
535                              DWORD style )
536 {
537     SP_FILE_COPY_PARAMS_W params;
538
539     params.cbSize             = sizeof(params);
540     params.QueueHandle        = queue;
541     params.SourceRootPath     = src_root;
542     params.SourcePath         = src_path;
543     params.SourceFilename     = src_file;
544     params.SourceDescription  = src_descr;
545     params.SourceTagfile      = src_tag;
546     params.TargetDirectory    = dst_dir;
547     params.TargetFilename     = dst_file;
548     params.CopyStyle          = style;
549     params.LayoutInf          = 0;
550     params.SecurityDescriptor = NULL;
551     return SetupQueueCopyIndirectW( &params );
552 }
553
554
555 /***********************************************************************
556  *            SetupQueueDefaultCopyA   (SETUPAPI.@)
557  */
558 BOOL WINAPI SetupQueueDefaultCopyA( HSPFILEQ queue, HINF hinf, PCSTR src_root, PCSTR src_file,
559                                     PCSTR dst_file, DWORD style )
560 {
561     SP_FILE_COPY_PARAMS_A params;
562
563     params.cbSize             = sizeof(params);
564     params.QueueHandle        = queue;
565     params.SourceRootPath     = src_root;
566     params.SourcePath         = NULL;
567     params.SourceFilename     = src_file;
568     params.SourceDescription  = NULL;
569     params.SourceTagfile      = NULL;
570     params.TargetDirectory    = NULL;
571     params.TargetFilename     = dst_file;
572     params.CopyStyle          = style;
573     params.LayoutInf          = hinf;
574     params.SecurityDescriptor = NULL;
575     return SetupQueueCopyIndirectA( &params );
576 }
577
578
579 /***********************************************************************
580  *            SetupQueueDefaultCopyW   (SETUPAPI.@)
581  */
582 BOOL WINAPI SetupQueueDefaultCopyW( HSPFILEQ queue, HINF hinf, PCWSTR src_root, PCWSTR src_file,
583                                     PCWSTR dst_file, DWORD style )
584 {
585     SP_FILE_COPY_PARAMS_W params;
586
587     params.cbSize             = sizeof(params);
588     params.QueueHandle        = queue;
589     params.SourceRootPath     = src_root;
590     params.SourcePath         = NULL;
591     params.SourceFilename     = src_file;
592     params.SourceDescription  = NULL;
593     params.SourceTagfile      = NULL;
594     params.TargetDirectory    = NULL;
595     params.TargetFilename     = dst_file;
596     params.CopyStyle          = style;
597     params.LayoutInf          = hinf;
598     params.SecurityDescriptor = NULL;
599     return SetupQueueCopyIndirectW( &params );
600 }
601
602
603 /***********************************************************************
604  *            SetupQueueDeleteA   (SETUPAPI.@)
605  */
606 BOOL WINAPI SetupQueueDeleteA( HSPFILEQ handle, PCSTR part1, PCSTR part2 )
607 {
608     struct file_queue *queue = handle;
609     struct file_op *op;
610
611     if (!(op = HeapAlloc( GetProcessHeap(), 0, sizeof(*op) ))) return FALSE;
612     op->style      = 0;
613     op->src_root   = NULL;
614     op->src_path   = NULL;
615     op->src_file   = NULL;
616     op->src_descr  = NULL;
617     op->src_tag    = NULL;
618     op->dst_path   = strdupAtoW( part1 );
619     op->dst_file   = strdupAtoW( part2 );
620     queue_file_op( &queue->delete_queue, op );
621     return TRUE;
622 }
623
624
625 /***********************************************************************
626  *            SetupQueueDeleteW   (SETUPAPI.@)
627  */
628 BOOL WINAPI SetupQueueDeleteW( HSPFILEQ handle, PCWSTR part1, PCWSTR part2 )
629 {
630     struct file_queue *queue = handle;
631     struct file_op *op;
632
633     if (!(op = HeapAlloc( GetProcessHeap(), 0, sizeof(*op) ))) return FALSE;
634     op->style      = 0;
635     op->src_root   = NULL;
636     op->src_path   = NULL;
637     op->src_file   = NULL;
638     op->src_descr  = NULL;
639     op->src_tag    = NULL;
640     op->dst_path   = strdupW( part1 );
641     op->dst_file   = strdupW( part2 );
642     queue_file_op( &queue->delete_queue, op );
643     return TRUE;
644 }
645
646
647 /***********************************************************************
648  *            SetupQueueRenameA   (SETUPAPI.@)
649  */
650 BOOL WINAPI SetupQueueRenameA( HSPFILEQ handle, PCSTR SourcePath, PCSTR SourceFilename,
651                                PCSTR TargetPath, PCSTR TargetFilename )
652 {
653     struct file_queue *queue = handle;
654     struct file_op *op;
655
656     if (!(op = HeapAlloc( GetProcessHeap(), 0, sizeof(*op) ))) return FALSE;
657     op->style      = 0;
658     op->src_root   = NULL;
659     op->src_path   = strdupAtoW( SourcePath );
660     op->src_file   = strdupAtoW( SourceFilename );
661     op->src_descr  = NULL;
662     op->src_tag    = NULL;
663     op->dst_path   = strdupAtoW( TargetPath );
664     op->dst_file   = strdupAtoW( TargetFilename );
665     queue_file_op( &queue->rename_queue, op );
666     return TRUE;
667 }
668
669
670 /***********************************************************************
671  *            SetupQueueRenameW   (SETUPAPI.@)
672  */
673 BOOL WINAPI SetupQueueRenameW( HSPFILEQ handle, PCWSTR SourcePath, PCWSTR SourceFilename,
674                                PCWSTR TargetPath, PCWSTR TargetFilename )
675 {
676     struct file_queue *queue = handle;
677     struct file_op *op;
678
679     if (!(op = HeapAlloc( GetProcessHeap(), 0, sizeof(*op) ))) return FALSE;
680     op->style      = 0;
681     op->src_root   = NULL;
682     op->src_path   = strdupW( SourcePath );
683     op->src_file   = strdupW( SourceFilename );
684     op->src_descr  = NULL;
685     op->src_tag    = NULL;
686     op->dst_path   = strdupW( TargetPath );
687     op->dst_file   = strdupW( TargetFilename );
688     queue_file_op( &queue->rename_queue, op );
689     return TRUE;
690 }
691
692
693 /***********************************************************************
694  *            SetupQueueCopySectionA   (SETUPAPI.@)
695  */
696 BOOL WINAPI SetupQueueCopySectionA( HSPFILEQ queue, PCSTR src_root, HINF hinf, HINF hlist,
697                                     PCSTR section, DWORD style )
698 {
699     UNICODE_STRING sectionW;
700     BOOL ret = FALSE;
701
702     if (!RtlCreateUnicodeStringFromAsciiz( &sectionW, section ))
703     {
704         SetLastError( ERROR_NOT_ENOUGH_MEMORY );
705         return FALSE;
706     }
707     if (!src_root)
708         ret = SetupQueueCopySectionW( queue, NULL, hinf, hlist, sectionW.Buffer, style );
709     else
710     {
711         UNICODE_STRING srcW;
712         if (RtlCreateUnicodeStringFromAsciiz( &srcW, src_root ))
713         {
714             ret = SetupQueueCopySectionW( queue, srcW.Buffer, hinf, hlist, sectionW.Buffer, style );
715             RtlFreeUnicodeString( &srcW );
716         }
717         else SetLastError( ERROR_NOT_ENOUGH_MEMORY );
718     }
719     RtlFreeUnicodeString( &sectionW );
720     return ret;
721 }
722
723
724 /***********************************************************************
725  *            SetupQueueCopySectionW   (SETUPAPI.@)
726  */
727 BOOL WINAPI SetupQueueCopySectionW( HSPFILEQ queue, PCWSTR src_root, HINF hinf, HINF hlist,
728                                     PCWSTR section, DWORD style )
729 {
730     SP_FILE_COPY_PARAMS_W params;
731     INFCONTEXT context;
732     WCHAR dest[MAX_PATH], src[MAX_PATH], *dest_dir;
733     INT flags;
734     BOOL ret = FALSE;
735
736     TRACE( "hinf=%p/%p section=%s root=%s\n",
737            hinf, hlist, debugstr_w(section), debugstr_w(src_root) );
738
739     params.cbSize             = sizeof(params);
740     params.QueueHandle        = queue;
741     params.SourceRootPath     = src_root;
742     params.SourcePath         = NULL;
743     params.SourceDescription  = NULL;
744     params.SourceTagfile      = NULL;
745     params.TargetFilename     = dest;
746     params.CopyStyle          = style;
747     params.LayoutInf          = hinf;
748     params.SecurityDescriptor = NULL;
749
750     if (!hlist) hlist = hinf;
751     if (!hinf) hinf = hlist;
752     if (!SetupFindFirstLineW( hlist, section, NULL, &context )) return FALSE;
753     if (!(params.TargetDirectory = dest_dir = get_destination_dir( hinf, section ))) return FALSE;
754     do
755     {
756         if (!SetupGetStringFieldW( &context, 1, dest, sizeof(dest)/sizeof(WCHAR), NULL ))
757             goto end;
758         if (!SetupGetStringFieldW( &context, 2, src, sizeof(src)/sizeof(WCHAR), NULL )) *src = 0;
759         if (!SetupGetIntField( &context, 4, &flags )) flags = 0;  /* FIXME */
760
761         params.SourceFilename = *src ? src : NULL;
762         if (!SetupQueueCopyIndirectW( &params )) goto end;
763     } while (SetupFindNextLine( &context, &context ));
764     ret = TRUE;
765 end:
766     HeapFree(GetProcessHeap(), 0, dest_dir);
767     return ret;
768 }
769
770
771 /***********************************************************************
772  *            SetupQueueDeleteSectionA   (SETUPAPI.@)
773  */
774 BOOL WINAPI SetupQueueDeleteSectionA( HSPFILEQ queue, HINF hinf, HINF hlist, PCSTR section )
775 {
776     UNICODE_STRING sectionW;
777     BOOL ret = FALSE;
778
779     if (RtlCreateUnicodeStringFromAsciiz( &sectionW, section ))
780     {
781         ret = SetupQueueDeleteSectionW( queue, hinf, hlist, sectionW.Buffer );
782         RtlFreeUnicodeString( &sectionW );
783     }
784     else SetLastError( ERROR_NOT_ENOUGH_MEMORY );
785     return ret;
786 }
787
788
789 /***********************************************************************
790  *            SetupQueueDeleteSectionW   (SETUPAPI.@)
791  */
792 BOOL WINAPI SetupQueueDeleteSectionW( HSPFILEQ queue, HINF hinf, HINF hlist, PCWSTR section )
793 {
794     INFCONTEXT context;
795     WCHAR *dest_dir;
796     WCHAR buffer[MAX_PATH];
797     BOOL ret = FALSE;
798     INT flags;
799
800     TRACE( "hinf=%p/%p section=%s\n", hinf, hlist, debugstr_w(section) );
801
802     if (!hlist) hlist = hinf;
803     if (!SetupFindFirstLineW( hlist, section, NULL, &context )) return FALSE;
804     if (!(dest_dir = get_destination_dir( hinf, section ))) return FALSE;
805     do
806     {
807         if (!SetupGetStringFieldW( &context, 1, buffer, sizeof(buffer)/sizeof(WCHAR), NULL ))
808             goto done;
809         if (!SetupGetIntField( &context, 4, &flags )) flags = 0;
810         if (!SetupQueueDeleteW( queue, dest_dir, buffer )) goto done;
811     } while (SetupFindNextLine( &context, &context ));
812
813     ret = TRUE;
814  done:
815     HeapFree( GetProcessHeap(), 0, dest_dir );
816     return ret;
817 }
818
819
820 /***********************************************************************
821  *            SetupQueueRenameSectionA   (SETUPAPI.@)
822  */
823 BOOL WINAPI SetupQueueRenameSectionA( HSPFILEQ queue, HINF hinf, HINF hlist, PCSTR section )
824 {
825     UNICODE_STRING sectionW;
826     BOOL ret = FALSE;
827
828     if (RtlCreateUnicodeStringFromAsciiz( &sectionW, section ))
829     {
830         ret = SetupQueueRenameSectionW( queue, hinf, hlist, sectionW.Buffer );
831         RtlFreeUnicodeString( &sectionW );
832     }
833     else SetLastError( ERROR_NOT_ENOUGH_MEMORY );
834     return ret;
835 }
836
837
838 /***********************************************************************
839  *            SetupQueueRenameSectionW   (SETUPAPI.@)
840  */
841 BOOL WINAPI SetupQueueRenameSectionW( HSPFILEQ queue, HINF hinf, HINF hlist, PCWSTR section )
842 {
843     INFCONTEXT context;
844     WCHAR *dest_dir;
845     WCHAR src[MAX_PATH], dst[MAX_PATH];
846     BOOL ret = FALSE;
847
848     TRACE( "hinf=%p/%p section=%s\n", hinf, hlist, debugstr_w(section) );
849
850     if (!hlist) hlist = hinf;
851     if (!SetupFindFirstLineW( hlist, section, NULL, &context )) return FALSE;
852     if (!(dest_dir = get_destination_dir( hinf, section ))) return FALSE;
853     do
854     {
855         if (!SetupGetStringFieldW( &context, 1, dst, sizeof(dst)/sizeof(WCHAR), NULL ))
856             goto done;
857         if (!SetupGetStringFieldW( &context, 2, src, sizeof(src)/sizeof(WCHAR), NULL ))
858             goto done;
859         if (!SetupQueueRenameW( queue, dest_dir, src, NULL, dst )) goto done;
860     } while (SetupFindNextLine( &context, &context ));
861
862     ret = TRUE;
863  done:
864     HeapFree( GetProcessHeap(), 0, dest_dir );
865     return ret;
866 }
867
868
869 /***********************************************************************
870  *            SetupCommitFileQueueA   (SETUPAPI.@)
871  */
872 BOOL WINAPI SetupCommitFileQueueA( HWND owner, HSPFILEQ queue, PSP_FILE_CALLBACK_A handler,
873                                    PVOID context )
874 {
875     struct callback_WtoA_context ctx;
876
877     ctx.orig_context = context;
878     ctx.orig_handler = handler;
879     return SetupCommitFileQueueW( owner, queue, QUEUE_callback_WtoA, &ctx );
880 }
881
882
883 /***********************************************************************
884  *            create_full_pathW
885  *
886  * Recursively create all directories in the path.
887  */
888 static BOOL create_full_pathW(const WCHAR *path)
889 {
890     BOOL ret = TRUE;
891     int len;
892     WCHAR *new_path;
893
894     new_path = HeapAlloc(GetProcessHeap(), 0, (strlenW(path) + 1) * sizeof(WCHAR));
895     strcpyW(new_path, path);
896
897     while((len = strlenW(new_path)) && new_path[len - 1] == '\\')
898         new_path[len - 1] = 0;
899
900     while(!CreateDirectoryW(new_path, NULL))
901     {
902         WCHAR *slash;
903         DWORD last_error = GetLastError();
904
905         if(last_error == ERROR_ALREADY_EXISTS)
906             break;
907
908         if(last_error != ERROR_PATH_NOT_FOUND)
909         {
910             ret = FALSE;
911             break;
912         }
913
914         if(!(slash = strrchrW(new_path, '\\')))
915         {
916             ret = FALSE;
917             break;
918         }
919
920         len = slash - new_path;
921         new_path[len] = 0;
922         if(!create_full_pathW(new_path))
923         {
924             ret = FALSE;
925             break;
926         }
927         new_path[len] = '\\';
928     }
929
930     HeapFree(GetProcessHeap(), 0, new_path);
931     return ret;
932 }
933
934 static BOOL do_file_copyW( LPCWSTR source, LPCWSTR target, DWORD style, 
935                            PSP_FILE_CALLBACK_W handler, PVOID context )
936 {
937     BOOL rc = FALSE;
938     BOOL docopy = TRUE;
939
940     TRACE("copy %s to %s style 0x%x\n",debugstr_w(source),debugstr_w(target),style);
941
942     /* before copy processing */
943     if (style & SP_COPY_REPLACEONLY)
944     {
945         if (GetFileAttributesW(target) == INVALID_FILE_ATTRIBUTES)
946             docopy = FALSE;
947     }
948     if (style & (SP_COPY_NEWER_OR_SAME | SP_COPY_NEWER_ONLY | SP_COPY_FORCE_NEWER))
949     {
950         DWORD VersionSizeSource=0;
951         DWORD VersionSizeTarget=0;
952         DWORD zero=0;
953
954         /*
955          * This is sort of an interesting workaround. You see, calling
956          * GetVersionInfoSize on a builtin dll loads that dll into memory
957          * and we do not properly unload builtin dlls.. so we effectively
958          * lock into memory all the targets we are replacing. This leads
959          * to problems when we try to register the replaced dlls.
960          *
961          * So I will test for the existence of the files first so that
962          * we just basically unconditionally replace the builtin versions.
963          */
964         if ((GetFileAttributesW(target) != INVALID_FILE_ATTRIBUTES) &&
965             (GetFileAttributesW(source) != INVALID_FILE_ATTRIBUTES))
966         {
967             VersionSizeSource = GetFileVersionInfoSizeW(source,&zero);
968             VersionSizeTarget = GetFileVersionInfoSizeW(target,&zero);
969         }
970
971         TRACE("SizeTarget %i ... SizeSource %i\n",VersionSizeTarget,
972                 VersionSizeSource);
973
974         if (VersionSizeSource && VersionSizeTarget)
975         {
976             LPVOID VersionSource;
977             LPVOID VersionTarget;
978             VS_FIXEDFILEINFO *TargetInfo;
979             VS_FIXEDFILEINFO *SourceInfo;
980             UINT length;
981             static const WCHAR SubBlock[]={'\\',0};
982             DWORD  ret;
983
984             VersionSource = HeapAlloc(GetProcessHeap(),0,VersionSizeSource);
985             VersionTarget = HeapAlloc(GetProcessHeap(),0,VersionSizeTarget);
986
987             ret = GetFileVersionInfoW(source,0,VersionSizeSource,VersionSource);
988             if (ret)
989               ret = GetFileVersionInfoW(target, 0, VersionSizeTarget,
990                     VersionTarget);
991
992             if (ret)
993             {
994                 ret = VerQueryValueW(VersionSource, SubBlock,
995                                     (LPVOID*)&SourceInfo, &length);
996                 if (ret)
997                     ret = VerQueryValueW(VersionTarget, SubBlock,
998                                          (LPVOID*)&TargetInfo, &length);
999
1000                 if (ret)
1001                 {
1002                     FILEPATHS_W filepaths;
1003
1004                     TRACE("Versions: Source %i.%i target %i.%i\n",
1005                       SourceInfo->dwFileVersionMS, SourceInfo->dwFileVersionLS,
1006                       TargetInfo->dwFileVersionMS, TargetInfo->dwFileVersionLS);
1007
1008                     /* used in case of notification */
1009                     filepaths.Target = target;
1010                     filepaths.Source = source;
1011                     filepaths.Win32Error = 0;
1012                     filepaths.Flags = 0;
1013
1014                     if (TargetInfo->dwFileVersionMS > SourceInfo->dwFileVersionMS)
1015                     {
1016                         if (handler)
1017                             docopy = handler (context, SPFILENOTIFY_TARGETNEWER, (UINT_PTR)&filepaths, 0);
1018                         else
1019                             docopy = FALSE;
1020                     }
1021                     else if ((TargetInfo->dwFileVersionMS == SourceInfo->dwFileVersionMS)
1022                              && (TargetInfo->dwFileVersionLS > SourceInfo->dwFileVersionLS))
1023                     {
1024                         if (handler)
1025                             docopy = handler (context, SPFILENOTIFY_TARGETNEWER, (UINT_PTR)&filepaths, 0);
1026                         else
1027                             docopy = FALSE;
1028                     }
1029                     else if ((style & SP_COPY_NEWER_ONLY) &&
1030                         (TargetInfo->dwFileVersionMS ==
1031                          SourceInfo->dwFileVersionMS)
1032                         &&(TargetInfo->dwFileVersionLS ==
1033                         SourceInfo->dwFileVersionLS))
1034                     {
1035                         if (handler)
1036                             docopy = handler (context, SPFILENOTIFY_TARGETNEWER, (UINT_PTR)&filepaths, 0);
1037                         else
1038                             docopy = FALSE;
1039                     }
1040                 }
1041             }
1042             HeapFree(GetProcessHeap(),0,VersionSource);
1043             HeapFree(GetProcessHeap(),0,VersionTarget);
1044         }
1045     }
1046     if (style & (SP_COPY_NOOVERWRITE | SP_COPY_FORCE_NOOVERWRITE))
1047     {
1048         if (GetFileAttributesW(target) != INVALID_FILE_ATTRIBUTES)
1049         {
1050             FIXME("Notify user target file exists\n");
1051             docopy = FALSE;
1052         }
1053     }
1054     if (style & (SP_COPY_NODECOMP | SP_COPY_LANGUAGEAWARE | SP_COPY_FORCE_IN_USE |
1055                  SP_COPY_IN_USE_NEEDS_REBOOT | SP_COPY_NOSKIP | SP_COPY_WARNIFSKIP))
1056     {
1057         ERR("Unsupported style(s) 0x%x\n",style);
1058     }
1059
1060     if (docopy)
1061     {
1062         rc = CopyFileW(source,target,FALSE);
1063         TRACE("Did copy... rc was %i\n",rc);
1064     }
1065
1066     /* after copy processing */
1067     if (style & SP_COPY_DELETESOURCE)
1068     {
1069        if (rc)
1070             DeleteFileW(source);
1071     }
1072
1073     return rc;
1074 }
1075
1076 /***********************************************************************
1077  *            SetupInstallFileExA   (SETUPAPI.@)
1078  */
1079 BOOL WINAPI SetupInstallFileExA( HINF hinf, PINFCONTEXT inf_context, PCSTR source, PCSTR root,
1080                                  PCSTR dest, DWORD style, PSP_FILE_CALLBACK_A handler, PVOID context, PBOOL in_use )
1081 {
1082     BOOL ret = FALSE;
1083     struct callback_WtoA_context ctx;
1084     UNICODE_STRING sourceW, rootW, destW;
1085
1086     TRACE("%p %p %s %s %s %x %p %p %p\n", hinf, inf_context, debugstr_a(source), debugstr_a(root),
1087           debugstr_a(dest), style, handler, context, in_use);
1088
1089     sourceW.Buffer = rootW.Buffer = destW.Buffer = NULL;
1090     if (source && !RtlCreateUnicodeStringFromAsciiz( &sourceW, source ))
1091     {
1092         SetLastError( ERROR_NOT_ENOUGH_MEMORY );
1093         return FALSE;
1094     }
1095     if (root && !RtlCreateUnicodeStringFromAsciiz( &rootW, root ))
1096     {
1097         SetLastError( ERROR_NOT_ENOUGH_MEMORY );
1098         goto exit;
1099     }
1100     if (dest && !RtlCreateUnicodeStringFromAsciiz( &destW, dest ))
1101     {
1102         SetLastError( ERROR_NOT_ENOUGH_MEMORY );
1103         goto exit;
1104     }
1105
1106     ctx.orig_context = context;
1107     ctx.orig_handler = handler;
1108
1109     ret = SetupInstallFileExW( hinf, inf_context, sourceW.Buffer, rootW.Buffer, destW.Buffer, style, QUEUE_callback_WtoA, &ctx, in_use );
1110
1111 exit:
1112     RtlFreeUnicodeString( &sourceW );
1113     RtlFreeUnicodeString( &rootW );
1114     RtlFreeUnicodeString( &destW );
1115     return ret;
1116 }
1117
1118 /***********************************************************************
1119  *            SetupInstallFileA   (SETUPAPI.@)
1120  */
1121 BOOL WINAPI SetupInstallFileA( HINF hinf, PINFCONTEXT inf_context, PCSTR source, PCSTR root,
1122                                PCSTR dest, DWORD style, PSP_FILE_CALLBACK_A handler, PVOID context )
1123 {
1124     return SetupInstallFileExA( hinf, inf_context, source, root, dest, style, handler, context, NULL );
1125 }
1126
1127 /***********************************************************************
1128  *            SetupInstallFileExW   (SETUPAPI.@)
1129  */
1130 BOOL WINAPI SetupInstallFileExW( HINF hinf, PINFCONTEXT inf_context, PCWSTR source, PCWSTR root,
1131                                  PCWSTR dest, DWORD style, PSP_FILE_CALLBACK_W handler, PVOID context, PBOOL in_use )
1132 {
1133     static const WCHAR CopyFiles[] = {'C','o','p','y','F','i','l','e','s',0};
1134
1135     BOOL ret, absolute = (root && *root && !(style & SP_COPY_SOURCE_ABSOLUTE));
1136     WCHAR *buffer, *p, *inf_source = NULL;
1137     unsigned int len;
1138
1139     TRACE("%p %p %s %s %s %x %p %p %p\n", hinf, inf_context, debugstr_w(source), debugstr_w(root),
1140           debugstr_w(dest), style, handler, context, in_use);
1141
1142     if (in_use) FIXME("no file in use support\n");
1143
1144     if (hinf)
1145     {
1146         INFCONTEXT ctx;
1147
1148         if (!inf_context)
1149         {
1150             inf_context = &ctx;
1151             if (!SetupFindFirstLineW( hinf, CopyFiles, NULL, inf_context )) return FALSE;
1152         }
1153         if (!SetupGetStringFieldW( inf_context, 1, NULL, 0, &len )) return FALSE;
1154         if (!(inf_source = HeapAlloc( GetProcessHeap(), 0, len * sizeof(WCHAR) )))
1155         {
1156             SetLastError( ERROR_NOT_ENOUGH_MEMORY );
1157             return FALSE;
1158         }
1159         if (!SetupGetStringFieldW( inf_context, 1, inf_source, len, NULL ))
1160         {
1161             HeapFree( GetProcessHeap(), 0, inf_source );
1162             return FALSE;
1163         }
1164         source = inf_source;
1165     }
1166     else if (!source)
1167     {
1168         SetLastError( ERROR_INVALID_PARAMETER );
1169         return FALSE;
1170     }
1171
1172     len = strlenW( source ) + 1;
1173     if (absolute) len += strlenW( root ) + 1;
1174
1175     if (!(p = buffer = HeapAlloc( GetProcessHeap(), 0, len * sizeof(WCHAR) )))
1176     {
1177         HeapFree( GetProcessHeap(), 0, inf_source );
1178         SetLastError( ERROR_NOT_ENOUGH_MEMORY );
1179         return FALSE;
1180     }
1181
1182     if (absolute)
1183     {
1184         strcpyW( buffer, root );
1185         p += strlenW( buffer );
1186         if (p[-1] != '\\') *p++ = '\\';
1187     }
1188     while (*source == '\\') source++;
1189     strcpyW( p, source );
1190
1191     ret = do_file_copyW( buffer, dest, style, handler, context );
1192
1193     HeapFree( GetProcessHeap(), 0, inf_source );
1194     HeapFree( GetProcessHeap(), 0, buffer );
1195     return ret;
1196 }
1197
1198 /***********************************************************************
1199  *            SetupInstallFileW   (SETUPAPI.@)
1200  */
1201 BOOL WINAPI SetupInstallFileW( HINF hinf, PINFCONTEXT inf_context, PCWSTR source, PCWSTR root,
1202                                PCWSTR dest, DWORD style, PSP_FILE_CALLBACK_W handler, PVOID context )
1203 {
1204     return SetupInstallFileExW( hinf, inf_context, source, root, dest, style, handler, context, NULL );
1205 }
1206
1207 /***********************************************************************
1208  *            SetupCommitFileQueueW   (SETUPAPI.@)
1209  */
1210 BOOL WINAPI SetupCommitFileQueueW( HWND owner, HSPFILEQ handle, PSP_FILE_CALLBACK_W handler,
1211                                    PVOID context )
1212 {
1213     struct file_queue *queue = handle;
1214     struct file_op *op;
1215     BOOL result = FALSE;
1216     FILEPATHS_W paths;
1217     UINT op_result;
1218
1219     paths.Source = paths.Target = NULL;
1220
1221     if (!queue->copy_queue.count && !queue->delete_queue.count && !queue->rename_queue.count)
1222         return TRUE;  /* nothing to do */
1223
1224     if (!handler( context, SPFILENOTIFY_STARTQUEUE, (UINT_PTR)owner, 0 )) return FALSE;
1225
1226     /* perform deletes */
1227
1228     if (queue->delete_queue.count)
1229     {
1230         if (!(handler( context, SPFILENOTIFY_STARTSUBQUEUE, FILEOP_DELETE,
1231                        queue->delete_queue.count ))) goto done;
1232         for (op = queue->delete_queue.head; op; op = op->next)
1233         {
1234             build_filepathsW( op, &paths );
1235             op_result = handler( context, SPFILENOTIFY_STARTDELETE, (UINT_PTR)&paths, FILEOP_DELETE);
1236             if (op_result == FILEOP_ABORT) goto done;
1237             while (op_result == FILEOP_DOIT)
1238             {
1239                 TRACE( "deleting file %s\n", debugstr_w(paths.Target) );
1240                 if (DeleteFileW( paths.Target )) break;  /* success */
1241                 paths.Win32Error = GetLastError();
1242                 op_result = handler( context, SPFILENOTIFY_DELETEERROR, (UINT_PTR)&paths, 0 );
1243                 if (op_result == FILEOP_ABORT) goto done;
1244             }
1245             handler( context, SPFILENOTIFY_ENDDELETE, (UINT_PTR)&paths, 0 );
1246         }
1247         handler( context, SPFILENOTIFY_ENDSUBQUEUE, FILEOP_DELETE, 0 );
1248     }
1249
1250     /* perform renames */
1251
1252     if (queue->rename_queue.count)
1253     {
1254         if (!(handler( context, SPFILENOTIFY_STARTSUBQUEUE, FILEOP_RENAME,
1255                        queue->rename_queue.count ))) goto done;
1256         for (op = queue->rename_queue.head; op; op = op->next)
1257         {
1258             build_filepathsW( op, &paths );
1259             op_result = handler( context, SPFILENOTIFY_STARTRENAME, (UINT_PTR)&paths, FILEOP_RENAME);
1260             if (op_result == FILEOP_ABORT) goto done;
1261             while (op_result == FILEOP_DOIT)
1262             {
1263                 TRACE( "renaming file %s -> %s\n",
1264                        debugstr_w(paths.Source), debugstr_w(paths.Target) );
1265                 if (MoveFileW( paths.Source, paths.Target )) break;  /* success */
1266                 paths.Win32Error = GetLastError();
1267                 op_result = handler( context, SPFILENOTIFY_RENAMEERROR, (UINT_PTR)&paths, 0 );
1268                 if (op_result == FILEOP_ABORT) goto done;
1269             }
1270             handler( context, SPFILENOTIFY_ENDRENAME, (UINT_PTR)&paths, 0 );
1271         }
1272         handler( context, SPFILENOTIFY_ENDSUBQUEUE, FILEOP_RENAME, 0 );
1273     }
1274
1275     /* perform copies */
1276
1277     if (queue->copy_queue.count)
1278     {
1279         if (!(handler( context, SPFILENOTIFY_STARTSUBQUEUE, FILEOP_COPY,
1280                        queue->copy_queue.count ))) goto done;
1281         for (op = queue->copy_queue.head; op; op = op->next)
1282         {
1283             WCHAR newpath[MAX_PATH];
1284
1285             build_filepathsW( op, &paths );
1286             op_result = handler( context, SPFILENOTIFY_STARTCOPY, (UINT_PTR)&paths, FILEOP_COPY );
1287             if (op_result == FILEOP_ABORT) goto done;
1288             if (op_result == FILEOP_NEWPATH) op_result = FILEOP_DOIT;
1289             while (op_result == FILEOP_DOIT || op_result == FILEOP_NEWPATH)
1290             {
1291                 TRACE( "copying file %s -> %s\n",
1292                        debugstr_w( op_result == FILEOP_NEWPATH ? newpath : paths.Source ),
1293                        debugstr_w(paths.Target) );
1294                 if (op->dst_path)
1295                 {
1296                     if (!create_full_pathW( op->dst_path ))
1297                     {
1298                         paths.Win32Error = GetLastError();
1299                         op_result = handler( context, SPFILENOTIFY_COPYERROR,
1300                                              (UINT_PTR)&paths, (UINT_PTR)newpath );
1301                         if (op_result == FILEOP_ABORT) goto done;
1302                     }
1303                 }
1304                 if (do_file_copyW( op_result == FILEOP_NEWPATH ? newpath : paths.Source,
1305                                paths.Target, op->style, handler, context )) break;  /* success */
1306                 /* try to extract it from the cabinet file */
1307                 if (op->src_tag)
1308                 {
1309                     if (extract_cabinet_file( op->src_tag, op->src_root,
1310                                               paths.Source, paths.Target )) break;
1311                 }
1312                 paths.Win32Error = GetLastError();
1313                 op_result = handler( context, SPFILENOTIFY_COPYERROR,
1314                                      (UINT_PTR)&paths, (UINT_PTR)newpath );
1315                 if (op_result == FILEOP_ABORT) goto done;
1316             }
1317             handler( context, SPFILENOTIFY_ENDCOPY, (UINT_PTR)&paths, 0 );
1318         }
1319         handler( context, SPFILENOTIFY_ENDSUBQUEUE, FILEOP_COPY, 0 );
1320     }
1321
1322
1323     result = TRUE;
1324
1325  done:
1326     handler( context, SPFILENOTIFY_ENDQUEUE, result, 0 );
1327     HeapFree( GetProcessHeap(), 0, (void *)paths.Source );
1328     HeapFree( GetProcessHeap(), 0, (void *)paths.Target );
1329     return result;
1330 }
1331
1332
1333 /***********************************************************************
1334  *            SetupScanFileQueueA   (SETUPAPI.@)
1335  */
1336 BOOL WINAPI SetupScanFileQueueA( HSPFILEQ handle, DWORD flags, HWND window,
1337                                  PSP_FILE_CALLBACK_A handler, PVOID context, PDWORD result )
1338 {
1339     struct callback_WtoA_context ctx;
1340
1341     TRACE("%p %x %p %p %p %p\n", handle, flags, window, handler, context, result);
1342
1343     ctx.orig_context = context;
1344     ctx.orig_handler = handler;
1345
1346     return SetupScanFileQueueW( handle, flags, window, QUEUE_callback_WtoA, &ctx, result );
1347 }
1348
1349
1350 /***********************************************************************
1351  *            SetupScanFileQueueW   (SETUPAPI.@)
1352  */
1353 BOOL WINAPI SetupScanFileQueueW( HSPFILEQ handle, DWORD flags, HWND window,
1354                                  PSP_FILE_CALLBACK_W handler, PVOID context, PDWORD result )
1355 {
1356     struct file_queue *queue = handle;
1357     struct file_op *op;
1358     FILEPATHS_W paths;
1359     UINT notification = 0;
1360     BOOL ret = FALSE;
1361
1362     TRACE("%p %x %p %p %p %p\n", handle, flags, window, handler, context, result);
1363
1364     if (!queue->copy_queue.count) return TRUE;
1365
1366     if (flags & SPQ_SCAN_USE_CALLBACK)        notification = SPFILENOTIFY_QUEUESCAN;
1367     else if (flags & SPQ_SCAN_USE_CALLBACKEX) notification = SPFILENOTIFY_QUEUESCAN_EX;
1368
1369     if (flags & ~(SPQ_SCAN_USE_CALLBACK | SPQ_SCAN_USE_CALLBACKEX))
1370     {
1371         FIXME("flags %x not fully implemented\n", flags);
1372     }
1373
1374     paths.Source = paths.Target = NULL;
1375
1376     for (op = queue->copy_queue.head; op; op = op->next)
1377     {
1378         build_filepathsW( op, &paths );
1379         switch (notification)
1380         {
1381         case SPFILENOTIFY_QUEUESCAN:
1382             /* FIXME: handle delay flag */
1383             if (handler( context,  notification, (UINT_PTR)paths.Target, 0 )) goto done;
1384             break;
1385         case SPFILENOTIFY_QUEUESCAN_EX:
1386             if (handler( context, notification, (UINT_PTR)&paths, 0 )) goto done;
1387             break;
1388         default:
1389             ret = TRUE; goto done;
1390         }
1391     }
1392
1393     ret = TRUE;
1394
1395  done:
1396     if (result) *result = 0;
1397     HeapFree( GetProcessHeap(), 0, (void *)paths.Source );
1398     HeapFree( GetProcessHeap(), 0, (void *)paths.Target );
1399     return ret;
1400 }
1401
1402
1403 /***********************************************************************
1404  *            SetupGetFileQueueCount   (SETUPAPI.@)
1405  */
1406 BOOL WINAPI SetupGetFileQueueCount( HSPFILEQ handle, UINT op, PUINT result )
1407 {
1408     struct file_queue *queue = handle;
1409
1410     switch(op)
1411     {
1412     case FILEOP_COPY:
1413         *result = queue->copy_queue.count;
1414         return TRUE;
1415     case FILEOP_RENAME:
1416         *result = queue->rename_queue.count;
1417         return TRUE;
1418     case FILEOP_DELETE:
1419         *result = queue->delete_queue.count;
1420         return TRUE;
1421     }
1422     return FALSE;
1423 }
1424
1425
1426 /***********************************************************************
1427  *            SetupGetFileQueueFlags   (SETUPAPI.@)
1428  */
1429 BOOL WINAPI SetupGetFileQueueFlags( HSPFILEQ handle, PDWORD flags )
1430 {
1431     struct file_queue *queue = handle;
1432     *flags = queue->flags;
1433     return TRUE;
1434 }
1435
1436
1437 /***********************************************************************
1438  *            SetupSetFileQueueFlags   (SETUPAPI.@)
1439  */
1440 BOOL WINAPI SetupSetFileQueueFlags( HSPFILEQ handle, DWORD mask, DWORD flags )
1441 {
1442     struct file_queue *queue = handle;
1443     queue->flags = (queue->flags & ~mask) | flags;
1444     return TRUE;
1445 }
1446
1447
1448 /***********************************************************************
1449  *   SetupSetFileQueueAlternatePlatformA  (SETUPAPI.@)
1450  */
1451 BOOL WINAPI SetupSetFileQueueAlternatePlatformA(HSPFILEQ handle, PSP_ALTPLATFORM_INFO platform, PCSTR catalogfile)
1452 {
1453     FIXME("(%p, %p, %s) stub!\n", handle, platform, debugstr_a(catalogfile));
1454     return FALSE;
1455 }
1456
1457
1458 /***********************************************************************
1459  *   SetupSetFileQueueAlternatePlatformW  (SETUPAPI.@)
1460  */
1461 BOOL WINAPI SetupSetFileQueueAlternatePlatformW(HSPFILEQ handle, PSP_ALTPLATFORM_INFO platform, PCWSTR catalogfile)
1462 {
1463     FIXME("(%p, %p, %s) stub!\n", handle, platform, debugstr_w(catalogfile));
1464     return FALSE;
1465 }
1466
1467
1468 /***********************************************************************
1469  *            SetupInitDefaultQueueCallback   (SETUPAPI.@)
1470  */
1471 PVOID WINAPI SetupInitDefaultQueueCallback( HWND owner )
1472 {
1473     return SetupInitDefaultQueueCallbackEx( owner, 0, 0, 0, NULL );
1474 }
1475
1476
1477 /***********************************************************************
1478  *            SetupInitDefaultQueueCallbackEx   (SETUPAPI.@)
1479  */
1480 PVOID WINAPI SetupInitDefaultQueueCallbackEx( HWND owner, HWND progress, UINT msg,
1481                                               DWORD reserved1, PVOID reserved2 )
1482 {
1483     struct default_callback_context *context;
1484
1485     if ((context = HeapAlloc( GetProcessHeap(), 0, sizeof(*context) )))
1486     {
1487         context->owner    = owner;
1488         context->progress = progress;
1489         context->message  = msg;
1490     }
1491     return context;
1492 }
1493
1494
1495 /***********************************************************************
1496  *            SetupTermDefaultQueueCallback   (SETUPAPI.@)
1497  */
1498 void WINAPI SetupTermDefaultQueueCallback( PVOID context )
1499 {
1500     HeapFree( GetProcessHeap(), 0, context );
1501 }
1502
1503
1504 /***********************************************************************
1505  *            SetupDefaultQueueCallbackA   (SETUPAPI.@)
1506  */
1507 UINT WINAPI SetupDefaultQueueCallbackA( PVOID context, UINT notification,
1508                                         UINT_PTR param1, UINT_PTR param2 )
1509 {
1510     FILEPATHS_A *paths = (FILEPATHS_A *)param1;
1511     struct default_callback_context *ctx = context;
1512
1513     switch(notification)
1514     {
1515     case SPFILENOTIFY_STARTQUEUE:
1516         TRACE( "start queue\n" );
1517         return TRUE;
1518     case SPFILENOTIFY_ENDQUEUE:
1519         TRACE( "end queue\n" );
1520         return 0;
1521     case SPFILENOTIFY_STARTSUBQUEUE:
1522         TRACE( "start subqueue %ld count %ld\n", param1, param2 );
1523         return TRUE;
1524     case SPFILENOTIFY_ENDSUBQUEUE:
1525         TRACE( "end subqueue %ld\n", param1 );
1526         return 0;
1527     case SPFILENOTIFY_STARTDELETE:
1528         TRACE( "start delete %s\n", debugstr_a(paths->Target) );
1529         return FILEOP_DOIT;
1530     case SPFILENOTIFY_ENDDELETE:
1531         TRACE( "end delete %s\n", debugstr_a(paths->Target) );
1532         return 0;
1533     case SPFILENOTIFY_DELETEERROR:
1534         /*Windows Ignores attempts to delete files / folders which do not exist*/
1535         if ((paths->Win32Error != ERROR_FILE_NOT_FOUND) && (paths->Win32Error != ERROR_PATH_NOT_FOUND))
1536         SetupDeleteErrorA(ctx->owner, NULL, paths->Target, paths->Win32Error, 0);
1537         return FILEOP_SKIP;
1538     case SPFILENOTIFY_STARTRENAME:
1539         TRACE( "start rename %s -> %s\n", debugstr_a(paths->Source), debugstr_a(paths->Target) );
1540         return FILEOP_DOIT;
1541     case SPFILENOTIFY_ENDRENAME:
1542         TRACE( "end rename %s -> %s\n", debugstr_a(paths->Source), debugstr_a(paths->Target) );
1543         return 0;
1544     case SPFILENOTIFY_RENAMEERROR:
1545         SetupRenameErrorA(ctx->owner, NULL, paths->Source, paths->Target, paths->Win32Error, 0);
1546         return FILEOP_SKIP;
1547     case SPFILENOTIFY_STARTCOPY:
1548         TRACE( "start copy %s -> %s\n", debugstr_a(paths->Source), debugstr_a(paths->Target) );
1549         return FILEOP_DOIT;
1550     case SPFILENOTIFY_ENDCOPY:
1551         TRACE( "end copy %s -> %s\n", debugstr_a(paths->Source), debugstr_a(paths->Target) );
1552         return 0;
1553     case SPFILENOTIFY_COPYERROR:
1554         ERR( "copy error %d %s -> %s\n", paths->Win32Error,
1555              debugstr_a(paths->Source), debugstr_a(paths->Target) );
1556         return FILEOP_SKIP;
1557     case SPFILENOTIFY_NEEDMEDIA:
1558         TRACE( "need media\n" );
1559         return FILEOP_SKIP;
1560     default:
1561         FIXME( "notification %d params %lx,%lx\n", notification, param1, param2 );
1562         break;
1563     }
1564     return 0;
1565 }
1566
1567
1568 /***********************************************************************
1569  *            SetupDefaultQueueCallbackW   (SETUPAPI.@)
1570  */
1571 UINT WINAPI SetupDefaultQueueCallbackW( PVOID context, UINT notification,
1572                                         UINT_PTR param1, UINT_PTR param2 )
1573 {
1574     FILEPATHS_W *paths = (FILEPATHS_W *)param1;
1575     struct default_callback_context *ctx = context;
1576
1577     switch(notification)
1578     {
1579     case SPFILENOTIFY_STARTQUEUE:
1580         TRACE( "start queue\n" );
1581         return TRUE;
1582     case SPFILENOTIFY_ENDQUEUE:
1583         TRACE( "end queue\n" );
1584         return 0;
1585     case SPFILENOTIFY_STARTSUBQUEUE:
1586         TRACE( "start subqueue %ld count %ld\n", param1, param2 );
1587         return TRUE;
1588     case SPFILENOTIFY_ENDSUBQUEUE:
1589         TRACE( "end subqueue %ld\n", param1 );
1590         return 0;
1591     case SPFILENOTIFY_STARTDELETE:
1592         TRACE( "start delete %s\n", debugstr_w(paths->Target) );
1593         return FILEOP_DOIT;
1594     case SPFILENOTIFY_ENDDELETE:
1595         TRACE( "end delete %s\n", debugstr_w(paths->Target) );
1596         return 0;
1597     case SPFILENOTIFY_DELETEERROR:
1598         /*Windows Ignores attempts to delete files / folders which do not exist*/
1599         if ((paths->Win32Error != ERROR_FILE_NOT_FOUND) && (paths->Win32Error != ERROR_PATH_NOT_FOUND))
1600             SetupDeleteErrorW(ctx->owner, NULL, paths->Target, paths->Win32Error, 0);
1601         return FILEOP_SKIP;
1602     case SPFILENOTIFY_STARTRENAME:
1603         SetupRenameErrorW(ctx->owner, NULL, paths->Source, paths->Target, paths->Win32Error, 0);
1604         return FILEOP_DOIT;
1605     case SPFILENOTIFY_ENDRENAME:
1606         TRACE( "end rename %s -> %s\n", debugstr_w(paths->Source), debugstr_w(paths->Target) );
1607         return 0;
1608     case SPFILENOTIFY_RENAMEERROR:
1609         ERR( "rename error %d %s -> %s\n", paths->Win32Error,
1610              debugstr_w(paths->Source), debugstr_w(paths->Target) );
1611         return FILEOP_SKIP;
1612     case SPFILENOTIFY_STARTCOPY:
1613         TRACE( "start copy %s -> %s\n", debugstr_w(paths->Source), debugstr_w(paths->Target) );
1614         return FILEOP_DOIT;
1615     case SPFILENOTIFY_ENDCOPY:
1616         TRACE( "end copy %s -> %s\n", debugstr_w(paths->Source), debugstr_w(paths->Target) );
1617         return 0;
1618     case SPFILENOTIFY_COPYERROR:
1619         ERR( "copy error %d %s -> %s\n", paths->Win32Error,
1620              debugstr_w(paths->Source), debugstr_w(paths->Target) );
1621         return FILEOP_SKIP;
1622     case SPFILENOTIFY_NEEDMEDIA:
1623         TRACE( "need media\n" );
1624         return FILEOP_SKIP;
1625     default:
1626         FIXME( "notification %d params %lx,%lx\n", notification, param1, param2 );
1627         break;
1628     }
1629     return 0;
1630 }
1631
1632 /***********************************************************************
1633  *            SetupDeleteErrorA   (SETUPAPI.@)
1634  */
1635
1636 UINT WINAPI SetupDeleteErrorA( HWND parent, PCSTR dialogTitle, PCSTR file,
1637                                UINT w32error, DWORD style)
1638 {
1639     FIXME( "stub: (Error Number %d when attempting to delete %s)\n",
1640            w32error, debugstr_a(file) );
1641     return DPROMPT_SKIPFILE;
1642 }
1643
1644 /***********************************************************************
1645  *            SetupDeleteErrorW   (SETUPAPI.@)
1646  */
1647
1648 UINT WINAPI SetupDeleteErrorW( HWND parent, PCWSTR dialogTitle, PCWSTR file,
1649                                UINT w32error, DWORD style)
1650 {
1651     FIXME( "stub: (Error Number %d when attempting to delete %s)\n",
1652            w32error, debugstr_w(file) );
1653     return DPROMPT_SKIPFILE;
1654 }
1655
1656 /***********************************************************************
1657  *            SetupRenameErrorA   (SETUPAPI.@)
1658  */
1659
1660 UINT WINAPI SetupRenameErrorA( HWND parent, PCSTR dialogTitle, PCSTR source,
1661                                PCSTR target, UINT w32error, DWORD style)
1662 {
1663     FIXME( "stub: (Error Number %d when attempting to rename %s to %s)\n",
1664            w32error, debugstr_a(source), debugstr_a(target));
1665     return DPROMPT_SKIPFILE;
1666 }
1667
1668 /***********************************************************************
1669  *            SetupRenameErrorW   (SETUPAPI.@)
1670  */
1671
1672 UINT WINAPI SetupRenameErrorW( HWND parent, PCWSTR dialogTitle, PCWSTR source,
1673                                PCWSTR target, UINT w32error, DWORD style)
1674 {
1675     FIXME( "stub: (Error Number %d when attempting to rename %s to %s)\n",
1676            w32error, debugstr_w(source), debugstr_w(target));
1677     return DPROMPT_SKIPFILE;
1678 }
1679
1680
1681 /***********************************************************************
1682  *            SetupCopyErrorA   (SETUPAPI.@)
1683  */
1684
1685 UINT WINAPI SetupCopyErrorA( HWND parent, PCSTR dialogTitle, PCSTR diskname, 
1686                              PCSTR sourcepath, PCSTR sourcefile, PCSTR targetpath,
1687                              UINT w32error, DWORD style, PSTR pathbuffer, 
1688                              DWORD buffersize, PDWORD requiredsize)
1689 {
1690     FIXME( "stub: (Error Number %d when attempting to copy file %s from %s to %s)\n",
1691            w32error, debugstr_a(sourcefile), debugstr_a(sourcepath) ,debugstr_a(targetpath));
1692     return DPROMPT_SKIPFILE;
1693 }
1694
1695 /***********************************************************************
1696  *            SetupCopyErrorW   (SETUPAPI.@)
1697  */
1698
1699 UINT WINAPI SetupCopyErrorW( HWND parent, PCWSTR dialogTitle, PCWSTR diskname, 
1700                              PCWSTR sourcepath, PCWSTR sourcefile, PCWSTR targetpath,
1701                              UINT w32error, DWORD style, PWSTR pathbuffer, 
1702                              DWORD buffersize, PDWORD requiredsize)
1703 {
1704     FIXME( "stub: (Error Number %d when attempting to copy file %s from %s to %s)\n",
1705            w32error, debugstr_w(sourcefile), debugstr_w(sourcepath) ,debugstr_w(targetpath));
1706     return DPROMPT_SKIPFILE;
1707 }
1708
1709 /***********************************************************************
1710  *            pSetupGetQueueFlags   (SETUPAPI.@)
1711  */
1712 DWORD WINAPI pSetupGetQueueFlags( HSPFILEQ handle )
1713 {
1714     struct file_queue *queue = handle;
1715     return queue->flags;
1716 }
1717
1718 /***********************************************************************
1719  *            pSetupSetQueueFlags   (SETUPAPI.@)
1720  */
1721 BOOL WINAPI pSetupSetQueueFlags( HSPFILEQ handle, DWORD flags )
1722 {
1723     struct file_queue *queue = handle;
1724     queue->flags = flags;
1725     return TRUE;
1726 }