msiexec: Add support for /update.
[wine.git] / dlls / setupapi / queue.c
blobd57f8e1b31019576672a0a77c743165a03b97788
1 /*
2 * Setupapi file queue routines
4 * Copyright 2002 Alexandre Julliard for CodeWeavers
6 * This library is free software; you can redistribute it and/or
7 * modify it under the terms of the GNU Lesser General Public
8 * License as published by the Free Software Foundation; either
9 * version 2.1 of the License, or (at your option) any later version.
11 * This library is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14 * Lesser General Public License for more details.
16 * You should have received a copy of the GNU Lesser General Public
17 * License along with this library; if not, write to the Free Software
18 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
21 #include <stdarg.h>
23 #include "windef.h"
24 #include "winbase.h"
25 #include "winreg.h"
26 #include "winternl.h"
27 #include "winerror.h"
28 #include "wingdi.h"
29 #include "winuser.h"
30 #include "winnls.h"
31 #include "setupapi.h"
32 #include "wine/unicode.h"
33 #include "setupapi_private.h"
34 #include "winver.h"
35 #include "wine/debug.h"
37 WINE_DEFAULT_DEBUG_CHANNEL(setupapi);
39 /* context structure for the default queue callback */
40 struct default_callback_context
42 DWORD magic;
43 HWND owner;
44 DWORD unk1[4];
45 DWORD_PTR unk2[7];
46 HWND progress;
47 UINT message;
48 DWORD_PTR unk3[5];
51 struct file_op
53 struct file_op *next;
54 UINT style;
55 WCHAR *src_root;
56 WCHAR *src_path;
57 WCHAR *src_file;
58 WCHAR *src_descr;
59 WCHAR *src_tag;
60 WCHAR *dst_path;
61 WCHAR *dst_file;
64 struct file_op_queue
66 struct file_op *head;
67 struct file_op *tail;
68 unsigned int count;
71 struct file_queue
73 struct file_op_queue copy_queue;
74 struct file_op_queue delete_queue;
75 struct file_op_queue rename_queue;
76 DWORD flags;
80 /* append a file operation to a queue */
81 static inline void queue_file_op( struct file_op_queue *queue, struct file_op *op )
83 op->next = NULL;
84 if (queue->tail) queue->tail->next = op;
85 else queue->head = op;
86 queue->tail = op;
87 queue->count++;
90 /* free all the file operations on a given queue */
91 static void free_file_op_queue( struct file_op_queue *queue )
93 struct file_op *t, *op = queue->head;
95 while( op )
97 HeapFree( GetProcessHeap(), 0, op->src_root );
98 HeapFree( GetProcessHeap(), 0, op->src_path );
99 HeapFree( GetProcessHeap(), 0, op->src_file );
100 HeapFree( GetProcessHeap(), 0, op->src_descr );
101 HeapFree( GetProcessHeap(), 0, op->src_tag );
102 HeapFree( GetProcessHeap(), 0, op->dst_path );
103 if (op->dst_file != op->src_file) HeapFree( GetProcessHeap(), 0, op->dst_file );
104 t = op;
105 op = op->next;
106 HeapFree( GetProcessHeap(), 0, t );
110 /* concat 3 strings to make a path, handling separators correctly */
111 static void concat_W( WCHAR *buffer, const WCHAR *src1, const WCHAR *src2, const WCHAR *src3 )
113 *buffer = 0;
114 if (src1 && *src1)
116 strcpyW( buffer, src1 );
117 buffer += strlenW(buffer );
118 if (buffer[-1] != '\\') *buffer++ = '\\';
119 if (src2) while (*src2 == '\\') src2++;
122 if (src2)
124 strcpyW( buffer, src2 );
125 buffer += strlenW(buffer );
126 if (buffer[-1] != '\\') *buffer++ = '\\';
127 if (src3) while (*src3 == '\\') src3++;
129 if (src3)
131 strcpyW( buffer, src3 );
132 buffer += strlenW(buffer );
137 /***********************************************************************
138 * build_filepathsW
140 * Build a FILEPATHS_W structure for a given file operation.
142 static BOOL build_filepathsW( const struct file_op *op, FILEPATHS_W *paths )
144 unsigned int src_len = 1, dst_len = 1;
145 WCHAR *source = (PWSTR)paths->Source, *target = (PWSTR)paths->Target;
147 if (op->src_root) src_len += strlenW(op->src_root) + 1;
148 if (op->src_path) src_len += strlenW(op->src_path) + 1;
149 if (op->src_file) src_len += strlenW(op->src_file) + 1;
150 if (op->dst_path) dst_len += strlenW(op->dst_path) + 1;
151 if (op->dst_file) dst_len += strlenW(op->dst_file) + 1;
152 src_len *= sizeof(WCHAR);
153 dst_len *= sizeof(WCHAR);
155 if (!source || HeapSize( GetProcessHeap(), 0, source ) < src_len )
157 HeapFree( GetProcessHeap(), 0, source );
158 paths->Source = source = HeapAlloc( GetProcessHeap(), 0, src_len );
160 if (!target || HeapSize( GetProcessHeap(), 0, target ) < dst_len )
162 HeapFree( GetProcessHeap(), 0, target );
163 paths->Target = target = HeapAlloc( GetProcessHeap(), 0, dst_len );
165 if (!source || !target) return FALSE;
166 concat_W( source, op->src_root, op->src_path, op->src_file );
167 concat_W( target, NULL, op->dst_path, op->dst_file );
168 paths->Win32Error = 0;
169 paths->Flags = 0;
170 return TRUE;
174 /***********************************************************************
175 * QUEUE_callback_WtoA
177 * Map a file callback parameters from W to A and call the A callback.
179 UINT CALLBACK QUEUE_callback_WtoA( void *context, UINT notification,
180 UINT_PTR param1, UINT_PTR param2 )
182 struct callback_WtoA_context *callback_ctx = context;
183 char buffer[MAX_PATH];
184 UINT ret;
185 UINT_PTR old_param2 = param2;
187 switch(notification)
189 case SPFILENOTIFY_COPYERROR:
190 param2 = (UINT_PTR)buffer;
191 /* fall through */
192 case SPFILENOTIFY_STARTDELETE:
193 case SPFILENOTIFY_ENDDELETE:
194 case SPFILENOTIFY_DELETEERROR:
195 case SPFILENOTIFY_STARTRENAME:
196 case SPFILENOTIFY_ENDRENAME:
197 case SPFILENOTIFY_RENAMEERROR:
198 case SPFILENOTIFY_STARTCOPY:
199 case SPFILENOTIFY_ENDCOPY:
200 case SPFILENOTIFY_QUEUESCAN_EX:
202 FILEPATHS_W *pathsW = (FILEPATHS_W *)param1;
203 FILEPATHS_A pathsA;
205 pathsA.Source = strdupWtoA( pathsW->Source );
206 pathsA.Target = strdupWtoA( pathsW->Target );
207 pathsA.Win32Error = pathsW->Win32Error;
208 pathsA.Flags = pathsW->Flags;
209 ret = callback_ctx->orig_handler( callback_ctx->orig_context, notification,
210 (UINT_PTR)&pathsA, param2 );
211 HeapFree( GetProcessHeap(), 0, (void *)pathsA.Source );
212 HeapFree( GetProcessHeap(), 0, (void *)pathsA.Target );
214 if (notification == SPFILENOTIFY_COPYERROR)
215 MultiByteToWideChar( CP_ACP, 0, buffer, -1, (WCHAR *)old_param2, MAX_PATH );
216 break;
218 case SPFILENOTIFY_STARTREGISTRATION:
219 case SPFILENOTIFY_ENDREGISTRATION:
221 SP_REGISTER_CONTROL_STATUSW *statusW = (SP_REGISTER_CONTROL_STATUSW *)param1;
222 SP_REGISTER_CONTROL_STATUSA statusA;
224 statusA.cbSize = sizeof(statusA);
225 statusA.FileName = strdupWtoA( statusW->FileName );
226 statusA.Win32Error = statusW->Win32Error;
227 statusA.FailureCode = statusW->FailureCode;
228 ret = callback_ctx->orig_handler( callback_ctx->orig_context, notification,
229 (UINT_PTR)&statusA, param2 );
230 HeapFree( GetProcessHeap(), 0, (LPSTR)statusA.FileName );
232 break;
234 case SPFILENOTIFY_QUEUESCAN:
236 LPWSTR targetW = (LPWSTR)param1;
237 LPSTR target = strdupWtoA( targetW );
239 ret = callback_ctx->orig_handler( callback_ctx->orig_context, notification,
240 (UINT_PTR)target, param2 );
241 HeapFree( GetProcessHeap(), 0, target );
243 break;
245 case SPFILENOTIFY_NEEDMEDIA:
246 FIXME("mapping for %d not implemented\n",notification);
247 case SPFILENOTIFY_STARTQUEUE:
248 case SPFILENOTIFY_ENDQUEUE:
249 case SPFILENOTIFY_STARTSUBQUEUE:
250 case SPFILENOTIFY_ENDSUBQUEUE:
251 default:
252 ret = callback_ctx->orig_handler( callback_ctx->orig_context, notification, param1, param2 );
253 break;
255 return ret;
259 /***********************************************************************
260 * get_src_file_info
262 * Retrieve the source file information for a given file.
264 static void get_src_file_info( HINF hinf, struct file_op *op )
266 static const WCHAR SourceDisksNames[] =
267 {'S','o','u','r','c','e','D','i','s','k','s','N','a','m','e','s',0};
268 static const WCHAR SourceDisksFiles[] =
269 {'S','o','u','r','c','e','D','i','s','k','s','F','i','l','e','s',0};
271 INFCONTEXT file_ctx, disk_ctx;
272 INT id, diskid;
273 DWORD len, len2;
275 /* find the SourceDisksFiles entry */
276 if (!SetupFindFirstLineW( hinf, SourceDisksFiles, op->src_file, &file_ctx ))
278 if ((op->style & (SP_COPY_SOURCE_ABSOLUTE|SP_COPY_SOURCEPATH_ABSOLUTE))) return;
279 /* no specific info, use .inf file source directory */
280 if (!op->src_root) op->src_root = PARSER_get_src_root( hinf );
281 return;
283 if (!SetupGetIntField( &file_ctx, 1, &diskid )) return;
285 /* now find the diskid in the SourceDisksNames section */
286 if (!SetupFindFirstLineW( hinf, SourceDisksNames, NULL, &disk_ctx )) return;
287 for (;;)
289 if (SetupGetIntField( &disk_ctx, 0, &id ) && (id == diskid)) break;
290 if (!SetupFindNextLine( &disk_ctx, &disk_ctx )) return;
293 /* and fill in the missing info */
295 if (!op->src_descr)
297 if (SetupGetStringFieldW( &disk_ctx, 1, NULL, 0, &len ) &&
298 (op->src_descr = HeapAlloc( GetProcessHeap(), 0, len*sizeof(WCHAR) )))
299 SetupGetStringFieldW( &disk_ctx, 1, op->src_descr, len, NULL );
301 if (!op->src_tag)
303 if (SetupGetStringFieldW( &disk_ctx, 2, NULL, 0, &len ) &&
304 (op->src_tag = HeapAlloc( GetProcessHeap(), 0, len*sizeof(WCHAR) )))
305 SetupGetStringFieldW( &disk_ctx, 2, op->src_tag, len, NULL );
307 if (!op->src_path && !(op->style & SP_COPY_SOURCE_ABSOLUTE))
309 len = len2 = 0;
310 if (!(op->style & SP_COPY_SOURCEPATH_ABSOLUTE))
312 /* retrieve relative path for this disk */
313 if (!SetupGetStringFieldW( &disk_ctx, 4, NULL, 0, &len )) len = 0;
315 /* retrieve relative path for this file */
316 if (!SetupGetStringFieldW( &file_ctx, 2, NULL, 0, &len2 )) len2 = 0;
318 if ((len || len2) &&
319 (op->src_path = HeapAlloc( GetProcessHeap(), 0, (len+len2)*sizeof(WCHAR) )))
321 WCHAR *ptr = op->src_path;
322 if (len)
324 SetupGetStringFieldW( &disk_ctx, 4, op->src_path, len, NULL );
325 ptr = op->src_path + strlenW(op->src_path);
326 if (len2 && ptr > op->src_path && ptr[-1] != '\\') *ptr++ = '\\';
328 if (!SetupGetStringFieldW( &file_ctx, 2, ptr, len2, NULL )) *ptr = 0;
331 if (!op->src_root) op->src_root = PARSER_get_src_root(hinf);
335 /***********************************************************************
336 * get_destination_dir
338 * Retrieve the destination dir for a given section.
340 static WCHAR *get_destination_dir( HINF hinf, const WCHAR *section )
342 static const WCHAR Dest[] = {'D','e','s','t','i','n','a','t','i','o','n','D','i','r','s',0};
343 static const WCHAR Def[] = {'D','e','f','a','u','l','t','D','e','s','t','D','i','r',0};
344 INFCONTEXT context;
345 WCHAR systemdir[MAX_PATH], *dir;
346 BOOL ret;
348 if (!(ret = SetupFindFirstLineW( hinf, Dest, section, &context )))
349 ret = SetupFindFirstLineW( hinf, Dest, Def, &context );
351 if (ret && (dir = PARSER_get_dest_dir( &context )))
352 return dir;
354 GetSystemDirectoryW( systemdir, MAX_PATH );
355 return strdupW( systemdir );
359 static void (WINAPI *pExtractFiles)( LPSTR, LPSTR, DWORD, DWORD, DWORD, DWORD );
361 /***********************************************************************
362 * extract_cabinet_file
364 * Extract a file from a .cab file.
366 static BOOL extract_cabinet_file( const WCHAR *cabinet, const WCHAR *root,
367 const WCHAR *src, const WCHAR *dst )
369 static const WCHAR extW[] = {'.','c','a','b',0};
370 static HMODULE advpack;
372 char *cab_path, *cab_file;
373 int len = strlenW( cabinet );
375 /* make sure the cabinet file has a .cab extension */
376 if (len <= 4 || strcmpiW( cabinet + len - 4, extW )) return FALSE;
377 if (!pExtractFiles)
379 if (!advpack && !(advpack = LoadLibraryA( "advpack.dll" )))
381 ERR( "could not load advpack.dll\n" );
382 return FALSE;
384 if (!(pExtractFiles = (void *)GetProcAddress( advpack, "ExtractFiles" )))
386 ERR( "could not find ExtractFiles in advpack.dll\n" );
387 return FALSE;
391 if (!(cab_path = strdupWtoA( root ))) return FALSE;
392 len = WideCharToMultiByte( CP_ACP, 0, cabinet, -1, NULL, 0, NULL, NULL );
393 if (!(cab_file = HeapAlloc( GetProcessHeap(), 0, strlen(cab_path) + len + 1 )))
395 HeapFree( GetProcessHeap(), 0, cab_path );
396 return FALSE;
398 strcpy( cab_file, cab_path );
399 if (cab_file[0] && cab_file[strlen(cab_file)-1] != '\\') strcat( cab_file, "\\" );
400 WideCharToMultiByte( CP_ACP, 0, cabinet, -1, cab_file + strlen(cab_file), len, NULL, NULL );
401 FIXME( "awful hack: extracting cabinet %s\n", debugstr_a(cab_file) );
402 pExtractFiles( cab_file, cab_path, 0, 0, 0, 0 );
403 HeapFree( GetProcessHeap(), 0, cab_file );
404 HeapFree( GetProcessHeap(), 0, cab_path );
405 return CopyFileW( src, dst, FALSE /*FIXME*/ );
409 /***********************************************************************
410 * SetupOpenFileQueue (SETUPAPI.@)
412 HSPFILEQ WINAPI SetupOpenFileQueue(void)
414 struct file_queue *queue;
416 if (!(queue = HeapAlloc( GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*queue))))
417 return INVALID_HANDLE_VALUE;
418 return queue;
422 /***********************************************************************
423 * SetupCloseFileQueue (SETUPAPI.@)
425 BOOL WINAPI SetupCloseFileQueue( HSPFILEQ handle )
427 struct file_queue *queue = handle;
429 free_file_op_queue( &queue->copy_queue );
430 free_file_op_queue( &queue->rename_queue );
431 free_file_op_queue( &queue->delete_queue );
432 HeapFree( GetProcessHeap(), 0, queue );
433 return TRUE;
437 /***********************************************************************
438 * SetupQueueCopyIndirectA (SETUPAPI.@)
440 BOOL WINAPI SetupQueueCopyIndirectA( PSP_FILE_COPY_PARAMS_A params )
442 struct file_queue *queue = params->QueueHandle;
443 struct file_op *op;
445 if (!(op = HeapAlloc( GetProcessHeap(), 0, sizeof(*op) ))) return FALSE;
446 op->style = params->CopyStyle;
447 op->src_root = strdupAtoW( params->SourceRootPath );
448 op->src_path = strdupAtoW( params->SourcePath );
449 op->src_file = strdupAtoW( params->SourceFilename );
450 op->src_descr = strdupAtoW( params->SourceDescription );
451 op->src_tag = strdupAtoW( params->SourceTagfile );
452 op->dst_path = strdupAtoW( params->TargetDirectory );
453 op->dst_file = strdupAtoW( params->TargetFilename );
455 /* some defaults */
456 if (!op->src_file) op->src_file = op->dst_file;
457 if (params->LayoutInf)
459 get_src_file_info( params->LayoutInf, op );
460 if (!op->dst_path) op->dst_path = get_destination_dir( params->LayoutInf, op->dst_file );
463 TRACE( "root=%s path=%s file=%s -> dir=%s file=%s descr=%s tag=%s\n",
464 debugstr_w(op->src_root), debugstr_w(op->src_path), debugstr_w(op->src_file),
465 debugstr_w(op->dst_path), debugstr_w(op->dst_file),
466 debugstr_w(op->src_descr), debugstr_w(op->src_tag) );
468 queue_file_op( &queue->copy_queue, op );
469 return TRUE;
473 /***********************************************************************
474 * SetupQueueCopyIndirectW (SETUPAPI.@)
476 BOOL WINAPI SetupQueueCopyIndirectW( PSP_FILE_COPY_PARAMS_W params )
478 struct file_queue *queue = params->QueueHandle;
479 struct file_op *op;
481 if (!(op = HeapAlloc( GetProcessHeap(), 0, sizeof(*op) ))) return FALSE;
482 op->style = params->CopyStyle;
483 op->src_root = strdupW( params->SourceRootPath );
484 op->src_path = strdupW( params->SourcePath );
485 op->src_file = strdupW( params->SourceFilename );
486 op->src_descr = strdupW( params->SourceDescription );
487 op->src_tag = strdupW( params->SourceTagfile );
488 op->dst_path = strdupW( params->TargetDirectory );
489 op->dst_file = strdupW( params->TargetFilename );
491 /* some defaults */
492 if (!op->src_file) op->src_file = op->dst_file;
493 if (params->LayoutInf)
495 get_src_file_info( params->LayoutInf, op );
496 if (!op->dst_path) op->dst_path = get_destination_dir( params->LayoutInf, op->dst_file );
499 TRACE( "root=%s path=%s file=%s -> dir=%s file=%s descr=%s tag=%s\n",
500 debugstr_w(op->src_root), debugstr_w(op->src_path), debugstr_w(op->src_file),
501 debugstr_w(op->dst_path), debugstr_w(op->dst_file),
502 debugstr_w(op->src_descr), debugstr_w(op->src_tag) );
504 queue_file_op( &queue->copy_queue, op );
505 return TRUE;
509 /***********************************************************************
510 * SetupQueueCopyA (SETUPAPI.@)
512 BOOL WINAPI SetupQueueCopyA( HSPFILEQ queue, PCSTR src_root, PCSTR src_path, PCSTR src_file,
513 PCSTR src_descr, PCSTR src_tag, PCSTR dst_dir, PCSTR dst_file,
514 DWORD style )
516 SP_FILE_COPY_PARAMS_A params;
518 params.cbSize = sizeof(params);
519 params.QueueHandle = queue;
520 params.SourceRootPath = src_root;
521 params.SourcePath = src_path;
522 params.SourceFilename = src_file;
523 params.SourceDescription = src_descr;
524 params.SourceTagfile = src_tag;
525 params.TargetDirectory = dst_dir;
526 params.TargetFilename = dst_file;
527 params.CopyStyle = style;
528 params.LayoutInf = 0;
529 params.SecurityDescriptor = NULL;
530 return SetupQueueCopyIndirectA( &params );
534 /***********************************************************************
535 * SetupQueueCopyW (SETUPAPI.@)
537 BOOL WINAPI SetupQueueCopyW( HSPFILEQ queue, PCWSTR src_root, PCWSTR src_path, PCWSTR src_file,
538 PCWSTR src_descr, PCWSTR src_tag, PCWSTR dst_dir, PCWSTR dst_file,
539 DWORD style )
541 SP_FILE_COPY_PARAMS_W params;
543 params.cbSize = sizeof(params);
544 params.QueueHandle = queue;
545 params.SourceRootPath = src_root;
546 params.SourcePath = src_path;
547 params.SourceFilename = src_file;
548 params.SourceDescription = src_descr;
549 params.SourceTagfile = src_tag;
550 params.TargetDirectory = dst_dir;
551 params.TargetFilename = dst_file;
552 params.CopyStyle = style;
553 params.LayoutInf = 0;
554 params.SecurityDescriptor = NULL;
555 return SetupQueueCopyIndirectW( &params );
559 /***********************************************************************
560 * SetupQueueDefaultCopyA (SETUPAPI.@)
562 BOOL WINAPI SetupQueueDefaultCopyA( HSPFILEQ queue, HINF hinf, PCSTR src_root, PCSTR src_file,
563 PCSTR dst_file, DWORD style )
565 SP_FILE_COPY_PARAMS_A params;
567 params.cbSize = sizeof(params);
568 params.QueueHandle = queue;
569 params.SourceRootPath = src_root;
570 params.SourcePath = NULL;
571 params.SourceFilename = src_file;
572 params.SourceDescription = NULL;
573 params.SourceTagfile = NULL;
574 params.TargetDirectory = NULL;
575 params.TargetFilename = dst_file;
576 params.CopyStyle = style;
577 params.LayoutInf = hinf;
578 params.SecurityDescriptor = NULL;
579 return SetupQueueCopyIndirectA( &params );
583 /***********************************************************************
584 * SetupQueueDefaultCopyW (SETUPAPI.@)
586 BOOL WINAPI SetupQueueDefaultCopyW( HSPFILEQ queue, HINF hinf, PCWSTR src_root, PCWSTR src_file,
587 PCWSTR dst_file, DWORD style )
589 SP_FILE_COPY_PARAMS_W params;
591 params.cbSize = sizeof(params);
592 params.QueueHandle = queue;
593 params.SourceRootPath = src_root;
594 params.SourcePath = NULL;
595 params.SourceFilename = src_file;
596 params.SourceDescription = NULL;
597 params.SourceTagfile = NULL;
598 params.TargetDirectory = NULL;
599 params.TargetFilename = dst_file;
600 params.CopyStyle = style;
601 params.LayoutInf = hinf;
602 params.SecurityDescriptor = NULL;
603 return SetupQueueCopyIndirectW( &params );
607 /***********************************************************************
608 * SetupQueueDeleteA (SETUPAPI.@)
610 BOOL WINAPI SetupQueueDeleteA( HSPFILEQ handle, PCSTR part1, PCSTR part2 )
612 struct file_queue *queue = handle;
613 struct file_op *op;
615 if (!(op = HeapAlloc( GetProcessHeap(), 0, sizeof(*op) ))) return FALSE;
616 op->style = 0;
617 op->src_root = NULL;
618 op->src_path = NULL;
619 op->src_file = NULL;
620 op->src_descr = NULL;
621 op->src_tag = NULL;
622 op->dst_path = strdupAtoW( part1 );
623 op->dst_file = strdupAtoW( part2 );
624 queue_file_op( &queue->delete_queue, op );
625 return TRUE;
629 /***********************************************************************
630 * SetupQueueDeleteW (SETUPAPI.@)
632 BOOL WINAPI SetupQueueDeleteW( HSPFILEQ handle, PCWSTR part1, PCWSTR part2 )
634 struct file_queue *queue = handle;
635 struct file_op *op;
637 if (!(op = HeapAlloc( GetProcessHeap(), 0, sizeof(*op) ))) return FALSE;
638 op->style = 0;
639 op->src_root = NULL;
640 op->src_path = NULL;
641 op->src_file = NULL;
642 op->src_descr = NULL;
643 op->src_tag = NULL;
644 op->dst_path = strdupW( part1 );
645 op->dst_file = strdupW( part2 );
646 queue_file_op( &queue->delete_queue, op );
647 return TRUE;
651 /***********************************************************************
652 * SetupQueueRenameA (SETUPAPI.@)
654 BOOL WINAPI SetupQueueRenameA( HSPFILEQ handle, PCSTR SourcePath, PCSTR SourceFilename,
655 PCSTR TargetPath, PCSTR TargetFilename )
657 struct file_queue *queue = handle;
658 struct file_op *op;
660 if (!(op = HeapAlloc( GetProcessHeap(), 0, sizeof(*op) ))) return FALSE;
661 op->style = 0;
662 op->src_root = NULL;
663 op->src_path = strdupAtoW( SourcePath );
664 op->src_file = strdupAtoW( SourceFilename );
665 op->src_descr = NULL;
666 op->src_tag = NULL;
667 op->dst_path = strdupAtoW( TargetPath );
668 op->dst_file = strdupAtoW( TargetFilename );
669 queue_file_op( &queue->rename_queue, op );
670 return TRUE;
674 /***********************************************************************
675 * SetupQueueRenameW (SETUPAPI.@)
677 BOOL WINAPI SetupQueueRenameW( HSPFILEQ handle, PCWSTR SourcePath, PCWSTR SourceFilename,
678 PCWSTR TargetPath, PCWSTR TargetFilename )
680 struct file_queue *queue = handle;
681 struct file_op *op;
683 if (!(op = HeapAlloc( GetProcessHeap(), 0, sizeof(*op) ))) return FALSE;
684 op->style = 0;
685 op->src_root = NULL;
686 op->src_path = strdupW( SourcePath );
687 op->src_file = strdupW( SourceFilename );
688 op->src_descr = NULL;
689 op->src_tag = NULL;
690 op->dst_path = strdupW( TargetPath );
691 op->dst_file = strdupW( TargetFilename );
692 queue_file_op( &queue->rename_queue, op );
693 return TRUE;
697 /***********************************************************************
698 * SetupQueueCopySectionA (SETUPAPI.@)
700 BOOL WINAPI SetupQueueCopySectionA( HSPFILEQ queue, PCSTR src_root, HINF hinf, HINF hlist,
701 PCSTR section, DWORD style )
703 UNICODE_STRING sectionW;
704 BOOL ret = FALSE;
706 if (!RtlCreateUnicodeStringFromAsciiz( &sectionW, section ))
708 SetLastError( ERROR_NOT_ENOUGH_MEMORY );
709 return FALSE;
711 if (!src_root)
712 ret = SetupQueueCopySectionW( queue, NULL, hinf, hlist, sectionW.Buffer, style );
713 else
715 UNICODE_STRING srcW;
716 if (RtlCreateUnicodeStringFromAsciiz( &srcW, src_root ))
718 ret = SetupQueueCopySectionW( queue, srcW.Buffer, hinf, hlist, sectionW.Buffer, style );
719 RtlFreeUnicodeString( &srcW );
721 else SetLastError( ERROR_NOT_ENOUGH_MEMORY );
723 RtlFreeUnicodeString( &sectionW );
724 return ret;
728 /***********************************************************************
729 * SetupQueueCopySectionW (SETUPAPI.@)
731 BOOL WINAPI SetupQueueCopySectionW( HSPFILEQ queue, PCWSTR src_root, HINF hinf, HINF hlist,
732 PCWSTR section, DWORD style )
734 SP_FILE_COPY_PARAMS_W params;
735 INFCONTEXT context;
736 WCHAR dest[MAX_PATH], src[MAX_PATH], *dest_dir;
737 INT flags;
738 BOOL ret = FALSE;
740 TRACE( "hinf=%p/%p section=%s root=%s\n",
741 hinf, hlist, debugstr_w(section), debugstr_w(src_root) );
743 params.cbSize = sizeof(params);
744 params.QueueHandle = queue;
745 params.SourceRootPath = src_root;
746 params.SourcePath = NULL;
747 params.SourceDescription = NULL;
748 params.SourceTagfile = NULL;
749 params.TargetFilename = dest;
750 params.CopyStyle = style;
751 params.LayoutInf = hinf;
752 params.SecurityDescriptor = NULL;
754 if (!hlist) hlist = hinf;
755 if (!hinf) hinf = hlist;
756 if (!SetupFindFirstLineW( hlist, section, NULL, &context )) return FALSE;
757 if (!(params.TargetDirectory = dest_dir = get_destination_dir( hinf, section ))) return FALSE;
760 if (!SetupGetStringFieldW( &context, 1, dest, sizeof(dest)/sizeof(WCHAR), NULL ))
761 goto end;
762 if (!SetupGetStringFieldW( &context, 2, src, sizeof(src)/sizeof(WCHAR), NULL )) *src = 0;
763 if (!SetupGetIntField( &context, 4, &flags )) flags = 0; /* FIXME */
765 params.SourceFilename = *src ? src : NULL;
766 if (!SetupQueueCopyIndirectW( &params )) goto end;
767 } while (SetupFindNextLine( &context, &context ));
768 ret = TRUE;
769 end:
770 HeapFree(GetProcessHeap(), 0, dest_dir);
771 return ret;
775 /***********************************************************************
776 * SetupQueueDeleteSectionA (SETUPAPI.@)
778 BOOL WINAPI SetupQueueDeleteSectionA( HSPFILEQ queue, HINF hinf, HINF hlist, PCSTR section )
780 UNICODE_STRING sectionW;
781 BOOL ret = FALSE;
783 if (RtlCreateUnicodeStringFromAsciiz( &sectionW, section ))
785 ret = SetupQueueDeleteSectionW( queue, hinf, hlist, sectionW.Buffer );
786 RtlFreeUnicodeString( &sectionW );
788 else SetLastError( ERROR_NOT_ENOUGH_MEMORY );
789 return ret;
793 /***********************************************************************
794 * SetupQueueDeleteSectionW (SETUPAPI.@)
796 BOOL WINAPI SetupQueueDeleteSectionW( HSPFILEQ queue, HINF hinf, HINF hlist, PCWSTR section )
798 INFCONTEXT context;
799 WCHAR *dest_dir;
800 WCHAR buffer[MAX_PATH];
801 BOOL ret = FALSE;
802 INT flags;
804 TRACE( "hinf=%p/%p section=%s\n", hinf, hlist, debugstr_w(section) );
806 if (!hlist) hlist = hinf;
807 if (!SetupFindFirstLineW( hlist, section, NULL, &context )) return FALSE;
808 if (!(dest_dir = get_destination_dir( hinf, section ))) return FALSE;
811 if (!SetupGetStringFieldW( &context, 1, buffer, sizeof(buffer)/sizeof(WCHAR), NULL ))
812 goto done;
813 if (!SetupGetIntField( &context, 4, &flags )) flags = 0;
814 if (!SetupQueueDeleteW( queue, dest_dir, buffer )) goto done;
815 } while (SetupFindNextLine( &context, &context ));
817 ret = TRUE;
818 done:
819 HeapFree( GetProcessHeap(), 0, dest_dir );
820 return ret;
824 /***********************************************************************
825 * SetupQueueRenameSectionA (SETUPAPI.@)
827 BOOL WINAPI SetupQueueRenameSectionA( HSPFILEQ queue, HINF hinf, HINF hlist, PCSTR section )
829 UNICODE_STRING sectionW;
830 BOOL ret = FALSE;
832 if (RtlCreateUnicodeStringFromAsciiz( &sectionW, section ))
834 ret = SetupQueueRenameSectionW( queue, hinf, hlist, sectionW.Buffer );
835 RtlFreeUnicodeString( &sectionW );
837 else SetLastError( ERROR_NOT_ENOUGH_MEMORY );
838 return ret;
842 /***********************************************************************
843 * SetupQueueRenameSectionW (SETUPAPI.@)
845 BOOL WINAPI SetupQueueRenameSectionW( HSPFILEQ queue, HINF hinf, HINF hlist, PCWSTR section )
847 INFCONTEXT context;
848 WCHAR *dest_dir;
849 WCHAR src[MAX_PATH], dst[MAX_PATH];
850 BOOL ret = FALSE;
852 TRACE( "hinf=%p/%p section=%s\n", hinf, hlist, debugstr_w(section) );
854 if (!hlist) hlist = hinf;
855 if (!SetupFindFirstLineW( hlist, section, NULL, &context )) return FALSE;
856 if (!(dest_dir = get_destination_dir( hinf, section ))) return FALSE;
859 if (!SetupGetStringFieldW( &context, 1, dst, sizeof(dst)/sizeof(WCHAR), NULL ))
860 goto done;
861 if (!SetupGetStringFieldW( &context, 2, src, sizeof(src)/sizeof(WCHAR), NULL ))
862 goto done;
863 if (!SetupQueueRenameW( queue, dest_dir, src, NULL, dst )) goto done;
864 } while (SetupFindNextLine( &context, &context ));
866 ret = TRUE;
867 done:
868 HeapFree( GetProcessHeap(), 0, dest_dir );
869 return ret;
873 /***********************************************************************
874 * SetupCommitFileQueueA (SETUPAPI.@)
876 BOOL WINAPI SetupCommitFileQueueA( HWND owner, HSPFILEQ queue, PSP_FILE_CALLBACK_A handler,
877 PVOID context )
879 struct callback_WtoA_context ctx;
881 ctx.orig_context = context;
882 ctx.orig_handler = handler;
883 return SetupCommitFileQueueW( owner, queue, QUEUE_callback_WtoA, &ctx );
887 /***********************************************************************
888 * create_full_pathW
890 * Recursively create all directories in the path.
892 static BOOL create_full_pathW(const WCHAR *path)
894 BOOL ret = TRUE;
895 int len;
896 WCHAR *new_path;
898 new_path = HeapAlloc(GetProcessHeap(), 0, (strlenW(path) + 1) * sizeof(WCHAR));
899 strcpyW(new_path, path);
901 while((len = strlenW(new_path)) && new_path[len - 1] == '\\')
902 new_path[len - 1] = 0;
904 while(!CreateDirectoryW(new_path, NULL))
906 WCHAR *slash;
907 DWORD last_error = GetLastError();
909 if(last_error == ERROR_ALREADY_EXISTS)
910 break;
912 if(last_error != ERROR_PATH_NOT_FOUND)
914 ret = FALSE;
915 break;
918 if(!(slash = strrchrW(new_path, '\\')))
920 ret = FALSE;
921 break;
924 len = slash - new_path;
925 new_path[len] = 0;
926 if(!create_full_pathW(new_path))
928 ret = FALSE;
929 break;
931 new_path[len] = '\\';
934 HeapFree(GetProcessHeap(), 0, new_path);
935 return ret;
938 static BOOL do_file_copyW( LPCWSTR source, LPCWSTR target, DWORD style,
939 PSP_FILE_CALLBACK_W handler, PVOID context )
941 BOOL rc = FALSE;
942 BOOL docopy = TRUE;
944 TRACE("copy %s to %s style 0x%x\n",debugstr_w(source),debugstr_w(target),style);
946 /* before copy processing */
947 if (style & SP_COPY_REPLACEONLY)
949 if (GetFileAttributesW(target) == INVALID_FILE_ATTRIBUTES)
950 docopy = FALSE;
952 if (style & (SP_COPY_NEWER_OR_SAME | SP_COPY_NEWER_ONLY | SP_COPY_FORCE_NEWER))
954 DWORD VersionSizeSource=0;
955 DWORD VersionSizeTarget=0;
956 DWORD zero=0;
959 * This is sort of an interesting workaround. You see, calling
960 * GetVersionInfoSize on a builtin dll loads that dll into memory
961 * and we do not properly unload builtin dlls.. so we effectively
962 * lock into memory all the targets we are replacing. This leads
963 * to problems when we try to register the replaced dlls.
965 * So I will test for the existence of the files first so that
966 * we just basically unconditionally replace the builtin versions.
968 if ((GetFileAttributesW(target) != INVALID_FILE_ATTRIBUTES) &&
969 (GetFileAttributesW(source) != INVALID_FILE_ATTRIBUTES))
971 VersionSizeSource = GetFileVersionInfoSizeW(source,&zero);
972 VersionSizeTarget = GetFileVersionInfoSizeW(target,&zero);
975 TRACE("SizeTarget %i ... SizeSource %i\n",VersionSizeTarget,
976 VersionSizeSource);
978 if (VersionSizeSource && VersionSizeTarget)
980 LPVOID VersionSource;
981 LPVOID VersionTarget;
982 VS_FIXEDFILEINFO *TargetInfo;
983 VS_FIXEDFILEINFO *SourceInfo;
984 UINT length;
985 static const WCHAR SubBlock[]={'\\',0};
986 DWORD ret;
988 VersionSource = HeapAlloc(GetProcessHeap(),0,VersionSizeSource);
989 VersionTarget = HeapAlloc(GetProcessHeap(),0,VersionSizeTarget);
991 ret = GetFileVersionInfoW(source,0,VersionSizeSource,VersionSource);
992 if (ret)
993 ret = GetFileVersionInfoW(target, 0, VersionSizeTarget,
994 VersionTarget);
996 if (ret)
998 ret = VerQueryValueW(VersionSource, SubBlock,
999 (LPVOID*)&SourceInfo, &length);
1000 if (ret)
1001 ret = VerQueryValueW(VersionTarget, SubBlock,
1002 (LPVOID*)&TargetInfo, &length);
1004 if (ret)
1006 FILEPATHS_W filepaths;
1008 TRACE("Versions: Source %i.%i target %i.%i\n",
1009 SourceInfo->dwFileVersionMS, SourceInfo->dwFileVersionLS,
1010 TargetInfo->dwFileVersionMS, TargetInfo->dwFileVersionLS);
1012 /* used in case of notification */
1013 filepaths.Target = target;
1014 filepaths.Source = source;
1015 filepaths.Win32Error = 0;
1016 filepaths.Flags = 0;
1018 if (TargetInfo->dwFileVersionMS > SourceInfo->dwFileVersionMS)
1020 if (handler)
1021 docopy = handler (context, SPFILENOTIFY_TARGETNEWER, (UINT_PTR)&filepaths, 0);
1022 else
1023 docopy = FALSE;
1025 else if ((TargetInfo->dwFileVersionMS == SourceInfo->dwFileVersionMS)
1026 && (TargetInfo->dwFileVersionLS > SourceInfo->dwFileVersionLS))
1028 if (handler)
1029 docopy = handler (context, SPFILENOTIFY_TARGETNEWER, (UINT_PTR)&filepaths, 0);
1030 else
1031 docopy = FALSE;
1033 else if ((style & SP_COPY_NEWER_ONLY) &&
1034 (TargetInfo->dwFileVersionMS ==
1035 SourceInfo->dwFileVersionMS)
1036 &&(TargetInfo->dwFileVersionLS ==
1037 SourceInfo->dwFileVersionLS))
1039 if (handler)
1040 docopy = handler (context, SPFILENOTIFY_TARGETNEWER, (UINT_PTR)&filepaths, 0);
1041 else
1042 docopy = FALSE;
1046 HeapFree(GetProcessHeap(),0,VersionSource);
1047 HeapFree(GetProcessHeap(),0,VersionTarget);
1050 if (style & (SP_COPY_NOOVERWRITE | SP_COPY_FORCE_NOOVERWRITE))
1052 if (GetFileAttributesW(target) != INVALID_FILE_ATTRIBUTES)
1054 FIXME("Notify user target file exists\n");
1055 docopy = FALSE;
1058 if (style & (SP_COPY_NODECOMP | SP_COPY_LANGUAGEAWARE | SP_COPY_FORCE_IN_USE |
1059 SP_COPY_IN_USE_NEEDS_REBOOT | SP_COPY_NOSKIP | SP_COPY_WARNIFSKIP))
1061 ERR("Unsupported style(s) 0x%x\n",style);
1064 if (docopy)
1066 rc = CopyFileW(source,target,FALSE);
1067 TRACE("Did copy... rc was %i\n",rc);
1070 /* after copy processing */
1071 if (style & SP_COPY_DELETESOURCE)
1073 if (rc)
1074 DeleteFileW(source);
1077 return rc;
1080 /***********************************************************************
1081 * SetupInstallFileExA (SETUPAPI.@)
1083 BOOL WINAPI SetupInstallFileExA( HINF hinf, PINFCONTEXT inf_context, PCSTR source, PCSTR root,
1084 PCSTR dest, DWORD style, PSP_FILE_CALLBACK_A handler, PVOID context, PBOOL in_use )
1086 BOOL ret = FALSE;
1087 struct callback_WtoA_context ctx;
1088 UNICODE_STRING sourceW, rootW, destW;
1090 TRACE("%p %p %s %s %s %x %p %p %p\n", hinf, inf_context, debugstr_a(source), debugstr_a(root),
1091 debugstr_a(dest), style, handler, context, in_use);
1093 sourceW.Buffer = rootW.Buffer = destW.Buffer = NULL;
1094 if (source && !RtlCreateUnicodeStringFromAsciiz( &sourceW, source ))
1096 SetLastError( ERROR_NOT_ENOUGH_MEMORY );
1097 return FALSE;
1099 if (root && !RtlCreateUnicodeStringFromAsciiz( &rootW, root ))
1101 SetLastError( ERROR_NOT_ENOUGH_MEMORY );
1102 goto exit;
1104 if (dest && !RtlCreateUnicodeStringFromAsciiz( &destW, dest ))
1106 SetLastError( ERROR_NOT_ENOUGH_MEMORY );
1107 goto exit;
1110 ctx.orig_context = context;
1111 ctx.orig_handler = handler;
1113 ret = SetupInstallFileExW( hinf, inf_context, sourceW.Buffer, rootW.Buffer, destW.Buffer, style, QUEUE_callback_WtoA, &ctx, in_use );
1115 exit:
1116 RtlFreeUnicodeString( &sourceW );
1117 RtlFreeUnicodeString( &rootW );
1118 RtlFreeUnicodeString( &destW );
1119 return ret;
1122 /***********************************************************************
1123 * SetupInstallFileA (SETUPAPI.@)
1125 BOOL WINAPI SetupInstallFileA( HINF hinf, PINFCONTEXT inf_context, PCSTR source, PCSTR root,
1126 PCSTR dest, DWORD style, PSP_FILE_CALLBACK_A handler, PVOID context )
1128 return SetupInstallFileExA( hinf, inf_context, source, root, dest, style, handler, context, NULL );
1131 /***********************************************************************
1132 * SetupInstallFileExW (SETUPAPI.@)
1134 BOOL WINAPI SetupInstallFileExW( HINF hinf, PINFCONTEXT inf_context, PCWSTR source, PCWSTR root,
1135 PCWSTR dest, DWORD style, PSP_FILE_CALLBACK_W handler, PVOID context, PBOOL in_use )
1137 static const WCHAR CopyFiles[] = {'C','o','p','y','F','i','l','e','s',0};
1139 BOOL ret, absolute = (root && *root && !(style & SP_COPY_SOURCE_ABSOLUTE));
1140 WCHAR *buffer, *p, *inf_source = NULL;
1141 unsigned int len;
1143 TRACE("%p %p %s %s %s %x %p %p %p\n", hinf, inf_context, debugstr_w(source), debugstr_w(root),
1144 debugstr_w(dest), style, handler, context, in_use);
1146 if (in_use) FIXME("no file in use support\n");
1148 if (hinf)
1150 INFCONTEXT ctx;
1152 if (!inf_context)
1154 inf_context = &ctx;
1155 if (!SetupFindFirstLineW( hinf, CopyFiles, NULL, inf_context )) return FALSE;
1157 if (!SetupGetStringFieldW( inf_context, 1, NULL, 0, &len )) return FALSE;
1158 if (!(inf_source = HeapAlloc( GetProcessHeap(), 0, len * sizeof(WCHAR) )))
1160 SetLastError( ERROR_NOT_ENOUGH_MEMORY );
1161 return FALSE;
1163 if (!SetupGetStringFieldW( inf_context, 1, inf_source, len, NULL ))
1165 HeapFree( GetProcessHeap(), 0, inf_source );
1166 return FALSE;
1168 source = inf_source;
1170 else if (!source)
1172 SetLastError( ERROR_INVALID_PARAMETER );
1173 return FALSE;
1176 len = strlenW( source ) + 1;
1177 if (absolute) len += strlenW( root ) + 1;
1179 if (!(p = buffer = HeapAlloc( GetProcessHeap(), 0, len * sizeof(WCHAR) )))
1181 HeapFree( GetProcessHeap(), 0, inf_source );
1182 SetLastError( ERROR_NOT_ENOUGH_MEMORY );
1183 return FALSE;
1186 if (absolute)
1188 strcpyW( buffer, root );
1189 p += strlenW( buffer );
1190 if (p[-1] != '\\') *p++ = '\\';
1192 while (*source == '\\') source++;
1193 strcpyW( p, source );
1195 ret = do_file_copyW( buffer, dest, style, handler, context );
1197 HeapFree( GetProcessHeap(), 0, inf_source );
1198 HeapFree( GetProcessHeap(), 0, buffer );
1199 return ret;
1202 /***********************************************************************
1203 * SetupInstallFileW (SETUPAPI.@)
1205 BOOL WINAPI SetupInstallFileW( HINF hinf, PINFCONTEXT inf_context, PCWSTR source, PCWSTR root,
1206 PCWSTR dest, DWORD style, PSP_FILE_CALLBACK_W handler, PVOID context )
1208 return SetupInstallFileExW( hinf, inf_context, source, root, dest, style, handler, context, NULL );
1211 /***********************************************************************
1212 * SetupCommitFileQueueW (SETUPAPI.@)
1214 BOOL WINAPI SetupCommitFileQueueW( HWND owner, HSPFILEQ handle, PSP_FILE_CALLBACK_W handler,
1215 PVOID context )
1217 struct file_queue *queue = handle;
1218 struct file_op *op;
1219 BOOL result = FALSE;
1220 FILEPATHS_W paths;
1221 UINT op_result;
1223 paths.Source = paths.Target = NULL;
1225 if (!queue->copy_queue.count && !queue->delete_queue.count && !queue->rename_queue.count)
1226 return TRUE; /* nothing to do */
1228 if (!handler( context, SPFILENOTIFY_STARTQUEUE, (UINT_PTR)owner, 0 )) return FALSE;
1230 /* perform deletes */
1232 if (queue->delete_queue.count)
1234 if (!(handler( context, SPFILENOTIFY_STARTSUBQUEUE, FILEOP_DELETE,
1235 queue->delete_queue.count ))) goto done;
1236 for (op = queue->delete_queue.head; op; op = op->next)
1238 build_filepathsW( op, &paths );
1239 op_result = handler( context, SPFILENOTIFY_STARTDELETE, (UINT_PTR)&paths, FILEOP_DELETE);
1240 if (op_result == FILEOP_ABORT) goto done;
1241 while (op_result == FILEOP_DOIT)
1243 TRACE( "deleting file %s\n", debugstr_w(paths.Target) );
1244 if (DeleteFileW( paths.Target )) break; /* success */
1245 paths.Win32Error = GetLastError();
1246 op_result = handler( context, SPFILENOTIFY_DELETEERROR, (UINT_PTR)&paths, 0 );
1247 if (op_result == FILEOP_ABORT) goto done;
1249 handler( context, SPFILENOTIFY_ENDDELETE, (UINT_PTR)&paths, 0 );
1251 handler( context, SPFILENOTIFY_ENDSUBQUEUE, FILEOP_DELETE, 0 );
1254 /* perform renames */
1256 if (queue->rename_queue.count)
1258 if (!(handler( context, SPFILENOTIFY_STARTSUBQUEUE, FILEOP_RENAME,
1259 queue->rename_queue.count ))) goto done;
1260 for (op = queue->rename_queue.head; op; op = op->next)
1262 build_filepathsW( op, &paths );
1263 op_result = handler( context, SPFILENOTIFY_STARTRENAME, (UINT_PTR)&paths, FILEOP_RENAME);
1264 if (op_result == FILEOP_ABORT) goto done;
1265 while (op_result == FILEOP_DOIT)
1267 TRACE( "renaming file %s -> %s\n",
1268 debugstr_w(paths.Source), debugstr_w(paths.Target) );
1269 if (MoveFileW( paths.Source, paths.Target )) break; /* success */
1270 paths.Win32Error = GetLastError();
1271 op_result = handler( context, SPFILENOTIFY_RENAMEERROR, (UINT_PTR)&paths, 0 );
1272 if (op_result == FILEOP_ABORT) goto done;
1274 handler( context, SPFILENOTIFY_ENDRENAME, (UINT_PTR)&paths, 0 );
1276 handler( context, SPFILENOTIFY_ENDSUBQUEUE, FILEOP_RENAME, 0 );
1279 /* perform copies */
1281 if (queue->copy_queue.count)
1283 if (!(handler( context, SPFILENOTIFY_STARTSUBQUEUE, FILEOP_COPY,
1284 queue->copy_queue.count ))) goto done;
1285 for (op = queue->copy_queue.head; op; op = op->next)
1287 WCHAR newpath[MAX_PATH];
1289 build_filepathsW( op, &paths );
1290 op_result = handler( context, SPFILENOTIFY_STARTCOPY, (UINT_PTR)&paths, FILEOP_COPY );
1291 if (op_result == FILEOP_ABORT) goto done;
1292 if (op_result == FILEOP_NEWPATH) op_result = FILEOP_DOIT;
1293 while (op_result == FILEOP_DOIT || op_result == FILEOP_NEWPATH)
1295 TRACE( "copying file %s -> %s\n",
1296 debugstr_w( op_result == FILEOP_NEWPATH ? newpath : paths.Source ),
1297 debugstr_w(paths.Target) );
1298 if (op->dst_path)
1300 if (!create_full_pathW( op->dst_path ))
1302 paths.Win32Error = GetLastError();
1303 op_result = handler( context, SPFILENOTIFY_COPYERROR,
1304 (UINT_PTR)&paths, (UINT_PTR)newpath );
1305 if (op_result == FILEOP_ABORT) goto done;
1308 if (do_file_copyW( op_result == FILEOP_NEWPATH ? newpath : paths.Source,
1309 paths.Target, op->style, handler, context )) break; /* success */
1310 /* try to extract it from the cabinet file */
1311 if (op->src_tag)
1313 if (extract_cabinet_file( op->src_tag, op->src_root,
1314 paths.Source, paths.Target )) break;
1316 paths.Win32Error = GetLastError();
1317 op_result = handler( context, SPFILENOTIFY_COPYERROR,
1318 (UINT_PTR)&paths, (UINT_PTR)newpath );
1319 if (op_result == FILEOP_ABORT) goto done;
1321 handler( context, SPFILENOTIFY_ENDCOPY, (UINT_PTR)&paths, 0 );
1323 handler( context, SPFILENOTIFY_ENDSUBQUEUE, FILEOP_COPY, 0 );
1327 result = TRUE;
1329 done:
1330 handler( context, SPFILENOTIFY_ENDQUEUE, result, 0 );
1331 HeapFree( GetProcessHeap(), 0, (void *)paths.Source );
1332 HeapFree( GetProcessHeap(), 0, (void *)paths.Target );
1333 return result;
1337 /***********************************************************************
1338 * SetupScanFileQueueA (SETUPAPI.@)
1340 BOOL WINAPI SetupScanFileQueueA( HSPFILEQ handle, DWORD flags, HWND window,
1341 PSP_FILE_CALLBACK_A handler, PVOID context, PDWORD result )
1343 struct callback_WtoA_context ctx;
1345 TRACE("%p %x %p %p %p %p\n", handle, flags, window, handler, context, result);
1347 ctx.orig_context = context;
1348 ctx.orig_handler = handler;
1350 return SetupScanFileQueueW( handle, flags, window, QUEUE_callback_WtoA, &ctx, result );
1354 /***********************************************************************
1355 * SetupScanFileQueueW (SETUPAPI.@)
1357 BOOL WINAPI SetupScanFileQueueW( HSPFILEQ handle, DWORD flags, HWND window,
1358 PSP_FILE_CALLBACK_W handler, PVOID context, PDWORD result )
1360 struct file_queue *queue = handle;
1361 struct file_op *op;
1362 FILEPATHS_W paths;
1363 UINT notification = 0;
1364 BOOL ret = FALSE;
1366 TRACE("%p %x %p %p %p %p\n", handle, flags, window, handler, context, result);
1368 if (!queue->copy_queue.count) return TRUE;
1370 if (flags & SPQ_SCAN_USE_CALLBACK) notification = SPFILENOTIFY_QUEUESCAN;
1371 else if (flags & SPQ_SCAN_USE_CALLBACKEX) notification = SPFILENOTIFY_QUEUESCAN_EX;
1373 if (flags & ~(SPQ_SCAN_USE_CALLBACK | SPQ_SCAN_USE_CALLBACKEX))
1375 FIXME("flags %x not fully implemented\n", flags);
1378 paths.Source = paths.Target = NULL;
1380 for (op = queue->copy_queue.head; op; op = op->next)
1382 build_filepathsW( op, &paths );
1383 switch (notification)
1385 case SPFILENOTIFY_QUEUESCAN:
1386 /* FIXME: handle delay flag */
1387 if (handler( context, notification, (UINT_PTR)paths.Target, 0 )) goto done;
1388 break;
1389 case SPFILENOTIFY_QUEUESCAN_EX:
1390 if (handler( context, notification, (UINT_PTR)&paths, 0 )) goto done;
1391 break;
1392 default:
1393 ret = TRUE; goto done;
1397 ret = TRUE;
1399 done:
1400 if (result) *result = 0;
1401 HeapFree( GetProcessHeap(), 0, (void *)paths.Source );
1402 HeapFree( GetProcessHeap(), 0, (void *)paths.Target );
1403 return ret;
1407 /***********************************************************************
1408 * SetupGetFileQueueCount (SETUPAPI.@)
1410 BOOL WINAPI SetupGetFileQueueCount( HSPFILEQ handle, UINT op, PUINT result )
1412 struct file_queue *queue = handle;
1414 switch(op)
1416 case FILEOP_COPY:
1417 *result = queue->copy_queue.count;
1418 return TRUE;
1419 case FILEOP_RENAME:
1420 *result = queue->rename_queue.count;
1421 return TRUE;
1422 case FILEOP_DELETE:
1423 *result = queue->delete_queue.count;
1424 return TRUE;
1426 return FALSE;
1430 /***********************************************************************
1431 * SetupGetFileQueueFlags (SETUPAPI.@)
1433 BOOL WINAPI SetupGetFileQueueFlags( HSPFILEQ handle, PDWORD flags )
1435 struct file_queue *queue = handle;
1436 *flags = queue->flags;
1437 return TRUE;
1441 /***********************************************************************
1442 * SetupSetFileQueueFlags (SETUPAPI.@)
1444 BOOL WINAPI SetupSetFileQueueFlags( HSPFILEQ handle, DWORD mask, DWORD flags )
1446 struct file_queue *queue = handle;
1447 queue->flags = (queue->flags & ~mask) | flags;
1448 return TRUE;
1452 /***********************************************************************
1453 * SetupSetFileQueueAlternatePlatformA (SETUPAPI.@)
1455 BOOL WINAPI SetupSetFileQueueAlternatePlatformA(HSPFILEQ handle, PSP_ALTPLATFORM_INFO platform, PCSTR catalogfile)
1457 FIXME("(%p, %p, %s) stub!\n", handle, platform, debugstr_a(catalogfile));
1458 return FALSE;
1462 /***********************************************************************
1463 * SetupSetFileQueueAlternatePlatformW (SETUPAPI.@)
1465 BOOL WINAPI SetupSetFileQueueAlternatePlatformW(HSPFILEQ handle, PSP_ALTPLATFORM_INFO platform, PCWSTR catalogfile)
1467 FIXME("(%p, %p, %s) stub!\n", handle, platform, debugstr_w(catalogfile));
1468 return FALSE;
1472 /***********************************************************************
1473 * SetupInitDefaultQueueCallback (SETUPAPI.@)
1475 PVOID WINAPI SetupInitDefaultQueueCallback( HWND owner )
1477 return SetupInitDefaultQueueCallbackEx( owner, 0, 0, 0, NULL );
1481 /***********************************************************************
1482 * SetupInitDefaultQueueCallbackEx (SETUPAPI.@)
1484 PVOID WINAPI SetupInitDefaultQueueCallbackEx( HWND owner, HWND progress, UINT msg,
1485 DWORD reserved1, PVOID reserved2 )
1487 struct default_callback_context *context;
1489 if ((context = HeapAlloc( GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*context) )))
1491 context->magic = 0x43515053; /* "SPQC" */
1492 context->owner = owner;
1493 context->progress = progress;
1494 context->message = msg;
1496 return context;
1500 /***********************************************************************
1501 * SetupTermDefaultQueueCallback (SETUPAPI.@)
1503 void WINAPI SetupTermDefaultQueueCallback( PVOID context )
1505 HeapFree( GetProcessHeap(), 0, context );
1509 /***********************************************************************
1510 * SetupDefaultQueueCallbackA (SETUPAPI.@)
1512 UINT WINAPI SetupDefaultQueueCallbackA( PVOID context, UINT notification,
1513 UINT_PTR param1, UINT_PTR param2 )
1515 FILEPATHS_A *paths = (FILEPATHS_A *)param1;
1516 struct default_callback_context *ctx = context;
1518 switch(notification)
1520 case SPFILENOTIFY_STARTQUEUE:
1521 TRACE( "start queue\n" );
1522 return TRUE;
1523 case SPFILENOTIFY_ENDQUEUE:
1524 TRACE( "end queue\n" );
1525 return 0;
1526 case SPFILENOTIFY_STARTSUBQUEUE:
1527 TRACE( "start subqueue %ld count %ld\n", param1, param2 );
1528 return TRUE;
1529 case SPFILENOTIFY_ENDSUBQUEUE:
1530 TRACE( "end subqueue %ld\n", param1 );
1531 return 0;
1532 case SPFILENOTIFY_STARTDELETE:
1533 TRACE( "start delete %s\n", debugstr_a(paths->Target) );
1534 return FILEOP_DOIT;
1535 case SPFILENOTIFY_ENDDELETE:
1536 TRACE( "end delete %s\n", debugstr_a(paths->Target) );
1537 return 0;
1538 case SPFILENOTIFY_DELETEERROR:
1539 /*Windows Ignores attempts to delete files / folders which do not exist*/
1540 if ((paths->Win32Error != ERROR_FILE_NOT_FOUND) && (paths->Win32Error != ERROR_PATH_NOT_FOUND))
1541 SetupDeleteErrorA(ctx->owner, NULL, paths->Target, paths->Win32Error, 0);
1542 return FILEOP_SKIP;
1543 case SPFILENOTIFY_STARTRENAME:
1544 TRACE( "start rename %s -> %s\n", debugstr_a(paths->Source), debugstr_a(paths->Target) );
1545 return FILEOP_DOIT;
1546 case SPFILENOTIFY_ENDRENAME:
1547 TRACE( "end rename %s -> %s\n", debugstr_a(paths->Source), debugstr_a(paths->Target) );
1548 return 0;
1549 case SPFILENOTIFY_RENAMEERROR:
1550 SetupRenameErrorA(ctx->owner, NULL, paths->Source, paths->Target, paths->Win32Error, 0);
1551 return FILEOP_SKIP;
1552 case SPFILENOTIFY_STARTCOPY:
1553 TRACE( "start copy %s -> %s\n", debugstr_a(paths->Source), debugstr_a(paths->Target) );
1554 return FILEOP_DOIT;
1555 case SPFILENOTIFY_ENDCOPY:
1556 TRACE( "end copy %s -> %s\n", debugstr_a(paths->Source), debugstr_a(paths->Target) );
1557 return 0;
1558 case SPFILENOTIFY_COPYERROR:
1559 ERR( "copy error %d %s -> %s\n", paths->Win32Error,
1560 debugstr_a(paths->Source), debugstr_a(paths->Target) );
1561 return FILEOP_SKIP;
1562 case SPFILENOTIFY_NEEDMEDIA:
1563 TRACE( "need media\n" );
1564 return FILEOP_SKIP;
1565 default:
1566 FIXME( "notification %d params %lx,%lx\n", notification, param1, param2 );
1567 break;
1569 return 0;
1573 /***********************************************************************
1574 * SetupDefaultQueueCallbackW (SETUPAPI.@)
1576 UINT WINAPI SetupDefaultQueueCallbackW( PVOID context, UINT notification,
1577 UINT_PTR param1, UINT_PTR param2 )
1579 FILEPATHS_W *paths = (FILEPATHS_W *)param1;
1580 struct default_callback_context *ctx = context;
1582 switch(notification)
1584 case SPFILENOTIFY_STARTQUEUE:
1585 TRACE( "start queue\n" );
1586 return TRUE;
1587 case SPFILENOTIFY_ENDQUEUE:
1588 TRACE( "end queue\n" );
1589 return 0;
1590 case SPFILENOTIFY_STARTSUBQUEUE:
1591 TRACE( "start subqueue %ld count %ld\n", param1, param2 );
1592 return TRUE;
1593 case SPFILENOTIFY_ENDSUBQUEUE:
1594 TRACE( "end subqueue %ld\n", param1 );
1595 return 0;
1596 case SPFILENOTIFY_STARTDELETE:
1597 TRACE( "start delete %s\n", debugstr_w(paths->Target) );
1598 return FILEOP_DOIT;
1599 case SPFILENOTIFY_ENDDELETE:
1600 TRACE( "end delete %s\n", debugstr_w(paths->Target) );
1601 return 0;
1602 case SPFILENOTIFY_DELETEERROR:
1603 /*Windows Ignores attempts to delete files / folders which do not exist*/
1604 if ((paths->Win32Error != ERROR_FILE_NOT_FOUND) && (paths->Win32Error != ERROR_PATH_NOT_FOUND))
1605 SetupDeleteErrorW(ctx->owner, NULL, paths->Target, paths->Win32Error, 0);
1606 return FILEOP_SKIP;
1607 case SPFILENOTIFY_STARTRENAME:
1608 SetupRenameErrorW(ctx->owner, NULL, paths->Source, paths->Target, paths->Win32Error, 0);
1609 return FILEOP_DOIT;
1610 case SPFILENOTIFY_ENDRENAME:
1611 TRACE( "end rename %s -> %s\n", debugstr_w(paths->Source), debugstr_w(paths->Target) );
1612 return 0;
1613 case SPFILENOTIFY_RENAMEERROR:
1614 ERR( "rename error %d %s -> %s\n", paths->Win32Error,
1615 debugstr_w(paths->Source), debugstr_w(paths->Target) );
1616 return FILEOP_SKIP;
1617 case SPFILENOTIFY_STARTCOPY:
1618 TRACE( "start copy %s -> %s\n", debugstr_w(paths->Source), debugstr_w(paths->Target) );
1619 return FILEOP_DOIT;
1620 case SPFILENOTIFY_ENDCOPY:
1621 TRACE( "end copy %s -> %s\n", debugstr_w(paths->Source), debugstr_w(paths->Target) );
1622 return 0;
1623 case SPFILENOTIFY_COPYERROR:
1624 ERR( "copy error %d %s -> %s\n", paths->Win32Error,
1625 debugstr_w(paths->Source), debugstr_w(paths->Target) );
1626 return FILEOP_SKIP;
1627 case SPFILENOTIFY_NEEDMEDIA:
1628 TRACE( "need media\n" );
1629 return FILEOP_SKIP;
1630 default:
1631 FIXME( "notification %d params %lx,%lx\n", notification, param1, param2 );
1632 break;
1634 return 0;
1637 /***********************************************************************
1638 * SetupDeleteErrorA (SETUPAPI.@)
1641 UINT WINAPI SetupDeleteErrorA( HWND parent, PCSTR dialogTitle, PCSTR file,
1642 UINT w32error, DWORD style)
1644 FIXME( "stub: (Error Number %d when attempting to delete %s)\n",
1645 w32error, debugstr_a(file) );
1646 return DPROMPT_SKIPFILE;
1649 /***********************************************************************
1650 * SetupDeleteErrorW (SETUPAPI.@)
1653 UINT WINAPI SetupDeleteErrorW( HWND parent, PCWSTR dialogTitle, PCWSTR file,
1654 UINT w32error, DWORD style)
1656 FIXME( "stub: (Error Number %d when attempting to delete %s)\n",
1657 w32error, debugstr_w(file) );
1658 return DPROMPT_SKIPFILE;
1661 /***********************************************************************
1662 * SetupRenameErrorA (SETUPAPI.@)
1665 UINT WINAPI SetupRenameErrorA( HWND parent, PCSTR dialogTitle, PCSTR source,
1666 PCSTR target, UINT w32error, DWORD style)
1668 FIXME( "stub: (Error Number %d when attempting to rename %s to %s)\n",
1669 w32error, debugstr_a(source), debugstr_a(target));
1670 return DPROMPT_SKIPFILE;
1673 /***********************************************************************
1674 * SetupRenameErrorW (SETUPAPI.@)
1677 UINT WINAPI SetupRenameErrorW( HWND parent, PCWSTR dialogTitle, PCWSTR source,
1678 PCWSTR target, UINT w32error, DWORD style)
1680 FIXME( "stub: (Error Number %d when attempting to rename %s to %s)\n",
1681 w32error, debugstr_w(source), debugstr_w(target));
1682 return DPROMPT_SKIPFILE;
1686 /***********************************************************************
1687 * SetupCopyErrorA (SETUPAPI.@)
1690 UINT WINAPI SetupCopyErrorA( HWND parent, PCSTR dialogTitle, PCSTR diskname,
1691 PCSTR sourcepath, PCSTR sourcefile, PCSTR targetpath,
1692 UINT w32error, DWORD style, PSTR pathbuffer,
1693 DWORD buffersize, PDWORD requiredsize)
1695 FIXME( "stub: (Error Number %d when attempting to copy file %s from %s to %s)\n",
1696 w32error, debugstr_a(sourcefile), debugstr_a(sourcepath) ,debugstr_a(targetpath));
1697 return DPROMPT_SKIPFILE;
1700 /***********************************************************************
1701 * SetupCopyErrorW (SETUPAPI.@)
1704 UINT WINAPI SetupCopyErrorW( HWND parent, PCWSTR dialogTitle, PCWSTR diskname,
1705 PCWSTR sourcepath, PCWSTR sourcefile, PCWSTR targetpath,
1706 UINT w32error, DWORD style, PWSTR pathbuffer,
1707 DWORD buffersize, PDWORD requiredsize)
1709 FIXME( "stub: (Error Number %d when attempting to copy file %s from %s to %s)\n",
1710 w32error, debugstr_w(sourcefile), debugstr_w(sourcepath) ,debugstr_w(targetpath));
1711 return DPROMPT_SKIPFILE;
1714 /***********************************************************************
1715 * pSetupGetQueueFlags (SETUPAPI.@)
1717 DWORD WINAPI pSetupGetQueueFlags( HSPFILEQ handle )
1719 struct file_queue *queue = handle;
1720 return queue->flags;
1723 /***********************************************************************
1724 * pSetupSetQueueFlags (SETUPAPI.@)
1726 BOOL WINAPI pSetupSetQueueFlags( HSPFILEQ handle, DWORD flags )
1728 struct file_queue *queue = handle;
1729 queue->flags = flags;
1730 return TRUE;