push b5232b2081a0e20e4bf07d6ded424d0101e4a589
[wine/hacks.git] / dlls / setupapi / queue.c
blobfa212fbd8e859b300e2b284f4245bad0ad411e14
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 static inline WCHAR *strdupW( const WCHAR *str )
78 WCHAR *ret = NULL;
79 if (str)
81 int len = (strlenW(str) + 1) * sizeof(WCHAR);
82 if ((ret = HeapAlloc( GetProcessHeap(), 0, len ))) memcpy( ret, str, len );
84 return ret;
87 static inline char *strdupWtoA( const WCHAR *str )
89 char *ret = NULL;
90 if (str)
92 DWORD len = WideCharToMultiByte( CP_ACP, 0, str, -1, NULL, 0, NULL, NULL );
93 if ((ret = HeapAlloc( GetProcessHeap(), 0, len )))
94 WideCharToMultiByte( CP_ACP, 0, str, -1, ret, len, NULL, NULL );
96 return ret;
99 /* append a file operation to a queue */
100 static inline void queue_file_op( struct file_op_queue *queue, struct file_op *op )
102 op->next = NULL;
103 if (queue->tail) queue->tail->next = op;
104 else queue->head = op;
105 queue->tail = op;
106 queue->count++;
109 /* free all the file operations on a given queue */
110 static void free_file_op_queue( struct file_op_queue *queue )
112 struct file_op *t, *op = queue->head;
114 while( op )
116 HeapFree( GetProcessHeap(), 0, op->src_root );
117 HeapFree( GetProcessHeap(), 0, op->src_path );
118 HeapFree( GetProcessHeap(), 0, op->src_file );
119 HeapFree( GetProcessHeap(), 0, op->src_descr );
120 HeapFree( GetProcessHeap(), 0, op->src_tag );
121 HeapFree( GetProcessHeap(), 0, op->dst_path );
122 if (op->dst_file != op->src_file) HeapFree( GetProcessHeap(), 0, op->dst_file );
123 t = op;
124 op = op->next;
125 HeapFree( GetProcessHeap(), 0, t );
129 /* concat 3 strings to make a path, handling separators correctly */
130 static void concat_W( WCHAR *buffer, const WCHAR *src1, const WCHAR *src2, const WCHAR *src3 )
132 *buffer = 0;
133 if (src1 && *src1)
135 strcpyW( buffer, src1 );
136 buffer += strlenW(buffer );
137 if (buffer[-1] != '\\') *buffer++ = '\\';
138 if (src2) while (*src2 == '\\') src2++;
141 if (src2)
143 strcpyW( buffer, src2 );
144 buffer += strlenW(buffer );
145 if (buffer[-1] != '\\') *buffer++ = '\\';
146 if (src3) while (*src3 == '\\') src3++;
148 if (src3)
150 strcpyW( buffer, src3 );
151 buffer += strlenW(buffer );
156 /***********************************************************************
157 * build_filepathsW
159 * Build a FILEPATHS_W structure for a given file operation.
161 static BOOL build_filepathsW( const struct file_op *op, FILEPATHS_W *paths )
163 unsigned int src_len = 1, dst_len = 1;
164 WCHAR *source = (PWSTR)paths->Source, *target = (PWSTR)paths->Target;
166 if (op->src_root) src_len += strlenW(op->src_root) + 1;
167 if (op->src_path) src_len += strlenW(op->src_path) + 1;
168 if (op->src_file) src_len += strlenW(op->src_file) + 1;
169 if (op->dst_path) dst_len += strlenW(op->dst_path) + 1;
170 if (op->dst_file) dst_len += strlenW(op->dst_file) + 1;
171 src_len *= sizeof(WCHAR);
172 dst_len *= sizeof(WCHAR);
174 if (!source || HeapSize( GetProcessHeap(), 0, source ) < src_len )
176 HeapFree( GetProcessHeap(), 0, source );
177 paths->Source = source = HeapAlloc( GetProcessHeap(), 0, src_len );
179 if (!target || HeapSize( GetProcessHeap(), 0, target ) < dst_len )
181 HeapFree( GetProcessHeap(), 0, target );
182 paths->Target = target = HeapAlloc( GetProcessHeap(), 0, dst_len );
184 if (!source || !target) return FALSE;
185 concat_W( source, op->src_root, op->src_path, op->src_file );
186 concat_W( target, NULL, op->dst_path, op->dst_file );
187 paths->Win32Error = 0;
188 paths->Flags = 0;
189 return TRUE;
193 /***********************************************************************
194 * QUEUE_callback_WtoA
196 * Map a file callback parameters from W to A and call the A callback.
198 UINT CALLBACK QUEUE_callback_WtoA( void *context, UINT notification,
199 UINT_PTR param1, UINT_PTR param2 )
201 struct callback_WtoA_context *callback_ctx = context;
202 char buffer[MAX_PATH];
203 UINT ret;
204 UINT_PTR old_param2 = param2;
206 switch(notification)
208 case SPFILENOTIFY_COPYERROR:
209 param2 = (UINT_PTR)&buffer;
210 /* fall through */
211 case SPFILENOTIFY_STARTDELETE:
212 case SPFILENOTIFY_ENDDELETE:
213 case SPFILENOTIFY_DELETEERROR:
214 case SPFILENOTIFY_STARTRENAME:
215 case SPFILENOTIFY_ENDRENAME:
216 case SPFILENOTIFY_RENAMEERROR:
217 case SPFILENOTIFY_STARTCOPY:
218 case SPFILENOTIFY_ENDCOPY:
219 case SPFILENOTIFY_QUEUESCAN_EX:
221 FILEPATHS_W *pathsW = (FILEPATHS_W *)param1;
222 FILEPATHS_A pathsA;
224 pathsA.Source = strdupWtoA( pathsW->Source );
225 pathsA.Target = strdupWtoA( pathsW->Target );
226 pathsA.Win32Error = pathsW->Win32Error;
227 pathsA.Flags = pathsW->Flags;
228 ret = callback_ctx->orig_handler( callback_ctx->orig_context, notification,
229 (UINT_PTR)&pathsA, param2 );
230 HeapFree( GetProcessHeap(), 0, (void *)pathsA.Source );
231 HeapFree( GetProcessHeap(), 0, (void *)pathsA.Target );
233 if (notification == SPFILENOTIFY_COPYERROR)
234 MultiByteToWideChar( CP_ACP, 0, buffer, -1, (WCHAR *)old_param2, MAX_PATH );
235 break;
237 case SPFILENOTIFY_STARTREGISTRATION:
238 case SPFILENOTIFY_ENDREGISTRATION:
240 SP_REGISTER_CONTROL_STATUSW *statusW = (SP_REGISTER_CONTROL_STATUSW *)param1;
241 SP_REGISTER_CONTROL_STATUSA statusA;
243 statusA.cbSize = sizeof(statusA);
244 statusA.FileName = strdupWtoA( statusW->FileName );
245 statusA.Win32Error = statusW->Win32Error;
246 statusA.FailureCode = statusW->FailureCode;
247 ret = callback_ctx->orig_handler( callback_ctx->orig_context, notification,
248 (UINT_PTR)&statusA, param2 );
249 HeapFree( GetProcessHeap(), 0, (LPSTR)statusA.FileName );
251 break;
253 case SPFILENOTIFY_QUEUESCAN:
255 LPWSTR targetW = (LPWSTR)param1;
256 LPSTR target = strdupWtoA( targetW );
258 ret = callback_ctx->orig_handler( callback_ctx->orig_context, notification,
259 (UINT_PTR)target, param2 );
260 HeapFree( GetProcessHeap(), 0, target );
262 break;
264 case SPFILENOTIFY_NEEDMEDIA:
265 FIXME("mapping for %d not implemented\n",notification);
266 case SPFILENOTIFY_STARTQUEUE:
267 case SPFILENOTIFY_ENDQUEUE:
268 case SPFILENOTIFY_STARTSUBQUEUE:
269 case SPFILENOTIFY_ENDSUBQUEUE:
270 default:
271 ret = callback_ctx->orig_handler( callback_ctx->orig_context, notification, param1, param2 );
272 break;
274 return ret;
278 /***********************************************************************
279 * get_src_file_info
281 * Retrieve the source file information for a given file.
283 static void get_src_file_info( HINF hinf, struct file_op *op )
285 static const WCHAR SourceDisksNames[] =
286 {'S','o','u','r','c','e','D','i','s','k','s','N','a','m','e','s',0};
287 static const WCHAR SourceDisksFiles[] =
288 {'S','o','u','r','c','e','D','i','s','k','s','F','i','l','e','s',0};
290 INFCONTEXT file_ctx, disk_ctx;
291 INT id, diskid;
292 DWORD len, len2;
294 /* find the SourceDisksFiles entry */
295 if (!SetupFindFirstLineW( hinf, SourceDisksFiles, op->src_file, &file_ctx ))
297 if ((op->style & (SP_COPY_SOURCE_ABSOLUTE|SP_COPY_SOURCEPATH_ABSOLUTE))) return;
298 /* no specific info, use .inf file source directory */
299 if (!op->src_root) op->src_root = PARSER_get_src_root( hinf );
300 return;
302 if (!SetupGetIntField( &file_ctx, 1, &diskid )) return;
304 /* now find the diskid in the SourceDisksNames section */
305 if (!SetupFindFirstLineW( hinf, SourceDisksNames, NULL, &disk_ctx )) return;
306 for (;;)
308 if (SetupGetIntField( &disk_ctx, 0, &id ) && (id == diskid)) break;
309 if (!SetupFindNextLine( &disk_ctx, &disk_ctx )) return;
312 /* and fill in the missing info */
314 if (!op->src_descr)
316 if (SetupGetStringFieldW( &disk_ctx, 1, NULL, 0, &len ) &&
317 (op->src_descr = HeapAlloc( GetProcessHeap(), 0, len*sizeof(WCHAR) )))
318 SetupGetStringFieldW( &disk_ctx, 1, op->src_descr, len, NULL );
320 if (!op->src_tag)
322 if (SetupGetStringFieldW( &disk_ctx, 2, NULL, 0, &len ) &&
323 (op->src_tag = HeapAlloc( GetProcessHeap(), 0, len*sizeof(WCHAR) )))
324 SetupGetStringFieldW( &disk_ctx, 2, op->src_tag, len, NULL );
326 if (!op->src_path && !(op->style & SP_COPY_SOURCE_ABSOLUTE))
328 len = len2 = 0;
329 if (!(op->style & SP_COPY_SOURCEPATH_ABSOLUTE))
331 /* retrieve relative path for this disk */
332 if (!SetupGetStringFieldW( &disk_ctx, 4, NULL, 0, &len )) len = 0;
334 /* retrieve relative path for this file */
335 if (!SetupGetStringFieldW( &file_ctx, 2, NULL, 0, &len2 )) len2 = 0;
337 if ((len || len2) &&
338 (op->src_path = HeapAlloc( GetProcessHeap(), 0, (len+len2)*sizeof(WCHAR) )))
340 WCHAR *ptr = op->src_path;
341 if (len)
343 SetupGetStringFieldW( &disk_ctx, 4, op->src_path, len, NULL );
344 ptr = op->src_path + strlenW(op->src_path);
345 if (len2 && ptr > op->src_path && ptr[-1] != '\\') *ptr++ = '\\';
347 if (!SetupGetStringFieldW( &file_ctx, 2, ptr, len2, NULL )) *ptr = 0;
350 if (!op->src_root) op->src_root = PARSER_get_src_root(hinf);
354 /***********************************************************************
355 * get_destination_dir
357 * Retrieve the destination dir for a given section.
359 static WCHAR *get_destination_dir( HINF hinf, const WCHAR *section )
361 static const WCHAR Dest[] = {'D','e','s','t','i','n','a','t','i','o','n','D','i','r','s',0};
362 static const WCHAR Def[] = {'D','e','f','a','u','l','t','D','e','s','t','D','i','r',0};
363 INFCONTEXT context;
365 if (!SetupFindFirstLineW( hinf, Dest, section, &context ) &&
366 !SetupFindFirstLineW( hinf, Dest, Def, &context )) return NULL;
367 return PARSER_get_dest_dir( &context );
371 static void (WINAPI *pExtractFiles)( LPSTR, LPSTR, DWORD, DWORD, DWORD, DWORD );
373 /***********************************************************************
374 * extract_cabinet_file
376 * Extract a file from a .cab file.
378 static BOOL extract_cabinet_file( const WCHAR *cabinet, const WCHAR *root,
379 const WCHAR *src, const WCHAR *dst )
381 static const WCHAR extW[] = {'.','c','a','b',0};
382 static HMODULE advpack;
384 char *cab_path, *cab_file;
385 int len = strlenW( cabinet );
387 /* make sure the cabinet file has a .cab extension */
388 if (len <= 4 || strcmpiW( cabinet + len - 4, extW )) return FALSE;
389 if (!pExtractFiles)
391 if (!advpack && !(advpack = LoadLibraryA( "advpack.dll" )))
393 ERR( "could not load advpack.dll\n" );
394 return FALSE;
396 if (!(pExtractFiles = (void *)GetProcAddress( advpack, "ExtractFiles" )))
398 ERR( "could not find ExtractFiles in advpack.dll\n" );
399 return FALSE;
403 if (!(cab_path = strdupWtoA( root ))) return FALSE;
404 len = WideCharToMultiByte( CP_ACP, 0, cabinet, -1, NULL, 0, NULL, NULL );
405 if (!(cab_file = HeapAlloc( GetProcessHeap(), 0, strlen(cab_path) + len + 1 )))
407 HeapFree( GetProcessHeap(), 0, cab_path );
408 return FALSE;
410 strcpy( cab_file, cab_path );
411 if (cab_file[0] && cab_file[strlen(cab_file)-1] != '\\') strcat( cab_file, "\\" );
412 WideCharToMultiByte( CP_ACP, 0, cabinet, -1, cab_file + strlen(cab_file), len, NULL, NULL );
413 FIXME( "awful hack: extracting cabinet %s\n", debugstr_a(cab_file) );
414 pExtractFiles( cab_file, cab_path, 0, 0, 0, 0 );
415 HeapFree( GetProcessHeap(), 0, cab_file );
416 HeapFree( GetProcessHeap(), 0, cab_path );
417 return CopyFileW( src, dst, FALSE /*FIXME*/ );
421 /***********************************************************************
422 * SetupOpenFileQueue (SETUPAPI.@)
424 HSPFILEQ WINAPI SetupOpenFileQueue(void)
426 struct file_queue *queue;
428 if (!(queue = HeapAlloc( GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*queue))))
429 return (HSPFILEQ)INVALID_HANDLE_VALUE;
430 return queue;
434 /***********************************************************************
435 * SetupCloseFileQueue (SETUPAPI.@)
437 BOOL WINAPI SetupCloseFileQueue( HSPFILEQ handle )
439 struct file_queue *queue = handle;
441 free_file_op_queue( &queue->copy_queue );
442 free_file_op_queue( &queue->rename_queue );
443 free_file_op_queue( &queue->delete_queue );
444 HeapFree( GetProcessHeap(), 0, queue );
445 return TRUE;
449 /***********************************************************************
450 * SetupQueueCopyIndirectA (SETUPAPI.@)
452 BOOL WINAPI SetupQueueCopyIndirectA( PSP_FILE_COPY_PARAMS_A params )
454 struct file_queue *queue = params->QueueHandle;
455 struct file_op *op;
457 if (!(op = HeapAlloc( GetProcessHeap(), 0, sizeof(*op) ))) return FALSE;
458 op->style = params->CopyStyle;
459 op->src_root = strdupAtoW( params->SourceRootPath );
460 op->src_path = strdupAtoW( params->SourcePath );
461 op->src_file = strdupAtoW( params->SourceFilename );
462 op->src_descr = strdupAtoW( params->SourceDescription );
463 op->src_tag = strdupAtoW( params->SourceTagfile );
464 op->dst_path = strdupAtoW( params->TargetDirectory );
465 op->dst_file = strdupAtoW( params->TargetFilename );
467 /* some defaults */
468 if (!op->src_file) op->src_file = op->dst_file;
469 if (params->LayoutInf)
471 get_src_file_info( params->LayoutInf, op );
472 if (!op->dst_path) op->dst_path = get_destination_dir( params->LayoutInf, op->dst_file );
475 TRACE( "root=%s path=%s file=%s -> dir=%s file=%s descr=%s tag=%s\n",
476 debugstr_w(op->src_root), debugstr_w(op->src_path), debugstr_w(op->src_file),
477 debugstr_w(op->dst_path), debugstr_w(op->dst_file),
478 debugstr_w(op->src_descr), debugstr_w(op->src_tag) );
480 queue_file_op( &queue->copy_queue, op );
481 return TRUE;
485 /***********************************************************************
486 * SetupQueueCopyIndirectW (SETUPAPI.@)
488 BOOL WINAPI SetupQueueCopyIndirectW( PSP_FILE_COPY_PARAMS_W params )
490 struct file_queue *queue = params->QueueHandle;
491 struct file_op *op;
493 if (!(op = HeapAlloc( GetProcessHeap(), 0, sizeof(*op) ))) return FALSE;
494 op->style = params->CopyStyle;
495 op->src_root = strdupW( params->SourceRootPath );
496 op->src_path = strdupW( params->SourcePath );
497 op->src_file = strdupW( params->SourceFilename );
498 op->src_descr = strdupW( params->SourceDescription );
499 op->src_tag = strdupW( params->SourceTagfile );
500 op->dst_path = strdupW( params->TargetDirectory );
501 op->dst_file = strdupW( params->TargetFilename );
503 /* some defaults */
504 if (!op->src_file) op->src_file = op->dst_file;
505 if (params->LayoutInf)
507 get_src_file_info( params->LayoutInf, op );
508 if (!op->dst_path) op->dst_path = get_destination_dir( params->LayoutInf, op->dst_file );
511 TRACE( "root=%s path=%s file=%s -> dir=%s file=%s descr=%s tag=%s\n",
512 debugstr_w(op->src_root), debugstr_w(op->src_path), debugstr_w(op->src_file),
513 debugstr_w(op->dst_path), debugstr_w(op->dst_file),
514 debugstr_w(op->src_descr), debugstr_w(op->src_tag) );
516 queue_file_op( &queue->copy_queue, op );
517 return TRUE;
521 /***********************************************************************
522 * SetupQueueCopyA (SETUPAPI.@)
524 BOOL WINAPI SetupQueueCopyA( HSPFILEQ queue, PCSTR src_root, PCSTR src_path, PCSTR src_file,
525 PCSTR src_descr, PCSTR src_tag, PCSTR dst_dir, PCSTR dst_file,
526 DWORD style )
528 SP_FILE_COPY_PARAMS_A params;
530 params.cbSize = sizeof(params);
531 params.QueueHandle = queue;
532 params.SourceRootPath = src_root;
533 params.SourcePath = src_path;
534 params.SourceFilename = src_file;
535 params.SourceDescription = src_descr;
536 params.SourceTagfile = src_tag;
537 params.TargetDirectory = dst_dir;
538 params.TargetFilename = dst_file;
539 params.CopyStyle = style;
540 params.LayoutInf = 0;
541 params.SecurityDescriptor = NULL;
542 return SetupQueueCopyIndirectA( &params );
546 /***********************************************************************
547 * SetupQueueCopyW (SETUPAPI.@)
549 BOOL WINAPI SetupQueueCopyW( HSPFILEQ queue, PCWSTR src_root, PCWSTR src_path, PCWSTR src_file,
550 PCWSTR src_descr, PCWSTR src_tag, PCWSTR dst_dir, PCWSTR dst_file,
551 DWORD style )
553 SP_FILE_COPY_PARAMS_W params;
555 params.cbSize = sizeof(params);
556 params.QueueHandle = queue;
557 params.SourceRootPath = src_root;
558 params.SourcePath = src_path;
559 params.SourceFilename = src_file;
560 params.SourceDescription = src_descr;
561 params.SourceTagfile = src_tag;
562 params.TargetDirectory = dst_dir;
563 params.TargetFilename = dst_file;
564 params.CopyStyle = style;
565 params.LayoutInf = 0;
566 params.SecurityDescriptor = NULL;
567 return SetupQueueCopyIndirectW( &params );
571 /***********************************************************************
572 * SetupQueueDefaultCopyA (SETUPAPI.@)
574 BOOL WINAPI SetupQueueDefaultCopyA( HSPFILEQ queue, HINF hinf, PCSTR src_root, PCSTR src_file,
575 PCSTR dst_file, DWORD style )
577 SP_FILE_COPY_PARAMS_A params;
579 params.cbSize = sizeof(params);
580 params.QueueHandle = queue;
581 params.SourceRootPath = src_root;
582 params.SourcePath = NULL;
583 params.SourceFilename = src_file;
584 params.SourceDescription = NULL;
585 params.SourceTagfile = NULL;
586 params.TargetDirectory = NULL;
587 params.TargetFilename = dst_file;
588 params.CopyStyle = style;
589 params.LayoutInf = hinf;
590 params.SecurityDescriptor = NULL;
591 return SetupQueueCopyIndirectA( &params );
595 /***********************************************************************
596 * SetupQueueDefaultCopyW (SETUPAPI.@)
598 BOOL WINAPI SetupQueueDefaultCopyW( HSPFILEQ queue, HINF hinf, PCWSTR src_root, PCWSTR src_file,
599 PCWSTR dst_file, DWORD style )
601 SP_FILE_COPY_PARAMS_W params;
603 params.cbSize = sizeof(params);
604 params.QueueHandle = queue;
605 params.SourceRootPath = src_root;
606 params.SourcePath = NULL;
607 params.SourceFilename = src_file;
608 params.SourceDescription = NULL;
609 params.SourceTagfile = NULL;
610 params.TargetDirectory = NULL;
611 params.TargetFilename = dst_file;
612 params.CopyStyle = style;
613 params.LayoutInf = hinf;
614 params.SecurityDescriptor = NULL;
615 return SetupQueueCopyIndirectW( &params );
619 /***********************************************************************
620 * SetupQueueDeleteA (SETUPAPI.@)
622 BOOL WINAPI SetupQueueDeleteA( HSPFILEQ handle, PCSTR part1, PCSTR part2 )
624 struct file_queue *queue = handle;
625 struct file_op *op;
627 if (!(op = HeapAlloc( GetProcessHeap(), 0, sizeof(*op) ))) return FALSE;
628 op->style = 0;
629 op->src_root = NULL;
630 op->src_path = NULL;
631 op->src_file = NULL;
632 op->src_descr = NULL;
633 op->src_tag = NULL;
634 op->dst_path = strdupAtoW( part1 );
635 op->dst_file = strdupAtoW( part2 );
636 queue_file_op( &queue->delete_queue, op );
637 return TRUE;
641 /***********************************************************************
642 * SetupQueueDeleteW (SETUPAPI.@)
644 BOOL WINAPI SetupQueueDeleteW( HSPFILEQ handle, PCWSTR part1, PCWSTR part2 )
646 struct file_queue *queue = handle;
647 struct file_op *op;
649 if (!(op = HeapAlloc( GetProcessHeap(), 0, sizeof(*op) ))) return FALSE;
650 op->style = 0;
651 op->src_root = NULL;
652 op->src_path = NULL;
653 op->src_file = NULL;
654 op->src_descr = NULL;
655 op->src_tag = NULL;
656 op->dst_path = strdupW( part1 );
657 op->dst_file = strdupW( part2 );
658 queue_file_op( &queue->delete_queue, op );
659 return TRUE;
663 /***********************************************************************
664 * SetupQueueRenameA (SETUPAPI.@)
666 BOOL WINAPI SetupQueueRenameA( HSPFILEQ handle, PCSTR SourcePath, PCSTR SourceFilename,
667 PCSTR TargetPath, PCSTR TargetFilename )
669 struct file_queue *queue = handle;
670 struct file_op *op;
672 if (!(op = HeapAlloc( GetProcessHeap(), 0, sizeof(*op) ))) return FALSE;
673 op->style = 0;
674 op->src_root = NULL;
675 op->src_path = strdupAtoW( SourcePath );
676 op->src_file = strdupAtoW( SourceFilename );
677 op->src_descr = NULL;
678 op->src_tag = NULL;
679 op->dst_path = strdupAtoW( TargetPath );
680 op->dst_file = strdupAtoW( TargetFilename );
681 queue_file_op( &queue->rename_queue, op );
682 return TRUE;
686 /***********************************************************************
687 * SetupQueueRenameW (SETUPAPI.@)
689 BOOL WINAPI SetupQueueRenameW( HSPFILEQ handle, PCWSTR SourcePath, PCWSTR SourceFilename,
690 PCWSTR TargetPath, PCWSTR TargetFilename )
692 struct file_queue *queue = handle;
693 struct file_op *op;
695 if (!(op = HeapAlloc( GetProcessHeap(), 0, sizeof(*op) ))) return FALSE;
696 op->style = 0;
697 op->src_root = NULL;
698 op->src_path = strdupW( SourcePath );
699 op->src_file = strdupW( SourceFilename );
700 op->src_descr = NULL;
701 op->src_tag = NULL;
702 op->dst_path = strdupW( TargetPath );
703 op->dst_file = strdupW( TargetFilename );
704 queue_file_op( &queue->rename_queue, op );
705 return TRUE;
709 /***********************************************************************
710 * SetupQueueCopySectionA (SETUPAPI.@)
712 BOOL WINAPI SetupQueueCopySectionA( HSPFILEQ queue, PCSTR src_root, HINF hinf, HINF hlist,
713 PCSTR section, DWORD style )
715 UNICODE_STRING sectionW;
716 BOOL ret = FALSE;
718 if (!RtlCreateUnicodeStringFromAsciiz( &sectionW, section ))
720 SetLastError( ERROR_NOT_ENOUGH_MEMORY );
721 return FALSE;
723 if (!src_root)
724 ret = SetupQueueCopySectionW( queue, NULL, hinf, hlist, sectionW.Buffer, style );
725 else
727 UNICODE_STRING srcW;
728 if (RtlCreateUnicodeStringFromAsciiz( &srcW, src_root ))
730 ret = SetupQueueCopySectionW( queue, srcW.Buffer, hinf, hlist, sectionW.Buffer, style );
731 RtlFreeUnicodeString( &srcW );
733 else SetLastError( ERROR_NOT_ENOUGH_MEMORY );
735 RtlFreeUnicodeString( &sectionW );
736 return ret;
740 /***********************************************************************
741 * SetupQueueCopySectionW (SETUPAPI.@)
743 BOOL WINAPI SetupQueueCopySectionW( HSPFILEQ queue, PCWSTR src_root, HINF hinf, HINF hlist,
744 PCWSTR section, DWORD style )
746 SP_FILE_COPY_PARAMS_W params;
747 INFCONTEXT context;
748 WCHAR dest[MAX_PATH], src[MAX_PATH];
749 INT flags;
751 TRACE( "hinf=%p/%p section=%s root=%s\n",
752 hinf, hlist, debugstr_w(section), debugstr_w(src_root) );
754 params.cbSize = sizeof(params);
755 params.QueueHandle = queue;
756 params.SourceRootPath = src_root;
757 params.SourcePath = NULL;
758 params.SourceDescription = NULL;
759 params.SourceTagfile = NULL;
760 params.TargetFilename = dest;
761 params.CopyStyle = style;
762 params.LayoutInf = hinf;
763 params.SecurityDescriptor = NULL;
765 if (!hlist) hlist = hinf;
766 if (!hinf) hinf = hlist;
767 if (!SetupFindFirstLineW( hlist, section, NULL, &context )) return FALSE;
768 if (!(params.TargetDirectory = get_destination_dir( hinf, section ))) return FALSE;
771 if (!SetupGetStringFieldW( &context, 1, dest, sizeof(dest)/sizeof(WCHAR), NULL ))
772 return FALSE;
773 if (!SetupGetStringFieldW( &context, 2, src, sizeof(src)/sizeof(WCHAR), NULL )) *src = 0;
774 if (!SetupGetIntField( &context, 4, &flags )) flags = 0; /* FIXME */
776 params.SourceFilename = *src ? src : NULL;
777 if (!SetupQueueCopyIndirectW( &params )) return FALSE;
778 } while (SetupFindNextLine( &context, &context ));
779 return TRUE;
783 /***********************************************************************
784 * SetupQueueDeleteSectionA (SETUPAPI.@)
786 BOOL WINAPI SetupQueueDeleteSectionA( HSPFILEQ queue, HINF hinf, HINF hlist, PCSTR section )
788 UNICODE_STRING sectionW;
789 BOOL ret = FALSE;
791 if (RtlCreateUnicodeStringFromAsciiz( &sectionW, section ))
793 ret = SetupQueueDeleteSectionW( queue, hinf, hlist, sectionW.Buffer );
794 RtlFreeUnicodeString( &sectionW );
796 else SetLastError( ERROR_NOT_ENOUGH_MEMORY );
797 return ret;
801 /***********************************************************************
802 * SetupQueueDeleteSectionW (SETUPAPI.@)
804 BOOL WINAPI SetupQueueDeleteSectionW( HSPFILEQ queue, HINF hinf, HINF hlist, PCWSTR section )
806 INFCONTEXT context;
807 WCHAR *dest_dir;
808 WCHAR buffer[MAX_PATH];
809 BOOL ret = FALSE;
810 INT flags;
812 TRACE( "hinf=%p/%p section=%s\n", hinf, hlist, debugstr_w(section) );
814 if (!hlist) hlist = hinf;
815 if (!SetupFindFirstLineW( hlist, section, NULL, &context )) return FALSE;
816 if (!(dest_dir = get_destination_dir( hinf, section ))) return FALSE;
819 if (!SetupGetStringFieldW( &context, 1, buffer, sizeof(buffer)/sizeof(WCHAR), NULL ))
820 goto done;
821 if (!SetupGetIntField( &context, 4, &flags )) flags = 0;
822 if (!SetupQueueDeleteW( queue, dest_dir, buffer )) goto done;
823 } while (SetupFindNextLine( &context, &context ));
825 ret = TRUE;
826 done:
827 HeapFree( GetProcessHeap(), 0, dest_dir );
828 return ret;
832 /***********************************************************************
833 * SetupQueueRenameSectionA (SETUPAPI.@)
835 BOOL WINAPI SetupQueueRenameSectionA( HSPFILEQ queue, HINF hinf, HINF hlist, PCSTR section )
837 UNICODE_STRING sectionW;
838 BOOL ret = FALSE;
840 if (RtlCreateUnicodeStringFromAsciiz( &sectionW, section ))
842 ret = SetupQueueRenameSectionW( queue, hinf, hlist, sectionW.Buffer );
843 RtlFreeUnicodeString( &sectionW );
845 else SetLastError( ERROR_NOT_ENOUGH_MEMORY );
846 return ret;
850 /***********************************************************************
851 * SetupQueueRenameSectionW (SETUPAPI.@)
853 BOOL WINAPI SetupQueueRenameSectionW( HSPFILEQ queue, HINF hinf, HINF hlist, PCWSTR section )
855 INFCONTEXT context;
856 WCHAR *dest_dir;
857 WCHAR src[MAX_PATH], dst[MAX_PATH];
858 BOOL ret = FALSE;
860 TRACE( "hinf=%p/%p section=%s\n", hinf, hlist, debugstr_w(section) );
862 if (!hlist) hlist = hinf;
863 if (!SetupFindFirstLineW( hlist, section, NULL, &context )) return FALSE;
864 if (!(dest_dir = get_destination_dir( hinf, section ))) return FALSE;
867 if (!SetupGetStringFieldW( &context, 1, dst, sizeof(dst)/sizeof(WCHAR), NULL ))
868 goto done;
869 if (!SetupGetStringFieldW( &context, 2, src, sizeof(src)/sizeof(WCHAR), NULL ))
870 goto done;
871 if (!SetupQueueRenameW( queue, dest_dir, src, NULL, dst )) goto done;
872 } while (SetupFindNextLine( &context, &context ));
874 ret = TRUE;
875 done:
876 HeapFree( GetProcessHeap(), 0, dest_dir );
877 return ret;
881 /***********************************************************************
882 * SetupCommitFileQueueA (SETUPAPI.@)
884 BOOL WINAPI SetupCommitFileQueueA( HWND owner, HSPFILEQ queue, PSP_FILE_CALLBACK_A handler,
885 PVOID context )
887 struct callback_WtoA_context ctx;
889 ctx.orig_context = context;
890 ctx.orig_handler = handler;
891 return SetupCommitFileQueueW( owner, queue, QUEUE_callback_WtoA, &ctx );
895 /***********************************************************************
896 * create_full_pathW
898 * Recursively create all directories in the path.
900 static BOOL create_full_pathW(const WCHAR *path)
902 BOOL ret = TRUE;
903 int len;
904 WCHAR *new_path;
906 new_path = HeapAlloc(GetProcessHeap(), 0, (strlenW(path) + 1) * sizeof(WCHAR));
907 strcpyW(new_path, path);
909 while((len = strlenW(new_path)) && new_path[len - 1] == '\\')
910 new_path[len - 1] = 0;
912 while(!CreateDirectoryW(new_path, NULL))
914 WCHAR *slash;
915 DWORD last_error = GetLastError();
917 if(last_error == ERROR_ALREADY_EXISTS)
918 break;
920 if(last_error != ERROR_PATH_NOT_FOUND)
922 ret = FALSE;
923 break;
926 if(!(slash = strrchrW(new_path, '\\')))
928 ret = FALSE;
929 break;
932 len = slash - new_path;
933 new_path[len] = 0;
934 if(!create_full_pathW(new_path))
936 ret = FALSE;
937 break;
939 new_path[len] = '\\';
942 HeapFree(GetProcessHeap(), 0, new_path);
943 return ret;
946 static BOOL do_file_copyW( LPCWSTR source, LPCWSTR target, DWORD style,
947 PSP_FILE_CALLBACK_W handler, PVOID context )
949 BOOL rc = FALSE;
950 BOOL docopy = TRUE;
952 TRACE("copy %s to %s style 0x%x\n",debugstr_w(source),debugstr_w(target),style);
954 /* before copy processing */
955 if (style & SP_COPY_REPLACEONLY)
957 if (GetFileAttributesW(target) == INVALID_FILE_ATTRIBUTES)
958 docopy = FALSE;
960 if (style & (SP_COPY_NEWER_OR_SAME | SP_COPY_NEWER_ONLY | SP_COPY_FORCE_NEWER))
962 DWORD VersionSizeSource=0;
963 DWORD VersionSizeTarget=0;
964 DWORD zero=0;
967 * This is sort of an interesting workaround. You see, calling
968 * GetVersionInfoSize on a builtin dll loads that dll into memory
969 * and we do not properly unload builtin dlls.. so we effectively
970 * lock into memory all the targets we are replacing. This leads
971 * to problems when we try to register the replaced dlls.
973 * So I will test for the existence of the files first so that
974 * we just basically unconditionally replace the builtin versions.
976 if ((GetFileAttributesW(target) != INVALID_FILE_ATTRIBUTES) &&
977 (GetFileAttributesW(source) != INVALID_FILE_ATTRIBUTES))
979 VersionSizeSource = GetFileVersionInfoSizeW(source,&zero);
980 VersionSizeTarget = GetFileVersionInfoSizeW(target,&zero);
983 TRACE("SizeTarget %i ... SizeSource %i\n",VersionSizeTarget,
984 VersionSizeSource);
986 if (VersionSizeSource && VersionSizeTarget)
988 LPVOID VersionSource;
989 LPVOID VersionTarget;
990 VS_FIXEDFILEINFO *TargetInfo;
991 VS_FIXEDFILEINFO *SourceInfo;
992 UINT length;
993 WCHAR SubBlock[2]={'\\',0};
994 DWORD ret;
996 VersionSource = HeapAlloc(GetProcessHeap(),0,VersionSizeSource);
997 VersionTarget = HeapAlloc(GetProcessHeap(),0,VersionSizeTarget);
999 ret = GetFileVersionInfoW(source,0,VersionSizeSource,VersionSource);
1000 if (ret)
1001 ret = GetFileVersionInfoW(target, 0, VersionSizeTarget,
1002 VersionTarget);
1004 if (ret)
1006 ret = VerQueryValueW(VersionSource, SubBlock,
1007 (LPVOID*)&SourceInfo, &length);
1008 if (ret)
1009 ret = VerQueryValueW(VersionTarget, SubBlock,
1010 (LPVOID*)&TargetInfo, &length);
1012 if (ret)
1014 FILEPATHS_W filepaths;
1016 TRACE("Versions: Source %i.%i target %i.%i\n",
1017 SourceInfo->dwFileVersionMS, SourceInfo->dwFileVersionLS,
1018 TargetInfo->dwFileVersionMS, TargetInfo->dwFileVersionLS);
1020 /* used in case of notification */
1021 filepaths.Target = target;
1022 filepaths.Source = source;
1023 filepaths.Win32Error = 0;
1024 filepaths.Flags = 0;
1026 if (TargetInfo->dwFileVersionMS > SourceInfo->dwFileVersionMS)
1028 if (handler)
1029 docopy = handler (context, SPFILENOTIFY_TARGETNEWER, (UINT_PTR)&filepaths, 0);
1030 else
1031 docopy = FALSE;
1033 else if ((TargetInfo->dwFileVersionMS == SourceInfo->dwFileVersionMS)
1034 && (TargetInfo->dwFileVersionLS > SourceInfo->dwFileVersionLS))
1036 if (handler)
1037 docopy = handler (context, SPFILENOTIFY_TARGETNEWER, (UINT_PTR)&filepaths, 0);
1038 else
1039 docopy = FALSE;
1041 else if ((style & SP_COPY_NEWER_ONLY) &&
1042 (TargetInfo->dwFileVersionMS ==
1043 SourceInfo->dwFileVersionMS)
1044 &&(TargetInfo->dwFileVersionLS ==
1045 SourceInfo->dwFileVersionLS))
1047 if (handler)
1048 docopy = handler (context, SPFILENOTIFY_TARGETNEWER, (UINT_PTR)&filepaths, 0);
1049 else
1050 docopy = FALSE;
1054 HeapFree(GetProcessHeap(),0,VersionSource);
1055 HeapFree(GetProcessHeap(),0,VersionTarget);
1058 if (style & (SP_COPY_NOOVERWRITE | SP_COPY_FORCE_NOOVERWRITE))
1060 if (GetFileAttributesW(target) != INVALID_FILE_ATTRIBUTES)
1062 FIXME("Notify user target file exists\n");
1063 docopy = FALSE;
1066 if (style & (SP_COPY_NODECOMP | SP_COPY_LANGUAGEAWARE | SP_COPY_FORCE_IN_USE |
1067 SP_COPY_IN_USE_NEEDS_REBOOT | SP_COPY_NOSKIP | SP_COPY_WARNIFSKIP))
1069 ERR("Unsupported style(s) 0x%x\n",style);
1072 if (docopy)
1074 rc = CopyFileW(source,target,FALSE);
1075 TRACE("Did copy... rc was %i\n",rc);
1078 /* after copy processing */
1079 if (style & SP_COPY_DELETESOURCE)
1081 if (rc)
1082 DeleteFileW(source);
1085 return rc;
1088 /***********************************************************************
1089 * SetupCommitFileQueueW (SETUPAPI.@)
1091 BOOL WINAPI SetupCommitFileQueueW( HWND owner, HSPFILEQ handle, PSP_FILE_CALLBACK_W handler,
1092 PVOID context )
1094 struct file_queue *queue = handle;
1095 struct file_op *op;
1096 BOOL result = FALSE;
1097 FILEPATHS_W paths;
1098 UINT op_result;
1100 paths.Source = paths.Target = NULL;
1102 if (!queue->copy_queue.count && !queue->delete_queue.count && !queue->rename_queue.count)
1103 return TRUE; /* nothing to do */
1105 if (!handler( context, SPFILENOTIFY_STARTQUEUE, (UINT_PTR)owner, 0 )) return FALSE;
1107 /* perform deletes */
1109 if (queue->delete_queue.count)
1111 if (!(handler( context, SPFILENOTIFY_STARTSUBQUEUE, FILEOP_DELETE,
1112 queue->delete_queue.count ))) goto done;
1113 for (op = queue->delete_queue.head; op; op = op->next)
1115 build_filepathsW( op, &paths );
1116 op_result = handler( context, SPFILENOTIFY_STARTDELETE, (UINT_PTR)&paths, FILEOP_DELETE);
1117 if (op_result == FILEOP_ABORT) goto done;
1118 while (op_result == FILEOP_DOIT)
1120 TRACE( "deleting file %s\n", debugstr_w(paths.Target) );
1121 if (DeleteFileW( paths.Target )) break; /* success */
1122 paths.Win32Error = GetLastError();
1123 op_result = handler( context, SPFILENOTIFY_DELETEERROR, (UINT_PTR)&paths, 0 );
1124 if (op_result == FILEOP_ABORT) goto done;
1126 handler( context, SPFILENOTIFY_ENDDELETE, (UINT_PTR)&paths, 0 );
1128 handler( context, SPFILENOTIFY_ENDSUBQUEUE, FILEOP_DELETE, 0 );
1131 /* perform renames */
1133 if (queue->rename_queue.count)
1135 if (!(handler( context, SPFILENOTIFY_STARTSUBQUEUE, FILEOP_RENAME,
1136 queue->rename_queue.count ))) goto done;
1137 for (op = queue->rename_queue.head; op; op = op->next)
1139 build_filepathsW( op, &paths );
1140 op_result = handler( context, SPFILENOTIFY_STARTRENAME, (UINT_PTR)&paths, FILEOP_RENAME);
1141 if (op_result == FILEOP_ABORT) goto done;
1142 while (op_result == FILEOP_DOIT)
1144 TRACE( "renaming file %s -> %s\n",
1145 debugstr_w(paths.Source), debugstr_w(paths.Target) );
1146 if (MoveFileW( paths.Source, paths.Target )) break; /* success */
1147 paths.Win32Error = GetLastError();
1148 op_result = handler( context, SPFILENOTIFY_RENAMEERROR, (UINT_PTR)&paths, 0 );
1149 if (op_result == FILEOP_ABORT) goto done;
1151 handler( context, SPFILENOTIFY_ENDRENAME, (UINT_PTR)&paths, 0 );
1153 handler( context, SPFILENOTIFY_ENDSUBQUEUE, FILEOP_RENAME, 0 );
1156 /* perform copies */
1158 if (queue->copy_queue.count)
1160 if (!(handler( context, SPFILENOTIFY_STARTSUBQUEUE, FILEOP_COPY,
1161 queue->copy_queue.count ))) goto done;
1162 for (op = queue->copy_queue.head; op; op = op->next)
1164 WCHAR newpath[MAX_PATH];
1166 build_filepathsW( op, &paths );
1167 op_result = handler( context, SPFILENOTIFY_STARTCOPY, (UINT_PTR)&paths, FILEOP_COPY );
1168 if (op_result == FILEOP_ABORT) goto done;
1169 if (op_result == FILEOP_NEWPATH) op_result = FILEOP_DOIT;
1170 while (op_result == FILEOP_DOIT || op_result == FILEOP_NEWPATH)
1172 TRACE( "copying file %s -> %s\n",
1173 debugstr_w( op_result == FILEOP_NEWPATH ? newpath : paths.Source ),
1174 debugstr_w(paths.Target) );
1175 if (op->dst_path)
1177 if (!create_full_pathW( op->dst_path ))
1179 paths.Win32Error = GetLastError();
1180 op_result = handler( context, SPFILENOTIFY_COPYERROR,
1181 (UINT_PTR)&paths, (UINT_PTR)newpath );
1182 if (op_result == FILEOP_ABORT) goto done;
1185 if (do_file_copyW( op_result == FILEOP_NEWPATH ? newpath : paths.Source,
1186 paths.Target, op->style, handler, context )) break; /* success */
1187 /* try to extract it from the cabinet file */
1188 if (op->src_tag)
1190 if (extract_cabinet_file( op->src_tag, op->src_root,
1191 paths.Source, paths.Target )) break;
1193 paths.Win32Error = GetLastError();
1194 op_result = handler( context, SPFILENOTIFY_COPYERROR,
1195 (UINT_PTR)&paths, (UINT_PTR)newpath );
1196 if (op_result == FILEOP_ABORT) goto done;
1198 handler( context, SPFILENOTIFY_ENDCOPY, (UINT_PTR)&paths, 0 );
1200 handler( context, SPFILENOTIFY_ENDSUBQUEUE, FILEOP_COPY, 0 );
1204 result = TRUE;
1206 done:
1207 handler( context, SPFILENOTIFY_ENDQUEUE, result, 0 );
1208 HeapFree( GetProcessHeap(), 0, (void *)paths.Source );
1209 HeapFree( GetProcessHeap(), 0, (void *)paths.Target );
1210 return result;
1214 /***********************************************************************
1215 * SetupScanFileQueueA (SETUPAPI.@)
1217 BOOL WINAPI SetupScanFileQueueA( HSPFILEQ handle, DWORD flags, HWND window,
1218 PSP_FILE_CALLBACK_A handler, PVOID context, PDWORD result )
1220 struct callback_WtoA_context ctx;
1222 TRACE("%p %x %p %p %p %p\n", handle, flags, window, handler, context, result);
1224 ctx.orig_context = context;
1225 ctx.orig_handler = handler;
1227 return SetupScanFileQueueW( handle, flags, window, QUEUE_callback_WtoA, &ctx, result );
1231 /***********************************************************************
1232 * SetupScanFileQueueW (SETUPAPI.@)
1234 BOOL WINAPI SetupScanFileQueueW( HSPFILEQ handle, DWORD flags, HWND window,
1235 PSP_FILE_CALLBACK_W handler, PVOID context, PDWORD result )
1237 struct file_queue *queue = handle;
1238 struct file_op *op;
1239 FILEPATHS_W paths;
1240 UINT notification = 0;
1241 BOOL ret = FALSE;
1243 TRACE("%p %x %p %p %p %p\n", handle, flags, window, handler, context, result);
1245 if (!queue->copy_queue.count) return TRUE;
1247 if (flags & SPQ_SCAN_USE_CALLBACK) notification = SPFILENOTIFY_QUEUESCAN;
1248 else if (flags & SPQ_SCAN_USE_CALLBACKEX) notification = SPFILENOTIFY_QUEUESCAN_EX;
1250 if (flags & ~(SPQ_SCAN_USE_CALLBACK | SPQ_SCAN_USE_CALLBACKEX))
1252 FIXME("flags %x not fully implemented\n", flags);
1255 paths.Source = paths.Target = NULL;
1257 for (op = queue->copy_queue.head; op; op = op->next)
1259 build_filepathsW( op, &paths );
1260 switch (notification)
1262 case SPFILENOTIFY_QUEUESCAN:
1263 /* FIXME: handle delay flag */
1264 if (handler( context, notification, (UINT_PTR)paths.Target, 0 )) goto done;
1265 break;
1266 case SPFILENOTIFY_QUEUESCAN_EX:
1267 if (handler( context, notification, (UINT_PTR)&paths, 0 )) goto done;
1268 break;
1269 default:
1270 ret = TRUE; goto done;
1274 ret = TRUE;
1276 done:
1277 if (result) *result = 0;
1278 HeapFree( GetProcessHeap(), 0, (void *)paths.Source );
1279 HeapFree( GetProcessHeap(), 0, (void *)paths.Target );
1280 return ret;
1284 /***********************************************************************
1285 * SetupGetFileQueueCount (SETUPAPI.@)
1287 BOOL WINAPI SetupGetFileQueueCount( HSPFILEQ handle, UINT op, PUINT result )
1289 struct file_queue *queue = handle;
1291 switch(op)
1293 case FILEOP_COPY:
1294 *result = queue->copy_queue.count;
1295 return TRUE;
1296 case FILEOP_RENAME:
1297 *result = queue->rename_queue.count;
1298 return TRUE;
1299 case FILEOP_DELETE:
1300 *result = queue->delete_queue.count;
1301 return TRUE;
1303 return FALSE;
1307 /***********************************************************************
1308 * SetupGetFileQueueFlags (SETUPAPI.@)
1310 BOOL WINAPI SetupGetFileQueueFlags( HSPFILEQ handle, PDWORD flags )
1312 struct file_queue *queue = handle;
1313 *flags = queue->flags;
1314 return TRUE;
1318 /***********************************************************************
1319 * SetupSetFileQueueFlags (SETUPAPI.@)
1321 BOOL WINAPI SetupSetFileQueueFlags( HSPFILEQ handle, DWORD mask, DWORD flags )
1323 struct file_queue *queue = handle;
1324 queue->flags = (queue->flags & ~mask) | flags;
1325 return TRUE;
1329 /***********************************************************************
1330 * SetupSetFileQueueAlternatePlatformA (SETUPAPI.@)
1332 BOOL WINAPI SetupSetFileQueueAlternatePlatformA(HSPFILEQ handle, PSP_ALTPLATFORM_INFO platform, PCSTR catalogfile)
1334 FIXME("(%p, %p, %s) stub!\n", handle, platform, debugstr_a(catalogfile));
1335 return FALSE;
1339 /***********************************************************************
1340 * SetupSetFileQueueAlternatePlatformW (SETUPAPI.@)
1342 BOOL WINAPI SetupSetFileQueueAlternatePlatformW(HSPFILEQ handle, PSP_ALTPLATFORM_INFO platform, PCWSTR catalogfile)
1344 FIXME("(%p, %p, %s) stub!\n", handle, platform, debugstr_w(catalogfile));
1345 return FALSE;
1349 /***********************************************************************
1350 * SetupInitDefaultQueueCallback (SETUPAPI.@)
1352 PVOID WINAPI SetupInitDefaultQueueCallback( HWND owner )
1354 return SetupInitDefaultQueueCallbackEx( owner, 0, 0, 0, NULL );
1358 /***********************************************************************
1359 * SetupInitDefaultQueueCallbackEx (SETUPAPI.@)
1361 PVOID WINAPI SetupInitDefaultQueueCallbackEx( HWND owner, HWND progress, UINT msg,
1362 DWORD reserved1, PVOID reserved2 )
1364 struct default_callback_context *context;
1366 if ((context = HeapAlloc( GetProcessHeap(), 0, sizeof(*context) )))
1368 context->owner = owner;
1369 context->progress = progress;
1370 context->message = msg;
1372 return context;
1376 /***********************************************************************
1377 * SetupTermDefaultQueueCallback (SETUPAPI.@)
1379 void WINAPI SetupTermDefaultQueueCallback( PVOID context )
1381 HeapFree( GetProcessHeap(), 0, context );
1385 /***********************************************************************
1386 * SetupDefaultQueueCallbackA (SETUPAPI.@)
1388 UINT WINAPI SetupDefaultQueueCallbackA( PVOID context, UINT notification,
1389 UINT_PTR param1, UINT_PTR param2 )
1391 FILEPATHS_A *paths = (FILEPATHS_A *)param1;
1392 struct default_callback_context *ctx = (struct default_callback_context *)context;
1394 switch(notification)
1396 case SPFILENOTIFY_STARTQUEUE:
1397 TRACE( "start queue\n" );
1398 return TRUE;
1399 case SPFILENOTIFY_ENDQUEUE:
1400 TRACE( "end queue\n" );
1401 return 0;
1402 case SPFILENOTIFY_STARTSUBQUEUE:
1403 TRACE( "start subqueue %ld count %ld\n", param1, param2 );
1404 return TRUE;
1405 case SPFILENOTIFY_ENDSUBQUEUE:
1406 TRACE( "end subqueue %ld\n", param1 );
1407 return 0;
1408 case SPFILENOTIFY_STARTDELETE:
1409 TRACE( "start delete %s\n", debugstr_a(paths->Target) );
1410 return FILEOP_DOIT;
1411 case SPFILENOTIFY_ENDDELETE:
1412 TRACE( "end delete %s\n", debugstr_a(paths->Target) );
1413 return 0;
1414 case SPFILENOTIFY_DELETEERROR:
1415 /*Windows Ignores attempts to delete files / folders which do not exist*/
1416 if ((paths->Win32Error != ERROR_FILE_NOT_FOUND) && (paths->Win32Error != ERROR_PATH_NOT_FOUND))
1417 SetupDeleteErrorA(ctx->owner, NULL, paths->Target, paths->Win32Error, 0);
1418 return FILEOP_SKIP;
1419 case SPFILENOTIFY_STARTRENAME:
1420 TRACE( "start rename %s -> %s\n", debugstr_a(paths->Source), debugstr_a(paths->Target) );
1421 return FILEOP_DOIT;
1422 case SPFILENOTIFY_ENDRENAME:
1423 TRACE( "end rename %s -> %s\n", debugstr_a(paths->Source), debugstr_a(paths->Target) );
1424 return 0;
1425 case SPFILENOTIFY_RENAMEERROR:
1426 SetupRenameErrorA(ctx->owner, NULL, paths->Source, paths->Target, paths->Win32Error, 0);
1427 return FILEOP_SKIP;
1428 case SPFILENOTIFY_STARTCOPY:
1429 TRACE( "start copy %s -> %s\n", debugstr_a(paths->Source), debugstr_a(paths->Target) );
1430 return FILEOP_DOIT;
1431 case SPFILENOTIFY_ENDCOPY:
1432 TRACE( "end copy %s -> %s\n", debugstr_a(paths->Source), debugstr_a(paths->Target) );
1433 return 0;
1434 case SPFILENOTIFY_COPYERROR:
1435 ERR( "copy error %d %s -> %s\n", paths->Win32Error,
1436 debugstr_a(paths->Source), debugstr_a(paths->Target) );
1437 return FILEOP_SKIP;
1438 case SPFILENOTIFY_NEEDMEDIA:
1439 TRACE( "need media\n" );
1440 return FILEOP_SKIP;
1441 default:
1442 FIXME( "notification %d params %lx,%lx\n", notification, param1, param2 );
1443 break;
1445 return 0;
1449 /***********************************************************************
1450 * SetupDefaultQueueCallbackW (SETUPAPI.@)
1452 UINT WINAPI SetupDefaultQueueCallbackW( PVOID context, UINT notification,
1453 UINT_PTR param1, UINT_PTR param2 )
1455 FILEPATHS_W *paths = (FILEPATHS_W *)param1;
1456 struct default_callback_context *ctx = (struct default_callback_context *)context;
1458 switch(notification)
1460 case SPFILENOTIFY_STARTQUEUE:
1461 TRACE( "start queue\n" );
1462 return TRUE;
1463 case SPFILENOTIFY_ENDQUEUE:
1464 TRACE( "end queue\n" );
1465 return 0;
1466 case SPFILENOTIFY_STARTSUBQUEUE:
1467 TRACE( "start subqueue %ld count %ld\n", param1, param2 );
1468 return TRUE;
1469 case SPFILENOTIFY_ENDSUBQUEUE:
1470 TRACE( "end subqueue %ld\n", param1 );
1471 return 0;
1472 case SPFILENOTIFY_STARTDELETE:
1473 TRACE( "start delete %s\n", debugstr_w(paths->Target) );
1474 return FILEOP_DOIT;
1475 case SPFILENOTIFY_ENDDELETE:
1476 TRACE( "end delete %s\n", debugstr_w(paths->Target) );
1477 return 0;
1478 case SPFILENOTIFY_DELETEERROR:
1479 /*Windows Ignores attempts to delete files / folders which do not exist*/
1480 if ((paths->Win32Error != ERROR_FILE_NOT_FOUND) && (paths->Win32Error != ERROR_PATH_NOT_FOUND))
1481 SetupDeleteErrorW(ctx->owner, NULL, paths->Target, paths->Win32Error, 0);
1482 return FILEOP_SKIP;
1483 case SPFILENOTIFY_STARTRENAME:
1484 SetupRenameErrorW(ctx->owner, NULL, paths->Source, paths->Target, paths->Win32Error, 0);
1485 return FILEOP_DOIT;
1486 case SPFILENOTIFY_ENDRENAME:
1487 TRACE( "end rename %s -> %s\n", debugstr_w(paths->Source), debugstr_w(paths->Target) );
1488 return 0;
1489 case SPFILENOTIFY_RENAMEERROR:
1490 ERR( "rename error %d %s -> %s\n", paths->Win32Error,
1491 debugstr_w(paths->Source), debugstr_w(paths->Target) );
1492 return FILEOP_SKIP;
1493 case SPFILENOTIFY_STARTCOPY:
1494 TRACE( "start copy %s -> %s\n", debugstr_w(paths->Source), debugstr_w(paths->Target) );
1495 return FILEOP_DOIT;
1496 case SPFILENOTIFY_ENDCOPY:
1497 TRACE( "end copy %s -> %s\n", debugstr_w(paths->Source), debugstr_w(paths->Target) );
1498 return 0;
1499 case SPFILENOTIFY_COPYERROR:
1500 ERR( "copy error %d %s -> %s\n", paths->Win32Error,
1501 debugstr_w(paths->Source), debugstr_w(paths->Target) );
1502 return FILEOP_SKIP;
1503 case SPFILENOTIFY_NEEDMEDIA:
1504 TRACE( "need media\n" );
1505 return FILEOP_SKIP;
1506 default:
1507 FIXME( "notification %d params %lx,%lx\n", notification, param1, param2 );
1508 break;
1510 return 0;
1513 /***********************************************************************
1514 * SetupDeleteErrorA (SETUPAPI.@)
1517 UINT WINAPI SetupDeleteErrorA( HWND parent, PCSTR dialogTitle, PCSTR file,
1518 UINT w32error, DWORD style)
1520 FIXME( "stub: (Error Number %d when attempting to delete %s)\n",
1521 w32error, debugstr_a(file) );
1522 return DPROMPT_SKIPFILE;
1525 /***********************************************************************
1526 * SetupDeleteErrorW (SETUPAPI.@)
1529 UINT WINAPI SetupDeleteErrorW( HWND parent, PCWSTR dialogTitle, PCWSTR file,
1530 UINT w32error, DWORD style)
1532 FIXME( "stub: (Error Number %d when attempting to delete %s)\n",
1533 w32error, debugstr_w(file) );
1534 return DPROMPT_SKIPFILE;
1537 /***********************************************************************
1538 * SetupRenameErrorA (SETUPAPI.@)
1541 UINT WINAPI SetupRenameErrorA( HWND parent, PCSTR dialogTitle, PCSTR source,
1542 PCSTR target, UINT w32error, DWORD style)
1544 FIXME( "stub: (Error Number %d when attempting to rename %s to %s)\n",
1545 w32error, debugstr_a(source), debugstr_a(target));
1546 return DPROMPT_SKIPFILE;
1549 /***********************************************************************
1550 * SetupRenameErrorW (SETUPAPI.@)
1553 UINT WINAPI SetupRenameErrorW( HWND parent, PCWSTR dialogTitle, PCWSTR source,
1554 PCWSTR target, UINT w32error, DWORD style)
1556 FIXME( "stub: (Error Number %d when attempting to rename %s to %s)\n",
1557 w32error, debugstr_w(source), debugstr_w(target));
1558 return DPROMPT_SKIPFILE;
1562 /***********************************************************************
1563 * SetupCopyErrorA (SETUPAPI.@)
1566 UINT WINAPI SetupCopyErrorA( HWND parent, PCSTR dialogTitle, PCSTR diskname,
1567 PCSTR sourcepath, PCSTR sourcefile, PCSTR targetpath,
1568 UINT w32error, DWORD style, PSTR pathbuffer,
1569 DWORD buffersize, PDWORD requiredsize)
1571 FIXME( "stub: (Error Number %d when attempting to copy file %s from %s to %s)\n",
1572 w32error, debugstr_a(sourcefile), debugstr_a(sourcepath) ,debugstr_a(targetpath));
1573 return DPROMPT_SKIPFILE;
1576 /***********************************************************************
1577 * SetupCopyErrorW (SETUPAPI.@)
1580 UINT WINAPI SetupCopyErrorW( HWND parent, PCWSTR dialogTitle, PCWSTR diskname,
1581 PCWSTR sourcepath, PCWSTR sourcefile, PCWSTR targetpath,
1582 UINT w32error, DWORD style, PWSTR pathbuffer,
1583 DWORD buffersize, PDWORD requiredsize)
1585 FIXME( "stub: (Error Number %d when attempting to copy file %s from %s to %s)\n",
1586 w32error, debugstr_w(sourcefile), debugstr_w(sourcepath) ,debugstr_w(targetpath));
1587 return DPROMPT_SKIPFILE;
1590 /***********************************************************************
1591 * pSetupGetQueueFlags (SETUPAPI.@)
1593 DWORD WINAPI pSetupGetQueueFlags( HSPFILEQ handle )
1595 struct file_queue *queue = handle;
1596 return queue->flags;
1599 /***********************************************************************
1600 * pSetupSetQueueFlags (SETUPAPI.@)
1602 BOOL WINAPI pSetupSetQueueFlags( HSPFILEQ handle, DWORD flags )
1604 struct file_queue *queue = handle;
1605 queue->flags = flags;
1606 return TRUE;