06d3184cc6fbbfc262bc7f1194960716e4e5b3a0
[reactos.git] / reactos / lib / setupapi / queue.c
1 /*
2 * Setupapi file queue routines
3 *
4 * Copyright 2002 Alexandre Julliard for CodeWeavers
5 *
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.
10 *
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.
15 *
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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
19 */
20
21 #include "setupapi_private.h"
22
23 WINE_DEFAULT_DEBUG_CHANNEL(setupapi);
24
25 /* context structure for the default queue callback */
26 struct default_callback_context
27 {
28 HWND owner;
29 HWND progress;
30 UINT message;
31 };
32
33 struct file_op
34 {
35 struct file_op *next;
36 UINT style;
37 WCHAR *src_root;
38 WCHAR *src_path;
39 WCHAR *src_file;
40 WCHAR *src_descr;
41 WCHAR *src_tag;
42 WCHAR *dst_path;
43 WCHAR *dst_file;
44 };
45
46 struct file_op_queue
47 {
48 struct file_op *head;
49 struct file_op *tail;
50 unsigned int count;
51 };
52
53 struct file_queue
54 {
55 struct file_op_queue copy_queue;
56 struct file_op_queue delete_queue;
57 struct file_op_queue rename_queue;
58 DWORD flags;
59 };
60
61
62 inline static WCHAR *strdupW( const WCHAR *str )
63 {
64 WCHAR *ret = NULL;
65 if (str)
66 {
67 int len = (strlenW(str) + 1) * sizeof(WCHAR);
68 if ((ret = HeapAlloc( GetProcessHeap(), 0, len ))) memcpy( ret, str, len );
69 }
70 return ret;
71 }
72
73
74 inline static WCHAR *strdupAtoW( const char *str )
75 {
76 WCHAR *ret = NULL;
77 if (str)
78 {
79 DWORD len = MultiByteToWideChar( CP_ACP, 0, str, -1, NULL, 0 );
80 if ((ret = HeapAlloc( GetProcessHeap(), 0, len * sizeof(WCHAR) )))
81 MultiByteToWideChar( CP_ACP, 0, str, -1, ret, len );
82 }
83 return ret;
84 }
85
86 inline static char *strdupWtoA( const WCHAR *str )
87 {
88 char *ret = NULL;
89 if (str)
90 {
91 DWORD len = WideCharToMultiByte( CP_ACP, 0, str, -1, NULL, 0, NULL, NULL );
92 if ((ret = HeapAlloc( GetProcessHeap(), 0, len )))
93 WideCharToMultiByte( CP_ACP, 0, str, -1, ret, len, NULL, NULL );
94 }
95 return ret;
96 }
97
98 /* append a file operation to a queue */
99 inline static void queue_file_op( struct file_op_queue *queue, struct file_op *op )
100 {
101 op->next = NULL;
102 if (queue->tail) queue->tail->next = op;
103 else queue->head = op;
104 queue->tail = op;
105 queue->count++;
106 }
107
108 /* free all the file operations on a given queue */
109 static void free_file_op_queue( struct file_op_queue *queue )
110 {
111 struct file_op *t, *op = queue->head;
112
113 while( op )
114 {
115 HeapFree( GetProcessHeap(), 0, op->src_root );
116 HeapFree( GetProcessHeap(), 0, op->src_path );
117 HeapFree( GetProcessHeap(), 0, op->src_file );
118 HeapFree( GetProcessHeap(), 0, op->src_descr );
119 HeapFree( GetProcessHeap(), 0, op->src_tag );
120 HeapFree( GetProcessHeap(), 0, op->dst_path );
121 if (op->dst_file != op->src_file) HeapFree( GetProcessHeap(), 0, op->dst_file );
122 t = op;
123 op = op->next;
124 HeapFree( GetProcessHeap(), 0, t );
125 }
126 }
127
128 /* concat 3 strings to make a path, handling separators correctly */
129 static void concat_W( WCHAR *buffer, const WCHAR *src1, const WCHAR *src2, const WCHAR *src3 )
130 {
131 *buffer = 0;
132 if (src1 && *src1)
133 {
134 strcpyW( buffer, src1 );
135 buffer += strlenW(buffer );
136 if (buffer[-1] != '\\') *buffer++ = '\\';
137 if (src2) while (*src2 == '\\') src2++;
138 }
139
140 if (src2)
141 {
142 strcpyW( buffer, src2 );
143 buffer += strlenW(buffer );
144 if (buffer[-1] != '\\') *buffer++ = '\\';
145 if (src3) while (*src3 == '\\') src3++;
146 }
147 if (src3)
148 {
149 strcpyW( buffer, src3 );
150 buffer += strlenW(buffer );
151 }
152 }
153
154
155 /***********************************************************************
156 * build_filepathsW
157 *
158 * Build a FILEPATHS_W structure for a given file operation.
159 */
160 static BOOL build_filepathsW( const struct file_op *op, FILEPATHS_W *paths )
161 {
162 unsigned int src_len = 1, dst_len = 1;
163 WCHAR *source = (PWSTR)paths->Source, *target = (PWSTR)paths->Target;
164
165 if (op->src_root) src_len += strlenW(op->src_root) + 1;
166 if (op->src_path) src_len += strlenW(op->src_path) + 1;
167 if (op->src_file) src_len += strlenW(op->src_file) + 1;
168 if (op->dst_path) dst_len += strlenW(op->dst_path) + 1;
169 if (op->dst_file) dst_len += strlenW(op->dst_file) + 1;
170 src_len *= sizeof(WCHAR);
171 dst_len *= sizeof(WCHAR);
172
173 if (!source || HeapSize( GetProcessHeap(), 0, source ) < src_len )
174 {
175 HeapFree( GetProcessHeap(), 0, source );
176 paths->Source = source = HeapAlloc( GetProcessHeap(), 0, src_len );
177 }
178 if (!target || HeapSize( GetProcessHeap(), 0, target ) < dst_len )
179 {
180 HeapFree( GetProcessHeap(), 0, target );
181 paths->Target = target = HeapAlloc( GetProcessHeap(), 0, dst_len );
182 }
183 if (!source || !target) return FALSE;
184 concat_W( source, op->src_root, op->src_path, op->src_file );
185 concat_W( target, NULL, op->dst_path, op->dst_file );
186 paths->Win32Error = 0;
187 paths->Flags = 0;
188 return TRUE;
189 }
190
191
192 /***********************************************************************
193 * QUEUE_callback_WtoA
194 *
195 * Map a file callback parameters from W to A and call the A callback.
196 */
197 UINT CALLBACK QUEUE_callback_WtoA( void *context, UINT notification,
198 UINT_PTR param1, UINT_PTR param2 )
199 {
200 struct callback_WtoA_context *callback_ctx = context;
201 char buffer[MAX_PATH];
202 UINT ret;
203 UINT_PTR old_param2 = param2;
204
205 switch(notification)
206 {
207 case SPFILENOTIFY_COPYERROR:
208 param2 = (UINT_PTR)&buffer;
209 /* fall through */
210 case SPFILENOTIFY_STARTDELETE:
211 case SPFILENOTIFY_ENDDELETE:
212 case SPFILENOTIFY_DELETEERROR:
213 case SPFILENOTIFY_STARTRENAME:
214 case SPFILENOTIFY_ENDRENAME:
215 case SPFILENOTIFY_RENAMEERROR:
216 case SPFILENOTIFY_STARTCOPY:
217 case SPFILENOTIFY_ENDCOPY:
218 {
219 FILEPATHS_W *pathsW = (FILEPATHS_W *)param1;
220 FILEPATHS_A pathsA;
221
222 pathsA.Source = strdupWtoA( pathsW->Source );
223 pathsA.Target = strdupWtoA( pathsW->Target );
224 pathsA.Win32Error = pathsW->Win32Error;
225 pathsA.Flags = pathsW->Flags;
226 ret = callback_ctx->orig_handler( callback_ctx->orig_context, notification,
227 (UINT_PTR)&pathsA, param2 );
228 HeapFree( GetProcessHeap(), 0, (void *)pathsA.Source );
229 HeapFree( GetProcessHeap(), 0, (void *)pathsA.Target );
230 }
231 if (notification == SPFILENOTIFY_COPYERROR)
232 MultiByteToWideChar( CP_ACP, 0, buffer, -1, (WCHAR *)old_param2, MAX_PATH );
233 break;
234
235 case SPFILENOTIFY_STARTREGISTRATION:
236 case SPFILENOTIFY_ENDREGISTRATION:
237 {
238 SP_REGISTER_CONTROL_STATUSW *statusW = (SP_REGISTER_CONTROL_STATUSW *)param1;
239 SP_REGISTER_CONTROL_STATUSA statusA;
240
241 statusA.cbSize = sizeof(statusA);
242 statusA.FileName = strdupWtoA( statusW->FileName );
243 statusA.Win32Error = statusW->Win32Error;
244 statusA.FailureCode = statusW->FailureCode;
245 ret = callback_ctx->orig_handler( callback_ctx->orig_context, notification,
246 (UINT_PTR)&statusA, param2 );
247 HeapFree( GetProcessHeap(), 0, (LPSTR)statusA.FileName );
248 }
249 break;
250
251 case SPFILENOTIFY_NEEDMEDIA:
252 case SPFILENOTIFY_QUEUESCAN:
253 FIXME("mapping for %d not implemented\n",notification);
254 case SPFILENOTIFY_STARTQUEUE:
255 case SPFILENOTIFY_ENDQUEUE:
256 case SPFILENOTIFY_STARTSUBQUEUE:
257 case SPFILENOTIFY_ENDSUBQUEUE:
258 default:
259 ret = callback_ctx->orig_handler( callback_ctx->orig_context, notification, param1, param2 );
260 break;
261 }
262 return ret;
263 }
264
265
266 /***********************************************************************
267 * get_src_file_info
268 *
269 * Retrieve the source file information for a given file.
270 */
271 static void get_src_file_info( HINF hinf, struct file_op *op )
272 {
273 static const WCHAR SourceDisksNames[] =
274 {'S','o','u','r','c','e','D','i','s','k','s','N','a','m','e','s',0};
275 static const WCHAR SourceDisksFiles[] =
276 {'S','o','u','r','c','e','D','i','s','k','s','F','i','l','e','s',0};
277
278 INFCONTEXT file_ctx, disk_ctx;
279 INT id, diskid;
280 DWORD len, len2;
281
282 /* find the SourceDisksFiles entry */
283 if (!SetupFindFirstLineW( hinf, SourceDisksFiles, op->src_file, &file_ctx ))
284 {
285 const WCHAR *dir;
286
287 if ((op->style & (SP_COPY_SOURCE_ABSOLUTE|SP_COPY_SOURCEPATH_ABSOLUTE))) return;
288 /* no specific info, use .inf file source directory */
289 if (!op->src_root && (dir = DIRID_get_string( hinf, DIRID_SRCPATH )))
290 op->src_root = strdupW( dir );
291 return;
292 }
293 if (!SetupGetIntField( &file_ctx, 1, &diskid )) return;
294
295 /* now find the diskid in the SourceDisksNames section */
296 if (!SetupFindFirstLineW( hinf, SourceDisksNames, NULL, &disk_ctx )) return;
297 for (;;)
298 {
299 if (SetupGetIntField( &disk_ctx, 0, &id ) && (id == diskid)) break;
300 if (!SetupFindNextLine( &disk_ctx, &disk_ctx )) return;
301 }
302
303 /* and fill in the missing info */
304
305 if (!op->src_descr)
306 {
307 if (SetupGetStringFieldW( &disk_ctx, 1, NULL, 0, &len ) &&
308 (op->src_descr = HeapAlloc( GetProcessHeap(), 0, len*sizeof(WCHAR) )))
309 SetupGetStringFieldW( &disk_ctx, 1, op->src_descr, len, NULL );
310 }
311 if (!op->src_tag)
312 {
313 if (SetupGetStringFieldW( &disk_ctx, 2, NULL, 0, &len ) &&
314 (op->src_tag = HeapAlloc( GetProcessHeap(), 0, len*sizeof(WCHAR) )))
315 SetupGetStringFieldW( &disk_ctx, 2, op->src_tag, len, NULL );
316 }
317 if (!op->src_path && !(op->style & SP_COPY_SOURCE_ABSOLUTE))
318 {
319 if (!(op->style & SP_COPY_SOURCEPATH_ABSOLUTE))
320 {
321 /* retrieve relative path for this disk */
322 if (!SetupGetStringFieldW( &disk_ctx, 4, NULL, 0, &len )) len = 0;
323 }
324 /* retrieve relative path for this file */
325 if (!SetupGetStringFieldW( &file_ctx, 2, NULL, 0, &len2 )) len2 = 0;
326
327 if ((len || len2) &&
328 (op->src_path = HeapAlloc( GetProcessHeap(), 0, (len+len2)*sizeof(WCHAR) )))
329 {
330 WCHAR *ptr = op->src_path;
331 if (len)
332 {
333 SetupGetStringFieldW( &disk_ctx, 4, op->src_path, len, NULL );
334 ptr = op->src_path + strlenW(op->src_path);
335 if (len2 && ptr > op->src_path && ptr[-1] != '\\') *ptr++ = '\\';
336 }
337 if (!SetupGetStringFieldW( &disk_ctx, 4, ptr, len2, NULL )) *ptr = 0;
338 }
339 }
340 if (!op->src_root) op->src_root = strdupW( PARSER_get_src_root(hinf) );
341 }
342
343
344 /***********************************************************************
345 * get_destination_dir
346 *
347 * Retrieve the destination dir for a given section.
348 */
349 static WCHAR *get_destination_dir( HINF hinf, const WCHAR *section )
350 {
351 static const WCHAR Dest[] = {'D','e','s','t','i','n','a','t','i','o','n','D','i','r','s',0};
352 static const WCHAR Def[] = {'D','e','f','a','u','l','t','D','e','s','t','D','i','r',0};
353 INFCONTEXT context;
354
355 if (!SetupFindFirstLineW( hinf, Dest, section, &context ) &&
356 !SetupFindFirstLineW( hinf, Dest, Def, &context )) return NULL;
357 return PARSER_get_dest_dir( &context );
358 }
359
360
361 static void (WINAPI *pExtractFiles)( LPSTR, LPSTR, DWORD, DWORD, DWORD, DWORD );
362
363 /***********************************************************************
364 * extract_cabinet_file
365 *
366 * Extract a file from a .cab file.
367 */
368 static BOOL extract_cabinet_file( const WCHAR *cabinet, const WCHAR *root,
369 const WCHAR *src, const WCHAR *dst )
370 {
371 static const WCHAR extW[] = {'.','c','a','b',0};
372 static HMODULE advpack;
373
374 char *cab_path, *cab_file;
375 int len = strlenW( cabinet );
376
377 /* make sure the cabinet file has a .cab extension */
378 if (len <= 4 || strcmpiW( cabinet + len - 4, extW )) return FALSE;
379 if (!pExtractFiles)
380 {
381 if (!advpack && !(advpack = LoadLibraryA( "advpack.dll" )))
382 {
383 ERR( "could not load advpack.dll\n" );
384 return FALSE;
385 }
386 if (!(pExtractFiles = (void *)GetProcAddress( advpack, "ExtractFiles" )))
387 {
388 ERR( "could not find ExtractFiles in advpack.dll\n" );
389 return FALSE;
390 }
391 }
392
393 if (!(cab_path = strdupWtoA( root ))) return FALSE;
394 len = WideCharToMultiByte( CP_ACP, 0, cabinet, -1, NULL, 0, NULL, NULL );
395 if (!(cab_file = HeapAlloc( GetProcessHeap(), 0, strlen(cab_path) + len + 1 )))
396 {
397 HeapFree( GetProcessHeap(), 0, cab_path );
398 return FALSE;
399 }
400 strcpy( cab_file, cab_path );
401 if (cab_file[0] && cab_file[strlen(cab_file)-1] != '\\') strcat( cab_file, "\\" );
402 WideCharToMultiByte( CP_ACP, 0, cabinet, -1, cab_file + strlen(cab_file), len, NULL, NULL );
403 FIXME( "awful hack: extracting cabinet %s\n", debugstr_a(cab_file) );
404 pExtractFiles( cab_file, cab_path, 0, 0, 0, 0 );
405 HeapFree( GetProcessHeap(), 0, cab_file );
406 HeapFree( GetProcessHeap(), 0, cab_path );
407 return CopyFileW( src, dst, FALSE /*FIXME*/ );
408 }
409
410
411 /***********************************************************************
412 * SetupOpenFileQueue (SETUPAPI.@)
413 */
414 HSPFILEQ WINAPI SetupOpenFileQueue(void)
415 {
416 struct file_queue *queue;
417
418 if (!(queue = HeapAlloc( GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*queue))))
419 return (HSPFILEQ)INVALID_HANDLE_VALUE;
420 return queue;
421 }
422
423
424 /***********************************************************************
425 * SetupCloseFileQueue (SETUPAPI.@)
426 */
427 BOOL WINAPI SetupCloseFileQueue( HSPFILEQ handle )
428 {
429 struct file_queue *queue = handle;
430
431 free_file_op_queue( &queue->copy_queue );
432 free_file_op_queue( &queue->rename_queue );
433 free_file_op_queue( &queue->delete_queue );
434 HeapFree( GetProcessHeap(), 0, queue );
435 return TRUE;
436 }
437
438
439 /***********************************************************************
440 * SetupQueueCopyIndirectA (SETUPAPI.@)
441 */
442 BOOL WINAPI SetupQueueCopyIndirectA( PSP_FILE_COPY_PARAMS_A params )
443 {
444 struct file_queue *queue = params->QueueHandle;
445 struct file_op *op;
446
447 if (!(op = HeapAlloc( GetProcessHeap(), 0, sizeof(*op) ))) return FALSE;
448 op->style = params->CopyStyle;
449 op->src_root = strdupAtoW( params->SourceRootPath );
450 op->src_path = strdupAtoW( params->SourcePath );
451 op->src_file = strdupAtoW( params->SourceFilename );
452 op->src_descr = strdupAtoW( params->SourceDescription );
453 op->src_tag = strdupAtoW( params->SourceTagfile );
454 op->dst_path = strdupAtoW( params->TargetDirectory );
455 op->dst_file = strdupAtoW( params->TargetFilename );
456
457 /* some defaults */
458 if (!op->src_file) op->src_file = op->dst_file;
459 if (params->LayoutInf)
460 {
461 get_src_file_info( params->LayoutInf, op );
462 if (!op->dst_path) op->dst_path = get_destination_dir( params->LayoutInf, op->dst_file );
463 }
464
465 TRACE( "root=%s path=%s file=%s -> dir=%s file=%s descr=%s tag=%s\n",
466 debugstr_w(op->src_root), debugstr_w(op->src_path), debugstr_w(op->src_file),
467 debugstr_w(op->dst_path), debugstr_w(op->dst_file),
468 debugstr_w(op->src_descr), debugstr_w(op->src_tag) );
469
470 queue_file_op( &queue->copy_queue, op );
471 return TRUE;
472 }
473
474
475 /***********************************************************************
476 * SetupQueueCopyIndirectW (SETUPAPI.@)
477 */
478 BOOL WINAPI SetupQueueCopyIndirectW( PSP_FILE_COPY_PARAMS_W params )
479 {
480 struct file_queue *queue = params->QueueHandle;
481 struct file_op *op;
482
483 if (!(op = HeapAlloc( GetProcessHeap(), 0, sizeof(*op) ))) return FALSE;
484 op->style = params->CopyStyle;
485 op->src_root = strdupW( params->SourceRootPath );
486 op->src_path = strdupW( params->SourcePath );
487 op->src_file = strdupW( params->SourceFilename );
488 op->src_descr = strdupW( params->SourceDescription );
489 op->src_tag = strdupW( params->SourceTagfile );
490 op->dst_path = strdupW( params->TargetDirectory );
491 op->dst_file = strdupW( params->TargetFilename );
492
493 /* some defaults */
494 if (!op->src_file) op->src_file = op->dst_file;
495 if (params->LayoutInf)
496 {
497 get_src_file_info( params->LayoutInf, op );
498 if (!op->dst_path) op->dst_path = get_destination_dir( params->LayoutInf, op->dst_file );
499 }
500
501 TRACE( "root=%s path=%s file=%s -> dir=%s file=%s descr=%s tag=%s\n",
502 debugstr_w(op->src_root), debugstr_w(op->src_path), debugstr_w(op->src_file),
503 debugstr_w(op->dst_path), debugstr_w(op->dst_file),
504 debugstr_w(op->src_descr), debugstr_w(op->src_tag) );
505
506 queue_file_op( &queue->copy_queue, op );
507 return TRUE;
508 }
509
510
511 /***********************************************************************
512 * SetupQueueCopyA (SETUPAPI.@)
513 */
514 BOOL WINAPI SetupQueueCopyA( HSPFILEQ queue, PCSTR src_root, PCSTR src_path, PCSTR src_file,
515 PCSTR src_descr, PCSTR src_tag, PCSTR dst_dir, PCSTR dst_file,
516 DWORD style )
517 {
518 SP_FILE_COPY_PARAMS_A params;
519
520 params.cbSize = sizeof(params);
521 params.QueueHandle = queue;
522 params.SourceRootPath = src_root;
523 params.SourcePath = src_path;
524 params.SourceFilename = src_file;
525 params.SourceDescription = src_descr;
526 params.SourceTagfile = src_tag;
527 params.TargetDirectory = dst_dir;
528 params.TargetFilename = dst_file;
529 params.CopyStyle = style;
530 params.LayoutInf = 0;
531 params.SecurityDescriptor = NULL;
532 return SetupQueueCopyIndirectA( &params );
533 }
534
535
536 /***********************************************************************
537 * SetupQueueCopyW (SETUPAPI.@)
538 */
539 BOOL WINAPI SetupQueueCopyW( HSPFILEQ queue, PCWSTR src_root, PCWSTR src_path, PCWSTR src_file,
540 PCWSTR src_descr, PCWSTR src_tag, PCWSTR dst_dir, PCWSTR dst_file,
541 DWORD style )
542 {
543 SP_FILE_COPY_PARAMS_W params;
544
545 params.cbSize = sizeof(params);
546 params.QueueHandle = queue;
547 params.SourceRootPath = src_root;
548 params.SourcePath = src_path;
549 params.SourceFilename = src_file;
550 params.SourceDescription = src_descr;
551 params.SourceTagfile = src_tag;
552 params.TargetDirectory = dst_dir;
553 params.TargetFilename = dst_file;
554 params.CopyStyle = style;
555 params.LayoutInf = 0;
556 params.SecurityDescriptor = NULL;
557 return SetupQueueCopyIndirectW( &params );
558 }
559
560
561 /***********************************************************************
562 * SetupQueueDefaultCopyA (SETUPAPI.@)
563 */
564 BOOL WINAPI SetupQueueDefaultCopyA( HSPFILEQ queue, HINF hinf, PCSTR src_root, PCSTR src_file,
565 PCSTR dst_file, DWORD style )
566 {
567 SP_FILE_COPY_PARAMS_A params;
568
569 params.cbSize = sizeof(params);
570 params.QueueHandle = queue;
571 params.SourceRootPath = src_root;
572 params.SourcePath = NULL;
573 params.SourceFilename = src_file;
574 params.SourceDescription = NULL;
575 params.SourceTagfile = NULL;
576 params.TargetDirectory = NULL;
577 params.TargetFilename = dst_file;
578 params.CopyStyle = style;
579 params.LayoutInf = hinf;
580 params.SecurityDescriptor = NULL;
581 return SetupQueueCopyIndirectA( &params );
582 }
583
584
585 /***********************************************************************
586 * SetupQueueDefaultCopyW (SETUPAPI.@)
587 */
588 BOOL WINAPI SetupQueueDefaultCopyW( HSPFILEQ queue, HINF hinf, PCWSTR src_root, PCWSTR src_file,
589 PCWSTR dst_file, DWORD style )
590 {
591 SP_FILE_COPY_PARAMS_W params;
592
593 params.cbSize = sizeof(params);
594 params.QueueHandle = queue;
595 params.SourceRootPath = src_root;
596 params.SourcePath = NULL;
597 params.SourceFilename = src_file;
598 params.SourceDescription = NULL;
599 params.SourceTagfile = NULL;
600 params.TargetDirectory = NULL;
601 params.TargetFilename = dst_file;
602 params.CopyStyle = style;
603 params.LayoutInf = hinf;
604 params.SecurityDescriptor = NULL;
605 return SetupQueueCopyIndirectW( &params );
606 }
607
608
609 /***********************************************************************
610 * SetupQueueDeleteA (SETUPAPI.@)
611 */
612 BOOL WINAPI SetupQueueDeleteA( HSPFILEQ handle, PCSTR part1, PCSTR part2 )
613 {
614 struct file_queue *queue = handle;
615 struct file_op *op;
616
617 if (!(op = HeapAlloc( GetProcessHeap(), 0, sizeof(*op) ))) return FALSE;
618 op->style = 0;
619 op->src_root = NULL;
620 op->src_path = NULL;
621 op->src_file = NULL;
622 op->src_descr = NULL;
623 op->src_tag = NULL;
624 op->dst_path = strdupAtoW( part1 );
625 op->dst_file = strdupAtoW( part2 );
626 queue_file_op( &queue->delete_queue, op );
627 return TRUE;
628 }
629
630
631 /***********************************************************************
632 * SetupQueueDeleteW (SETUPAPI.@)
633 */
634 BOOL WINAPI SetupQueueDeleteW( HSPFILEQ handle, PCWSTR part1, PCWSTR part2 )
635 {
636 struct file_queue *queue = handle;
637 struct file_op *op;
638
639 if (!(op = HeapAlloc( GetProcessHeap(), 0, sizeof(*op) ))) return FALSE;
640 op->style = 0;
641 op->src_root = NULL;
642 op->src_path = NULL;
643 op->src_file = NULL;
644 op->src_descr = NULL;
645 op->src_tag = NULL;
646 op->dst_path = strdupW( part1 );
647 op->dst_file = strdupW( part2 );
648 queue_file_op( &queue->delete_queue, op );
649 return TRUE;
650 }
651
652
653 /***********************************************************************
654 * SetupQueueRenameA (SETUPAPI.@)
655 */
656 BOOL WINAPI SetupQueueRenameA( HSPFILEQ handle, PCSTR SourcePath, PCSTR SourceFilename,
657 PCSTR TargetPath, PCSTR TargetFilename )
658 {
659 struct file_queue *queue = handle;
660 struct file_op *op;
661
662 if (!(op = HeapAlloc( GetProcessHeap(), 0, sizeof(*op) ))) return FALSE;
663 op->style = 0;
664 op->src_root = NULL;
665 op->src_path = strdupAtoW( SourcePath );
666 op->src_file = strdupAtoW( SourceFilename );
667 op->src_descr = NULL;
668 op->src_tag = NULL;
669 op->dst_path = strdupAtoW( TargetPath );
670 op->dst_file = strdupAtoW( TargetFilename );
671 queue_file_op( &queue->rename_queue, op );
672 return TRUE;
673 }
674
675
676 /***********************************************************************
677 * SetupQueueRenameW (SETUPAPI.@)
678 */
679 BOOL WINAPI SetupQueueRenameW( HSPFILEQ handle, PCWSTR SourcePath, PCWSTR SourceFilename,
680 PCWSTR TargetPath, PCWSTR TargetFilename )
681 {
682 struct file_queue *queue = handle;
683 struct file_op *op;
684
685 if (!(op = HeapAlloc( GetProcessHeap(), 0, sizeof(*op) ))) return FALSE;
686 op->style = 0;
687 op->src_root = NULL;
688 op->src_path = strdupW( SourcePath );
689 op->src_file = strdupW( SourceFilename );
690 op->src_descr = NULL;
691 op->src_tag = NULL;
692 op->dst_path = strdupW( TargetPath );
693 op->dst_file = strdupW( TargetFilename );
694 queue_file_op( &queue->rename_queue, op );
695 return TRUE;
696 }
697
698
699 /***********************************************************************
700 * SetupQueueCopySectionA (SETUPAPI.@)
701 */
702 BOOL WINAPI SetupQueueCopySectionA( HSPFILEQ queue, PCSTR src_root, HINF hinf, HINF hlist,
703 PCSTR section, DWORD style )
704 {
705 UNICODE_STRING sectionW;
706 BOOL ret = FALSE;
707
708 if (!RtlCreateUnicodeStringFromAsciiz( &sectionW, section ))
709 {
710 SetLastError( ERROR_NOT_ENOUGH_MEMORY );
711 return FALSE;
712 }
713 if (!src_root)
714 ret = SetupQueueCopySectionW( queue, NULL, hinf, hlist, sectionW.Buffer, style );
715 else
716 {
717 UNICODE_STRING srcW;
718 if (RtlCreateUnicodeStringFromAsciiz( &srcW, src_root ))
719 {
720 ret = SetupQueueCopySectionW( queue, srcW.Buffer, hinf, hlist, sectionW.Buffer, style );
721 RtlFreeUnicodeString( &srcW );
722 }
723 else SetLastError( ERROR_NOT_ENOUGH_MEMORY );
724 }
725 RtlFreeUnicodeString( &sectionW );
726 return ret;
727 }
728
729
730 /***********************************************************************
731 * SetupQueueCopySectionW (SETUPAPI.@)
732 */
733 BOOL WINAPI SetupQueueCopySectionW( HSPFILEQ queue, PCWSTR src_root, HINF hinf, HINF hlist,
734 PCWSTR section, DWORD style )
735 {
736 SP_FILE_COPY_PARAMS_W params;
737 INFCONTEXT context;
738 WCHAR dest[MAX_PATH], src[MAX_PATH];
739 INT flags;
740
741 TRACE( "hinf=%p/%p section=%s root=%s\n",
742 hinf, hlist, debugstr_w(section), debugstr_w(src_root) );
743
744 params.cbSize = sizeof(params);
745 params.QueueHandle = queue;
746 params.SourceRootPath = src_root;
747 params.SourcePath = NULL;
748 params.SourceDescription = NULL;
749 params.SourceTagfile = NULL;
750 params.TargetFilename = dest;
751 params.CopyStyle = style;
752 params.LayoutInf = hinf;
753 params.SecurityDescriptor = NULL;
754
755 if (!hlist) hlist = hinf;
756 if (!hinf) hinf = hlist;
757 if (!SetupFindFirstLineW( hlist, section, NULL, &context )) return FALSE;
758 if (!(params.TargetDirectory = get_destination_dir( hinf, section ))) return FALSE;
759 do
760 {
761 if (!SetupGetStringFieldW( &context, 1, dest, sizeof(dest)/sizeof(WCHAR), NULL ))
762 return FALSE;
763 if (!SetupGetStringFieldW( &context, 2, src, sizeof(src)/sizeof(WCHAR), NULL )) *src = 0;
764 if (!SetupGetIntField( &context, 4, &flags )) flags = 0; /* FIXME */
765
766 params.SourceFilename = *src ? src : NULL;
767 if (!SetupQueueCopyIndirectW( &params )) return FALSE;
768 } while (SetupFindNextLine( &context, &context ));
769 return TRUE;
770 }
771
772
773 /***********************************************************************
774 * SetupQueueDeleteSectionA (SETUPAPI.@)
775 */
776 BOOL WINAPI SetupQueueDeleteSectionA( HSPFILEQ queue, HINF hinf, HINF hlist, PCSTR section )
777 {
778 UNICODE_STRING sectionW;
779 BOOL ret = FALSE;
780
781 if (RtlCreateUnicodeStringFromAsciiz( &sectionW, section ))
782 {
783 ret = SetupQueueDeleteSectionW( queue, hinf, hlist, sectionW.Buffer );
784 RtlFreeUnicodeString( &sectionW );
785 }
786 else SetLastError( ERROR_NOT_ENOUGH_MEMORY );
787 return ret;
788 }
789
790
791 /***********************************************************************
792 * SetupQueueDeleteSectionW (SETUPAPI.@)
793 */
794 BOOL WINAPI SetupQueueDeleteSectionW( HSPFILEQ queue, HINF hinf, HINF hlist, PCWSTR section )
795 {
796 INFCONTEXT context;
797 WCHAR *dest_dir;
798 WCHAR buffer[MAX_PATH];
799 BOOL ret = FALSE;
800 INT flags;
801
802 TRACE( "hinf=%p/%p section=%s\n", hinf, hlist, debugstr_w(section) );
803
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;
807 do
808 {
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 ));
814
815 ret = TRUE;
816 done:
817 HeapFree( GetProcessHeap(), 0, dest_dir );
818 return ret;
819 }
820
821
822 /***********************************************************************
823 * SetupQueueRenameSectionA (SETUPAPI.@)
824 */
825 BOOL WINAPI SetupQueueRenameSectionA( HSPFILEQ queue, HINF hinf, HINF hlist, PCSTR section )
826 {
827 UNICODE_STRING sectionW;
828 BOOL ret = FALSE;
829
830 if (RtlCreateUnicodeStringFromAsciiz( &sectionW, section ))
831 {
832 ret = SetupQueueRenameSectionW( queue, hinf, hlist, sectionW.Buffer );
833 RtlFreeUnicodeString( &sectionW );
834 }
835 else SetLastError( ERROR_NOT_ENOUGH_MEMORY );
836 return ret;
837 }
838
839
840 /***********************************************************************
841 * SetupQueueRenameSectionW (SETUPAPI.@)
842 */
843 BOOL WINAPI SetupQueueRenameSectionW( HSPFILEQ queue, HINF hinf, HINF hlist, PCWSTR section )
844 {
845 INFCONTEXT context;
846 WCHAR *dest_dir;
847 WCHAR src[MAX_PATH], dst[MAX_PATH];
848 BOOL ret = FALSE;
849
850 TRACE( "hinf=%p/%p section=%s\n", hinf, hlist, debugstr_w(section) );
851
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;
855 do
856 {
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 ));
863
864 ret = TRUE;
865 done:
866 HeapFree( GetProcessHeap(), 0, dest_dir );
867 return ret;
868 }
869
870
871 /***********************************************************************
872 * SetupCommitFileQueueA (SETUPAPI.@)
873 */
874 BOOL WINAPI SetupCommitFileQueueA( HWND owner, HSPFILEQ queue, PSP_FILE_CALLBACK_A handler,
875 PVOID context )
876 {
877 struct callback_WtoA_context ctx;
878
879 ctx.orig_context = context;
880 ctx.orig_handler = handler;
881 return SetupCommitFileQueueW( owner, queue, QUEUE_callback_WtoA, &ctx );
882 }
883
884
885 /***********************************************************************
886 * create_full_pathW
887 *
888 * Recursively create all directories in the path.
889 */
890 static BOOL create_full_pathW(const WCHAR *path)
891 {
892 BOOL ret = TRUE;
893 int len;
894 WCHAR *new_path;
895
896 new_path = HeapAlloc(GetProcessHeap(), 0, (strlenW(path) + 1) * sizeof(WCHAR));
897 strcpyW(new_path, path);
898
899 while((len = strlenW(new_path)) && new_path[len - 1] == '\\')
900 new_path[len - 1] = 0;
901
902 while(!CreateDirectoryW(new_path, NULL))
903 {
904 WCHAR *slash;
905 DWORD last_error = GetLastError();
906
907 if(last_error == ERROR_ALREADY_EXISTS)
908 break;
909
910 if(last_error != ERROR_PATH_NOT_FOUND)
911 {
912 ret = FALSE;
913 break;
914 }
915
916 if(!(slash = strrchrW(new_path, '\\')))
917 {
918 ret = FALSE;
919 break;
920 }
921
922 len = slash - new_path;
923 new_path[len] = 0;
924 if(!create_full_pathW(new_path))
925 {
926 ret = FALSE;
927 break;
928 }
929 new_path[len] = '\\';
930 }
931
932 HeapFree(GetProcessHeap(), 0, new_path);
933 return ret;
934 }
935
936 BOOL static do_file_copyW( LPCWSTR source, LPCWSTR target, DWORD style)
937 {
938 BOOL rc = FALSE;
939 BOOL docopy = TRUE;
940
941 TRACE("copy %s to %s style 0x%lx\n",debugstr_w(source),debugstr_w(target),style);
942
943 /* before copy processing */
944 if (style & SP_COPY_REPLACEONLY)
945 {
946 if (GetFileAttributesW(target) == INVALID_FILE_ATTRIBUTES)
947 docopy = FALSE;
948 }
949 if (style & (SP_COPY_NEWER_OR_SAME | SP_COPY_NEWER_ONLY | SP_COPY_FORCE_NEWER))
950 {
951 DWORD VersionSizeSource=0;
952 DWORD VersionSizeTarget=0;
953 DWORD zero=0;
954
955 /*
956 * This is sort of an interesting workaround. You see, calling
957 * GetVersionInfoSize on a builtin dll loads that dll into memory
958 * and we do not properly unload builtin dlls.. so we effectively
959 * lock into memory all the targets we are replacing. This leads
960 * to problems when we try to register the replaced dlls.
961 *
962 * So I will test for the existence of the files first so that
963 * we just basically unconditionally replace the builtin versions.
964 */
965 if ((GetFileAttributesW(target) != INVALID_FILE_ATTRIBUTES) &&
966 (GetFileAttributesW(source) != INVALID_FILE_ATTRIBUTES))
967 {
968 VersionSizeSource = GetFileVersionInfoSizeW((LPWSTR)source,&zero);
969 VersionSizeTarget = GetFileVersionInfoSizeW((LPWSTR)target,&zero);
970 }
971
972 TRACE("SizeTarget %li ... SizeSource %li\n",VersionSizeTarget,
973 VersionSizeSource);
974
975 if (VersionSizeSource && VersionSizeTarget)
976 {
977 LPVOID VersionSource;
978 LPVOID VersionTarget;
979 VS_FIXEDFILEINFO *TargetInfo;
980 VS_FIXEDFILEINFO *SourceInfo;
981 UINT length;
982 WCHAR SubBlock[2]={'\\',0};
983 DWORD ret;
984
985 VersionSource = HeapAlloc(GetProcessHeap(),0,VersionSizeSource);
986 VersionTarget = HeapAlloc(GetProcessHeap(),0,VersionSizeTarget);
987
988 ret = GetFileVersionInfoW((LPWSTR)source,0,VersionSizeSource,VersionSource);
989 if (ret)
990 ret = GetFileVersionInfoW((LPWSTR)target, 0, VersionSizeTarget,
991 VersionTarget);
992
993 if (ret)
994 {
995 ret = VerQueryValueW(VersionSource, SubBlock,
996 (LPVOID*)&SourceInfo, &length);
997 if (ret)
998 ret = VerQueryValueW(VersionTarget, SubBlock,
999 (LPVOID*)&TargetInfo, &length);
1000
1001 if (ret)
1002 {
1003 TRACE("Versions: Source %li.%li target %li.%li\n",
1004 SourceInfo->dwFileVersionMS, SourceInfo->dwFileVersionLS,
1005 TargetInfo->dwFileVersionMS, TargetInfo->dwFileVersionLS);
1006
1007 if (TargetInfo->dwFileVersionMS > SourceInfo->dwFileVersionMS)
1008 {
1009 FIXME("Notify that target version is greater..\n");
1010 docopy = FALSE;
1011 }
1012 else if ((TargetInfo->dwFileVersionMS == SourceInfo->dwFileVersionMS)
1013 && (TargetInfo->dwFileVersionLS > SourceInfo->dwFileVersionLS))
1014 {
1015 FIXME("Notify that target version is greater..\n");
1016 docopy = FALSE;
1017 }
1018 else if ((style & SP_COPY_NEWER_ONLY) &&
1019 (TargetInfo->dwFileVersionMS ==
1020 SourceInfo->dwFileVersionMS)
1021 &&(TargetInfo->dwFileVersionLS ==
1022 SourceInfo->dwFileVersionLS))
1023 {
1024 FIXME("Notify that target version is greater..\n");
1025 docopy = FALSE;
1026 }
1027 }
1028 }
1029 HeapFree(GetProcessHeap(),0,VersionSource);
1030 HeapFree(GetProcessHeap(),0,VersionTarget);
1031 }
1032 }
1033 if (style & (SP_COPY_NOOVERWRITE | SP_COPY_FORCE_NOOVERWRITE))
1034 {
1035 if (GetFileAttributesW(target) != INVALID_FILE_ATTRIBUTES)
1036 {
1037 FIXME("Notify user target file exists\n");
1038 docopy = FALSE;
1039 }
1040 }
1041 if (style & (SP_COPY_NODECOMP | SP_COPY_LANGUAGEAWARE | SP_COPY_FORCE_IN_USE |
1042 SP_COPY_IN_USE_NEEDS_REBOOT | SP_COPY_NOSKIP | SP_COPY_WARNIFSKIP))
1043 {
1044 ERR("Unsupported style(s) 0x%lx\n",style);
1045 }
1046
1047 if (docopy)
1048 {
1049 rc = CopyFileW(source,target,FALSE);
1050 TRACE("Did copy... rc was %i\n",rc);
1051 }
1052
1053 /* after copy processing */
1054 if (style & SP_COPY_DELETESOURCE)
1055 {
1056 if (rc)
1057 DeleteFileW(source);
1058 }
1059
1060 return rc;
1061 }
1062
1063 /***********************************************************************
1064 * SetupCommitFileQueueW (SETUPAPI.@)
1065 */
1066 BOOL WINAPI SetupCommitFileQueueW( HWND owner, HSPFILEQ handle, PSP_FILE_CALLBACK_W handler,
1067 PVOID context )
1068 {
1069 struct file_queue *queue = handle;
1070 struct file_op *op;
1071 BOOL result = FALSE;
1072 FILEPATHS_W paths;
1073 UINT op_result;
1074
1075 paths.Source = paths.Target = NULL;
1076
1077 if (!queue->copy_queue.count && !queue->delete_queue.count && !queue->rename_queue.count)
1078 return TRUE; /* nothing to do */
1079
1080 if (!handler( context, SPFILENOTIFY_STARTQUEUE, (UINT)owner, 0 )) return FALSE;
1081
1082 /* perform deletes */
1083
1084 if (queue->delete_queue.count)
1085 {
1086 if (!(handler( context, SPFILENOTIFY_STARTSUBQUEUE, FILEOP_DELETE,
1087 queue->delete_queue.count ))) goto done;
1088 for (op = queue->delete_queue.head; op; op = op->next)
1089 {
1090 build_filepathsW( op, &paths );
1091 op_result = handler( context, SPFILENOTIFY_STARTDELETE, (UINT_PTR)&paths, FILEOP_DELETE);
1092 if (op_result == FILEOP_ABORT) goto done;
1093 while (op_result == FILEOP_DOIT)
1094 {
1095 TRACE( "deleting file %s\n", debugstr_w(paths.Target) );
1096 if (DeleteFileW( paths.Target )) break; /* success */
1097 paths.Win32Error = GetLastError();
1098 op_result = handler( context, SPFILENOTIFY_DELETEERROR, (UINT_PTR)&paths, 0 );
1099 if (op_result == FILEOP_ABORT) goto done;
1100 }
1101 handler( context, SPFILENOTIFY_ENDDELETE, (UINT_PTR)&paths, 0 );
1102 }
1103 handler( context, SPFILENOTIFY_ENDSUBQUEUE, FILEOP_DELETE, 0 );
1104 }
1105
1106 /* perform renames */
1107
1108 if (queue->rename_queue.count)
1109 {
1110 if (!(handler( context, SPFILENOTIFY_STARTSUBQUEUE, FILEOP_RENAME,
1111 queue->rename_queue.count ))) goto done;
1112 for (op = queue->rename_queue.head; op; op = op->next)
1113 {
1114 build_filepathsW( op, &paths );
1115 op_result = handler( context, SPFILENOTIFY_STARTRENAME, (UINT_PTR)&paths, FILEOP_RENAME);
1116 if (op_result == FILEOP_ABORT) goto done;
1117 while (op_result == FILEOP_DOIT)
1118 {
1119 TRACE( "renaming file %s -> %s\n",
1120 debugstr_w(paths.Source), debugstr_w(paths.Target) );
1121 if (MoveFileW( paths.Source, paths.Target )) break; /* success */
1122 paths.Win32Error = GetLastError();
1123 op_result = handler( context, SPFILENOTIFY_RENAMEERROR, (UINT_PTR)&paths, 0 );
1124 if (op_result == FILEOP_ABORT) goto done;
1125 }
1126 handler( context, SPFILENOTIFY_ENDRENAME, (UINT_PTR)&paths, 0 );
1127 }
1128 handler( context, SPFILENOTIFY_ENDSUBQUEUE, FILEOP_RENAME, 0 );
1129 }
1130
1131 /* perform copies */
1132
1133 if (queue->copy_queue.count)
1134 {
1135 if (!(handler( context, SPFILENOTIFY_STARTSUBQUEUE, FILEOP_COPY,
1136 queue->copy_queue.count ))) goto done;
1137 for (op = queue->copy_queue.head; op; op = op->next)
1138 {
1139 WCHAR newpath[MAX_PATH];
1140
1141 build_filepathsW( op, &paths );
1142 op_result = handler( context, SPFILENOTIFY_STARTCOPY, (UINT_PTR)&paths, FILEOP_COPY );
1143 if (op_result == FILEOP_ABORT) goto done;
1144 if (op_result == FILEOP_NEWPATH) op_result = FILEOP_DOIT;
1145 while (op_result == FILEOP_DOIT || op_result == FILEOP_NEWPATH)
1146 {
1147 TRACE( "copying file %s -> %s\n",
1148 debugstr_w( op_result == FILEOP_NEWPATH ? newpath : paths.Source ),
1149 debugstr_w(paths.Target) );
1150 if (op->dst_path)
1151 {
1152 if (!create_full_pathW( op->dst_path ))
1153 {
1154 paths.Win32Error = GetLastError();
1155 op_result = handler( context, SPFILENOTIFY_COPYERROR,
1156 (UINT_PTR)&paths, (UINT_PTR)newpath );
1157 if (op_result == FILEOP_ABORT) goto done;
1158 }
1159 }
1160 if (do_file_copyW( op_result == FILEOP_NEWPATH ? newpath : paths.Source,
1161 paths.Target, op->style )) break; /* success */
1162 /* try to extract it from the cabinet file */
1163 if (op->src_tag)
1164 {
1165 if (extract_cabinet_file( op->src_tag, op->src_root,
1166 paths.Source, paths.Target )) break;
1167 }
1168 paths.Win32Error = GetLastError();
1169 op_result = handler( context, SPFILENOTIFY_COPYERROR,
1170 (UINT_PTR)&paths, (UINT_PTR)newpath );
1171 if (op_result == FILEOP_ABORT) goto done;
1172 }
1173 handler( context, SPFILENOTIFY_ENDCOPY, (UINT_PTR)&paths, 0 );
1174 }
1175 handler( context, SPFILENOTIFY_ENDSUBQUEUE, FILEOP_COPY, 0 );
1176 }
1177
1178
1179 result = TRUE;
1180
1181 done:
1182 handler( context, SPFILENOTIFY_ENDQUEUE, result, 0 );
1183 HeapFree( GetProcessHeap(), 0, (void *)paths.Source );
1184 HeapFree( GetProcessHeap(), 0, (void *)paths.Target );
1185 return result;
1186 }
1187
1188
1189 /***********************************************************************
1190 * SetupScanFileQueueA (SETUPAPI.@)
1191 */
1192 BOOL WINAPI SetupScanFileQueueA( HSPFILEQ queue, DWORD flags, HWND window,
1193 PSP_FILE_CALLBACK_A callback, PVOID context, PDWORD result )
1194 {
1195 FIXME("stub\n");
1196 return FALSE;
1197 }
1198
1199
1200 /***********************************************************************
1201 * SetupScanFileQueueW (SETUPAPI.@)
1202 */
1203 BOOL WINAPI SetupScanFileQueueW( HSPFILEQ queue, DWORD flags, HWND window,
1204 PSP_FILE_CALLBACK_W callback, PVOID context, PDWORD result )
1205 {
1206 FIXME("stub\n");
1207 return FALSE;
1208 }
1209
1210
1211 /***********************************************************************
1212 * SetupGetFileQueueCount (SETUPAPI.@)
1213 */
1214 BOOL WINAPI SetupGetFileQueueCount( HSPFILEQ handle, UINT op, PUINT result )
1215 {
1216 struct file_queue *queue = handle;
1217
1218 switch(op)
1219 {
1220 case FILEOP_COPY:
1221 *result = queue->copy_queue.count;
1222 return TRUE;
1223 case FILEOP_RENAME:
1224 *result = queue->rename_queue.count;
1225 return TRUE;
1226 case FILEOP_DELETE:
1227 *result = queue->delete_queue.count;
1228 return TRUE;
1229 }
1230 return FALSE;
1231 }
1232
1233
1234 /***********************************************************************
1235 * SetupGetFileQueueFlags (SETUPAPI.@)
1236 */
1237 BOOL WINAPI SetupGetFileQueueFlags( HSPFILEQ handle, PDWORD flags )
1238 {
1239 struct file_queue *queue = handle;
1240 *flags = queue->flags;
1241 return TRUE;
1242 }
1243
1244
1245 /***********************************************************************
1246 * SetupSetFileQueueFlags (SETUPAPI.@)
1247 */
1248 BOOL WINAPI SetupSetFileQueueFlags( HSPFILEQ handle, DWORD mask, DWORD flags )
1249 {
1250 struct file_queue *queue = handle;
1251 queue->flags = (queue->flags & ~mask) | flags;
1252 return TRUE;
1253 }
1254
1255
1256 /***********************************************************************
1257 * SetupSetFileQueueAlternatePlatformA (SETUPAPI.@)
1258 */
1259 BOOL WINAPI SetupSetFileQueueAlternatePlatformA(HSPFILEQ handle, PSP_ALTPLATFORM_INFO platform, PCSTR catalogfile)
1260 {
1261 FIXME("(%p, %p, %s) stub!\n", handle, platform, debugstr_a(catalogfile));
1262 return FALSE;
1263 }
1264
1265
1266 /***********************************************************************
1267 * SetupSetFileQueueAlternatePlatformW (SETUPAPI.@)
1268 */
1269 BOOL WINAPI SetupSetFileQueueAlternatePlatformW(HSPFILEQ handle, PSP_ALTPLATFORM_INFO platform, PCWSTR catalogfile)
1270 {
1271 FIXME("(%p, %p, %s) stub!\n", handle, platform, debugstr_w(catalogfile));
1272 return FALSE;
1273 }
1274
1275
1276 /***********************************************************************
1277 * SetupInitDefaultQueueCallback (SETUPAPI.@)
1278 */
1279 PVOID WINAPI SetupInitDefaultQueueCallback( HWND owner )
1280 {
1281 return SetupInitDefaultQueueCallbackEx( owner, 0, 0, 0, NULL );
1282 }
1283
1284
1285 /***********************************************************************
1286 * SetupInitDefaultQueueCallbackEx (SETUPAPI.@)
1287 */
1288 PVOID WINAPI SetupInitDefaultQueueCallbackEx( HWND owner, HWND progress, UINT msg,
1289 DWORD reserved1, PVOID reserved2 )
1290 {
1291 struct default_callback_context *context;
1292
1293 if ((context = HeapAlloc( GetProcessHeap(), 0, sizeof(*context) )))
1294 {
1295 context->owner = owner;
1296 context->progress = progress;
1297 context->message = msg;
1298 }
1299 return context;
1300 }
1301
1302
1303 /***********************************************************************
1304 * SetupTermDefaultQueueCallback (SETUPAPI.@)
1305 */
1306 void WINAPI SetupTermDefaultQueueCallback( PVOID context )
1307 {
1308 HeapFree( GetProcessHeap(), 0, context );
1309 }
1310
1311
1312 /***********************************************************************
1313 * SetupDefaultQueueCallbackA (SETUPAPI.@)
1314 */
1315 UINT WINAPI SetupDefaultQueueCallbackA( PVOID context, UINT notification,
1316 UINT_PTR param1, UINT_PTR param2 )
1317 {
1318 FILEPATHS_A *paths = (FILEPATHS_A *)param1;
1319 struct default_callback_context *ctx = (struct default_callback_context *)context;
1320
1321 switch(notification)
1322 {
1323 case SPFILENOTIFY_STARTQUEUE:
1324 TRACE( "start queue\n" );
1325 return TRUE;
1326 case SPFILENOTIFY_ENDQUEUE:
1327 TRACE( "end queue\n" );
1328 return 0;
1329 case SPFILENOTIFY_STARTSUBQUEUE:
1330 TRACE( "start subqueue %d count %d\n", param1, param2 );
1331 return TRUE;
1332 case SPFILENOTIFY_ENDSUBQUEUE:
1333 TRACE( "end subqueue %d\n", param1 );
1334 return 0;
1335 case SPFILENOTIFY_STARTDELETE:
1336 TRACE( "start delete %s\n", debugstr_a(paths->Target) );
1337 return FILEOP_DOIT;
1338 case SPFILENOTIFY_ENDDELETE:
1339 TRACE( "end delete %s\n", debugstr_a(paths->Target) );
1340 return 0;
1341 case SPFILENOTIFY_DELETEERROR:
1342 /*Windows Ignores attempts to delete files / folders which do not exist*/
1343 if ((paths->Win32Error != ERROR_FILE_NOT_FOUND) && (paths->Win32Error != ERROR_PATH_NOT_FOUND))
1344 SetupDeleteErrorA(ctx->owner, NULL, paths->Target, paths->Win32Error, 0);
1345 return FILEOP_SKIP;
1346 case SPFILENOTIFY_STARTRENAME:
1347 TRACE( "start rename %s -> %s\n", debugstr_a(paths->Source), debugstr_a(paths->Target) );
1348 return FILEOP_DOIT;
1349 case SPFILENOTIFY_ENDRENAME:
1350 TRACE( "end rename %s -> %s\n", debugstr_a(paths->Source), debugstr_a(paths->Target) );
1351 return 0;
1352 case SPFILENOTIFY_RENAMEERROR:
1353 SetupRenameErrorA(ctx->owner, NULL, paths->Source, paths->Target, paths->Win32Error, 0);
1354 return FILEOP_SKIP;
1355 case SPFILENOTIFY_STARTCOPY:
1356 TRACE( "start copy %s -> %s\n", debugstr_a(paths->Source), debugstr_a(paths->Target) );
1357 return FILEOP_DOIT;
1358 case SPFILENOTIFY_ENDCOPY:
1359 TRACE( "end copy %s -> %s\n", debugstr_a(paths->Source), debugstr_a(paths->Target) );
1360 return 0;
1361 case SPFILENOTIFY_COPYERROR:
1362 ERR( "copy error %d %s -> %s\n", paths->Win32Error,
1363 debugstr_a(paths->Source), debugstr_a(paths->Target) );
1364 return FILEOP_SKIP;
1365 case SPFILENOTIFY_NEEDMEDIA:
1366 TRACE( "need media\n" );
1367 return FILEOP_SKIP;
1368 default:
1369 FIXME( "notification %d params %x,%x\n", notification, param1, param2 );
1370 break;
1371 }
1372 return 0;
1373 }
1374
1375
1376 /***********************************************************************
1377 * SetupDefaultQueueCallbackW (SETUPAPI.@)
1378 */
1379 UINT WINAPI SetupDefaultQueueCallbackW( PVOID context, UINT notification,
1380 UINT_PTR param1, UINT_PTR param2 )
1381 {
1382 FILEPATHS_W *paths = (FILEPATHS_W *)param1;
1383 struct default_callback_context *ctx = (struct default_callback_context *)context;
1384
1385 switch(notification)
1386 {
1387 case SPFILENOTIFY_STARTQUEUE:
1388 TRACE( "start queue\n" );
1389 return TRUE;
1390 case SPFILENOTIFY_ENDQUEUE:
1391 TRACE( "end queue\n" );
1392 return 0;
1393 case SPFILENOTIFY_STARTSUBQUEUE:
1394 TRACE( "start subqueue %d count %d\n", param1, param2 );
1395 return TRUE;
1396 case SPFILENOTIFY_ENDSUBQUEUE:
1397 TRACE( "end subqueue %d\n", param1 );
1398 return 0;
1399 case SPFILENOTIFY_STARTDELETE:
1400 TRACE( "start delete %s\n", debugstr_w(paths->Target) );
1401 return FILEOP_DOIT;
1402 case SPFILENOTIFY_ENDDELETE:
1403 TRACE( "end delete %s\n", debugstr_w(paths->Target) );
1404 return 0;
1405 case SPFILENOTIFY_DELETEERROR:
1406 /*Windows Ignores attempts to delete files / folders which do not exist*/
1407 if ((paths->Win32Error != ERROR_FILE_NOT_FOUND) && (paths->Win32Error != ERROR_PATH_NOT_FOUND))
1408 SetupDeleteErrorW(ctx->owner, NULL, paths->Target, paths->Win32Error, 0);
1409 return FILEOP_SKIP;
1410 case SPFILENOTIFY_STARTRENAME:
1411 SetupRenameErrorW(ctx->owner, NULL, paths->Source, paths->Target, paths->Win32Error, 0);
1412 return FILEOP_DOIT;
1413 case SPFILENOTIFY_ENDRENAME:
1414 TRACE( "end rename %s -> %s\n", debugstr_w(paths->Source), debugstr_w(paths->Target) );
1415 return 0;
1416 case SPFILENOTIFY_RENAMEERROR:
1417 ERR( "rename error %d %s -> %s\n", paths->Win32Error,
1418 debugstr_w(paths->Source), debugstr_w(paths->Target) );
1419 return FILEOP_SKIP;
1420 case SPFILENOTIFY_STARTCOPY:
1421 TRACE( "start copy %s -> %s\n", debugstr_w(paths->Source), debugstr_w(paths->Target) );
1422 return FILEOP_DOIT;
1423 case SPFILENOTIFY_ENDCOPY:
1424 TRACE( "end copy %s -> %s\n", debugstr_w(paths->Source), debugstr_w(paths->Target) );
1425 return 0;
1426 case SPFILENOTIFY_COPYERROR:
1427 ERR( "copy error %d %s -> %s\n", paths->Win32Error,
1428 debugstr_w(paths->Source), debugstr_w(paths->Target) );
1429 return FILEOP_SKIP;
1430 case SPFILENOTIFY_NEEDMEDIA:
1431 TRACE( "need media\n" );
1432 return FILEOP_SKIP;
1433 default:
1434 FIXME( "notification %d params %x,%x\n", notification, param1, param2 );
1435 break;
1436 }
1437 return 0;
1438 }
1439
1440 /***********************************************************************
1441 * SetupDeleteErrorA (SETUPAPI.@)
1442 */
1443
1444 UINT WINAPI SetupDeleteErrorA( HWND parent, PCSTR dialogTitle, PCSTR file,
1445 UINT w32error, DWORD style)
1446 {
1447 FIXME( "stub: (Error Number %d when attempting to delete %s)\n",
1448 w32error, debugstr_a(file) );
1449 return DPROMPT_SKIPFILE;
1450 }
1451
1452 /***********************************************************************
1453 * SetupDeleteErrorW (SETUPAPI.@)
1454 */
1455
1456 UINT WINAPI SetupDeleteErrorW( HWND parent, PCWSTR dialogTitle, PCWSTR file,
1457 UINT w32error, DWORD style)
1458 {
1459 FIXME( "stub: (Error Number %d when attempting to delete %s)\n",
1460 w32error, debugstr_w(file) );
1461 return DPROMPT_SKIPFILE;
1462 }
1463
1464 /***********************************************************************
1465 * SetupRenameErrorA (SETUPAPI.@)
1466 */
1467
1468 UINT WINAPI SetupRenameErrorA( HWND parent, PCSTR dialogTitle, PCSTR source,
1469 PCSTR target, UINT w32error, DWORD style)
1470 {
1471 FIXME( "stub: (Error Number %d when attempting to rename %s to %s)\n",
1472 w32error, debugstr_a(source), debugstr_a(target));
1473 return DPROMPT_SKIPFILE;
1474 }
1475
1476 /***********************************************************************
1477 * SetupRenameErrorW (SETUPAPI.@)
1478 */
1479
1480 UINT WINAPI SetupRenameErrorW( HWND parent, PCWSTR dialogTitle, PCWSTR source,
1481 PCWSTR target, UINT w32error, DWORD style)
1482 {
1483 FIXME( "stub: (Error Number %d when attempting to rename %s to %s)\n",
1484 w32error, debugstr_w(source), debugstr_w(target));
1485 return DPROMPT_SKIPFILE;
1486 }
1487
1488
1489 /***********************************************************************
1490 * SetupCopyErrorA (SETUPAPI.@)
1491 */
1492
1493 UINT WINAPI SetupCopyErrorA( HWND parent, PCSTR dialogTitle, PCSTR diskname,
1494 PCSTR sourcepath, PCSTR sourcefile, PCSTR targetpath,
1495 UINT w32error, DWORD style, PSTR pathbuffer,
1496 DWORD buffersize, PDWORD requiredsize)
1497 {
1498 FIXME( "stub: (Error Number %d when attempting to copy file %s from %s to %s)\n",
1499 w32error, debugstr_a(sourcefile), debugstr_a(sourcepath) ,debugstr_a(targetpath));
1500 return DPROMPT_SKIPFILE;
1501 }
1502
1503 /***********************************************************************
1504 * SetupCopyErrorW (SETUPAPI.@)
1505 */
1506
1507 UINT WINAPI SetupCopyErrorW( HWND parent, PCWSTR dialogTitle, PCWSTR diskname,
1508 PCWSTR sourcepath, PCWSTR sourcefile, PCWSTR targetpath,
1509 UINT w32error, DWORD style, PWSTR pathbuffer,
1510 DWORD buffersize, PDWORD requiredsize)
1511 {
1512 FIXME( "stub: (Error Number %d when attempting to copy file %s from %s to %s)\n",
1513 w32error, debugstr_w(sourcefile), debugstr_w(sourcepath) ,debugstr_w(targetpath));
1514 return DPROMPT_SKIPFILE;
1515 }