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