dbghelp: Use CONTAINING_RECORD instead of reimplementing it.
[wine.git] / dlls / setupapi / queue.c
blobd2e2a1d9d5ef95870a400fce093b66145231b444
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 DWORD magic;
43 HWND owner;
44 DWORD unk1[4];
45 DWORD_PTR unk2[7];
46 HWND progress;
47 UINT message;
48 DWORD_PTR unk3[5];
51 struct file_op
53 struct file_op *next;
54 UINT style;
55 WCHAR *src_root;
56 WCHAR *src_path;
57 WCHAR *src_file;
58 WCHAR *src_descr;
59 WCHAR *src_tag;
60 WCHAR *dst_path;
61 WCHAR *dst_file;
64 struct file_op_queue
66 struct file_op *head;
67 struct file_op *tail;
68 unsigned int count;
71 struct file_queue
73 struct file_op_queue copy_queue;
74 struct file_op_queue delete_queue;
75 struct file_op_queue rename_queue;
76 DWORD flags;
80 /* append a file operation to a queue */
81 static inline void queue_file_op( struct file_op_queue *queue, struct file_op *op )
83 op->next = NULL;
84 if (queue->tail) queue->tail->next = op;
85 else queue->head = op;
86 queue->tail = op;
87 queue->count++;
90 /* free all the file operations on a given queue */
91 static void free_file_op_queue( struct file_op_queue *queue )
93 struct file_op *t, *op = queue->head;
95 while( op )
97 HeapFree( GetProcessHeap(), 0, op->src_root );
98 HeapFree( GetProcessHeap(), 0, op->src_path );
99 HeapFree( GetProcessHeap(), 0, op->src_file );
100 HeapFree( GetProcessHeap(), 0, op->src_descr );
101 HeapFree( GetProcessHeap(), 0, op->src_tag );
102 HeapFree( GetProcessHeap(), 0, op->dst_path );
103 if (op->dst_file != op->src_file) HeapFree( GetProcessHeap(), 0, op->dst_file );
104 t = op;
105 op = op->next;
106 HeapFree( GetProcessHeap(), 0, t );
110 /* concat 3 strings to make a path, handling separators correctly */
111 static void concat_W( WCHAR *buffer, const WCHAR *src1, const WCHAR *src2, const WCHAR *src3 )
113 *buffer = 0;
114 if (src1 && *src1)
116 strcpyW( buffer, src1 );
117 buffer += strlenW(buffer );
118 if (buffer[-1] != '\\') *buffer++ = '\\';
119 if (src2) while (*src2 == '\\') src2++;
122 if (src2)
124 strcpyW( buffer, src2 );
125 buffer += strlenW(buffer );
126 if (buffer[-1] != '\\') *buffer++ = '\\';
127 if (src3) while (*src3 == '\\') src3++;
130 if (src3)
131 strcpyW( buffer, src3 );
135 /***********************************************************************
136 * build_filepathsW
138 * Build a FILEPATHS_W structure for a given file operation.
140 static BOOL build_filepathsW( const struct file_op *op, FILEPATHS_W *paths )
142 unsigned int src_len = 1, dst_len = 1;
143 WCHAR *source = (PWSTR)paths->Source, *target = (PWSTR)paths->Target;
145 if (op->src_root) src_len += strlenW(op->src_root) + 1;
146 if (op->src_path) src_len += strlenW(op->src_path) + 1;
147 if (op->src_file) src_len += strlenW(op->src_file) + 1;
148 if (op->dst_path) dst_len += strlenW(op->dst_path) + 1;
149 if (op->dst_file) dst_len += strlenW(op->dst_file) + 1;
150 src_len *= sizeof(WCHAR);
151 dst_len *= sizeof(WCHAR);
153 if (!source || HeapSize( GetProcessHeap(), 0, source ) < src_len )
155 HeapFree( GetProcessHeap(), 0, source );
156 paths->Source = source = HeapAlloc( GetProcessHeap(), 0, src_len );
158 if (!target || HeapSize( GetProcessHeap(), 0, target ) < dst_len )
160 HeapFree( GetProcessHeap(), 0, target );
161 paths->Target = target = HeapAlloc( GetProcessHeap(), 0, dst_len );
163 if (!source || !target) return FALSE;
164 concat_W( source, op->src_root, op->src_path, op->src_file );
165 concat_W( target, NULL, op->dst_path, op->dst_file );
166 paths->Win32Error = 0;
167 paths->Flags = 0;
168 return TRUE;
172 /***********************************************************************
173 * QUEUE_callback_WtoA
175 * Map a file callback parameters from W to A and call the A callback.
177 UINT CALLBACK QUEUE_callback_WtoA( void *context, UINT notification,
178 UINT_PTR param1, UINT_PTR param2 )
180 struct callback_WtoA_context *callback_ctx = context;
181 char buffer[MAX_PATH];
182 UINT ret;
183 UINT_PTR old_param2 = param2;
185 switch(notification)
187 case SPFILENOTIFY_COPYERROR:
188 param2 = (UINT_PTR)buffer;
189 /* fall through */
190 case SPFILENOTIFY_STARTDELETE:
191 case SPFILENOTIFY_ENDDELETE:
192 case SPFILENOTIFY_DELETEERROR:
193 case SPFILENOTIFY_STARTRENAME:
194 case SPFILENOTIFY_ENDRENAME:
195 case SPFILENOTIFY_RENAMEERROR:
196 case SPFILENOTIFY_STARTCOPY:
197 case SPFILENOTIFY_ENDCOPY:
198 case SPFILENOTIFY_QUEUESCAN_EX:
200 FILEPATHS_W *pathsW = (FILEPATHS_W *)param1;
201 FILEPATHS_A pathsA;
203 pathsA.Source = strdupWtoA( pathsW->Source );
204 pathsA.Target = strdupWtoA( pathsW->Target );
205 pathsA.Win32Error = pathsW->Win32Error;
206 pathsA.Flags = pathsW->Flags;
207 ret = callback_ctx->orig_handler( callback_ctx->orig_context, notification,
208 (UINT_PTR)&pathsA, param2 );
209 HeapFree( GetProcessHeap(), 0, (void *)pathsA.Source );
210 HeapFree( GetProcessHeap(), 0, (void *)pathsA.Target );
212 if (notification == SPFILENOTIFY_COPYERROR)
213 MultiByteToWideChar( CP_ACP, 0, buffer, -1, (WCHAR *)old_param2, MAX_PATH );
214 break;
216 case SPFILENOTIFY_STARTREGISTRATION:
217 case SPFILENOTIFY_ENDREGISTRATION:
219 SP_REGISTER_CONTROL_STATUSW *statusW = (SP_REGISTER_CONTROL_STATUSW *)param1;
220 SP_REGISTER_CONTROL_STATUSA statusA;
222 statusA.cbSize = sizeof(statusA);
223 statusA.FileName = strdupWtoA( statusW->FileName );
224 statusA.Win32Error = statusW->Win32Error;
225 statusA.FailureCode = statusW->FailureCode;
226 ret = callback_ctx->orig_handler( callback_ctx->orig_context, notification,
227 (UINT_PTR)&statusA, param2 );
228 HeapFree( GetProcessHeap(), 0, (LPSTR)statusA.FileName );
230 break;
232 case SPFILENOTIFY_QUEUESCAN:
234 LPWSTR targetW = (LPWSTR)param1;
235 LPSTR target = strdupWtoA( targetW );
237 ret = callback_ctx->orig_handler( callback_ctx->orig_context, notification,
238 (UINT_PTR)target, param2 );
239 HeapFree( GetProcessHeap(), 0, target );
241 break;
243 case SPFILENOTIFY_NEEDMEDIA:
244 FIXME("mapping for %d not implemented\n",notification);
245 case SPFILENOTIFY_STARTQUEUE:
246 case SPFILENOTIFY_ENDQUEUE:
247 case SPFILENOTIFY_STARTSUBQUEUE:
248 case SPFILENOTIFY_ENDSUBQUEUE:
249 default:
250 ret = callback_ctx->orig_handler( callback_ctx->orig_context, notification, param1, param2 );
251 break;
253 return ret;
257 /***********************************************************************
258 * get_src_file_info
260 * Retrieve the source file information for a given file.
262 static void get_src_file_info( HINF hinf, struct file_op *op )
264 static const WCHAR SourceDisksNames[] =
265 {'S','o','u','r','c','e','D','i','s','k','s','N','a','m','e','s',0};
266 static const WCHAR SourceDisksFiles[] =
267 {'S','o','u','r','c','e','D','i','s','k','s','F','i','l','e','s',0};
269 INFCONTEXT file_ctx, disk_ctx;
270 INT id, diskid;
271 DWORD len, len2;
273 /* find the SourceDisksFiles entry */
274 if (!SetupFindFirstLineW( hinf, SourceDisksFiles, op->src_file, &file_ctx ))
276 if ((op->style & (SP_COPY_SOURCE_ABSOLUTE|SP_COPY_SOURCEPATH_ABSOLUTE))) return;
277 /* no specific info, use .inf file source directory */
278 if (!op->src_root) op->src_root = PARSER_get_src_root( hinf );
279 return;
281 if (!SetupGetIntField( &file_ctx, 1, &diskid )) return;
283 /* now find the diskid in the SourceDisksNames section */
284 if (!SetupFindFirstLineW( hinf, SourceDisksNames, NULL, &disk_ctx )) return;
285 for (;;)
287 if (SetupGetIntField( &disk_ctx, 0, &id ) && (id == diskid)) break;
288 if (!SetupFindNextLine( &disk_ctx, &disk_ctx )) return;
291 /* and fill in the missing info */
293 if (!op->src_descr)
295 if (SetupGetStringFieldW( &disk_ctx, 1, NULL, 0, &len ) &&
296 (op->src_descr = HeapAlloc( GetProcessHeap(), 0, len*sizeof(WCHAR) )))
297 SetupGetStringFieldW( &disk_ctx, 1, op->src_descr, len, NULL );
299 if (!op->src_tag)
301 if (SetupGetStringFieldW( &disk_ctx, 2, NULL, 0, &len ) &&
302 (op->src_tag = HeapAlloc( GetProcessHeap(), 0, len*sizeof(WCHAR) )))
303 SetupGetStringFieldW( &disk_ctx, 2, op->src_tag, len, NULL );
305 if (!op->src_path && !(op->style & SP_COPY_SOURCE_ABSOLUTE))
307 len = len2 = 0;
308 if (!(op->style & SP_COPY_SOURCEPATH_ABSOLUTE))
310 /* retrieve relative path for this disk */
311 if (!SetupGetStringFieldW( &disk_ctx, 4, NULL, 0, &len )) len = 0;
313 /* retrieve relative path for this file */
314 if (!SetupGetStringFieldW( &file_ctx, 2, NULL, 0, &len2 )) len2 = 0;
316 if ((len || len2) &&
317 (op->src_path = HeapAlloc( GetProcessHeap(), 0, (len+len2)*sizeof(WCHAR) )))
319 WCHAR *ptr = op->src_path;
320 if (len)
322 SetupGetStringFieldW( &disk_ctx, 4, op->src_path, len, NULL );
323 ptr = op->src_path + strlenW(op->src_path);
324 if (len2 && ptr > op->src_path && ptr[-1] != '\\') *ptr++ = '\\';
326 if (!SetupGetStringFieldW( &file_ctx, 2, ptr, len2, NULL )) *ptr = 0;
329 if (!op->src_root) op->src_root = PARSER_get_src_root(hinf);
333 /***********************************************************************
334 * get_destination_dir
336 * Retrieve the destination dir for a given section.
338 static WCHAR *get_destination_dir( HINF hinf, const WCHAR *section )
340 static const WCHAR Dest[] = {'D','e','s','t','i','n','a','t','i','o','n','D','i','r','s',0};
341 static const WCHAR Def[] = {'D','e','f','a','u','l','t','D','e','s','t','D','i','r',0};
342 INFCONTEXT context;
343 WCHAR systemdir[MAX_PATH], *dir;
344 BOOL ret;
346 if (!(ret = SetupFindFirstLineW( hinf, Dest, section, &context )))
347 ret = SetupFindFirstLineW( hinf, Dest, Def, &context );
349 if (ret && (dir = PARSER_get_dest_dir( &context )))
350 return dir;
352 GetSystemDirectoryW( systemdir, MAX_PATH );
353 return strdupW( systemdir );
357 static void (WINAPI *pExtractFiles)( LPSTR, LPSTR, DWORD, DWORD, DWORD, DWORD );
359 /***********************************************************************
360 * extract_cabinet_file
362 * Extract a file from a .cab file.
364 static BOOL extract_cabinet_file( const WCHAR *cabinet, const WCHAR *root,
365 const WCHAR *src, const WCHAR *dst )
367 static const WCHAR extW[] = {'.','c','a','b',0};
368 static HMODULE advpack;
370 char *cab_path, *cab_file;
371 int len = strlenW( cabinet );
373 /* make sure the cabinet file has a .cab extension */
374 if (len <= 4 || strcmpiW( cabinet + len - 4, extW )) return FALSE;
375 if (!pExtractFiles)
377 if (!advpack && !(advpack = LoadLibraryA( "advpack.dll" )))
379 ERR( "could not load advpack.dll\n" );
380 return FALSE;
382 if (!(pExtractFiles = (void *)GetProcAddress( advpack, "ExtractFiles" )))
384 ERR( "could not find ExtractFiles in advpack.dll\n" );
385 return FALSE;
389 if (!(cab_path = strdupWtoA( root ))) return FALSE;
390 len = WideCharToMultiByte( CP_ACP, 0, cabinet, -1, NULL, 0, NULL, NULL );
391 if (!(cab_file = HeapAlloc( GetProcessHeap(), 0, strlen(cab_path) + len + 1 )))
393 HeapFree( GetProcessHeap(), 0, cab_path );
394 return FALSE;
396 strcpy( cab_file, cab_path );
397 if (cab_file[0] && cab_file[strlen(cab_file)-1] != '\\') strcat( cab_file, "\\" );
398 WideCharToMultiByte( CP_ACP, 0, cabinet, -1, cab_file + strlen(cab_file), len, NULL, NULL );
399 FIXME( "awful hack: extracting cabinet %s\n", debugstr_a(cab_file) );
400 pExtractFiles( cab_file, cab_path, 0, 0, 0, 0 );
401 HeapFree( GetProcessHeap(), 0, cab_file );
402 HeapFree( GetProcessHeap(), 0, cab_path );
403 return CopyFileW( src, dst, FALSE /*FIXME*/ );
407 /***********************************************************************
408 * SetupOpenFileQueue (SETUPAPI.@)
410 HSPFILEQ WINAPI SetupOpenFileQueue(void)
412 struct file_queue *queue;
414 if (!(queue = HeapAlloc( GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*queue))))
415 return INVALID_HANDLE_VALUE;
416 return queue;
420 /***********************************************************************
421 * SetupCloseFileQueue (SETUPAPI.@)
423 BOOL WINAPI SetupCloseFileQueue( HSPFILEQ handle )
425 struct file_queue *queue = handle;
427 free_file_op_queue( &queue->copy_queue );
428 free_file_op_queue( &queue->rename_queue );
429 free_file_op_queue( &queue->delete_queue );
430 HeapFree( GetProcessHeap(), 0, queue );
431 return TRUE;
435 /***********************************************************************
436 * SetupQueueCopyIndirectA (SETUPAPI.@)
438 BOOL WINAPI SetupQueueCopyIndirectA( PSP_FILE_COPY_PARAMS_A params )
440 struct file_queue *queue = params->QueueHandle;
441 struct file_op *op;
443 if (!(op = HeapAlloc( GetProcessHeap(), 0, sizeof(*op) ))) return FALSE;
444 op->style = params->CopyStyle;
445 op->src_root = strdupAtoW( params->SourceRootPath );
446 op->src_path = strdupAtoW( params->SourcePath );
447 op->src_file = strdupAtoW( params->SourceFilename );
448 op->src_descr = strdupAtoW( params->SourceDescription );
449 op->src_tag = strdupAtoW( params->SourceTagfile );
450 op->dst_path = strdupAtoW( params->TargetDirectory );
451 op->dst_file = strdupAtoW( params->TargetFilename );
453 /* some defaults */
454 if (!op->src_file) op->src_file = op->dst_file;
455 if (params->LayoutInf)
457 get_src_file_info( params->LayoutInf, op );
458 if (!op->dst_path) op->dst_path = get_destination_dir( params->LayoutInf, op->dst_file );
461 TRACE( "root=%s path=%s file=%s -> dir=%s file=%s descr=%s tag=%s\n",
462 debugstr_w(op->src_root), debugstr_w(op->src_path), debugstr_w(op->src_file),
463 debugstr_w(op->dst_path), debugstr_w(op->dst_file),
464 debugstr_w(op->src_descr), debugstr_w(op->src_tag) );
466 queue_file_op( &queue->copy_queue, op );
467 return TRUE;
471 /***********************************************************************
472 * SetupQueueCopyIndirectW (SETUPAPI.@)
474 BOOL WINAPI SetupQueueCopyIndirectW( PSP_FILE_COPY_PARAMS_W params )
476 struct file_queue *queue = params->QueueHandle;
477 struct file_op *op;
479 if (!(op = HeapAlloc( GetProcessHeap(), 0, sizeof(*op) ))) return FALSE;
480 op->style = params->CopyStyle;
481 op->src_root = strdupW( params->SourceRootPath );
482 op->src_path = strdupW( params->SourcePath );
483 op->src_file = strdupW( params->SourceFilename );
484 op->src_descr = strdupW( params->SourceDescription );
485 op->src_tag = strdupW( params->SourceTagfile );
486 op->dst_path = strdupW( params->TargetDirectory );
487 op->dst_file = strdupW( params->TargetFilename );
489 /* some defaults */
490 if (!op->src_file) op->src_file = op->dst_file;
491 if (params->LayoutInf)
493 get_src_file_info( params->LayoutInf, op );
494 if (!op->dst_path) op->dst_path = get_destination_dir( params->LayoutInf, op->dst_file );
497 TRACE( "root=%s path=%s file=%s -> dir=%s file=%s descr=%s tag=%s\n",
498 debugstr_w(op->src_root), debugstr_w(op->src_path), debugstr_w(op->src_file),
499 debugstr_w(op->dst_path), debugstr_w(op->dst_file),
500 debugstr_w(op->src_descr), debugstr_w(op->src_tag) );
502 queue_file_op( &queue->copy_queue, op );
503 return TRUE;
507 /***********************************************************************
508 * SetupQueueCopyA (SETUPAPI.@)
510 BOOL WINAPI SetupQueueCopyA( HSPFILEQ queue, PCSTR src_root, PCSTR src_path, PCSTR src_file,
511 PCSTR src_descr, PCSTR src_tag, PCSTR dst_dir, PCSTR dst_file,
512 DWORD style )
514 SP_FILE_COPY_PARAMS_A params;
516 params.cbSize = sizeof(params);
517 params.QueueHandle = queue;
518 params.SourceRootPath = src_root;
519 params.SourcePath = src_path;
520 params.SourceFilename = src_file;
521 params.SourceDescription = src_descr;
522 params.SourceTagfile = src_tag;
523 params.TargetDirectory = dst_dir;
524 params.TargetFilename = dst_file;
525 params.CopyStyle = style;
526 params.LayoutInf = 0;
527 params.SecurityDescriptor = NULL;
528 return SetupQueueCopyIndirectA( &params );
532 /***********************************************************************
533 * SetupQueueCopyW (SETUPAPI.@)
535 BOOL WINAPI SetupQueueCopyW( HSPFILEQ queue, PCWSTR src_root, PCWSTR src_path, PCWSTR src_file,
536 PCWSTR src_descr, PCWSTR src_tag, PCWSTR dst_dir, PCWSTR dst_file,
537 DWORD style )
539 SP_FILE_COPY_PARAMS_W params;
541 params.cbSize = sizeof(params);
542 params.QueueHandle = queue;
543 params.SourceRootPath = src_root;
544 params.SourcePath = src_path;
545 params.SourceFilename = src_file;
546 params.SourceDescription = src_descr;
547 params.SourceTagfile = src_tag;
548 params.TargetDirectory = dst_dir;
549 params.TargetFilename = dst_file;
550 params.CopyStyle = style;
551 params.LayoutInf = 0;
552 params.SecurityDescriptor = NULL;
553 return SetupQueueCopyIndirectW( &params );
557 /***********************************************************************
558 * SetupQueueDefaultCopyA (SETUPAPI.@)
560 BOOL WINAPI SetupQueueDefaultCopyA( HSPFILEQ queue, HINF hinf, PCSTR src_root, PCSTR src_file,
561 PCSTR dst_file, DWORD style )
563 SP_FILE_COPY_PARAMS_A params;
565 params.cbSize = sizeof(params);
566 params.QueueHandle = queue;
567 params.SourceRootPath = src_root;
568 params.SourcePath = NULL;
569 params.SourceFilename = src_file;
570 params.SourceDescription = NULL;
571 params.SourceTagfile = NULL;
572 params.TargetDirectory = NULL;
573 params.TargetFilename = dst_file;
574 params.CopyStyle = style;
575 params.LayoutInf = hinf;
576 params.SecurityDescriptor = NULL;
577 return SetupQueueCopyIndirectA( &params );
581 /***********************************************************************
582 * SetupQueueDefaultCopyW (SETUPAPI.@)
584 BOOL WINAPI SetupQueueDefaultCopyW( HSPFILEQ queue, HINF hinf, PCWSTR src_root, PCWSTR src_file,
585 PCWSTR dst_file, DWORD style )
587 SP_FILE_COPY_PARAMS_W params;
589 params.cbSize = sizeof(params);
590 params.QueueHandle = queue;
591 params.SourceRootPath = src_root;
592 params.SourcePath = NULL;
593 params.SourceFilename = src_file;
594 params.SourceDescription = NULL;
595 params.SourceTagfile = NULL;
596 params.TargetDirectory = NULL;
597 params.TargetFilename = dst_file;
598 params.CopyStyle = style;
599 params.LayoutInf = hinf;
600 params.SecurityDescriptor = NULL;
601 return SetupQueueCopyIndirectW( &params );
605 /***********************************************************************
606 * SetupQueueDeleteA (SETUPAPI.@)
608 BOOL WINAPI SetupQueueDeleteA( HSPFILEQ handle, PCSTR part1, PCSTR part2 )
610 struct file_queue *queue = handle;
611 struct file_op *op;
613 if (!(op = HeapAlloc( GetProcessHeap(), 0, sizeof(*op) ))) return FALSE;
614 op->style = 0;
615 op->src_root = NULL;
616 op->src_path = NULL;
617 op->src_file = NULL;
618 op->src_descr = NULL;
619 op->src_tag = NULL;
620 op->dst_path = strdupAtoW( part1 );
621 op->dst_file = strdupAtoW( part2 );
622 queue_file_op( &queue->delete_queue, op );
623 return TRUE;
627 /***********************************************************************
628 * SetupQueueDeleteW (SETUPAPI.@)
630 BOOL WINAPI SetupQueueDeleteW( HSPFILEQ handle, PCWSTR part1, PCWSTR part2 )
632 struct file_queue *queue = handle;
633 struct file_op *op;
635 if (!(op = HeapAlloc( GetProcessHeap(), 0, sizeof(*op) ))) return FALSE;
636 op->style = 0;
637 op->src_root = NULL;
638 op->src_path = NULL;
639 op->src_file = NULL;
640 op->src_descr = NULL;
641 op->src_tag = NULL;
642 op->dst_path = strdupW( part1 );
643 op->dst_file = strdupW( part2 );
644 queue_file_op( &queue->delete_queue, op );
645 return TRUE;
649 /***********************************************************************
650 * SetupQueueRenameA (SETUPAPI.@)
652 BOOL WINAPI SetupQueueRenameA( HSPFILEQ handle, PCSTR SourcePath, PCSTR SourceFilename,
653 PCSTR TargetPath, PCSTR TargetFilename )
655 struct file_queue *queue = handle;
656 struct file_op *op;
658 if (!(op = HeapAlloc( GetProcessHeap(), 0, sizeof(*op) ))) return FALSE;
659 op->style = 0;
660 op->src_root = NULL;
661 op->src_path = strdupAtoW( SourcePath );
662 op->src_file = strdupAtoW( SourceFilename );
663 op->src_descr = NULL;
664 op->src_tag = NULL;
665 op->dst_path = strdupAtoW( TargetPath );
666 op->dst_file = strdupAtoW( TargetFilename );
667 queue_file_op( &queue->rename_queue, op );
668 return TRUE;
672 /***********************************************************************
673 * SetupQueueRenameW (SETUPAPI.@)
675 BOOL WINAPI SetupQueueRenameW( HSPFILEQ handle, PCWSTR SourcePath, PCWSTR SourceFilename,
676 PCWSTR TargetPath, PCWSTR TargetFilename )
678 struct file_queue *queue = handle;
679 struct file_op *op;
681 if (!(op = HeapAlloc( GetProcessHeap(), 0, sizeof(*op) ))) return FALSE;
682 op->style = 0;
683 op->src_root = NULL;
684 op->src_path = strdupW( SourcePath );
685 op->src_file = strdupW( SourceFilename );
686 op->src_descr = NULL;
687 op->src_tag = NULL;
688 op->dst_path = strdupW( TargetPath );
689 op->dst_file = strdupW( TargetFilename );
690 queue_file_op( &queue->rename_queue, op );
691 return TRUE;
695 /***********************************************************************
696 * SetupQueueCopySectionA (SETUPAPI.@)
698 BOOL WINAPI SetupQueueCopySectionA( HSPFILEQ queue, PCSTR src_root, HINF hinf, HINF hlist,
699 PCSTR section, DWORD style )
701 UNICODE_STRING sectionW;
702 BOOL ret = FALSE;
704 if (!RtlCreateUnicodeStringFromAsciiz( &sectionW, section ))
706 SetLastError( ERROR_NOT_ENOUGH_MEMORY );
707 return FALSE;
709 if (!src_root)
710 ret = SetupQueueCopySectionW( queue, NULL, hinf, hlist, sectionW.Buffer, style );
711 else
713 UNICODE_STRING srcW;
714 if (RtlCreateUnicodeStringFromAsciiz( &srcW, src_root ))
716 ret = SetupQueueCopySectionW( queue, srcW.Buffer, hinf, hlist, sectionW.Buffer, style );
717 RtlFreeUnicodeString( &srcW );
719 else SetLastError( ERROR_NOT_ENOUGH_MEMORY );
721 RtlFreeUnicodeString( &sectionW );
722 return ret;
726 /***********************************************************************
727 * SetupQueueCopySectionW (SETUPAPI.@)
729 BOOL WINAPI SetupQueueCopySectionW( HSPFILEQ queue, PCWSTR src_root, HINF hinf, HINF hlist,
730 PCWSTR section, DWORD style )
732 SP_FILE_COPY_PARAMS_W params;
733 INFCONTEXT context;
734 WCHAR dest[MAX_PATH], src[MAX_PATH], *dest_dir;
735 INT flags;
736 BOOL ret = FALSE;
738 TRACE( "hinf=%p/%p section=%s root=%s\n",
739 hinf, hlist, debugstr_w(section), debugstr_w(src_root) );
741 params.cbSize = sizeof(params);
742 params.QueueHandle = queue;
743 params.SourceRootPath = src_root;
744 params.SourcePath = NULL;
745 params.SourceDescription = NULL;
746 params.SourceTagfile = NULL;
747 params.TargetFilename = dest;
748 params.CopyStyle = style;
749 params.LayoutInf = hinf;
750 params.SecurityDescriptor = NULL;
752 if (!hlist) hlist = hinf;
753 if (!hinf) hinf = hlist;
754 if (!SetupFindFirstLineW( hlist, section, NULL, &context )) return FALSE;
755 if (!(params.TargetDirectory = dest_dir = get_destination_dir( hinf, section ))) return FALSE;
758 if (!SetupGetStringFieldW( &context, 1, dest, sizeof(dest)/sizeof(WCHAR), NULL ))
759 goto end;
760 if (!SetupGetStringFieldW( &context, 2, src, sizeof(src)/sizeof(WCHAR), NULL )) *src = 0;
761 if (!SetupGetIntField( &context, 4, &flags )) flags = 0; /* FIXME */
763 params.SourceFilename = *src ? src : NULL;
764 if (!SetupQueueCopyIndirectW( &params )) goto end;
765 } while (SetupFindNextLine( &context, &context ));
766 ret = TRUE;
767 end:
768 HeapFree(GetProcessHeap(), 0, dest_dir);
769 return ret;
773 /***********************************************************************
774 * SetupQueueDeleteSectionA (SETUPAPI.@)
776 BOOL WINAPI SetupQueueDeleteSectionA( HSPFILEQ queue, HINF hinf, HINF hlist, PCSTR section )
778 UNICODE_STRING sectionW;
779 BOOL ret = FALSE;
781 if (RtlCreateUnicodeStringFromAsciiz( &sectionW, section ))
783 ret = SetupQueueDeleteSectionW( queue, hinf, hlist, sectionW.Buffer );
784 RtlFreeUnicodeString( &sectionW );
786 else SetLastError( ERROR_NOT_ENOUGH_MEMORY );
787 return ret;
791 /***********************************************************************
792 * SetupQueueDeleteSectionW (SETUPAPI.@)
794 BOOL WINAPI SetupQueueDeleteSectionW( HSPFILEQ queue, HINF hinf, HINF hlist, PCWSTR section )
796 INFCONTEXT context;
797 WCHAR *dest_dir;
798 WCHAR buffer[MAX_PATH];
799 BOOL ret = FALSE;
800 INT flags;
802 TRACE( "hinf=%p/%p section=%s\n", hinf, hlist, debugstr_w(section) );
804 if (!hlist) hlist = hinf;
805 if (!SetupFindFirstLineW( hlist, section, NULL, &context )) return FALSE;
806 if (!(dest_dir = get_destination_dir( hinf, section ))) return FALSE;
809 if (!SetupGetStringFieldW( &context, 1, buffer, sizeof(buffer)/sizeof(WCHAR), NULL ))
810 goto done;
811 if (!SetupGetIntField( &context, 4, &flags )) flags = 0;
812 if (!SetupQueueDeleteW( queue, dest_dir, buffer )) goto done;
813 } while (SetupFindNextLine( &context, &context ));
815 ret = TRUE;
816 done:
817 HeapFree( GetProcessHeap(), 0, dest_dir );
818 return ret;
822 /***********************************************************************
823 * SetupQueueRenameSectionA (SETUPAPI.@)
825 BOOL WINAPI SetupQueueRenameSectionA( HSPFILEQ queue, HINF hinf, HINF hlist, PCSTR section )
827 UNICODE_STRING sectionW;
828 BOOL ret = FALSE;
830 if (RtlCreateUnicodeStringFromAsciiz( &sectionW, section ))
832 ret = SetupQueueRenameSectionW( queue, hinf, hlist, sectionW.Buffer );
833 RtlFreeUnicodeString( &sectionW );
835 else SetLastError( ERROR_NOT_ENOUGH_MEMORY );
836 return ret;
840 /***********************************************************************
841 * SetupQueueRenameSectionW (SETUPAPI.@)
843 BOOL WINAPI SetupQueueRenameSectionW( HSPFILEQ queue, HINF hinf, HINF hlist, PCWSTR section )
845 INFCONTEXT context;
846 WCHAR *dest_dir;
847 WCHAR src[MAX_PATH], dst[MAX_PATH];
848 BOOL ret = FALSE;
850 TRACE( "hinf=%p/%p section=%s\n", hinf, hlist, debugstr_w(section) );
852 if (!hlist) hlist = hinf;
853 if (!SetupFindFirstLineW( hlist, section, NULL, &context )) return FALSE;
854 if (!(dest_dir = get_destination_dir( hinf, section ))) return FALSE;
857 if (!SetupGetStringFieldW( &context, 1, dst, sizeof(dst)/sizeof(WCHAR), NULL ))
858 goto done;
859 if (!SetupGetStringFieldW( &context, 2, src, sizeof(src)/sizeof(WCHAR), NULL ))
860 goto done;
861 if (!SetupQueueRenameW( queue, dest_dir, src, NULL, dst )) goto done;
862 } while (SetupFindNextLine( &context, &context ));
864 ret = TRUE;
865 done:
866 HeapFree( GetProcessHeap(), 0, dest_dir );
867 return ret;
871 /***********************************************************************
872 * SetupCommitFileQueueA (SETUPAPI.@)
874 BOOL WINAPI SetupCommitFileQueueA( HWND owner, HSPFILEQ queue, PSP_FILE_CALLBACK_A handler,
875 PVOID context )
877 struct callback_WtoA_context ctx;
879 ctx.orig_context = context;
880 ctx.orig_handler = handler;
881 return SetupCommitFileQueueW( owner, queue, QUEUE_callback_WtoA, &ctx );
885 /***********************************************************************
886 * create_full_pathW
888 * Recursively create all directories in the path.
890 static BOOL create_full_pathW(const WCHAR *path)
892 BOOL ret = TRUE;
893 int len;
894 WCHAR *new_path;
896 new_path = HeapAlloc(GetProcessHeap(), 0, (strlenW(path) + 1) * sizeof(WCHAR));
897 strcpyW(new_path, path);
899 while((len = strlenW(new_path)) && new_path[len - 1] == '\\')
900 new_path[len - 1] = 0;
902 while(!CreateDirectoryW(new_path, NULL))
904 WCHAR *slash;
905 DWORD last_error = GetLastError();
907 if(last_error == ERROR_ALREADY_EXISTS)
908 break;
910 if(last_error != ERROR_PATH_NOT_FOUND)
912 ret = FALSE;
913 break;
916 if(!(slash = strrchrW(new_path, '\\')))
918 ret = FALSE;
919 break;
922 len = slash - new_path;
923 new_path[len] = 0;
924 if(!create_full_pathW(new_path))
926 ret = FALSE;
927 break;
929 new_path[len] = '\\';
932 HeapFree(GetProcessHeap(), 0, new_path);
933 return ret;
936 static BOOL do_file_copyW( LPCWSTR source, LPCWSTR target, DWORD style,
937 PSP_FILE_CALLBACK_W handler, PVOID context )
939 BOOL rc = FALSE;
940 BOOL docopy = TRUE;
942 TRACE("copy %s to %s style 0x%x\n",debugstr_w(source),debugstr_w(target),style);
944 /* before copy processing */
945 if (style & SP_COPY_REPLACEONLY)
947 if (GetFileAttributesW(target) == INVALID_FILE_ATTRIBUTES)
948 docopy = FALSE;
950 if (style & (SP_COPY_NEWER_OR_SAME | SP_COPY_NEWER_ONLY | SP_COPY_FORCE_NEWER))
952 DWORD VersionSizeSource=0;
953 DWORD VersionSizeTarget=0;
954 DWORD zero=0;
957 * This is sort of an interesting workaround. You see, calling
958 * GetVersionInfoSize on a builtin dll loads that dll into memory
959 * and we do not properly unload builtin dlls.. so we effectively
960 * lock into memory all the targets we are replacing. This leads
961 * to problems when we try to register the replaced dlls.
963 * So I will test for the existence of the files first so that
964 * we just basically unconditionally replace the builtin versions.
966 if ((GetFileAttributesW(target) != INVALID_FILE_ATTRIBUTES) &&
967 (GetFileAttributesW(source) != INVALID_FILE_ATTRIBUTES))
969 VersionSizeSource = GetFileVersionInfoSizeW(source,&zero);
970 VersionSizeTarget = GetFileVersionInfoSizeW(target,&zero);
973 TRACE("SizeTarget %i ... SizeSource %i\n",VersionSizeTarget,
974 VersionSizeSource);
976 if (VersionSizeSource && VersionSizeTarget)
978 LPVOID VersionSource;
979 LPVOID VersionTarget;
980 VS_FIXEDFILEINFO *TargetInfo;
981 VS_FIXEDFILEINFO *SourceInfo;
982 UINT length;
983 static const WCHAR SubBlock[]={'\\',0};
984 DWORD ret;
986 VersionSource = HeapAlloc(GetProcessHeap(),0,VersionSizeSource);
987 VersionTarget = HeapAlloc(GetProcessHeap(),0,VersionSizeTarget);
989 ret = GetFileVersionInfoW(source,0,VersionSizeSource,VersionSource);
990 if (ret)
991 ret = GetFileVersionInfoW(target, 0, VersionSizeTarget,
992 VersionTarget);
994 if (ret)
996 ret = VerQueryValueW(VersionSource, SubBlock,
997 (LPVOID*)&SourceInfo, &length);
998 if (ret)
999 ret = VerQueryValueW(VersionTarget, SubBlock,
1000 (LPVOID*)&TargetInfo, &length);
1002 if (ret)
1004 FILEPATHS_W filepaths;
1006 TRACE("Versions: Source %i.%i target %i.%i\n",
1007 SourceInfo->dwFileVersionMS, SourceInfo->dwFileVersionLS,
1008 TargetInfo->dwFileVersionMS, TargetInfo->dwFileVersionLS);
1010 /* used in case of notification */
1011 filepaths.Target = target;
1012 filepaths.Source = source;
1013 filepaths.Win32Error = 0;
1014 filepaths.Flags = 0;
1016 if (TargetInfo->dwFileVersionMS > SourceInfo->dwFileVersionMS)
1018 if (handler)
1019 docopy = handler (context, SPFILENOTIFY_TARGETNEWER, (UINT_PTR)&filepaths, 0);
1020 else
1021 docopy = FALSE;
1023 else if ((TargetInfo->dwFileVersionMS == SourceInfo->dwFileVersionMS)
1024 && (TargetInfo->dwFileVersionLS > SourceInfo->dwFileVersionLS))
1026 if (handler)
1027 docopy = handler (context, SPFILENOTIFY_TARGETNEWER, (UINT_PTR)&filepaths, 0);
1028 else
1029 docopy = FALSE;
1031 else if ((style & SP_COPY_NEWER_ONLY) &&
1032 (TargetInfo->dwFileVersionMS ==
1033 SourceInfo->dwFileVersionMS)
1034 &&(TargetInfo->dwFileVersionLS ==
1035 SourceInfo->dwFileVersionLS))
1037 if (handler)
1038 docopy = handler (context, SPFILENOTIFY_TARGETNEWER, (UINT_PTR)&filepaths, 0);
1039 else
1040 docopy = FALSE;
1044 HeapFree(GetProcessHeap(),0,VersionSource);
1045 HeapFree(GetProcessHeap(),0,VersionTarget);
1048 if (style & (SP_COPY_NOOVERWRITE | SP_COPY_FORCE_NOOVERWRITE))
1050 if (GetFileAttributesW(target) != INVALID_FILE_ATTRIBUTES)
1052 FIXME("Notify user target file exists\n");
1053 docopy = FALSE;
1056 if (style & (SP_COPY_NODECOMP | SP_COPY_LANGUAGEAWARE | SP_COPY_FORCE_IN_USE |
1057 SP_COPY_IN_USE_NEEDS_REBOOT | SP_COPY_NOSKIP | SP_COPY_WARNIFSKIP))
1059 ERR("Unsupported style(s) 0x%x\n",style);
1062 if (docopy)
1064 rc = CopyFileW(source,target,FALSE);
1065 TRACE("Did copy... rc was %i\n",rc);
1068 /* after copy processing */
1069 if (style & SP_COPY_DELETESOURCE)
1071 if (rc)
1072 DeleteFileW(source);
1075 return rc;
1078 /***********************************************************************
1079 * SetupInstallFileExA (SETUPAPI.@)
1081 BOOL WINAPI SetupInstallFileExA( HINF hinf, PINFCONTEXT inf_context, PCSTR source, PCSTR root,
1082 PCSTR dest, DWORD style, PSP_FILE_CALLBACK_A handler, PVOID context, PBOOL in_use )
1084 BOOL ret = FALSE;
1085 struct callback_WtoA_context ctx;
1086 UNICODE_STRING sourceW, rootW, destW;
1088 TRACE("%p %p %s %s %s %x %p %p %p\n", hinf, inf_context, debugstr_a(source), debugstr_a(root),
1089 debugstr_a(dest), style, handler, context, in_use);
1091 sourceW.Buffer = rootW.Buffer = destW.Buffer = NULL;
1092 if (source && !RtlCreateUnicodeStringFromAsciiz( &sourceW, source ))
1094 SetLastError( ERROR_NOT_ENOUGH_MEMORY );
1095 return FALSE;
1097 if (root && !RtlCreateUnicodeStringFromAsciiz( &rootW, root ))
1099 SetLastError( ERROR_NOT_ENOUGH_MEMORY );
1100 goto exit;
1102 if (dest && !RtlCreateUnicodeStringFromAsciiz( &destW, dest ))
1104 SetLastError( ERROR_NOT_ENOUGH_MEMORY );
1105 goto exit;
1108 ctx.orig_context = context;
1109 ctx.orig_handler = handler;
1111 ret = SetupInstallFileExW( hinf, inf_context, sourceW.Buffer, rootW.Buffer, destW.Buffer, style, QUEUE_callback_WtoA, &ctx, in_use );
1113 exit:
1114 RtlFreeUnicodeString( &sourceW );
1115 RtlFreeUnicodeString( &rootW );
1116 RtlFreeUnicodeString( &destW );
1117 return ret;
1120 /***********************************************************************
1121 * SetupInstallFileA (SETUPAPI.@)
1123 BOOL WINAPI SetupInstallFileA( HINF hinf, PINFCONTEXT inf_context, PCSTR source, PCSTR root,
1124 PCSTR dest, DWORD style, PSP_FILE_CALLBACK_A handler, PVOID context )
1126 return SetupInstallFileExA( hinf, inf_context, source, root, dest, style, handler, context, NULL );
1129 /***********************************************************************
1130 * SetupInstallFileExW (SETUPAPI.@)
1132 BOOL WINAPI SetupInstallFileExW( HINF hinf, PINFCONTEXT inf_context, PCWSTR source, PCWSTR root,
1133 PCWSTR dest, DWORD style, PSP_FILE_CALLBACK_W handler, PVOID context, PBOOL in_use )
1135 static const WCHAR CopyFiles[] = {'C','o','p','y','F','i','l','e','s',0};
1137 BOOL ret, absolute = (root && *root && !(style & SP_COPY_SOURCE_ABSOLUTE));
1138 WCHAR *buffer, *p, *inf_source = NULL;
1139 unsigned int len;
1141 TRACE("%p %p %s %s %s %x %p %p %p\n", hinf, inf_context, debugstr_w(source), debugstr_w(root),
1142 debugstr_w(dest), style, handler, context, in_use);
1144 if (in_use) FIXME("no file in use support\n");
1146 if (hinf)
1148 INFCONTEXT ctx;
1150 if (!inf_context)
1152 inf_context = &ctx;
1153 if (!SetupFindFirstLineW( hinf, CopyFiles, NULL, inf_context )) return FALSE;
1155 if (!SetupGetStringFieldW( inf_context, 1, NULL, 0, &len )) return FALSE;
1156 if (!(inf_source = HeapAlloc( GetProcessHeap(), 0, len * sizeof(WCHAR) )))
1158 SetLastError( ERROR_NOT_ENOUGH_MEMORY );
1159 return FALSE;
1161 if (!SetupGetStringFieldW( inf_context, 1, inf_source, len, NULL ))
1163 HeapFree( GetProcessHeap(), 0, inf_source );
1164 return FALSE;
1166 source = inf_source;
1168 else if (!source)
1170 SetLastError( ERROR_INVALID_PARAMETER );
1171 return FALSE;
1174 len = strlenW( source ) + 1;
1175 if (absolute) len += strlenW( root ) + 1;
1177 if (!(p = buffer = HeapAlloc( GetProcessHeap(), 0, len * sizeof(WCHAR) )))
1179 HeapFree( GetProcessHeap(), 0, inf_source );
1180 SetLastError( ERROR_NOT_ENOUGH_MEMORY );
1181 return FALSE;
1184 if (absolute)
1186 strcpyW( buffer, root );
1187 p += strlenW( buffer );
1188 if (p[-1] != '\\') *p++ = '\\';
1190 while (*source == '\\') source++;
1191 strcpyW( p, source );
1193 ret = do_file_copyW( buffer, dest, style, handler, context );
1195 HeapFree( GetProcessHeap(), 0, inf_source );
1196 HeapFree( GetProcessHeap(), 0, buffer );
1197 return ret;
1200 /***********************************************************************
1201 * SetupInstallFileW (SETUPAPI.@)
1203 BOOL WINAPI SetupInstallFileW( HINF hinf, PINFCONTEXT inf_context, PCWSTR source, PCWSTR root,
1204 PCWSTR dest, DWORD style, PSP_FILE_CALLBACK_W handler, PVOID context )
1206 return SetupInstallFileExW( hinf, inf_context, source, root, dest, style, handler, context, NULL );
1209 /***********************************************************************
1210 * SetupCommitFileQueueW (SETUPAPI.@)
1212 BOOL WINAPI SetupCommitFileQueueW( HWND owner, HSPFILEQ handle, PSP_FILE_CALLBACK_W handler,
1213 PVOID context )
1215 struct file_queue *queue = handle;
1216 struct file_op *op;
1217 BOOL result = FALSE;
1218 FILEPATHS_W paths;
1219 UINT op_result;
1221 paths.Source = paths.Target = NULL;
1223 if (!queue->copy_queue.count && !queue->delete_queue.count && !queue->rename_queue.count)
1224 return TRUE; /* nothing to do */
1226 if (!handler( context, SPFILENOTIFY_STARTQUEUE, (UINT_PTR)owner, 0 )) return FALSE;
1228 /* perform deletes */
1230 if (queue->delete_queue.count)
1232 if (!(handler( context, SPFILENOTIFY_STARTSUBQUEUE, FILEOP_DELETE,
1233 queue->delete_queue.count ))) goto done;
1234 for (op = queue->delete_queue.head; op; op = op->next)
1236 build_filepathsW( op, &paths );
1237 op_result = handler( context, SPFILENOTIFY_STARTDELETE, (UINT_PTR)&paths, FILEOP_DELETE);
1238 if (op_result == FILEOP_ABORT) goto done;
1239 while (op_result == FILEOP_DOIT)
1241 TRACE( "deleting file %s\n", debugstr_w(paths.Target) );
1242 if (DeleteFileW( paths.Target )) break; /* success */
1243 paths.Win32Error = GetLastError();
1244 op_result = handler( context, SPFILENOTIFY_DELETEERROR, (UINT_PTR)&paths, 0 );
1245 if (op_result == FILEOP_ABORT) goto done;
1247 handler( context, SPFILENOTIFY_ENDDELETE, (UINT_PTR)&paths, 0 );
1249 handler( context, SPFILENOTIFY_ENDSUBQUEUE, FILEOP_DELETE, 0 );
1252 /* perform renames */
1254 if (queue->rename_queue.count)
1256 if (!(handler( context, SPFILENOTIFY_STARTSUBQUEUE, FILEOP_RENAME,
1257 queue->rename_queue.count ))) goto done;
1258 for (op = queue->rename_queue.head; op; op = op->next)
1260 build_filepathsW( op, &paths );
1261 op_result = handler( context, SPFILENOTIFY_STARTRENAME, (UINT_PTR)&paths, FILEOP_RENAME);
1262 if (op_result == FILEOP_ABORT) goto done;
1263 while (op_result == FILEOP_DOIT)
1265 TRACE( "renaming file %s -> %s\n",
1266 debugstr_w(paths.Source), debugstr_w(paths.Target) );
1267 if (MoveFileW( paths.Source, paths.Target )) break; /* success */
1268 paths.Win32Error = GetLastError();
1269 op_result = handler( context, SPFILENOTIFY_RENAMEERROR, (UINT_PTR)&paths, 0 );
1270 if (op_result == FILEOP_ABORT) goto done;
1272 handler( context, SPFILENOTIFY_ENDRENAME, (UINT_PTR)&paths, 0 );
1274 handler( context, SPFILENOTIFY_ENDSUBQUEUE, FILEOP_RENAME, 0 );
1277 /* perform copies */
1279 if (queue->copy_queue.count)
1281 if (!(handler( context, SPFILENOTIFY_STARTSUBQUEUE, FILEOP_COPY,
1282 queue->copy_queue.count ))) goto done;
1283 for (op = queue->copy_queue.head; op; op = op->next)
1285 WCHAR newpath[MAX_PATH];
1287 build_filepathsW( op, &paths );
1288 op_result = handler( context, SPFILENOTIFY_STARTCOPY, (UINT_PTR)&paths, FILEOP_COPY );
1289 if (op_result == FILEOP_ABORT) goto done;
1290 if (op_result == FILEOP_NEWPATH) op_result = FILEOP_DOIT;
1291 while (op_result == FILEOP_DOIT || op_result == FILEOP_NEWPATH)
1293 TRACE( "copying file %s -> %s\n",
1294 debugstr_w( op_result == FILEOP_NEWPATH ? newpath : paths.Source ),
1295 debugstr_w(paths.Target) );
1296 if (op->dst_path)
1298 if (!create_full_pathW( op->dst_path ))
1300 paths.Win32Error = GetLastError();
1301 op_result = handler( context, SPFILENOTIFY_COPYERROR,
1302 (UINT_PTR)&paths, (UINT_PTR)newpath );
1303 if (op_result == FILEOP_ABORT) goto done;
1306 if (do_file_copyW( op_result == FILEOP_NEWPATH ? newpath : paths.Source,
1307 paths.Target, op->style, handler, context )) break; /* success */
1308 /* try to extract it from the cabinet file */
1309 if (op->src_tag)
1311 if (extract_cabinet_file( op->src_tag, op->src_root,
1312 paths.Source, paths.Target )) break;
1314 paths.Win32Error = GetLastError();
1315 op_result = handler( context, SPFILENOTIFY_COPYERROR,
1316 (UINT_PTR)&paths, (UINT_PTR)newpath );
1317 if (op_result == FILEOP_ABORT) goto done;
1319 handler( context, SPFILENOTIFY_ENDCOPY, (UINT_PTR)&paths, 0 );
1321 handler( context, SPFILENOTIFY_ENDSUBQUEUE, FILEOP_COPY, 0 );
1325 result = TRUE;
1327 done:
1328 handler( context, SPFILENOTIFY_ENDQUEUE, result, 0 );
1329 HeapFree( GetProcessHeap(), 0, (void *)paths.Source );
1330 HeapFree( GetProcessHeap(), 0, (void *)paths.Target );
1331 return result;
1335 /***********************************************************************
1336 * SetupScanFileQueueA (SETUPAPI.@)
1338 BOOL WINAPI SetupScanFileQueueA( HSPFILEQ handle, DWORD flags, HWND window,
1339 PSP_FILE_CALLBACK_A handler, PVOID context, PDWORD result )
1341 struct callback_WtoA_context ctx;
1343 TRACE("%p %x %p %p %p %p\n", handle, flags, window, handler, context, result);
1345 ctx.orig_context = context;
1346 ctx.orig_handler = handler;
1348 return SetupScanFileQueueW( handle, flags, window, QUEUE_callback_WtoA, &ctx, result );
1352 /***********************************************************************
1353 * SetupScanFileQueueW (SETUPAPI.@)
1355 BOOL WINAPI SetupScanFileQueueW( HSPFILEQ handle, DWORD flags, HWND window,
1356 PSP_FILE_CALLBACK_W handler, PVOID context, PDWORD result )
1358 struct file_queue *queue = handle;
1359 struct file_op *op;
1360 FILEPATHS_W paths;
1361 UINT notification = 0;
1362 BOOL ret = FALSE;
1364 TRACE("%p %x %p %p %p %p\n", handle, flags, window, handler, context, result);
1366 if (!queue->copy_queue.count) return TRUE;
1368 if (flags & SPQ_SCAN_USE_CALLBACK) notification = SPFILENOTIFY_QUEUESCAN;
1369 else if (flags & SPQ_SCAN_USE_CALLBACKEX) notification = SPFILENOTIFY_QUEUESCAN_EX;
1371 if (flags & ~(SPQ_SCAN_USE_CALLBACK | SPQ_SCAN_USE_CALLBACKEX))
1373 FIXME("flags %x not fully implemented\n", flags);
1376 paths.Source = paths.Target = NULL;
1378 for (op = queue->copy_queue.head; op; op = op->next)
1380 build_filepathsW( op, &paths );
1381 switch (notification)
1383 case SPFILENOTIFY_QUEUESCAN:
1384 /* FIXME: handle delay flag */
1385 if (handler( context, notification, (UINT_PTR)paths.Target, 0 )) goto done;
1386 break;
1387 case SPFILENOTIFY_QUEUESCAN_EX:
1388 if (handler( context, notification, (UINT_PTR)&paths, 0 )) goto done;
1389 break;
1390 default:
1391 ret = TRUE; goto done;
1395 ret = TRUE;
1397 done:
1398 if (result) *result = 0;
1399 HeapFree( GetProcessHeap(), 0, (void *)paths.Source );
1400 HeapFree( GetProcessHeap(), 0, (void *)paths.Target );
1401 return ret;
1405 /***********************************************************************
1406 * SetupGetFileQueueCount (SETUPAPI.@)
1408 BOOL WINAPI SetupGetFileQueueCount( HSPFILEQ handle, UINT op, PUINT result )
1410 struct file_queue *queue = handle;
1412 switch(op)
1414 case FILEOP_COPY:
1415 *result = queue->copy_queue.count;
1416 return TRUE;
1417 case FILEOP_RENAME:
1418 *result = queue->rename_queue.count;
1419 return TRUE;
1420 case FILEOP_DELETE:
1421 *result = queue->delete_queue.count;
1422 return TRUE;
1424 return FALSE;
1428 /***********************************************************************
1429 * SetupGetFileQueueFlags (SETUPAPI.@)
1431 BOOL WINAPI SetupGetFileQueueFlags( HSPFILEQ handle, PDWORD flags )
1433 struct file_queue *queue = handle;
1434 *flags = queue->flags;
1435 return TRUE;
1439 /***********************************************************************
1440 * SetupSetFileQueueFlags (SETUPAPI.@)
1442 BOOL WINAPI SetupSetFileQueueFlags( HSPFILEQ handle, DWORD mask, DWORD flags )
1444 struct file_queue *queue = handle;
1445 queue->flags = (queue->flags & ~mask) | flags;
1446 return TRUE;
1450 /***********************************************************************
1451 * SetupSetFileQueueAlternatePlatformA (SETUPAPI.@)
1453 BOOL WINAPI SetupSetFileQueueAlternatePlatformA(HSPFILEQ handle, PSP_ALTPLATFORM_INFO platform, PCSTR catalogfile)
1455 FIXME("(%p, %p, %s) stub!\n", handle, platform, debugstr_a(catalogfile));
1456 return FALSE;
1460 /***********************************************************************
1461 * SetupSetFileQueueAlternatePlatformW (SETUPAPI.@)
1463 BOOL WINAPI SetupSetFileQueueAlternatePlatformW(HSPFILEQ handle, PSP_ALTPLATFORM_INFO platform, PCWSTR catalogfile)
1465 FIXME("(%p, %p, %s) stub!\n", handle, platform, debugstr_w(catalogfile));
1466 return FALSE;
1470 /***********************************************************************
1471 * SetupInitDefaultQueueCallback (SETUPAPI.@)
1473 PVOID WINAPI SetupInitDefaultQueueCallback( HWND owner )
1475 return SetupInitDefaultQueueCallbackEx( owner, 0, 0, 0, NULL );
1479 /***********************************************************************
1480 * SetupInitDefaultQueueCallbackEx (SETUPAPI.@)
1482 PVOID WINAPI SetupInitDefaultQueueCallbackEx( HWND owner, HWND progress, UINT msg,
1483 DWORD reserved1, PVOID reserved2 )
1485 struct default_callback_context *context;
1487 if ((context = HeapAlloc( GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*context) )))
1489 context->magic = 0x43515053; /* "SPQC" */
1490 context->owner = owner;
1491 context->progress = progress;
1492 context->message = msg;
1494 return context;
1498 /***********************************************************************
1499 * SetupTermDefaultQueueCallback (SETUPAPI.@)
1501 void WINAPI SetupTermDefaultQueueCallback( PVOID context )
1503 HeapFree( GetProcessHeap(), 0, context );
1507 /***********************************************************************
1508 * SetupDefaultQueueCallbackA (SETUPAPI.@)
1510 UINT WINAPI SetupDefaultQueueCallbackA( PVOID context, UINT notification,
1511 UINT_PTR param1, UINT_PTR param2 )
1513 FILEPATHS_A *paths = (FILEPATHS_A *)param1;
1514 struct default_callback_context *ctx = context;
1516 switch(notification)
1518 case SPFILENOTIFY_STARTQUEUE:
1519 TRACE( "start queue\n" );
1520 return TRUE;
1521 case SPFILENOTIFY_ENDQUEUE:
1522 TRACE( "end queue\n" );
1523 return 0;
1524 case SPFILENOTIFY_STARTSUBQUEUE:
1525 TRACE( "start subqueue %ld count %ld\n", param1, param2 );
1526 return TRUE;
1527 case SPFILENOTIFY_ENDSUBQUEUE:
1528 TRACE( "end subqueue %ld\n", param1 );
1529 return 0;
1530 case SPFILENOTIFY_STARTDELETE:
1531 TRACE( "start delete %s\n", debugstr_a(paths->Target) );
1532 return FILEOP_DOIT;
1533 case SPFILENOTIFY_ENDDELETE:
1534 TRACE( "end delete %s\n", debugstr_a(paths->Target) );
1535 return 0;
1536 case SPFILENOTIFY_DELETEERROR:
1537 /*Windows Ignores attempts to delete files / folders which do not exist*/
1538 if ((paths->Win32Error != ERROR_FILE_NOT_FOUND) && (paths->Win32Error != ERROR_PATH_NOT_FOUND))
1539 SetupDeleteErrorA(ctx->owner, NULL, paths->Target, paths->Win32Error, 0);
1540 return FILEOP_SKIP;
1541 case SPFILENOTIFY_STARTRENAME:
1542 TRACE( "start rename %s -> %s\n", debugstr_a(paths->Source), debugstr_a(paths->Target) );
1543 return FILEOP_DOIT;
1544 case SPFILENOTIFY_ENDRENAME:
1545 TRACE( "end rename %s -> %s\n", debugstr_a(paths->Source), debugstr_a(paths->Target) );
1546 return 0;
1547 case SPFILENOTIFY_RENAMEERROR:
1548 SetupRenameErrorA(ctx->owner, NULL, paths->Source, paths->Target, paths->Win32Error, 0);
1549 return FILEOP_SKIP;
1550 case SPFILENOTIFY_STARTCOPY:
1551 TRACE( "start copy %s -> %s\n", debugstr_a(paths->Source), debugstr_a(paths->Target) );
1552 return FILEOP_DOIT;
1553 case SPFILENOTIFY_ENDCOPY:
1554 TRACE( "end copy %s -> %s\n", debugstr_a(paths->Source), debugstr_a(paths->Target) );
1555 return 0;
1556 case SPFILENOTIFY_COPYERROR:
1557 ERR( "copy error %d %s -> %s\n", paths->Win32Error,
1558 debugstr_a(paths->Source), debugstr_a(paths->Target) );
1559 return FILEOP_SKIP;
1560 case SPFILENOTIFY_NEEDMEDIA:
1561 TRACE( "need media\n" );
1562 return FILEOP_SKIP;
1563 default:
1564 FIXME( "notification %d params %lx,%lx\n", notification, param1, param2 );
1565 break;
1567 return 0;
1571 /***********************************************************************
1572 * SetupDefaultQueueCallbackW (SETUPAPI.@)
1574 UINT WINAPI SetupDefaultQueueCallbackW( PVOID context, UINT notification,
1575 UINT_PTR param1, UINT_PTR param2 )
1577 FILEPATHS_W *paths = (FILEPATHS_W *)param1;
1578 struct default_callback_context *ctx = context;
1580 switch(notification)
1582 case SPFILENOTIFY_STARTQUEUE:
1583 TRACE( "start queue\n" );
1584 return TRUE;
1585 case SPFILENOTIFY_ENDQUEUE:
1586 TRACE( "end queue\n" );
1587 return 0;
1588 case SPFILENOTIFY_STARTSUBQUEUE:
1589 TRACE( "start subqueue %ld count %ld\n", param1, param2 );
1590 return TRUE;
1591 case SPFILENOTIFY_ENDSUBQUEUE:
1592 TRACE( "end subqueue %ld\n", param1 );
1593 return 0;
1594 case SPFILENOTIFY_STARTDELETE:
1595 TRACE( "start delete %s\n", debugstr_w(paths->Target) );
1596 return FILEOP_DOIT;
1597 case SPFILENOTIFY_ENDDELETE:
1598 TRACE( "end delete %s\n", debugstr_w(paths->Target) );
1599 return 0;
1600 case SPFILENOTIFY_DELETEERROR:
1601 /*Windows Ignores attempts to delete files / folders which do not exist*/
1602 if ((paths->Win32Error != ERROR_FILE_NOT_FOUND) && (paths->Win32Error != ERROR_PATH_NOT_FOUND))
1603 SetupDeleteErrorW(ctx->owner, NULL, paths->Target, paths->Win32Error, 0);
1604 return FILEOP_SKIP;
1605 case SPFILENOTIFY_STARTRENAME:
1606 SetupRenameErrorW(ctx->owner, NULL, paths->Source, paths->Target, paths->Win32Error, 0);
1607 return FILEOP_DOIT;
1608 case SPFILENOTIFY_ENDRENAME:
1609 TRACE( "end rename %s -> %s\n", debugstr_w(paths->Source), debugstr_w(paths->Target) );
1610 return 0;
1611 case SPFILENOTIFY_RENAMEERROR:
1612 ERR( "rename error %d %s -> %s\n", paths->Win32Error,
1613 debugstr_w(paths->Source), debugstr_w(paths->Target) );
1614 return FILEOP_SKIP;
1615 case SPFILENOTIFY_STARTCOPY:
1616 TRACE( "start copy %s -> %s\n", debugstr_w(paths->Source), debugstr_w(paths->Target) );
1617 return FILEOP_DOIT;
1618 case SPFILENOTIFY_ENDCOPY:
1619 TRACE( "end copy %s -> %s\n", debugstr_w(paths->Source), debugstr_w(paths->Target) );
1620 return 0;
1621 case SPFILENOTIFY_COPYERROR:
1622 ERR( "copy error %d %s -> %s\n", paths->Win32Error,
1623 debugstr_w(paths->Source), debugstr_w(paths->Target) );
1624 return FILEOP_SKIP;
1625 case SPFILENOTIFY_NEEDMEDIA:
1626 TRACE( "need media\n" );
1627 return FILEOP_SKIP;
1628 default:
1629 FIXME( "notification %d params %lx,%lx\n", notification, param1, param2 );
1630 break;
1632 return 0;
1635 /***********************************************************************
1636 * SetupDeleteErrorA (SETUPAPI.@)
1639 UINT WINAPI SetupDeleteErrorA( HWND parent, PCSTR dialogTitle, PCSTR file,
1640 UINT w32error, DWORD style)
1642 FIXME( "stub: (Error Number %d when attempting to delete %s)\n",
1643 w32error, debugstr_a(file) );
1644 return DPROMPT_SKIPFILE;
1647 /***********************************************************************
1648 * SetupDeleteErrorW (SETUPAPI.@)
1651 UINT WINAPI SetupDeleteErrorW( HWND parent, PCWSTR dialogTitle, PCWSTR file,
1652 UINT w32error, DWORD style)
1654 FIXME( "stub: (Error Number %d when attempting to delete %s)\n",
1655 w32error, debugstr_w(file) );
1656 return DPROMPT_SKIPFILE;
1659 /***********************************************************************
1660 * SetupRenameErrorA (SETUPAPI.@)
1663 UINT WINAPI SetupRenameErrorA( HWND parent, PCSTR dialogTitle, PCSTR source,
1664 PCSTR target, UINT w32error, DWORD style)
1666 FIXME( "stub: (Error Number %d when attempting to rename %s to %s)\n",
1667 w32error, debugstr_a(source), debugstr_a(target));
1668 return DPROMPT_SKIPFILE;
1671 /***********************************************************************
1672 * SetupRenameErrorW (SETUPAPI.@)
1675 UINT WINAPI SetupRenameErrorW( HWND parent, PCWSTR dialogTitle, PCWSTR source,
1676 PCWSTR target, UINT w32error, DWORD style)
1678 FIXME( "stub: (Error Number %d when attempting to rename %s to %s)\n",
1679 w32error, debugstr_w(source), debugstr_w(target));
1680 return DPROMPT_SKIPFILE;
1684 /***********************************************************************
1685 * SetupCopyErrorA (SETUPAPI.@)
1688 UINT WINAPI SetupCopyErrorA( HWND parent, PCSTR dialogTitle, PCSTR diskname,
1689 PCSTR sourcepath, PCSTR sourcefile, PCSTR targetpath,
1690 UINT w32error, DWORD style, PSTR 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_a(sourcefile), debugstr_a(sourcepath) ,debugstr_a(targetpath));
1695 return DPROMPT_SKIPFILE;
1698 /***********************************************************************
1699 * SetupCopyErrorW (SETUPAPI.@)
1702 UINT WINAPI SetupCopyErrorW( HWND parent, PCWSTR dialogTitle, PCWSTR diskname,
1703 PCWSTR sourcepath, PCWSTR sourcefile, PCWSTR targetpath,
1704 UINT w32error, DWORD style, PWSTR pathbuffer,
1705 DWORD buffersize, PDWORD requiredsize)
1707 FIXME( "stub: (Error Number %d when attempting to copy file %s from %s to %s)\n",
1708 w32error, debugstr_w(sourcefile), debugstr_w(sourcepath) ,debugstr_w(targetpath));
1709 return DPROMPT_SKIPFILE;
1712 /***********************************************************************
1713 * pSetupGetQueueFlags (SETUPAPI.@)
1715 DWORD WINAPI pSetupGetQueueFlags( HSPFILEQ handle )
1717 struct file_queue *queue = handle;
1718 return queue->flags;
1721 /***********************************************************************
1722 * pSetupSetQueueFlags (SETUPAPI.@)
1724 BOOL WINAPI pSetupSetQueueFlags( HSPFILEQ handle, DWORD flags )
1726 struct file_queue *queue = handle;
1727 queue->flags = flags;
1728 return TRUE;