vbscript: Fix memory leak in owned safearray iterator.
[wine.git] / dlls / setupapi / queue.c
blobf6c83d30e1d4332feb682e86fc697da9bae348db
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"
36 #include "wine/heap.h"
38 WINE_DEFAULT_DEBUG_CHANNEL(setupapi);
40 /* context structure for the default queue callback */
41 struct default_callback_context
43 DWORD magic;
44 HWND owner;
45 DWORD unk1[4];
46 DWORD_PTR unk2[7];
47 HWND progress;
48 UINT message;
49 DWORD_PTR unk3[5];
52 struct source_media
54 WCHAR root[MAX_PATH];
55 WCHAR *desc, *tag;
56 BOOL resolved;
57 BOOL cabinet;
60 struct file_op
62 struct file_op *next;
63 UINT style;
64 WCHAR *src_path;
65 WCHAR *src_file;
66 WCHAR *dst_path;
67 WCHAR *dst_file;
68 struct source_media *media;
71 struct file_op_queue
73 struct file_op *head;
74 struct file_op *tail;
75 unsigned int count;
78 struct file_queue
80 DWORD magic;
81 struct file_op_queue copy_queue;
82 struct file_op_queue delete_queue;
83 struct file_op_queue rename_queue;
84 DWORD flags;
85 struct source_media **sources;
86 unsigned int source_count;
89 #define FILE_QUEUE_MAGIC 0x21514653
91 /* append a file operation to a queue */
92 static inline void queue_file_op( struct file_op_queue *queue, struct file_op *op )
94 op->next = NULL;
95 if (queue->tail) queue->tail->next = op;
96 else queue->head = op;
97 queue->tail = op;
98 queue->count++;
101 /* free all the file operations on a given queue */
102 static void free_file_op_queue( struct file_op_queue *queue )
104 struct file_op *t, *op = queue->head;
106 while( op )
108 HeapFree( GetProcessHeap(), 0, op->src_path );
109 HeapFree( GetProcessHeap(), 0, op->src_file );
110 HeapFree( GetProcessHeap(), 0, op->dst_path );
111 if (op->dst_file != op->src_file) HeapFree( GetProcessHeap(), 0, op->dst_file );
112 t = op;
113 op = op->next;
114 HeapFree( GetProcessHeap(), 0, t );
118 /* concat 3 strings to make a path, handling separators correctly */
119 static void concat_W( WCHAR *buffer, const WCHAR *src1, const WCHAR *src2, const WCHAR *src3 )
121 *buffer = 0;
122 if (src1 && *src1)
124 lstrcpyW( buffer, src1 );
125 buffer += lstrlenW(buffer );
126 if (buffer[-1] != '\\') *buffer++ = '\\';
127 *buffer = 0;
128 if (src2) while (*src2 == '\\') src2++;
131 if (src2)
133 lstrcpyW( buffer, src2 );
134 buffer += lstrlenW(buffer );
135 if (buffer[-1] != '\\') *buffer++ = '\\';
136 *buffer = 0;
137 if (src3) while (*src3 == '\\') src3++;
140 if (src3)
141 lstrcpyW( buffer, src3 );
145 /***********************************************************************
146 * build_filepathsW
148 * Build a FILEPATHS_W structure for a given file operation.
150 static BOOL build_filepathsW( const struct file_op *op, FILEPATHS_W *paths )
152 unsigned int src_len = 1, dst_len = 1;
153 WCHAR *source = (PWSTR)paths->Source, *target = (PWSTR)paths->Target;
155 if (!op->src_file || op->src_file[0] != '@')
157 if (op->media) src_len += lstrlenW(op->media->root) + 1;
158 if (op->src_path) src_len += lstrlenW(op->src_path) + 1;
160 if (op->src_file) src_len += lstrlenW(op->src_file) + 1;
161 if (op->dst_path) dst_len += lstrlenW(op->dst_path) + 1;
162 if (op->dst_file) dst_len += lstrlenW(op->dst_file) + 1;
163 src_len *= sizeof(WCHAR);
164 dst_len *= sizeof(WCHAR);
166 if (!source || HeapSize( GetProcessHeap(), 0, source ) < src_len )
168 HeapFree( GetProcessHeap(), 0, source );
169 paths->Source = source = HeapAlloc( GetProcessHeap(), 0, src_len );
171 if (!target || HeapSize( GetProcessHeap(), 0, target ) < dst_len )
173 HeapFree( GetProcessHeap(), 0, target );
174 paths->Target = target = HeapAlloc( GetProcessHeap(), 0, dst_len );
176 if (!source || !target) return FALSE;
177 if (!op->src_file || op->src_file[0] != '@')
178 concat_W( source, op->media ? op->media->root : NULL, op->src_path, op->src_file );
179 else
180 lstrcpyW( source, op->src_file );
181 concat_W( target, NULL, op->dst_path, op->dst_file );
182 paths->Win32Error = 0;
183 paths->Flags = 0;
184 return TRUE;
188 /***********************************************************************
189 * QUEUE_callback_WtoA
191 * Map a file callback parameters from W to A and call the A callback.
193 UINT CALLBACK QUEUE_callback_WtoA( void *context, UINT notification,
194 UINT_PTR param1, UINT_PTR param2 )
196 struct callback_WtoA_context *callback_ctx = context;
197 char buffer[MAX_PATH];
198 UINT ret;
199 UINT_PTR old_param2 = param2;
201 switch(notification)
203 case SPFILENOTIFY_COPYERROR:
204 buffer[0] = 0;
205 param2 = (UINT_PTR)buffer;
206 /* fall through */
207 case SPFILENOTIFY_STARTDELETE:
208 case SPFILENOTIFY_ENDDELETE:
209 case SPFILENOTIFY_DELETEERROR:
210 case SPFILENOTIFY_STARTRENAME:
211 case SPFILENOTIFY_ENDRENAME:
212 case SPFILENOTIFY_RENAMEERROR:
213 case SPFILENOTIFY_STARTCOPY:
214 case SPFILENOTIFY_ENDCOPY:
215 case SPFILENOTIFY_QUEUESCAN_EX:
217 FILEPATHS_W *pathsW = (FILEPATHS_W *)param1;
218 FILEPATHS_A pathsA;
220 pathsA.Source = strdupWtoA( pathsW->Source );
221 pathsA.Target = strdupWtoA( pathsW->Target );
222 pathsA.Win32Error = pathsW->Win32Error;
223 pathsA.Flags = pathsW->Flags;
224 ret = callback_ctx->orig_handler( callback_ctx->orig_context, notification,
225 (UINT_PTR)&pathsA, param2 );
226 HeapFree( GetProcessHeap(), 0, (void *)pathsA.Source );
227 HeapFree( GetProcessHeap(), 0, (void *)pathsA.Target );
229 if (notification == SPFILENOTIFY_COPYERROR)
230 MultiByteToWideChar( CP_ACP, 0, buffer, -1, (WCHAR *)old_param2, MAX_PATH );
231 break;
233 case SPFILENOTIFY_STARTREGISTRATION:
234 case SPFILENOTIFY_ENDREGISTRATION:
236 SP_REGISTER_CONTROL_STATUSW *statusW = (SP_REGISTER_CONTROL_STATUSW *)param1;
237 SP_REGISTER_CONTROL_STATUSA statusA;
239 statusA.cbSize = sizeof(statusA);
240 statusA.FileName = strdupWtoA( statusW->FileName );
241 statusA.Win32Error = statusW->Win32Error;
242 statusA.FailureCode = statusW->FailureCode;
243 ret = callback_ctx->orig_handler( callback_ctx->orig_context, notification,
244 (UINT_PTR)&statusA, param2 );
245 HeapFree( GetProcessHeap(), 0, (LPSTR)statusA.FileName );
247 break;
249 case SPFILENOTIFY_QUEUESCAN:
251 LPWSTR targetW = (LPWSTR)param1;
252 LPSTR target = strdupWtoA( targetW );
254 ret = callback_ctx->orig_handler( callback_ctx->orig_context, notification,
255 (UINT_PTR)target, param2 );
256 HeapFree( GetProcessHeap(), 0, target );
258 break;
260 case SPFILENOTIFY_NEEDMEDIA:
262 const SOURCE_MEDIA_W *mediaW = (const SOURCE_MEDIA_W *)param1;
263 char path[MAX_PATH];
264 SOURCE_MEDIA_A mediaA;
266 mediaA.Tagfile = strdupWtoA(mediaW->Tagfile);
267 mediaA.Description = strdupWtoA(mediaW->Description);
268 mediaA.SourcePath = strdupWtoA(mediaW->SourcePath);
269 mediaA.SourceFile = strdupWtoA(mediaW->SourceFile);
270 mediaA.Flags = mediaW->Flags;
271 path[0] = 0;
273 ret = callback_ctx->orig_handler(callback_ctx->orig_context, notification,
274 (UINT_PTR)&mediaA, (UINT_PTR)&path);
275 MultiByteToWideChar(CP_ACP, 0, path, -1, (WCHAR *)param2, MAX_PATH);
277 heap_free((char *)mediaA.Tagfile);
278 heap_free((char *)mediaA.Description);
279 heap_free((char *)mediaA.SourcePath);
280 heap_free((char *)mediaA.SourceFile);
281 break;
283 case SPFILENOTIFY_STARTQUEUE:
284 case SPFILENOTIFY_ENDQUEUE:
285 case SPFILENOTIFY_STARTSUBQUEUE:
286 case SPFILENOTIFY_ENDSUBQUEUE:
287 default:
288 ret = callback_ctx->orig_handler( callback_ctx->orig_context, notification, param1, param2 );
289 break;
291 return ret;
294 static void get_source_info( HINF hinf, const WCHAR *src_file, SP_FILE_COPY_PARAMS_W *params,
295 WCHAR *src_root, WCHAR *src_path)
297 INFCONTEXT file_ctx, disk_ctx;
298 INT id, diskid;
299 DWORD len;
301 /* find the SourceDisksFiles entry */
302 if (!SetupFindFirstLineW( hinf, L"SourceDisksFiles", src_file, &file_ctx )) return;
303 if (!SetupGetIntField( &file_ctx, 1, &diskid )) return;
305 /* now find the diskid in the SourceDisksNames section */
306 if (!SetupFindFirstLineW( hinf, L"SourceDisksNames", NULL, &disk_ctx )) return;
307 for (;;)
309 if (SetupGetIntField( &disk_ctx, 0, &id ) && (id == diskid)) break;
310 if (!SetupFindNextLine( &disk_ctx, &disk_ctx )) return;
313 if (SetupGetStringFieldW( &disk_ctx, 1, NULL, 0, &len ) && len > sizeof(WCHAR)
314 && (params->SourceDescription = heap_alloc( len * sizeof(WCHAR) )))
315 SetupGetStringFieldW( &disk_ctx, 1, (WCHAR *)params->SourceDescription, len, NULL );
317 if (SetupGetStringFieldW( &disk_ctx, 2, NULL, 0, &len ) && len > sizeof(WCHAR)
318 && (params->SourceTagfile = heap_alloc( len * sizeof(WCHAR) )))
319 SetupGetStringFieldW( &disk_ctx, 2, (WCHAR *)params->SourceTagfile, len, NULL );
321 if (SetupGetStringFieldW( &disk_ctx, 4, NULL, 0, &len ) && len > sizeof(WCHAR)
322 && len < MAX_PATH - lstrlenW( src_root ) - 1)
324 lstrcatW( src_root, L"\\" );
325 SetupGetStringFieldW( &disk_ctx, 4, src_root + lstrlenW( src_root ),
326 MAX_PATH - lstrlenW( src_root ), NULL );
329 if (SetupGetStringFieldW( &file_ctx, 2, NULL, 0, &len ) && len > sizeof(WCHAR) && len < MAX_PATH)
331 SetupGetStringFieldW( &file_ctx, 2, src_path, MAX_PATH, NULL );
332 params->SourcePath = src_path;
336 /***********************************************************************
337 * get_destination_dir
339 * Retrieve the destination dir for a given section.
341 static WCHAR *get_destination_dir( HINF hinf, const WCHAR *section )
343 INFCONTEXT context;
344 WCHAR systemdir[MAX_PATH], *dir;
345 BOOL ret;
347 if (!section || !(ret = SetupFindFirstLineW( hinf, L"DestinationDirs", section, &context )))
348 ret = SetupFindFirstLineW( hinf, L"DestinationDirs", L"DefaultDestDir", &context );
350 if (ret && (dir = PARSER_get_dest_dir( &context )))
351 return dir;
353 GetSystemDirectoryW( systemdir, MAX_PATH );
354 return strdupW( systemdir );
357 struct extract_cab_ctx
359 const WCHAR *src;
360 const WCHAR *dst;
363 static UINT WINAPI extract_cab_cb( void *arg, UINT message, UINT_PTR param1, UINT_PTR param2 )
365 struct extract_cab_ctx *ctx = arg;
367 switch (message)
369 case SPFILENOTIFY_FILEINCABINET:
371 FILE_IN_CABINET_INFO_W *info = (FILE_IN_CABINET_INFO_W *)param1;
372 const WCHAR *filename;
374 if ((filename = wcsrchr( info->NameInCabinet, '\\' )))
375 filename++;
376 else
377 filename = info->NameInCabinet;
379 if (lstrcmpiW( filename, ctx->src ))
380 return FILEOP_SKIP;
382 lstrcpyW( info->FullTargetName, ctx->dst );
383 return FILEOP_DOIT;
385 case SPFILENOTIFY_FILEEXTRACTED:
387 const FILEPATHS_W *paths = (const FILEPATHS_W *)param1;
388 return paths->Win32Error;
390 case SPFILENOTIFY_NEEDNEWCABINET:
392 const CABINET_INFO_W *info = (const CABINET_INFO_W *)param1;
393 lstrcpyW( (WCHAR *)param2, info->CabinetPath );
394 return ERROR_SUCCESS;
396 case SPFILENOTIFY_CABINETINFO:
397 return 0;
398 default:
399 FIXME("Unexpected message %#x.\n", message);
400 return 0;
404 /***********************************************************************
405 * extract_cabinet_file
407 * Extract a file from a .cab file.
409 static BOOL extract_cabinet_file( const WCHAR *cabinet, const WCHAR *root,
410 const WCHAR *src, const WCHAR *dst )
412 struct extract_cab_ctx ctx = {src, dst};
413 int len = lstrlenW( cabinet );
414 WCHAR path[MAX_PATH];
416 /* make sure the cabinet file has a .cab extension */
417 if (len <= 4 || wcsicmp( cabinet + len - 4, L".cab" )) return FALSE;
419 lstrcpyW(path, root);
420 lstrcatW(path, L"\\" );
421 lstrcatW(path, cabinet);
423 return SetupIterateCabinetW( path, 0, extract_cab_cb, &ctx );
426 /***********************************************************************
427 * SetupOpenFileQueue (SETUPAPI.@)
429 HSPFILEQ WINAPI SetupOpenFileQueue(void)
431 struct file_queue *queue;
433 if (!(queue = HeapAlloc( GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*queue))))
434 return INVALID_HANDLE_VALUE;
435 queue->magic = FILE_QUEUE_MAGIC;
436 return queue;
440 /***********************************************************************
441 * SetupCloseFileQueue (SETUPAPI.@)
443 BOOL WINAPI SetupCloseFileQueue( HSPFILEQ handle )
445 struct file_queue *queue = handle;
446 unsigned int i;
448 /* Windows XP DDK installer passes the handle returned from
449 * SetupInitDefaultQueueCallback() to this function. */
450 if (queue->magic != FILE_QUEUE_MAGIC)
452 SetLastError(ERROR_INVALID_HANDLE);
453 return FALSE;
456 free_file_op_queue( &queue->copy_queue );
457 free_file_op_queue( &queue->rename_queue );
458 free_file_op_queue( &queue->delete_queue );
459 for (i = 0; i < queue->source_count; ++i)
461 heap_free( queue->sources[i]->desc );
462 heap_free( queue->sources[i]->tag );
463 heap_free( queue->sources[i] );
465 heap_free( queue->sources );
466 HeapFree( GetProcessHeap(), 0, queue );
467 return TRUE;
471 /***********************************************************************
472 * SetupQueueCopyIndirectA (SETUPAPI.@)
474 BOOL WINAPI SetupQueueCopyIndirectA( SP_FILE_COPY_PARAMS_A *paramsA )
476 SP_FILE_COPY_PARAMS_W paramsW;
477 BOOL ret;
479 paramsW.cbSize = sizeof(paramsW);
480 paramsW.QueueHandle = paramsA->QueueHandle;
481 paramsW.SourceRootPath = strdupAtoW( paramsA->SourceRootPath );
482 paramsW.SourcePath = strdupAtoW( paramsA->SourcePath );
483 paramsW.SourceFilename = strdupAtoW( paramsA->SourceFilename );
484 paramsW.SourceDescription = strdupAtoW( paramsA->SourceDescription );
485 paramsW.SourceTagfile = strdupAtoW( paramsA->SourceTagfile );
486 paramsW.TargetDirectory = strdupAtoW( paramsA->TargetDirectory );
487 paramsW.TargetFilename = strdupAtoW( paramsA->TargetFilename );
488 paramsW.CopyStyle = paramsA->CopyStyle;
489 paramsW.LayoutInf = paramsA->LayoutInf;
490 paramsW.SecurityDescriptor = strdupAtoW( paramsA->SecurityDescriptor );
492 ret = SetupQueueCopyIndirectW( &paramsW );
494 heap_free( (WCHAR *)paramsW.SourceRootPath );
495 heap_free( (WCHAR *)paramsW.SourcePath );
496 heap_free( (WCHAR *)paramsW.SourceFilename );
497 heap_free( (WCHAR *)paramsW.SourceDescription );
498 heap_free( (WCHAR *)paramsW.SourceTagfile );
499 heap_free( (WCHAR *)paramsW.TargetDirectory );
500 heap_free( (WCHAR *)paramsW.TargetFilename );
501 heap_free( (WCHAR *)paramsW.SecurityDescriptor );
502 return ret;
505 static BOOL equal_str(const WCHAR *a, const WCHAR *b)
507 return (!a && !b) || (a && b && !wcscmp(a, b));
510 static struct source_media *get_source_media(struct file_queue *queue,
511 const WCHAR *root, const WCHAR *desc, const WCHAR *tag)
513 unsigned int i;
515 for (i = 0; i < queue->source_count; ++i)
517 if (!wcscmp(root, queue->sources[i]->root)
518 && equal_str(desc, queue->sources[i]->desc)
519 && equal_str(tag, queue->sources[i]->tag))
521 return queue->sources[i];
525 queue->sources = heap_realloc( queue->sources, ++queue->source_count * sizeof(*queue->sources) );
526 queue->sources[i] = heap_alloc( sizeof(*queue->sources[i]) );
527 lstrcpyW(queue->sources[i]->root, root);
528 queue->sources[i]->desc = strdupW(desc);
529 queue->sources[i]->tag = strdupW(tag);
530 queue->sources[i]->resolved = FALSE;
531 queue->sources[i]->cabinet = FALSE;
533 return queue->sources[i];
536 /***********************************************************************
537 * SetupQueueCopyIndirectW (SETUPAPI.@)
539 BOOL WINAPI SetupQueueCopyIndirectW( PSP_FILE_COPY_PARAMS_W params )
541 struct file_queue *queue = params->QueueHandle;
542 struct file_op *op;
544 if (!(op = HeapAlloc( GetProcessHeap(), 0, sizeof(*op) ))) return FALSE;
545 op->style = params->CopyStyle;
546 op->src_path = strdupW( params->SourcePath );
547 op->src_file = strdupW( params->SourceFilename );
548 op->dst_path = strdupW( params->TargetDirectory );
549 op->dst_file = strdupW( params->TargetFilename );
551 /* some defaults */
552 if (!op->dst_file) op->dst_file = op->src_file;
553 if (params->LayoutInf)
554 FIXME("Unhandled LayoutInf %p.\n", params->LayoutInf);
556 op->media = get_source_media( queue, params->SourceRootPath ? params->SourceRootPath : L"",
557 params->SourceDescription, params->SourceTagfile );
559 TRACE( "root=%s path=%s file=%s -> dir=%s file=%s descr=%s tag=%s\n",
560 debugstr_w(op->media->root), debugstr_w(op->src_path), debugstr_w(op->src_file),
561 debugstr_w(op->dst_path), debugstr_w(op->dst_file),
562 debugstr_w(op->media->desc), debugstr_w(op->media->tag) );
564 queue_file_op( &queue->copy_queue, op );
565 return TRUE;
569 /***********************************************************************
570 * SetupQueueCopyA (SETUPAPI.@)
572 BOOL WINAPI SetupQueueCopyA( HSPFILEQ queue, PCSTR src_root, PCSTR src_path, PCSTR src_file,
573 PCSTR src_descr, PCSTR src_tag, PCSTR dst_dir, PCSTR dst_file,
574 DWORD style )
576 SP_FILE_COPY_PARAMS_A params;
578 params.cbSize = sizeof(params);
579 params.QueueHandle = queue;
580 params.SourceRootPath = src_root;
581 params.SourcePath = src_path;
582 params.SourceFilename = src_file;
583 params.SourceDescription = src_descr;
584 params.SourceTagfile = src_tag;
585 params.TargetDirectory = dst_dir;
586 params.TargetFilename = dst_file;
587 params.CopyStyle = style;
588 params.LayoutInf = 0;
589 params.SecurityDescriptor = NULL;
590 return SetupQueueCopyIndirectA( &params );
594 /***********************************************************************
595 * SetupQueueCopyW (SETUPAPI.@)
597 BOOL WINAPI SetupQueueCopyW( HSPFILEQ queue, PCWSTR src_root, PCWSTR src_path, PCWSTR src_file,
598 PCWSTR src_descr, PCWSTR src_tag, PCWSTR dst_dir, PCWSTR dst_file,
599 DWORD style )
601 SP_FILE_COPY_PARAMS_W params;
603 params.cbSize = sizeof(params);
604 params.QueueHandle = queue;
605 params.SourceRootPath = src_root;
606 params.SourcePath = src_path;
607 params.SourceFilename = src_file;
608 params.SourceDescription = src_descr;
609 params.SourceTagfile = src_tag;
610 params.TargetDirectory = dst_dir;
611 params.TargetFilename = dst_file;
612 params.CopyStyle = style;
613 params.LayoutInf = 0;
614 params.SecurityDescriptor = NULL;
615 return SetupQueueCopyIndirectW( &params );
619 /***********************************************************************
620 * SetupQueueDefaultCopyA (SETUPAPI.@)
622 BOOL WINAPI SetupQueueDefaultCopyA( HSPFILEQ queue, HINF hinf, const char *src_rootA,
623 const char *src_fileA, const char *dst_fileA, DWORD style )
625 WCHAR src_rootW[MAX_PATH], src_fileW[MAX_PATH], dst_fileW[MAX_PATH];
627 if (!src_rootA || !src_fileA || !dst_fileA)
629 SetLastError(ERROR_INVALID_PARAMETER);
630 return FALSE;
633 MultiByteToWideChar( CP_ACP, 0, src_rootA, -1, src_rootW, ARRAY_SIZE(src_rootW) );
634 MultiByteToWideChar( CP_ACP, 0, src_fileA, -1, src_fileW, ARRAY_SIZE(src_fileW) );
635 MultiByteToWideChar( CP_ACP, 0, dst_fileA, -1, dst_fileW, ARRAY_SIZE(dst_fileW) );
636 return SetupQueueDefaultCopyW( queue, hinf, src_rootW, src_fileW, dst_fileW, style );
640 /***********************************************************************
641 * SetupQueueDefaultCopyW (SETUPAPI.@)
643 BOOL WINAPI SetupQueueDefaultCopyW( HSPFILEQ queue, HINF hinf, PCWSTR src_root, PCWSTR src_file,
644 PCWSTR dst_file, DWORD style )
646 WCHAR src_root_buffer[MAX_PATH], src_path[MAX_PATH];
647 SP_FILE_COPY_PARAMS_W params;
648 BOOL ret;
650 if (!src_root || !src_file || !dst_file)
652 SetLastError(ERROR_INVALID_PARAMETER);
653 return FALSE;
656 params.cbSize = sizeof(params);
657 params.QueueHandle = queue;
658 params.SourceRootPath = src_root_buffer;
659 params.SourcePath = NULL;
660 params.SourceFilename = src_file;
661 params.SourceDescription = NULL;
662 params.SourceTagfile = NULL;
663 params.TargetFilename = dst_file;
664 params.CopyStyle = style;
665 params.LayoutInf = NULL;
666 params.SecurityDescriptor = NULL;
668 lstrcpyW( src_root_buffer, src_root );
669 src_path[0] = 0;
670 if (!(params.TargetDirectory = get_destination_dir( hinf, NULL ))) return FALSE;
671 get_source_info( hinf, src_file, &params, src_root_buffer, src_path );
673 ret = SetupQueueCopyIndirectW( &params );
675 heap_free( (WCHAR *)params.TargetDirectory );
676 heap_free( (WCHAR *)params.SourceDescription );
677 heap_free( (WCHAR *)params.SourceTagfile );
678 return ret;
682 /***********************************************************************
683 * SetupQueueDeleteA (SETUPAPI.@)
685 BOOL WINAPI SetupQueueDeleteA( HSPFILEQ handle, PCSTR part1, PCSTR part2 )
687 struct file_queue *queue = handle;
688 struct file_op *op;
690 if (!(op = heap_alloc_zero( sizeof(*op) ))) return FALSE;
691 op->dst_path = strdupAtoW( part1 );
692 op->dst_file = strdupAtoW( part2 );
693 queue_file_op( &queue->delete_queue, op );
694 return TRUE;
698 /***********************************************************************
699 * SetupQueueDeleteW (SETUPAPI.@)
701 BOOL WINAPI SetupQueueDeleteW( HSPFILEQ handle, PCWSTR part1, PCWSTR part2 )
703 struct file_queue *queue = handle;
704 struct file_op *op;
706 if (!(op = heap_alloc_zero( sizeof(*op) ))) return FALSE;
707 op->dst_path = strdupW( part1 );
708 op->dst_file = strdupW( part2 );
709 queue_file_op( &queue->delete_queue, op );
710 return TRUE;
714 /***********************************************************************
715 * SetupQueueRenameA (SETUPAPI.@)
717 BOOL WINAPI SetupQueueRenameA( HSPFILEQ handle, PCSTR SourcePath, PCSTR SourceFilename,
718 PCSTR TargetPath, PCSTR TargetFilename )
720 struct file_queue *queue = handle;
721 struct file_op *op;
723 if (!(op = heap_alloc_zero( sizeof(*op) ))) return FALSE;
724 op->src_path = strdupAtoW( SourcePath );
725 op->src_file = strdupAtoW( SourceFilename );
726 op->dst_path = strdupAtoW( TargetPath ? TargetPath : SourcePath );
727 op->dst_file = strdupAtoW( TargetFilename );
728 queue_file_op( &queue->rename_queue, op );
729 return TRUE;
733 /***********************************************************************
734 * SetupQueueRenameW (SETUPAPI.@)
736 BOOL WINAPI SetupQueueRenameW( HSPFILEQ handle, PCWSTR SourcePath, PCWSTR SourceFilename,
737 PCWSTR TargetPath, PCWSTR TargetFilename )
739 struct file_queue *queue = handle;
740 struct file_op *op;
742 if (!(op = heap_alloc_zero( sizeof(*op) ))) return FALSE;
743 op->src_path = strdupW( SourcePath );
744 op->src_file = strdupW( SourceFilename );
745 op->dst_path = strdupW( TargetPath ? TargetPath : SourcePath );
746 op->dst_file = strdupW( TargetFilename );
747 queue_file_op( &queue->rename_queue, op );
748 return TRUE;
752 /***********************************************************************
753 * SetupQueueCopySectionA (SETUPAPI.@)
755 BOOL WINAPI SetupQueueCopySectionA( HSPFILEQ queue, PCSTR src_root, HINF hinf, HINF hlist,
756 PCSTR section, DWORD style )
758 UNICODE_STRING sectionW;
759 BOOL ret = FALSE;
761 if (!RtlCreateUnicodeStringFromAsciiz( &sectionW, section ))
763 SetLastError( ERROR_NOT_ENOUGH_MEMORY );
764 return FALSE;
766 if (!src_root)
767 ret = SetupQueueCopySectionW( queue, NULL, hinf, hlist, sectionW.Buffer, style );
768 else
770 UNICODE_STRING srcW;
771 if (RtlCreateUnicodeStringFromAsciiz( &srcW, src_root ))
773 ret = SetupQueueCopySectionW( queue, srcW.Buffer, hinf, hlist, sectionW.Buffer, style );
774 RtlFreeUnicodeString( &srcW );
776 else SetLastError( ERROR_NOT_ENOUGH_MEMORY );
778 RtlFreeUnicodeString( &sectionW );
779 return ret;
782 /***********************************************************************
783 * SetupQueueCopySectionW (SETUPAPI.@)
785 BOOL WINAPI SetupQueueCopySectionW( HSPFILEQ queue, PCWSTR src_root, HINF hinf, HINF hlist,
786 PCWSTR section, DWORD style )
788 WCHAR src_root_buffer[MAX_PATH], src_path[MAX_PATH], src_file[MAX_PATH], dst_file[MAX_PATH], *dest_dir;
789 INFCONTEXT context;
790 SP_FILE_COPY_PARAMS_W params;
791 INT flags;
792 BOOL ret = FALSE;
793 DWORD len;
795 TRACE("queue %p, src_root %s, hinf %p, hlist %p, section %s, style %#lx.\n",
796 queue, debugstr_w(src_root), hinf, hlist, debugstr_w(section), style);
798 if (!src_root)
800 SetLastError(ERROR_INVALID_PARAMETER);
801 return FALSE;
804 params.cbSize = sizeof(params);
805 params.QueueHandle = queue;
806 params.SourceRootPath = src_root_buffer;
807 params.SourceFilename = src_file;
808 params.TargetFilename = dst_file;
809 params.CopyStyle = style;
810 params.LayoutInf = NULL;
811 params.SecurityDescriptor = NULL;
813 lstrcpyW( src_root_buffer, src_root );
815 if (!hlist) hlist = hinf;
816 if (!hinf) hinf = hlist;
817 if (!SetupFindFirstLineW( hlist, section, NULL, &context )) return FALSE;
818 if (!(params.TargetDirectory = dest_dir = get_destination_dir( hinf, section ))) return FALSE;
821 params.SourcePath = NULL;
822 params.SourceDescription = NULL;
823 params.SourceTagfile = NULL;
824 lstrcpyW( src_root_buffer, src_root );
825 src_path[0] = 0;
827 if (!SetupGetStringFieldW( &context, 1, dst_file, ARRAY_SIZE( dst_file ), NULL ))
828 goto end;
829 if (!SetupGetStringFieldW( &context, 2, src_file, ARRAY_SIZE( src_file ), &len ) || len <= sizeof(WCHAR))
830 lstrcpyW( src_file, dst_file );
832 if (!SetupGetIntField( &context, 4, &flags )) flags = 0; /* FIXME */
834 get_source_info( hinf, src_file, &params, src_root_buffer, src_path );
836 if (!SetupQueueCopyIndirectW( &params )) goto end;
838 heap_free( (WCHAR *)params.SourceDescription );
839 heap_free( (WCHAR *)params.SourceTagfile );
840 } while (SetupFindNextLine( &context, &context ));
841 ret = TRUE;
843 end:
844 HeapFree(GetProcessHeap(), 0, dest_dir);
845 return ret;
849 /***********************************************************************
850 * SetupQueueDeleteSectionA (SETUPAPI.@)
852 BOOL WINAPI SetupQueueDeleteSectionA( HSPFILEQ queue, HINF hinf, HINF hlist, PCSTR section )
854 UNICODE_STRING sectionW;
855 BOOL ret = FALSE;
857 if (RtlCreateUnicodeStringFromAsciiz( &sectionW, section ))
859 ret = SetupQueueDeleteSectionW( queue, hinf, hlist, sectionW.Buffer );
860 RtlFreeUnicodeString( &sectionW );
862 else SetLastError( ERROR_NOT_ENOUGH_MEMORY );
863 return ret;
867 /***********************************************************************
868 * SetupQueueDeleteSectionW (SETUPAPI.@)
870 BOOL WINAPI SetupQueueDeleteSectionW( HSPFILEQ queue, HINF hinf, HINF hlist, PCWSTR section )
872 INFCONTEXT context;
873 WCHAR *dest_dir;
874 WCHAR buffer[MAX_PATH];
875 BOOL ret = FALSE;
876 INT flags;
878 TRACE( "hinf=%p/%p section=%s\n", hinf, hlist, debugstr_w(section) );
880 if (!hlist) hlist = hinf;
881 if (!SetupFindFirstLineW( hlist, section, NULL, &context )) return FALSE;
882 if (!(dest_dir = get_destination_dir( hinf, section ))) return FALSE;
885 if (!SetupGetStringFieldW( &context, 1, buffer, ARRAY_SIZE( buffer ), NULL ))
886 goto done;
887 if (!SetupGetIntField( &context, 4, &flags )) flags = 0;
888 if (!SetupQueueDeleteW( queue, dest_dir, buffer )) goto done;
889 } while (SetupFindNextLine( &context, &context ));
891 ret = TRUE;
892 done:
893 HeapFree( GetProcessHeap(), 0, dest_dir );
894 return ret;
898 /***********************************************************************
899 * SetupQueueRenameSectionA (SETUPAPI.@)
901 BOOL WINAPI SetupQueueRenameSectionA( HSPFILEQ queue, HINF hinf, HINF hlist, PCSTR section )
903 UNICODE_STRING sectionW;
904 BOOL ret = FALSE;
906 if (RtlCreateUnicodeStringFromAsciiz( &sectionW, section ))
908 ret = SetupQueueRenameSectionW( queue, hinf, hlist, sectionW.Buffer );
909 RtlFreeUnicodeString( &sectionW );
911 else SetLastError( ERROR_NOT_ENOUGH_MEMORY );
912 return ret;
916 /***********************************************************************
917 * SetupQueueRenameSectionW (SETUPAPI.@)
919 BOOL WINAPI SetupQueueRenameSectionW( HSPFILEQ queue, HINF hinf, HINF hlist, PCWSTR section )
921 INFCONTEXT context;
922 WCHAR *dest_dir;
923 WCHAR src[MAX_PATH], dst[MAX_PATH];
924 BOOL ret = FALSE;
926 TRACE( "hinf=%p/%p section=%s\n", hinf, hlist, debugstr_w(section) );
928 if (!hlist) hlist = hinf;
929 if (!SetupFindFirstLineW( hlist, section, NULL, &context )) return FALSE;
930 if (!(dest_dir = get_destination_dir( hinf, section ))) return FALSE;
933 if (!SetupGetStringFieldW( &context, 1, dst, ARRAY_SIZE( dst ), NULL ))
934 goto done;
935 if (!SetupGetStringFieldW( &context, 2, src, ARRAY_SIZE( src ), NULL ))
936 goto done;
937 if (!SetupQueueRenameW( queue, dest_dir, src, NULL, dst )) goto done;
938 } while (SetupFindNextLine( &context, &context ));
940 ret = TRUE;
941 done:
942 HeapFree( GetProcessHeap(), 0, dest_dir );
943 return ret;
947 /***********************************************************************
948 * SetupCommitFileQueueA (SETUPAPI.@)
950 BOOL WINAPI SetupCommitFileQueueA( HWND owner, HSPFILEQ queue, PSP_FILE_CALLBACK_A handler,
951 PVOID context )
953 struct callback_WtoA_context ctx;
955 ctx.orig_context = context;
956 ctx.orig_handler = handler;
957 return SetupCommitFileQueueW( owner, queue, QUEUE_callback_WtoA, &ctx );
961 /***********************************************************************
962 * create_full_pathW
964 * Recursively create all directories in the path.
966 static BOOL create_full_pathW(const WCHAR *path)
968 BOOL ret = TRUE;
969 int len;
970 WCHAR *new_path;
972 new_path = HeapAlloc(GetProcessHeap(), 0, (lstrlenW(path) + 1) * sizeof(WCHAR));
973 lstrcpyW(new_path, path);
975 while((len = lstrlenW(new_path)) && new_path[len - 1] == '\\')
976 new_path[len - 1] = 0;
978 while(!CreateDirectoryW(new_path, NULL))
980 WCHAR *slash;
981 DWORD last_error = GetLastError();
983 if(last_error == ERROR_ALREADY_EXISTS)
984 break;
986 if(last_error != ERROR_PATH_NOT_FOUND)
988 ret = FALSE;
989 break;
992 if(!(slash = wcsrchr(new_path, '\\')))
994 ret = FALSE;
995 break;
998 len = slash - new_path;
999 new_path[len] = 0;
1000 if(!create_full_pathW(new_path))
1002 ret = FALSE;
1003 break;
1005 new_path[len] = '\\';
1008 HeapFree(GetProcessHeap(), 0, new_path);
1009 return ret;
1012 static BOOL copy_file( LPCWSTR source, LPCWSTR target )
1014 WCHAR module[MAX_PATH];
1015 HMODULE mod = NULL;
1016 HRSRC res;
1017 HGLOBAL data;
1018 HANDLE handle;
1019 DWORD size, written;
1020 BOOL ret = FALSE;
1021 int id = 0;
1022 const WCHAR *p;
1024 TRACE( "%s -> %s\n", debugstr_w(source), debugstr_w(target) );
1026 if (source[0] != '@') return CopyFileW( source, target, FALSE );
1028 /* Wine extension: when the source of a file copy is in the format "@file.dll,-123"
1029 * the source data is extracted from the corresponding file.dll resource */
1031 source++; /* skip '@' */
1032 p = wcschr( source, ',' );
1033 if (!p || p - source >= MAX_PATH)
1035 SetLastError( ERROR_RESOURCE_DATA_NOT_FOUND );
1036 return FALSE;
1038 memcpy( module, source, (p - source) * sizeof(WCHAR) );
1039 module[p - source] = 0;
1040 id = -wcstol( p + 1, NULL, 10 );
1041 if (id <= 0 || id > 0xffff ||
1042 !(mod = LoadLibraryExW( module, 0, LOAD_LIBRARY_AS_DATAFILE )) ||
1043 !(res = FindResourceW( mod, MAKEINTRESOURCEW(id), L"WINE_DATA_FILE" )) ||
1044 !(data = LoadResource( mod, res )))
1046 WARN( "failed to save %s #%d to %s\n", debugstr_w(module), -id, debugstr_w(target) );
1047 if (mod) FreeLibrary( mod );
1048 SetLastError( ERROR_RESOURCE_DATA_NOT_FOUND );
1049 return FALSE;
1051 size = SizeofResource( mod, res );
1052 if ((handle = CreateFileW( target, GENERIC_WRITE, FILE_SHARE_READ | FILE_SHARE_WRITE, NULL,
1053 CREATE_ALWAYS, 0, 0 )) == INVALID_HANDLE_VALUE)
1055 WARN( "failed to save %s #%d to %s\n", debugstr_w(module), -id, debugstr_w(target) );
1056 if (mod) FreeLibrary( mod );
1057 return FALSE;
1059 ret = WriteFile( handle, LockResource(data), size, &written, NULL ) && written == size;
1060 CloseHandle( handle );
1061 if (!ret) DeleteFileW( target );
1062 return ret;
1065 static BOOL do_file_copyW( LPCWSTR source, LPCWSTR target, DWORD style,
1066 PSP_FILE_CALLBACK_W handler, PVOID context )
1068 BOOL rc = FALSE;
1069 BOOL docopy = TRUE;
1071 TRACE("copy %s to %s style 0x%lx\n",debugstr_w(source),debugstr_w(target),style);
1073 /* before copy processing */
1074 if (style & SP_COPY_REPLACEONLY)
1076 if (GetFileAttributesW(target) == INVALID_FILE_ATTRIBUTES)
1077 docopy = FALSE;
1079 if (style & (SP_COPY_NEWER_OR_SAME | SP_COPY_NEWER_ONLY | SP_COPY_FORCE_NEWER))
1081 DWORD VersionSizeSource=0;
1082 DWORD VersionSizeTarget=0;
1083 DWORD zero=0;
1086 * This is sort of an interesting workaround. You see, calling
1087 * GetVersionInfoSize on a builtin dll loads that dll into memory
1088 * and we do not properly unload builtin dlls.. so we effectively
1089 * lock into memory all the targets we are replacing. This leads
1090 * to problems when we try to register the replaced dlls.
1092 * So I will test for the existence of the files first so that
1093 * we just basically unconditionally replace the builtin versions.
1095 if ((GetFileAttributesW(target) != INVALID_FILE_ATTRIBUTES) &&
1096 (GetFileAttributesW(source) != INVALID_FILE_ATTRIBUTES))
1098 VersionSizeSource = GetFileVersionInfoSizeW(source,&zero);
1099 VersionSizeTarget = GetFileVersionInfoSizeW(target,&zero);
1102 if (VersionSizeSource && VersionSizeTarget)
1104 LPVOID VersionSource;
1105 LPVOID VersionTarget;
1106 VS_FIXEDFILEINFO *TargetInfo;
1107 VS_FIXEDFILEINFO *SourceInfo;
1108 UINT length;
1109 DWORD ret;
1111 VersionSource = HeapAlloc(GetProcessHeap(),0,VersionSizeSource);
1112 VersionTarget = HeapAlloc(GetProcessHeap(),0,VersionSizeTarget);
1114 ret = GetFileVersionInfoW(source,0,VersionSizeSource,VersionSource);
1115 if (ret)
1116 ret = GetFileVersionInfoW(target, 0, VersionSizeTarget,
1117 VersionTarget);
1119 if (ret)
1121 ret = VerQueryValueW(VersionSource, L"\\", (LPVOID*)&SourceInfo, &length);
1122 if (ret)
1123 ret = VerQueryValueW(VersionTarget, L"\\", (LPVOID*)&TargetInfo, &length);
1125 if (ret)
1127 FILEPATHS_W filepaths;
1129 TRACE("Versions: Source %li.%li target %li.%li\n",
1130 SourceInfo->dwFileVersionMS, SourceInfo->dwFileVersionLS,
1131 TargetInfo->dwFileVersionMS, TargetInfo->dwFileVersionLS);
1133 /* used in case of notification */
1134 filepaths.Target = target;
1135 filepaths.Source = source;
1136 filepaths.Win32Error = 0;
1137 filepaths.Flags = 0;
1139 if (TargetInfo->dwFileVersionMS > SourceInfo->dwFileVersionMS)
1141 if (handler)
1142 docopy = handler (context, SPFILENOTIFY_TARGETNEWER, (UINT_PTR)&filepaths, 0);
1143 else
1144 docopy = FALSE;
1146 else if ((TargetInfo->dwFileVersionMS == SourceInfo->dwFileVersionMS)
1147 && (TargetInfo->dwFileVersionLS > SourceInfo->dwFileVersionLS))
1149 if (handler)
1150 docopy = handler (context, SPFILENOTIFY_TARGETNEWER, (UINT_PTR)&filepaths, 0);
1151 else
1152 docopy = FALSE;
1154 else if ((style & SP_COPY_NEWER_ONLY) &&
1155 (TargetInfo->dwFileVersionMS ==
1156 SourceInfo->dwFileVersionMS)
1157 &&(TargetInfo->dwFileVersionLS ==
1158 SourceInfo->dwFileVersionLS))
1160 if (handler)
1161 docopy = handler (context, SPFILENOTIFY_TARGETNEWER, (UINT_PTR)&filepaths, 0);
1162 else
1163 docopy = FALSE;
1167 HeapFree(GetProcessHeap(),0,VersionSource);
1168 HeapFree(GetProcessHeap(),0,VersionTarget);
1171 if (style & (SP_COPY_NOOVERWRITE | SP_COPY_FORCE_NOOVERWRITE))
1173 if (GetFileAttributesW(target) != INVALID_FILE_ATTRIBUTES)
1175 FIXME("Notify user target file exists\n");
1176 docopy = FALSE;
1179 if (style & (SP_COPY_NODECOMP | SP_COPY_LANGUAGEAWARE | SP_COPY_FORCE_IN_USE |
1180 SP_COPY_NOSKIP | SP_COPY_WARNIFSKIP))
1182 ERR("Unsupported style(s) 0x%lx\n",style);
1185 if (docopy)
1187 rc = copy_file( source, target );
1188 if (!rc && GetLastError() == ERROR_SHARING_VIOLATION &&
1189 (style & SP_COPY_IN_USE_NEEDS_REBOOT))
1191 WCHAR temp_file[MAX_PATH];
1192 WCHAR temp[MAX_PATH];
1194 if (GetTempPathW(MAX_PATH, temp) &&
1195 GetTempFileNameW(temp, L"SET", 0, temp_file))
1197 rc = copy_file( source, temp_file );
1198 if (rc)
1199 rc = MoveFileExW(temp_file, target, MOVEFILE_DELAY_UNTIL_REBOOT);
1200 else
1201 DeleteFileW(temp_file);
1204 if (!rc) WARN( "failed to copy, err %lu\n", GetLastError() );
1206 else
1207 SetLastError(ERROR_SUCCESS);
1209 /* after copy processing */
1210 if (style & SP_COPY_DELETESOURCE)
1212 if (rc)
1213 DeleteFileW(source);
1216 return rc;
1219 /***********************************************************************
1220 * SetupInstallFileExA (SETUPAPI.@)
1222 BOOL WINAPI SetupInstallFileExA( HINF hinf, PINFCONTEXT inf_context, PCSTR source, PCSTR root,
1223 PCSTR dest, DWORD style, PSP_FILE_CALLBACK_A handler, PVOID context, PBOOL in_use )
1225 BOOL ret = FALSE;
1226 struct callback_WtoA_context ctx;
1227 UNICODE_STRING sourceW, rootW, destW;
1229 TRACE("%p %p %s %s %s %lx %p %p %p\n", hinf, inf_context, debugstr_a(source), debugstr_a(root),
1230 debugstr_a(dest), style, handler, context, in_use);
1232 sourceW.Buffer = rootW.Buffer = destW.Buffer = NULL;
1233 if (source && !RtlCreateUnicodeStringFromAsciiz( &sourceW, source ))
1235 SetLastError( ERROR_NOT_ENOUGH_MEMORY );
1236 return FALSE;
1238 if (root && !RtlCreateUnicodeStringFromAsciiz( &rootW, root ))
1240 SetLastError( ERROR_NOT_ENOUGH_MEMORY );
1241 goto exit;
1243 if (dest && !RtlCreateUnicodeStringFromAsciiz( &destW, dest ))
1245 SetLastError( ERROR_NOT_ENOUGH_MEMORY );
1246 goto exit;
1249 ctx.orig_context = context;
1250 ctx.orig_handler = handler;
1252 ret = SetupInstallFileExW( hinf, inf_context, sourceW.Buffer, rootW.Buffer, destW.Buffer, style, QUEUE_callback_WtoA, &ctx, in_use );
1254 exit:
1255 RtlFreeUnicodeString( &sourceW );
1256 RtlFreeUnicodeString( &rootW );
1257 RtlFreeUnicodeString( &destW );
1258 return ret;
1261 /***********************************************************************
1262 * SetupInstallFileA (SETUPAPI.@)
1264 BOOL WINAPI SetupInstallFileA( HINF hinf, PINFCONTEXT inf_context, PCSTR source, PCSTR root,
1265 PCSTR dest, DWORD style, PSP_FILE_CALLBACK_A handler, PVOID context )
1267 return SetupInstallFileExA( hinf, inf_context, source, root, dest, style, handler, context, NULL );
1270 /***********************************************************************
1271 * SetupInstallFileExW (SETUPAPI.@)
1273 BOOL WINAPI SetupInstallFileExW( HINF hinf, PINFCONTEXT inf_context, PCWSTR source, PCWSTR root,
1274 PCWSTR dest, DWORD style, PSP_FILE_CALLBACK_W handler, PVOID context, PBOOL in_use )
1276 BOOL ret, absolute = (root && *root && !(style & SP_COPY_SOURCE_ABSOLUTE));
1277 WCHAR *buffer, *p, *inf_source = NULL, dest_path[MAX_PATH];
1278 DWORD len;
1280 TRACE("%p %p %s %s %s %lx %p %p %p\n", hinf, inf_context, debugstr_w(source), debugstr_w(root),
1281 debugstr_w(dest), style, handler, context, in_use);
1283 if (in_use) FIXME("no file in use support\n");
1285 dest_path[0] = 0;
1287 if (hinf)
1289 WCHAR *dest_dir;
1290 INFCONTEXT ctx;
1292 if (!inf_context)
1294 inf_context = &ctx;
1295 if (!SetupFindFirstLineW( hinf, L"CopyFiles", NULL, inf_context )) return FALSE;
1297 if (!SetupGetStringFieldW( inf_context, 1, NULL, 0, &len )) return FALSE;
1298 if (!(inf_source = HeapAlloc( GetProcessHeap(), 0, len * sizeof(WCHAR) )))
1300 SetLastError( ERROR_NOT_ENOUGH_MEMORY );
1301 return FALSE;
1303 if (!SetupGetStringFieldW( inf_context, 1, inf_source, len, NULL ))
1305 HeapFree( GetProcessHeap(), 0, inf_source );
1306 return FALSE;
1308 source = inf_source;
1310 if ((dest_dir = get_destination_dir( hinf, NULL )))
1312 lstrcpyW( dest_path, dest_dir );
1313 lstrcatW( dest_path, L"\\" );
1314 heap_free( dest_dir );
1317 else if (!source)
1319 SetLastError( ERROR_INVALID_PARAMETER );
1320 return FALSE;
1323 len = lstrlenW( source ) + 1;
1324 if (absolute) len += lstrlenW( root ) + 1;
1326 if (!(p = buffer = HeapAlloc( GetProcessHeap(), 0, len * sizeof(WCHAR) )))
1328 HeapFree( GetProcessHeap(), 0, inf_source );
1329 SetLastError( ERROR_NOT_ENOUGH_MEMORY );
1330 return FALSE;
1333 if (absolute)
1335 lstrcpyW( buffer, root );
1336 p += lstrlenW( buffer );
1337 if (p[-1] != '\\') *p++ = '\\';
1339 while (*source == '\\') source++;
1340 lstrcpyW( p, source );
1342 lstrcatW( dest_path, dest );
1344 ret = do_file_copyW( buffer, dest_path, style, handler, context );
1346 HeapFree( GetProcessHeap(), 0, inf_source );
1347 HeapFree( GetProcessHeap(), 0, buffer );
1348 return ret;
1351 /***********************************************************************
1352 * SetupInstallFileW (SETUPAPI.@)
1354 BOOL WINAPI SetupInstallFileW( HINF hinf, PINFCONTEXT inf_context, PCWSTR source, PCWSTR root,
1355 PCWSTR dest, DWORD style, PSP_FILE_CALLBACK_W handler, PVOID context )
1357 return SetupInstallFileExW( hinf, inf_context, source, root, dest, style, handler, context, NULL );
1360 static BOOL queue_copy_file( const WCHAR *source, const WCHAR *dest,
1361 const struct file_op *op, PSP_FILE_CALLBACK_W handler, void *context )
1363 TRACE("copying file %s -> %s\n", debugstr_w(source), debugstr_w(dest));
1365 if (op->dst_path && !create_full_pathW(op->dst_path))
1366 return FALSE;
1368 if (do_file_copyW(source, dest, op->style, handler, context) || GetLastError() == ERROR_SUCCESS)
1369 return TRUE;
1371 /* try to extract it from the cabinet file */
1372 if (op->media->tag && extract_cabinet_file(op->media->tag, op->media->root, op->src_file, dest))
1374 op->media->cabinet = TRUE;
1375 return TRUE;
1378 return FALSE;
1381 /***********************************************************************
1382 * SetupCommitFileQueueW (SETUPAPI.@)
1384 BOOL WINAPI SetupCommitFileQueueW( HWND owner, HSPFILEQ handle, PSP_FILE_CALLBACK_W handler,
1385 PVOID context )
1387 struct file_queue *queue = handle;
1388 struct file_op *op;
1389 BOOL result = FALSE;
1390 FILEPATHS_W paths;
1391 UINT op_result;
1393 paths.Source = paths.Target = NULL;
1395 if (!queue->copy_queue.count && !queue->delete_queue.count && !queue->rename_queue.count)
1396 return TRUE; /* nothing to do */
1398 if (!handler( context, SPFILENOTIFY_STARTQUEUE, (UINT_PTR)owner, 0 )) return FALSE;
1400 /* perform deletes */
1402 if (queue->delete_queue.count)
1404 if (!(handler( context, SPFILENOTIFY_STARTSUBQUEUE, FILEOP_DELETE,
1405 queue->delete_queue.count ))) goto done;
1406 for (op = queue->delete_queue.head; op; op = op->next)
1408 build_filepathsW( op, &paths );
1409 op_result = handler( context, SPFILENOTIFY_STARTDELETE, (UINT_PTR)&paths, FILEOP_DELETE);
1410 if (op_result == FILEOP_ABORT) goto done;
1411 while (op_result == FILEOP_DOIT)
1413 TRACE( "deleting file %s\n", debugstr_w(paths.Target) );
1414 if (DeleteFileW( paths.Target )) break; /* success */
1415 paths.Win32Error = GetLastError();
1416 op_result = handler( context, SPFILENOTIFY_DELETEERROR, (UINT_PTR)&paths, 0 );
1417 if (op_result == FILEOP_ABORT) goto done;
1419 handler( context, SPFILENOTIFY_ENDDELETE, (UINT_PTR)&paths, 0 );
1421 handler( context, SPFILENOTIFY_ENDSUBQUEUE, FILEOP_DELETE, 0 );
1424 /* perform renames */
1426 if (queue->rename_queue.count)
1428 if (!(handler( context, SPFILENOTIFY_STARTSUBQUEUE, FILEOP_RENAME,
1429 queue->rename_queue.count ))) goto done;
1430 for (op = queue->rename_queue.head; op; op = op->next)
1432 build_filepathsW( op, &paths );
1433 op_result = handler( context, SPFILENOTIFY_STARTRENAME, (UINT_PTR)&paths, FILEOP_RENAME);
1434 if (op_result == FILEOP_ABORT) goto done;
1435 while (op_result == FILEOP_DOIT)
1437 TRACE( "renaming file %s -> %s\n",
1438 debugstr_w(paths.Source), debugstr_w(paths.Target) );
1439 if (MoveFileW( paths.Source, paths.Target )) break; /* success */
1440 paths.Win32Error = GetLastError();
1441 op_result = handler( context, SPFILENOTIFY_RENAMEERROR, (UINT_PTR)&paths, 0 );
1442 if (op_result == FILEOP_ABORT) goto done;
1444 handler( context, SPFILENOTIFY_ENDRENAME, (UINT_PTR)&paths, 0 );
1446 handler( context, SPFILENOTIFY_ENDSUBQUEUE, FILEOP_RENAME, 0 );
1449 /* perform copies */
1451 if (queue->copy_queue.count)
1453 if (!(handler( context, SPFILENOTIFY_STARTSUBQUEUE, FILEOP_COPY,
1454 queue->copy_queue.count ))) goto done;
1455 for (op = queue->copy_queue.head; op; op = op->next)
1457 WCHAR newpath[MAX_PATH];
1459 if (!op->media->resolved)
1461 /* The NEEDMEDIA callback asks for the folder containing the
1462 * first file, but that might be in a subdir of the source
1463 * disk's root directory. We have to do some contortions to
1464 * correct for this. Pretend that the file we're using
1465 * actually isn't in a subdirectory, but keep track of what it
1466 * was, and then later strip it from the root path that we
1467 * ultimately resolve the source disk to. */
1468 WCHAR src_path[MAX_PATH];
1469 size_t path_len = 0;
1471 src_path[0] = 0;
1472 if (op->src_path)
1474 lstrcpyW(src_path, op->src_path);
1475 path_len = lstrlenW(src_path);
1477 lstrcatW(op->media->root, L"\\");
1478 lstrcatW(op->media->root, op->src_path);
1480 heap_free(op->src_path);
1481 op->src_path = NULL;
1484 for (;;)
1486 SOURCE_MEDIA_W media;
1487 media.Reserved = NULL;
1488 media.Tagfile = op->media->tag;
1489 media.Description = op->media->desc;
1490 media.SourcePath = op->media->root;
1491 media.SourceFile = op->src_file;
1492 media.Flags = op->style & (SP_COPY_WARNIFSKIP | SP_COPY_NOSKIP | SP_FLAG_CABINETCONTINUATION | SP_COPY_NOBROWSE);
1494 newpath[0] = 0;
1495 op_result = handler( context, SPFILENOTIFY_NEEDMEDIA, (UINT_PTR)&media, (UINT_PTR)newpath );
1497 if (op_result == FILEOP_ABORT)
1498 goto done;
1499 else if (op_result == FILEOP_SKIP)
1500 break;
1501 else if (op_result == FILEOP_NEWPATH)
1502 lstrcpyW(op->media->root, newpath);
1503 else if (op_result != FILEOP_DOIT)
1504 FIXME("Unhandled return value %#x.\n", op_result);
1506 build_filepathsW( op, &paths );
1507 op_result = handler( context, SPFILENOTIFY_STARTCOPY, (UINT_PTR)&paths, FILEOP_COPY );
1508 if (op_result == FILEOP_ABORT)
1509 goto done;
1510 else if (op_result == FILEOP_SKIP)
1511 break;
1512 else if (op_result != FILEOP_DOIT)
1513 FIXME("Unhandled return value %#x.\n", op_result);
1515 if (queue_copy_file( paths.Source, paths.Target, op, handler, context ))
1517 if (path_len > 0 && !op->media->cabinet)
1519 size_t root_len = lstrlenW(op->media->root);
1520 if (path_len <= root_len && !wcsnicmp(op->media->root + root_len - path_len, src_path, path_len))
1521 op->media->root[root_len - path_len - 1] = 0;
1523 op->media->resolved = TRUE;
1524 handler( context, SPFILENOTIFY_ENDCOPY, (UINT_PTR)&paths, 0 );
1525 break;
1527 paths.Win32Error = GetLastError();
1528 if (paths.Win32Error == ERROR_PATH_NOT_FOUND ||
1529 paths.Win32Error == ERROR_FILE_NOT_FOUND)
1530 continue;
1532 newpath[0] = 0;
1533 op_result = handler( context, SPFILENOTIFY_COPYERROR, (UINT_PTR)&paths, (UINT_PTR)newpath );
1534 if (op_result == FILEOP_ABORT)
1535 goto done;
1536 else if (op_result == FILEOP_SKIP)
1537 break;
1538 else if (op_result == FILEOP_NEWPATH)
1540 lstrcpyW(op->media->root, newpath);
1541 build_filepathsW(op, &paths);
1543 else if (op_result != FILEOP_DOIT)
1544 FIXME("Unhandled return value %#x.\n", op_result);
1547 else
1549 build_filepathsW( op, &paths );
1550 op_result = handler( context, SPFILENOTIFY_STARTCOPY, (UINT_PTR)&paths, FILEOP_COPY );
1551 if (op_result == FILEOP_ABORT)
1552 goto done;
1553 else if (op_result == FILEOP_SKIP)
1554 continue;
1555 else if (op_result != FILEOP_DOIT)
1556 FIXME("Unhandled return value %#x.\n", op_result);
1558 while (op_result == FILEOP_DOIT || op_result == FILEOP_NEWPATH)
1560 if (queue_copy_file( paths.Source, paths.Target, op, handler, context ))
1561 break;
1563 paths.Win32Error = GetLastError();
1564 newpath[0] = 0;
1565 op_result = handler( context, SPFILENOTIFY_COPYERROR, (UINT_PTR)&paths, (UINT_PTR)newpath );
1566 if (op_result == FILEOP_ABORT)
1567 goto done;
1568 else if (op_result == FILEOP_NEWPATH)
1570 lstrcpyW(op->media->root, newpath);
1571 build_filepathsW(op, &paths);
1573 else if (op_result != FILEOP_SKIP && op_result != FILEOP_DOIT)
1574 FIXME("Unhandled return value %#x.\n", op_result);
1576 handler( context, SPFILENOTIFY_ENDCOPY, (UINT_PTR)&paths, 0 );
1579 handler( context, SPFILENOTIFY_ENDSUBQUEUE, FILEOP_COPY, 0 );
1583 result = TRUE;
1585 done:
1586 handler( context, SPFILENOTIFY_ENDQUEUE, result, 0 );
1587 HeapFree( GetProcessHeap(), 0, (void *)paths.Source );
1588 HeapFree( GetProcessHeap(), 0, (void *)paths.Target );
1589 return result;
1593 /***********************************************************************
1594 * SetupScanFileQueueA (SETUPAPI.@)
1596 BOOL WINAPI SetupScanFileQueueA( HSPFILEQ handle, DWORD flags, HWND window,
1597 PSP_FILE_CALLBACK_A handler, PVOID context, PDWORD result )
1599 struct callback_WtoA_context ctx;
1601 TRACE("%p %lx %p %p %p %p\n", handle, flags, window, handler, context, result);
1603 ctx.orig_context = context;
1604 ctx.orig_handler = handler;
1606 return SetupScanFileQueueW( handle, flags, window, QUEUE_callback_WtoA, &ctx, result );
1610 /***********************************************************************
1611 * SetupScanFileQueueW (SETUPAPI.@)
1613 BOOL WINAPI SetupScanFileQueueW( HSPFILEQ handle, DWORD flags, HWND window,
1614 PSP_FILE_CALLBACK_W handler, PVOID context, PDWORD result )
1616 struct file_queue *queue = handle;
1617 struct file_op *op;
1618 FILEPATHS_W paths;
1619 UINT notification = 0;
1620 BOOL ret = FALSE;
1622 TRACE("%p %lx %p %p %p %p\n", handle, flags, window, handler, context, result);
1624 if (!queue->copy_queue.count) return TRUE;
1626 if (flags & SPQ_SCAN_USE_CALLBACK) notification = SPFILENOTIFY_QUEUESCAN;
1627 else if (flags & SPQ_SCAN_USE_CALLBACKEX) notification = SPFILENOTIFY_QUEUESCAN_EX;
1629 if (flags & ~(SPQ_SCAN_USE_CALLBACK | SPQ_SCAN_USE_CALLBACKEX))
1631 FIXME("flags %lx not fully implemented\n", flags);
1634 paths.Source = paths.Target = NULL;
1636 for (op = queue->copy_queue.head; op; op = op->next)
1638 build_filepathsW( op, &paths );
1639 switch (notification)
1641 case SPFILENOTIFY_QUEUESCAN:
1642 /* FIXME: handle delay flag */
1643 if (handler( context, notification, (UINT_PTR)paths.Target, 0 )) goto done;
1644 break;
1645 case SPFILENOTIFY_QUEUESCAN_EX:
1646 if (handler( context, notification, (UINT_PTR)&paths, 0 )) goto done;
1647 break;
1648 default:
1649 ret = TRUE; goto done;
1653 ret = TRUE;
1655 done:
1656 if (result) *result = 0;
1657 HeapFree( GetProcessHeap(), 0, (void *)paths.Source );
1658 HeapFree( GetProcessHeap(), 0, (void *)paths.Target );
1659 return ret;
1663 /***********************************************************************
1664 * SetupGetFileQueueCount (SETUPAPI.@)
1666 BOOL WINAPI SetupGetFileQueueCount( HSPFILEQ handle, UINT op, PUINT result )
1668 struct file_queue *queue = handle;
1670 switch(op)
1672 case FILEOP_COPY:
1673 *result = queue->copy_queue.count;
1674 return TRUE;
1675 case FILEOP_RENAME:
1676 *result = queue->rename_queue.count;
1677 return TRUE;
1678 case FILEOP_DELETE:
1679 *result = queue->delete_queue.count;
1680 return TRUE;
1682 return FALSE;
1686 /***********************************************************************
1687 * SetupGetFileQueueFlags (SETUPAPI.@)
1689 BOOL WINAPI SetupGetFileQueueFlags( HSPFILEQ handle, PDWORD flags )
1691 struct file_queue *queue = handle;
1692 *flags = queue->flags;
1693 return TRUE;
1697 /***********************************************************************
1698 * SetupSetFileQueueFlags (SETUPAPI.@)
1700 BOOL WINAPI SetupSetFileQueueFlags( HSPFILEQ handle, DWORD mask, DWORD flags )
1702 struct file_queue *queue = handle;
1703 queue->flags = (queue->flags & ~mask) | flags;
1704 return TRUE;
1708 /***********************************************************************
1709 * SetupSetFileQueueAlternatePlatformA (SETUPAPI.@)
1711 BOOL WINAPI SetupSetFileQueueAlternatePlatformA(HSPFILEQ handle, PSP_ALTPLATFORM_INFO platform, PCSTR catalogfile)
1713 FIXME("(%p, %p, %s) stub!\n", handle, platform, debugstr_a(catalogfile));
1714 return FALSE;
1718 /***********************************************************************
1719 * SetupSetFileQueueAlternatePlatformW (SETUPAPI.@)
1721 BOOL WINAPI SetupSetFileQueueAlternatePlatformW(HSPFILEQ handle, PSP_ALTPLATFORM_INFO platform, PCWSTR catalogfile)
1723 FIXME("(%p, %p, %s) stub!\n", handle, platform, debugstr_w(catalogfile));
1724 return FALSE;
1728 /***********************************************************************
1729 * SetupInitDefaultQueueCallback (SETUPAPI.@)
1731 PVOID WINAPI SetupInitDefaultQueueCallback( HWND owner )
1733 return SetupInitDefaultQueueCallbackEx( owner, 0, 0, 0, NULL );
1737 /***********************************************************************
1738 * SetupInitDefaultQueueCallbackEx (SETUPAPI.@)
1740 PVOID WINAPI SetupInitDefaultQueueCallbackEx( HWND owner, HWND progress, UINT msg,
1741 DWORD reserved1, PVOID reserved2 )
1743 struct default_callback_context *context;
1745 if ((context = HeapAlloc( GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*context) )))
1747 context->magic = 0x43515053; /* "SPQC" */
1748 context->owner = owner;
1749 context->progress = progress;
1750 context->message = msg;
1752 return context;
1756 /***********************************************************************
1757 * SetupTermDefaultQueueCallback (SETUPAPI.@)
1759 void WINAPI SetupTermDefaultQueueCallback( PVOID context )
1761 HeapFree( GetProcessHeap(), 0, context );
1765 /***********************************************************************
1766 * SetupDefaultQueueCallbackA (SETUPAPI.@)
1768 UINT WINAPI SetupDefaultQueueCallbackA( PVOID context, UINT notification,
1769 UINT_PTR param1, UINT_PTR param2 )
1771 FILEPATHS_A *paths = (FILEPATHS_A *)param1;
1772 struct default_callback_context *ctx = context;
1774 switch(notification)
1776 case SPFILENOTIFY_STARTQUEUE:
1777 TRACE( "start queue\n" );
1778 return TRUE;
1779 case SPFILENOTIFY_ENDQUEUE:
1780 TRACE( "end queue\n" );
1781 return 0;
1782 case SPFILENOTIFY_STARTSUBQUEUE:
1783 TRACE( "start subqueue %Id count %Id\n", param1, param2 );
1784 return TRUE;
1785 case SPFILENOTIFY_ENDSUBQUEUE:
1786 TRACE( "end subqueue %Id\n", param1 );
1787 return 0;
1788 case SPFILENOTIFY_STARTDELETE:
1789 TRACE( "start delete %s\n", debugstr_a(paths->Target) );
1790 return FILEOP_DOIT;
1791 case SPFILENOTIFY_ENDDELETE:
1792 TRACE( "end delete %s\n", debugstr_a(paths->Target) );
1793 return 0;
1794 case SPFILENOTIFY_DELETEERROR:
1795 /*Windows Ignores attempts to delete files / folders which do not exist*/
1796 if ((paths->Win32Error != ERROR_FILE_NOT_FOUND) && (paths->Win32Error != ERROR_PATH_NOT_FOUND))
1797 SetupDeleteErrorA(ctx->owner, NULL, paths->Target, paths->Win32Error, 0);
1798 return FILEOP_SKIP;
1799 case SPFILENOTIFY_STARTRENAME:
1800 TRACE( "start rename %s -> %s\n", debugstr_a(paths->Source), debugstr_a(paths->Target) );
1801 return FILEOP_DOIT;
1802 case SPFILENOTIFY_ENDRENAME:
1803 TRACE( "end rename %s -> %s\n", debugstr_a(paths->Source), debugstr_a(paths->Target) );
1804 return 0;
1805 case SPFILENOTIFY_RENAMEERROR:
1806 SetupRenameErrorA(ctx->owner, NULL, paths->Source, paths->Target, paths->Win32Error, 0);
1807 return FILEOP_SKIP;
1808 case SPFILENOTIFY_STARTCOPY:
1809 TRACE( "start copy %s -> %s\n", debugstr_a(paths->Source), debugstr_a(paths->Target) );
1810 return FILEOP_DOIT;
1811 case SPFILENOTIFY_ENDCOPY:
1812 TRACE( "end copy %s -> %s\n", debugstr_a(paths->Source), debugstr_a(paths->Target) );
1813 return 0;
1814 case SPFILENOTIFY_COPYERROR:
1815 ERR( "copy error %d %s -> %s\n", paths->Win32Error,
1816 debugstr_a(paths->Source), debugstr_a(paths->Target) );
1817 return FILEOP_SKIP;
1818 case SPFILENOTIFY_NEEDMEDIA:
1820 const SOURCE_MEDIA_A *media = (const SOURCE_MEDIA_A *)param1;
1821 TRACE( "need media %s %s\n", debugstr_a(media->SourcePath), debugstr_a(media->SourceFile) );
1822 strcpy( (char *)param2, media->SourcePath );
1823 return FILEOP_DOIT;
1825 default:
1826 FIXME( "notification %d params %Ix,%Ix\n", notification, param1, param2 );
1827 break;
1829 return 0;
1833 /***********************************************************************
1834 * SetupDefaultQueueCallbackW (SETUPAPI.@)
1836 UINT WINAPI SetupDefaultQueueCallbackW( PVOID context, UINT notification,
1837 UINT_PTR param1, UINT_PTR param2 )
1839 FILEPATHS_W *paths = (FILEPATHS_W *)param1;
1840 struct default_callback_context *ctx = context;
1842 switch(notification)
1844 case SPFILENOTIFY_STARTQUEUE:
1845 TRACE( "start queue\n" );
1846 return TRUE;
1847 case SPFILENOTIFY_ENDQUEUE:
1848 TRACE( "end queue\n" );
1849 return 0;
1850 case SPFILENOTIFY_STARTSUBQUEUE:
1851 TRACE( "start subqueue %Id count %Id\n", param1, param2 );
1852 return TRUE;
1853 case SPFILENOTIFY_ENDSUBQUEUE:
1854 TRACE( "end subqueue %Id\n", param1 );
1855 return 0;
1856 case SPFILENOTIFY_STARTDELETE:
1857 TRACE( "start delete %s\n", debugstr_w(paths->Target) );
1858 return FILEOP_DOIT;
1859 case SPFILENOTIFY_ENDDELETE:
1860 TRACE( "end delete %s\n", debugstr_w(paths->Target) );
1861 return 0;
1862 case SPFILENOTIFY_DELETEERROR:
1863 /*Windows Ignores attempts to delete files / folders which do not exist*/
1864 if ((paths->Win32Error != ERROR_FILE_NOT_FOUND) && (paths->Win32Error != ERROR_PATH_NOT_FOUND))
1865 SetupDeleteErrorW(ctx->owner, NULL, paths->Target, paths->Win32Error, 0);
1866 return FILEOP_SKIP;
1867 case SPFILENOTIFY_STARTRENAME:
1868 SetupRenameErrorW(ctx->owner, NULL, paths->Source, paths->Target, paths->Win32Error, 0);
1869 return FILEOP_DOIT;
1870 case SPFILENOTIFY_ENDRENAME:
1871 TRACE( "end rename %s -> %s\n", debugstr_w(paths->Source), debugstr_w(paths->Target) );
1872 return 0;
1873 case SPFILENOTIFY_RENAMEERROR:
1874 ERR( "rename error %d %s -> %s\n", paths->Win32Error,
1875 debugstr_w(paths->Source), debugstr_w(paths->Target) );
1876 return FILEOP_SKIP;
1877 case SPFILENOTIFY_STARTCOPY:
1878 TRACE( "start copy %s -> %s\n", debugstr_w(paths->Source), debugstr_w(paths->Target) );
1879 return FILEOP_DOIT;
1880 case SPFILENOTIFY_ENDCOPY:
1881 TRACE( "end copy %s -> %s\n", debugstr_w(paths->Source), debugstr_w(paths->Target) );
1882 return 0;
1883 case SPFILENOTIFY_COPYERROR:
1884 ERR( "copy error %d %s -> %s\n", paths->Win32Error,
1885 debugstr_w(paths->Source), debugstr_w(paths->Target) );
1886 return FILEOP_SKIP;
1887 case SPFILENOTIFY_NEEDMEDIA:
1889 const SOURCE_MEDIA_W *media = (const SOURCE_MEDIA_W *)param1;
1890 TRACE( "need media %s %s\n", debugstr_w(media->SourcePath), debugstr_w(media->SourceFile) );
1891 lstrcpyW( (WCHAR *)param2, media->SourcePath );
1892 return FILEOP_DOIT;
1894 default:
1895 FIXME( "notification %d params %Ix,%Ix\n", notification, param1, param2 );
1896 break;
1898 return 0;
1901 /***********************************************************************
1902 * SetupDeleteErrorA (SETUPAPI.@)
1905 UINT WINAPI SetupDeleteErrorA( HWND parent, PCSTR dialogTitle, PCSTR file,
1906 UINT w32error, DWORD style)
1908 FIXME( "stub: (Error Number %d when attempting to delete %s)\n",
1909 w32error, debugstr_a(file) );
1910 return DPROMPT_SKIPFILE;
1913 /***********************************************************************
1914 * SetupDeleteErrorW (SETUPAPI.@)
1917 UINT WINAPI SetupDeleteErrorW( HWND parent, PCWSTR dialogTitle, PCWSTR file,
1918 UINT w32error, DWORD style)
1920 FIXME( "stub: (Error Number %d when attempting to delete %s)\n",
1921 w32error, debugstr_w(file) );
1922 return DPROMPT_SKIPFILE;
1925 /***********************************************************************
1926 * SetupRenameErrorA (SETUPAPI.@)
1929 UINT WINAPI SetupRenameErrorA( HWND parent, PCSTR dialogTitle, PCSTR source,
1930 PCSTR target, UINT w32error, DWORD style)
1932 FIXME( "stub: (Error Number %d when attempting to rename %s to %s)\n",
1933 w32error, debugstr_a(source), debugstr_a(target));
1934 return DPROMPT_SKIPFILE;
1937 /***********************************************************************
1938 * SetupRenameErrorW (SETUPAPI.@)
1941 UINT WINAPI SetupRenameErrorW( HWND parent, PCWSTR dialogTitle, PCWSTR source,
1942 PCWSTR target, UINT w32error, DWORD style)
1944 FIXME( "stub: (Error Number %d when attempting to rename %s to %s)\n",
1945 w32error, debugstr_w(source), debugstr_w(target));
1946 return DPROMPT_SKIPFILE;
1950 /***********************************************************************
1951 * SetupCopyErrorA (SETUPAPI.@)
1954 UINT WINAPI SetupCopyErrorA( HWND parent, PCSTR dialogTitle, PCSTR diskname,
1955 PCSTR sourcepath, PCSTR sourcefile, PCSTR targetpath,
1956 UINT w32error, DWORD style, PSTR pathbuffer,
1957 DWORD buffersize, PDWORD requiredsize)
1959 FIXME( "stub: (Error Number %d when attempting to copy file %s from %s to %s)\n",
1960 w32error, debugstr_a(sourcefile), debugstr_a(sourcepath) ,debugstr_a(targetpath));
1961 return DPROMPT_SKIPFILE;
1964 /***********************************************************************
1965 * SetupCopyErrorW (SETUPAPI.@)
1968 UINT WINAPI SetupCopyErrorW( HWND parent, PCWSTR dialogTitle, PCWSTR diskname,
1969 PCWSTR sourcepath, PCWSTR sourcefile, PCWSTR targetpath,
1970 UINT w32error, DWORD style, PWSTR pathbuffer,
1971 DWORD buffersize, PDWORD requiredsize)
1973 FIXME( "stub: (Error Number %d when attempting to copy file %s from %s to %s)\n",
1974 w32error, debugstr_w(sourcefile), debugstr_w(sourcepath) ,debugstr_w(targetpath));
1975 return DPROMPT_SKIPFILE;
1978 /***********************************************************************
1979 * pSetupGetQueueFlags (SETUPAPI.@)
1981 DWORD WINAPI pSetupGetQueueFlags( HSPFILEQ handle )
1983 struct file_queue *queue = handle;
1984 return queue->flags;
1987 /***********************************************************************
1988 * pSetupSetQueueFlags (SETUPAPI.@)
1990 BOOL WINAPI pSetupSetQueueFlags( HSPFILEQ handle, DWORD flags )
1992 struct file_queue *queue = handle;
1993 queue->flags = flags;
1994 return TRUE;