amstream: Implement AMAudioStream::NewSegment.
[wine/zf.git] / dlls / setupapi / queue.c
blobeebfe971546a82ad31fcc2b62b7e6c7096f96df6
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 "setupapi_private.h"
33 #include "winver.h"
34 #include "wine/debug.h"
35 #include "wine/heap.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 HeapFree( GetProcessHeap(), 0, op->src_path );
108 HeapFree( GetProcessHeap(), 0, op->src_file );
109 HeapFree( GetProcessHeap(), 0, op->dst_path );
110 if (op->dst_file != op->src_file) HeapFree( GetProcessHeap(), 0, op->dst_file );
111 t = op;
112 op = op->next;
113 HeapFree( GetProcessHeap(), 0, 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->media) src_len += lstrlenW(op->media->root) + 1;
155 if (op->src_path) src_len += lstrlenW(op->src_path) + 1;
156 if (op->src_file) src_len += lstrlenW(op->src_file) + 1;
157 if (op->dst_path) dst_len += lstrlenW(op->dst_path) + 1;
158 if (op->dst_file) dst_len += lstrlenW(op->dst_file) + 1;
159 src_len *= sizeof(WCHAR);
160 dst_len *= sizeof(WCHAR);
162 if (!source || HeapSize( GetProcessHeap(), 0, source ) < src_len )
164 HeapFree( GetProcessHeap(), 0, source );
165 paths->Source = source = HeapAlloc( GetProcessHeap(), 0, src_len );
167 if (!target || HeapSize( GetProcessHeap(), 0, target ) < dst_len )
169 HeapFree( GetProcessHeap(), 0, target );
170 paths->Target = target = HeapAlloc( GetProcessHeap(), 0, dst_len );
172 if (!source || !target) return FALSE;
173 concat_W( source, op->media ? op->media->root : NULL, op->src_path, op->src_file );
174 concat_W( target, NULL, op->dst_path, op->dst_file );
175 paths->Win32Error = 0;
176 paths->Flags = 0;
177 return TRUE;
181 /***********************************************************************
182 * QUEUE_callback_WtoA
184 * Map a file callback parameters from W to A and call the A callback.
186 UINT CALLBACK QUEUE_callback_WtoA( void *context, UINT notification,
187 UINT_PTR param1, UINT_PTR param2 )
189 struct callback_WtoA_context *callback_ctx = context;
190 char buffer[MAX_PATH];
191 UINT ret;
192 UINT_PTR old_param2 = param2;
194 switch(notification)
196 case SPFILENOTIFY_COPYERROR:
197 buffer[0] = 0;
198 param2 = (UINT_PTR)buffer;
199 /* fall through */
200 case SPFILENOTIFY_STARTDELETE:
201 case SPFILENOTIFY_ENDDELETE:
202 case SPFILENOTIFY_DELETEERROR:
203 case SPFILENOTIFY_STARTRENAME:
204 case SPFILENOTIFY_ENDRENAME:
205 case SPFILENOTIFY_RENAMEERROR:
206 case SPFILENOTIFY_STARTCOPY:
207 case SPFILENOTIFY_ENDCOPY:
208 case SPFILENOTIFY_QUEUESCAN_EX:
210 FILEPATHS_W *pathsW = (FILEPATHS_W *)param1;
211 FILEPATHS_A pathsA;
213 pathsA.Source = strdupWtoA( pathsW->Source );
214 pathsA.Target = strdupWtoA( pathsW->Target );
215 pathsA.Win32Error = pathsW->Win32Error;
216 pathsA.Flags = pathsW->Flags;
217 ret = callback_ctx->orig_handler( callback_ctx->orig_context, notification,
218 (UINT_PTR)&pathsA, param2 );
219 HeapFree( GetProcessHeap(), 0, (void *)pathsA.Source );
220 HeapFree( GetProcessHeap(), 0, (void *)pathsA.Target );
222 if (notification == SPFILENOTIFY_COPYERROR)
223 MultiByteToWideChar( CP_ACP, 0, buffer, -1, (WCHAR *)old_param2, MAX_PATH );
224 break;
226 case SPFILENOTIFY_STARTREGISTRATION:
227 case SPFILENOTIFY_ENDREGISTRATION:
229 SP_REGISTER_CONTROL_STATUSW *statusW = (SP_REGISTER_CONTROL_STATUSW *)param1;
230 SP_REGISTER_CONTROL_STATUSA statusA;
232 statusA.cbSize = sizeof(statusA);
233 statusA.FileName = strdupWtoA( statusW->FileName );
234 statusA.Win32Error = statusW->Win32Error;
235 statusA.FailureCode = statusW->FailureCode;
236 ret = callback_ctx->orig_handler( callback_ctx->orig_context, notification,
237 (UINT_PTR)&statusA, param2 );
238 HeapFree( GetProcessHeap(), 0, (LPSTR)statusA.FileName );
240 break;
242 case SPFILENOTIFY_QUEUESCAN:
244 LPWSTR targetW = (LPWSTR)param1;
245 LPSTR target = strdupWtoA( targetW );
247 ret = callback_ctx->orig_handler( callback_ctx->orig_context, notification,
248 (UINT_PTR)target, param2 );
249 HeapFree( GetProcessHeap(), 0, target );
251 break;
253 case SPFILENOTIFY_NEEDMEDIA:
255 const SOURCE_MEDIA_W *mediaW = (const SOURCE_MEDIA_W *)param1;
256 char path[MAX_PATH];
257 SOURCE_MEDIA_A mediaA;
259 mediaA.Tagfile = strdupWtoA(mediaW->Tagfile);
260 mediaA.Description = strdupWtoA(mediaW->Description);
261 mediaA.SourcePath = strdupWtoA(mediaW->SourcePath);
262 mediaA.SourceFile = strdupWtoA(mediaW->SourceFile);
263 mediaA.Flags = mediaW->Flags;
264 path[0] = 0;
266 ret = callback_ctx->orig_handler(callback_ctx->orig_context, notification,
267 (UINT_PTR)&mediaA, (UINT_PTR)&path);
268 MultiByteToWideChar(CP_ACP, 0, path, -1, (WCHAR *)param2, MAX_PATH);
270 heap_free((char *)mediaA.Tagfile);
271 heap_free((char *)mediaA.Description);
272 heap_free((char *)mediaA.SourcePath);
273 heap_free((char *)mediaA.SourceFile);
274 break;
276 case SPFILENOTIFY_STARTQUEUE:
277 case SPFILENOTIFY_ENDQUEUE:
278 case SPFILENOTIFY_STARTSUBQUEUE:
279 case SPFILENOTIFY_ENDSUBQUEUE:
280 default:
281 ret = callback_ctx->orig_handler( callback_ctx->orig_context, notification, param1, param2 );
282 break;
284 return ret;
287 static void get_source_info( HINF hinf, const WCHAR *src_file, SP_FILE_COPY_PARAMS_W *params,
288 WCHAR *src_root, WCHAR *src_path)
290 INFCONTEXT file_ctx, disk_ctx;
291 INT id, diskid;
292 DWORD len;
294 /* find the SourceDisksFiles entry */
295 if (!SetupFindFirstLineW( hinf, L"SourceDisksFiles", src_file, &file_ctx )) return;
296 if (!SetupGetIntField( &file_ctx, 1, &diskid )) return;
298 /* now find the diskid in the SourceDisksNames section */
299 if (!SetupFindFirstLineW( hinf, L"SourceDisksNames", NULL, &disk_ctx )) return;
300 for (;;)
302 if (SetupGetIntField( &disk_ctx, 0, &id ) && (id == diskid)) break;
303 if (!SetupFindNextLine( &disk_ctx, &disk_ctx )) return;
306 if (SetupGetStringFieldW( &disk_ctx, 1, NULL, 0, &len ) && len > sizeof(WCHAR)
307 && (params->SourceDescription = heap_alloc( len * sizeof(WCHAR) )))
308 SetupGetStringFieldW( &disk_ctx, 1, (WCHAR *)params->SourceDescription, len, NULL );
310 if (SetupGetStringFieldW( &disk_ctx, 2, NULL, 0, &len ) && len > sizeof(WCHAR)
311 && (params->SourceTagfile = heap_alloc( len * sizeof(WCHAR) )))
312 SetupGetStringFieldW( &disk_ctx, 2, (WCHAR *)params->SourceTagfile, len, NULL );
314 if (SetupGetStringFieldW( &disk_ctx, 4, NULL, 0, &len ) && len > sizeof(WCHAR)
315 && len < MAX_PATH - lstrlenW( src_root ) - 1)
317 lstrcatW( src_root, L"\\" );
318 SetupGetStringFieldW( &disk_ctx, 4, src_root + lstrlenW( src_root ),
319 MAX_PATH - lstrlenW( src_root ), NULL );
322 if (SetupGetStringFieldW( &file_ctx, 2, NULL, 0, &len ) && len > sizeof(WCHAR) && len < MAX_PATH)
324 SetupGetStringFieldW( &file_ctx, 2, src_path, MAX_PATH, NULL );
325 params->SourcePath = src_path;
329 /***********************************************************************
330 * get_destination_dir
332 * Retrieve the destination dir for a given section.
334 static WCHAR *get_destination_dir( HINF hinf, const WCHAR *section )
336 INFCONTEXT context;
337 WCHAR systemdir[MAX_PATH], *dir;
338 BOOL ret;
340 if (!section || !(ret = SetupFindFirstLineW( hinf, L"DestinationDirs", section, &context )))
341 ret = SetupFindFirstLineW( hinf, L"DestinationDirs", L"DefaultDestDir", &context );
343 if (ret && (dir = PARSER_get_dest_dir( &context )))
344 return dir;
346 GetSystemDirectoryW( systemdir, MAX_PATH );
347 return strdupW( systemdir );
350 struct extract_cab_ctx
352 const WCHAR *src;
353 const WCHAR *dst;
356 static UINT WINAPI extract_cab_cb( void *arg, UINT message, UINT_PTR param1, UINT_PTR param2 )
358 struct extract_cab_ctx *ctx = arg;
360 switch (message)
362 case SPFILENOTIFY_FILEINCABINET:
364 FILE_IN_CABINET_INFO_W *info = (FILE_IN_CABINET_INFO_W *)param1;
365 const WCHAR *filename;
367 if ((filename = wcsrchr( info->NameInCabinet, '\\' )))
368 filename++;
369 else
370 filename = info->NameInCabinet;
372 if (lstrcmpiW( filename, ctx->src ))
373 return FILEOP_SKIP;
375 lstrcpyW( info->FullTargetName, ctx->dst );
376 return FILEOP_DOIT;
378 case SPFILENOTIFY_FILEEXTRACTED:
380 const FILEPATHS_W *paths = (const FILEPATHS_W *)param1;
381 return paths->Win32Error;
383 case SPFILENOTIFY_NEEDNEWCABINET:
385 const CABINET_INFO_W *info = (const CABINET_INFO_W *)param1;
386 lstrcpyW( (WCHAR *)param2, info->CabinetPath );
387 return ERROR_SUCCESS;
389 case SPFILENOTIFY_CABINETINFO:
390 return 0;
391 default:
392 FIXME("Unexpected message %#x.\n", message);
393 return 0;
397 /***********************************************************************
398 * extract_cabinet_file
400 * Extract a file from a .cab file.
402 static BOOL extract_cabinet_file( const WCHAR *cabinet, const WCHAR *root,
403 const WCHAR *src, const WCHAR *dst )
405 struct extract_cab_ctx ctx = {src, dst};
406 int len = lstrlenW( cabinet );
407 WCHAR path[MAX_PATH];
409 /* make sure the cabinet file has a .cab extension */
410 if (len <= 4 || wcsicmp( cabinet + len - 4, L".cab" )) return FALSE;
412 lstrcpyW(path, root);
413 lstrcatW(path, L"\\" );
414 lstrcatW(path, cabinet);
416 return SetupIterateCabinetW( path, 0, extract_cab_cb, &ctx );
419 /***********************************************************************
420 * SetupOpenFileQueue (SETUPAPI.@)
422 HSPFILEQ WINAPI SetupOpenFileQueue(void)
424 struct file_queue *queue;
426 if (!(queue = HeapAlloc( GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*queue))))
427 return INVALID_HANDLE_VALUE;
428 queue->magic = FILE_QUEUE_MAGIC;
429 return queue;
433 /***********************************************************************
434 * SetupCloseFileQueue (SETUPAPI.@)
436 BOOL WINAPI SetupCloseFileQueue( HSPFILEQ handle )
438 struct file_queue *queue = handle;
439 unsigned int i;
441 /* Windows XP DDK installer passes the handle returned from
442 * SetupInitDefaultQueueCallback() to this function. */
443 if (queue->magic != FILE_QUEUE_MAGIC)
445 SetLastError(ERROR_INVALID_HANDLE);
446 return FALSE;
449 free_file_op_queue( &queue->copy_queue );
450 free_file_op_queue( &queue->rename_queue );
451 free_file_op_queue( &queue->delete_queue );
452 for (i = 0; i < queue->source_count; ++i)
454 heap_free( queue->sources[i]->desc );
455 heap_free( queue->sources[i]->tag );
456 heap_free( queue->sources[i] );
458 heap_free( queue->sources );
459 HeapFree( GetProcessHeap(), 0, queue );
460 return TRUE;
464 /***********************************************************************
465 * SetupQueueCopyIndirectA (SETUPAPI.@)
467 BOOL WINAPI SetupQueueCopyIndirectA( SP_FILE_COPY_PARAMS_A *paramsA )
469 SP_FILE_COPY_PARAMS_W paramsW;
470 BOOL ret;
472 paramsW.cbSize = sizeof(paramsW);
473 paramsW.QueueHandle = paramsA->QueueHandle;
474 paramsW.SourceRootPath = strdupAtoW( paramsA->SourceRootPath );
475 paramsW.SourcePath = strdupAtoW( paramsA->SourcePath );
476 paramsW.SourceFilename = strdupAtoW( paramsA->SourceFilename );
477 paramsW.SourceDescription = strdupAtoW( paramsA->SourceDescription );
478 paramsW.SourceTagfile = strdupAtoW( paramsA->SourceTagfile );
479 paramsW.TargetDirectory = strdupAtoW( paramsA->TargetDirectory );
480 paramsW.TargetFilename = strdupAtoW( paramsA->TargetFilename );
481 paramsW.CopyStyle = paramsA->CopyStyle;
482 paramsW.LayoutInf = paramsA->LayoutInf;
483 paramsW.SecurityDescriptor = strdupAtoW( paramsA->SecurityDescriptor );
485 ret = SetupQueueCopyIndirectW( &paramsW );
487 heap_free( (WCHAR *)paramsW.SourceRootPath );
488 heap_free( (WCHAR *)paramsW.SourcePath );
489 heap_free( (WCHAR *)paramsW.SourceFilename );
490 heap_free( (WCHAR *)paramsW.SourceDescription );
491 heap_free( (WCHAR *)paramsW.SourceTagfile );
492 heap_free( (WCHAR *)paramsW.TargetDirectory );
493 heap_free( (WCHAR *)paramsW.TargetFilename );
494 heap_free( (WCHAR *)paramsW.SecurityDescriptor );
495 return ret;
498 static BOOL equal_str(const WCHAR *a, const WCHAR *b)
500 return (!a && !b) || (a && b && !wcscmp(a, b));
503 static struct source_media *get_source_media(struct file_queue *queue,
504 const WCHAR *root, const WCHAR *desc, const WCHAR *tag)
506 unsigned int i;
508 for (i = 0; i < queue->source_count; ++i)
510 if (!wcscmp(root, queue->sources[i]->root)
511 && equal_str(desc, queue->sources[i]->desc)
512 && equal_str(tag, queue->sources[i]->tag))
514 return queue->sources[i];
518 queue->sources = heap_realloc( queue->sources, ++queue->source_count * sizeof(*queue->sources) );
519 queue->sources[i] = heap_alloc( sizeof(*queue->sources[i]) );
520 lstrcpyW(queue->sources[i]->root, root);
521 queue->sources[i]->desc = strdupW(desc);
522 queue->sources[i]->tag = strdupW(tag);
523 queue->sources[i]->resolved = FALSE;
524 queue->sources[i]->cabinet = FALSE;
526 return queue->sources[i];
529 /***********************************************************************
530 * SetupQueueCopyIndirectW (SETUPAPI.@)
532 BOOL WINAPI SetupQueueCopyIndirectW( PSP_FILE_COPY_PARAMS_W params )
534 struct file_queue *queue = params->QueueHandle;
535 struct file_op *op;
537 if (!(op = HeapAlloc( GetProcessHeap(), 0, sizeof(*op) ))) return FALSE;
538 op->style = params->CopyStyle;
539 op->src_path = strdupW( params->SourcePath );
540 op->src_file = strdupW( params->SourceFilename );
541 op->dst_path = strdupW( params->TargetDirectory );
542 op->dst_file = strdupW( params->TargetFilename );
544 /* some defaults */
545 if (!op->dst_file) op->dst_file = op->src_file;
546 if (params->LayoutInf)
547 FIXME("Unhandled LayoutInf %p.\n", params->LayoutInf);
549 op->media = get_source_media( queue, params->SourceRootPath ? params->SourceRootPath : L"",
550 params->SourceDescription, params->SourceTagfile );
552 TRACE( "root=%s path=%s file=%s -> dir=%s file=%s descr=%s tag=%s\n",
553 debugstr_w(op->media->root), debugstr_w(op->src_path), debugstr_w(op->src_file),
554 debugstr_w(op->dst_path), debugstr_w(op->dst_file),
555 debugstr_w(op->media->desc), debugstr_w(op->media->tag) );
557 queue_file_op( &queue->copy_queue, op );
558 return TRUE;
562 /***********************************************************************
563 * SetupQueueCopyA (SETUPAPI.@)
565 BOOL WINAPI SetupQueueCopyA( HSPFILEQ queue, PCSTR src_root, PCSTR src_path, PCSTR src_file,
566 PCSTR src_descr, PCSTR src_tag, PCSTR dst_dir, PCSTR dst_file,
567 DWORD style )
569 SP_FILE_COPY_PARAMS_A params;
571 params.cbSize = sizeof(params);
572 params.QueueHandle = queue;
573 params.SourceRootPath = src_root;
574 params.SourcePath = src_path;
575 params.SourceFilename = src_file;
576 params.SourceDescription = src_descr;
577 params.SourceTagfile = src_tag;
578 params.TargetDirectory = dst_dir;
579 params.TargetFilename = dst_file;
580 params.CopyStyle = style;
581 params.LayoutInf = 0;
582 params.SecurityDescriptor = NULL;
583 return SetupQueueCopyIndirectA( &params );
587 /***********************************************************************
588 * SetupQueueCopyW (SETUPAPI.@)
590 BOOL WINAPI SetupQueueCopyW( HSPFILEQ queue, PCWSTR src_root, PCWSTR src_path, PCWSTR src_file,
591 PCWSTR src_descr, PCWSTR src_tag, PCWSTR dst_dir, PCWSTR dst_file,
592 DWORD style )
594 SP_FILE_COPY_PARAMS_W params;
596 params.cbSize = sizeof(params);
597 params.QueueHandle = queue;
598 params.SourceRootPath = src_root;
599 params.SourcePath = src_path;
600 params.SourceFilename = src_file;
601 params.SourceDescription = src_descr;
602 params.SourceTagfile = src_tag;
603 params.TargetDirectory = dst_dir;
604 params.TargetFilename = dst_file;
605 params.CopyStyle = style;
606 params.LayoutInf = 0;
607 params.SecurityDescriptor = NULL;
608 return SetupQueueCopyIndirectW( &params );
612 /***********************************************************************
613 * SetupQueueDefaultCopyA (SETUPAPI.@)
615 BOOL WINAPI SetupQueueDefaultCopyA( HSPFILEQ queue, HINF hinf, const char *src_rootA,
616 const char *src_fileA, const char *dst_fileA, DWORD style )
618 WCHAR src_rootW[MAX_PATH], src_fileW[MAX_PATH], dst_fileW[MAX_PATH];
620 if (!src_rootA || !src_fileA || !dst_fileA)
622 SetLastError(ERROR_INVALID_PARAMETER);
623 return FALSE;
626 MultiByteToWideChar( CP_ACP, 0, src_rootA, -1, src_rootW, ARRAY_SIZE(src_rootW) );
627 MultiByteToWideChar( CP_ACP, 0, src_fileA, -1, src_fileW, ARRAY_SIZE(src_fileW) );
628 MultiByteToWideChar( CP_ACP, 0, dst_fileA, -1, dst_fileW, ARRAY_SIZE(dst_fileW) );
629 return SetupQueueDefaultCopyW( queue, hinf, src_rootW, src_fileW, dst_fileW, style );
633 /***********************************************************************
634 * SetupQueueDefaultCopyW (SETUPAPI.@)
636 BOOL WINAPI SetupQueueDefaultCopyW( HSPFILEQ queue, HINF hinf, PCWSTR src_root, PCWSTR src_file,
637 PCWSTR dst_file, DWORD style )
639 WCHAR src_root_buffer[MAX_PATH], src_path[MAX_PATH];
640 SP_FILE_COPY_PARAMS_W params;
641 BOOL ret;
643 if (!src_root || !src_file || !dst_file)
645 SetLastError(ERROR_INVALID_PARAMETER);
646 return FALSE;
649 params.cbSize = sizeof(params);
650 params.QueueHandle = queue;
651 params.SourceRootPath = src_root_buffer;
652 params.SourcePath = NULL;
653 params.SourceFilename = src_file;
654 params.SourceDescription = NULL;
655 params.SourceTagfile = NULL;
656 params.TargetFilename = dst_file;
657 params.CopyStyle = style;
658 params.LayoutInf = NULL;
659 params.SecurityDescriptor = NULL;
661 lstrcpyW( src_root_buffer, src_root );
662 src_path[0] = 0;
663 if (!(params.TargetDirectory = get_destination_dir( hinf, NULL ))) return FALSE;
664 get_source_info( hinf, src_file, &params, src_root_buffer, src_path );
666 ret = SetupQueueCopyIndirectW( &params );
668 heap_free( (WCHAR *)params.TargetDirectory );
669 heap_free( (WCHAR *)params.SourceDescription );
670 heap_free( (WCHAR *)params.SourceTagfile );
671 return ret;
675 /***********************************************************************
676 * SetupQueueDeleteA (SETUPAPI.@)
678 BOOL WINAPI SetupQueueDeleteA( HSPFILEQ handle, PCSTR part1, PCSTR part2 )
680 struct file_queue *queue = handle;
681 struct file_op *op;
683 if (!(op = heap_alloc_zero( sizeof(*op) ))) return FALSE;
684 op->dst_path = strdupAtoW( part1 );
685 op->dst_file = strdupAtoW( part2 );
686 queue_file_op( &queue->delete_queue, op );
687 return TRUE;
691 /***********************************************************************
692 * SetupQueueDeleteW (SETUPAPI.@)
694 BOOL WINAPI SetupQueueDeleteW( HSPFILEQ handle, PCWSTR part1, PCWSTR part2 )
696 struct file_queue *queue = handle;
697 struct file_op *op;
699 if (!(op = heap_alloc_zero( sizeof(*op) ))) return FALSE;
700 op->dst_path = strdupW( part1 );
701 op->dst_file = strdupW( part2 );
702 queue_file_op( &queue->delete_queue, op );
703 return TRUE;
707 /***********************************************************************
708 * SetupQueueRenameA (SETUPAPI.@)
710 BOOL WINAPI SetupQueueRenameA( HSPFILEQ handle, PCSTR SourcePath, PCSTR SourceFilename,
711 PCSTR TargetPath, PCSTR TargetFilename )
713 struct file_queue *queue = handle;
714 struct file_op *op;
716 if (!(op = heap_alloc_zero( sizeof(*op) ))) return FALSE;
717 op->src_path = strdupAtoW( SourcePath );
718 op->src_file = strdupAtoW( SourceFilename );
719 op->dst_path = strdupAtoW( TargetPath );
720 op->dst_file = strdupAtoW( TargetFilename );
721 queue_file_op( &queue->rename_queue, op );
722 return TRUE;
726 /***********************************************************************
727 * SetupQueueRenameW (SETUPAPI.@)
729 BOOL WINAPI SetupQueueRenameW( HSPFILEQ handle, PCWSTR SourcePath, PCWSTR SourceFilename,
730 PCWSTR TargetPath, PCWSTR TargetFilename )
732 struct file_queue *queue = handle;
733 struct file_op *op;
735 if (!(op = heap_alloc_zero( sizeof(*op) ))) return FALSE;
736 op->src_path = strdupW( SourcePath );
737 op->src_file = strdupW( SourceFilename );
738 op->dst_path = strdupW( TargetPath );
739 op->dst_file = strdupW( TargetFilename );
740 queue_file_op( &queue->rename_queue, op );
741 return TRUE;
745 /***********************************************************************
746 * SetupQueueCopySectionA (SETUPAPI.@)
748 BOOL WINAPI SetupQueueCopySectionA( HSPFILEQ queue, PCSTR src_root, HINF hinf, HINF hlist,
749 PCSTR section, DWORD style )
751 UNICODE_STRING sectionW;
752 BOOL ret = FALSE;
754 if (!RtlCreateUnicodeStringFromAsciiz( &sectionW, section ))
756 SetLastError( ERROR_NOT_ENOUGH_MEMORY );
757 return FALSE;
759 if (!src_root)
760 ret = SetupQueueCopySectionW( queue, NULL, hinf, hlist, sectionW.Buffer, style );
761 else
763 UNICODE_STRING srcW;
764 if (RtlCreateUnicodeStringFromAsciiz( &srcW, src_root ))
766 ret = SetupQueueCopySectionW( queue, srcW.Buffer, hinf, hlist, sectionW.Buffer, style );
767 RtlFreeUnicodeString( &srcW );
769 else SetLastError( ERROR_NOT_ENOUGH_MEMORY );
771 RtlFreeUnicodeString( &sectionW );
772 return ret;
775 /***********************************************************************
776 * SetupQueueCopySectionW (SETUPAPI.@)
778 BOOL WINAPI SetupQueueCopySectionW( HSPFILEQ queue, PCWSTR src_root, HINF hinf, HINF hlist,
779 PCWSTR section, DWORD style )
781 WCHAR src_root_buffer[MAX_PATH], src_path[MAX_PATH], src_file[MAX_PATH], dst_file[MAX_PATH], *dest_dir;
782 INFCONTEXT context;
783 SP_FILE_COPY_PARAMS_W params;
784 INT flags;
785 BOOL ret = FALSE;
786 DWORD len;
788 TRACE("queue %p, src_root %s, hinf %p, hlist %p, section %s, style %#x.\n",
789 queue, debugstr_w(src_root), hinf, hlist, debugstr_w(section), style);
791 if (!src_root)
793 SetLastError(ERROR_INVALID_PARAMETER);
794 return FALSE;
797 params.cbSize = sizeof(params);
798 params.QueueHandle = queue;
799 params.SourceRootPath = src_root_buffer;
800 params.SourceFilename = src_file;
801 params.TargetFilename = dst_file;
802 params.CopyStyle = style;
803 params.LayoutInf = NULL;
804 params.SecurityDescriptor = NULL;
806 lstrcpyW( src_root_buffer, src_root );
808 if (!hlist) hlist = hinf;
809 if (!hinf) hinf = hlist;
810 if (!SetupFindFirstLineW( hlist, section, NULL, &context )) return FALSE;
811 if (!(params.TargetDirectory = dest_dir = get_destination_dir( hinf, section ))) return FALSE;
814 params.SourcePath = NULL;
815 params.SourceDescription = NULL;
816 params.SourceTagfile = NULL;
817 lstrcpyW( src_root_buffer, src_root );
818 src_path[0] = 0;
820 if (!SetupGetStringFieldW( &context, 1, dst_file, ARRAY_SIZE( dst_file ), NULL ))
821 goto end;
822 if (!SetupGetStringFieldW( &context, 2, src_file, ARRAY_SIZE( src_file ), &len ) || len <= sizeof(WCHAR))
823 lstrcpyW( src_file, dst_file );
825 if (!SetupGetIntField( &context, 4, &flags )) flags = 0; /* FIXME */
827 get_source_info( hinf, src_file, &params, src_root_buffer, src_path );
829 if (!SetupQueueCopyIndirectW( &params )) goto end;
831 heap_free( (WCHAR *)params.SourceDescription );
832 heap_free( (WCHAR *)params.SourceTagfile );
833 } while (SetupFindNextLine( &context, &context ));
834 ret = TRUE;
836 end:
837 HeapFree(GetProcessHeap(), 0, dest_dir);
838 return ret;
842 /***********************************************************************
843 * SetupQueueDeleteSectionA (SETUPAPI.@)
845 BOOL WINAPI SetupQueueDeleteSectionA( HSPFILEQ queue, HINF hinf, HINF hlist, PCSTR section )
847 UNICODE_STRING sectionW;
848 BOOL ret = FALSE;
850 if (RtlCreateUnicodeStringFromAsciiz( &sectionW, section ))
852 ret = SetupQueueDeleteSectionW( queue, hinf, hlist, sectionW.Buffer );
853 RtlFreeUnicodeString( &sectionW );
855 else SetLastError( ERROR_NOT_ENOUGH_MEMORY );
856 return ret;
860 /***********************************************************************
861 * SetupQueueDeleteSectionW (SETUPAPI.@)
863 BOOL WINAPI SetupQueueDeleteSectionW( HSPFILEQ queue, HINF hinf, HINF hlist, PCWSTR section )
865 INFCONTEXT context;
866 WCHAR *dest_dir;
867 WCHAR buffer[MAX_PATH];
868 BOOL ret = FALSE;
869 INT flags;
871 TRACE( "hinf=%p/%p section=%s\n", hinf, hlist, debugstr_w(section) );
873 if (!hlist) hlist = hinf;
874 if (!SetupFindFirstLineW( hlist, section, NULL, &context )) return FALSE;
875 if (!(dest_dir = get_destination_dir( hinf, section ))) return FALSE;
878 if (!SetupGetStringFieldW( &context, 1, buffer, ARRAY_SIZE( buffer ), NULL ))
879 goto done;
880 if (!SetupGetIntField( &context, 4, &flags )) flags = 0;
881 if (!SetupQueueDeleteW( queue, dest_dir, buffer )) goto done;
882 } while (SetupFindNextLine( &context, &context ));
884 ret = TRUE;
885 done:
886 HeapFree( GetProcessHeap(), 0, dest_dir );
887 return ret;
891 /***********************************************************************
892 * SetupQueueRenameSectionA (SETUPAPI.@)
894 BOOL WINAPI SetupQueueRenameSectionA( HSPFILEQ queue, HINF hinf, HINF hlist, PCSTR section )
896 UNICODE_STRING sectionW;
897 BOOL ret = FALSE;
899 if (RtlCreateUnicodeStringFromAsciiz( &sectionW, section ))
901 ret = SetupQueueRenameSectionW( queue, hinf, hlist, sectionW.Buffer );
902 RtlFreeUnicodeString( &sectionW );
904 else SetLastError( ERROR_NOT_ENOUGH_MEMORY );
905 return ret;
909 /***********************************************************************
910 * SetupQueueRenameSectionW (SETUPAPI.@)
912 BOOL WINAPI SetupQueueRenameSectionW( HSPFILEQ queue, HINF hinf, HINF hlist, PCWSTR section )
914 INFCONTEXT context;
915 WCHAR *dest_dir;
916 WCHAR src[MAX_PATH], dst[MAX_PATH];
917 BOOL ret = FALSE;
919 TRACE( "hinf=%p/%p section=%s\n", hinf, hlist, debugstr_w(section) );
921 if (!hlist) hlist = hinf;
922 if (!SetupFindFirstLineW( hlist, section, NULL, &context )) return FALSE;
923 if (!(dest_dir = get_destination_dir( hinf, section ))) return FALSE;
926 if (!SetupGetStringFieldW( &context, 1, dst, ARRAY_SIZE( dst ), NULL ))
927 goto done;
928 if (!SetupGetStringFieldW( &context, 2, src, ARRAY_SIZE( src ), NULL ))
929 goto done;
930 if (!SetupQueueRenameW( queue, dest_dir, src, NULL, dst )) goto done;
931 } while (SetupFindNextLine( &context, &context ));
933 ret = TRUE;
934 done:
935 HeapFree( GetProcessHeap(), 0, dest_dir );
936 return ret;
940 /***********************************************************************
941 * SetupCommitFileQueueA (SETUPAPI.@)
943 BOOL WINAPI SetupCommitFileQueueA( HWND owner, HSPFILEQ queue, PSP_FILE_CALLBACK_A handler,
944 PVOID context )
946 struct callback_WtoA_context ctx;
948 ctx.orig_context = context;
949 ctx.orig_handler = handler;
950 return SetupCommitFileQueueW( owner, queue, QUEUE_callback_WtoA, &ctx );
954 /***********************************************************************
955 * create_full_pathW
957 * Recursively create all directories in the path.
959 static BOOL create_full_pathW(const WCHAR *path)
961 BOOL ret = TRUE;
962 int len;
963 WCHAR *new_path;
965 new_path = HeapAlloc(GetProcessHeap(), 0, (lstrlenW(path) + 1) * sizeof(WCHAR));
966 lstrcpyW(new_path, path);
968 while((len = lstrlenW(new_path)) && new_path[len - 1] == '\\')
969 new_path[len - 1] = 0;
971 while(!CreateDirectoryW(new_path, NULL))
973 WCHAR *slash;
974 DWORD last_error = GetLastError();
976 if(last_error == ERROR_ALREADY_EXISTS)
977 break;
979 if(last_error != ERROR_PATH_NOT_FOUND)
981 ret = FALSE;
982 break;
985 if(!(slash = wcsrchr(new_path, '\\')))
987 ret = FALSE;
988 break;
991 len = slash - new_path;
992 new_path[len] = 0;
993 if(!create_full_pathW(new_path))
995 ret = FALSE;
996 break;
998 new_path[len] = '\\';
1001 HeapFree(GetProcessHeap(), 0, new_path);
1002 return ret;
1005 static BOOL do_file_copyW( LPCWSTR source, LPCWSTR target, DWORD style,
1006 PSP_FILE_CALLBACK_W handler, PVOID context )
1008 BOOL rc = FALSE;
1009 BOOL docopy = TRUE;
1011 TRACE("copy %s to %s style 0x%x\n",debugstr_w(source),debugstr_w(target),style);
1013 /* before copy processing */
1014 if (style & SP_COPY_REPLACEONLY)
1016 if (GetFileAttributesW(target) == INVALID_FILE_ATTRIBUTES)
1017 docopy = FALSE;
1019 if (style & (SP_COPY_NEWER_OR_SAME | SP_COPY_NEWER_ONLY | SP_COPY_FORCE_NEWER))
1021 DWORD VersionSizeSource=0;
1022 DWORD VersionSizeTarget=0;
1023 DWORD zero=0;
1026 * This is sort of an interesting workaround. You see, calling
1027 * GetVersionInfoSize on a builtin dll loads that dll into memory
1028 * and we do not properly unload builtin dlls.. so we effectively
1029 * lock into memory all the targets we are replacing. This leads
1030 * to problems when we try to register the replaced dlls.
1032 * So I will test for the existence of the files first so that
1033 * we just basically unconditionally replace the builtin versions.
1035 if ((GetFileAttributesW(target) != INVALID_FILE_ATTRIBUTES) &&
1036 (GetFileAttributesW(source) != INVALID_FILE_ATTRIBUTES))
1038 VersionSizeSource = GetFileVersionInfoSizeW(source,&zero);
1039 VersionSizeTarget = GetFileVersionInfoSizeW(target,&zero);
1042 if (VersionSizeSource && VersionSizeTarget)
1044 LPVOID VersionSource;
1045 LPVOID VersionTarget;
1046 VS_FIXEDFILEINFO *TargetInfo;
1047 VS_FIXEDFILEINFO *SourceInfo;
1048 UINT length;
1049 DWORD ret;
1051 VersionSource = HeapAlloc(GetProcessHeap(),0,VersionSizeSource);
1052 VersionTarget = HeapAlloc(GetProcessHeap(),0,VersionSizeTarget);
1054 ret = GetFileVersionInfoW(source,0,VersionSizeSource,VersionSource);
1055 if (ret)
1056 ret = GetFileVersionInfoW(target, 0, VersionSizeTarget,
1057 VersionTarget);
1059 if (ret)
1061 ret = VerQueryValueW(VersionSource, L"\\", (LPVOID*)&SourceInfo, &length);
1062 if (ret)
1063 ret = VerQueryValueW(VersionTarget, L"\\", (LPVOID*)&TargetInfo, &length);
1065 if (ret)
1067 FILEPATHS_W filepaths;
1069 TRACE("Versions: Source %i.%i target %i.%i\n",
1070 SourceInfo->dwFileVersionMS, SourceInfo->dwFileVersionLS,
1071 TargetInfo->dwFileVersionMS, TargetInfo->dwFileVersionLS);
1073 /* used in case of notification */
1074 filepaths.Target = target;
1075 filepaths.Source = source;
1076 filepaths.Win32Error = 0;
1077 filepaths.Flags = 0;
1079 if (TargetInfo->dwFileVersionMS > SourceInfo->dwFileVersionMS)
1081 if (handler)
1082 docopy = handler (context, SPFILENOTIFY_TARGETNEWER, (UINT_PTR)&filepaths, 0);
1083 else
1084 docopy = FALSE;
1086 else if ((TargetInfo->dwFileVersionMS == SourceInfo->dwFileVersionMS)
1087 && (TargetInfo->dwFileVersionLS > SourceInfo->dwFileVersionLS))
1089 if (handler)
1090 docopy = handler (context, SPFILENOTIFY_TARGETNEWER, (UINT_PTR)&filepaths, 0);
1091 else
1092 docopy = FALSE;
1094 else if ((style & SP_COPY_NEWER_ONLY) &&
1095 (TargetInfo->dwFileVersionMS ==
1096 SourceInfo->dwFileVersionMS)
1097 &&(TargetInfo->dwFileVersionLS ==
1098 SourceInfo->dwFileVersionLS))
1100 if (handler)
1101 docopy = handler (context, SPFILENOTIFY_TARGETNEWER, (UINT_PTR)&filepaths, 0);
1102 else
1103 docopy = FALSE;
1107 HeapFree(GetProcessHeap(),0,VersionSource);
1108 HeapFree(GetProcessHeap(),0,VersionTarget);
1111 if (style & (SP_COPY_NOOVERWRITE | SP_COPY_FORCE_NOOVERWRITE))
1113 if (GetFileAttributesW(target) != INVALID_FILE_ATTRIBUTES)
1115 FIXME("Notify user target file exists\n");
1116 docopy = FALSE;
1119 if (style & (SP_COPY_NODECOMP | SP_COPY_LANGUAGEAWARE | SP_COPY_FORCE_IN_USE |
1120 SP_COPY_NOSKIP | SP_COPY_WARNIFSKIP))
1122 ERR("Unsupported style(s) 0x%x\n",style);
1125 if (docopy)
1127 rc = CopyFileW(source,target,FALSE);
1128 if (!rc && GetLastError() == ERROR_SHARING_VIOLATION &&
1129 (style & SP_COPY_IN_USE_NEEDS_REBOOT))
1131 WCHAR temp_file[MAX_PATH];
1132 WCHAR temp[MAX_PATH];
1134 if (GetTempPathW(MAX_PATH, temp) &&
1135 GetTempFileNameW(temp, L"SET", 0, temp_file))
1137 rc = CopyFileW(source, temp_file, FALSE);
1138 if (rc)
1139 rc = MoveFileExW(temp_file, target, MOVEFILE_DELAY_UNTIL_REBOOT);
1140 else
1141 DeleteFileW(temp_file);
1144 if (!rc) WARN( "failed to copy, err %u\n", GetLastError() );
1146 else
1147 SetLastError(ERROR_SUCCESS);
1149 /* after copy processing */
1150 if (style & SP_COPY_DELETESOURCE)
1152 if (rc)
1153 DeleteFileW(source);
1156 return rc;
1159 /***********************************************************************
1160 * SetupInstallFileExA (SETUPAPI.@)
1162 BOOL WINAPI SetupInstallFileExA( HINF hinf, PINFCONTEXT inf_context, PCSTR source, PCSTR root,
1163 PCSTR dest, DWORD style, PSP_FILE_CALLBACK_A handler, PVOID context, PBOOL in_use )
1165 BOOL ret = FALSE;
1166 struct callback_WtoA_context ctx;
1167 UNICODE_STRING sourceW, rootW, destW;
1169 TRACE("%p %p %s %s %s %x %p %p %p\n", hinf, inf_context, debugstr_a(source), debugstr_a(root),
1170 debugstr_a(dest), style, handler, context, in_use);
1172 sourceW.Buffer = rootW.Buffer = destW.Buffer = NULL;
1173 if (source && !RtlCreateUnicodeStringFromAsciiz( &sourceW, source ))
1175 SetLastError( ERROR_NOT_ENOUGH_MEMORY );
1176 return FALSE;
1178 if (root && !RtlCreateUnicodeStringFromAsciiz( &rootW, root ))
1180 SetLastError( ERROR_NOT_ENOUGH_MEMORY );
1181 goto exit;
1183 if (dest && !RtlCreateUnicodeStringFromAsciiz( &destW, dest ))
1185 SetLastError( ERROR_NOT_ENOUGH_MEMORY );
1186 goto exit;
1189 ctx.orig_context = context;
1190 ctx.orig_handler = handler;
1192 ret = SetupInstallFileExW( hinf, inf_context, sourceW.Buffer, rootW.Buffer, destW.Buffer, style, QUEUE_callback_WtoA, &ctx, in_use );
1194 exit:
1195 RtlFreeUnicodeString( &sourceW );
1196 RtlFreeUnicodeString( &rootW );
1197 RtlFreeUnicodeString( &destW );
1198 return ret;
1201 /***********************************************************************
1202 * SetupInstallFileA (SETUPAPI.@)
1204 BOOL WINAPI SetupInstallFileA( HINF hinf, PINFCONTEXT inf_context, PCSTR source, PCSTR root,
1205 PCSTR dest, DWORD style, PSP_FILE_CALLBACK_A handler, PVOID context )
1207 return SetupInstallFileExA( hinf, inf_context, source, root, dest, style, handler, context, NULL );
1210 /***********************************************************************
1211 * SetupInstallFileExW (SETUPAPI.@)
1213 BOOL WINAPI SetupInstallFileExW( HINF hinf, PINFCONTEXT inf_context, PCWSTR source, PCWSTR root,
1214 PCWSTR dest, DWORD style, PSP_FILE_CALLBACK_W handler, PVOID context, PBOOL in_use )
1216 BOOL ret, absolute = (root && *root && !(style & SP_COPY_SOURCE_ABSOLUTE));
1217 WCHAR *buffer, *p, *inf_source = NULL, dest_path[MAX_PATH];
1218 unsigned int len;
1220 TRACE("%p %p %s %s %s %x %p %p %p\n", hinf, inf_context, debugstr_w(source), debugstr_w(root),
1221 debugstr_w(dest), style, handler, context, in_use);
1223 if (in_use) FIXME("no file in use support\n");
1225 dest_path[0] = 0;
1227 if (hinf)
1229 WCHAR *dest_dir;
1230 INFCONTEXT ctx;
1232 if (!inf_context)
1234 inf_context = &ctx;
1235 if (!SetupFindFirstLineW( hinf, L"CopyFiles", NULL, inf_context )) return FALSE;
1237 if (!SetupGetStringFieldW( inf_context, 1, NULL, 0, &len )) return FALSE;
1238 if (!(inf_source = HeapAlloc( GetProcessHeap(), 0, len * sizeof(WCHAR) )))
1240 SetLastError( ERROR_NOT_ENOUGH_MEMORY );
1241 return FALSE;
1243 if (!SetupGetStringFieldW( inf_context, 1, inf_source, len, NULL ))
1245 HeapFree( GetProcessHeap(), 0, inf_source );
1246 return FALSE;
1248 source = inf_source;
1250 if ((dest_dir = get_destination_dir( hinf, NULL )))
1252 lstrcpyW( dest_path, dest_dir );
1253 lstrcatW( dest_path, L"\\" );
1254 heap_free( dest_dir );
1257 else if (!source)
1259 SetLastError( ERROR_INVALID_PARAMETER );
1260 return FALSE;
1263 len = lstrlenW( source ) + 1;
1264 if (absolute) len += lstrlenW( root ) + 1;
1266 if (!(p = buffer = HeapAlloc( GetProcessHeap(), 0, len * sizeof(WCHAR) )))
1268 HeapFree( GetProcessHeap(), 0, inf_source );
1269 SetLastError( ERROR_NOT_ENOUGH_MEMORY );
1270 return FALSE;
1273 if (absolute)
1275 lstrcpyW( buffer, root );
1276 p += lstrlenW( buffer );
1277 if (p[-1] != '\\') *p++ = '\\';
1279 while (*source == '\\') source++;
1280 lstrcpyW( p, source );
1282 lstrcatW( dest_path, dest );
1284 ret = do_file_copyW( buffer, dest_path, style, handler, context );
1286 HeapFree( GetProcessHeap(), 0, inf_source );
1287 HeapFree( GetProcessHeap(), 0, buffer );
1288 return ret;
1291 /***********************************************************************
1292 * SetupInstallFileW (SETUPAPI.@)
1294 BOOL WINAPI SetupInstallFileW( HINF hinf, PINFCONTEXT inf_context, PCWSTR source, PCWSTR root,
1295 PCWSTR dest, DWORD style, PSP_FILE_CALLBACK_W handler, PVOID context )
1297 return SetupInstallFileExW( hinf, inf_context, source, root, dest, style, handler, context, NULL );
1300 static BOOL queue_copy_file( const WCHAR *source, const WCHAR *dest,
1301 const struct file_op *op, PSP_FILE_CALLBACK_W handler, void *context )
1303 TRACE("copying file %s -> %s\n", debugstr_w(source), debugstr_w(dest));
1305 if (op->dst_path && !create_full_pathW(op->dst_path))
1306 return FALSE;
1308 if (do_file_copyW(source, dest, op->style, handler, context) || GetLastError() == ERROR_SUCCESS)
1309 return TRUE;
1311 /* try to extract it from the cabinet file */
1312 if (op->media->tag && extract_cabinet_file(op->media->tag, op->media->root, op->src_file, dest))
1314 op->media->cabinet = TRUE;
1315 return TRUE;
1318 return FALSE;
1321 /***********************************************************************
1322 * SetupCommitFileQueueW (SETUPAPI.@)
1324 BOOL WINAPI SetupCommitFileQueueW( HWND owner, HSPFILEQ handle, PSP_FILE_CALLBACK_W handler,
1325 PVOID context )
1327 struct file_queue *queue = handle;
1328 struct file_op *op;
1329 BOOL result = FALSE;
1330 FILEPATHS_W paths;
1331 UINT op_result;
1333 paths.Source = paths.Target = NULL;
1335 if (!queue->copy_queue.count && !queue->delete_queue.count && !queue->rename_queue.count)
1336 return TRUE; /* nothing to do */
1338 if (!handler( context, SPFILENOTIFY_STARTQUEUE, (UINT_PTR)owner, 0 )) return FALSE;
1340 /* perform deletes */
1342 if (queue->delete_queue.count)
1344 if (!(handler( context, SPFILENOTIFY_STARTSUBQUEUE, FILEOP_DELETE,
1345 queue->delete_queue.count ))) goto done;
1346 for (op = queue->delete_queue.head; op; op = op->next)
1348 build_filepathsW( op, &paths );
1349 op_result = handler( context, SPFILENOTIFY_STARTDELETE, (UINT_PTR)&paths, FILEOP_DELETE);
1350 if (op_result == FILEOP_ABORT) goto done;
1351 while (op_result == FILEOP_DOIT)
1353 TRACE( "deleting file %s\n", debugstr_w(paths.Target) );
1354 if (DeleteFileW( paths.Target )) break; /* success */
1355 paths.Win32Error = GetLastError();
1356 op_result = handler( context, SPFILENOTIFY_DELETEERROR, (UINT_PTR)&paths, 0 );
1357 if (op_result == FILEOP_ABORT) goto done;
1359 handler( context, SPFILENOTIFY_ENDDELETE, (UINT_PTR)&paths, 0 );
1361 handler( context, SPFILENOTIFY_ENDSUBQUEUE, FILEOP_DELETE, 0 );
1364 /* perform renames */
1366 if (queue->rename_queue.count)
1368 if (!(handler( context, SPFILENOTIFY_STARTSUBQUEUE, FILEOP_RENAME,
1369 queue->rename_queue.count ))) goto done;
1370 for (op = queue->rename_queue.head; op; op = op->next)
1372 build_filepathsW( op, &paths );
1373 op_result = handler( context, SPFILENOTIFY_STARTRENAME, (UINT_PTR)&paths, FILEOP_RENAME);
1374 if (op_result == FILEOP_ABORT) goto done;
1375 while (op_result == FILEOP_DOIT)
1377 TRACE( "renaming file %s -> %s\n",
1378 debugstr_w(paths.Source), debugstr_w(paths.Target) );
1379 if (MoveFileW( paths.Source, paths.Target )) break; /* success */
1380 paths.Win32Error = GetLastError();
1381 op_result = handler( context, SPFILENOTIFY_RENAMEERROR, (UINT_PTR)&paths, 0 );
1382 if (op_result == FILEOP_ABORT) goto done;
1384 handler( context, SPFILENOTIFY_ENDRENAME, (UINT_PTR)&paths, 0 );
1386 handler( context, SPFILENOTIFY_ENDSUBQUEUE, FILEOP_RENAME, 0 );
1389 /* perform copies */
1391 if (queue->copy_queue.count)
1393 if (!(handler( context, SPFILENOTIFY_STARTSUBQUEUE, FILEOP_COPY,
1394 queue->copy_queue.count ))) goto done;
1395 for (op = queue->copy_queue.head; op; op = op->next)
1397 WCHAR newpath[MAX_PATH];
1399 if (!op->media->resolved)
1401 /* The NEEDMEDIA callback asks for the folder containing the
1402 * first file, but that might be in a subdir of the source
1403 * disk's root directory. We have to do some contortions to
1404 * correct for this. Pretend that the file we're using
1405 * actually isn't in a subdirectory, but keep track of what it
1406 * was, and then later strip it from the root path that we
1407 * ultimately resolve the source disk to. */
1408 WCHAR src_path[MAX_PATH];
1409 size_t path_len = 0;
1411 src_path[0] = 0;
1412 if (op->src_path)
1414 lstrcpyW(src_path, op->src_path);
1415 path_len = lstrlenW(src_path);
1417 lstrcatW(op->media->root, L"\\");
1418 lstrcatW(op->media->root, op->src_path);
1420 heap_free(op->src_path);
1421 op->src_path = NULL;
1424 for (;;)
1426 SOURCE_MEDIA_W media;
1427 media.Reserved = NULL;
1428 media.Tagfile = op->media->tag;
1429 media.Description = op->media->desc;
1430 media.SourcePath = op->media->root;
1431 media.SourceFile = op->src_file;
1432 media.Flags = op->style & (SP_COPY_WARNIFSKIP | SP_COPY_NOSKIP | SP_FLAG_CABINETCONTINUATION | SP_COPY_NOBROWSE);
1434 newpath[0] = 0;
1435 op_result = handler( context, SPFILENOTIFY_NEEDMEDIA, (UINT_PTR)&media, (UINT_PTR)newpath );
1437 if (op_result == FILEOP_ABORT)
1438 goto done;
1439 else if (op_result == FILEOP_SKIP)
1440 break;
1441 else if (op_result == FILEOP_NEWPATH)
1442 lstrcpyW(op->media->root, newpath);
1443 else if (op_result != FILEOP_DOIT)
1444 FIXME("Unhandled return value %#x.\n", op_result);
1446 build_filepathsW( op, &paths );
1447 op_result = handler( context, SPFILENOTIFY_STARTCOPY, (UINT_PTR)&paths, FILEOP_COPY );
1448 if (op_result == FILEOP_ABORT)
1449 goto done;
1450 else if (op_result == FILEOP_SKIP)
1451 break;
1452 else if (op_result != FILEOP_DOIT)
1453 FIXME("Unhandled return value %#x.\n", op_result);
1455 if (queue_copy_file( paths.Source, paths.Target, op, handler, context ))
1457 if (path_len > 0 && !op->media->cabinet)
1459 size_t root_len = lstrlenW(op->media->root);
1460 if (path_len <= root_len && !wcsnicmp(op->media->root + root_len - path_len, src_path, path_len))
1461 op->media->root[root_len - path_len - 1] = 0;
1463 op->media->resolved = TRUE;
1464 handler( context, SPFILENOTIFY_ENDCOPY, (UINT_PTR)&paths, 0 );
1465 break;
1467 paths.Win32Error = GetLastError();
1468 if (paths.Win32Error == ERROR_PATH_NOT_FOUND ||
1469 paths.Win32Error == ERROR_FILE_NOT_FOUND)
1470 continue;
1472 newpath[0] = 0;
1473 op_result = handler( context, SPFILENOTIFY_COPYERROR, (UINT_PTR)&paths, (UINT_PTR)newpath );
1474 if (op_result == FILEOP_ABORT)
1475 goto done;
1476 else if (op_result == FILEOP_SKIP)
1477 break;
1478 else if (op_result == FILEOP_NEWPATH)
1480 lstrcpyW(op->media->root, newpath);
1481 build_filepathsW(op, &paths);
1483 else if (op_result != FILEOP_DOIT)
1484 FIXME("Unhandled return value %#x.\n", op_result);
1487 else
1489 build_filepathsW( op, &paths );
1490 op_result = handler( context, SPFILENOTIFY_STARTCOPY, (UINT_PTR)&paths, FILEOP_COPY );
1491 if (op_result == FILEOP_ABORT)
1492 goto done;
1493 else if (op_result == FILEOP_SKIP)
1494 continue;
1495 else if (op_result != FILEOP_DOIT)
1496 FIXME("Unhandled return value %#x.\n", op_result);
1498 while (op_result == FILEOP_DOIT || op_result == FILEOP_NEWPATH)
1500 if (queue_copy_file( paths.Source, paths.Target, op, handler, context ))
1501 break;
1503 paths.Win32Error = GetLastError();
1504 newpath[0] = 0;
1505 op_result = handler( context, SPFILENOTIFY_COPYERROR, (UINT_PTR)&paths, (UINT_PTR)newpath );
1506 if (op_result == FILEOP_ABORT)
1507 goto done;
1508 else if (op_result == FILEOP_NEWPATH)
1510 lstrcpyW(op->media->root, newpath);
1511 build_filepathsW(op, &paths);
1513 else if (op_result != FILEOP_SKIP && op_result != FILEOP_DOIT)
1514 FIXME("Unhandled return value %#x.\n", op_result);
1516 handler( context, SPFILENOTIFY_ENDCOPY, (UINT_PTR)&paths, 0 );
1519 handler( context, SPFILENOTIFY_ENDSUBQUEUE, FILEOP_COPY, 0 );
1523 result = TRUE;
1525 done:
1526 handler( context, SPFILENOTIFY_ENDQUEUE, result, 0 );
1527 HeapFree( GetProcessHeap(), 0, (void *)paths.Source );
1528 HeapFree( GetProcessHeap(), 0, (void *)paths.Target );
1529 return result;
1533 /***********************************************************************
1534 * SetupScanFileQueueA (SETUPAPI.@)
1536 BOOL WINAPI SetupScanFileQueueA( HSPFILEQ handle, DWORD flags, HWND window,
1537 PSP_FILE_CALLBACK_A handler, PVOID context, PDWORD result )
1539 struct callback_WtoA_context ctx;
1541 TRACE("%p %x %p %p %p %p\n", handle, flags, window, handler, context, result);
1543 ctx.orig_context = context;
1544 ctx.orig_handler = handler;
1546 return SetupScanFileQueueW( handle, flags, window, QUEUE_callback_WtoA, &ctx, result );
1550 /***********************************************************************
1551 * SetupScanFileQueueW (SETUPAPI.@)
1553 BOOL WINAPI SetupScanFileQueueW( HSPFILEQ handle, DWORD flags, HWND window,
1554 PSP_FILE_CALLBACK_W handler, PVOID context, PDWORD result )
1556 struct file_queue *queue = handle;
1557 struct file_op *op;
1558 FILEPATHS_W paths;
1559 UINT notification = 0;
1560 BOOL ret = FALSE;
1562 TRACE("%p %x %p %p %p %p\n", handle, flags, window, handler, context, result);
1564 if (!queue->copy_queue.count) return TRUE;
1566 if (flags & SPQ_SCAN_USE_CALLBACK) notification = SPFILENOTIFY_QUEUESCAN;
1567 else if (flags & SPQ_SCAN_USE_CALLBACKEX) notification = SPFILENOTIFY_QUEUESCAN_EX;
1569 if (flags & ~(SPQ_SCAN_USE_CALLBACK | SPQ_SCAN_USE_CALLBACKEX))
1571 FIXME("flags %x not fully implemented\n", flags);
1574 paths.Source = paths.Target = NULL;
1576 for (op = queue->copy_queue.head; op; op = op->next)
1578 build_filepathsW( op, &paths );
1579 switch (notification)
1581 case SPFILENOTIFY_QUEUESCAN:
1582 /* FIXME: handle delay flag */
1583 if (handler( context, notification, (UINT_PTR)paths.Target, 0 )) goto done;
1584 break;
1585 case SPFILENOTIFY_QUEUESCAN_EX:
1586 if (handler( context, notification, (UINT_PTR)&paths, 0 )) goto done;
1587 break;
1588 default:
1589 ret = TRUE; goto done;
1593 ret = TRUE;
1595 done:
1596 if (result) *result = 0;
1597 HeapFree( GetProcessHeap(), 0, (void *)paths.Source );
1598 HeapFree( GetProcessHeap(), 0, (void *)paths.Target );
1599 return ret;
1603 /***********************************************************************
1604 * SetupGetFileQueueCount (SETUPAPI.@)
1606 BOOL WINAPI SetupGetFileQueueCount( HSPFILEQ handle, UINT op, PUINT result )
1608 struct file_queue *queue = handle;
1610 switch(op)
1612 case FILEOP_COPY:
1613 *result = queue->copy_queue.count;
1614 return TRUE;
1615 case FILEOP_RENAME:
1616 *result = queue->rename_queue.count;
1617 return TRUE;
1618 case FILEOP_DELETE:
1619 *result = queue->delete_queue.count;
1620 return TRUE;
1622 return FALSE;
1626 /***********************************************************************
1627 * SetupGetFileQueueFlags (SETUPAPI.@)
1629 BOOL WINAPI SetupGetFileQueueFlags( HSPFILEQ handle, PDWORD flags )
1631 struct file_queue *queue = handle;
1632 *flags = queue->flags;
1633 return TRUE;
1637 /***********************************************************************
1638 * SetupSetFileQueueFlags (SETUPAPI.@)
1640 BOOL WINAPI SetupSetFileQueueFlags( HSPFILEQ handle, DWORD mask, DWORD flags )
1642 struct file_queue *queue = handle;
1643 queue->flags = (queue->flags & ~mask) | flags;
1644 return TRUE;
1648 /***********************************************************************
1649 * SetupSetFileQueueAlternatePlatformA (SETUPAPI.@)
1651 BOOL WINAPI SetupSetFileQueueAlternatePlatformA(HSPFILEQ handle, PSP_ALTPLATFORM_INFO platform, PCSTR catalogfile)
1653 FIXME("(%p, %p, %s) stub!\n", handle, platform, debugstr_a(catalogfile));
1654 return FALSE;
1658 /***********************************************************************
1659 * SetupSetFileQueueAlternatePlatformW (SETUPAPI.@)
1661 BOOL WINAPI SetupSetFileQueueAlternatePlatformW(HSPFILEQ handle, PSP_ALTPLATFORM_INFO platform, PCWSTR catalogfile)
1663 FIXME("(%p, %p, %s) stub!\n", handle, platform, debugstr_w(catalogfile));
1664 return FALSE;
1668 /***********************************************************************
1669 * SetupInitDefaultQueueCallback (SETUPAPI.@)
1671 PVOID WINAPI SetupInitDefaultQueueCallback( HWND owner )
1673 return SetupInitDefaultQueueCallbackEx( owner, 0, 0, 0, NULL );
1677 /***********************************************************************
1678 * SetupInitDefaultQueueCallbackEx (SETUPAPI.@)
1680 PVOID WINAPI SetupInitDefaultQueueCallbackEx( HWND owner, HWND progress, UINT msg,
1681 DWORD reserved1, PVOID reserved2 )
1683 struct default_callback_context *context;
1685 if ((context = HeapAlloc( GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*context) )))
1687 context->magic = 0x43515053; /* "SPQC" */
1688 context->owner = owner;
1689 context->progress = progress;
1690 context->message = msg;
1692 return context;
1696 /***********************************************************************
1697 * SetupTermDefaultQueueCallback (SETUPAPI.@)
1699 void WINAPI SetupTermDefaultQueueCallback( PVOID context )
1701 HeapFree( GetProcessHeap(), 0, context );
1705 /***********************************************************************
1706 * SetupDefaultQueueCallbackA (SETUPAPI.@)
1708 UINT WINAPI SetupDefaultQueueCallbackA( PVOID context, UINT notification,
1709 UINT_PTR param1, UINT_PTR param2 )
1711 FILEPATHS_A *paths = (FILEPATHS_A *)param1;
1712 struct default_callback_context *ctx = context;
1714 switch(notification)
1716 case SPFILENOTIFY_STARTQUEUE:
1717 TRACE( "start queue\n" );
1718 return TRUE;
1719 case SPFILENOTIFY_ENDQUEUE:
1720 TRACE( "end queue\n" );
1721 return 0;
1722 case SPFILENOTIFY_STARTSUBQUEUE:
1723 TRACE( "start subqueue %ld count %ld\n", param1, param2 );
1724 return TRUE;
1725 case SPFILENOTIFY_ENDSUBQUEUE:
1726 TRACE( "end subqueue %ld\n", param1 );
1727 return 0;
1728 case SPFILENOTIFY_STARTDELETE:
1729 TRACE( "start delete %s\n", debugstr_a(paths->Target) );
1730 return FILEOP_DOIT;
1731 case SPFILENOTIFY_ENDDELETE:
1732 TRACE( "end delete %s\n", debugstr_a(paths->Target) );
1733 return 0;
1734 case SPFILENOTIFY_DELETEERROR:
1735 /*Windows Ignores attempts to delete files / folders which do not exist*/
1736 if ((paths->Win32Error != ERROR_FILE_NOT_FOUND) && (paths->Win32Error != ERROR_PATH_NOT_FOUND))
1737 SetupDeleteErrorA(ctx->owner, NULL, paths->Target, paths->Win32Error, 0);
1738 return FILEOP_SKIP;
1739 case SPFILENOTIFY_STARTRENAME:
1740 TRACE( "start rename %s -> %s\n", debugstr_a(paths->Source), debugstr_a(paths->Target) );
1741 return FILEOP_DOIT;
1742 case SPFILENOTIFY_ENDRENAME:
1743 TRACE( "end rename %s -> %s\n", debugstr_a(paths->Source), debugstr_a(paths->Target) );
1744 return 0;
1745 case SPFILENOTIFY_RENAMEERROR:
1746 SetupRenameErrorA(ctx->owner, NULL, paths->Source, paths->Target, paths->Win32Error, 0);
1747 return FILEOP_SKIP;
1748 case SPFILENOTIFY_STARTCOPY:
1749 TRACE( "start copy %s -> %s\n", debugstr_a(paths->Source), debugstr_a(paths->Target) );
1750 return FILEOP_DOIT;
1751 case SPFILENOTIFY_ENDCOPY:
1752 TRACE( "end copy %s -> %s\n", debugstr_a(paths->Source), debugstr_a(paths->Target) );
1753 return 0;
1754 case SPFILENOTIFY_COPYERROR:
1755 ERR( "copy error %d %s -> %s\n", paths->Win32Error,
1756 debugstr_a(paths->Source), debugstr_a(paths->Target) );
1757 return FILEOP_SKIP;
1758 case SPFILENOTIFY_NEEDMEDIA:
1760 const SOURCE_MEDIA_A *media = (const SOURCE_MEDIA_A *)param1;
1761 TRACE( "need media %s %s\n", debugstr_a(media->SourcePath), debugstr_a(media->SourceFile) );
1762 strcpy( (char *)param2, media->SourcePath );
1763 return FILEOP_DOIT;
1765 default:
1766 FIXME( "notification %d params %lx,%lx\n", notification, param1, param2 );
1767 break;
1769 return 0;
1773 /***********************************************************************
1774 * SetupDefaultQueueCallbackW (SETUPAPI.@)
1776 UINT WINAPI SetupDefaultQueueCallbackW( PVOID context, UINT notification,
1777 UINT_PTR param1, UINT_PTR param2 )
1779 FILEPATHS_W *paths = (FILEPATHS_W *)param1;
1780 struct default_callback_context *ctx = context;
1782 switch(notification)
1784 case SPFILENOTIFY_STARTQUEUE:
1785 TRACE( "start queue\n" );
1786 return TRUE;
1787 case SPFILENOTIFY_ENDQUEUE:
1788 TRACE( "end queue\n" );
1789 return 0;
1790 case SPFILENOTIFY_STARTSUBQUEUE:
1791 TRACE( "start subqueue %ld count %ld\n", param1, param2 );
1792 return TRUE;
1793 case SPFILENOTIFY_ENDSUBQUEUE:
1794 TRACE( "end subqueue %ld\n", param1 );
1795 return 0;
1796 case SPFILENOTIFY_STARTDELETE:
1797 TRACE( "start delete %s\n", debugstr_w(paths->Target) );
1798 return FILEOP_DOIT;
1799 case SPFILENOTIFY_ENDDELETE:
1800 TRACE( "end delete %s\n", debugstr_w(paths->Target) );
1801 return 0;
1802 case SPFILENOTIFY_DELETEERROR:
1803 /*Windows Ignores attempts to delete files / folders which do not exist*/
1804 if ((paths->Win32Error != ERROR_FILE_NOT_FOUND) && (paths->Win32Error != ERROR_PATH_NOT_FOUND))
1805 SetupDeleteErrorW(ctx->owner, NULL, paths->Target, paths->Win32Error, 0);
1806 return FILEOP_SKIP;
1807 case SPFILENOTIFY_STARTRENAME:
1808 SetupRenameErrorW(ctx->owner, NULL, paths->Source, paths->Target, paths->Win32Error, 0);
1809 return FILEOP_DOIT;
1810 case SPFILENOTIFY_ENDRENAME:
1811 TRACE( "end rename %s -> %s\n", debugstr_w(paths->Source), debugstr_w(paths->Target) );
1812 return 0;
1813 case SPFILENOTIFY_RENAMEERROR:
1814 ERR( "rename error %d %s -> %s\n", paths->Win32Error,
1815 debugstr_w(paths->Source), debugstr_w(paths->Target) );
1816 return FILEOP_SKIP;
1817 case SPFILENOTIFY_STARTCOPY:
1818 TRACE( "start copy %s -> %s\n", debugstr_w(paths->Source), debugstr_w(paths->Target) );
1819 return FILEOP_DOIT;
1820 case SPFILENOTIFY_ENDCOPY:
1821 TRACE( "end copy %s -> %s\n", debugstr_w(paths->Source), debugstr_w(paths->Target) );
1822 return 0;
1823 case SPFILENOTIFY_COPYERROR:
1824 ERR( "copy error %d %s -> %s\n", paths->Win32Error,
1825 debugstr_w(paths->Source), debugstr_w(paths->Target) );
1826 return FILEOP_SKIP;
1827 case SPFILENOTIFY_NEEDMEDIA:
1829 const SOURCE_MEDIA_W *media = (const SOURCE_MEDIA_W *)param1;
1830 TRACE( "need media %s %s\n", debugstr_w(media->SourcePath), debugstr_w(media->SourceFile) );
1831 lstrcpyW( (WCHAR *)param2, media->SourcePath );
1832 return FILEOP_DOIT;
1834 default:
1835 FIXME( "notification %d params %lx,%lx\n", notification, param1, param2 );
1836 break;
1838 return 0;
1841 /***********************************************************************
1842 * SetupDeleteErrorA (SETUPAPI.@)
1845 UINT WINAPI SetupDeleteErrorA( HWND parent, PCSTR dialogTitle, PCSTR file,
1846 UINT w32error, DWORD style)
1848 FIXME( "stub: (Error Number %d when attempting to delete %s)\n",
1849 w32error, debugstr_a(file) );
1850 return DPROMPT_SKIPFILE;
1853 /***********************************************************************
1854 * SetupDeleteErrorW (SETUPAPI.@)
1857 UINT WINAPI SetupDeleteErrorW( HWND parent, PCWSTR dialogTitle, PCWSTR file,
1858 UINT w32error, DWORD style)
1860 FIXME( "stub: (Error Number %d when attempting to delete %s)\n",
1861 w32error, debugstr_w(file) );
1862 return DPROMPT_SKIPFILE;
1865 /***********************************************************************
1866 * SetupRenameErrorA (SETUPAPI.@)
1869 UINT WINAPI SetupRenameErrorA( HWND parent, PCSTR dialogTitle, PCSTR source,
1870 PCSTR target, UINT w32error, DWORD style)
1872 FIXME( "stub: (Error Number %d when attempting to rename %s to %s)\n",
1873 w32error, debugstr_a(source), debugstr_a(target));
1874 return DPROMPT_SKIPFILE;
1877 /***********************************************************************
1878 * SetupRenameErrorW (SETUPAPI.@)
1881 UINT WINAPI SetupRenameErrorW( HWND parent, PCWSTR dialogTitle, PCWSTR source,
1882 PCWSTR target, UINT w32error, DWORD style)
1884 FIXME( "stub: (Error Number %d when attempting to rename %s to %s)\n",
1885 w32error, debugstr_w(source), debugstr_w(target));
1886 return DPROMPT_SKIPFILE;
1890 /***********************************************************************
1891 * SetupCopyErrorA (SETUPAPI.@)
1894 UINT WINAPI SetupCopyErrorA( HWND parent, PCSTR dialogTitle, PCSTR diskname,
1895 PCSTR sourcepath, PCSTR sourcefile, PCSTR targetpath,
1896 UINT w32error, DWORD style, PSTR pathbuffer,
1897 DWORD buffersize, PDWORD requiredsize)
1899 FIXME( "stub: (Error Number %d when attempting to copy file %s from %s to %s)\n",
1900 w32error, debugstr_a(sourcefile), debugstr_a(sourcepath) ,debugstr_a(targetpath));
1901 return DPROMPT_SKIPFILE;
1904 /***********************************************************************
1905 * SetupCopyErrorW (SETUPAPI.@)
1908 UINT WINAPI SetupCopyErrorW( HWND parent, PCWSTR dialogTitle, PCWSTR diskname,
1909 PCWSTR sourcepath, PCWSTR sourcefile, PCWSTR targetpath,
1910 UINT w32error, DWORD style, PWSTR pathbuffer,
1911 DWORD buffersize, PDWORD requiredsize)
1913 FIXME( "stub: (Error Number %d when attempting to copy file %s from %s to %s)\n",
1914 w32error, debugstr_w(sourcefile), debugstr_w(sourcepath) ,debugstr_w(targetpath));
1915 return DPROMPT_SKIPFILE;
1918 /***********************************************************************
1919 * pSetupGetQueueFlags (SETUPAPI.@)
1921 DWORD WINAPI pSetupGetQueueFlags( HSPFILEQ handle )
1923 struct file_queue *queue = handle;
1924 return queue->flags;
1927 /***********************************************************************
1928 * pSetupSetQueueFlags (SETUPAPI.@)
1930 BOOL WINAPI pSetupSetQueueFlags( HSPFILEQ handle, DWORD flags )
1932 struct file_queue *queue = handle;
1933 queue->flags = flags;
1934 return TRUE;