gdiplus: Test the ability to load WMF images.
[wine/multimedia.git] / dlls / setupapi / queue.c
blob6a2b8d62009edbffdcc63273d31ba6a228619119
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;
342 if (!SetupFindFirstLineW( hinf, Dest, section, &context ) &&
343 !SetupFindFirstLineW( hinf, Dest, Def, &context )) return NULL;
344 return PARSER_get_dest_dir( &context );
348 static void (WINAPI *pExtractFiles)( LPSTR, LPSTR, DWORD, DWORD, DWORD, DWORD );
350 /***********************************************************************
351 * extract_cabinet_file
353 * Extract a file from a .cab file.
355 static BOOL extract_cabinet_file( const WCHAR *cabinet, const WCHAR *root,
356 const WCHAR *src, const WCHAR *dst )
358 static const WCHAR extW[] = {'.','c','a','b',0};
359 static HMODULE advpack;
361 char *cab_path, *cab_file;
362 int len = strlenW( cabinet );
364 /* make sure the cabinet file has a .cab extension */
365 if (len <= 4 || strcmpiW( cabinet + len - 4, extW )) return FALSE;
366 if (!pExtractFiles)
368 if (!advpack && !(advpack = LoadLibraryA( "advpack.dll" )))
370 ERR( "could not load advpack.dll\n" );
371 return FALSE;
373 if (!(pExtractFiles = (void *)GetProcAddress( advpack, "ExtractFiles" )))
375 ERR( "could not find ExtractFiles in advpack.dll\n" );
376 return FALSE;
380 if (!(cab_path = strdupWtoA( root ))) return FALSE;
381 len = WideCharToMultiByte( CP_ACP, 0, cabinet, -1, NULL, 0, NULL, NULL );
382 if (!(cab_file = HeapAlloc( GetProcessHeap(), 0, strlen(cab_path) + len + 1 )))
384 HeapFree( GetProcessHeap(), 0, cab_path );
385 return FALSE;
387 strcpy( cab_file, cab_path );
388 if (cab_file[0] && cab_file[strlen(cab_file)-1] != '\\') strcat( cab_file, "\\" );
389 WideCharToMultiByte( CP_ACP, 0, cabinet, -1, cab_file + strlen(cab_file), len, NULL, NULL );
390 FIXME( "awful hack: extracting cabinet %s\n", debugstr_a(cab_file) );
391 pExtractFiles( cab_file, cab_path, 0, 0, 0, 0 );
392 HeapFree( GetProcessHeap(), 0, cab_file );
393 HeapFree( GetProcessHeap(), 0, cab_path );
394 return CopyFileW( src, dst, FALSE /*FIXME*/ );
398 /***********************************************************************
399 * SetupOpenFileQueue (SETUPAPI.@)
401 HSPFILEQ WINAPI SetupOpenFileQueue(void)
403 struct file_queue *queue;
405 if (!(queue = HeapAlloc( GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*queue))))
406 return INVALID_HANDLE_VALUE;
407 return queue;
411 /***********************************************************************
412 * SetupCloseFileQueue (SETUPAPI.@)
414 BOOL WINAPI SetupCloseFileQueue( HSPFILEQ handle )
416 struct file_queue *queue = handle;
418 free_file_op_queue( &queue->copy_queue );
419 free_file_op_queue( &queue->rename_queue );
420 free_file_op_queue( &queue->delete_queue );
421 HeapFree( GetProcessHeap(), 0, queue );
422 return TRUE;
426 /***********************************************************************
427 * SetupQueueCopyIndirectA (SETUPAPI.@)
429 BOOL WINAPI SetupQueueCopyIndirectA( PSP_FILE_COPY_PARAMS_A params )
431 struct file_queue *queue = params->QueueHandle;
432 struct file_op *op;
434 if (!(op = HeapAlloc( GetProcessHeap(), 0, sizeof(*op) ))) return FALSE;
435 op->style = params->CopyStyle;
436 op->src_root = strdupAtoW( params->SourceRootPath );
437 op->src_path = strdupAtoW( params->SourcePath );
438 op->src_file = strdupAtoW( params->SourceFilename );
439 op->src_descr = strdupAtoW( params->SourceDescription );
440 op->src_tag = strdupAtoW( params->SourceTagfile );
441 op->dst_path = strdupAtoW( params->TargetDirectory );
442 op->dst_file = strdupAtoW( params->TargetFilename );
444 /* some defaults */
445 if (!op->src_file) op->src_file = op->dst_file;
446 if (params->LayoutInf)
448 get_src_file_info( params->LayoutInf, op );
449 if (!op->dst_path) op->dst_path = get_destination_dir( params->LayoutInf, op->dst_file );
452 TRACE( "root=%s path=%s file=%s -> dir=%s file=%s descr=%s tag=%s\n",
453 debugstr_w(op->src_root), debugstr_w(op->src_path), debugstr_w(op->src_file),
454 debugstr_w(op->dst_path), debugstr_w(op->dst_file),
455 debugstr_w(op->src_descr), debugstr_w(op->src_tag) );
457 queue_file_op( &queue->copy_queue, op );
458 return TRUE;
462 /***********************************************************************
463 * SetupQueueCopyIndirectW (SETUPAPI.@)
465 BOOL WINAPI SetupQueueCopyIndirectW( PSP_FILE_COPY_PARAMS_W params )
467 struct file_queue *queue = params->QueueHandle;
468 struct file_op *op;
470 if (!(op = HeapAlloc( GetProcessHeap(), 0, sizeof(*op) ))) return FALSE;
471 op->style = params->CopyStyle;
472 op->src_root = strdupW( params->SourceRootPath );
473 op->src_path = strdupW( params->SourcePath );
474 op->src_file = strdupW( params->SourceFilename );
475 op->src_descr = strdupW( params->SourceDescription );
476 op->src_tag = strdupW( params->SourceTagfile );
477 op->dst_path = strdupW( params->TargetDirectory );
478 op->dst_file = strdupW( params->TargetFilename );
480 /* some defaults */
481 if (!op->src_file) op->src_file = op->dst_file;
482 if (params->LayoutInf)
484 get_src_file_info( params->LayoutInf, op );
485 if (!op->dst_path) op->dst_path = get_destination_dir( params->LayoutInf, op->dst_file );
488 TRACE( "root=%s path=%s file=%s -> dir=%s file=%s descr=%s tag=%s\n",
489 debugstr_w(op->src_root), debugstr_w(op->src_path), debugstr_w(op->src_file),
490 debugstr_w(op->dst_path), debugstr_w(op->dst_file),
491 debugstr_w(op->src_descr), debugstr_w(op->src_tag) );
493 queue_file_op( &queue->copy_queue, op );
494 return TRUE;
498 /***********************************************************************
499 * SetupQueueCopyA (SETUPAPI.@)
501 BOOL WINAPI SetupQueueCopyA( HSPFILEQ queue, PCSTR src_root, PCSTR src_path, PCSTR src_file,
502 PCSTR src_descr, PCSTR src_tag, PCSTR dst_dir, PCSTR dst_file,
503 DWORD style )
505 SP_FILE_COPY_PARAMS_A params;
507 params.cbSize = sizeof(params);
508 params.QueueHandle = queue;
509 params.SourceRootPath = src_root;
510 params.SourcePath = src_path;
511 params.SourceFilename = src_file;
512 params.SourceDescription = src_descr;
513 params.SourceTagfile = src_tag;
514 params.TargetDirectory = dst_dir;
515 params.TargetFilename = dst_file;
516 params.CopyStyle = style;
517 params.LayoutInf = 0;
518 params.SecurityDescriptor = NULL;
519 return SetupQueueCopyIndirectA( &params );
523 /***********************************************************************
524 * SetupQueueCopyW (SETUPAPI.@)
526 BOOL WINAPI SetupQueueCopyW( HSPFILEQ queue, PCWSTR src_root, PCWSTR src_path, PCWSTR src_file,
527 PCWSTR src_descr, PCWSTR src_tag, PCWSTR dst_dir, PCWSTR dst_file,
528 DWORD style )
530 SP_FILE_COPY_PARAMS_W params;
532 params.cbSize = sizeof(params);
533 params.QueueHandle = queue;
534 params.SourceRootPath = src_root;
535 params.SourcePath = src_path;
536 params.SourceFilename = src_file;
537 params.SourceDescription = src_descr;
538 params.SourceTagfile = src_tag;
539 params.TargetDirectory = dst_dir;
540 params.TargetFilename = dst_file;
541 params.CopyStyle = style;
542 params.LayoutInf = 0;
543 params.SecurityDescriptor = NULL;
544 return SetupQueueCopyIndirectW( &params );
548 /***********************************************************************
549 * SetupQueueDefaultCopyA (SETUPAPI.@)
551 BOOL WINAPI SetupQueueDefaultCopyA( HSPFILEQ queue, HINF hinf, PCSTR src_root, PCSTR src_file,
552 PCSTR dst_file, DWORD style )
554 SP_FILE_COPY_PARAMS_A params;
556 params.cbSize = sizeof(params);
557 params.QueueHandle = queue;
558 params.SourceRootPath = src_root;
559 params.SourcePath = NULL;
560 params.SourceFilename = src_file;
561 params.SourceDescription = NULL;
562 params.SourceTagfile = NULL;
563 params.TargetDirectory = NULL;
564 params.TargetFilename = dst_file;
565 params.CopyStyle = style;
566 params.LayoutInf = hinf;
567 params.SecurityDescriptor = NULL;
568 return SetupQueueCopyIndirectA( &params );
572 /***********************************************************************
573 * SetupQueueDefaultCopyW (SETUPAPI.@)
575 BOOL WINAPI SetupQueueDefaultCopyW( HSPFILEQ queue, HINF hinf, PCWSTR src_root, PCWSTR src_file,
576 PCWSTR dst_file, DWORD style )
578 SP_FILE_COPY_PARAMS_W params;
580 params.cbSize = sizeof(params);
581 params.QueueHandle = queue;
582 params.SourceRootPath = src_root;
583 params.SourcePath = NULL;
584 params.SourceFilename = src_file;
585 params.SourceDescription = NULL;
586 params.SourceTagfile = NULL;
587 params.TargetDirectory = NULL;
588 params.TargetFilename = dst_file;
589 params.CopyStyle = style;
590 params.LayoutInf = hinf;
591 params.SecurityDescriptor = NULL;
592 return SetupQueueCopyIndirectW( &params );
596 /***********************************************************************
597 * SetupQueueDeleteA (SETUPAPI.@)
599 BOOL WINAPI SetupQueueDeleteA( HSPFILEQ handle, PCSTR part1, PCSTR part2 )
601 struct file_queue *queue = handle;
602 struct file_op *op;
604 if (!(op = HeapAlloc( GetProcessHeap(), 0, sizeof(*op) ))) return FALSE;
605 op->style = 0;
606 op->src_root = NULL;
607 op->src_path = NULL;
608 op->src_file = NULL;
609 op->src_descr = NULL;
610 op->src_tag = NULL;
611 op->dst_path = strdupAtoW( part1 );
612 op->dst_file = strdupAtoW( part2 );
613 queue_file_op( &queue->delete_queue, op );
614 return TRUE;
618 /***********************************************************************
619 * SetupQueueDeleteW (SETUPAPI.@)
621 BOOL WINAPI SetupQueueDeleteW( HSPFILEQ handle, PCWSTR part1, PCWSTR part2 )
623 struct file_queue *queue = handle;
624 struct file_op *op;
626 if (!(op = HeapAlloc( GetProcessHeap(), 0, sizeof(*op) ))) return FALSE;
627 op->style = 0;
628 op->src_root = NULL;
629 op->src_path = NULL;
630 op->src_file = NULL;
631 op->src_descr = NULL;
632 op->src_tag = NULL;
633 op->dst_path = strdupW( part1 );
634 op->dst_file = strdupW( part2 );
635 queue_file_op( &queue->delete_queue, op );
636 return TRUE;
640 /***********************************************************************
641 * SetupQueueRenameA (SETUPAPI.@)
643 BOOL WINAPI SetupQueueRenameA( HSPFILEQ handle, PCSTR SourcePath, PCSTR SourceFilename,
644 PCSTR TargetPath, PCSTR TargetFilename )
646 struct file_queue *queue = handle;
647 struct file_op *op;
649 if (!(op = HeapAlloc( GetProcessHeap(), 0, sizeof(*op) ))) return FALSE;
650 op->style = 0;
651 op->src_root = NULL;
652 op->src_path = strdupAtoW( SourcePath );
653 op->src_file = strdupAtoW( SourceFilename );
654 op->src_descr = NULL;
655 op->src_tag = NULL;
656 op->dst_path = strdupAtoW( TargetPath );
657 op->dst_file = strdupAtoW( TargetFilename );
658 queue_file_op( &queue->rename_queue, op );
659 return TRUE;
663 /***********************************************************************
664 * SetupQueueRenameW (SETUPAPI.@)
666 BOOL WINAPI SetupQueueRenameW( HSPFILEQ handle, PCWSTR SourcePath, PCWSTR SourceFilename,
667 PCWSTR TargetPath, PCWSTR TargetFilename )
669 struct file_queue *queue = handle;
670 struct file_op *op;
672 if (!(op = HeapAlloc( GetProcessHeap(), 0, sizeof(*op) ))) return FALSE;
673 op->style = 0;
674 op->src_root = NULL;
675 op->src_path = strdupW( SourcePath );
676 op->src_file = strdupW( SourceFilename );
677 op->src_descr = NULL;
678 op->src_tag = NULL;
679 op->dst_path = strdupW( TargetPath );
680 op->dst_file = strdupW( TargetFilename );
681 queue_file_op( &queue->rename_queue, op );
682 return TRUE;
686 /***********************************************************************
687 * SetupQueueCopySectionA (SETUPAPI.@)
689 BOOL WINAPI SetupQueueCopySectionA( HSPFILEQ queue, PCSTR src_root, HINF hinf, HINF hlist,
690 PCSTR section, DWORD style )
692 UNICODE_STRING sectionW;
693 BOOL ret = FALSE;
695 if (!RtlCreateUnicodeStringFromAsciiz( &sectionW, section ))
697 SetLastError( ERROR_NOT_ENOUGH_MEMORY );
698 return FALSE;
700 if (!src_root)
701 ret = SetupQueueCopySectionW( queue, NULL, hinf, hlist, sectionW.Buffer, style );
702 else
704 UNICODE_STRING srcW;
705 if (RtlCreateUnicodeStringFromAsciiz( &srcW, src_root ))
707 ret = SetupQueueCopySectionW( queue, srcW.Buffer, hinf, hlist, sectionW.Buffer, style );
708 RtlFreeUnicodeString( &srcW );
710 else SetLastError( ERROR_NOT_ENOUGH_MEMORY );
712 RtlFreeUnicodeString( &sectionW );
713 return ret;
717 /***********************************************************************
718 * SetupQueueCopySectionW (SETUPAPI.@)
720 BOOL WINAPI SetupQueueCopySectionW( HSPFILEQ queue, PCWSTR src_root, HINF hinf, HINF hlist,
721 PCWSTR section, DWORD style )
723 SP_FILE_COPY_PARAMS_W params;
724 INFCONTEXT context;
725 WCHAR dest[MAX_PATH], src[MAX_PATH], *dest_dir;
726 INT flags;
727 BOOL ret = FALSE;
729 TRACE( "hinf=%p/%p section=%s root=%s\n",
730 hinf, hlist, debugstr_w(section), debugstr_w(src_root) );
732 params.cbSize = sizeof(params);
733 params.QueueHandle = queue;
734 params.SourceRootPath = src_root;
735 params.SourcePath = NULL;
736 params.SourceDescription = NULL;
737 params.SourceTagfile = NULL;
738 params.TargetFilename = dest;
739 params.CopyStyle = style;
740 params.LayoutInf = hinf;
741 params.SecurityDescriptor = NULL;
743 if (!hlist) hlist = hinf;
744 if (!hinf) hinf = hlist;
745 if (!SetupFindFirstLineW( hlist, section, NULL, &context )) return FALSE;
746 if (!(params.TargetDirectory = dest_dir = get_destination_dir( hinf, section ))) return FALSE;
749 if (!SetupGetStringFieldW( &context, 1, dest, sizeof(dest)/sizeof(WCHAR), NULL ))
750 goto end;
751 if (!SetupGetStringFieldW( &context, 2, src, sizeof(src)/sizeof(WCHAR), NULL )) *src = 0;
752 if (!SetupGetIntField( &context, 4, &flags )) flags = 0; /* FIXME */
754 params.SourceFilename = *src ? src : NULL;
755 if (!SetupQueueCopyIndirectW( &params )) goto end;
756 } while (SetupFindNextLine( &context, &context ));
757 ret = TRUE;
758 end:
759 HeapFree(GetProcessHeap(), 0, dest_dir);
760 return ret;
764 /***********************************************************************
765 * SetupQueueDeleteSectionA (SETUPAPI.@)
767 BOOL WINAPI SetupQueueDeleteSectionA( HSPFILEQ queue, HINF hinf, HINF hlist, PCSTR section )
769 UNICODE_STRING sectionW;
770 BOOL ret = FALSE;
772 if (RtlCreateUnicodeStringFromAsciiz( &sectionW, section ))
774 ret = SetupQueueDeleteSectionW( queue, hinf, hlist, sectionW.Buffer );
775 RtlFreeUnicodeString( &sectionW );
777 else SetLastError( ERROR_NOT_ENOUGH_MEMORY );
778 return ret;
782 /***********************************************************************
783 * SetupQueueDeleteSectionW (SETUPAPI.@)
785 BOOL WINAPI SetupQueueDeleteSectionW( HSPFILEQ queue, HINF hinf, HINF hlist, PCWSTR section )
787 INFCONTEXT context;
788 WCHAR *dest_dir;
789 WCHAR buffer[MAX_PATH];
790 BOOL ret = FALSE;
791 INT flags;
793 TRACE( "hinf=%p/%p section=%s\n", hinf, hlist, debugstr_w(section) );
795 if (!hlist) hlist = hinf;
796 if (!SetupFindFirstLineW( hlist, section, NULL, &context )) return FALSE;
797 if (!(dest_dir = get_destination_dir( hinf, section ))) return FALSE;
800 if (!SetupGetStringFieldW( &context, 1, buffer, sizeof(buffer)/sizeof(WCHAR), NULL ))
801 goto done;
802 if (!SetupGetIntField( &context, 4, &flags )) flags = 0;
803 if (!SetupQueueDeleteW( queue, dest_dir, buffer )) goto done;
804 } while (SetupFindNextLine( &context, &context ));
806 ret = TRUE;
807 done:
808 HeapFree( GetProcessHeap(), 0, dest_dir );
809 return ret;
813 /***********************************************************************
814 * SetupQueueRenameSectionA (SETUPAPI.@)
816 BOOL WINAPI SetupQueueRenameSectionA( HSPFILEQ queue, HINF hinf, HINF hlist, PCSTR section )
818 UNICODE_STRING sectionW;
819 BOOL ret = FALSE;
821 if (RtlCreateUnicodeStringFromAsciiz( &sectionW, section ))
823 ret = SetupQueueRenameSectionW( queue, hinf, hlist, sectionW.Buffer );
824 RtlFreeUnicodeString( &sectionW );
826 else SetLastError( ERROR_NOT_ENOUGH_MEMORY );
827 return ret;
831 /***********************************************************************
832 * SetupQueueRenameSectionW (SETUPAPI.@)
834 BOOL WINAPI SetupQueueRenameSectionW( HSPFILEQ queue, HINF hinf, HINF hlist, PCWSTR section )
836 INFCONTEXT context;
837 WCHAR *dest_dir;
838 WCHAR src[MAX_PATH], dst[MAX_PATH];
839 BOOL ret = FALSE;
841 TRACE( "hinf=%p/%p section=%s\n", hinf, hlist, debugstr_w(section) );
843 if (!hlist) hlist = hinf;
844 if (!SetupFindFirstLineW( hlist, section, NULL, &context )) return FALSE;
845 if (!(dest_dir = get_destination_dir( hinf, section ))) return FALSE;
848 if (!SetupGetStringFieldW( &context, 1, dst, sizeof(dst)/sizeof(WCHAR), NULL ))
849 goto done;
850 if (!SetupGetStringFieldW( &context, 2, src, sizeof(src)/sizeof(WCHAR), NULL ))
851 goto done;
852 if (!SetupQueueRenameW( queue, dest_dir, src, NULL, dst )) goto done;
853 } while (SetupFindNextLine( &context, &context ));
855 ret = TRUE;
856 done:
857 HeapFree( GetProcessHeap(), 0, dest_dir );
858 return ret;
862 /***********************************************************************
863 * SetupCommitFileQueueA (SETUPAPI.@)
865 BOOL WINAPI SetupCommitFileQueueA( HWND owner, HSPFILEQ queue, PSP_FILE_CALLBACK_A handler,
866 PVOID context )
868 struct callback_WtoA_context ctx;
870 ctx.orig_context = context;
871 ctx.orig_handler = handler;
872 return SetupCommitFileQueueW( owner, queue, QUEUE_callback_WtoA, &ctx );
876 /***********************************************************************
877 * create_full_pathW
879 * Recursively create all directories in the path.
881 static BOOL create_full_pathW(const WCHAR *path)
883 BOOL ret = TRUE;
884 int len;
885 WCHAR *new_path;
887 new_path = HeapAlloc(GetProcessHeap(), 0, (strlenW(path) + 1) * sizeof(WCHAR));
888 strcpyW(new_path, path);
890 while((len = strlenW(new_path)) && new_path[len - 1] == '\\')
891 new_path[len - 1] = 0;
893 while(!CreateDirectoryW(new_path, NULL))
895 WCHAR *slash;
896 DWORD last_error = GetLastError();
898 if(last_error == ERROR_ALREADY_EXISTS)
899 break;
901 if(last_error != ERROR_PATH_NOT_FOUND)
903 ret = FALSE;
904 break;
907 if(!(slash = strrchrW(new_path, '\\')))
909 ret = FALSE;
910 break;
913 len = slash - new_path;
914 new_path[len] = 0;
915 if(!create_full_pathW(new_path))
917 ret = FALSE;
918 break;
920 new_path[len] = '\\';
923 HeapFree(GetProcessHeap(), 0, new_path);
924 return ret;
927 static BOOL do_file_copyW( LPCWSTR source, LPCWSTR target, DWORD style,
928 PSP_FILE_CALLBACK_W handler, PVOID context )
930 BOOL rc = FALSE;
931 BOOL docopy = TRUE;
933 TRACE("copy %s to %s style 0x%x\n",debugstr_w(source),debugstr_w(target),style);
935 /* before copy processing */
936 if (style & SP_COPY_REPLACEONLY)
938 if (GetFileAttributesW(target) == INVALID_FILE_ATTRIBUTES)
939 docopy = FALSE;
941 if (style & (SP_COPY_NEWER_OR_SAME | SP_COPY_NEWER_ONLY | SP_COPY_FORCE_NEWER))
943 DWORD VersionSizeSource=0;
944 DWORD VersionSizeTarget=0;
945 DWORD zero=0;
948 * This is sort of an interesting workaround. You see, calling
949 * GetVersionInfoSize on a builtin dll loads that dll into memory
950 * and we do not properly unload builtin dlls.. so we effectively
951 * lock into memory all the targets we are replacing. This leads
952 * to problems when we try to register the replaced dlls.
954 * So I will test for the existence of the files first so that
955 * we just basically unconditionally replace the builtin versions.
957 if ((GetFileAttributesW(target) != INVALID_FILE_ATTRIBUTES) &&
958 (GetFileAttributesW(source) != INVALID_FILE_ATTRIBUTES))
960 VersionSizeSource = GetFileVersionInfoSizeW(source,&zero);
961 VersionSizeTarget = GetFileVersionInfoSizeW(target,&zero);
964 TRACE("SizeTarget %i ... SizeSource %i\n",VersionSizeTarget,
965 VersionSizeSource);
967 if (VersionSizeSource && VersionSizeTarget)
969 LPVOID VersionSource;
970 LPVOID VersionTarget;
971 VS_FIXEDFILEINFO *TargetInfo;
972 VS_FIXEDFILEINFO *SourceInfo;
973 UINT length;
974 WCHAR SubBlock[2]={'\\',0};
975 DWORD ret;
977 VersionSource = HeapAlloc(GetProcessHeap(),0,VersionSizeSource);
978 VersionTarget = HeapAlloc(GetProcessHeap(),0,VersionSizeTarget);
980 ret = GetFileVersionInfoW(source,0,VersionSizeSource,VersionSource);
981 if (ret)
982 ret = GetFileVersionInfoW(target, 0, VersionSizeTarget,
983 VersionTarget);
985 if (ret)
987 ret = VerQueryValueW(VersionSource, SubBlock,
988 (LPVOID*)&SourceInfo, &length);
989 if (ret)
990 ret = VerQueryValueW(VersionTarget, SubBlock,
991 (LPVOID*)&TargetInfo, &length);
993 if (ret)
995 FILEPATHS_W filepaths;
997 TRACE("Versions: Source %i.%i target %i.%i\n",
998 SourceInfo->dwFileVersionMS, SourceInfo->dwFileVersionLS,
999 TargetInfo->dwFileVersionMS, TargetInfo->dwFileVersionLS);
1001 /* used in case of notification */
1002 filepaths.Target = target;
1003 filepaths.Source = source;
1004 filepaths.Win32Error = 0;
1005 filepaths.Flags = 0;
1007 if (TargetInfo->dwFileVersionMS > SourceInfo->dwFileVersionMS)
1009 if (handler)
1010 docopy = handler (context, SPFILENOTIFY_TARGETNEWER, (UINT_PTR)&filepaths, 0);
1011 else
1012 docopy = FALSE;
1014 else if ((TargetInfo->dwFileVersionMS == SourceInfo->dwFileVersionMS)
1015 && (TargetInfo->dwFileVersionLS > SourceInfo->dwFileVersionLS))
1017 if (handler)
1018 docopy = handler (context, SPFILENOTIFY_TARGETNEWER, (UINT_PTR)&filepaths, 0);
1019 else
1020 docopy = FALSE;
1022 else if ((style & SP_COPY_NEWER_ONLY) &&
1023 (TargetInfo->dwFileVersionMS ==
1024 SourceInfo->dwFileVersionMS)
1025 &&(TargetInfo->dwFileVersionLS ==
1026 SourceInfo->dwFileVersionLS))
1028 if (handler)
1029 docopy = handler (context, SPFILENOTIFY_TARGETNEWER, (UINT_PTR)&filepaths, 0);
1030 else
1031 docopy = FALSE;
1035 HeapFree(GetProcessHeap(),0,VersionSource);
1036 HeapFree(GetProcessHeap(),0,VersionTarget);
1039 if (style & (SP_COPY_NOOVERWRITE | SP_COPY_FORCE_NOOVERWRITE))
1041 if (GetFileAttributesW(target) != INVALID_FILE_ATTRIBUTES)
1043 FIXME("Notify user target file exists\n");
1044 docopy = FALSE;
1047 if (style & (SP_COPY_NODECOMP | SP_COPY_LANGUAGEAWARE | SP_COPY_FORCE_IN_USE |
1048 SP_COPY_IN_USE_NEEDS_REBOOT | SP_COPY_NOSKIP | SP_COPY_WARNIFSKIP))
1050 ERR("Unsupported style(s) 0x%x\n",style);
1053 if (docopy)
1055 rc = CopyFileW(source,target,FALSE);
1056 TRACE("Did copy... rc was %i\n",rc);
1059 /* after copy processing */
1060 if (style & SP_COPY_DELETESOURCE)
1062 if (rc)
1063 DeleteFileW(source);
1066 return rc;
1069 /***********************************************************************
1070 * SetupInstallFileExA (SETUPAPI.@)
1072 BOOL WINAPI SetupInstallFileExA( HINF hinf, PINFCONTEXT inf_context, PCSTR source, PCSTR root,
1073 PCSTR dest, DWORD style, PSP_FILE_CALLBACK_A handler, PVOID context, PBOOL in_use )
1075 BOOL ret = FALSE;
1076 struct callback_WtoA_context ctx;
1077 UNICODE_STRING sourceW, rootW, destW;
1079 TRACE("%p %p %s %s %s %x %p %p %p\n", hinf, inf_context, debugstr_a(source), debugstr_a(root),
1080 debugstr_a(dest), style, handler, context, in_use);
1082 sourceW.Buffer = rootW.Buffer = destW.Buffer = NULL;
1083 if (source && !RtlCreateUnicodeStringFromAsciiz( &sourceW, source ))
1085 SetLastError( ERROR_NOT_ENOUGH_MEMORY );
1086 return FALSE;
1088 if (root && !RtlCreateUnicodeStringFromAsciiz( &rootW, root ))
1090 SetLastError( ERROR_NOT_ENOUGH_MEMORY );
1091 goto exit;
1093 if (dest && !RtlCreateUnicodeStringFromAsciiz( &destW, dest ))
1095 SetLastError( ERROR_NOT_ENOUGH_MEMORY );
1096 goto exit;
1099 ctx.orig_context = context;
1100 ctx.orig_handler = handler;
1102 ret = SetupInstallFileExW( hinf, inf_context, sourceW.Buffer, rootW.Buffer, destW.Buffer, style, QUEUE_callback_WtoA, &ctx, in_use );
1104 exit:
1105 RtlFreeUnicodeString( &sourceW );
1106 RtlFreeUnicodeString( &rootW );
1107 RtlFreeUnicodeString( &destW );
1108 return ret;
1111 /***********************************************************************
1112 * SetupInstallFileA (SETUPAPI.@)
1114 BOOL WINAPI SetupInstallFileA( HINF hinf, PINFCONTEXT inf_context, PCSTR source, PCSTR root,
1115 PCSTR dest, DWORD style, PSP_FILE_CALLBACK_A handler, PVOID context )
1117 return SetupInstallFileExA( hinf, inf_context, source, root, dest, style, handler, context, NULL );
1120 /***********************************************************************
1121 * SetupInstallFileExW (SETUPAPI.@)
1123 BOOL WINAPI SetupInstallFileExW( HINF hinf, PINFCONTEXT inf_context, PCWSTR source, PCWSTR root,
1124 PCWSTR dest, DWORD style, PSP_FILE_CALLBACK_W handler, PVOID context, PBOOL in_use )
1126 static const WCHAR CopyFiles[] = {'C','o','p','y','F','i','l','e','s',0};
1128 BOOL ret, absolute = (root && *root && !(style & SP_COPY_SOURCE_ABSOLUTE));
1129 WCHAR *buffer, *p, *inf_source = NULL;
1130 unsigned int len;
1132 TRACE("%p %p %s %s %s %x %p %p %p\n", hinf, inf_context, debugstr_w(source), debugstr_w(root),
1133 debugstr_w(dest), style, handler, context, in_use);
1135 if (in_use) FIXME("no file in use support\n");
1137 if (hinf)
1139 INFCONTEXT ctx;
1141 if (!inf_context)
1143 inf_context = &ctx;
1144 if (!SetupFindFirstLineW( hinf, CopyFiles, NULL, inf_context )) return FALSE;
1146 if (!SetupGetStringFieldW( inf_context, 1, NULL, 0, &len )) return FALSE;
1147 if (!(inf_source = HeapAlloc( GetProcessHeap(), 0, len * sizeof(WCHAR) )))
1149 SetLastError( ERROR_NOT_ENOUGH_MEMORY );
1150 return FALSE;
1152 if (!SetupGetStringFieldW( inf_context, 1, inf_source, len, NULL )) return FALSE;
1153 source = inf_source;
1155 else if (!source)
1157 SetLastError( ERROR_INVALID_PARAMETER );
1158 return FALSE;
1161 len = strlenW( source ) + 1;
1162 if (absolute) len += strlenW( root ) + 1;
1164 if (!(p = buffer = HeapAlloc( GetProcessHeap(), 0, len * sizeof(WCHAR) )))
1166 HeapFree( GetProcessHeap(), 0, inf_source );
1167 SetLastError( ERROR_NOT_ENOUGH_MEMORY );
1168 return FALSE;
1171 if (absolute)
1173 strcpyW( buffer, root );
1174 p += strlenW( buffer );
1175 if (p[-1] != '\\') *p++ = '\\';
1177 while (*source == '\\') source++;
1178 strcpyW( p, source );
1180 ret = do_file_copyW( buffer, dest, style, handler, context );
1182 HeapFree( GetProcessHeap(), 0, inf_source );
1183 HeapFree( GetProcessHeap(), 0, buffer );
1184 return ret;
1187 /***********************************************************************
1188 * SetupInstallFileW (SETUPAPI.@)
1190 BOOL WINAPI SetupInstallFileW( HINF hinf, PINFCONTEXT inf_context, PCWSTR source, PCWSTR root,
1191 PCWSTR dest, DWORD style, PSP_FILE_CALLBACK_W handler, PVOID context )
1193 return SetupInstallFileExW( hinf, inf_context, source, root, dest, style, handler, context, NULL );
1196 /***********************************************************************
1197 * SetupCommitFileQueueW (SETUPAPI.@)
1199 BOOL WINAPI SetupCommitFileQueueW( HWND owner, HSPFILEQ handle, PSP_FILE_CALLBACK_W handler,
1200 PVOID context )
1202 struct file_queue *queue = handle;
1203 struct file_op *op;
1204 BOOL result = FALSE;
1205 FILEPATHS_W paths;
1206 UINT op_result;
1208 paths.Source = paths.Target = NULL;
1210 if (!queue->copy_queue.count && !queue->delete_queue.count && !queue->rename_queue.count)
1211 return TRUE; /* nothing to do */
1213 if (!handler( context, SPFILENOTIFY_STARTQUEUE, (UINT_PTR)owner, 0 )) return FALSE;
1215 /* perform deletes */
1217 if (queue->delete_queue.count)
1219 if (!(handler( context, SPFILENOTIFY_STARTSUBQUEUE, FILEOP_DELETE,
1220 queue->delete_queue.count ))) goto done;
1221 for (op = queue->delete_queue.head; op; op = op->next)
1223 build_filepathsW( op, &paths );
1224 op_result = handler( context, SPFILENOTIFY_STARTDELETE, (UINT_PTR)&paths, FILEOP_DELETE);
1225 if (op_result == FILEOP_ABORT) goto done;
1226 while (op_result == FILEOP_DOIT)
1228 TRACE( "deleting file %s\n", debugstr_w(paths.Target) );
1229 if (DeleteFileW( paths.Target )) break; /* success */
1230 paths.Win32Error = GetLastError();
1231 op_result = handler( context, SPFILENOTIFY_DELETEERROR, (UINT_PTR)&paths, 0 );
1232 if (op_result == FILEOP_ABORT) goto done;
1234 handler( context, SPFILENOTIFY_ENDDELETE, (UINT_PTR)&paths, 0 );
1236 handler( context, SPFILENOTIFY_ENDSUBQUEUE, FILEOP_DELETE, 0 );
1239 /* perform renames */
1241 if (queue->rename_queue.count)
1243 if (!(handler( context, SPFILENOTIFY_STARTSUBQUEUE, FILEOP_RENAME,
1244 queue->rename_queue.count ))) goto done;
1245 for (op = queue->rename_queue.head; op; op = op->next)
1247 build_filepathsW( op, &paths );
1248 op_result = handler( context, SPFILENOTIFY_STARTRENAME, (UINT_PTR)&paths, FILEOP_RENAME);
1249 if (op_result == FILEOP_ABORT) goto done;
1250 while (op_result == FILEOP_DOIT)
1252 TRACE( "renaming file %s -> %s\n",
1253 debugstr_w(paths.Source), debugstr_w(paths.Target) );
1254 if (MoveFileW( paths.Source, paths.Target )) break; /* success */
1255 paths.Win32Error = GetLastError();
1256 op_result = handler( context, SPFILENOTIFY_RENAMEERROR, (UINT_PTR)&paths, 0 );
1257 if (op_result == FILEOP_ABORT) goto done;
1259 handler( context, SPFILENOTIFY_ENDRENAME, (UINT_PTR)&paths, 0 );
1261 handler( context, SPFILENOTIFY_ENDSUBQUEUE, FILEOP_RENAME, 0 );
1264 /* perform copies */
1266 if (queue->copy_queue.count)
1268 if (!(handler( context, SPFILENOTIFY_STARTSUBQUEUE, FILEOP_COPY,
1269 queue->copy_queue.count ))) goto done;
1270 for (op = queue->copy_queue.head; op; op = op->next)
1272 WCHAR newpath[MAX_PATH];
1274 build_filepathsW( op, &paths );
1275 op_result = handler( context, SPFILENOTIFY_STARTCOPY, (UINT_PTR)&paths, FILEOP_COPY );
1276 if (op_result == FILEOP_ABORT) goto done;
1277 if (op_result == FILEOP_NEWPATH) op_result = FILEOP_DOIT;
1278 while (op_result == FILEOP_DOIT || op_result == FILEOP_NEWPATH)
1280 TRACE( "copying file %s -> %s\n",
1281 debugstr_w( op_result == FILEOP_NEWPATH ? newpath : paths.Source ),
1282 debugstr_w(paths.Target) );
1283 if (op->dst_path)
1285 if (!create_full_pathW( op->dst_path ))
1287 paths.Win32Error = GetLastError();
1288 op_result = handler( context, SPFILENOTIFY_COPYERROR,
1289 (UINT_PTR)&paths, (UINT_PTR)newpath );
1290 if (op_result == FILEOP_ABORT) goto done;
1293 if (do_file_copyW( op_result == FILEOP_NEWPATH ? newpath : paths.Source,
1294 paths.Target, op->style, handler, context )) break; /* success */
1295 /* try to extract it from the cabinet file */
1296 if (op->src_tag)
1298 if (extract_cabinet_file( op->src_tag, op->src_root,
1299 paths.Source, paths.Target )) break;
1301 paths.Win32Error = GetLastError();
1302 op_result = handler( context, SPFILENOTIFY_COPYERROR,
1303 (UINT_PTR)&paths, (UINT_PTR)newpath );
1304 if (op_result == FILEOP_ABORT) goto done;
1306 handler( context, SPFILENOTIFY_ENDCOPY, (UINT_PTR)&paths, 0 );
1308 handler( context, SPFILENOTIFY_ENDSUBQUEUE, FILEOP_COPY, 0 );
1312 result = TRUE;
1314 done:
1315 handler( context, SPFILENOTIFY_ENDQUEUE, result, 0 );
1316 HeapFree( GetProcessHeap(), 0, (void *)paths.Source );
1317 HeapFree( GetProcessHeap(), 0, (void *)paths.Target );
1318 return result;
1322 /***********************************************************************
1323 * SetupScanFileQueueA (SETUPAPI.@)
1325 BOOL WINAPI SetupScanFileQueueA( HSPFILEQ handle, DWORD flags, HWND window,
1326 PSP_FILE_CALLBACK_A handler, PVOID context, PDWORD result )
1328 struct callback_WtoA_context ctx;
1330 TRACE("%p %x %p %p %p %p\n", handle, flags, window, handler, context, result);
1332 ctx.orig_context = context;
1333 ctx.orig_handler = handler;
1335 return SetupScanFileQueueW( handle, flags, window, QUEUE_callback_WtoA, &ctx, result );
1339 /***********************************************************************
1340 * SetupScanFileQueueW (SETUPAPI.@)
1342 BOOL WINAPI SetupScanFileQueueW( HSPFILEQ handle, DWORD flags, HWND window,
1343 PSP_FILE_CALLBACK_W handler, PVOID context, PDWORD result )
1345 struct file_queue *queue = handle;
1346 struct file_op *op;
1347 FILEPATHS_W paths;
1348 UINT notification = 0;
1349 BOOL ret = FALSE;
1351 TRACE("%p %x %p %p %p %p\n", handle, flags, window, handler, context, result);
1353 if (!queue->copy_queue.count) return TRUE;
1355 if (flags & SPQ_SCAN_USE_CALLBACK) notification = SPFILENOTIFY_QUEUESCAN;
1356 else if (flags & SPQ_SCAN_USE_CALLBACKEX) notification = SPFILENOTIFY_QUEUESCAN_EX;
1358 if (flags & ~(SPQ_SCAN_USE_CALLBACK | SPQ_SCAN_USE_CALLBACKEX))
1360 FIXME("flags %x not fully implemented\n", flags);
1363 paths.Source = paths.Target = NULL;
1365 for (op = queue->copy_queue.head; op; op = op->next)
1367 build_filepathsW( op, &paths );
1368 switch (notification)
1370 case SPFILENOTIFY_QUEUESCAN:
1371 /* FIXME: handle delay flag */
1372 if (handler( context, notification, (UINT_PTR)paths.Target, 0 )) goto done;
1373 break;
1374 case SPFILENOTIFY_QUEUESCAN_EX:
1375 if (handler( context, notification, (UINT_PTR)&paths, 0 )) goto done;
1376 break;
1377 default:
1378 ret = TRUE; goto done;
1382 ret = TRUE;
1384 done:
1385 if (result) *result = 0;
1386 HeapFree( GetProcessHeap(), 0, (void *)paths.Source );
1387 HeapFree( GetProcessHeap(), 0, (void *)paths.Target );
1388 return ret;
1392 /***********************************************************************
1393 * SetupGetFileQueueCount (SETUPAPI.@)
1395 BOOL WINAPI SetupGetFileQueueCount( HSPFILEQ handle, UINT op, PUINT result )
1397 struct file_queue *queue = handle;
1399 switch(op)
1401 case FILEOP_COPY:
1402 *result = queue->copy_queue.count;
1403 return TRUE;
1404 case FILEOP_RENAME:
1405 *result = queue->rename_queue.count;
1406 return TRUE;
1407 case FILEOP_DELETE:
1408 *result = queue->delete_queue.count;
1409 return TRUE;
1411 return FALSE;
1415 /***********************************************************************
1416 * SetupGetFileQueueFlags (SETUPAPI.@)
1418 BOOL WINAPI SetupGetFileQueueFlags( HSPFILEQ handle, PDWORD flags )
1420 struct file_queue *queue = handle;
1421 *flags = queue->flags;
1422 return TRUE;
1426 /***********************************************************************
1427 * SetupSetFileQueueFlags (SETUPAPI.@)
1429 BOOL WINAPI SetupSetFileQueueFlags( HSPFILEQ handle, DWORD mask, DWORD flags )
1431 struct file_queue *queue = handle;
1432 queue->flags = (queue->flags & ~mask) | flags;
1433 return TRUE;
1437 /***********************************************************************
1438 * SetupSetFileQueueAlternatePlatformA (SETUPAPI.@)
1440 BOOL WINAPI SetupSetFileQueueAlternatePlatformA(HSPFILEQ handle, PSP_ALTPLATFORM_INFO platform, PCSTR catalogfile)
1442 FIXME("(%p, %p, %s) stub!\n", handle, platform, debugstr_a(catalogfile));
1443 return FALSE;
1447 /***********************************************************************
1448 * SetupSetFileQueueAlternatePlatformW (SETUPAPI.@)
1450 BOOL WINAPI SetupSetFileQueueAlternatePlatformW(HSPFILEQ handle, PSP_ALTPLATFORM_INFO platform, PCWSTR catalogfile)
1452 FIXME("(%p, %p, %s) stub!\n", handle, platform, debugstr_w(catalogfile));
1453 return FALSE;
1457 /***********************************************************************
1458 * SetupInitDefaultQueueCallback (SETUPAPI.@)
1460 PVOID WINAPI SetupInitDefaultQueueCallback( HWND owner )
1462 return SetupInitDefaultQueueCallbackEx( owner, 0, 0, 0, NULL );
1466 /***********************************************************************
1467 * SetupInitDefaultQueueCallbackEx (SETUPAPI.@)
1469 PVOID WINAPI SetupInitDefaultQueueCallbackEx( HWND owner, HWND progress, UINT msg,
1470 DWORD reserved1, PVOID reserved2 )
1472 struct default_callback_context *context;
1474 if ((context = HeapAlloc( GetProcessHeap(), 0, sizeof(*context) )))
1476 context->owner = owner;
1477 context->progress = progress;
1478 context->message = msg;
1480 return context;
1484 /***********************************************************************
1485 * SetupTermDefaultQueueCallback (SETUPAPI.@)
1487 void WINAPI SetupTermDefaultQueueCallback( PVOID context )
1489 HeapFree( GetProcessHeap(), 0, context );
1493 /***********************************************************************
1494 * SetupDefaultQueueCallbackA (SETUPAPI.@)
1496 UINT WINAPI SetupDefaultQueueCallbackA( PVOID context, UINT notification,
1497 UINT_PTR param1, UINT_PTR param2 )
1499 FILEPATHS_A *paths = (FILEPATHS_A *)param1;
1500 struct default_callback_context *ctx = context;
1502 switch(notification)
1504 case SPFILENOTIFY_STARTQUEUE:
1505 TRACE( "start queue\n" );
1506 return TRUE;
1507 case SPFILENOTIFY_ENDQUEUE:
1508 TRACE( "end queue\n" );
1509 return 0;
1510 case SPFILENOTIFY_STARTSUBQUEUE:
1511 TRACE( "start subqueue %ld count %ld\n", param1, param2 );
1512 return TRUE;
1513 case SPFILENOTIFY_ENDSUBQUEUE:
1514 TRACE( "end subqueue %ld\n", param1 );
1515 return 0;
1516 case SPFILENOTIFY_STARTDELETE:
1517 TRACE( "start delete %s\n", debugstr_a(paths->Target) );
1518 return FILEOP_DOIT;
1519 case SPFILENOTIFY_ENDDELETE:
1520 TRACE( "end delete %s\n", debugstr_a(paths->Target) );
1521 return 0;
1522 case SPFILENOTIFY_DELETEERROR:
1523 /*Windows Ignores attempts to delete files / folders which do not exist*/
1524 if ((paths->Win32Error != ERROR_FILE_NOT_FOUND) && (paths->Win32Error != ERROR_PATH_NOT_FOUND))
1525 SetupDeleteErrorA(ctx->owner, NULL, paths->Target, paths->Win32Error, 0);
1526 return FILEOP_SKIP;
1527 case SPFILENOTIFY_STARTRENAME:
1528 TRACE( "start rename %s -> %s\n", debugstr_a(paths->Source), debugstr_a(paths->Target) );
1529 return FILEOP_DOIT;
1530 case SPFILENOTIFY_ENDRENAME:
1531 TRACE( "end rename %s -> %s\n", debugstr_a(paths->Source), debugstr_a(paths->Target) );
1532 return 0;
1533 case SPFILENOTIFY_RENAMEERROR:
1534 SetupRenameErrorA(ctx->owner, NULL, paths->Source, paths->Target, paths->Win32Error, 0);
1535 return FILEOP_SKIP;
1536 case SPFILENOTIFY_STARTCOPY:
1537 TRACE( "start copy %s -> %s\n", debugstr_a(paths->Source), debugstr_a(paths->Target) );
1538 return FILEOP_DOIT;
1539 case SPFILENOTIFY_ENDCOPY:
1540 TRACE( "end copy %s -> %s\n", debugstr_a(paths->Source), debugstr_a(paths->Target) );
1541 return 0;
1542 case SPFILENOTIFY_COPYERROR:
1543 ERR( "copy error %d %s -> %s\n", paths->Win32Error,
1544 debugstr_a(paths->Source), debugstr_a(paths->Target) );
1545 return FILEOP_SKIP;
1546 case SPFILENOTIFY_NEEDMEDIA:
1547 TRACE( "need media\n" );
1548 return FILEOP_SKIP;
1549 default:
1550 FIXME( "notification %d params %lx,%lx\n", notification, param1, param2 );
1551 break;
1553 return 0;
1557 /***********************************************************************
1558 * SetupDefaultQueueCallbackW (SETUPAPI.@)
1560 UINT WINAPI SetupDefaultQueueCallbackW( PVOID context, UINT notification,
1561 UINT_PTR param1, UINT_PTR param2 )
1563 FILEPATHS_W *paths = (FILEPATHS_W *)param1;
1564 struct default_callback_context *ctx = context;
1566 switch(notification)
1568 case SPFILENOTIFY_STARTQUEUE:
1569 TRACE( "start queue\n" );
1570 return TRUE;
1571 case SPFILENOTIFY_ENDQUEUE:
1572 TRACE( "end queue\n" );
1573 return 0;
1574 case SPFILENOTIFY_STARTSUBQUEUE:
1575 TRACE( "start subqueue %ld count %ld\n", param1, param2 );
1576 return TRUE;
1577 case SPFILENOTIFY_ENDSUBQUEUE:
1578 TRACE( "end subqueue %ld\n", param1 );
1579 return 0;
1580 case SPFILENOTIFY_STARTDELETE:
1581 TRACE( "start delete %s\n", debugstr_w(paths->Target) );
1582 return FILEOP_DOIT;
1583 case SPFILENOTIFY_ENDDELETE:
1584 TRACE( "end delete %s\n", debugstr_w(paths->Target) );
1585 return 0;
1586 case SPFILENOTIFY_DELETEERROR:
1587 /*Windows Ignores attempts to delete files / folders which do not exist*/
1588 if ((paths->Win32Error != ERROR_FILE_NOT_FOUND) && (paths->Win32Error != ERROR_PATH_NOT_FOUND))
1589 SetupDeleteErrorW(ctx->owner, NULL, paths->Target, paths->Win32Error, 0);
1590 return FILEOP_SKIP;
1591 case SPFILENOTIFY_STARTRENAME:
1592 SetupRenameErrorW(ctx->owner, NULL, paths->Source, paths->Target, paths->Win32Error, 0);
1593 return FILEOP_DOIT;
1594 case SPFILENOTIFY_ENDRENAME:
1595 TRACE( "end rename %s -> %s\n", debugstr_w(paths->Source), debugstr_w(paths->Target) );
1596 return 0;
1597 case SPFILENOTIFY_RENAMEERROR:
1598 ERR( "rename error %d %s -> %s\n", paths->Win32Error,
1599 debugstr_w(paths->Source), debugstr_w(paths->Target) );
1600 return FILEOP_SKIP;
1601 case SPFILENOTIFY_STARTCOPY:
1602 TRACE( "start copy %s -> %s\n", debugstr_w(paths->Source), debugstr_w(paths->Target) );
1603 return FILEOP_DOIT;
1604 case SPFILENOTIFY_ENDCOPY:
1605 TRACE( "end copy %s -> %s\n", debugstr_w(paths->Source), debugstr_w(paths->Target) );
1606 return 0;
1607 case SPFILENOTIFY_COPYERROR:
1608 ERR( "copy error %d %s -> %s\n", paths->Win32Error,
1609 debugstr_w(paths->Source), debugstr_w(paths->Target) );
1610 return FILEOP_SKIP;
1611 case SPFILENOTIFY_NEEDMEDIA:
1612 TRACE( "need media\n" );
1613 return FILEOP_SKIP;
1614 default:
1615 FIXME( "notification %d params %lx,%lx\n", notification, param1, param2 );
1616 break;
1618 return 0;
1621 /***********************************************************************
1622 * SetupDeleteErrorA (SETUPAPI.@)
1625 UINT WINAPI SetupDeleteErrorA( HWND parent, PCSTR dialogTitle, PCSTR file,
1626 UINT w32error, DWORD style)
1628 FIXME( "stub: (Error Number %d when attempting to delete %s)\n",
1629 w32error, debugstr_a(file) );
1630 return DPROMPT_SKIPFILE;
1633 /***********************************************************************
1634 * SetupDeleteErrorW (SETUPAPI.@)
1637 UINT WINAPI SetupDeleteErrorW( HWND parent, PCWSTR dialogTitle, PCWSTR file,
1638 UINT w32error, DWORD style)
1640 FIXME( "stub: (Error Number %d when attempting to delete %s)\n",
1641 w32error, debugstr_w(file) );
1642 return DPROMPT_SKIPFILE;
1645 /***********************************************************************
1646 * SetupRenameErrorA (SETUPAPI.@)
1649 UINT WINAPI SetupRenameErrorA( HWND parent, PCSTR dialogTitle, PCSTR source,
1650 PCSTR target, UINT w32error, DWORD style)
1652 FIXME( "stub: (Error Number %d when attempting to rename %s to %s)\n",
1653 w32error, debugstr_a(source), debugstr_a(target));
1654 return DPROMPT_SKIPFILE;
1657 /***********************************************************************
1658 * SetupRenameErrorW (SETUPAPI.@)
1661 UINT WINAPI SetupRenameErrorW( HWND parent, PCWSTR dialogTitle, PCWSTR source,
1662 PCWSTR target, UINT w32error, DWORD style)
1664 FIXME( "stub: (Error Number %d when attempting to rename %s to %s)\n",
1665 w32error, debugstr_w(source), debugstr_w(target));
1666 return DPROMPT_SKIPFILE;
1670 /***********************************************************************
1671 * SetupCopyErrorA (SETUPAPI.@)
1674 UINT WINAPI SetupCopyErrorA( HWND parent, PCSTR dialogTitle, PCSTR diskname,
1675 PCSTR sourcepath, PCSTR sourcefile, PCSTR targetpath,
1676 UINT w32error, DWORD style, PSTR pathbuffer,
1677 DWORD buffersize, PDWORD requiredsize)
1679 FIXME( "stub: (Error Number %d when attempting to copy file %s from %s to %s)\n",
1680 w32error, debugstr_a(sourcefile), debugstr_a(sourcepath) ,debugstr_a(targetpath));
1681 return DPROMPT_SKIPFILE;
1684 /***********************************************************************
1685 * SetupCopyErrorW (SETUPAPI.@)
1688 UINT WINAPI SetupCopyErrorW( HWND parent, PCWSTR dialogTitle, PCWSTR diskname,
1689 PCWSTR sourcepath, PCWSTR sourcefile, PCWSTR targetpath,
1690 UINT w32error, DWORD style, PWSTR pathbuffer,
1691 DWORD buffersize, PDWORD requiredsize)
1693 FIXME( "stub: (Error Number %d when attempting to copy file %s from %s to %s)\n",
1694 w32error, debugstr_w(sourcefile), debugstr_w(sourcepath) ,debugstr_w(targetpath));
1695 return DPROMPT_SKIPFILE;
1698 /***********************************************************************
1699 * pSetupGetQueueFlags (SETUPAPI.@)
1701 DWORD WINAPI pSetupGetQueueFlags( HSPFILEQ handle )
1703 struct file_queue *queue = handle;
1704 return queue->flags;
1707 /***********************************************************************
1708 * pSetupSetQueueFlags (SETUPAPI.@)
1710 BOOL WINAPI pSetupSetQueueFlags( HSPFILEQ handle, DWORD flags )
1712 struct file_queue *queue = handle;
1713 queue->flags = flags;
1714 return TRUE;