setupx.dll16: Use BOOL type where appropriate.
[wine/multimedia.git] / dlls / setupapi / queue.c
blob1855e99ddb7f58a654daf16d5db442b34d84d67e
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 ))
1161 HeapFree( GetProcessHeap(), 0, inf_source );
1162 return FALSE;
1164 source = inf_source;
1166 else if (!source)
1168 SetLastError( ERROR_INVALID_PARAMETER );
1169 return FALSE;
1172 len = strlenW( source ) + 1;
1173 if (absolute) len += strlenW( root ) + 1;
1175 if (!(p = buffer = HeapAlloc( GetProcessHeap(), 0, len * sizeof(WCHAR) )))
1177 HeapFree( GetProcessHeap(), 0, inf_source );
1178 SetLastError( ERROR_NOT_ENOUGH_MEMORY );
1179 return FALSE;
1182 if (absolute)
1184 strcpyW( buffer, root );
1185 p += strlenW( buffer );
1186 if (p[-1] != '\\') *p++ = '\\';
1188 while (*source == '\\') source++;
1189 strcpyW( p, source );
1191 ret = do_file_copyW( buffer, dest, style, handler, context );
1193 HeapFree( GetProcessHeap(), 0, inf_source );
1194 HeapFree( GetProcessHeap(), 0, buffer );
1195 return ret;
1198 /***********************************************************************
1199 * SetupInstallFileW (SETUPAPI.@)
1201 BOOL WINAPI SetupInstallFileW( HINF hinf, PINFCONTEXT inf_context, PCWSTR source, PCWSTR root,
1202 PCWSTR dest, DWORD style, PSP_FILE_CALLBACK_W handler, PVOID context )
1204 return SetupInstallFileExW( hinf, inf_context, source, root, dest, style, handler, context, NULL );
1207 /***********************************************************************
1208 * SetupCommitFileQueueW (SETUPAPI.@)
1210 BOOL WINAPI SetupCommitFileQueueW( HWND owner, HSPFILEQ handle, PSP_FILE_CALLBACK_W handler,
1211 PVOID context )
1213 struct file_queue *queue = handle;
1214 struct file_op *op;
1215 BOOL result = FALSE;
1216 FILEPATHS_W paths;
1217 UINT op_result;
1219 paths.Source = paths.Target = NULL;
1221 if (!queue->copy_queue.count && !queue->delete_queue.count && !queue->rename_queue.count)
1222 return TRUE; /* nothing to do */
1224 if (!handler( context, SPFILENOTIFY_STARTQUEUE, (UINT_PTR)owner, 0 )) return FALSE;
1226 /* perform deletes */
1228 if (queue->delete_queue.count)
1230 if (!(handler( context, SPFILENOTIFY_STARTSUBQUEUE, FILEOP_DELETE,
1231 queue->delete_queue.count ))) goto done;
1232 for (op = queue->delete_queue.head; op; op = op->next)
1234 build_filepathsW( op, &paths );
1235 op_result = handler( context, SPFILENOTIFY_STARTDELETE, (UINT_PTR)&paths, FILEOP_DELETE);
1236 if (op_result == FILEOP_ABORT) goto done;
1237 while (op_result == FILEOP_DOIT)
1239 TRACE( "deleting file %s\n", debugstr_w(paths.Target) );
1240 if (DeleteFileW( paths.Target )) break; /* success */
1241 paths.Win32Error = GetLastError();
1242 op_result = handler( context, SPFILENOTIFY_DELETEERROR, (UINT_PTR)&paths, 0 );
1243 if (op_result == FILEOP_ABORT) goto done;
1245 handler( context, SPFILENOTIFY_ENDDELETE, (UINT_PTR)&paths, 0 );
1247 handler( context, SPFILENOTIFY_ENDSUBQUEUE, FILEOP_DELETE, 0 );
1250 /* perform renames */
1252 if (queue->rename_queue.count)
1254 if (!(handler( context, SPFILENOTIFY_STARTSUBQUEUE, FILEOP_RENAME,
1255 queue->rename_queue.count ))) goto done;
1256 for (op = queue->rename_queue.head; op; op = op->next)
1258 build_filepathsW( op, &paths );
1259 op_result = handler( context, SPFILENOTIFY_STARTRENAME, (UINT_PTR)&paths, FILEOP_RENAME);
1260 if (op_result == FILEOP_ABORT) goto done;
1261 while (op_result == FILEOP_DOIT)
1263 TRACE( "renaming file %s -> %s\n",
1264 debugstr_w(paths.Source), debugstr_w(paths.Target) );
1265 if (MoveFileW( paths.Source, paths.Target )) break; /* success */
1266 paths.Win32Error = GetLastError();
1267 op_result = handler( context, SPFILENOTIFY_RENAMEERROR, (UINT_PTR)&paths, 0 );
1268 if (op_result == FILEOP_ABORT) goto done;
1270 handler( context, SPFILENOTIFY_ENDRENAME, (UINT_PTR)&paths, 0 );
1272 handler( context, SPFILENOTIFY_ENDSUBQUEUE, FILEOP_RENAME, 0 );
1275 /* perform copies */
1277 if (queue->copy_queue.count)
1279 if (!(handler( context, SPFILENOTIFY_STARTSUBQUEUE, FILEOP_COPY,
1280 queue->copy_queue.count ))) goto done;
1281 for (op = queue->copy_queue.head; op; op = op->next)
1283 WCHAR newpath[MAX_PATH];
1285 build_filepathsW( op, &paths );
1286 op_result = handler( context, SPFILENOTIFY_STARTCOPY, (UINT_PTR)&paths, FILEOP_COPY );
1287 if (op_result == FILEOP_ABORT) goto done;
1288 if (op_result == FILEOP_NEWPATH) op_result = FILEOP_DOIT;
1289 while (op_result == FILEOP_DOIT || op_result == FILEOP_NEWPATH)
1291 TRACE( "copying file %s -> %s\n",
1292 debugstr_w( op_result == FILEOP_NEWPATH ? newpath : paths.Source ),
1293 debugstr_w(paths.Target) );
1294 if (op->dst_path)
1296 if (!create_full_pathW( op->dst_path ))
1298 paths.Win32Error = GetLastError();
1299 op_result = handler( context, SPFILENOTIFY_COPYERROR,
1300 (UINT_PTR)&paths, (UINT_PTR)newpath );
1301 if (op_result == FILEOP_ABORT) goto done;
1304 if (do_file_copyW( op_result == FILEOP_NEWPATH ? newpath : paths.Source,
1305 paths.Target, op->style, handler, context )) break; /* success */
1306 /* try to extract it from the cabinet file */
1307 if (op->src_tag)
1309 if (extract_cabinet_file( op->src_tag, op->src_root,
1310 paths.Source, paths.Target )) break;
1312 paths.Win32Error = GetLastError();
1313 op_result = handler( context, SPFILENOTIFY_COPYERROR,
1314 (UINT_PTR)&paths, (UINT_PTR)newpath );
1315 if (op_result == FILEOP_ABORT) goto done;
1317 handler( context, SPFILENOTIFY_ENDCOPY, (UINT_PTR)&paths, 0 );
1319 handler( context, SPFILENOTIFY_ENDSUBQUEUE, FILEOP_COPY, 0 );
1323 result = TRUE;
1325 done:
1326 handler( context, SPFILENOTIFY_ENDQUEUE, result, 0 );
1327 HeapFree( GetProcessHeap(), 0, (void *)paths.Source );
1328 HeapFree( GetProcessHeap(), 0, (void *)paths.Target );
1329 return result;
1333 /***********************************************************************
1334 * SetupScanFileQueueA (SETUPAPI.@)
1336 BOOL WINAPI SetupScanFileQueueA( HSPFILEQ handle, DWORD flags, HWND window,
1337 PSP_FILE_CALLBACK_A handler, PVOID context, PDWORD result )
1339 struct callback_WtoA_context ctx;
1341 TRACE("%p %x %p %p %p %p\n", handle, flags, window, handler, context, result);
1343 ctx.orig_context = context;
1344 ctx.orig_handler = handler;
1346 return SetupScanFileQueueW( handle, flags, window, QUEUE_callback_WtoA, &ctx, result );
1350 /***********************************************************************
1351 * SetupScanFileQueueW (SETUPAPI.@)
1353 BOOL WINAPI SetupScanFileQueueW( HSPFILEQ handle, DWORD flags, HWND window,
1354 PSP_FILE_CALLBACK_W handler, PVOID context, PDWORD result )
1356 struct file_queue *queue = handle;
1357 struct file_op *op;
1358 FILEPATHS_W paths;
1359 UINT notification = 0;
1360 BOOL ret = FALSE;
1362 TRACE("%p %x %p %p %p %p\n", handle, flags, window, handler, context, result);
1364 if (!queue->copy_queue.count) return TRUE;
1366 if (flags & SPQ_SCAN_USE_CALLBACK) notification = SPFILENOTIFY_QUEUESCAN;
1367 else if (flags & SPQ_SCAN_USE_CALLBACKEX) notification = SPFILENOTIFY_QUEUESCAN_EX;
1369 if (flags & ~(SPQ_SCAN_USE_CALLBACK | SPQ_SCAN_USE_CALLBACKEX))
1371 FIXME("flags %x not fully implemented\n", flags);
1374 paths.Source = paths.Target = NULL;
1376 for (op = queue->copy_queue.head; op; op = op->next)
1378 build_filepathsW( op, &paths );
1379 switch (notification)
1381 case SPFILENOTIFY_QUEUESCAN:
1382 /* FIXME: handle delay flag */
1383 if (handler( context, notification, (UINT_PTR)paths.Target, 0 )) goto done;
1384 break;
1385 case SPFILENOTIFY_QUEUESCAN_EX:
1386 if (handler( context, notification, (UINT_PTR)&paths, 0 )) goto done;
1387 break;
1388 default:
1389 ret = TRUE; goto done;
1393 ret = TRUE;
1395 done:
1396 if (result) *result = 0;
1397 HeapFree( GetProcessHeap(), 0, (void *)paths.Source );
1398 HeapFree( GetProcessHeap(), 0, (void *)paths.Target );
1399 return ret;
1403 /***********************************************************************
1404 * SetupGetFileQueueCount (SETUPAPI.@)
1406 BOOL WINAPI SetupGetFileQueueCount( HSPFILEQ handle, UINT op, PUINT result )
1408 struct file_queue *queue = handle;
1410 switch(op)
1412 case FILEOP_COPY:
1413 *result = queue->copy_queue.count;
1414 return TRUE;
1415 case FILEOP_RENAME:
1416 *result = queue->rename_queue.count;
1417 return TRUE;
1418 case FILEOP_DELETE:
1419 *result = queue->delete_queue.count;
1420 return TRUE;
1422 return FALSE;
1426 /***********************************************************************
1427 * SetupGetFileQueueFlags (SETUPAPI.@)
1429 BOOL WINAPI SetupGetFileQueueFlags( HSPFILEQ handle, PDWORD flags )
1431 struct file_queue *queue = handle;
1432 *flags = queue->flags;
1433 return TRUE;
1437 /***********************************************************************
1438 * SetupSetFileQueueFlags (SETUPAPI.@)
1440 BOOL WINAPI SetupSetFileQueueFlags( HSPFILEQ handle, DWORD mask, DWORD flags )
1442 struct file_queue *queue = handle;
1443 queue->flags = (queue->flags & ~mask) | flags;
1444 return TRUE;
1448 /***********************************************************************
1449 * SetupSetFileQueueAlternatePlatformA (SETUPAPI.@)
1451 BOOL WINAPI SetupSetFileQueueAlternatePlatformA(HSPFILEQ handle, PSP_ALTPLATFORM_INFO platform, PCSTR catalogfile)
1453 FIXME("(%p, %p, %s) stub!\n", handle, platform, debugstr_a(catalogfile));
1454 return FALSE;
1458 /***********************************************************************
1459 * SetupSetFileQueueAlternatePlatformW (SETUPAPI.@)
1461 BOOL WINAPI SetupSetFileQueueAlternatePlatformW(HSPFILEQ handle, PSP_ALTPLATFORM_INFO platform, PCWSTR catalogfile)
1463 FIXME("(%p, %p, %s) stub!\n", handle, platform, debugstr_w(catalogfile));
1464 return FALSE;
1468 /***********************************************************************
1469 * SetupInitDefaultQueueCallback (SETUPAPI.@)
1471 PVOID WINAPI SetupInitDefaultQueueCallback( HWND owner )
1473 return SetupInitDefaultQueueCallbackEx( owner, 0, 0, 0, NULL );
1477 /***********************************************************************
1478 * SetupInitDefaultQueueCallbackEx (SETUPAPI.@)
1480 PVOID WINAPI SetupInitDefaultQueueCallbackEx( HWND owner, HWND progress, UINT msg,
1481 DWORD reserved1, PVOID reserved2 )
1483 struct default_callback_context *context;
1485 if ((context = HeapAlloc( GetProcessHeap(), 0, sizeof(*context) )))
1487 context->owner = owner;
1488 context->progress = progress;
1489 context->message = msg;
1491 return context;
1495 /***********************************************************************
1496 * SetupTermDefaultQueueCallback (SETUPAPI.@)
1498 void WINAPI SetupTermDefaultQueueCallback( PVOID context )
1500 HeapFree( GetProcessHeap(), 0, context );
1504 /***********************************************************************
1505 * SetupDefaultQueueCallbackA (SETUPAPI.@)
1507 UINT WINAPI SetupDefaultQueueCallbackA( PVOID context, UINT notification,
1508 UINT_PTR param1, UINT_PTR param2 )
1510 FILEPATHS_A *paths = (FILEPATHS_A *)param1;
1511 struct default_callback_context *ctx = context;
1513 switch(notification)
1515 case SPFILENOTIFY_STARTQUEUE:
1516 TRACE( "start queue\n" );
1517 return TRUE;
1518 case SPFILENOTIFY_ENDQUEUE:
1519 TRACE( "end queue\n" );
1520 return 0;
1521 case SPFILENOTIFY_STARTSUBQUEUE:
1522 TRACE( "start subqueue %ld count %ld\n", param1, param2 );
1523 return TRUE;
1524 case SPFILENOTIFY_ENDSUBQUEUE:
1525 TRACE( "end subqueue %ld\n", param1 );
1526 return 0;
1527 case SPFILENOTIFY_STARTDELETE:
1528 TRACE( "start delete %s\n", debugstr_a(paths->Target) );
1529 return FILEOP_DOIT;
1530 case SPFILENOTIFY_ENDDELETE:
1531 TRACE( "end delete %s\n", debugstr_a(paths->Target) );
1532 return 0;
1533 case SPFILENOTIFY_DELETEERROR:
1534 /*Windows Ignores attempts to delete files / folders which do not exist*/
1535 if ((paths->Win32Error != ERROR_FILE_NOT_FOUND) && (paths->Win32Error != ERROR_PATH_NOT_FOUND))
1536 SetupDeleteErrorA(ctx->owner, NULL, paths->Target, paths->Win32Error, 0);
1537 return FILEOP_SKIP;
1538 case SPFILENOTIFY_STARTRENAME:
1539 TRACE( "start rename %s -> %s\n", debugstr_a(paths->Source), debugstr_a(paths->Target) );
1540 return FILEOP_DOIT;
1541 case SPFILENOTIFY_ENDRENAME:
1542 TRACE( "end rename %s -> %s\n", debugstr_a(paths->Source), debugstr_a(paths->Target) );
1543 return 0;
1544 case SPFILENOTIFY_RENAMEERROR:
1545 SetupRenameErrorA(ctx->owner, NULL, paths->Source, paths->Target, paths->Win32Error, 0);
1546 return FILEOP_SKIP;
1547 case SPFILENOTIFY_STARTCOPY:
1548 TRACE( "start copy %s -> %s\n", debugstr_a(paths->Source), debugstr_a(paths->Target) );
1549 return FILEOP_DOIT;
1550 case SPFILENOTIFY_ENDCOPY:
1551 TRACE( "end copy %s -> %s\n", debugstr_a(paths->Source), debugstr_a(paths->Target) );
1552 return 0;
1553 case SPFILENOTIFY_COPYERROR:
1554 ERR( "copy error %d %s -> %s\n", paths->Win32Error,
1555 debugstr_a(paths->Source), debugstr_a(paths->Target) );
1556 return FILEOP_SKIP;
1557 case SPFILENOTIFY_NEEDMEDIA:
1558 TRACE( "need media\n" );
1559 return FILEOP_SKIP;
1560 default:
1561 FIXME( "notification %d params %lx,%lx\n", notification, param1, param2 );
1562 break;
1564 return 0;
1568 /***********************************************************************
1569 * SetupDefaultQueueCallbackW (SETUPAPI.@)
1571 UINT WINAPI SetupDefaultQueueCallbackW( PVOID context, UINT notification,
1572 UINT_PTR param1, UINT_PTR param2 )
1574 FILEPATHS_W *paths = (FILEPATHS_W *)param1;
1575 struct default_callback_context *ctx = context;
1577 switch(notification)
1579 case SPFILENOTIFY_STARTQUEUE:
1580 TRACE( "start queue\n" );
1581 return TRUE;
1582 case SPFILENOTIFY_ENDQUEUE:
1583 TRACE( "end queue\n" );
1584 return 0;
1585 case SPFILENOTIFY_STARTSUBQUEUE:
1586 TRACE( "start subqueue %ld count %ld\n", param1, param2 );
1587 return TRUE;
1588 case SPFILENOTIFY_ENDSUBQUEUE:
1589 TRACE( "end subqueue %ld\n", param1 );
1590 return 0;
1591 case SPFILENOTIFY_STARTDELETE:
1592 TRACE( "start delete %s\n", debugstr_w(paths->Target) );
1593 return FILEOP_DOIT;
1594 case SPFILENOTIFY_ENDDELETE:
1595 TRACE( "end delete %s\n", debugstr_w(paths->Target) );
1596 return 0;
1597 case SPFILENOTIFY_DELETEERROR:
1598 /*Windows Ignores attempts to delete files / folders which do not exist*/
1599 if ((paths->Win32Error != ERROR_FILE_NOT_FOUND) && (paths->Win32Error != ERROR_PATH_NOT_FOUND))
1600 SetupDeleteErrorW(ctx->owner, NULL, paths->Target, paths->Win32Error, 0);
1601 return FILEOP_SKIP;
1602 case SPFILENOTIFY_STARTRENAME:
1603 SetupRenameErrorW(ctx->owner, NULL, paths->Source, paths->Target, paths->Win32Error, 0);
1604 return FILEOP_DOIT;
1605 case SPFILENOTIFY_ENDRENAME:
1606 TRACE( "end rename %s -> %s\n", debugstr_w(paths->Source), debugstr_w(paths->Target) );
1607 return 0;
1608 case SPFILENOTIFY_RENAMEERROR:
1609 ERR( "rename error %d %s -> %s\n", paths->Win32Error,
1610 debugstr_w(paths->Source), debugstr_w(paths->Target) );
1611 return FILEOP_SKIP;
1612 case SPFILENOTIFY_STARTCOPY:
1613 TRACE( "start copy %s -> %s\n", debugstr_w(paths->Source), debugstr_w(paths->Target) );
1614 return FILEOP_DOIT;
1615 case SPFILENOTIFY_ENDCOPY:
1616 TRACE( "end copy %s -> %s\n", debugstr_w(paths->Source), debugstr_w(paths->Target) );
1617 return 0;
1618 case SPFILENOTIFY_COPYERROR:
1619 ERR( "copy error %d %s -> %s\n", paths->Win32Error,
1620 debugstr_w(paths->Source), debugstr_w(paths->Target) );
1621 return FILEOP_SKIP;
1622 case SPFILENOTIFY_NEEDMEDIA:
1623 TRACE( "need media\n" );
1624 return FILEOP_SKIP;
1625 default:
1626 FIXME( "notification %d params %lx,%lx\n", notification, param1, param2 );
1627 break;
1629 return 0;
1632 /***********************************************************************
1633 * SetupDeleteErrorA (SETUPAPI.@)
1636 UINT WINAPI SetupDeleteErrorA( HWND parent, PCSTR dialogTitle, PCSTR file,
1637 UINT w32error, DWORD style)
1639 FIXME( "stub: (Error Number %d when attempting to delete %s)\n",
1640 w32error, debugstr_a(file) );
1641 return DPROMPT_SKIPFILE;
1644 /***********************************************************************
1645 * SetupDeleteErrorW (SETUPAPI.@)
1648 UINT WINAPI SetupDeleteErrorW( HWND parent, PCWSTR dialogTitle, PCWSTR file,
1649 UINT w32error, DWORD style)
1651 FIXME( "stub: (Error Number %d when attempting to delete %s)\n",
1652 w32error, debugstr_w(file) );
1653 return DPROMPT_SKIPFILE;
1656 /***********************************************************************
1657 * SetupRenameErrorA (SETUPAPI.@)
1660 UINT WINAPI SetupRenameErrorA( HWND parent, PCSTR dialogTitle, PCSTR source,
1661 PCSTR target, UINT w32error, DWORD style)
1663 FIXME( "stub: (Error Number %d when attempting to rename %s to %s)\n",
1664 w32error, debugstr_a(source), debugstr_a(target));
1665 return DPROMPT_SKIPFILE;
1668 /***********************************************************************
1669 * SetupRenameErrorW (SETUPAPI.@)
1672 UINT WINAPI SetupRenameErrorW( HWND parent, PCWSTR dialogTitle, PCWSTR source,
1673 PCWSTR target, UINT w32error, DWORD style)
1675 FIXME( "stub: (Error Number %d when attempting to rename %s to %s)\n",
1676 w32error, debugstr_w(source), debugstr_w(target));
1677 return DPROMPT_SKIPFILE;
1681 /***********************************************************************
1682 * SetupCopyErrorA (SETUPAPI.@)
1685 UINT WINAPI SetupCopyErrorA( HWND parent, PCSTR dialogTitle, PCSTR diskname,
1686 PCSTR sourcepath, PCSTR sourcefile, PCSTR targetpath,
1687 UINT w32error, DWORD style, PSTR pathbuffer,
1688 DWORD buffersize, PDWORD requiredsize)
1690 FIXME( "stub: (Error Number %d when attempting to copy file %s from %s to %s)\n",
1691 w32error, debugstr_a(sourcefile), debugstr_a(sourcepath) ,debugstr_a(targetpath));
1692 return DPROMPT_SKIPFILE;
1695 /***********************************************************************
1696 * SetupCopyErrorW (SETUPAPI.@)
1699 UINT WINAPI SetupCopyErrorW( HWND parent, PCWSTR dialogTitle, PCWSTR diskname,
1700 PCWSTR sourcepath, PCWSTR sourcefile, PCWSTR targetpath,
1701 UINT w32error, DWORD style, PWSTR pathbuffer,
1702 DWORD buffersize, PDWORD requiredsize)
1704 FIXME( "stub: (Error Number %d when attempting to copy file %s from %s to %s)\n",
1705 w32error, debugstr_w(sourcefile), debugstr_w(sourcepath) ,debugstr_w(targetpath));
1706 return DPROMPT_SKIPFILE;
1709 /***********************************************************************
1710 * pSetupGetQueueFlags (SETUPAPI.@)
1712 DWORD WINAPI pSetupGetQueueFlags( HSPFILEQ handle )
1714 struct file_queue *queue = handle;
1715 return queue->flags;
1718 /***********************************************************************
1719 * pSetupSetQueueFlags (SETUPAPI.@)
1721 BOOL WINAPI pSetupSetQueueFlags( HSPFILEQ handle, DWORD flags )
1723 struct file_queue *queue = handle;
1724 queue->flags = flags;
1725 return TRUE;