windows.applicationmodel/tests: Use PathRemoveFileSpecW() instead of PathCchRemoveFil...
[wine.git] / dlls / setupapi / queue.c
blob40e106fffcd68e4bacdd2fa774b31ad59ecec396
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>
22 #include <stdlib.h>
24 #include "windef.h"
25 #include "winbase.h"
26 #include "winreg.h"
27 #include "winternl.h"
28 #include "winerror.h"
29 #include "wingdi.h"
30 #include "winuser.h"
31 #include "winnls.h"
32 #include "setupapi.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 source_media
53 WCHAR root[MAX_PATH];
54 WCHAR *desc, *tag;
55 BOOL resolved;
56 BOOL cabinet;
59 struct file_op
61 struct file_op *next;
62 UINT style;
63 WCHAR *src_path;
64 WCHAR *src_file;
65 WCHAR *dst_path;
66 WCHAR *dst_file;
67 struct source_media *media;
70 struct file_op_queue
72 struct file_op *head;
73 struct file_op *tail;
74 unsigned int count;
77 struct file_queue
79 DWORD magic;
80 struct file_op_queue copy_queue;
81 struct file_op_queue delete_queue;
82 struct file_op_queue rename_queue;
83 DWORD flags;
84 struct source_media **sources;
85 unsigned int source_count;
88 #define FILE_QUEUE_MAGIC 0x21514653
90 /* append a file operation to a queue */
91 static inline void queue_file_op( struct file_op_queue *queue, struct file_op *op )
93 op->next = NULL;
94 if (queue->tail) queue->tail->next = op;
95 else queue->head = op;
96 queue->tail = op;
97 queue->count++;
100 /* free all the file operations on a given queue */
101 static void free_file_op_queue( struct file_op_queue *queue )
103 struct file_op *t, *op = queue->head;
105 while( op )
107 free( op->src_path );
108 free( op->src_file );
109 free( op->dst_path );
110 if (op->dst_file != op->src_file) free( op->dst_file );
111 t = op;
112 op = op->next;
113 free( t );
117 /* concat 3 strings to make a path, handling separators correctly */
118 static void concat_W( WCHAR *buffer, const WCHAR *src1, const WCHAR *src2, const WCHAR *src3 )
120 *buffer = 0;
121 if (src1 && *src1)
123 lstrcpyW( buffer, src1 );
124 buffer += lstrlenW(buffer );
125 if (buffer[-1] != '\\') *buffer++ = '\\';
126 *buffer = 0;
127 if (src2) while (*src2 == '\\') src2++;
130 if (src2)
132 lstrcpyW( buffer, src2 );
133 buffer += lstrlenW(buffer );
134 if (buffer[-1] != '\\') *buffer++ = '\\';
135 *buffer = 0;
136 if (src3) while (*src3 == '\\') src3++;
139 if (src3)
140 lstrcpyW( buffer, src3 );
144 /***********************************************************************
145 * build_filepathsW
147 * Build a FILEPATHS_W structure for a given file operation.
149 static BOOL build_filepathsW( const struct file_op *op, FILEPATHS_W *paths )
151 unsigned int src_len = 1, dst_len = 1;
152 WCHAR *source = (PWSTR)paths->Source, *target = (PWSTR)paths->Target;
154 if (!op->src_file || op->src_file[0] != '@')
156 if (op->media) src_len += lstrlenW(op->media->root) + 1;
157 if (op->src_path) src_len += lstrlenW(op->src_path) + 1;
159 if (op->src_file) src_len += lstrlenW(op->src_file) + 1;
160 if (op->dst_path) dst_len += lstrlenW(op->dst_path) + 1;
161 if (op->dst_file) dst_len += lstrlenW(op->dst_file) + 1;
162 src_len *= sizeof(WCHAR);
163 dst_len *= sizeof(WCHAR);
165 if (!source || HeapSize( GetProcessHeap(), 0, source ) < src_len )
167 HeapFree( GetProcessHeap(), 0, source );
168 paths->Source = source = HeapAlloc( GetProcessHeap(), 0, src_len );
170 if (!target || HeapSize( GetProcessHeap(), 0, target ) < dst_len )
172 HeapFree( GetProcessHeap(), 0, target );
173 paths->Target = target = HeapAlloc( GetProcessHeap(), 0, dst_len );
175 if (!source || !target) return FALSE;
176 if (!op->src_file || op->src_file[0] != '@')
177 concat_W( source, op->media ? op->media->root : NULL, op->src_path, op->src_file );
178 else
179 lstrcpyW( source, op->src_file );
180 concat_W( target, NULL, op->dst_path, op->dst_file );
181 paths->Win32Error = 0;
182 paths->Flags = 0;
183 return TRUE;
187 /***********************************************************************
188 * QUEUE_callback_WtoA
190 * Map a file callback parameters from W to A and call the A callback.
192 UINT CALLBACK QUEUE_callback_WtoA( void *context, UINT notification,
193 UINT_PTR param1, UINT_PTR param2 )
195 struct callback_WtoA_context *callback_ctx = context;
196 char buffer[MAX_PATH];
197 UINT ret;
198 UINT_PTR old_param2 = param2;
200 switch(notification)
202 case SPFILENOTIFY_COPYERROR:
203 buffer[0] = 0;
204 param2 = (UINT_PTR)buffer;
205 /* fall through */
206 case SPFILENOTIFY_STARTDELETE:
207 case SPFILENOTIFY_ENDDELETE:
208 case SPFILENOTIFY_DELETEERROR:
209 case SPFILENOTIFY_STARTRENAME:
210 case SPFILENOTIFY_ENDRENAME:
211 case SPFILENOTIFY_RENAMEERROR:
212 case SPFILENOTIFY_STARTCOPY:
213 case SPFILENOTIFY_ENDCOPY:
214 case SPFILENOTIFY_QUEUESCAN_EX:
216 FILEPATHS_W *pathsW = (FILEPATHS_W *)param1;
217 FILEPATHS_A pathsA;
219 pathsA.Source = strdupWtoA( pathsW->Source );
220 pathsA.Target = strdupWtoA( pathsW->Target );
221 pathsA.Win32Error = pathsW->Win32Error;
222 pathsA.Flags = pathsW->Flags;
223 ret = callback_ctx->orig_handler( callback_ctx->orig_context, notification,
224 (UINT_PTR)&pathsA, param2 );
225 HeapFree( GetProcessHeap(), 0, (void *)pathsA.Source );
226 HeapFree( GetProcessHeap(), 0, (void *)pathsA.Target );
228 if (notification == SPFILENOTIFY_COPYERROR)
229 MultiByteToWideChar( CP_ACP, 0, buffer, -1, (WCHAR *)old_param2, MAX_PATH );
230 break;
232 case SPFILENOTIFY_STARTREGISTRATION:
233 case SPFILENOTIFY_ENDREGISTRATION:
235 SP_REGISTER_CONTROL_STATUSW *statusW = (SP_REGISTER_CONTROL_STATUSW *)param1;
236 SP_REGISTER_CONTROL_STATUSA statusA;
238 statusA.cbSize = sizeof(statusA);
239 statusA.FileName = strdupWtoA( statusW->FileName );
240 statusA.Win32Error = statusW->Win32Error;
241 statusA.FailureCode = statusW->FailureCode;
242 ret = callback_ctx->orig_handler( callback_ctx->orig_context, notification,
243 (UINT_PTR)&statusA, param2 );
244 free( (char *)statusA.FileName );
246 break;
248 case SPFILENOTIFY_QUEUESCAN:
250 LPWSTR targetW = (LPWSTR)param1;
251 LPSTR target = strdupWtoA( targetW );
253 ret = callback_ctx->orig_handler( callback_ctx->orig_context, notification,
254 (UINT_PTR)target, param2 );
255 free( target );
257 break;
259 case SPFILENOTIFY_NEEDMEDIA:
261 const SOURCE_MEDIA_W *mediaW = (const SOURCE_MEDIA_W *)param1;
262 char path[MAX_PATH];
263 SOURCE_MEDIA_A mediaA;
265 mediaA.Tagfile = strdupWtoA(mediaW->Tagfile);
266 mediaA.Description = strdupWtoA(mediaW->Description);
267 mediaA.SourcePath = strdupWtoA(mediaW->SourcePath);
268 mediaA.SourceFile = strdupWtoA(mediaW->SourceFile);
269 mediaA.Flags = mediaW->Flags;
270 path[0] = 0;
272 ret = callback_ctx->orig_handler(callback_ctx->orig_context, notification,
273 (UINT_PTR)&mediaA, (UINT_PTR)&path);
274 MultiByteToWideChar(CP_ACP, 0, path, -1, (WCHAR *)param2, MAX_PATH);
276 free((char *)mediaA.Tagfile);
277 free((char *)mediaA.Description);
278 free((char *)mediaA.SourcePath);
279 free((char *)mediaA.SourceFile);
280 break;
282 case SPFILENOTIFY_STARTQUEUE:
283 case SPFILENOTIFY_ENDQUEUE:
284 case SPFILENOTIFY_STARTSUBQUEUE:
285 case SPFILENOTIFY_ENDSUBQUEUE:
286 default:
287 ret = callback_ctx->orig_handler( callback_ctx->orig_context, notification, param1, param2 );
288 break;
290 return ret;
293 static void get_source_info( HINF hinf, const WCHAR *src_file, SP_FILE_COPY_PARAMS_W *params,
294 WCHAR *src_root, WCHAR *src_path)
296 INFCONTEXT file_ctx, disk_ctx;
297 INT id, diskid;
298 DWORD len;
300 /* find the SourceDisksFiles entry */
301 if (!SetupFindFirstLineW( hinf, L"SourceDisksFiles", src_file, &file_ctx )) return;
302 if (!SetupGetIntField( &file_ctx, 1, &diskid )) return;
304 /* now find the diskid in the SourceDisksNames section */
305 if (!SetupFindFirstLineW( hinf, L"SourceDisksNames", NULL, &disk_ctx )) return;
306 for (;;)
308 if (SetupGetIntField( &disk_ctx, 0, &id ) && (id == diskid)) break;
309 if (!SetupFindNextLine( &disk_ctx, &disk_ctx )) return;
312 if (SetupGetStringFieldW( &disk_ctx, 1, NULL, 0, &len ) && len > sizeof(WCHAR)
313 && (params->SourceDescription = malloc( len * sizeof(WCHAR) )))
314 SetupGetStringFieldW( &disk_ctx, 1, (WCHAR *)params->SourceDescription, len, NULL );
316 if (SetupGetStringFieldW( &disk_ctx, 2, NULL, 0, &len ) && len > sizeof(WCHAR)
317 && (params->SourceTagfile = malloc( len * sizeof(WCHAR) )))
318 SetupGetStringFieldW( &disk_ctx, 2, (WCHAR *)params->SourceTagfile, len, NULL );
320 if (SetupGetStringFieldW( &disk_ctx, 4, NULL, 0, &len ) && len > sizeof(WCHAR)
321 && len < MAX_PATH - lstrlenW( src_root ) - 1)
323 lstrcatW( src_root, L"\\" );
324 SetupGetStringFieldW( &disk_ctx, 4, src_root + lstrlenW( src_root ),
325 MAX_PATH - lstrlenW( src_root ), NULL );
328 if (SetupGetStringFieldW( &file_ctx, 2, NULL, 0, &len ) && len > sizeof(WCHAR) && len < MAX_PATH)
330 SetupGetStringFieldW( &file_ctx, 2, src_path, MAX_PATH, NULL );
331 params->SourcePath = src_path;
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 INFCONTEXT context;
343 WCHAR systemdir[MAX_PATH], *dir;
344 BOOL ret;
346 if (!section || !(ret = SetupFindFirstLineW( hinf, L"DestinationDirs", section, &context )))
347 ret = SetupFindFirstLineW( hinf, L"DestinationDirs", L"DefaultDestDir", &context );
349 if (ret && (dir = PARSER_get_dest_dir( &context )))
350 return dir;
352 GetSystemDirectoryW( systemdir, MAX_PATH );
353 return wcsdup( systemdir );
356 struct extract_cab_ctx
358 const WCHAR *src;
359 const WCHAR *dst;
362 static UINT WINAPI extract_cab_cb( void *arg, UINT message, UINT_PTR param1, UINT_PTR param2 )
364 struct extract_cab_ctx *ctx = arg;
366 switch (message)
368 case SPFILENOTIFY_FILEINCABINET:
370 FILE_IN_CABINET_INFO_W *info = (FILE_IN_CABINET_INFO_W *)param1;
371 const WCHAR *filename;
373 if ((filename = wcsrchr( info->NameInCabinet, '\\' )))
374 filename++;
375 else
376 filename = info->NameInCabinet;
378 if (lstrcmpiW( filename, ctx->src ))
379 return FILEOP_SKIP;
381 lstrcpyW( info->FullTargetName, ctx->dst );
382 return FILEOP_DOIT;
384 case SPFILENOTIFY_FILEEXTRACTED:
386 const FILEPATHS_W *paths = (const FILEPATHS_W *)param1;
387 return paths->Win32Error;
389 case SPFILENOTIFY_NEEDNEWCABINET:
391 const CABINET_INFO_W *info = (const CABINET_INFO_W *)param1;
392 lstrcpyW( (WCHAR *)param2, info->CabinetPath );
393 return ERROR_SUCCESS;
395 case SPFILENOTIFY_CABINETINFO:
396 return 0;
397 default:
398 FIXME("Unexpected message %#x.\n", message);
399 return 0;
403 /***********************************************************************
404 * extract_cabinet_file
406 * Extract a file from a .cab file.
408 static BOOL extract_cabinet_file( const WCHAR *cabinet, const WCHAR *root,
409 const WCHAR *src, const WCHAR *dst )
411 struct extract_cab_ctx ctx = {src, dst};
412 int len = lstrlenW( cabinet );
413 WCHAR path[MAX_PATH];
415 /* make sure the cabinet file has a .cab extension */
416 if (len <= 4 || wcsicmp( cabinet + len - 4, L".cab" )) return FALSE;
418 lstrcpyW(path, root);
419 lstrcatW(path, L"\\" );
420 lstrcatW(path, cabinet);
422 return SetupIterateCabinetW( path, 0, extract_cab_cb, &ctx );
425 /***********************************************************************
426 * SetupOpenFileQueue (SETUPAPI.@)
428 HSPFILEQ WINAPI SetupOpenFileQueue(void)
430 struct file_queue *queue;
432 if (!(queue = calloc( 1, sizeof(*queue) )))
433 return INVALID_HANDLE_VALUE;
434 queue->magic = FILE_QUEUE_MAGIC;
435 return queue;
439 /***********************************************************************
440 * SetupCloseFileQueue (SETUPAPI.@)
442 BOOL WINAPI SetupCloseFileQueue( HSPFILEQ handle )
444 struct file_queue *queue = handle;
445 unsigned int i;
447 /* Windows XP DDK installer passes the handle returned from
448 * SetupInitDefaultQueueCallback() to this function. */
449 if (queue->magic != FILE_QUEUE_MAGIC)
451 SetLastError(ERROR_INVALID_HANDLE);
452 return FALSE;
455 free_file_op_queue( &queue->copy_queue );
456 free_file_op_queue( &queue->rename_queue );
457 free_file_op_queue( &queue->delete_queue );
458 for (i = 0; i < queue->source_count; ++i)
460 free( queue->sources[i]->desc );
461 free( queue->sources[i]->tag );
462 free( queue->sources[i] );
464 free( queue->sources );
465 free( queue );
466 return TRUE;
470 /***********************************************************************
471 * SetupQueueCopyIndirectA (SETUPAPI.@)
473 BOOL WINAPI SetupQueueCopyIndirectA( SP_FILE_COPY_PARAMS_A *paramsA )
475 SP_FILE_COPY_PARAMS_W paramsW;
476 BOOL ret;
478 paramsW.cbSize = sizeof(paramsW);
479 paramsW.QueueHandle = paramsA->QueueHandle;
480 paramsW.SourceRootPath = strdupAtoW( paramsA->SourceRootPath );
481 paramsW.SourcePath = strdupAtoW( paramsA->SourcePath );
482 paramsW.SourceFilename = strdupAtoW( paramsA->SourceFilename );
483 paramsW.SourceDescription = strdupAtoW( paramsA->SourceDescription );
484 paramsW.SourceTagfile = strdupAtoW( paramsA->SourceTagfile );
485 paramsW.TargetDirectory = strdupAtoW( paramsA->TargetDirectory );
486 paramsW.TargetFilename = strdupAtoW( paramsA->TargetFilename );
487 paramsW.CopyStyle = paramsA->CopyStyle;
488 paramsW.LayoutInf = paramsA->LayoutInf;
489 paramsW.SecurityDescriptor = strdupAtoW( paramsA->SecurityDescriptor );
491 ret = SetupQueueCopyIndirectW( &paramsW );
493 free( (WCHAR *)paramsW.SourceRootPath );
494 free( (WCHAR *)paramsW.SourcePath );
495 free( (WCHAR *)paramsW.SourceFilename );
496 free( (WCHAR *)paramsW.SourceDescription );
497 free( (WCHAR *)paramsW.SourceTagfile );
498 free( (WCHAR *)paramsW.TargetDirectory );
499 free( (WCHAR *)paramsW.TargetFilename );
500 free( (WCHAR *)paramsW.SecurityDescriptor );
501 return ret;
504 static BOOL equal_str(const WCHAR *a, const WCHAR *b)
506 return (!a && !b) || (a && b && !wcscmp(a, b));
509 static struct source_media *get_source_media(struct file_queue *queue,
510 const WCHAR *root, const WCHAR *desc, const WCHAR *tag)
512 unsigned int i;
514 for (i = 0; i < queue->source_count; ++i)
516 if (!wcscmp(root, queue->sources[i]->root)
517 && equal_str(desc, queue->sources[i]->desc)
518 && equal_str(tag, queue->sources[i]->tag))
520 return queue->sources[i];
524 queue->sources = realloc( queue->sources, ++queue->source_count * sizeof(*queue->sources) );
525 queue->sources[i] = malloc( sizeof(*queue->sources[i]) );
526 lstrcpyW(queue->sources[i]->root, root);
527 queue->sources[i]->desc = wcsdup( desc );
528 queue->sources[i]->tag = wcsdup( tag );
529 queue->sources[i]->resolved = FALSE;
530 queue->sources[i]->cabinet = FALSE;
532 return queue->sources[i];
535 /***********************************************************************
536 * SetupQueueCopyIndirectW (SETUPAPI.@)
538 BOOL WINAPI SetupQueueCopyIndirectW( PSP_FILE_COPY_PARAMS_W params )
540 struct file_queue *queue = params->QueueHandle;
541 struct file_op *op;
543 if (!(op = malloc( sizeof(*op) ))) return FALSE;
544 op->style = params->CopyStyle;
545 op->src_path = wcsdup( params->SourcePath );
546 op->src_file = wcsdup( params->SourceFilename );
547 op->dst_path = wcsdup( params->TargetDirectory );
548 op->dst_file = wcsdup( params->TargetFilename );
550 /* some defaults */
551 if (!op->dst_file) op->dst_file = op->src_file;
552 if (params->LayoutInf)
553 FIXME("Unhandled LayoutInf %p.\n", params->LayoutInf);
555 op->media = get_source_media( queue, params->SourceRootPath ? params->SourceRootPath : L"",
556 params->SourceDescription, params->SourceTagfile );
558 TRACE( "root=%s path=%s file=%s -> dir=%s file=%s descr=%s tag=%s\n",
559 debugstr_w(op->media->root), debugstr_w(op->src_path), debugstr_w(op->src_file),
560 debugstr_w(op->dst_path), debugstr_w(op->dst_file),
561 debugstr_w(op->media->desc), debugstr_w(op->media->tag) );
563 queue_file_op( &queue->copy_queue, op );
564 return TRUE;
568 /***********************************************************************
569 * SetupQueueCopyA (SETUPAPI.@)
571 BOOL WINAPI SetupQueueCopyA( HSPFILEQ queue, PCSTR src_root, PCSTR src_path, PCSTR src_file,
572 PCSTR src_descr, PCSTR src_tag, PCSTR dst_dir, PCSTR dst_file,
573 DWORD style )
575 SP_FILE_COPY_PARAMS_A params;
577 params.cbSize = sizeof(params);
578 params.QueueHandle = queue;
579 params.SourceRootPath = src_root;
580 params.SourcePath = src_path;
581 params.SourceFilename = src_file;
582 params.SourceDescription = src_descr;
583 params.SourceTagfile = src_tag;
584 params.TargetDirectory = dst_dir;
585 params.TargetFilename = dst_file;
586 params.CopyStyle = style;
587 params.LayoutInf = 0;
588 params.SecurityDescriptor = NULL;
589 return SetupQueueCopyIndirectA( &params );
593 /***********************************************************************
594 * SetupQueueCopyW (SETUPAPI.@)
596 BOOL WINAPI SetupQueueCopyW( HSPFILEQ queue, PCWSTR src_root, PCWSTR src_path, PCWSTR src_file,
597 PCWSTR src_descr, PCWSTR src_tag, PCWSTR dst_dir, PCWSTR dst_file,
598 DWORD style )
600 SP_FILE_COPY_PARAMS_W params;
602 params.cbSize = sizeof(params);
603 params.QueueHandle = queue;
604 params.SourceRootPath = src_root;
605 params.SourcePath = src_path;
606 params.SourceFilename = src_file;
607 params.SourceDescription = src_descr;
608 params.SourceTagfile = src_tag;
609 params.TargetDirectory = dst_dir;
610 params.TargetFilename = dst_file;
611 params.CopyStyle = style;
612 params.LayoutInf = 0;
613 params.SecurityDescriptor = NULL;
614 return SetupQueueCopyIndirectW( &params );
618 /***********************************************************************
619 * SetupQueueDefaultCopyA (SETUPAPI.@)
621 BOOL WINAPI SetupQueueDefaultCopyA( HSPFILEQ queue, HINF hinf, const char *src_rootA,
622 const char *src_fileA, const char *dst_fileA, DWORD style )
624 WCHAR src_rootW[MAX_PATH], src_fileW[MAX_PATH], dst_fileW[MAX_PATH];
626 if (!src_rootA || !src_fileA || !dst_fileA)
628 SetLastError(ERROR_INVALID_PARAMETER);
629 return FALSE;
632 MultiByteToWideChar( CP_ACP, 0, src_rootA, -1, src_rootW, ARRAY_SIZE(src_rootW) );
633 MultiByteToWideChar( CP_ACP, 0, src_fileA, -1, src_fileW, ARRAY_SIZE(src_fileW) );
634 MultiByteToWideChar( CP_ACP, 0, dst_fileA, -1, dst_fileW, ARRAY_SIZE(dst_fileW) );
635 return SetupQueueDefaultCopyW( queue, hinf, src_rootW, src_fileW, dst_fileW, style );
639 /***********************************************************************
640 * SetupQueueDefaultCopyW (SETUPAPI.@)
642 BOOL WINAPI SetupQueueDefaultCopyW( HSPFILEQ queue, HINF hinf, PCWSTR src_root, PCWSTR src_file,
643 PCWSTR dst_file, DWORD style )
645 WCHAR src_root_buffer[MAX_PATH], src_path[MAX_PATH];
646 SP_FILE_COPY_PARAMS_W params;
647 BOOL ret;
649 if (!src_root || !src_file || !dst_file)
651 SetLastError(ERROR_INVALID_PARAMETER);
652 return FALSE;
655 params.cbSize = sizeof(params);
656 params.QueueHandle = queue;
657 params.SourceRootPath = src_root_buffer;
658 params.SourcePath = NULL;
659 params.SourceFilename = src_file;
660 params.SourceDescription = NULL;
661 params.SourceTagfile = NULL;
662 params.TargetFilename = dst_file;
663 params.CopyStyle = style;
664 params.LayoutInf = NULL;
665 params.SecurityDescriptor = NULL;
667 lstrcpyW( src_root_buffer, src_root );
668 src_path[0] = 0;
669 if (!(params.TargetDirectory = get_destination_dir( hinf, NULL ))) return FALSE;
670 get_source_info( hinf, src_file, &params, src_root_buffer, src_path );
672 ret = SetupQueueCopyIndirectW( &params );
674 free( (WCHAR *)params.TargetDirectory );
675 free( (WCHAR *)params.SourceDescription );
676 free( (WCHAR *)params.SourceTagfile );
677 return ret;
681 /***********************************************************************
682 * SetupQueueDeleteA (SETUPAPI.@)
684 BOOL WINAPI SetupQueueDeleteA( HSPFILEQ handle, PCSTR part1, PCSTR part2 )
686 struct file_queue *queue = handle;
687 struct file_op *op;
689 if (!(op = calloc( 1, sizeof(*op) ))) return FALSE;
690 op->dst_path = strdupAtoW( part1 );
691 op->dst_file = strdupAtoW( part2 );
692 queue_file_op( &queue->delete_queue, op );
693 return TRUE;
697 /***********************************************************************
698 * SetupQueueDeleteW (SETUPAPI.@)
700 BOOL WINAPI SetupQueueDeleteW( HSPFILEQ handle, PCWSTR part1, PCWSTR part2 )
702 struct file_queue *queue = handle;
703 struct file_op *op;
705 if (!(op = calloc( 1, sizeof(*op) ))) return FALSE;
706 op->dst_path = wcsdup( part1 );
707 op->dst_file = wcsdup( part2 );
708 queue_file_op( &queue->delete_queue, op );
709 return TRUE;
713 /***********************************************************************
714 * SetupQueueRenameA (SETUPAPI.@)
716 BOOL WINAPI SetupQueueRenameA( HSPFILEQ handle, PCSTR SourcePath, PCSTR SourceFilename,
717 PCSTR TargetPath, PCSTR TargetFilename )
719 struct file_queue *queue = handle;
720 struct file_op *op;
722 if (!(op = calloc( 1, sizeof(*op) ))) return FALSE;
723 op->src_path = strdupAtoW( SourcePath );
724 op->src_file = strdupAtoW( SourceFilename );
725 op->dst_path = strdupAtoW( TargetPath ? TargetPath : SourcePath );
726 op->dst_file = strdupAtoW( TargetFilename );
727 queue_file_op( &queue->rename_queue, op );
728 return TRUE;
732 /***********************************************************************
733 * SetupQueueRenameW (SETUPAPI.@)
735 BOOL WINAPI SetupQueueRenameW( HSPFILEQ handle, PCWSTR SourcePath, PCWSTR SourceFilename,
736 PCWSTR TargetPath, PCWSTR TargetFilename )
738 struct file_queue *queue = handle;
739 struct file_op *op;
741 if (!(op = calloc( 1, sizeof(*op) ))) return FALSE;
742 op->src_path = wcsdup( SourcePath );
743 op->src_file = wcsdup( SourceFilename );
744 op->dst_path = wcsdup( TargetPath ? TargetPath : SourcePath );
745 op->dst_file = wcsdup( TargetFilename );
746 queue_file_op( &queue->rename_queue, op );
747 return TRUE;
751 /***********************************************************************
752 * SetupQueueCopySectionA (SETUPAPI.@)
754 BOOL WINAPI SetupQueueCopySectionA( HSPFILEQ queue, PCSTR src_root, HINF hinf, HINF hlist,
755 PCSTR section, DWORD style )
757 UNICODE_STRING sectionW;
758 BOOL ret = FALSE;
760 if (!RtlCreateUnicodeStringFromAsciiz( &sectionW, section ))
762 SetLastError( ERROR_NOT_ENOUGH_MEMORY );
763 return FALSE;
765 if (!src_root)
766 ret = SetupQueueCopySectionW( queue, NULL, hinf, hlist, sectionW.Buffer, style );
767 else
769 UNICODE_STRING srcW;
770 if (RtlCreateUnicodeStringFromAsciiz( &srcW, src_root ))
772 ret = SetupQueueCopySectionW( queue, srcW.Buffer, hinf, hlist, sectionW.Buffer, style );
773 RtlFreeUnicodeString( &srcW );
775 else SetLastError( ERROR_NOT_ENOUGH_MEMORY );
777 RtlFreeUnicodeString( &sectionW );
778 return ret;
781 /***********************************************************************
782 * SetupQueueCopySectionW (SETUPAPI.@)
784 BOOL WINAPI SetupQueueCopySectionW( HSPFILEQ queue, PCWSTR src_root, HINF hinf, HINF hlist,
785 PCWSTR section, DWORD style )
787 WCHAR src_root_buffer[MAX_PATH], src_path[MAX_PATH], src_file[MAX_PATH], dst_file[MAX_PATH], *dest_dir;
788 INFCONTEXT context;
789 SP_FILE_COPY_PARAMS_W params;
790 INT flags;
791 BOOL ret = FALSE;
792 DWORD len;
794 TRACE("queue %p, src_root %s, hinf %p, hlist %p, section %s, style %#lx.\n",
795 queue, debugstr_w(src_root), hinf, hlist, debugstr_w(section), style);
797 if (!src_root)
799 SetLastError(ERROR_INVALID_PARAMETER);
800 return FALSE;
803 params.cbSize = sizeof(params);
804 params.QueueHandle = queue;
805 params.SourceRootPath = src_root_buffer;
806 params.SourceFilename = src_file;
807 params.TargetFilename = dst_file;
808 params.CopyStyle = style;
809 params.LayoutInf = NULL;
810 params.SecurityDescriptor = NULL;
812 lstrcpyW( src_root_buffer, src_root );
814 if (!hlist) hlist = hinf;
815 if (!hinf) hinf = hlist;
816 if (!SetupFindFirstLineW( hlist, section, NULL, &context )) return FALSE;
817 if (!(params.TargetDirectory = dest_dir = get_destination_dir( hinf, section ))) return FALSE;
820 params.SourcePath = NULL;
821 params.SourceDescription = NULL;
822 params.SourceTagfile = NULL;
823 lstrcpyW( src_root_buffer, src_root );
824 src_path[0] = 0;
826 if (!SetupGetStringFieldW( &context, 1, dst_file, ARRAY_SIZE( dst_file ), NULL ))
827 goto end;
828 if (!SetupGetStringFieldW( &context, 2, src_file, ARRAY_SIZE( src_file ), &len ) || len <= sizeof(WCHAR))
829 lstrcpyW( src_file, dst_file );
831 if (!SetupGetIntField( &context, 4, &flags )) flags = 0; /* FIXME */
833 get_source_info( hinf, src_file, &params, src_root_buffer, src_path );
835 if (!SetupQueueCopyIndirectW( &params )) goto end;
837 free( (WCHAR *)params.SourceDescription );
838 free( (WCHAR *)params.SourceTagfile );
839 } while (SetupFindNextLine( &context, &context ));
840 ret = TRUE;
842 end:
843 free( dest_dir );
844 return ret;
848 /***********************************************************************
849 * SetupQueueDeleteSectionA (SETUPAPI.@)
851 BOOL WINAPI SetupQueueDeleteSectionA( HSPFILEQ queue, HINF hinf, HINF hlist, PCSTR section )
853 UNICODE_STRING sectionW;
854 BOOL ret = FALSE;
856 if (RtlCreateUnicodeStringFromAsciiz( &sectionW, section ))
858 ret = SetupQueueDeleteSectionW( queue, hinf, hlist, sectionW.Buffer );
859 RtlFreeUnicodeString( &sectionW );
861 else SetLastError( ERROR_NOT_ENOUGH_MEMORY );
862 return ret;
866 /***********************************************************************
867 * SetupQueueDeleteSectionW (SETUPAPI.@)
869 BOOL WINAPI SetupQueueDeleteSectionW( HSPFILEQ queue, HINF hinf, HINF hlist, PCWSTR section )
871 INFCONTEXT context;
872 WCHAR *dest_dir;
873 WCHAR buffer[MAX_PATH];
874 BOOL ret = FALSE;
875 INT flags;
877 TRACE( "hinf=%p/%p section=%s\n", hinf, hlist, debugstr_w(section) );
879 if (!hlist) hlist = hinf;
880 if (!SetupFindFirstLineW( hlist, section, NULL, &context )) return FALSE;
881 if (!(dest_dir = get_destination_dir( hinf, section ))) return FALSE;
884 if (!SetupGetStringFieldW( &context, 1, buffer, ARRAY_SIZE( buffer ), NULL ))
885 goto done;
886 if (!SetupGetIntField( &context, 4, &flags )) flags = 0;
887 if (!SetupQueueDeleteW( queue, dest_dir, buffer )) goto done;
888 } while (SetupFindNextLine( &context, &context ));
890 ret = TRUE;
891 done:
892 free( dest_dir );
893 return ret;
897 /***********************************************************************
898 * SetupQueueRenameSectionA (SETUPAPI.@)
900 BOOL WINAPI SetupQueueRenameSectionA( HSPFILEQ queue, HINF hinf, HINF hlist, PCSTR section )
902 UNICODE_STRING sectionW;
903 BOOL ret = FALSE;
905 if (RtlCreateUnicodeStringFromAsciiz( &sectionW, section ))
907 ret = SetupQueueRenameSectionW( queue, hinf, hlist, sectionW.Buffer );
908 RtlFreeUnicodeString( &sectionW );
910 else SetLastError( ERROR_NOT_ENOUGH_MEMORY );
911 return ret;
915 /***********************************************************************
916 * SetupQueueRenameSectionW (SETUPAPI.@)
918 BOOL WINAPI SetupQueueRenameSectionW( HSPFILEQ queue, HINF hinf, HINF hlist, PCWSTR section )
920 INFCONTEXT context;
921 WCHAR *dest_dir;
922 WCHAR src[MAX_PATH], dst[MAX_PATH];
923 BOOL ret = FALSE;
925 TRACE( "hinf=%p/%p section=%s\n", hinf, hlist, debugstr_w(section) );
927 if (!hlist) hlist = hinf;
928 if (!SetupFindFirstLineW( hlist, section, NULL, &context )) return FALSE;
929 if (!(dest_dir = get_destination_dir( hinf, section ))) return FALSE;
932 if (!SetupGetStringFieldW( &context, 1, dst, ARRAY_SIZE( dst ), NULL ))
933 goto done;
934 if (!SetupGetStringFieldW( &context, 2, src, ARRAY_SIZE( src ), NULL ))
935 goto done;
936 if (!SetupQueueRenameW( queue, dest_dir, src, NULL, dst )) goto done;
937 } while (SetupFindNextLine( &context, &context ));
939 ret = TRUE;
940 done:
941 free( dest_dir );
942 return ret;
946 /***********************************************************************
947 * SetupCommitFileQueueA (SETUPAPI.@)
949 BOOL WINAPI SetupCommitFileQueueA( HWND owner, HSPFILEQ queue, PSP_FILE_CALLBACK_A handler,
950 PVOID context )
952 struct callback_WtoA_context ctx;
954 ctx.orig_context = context;
955 ctx.orig_handler = handler;
956 return SetupCommitFileQueueW( owner, queue, QUEUE_callback_WtoA, &ctx );
960 /***********************************************************************
961 * create_full_pathW
963 * Recursively create all directories in the path.
965 static BOOL create_full_pathW(const WCHAR *path)
967 BOOL ret = TRUE;
968 int len;
969 WCHAR *new_path;
971 new_path = malloc((lstrlenW(path) + 1) * sizeof(WCHAR));
972 lstrcpyW(new_path, path);
974 while((len = lstrlenW(new_path)) && new_path[len - 1] == '\\')
975 new_path[len - 1] = 0;
977 while(!CreateDirectoryW(new_path, NULL))
979 WCHAR *slash;
980 DWORD last_error = GetLastError();
982 if(last_error == ERROR_ALREADY_EXISTS)
983 break;
985 if(last_error != ERROR_PATH_NOT_FOUND)
987 ret = FALSE;
988 break;
991 if(!(slash = wcsrchr(new_path, '\\')))
993 ret = FALSE;
994 break;
997 len = slash - new_path;
998 new_path[len] = 0;
999 if(!create_full_pathW(new_path))
1001 ret = FALSE;
1002 break;
1004 new_path[len] = '\\';
1007 free(new_path);
1008 return ret;
1011 static BOOL copy_file( LPCWSTR source, LPCWSTR target )
1013 WCHAR module[MAX_PATH];
1014 HMODULE mod = NULL;
1015 HRSRC res;
1016 HGLOBAL data;
1017 HANDLE handle;
1018 DWORD size, written;
1019 BOOL ret = FALSE;
1020 int id = 0;
1021 const WCHAR *p;
1023 TRACE( "%s -> %s\n", debugstr_w(source), debugstr_w(target) );
1025 if (source[0] != '@') return CopyFileW( source, target, FALSE );
1027 /* Wine extension: when the source of a file copy is in the format "@file.dll,-123"
1028 * the source data is extracted from the corresponding file.dll resource */
1030 source++; /* skip '@' */
1031 p = wcschr( source, ',' );
1032 if (!p || p - source >= MAX_PATH)
1034 SetLastError( ERROR_RESOURCE_DATA_NOT_FOUND );
1035 return FALSE;
1037 memcpy( module, source, (p - source) * sizeof(WCHAR) );
1038 module[p - source] = 0;
1039 id = -wcstol( p + 1, NULL, 10 );
1040 if (id <= 0 || id > 0xffff ||
1041 !(mod = LoadLibraryExW( module, 0, LOAD_LIBRARY_AS_DATAFILE )) ||
1042 !(res = FindResourceW( mod, MAKEINTRESOURCEW(id), L"WINE_DATA_FILE" )) ||
1043 !(data = LoadResource( mod, res )))
1045 WARN( "failed to save %s #%d to %s\n", debugstr_w(module), -id, debugstr_w(target) );
1046 if (mod) FreeLibrary( mod );
1047 SetLastError( ERROR_RESOURCE_DATA_NOT_FOUND );
1048 return FALSE;
1050 size = SizeofResource( mod, res );
1051 if ((handle = CreateFileW( target, GENERIC_WRITE, FILE_SHARE_READ | FILE_SHARE_WRITE, NULL,
1052 CREATE_ALWAYS, 0, 0 )) == INVALID_HANDLE_VALUE)
1054 WARN( "failed to save %s #%d to %s\n", debugstr_w(module), -id, debugstr_w(target) );
1055 if (mod) FreeLibrary( mod );
1056 return FALSE;
1058 ret = WriteFile( handle, LockResource(data), size, &written, NULL ) && written == size;
1059 CloseHandle( handle );
1060 if (!ret) DeleteFileW( target );
1061 return ret;
1064 static BOOL do_file_copyW( LPCWSTR source, LPCWSTR target, DWORD style,
1065 PSP_FILE_CALLBACK_W handler, PVOID context )
1067 BOOL rc = FALSE;
1068 BOOL docopy = TRUE;
1070 TRACE("copy %s to %s style 0x%lx\n",debugstr_w(source),debugstr_w(target),style);
1072 /* before copy processing */
1073 if (style & SP_COPY_REPLACEONLY)
1075 if (GetFileAttributesW(target) == INVALID_FILE_ATTRIBUTES)
1076 docopy = FALSE;
1078 if (style & (SP_COPY_NEWER_OR_SAME | SP_COPY_NEWER_ONLY | SP_COPY_FORCE_NEWER))
1080 DWORD VersionSizeSource=0;
1081 DWORD VersionSizeTarget=0;
1082 DWORD zero=0;
1085 * This is sort of an interesting workaround. You see, calling
1086 * GetVersionInfoSize on a builtin dll loads that dll into memory
1087 * and we do not properly unload builtin dlls.. so we effectively
1088 * lock into memory all the targets we are replacing. This leads
1089 * to problems when we try to register the replaced dlls.
1091 * So I will test for the existence of the files first so that
1092 * we just basically unconditionally replace the builtin versions.
1094 if ((GetFileAttributesW(target) != INVALID_FILE_ATTRIBUTES) &&
1095 (GetFileAttributesW(source) != INVALID_FILE_ATTRIBUTES))
1097 VersionSizeSource = GetFileVersionInfoSizeW(source,&zero);
1098 VersionSizeTarget = GetFileVersionInfoSizeW(target,&zero);
1101 if (VersionSizeSource && VersionSizeTarget)
1103 LPVOID VersionSource;
1104 LPVOID VersionTarget;
1105 VS_FIXEDFILEINFO *TargetInfo;
1106 VS_FIXEDFILEINFO *SourceInfo;
1107 UINT length;
1108 DWORD ret;
1110 VersionSource = malloc(VersionSizeSource);
1111 VersionTarget = malloc(VersionSizeTarget);
1113 ret = GetFileVersionInfoW(source,0,VersionSizeSource,VersionSource);
1114 if (ret)
1115 ret = GetFileVersionInfoW(target, 0, VersionSizeTarget,
1116 VersionTarget);
1118 if (ret)
1120 ret = VerQueryValueW(VersionSource, L"\\", (LPVOID*)&SourceInfo, &length);
1121 if (ret)
1122 ret = VerQueryValueW(VersionTarget, L"\\", (LPVOID*)&TargetInfo, &length);
1124 if (ret)
1126 FILEPATHS_W filepaths;
1128 TRACE("Versions: Source %li.%li target %li.%li\n",
1129 SourceInfo->dwFileVersionMS, SourceInfo->dwFileVersionLS,
1130 TargetInfo->dwFileVersionMS, TargetInfo->dwFileVersionLS);
1132 /* used in case of notification */
1133 filepaths.Target = target;
1134 filepaths.Source = source;
1135 filepaths.Win32Error = 0;
1136 filepaths.Flags = 0;
1138 if (TargetInfo->dwFileVersionMS > SourceInfo->dwFileVersionMS)
1140 if (handler)
1141 docopy = handler (context, SPFILENOTIFY_TARGETNEWER, (UINT_PTR)&filepaths, 0);
1142 else
1143 docopy = FALSE;
1145 else if ((TargetInfo->dwFileVersionMS == SourceInfo->dwFileVersionMS)
1146 && (TargetInfo->dwFileVersionLS > SourceInfo->dwFileVersionLS))
1148 if (handler)
1149 docopy = handler (context, SPFILENOTIFY_TARGETNEWER, (UINT_PTR)&filepaths, 0);
1150 else
1151 docopy = FALSE;
1153 else if ((style & SP_COPY_NEWER_ONLY) &&
1154 (TargetInfo->dwFileVersionMS ==
1155 SourceInfo->dwFileVersionMS)
1156 &&(TargetInfo->dwFileVersionLS ==
1157 SourceInfo->dwFileVersionLS))
1159 if (handler)
1160 docopy = handler (context, SPFILENOTIFY_TARGETNEWER, (UINT_PTR)&filepaths, 0);
1161 else
1162 docopy = FALSE;
1166 free(VersionSource);
1167 free(VersionTarget);
1170 if (style & (SP_COPY_NOOVERWRITE | SP_COPY_FORCE_NOOVERWRITE))
1172 if (GetFileAttributesW(target) != INVALID_FILE_ATTRIBUTES)
1174 FIXME("Notify user target file exists\n");
1175 docopy = FALSE;
1178 if (style & (SP_COPY_NODECOMP | SP_COPY_LANGUAGEAWARE | SP_COPY_FORCE_IN_USE |
1179 SP_COPY_NOSKIP | SP_COPY_WARNIFSKIP))
1181 ERR("Unsupported style(s) 0x%lx\n",style);
1184 if (docopy)
1186 rc = copy_file( source, target );
1187 if (!rc && GetLastError() == ERROR_SHARING_VIOLATION &&
1188 (style & SP_COPY_IN_USE_NEEDS_REBOOT))
1190 WCHAR temp_file[MAX_PATH];
1191 WCHAR temp[MAX_PATH];
1193 if (GetTempPathW(MAX_PATH, temp) &&
1194 GetTempFileNameW(temp, L"SET", 0, temp_file))
1196 rc = copy_file( source, temp_file );
1197 if (rc)
1198 rc = MoveFileExW(temp_file, target, MOVEFILE_DELAY_UNTIL_REBOOT);
1199 else
1200 DeleteFileW(temp_file);
1203 if (!rc) WARN( "failed to copy, err %lu\n", GetLastError() );
1205 else
1206 SetLastError(ERROR_SUCCESS);
1208 /* after copy processing */
1209 if (style & SP_COPY_DELETESOURCE)
1211 if (rc)
1212 DeleteFileW(source);
1215 return rc;
1218 /***********************************************************************
1219 * SetupInstallFileExA (SETUPAPI.@)
1221 BOOL WINAPI SetupInstallFileExA( HINF hinf, PINFCONTEXT inf_context, PCSTR source, PCSTR root,
1222 PCSTR dest, DWORD style, PSP_FILE_CALLBACK_A handler, PVOID context, PBOOL in_use )
1224 BOOL ret = FALSE;
1225 struct callback_WtoA_context ctx;
1226 UNICODE_STRING sourceW, rootW, destW;
1228 TRACE("%p %p %s %s %s %lx %p %p %p\n", hinf, inf_context, debugstr_a(source), debugstr_a(root),
1229 debugstr_a(dest), style, handler, context, in_use);
1231 sourceW.Buffer = rootW.Buffer = destW.Buffer = NULL;
1232 if (source && !RtlCreateUnicodeStringFromAsciiz( &sourceW, source ))
1234 SetLastError( ERROR_NOT_ENOUGH_MEMORY );
1235 return FALSE;
1237 if (root && !RtlCreateUnicodeStringFromAsciiz( &rootW, root ))
1239 SetLastError( ERROR_NOT_ENOUGH_MEMORY );
1240 goto exit;
1242 if (dest && !RtlCreateUnicodeStringFromAsciiz( &destW, dest ))
1244 SetLastError( ERROR_NOT_ENOUGH_MEMORY );
1245 goto exit;
1248 ctx.orig_context = context;
1249 ctx.orig_handler = handler;
1251 ret = SetupInstallFileExW( hinf, inf_context, sourceW.Buffer, rootW.Buffer, destW.Buffer, style, QUEUE_callback_WtoA, &ctx, in_use );
1253 exit:
1254 RtlFreeUnicodeString( &sourceW );
1255 RtlFreeUnicodeString( &rootW );
1256 RtlFreeUnicodeString( &destW );
1257 return ret;
1260 /***********************************************************************
1261 * SetupInstallFileA (SETUPAPI.@)
1263 BOOL WINAPI SetupInstallFileA( HINF hinf, PINFCONTEXT inf_context, PCSTR source, PCSTR root,
1264 PCSTR dest, DWORD style, PSP_FILE_CALLBACK_A handler, PVOID context )
1266 return SetupInstallFileExA( hinf, inf_context, source, root, dest, style, handler, context, NULL );
1269 /***********************************************************************
1270 * SetupInstallFileExW (SETUPAPI.@)
1272 BOOL WINAPI SetupInstallFileExW( HINF hinf, PINFCONTEXT inf_context, PCWSTR source, PCWSTR root,
1273 PCWSTR dest, DWORD style, PSP_FILE_CALLBACK_W handler, PVOID context, PBOOL in_use )
1275 BOOL ret, absolute = (root && *root && !(style & SP_COPY_SOURCE_ABSOLUTE));
1276 WCHAR *buffer, *p, *inf_source = NULL, dest_path[MAX_PATH];
1277 DWORD len;
1279 TRACE("%p %p %s %s %s %lx %p %p %p\n", hinf, inf_context, debugstr_w(source), debugstr_w(root),
1280 debugstr_w(dest), style, handler, context, in_use);
1282 if (in_use) FIXME("no file in use support\n");
1284 dest_path[0] = 0;
1286 if (hinf)
1288 WCHAR *dest_dir;
1289 INFCONTEXT ctx;
1291 if (!inf_context)
1293 inf_context = &ctx;
1294 if (!SetupFindFirstLineW( hinf, L"CopyFiles", NULL, inf_context )) return FALSE;
1296 if (!SetupGetStringFieldW( inf_context, 1, NULL, 0, &len )) return FALSE;
1297 if (!(inf_source = malloc( len * sizeof(WCHAR) )))
1299 SetLastError( ERROR_NOT_ENOUGH_MEMORY );
1300 return FALSE;
1302 if (!SetupGetStringFieldW( inf_context, 1, inf_source, len, NULL ))
1304 free( inf_source );
1305 return FALSE;
1307 source = inf_source;
1309 if ((dest_dir = get_destination_dir( hinf, NULL )))
1311 lstrcpyW( dest_path, dest_dir );
1312 lstrcatW( dest_path, L"\\" );
1313 free( dest_dir );
1316 else if (!source)
1318 SetLastError( ERROR_INVALID_PARAMETER );
1319 return FALSE;
1322 len = lstrlenW( source ) + 1;
1323 if (absolute) len += lstrlenW( root ) + 1;
1325 if (!(p = buffer = malloc( len * sizeof(WCHAR) )))
1327 free( inf_source );
1328 SetLastError( ERROR_NOT_ENOUGH_MEMORY );
1329 return FALSE;
1332 if (absolute)
1334 lstrcpyW( buffer, root );
1335 p += lstrlenW( buffer );
1336 if (p[-1] != '\\') *p++ = '\\';
1338 while (*source == '\\') source++;
1339 lstrcpyW( p, source );
1341 lstrcatW( dest_path, dest );
1343 ret = do_file_copyW( buffer, dest_path, style, handler, context );
1345 free( inf_source );
1346 free( buffer );
1347 return ret;
1350 /***********************************************************************
1351 * SetupInstallFileW (SETUPAPI.@)
1353 BOOL WINAPI SetupInstallFileW( HINF hinf, PINFCONTEXT inf_context, PCWSTR source, PCWSTR root,
1354 PCWSTR dest, DWORD style, PSP_FILE_CALLBACK_W handler, PVOID context )
1356 return SetupInstallFileExW( hinf, inf_context, source, root, dest, style, handler, context, NULL );
1359 static BOOL queue_copy_file( const WCHAR *source, const WCHAR *dest,
1360 const struct file_op *op, PSP_FILE_CALLBACK_W handler, void *context )
1362 TRACE("copying file %s -> %s\n", debugstr_w(source), debugstr_w(dest));
1364 if (op->dst_path && !create_full_pathW(op->dst_path))
1365 return FALSE;
1367 if (do_file_copyW(source, dest, op->style, handler, context) || GetLastError() == ERROR_SUCCESS)
1368 return TRUE;
1370 /* try to extract it from the cabinet file */
1371 if (op->media->tag && extract_cabinet_file(op->media->tag, op->media->root, op->src_file, dest))
1373 op->media->cabinet = TRUE;
1374 return TRUE;
1377 return FALSE;
1380 /***********************************************************************
1381 * SetupCommitFileQueueW (SETUPAPI.@)
1383 BOOL WINAPI SetupCommitFileQueueW( HWND owner, HSPFILEQ handle, PSP_FILE_CALLBACK_W handler,
1384 PVOID context )
1386 struct file_queue *queue = handle;
1387 struct file_op *op;
1388 BOOL result = FALSE;
1389 FILEPATHS_W paths;
1390 UINT op_result;
1392 paths.Source = paths.Target = NULL;
1394 if (!queue->copy_queue.count && !queue->delete_queue.count && !queue->rename_queue.count)
1395 return TRUE; /* nothing to do */
1397 if (!handler( context, SPFILENOTIFY_STARTQUEUE, (UINT_PTR)owner, 0 )) return FALSE;
1399 /* perform deletes */
1401 if (queue->delete_queue.count)
1403 if (!(handler( context, SPFILENOTIFY_STARTSUBQUEUE, FILEOP_DELETE,
1404 queue->delete_queue.count ))) goto done;
1405 for (op = queue->delete_queue.head; op; op = op->next)
1407 build_filepathsW( op, &paths );
1408 op_result = handler( context, SPFILENOTIFY_STARTDELETE, (UINT_PTR)&paths, FILEOP_DELETE);
1409 if (op_result == FILEOP_ABORT) goto done;
1410 while (op_result == FILEOP_DOIT)
1412 TRACE( "deleting file %s\n", debugstr_w(paths.Target) );
1413 if (DeleteFileW( paths.Target )) break; /* success */
1414 paths.Win32Error = GetLastError();
1415 op_result = handler( context, SPFILENOTIFY_DELETEERROR, (UINT_PTR)&paths, 0 );
1416 if (op_result == FILEOP_ABORT) goto done;
1418 handler( context, SPFILENOTIFY_ENDDELETE, (UINT_PTR)&paths, 0 );
1420 handler( context, SPFILENOTIFY_ENDSUBQUEUE, FILEOP_DELETE, 0 );
1423 /* perform renames */
1425 if (queue->rename_queue.count)
1427 if (!(handler( context, SPFILENOTIFY_STARTSUBQUEUE, FILEOP_RENAME,
1428 queue->rename_queue.count ))) goto done;
1429 for (op = queue->rename_queue.head; op; op = op->next)
1431 build_filepathsW( op, &paths );
1432 op_result = handler( context, SPFILENOTIFY_STARTRENAME, (UINT_PTR)&paths, FILEOP_RENAME);
1433 if (op_result == FILEOP_ABORT) goto done;
1434 while (op_result == FILEOP_DOIT)
1436 TRACE( "renaming file %s -> %s\n",
1437 debugstr_w(paths.Source), debugstr_w(paths.Target) );
1438 if (MoveFileW( paths.Source, paths.Target )) break; /* success */
1439 paths.Win32Error = GetLastError();
1440 op_result = handler( context, SPFILENOTIFY_RENAMEERROR, (UINT_PTR)&paths, 0 );
1441 if (op_result == FILEOP_ABORT) goto done;
1443 handler( context, SPFILENOTIFY_ENDRENAME, (UINT_PTR)&paths, 0 );
1445 handler( context, SPFILENOTIFY_ENDSUBQUEUE, FILEOP_RENAME, 0 );
1448 /* perform copies */
1450 if (queue->copy_queue.count)
1452 if (!(handler( context, SPFILENOTIFY_STARTSUBQUEUE, FILEOP_COPY,
1453 queue->copy_queue.count ))) goto done;
1454 for (op = queue->copy_queue.head; op; op = op->next)
1456 WCHAR newpath[MAX_PATH];
1458 if (!op->media->resolved)
1460 /* The NEEDMEDIA callback asks for the folder containing the
1461 * first file, but that might be in a subdir of the source
1462 * disk's root directory. We have to do some contortions to
1463 * correct for this. Pretend that the file we're using
1464 * actually isn't in a subdirectory, but keep track of what it
1465 * was, and then later strip it from the root path that we
1466 * ultimately resolve the source disk to. */
1467 WCHAR src_path[MAX_PATH];
1468 size_t path_len = 0;
1470 src_path[0] = 0;
1471 if (op->src_path)
1473 lstrcpyW(src_path, op->src_path);
1474 path_len = lstrlenW(src_path);
1476 lstrcatW(op->media->root, L"\\");
1477 lstrcatW(op->media->root, op->src_path);
1479 free(op->src_path);
1480 op->src_path = NULL;
1483 for (;;)
1485 SOURCE_MEDIA_W media;
1486 media.Reserved = NULL;
1487 media.Tagfile = op->media->tag;
1488 media.Description = op->media->desc;
1489 media.SourcePath = op->media->root;
1490 media.SourceFile = op->src_file;
1491 media.Flags = op->style & (SP_COPY_WARNIFSKIP | SP_COPY_NOSKIP | SP_FLAG_CABINETCONTINUATION | SP_COPY_NOBROWSE);
1493 newpath[0] = 0;
1494 op_result = handler( context, SPFILENOTIFY_NEEDMEDIA, (UINT_PTR)&media, (UINT_PTR)newpath );
1496 if (op_result == FILEOP_ABORT)
1497 goto done;
1498 else if (op_result == FILEOP_SKIP)
1499 break;
1500 else if (op_result == FILEOP_NEWPATH)
1501 lstrcpyW(op->media->root, newpath);
1502 else if (op_result != FILEOP_DOIT)
1503 FIXME("Unhandled return value %#x.\n", op_result);
1505 build_filepathsW( op, &paths );
1506 op_result = handler( context, SPFILENOTIFY_STARTCOPY, (UINT_PTR)&paths, FILEOP_COPY );
1507 if (op_result == FILEOP_ABORT)
1508 goto done;
1509 else if (op_result == FILEOP_SKIP)
1510 break;
1511 else if (op_result != FILEOP_DOIT)
1512 FIXME("Unhandled return value %#x.\n", op_result);
1514 if (queue_copy_file( paths.Source, paths.Target, op, handler, context ))
1516 if (path_len > 0 && !op->media->cabinet)
1518 size_t root_len = lstrlenW(op->media->root);
1519 if (path_len <= root_len && !wcsnicmp(op->media->root + root_len - path_len, src_path, path_len))
1520 op->media->root[root_len - path_len - 1] = 0;
1522 op->media->resolved = TRUE;
1523 handler( context, SPFILENOTIFY_ENDCOPY, (UINT_PTR)&paths, 0 );
1524 break;
1526 paths.Win32Error = GetLastError();
1527 if (paths.Win32Error == ERROR_PATH_NOT_FOUND ||
1528 paths.Win32Error == ERROR_FILE_NOT_FOUND)
1529 continue;
1531 newpath[0] = 0;
1532 op_result = handler( context, SPFILENOTIFY_COPYERROR, (UINT_PTR)&paths, (UINT_PTR)newpath );
1533 if (op_result == FILEOP_ABORT)
1534 goto done;
1535 else if (op_result == FILEOP_SKIP)
1536 break;
1537 else if (op_result == FILEOP_NEWPATH)
1539 lstrcpyW(op->media->root, newpath);
1540 build_filepathsW(op, &paths);
1542 else if (op_result != FILEOP_DOIT)
1543 FIXME("Unhandled return value %#x.\n", op_result);
1546 else
1548 build_filepathsW( op, &paths );
1549 op_result = handler( context, SPFILENOTIFY_STARTCOPY, (UINT_PTR)&paths, FILEOP_COPY );
1550 if (op_result == FILEOP_ABORT)
1551 goto done;
1552 else if (op_result == FILEOP_SKIP)
1553 continue;
1554 else if (op_result != FILEOP_DOIT)
1555 FIXME("Unhandled return value %#x.\n", op_result);
1557 while (op_result == FILEOP_DOIT || op_result == FILEOP_NEWPATH)
1559 if (queue_copy_file( paths.Source, paths.Target, op, handler, context ))
1560 break;
1562 paths.Win32Error = GetLastError();
1563 newpath[0] = 0;
1564 op_result = handler( context, SPFILENOTIFY_COPYERROR, (UINT_PTR)&paths, (UINT_PTR)newpath );
1565 if (op_result == FILEOP_ABORT)
1566 goto done;
1567 else if (op_result == FILEOP_NEWPATH)
1569 lstrcpyW(op->media->root, newpath);
1570 build_filepathsW(op, &paths);
1572 else if (op_result != FILEOP_SKIP && op_result != FILEOP_DOIT)
1573 FIXME("Unhandled return value %#x.\n", op_result);
1575 handler( context, SPFILENOTIFY_ENDCOPY, (UINT_PTR)&paths, 0 );
1578 handler( context, SPFILENOTIFY_ENDSUBQUEUE, FILEOP_COPY, 0 );
1582 result = TRUE;
1584 done:
1585 handler( context, SPFILENOTIFY_ENDQUEUE, result, 0 );
1586 HeapFree( GetProcessHeap(), 0, (void *)paths.Source );
1587 HeapFree( GetProcessHeap(), 0, (void *)paths.Target );
1588 return result;
1592 /***********************************************************************
1593 * SetupScanFileQueueA (SETUPAPI.@)
1595 BOOL WINAPI SetupScanFileQueueA( HSPFILEQ handle, DWORD flags, HWND window,
1596 PSP_FILE_CALLBACK_A handler, PVOID context, PDWORD result )
1598 struct callback_WtoA_context ctx;
1600 TRACE("%p %lx %p %p %p %p\n", handle, flags, window, handler, context, result);
1602 ctx.orig_context = context;
1603 ctx.orig_handler = handler;
1605 return SetupScanFileQueueW( handle, flags, window, QUEUE_callback_WtoA, &ctx, result );
1609 /***********************************************************************
1610 * SetupScanFileQueueW (SETUPAPI.@)
1612 BOOL WINAPI SetupScanFileQueueW( HSPFILEQ handle, DWORD flags, HWND window,
1613 PSP_FILE_CALLBACK_W handler, PVOID context, PDWORD result )
1615 struct file_queue *queue = handle;
1616 struct file_op *op;
1617 FILEPATHS_W paths;
1618 UINT notification = 0;
1619 BOOL ret = FALSE;
1621 TRACE("%p %lx %p %p %p %p\n", handle, flags, window, handler, context, result);
1623 if (!queue->copy_queue.count) return TRUE;
1625 if (flags & SPQ_SCAN_USE_CALLBACK) notification = SPFILENOTIFY_QUEUESCAN;
1626 else if (flags & SPQ_SCAN_USE_CALLBACKEX) notification = SPFILENOTIFY_QUEUESCAN_EX;
1628 if (flags & ~(SPQ_SCAN_USE_CALLBACK | SPQ_SCAN_USE_CALLBACKEX))
1630 FIXME("flags %lx not fully implemented\n", flags);
1633 paths.Source = paths.Target = NULL;
1635 for (op = queue->copy_queue.head; op; op = op->next)
1637 build_filepathsW( op, &paths );
1638 switch (notification)
1640 case SPFILENOTIFY_QUEUESCAN:
1641 /* FIXME: handle delay flag */
1642 if (handler( context, notification, (UINT_PTR)paths.Target, 0 )) goto done;
1643 break;
1644 case SPFILENOTIFY_QUEUESCAN_EX:
1645 if (handler( context, notification, (UINT_PTR)&paths, 0 )) goto done;
1646 break;
1647 default:
1648 ret = TRUE; goto done;
1652 ret = TRUE;
1654 done:
1655 if (result) *result = 0;
1656 HeapFree( GetProcessHeap(), 0, (void *)paths.Source );
1657 HeapFree( GetProcessHeap(), 0, (void *)paths.Target );
1658 return ret;
1662 /***********************************************************************
1663 * SetupGetFileQueueCount (SETUPAPI.@)
1665 BOOL WINAPI SetupGetFileQueueCount( HSPFILEQ handle, UINT op, PUINT result )
1667 struct file_queue *queue = handle;
1669 switch(op)
1671 case FILEOP_COPY:
1672 *result = queue->copy_queue.count;
1673 return TRUE;
1674 case FILEOP_RENAME:
1675 *result = queue->rename_queue.count;
1676 return TRUE;
1677 case FILEOP_DELETE:
1678 *result = queue->delete_queue.count;
1679 return TRUE;
1681 return FALSE;
1685 /***********************************************************************
1686 * SetupGetFileQueueFlags (SETUPAPI.@)
1688 BOOL WINAPI SetupGetFileQueueFlags( HSPFILEQ handle, PDWORD flags )
1690 struct file_queue *queue = handle;
1691 *flags = queue->flags;
1692 return TRUE;
1696 /***********************************************************************
1697 * SetupSetFileQueueFlags (SETUPAPI.@)
1699 BOOL WINAPI SetupSetFileQueueFlags( HSPFILEQ handle, DWORD mask, DWORD flags )
1701 struct file_queue *queue = handle;
1702 queue->flags = (queue->flags & ~mask) | flags;
1703 return TRUE;
1707 /***********************************************************************
1708 * SetupSetFileQueueAlternatePlatformA (SETUPAPI.@)
1710 BOOL WINAPI SetupSetFileQueueAlternatePlatformA(HSPFILEQ handle, PSP_ALTPLATFORM_INFO platform, PCSTR catalogfile)
1712 FIXME("(%p, %p, %s) stub!\n", handle, platform, debugstr_a(catalogfile));
1713 return FALSE;
1717 /***********************************************************************
1718 * SetupSetFileQueueAlternatePlatformW (SETUPAPI.@)
1720 BOOL WINAPI SetupSetFileQueueAlternatePlatformW(HSPFILEQ handle, PSP_ALTPLATFORM_INFO platform, PCWSTR catalogfile)
1722 FIXME("(%p, %p, %s) stub!\n", handle, platform, debugstr_w(catalogfile));
1723 return FALSE;
1727 /***********************************************************************
1728 * SetupInitDefaultQueueCallback (SETUPAPI.@)
1730 PVOID WINAPI SetupInitDefaultQueueCallback( HWND owner )
1732 return SetupInitDefaultQueueCallbackEx( owner, 0, 0, 0, NULL );
1736 /***********************************************************************
1737 * SetupInitDefaultQueueCallbackEx (SETUPAPI.@)
1739 PVOID WINAPI SetupInitDefaultQueueCallbackEx( HWND owner, HWND progress, UINT msg,
1740 DWORD reserved1, PVOID reserved2 )
1742 struct default_callback_context *context;
1744 if ((context = calloc( 1, sizeof(*context) )))
1746 context->magic = 0x43515053; /* "SPQC" */
1747 context->owner = owner;
1748 context->progress = progress;
1749 context->message = msg;
1751 return context;
1755 /***********************************************************************
1756 * SetupTermDefaultQueueCallback (SETUPAPI.@)
1758 void WINAPI SetupTermDefaultQueueCallback( PVOID context )
1760 free( context );
1764 /***********************************************************************
1765 * SetupDefaultQueueCallbackA (SETUPAPI.@)
1767 UINT WINAPI SetupDefaultQueueCallbackA( PVOID context, UINT notification,
1768 UINT_PTR param1, UINT_PTR param2 )
1770 FILEPATHS_A *paths = (FILEPATHS_A *)param1;
1771 struct default_callback_context *ctx = context;
1773 switch(notification)
1775 case SPFILENOTIFY_STARTQUEUE:
1776 TRACE( "start queue\n" );
1777 return TRUE;
1778 case SPFILENOTIFY_ENDQUEUE:
1779 TRACE( "end queue\n" );
1780 return 0;
1781 case SPFILENOTIFY_STARTSUBQUEUE:
1782 TRACE( "start subqueue %Id count %Id\n", param1, param2 );
1783 return TRUE;
1784 case SPFILENOTIFY_ENDSUBQUEUE:
1785 TRACE( "end subqueue %Id\n", param1 );
1786 return 0;
1787 case SPFILENOTIFY_STARTDELETE:
1788 TRACE( "start delete %s\n", debugstr_a(paths->Target) );
1789 return FILEOP_DOIT;
1790 case SPFILENOTIFY_ENDDELETE:
1791 TRACE( "end delete %s\n", debugstr_a(paths->Target) );
1792 return 0;
1793 case SPFILENOTIFY_DELETEERROR:
1794 /*Windows Ignores attempts to delete files / folders which do not exist*/
1795 if ((paths->Win32Error != ERROR_FILE_NOT_FOUND) && (paths->Win32Error != ERROR_PATH_NOT_FOUND))
1796 SetupDeleteErrorA(ctx->owner, NULL, paths->Target, paths->Win32Error, 0);
1797 return FILEOP_SKIP;
1798 case SPFILENOTIFY_STARTRENAME:
1799 TRACE( "start rename %s -> %s\n", debugstr_a(paths->Source), debugstr_a(paths->Target) );
1800 return FILEOP_DOIT;
1801 case SPFILENOTIFY_ENDRENAME:
1802 TRACE( "end rename %s -> %s\n", debugstr_a(paths->Source), debugstr_a(paths->Target) );
1803 return 0;
1804 case SPFILENOTIFY_RENAMEERROR:
1805 SetupRenameErrorA(ctx->owner, NULL, paths->Source, paths->Target, paths->Win32Error, 0);
1806 return FILEOP_SKIP;
1807 case SPFILENOTIFY_STARTCOPY:
1808 TRACE( "start copy %s -> %s\n", debugstr_a(paths->Source), debugstr_a(paths->Target) );
1809 return FILEOP_DOIT;
1810 case SPFILENOTIFY_ENDCOPY:
1811 TRACE( "end copy %s -> %s\n", debugstr_a(paths->Source), debugstr_a(paths->Target) );
1812 return 0;
1813 case SPFILENOTIFY_COPYERROR:
1814 ERR( "copy error %d %s -> %s\n", paths->Win32Error,
1815 debugstr_a(paths->Source), debugstr_a(paths->Target) );
1816 return FILEOP_SKIP;
1817 case SPFILENOTIFY_NEEDMEDIA:
1819 const SOURCE_MEDIA_A *media = (const SOURCE_MEDIA_A *)param1;
1820 TRACE( "need media %s %s\n", debugstr_a(media->SourcePath), debugstr_a(media->SourceFile) );
1821 strcpy( (char *)param2, media->SourcePath );
1822 return FILEOP_DOIT;
1824 default:
1825 FIXME( "notification %d params %Ix,%Ix\n", notification, param1, param2 );
1826 break;
1828 return 0;
1832 /***********************************************************************
1833 * SetupDefaultQueueCallbackW (SETUPAPI.@)
1835 UINT WINAPI SetupDefaultQueueCallbackW( PVOID context, UINT notification,
1836 UINT_PTR param1, UINT_PTR param2 )
1838 FILEPATHS_W *paths = (FILEPATHS_W *)param1;
1839 struct default_callback_context *ctx = context;
1841 switch(notification)
1843 case SPFILENOTIFY_STARTQUEUE:
1844 TRACE( "start queue\n" );
1845 return TRUE;
1846 case SPFILENOTIFY_ENDQUEUE:
1847 TRACE( "end queue\n" );
1848 return 0;
1849 case SPFILENOTIFY_STARTSUBQUEUE:
1850 TRACE( "start subqueue %Id count %Id\n", param1, param2 );
1851 return TRUE;
1852 case SPFILENOTIFY_ENDSUBQUEUE:
1853 TRACE( "end subqueue %Id\n", param1 );
1854 return 0;
1855 case SPFILENOTIFY_STARTDELETE:
1856 TRACE( "start delete %s\n", debugstr_w(paths->Target) );
1857 return FILEOP_DOIT;
1858 case SPFILENOTIFY_ENDDELETE:
1859 TRACE( "end delete %s\n", debugstr_w(paths->Target) );
1860 return 0;
1861 case SPFILENOTIFY_DELETEERROR:
1862 /*Windows Ignores attempts to delete files / folders which do not exist*/
1863 if ((paths->Win32Error != ERROR_FILE_NOT_FOUND) && (paths->Win32Error != ERROR_PATH_NOT_FOUND))
1864 SetupDeleteErrorW(ctx->owner, NULL, paths->Target, paths->Win32Error, 0);
1865 return FILEOP_SKIP;
1866 case SPFILENOTIFY_STARTRENAME:
1867 SetupRenameErrorW(ctx->owner, NULL, paths->Source, paths->Target, paths->Win32Error, 0);
1868 return FILEOP_DOIT;
1869 case SPFILENOTIFY_ENDRENAME:
1870 TRACE( "end rename %s -> %s\n", debugstr_w(paths->Source), debugstr_w(paths->Target) );
1871 return 0;
1872 case SPFILENOTIFY_RENAMEERROR:
1873 ERR( "rename error %d %s -> %s\n", paths->Win32Error,
1874 debugstr_w(paths->Source), debugstr_w(paths->Target) );
1875 return FILEOP_SKIP;
1876 case SPFILENOTIFY_STARTCOPY:
1877 TRACE( "start copy %s -> %s\n", debugstr_w(paths->Source), debugstr_w(paths->Target) );
1878 return FILEOP_DOIT;
1879 case SPFILENOTIFY_ENDCOPY:
1880 TRACE( "end copy %s -> %s\n", debugstr_w(paths->Source), debugstr_w(paths->Target) );
1881 return 0;
1882 case SPFILENOTIFY_COPYERROR:
1883 ERR( "copy error %d %s -> %s\n", paths->Win32Error,
1884 debugstr_w(paths->Source), debugstr_w(paths->Target) );
1885 return FILEOP_SKIP;
1886 case SPFILENOTIFY_NEEDMEDIA:
1888 const SOURCE_MEDIA_W *media = (const SOURCE_MEDIA_W *)param1;
1889 TRACE( "need media %s %s\n", debugstr_w(media->SourcePath), debugstr_w(media->SourceFile) );
1890 lstrcpyW( (WCHAR *)param2, media->SourcePath );
1891 return FILEOP_DOIT;
1893 default:
1894 FIXME( "notification %d params %Ix,%Ix\n", notification, param1, param2 );
1895 break;
1897 return 0;
1900 /***********************************************************************
1901 * SetupDeleteErrorA (SETUPAPI.@)
1904 UINT WINAPI SetupDeleteErrorA( HWND parent, PCSTR dialogTitle, PCSTR file,
1905 UINT w32error, DWORD style)
1907 FIXME( "stub: (Error Number %d when attempting to delete %s)\n",
1908 w32error, debugstr_a(file) );
1909 return DPROMPT_SKIPFILE;
1912 /***********************************************************************
1913 * SetupDeleteErrorW (SETUPAPI.@)
1916 UINT WINAPI SetupDeleteErrorW( HWND parent, PCWSTR dialogTitle, PCWSTR file,
1917 UINT w32error, DWORD style)
1919 FIXME( "stub: (Error Number %d when attempting to delete %s)\n",
1920 w32error, debugstr_w(file) );
1921 return DPROMPT_SKIPFILE;
1924 /***********************************************************************
1925 * SetupRenameErrorA (SETUPAPI.@)
1928 UINT WINAPI SetupRenameErrorA( HWND parent, PCSTR dialogTitle, PCSTR source,
1929 PCSTR target, UINT w32error, DWORD style)
1931 FIXME( "stub: (Error Number %d when attempting to rename %s to %s)\n",
1932 w32error, debugstr_a(source), debugstr_a(target));
1933 return DPROMPT_SKIPFILE;
1936 /***********************************************************************
1937 * SetupRenameErrorW (SETUPAPI.@)
1940 UINT WINAPI SetupRenameErrorW( HWND parent, PCWSTR dialogTitle, PCWSTR source,
1941 PCWSTR target, UINT w32error, DWORD style)
1943 FIXME( "stub: (Error Number %d when attempting to rename %s to %s)\n",
1944 w32error, debugstr_w(source), debugstr_w(target));
1945 return DPROMPT_SKIPFILE;
1949 /***********************************************************************
1950 * SetupCopyErrorA (SETUPAPI.@)
1953 UINT WINAPI SetupCopyErrorA( HWND parent, PCSTR dialogTitle, PCSTR diskname,
1954 PCSTR sourcepath, PCSTR sourcefile, PCSTR targetpath,
1955 UINT w32error, DWORD style, PSTR pathbuffer,
1956 DWORD buffersize, PDWORD requiredsize)
1958 FIXME( "stub: (Error Number %d when attempting to copy file %s from %s to %s)\n",
1959 w32error, debugstr_a(sourcefile), debugstr_a(sourcepath) ,debugstr_a(targetpath));
1960 return DPROMPT_SKIPFILE;
1963 /***********************************************************************
1964 * SetupCopyErrorW (SETUPAPI.@)
1967 UINT WINAPI SetupCopyErrorW( HWND parent, PCWSTR dialogTitle, PCWSTR diskname,
1968 PCWSTR sourcepath, PCWSTR sourcefile, PCWSTR targetpath,
1969 UINT w32error, DWORD style, PWSTR pathbuffer,
1970 DWORD buffersize, PDWORD requiredsize)
1972 FIXME( "stub: (Error Number %d when attempting to copy file %s from %s to %s)\n",
1973 w32error, debugstr_w(sourcefile), debugstr_w(sourcepath) ,debugstr_w(targetpath));
1974 return DPROMPT_SKIPFILE;
1977 /***********************************************************************
1978 * pSetupGetQueueFlags (SETUPAPI.@)
1980 DWORD WINAPI pSetupGetQueueFlags( HSPFILEQ handle )
1982 struct file_queue *queue = handle;
1983 return queue->flags;
1986 /***********************************************************************
1987 * pSetupSetQueueFlags (SETUPAPI.@)
1989 BOOL WINAPI pSetupSetQueueFlags( HSPFILEQ handle, DWORD flags )
1991 struct file_queue *queue = handle;
1992 queue->flags = flags;
1993 return TRUE;