setupapi: Avoid hardcoding the Unicode string literal lengths.
[wine/multimedia.git] / dlls / setupapi / queue.c
blobcd733a0897d2e59734bf12a7b467f339e272c872
1 /*
2 * Setupapi file queue routines
4 * Copyright 2002 Alexandre Julliard for CodeWeavers
6 * This library is free software; you can redistribute it and/or
7 * modify it under the terms of the GNU Lesser General Public
8 * License as published by the Free Software Foundation; either
9 * version 2.1 of the License, or (at your option) any later version.
11 * This library is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14 * Lesser General Public License for more details.
16 * You should have received a copy of the GNU Lesser General Public
17 * License along with this library; if not, write to the Free Software
18 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
21 #include <stdarg.h>
23 #include "windef.h"
24 #include "winbase.h"
25 #include "winreg.h"
26 #include "winternl.h"
27 #include "winerror.h"
28 #include "wingdi.h"
29 #include "winuser.h"
30 #include "winnls.h"
31 #include "setupapi.h"
32 #include "wine/unicode.h"
33 #include "setupapi_private.h"
34 #include "winver.h"
35 #include "wine/debug.h"
37 WINE_DEFAULT_DEBUG_CHANNEL(setupapi);
39 /* context structure for the default queue callback */
40 struct default_callback_context
42 HWND owner;
43 HWND progress;
44 UINT message;
47 struct file_op
49 struct file_op *next;
50 UINT style;
51 WCHAR *src_root;
52 WCHAR *src_path;
53 WCHAR *src_file;
54 WCHAR *src_descr;
55 WCHAR *src_tag;
56 WCHAR *dst_path;
57 WCHAR *dst_file;
60 struct file_op_queue
62 struct file_op *head;
63 struct file_op *tail;
64 unsigned int count;
67 struct file_queue
69 struct file_op_queue copy_queue;
70 struct file_op_queue delete_queue;
71 struct file_op_queue rename_queue;
72 DWORD flags;
76 /* append a file operation to a queue */
77 static inline void queue_file_op( struct file_op_queue *queue, struct file_op *op )
79 op->next = NULL;
80 if (queue->tail) queue->tail->next = op;
81 else queue->head = op;
82 queue->tail = op;
83 queue->count++;
86 /* free all the file operations on a given queue */
87 static void free_file_op_queue( struct file_op_queue *queue )
89 struct file_op *t, *op = queue->head;
91 while( op )
93 HeapFree( GetProcessHeap(), 0, op->src_root );
94 HeapFree( GetProcessHeap(), 0, op->src_path );
95 HeapFree( GetProcessHeap(), 0, op->src_file );
96 HeapFree( GetProcessHeap(), 0, op->src_descr );
97 HeapFree( GetProcessHeap(), 0, op->src_tag );
98 HeapFree( GetProcessHeap(), 0, op->dst_path );
99 if (op->dst_file != op->src_file) HeapFree( GetProcessHeap(), 0, op->dst_file );
100 t = op;
101 op = op->next;
102 HeapFree( GetProcessHeap(), 0, t );
106 /* concat 3 strings to make a path, handling separators correctly */
107 static void concat_W( WCHAR *buffer, const WCHAR *src1, const WCHAR *src2, const WCHAR *src3 )
109 *buffer = 0;
110 if (src1 && *src1)
112 strcpyW( buffer, src1 );
113 buffer += strlenW(buffer );
114 if (buffer[-1] != '\\') *buffer++ = '\\';
115 if (src2) while (*src2 == '\\') src2++;
118 if (src2)
120 strcpyW( buffer, src2 );
121 buffer += strlenW(buffer );
122 if (buffer[-1] != '\\') *buffer++ = '\\';
123 if (src3) while (*src3 == '\\') src3++;
125 if (src3)
127 strcpyW( buffer, src3 );
128 buffer += strlenW(buffer );
133 /***********************************************************************
134 * build_filepathsW
136 * Build a FILEPATHS_W structure for a given file operation.
138 static BOOL build_filepathsW( const struct file_op *op, FILEPATHS_W *paths )
140 unsigned int src_len = 1, dst_len = 1;
141 WCHAR *source = (PWSTR)paths->Source, *target = (PWSTR)paths->Target;
143 if (op->src_root) src_len += strlenW(op->src_root) + 1;
144 if (op->src_path) src_len += strlenW(op->src_path) + 1;
145 if (op->src_file) src_len += strlenW(op->src_file) + 1;
146 if (op->dst_path) dst_len += strlenW(op->dst_path) + 1;
147 if (op->dst_file) dst_len += strlenW(op->dst_file) + 1;
148 src_len *= sizeof(WCHAR);
149 dst_len *= sizeof(WCHAR);
151 if (!source || HeapSize( GetProcessHeap(), 0, source ) < src_len )
153 HeapFree( GetProcessHeap(), 0, source );
154 paths->Source = source = HeapAlloc( GetProcessHeap(), 0, src_len );
156 if (!target || HeapSize( GetProcessHeap(), 0, target ) < dst_len )
158 HeapFree( GetProcessHeap(), 0, target );
159 paths->Target = target = HeapAlloc( GetProcessHeap(), 0, dst_len );
161 if (!source || !target) return FALSE;
162 concat_W( source, op->src_root, op->src_path, op->src_file );
163 concat_W( target, NULL, op->dst_path, op->dst_file );
164 paths->Win32Error = 0;
165 paths->Flags = 0;
166 return TRUE;
170 /***********************************************************************
171 * QUEUE_callback_WtoA
173 * Map a file callback parameters from W to A and call the A callback.
175 UINT CALLBACK QUEUE_callback_WtoA( void *context, UINT notification,
176 UINT_PTR param1, UINT_PTR param2 )
178 struct callback_WtoA_context *callback_ctx = context;
179 char buffer[MAX_PATH];
180 UINT ret;
181 UINT_PTR old_param2 = param2;
183 switch(notification)
185 case SPFILENOTIFY_COPYERROR:
186 param2 = (UINT_PTR)buffer;
187 /* fall through */
188 case SPFILENOTIFY_STARTDELETE:
189 case SPFILENOTIFY_ENDDELETE:
190 case SPFILENOTIFY_DELETEERROR:
191 case SPFILENOTIFY_STARTRENAME:
192 case SPFILENOTIFY_ENDRENAME:
193 case SPFILENOTIFY_RENAMEERROR:
194 case SPFILENOTIFY_STARTCOPY:
195 case SPFILENOTIFY_ENDCOPY:
196 case SPFILENOTIFY_QUEUESCAN_EX:
198 FILEPATHS_W *pathsW = (FILEPATHS_W *)param1;
199 FILEPATHS_A pathsA;
201 pathsA.Source = strdupWtoA( pathsW->Source );
202 pathsA.Target = strdupWtoA( pathsW->Target );
203 pathsA.Win32Error = pathsW->Win32Error;
204 pathsA.Flags = pathsW->Flags;
205 ret = callback_ctx->orig_handler( callback_ctx->orig_context, notification,
206 (UINT_PTR)&pathsA, param2 );
207 HeapFree( GetProcessHeap(), 0, (void *)pathsA.Source );
208 HeapFree( GetProcessHeap(), 0, (void *)pathsA.Target );
210 if (notification == SPFILENOTIFY_COPYERROR)
211 MultiByteToWideChar( CP_ACP, 0, buffer, -1, (WCHAR *)old_param2, MAX_PATH );
212 break;
214 case SPFILENOTIFY_STARTREGISTRATION:
215 case SPFILENOTIFY_ENDREGISTRATION:
217 SP_REGISTER_CONTROL_STATUSW *statusW = (SP_REGISTER_CONTROL_STATUSW *)param1;
218 SP_REGISTER_CONTROL_STATUSA statusA;
220 statusA.cbSize = sizeof(statusA);
221 statusA.FileName = strdupWtoA( statusW->FileName );
222 statusA.Win32Error = statusW->Win32Error;
223 statusA.FailureCode = statusW->FailureCode;
224 ret = callback_ctx->orig_handler( callback_ctx->orig_context, notification,
225 (UINT_PTR)&statusA, param2 );
226 HeapFree( GetProcessHeap(), 0, (LPSTR)statusA.FileName );
228 break;
230 case SPFILENOTIFY_QUEUESCAN:
232 LPWSTR targetW = (LPWSTR)param1;
233 LPSTR target = strdupWtoA( targetW );
235 ret = callback_ctx->orig_handler( callback_ctx->orig_context, notification,
236 (UINT_PTR)target, param2 );
237 HeapFree( GetProcessHeap(), 0, target );
239 break;
241 case SPFILENOTIFY_NEEDMEDIA:
242 FIXME("mapping for %d not implemented\n",notification);
243 case SPFILENOTIFY_STARTQUEUE:
244 case SPFILENOTIFY_ENDQUEUE:
245 case SPFILENOTIFY_STARTSUBQUEUE:
246 case SPFILENOTIFY_ENDSUBQUEUE:
247 default:
248 ret = callback_ctx->orig_handler( callback_ctx->orig_context, notification, param1, param2 );
249 break;
251 return ret;
255 /***********************************************************************
256 * get_src_file_info
258 * Retrieve the source file information for a given file.
260 static void get_src_file_info( HINF hinf, struct file_op *op )
262 static const WCHAR SourceDisksNames[] =
263 {'S','o','u','r','c','e','D','i','s','k','s','N','a','m','e','s',0};
264 static const WCHAR SourceDisksFiles[] =
265 {'S','o','u','r','c','e','D','i','s','k','s','F','i','l','e','s',0};
267 INFCONTEXT file_ctx, disk_ctx;
268 INT id, diskid;
269 DWORD len, len2;
271 /* find the SourceDisksFiles entry */
272 if (!SetupFindFirstLineW( hinf, SourceDisksFiles, op->src_file, &file_ctx ))
274 if ((op->style & (SP_COPY_SOURCE_ABSOLUTE|SP_COPY_SOURCEPATH_ABSOLUTE))) return;
275 /* no specific info, use .inf file source directory */
276 if (!op->src_root) op->src_root = PARSER_get_src_root( hinf );
277 return;
279 if (!SetupGetIntField( &file_ctx, 1, &diskid )) return;
281 /* now find the diskid in the SourceDisksNames section */
282 if (!SetupFindFirstLineW( hinf, SourceDisksNames, NULL, &disk_ctx )) return;
283 for (;;)
285 if (SetupGetIntField( &disk_ctx, 0, &id ) && (id == diskid)) break;
286 if (!SetupFindNextLine( &disk_ctx, &disk_ctx )) return;
289 /* and fill in the missing info */
291 if (!op->src_descr)
293 if (SetupGetStringFieldW( &disk_ctx, 1, NULL, 0, &len ) &&
294 (op->src_descr = HeapAlloc( GetProcessHeap(), 0, len*sizeof(WCHAR) )))
295 SetupGetStringFieldW( &disk_ctx, 1, op->src_descr, len, NULL );
297 if (!op->src_tag)
299 if (SetupGetStringFieldW( &disk_ctx, 2, NULL, 0, &len ) &&
300 (op->src_tag = HeapAlloc( GetProcessHeap(), 0, len*sizeof(WCHAR) )))
301 SetupGetStringFieldW( &disk_ctx, 2, op->src_tag, len, NULL );
303 if (!op->src_path && !(op->style & SP_COPY_SOURCE_ABSOLUTE))
305 len = len2 = 0;
306 if (!(op->style & SP_COPY_SOURCEPATH_ABSOLUTE))
308 /* retrieve relative path for this disk */
309 if (!SetupGetStringFieldW( &disk_ctx, 4, NULL, 0, &len )) len = 0;
311 /* retrieve relative path for this file */
312 if (!SetupGetStringFieldW( &file_ctx, 2, NULL, 0, &len2 )) len2 = 0;
314 if ((len || len2) &&
315 (op->src_path = HeapAlloc( GetProcessHeap(), 0, (len+len2)*sizeof(WCHAR) )))
317 WCHAR *ptr = op->src_path;
318 if (len)
320 SetupGetStringFieldW( &disk_ctx, 4, op->src_path, len, NULL );
321 ptr = op->src_path + strlenW(op->src_path);
322 if (len2 && ptr > op->src_path && ptr[-1] != '\\') *ptr++ = '\\';
324 if (!SetupGetStringFieldW( &file_ctx, 2, ptr, len2, NULL )) *ptr = 0;
327 if (!op->src_root) op->src_root = PARSER_get_src_root(hinf);
331 /***********************************************************************
332 * get_destination_dir
334 * Retrieve the destination dir for a given section.
336 static WCHAR *get_destination_dir( HINF hinf, const WCHAR *section )
338 static const WCHAR Dest[] = {'D','e','s','t','i','n','a','t','i','o','n','D','i','r','s',0};
339 static const WCHAR Def[] = {'D','e','f','a','u','l','t','D','e','s','t','D','i','r',0};
340 INFCONTEXT context;
341 WCHAR systemdir[MAX_PATH], *dir;
342 BOOL ret;
344 if (!(ret = SetupFindFirstLineW( hinf, Dest, section, &context )))
345 ret = SetupFindFirstLineW( hinf, Dest, Def, &context );
347 if (ret && (dir = PARSER_get_dest_dir( &context )))
348 return dir;
350 GetSystemDirectoryW( systemdir, MAX_PATH );
351 return strdupW( systemdir );
355 static void (WINAPI *pExtractFiles)( LPSTR, LPSTR, DWORD, DWORD, DWORD, DWORD );
357 /***********************************************************************
358 * extract_cabinet_file
360 * Extract a file from a .cab file.
362 static BOOL extract_cabinet_file( const WCHAR *cabinet, const WCHAR *root,
363 const WCHAR *src, const WCHAR *dst )
365 static const WCHAR extW[] = {'.','c','a','b',0};
366 static HMODULE advpack;
368 char *cab_path, *cab_file;
369 int len = strlenW( cabinet );
371 /* make sure the cabinet file has a .cab extension */
372 if (len <= 4 || strcmpiW( cabinet + len - 4, extW )) return FALSE;
373 if (!pExtractFiles)
375 if (!advpack && !(advpack = LoadLibraryA( "advpack.dll" )))
377 ERR( "could not load advpack.dll\n" );
378 return FALSE;
380 if (!(pExtractFiles = (void *)GetProcAddress( advpack, "ExtractFiles" )))
382 ERR( "could not find ExtractFiles in advpack.dll\n" );
383 return FALSE;
387 if (!(cab_path = strdupWtoA( root ))) return FALSE;
388 len = WideCharToMultiByte( CP_ACP, 0, cabinet, -1, NULL, 0, NULL, NULL );
389 if (!(cab_file = HeapAlloc( GetProcessHeap(), 0, strlen(cab_path) + len + 1 )))
391 HeapFree( GetProcessHeap(), 0, cab_path );
392 return FALSE;
394 strcpy( cab_file, cab_path );
395 if (cab_file[0] && cab_file[strlen(cab_file)-1] != '\\') strcat( cab_file, "\\" );
396 WideCharToMultiByte( CP_ACP, 0, cabinet, -1, cab_file + strlen(cab_file), len, NULL, NULL );
397 FIXME( "awful hack: extracting cabinet %s\n", debugstr_a(cab_file) );
398 pExtractFiles( cab_file, cab_path, 0, 0, 0, 0 );
399 HeapFree( GetProcessHeap(), 0, cab_file );
400 HeapFree( GetProcessHeap(), 0, cab_path );
401 return CopyFileW( src, dst, FALSE /*FIXME*/ );
405 /***********************************************************************
406 * SetupOpenFileQueue (SETUPAPI.@)
408 HSPFILEQ WINAPI SetupOpenFileQueue(void)
410 struct file_queue *queue;
412 if (!(queue = HeapAlloc( GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*queue))))
413 return INVALID_HANDLE_VALUE;
414 return queue;
418 /***********************************************************************
419 * SetupCloseFileQueue (SETUPAPI.@)
421 BOOL WINAPI SetupCloseFileQueue( HSPFILEQ handle )
423 struct file_queue *queue = handle;
425 free_file_op_queue( &queue->copy_queue );
426 free_file_op_queue( &queue->rename_queue );
427 free_file_op_queue( &queue->delete_queue );
428 HeapFree( GetProcessHeap(), 0, queue );
429 return TRUE;
433 /***********************************************************************
434 * SetupQueueCopyIndirectA (SETUPAPI.@)
436 BOOL WINAPI SetupQueueCopyIndirectA( PSP_FILE_COPY_PARAMS_A params )
438 struct file_queue *queue = params->QueueHandle;
439 struct file_op *op;
441 if (!(op = HeapAlloc( GetProcessHeap(), 0, sizeof(*op) ))) return FALSE;
442 op->style = params->CopyStyle;
443 op->src_root = strdupAtoW( params->SourceRootPath );
444 op->src_path = strdupAtoW( params->SourcePath );
445 op->src_file = strdupAtoW( params->SourceFilename );
446 op->src_descr = strdupAtoW( params->SourceDescription );
447 op->src_tag = strdupAtoW( params->SourceTagfile );
448 op->dst_path = strdupAtoW( params->TargetDirectory );
449 op->dst_file = strdupAtoW( params->TargetFilename );
451 /* some defaults */
452 if (!op->src_file) op->src_file = op->dst_file;
453 if (params->LayoutInf)
455 get_src_file_info( params->LayoutInf, op );
456 if (!op->dst_path) op->dst_path = get_destination_dir( params->LayoutInf, op->dst_file );
459 TRACE( "root=%s path=%s file=%s -> dir=%s file=%s descr=%s tag=%s\n",
460 debugstr_w(op->src_root), debugstr_w(op->src_path), debugstr_w(op->src_file),
461 debugstr_w(op->dst_path), debugstr_w(op->dst_file),
462 debugstr_w(op->src_descr), debugstr_w(op->src_tag) );
464 queue_file_op( &queue->copy_queue, op );
465 return TRUE;
469 /***********************************************************************
470 * SetupQueueCopyIndirectW (SETUPAPI.@)
472 BOOL WINAPI SetupQueueCopyIndirectW( PSP_FILE_COPY_PARAMS_W params )
474 struct file_queue *queue = params->QueueHandle;
475 struct file_op *op;
477 if (!(op = HeapAlloc( GetProcessHeap(), 0, sizeof(*op) ))) return FALSE;
478 op->style = params->CopyStyle;
479 op->src_root = strdupW( params->SourceRootPath );
480 op->src_path = strdupW( params->SourcePath );
481 op->src_file = strdupW( params->SourceFilename );
482 op->src_descr = strdupW( params->SourceDescription );
483 op->src_tag = strdupW( params->SourceTagfile );
484 op->dst_path = strdupW( params->TargetDirectory );
485 op->dst_file = strdupW( params->TargetFilename );
487 /* some defaults */
488 if (!op->src_file) op->src_file = op->dst_file;
489 if (params->LayoutInf)
491 get_src_file_info( params->LayoutInf, op );
492 if (!op->dst_path) op->dst_path = get_destination_dir( params->LayoutInf, op->dst_file );
495 TRACE( "root=%s path=%s file=%s -> dir=%s file=%s descr=%s tag=%s\n",
496 debugstr_w(op->src_root), debugstr_w(op->src_path), debugstr_w(op->src_file),
497 debugstr_w(op->dst_path), debugstr_w(op->dst_file),
498 debugstr_w(op->src_descr), debugstr_w(op->src_tag) );
500 queue_file_op( &queue->copy_queue, op );
501 return TRUE;
505 /***********************************************************************
506 * SetupQueueCopyA (SETUPAPI.@)
508 BOOL WINAPI SetupQueueCopyA( HSPFILEQ queue, PCSTR src_root, PCSTR src_path, PCSTR src_file,
509 PCSTR src_descr, PCSTR src_tag, PCSTR dst_dir, PCSTR dst_file,
510 DWORD style )
512 SP_FILE_COPY_PARAMS_A params;
514 params.cbSize = sizeof(params);
515 params.QueueHandle = queue;
516 params.SourceRootPath = src_root;
517 params.SourcePath = src_path;
518 params.SourceFilename = src_file;
519 params.SourceDescription = src_descr;
520 params.SourceTagfile = src_tag;
521 params.TargetDirectory = dst_dir;
522 params.TargetFilename = dst_file;
523 params.CopyStyle = style;
524 params.LayoutInf = 0;
525 params.SecurityDescriptor = NULL;
526 return SetupQueueCopyIndirectA( &params );
530 /***********************************************************************
531 * SetupQueueCopyW (SETUPAPI.@)
533 BOOL WINAPI SetupQueueCopyW( HSPFILEQ queue, PCWSTR src_root, PCWSTR src_path, PCWSTR src_file,
534 PCWSTR src_descr, PCWSTR src_tag, PCWSTR dst_dir, PCWSTR dst_file,
535 DWORD style )
537 SP_FILE_COPY_PARAMS_W params;
539 params.cbSize = sizeof(params);
540 params.QueueHandle = queue;
541 params.SourceRootPath = src_root;
542 params.SourcePath = src_path;
543 params.SourceFilename = src_file;
544 params.SourceDescription = src_descr;
545 params.SourceTagfile = src_tag;
546 params.TargetDirectory = dst_dir;
547 params.TargetFilename = dst_file;
548 params.CopyStyle = style;
549 params.LayoutInf = 0;
550 params.SecurityDescriptor = NULL;
551 return SetupQueueCopyIndirectW( &params );
555 /***********************************************************************
556 * SetupQueueDefaultCopyA (SETUPAPI.@)
558 BOOL WINAPI SetupQueueDefaultCopyA( HSPFILEQ queue, HINF hinf, PCSTR src_root, PCSTR src_file,
559 PCSTR dst_file, DWORD style )
561 SP_FILE_COPY_PARAMS_A params;
563 params.cbSize = sizeof(params);
564 params.QueueHandle = queue;
565 params.SourceRootPath = src_root;
566 params.SourcePath = NULL;
567 params.SourceFilename = src_file;
568 params.SourceDescription = NULL;
569 params.SourceTagfile = NULL;
570 params.TargetDirectory = NULL;
571 params.TargetFilename = dst_file;
572 params.CopyStyle = style;
573 params.LayoutInf = hinf;
574 params.SecurityDescriptor = NULL;
575 return SetupQueueCopyIndirectA( &params );
579 /***********************************************************************
580 * SetupQueueDefaultCopyW (SETUPAPI.@)
582 BOOL WINAPI SetupQueueDefaultCopyW( HSPFILEQ queue, HINF hinf, PCWSTR src_root, PCWSTR src_file,
583 PCWSTR dst_file, DWORD style )
585 SP_FILE_COPY_PARAMS_W params;
587 params.cbSize = sizeof(params);
588 params.QueueHandle = queue;
589 params.SourceRootPath = src_root;
590 params.SourcePath = NULL;
591 params.SourceFilename = src_file;
592 params.SourceDescription = NULL;
593 params.SourceTagfile = NULL;
594 params.TargetDirectory = NULL;
595 params.TargetFilename = dst_file;
596 params.CopyStyle = style;
597 params.LayoutInf = hinf;
598 params.SecurityDescriptor = NULL;
599 return SetupQueueCopyIndirectW( &params );
603 /***********************************************************************
604 * SetupQueueDeleteA (SETUPAPI.@)
606 BOOL WINAPI SetupQueueDeleteA( HSPFILEQ handle, PCSTR part1, PCSTR part2 )
608 struct file_queue *queue = handle;
609 struct file_op *op;
611 if (!(op = HeapAlloc( GetProcessHeap(), 0, sizeof(*op) ))) return FALSE;
612 op->style = 0;
613 op->src_root = NULL;
614 op->src_path = NULL;
615 op->src_file = NULL;
616 op->src_descr = NULL;
617 op->src_tag = NULL;
618 op->dst_path = strdupAtoW( part1 );
619 op->dst_file = strdupAtoW( part2 );
620 queue_file_op( &queue->delete_queue, op );
621 return TRUE;
625 /***********************************************************************
626 * SetupQueueDeleteW (SETUPAPI.@)
628 BOOL WINAPI SetupQueueDeleteW( HSPFILEQ handle, PCWSTR part1, PCWSTR part2 )
630 struct file_queue *queue = handle;
631 struct file_op *op;
633 if (!(op = HeapAlloc( GetProcessHeap(), 0, sizeof(*op) ))) return FALSE;
634 op->style = 0;
635 op->src_root = NULL;
636 op->src_path = NULL;
637 op->src_file = NULL;
638 op->src_descr = NULL;
639 op->src_tag = NULL;
640 op->dst_path = strdupW( part1 );
641 op->dst_file = strdupW( part2 );
642 queue_file_op( &queue->delete_queue, op );
643 return TRUE;
647 /***********************************************************************
648 * SetupQueueRenameA (SETUPAPI.@)
650 BOOL WINAPI SetupQueueRenameA( HSPFILEQ handle, PCSTR SourcePath, PCSTR SourceFilename,
651 PCSTR TargetPath, PCSTR TargetFilename )
653 struct file_queue *queue = handle;
654 struct file_op *op;
656 if (!(op = HeapAlloc( GetProcessHeap(), 0, sizeof(*op) ))) return FALSE;
657 op->style = 0;
658 op->src_root = NULL;
659 op->src_path = strdupAtoW( SourcePath );
660 op->src_file = strdupAtoW( SourceFilename );
661 op->src_descr = NULL;
662 op->src_tag = NULL;
663 op->dst_path = strdupAtoW( TargetPath );
664 op->dst_file = strdupAtoW( TargetFilename );
665 queue_file_op( &queue->rename_queue, op );
666 return TRUE;
670 /***********************************************************************
671 * SetupQueueRenameW (SETUPAPI.@)
673 BOOL WINAPI SetupQueueRenameW( HSPFILEQ handle, PCWSTR SourcePath, PCWSTR SourceFilename,
674 PCWSTR TargetPath, PCWSTR TargetFilename )
676 struct file_queue *queue = handle;
677 struct file_op *op;
679 if (!(op = HeapAlloc( GetProcessHeap(), 0, sizeof(*op) ))) return FALSE;
680 op->style = 0;
681 op->src_root = NULL;
682 op->src_path = strdupW( SourcePath );
683 op->src_file = strdupW( SourceFilename );
684 op->src_descr = NULL;
685 op->src_tag = NULL;
686 op->dst_path = strdupW( TargetPath );
687 op->dst_file = strdupW( TargetFilename );
688 queue_file_op( &queue->rename_queue, op );
689 return TRUE;
693 /***********************************************************************
694 * SetupQueueCopySectionA (SETUPAPI.@)
696 BOOL WINAPI SetupQueueCopySectionA( HSPFILEQ queue, PCSTR src_root, HINF hinf, HINF hlist,
697 PCSTR section, DWORD style )
699 UNICODE_STRING sectionW;
700 BOOL ret = FALSE;
702 if (!RtlCreateUnicodeStringFromAsciiz( &sectionW, section ))
704 SetLastError( ERROR_NOT_ENOUGH_MEMORY );
705 return FALSE;
707 if (!src_root)
708 ret = SetupQueueCopySectionW( queue, NULL, hinf, hlist, sectionW.Buffer, style );
709 else
711 UNICODE_STRING srcW;
712 if (RtlCreateUnicodeStringFromAsciiz( &srcW, src_root ))
714 ret = SetupQueueCopySectionW( queue, srcW.Buffer, hinf, hlist, sectionW.Buffer, style );
715 RtlFreeUnicodeString( &srcW );
717 else SetLastError( ERROR_NOT_ENOUGH_MEMORY );
719 RtlFreeUnicodeString( &sectionW );
720 return ret;
724 /***********************************************************************
725 * SetupQueueCopySectionW (SETUPAPI.@)
727 BOOL WINAPI SetupQueueCopySectionW( HSPFILEQ queue, PCWSTR src_root, HINF hinf, HINF hlist,
728 PCWSTR section, DWORD style )
730 SP_FILE_COPY_PARAMS_W params;
731 INFCONTEXT context;
732 WCHAR dest[MAX_PATH], src[MAX_PATH], *dest_dir;
733 INT flags;
734 BOOL ret = FALSE;
736 TRACE( "hinf=%p/%p section=%s root=%s\n",
737 hinf, hlist, debugstr_w(section), debugstr_w(src_root) );
739 params.cbSize = sizeof(params);
740 params.QueueHandle = queue;
741 params.SourceRootPath = src_root;
742 params.SourcePath = NULL;
743 params.SourceDescription = NULL;
744 params.SourceTagfile = NULL;
745 params.TargetFilename = dest;
746 params.CopyStyle = style;
747 params.LayoutInf = hinf;
748 params.SecurityDescriptor = NULL;
750 if (!hlist) hlist = hinf;
751 if (!hinf) hinf = hlist;
752 if (!SetupFindFirstLineW( hlist, section, NULL, &context )) return FALSE;
753 if (!(params.TargetDirectory = dest_dir = get_destination_dir( hinf, section ))) return FALSE;
756 if (!SetupGetStringFieldW( &context, 1, dest, sizeof(dest)/sizeof(WCHAR), NULL ))
757 goto end;
758 if (!SetupGetStringFieldW( &context, 2, src, sizeof(src)/sizeof(WCHAR), NULL )) *src = 0;
759 if (!SetupGetIntField( &context, 4, &flags )) flags = 0; /* FIXME */
761 params.SourceFilename = *src ? src : NULL;
762 if (!SetupQueueCopyIndirectW( &params )) goto end;
763 } while (SetupFindNextLine( &context, &context ));
764 ret = TRUE;
765 end:
766 HeapFree(GetProcessHeap(), 0, dest_dir);
767 return ret;
771 /***********************************************************************
772 * SetupQueueDeleteSectionA (SETUPAPI.@)
774 BOOL WINAPI SetupQueueDeleteSectionA( HSPFILEQ queue, HINF hinf, HINF hlist, PCSTR section )
776 UNICODE_STRING sectionW;
777 BOOL ret = FALSE;
779 if (RtlCreateUnicodeStringFromAsciiz( &sectionW, section ))
781 ret = SetupQueueDeleteSectionW( queue, hinf, hlist, sectionW.Buffer );
782 RtlFreeUnicodeString( &sectionW );
784 else SetLastError( ERROR_NOT_ENOUGH_MEMORY );
785 return ret;
789 /***********************************************************************
790 * SetupQueueDeleteSectionW (SETUPAPI.@)
792 BOOL WINAPI SetupQueueDeleteSectionW( HSPFILEQ queue, HINF hinf, HINF hlist, PCWSTR section )
794 INFCONTEXT context;
795 WCHAR *dest_dir;
796 WCHAR buffer[MAX_PATH];
797 BOOL ret = FALSE;
798 INT flags;
800 TRACE( "hinf=%p/%p section=%s\n", hinf, hlist, debugstr_w(section) );
802 if (!hlist) hlist = hinf;
803 if (!SetupFindFirstLineW( hlist, section, NULL, &context )) return FALSE;
804 if (!(dest_dir = get_destination_dir( hinf, section ))) return FALSE;
807 if (!SetupGetStringFieldW( &context, 1, buffer, sizeof(buffer)/sizeof(WCHAR), NULL ))
808 goto done;
809 if (!SetupGetIntField( &context, 4, &flags )) flags = 0;
810 if (!SetupQueueDeleteW( queue, dest_dir, buffer )) goto done;
811 } while (SetupFindNextLine( &context, &context ));
813 ret = TRUE;
814 done:
815 HeapFree( GetProcessHeap(), 0, dest_dir );
816 return ret;
820 /***********************************************************************
821 * SetupQueueRenameSectionA (SETUPAPI.@)
823 BOOL WINAPI SetupQueueRenameSectionA( HSPFILEQ queue, HINF hinf, HINF hlist, PCSTR section )
825 UNICODE_STRING sectionW;
826 BOOL ret = FALSE;
828 if (RtlCreateUnicodeStringFromAsciiz( &sectionW, section ))
830 ret = SetupQueueRenameSectionW( queue, hinf, hlist, sectionW.Buffer );
831 RtlFreeUnicodeString( &sectionW );
833 else SetLastError( ERROR_NOT_ENOUGH_MEMORY );
834 return ret;
838 /***********************************************************************
839 * SetupQueueRenameSectionW (SETUPAPI.@)
841 BOOL WINAPI SetupQueueRenameSectionW( HSPFILEQ queue, HINF hinf, HINF hlist, PCWSTR section )
843 INFCONTEXT context;
844 WCHAR *dest_dir;
845 WCHAR src[MAX_PATH], dst[MAX_PATH];
846 BOOL ret = FALSE;
848 TRACE( "hinf=%p/%p section=%s\n", hinf, hlist, debugstr_w(section) );
850 if (!hlist) hlist = hinf;
851 if (!SetupFindFirstLineW( hlist, section, NULL, &context )) return FALSE;
852 if (!(dest_dir = get_destination_dir( hinf, section ))) return FALSE;
855 if (!SetupGetStringFieldW( &context, 1, dst, sizeof(dst)/sizeof(WCHAR), NULL ))
856 goto done;
857 if (!SetupGetStringFieldW( &context, 2, src, sizeof(src)/sizeof(WCHAR), NULL ))
858 goto done;
859 if (!SetupQueueRenameW( queue, dest_dir, src, NULL, dst )) goto done;
860 } while (SetupFindNextLine( &context, &context ));
862 ret = TRUE;
863 done:
864 HeapFree( GetProcessHeap(), 0, dest_dir );
865 return ret;
869 /***********************************************************************
870 * SetupCommitFileQueueA (SETUPAPI.@)
872 BOOL WINAPI SetupCommitFileQueueA( HWND owner, HSPFILEQ queue, PSP_FILE_CALLBACK_A handler,
873 PVOID context )
875 struct callback_WtoA_context ctx;
877 ctx.orig_context = context;
878 ctx.orig_handler = handler;
879 return SetupCommitFileQueueW( owner, queue, QUEUE_callback_WtoA, &ctx );
883 /***********************************************************************
884 * create_full_pathW
886 * Recursively create all directories in the path.
888 static BOOL create_full_pathW(const WCHAR *path)
890 BOOL ret = TRUE;
891 int len;
892 WCHAR *new_path;
894 new_path = HeapAlloc(GetProcessHeap(), 0, (strlenW(path) + 1) * sizeof(WCHAR));
895 strcpyW(new_path, path);
897 while((len = strlenW(new_path)) && new_path[len - 1] == '\\')
898 new_path[len - 1] = 0;
900 while(!CreateDirectoryW(new_path, NULL))
902 WCHAR *slash;
903 DWORD last_error = GetLastError();
905 if(last_error == ERROR_ALREADY_EXISTS)
906 break;
908 if(last_error != ERROR_PATH_NOT_FOUND)
910 ret = FALSE;
911 break;
914 if(!(slash = strrchrW(new_path, '\\')))
916 ret = FALSE;
917 break;
920 len = slash - new_path;
921 new_path[len] = 0;
922 if(!create_full_pathW(new_path))
924 ret = FALSE;
925 break;
927 new_path[len] = '\\';
930 HeapFree(GetProcessHeap(), 0, new_path);
931 return ret;
934 static BOOL do_file_copyW( LPCWSTR source, LPCWSTR target, DWORD style,
935 PSP_FILE_CALLBACK_W handler, PVOID context )
937 BOOL rc = FALSE;
938 BOOL docopy = TRUE;
940 TRACE("copy %s to %s style 0x%x\n",debugstr_w(source),debugstr_w(target),style);
942 /* before copy processing */
943 if (style & SP_COPY_REPLACEONLY)
945 if (GetFileAttributesW(target) == INVALID_FILE_ATTRIBUTES)
946 docopy = FALSE;
948 if (style & (SP_COPY_NEWER_OR_SAME | SP_COPY_NEWER_ONLY | SP_COPY_FORCE_NEWER))
950 DWORD VersionSizeSource=0;
951 DWORD VersionSizeTarget=0;
952 DWORD zero=0;
955 * This is sort of an interesting workaround. You see, calling
956 * GetVersionInfoSize on a builtin dll loads that dll into memory
957 * and we do not properly unload builtin dlls.. so we effectively
958 * lock into memory all the targets we are replacing. This leads
959 * to problems when we try to register the replaced dlls.
961 * So I will test for the existence of the files first so that
962 * we just basically unconditionally replace the builtin versions.
964 if ((GetFileAttributesW(target) != INVALID_FILE_ATTRIBUTES) &&
965 (GetFileAttributesW(source) != INVALID_FILE_ATTRIBUTES))
967 VersionSizeSource = GetFileVersionInfoSizeW(source,&zero);
968 VersionSizeTarget = GetFileVersionInfoSizeW(target,&zero);
971 TRACE("SizeTarget %i ... SizeSource %i\n",VersionSizeTarget,
972 VersionSizeSource);
974 if (VersionSizeSource && VersionSizeTarget)
976 LPVOID VersionSource;
977 LPVOID VersionTarget;
978 VS_FIXEDFILEINFO *TargetInfo;
979 VS_FIXEDFILEINFO *SourceInfo;
980 UINT length;
981 static const WCHAR SubBlock[]={'\\',0};
982 DWORD ret;
984 VersionSource = HeapAlloc(GetProcessHeap(),0,VersionSizeSource);
985 VersionTarget = HeapAlloc(GetProcessHeap(),0,VersionSizeTarget);
987 ret = GetFileVersionInfoW(source,0,VersionSizeSource,VersionSource);
988 if (ret)
989 ret = GetFileVersionInfoW(target, 0, VersionSizeTarget,
990 VersionTarget);
992 if (ret)
994 ret = VerQueryValueW(VersionSource, SubBlock,
995 (LPVOID*)&SourceInfo, &length);
996 if (ret)
997 ret = VerQueryValueW(VersionTarget, SubBlock,
998 (LPVOID*)&TargetInfo, &length);
1000 if (ret)
1002 FILEPATHS_W filepaths;
1004 TRACE("Versions: Source %i.%i target %i.%i\n",
1005 SourceInfo->dwFileVersionMS, SourceInfo->dwFileVersionLS,
1006 TargetInfo->dwFileVersionMS, TargetInfo->dwFileVersionLS);
1008 /* used in case of notification */
1009 filepaths.Target = target;
1010 filepaths.Source = source;
1011 filepaths.Win32Error = 0;
1012 filepaths.Flags = 0;
1014 if (TargetInfo->dwFileVersionMS > SourceInfo->dwFileVersionMS)
1016 if (handler)
1017 docopy = handler (context, SPFILENOTIFY_TARGETNEWER, (UINT_PTR)&filepaths, 0);
1018 else
1019 docopy = FALSE;
1021 else if ((TargetInfo->dwFileVersionMS == SourceInfo->dwFileVersionMS)
1022 && (TargetInfo->dwFileVersionLS > SourceInfo->dwFileVersionLS))
1024 if (handler)
1025 docopy = handler (context, SPFILENOTIFY_TARGETNEWER, (UINT_PTR)&filepaths, 0);
1026 else
1027 docopy = FALSE;
1029 else if ((style & SP_COPY_NEWER_ONLY) &&
1030 (TargetInfo->dwFileVersionMS ==
1031 SourceInfo->dwFileVersionMS)
1032 &&(TargetInfo->dwFileVersionLS ==
1033 SourceInfo->dwFileVersionLS))
1035 if (handler)
1036 docopy = handler (context, SPFILENOTIFY_TARGETNEWER, (UINT_PTR)&filepaths, 0);
1037 else
1038 docopy = FALSE;
1042 HeapFree(GetProcessHeap(),0,VersionSource);
1043 HeapFree(GetProcessHeap(),0,VersionTarget);
1046 if (style & (SP_COPY_NOOVERWRITE | SP_COPY_FORCE_NOOVERWRITE))
1048 if (GetFileAttributesW(target) != INVALID_FILE_ATTRIBUTES)
1050 FIXME("Notify user target file exists\n");
1051 docopy = FALSE;
1054 if (style & (SP_COPY_NODECOMP | SP_COPY_LANGUAGEAWARE | SP_COPY_FORCE_IN_USE |
1055 SP_COPY_IN_USE_NEEDS_REBOOT | SP_COPY_NOSKIP | SP_COPY_WARNIFSKIP))
1057 ERR("Unsupported style(s) 0x%x\n",style);
1060 if (docopy)
1062 rc = CopyFileW(source,target,FALSE);
1063 TRACE("Did copy... rc was %i\n",rc);
1066 /* after copy processing */
1067 if (style & SP_COPY_DELETESOURCE)
1069 if (rc)
1070 DeleteFileW(source);
1073 return rc;
1076 /***********************************************************************
1077 * SetupInstallFileExA (SETUPAPI.@)
1079 BOOL WINAPI SetupInstallFileExA( HINF hinf, PINFCONTEXT inf_context, PCSTR source, PCSTR root,
1080 PCSTR dest, DWORD style, PSP_FILE_CALLBACK_A handler, PVOID context, PBOOL in_use )
1082 BOOL ret = FALSE;
1083 struct callback_WtoA_context ctx;
1084 UNICODE_STRING sourceW, rootW, destW;
1086 TRACE("%p %p %s %s %s %x %p %p %p\n", hinf, inf_context, debugstr_a(source), debugstr_a(root),
1087 debugstr_a(dest), style, handler, context, in_use);
1089 sourceW.Buffer = rootW.Buffer = destW.Buffer = NULL;
1090 if (source && !RtlCreateUnicodeStringFromAsciiz( &sourceW, source ))
1092 SetLastError( ERROR_NOT_ENOUGH_MEMORY );
1093 return FALSE;
1095 if (root && !RtlCreateUnicodeStringFromAsciiz( &rootW, root ))
1097 SetLastError( ERROR_NOT_ENOUGH_MEMORY );
1098 goto exit;
1100 if (dest && !RtlCreateUnicodeStringFromAsciiz( &destW, dest ))
1102 SetLastError( ERROR_NOT_ENOUGH_MEMORY );
1103 goto exit;
1106 ctx.orig_context = context;
1107 ctx.orig_handler = handler;
1109 ret = SetupInstallFileExW( hinf, inf_context, sourceW.Buffer, rootW.Buffer, destW.Buffer, style, QUEUE_callback_WtoA, &ctx, in_use );
1111 exit:
1112 RtlFreeUnicodeString( &sourceW );
1113 RtlFreeUnicodeString( &rootW );
1114 RtlFreeUnicodeString( &destW );
1115 return ret;
1118 /***********************************************************************
1119 * SetupInstallFileA (SETUPAPI.@)
1121 BOOL WINAPI SetupInstallFileA( HINF hinf, PINFCONTEXT inf_context, PCSTR source, PCSTR root,
1122 PCSTR dest, DWORD style, PSP_FILE_CALLBACK_A handler, PVOID context )
1124 return SetupInstallFileExA( hinf, inf_context, source, root, dest, style, handler, context, NULL );
1127 /***********************************************************************
1128 * SetupInstallFileExW (SETUPAPI.@)
1130 BOOL WINAPI SetupInstallFileExW( HINF hinf, PINFCONTEXT inf_context, PCWSTR source, PCWSTR root,
1131 PCWSTR dest, DWORD style, PSP_FILE_CALLBACK_W handler, PVOID context, PBOOL in_use )
1133 static const WCHAR CopyFiles[] = {'C','o','p','y','F','i','l','e','s',0};
1135 BOOL ret, absolute = (root && *root && !(style & SP_COPY_SOURCE_ABSOLUTE));
1136 WCHAR *buffer, *p, *inf_source = NULL;
1137 unsigned int len;
1139 TRACE("%p %p %s %s %s %x %p %p %p\n", hinf, inf_context, debugstr_w(source), debugstr_w(root),
1140 debugstr_w(dest), style, handler, context, in_use);
1142 if (in_use) FIXME("no file in use support\n");
1144 if (hinf)
1146 INFCONTEXT ctx;
1148 if (!inf_context)
1150 inf_context = &ctx;
1151 if (!SetupFindFirstLineW( hinf, CopyFiles, NULL, inf_context )) return FALSE;
1153 if (!SetupGetStringFieldW( inf_context, 1, NULL, 0, &len )) return FALSE;
1154 if (!(inf_source = HeapAlloc( GetProcessHeap(), 0, len * sizeof(WCHAR) )))
1156 SetLastError( ERROR_NOT_ENOUGH_MEMORY );
1157 return FALSE;
1159 if (!SetupGetStringFieldW( inf_context, 1, inf_source, len, NULL )) return FALSE;
1160 source = inf_source;
1162 else if (!source)
1164 SetLastError( ERROR_INVALID_PARAMETER );
1165 return FALSE;
1168 len = strlenW( source ) + 1;
1169 if (absolute) len += strlenW( root ) + 1;
1171 if (!(p = buffer = HeapAlloc( GetProcessHeap(), 0, len * sizeof(WCHAR) )))
1173 HeapFree( GetProcessHeap(), 0, inf_source );
1174 SetLastError( ERROR_NOT_ENOUGH_MEMORY );
1175 return FALSE;
1178 if (absolute)
1180 strcpyW( buffer, root );
1181 p += strlenW( buffer );
1182 if (p[-1] != '\\') *p++ = '\\';
1184 while (*source == '\\') source++;
1185 strcpyW( p, source );
1187 ret = do_file_copyW( buffer, dest, style, handler, context );
1189 HeapFree( GetProcessHeap(), 0, inf_source );
1190 HeapFree( GetProcessHeap(), 0, buffer );
1191 return ret;
1194 /***********************************************************************
1195 * SetupInstallFileW (SETUPAPI.@)
1197 BOOL WINAPI SetupInstallFileW( HINF hinf, PINFCONTEXT inf_context, PCWSTR source, PCWSTR root,
1198 PCWSTR dest, DWORD style, PSP_FILE_CALLBACK_W handler, PVOID context )
1200 return SetupInstallFileExW( hinf, inf_context, source, root, dest, style, handler, context, NULL );
1203 /***********************************************************************
1204 * SetupCommitFileQueueW (SETUPAPI.@)
1206 BOOL WINAPI SetupCommitFileQueueW( HWND owner, HSPFILEQ handle, PSP_FILE_CALLBACK_W handler,
1207 PVOID context )
1209 struct file_queue *queue = handle;
1210 struct file_op *op;
1211 BOOL result = FALSE;
1212 FILEPATHS_W paths;
1213 UINT op_result;
1215 paths.Source = paths.Target = NULL;
1217 if (!queue->copy_queue.count && !queue->delete_queue.count && !queue->rename_queue.count)
1218 return TRUE; /* nothing to do */
1220 if (!handler( context, SPFILENOTIFY_STARTQUEUE, (UINT_PTR)owner, 0 )) return FALSE;
1222 /* perform deletes */
1224 if (queue->delete_queue.count)
1226 if (!(handler( context, SPFILENOTIFY_STARTSUBQUEUE, FILEOP_DELETE,
1227 queue->delete_queue.count ))) goto done;
1228 for (op = queue->delete_queue.head; op; op = op->next)
1230 build_filepathsW( op, &paths );
1231 op_result = handler( context, SPFILENOTIFY_STARTDELETE, (UINT_PTR)&paths, FILEOP_DELETE);
1232 if (op_result == FILEOP_ABORT) goto done;
1233 while (op_result == FILEOP_DOIT)
1235 TRACE( "deleting file %s\n", debugstr_w(paths.Target) );
1236 if (DeleteFileW( paths.Target )) break; /* success */
1237 paths.Win32Error = GetLastError();
1238 op_result = handler( context, SPFILENOTIFY_DELETEERROR, (UINT_PTR)&paths, 0 );
1239 if (op_result == FILEOP_ABORT) goto done;
1241 handler( context, SPFILENOTIFY_ENDDELETE, (UINT_PTR)&paths, 0 );
1243 handler( context, SPFILENOTIFY_ENDSUBQUEUE, FILEOP_DELETE, 0 );
1246 /* perform renames */
1248 if (queue->rename_queue.count)
1250 if (!(handler( context, SPFILENOTIFY_STARTSUBQUEUE, FILEOP_RENAME,
1251 queue->rename_queue.count ))) goto done;
1252 for (op = queue->rename_queue.head; op; op = op->next)
1254 build_filepathsW( op, &paths );
1255 op_result = handler( context, SPFILENOTIFY_STARTRENAME, (UINT_PTR)&paths, FILEOP_RENAME);
1256 if (op_result == FILEOP_ABORT) goto done;
1257 while (op_result == FILEOP_DOIT)
1259 TRACE( "renaming file %s -> %s\n",
1260 debugstr_w(paths.Source), debugstr_w(paths.Target) );
1261 if (MoveFileW( paths.Source, paths.Target )) break; /* success */
1262 paths.Win32Error = GetLastError();
1263 op_result = handler( context, SPFILENOTIFY_RENAMEERROR, (UINT_PTR)&paths, 0 );
1264 if (op_result == FILEOP_ABORT) goto done;
1266 handler( context, SPFILENOTIFY_ENDRENAME, (UINT_PTR)&paths, 0 );
1268 handler( context, SPFILENOTIFY_ENDSUBQUEUE, FILEOP_RENAME, 0 );
1271 /* perform copies */
1273 if (queue->copy_queue.count)
1275 if (!(handler( context, SPFILENOTIFY_STARTSUBQUEUE, FILEOP_COPY,
1276 queue->copy_queue.count ))) goto done;
1277 for (op = queue->copy_queue.head; op; op = op->next)
1279 WCHAR newpath[MAX_PATH];
1281 build_filepathsW( op, &paths );
1282 op_result = handler( context, SPFILENOTIFY_STARTCOPY, (UINT_PTR)&paths, FILEOP_COPY );
1283 if (op_result == FILEOP_ABORT) goto done;
1284 if (op_result == FILEOP_NEWPATH) op_result = FILEOP_DOIT;
1285 while (op_result == FILEOP_DOIT || op_result == FILEOP_NEWPATH)
1287 TRACE( "copying file %s -> %s\n",
1288 debugstr_w( op_result == FILEOP_NEWPATH ? newpath : paths.Source ),
1289 debugstr_w(paths.Target) );
1290 if (op->dst_path)
1292 if (!create_full_pathW( op->dst_path ))
1294 paths.Win32Error = GetLastError();
1295 op_result = handler( context, SPFILENOTIFY_COPYERROR,
1296 (UINT_PTR)&paths, (UINT_PTR)newpath );
1297 if (op_result == FILEOP_ABORT) goto done;
1300 if (do_file_copyW( op_result == FILEOP_NEWPATH ? newpath : paths.Source,
1301 paths.Target, op->style, handler, context )) break; /* success */
1302 /* try to extract it from the cabinet file */
1303 if (op->src_tag)
1305 if (extract_cabinet_file( op->src_tag, op->src_root,
1306 paths.Source, paths.Target )) break;
1308 paths.Win32Error = GetLastError();
1309 op_result = handler( context, SPFILENOTIFY_COPYERROR,
1310 (UINT_PTR)&paths, (UINT_PTR)newpath );
1311 if (op_result == FILEOP_ABORT) goto done;
1313 handler( context, SPFILENOTIFY_ENDCOPY, (UINT_PTR)&paths, 0 );
1315 handler( context, SPFILENOTIFY_ENDSUBQUEUE, FILEOP_COPY, 0 );
1319 result = TRUE;
1321 done:
1322 handler( context, SPFILENOTIFY_ENDQUEUE, result, 0 );
1323 HeapFree( GetProcessHeap(), 0, (void *)paths.Source );
1324 HeapFree( GetProcessHeap(), 0, (void *)paths.Target );
1325 return result;
1329 /***********************************************************************
1330 * SetupScanFileQueueA (SETUPAPI.@)
1332 BOOL WINAPI SetupScanFileQueueA( HSPFILEQ handle, DWORD flags, HWND window,
1333 PSP_FILE_CALLBACK_A handler, PVOID context, PDWORD result )
1335 struct callback_WtoA_context ctx;
1337 TRACE("%p %x %p %p %p %p\n", handle, flags, window, handler, context, result);
1339 ctx.orig_context = context;
1340 ctx.orig_handler = handler;
1342 return SetupScanFileQueueW( handle, flags, window, QUEUE_callback_WtoA, &ctx, result );
1346 /***********************************************************************
1347 * SetupScanFileQueueW (SETUPAPI.@)
1349 BOOL WINAPI SetupScanFileQueueW( HSPFILEQ handle, DWORD flags, HWND window,
1350 PSP_FILE_CALLBACK_W handler, PVOID context, PDWORD result )
1352 struct file_queue *queue = handle;
1353 struct file_op *op;
1354 FILEPATHS_W paths;
1355 UINT notification = 0;
1356 BOOL ret = FALSE;
1358 TRACE("%p %x %p %p %p %p\n", handle, flags, window, handler, context, result);
1360 if (!queue->copy_queue.count) return TRUE;
1362 if (flags & SPQ_SCAN_USE_CALLBACK) notification = SPFILENOTIFY_QUEUESCAN;
1363 else if (flags & SPQ_SCAN_USE_CALLBACKEX) notification = SPFILENOTIFY_QUEUESCAN_EX;
1365 if (flags & ~(SPQ_SCAN_USE_CALLBACK | SPQ_SCAN_USE_CALLBACKEX))
1367 FIXME("flags %x not fully implemented\n", flags);
1370 paths.Source = paths.Target = NULL;
1372 for (op = queue->copy_queue.head; op; op = op->next)
1374 build_filepathsW( op, &paths );
1375 switch (notification)
1377 case SPFILENOTIFY_QUEUESCAN:
1378 /* FIXME: handle delay flag */
1379 if (handler( context, notification, (UINT_PTR)paths.Target, 0 )) goto done;
1380 break;
1381 case SPFILENOTIFY_QUEUESCAN_EX:
1382 if (handler( context, notification, (UINT_PTR)&paths, 0 )) goto done;
1383 break;
1384 default:
1385 ret = TRUE; goto done;
1389 ret = TRUE;
1391 done:
1392 if (result) *result = 0;
1393 HeapFree( GetProcessHeap(), 0, (void *)paths.Source );
1394 HeapFree( GetProcessHeap(), 0, (void *)paths.Target );
1395 return ret;
1399 /***********************************************************************
1400 * SetupGetFileQueueCount (SETUPAPI.@)
1402 BOOL WINAPI SetupGetFileQueueCount( HSPFILEQ handle, UINT op, PUINT result )
1404 struct file_queue *queue = handle;
1406 switch(op)
1408 case FILEOP_COPY:
1409 *result = queue->copy_queue.count;
1410 return TRUE;
1411 case FILEOP_RENAME:
1412 *result = queue->rename_queue.count;
1413 return TRUE;
1414 case FILEOP_DELETE:
1415 *result = queue->delete_queue.count;
1416 return TRUE;
1418 return FALSE;
1422 /***********************************************************************
1423 * SetupGetFileQueueFlags (SETUPAPI.@)
1425 BOOL WINAPI SetupGetFileQueueFlags( HSPFILEQ handle, PDWORD flags )
1427 struct file_queue *queue = handle;
1428 *flags = queue->flags;
1429 return TRUE;
1433 /***********************************************************************
1434 * SetupSetFileQueueFlags (SETUPAPI.@)
1436 BOOL WINAPI SetupSetFileQueueFlags( HSPFILEQ handle, DWORD mask, DWORD flags )
1438 struct file_queue *queue = handle;
1439 queue->flags = (queue->flags & ~mask) | flags;
1440 return TRUE;
1444 /***********************************************************************
1445 * SetupSetFileQueueAlternatePlatformA (SETUPAPI.@)
1447 BOOL WINAPI SetupSetFileQueueAlternatePlatformA(HSPFILEQ handle, PSP_ALTPLATFORM_INFO platform, PCSTR catalogfile)
1449 FIXME("(%p, %p, %s) stub!\n", handle, platform, debugstr_a(catalogfile));
1450 return FALSE;
1454 /***********************************************************************
1455 * SetupSetFileQueueAlternatePlatformW (SETUPAPI.@)
1457 BOOL WINAPI SetupSetFileQueueAlternatePlatformW(HSPFILEQ handle, PSP_ALTPLATFORM_INFO platform, PCWSTR catalogfile)
1459 FIXME("(%p, %p, %s) stub!\n", handle, platform, debugstr_w(catalogfile));
1460 return FALSE;
1464 /***********************************************************************
1465 * SetupInitDefaultQueueCallback (SETUPAPI.@)
1467 PVOID WINAPI SetupInitDefaultQueueCallback( HWND owner )
1469 return SetupInitDefaultQueueCallbackEx( owner, 0, 0, 0, NULL );
1473 /***********************************************************************
1474 * SetupInitDefaultQueueCallbackEx (SETUPAPI.@)
1476 PVOID WINAPI SetupInitDefaultQueueCallbackEx( HWND owner, HWND progress, UINT msg,
1477 DWORD reserved1, PVOID reserved2 )
1479 struct default_callback_context *context;
1481 if ((context = HeapAlloc( GetProcessHeap(), 0, sizeof(*context) )))
1483 context->owner = owner;
1484 context->progress = progress;
1485 context->message = msg;
1487 return context;
1491 /***********************************************************************
1492 * SetupTermDefaultQueueCallback (SETUPAPI.@)
1494 void WINAPI SetupTermDefaultQueueCallback( PVOID context )
1496 HeapFree( GetProcessHeap(), 0, context );
1500 /***********************************************************************
1501 * SetupDefaultQueueCallbackA (SETUPAPI.@)
1503 UINT WINAPI SetupDefaultQueueCallbackA( PVOID context, UINT notification,
1504 UINT_PTR param1, UINT_PTR param2 )
1506 FILEPATHS_A *paths = (FILEPATHS_A *)param1;
1507 struct default_callback_context *ctx = context;
1509 switch(notification)
1511 case SPFILENOTIFY_STARTQUEUE:
1512 TRACE( "start queue\n" );
1513 return TRUE;
1514 case SPFILENOTIFY_ENDQUEUE:
1515 TRACE( "end queue\n" );
1516 return 0;
1517 case SPFILENOTIFY_STARTSUBQUEUE:
1518 TRACE( "start subqueue %ld count %ld\n", param1, param2 );
1519 return TRUE;
1520 case SPFILENOTIFY_ENDSUBQUEUE:
1521 TRACE( "end subqueue %ld\n", param1 );
1522 return 0;
1523 case SPFILENOTIFY_STARTDELETE:
1524 TRACE( "start delete %s\n", debugstr_a(paths->Target) );
1525 return FILEOP_DOIT;
1526 case SPFILENOTIFY_ENDDELETE:
1527 TRACE( "end delete %s\n", debugstr_a(paths->Target) );
1528 return 0;
1529 case SPFILENOTIFY_DELETEERROR:
1530 /*Windows Ignores attempts to delete files / folders which do not exist*/
1531 if ((paths->Win32Error != ERROR_FILE_NOT_FOUND) && (paths->Win32Error != ERROR_PATH_NOT_FOUND))
1532 SetupDeleteErrorA(ctx->owner, NULL, paths->Target, paths->Win32Error, 0);
1533 return FILEOP_SKIP;
1534 case SPFILENOTIFY_STARTRENAME:
1535 TRACE( "start rename %s -> %s\n", debugstr_a(paths->Source), debugstr_a(paths->Target) );
1536 return FILEOP_DOIT;
1537 case SPFILENOTIFY_ENDRENAME:
1538 TRACE( "end rename %s -> %s\n", debugstr_a(paths->Source), debugstr_a(paths->Target) );
1539 return 0;
1540 case SPFILENOTIFY_RENAMEERROR:
1541 SetupRenameErrorA(ctx->owner, NULL, paths->Source, paths->Target, paths->Win32Error, 0);
1542 return FILEOP_SKIP;
1543 case SPFILENOTIFY_STARTCOPY:
1544 TRACE( "start copy %s -> %s\n", debugstr_a(paths->Source), debugstr_a(paths->Target) );
1545 return FILEOP_DOIT;
1546 case SPFILENOTIFY_ENDCOPY:
1547 TRACE( "end copy %s -> %s\n", debugstr_a(paths->Source), debugstr_a(paths->Target) );
1548 return 0;
1549 case SPFILENOTIFY_COPYERROR:
1550 ERR( "copy error %d %s -> %s\n", paths->Win32Error,
1551 debugstr_a(paths->Source), debugstr_a(paths->Target) );
1552 return FILEOP_SKIP;
1553 case SPFILENOTIFY_NEEDMEDIA:
1554 TRACE( "need media\n" );
1555 return FILEOP_SKIP;
1556 default:
1557 FIXME( "notification %d params %lx,%lx\n", notification, param1, param2 );
1558 break;
1560 return 0;
1564 /***********************************************************************
1565 * SetupDefaultQueueCallbackW (SETUPAPI.@)
1567 UINT WINAPI SetupDefaultQueueCallbackW( PVOID context, UINT notification,
1568 UINT_PTR param1, UINT_PTR param2 )
1570 FILEPATHS_W *paths = (FILEPATHS_W *)param1;
1571 struct default_callback_context *ctx = context;
1573 switch(notification)
1575 case SPFILENOTIFY_STARTQUEUE:
1576 TRACE( "start queue\n" );
1577 return TRUE;
1578 case SPFILENOTIFY_ENDQUEUE:
1579 TRACE( "end queue\n" );
1580 return 0;
1581 case SPFILENOTIFY_STARTSUBQUEUE:
1582 TRACE( "start subqueue %ld count %ld\n", param1, param2 );
1583 return TRUE;
1584 case SPFILENOTIFY_ENDSUBQUEUE:
1585 TRACE( "end subqueue %ld\n", param1 );
1586 return 0;
1587 case SPFILENOTIFY_STARTDELETE:
1588 TRACE( "start delete %s\n", debugstr_w(paths->Target) );
1589 return FILEOP_DOIT;
1590 case SPFILENOTIFY_ENDDELETE:
1591 TRACE( "end delete %s\n", debugstr_w(paths->Target) );
1592 return 0;
1593 case SPFILENOTIFY_DELETEERROR:
1594 /*Windows Ignores attempts to delete files / folders which do not exist*/
1595 if ((paths->Win32Error != ERROR_FILE_NOT_FOUND) && (paths->Win32Error != ERROR_PATH_NOT_FOUND))
1596 SetupDeleteErrorW(ctx->owner, NULL, paths->Target, paths->Win32Error, 0);
1597 return FILEOP_SKIP;
1598 case SPFILENOTIFY_STARTRENAME:
1599 SetupRenameErrorW(ctx->owner, NULL, paths->Source, paths->Target, paths->Win32Error, 0);
1600 return FILEOP_DOIT;
1601 case SPFILENOTIFY_ENDRENAME:
1602 TRACE( "end rename %s -> %s\n", debugstr_w(paths->Source), debugstr_w(paths->Target) );
1603 return 0;
1604 case SPFILENOTIFY_RENAMEERROR:
1605 ERR( "rename error %d %s -> %s\n", paths->Win32Error,
1606 debugstr_w(paths->Source), debugstr_w(paths->Target) );
1607 return FILEOP_SKIP;
1608 case SPFILENOTIFY_STARTCOPY:
1609 TRACE( "start copy %s -> %s\n", debugstr_w(paths->Source), debugstr_w(paths->Target) );
1610 return FILEOP_DOIT;
1611 case SPFILENOTIFY_ENDCOPY:
1612 TRACE( "end copy %s -> %s\n", debugstr_w(paths->Source), debugstr_w(paths->Target) );
1613 return 0;
1614 case SPFILENOTIFY_COPYERROR:
1615 ERR( "copy error %d %s -> %s\n", paths->Win32Error,
1616 debugstr_w(paths->Source), debugstr_w(paths->Target) );
1617 return FILEOP_SKIP;
1618 case SPFILENOTIFY_NEEDMEDIA:
1619 TRACE( "need media\n" );
1620 return FILEOP_SKIP;
1621 default:
1622 FIXME( "notification %d params %lx,%lx\n", notification, param1, param2 );
1623 break;
1625 return 0;
1628 /***********************************************************************
1629 * SetupDeleteErrorA (SETUPAPI.@)
1632 UINT WINAPI SetupDeleteErrorA( HWND parent, PCSTR dialogTitle, PCSTR file,
1633 UINT w32error, DWORD style)
1635 FIXME( "stub: (Error Number %d when attempting to delete %s)\n",
1636 w32error, debugstr_a(file) );
1637 return DPROMPT_SKIPFILE;
1640 /***********************************************************************
1641 * SetupDeleteErrorW (SETUPAPI.@)
1644 UINT WINAPI SetupDeleteErrorW( HWND parent, PCWSTR dialogTitle, PCWSTR file,
1645 UINT w32error, DWORD style)
1647 FIXME( "stub: (Error Number %d when attempting to delete %s)\n",
1648 w32error, debugstr_w(file) );
1649 return DPROMPT_SKIPFILE;
1652 /***********************************************************************
1653 * SetupRenameErrorA (SETUPAPI.@)
1656 UINT WINAPI SetupRenameErrorA( HWND parent, PCSTR dialogTitle, PCSTR source,
1657 PCSTR target, UINT w32error, DWORD style)
1659 FIXME( "stub: (Error Number %d when attempting to rename %s to %s)\n",
1660 w32error, debugstr_a(source), debugstr_a(target));
1661 return DPROMPT_SKIPFILE;
1664 /***********************************************************************
1665 * SetupRenameErrorW (SETUPAPI.@)
1668 UINT WINAPI SetupRenameErrorW( HWND parent, PCWSTR dialogTitle, PCWSTR source,
1669 PCWSTR target, UINT w32error, DWORD style)
1671 FIXME( "stub: (Error Number %d when attempting to rename %s to %s)\n",
1672 w32error, debugstr_w(source), debugstr_w(target));
1673 return DPROMPT_SKIPFILE;
1677 /***********************************************************************
1678 * SetupCopyErrorA (SETUPAPI.@)
1681 UINT WINAPI SetupCopyErrorA( HWND parent, PCSTR dialogTitle, PCSTR diskname,
1682 PCSTR sourcepath, PCSTR sourcefile, PCSTR targetpath,
1683 UINT w32error, DWORD style, PSTR pathbuffer,
1684 DWORD buffersize, PDWORD requiredsize)
1686 FIXME( "stub: (Error Number %d when attempting to copy file %s from %s to %s)\n",
1687 w32error, debugstr_a(sourcefile), debugstr_a(sourcepath) ,debugstr_a(targetpath));
1688 return DPROMPT_SKIPFILE;
1691 /***********************************************************************
1692 * SetupCopyErrorW (SETUPAPI.@)
1695 UINT WINAPI SetupCopyErrorW( HWND parent, PCWSTR dialogTitle, PCWSTR diskname,
1696 PCWSTR sourcepath, PCWSTR sourcefile, PCWSTR targetpath,
1697 UINT w32error, DWORD style, PWSTR pathbuffer,
1698 DWORD buffersize, PDWORD requiredsize)
1700 FIXME( "stub: (Error Number %d when attempting to copy file %s from %s to %s)\n",
1701 w32error, debugstr_w(sourcefile), debugstr_w(sourcepath) ,debugstr_w(targetpath));
1702 return DPROMPT_SKIPFILE;
1705 /***********************************************************************
1706 * pSetupGetQueueFlags (SETUPAPI.@)
1708 DWORD WINAPI pSetupGetQueueFlags( HSPFILEQ handle )
1710 struct file_queue *queue = handle;
1711 return queue->flags;
1714 /***********************************************************************
1715 * pSetupSetQueueFlags (SETUPAPI.@)
1717 BOOL WINAPI pSetupSetQueueFlags( HSPFILEQ handle, DWORD flags )
1719 struct file_queue *queue = handle;
1720 queue->flags = flags;
1721 return TRUE;