2 * Setupapi file queue routines
4 * Copyright 2002 Alexandre Julliard for CodeWeavers
6 * This library is free software; you can redistribute it and/or
7 * modify it under the terms of the GNU Lesser General Public
8 * License as published by the Free Software Foundation; either
9 * version 2.1 of the License, or (at your option) any later version.
11 * This library is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14 * Lesser General Public License for more details.
16 * You should have received a copy of the GNU Lesser General Public
17 * License along with this library; if not, write to the Free Software
18 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
32 #include "wine/unicode.h"
33 #include "setupapi_private.h"
35 #include "wine/debug.h"
37 WINE_DEFAULT_DEBUG_CHANNEL(setupapi
);
39 /* context structure for the default queue callback */
40 struct default_callback_context
69 struct file_op_queue copy_queue
;
70 struct file_op_queue delete_queue
;
71 struct file_op_queue rename_queue
;
76 inline static WCHAR
*strdupW( const WCHAR
*str
)
81 int len
= (strlenW(str
) + 1) * sizeof(WCHAR
);
82 if ((ret
= HeapAlloc( GetProcessHeap(), 0, len
))) memcpy( ret
, str
, len
);
88 inline static WCHAR
*strdupAtoW( const char *str
)
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
);
100 inline static char *strdupWtoA( const WCHAR
*str
)
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
);
112 /* append a file operation to a queue */
113 inline static void queue_file_op( struct file_op_queue
*queue
, struct file_op
*op
)
116 if (queue
->tail
) queue
->tail
->next
= op
;
117 else queue
->head
= op
;
122 /* free all the file operations on a given queue */
123 static void free_file_op_queue( struct file_op_queue
*queue
)
125 struct file_op
*t
, *op
= queue
->head
;
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
);
138 HeapFree( GetProcessHeap(), 0, t
);
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
)
148 strcpyW( buffer
, src1
);
149 buffer
+= strlenW(buffer
);
150 if (buffer
[-1] != '\\') *buffer
++ = '\\';
151 if (src2
) while (*src2
== '\\') src2
++;
156 strcpyW( buffer
, src2
);
157 buffer
+= strlenW(buffer
);
158 if (buffer
[-1] != '\\') *buffer
++ = '\\';
159 if (src3
) while (*src3
== '\\') src3
++;
163 strcpyW( buffer
, src3
);
164 buffer
+= strlenW(buffer
);
169 /***********************************************************************
172 * Build a FILEPATHS_W structure for a given file operation.
174 static BOOL
build_filepathsW( const struct file_op
*op
, FILEPATHS_W
*paths
)
176 unsigned int src_len
= 1, dst_len
= 1;
177 WCHAR
*source
= (PWSTR
)paths
->Source
, *target
= (PWSTR
)paths
->Target
;
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
);
187 if (!source
|| HeapSize( GetProcessHeap(), 0, source
) < src_len
)
189 HeapFree( GetProcessHeap(), 0, source
);
190 paths
->Source
= source
= HeapAlloc( GetProcessHeap(), 0, src_len
);
192 if (!target
|| HeapSize( GetProcessHeap(), 0, target
) < dst_len
)
194 HeapFree( GetProcessHeap(), 0, target
);
195 paths
->Target
= target
= HeapAlloc( GetProcessHeap(), 0, dst_len
);
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;
206 /***********************************************************************
207 * QUEUE_callback_WtoA
209 * Map a file callback parameters from W to A and call the A callback.
211 UINT CALLBACK
QUEUE_callback_WtoA( void *context
, UINT notification
,
212 UINT_PTR param1
, UINT_PTR param2
)
214 struct callback_WtoA_context
*callback_ctx
= context
;
215 char buffer
[MAX_PATH
];
217 UINT_PTR old_param2
= param2
;
221 case SPFILENOTIFY_COPYERROR
:
222 param2
= (UINT_PTR
)&buffer
;
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
:
233 FILEPATHS_W
*pathsW
= (FILEPATHS_W
*)param1
;
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
);
245 if (notification
== SPFILENOTIFY_COPYERROR
)
246 MultiByteToWideChar( CP_ACP
, 0, buffer
, -1, (WCHAR
*)old_param2
, MAX_PATH
);
249 case SPFILENOTIFY_STARTREGISTRATION
:
250 case SPFILENOTIFY_ENDREGISTRATION
:
252 SP_REGISTER_CONTROL_STATUSW
*statusW
= (SP_REGISTER_CONTROL_STATUSW
*)param1
;
253 SP_REGISTER_CONTROL_STATUSA statusA
;
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
);
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
:
273 ret
= callback_ctx
->orig_handler( callback_ctx
->orig_context
, notification
, param1
, param2
);
280 /***********************************************************************
283 * Retrieve the source file information for a given file.
285 static void get_src_file_info( HINF hinf
, struct file_op
*op
)
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};
292 INFCONTEXT file_ctx
, disk_ctx
;
296 /* find the SourceDisksFiles entry */
297 if (!SetupFindFirstLineW( hinf
, SourceDisksFiles
, op
->src_file
, &file_ctx
))
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
);
307 if (!SetupGetIntField( &file_ctx
, 1, &diskid
)) return;
309 /* now find the diskid in the SourceDisksNames section */
310 if (!SetupFindFirstLineW( hinf
, SourceDisksNames
, NULL
, &disk_ctx
)) return;
313 if (SetupGetIntField( &disk_ctx
, 0, &id
) && (id
== diskid
)) break;
314 if (!SetupFindNextLine( &disk_ctx
, &disk_ctx
)) return;
317 /* and fill in the missing info */
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
);
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
);
331 if (!op
->src_path
&& !(op
->style
& SP_COPY_SOURCE_ABSOLUTE
))
333 if (!(op
->style
& SP_COPY_SOURCEPATH_ABSOLUTE
))
335 /* retrieve relative path for this disk */
336 if (!SetupGetStringFieldW( &disk_ctx
, 4, NULL
, 0, &len
)) len
= 0;
338 /* retrieve relative path for this file */
339 if (!SetupGetStringFieldW( &file_ctx
, 2, NULL
, 0, &len2
)) len2
= 0;
342 (op
->src_path
= HeapAlloc( GetProcessHeap(), 0, (len
+len2
)*sizeof(WCHAR
) )))
344 WCHAR
*ptr
= op
->src_path
;
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
++ = '\\';
351 if (!SetupGetStringFieldW( &disk_ctx
, 4, ptr
, len2
, NULL
)) *ptr
= 0;
354 if (!op
->src_root
) op
->src_root
= strdupW( PARSER_get_src_root(hinf
) );
358 /***********************************************************************
359 * get_destination_dir
361 * Retrieve the destination dir for a given section.
363 static WCHAR
*get_destination_dir( HINF hinf
, const WCHAR
*section
)
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};
369 if (!SetupFindFirstLineW( hinf
, Dest
, section
, &context
) &&
370 !SetupFindFirstLineW( hinf
, Dest
, Def
, &context
)) return NULL
;
371 return PARSER_get_dest_dir( &context
);
375 static void (WINAPI
*pExtractFiles
)( LPSTR
, LPSTR
, DWORD
, DWORD
, DWORD
, DWORD
);
377 /***********************************************************************
378 * extract_cabinet_file
380 * Extract a file from a .cab file.
382 static BOOL
extract_cabinet_file( const WCHAR
*cabinet
, const WCHAR
*root
,
383 const WCHAR
*src
, const WCHAR
*dst
)
385 static const WCHAR extW
[] = {'.','c','a','b',0};
386 static HMODULE advpack
;
388 char *cab_path
, *cab_file
;
389 int len
= strlenW( cabinet
);
391 /* make sure the cabinet file has a .cab extension */
392 if (len
<= 4 || strcmpiW( cabinet
+ len
- 4, extW
)) return FALSE
;
395 if (!advpack
&& !(advpack
= LoadLibraryA( "advpack.dll" )))
397 ERR( "could not load advpack.dll\n" );
400 if (!(pExtractFiles
= (void *)GetProcAddress( advpack
, "ExtractFiles" )))
402 ERR( "could not find ExtractFiles in advpack.dll\n" );
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 )))
411 HeapFree( GetProcessHeap(), 0, cab_path
);
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*/ );
425 /***********************************************************************
426 * SetupOpenFileQueue (SETUPAPI.@)
428 HSPFILEQ WINAPI
SetupOpenFileQueue(void)
430 struct file_queue
*queue
;
432 if (!(queue
= HeapAlloc( GetProcessHeap(), HEAP_ZERO_MEMORY
, sizeof(*queue
))))
433 return (HSPFILEQ
)INVALID_HANDLE_VALUE
;
438 /***********************************************************************
439 * SetupCloseFileQueue (SETUPAPI.@)
441 BOOL WINAPI
SetupCloseFileQueue( HSPFILEQ handle
)
443 struct file_queue
*queue
= handle
;
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
);
453 /***********************************************************************
454 * SetupQueueCopyIndirectA (SETUPAPI.@)
456 BOOL WINAPI
SetupQueueCopyIndirectA( PSP_FILE_COPY_PARAMS_A params
)
458 struct file_queue
*queue
= params
->QueueHandle
;
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
);
472 if (!op
->src_file
) op
->src_file
= op
->dst_file
;
473 if (params
->LayoutInf
)
475 get_src_file_info( params
->LayoutInf
, op
);
476 if (!op
->dst_path
) op
->dst_path
= get_destination_dir( params
->LayoutInf
, op
->dst_file
);
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
) );
484 queue_file_op( &queue
->copy_queue
, op
);
489 /***********************************************************************
490 * SetupQueueCopyIndirectW (SETUPAPI.@)
492 BOOL WINAPI
SetupQueueCopyIndirectW( PSP_FILE_COPY_PARAMS_W params
)
494 struct file_queue
*queue
= params
->QueueHandle
;
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
);
508 if (!op
->src_file
) op
->src_file
= op
->dst_file
;
509 if (params
->LayoutInf
)
511 get_src_file_info( params
->LayoutInf
, op
);
512 if (!op
->dst_path
) op
->dst_path
= get_destination_dir( params
->LayoutInf
, op
->dst_file
);
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
) );
520 queue_file_op( &queue
->copy_queue
, op
);
525 /***********************************************************************
526 * SetupQueueCopyA (SETUPAPI.@)
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
,
532 SP_FILE_COPY_PARAMS_A params
;
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( ¶ms
);
550 /***********************************************************************
551 * SetupQueueCopyW (SETUPAPI.@)
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
,
557 SP_FILE_COPY_PARAMS_W params
;
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( ¶ms
);
575 /***********************************************************************
576 * SetupQueueDefaultCopyA (SETUPAPI.@)
578 BOOL WINAPI
SetupQueueDefaultCopyA( HSPFILEQ queue
, HINF hinf
, PCSTR src_root
, PCSTR src_file
,
579 PCSTR dst_file
, DWORD style
)
581 SP_FILE_COPY_PARAMS_A params
;
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( ¶ms
);
599 /***********************************************************************
600 * SetupQueueDefaultCopyW (SETUPAPI.@)
602 BOOL WINAPI
SetupQueueDefaultCopyW( HSPFILEQ queue
, HINF hinf
, PCWSTR src_root
, PCWSTR src_file
,
603 PCWSTR dst_file
, DWORD style
)
605 SP_FILE_COPY_PARAMS_W params
;
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( ¶ms
);
623 /***********************************************************************
624 * SetupQueueDeleteA (SETUPAPI.@)
626 BOOL WINAPI
SetupQueueDeleteA( HSPFILEQ handle
, PCSTR part1
, PCSTR part2
)
628 struct file_queue
*queue
= handle
;
631 if (!(op
= HeapAlloc( GetProcessHeap(), 0, sizeof(*op
) ))) return FALSE
;
636 op
->src_descr
= NULL
;
638 op
->dst_path
= strdupAtoW( part1
);
639 op
->dst_file
= strdupAtoW( part2
);
640 queue_file_op( &queue
->delete_queue
, op
);
645 /***********************************************************************
646 * SetupQueueDeleteW (SETUPAPI.@)
648 BOOL WINAPI
SetupQueueDeleteW( HSPFILEQ handle
, PCWSTR part1
, PCWSTR part2
)
650 struct file_queue
*queue
= handle
;
653 if (!(op
= HeapAlloc( GetProcessHeap(), 0, sizeof(*op
) ))) return FALSE
;
658 op
->src_descr
= NULL
;
660 op
->dst_path
= strdupW( part1
);
661 op
->dst_file
= strdupW( part2
);
662 queue_file_op( &queue
->delete_queue
, op
);
667 /***********************************************************************
668 * SetupQueueRenameA (SETUPAPI.@)
670 BOOL WINAPI
SetupQueueRenameA( HSPFILEQ handle
, PCSTR SourcePath
, PCSTR SourceFilename
,
671 PCSTR TargetPath
, PCSTR TargetFilename
)
673 struct file_queue
*queue
= handle
;
676 if (!(op
= HeapAlloc( GetProcessHeap(), 0, sizeof(*op
) ))) return FALSE
;
679 op
->src_path
= strdupAtoW( SourcePath
);
680 op
->src_file
= strdupAtoW( SourceFilename
);
681 op
->src_descr
= NULL
;
683 op
->dst_path
= strdupAtoW( TargetPath
);
684 op
->dst_file
= strdupAtoW( TargetFilename
);
685 queue_file_op( &queue
->rename_queue
, op
);
690 /***********************************************************************
691 * SetupQueueRenameW (SETUPAPI.@)
693 BOOL WINAPI
SetupQueueRenameW( HSPFILEQ handle
, PCWSTR SourcePath
, PCWSTR SourceFilename
,
694 PCWSTR TargetPath
, PCWSTR TargetFilename
)
696 struct file_queue
*queue
= handle
;
699 if (!(op
= HeapAlloc( GetProcessHeap(), 0, sizeof(*op
) ))) return FALSE
;
702 op
->src_path
= strdupW( SourcePath
);
703 op
->src_file
= strdupW( SourceFilename
);
704 op
->src_descr
= NULL
;
706 op
->dst_path
= strdupW( TargetPath
);
707 op
->dst_file
= strdupW( TargetFilename
);
708 queue_file_op( &queue
->rename_queue
, op
);
713 /***********************************************************************
714 * SetupQueueCopySectionA (SETUPAPI.@)
716 BOOL WINAPI
SetupQueueCopySectionA( HSPFILEQ queue
, PCSTR src_root
, HINF hinf
, HINF hlist
,
717 PCSTR section
, DWORD style
)
719 UNICODE_STRING sectionW
;
722 if (!RtlCreateUnicodeStringFromAsciiz( §ionW
, section
))
724 SetLastError( ERROR_NOT_ENOUGH_MEMORY
);
728 ret
= SetupQueueCopySectionW( queue
, NULL
, hinf
, hlist
, sectionW
.Buffer
, style
);
732 if (RtlCreateUnicodeStringFromAsciiz( &srcW
, src_root
))
734 ret
= SetupQueueCopySectionW( queue
, srcW
.Buffer
, hinf
, hlist
, sectionW
.Buffer
, style
);
735 RtlFreeUnicodeString( &srcW
);
737 else SetLastError( ERROR_NOT_ENOUGH_MEMORY
);
739 RtlFreeUnicodeString( §ionW
);
744 /***********************************************************************
745 * SetupQueueCopySectionW (SETUPAPI.@)
747 BOOL WINAPI
SetupQueueCopySectionW( HSPFILEQ queue
, PCWSTR src_root
, HINF hinf
, HINF hlist
,
748 PCWSTR section
, DWORD style
)
750 SP_FILE_COPY_PARAMS_W params
;
752 WCHAR dest
[MAX_PATH
], src
[MAX_PATH
];
755 TRACE( "hinf=%p/%p section=%s root=%s\n",
756 hinf
, hlist
, debugstr_w(section
), debugstr_w(src_root
) );
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
;
769 if (!hlist
) hlist
= hinf
;
770 if (!SetupFindFirstLineW( hlist
, section
, NULL
, &context
)) return FALSE
;
771 if (!(params
.TargetDirectory
= get_destination_dir( hinf
, section
))) return FALSE
;
774 if (!SetupGetStringFieldW( &context
, 1, dest
, sizeof(dest
)/sizeof(WCHAR
), NULL
))
776 if (!SetupGetStringFieldW( &context
, 2, src
, sizeof(src
)/sizeof(WCHAR
), NULL
)) *src
= 0;
777 if (!SetupGetIntField( &context
, 4, &flags
)) flags
= 0; /* FIXME */
779 params
.SourceFilename
= *src
? src
: NULL
;
780 if (!SetupQueueCopyIndirectW( ¶ms
)) return FALSE
;
781 } while (SetupFindNextLine( &context
, &context
));
786 /***********************************************************************
787 * SetupQueueDeleteSectionA (SETUPAPI.@)
789 BOOL WINAPI
SetupQueueDeleteSectionA( HSPFILEQ queue
, HINF hinf
, HINF hlist
, PCSTR section
)
791 UNICODE_STRING sectionW
;
794 if (RtlCreateUnicodeStringFromAsciiz( §ionW
, section
))
796 ret
= SetupQueueDeleteSectionW( queue
, hinf
, hlist
, sectionW
.Buffer
);
797 RtlFreeUnicodeString( §ionW
);
799 else SetLastError( ERROR_NOT_ENOUGH_MEMORY
);
804 /***********************************************************************
805 * SetupQueueDeleteSectionW (SETUPAPI.@)
807 BOOL WINAPI
SetupQueueDeleteSectionW( HSPFILEQ queue
, HINF hinf
, HINF hlist
, PCWSTR section
)
811 WCHAR buffer
[MAX_PATH
];
815 TRACE( "hinf=%p/%p section=%s\n", hinf
, hlist
, debugstr_w(section
) );
817 if (!hlist
) hlist
= hinf
;
818 if (!SetupFindFirstLineW( hlist
, section
, NULL
, &context
)) return FALSE
;
819 if (!(dest_dir
= get_destination_dir( hinf
, section
))) return FALSE
;
822 if (!SetupGetStringFieldW( &context
, 1, buffer
, sizeof(buffer
)/sizeof(WCHAR
), NULL
))
824 if (!SetupGetIntField( &context
, 4, &flags
)) flags
= 0;
825 if (!SetupQueueDeleteW( queue
, dest_dir
, buffer
)) goto done
;
826 } while (SetupFindNextLine( &context
, &context
));
830 HeapFree( GetProcessHeap(), 0, dest_dir
);
835 /***********************************************************************
836 * SetupQueueRenameSectionA (SETUPAPI.@)
838 BOOL WINAPI
SetupQueueRenameSectionA( HSPFILEQ queue
, HINF hinf
, HINF hlist
, PCSTR section
)
840 UNICODE_STRING sectionW
;
843 if (RtlCreateUnicodeStringFromAsciiz( §ionW
, section
))
845 ret
= SetupQueueRenameSectionW( queue
, hinf
, hlist
, sectionW
.Buffer
);
846 RtlFreeUnicodeString( §ionW
);
848 else SetLastError( ERROR_NOT_ENOUGH_MEMORY
);
853 /***********************************************************************
854 * SetupQueueRenameSectionW (SETUPAPI.@)
856 BOOL WINAPI
SetupQueueRenameSectionW( HSPFILEQ queue
, HINF hinf
, HINF hlist
, PCWSTR section
)
860 WCHAR src
[MAX_PATH
], dst
[MAX_PATH
];
863 TRACE( "hinf=%p/%p section=%s\n", hinf
, hlist
, debugstr_w(section
) );
865 if (!hlist
) hlist
= hinf
;
866 if (!SetupFindFirstLineW( hlist
, section
, NULL
, &context
)) return FALSE
;
867 if (!(dest_dir
= get_destination_dir( hinf
, section
))) return FALSE
;
870 if (!SetupGetStringFieldW( &context
, 1, dst
, sizeof(dst
)/sizeof(WCHAR
), NULL
))
872 if (!SetupGetStringFieldW( &context
, 2, src
, sizeof(src
)/sizeof(WCHAR
), NULL
))
874 if (!SetupQueueRenameW( queue
, dest_dir
, src
, NULL
, dst
)) goto done
;
875 } while (SetupFindNextLine( &context
, &context
));
879 HeapFree( GetProcessHeap(), 0, dest_dir
);
884 /***********************************************************************
885 * SetupCommitFileQueueA (SETUPAPI.@)
887 BOOL WINAPI
SetupCommitFileQueueA( HWND owner
, HSPFILEQ queue
, PSP_FILE_CALLBACK_A handler
,
890 struct callback_WtoA_context ctx
;
892 ctx
.orig_context
= context
;
893 ctx
.orig_handler
= handler
;
894 return SetupCommitFileQueueW( owner
, queue
, QUEUE_callback_WtoA
, &ctx
);
898 /***********************************************************************
901 * Recursively create all directories in the path.
903 static BOOL
create_full_pathW(const WCHAR
*path
)
909 new_path
= HeapAlloc(GetProcessHeap(), 0, (strlenW(path
) + 1) * sizeof(WCHAR
));
910 strcpyW(new_path
, path
);
912 while((len
= strlenW(new_path
)) && new_path
[len
- 1] == '\\')
913 new_path
[len
- 1] = 0;
915 while(!CreateDirectoryW(new_path
, NULL
))
918 DWORD last_error
= GetLastError();
920 if(last_error
== ERROR_ALREADY_EXISTS
)
923 if(last_error
!= ERROR_PATH_NOT_FOUND
)
929 if(!(slash
= strrchrW(new_path
, '\\')))
935 len
= slash
- new_path
;
937 if(!create_full_pathW(new_path
))
942 new_path
[len
] = '\\';
945 HeapFree(GetProcessHeap(), 0, new_path
);
949 BOOL
static do_file_copyW( LPCWSTR source
, LPCWSTR target
, DWORD style
)
954 TRACE("copy %s to %s style 0x%lx\n",debugstr_w(source
),debugstr_w(target
),style
);
956 /* before copy processing */
957 if (style
& SP_COPY_REPLACEONLY
)
959 if (GetFileAttributesW(target
) == INVALID_FILE_ATTRIBUTES
)
962 if (style
& (SP_COPY_NEWER_OR_SAME
| SP_COPY_NEWER_ONLY
| SP_COPY_FORCE_NEWER
))
964 DWORD VersionSizeSource
=0;
965 DWORD VersionSizeTarget
=0;
969 * This is sort of an interesting workaround. You see, calling
970 * GetVersionInfoSize on a builtin dll loads that dll into memory
971 * and we do not properly unload builtin dlls.. so we effectively
972 * lock into memory all the targets we are replacing. This leads
973 * to problems when we try to register the replaced dlls.
975 * So I will test for the existence of the files first so that
976 * we just basically unconditionally replace the builtin versions.
978 if ((GetFileAttributesW(target
) != INVALID_FILE_ATTRIBUTES
) &&
979 (GetFileAttributesW(source
) != INVALID_FILE_ATTRIBUTES
))
981 VersionSizeSource
= GetFileVersionInfoSizeW(source
,&zero
);
982 VersionSizeTarget
= GetFileVersionInfoSizeW(target
,&zero
);
985 TRACE("SizeTarget %li ... SizeSource %li\n",VersionSizeTarget
,
988 if (VersionSizeSource
&& VersionSizeTarget
)
990 LPVOID VersionSource
;
991 LPVOID VersionTarget
;
992 VS_FIXEDFILEINFO
*TargetInfo
;
993 VS_FIXEDFILEINFO
*SourceInfo
;
995 WCHAR SubBlock
[2]={'\\',0};
998 VersionSource
= HeapAlloc(GetProcessHeap(),0,VersionSizeSource
);
999 VersionTarget
= HeapAlloc(GetProcessHeap(),0,VersionSizeTarget
);
1001 ret
= GetFileVersionInfoW(source
,0,VersionSizeSource
,VersionSource
);
1003 ret
= GetFileVersionInfoW(target
, 0, VersionSizeTarget
,
1008 ret
= VerQueryValueW(VersionSource
, SubBlock
,
1009 (LPVOID
*)&SourceInfo
, &length
);
1011 ret
= VerQueryValueW(VersionTarget
, SubBlock
,
1012 (LPVOID
*)&TargetInfo
, &length
);
1016 TRACE("Versions: Source %li.%li target %li.%li\n",
1017 SourceInfo
->dwFileVersionMS
, SourceInfo
->dwFileVersionLS
,
1018 TargetInfo
->dwFileVersionMS
, TargetInfo
->dwFileVersionLS
);
1020 if (TargetInfo
->dwFileVersionMS
> SourceInfo
->dwFileVersionMS
)
1022 FIXME("Notify that target version is greater..\n");
1025 else if ((TargetInfo
->dwFileVersionMS
== SourceInfo
->dwFileVersionMS
)
1026 && (TargetInfo
->dwFileVersionLS
> SourceInfo
->dwFileVersionLS
))
1028 FIXME("Notify that target version is greater..\n");
1031 else if ((style
& SP_COPY_NEWER_ONLY
) &&
1032 (TargetInfo
->dwFileVersionMS
==
1033 SourceInfo
->dwFileVersionMS
)
1034 &&(TargetInfo
->dwFileVersionLS
==
1035 SourceInfo
->dwFileVersionLS
))
1037 FIXME("Notify that target version is greater..\n");
1042 HeapFree(GetProcessHeap(),0,VersionSource
);
1043 HeapFree(GetProcessHeap(),0,VersionTarget
);
1046 if (style
& (SP_COPY_NOOVERWRITE
| SP_COPY_FORCE_NOOVERWRITE
))
1048 if (GetFileAttributesW(target
) != INVALID_FILE_ATTRIBUTES
)
1050 FIXME("Notify user target file exists\n");
1054 if (style
& (SP_COPY_NODECOMP
| SP_COPY_LANGUAGEAWARE
| SP_COPY_FORCE_IN_USE
|
1055 SP_COPY_IN_USE_NEEDS_REBOOT
| SP_COPY_NOSKIP
| SP_COPY_WARNIFSKIP
))
1057 ERR("Unsupported style(s) 0x%lx\n",style
);
1062 rc
= CopyFileW(source
,target
,FALSE
);
1063 TRACE("Did copy... rc was %i\n",rc
);
1066 /* after copy processing */
1067 if (style
& SP_COPY_DELETESOURCE
)
1070 DeleteFileW(source
);
1076 /***********************************************************************
1077 * SetupCommitFileQueueW (SETUPAPI.@)
1079 BOOL WINAPI
SetupCommitFileQueueW( HWND owner
, HSPFILEQ handle
, PSP_FILE_CALLBACK_W handler
,
1082 struct file_queue
*queue
= handle
;
1084 BOOL result
= FALSE
;
1088 paths
.Source
= paths
.Target
= NULL
;
1090 if (!queue
->copy_queue
.count
&& !queue
->delete_queue
.count
&& !queue
->rename_queue
.count
)
1091 return TRUE
; /* nothing to do */
1093 if (!handler( context
, SPFILENOTIFY_STARTQUEUE
, (UINT
)owner
, 0 )) return FALSE
;
1095 /* perform deletes */
1097 if (queue
->delete_queue
.count
)
1099 if (!(handler( context
, SPFILENOTIFY_STARTSUBQUEUE
, FILEOP_DELETE
,
1100 queue
->delete_queue
.count
))) goto done
;
1101 for (op
= queue
->delete_queue
.head
; op
; op
= op
->next
)
1103 build_filepathsW( op
, &paths
);
1104 op_result
= handler( context
, SPFILENOTIFY_STARTDELETE
, (UINT_PTR
)&paths
, FILEOP_DELETE
);
1105 if (op_result
== FILEOP_ABORT
) goto done
;
1106 while (op_result
== FILEOP_DOIT
)
1108 TRACE( "deleting file %s\n", debugstr_w(paths
.Target
) );
1109 if (DeleteFileW( paths
.Target
)) break; /* success */
1110 paths
.Win32Error
= GetLastError();
1111 op_result
= handler( context
, SPFILENOTIFY_DELETEERROR
, (UINT_PTR
)&paths
, 0 );
1112 if (op_result
== FILEOP_ABORT
) goto done
;
1114 handler( context
, SPFILENOTIFY_ENDDELETE
, (UINT_PTR
)&paths
, 0 );
1116 handler( context
, SPFILENOTIFY_ENDSUBQUEUE
, FILEOP_DELETE
, 0 );
1119 /* perform renames */
1121 if (queue
->rename_queue
.count
)
1123 if (!(handler( context
, SPFILENOTIFY_STARTSUBQUEUE
, FILEOP_RENAME
,
1124 queue
->rename_queue
.count
))) goto done
;
1125 for (op
= queue
->rename_queue
.head
; op
; op
= op
->next
)
1127 build_filepathsW( op
, &paths
);
1128 op_result
= handler( context
, SPFILENOTIFY_STARTRENAME
, (UINT_PTR
)&paths
, FILEOP_RENAME
);
1129 if (op_result
== FILEOP_ABORT
) goto done
;
1130 while (op_result
== FILEOP_DOIT
)
1132 TRACE( "renaming file %s -> %s\n",
1133 debugstr_w(paths
.Source
), debugstr_w(paths
.Target
) );
1134 if (MoveFileW( paths
.Source
, paths
.Target
)) break; /* success */
1135 paths
.Win32Error
= GetLastError();
1136 op_result
= handler( context
, SPFILENOTIFY_RENAMEERROR
, (UINT_PTR
)&paths
, 0 );
1137 if (op_result
== FILEOP_ABORT
) goto done
;
1139 handler( context
, SPFILENOTIFY_ENDRENAME
, (UINT_PTR
)&paths
, 0 );
1141 handler( context
, SPFILENOTIFY_ENDSUBQUEUE
, FILEOP_RENAME
, 0 );
1144 /* perform copies */
1146 if (queue
->copy_queue
.count
)
1148 if (!(handler( context
, SPFILENOTIFY_STARTSUBQUEUE
, FILEOP_COPY
,
1149 queue
->copy_queue
.count
))) goto done
;
1150 for (op
= queue
->copy_queue
.head
; op
; op
= op
->next
)
1152 WCHAR newpath
[MAX_PATH
];
1154 build_filepathsW( op
, &paths
);
1155 op_result
= handler( context
, SPFILENOTIFY_STARTCOPY
, (UINT_PTR
)&paths
, FILEOP_COPY
);
1156 if (op_result
== FILEOP_ABORT
) goto done
;
1157 if (op_result
== FILEOP_NEWPATH
) op_result
= FILEOP_DOIT
;
1158 while (op_result
== FILEOP_DOIT
|| op_result
== FILEOP_NEWPATH
)
1160 TRACE( "copying file %s -> %s\n",
1161 debugstr_w( op_result
== FILEOP_NEWPATH
? newpath
: paths
.Source
),
1162 debugstr_w(paths
.Target
) );
1165 if (!create_full_pathW( op
->dst_path
))
1167 paths
.Win32Error
= GetLastError();
1168 op_result
= handler( context
, SPFILENOTIFY_COPYERROR
,
1169 (UINT_PTR
)&paths
, (UINT_PTR
)newpath
);
1170 if (op_result
== FILEOP_ABORT
) goto done
;
1173 if (do_file_copyW( op_result
== FILEOP_NEWPATH
? newpath
: paths
.Source
,
1174 paths
.Target
, op
->style
)) break; /* success */
1175 /* try to extract it from the cabinet file */
1178 if (extract_cabinet_file( op
->src_tag
, op
->src_root
,
1179 paths
.Source
, paths
.Target
)) break;
1181 paths
.Win32Error
= GetLastError();
1182 op_result
= handler( context
, SPFILENOTIFY_COPYERROR
,
1183 (UINT_PTR
)&paths
, (UINT_PTR
)newpath
);
1184 if (op_result
== FILEOP_ABORT
) goto done
;
1186 handler( context
, SPFILENOTIFY_ENDCOPY
, (UINT_PTR
)&paths
, 0 );
1188 handler( context
, SPFILENOTIFY_ENDSUBQUEUE
, FILEOP_COPY
, 0 );
1195 handler( context
, SPFILENOTIFY_ENDQUEUE
, result
, 0 );
1196 HeapFree( GetProcessHeap(), 0, (void *)paths
.Source
);
1197 HeapFree( GetProcessHeap(), 0, (void *)paths
.Target
);
1202 /***********************************************************************
1203 * SetupScanFileQueueA (SETUPAPI.@)
1205 BOOL WINAPI
SetupScanFileQueueA( HSPFILEQ queue
, DWORD flags
, HWND window
,
1206 PSP_FILE_CALLBACK_A callback
, PVOID context
, PDWORD result
)
1213 /***********************************************************************
1214 * SetupScanFileQueueW (SETUPAPI.@)
1216 BOOL WINAPI
SetupScanFileQueueW( HSPFILEQ queue
, DWORD flags
, HWND window
,
1217 PSP_FILE_CALLBACK_W callback
, PVOID context
, PDWORD result
)
1224 /***********************************************************************
1225 * SetupGetFileQueueCount (SETUPAPI.@)
1227 BOOL WINAPI
SetupGetFileQueueCount( HSPFILEQ handle
, UINT op
, PUINT result
)
1229 struct file_queue
*queue
= handle
;
1234 *result
= queue
->copy_queue
.count
;
1237 *result
= queue
->rename_queue
.count
;
1240 *result
= queue
->delete_queue
.count
;
1247 /***********************************************************************
1248 * SetupGetFileQueueFlags (SETUPAPI.@)
1250 BOOL WINAPI
SetupGetFileQueueFlags( HSPFILEQ handle
, PDWORD flags
)
1252 struct file_queue
*queue
= handle
;
1253 *flags
= queue
->flags
;
1258 /***********************************************************************
1259 * SetupSetFileQueueFlags (SETUPAPI.@)
1261 BOOL WINAPI
SetupSetFileQueueFlags( HSPFILEQ handle
, DWORD mask
, DWORD flags
)
1263 struct file_queue
*queue
= handle
;
1264 queue
->flags
= (queue
->flags
& ~mask
) | flags
;
1269 /***********************************************************************
1270 * SetupInitDefaultQueueCallback (SETUPAPI.@)
1272 PVOID WINAPI
SetupInitDefaultQueueCallback( HWND owner
)
1274 return SetupInitDefaultQueueCallbackEx( owner
, 0, 0, 0, NULL
);
1278 /***********************************************************************
1279 * SetupInitDefaultQueueCallbackEx (SETUPAPI.@)
1281 PVOID WINAPI
SetupInitDefaultQueueCallbackEx( HWND owner
, HWND progress
, UINT msg
,
1282 DWORD reserved1
, PVOID reserved2
)
1284 struct default_callback_context
*context
;
1286 if ((context
= HeapAlloc( GetProcessHeap(), 0, sizeof(*context
) )))
1288 context
->owner
= owner
;
1289 context
->progress
= progress
;
1290 context
->message
= msg
;
1296 /***********************************************************************
1297 * SetupTermDefaultQueueCallback (SETUPAPI.@)
1299 void WINAPI
SetupTermDefaultQueueCallback( PVOID context
)
1301 HeapFree( GetProcessHeap(), 0, context
);
1305 /***********************************************************************
1306 * SetupDefaultQueueCallbackA (SETUPAPI.@)
1308 UINT WINAPI
SetupDefaultQueueCallbackA( PVOID context
, UINT notification
,
1309 UINT_PTR param1
, UINT_PTR param2
)
1311 FILEPATHS_A
*paths
= (FILEPATHS_A
*)param1
;
1313 switch(notification
)
1315 case SPFILENOTIFY_STARTQUEUE
:
1316 TRACE( "start queue\n" );
1318 case SPFILENOTIFY_ENDQUEUE
:
1319 TRACE( "end queue\n" );
1321 case SPFILENOTIFY_STARTSUBQUEUE
:
1322 TRACE( "start subqueue %d count %d\n", param1
, param2
);
1324 case SPFILENOTIFY_ENDSUBQUEUE
:
1325 TRACE( "end subqueue %d\n", param1
);
1327 case SPFILENOTIFY_STARTDELETE
:
1328 TRACE( "start delete %s\n", debugstr_a(paths
->Target
) );
1330 case SPFILENOTIFY_ENDDELETE
:
1331 TRACE( "end delete %s\n", debugstr_a(paths
->Target
) );
1333 case SPFILENOTIFY_DELETEERROR
:
1334 ERR( "delete error %d %s\n", paths
->Win32Error
, debugstr_a(paths
->Target
) );
1336 case SPFILENOTIFY_STARTRENAME
:
1337 TRACE( "start rename %s -> %s\n", debugstr_a(paths
->Source
), debugstr_a(paths
->Target
) );
1339 case SPFILENOTIFY_ENDRENAME
:
1340 TRACE( "end rename %s -> %s\n", debugstr_a(paths
->Source
), debugstr_a(paths
->Target
) );
1342 case SPFILENOTIFY_RENAMEERROR
:
1343 ERR( "rename error %d %s -> %s\n", paths
->Win32Error
,
1344 debugstr_a(paths
->Source
), debugstr_a(paths
->Target
) );
1346 case SPFILENOTIFY_STARTCOPY
:
1347 TRACE( "start copy %s -> %s\n", debugstr_a(paths
->Source
), debugstr_a(paths
->Target
) );
1349 case SPFILENOTIFY_ENDCOPY
:
1350 TRACE( "end copy %s -> %s\n", debugstr_a(paths
->Source
), debugstr_a(paths
->Target
) );
1352 case SPFILENOTIFY_COPYERROR
:
1353 ERR( "copy error %d %s -> %s\n", paths
->Win32Error
,
1354 debugstr_a(paths
->Source
), debugstr_a(paths
->Target
) );
1356 case SPFILENOTIFY_NEEDMEDIA
:
1357 TRACE( "need media\n" );
1360 FIXME( "notification %d params %x,%x\n", notification
, param1
, param2
);
1367 /***********************************************************************
1368 * SetupDefaultQueueCallbackW (SETUPAPI.@)
1370 UINT WINAPI
SetupDefaultQueueCallbackW( PVOID context
, UINT notification
,
1371 UINT_PTR param1
, UINT_PTR param2
)
1373 FIXME( "notification %d params %x,%x\n", notification
, param1
, param2
);