2 * Setupapi file queue routines
4 * Copyright 2002 Alexandre Julliard for CodeWeavers
6 * This library is free software; you can redistribute it and/or
7 * modify it under the terms of the GNU Lesser General Public
8 * License as published by the Free Software Foundation; either
9 * version 2.1 of the License, or (at your option) any later version.
11 * This library is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14 * Lesser General Public License for more details.
16 * You should have received a copy of the GNU Lesser General Public
17 * License along with this library; if not, write to the Free Software
18 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
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
67 struct source_media
*media
;
80 struct file_op_queue copy_queue
;
81 struct file_op_queue delete_queue
;
82 struct file_op_queue rename_queue
;
84 struct source_media
**sources
;
85 unsigned int source_count
;
88 #define FILE_QUEUE_MAGIC 0x21514653
90 /* append a file operation to a queue */
91 static inline void queue_file_op( struct file_op_queue
*queue
, struct file_op
*op
)
94 if (queue
->tail
) queue
->tail
->next
= op
;
95 else queue
->head
= op
;
100 /* free all the file operations on a given queue */
101 static void free_file_op_queue( struct file_op_queue
*queue
)
103 struct file_op
*t
, *op
= queue
->head
;
107 free( op
->src_path
);
108 free( op
->src_file
);
109 free( op
->dst_path
);
110 if (op
->dst_file
!= op
->src_file
) free( op
->dst_file
);
117 /* concat 3 strings to make a path, handling separators correctly */
118 static void concat_W( WCHAR
*buffer
, const WCHAR
*src1
, const WCHAR
*src2
, const WCHAR
*src3
)
123 lstrcpyW( buffer
, src1
);
124 buffer
+= lstrlenW(buffer
);
125 if (buffer
[-1] != '\\') *buffer
++ = '\\';
127 if (src2
) while (*src2
== '\\') src2
++;
132 lstrcpyW( buffer
, src2
);
133 buffer
+= lstrlenW(buffer
);
134 if (buffer
[-1] != '\\') *buffer
++ = '\\';
136 if (src3
) while (*src3
== '\\') src3
++;
140 lstrcpyW( buffer
, src3
);
144 /***********************************************************************
147 * Build a FILEPATHS_W structure for a given file operation.
149 static BOOL
build_filepathsW( const struct file_op
*op
, FILEPATHS_W
*paths
)
151 unsigned int src_len
= 1, dst_len
= 1;
152 WCHAR
*source
= (PWSTR
)paths
->Source
, *target
= (PWSTR
)paths
->Target
;
154 if (!op
->src_file
|| op
->src_file
[0] != '@')
156 if (op
->media
) src_len
+= lstrlenW(op
->media
->root
) + 1;
157 if (op
->src_path
) src_len
+= lstrlenW(op
->src_path
) + 1;
159 if (op
->src_file
) src_len
+= lstrlenW(op
->src_file
) + 1;
160 if (op
->dst_path
) dst_len
+= lstrlenW(op
->dst_path
) + 1;
161 if (op
->dst_file
) dst_len
+= lstrlenW(op
->dst_file
) + 1;
162 src_len
*= sizeof(WCHAR
);
163 dst_len
*= sizeof(WCHAR
);
165 if (!source
|| HeapSize( GetProcessHeap(), 0, source
) < src_len
)
167 HeapFree( GetProcessHeap(), 0, source
);
168 paths
->Source
= source
= HeapAlloc( GetProcessHeap(), 0, src_len
);
170 if (!target
|| HeapSize( GetProcessHeap(), 0, target
) < dst_len
)
172 HeapFree( GetProcessHeap(), 0, target
);
173 paths
->Target
= target
= HeapAlloc( GetProcessHeap(), 0, dst_len
);
175 if (!source
|| !target
) return FALSE
;
176 if (!op
->src_file
|| op
->src_file
[0] != '@')
177 concat_W( source
, op
->media
? op
->media
->root
: NULL
, op
->src_path
, op
->src_file
);
179 lstrcpyW( source
, op
->src_file
);
180 concat_W( target
, NULL
, op
->dst_path
, op
->dst_file
);
181 paths
->Win32Error
= 0;
187 /***********************************************************************
188 * QUEUE_callback_WtoA
190 * Map a file callback parameters from W to A and call the A callback.
192 UINT CALLBACK
QUEUE_callback_WtoA( void *context
, UINT notification
,
193 UINT_PTR param1
, UINT_PTR param2
)
195 struct callback_WtoA_context
*callback_ctx
= context
;
196 char buffer
[MAX_PATH
];
198 UINT_PTR old_param2
= param2
;
202 case SPFILENOTIFY_COPYERROR
:
204 param2
= (UINT_PTR
)buffer
;
206 case SPFILENOTIFY_STARTDELETE
:
207 case SPFILENOTIFY_ENDDELETE
:
208 case SPFILENOTIFY_DELETEERROR
:
209 case SPFILENOTIFY_STARTRENAME
:
210 case SPFILENOTIFY_ENDRENAME
:
211 case SPFILENOTIFY_RENAMEERROR
:
212 case SPFILENOTIFY_STARTCOPY
:
213 case SPFILENOTIFY_ENDCOPY
:
214 case SPFILENOTIFY_QUEUESCAN_EX
:
216 FILEPATHS_W
*pathsW
= (FILEPATHS_W
*)param1
;
219 pathsA
.Source
= strdupWtoA( pathsW
->Source
);
220 pathsA
.Target
= strdupWtoA( pathsW
->Target
);
221 pathsA
.Win32Error
= pathsW
->Win32Error
;
222 pathsA
.Flags
= pathsW
->Flags
;
223 ret
= callback_ctx
->orig_handler( callback_ctx
->orig_context
, notification
,
224 (UINT_PTR
)&pathsA
, param2
);
225 HeapFree( GetProcessHeap(), 0, (void *)pathsA
.Source
);
226 HeapFree( GetProcessHeap(), 0, (void *)pathsA
.Target
);
228 if (notification
== SPFILENOTIFY_COPYERROR
)
229 MultiByteToWideChar( CP_ACP
, 0, buffer
, -1, (WCHAR
*)old_param2
, MAX_PATH
);
232 case SPFILENOTIFY_STARTREGISTRATION
:
233 case SPFILENOTIFY_ENDREGISTRATION
:
235 SP_REGISTER_CONTROL_STATUSW
*statusW
= (SP_REGISTER_CONTROL_STATUSW
*)param1
;
236 SP_REGISTER_CONTROL_STATUSA statusA
;
238 statusA
.cbSize
= sizeof(statusA
);
239 statusA
.FileName
= strdupWtoA( statusW
->FileName
);
240 statusA
.Win32Error
= statusW
->Win32Error
;
241 statusA
.FailureCode
= statusW
->FailureCode
;
242 ret
= callback_ctx
->orig_handler( callback_ctx
->orig_context
, notification
,
243 (UINT_PTR
)&statusA
, param2
);
244 free( (char *)statusA
.FileName
);
248 case SPFILENOTIFY_QUEUESCAN
:
250 LPWSTR targetW
= (LPWSTR
)param1
;
251 LPSTR target
= strdupWtoA( targetW
);
253 ret
= callback_ctx
->orig_handler( callback_ctx
->orig_context
, notification
,
254 (UINT_PTR
)target
, param2
);
259 case SPFILENOTIFY_NEEDMEDIA
:
261 const SOURCE_MEDIA_W
*mediaW
= (const SOURCE_MEDIA_W
*)param1
;
263 SOURCE_MEDIA_A mediaA
;
265 mediaA
.Tagfile
= strdupWtoA(mediaW
->Tagfile
);
266 mediaA
.Description
= strdupWtoA(mediaW
->Description
);
267 mediaA
.SourcePath
= strdupWtoA(mediaW
->SourcePath
);
268 mediaA
.SourceFile
= strdupWtoA(mediaW
->SourceFile
);
269 mediaA
.Flags
= mediaW
->Flags
;
272 ret
= callback_ctx
->orig_handler(callback_ctx
->orig_context
, notification
,
273 (UINT_PTR
)&mediaA
, (UINT_PTR
)&path
);
274 MultiByteToWideChar(CP_ACP
, 0, path
, -1, (WCHAR
*)param2
, MAX_PATH
);
276 free((char *)mediaA
.Tagfile
);
277 free((char *)mediaA
.Description
);
278 free((char *)mediaA
.SourcePath
);
279 free((char *)mediaA
.SourceFile
);
282 case SPFILENOTIFY_STARTQUEUE
:
283 case SPFILENOTIFY_ENDQUEUE
:
284 case SPFILENOTIFY_STARTSUBQUEUE
:
285 case SPFILENOTIFY_ENDSUBQUEUE
:
287 ret
= callback_ctx
->orig_handler( callback_ctx
->orig_context
, notification
, param1
, param2
);
293 static void get_source_info( HINF hinf
, const WCHAR
*src_file
, SP_FILE_COPY_PARAMS_W
*params
,
294 WCHAR
*src_root
, WCHAR
*src_path
)
296 INFCONTEXT file_ctx
, disk_ctx
;
300 /* find the SourceDisksFiles entry */
301 if (!SetupFindFirstLineW( hinf
, L
"SourceDisksFiles", src_file
, &file_ctx
)) return;
302 if (!SetupGetIntField( &file_ctx
, 1, &diskid
)) return;
304 /* now find the diskid in the SourceDisksNames section */
305 if (!SetupFindFirstLineW( hinf
, L
"SourceDisksNames", NULL
, &disk_ctx
)) return;
308 if (SetupGetIntField( &disk_ctx
, 0, &id
) && (id
== diskid
)) break;
309 if (!SetupFindNextLine( &disk_ctx
, &disk_ctx
)) return;
312 if (SetupGetStringFieldW( &disk_ctx
, 1, NULL
, 0, &len
) && len
> sizeof(WCHAR
)
313 && (params
->SourceDescription
= malloc( len
* sizeof(WCHAR
) )))
314 SetupGetStringFieldW( &disk_ctx
, 1, (WCHAR
*)params
->SourceDescription
, len
, NULL
);
316 if (SetupGetStringFieldW( &disk_ctx
, 2, NULL
, 0, &len
) && len
> sizeof(WCHAR
)
317 && (params
->SourceTagfile
= malloc( len
* sizeof(WCHAR
) )))
318 SetupGetStringFieldW( &disk_ctx
, 2, (WCHAR
*)params
->SourceTagfile
, len
, NULL
);
320 if (SetupGetStringFieldW( &disk_ctx
, 4, NULL
, 0, &len
) && len
> sizeof(WCHAR
)
321 && len
< MAX_PATH
- lstrlenW( src_root
) - 1)
323 lstrcatW( src_root
, L
"\\" );
324 SetupGetStringFieldW( &disk_ctx
, 4, src_root
+ lstrlenW( src_root
),
325 MAX_PATH
- lstrlenW( src_root
), NULL
);
328 if (SetupGetStringFieldW( &file_ctx
, 2, NULL
, 0, &len
) && len
> sizeof(WCHAR
) && len
< MAX_PATH
)
330 SetupGetStringFieldW( &file_ctx
, 2, src_path
, MAX_PATH
, NULL
);
331 params
->SourcePath
= src_path
;
335 /***********************************************************************
336 * get_destination_dir
338 * Retrieve the destination dir for a given section.
340 static WCHAR
*get_destination_dir( HINF hinf
, const WCHAR
*section
)
343 WCHAR systemdir
[MAX_PATH
], *dir
;
346 if (!section
|| !(ret
= SetupFindFirstLineW( hinf
, L
"DestinationDirs", section
, &context
)))
347 ret
= SetupFindFirstLineW( hinf
, L
"DestinationDirs", L
"DefaultDestDir", &context
);
349 if (ret
&& (dir
= PARSER_get_dest_dir( &context
)))
352 GetSystemDirectoryW( systemdir
, MAX_PATH
);
353 return wcsdup( systemdir
);
356 struct extract_cab_ctx
362 static UINT WINAPI
extract_cab_cb( void *arg
, UINT message
, UINT_PTR param1
, UINT_PTR param2
)
364 struct extract_cab_ctx
*ctx
= arg
;
368 case SPFILENOTIFY_FILEINCABINET
:
370 FILE_IN_CABINET_INFO_W
*info
= (FILE_IN_CABINET_INFO_W
*)param1
;
371 const WCHAR
*filename
;
373 if ((filename
= wcsrchr( info
->NameInCabinet
, '\\' )))
376 filename
= info
->NameInCabinet
;
378 if (lstrcmpiW( filename
, ctx
->src
))
381 lstrcpyW( info
->FullTargetName
, ctx
->dst
);
384 case SPFILENOTIFY_FILEEXTRACTED
:
386 const FILEPATHS_W
*paths
= (const FILEPATHS_W
*)param1
;
387 return paths
->Win32Error
;
389 case SPFILENOTIFY_NEEDNEWCABINET
:
391 const CABINET_INFO_W
*info
= (const CABINET_INFO_W
*)param1
;
392 lstrcpyW( (WCHAR
*)param2
, info
->CabinetPath
);
393 return ERROR_SUCCESS
;
395 case SPFILENOTIFY_CABINETINFO
:
398 FIXME("Unexpected message %#x.\n", message
);
403 /***********************************************************************
404 * extract_cabinet_file
406 * Extract a file from a .cab file.
408 static BOOL
extract_cabinet_file( const WCHAR
*cabinet
, const WCHAR
*root
,
409 const WCHAR
*src
, const WCHAR
*dst
)
411 struct extract_cab_ctx ctx
= {src
, dst
};
412 int len
= lstrlenW( cabinet
);
413 WCHAR path
[MAX_PATH
];
415 /* make sure the cabinet file has a .cab extension */
416 if (len
<= 4 || wcsicmp( cabinet
+ len
- 4, L
".cab" )) return FALSE
;
418 lstrcpyW(path
, root
);
419 lstrcatW(path
, L
"\\" );
420 lstrcatW(path
, cabinet
);
422 return SetupIterateCabinetW( path
, 0, extract_cab_cb
, &ctx
);
425 /***********************************************************************
426 * SetupOpenFileQueue (SETUPAPI.@)
428 HSPFILEQ WINAPI
SetupOpenFileQueue(void)
430 struct file_queue
*queue
;
432 if (!(queue
= calloc( 1, sizeof(*queue
) )))
433 return INVALID_HANDLE_VALUE
;
434 queue
->magic
= FILE_QUEUE_MAGIC
;
439 /***********************************************************************
440 * SetupCloseFileQueue (SETUPAPI.@)
442 BOOL WINAPI
SetupCloseFileQueue( HSPFILEQ handle
)
444 struct file_queue
*queue
= handle
;
447 /* Windows XP DDK installer passes the handle returned from
448 * SetupInitDefaultQueueCallback() to this function. */
449 if (queue
->magic
!= FILE_QUEUE_MAGIC
)
451 SetLastError(ERROR_INVALID_HANDLE
);
455 free_file_op_queue( &queue
->copy_queue
);
456 free_file_op_queue( &queue
->rename_queue
);
457 free_file_op_queue( &queue
->delete_queue
);
458 for (i
= 0; i
< queue
->source_count
; ++i
)
460 free( queue
->sources
[i
]->desc
);
461 free( queue
->sources
[i
]->tag
);
462 free( queue
->sources
[i
] );
464 free( queue
->sources
);
470 /***********************************************************************
471 * SetupQueueCopyIndirectA (SETUPAPI.@)
473 BOOL WINAPI
SetupQueueCopyIndirectA( SP_FILE_COPY_PARAMS_A
*paramsA
)
475 SP_FILE_COPY_PARAMS_W paramsW
;
478 paramsW
.cbSize
= sizeof(paramsW
);
479 paramsW
.QueueHandle
= paramsA
->QueueHandle
;
480 paramsW
.SourceRootPath
= strdupAtoW( paramsA
->SourceRootPath
);
481 paramsW
.SourcePath
= strdupAtoW( paramsA
->SourcePath
);
482 paramsW
.SourceFilename
= strdupAtoW( paramsA
->SourceFilename
);
483 paramsW
.SourceDescription
= strdupAtoW( paramsA
->SourceDescription
);
484 paramsW
.SourceTagfile
= strdupAtoW( paramsA
->SourceTagfile
);
485 paramsW
.TargetDirectory
= strdupAtoW( paramsA
->TargetDirectory
);
486 paramsW
.TargetFilename
= strdupAtoW( paramsA
->TargetFilename
);
487 paramsW
.CopyStyle
= paramsA
->CopyStyle
;
488 paramsW
.LayoutInf
= paramsA
->LayoutInf
;
489 paramsW
.SecurityDescriptor
= strdupAtoW( paramsA
->SecurityDescriptor
);
491 ret
= SetupQueueCopyIndirectW( ¶msW
);
493 free( (WCHAR
*)paramsW
.SourceRootPath
);
494 free( (WCHAR
*)paramsW
.SourcePath
);
495 free( (WCHAR
*)paramsW
.SourceFilename
);
496 free( (WCHAR
*)paramsW
.SourceDescription
);
497 free( (WCHAR
*)paramsW
.SourceTagfile
);
498 free( (WCHAR
*)paramsW
.TargetDirectory
);
499 free( (WCHAR
*)paramsW
.TargetFilename
);
500 free( (WCHAR
*)paramsW
.SecurityDescriptor
);
504 static BOOL
equal_str(const WCHAR
*a
, const WCHAR
*b
)
506 return (!a
&& !b
) || (a
&& b
&& !wcscmp(a
, b
));
509 static struct source_media
*get_source_media(struct file_queue
*queue
,
510 const WCHAR
*root
, const WCHAR
*desc
, const WCHAR
*tag
)
514 for (i
= 0; i
< queue
->source_count
; ++i
)
516 if (!wcscmp(root
, queue
->sources
[i
]->root
)
517 && equal_str(desc
, queue
->sources
[i
]->desc
)
518 && equal_str(tag
, queue
->sources
[i
]->tag
))
520 return queue
->sources
[i
];
524 queue
->sources
= realloc( queue
->sources
, ++queue
->source_count
* sizeof(*queue
->sources
) );
525 queue
->sources
[i
] = malloc( sizeof(*queue
->sources
[i
]) );
526 lstrcpyW(queue
->sources
[i
]->root
, root
);
527 queue
->sources
[i
]->desc
= wcsdup( desc
);
528 queue
->sources
[i
]->tag
= wcsdup( tag
);
529 queue
->sources
[i
]->resolved
= FALSE
;
530 queue
->sources
[i
]->cabinet
= FALSE
;
532 return queue
->sources
[i
];
535 /***********************************************************************
536 * SetupQueueCopyIndirectW (SETUPAPI.@)
538 BOOL WINAPI
SetupQueueCopyIndirectW( PSP_FILE_COPY_PARAMS_W params
)
540 struct file_queue
*queue
= params
->QueueHandle
;
543 if (!(op
= malloc( sizeof(*op
) ))) return FALSE
;
544 op
->style
= params
->CopyStyle
;
545 op
->src_path
= wcsdup( params
->SourcePath
);
546 op
->src_file
= wcsdup( params
->SourceFilename
);
547 op
->dst_path
= wcsdup( params
->TargetDirectory
);
548 op
->dst_file
= wcsdup( params
->TargetFilename
);
551 if (!op
->dst_file
) op
->dst_file
= op
->src_file
;
552 if (params
->LayoutInf
)
553 FIXME("Unhandled LayoutInf %p.\n", params
->LayoutInf
);
555 op
->media
= get_source_media( queue
, params
->SourceRootPath
? params
->SourceRootPath
: L
"",
556 params
->SourceDescription
, params
->SourceTagfile
);
558 TRACE( "root=%s path=%s file=%s -> dir=%s file=%s descr=%s tag=%s\n",
559 debugstr_w(op
->media
->root
), debugstr_w(op
->src_path
), debugstr_w(op
->src_file
),
560 debugstr_w(op
->dst_path
), debugstr_w(op
->dst_file
),
561 debugstr_w(op
->media
->desc
), debugstr_w(op
->media
->tag
) );
563 queue_file_op( &queue
->copy_queue
, op
);
568 /***********************************************************************
569 * SetupQueueCopyA (SETUPAPI.@)
571 BOOL WINAPI
SetupQueueCopyA( HSPFILEQ queue
, PCSTR src_root
, PCSTR src_path
, PCSTR src_file
,
572 PCSTR src_descr
, PCSTR src_tag
, PCSTR dst_dir
, PCSTR dst_file
,
575 SP_FILE_COPY_PARAMS_A params
;
577 params
.cbSize
= sizeof(params
);
578 params
.QueueHandle
= queue
;
579 params
.SourceRootPath
= src_root
;
580 params
.SourcePath
= src_path
;
581 params
.SourceFilename
= src_file
;
582 params
.SourceDescription
= src_descr
;
583 params
.SourceTagfile
= src_tag
;
584 params
.TargetDirectory
= dst_dir
;
585 params
.TargetFilename
= dst_file
;
586 params
.CopyStyle
= style
;
587 params
.LayoutInf
= 0;
588 params
.SecurityDescriptor
= NULL
;
589 return SetupQueueCopyIndirectA( ¶ms
);
593 /***********************************************************************
594 * SetupQueueCopyW (SETUPAPI.@)
596 BOOL WINAPI
SetupQueueCopyW( HSPFILEQ queue
, PCWSTR src_root
, PCWSTR src_path
, PCWSTR src_file
,
597 PCWSTR src_descr
, PCWSTR src_tag
, PCWSTR dst_dir
, PCWSTR dst_file
,
600 SP_FILE_COPY_PARAMS_W params
;
602 params
.cbSize
= sizeof(params
);
603 params
.QueueHandle
= queue
;
604 params
.SourceRootPath
= src_root
;
605 params
.SourcePath
= src_path
;
606 params
.SourceFilename
= src_file
;
607 params
.SourceDescription
= src_descr
;
608 params
.SourceTagfile
= src_tag
;
609 params
.TargetDirectory
= dst_dir
;
610 params
.TargetFilename
= dst_file
;
611 params
.CopyStyle
= style
;
612 params
.LayoutInf
= 0;
613 params
.SecurityDescriptor
= NULL
;
614 return SetupQueueCopyIndirectW( ¶ms
);
618 /***********************************************************************
619 * SetupQueueDefaultCopyA (SETUPAPI.@)
621 BOOL WINAPI
SetupQueueDefaultCopyA( HSPFILEQ queue
, HINF hinf
, const char *src_rootA
,
622 const char *src_fileA
, const char *dst_fileA
, DWORD style
)
624 WCHAR src_rootW
[MAX_PATH
], src_fileW
[MAX_PATH
], dst_fileW
[MAX_PATH
];
626 if (!src_rootA
|| !src_fileA
|| !dst_fileA
)
628 SetLastError(ERROR_INVALID_PARAMETER
);
632 MultiByteToWideChar( CP_ACP
, 0, src_rootA
, -1, src_rootW
, ARRAY_SIZE(src_rootW
) );
633 MultiByteToWideChar( CP_ACP
, 0, src_fileA
, -1, src_fileW
, ARRAY_SIZE(src_fileW
) );
634 MultiByteToWideChar( CP_ACP
, 0, dst_fileA
, -1, dst_fileW
, ARRAY_SIZE(dst_fileW
) );
635 return SetupQueueDefaultCopyW( queue
, hinf
, src_rootW
, src_fileW
, dst_fileW
, style
);
639 /***********************************************************************
640 * SetupQueueDefaultCopyW (SETUPAPI.@)
642 BOOL WINAPI
SetupQueueDefaultCopyW( HSPFILEQ queue
, HINF hinf
, PCWSTR src_root
, PCWSTR src_file
,
643 PCWSTR dst_file
, DWORD style
)
645 WCHAR src_root_buffer
[MAX_PATH
], src_path
[MAX_PATH
];
646 SP_FILE_COPY_PARAMS_W params
;
649 if (!src_root
|| !src_file
|| !dst_file
)
651 SetLastError(ERROR_INVALID_PARAMETER
);
655 params
.cbSize
= sizeof(params
);
656 params
.QueueHandle
= queue
;
657 params
.SourceRootPath
= src_root_buffer
;
658 params
.SourcePath
= NULL
;
659 params
.SourceFilename
= src_file
;
660 params
.SourceDescription
= NULL
;
661 params
.SourceTagfile
= NULL
;
662 params
.TargetFilename
= dst_file
;
663 params
.CopyStyle
= style
;
664 params
.LayoutInf
= NULL
;
665 params
.SecurityDescriptor
= NULL
;
667 lstrcpyW( src_root_buffer
, src_root
);
669 if (!(params
.TargetDirectory
= get_destination_dir( hinf
, NULL
))) return FALSE
;
670 get_source_info( hinf
, src_file
, ¶ms
, src_root_buffer
, src_path
);
672 ret
= SetupQueueCopyIndirectW( ¶ms
);
674 free( (WCHAR
*)params
.TargetDirectory
);
675 free( (WCHAR
*)params
.SourceDescription
);
676 free( (WCHAR
*)params
.SourceTagfile
);
681 /***********************************************************************
682 * SetupQueueDeleteA (SETUPAPI.@)
684 BOOL WINAPI
SetupQueueDeleteA( HSPFILEQ handle
, PCSTR part1
, PCSTR part2
)
686 struct file_queue
*queue
= handle
;
689 if (!(op
= calloc( 1, sizeof(*op
) ))) return FALSE
;
690 op
->dst_path
= strdupAtoW( part1
);
691 op
->dst_file
= strdupAtoW( part2
);
692 queue_file_op( &queue
->delete_queue
, op
);
697 /***********************************************************************
698 * SetupQueueDeleteW (SETUPAPI.@)
700 BOOL WINAPI
SetupQueueDeleteW( HSPFILEQ handle
, PCWSTR part1
, PCWSTR part2
)
702 struct file_queue
*queue
= handle
;
705 if (!(op
= calloc( 1, sizeof(*op
) ))) return FALSE
;
706 op
->dst_path
= wcsdup( part1
);
707 op
->dst_file
= wcsdup( part2
);
708 queue_file_op( &queue
->delete_queue
, op
);
713 /***********************************************************************
714 * SetupQueueRenameA (SETUPAPI.@)
716 BOOL WINAPI
SetupQueueRenameA( HSPFILEQ handle
, PCSTR SourcePath
, PCSTR SourceFilename
,
717 PCSTR TargetPath
, PCSTR TargetFilename
)
719 struct file_queue
*queue
= handle
;
722 if (!(op
= calloc( 1, sizeof(*op
) ))) return FALSE
;
723 op
->src_path
= strdupAtoW( SourcePath
);
724 op
->src_file
= strdupAtoW( SourceFilename
);
725 op
->dst_path
= strdupAtoW( TargetPath
? TargetPath
: SourcePath
);
726 op
->dst_file
= strdupAtoW( TargetFilename
);
727 queue_file_op( &queue
->rename_queue
, op
);
732 /***********************************************************************
733 * SetupQueueRenameW (SETUPAPI.@)
735 BOOL WINAPI
SetupQueueRenameW( HSPFILEQ handle
, PCWSTR SourcePath
, PCWSTR SourceFilename
,
736 PCWSTR TargetPath
, PCWSTR TargetFilename
)
738 struct file_queue
*queue
= handle
;
741 if (!(op
= calloc( 1, sizeof(*op
) ))) return FALSE
;
742 op
->src_path
= wcsdup( SourcePath
);
743 op
->src_file
= wcsdup( SourceFilename
);
744 op
->dst_path
= wcsdup( TargetPath
? TargetPath
: SourcePath
);
745 op
->dst_file
= wcsdup( TargetFilename
);
746 queue_file_op( &queue
->rename_queue
, op
);
751 /***********************************************************************
752 * SetupQueueCopySectionA (SETUPAPI.@)
754 BOOL WINAPI
SetupQueueCopySectionA( HSPFILEQ queue
, PCSTR src_root
, HINF hinf
, HINF hlist
,
755 PCSTR section
, DWORD style
)
757 UNICODE_STRING sectionW
;
760 if (!RtlCreateUnicodeStringFromAsciiz( §ionW
, section
))
762 SetLastError( ERROR_NOT_ENOUGH_MEMORY
);
766 ret
= SetupQueueCopySectionW( queue
, NULL
, hinf
, hlist
, sectionW
.Buffer
, style
);
770 if (RtlCreateUnicodeStringFromAsciiz( &srcW
, src_root
))
772 ret
= SetupQueueCopySectionW( queue
, srcW
.Buffer
, hinf
, hlist
, sectionW
.Buffer
, style
);
773 RtlFreeUnicodeString( &srcW
);
775 else SetLastError( ERROR_NOT_ENOUGH_MEMORY
);
777 RtlFreeUnicodeString( §ionW
);
781 /***********************************************************************
782 * SetupQueueCopySectionW (SETUPAPI.@)
784 BOOL WINAPI
SetupQueueCopySectionW( HSPFILEQ queue
, PCWSTR src_root
, HINF hinf
, HINF hlist
,
785 PCWSTR section
, DWORD style
)
787 WCHAR src_root_buffer
[MAX_PATH
], src_path
[MAX_PATH
], src_file
[MAX_PATH
], dst_file
[MAX_PATH
], *dest_dir
;
789 SP_FILE_COPY_PARAMS_W params
;
794 TRACE("queue %p, src_root %s, hinf %p, hlist %p, section %s, style %#lx.\n",
795 queue
, debugstr_w(src_root
), hinf
, hlist
, debugstr_w(section
), style
);
799 SetLastError(ERROR_INVALID_PARAMETER
);
803 params
.cbSize
= sizeof(params
);
804 params
.QueueHandle
= queue
;
805 params
.SourceRootPath
= src_root_buffer
;
806 params
.SourceFilename
= src_file
;
807 params
.TargetFilename
= dst_file
;
808 params
.CopyStyle
= style
;
809 params
.LayoutInf
= NULL
;
810 params
.SecurityDescriptor
= NULL
;
812 lstrcpyW( src_root_buffer
, src_root
);
814 if (!hlist
) hlist
= hinf
;
815 if (!hinf
) hinf
= hlist
;
816 if (!SetupFindFirstLineW( hlist
, section
, NULL
, &context
)) return FALSE
;
817 if (!(params
.TargetDirectory
= dest_dir
= get_destination_dir( hinf
, section
))) return FALSE
;
820 params
.SourcePath
= NULL
;
821 params
.SourceDescription
= NULL
;
822 params
.SourceTagfile
= NULL
;
823 lstrcpyW( src_root_buffer
, src_root
);
826 if (!SetupGetStringFieldW( &context
, 1, dst_file
, ARRAY_SIZE( dst_file
), NULL
))
828 if (!SetupGetStringFieldW( &context
, 2, src_file
, ARRAY_SIZE( src_file
), &len
) || len
<= sizeof(WCHAR
))
829 lstrcpyW( src_file
, dst_file
);
831 if (!SetupGetIntField( &context
, 4, &flags
)) flags
= 0; /* FIXME */
833 get_source_info( hinf
, src_file
, ¶ms
, src_root_buffer
, src_path
);
835 if (!SetupQueueCopyIndirectW( ¶ms
)) goto end
;
837 free( (WCHAR
*)params
.SourceDescription
);
838 free( (WCHAR
*)params
.SourceTagfile
);
839 } while (SetupFindNextLine( &context
, &context
));
848 /***********************************************************************
849 * SetupQueueDeleteSectionA (SETUPAPI.@)
851 BOOL WINAPI
SetupQueueDeleteSectionA( HSPFILEQ queue
, HINF hinf
, HINF hlist
, PCSTR section
)
853 UNICODE_STRING sectionW
;
856 if (RtlCreateUnicodeStringFromAsciiz( §ionW
, section
))
858 ret
= SetupQueueDeleteSectionW( queue
, hinf
, hlist
, sectionW
.Buffer
);
859 RtlFreeUnicodeString( §ionW
);
861 else SetLastError( ERROR_NOT_ENOUGH_MEMORY
);
866 /***********************************************************************
867 * SetupQueueDeleteSectionW (SETUPAPI.@)
869 BOOL WINAPI
SetupQueueDeleteSectionW( HSPFILEQ queue
, HINF hinf
, HINF hlist
, PCWSTR section
)
873 WCHAR buffer
[MAX_PATH
];
877 TRACE( "hinf=%p/%p section=%s\n", hinf
, hlist
, debugstr_w(section
) );
879 if (!hlist
) hlist
= hinf
;
880 if (!SetupFindFirstLineW( hlist
, section
, NULL
, &context
)) return FALSE
;
881 if (!(dest_dir
= get_destination_dir( hinf
, section
))) return FALSE
;
884 if (!SetupGetStringFieldW( &context
, 1, buffer
, ARRAY_SIZE( buffer
), NULL
))
886 if (!SetupGetIntField( &context
, 4, &flags
)) flags
= 0;
887 if (!SetupQueueDeleteW( queue
, dest_dir
, buffer
)) goto done
;
888 } while (SetupFindNextLine( &context
, &context
));
897 /***********************************************************************
898 * SetupQueueRenameSectionA (SETUPAPI.@)
900 BOOL WINAPI
SetupQueueRenameSectionA( HSPFILEQ queue
, HINF hinf
, HINF hlist
, PCSTR section
)
902 UNICODE_STRING sectionW
;
905 if (RtlCreateUnicodeStringFromAsciiz( §ionW
, section
))
907 ret
= SetupQueueRenameSectionW( queue
, hinf
, hlist
, sectionW
.Buffer
);
908 RtlFreeUnicodeString( §ionW
);
910 else SetLastError( ERROR_NOT_ENOUGH_MEMORY
);
915 /***********************************************************************
916 * SetupQueueRenameSectionW (SETUPAPI.@)
918 BOOL WINAPI
SetupQueueRenameSectionW( HSPFILEQ queue
, HINF hinf
, HINF hlist
, PCWSTR section
)
922 WCHAR src
[MAX_PATH
], dst
[MAX_PATH
];
925 TRACE( "hinf=%p/%p section=%s\n", hinf
, hlist
, debugstr_w(section
) );
927 if (!hlist
) hlist
= hinf
;
928 if (!SetupFindFirstLineW( hlist
, section
, NULL
, &context
)) return FALSE
;
929 if (!(dest_dir
= get_destination_dir( hinf
, section
))) return FALSE
;
932 if (!SetupGetStringFieldW( &context
, 1, dst
, ARRAY_SIZE( dst
), NULL
))
934 if (!SetupGetStringFieldW( &context
, 2, src
, ARRAY_SIZE( src
), NULL
))
936 if (!SetupQueueRenameW( queue
, dest_dir
, src
, NULL
, dst
)) goto done
;
937 } while (SetupFindNextLine( &context
, &context
));
946 /***********************************************************************
947 * SetupCommitFileQueueA (SETUPAPI.@)
949 BOOL WINAPI
SetupCommitFileQueueA( HWND owner
, HSPFILEQ queue
, PSP_FILE_CALLBACK_A handler
,
952 struct callback_WtoA_context ctx
;
954 ctx
.orig_context
= context
;
955 ctx
.orig_handler
= handler
;
956 return SetupCommitFileQueueW( owner
, queue
, QUEUE_callback_WtoA
, &ctx
);
960 /***********************************************************************
963 * Recursively create all directories in the path.
965 static BOOL
create_full_pathW(const WCHAR
*path
)
971 new_path
= malloc((lstrlenW(path
) + 1) * sizeof(WCHAR
));
972 lstrcpyW(new_path
, path
);
974 while((len
= lstrlenW(new_path
)) && new_path
[len
- 1] == '\\')
975 new_path
[len
- 1] = 0;
977 while(!CreateDirectoryW(new_path
, NULL
))
980 DWORD last_error
= GetLastError();
982 if(last_error
== ERROR_ALREADY_EXISTS
)
985 if(last_error
!= ERROR_PATH_NOT_FOUND
)
991 if(!(slash
= wcsrchr(new_path
, '\\')))
997 len
= slash
- new_path
;
999 if(!create_full_pathW(new_path
))
1004 new_path
[len
] = '\\';
1011 static BOOL
copy_file( LPCWSTR source
, LPCWSTR target
)
1013 WCHAR module
[MAX_PATH
];
1018 DWORD size
, written
;
1023 TRACE( "%s -> %s\n", debugstr_w(source
), debugstr_w(target
) );
1025 if (source
[0] != '@') return CopyFileW( source
, target
, FALSE
);
1027 /* Wine extension: when the source of a file copy is in the format "@file.dll,-123"
1028 * the source data is extracted from the corresponding file.dll resource */
1030 source
++; /* skip '@' */
1031 p
= wcschr( source
, ',' );
1032 if (!p
|| p
- source
>= MAX_PATH
)
1034 SetLastError( ERROR_RESOURCE_DATA_NOT_FOUND
);
1037 memcpy( module
, source
, (p
- source
) * sizeof(WCHAR
) );
1038 module
[p
- source
] = 0;
1039 id
= -wcstol( p
+ 1, NULL
, 10 );
1040 if (id
<= 0 || id
> 0xffff ||
1041 !(mod
= LoadLibraryExW( module
, 0, LOAD_LIBRARY_AS_DATAFILE
)) ||
1042 !(res
= FindResourceW( mod
, MAKEINTRESOURCEW(id
), L
"WINE_DATA_FILE" )) ||
1043 !(data
= LoadResource( mod
, res
)))
1045 WARN( "failed to save %s #%d to %s\n", debugstr_w(module
), -id
, debugstr_w(target
) );
1046 if (mod
) FreeLibrary( mod
);
1047 SetLastError( ERROR_RESOURCE_DATA_NOT_FOUND
);
1050 size
= SizeofResource( mod
, res
);
1051 if ((handle
= CreateFileW( target
, GENERIC_WRITE
, FILE_SHARE_READ
| FILE_SHARE_WRITE
, NULL
,
1052 CREATE_ALWAYS
, 0, 0 )) == INVALID_HANDLE_VALUE
)
1054 WARN( "failed to save %s #%d to %s\n", debugstr_w(module
), -id
, debugstr_w(target
) );
1055 if (mod
) FreeLibrary( mod
);
1058 ret
= WriteFile( handle
, LockResource(data
), size
, &written
, NULL
) && written
== size
;
1059 CloseHandle( handle
);
1060 if (!ret
) DeleteFileW( target
);
1064 static BOOL
do_file_copyW( LPCWSTR source
, LPCWSTR target
, DWORD style
,
1065 PSP_FILE_CALLBACK_W handler
, PVOID context
)
1070 TRACE("copy %s to %s style 0x%lx\n",debugstr_w(source
),debugstr_w(target
),style
);
1072 /* before copy processing */
1073 if (style
& SP_COPY_REPLACEONLY
)
1075 if (GetFileAttributesW(target
) == INVALID_FILE_ATTRIBUTES
)
1078 if (style
& (SP_COPY_NEWER_OR_SAME
| SP_COPY_NEWER_ONLY
| SP_COPY_FORCE_NEWER
))
1080 DWORD VersionSizeSource
=0;
1081 DWORD VersionSizeTarget
=0;
1085 * This is sort of an interesting workaround. You see, calling
1086 * GetVersionInfoSize on a builtin dll loads that dll into memory
1087 * and we do not properly unload builtin dlls.. so we effectively
1088 * lock into memory all the targets we are replacing. This leads
1089 * to problems when we try to register the replaced dlls.
1091 * So I will test for the existence of the files first so that
1092 * we just basically unconditionally replace the builtin versions.
1094 if ((GetFileAttributesW(target
) != INVALID_FILE_ATTRIBUTES
) &&
1095 (GetFileAttributesW(source
) != INVALID_FILE_ATTRIBUTES
))
1097 VersionSizeSource
= GetFileVersionInfoSizeW(source
,&zero
);
1098 VersionSizeTarget
= GetFileVersionInfoSizeW(target
,&zero
);
1101 if (VersionSizeSource
&& VersionSizeTarget
)
1103 LPVOID VersionSource
;
1104 LPVOID VersionTarget
;
1105 VS_FIXEDFILEINFO
*TargetInfo
;
1106 VS_FIXEDFILEINFO
*SourceInfo
;
1110 VersionSource
= malloc(VersionSizeSource
);
1111 VersionTarget
= malloc(VersionSizeTarget
);
1113 ret
= GetFileVersionInfoW(source
,0,VersionSizeSource
,VersionSource
);
1115 ret
= GetFileVersionInfoW(target
, 0, VersionSizeTarget
,
1120 ret
= VerQueryValueW(VersionSource
, L
"\\", (LPVOID
*)&SourceInfo
, &length
);
1122 ret
= VerQueryValueW(VersionTarget
, L
"\\", (LPVOID
*)&TargetInfo
, &length
);
1126 FILEPATHS_W filepaths
;
1128 TRACE("Versions: Source %li.%li target %li.%li\n",
1129 SourceInfo
->dwFileVersionMS
, SourceInfo
->dwFileVersionLS
,
1130 TargetInfo
->dwFileVersionMS
, TargetInfo
->dwFileVersionLS
);
1132 /* used in case of notification */
1133 filepaths
.Target
= target
;
1134 filepaths
.Source
= source
;
1135 filepaths
.Win32Error
= 0;
1136 filepaths
.Flags
= 0;
1138 if (TargetInfo
->dwFileVersionMS
> SourceInfo
->dwFileVersionMS
)
1141 docopy
= handler (context
, SPFILENOTIFY_TARGETNEWER
, (UINT_PTR
)&filepaths
, 0);
1145 else if ((TargetInfo
->dwFileVersionMS
== SourceInfo
->dwFileVersionMS
)
1146 && (TargetInfo
->dwFileVersionLS
> SourceInfo
->dwFileVersionLS
))
1149 docopy
= handler (context
, SPFILENOTIFY_TARGETNEWER
, (UINT_PTR
)&filepaths
, 0);
1153 else if ((style
& SP_COPY_NEWER_ONLY
) &&
1154 (TargetInfo
->dwFileVersionMS
==
1155 SourceInfo
->dwFileVersionMS
)
1156 &&(TargetInfo
->dwFileVersionLS
==
1157 SourceInfo
->dwFileVersionLS
))
1160 docopy
= handler (context
, SPFILENOTIFY_TARGETNEWER
, (UINT_PTR
)&filepaths
, 0);
1166 free(VersionSource
);
1167 free(VersionTarget
);
1170 if (style
& (SP_COPY_NOOVERWRITE
| SP_COPY_FORCE_NOOVERWRITE
))
1172 if (GetFileAttributesW(target
) != INVALID_FILE_ATTRIBUTES
)
1174 FIXME("Notify user target file exists\n");
1178 if (style
& (SP_COPY_NODECOMP
| SP_COPY_LANGUAGEAWARE
| SP_COPY_FORCE_IN_USE
|
1179 SP_COPY_NOSKIP
| SP_COPY_WARNIFSKIP
))
1181 ERR("Unsupported style(s) 0x%lx\n",style
);
1186 rc
= copy_file( source
, target
);
1187 if (!rc
&& GetLastError() == ERROR_SHARING_VIOLATION
&&
1188 (style
& SP_COPY_IN_USE_NEEDS_REBOOT
))
1190 WCHAR temp_file
[MAX_PATH
];
1191 WCHAR temp
[MAX_PATH
];
1193 if (GetTempPathW(MAX_PATH
, temp
) &&
1194 GetTempFileNameW(temp
, L
"SET", 0, temp_file
))
1196 rc
= copy_file( source
, temp_file
);
1198 rc
= MoveFileExW(temp_file
, target
, MOVEFILE_DELAY_UNTIL_REBOOT
);
1200 DeleteFileW(temp_file
);
1203 if (!rc
) WARN( "failed to copy, err %lu\n", GetLastError() );
1206 SetLastError(ERROR_SUCCESS
);
1208 /* after copy processing */
1209 if (style
& SP_COPY_DELETESOURCE
)
1212 DeleteFileW(source
);
1218 /***********************************************************************
1219 * SetupInstallFileExA (SETUPAPI.@)
1221 BOOL WINAPI
SetupInstallFileExA( HINF hinf
, PINFCONTEXT inf_context
, PCSTR source
, PCSTR root
,
1222 PCSTR dest
, DWORD style
, PSP_FILE_CALLBACK_A handler
, PVOID context
, PBOOL in_use
)
1225 struct callback_WtoA_context ctx
;
1226 UNICODE_STRING sourceW
, rootW
, destW
;
1228 TRACE("%p %p %s %s %s %lx %p %p %p\n", hinf
, inf_context
, debugstr_a(source
), debugstr_a(root
),
1229 debugstr_a(dest
), style
, handler
, context
, in_use
);
1231 sourceW
.Buffer
= rootW
.Buffer
= destW
.Buffer
= NULL
;
1232 if (source
&& !RtlCreateUnicodeStringFromAsciiz( &sourceW
, source
))
1234 SetLastError( ERROR_NOT_ENOUGH_MEMORY
);
1237 if (root
&& !RtlCreateUnicodeStringFromAsciiz( &rootW
, root
))
1239 SetLastError( ERROR_NOT_ENOUGH_MEMORY
);
1242 if (dest
&& !RtlCreateUnicodeStringFromAsciiz( &destW
, dest
))
1244 SetLastError( ERROR_NOT_ENOUGH_MEMORY
);
1248 ctx
.orig_context
= context
;
1249 ctx
.orig_handler
= handler
;
1251 ret
= SetupInstallFileExW( hinf
, inf_context
, sourceW
.Buffer
, rootW
.Buffer
, destW
.Buffer
, style
, QUEUE_callback_WtoA
, &ctx
, in_use
);
1254 RtlFreeUnicodeString( &sourceW
);
1255 RtlFreeUnicodeString( &rootW
);
1256 RtlFreeUnicodeString( &destW
);
1260 /***********************************************************************
1261 * SetupInstallFileA (SETUPAPI.@)
1263 BOOL WINAPI
SetupInstallFileA( HINF hinf
, PINFCONTEXT inf_context
, PCSTR source
, PCSTR root
,
1264 PCSTR dest
, DWORD style
, PSP_FILE_CALLBACK_A handler
, PVOID context
)
1266 return SetupInstallFileExA( hinf
, inf_context
, source
, root
, dest
, style
, handler
, context
, NULL
);
1269 /***********************************************************************
1270 * SetupInstallFileExW (SETUPAPI.@)
1272 BOOL WINAPI
SetupInstallFileExW( HINF hinf
, PINFCONTEXT inf_context
, PCWSTR source
, PCWSTR root
,
1273 PCWSTR dest
, DWORD style
, PSP_FILE_CALLBACK_W handler
, PVOID context
, PBOOL in_use
)
1275 BOOL ret
, absolute
= (root
&& *root
&& !(style
& SP_COPY_SOURCE_ABSOLUTE
));
1276 WCHAR
*buffer
, *p
, *inf_source
= NULL
, dest_path
[MAX_PATH
];
1279 TRACE("%p %p %s %s %s %lx %p %p %p\n", hinf
, inf_context
, debugstr_w(source
), debugstr_w(root
),
1280 debugstr_w(dest
), style
, handler
, context
, in_use
);
1282 if (in_use
) FIXME("no file in use support\n");
1294 if (!SetupFindFirstLineW( hinf
, L
"CopyFiles", NULL
, inf_context
)) return FALSE
;
1296 if (!SetupGetStringFieldW( inf_context
, 1, NULL
, 0, &len
)) return FALSE
;
1297 if (!(inf_source
= malloc( len
* sizeof(WCHAR
) )))
1299 SetLastError( ERROR_NOT_ENOUGH_MEMORY
);
1302 if (!SetupGetStringFieldW( inf_context
, 1, inf_source
, len
, NULL
))
1307 source
= inf_source
;
1309 if ((dest_dir
= get_destination_dir( hinf
, NULL
)))
1311 lstrcpyW( dest_path
, dest_dir
);
1312 lstrcatW( dest_path
, L
"\\" );
1318 SetLastError( ERROR_INVALID_PARAMETER
);
1322 len
= lstrlenW( source
) + 1;
1323 if (absolute
) len
+= lstrlenW( root
) + 1;
1325 if (!(p
= buffer
= malloc( len
* sizeof(WCHAR
) )))
1328 SetLastError( ERROR_NOT_ENOUGH_MEMORY
);
1334 lstrcpyW( buffer
, root
);
1335 p
+= lstrlenW( buffer
);
1336 if (p
[-1] != '\\') *p
++ = '\\';
1338 while (*source
== '\\') source
++;
1339 lstrcpyW( p
, source
);
1341 lstrcatW( dest_path
, dest
);
1343 ret
= do_file_copyW( buffer
, dest_path
, style
, handler
, context
);
1350 /***********************************************************************
1351 * SetupInstallFileW (SETUPAPI.@)
1353 BOOL WINAPI
SetupInstallFileW( HINF hinf
, PINFCONTEXT inf_context
, PCWSTR source
, PCWSTR root
,
1354 PCWSTR dest
, DWORD style
, PSP_FILE_CALLBACK_W handler
, PVOID context
)
1356 return SetupInstallFileExW( hinf
, inf_context
, source
, root
, dest
, style
, handler
, context
, NULL
);
1359 static BOOL
queue_copy_file( const WCHAR
*source
, const WCHAR
*dest
,
1360 const struct file_op
*op
, PSP_FILE_CALLBACK_W handler
, void *context
)
1362 TRACE("copying file %s -> %s\n", debugstr_w(source
), debugstr_w(dest
));
1364 if (op
->dst_path
&& !create_full_pathW(op
->dst_path
))
1367 if (do_file_copyW(source
, dest
, op
->style
, handler
, context
) || GetLastError() == ERROR_SUCCESS
)
1370 /* try to extract it from the cabinet file */
1371 if (op
->media
->tag
&& extract_cabinet_file(op
->media
->tag
, op
->media
->root
, op
->src_file
, dest
))
1373 op
->media
->cabinet
= TRUE
;
1380 /***********************************************************************
1381 * SetupCommitFileQueueW (SETUPAPI.@)
1383 BOOL WINAPI
SetupCommitFileQueueW( HWND owner
, HSPFILEQ handle
, PSP_FILE_CALLBACK_W handler
,
1386 struct file_queue
*queue
= handle
;
1388 BOOL result
= FALSE
;
1392 paths
.Source
= paths
.Target
= NULL
;
1394 if (!queue
->copy_queue
.count
&& !queue
->delete_queue
.count
&& !queue
->rename_queue
.count
)
1395 return TRUE
; /* nothing to do */
1397 if (!handler( context
, SPFILENOTIFY_STARTQUEUE
, (UINT_PTR
)owner
, 0 )) return FALSE
;
1399 /* perform deletes */
1401 if (queue
->delete_queue
.count
)
1403 if (!(handler( context
, SPFILENOTIFY_STARTSUBQUEUE
, FILEOP_DELETE
,
1404 queue
->delete_queue
.count
))) goto done
;
1405 for (op
= queue
->delete_queue
.head
; op
; op
= op
->next
)
1407 build_filepathsW( op
, &paths
);
1408 op_result
= handler( context
, SPFILENOTIFY_STARTDELETE
, (UINT_PTR
)&paths
, FILEOP_DELETE
);
1409 if (op_result
== FILEOP_ABORT
) goto done
;
1410 while (op_result
== FILEOP_DOIT
)
1412 TRACE( "deleting file %s\n", debugstr_w(paths
.Target
) );
1413 if (DeleteFileW( paths
.Target
)) break; /* success */
1414 paths
.Win32Error
= GetLastError();
1415 op_result
= handler( context
, SPFILENOTIFY_DELETEERROR
, (UINT_PTR
)&paths
, 0 );
1416 if (op_result
== FILEOP_ABORT
) goto done
;
1418 handler( context
, SPFILENOTIFY_ENDDELETE
, (UINT_PTR
)&paths
, 0 );
1420 handler( context
, SPFILENOTIFY_ENDSUBQUEUE
, FILEOP_DELETE
, 0 );
1423 /* perform renames */
1425 if (queue
->rename_queue
.count
)
1427 if (!(handler( context
, SPFILENOTIFY_STARTSUBQUEUE
, FILEOP_RENAME
,
1428 queue
->rename_queue
.count
))) goto done
;
1429 for (op
= queue
->rename_queue
.head
; op
; op
= op
->next
)
1431 build_filepathsW( op
, &paths
);
1432 op_result
= handler( context
, SPFILENOTIFY_STARTRENAME
, (UINT_PTR
)&paths
, FILEOP_RENAME
);
1433 if (op_result
== FILEOP_ABORT
) goto done
;
1434 while (op_result
== FILEOP_DOIT
)
1436 TRACE( "renaming file %s -> %s\n",
1437 debugstr_w(paths
.Source
), debugstr_w(paths
.Target
) );
1438 if (MoveFileW( paths
.Source
, paths
.Target
)) break; /* success */
1439 paths
.Win32Error
= GetLastError();
1440 op_result
= handler( context
, SPFILENOTIFY_RENAMEERROR
, (UINT_PTR
)&paths
, 0 );
1441 if (op_result
== FILEOP_ABORT
) goto done
;
1443 handler( context
, SPFILENOTIFY_ENDRENAME
, (UINT_PTR
)&paths
, 0 );
1445 handler( context
, SPFILENOTIFY_ENDSUBQUEUE
, FILEOP_RENAME
, 0 );
1448 /* perform copies */
1450 if (queue
->copy_queue
.count
)
1452 if (!(handler( context
, SPFILENOTIFY_STARTSUBQUEUE
, FILEOP_COPY
,
1453 queue
->copy_queue
.count
))) goto done
;
1454 for (op
= queue
->copy_queue
.head
; op
; op
= op
->next
)
1456 WCHAR newpath
[MAX_PATH
];
1458 if (!op
->media
->resolved
)
1460 /* The NEEDMEDIA callback asks for the folder containing the
1461 * first file, but that might be in a subdir of the source
1462 * disk's root directory. We have to do some contortions to
1463 * correct for this. Pretend that the file we're using
1464 * actually isn't in a subdirectory, but keep track of what it
1465 * was, and then later strip it from the root path that we
1466 * ultimately resolve the source disk to. */
1467 WCHAR src_path
[MAX_PATH
];
1468 size_t path_len
= 0;
1473 lstrcpyW(src_path
, op
->src_path
);
1474 path_len
= lstrlenW(src_path
);
1476 lstrcatW(op
->media
->root
, L
"\\");
1477 lstrcatW(op
->media
->root
, op
->src_path
);
1480 op
->src_path
= NULL
;
1485 SOURCE_MEDIA_W media
;
1486 media
.Reserved
= NULL
;
1487 media
.Tagfile
= op
->media
->tag
;
1488 media
.Description
= op
->media
->desc
;
1489 media
.SourcePath
= op
->media
->root
;
1490 media
.SourceFile
= op
->src_file
;
1491 media
.Flags
= op
->style
& (SP_COPY_WARNIFSKIP
| SP_COPY_NOSKIP
| SP_FLAG_CABINETCONTINUATION
| SP_COPY_NOBROWSE
);
1494 op_result
= handler( context
, SPFILENOTIFY_NEEDMEDIA
, (UINT_PTR
)&media
, (UINT_PTR
)newpath
);
1496 if (op_result
== FILEOP_ABORT
)
1498 else if (op_result
== FILEOP_SKIP
)
1500 else if (op_result
== FILEOP_NEWPATH
)
1501 lstrcpyW(op
->media
->root
, newpath
);
1502 else if (op_result
!= FILEOP_DOIT
)
1503 FIXME("Unhandled return value %#x.\n", op_result
);
1505 build_filepathsW( op
, &paths
);
1506 op_result
= handler( context
, SPFILENOTIFY_STARTCOPY
, (UINT_PTR
)&paths
, FILEOP_COPY
);
1507 if (op_result
== FILEOP_ABORT
)
1509 else if (op_result
== FILEOP_SKIP
)
1511 else if (op_result
!= FILEOP_DOIT
)
1512 FIXME("Unhandled return value %#x.\n", op_result
);
1514 if (queue_copy_file( paths
.Source
, paths
.Target
, op
, handler
, context
))
1516 if (path_len
> 0 && !op
->media
->cabinet
)
1518 size_t root_len
= lstrlenW(op
->media
->root
);
1519 if (path_len
<= root_len
&& !wcsnicmp(op
->media
->root
+ root_len
- path_len
, src_path
, path_len
))
1520 op
->media
->root
[root_len
- path_len
- 1] = 0;
1522 op
->media
->resolved
= TRUE
;
1523 handler( context
, SPFILENOTIFY_ENDCOPY
, (UINT_PTR
)&paths
, 0 );
1526 paths
.Win32Error
= GetLastError();
1527 if (paths
.Win32Error
== ERROR_PATH_NOT_FOUND
||
1528 paths
.Win32Error
== ERROR_FILE_NOT_FOUND
)
1532 op_result
= handler( context
, SPFILENOTIFY_COPYERROR
, (UINT_PTR
)&paths
, (UINT_PTR
)newpath
);
1533 if (op_result
== FILEOP_ABORT
)
1535 else if (op_result
== FILEOP_SKIP
)
1537 else if (op_result
== FILEOP_NEWPATH
)
1539 lstrcpyW(op
->media
->root
, newpath
);
1540 build_filepathsW(op
, &paths
);
1542 else if (op_result
!= FILEOP_DOIT
)
1543 FIXME("Unhandled return value %#x.\n", op_result
);
1548 build_filepathsW( op
, &paths
);
1549 op_result
= handler( context
, SPFILENOTIFY_STARTCOPY
, (UINT_PTR
)&paths
, FILEOP_COPY
);
1550 if (op_result
== FILEOP_ABORT
)
1552 else if (op_result
== FILEOP_SKIP
)
1554 else if (op_result
!= FILEOP_DOIT
)
1555 FIXME("Unhandled return value %#x.\n", op_result
);
1557 while (op_result
== FILEOP_DOIT
|| op_result
== FILEOP_NEWPATH
)
1559 if (queue_copy_file( paths
.Source
, paths
.Target
, op
, handler
, context
))
1562 paths
.Win32Error
= GetLastError();
1564 op_result
= handler( context
, SPFILENOTIFY_COPYERROR
, (UINT_PTR
)&paths
, (UINT_PTR
)newpath
);
1565 if (op_result
== FILEOP_ABORT
)
1567 else if (op_result
== FILEOP_NEWPATH
)
1569 lstrcpyW(op
->media
->root
, newpath
);
1570 build_filepathsW(op
, &paths
);
1572 else if (op_result
!= FILEOP_SKIP
&& op_result
!= FILEOP_DOIT
)
1573 FIXME("Unhandled return value %#x.\n", op_result
);
1575 handler( context
, SPFILENOTIFY_ENDCOPY
, (UINT_PTR
)&paths
, 0 );
1578 handler( context
, SPFILENOTIFY_ENDSUBQUEUE
, FILEOP_COPY
, 0 );
1585 handler( context
, SPFILENOTIFY_ENDQUEUE
, result
, 0 );
1586 HeapFree( GetProcessHeap(), 0, (void *)paths
.Source
);
1587 HeapFree( GetProcessHeap(), 0, (void *)paths
.Target
);
1592 /***********************************************************************
1593 * SetupScanFileQueueA (SETUPAPI.@)
1595 BOOL WINAPI
SetupScanFileQueueA( HSPFILEQ handle
, DWORD flags
, HWND window
,
1596 PSP_FILE_CALLBACK_A handler
, PVOID context
, PDWORD result
)
1598 struct callback_WtoA_context ctx
;
1600 TRACE("%p %lx %p %p %p %p\n", handle
, flags
, window
, handler
, context
, result
);
1602 ctx
.orig_context
= context
;
1603 ctx
.orig_handler
= handler
;
1605 return SetupScanFileQueueW( handle
, flags
, window
, QUEUE_callback_WtoA
, &ctx
, result
);
1609 /***********************************************************************
1610 * SetupScanFileQueueW (SETUPAPI.@)
1612 BOOL WINAPI
SetupScanFileQueueW( HSPFILEQ handle
, DWORD flags
, HWND window
,
1613 PSP_FILE_CALLBACK_W handler
, PVOID context
, PDWORD result
)
1615 struct file_queue
*queue
= handle
;
1618 UINT notification
= 0;
1621 TRACE("%p %lx %p %p %p %p\n", handle
, flags
, window
, handler
, context
, result
);
1623 if (!queue
->copy_queue
.count
) return TRUE
;
1625 if (flags
& SPQ_SCAN_USE_CALLBACK
) notification
= SPFILENOTIFY_QUEUESCAN
;
1626 else if (flags
& SPQ_SCAN_USE_CALLBACKEX
) notification
= SPFILENOTIFY_QUEUESCAN_EX
;
1628 if (flags
& ~(SPQ_SCAN_USE_CALLBACK
| SPQ_SCAN_USE_CALLBACKEX
))
1630 FIXME("flags %lx not fully implemented\n", flags
);
1633 paths
.Source
= paths
.Target
= NULL
;
1635 for (op
= queue
->copy_queue
.head
; op
; op
= op
->next
)
1637 build_filepathsW( op
, &paths
);
1638 switch (notification
)
1640 case SPFILENOTIFY_QUEUESCAN
:
1641 /* FIXME: handle delay flag */
1642 if (handler( context
, notification
, (UINT_PTR
)paths
.Target
, 0 )) goto done
;
1644 case SPFILENOTIFY_QUEUESCAN_EX
:
1645 if (handler( context
, notification
, (UINT_PTR
)&paths
, 0 )) goto done
;
1648 ret
= TRUE
; goto done
;
1655 if (result
) *result
= 0;
1656 HeapFree( GetProcessHeap(), 0, (void *)paths
.Source
);
1657 HeapFree( GetProcessHeap(), 0, (void *)paths
.Target
);
1662 /***********************************************************************
1663 * SetupGetFileQueueCount (SETUPAPI.@)
1665 BOOL WINAPI
SetupGetFileQueueCount( HSPFILEQ handle
, UINT op
, PUINT result
)
1667 struct file_queue
*queue
= handle
;
1672 *result
= queue
->copy_queue
.count
;
1675 *result
= queue
->rename_queue
.count
;
1678 *result
= queue
->delete_queue
.count
;
1685 /***********************************************************************
1686 * SetupGetFileQueueFlags (SETUPAPI.@)
1688 BOOL WINAPI
SetupGetFileQueueFlags( HSPFILEQ handle
, PDWORD flags
)
1690 struct file_queue
*queue
= handle
;
1691 *flags
= queue
->flags
;
1696 /***********************************************************************
1697 * SetupSetFileQueueFlags (SETUPAPI.@)
1699 BOOL WINAPI
SetupSetFileQueueFlags( HSPFILEQ handle
, DWORD mask
, DWORD flags
)
1701 struct file_queue
*queue
= handle
;
1702 queue
->flags
= (queue
->flags
& ~mask
) | flags
;
1707 /***********************************************************************
1708 * SetupSetFileQueueAlternatePlatformA (SETUPAPI.@)
1710 BOOL WINAPI
SetupSetFileQueueAlternatePlatformA(HSPFILEQ handle
, PSP_ALTPLATFORM_INFO platform
, PCSTR catalogfile
)
1712 FIXME("(%p, %p, %s) stub!\n", handle
, platform
, debugstr_a(catalogfile
));
1717 /***********************************************************************
1718 * SetupSetFileQueueAlternatePlatformW (SETUPAPI.@)
1720 BOOL WINAPI
SetupSetFileQueueAlternatePlatformW(HSPFILEQ handle
, PSP_ALTPLATFORM_INFO platform
, PCWSTR catalogfile
)
1722 FIXME("(%p, %p, %s) stub!\n", handle
, platform
, debugstr_w(catalogfile
));
1727 /***********************************************************************
1728 * SetupInitDefaultQueueCallback (SETUPAPI.@)
1730 PVOID WINAPI
SetupInitDefaultQueueCallback( HWND owner
)
1732 return SetupInitDefaultQueueCallbackEx( owner
, 0, 0, 0, NULL
);
1736 /***********************************************************************
1737 * SetupInitDefaultQueueCallbackEx (SETUPAPI.@)
1739 PVOID WINAPI
SetupInitDefaultQueueCallbackEx( HWND owner
, HWND progress
, UINT msg
,
1740 DWORD reserved1
, PVOID reserved2
)
1742 struct default_callback_context
*context
;
1744 if ((context
= calloc( 1, sizeof(*context
) )))
1746 context
->magic
= 0x43515053; /* "SPQC" */
1747 context
->owner
= owner
;
1748 context
->progress
= progress
;
1749 context
->message
= msg
;
1755 /***********************************************************************
1756 * SetupTermDefaultQueueCallback (SETUPAPI.@)
1758 void WINAPI
SetupTermDefaultQueueCallback( PVOID context
)
1764 /***********************************************************************
1765 * SetupDefaultQueueCallbackA (SETUPAPI.@)
1767 UINT WINAPI
SetupDefaultQueueCallbackA( PVOID context
, UINT notification
,
1768 UINT_PTR param1
, UINT_PTR param2
)
1770 FILEPATHS_A
*paths
= (FILEPATHS_A
*)param1
;
1771 struct default_callback_context
*ctx
= context
;
1773 switch(notification
)
1775 case SPFILENOTIFY_STARTQUEUE
:
1776 TRACE( "start queue\n" );
1778 case SPFILENOTIFY_ENDQUEUE
:
1779 TRACE( "end queue\n" );
1781 case SPFILENOTIFY_STARTSUBQUEUE
:
1782 TRACE( "start subqueue %Id count %Id\n", param1
, param2
);
1784 case SPFILENOTIFY_ENDSUBQUEUE
:
1785 TRACE( "end subqueue %Id\n", param1
);
1787 case SPFILENOTIFY_STARTDELETE
:
1788 TRACE( "start delete %s\n", debugstr_a(paths
->Target
) );
1790 case SPFILENOTIFY_ENDDELETE
:
1791 TRACE( "end delete %s\n", debugstr_a(paths
->Target
) );
1793 case SPFILENOTIFY_DELETEERROR
:
1794 /*Windows Ignores attempts to delete files / folders which do not exist*/
1795 if ((paths
->Win32Error
!= ERROR_FILE_NOT_FOUND
) && (paths
->Win32Error
!= ERROR_PATH_NOT_FOUND
))
1796 SetupDeleteErrorA(ctx
->owner
, NULL
, paths
->Target
, paths
->Win32Error
, 0);
1798 case SPFILENOTIFY_STARTRENAME
:
1799 TRACE( "start rename %s -> %s\n", debugstr_a(paths
->Source
), debugstr_a(paths
->Target
) );
1801 case SPFILENOTIFY_ENDRENAME
:
1802 TRACE( "end rename %s -> %s\n", debugstr_a(paths
->Source
), debugstr_a(paths
->Target
) );
1804 case SPFILENOTIFY_RENAMEERROR
:
1805 SetupRenameErrorA(ctx
->owner
, NULL
, paths
->Source
, paths
->Target
, paths
->Win32Error
, 0);
1807 case SPFILENOTIFY_STARTCOPY
:
1808 TRACE( "start copy %s -> %s\n", debugstr_a(paths
->Source
), debugstr_a(paths
->Target
) );
1810 case SPFILENOTIFY_ENDCOPY
:
1811 TRACE( "end copy %s -> %s\n", debugstr_a(paths
->Source
), debugstr_a(paths
->Target
) );
1813 case SPFILENOTIFY_COPYERROR
:
1814 ERR( "copy error %d %s -> %s\n", paths
->Win32Error
,
1815 debugstr_a(paths
->Source
), debugstr_a(paths
->Target
) );
1817 case SPFILENOTIFY_NEEDMEDIA
:
1819 const SOURCE_MEDIA_A
*media
= (const SOURCE_MEDIA_A
*)param1
;
1820 TRACE( "need media %s %s\n", debugstr_a(media
->SourcePath
), debugstr_a(media
->SourceFile
) );
1821 strcpy( (char *)param2
, media
->SourcePath
);
1825 FIXME( "notification %d params %Ix,%Ix\n", notification
, param1
, param2
);
1832 /***********************************************************************
1833 * SetupDefaultQueueCallbackW (SETUPAPI.@)
1835 UINT WINAPI
SetupDefaultQueueCallbackW( PVOID context
, UINT notification
,
1836 UINT_PTR param1
, UINT_PTR param2
)
1838 FILEPATHS_W
*paths
= (FILEPATHS_W
*)param1
;
1839 struct default_callback_context
*ctx
= context
;
1841 switch(notification
)
1843 case SPFILENOTIFY_STARTQUEUE
:
1844 TRACE( "start queue\n" );
1846 case SPFILENOTIFY_ENDQUEUE
:
1847 TRACE( "end queue\n" );
1849 case SPFILENOTIFY_STARTSUBQUEUE
:
1850 TRACE( "start subqueue %Id count %Id\n", param1
, param2
);
1852 case SPFILENOTIFY_ENDSUBQUEUE
:
1853 TRACE( "end subqueue %Id\n", param1
);
1855 case SPFILENOTIFY_STARTDELETE
:
1856 TRACE( "start delete %s\n", debugstr_w(paths
->Target
) );
1858 case SPFILENOTIFY_ENDDELETE
:
1859 TRACE( "end delete %s\n", debugstr_w(paths
->Target
) );
1861 case SPFILENOTIFY_DELETEERROR
:
1862 /*Windows Ignores attempts to delete files / folders which do not exist*/
1863 if ((paths
->Win32Error
!= ERROR_FILE_NOT_FOUND
) && (paths
->Win32Error
!= ERROR_PATH_NOT_FOUND
))
1864 SetupDeleteErrorW(ctx
->owner
, NULL
, paths
->Target
, paths
->Win32Error
, 0);
1866 case SPFILENOTIFY_STARTRENAME
:
1867 SetupRenameErrorW(ctx
->owner
, NULL
, paths
->Source
, paths
->Target
, paths
->Win32Error
, 0);
1869 case SPFILENOTIFY_ENDRENAME
:
1870 TRACE( "end rename %s -> %s\n", debugstr_w(paths
->Source
), debugstr_w(paths
->Target
) );
1872 case SPFILENOTIFY_RENAMEERROR
:
1873 ERR( "rename error %d %s -> %s\n", paths
->Win32Error
,
1874 debugstr_w(paths
->Source
), debugstr_w(paths
->Target
) );
1876 case SPFILENOTIFY_STARTCOPY
:
1877 TRACE( "start copy %s -> %s\n", debugstr_w(paths
->Source
), debugstr_w(paths
->Target
) );
1879 case SPFILENOTIFY_ENDCOPY
:
1880 TRACE( "end copy %s -> %s\n", debugstr_w(paths
->Source
), debugstr_w(paths
->Target
) );
1882 case SPFILENOTIFY_COPYERROR
:
1883 ERR( "copy error %d %s -> %s\n", paths
->Win32Error
,
1884 debugstr_w(paths
->Source
), debugstr_w(paths
->Target
) );
1886 case SPFILENOTIFY_NEEDMEDIA
:
1888 const SOURCE_MEDIA_W
*media
= (const SOURCE_MEDIA_W
*)param1
;
1889 TRACE( "need media %s %s\n", debugstr_w(media
->SourcePath
), debugstr_w(media
->SourceFile
) );
1890 lstrcpyW( (WCHAR
*)param2
, media
->SourcePath
);
1894 FIXME( "notification %d params %Ix,%Ix\n", notification
, param1
, param2
);
1900 /***********************************************************************
1901 * SetupDeleteErrorA (SETUPAPI.@)
1904 UINT WINAPI
SetupDeleteErrorA( HWND parent
, PCSTR dialogTitle
, PCSTR file
,
1905 UINT w32error
, DWORD style
)
1907 FIXME( "stub: (Error Number %d when attempting to delete %s)\n",
1908 w32error
, debugstr_a(file
) );
1909 return DPROMPT_SKIPFILE
;
1912 /***********************************************************************
1913 * SetupDeleteErrorW (SETUPAPI.@)
1916 UINT WINAPI
SetupDeleteErrorW( HWND parent
, PCWSTR dialogTitle
, PCWSTR file
,
1917 UINT w32error
, DWORD style
)
1919 FIXME( "stub: (Error Number %d when attempting to delete %s)\n",
1920 w32error
, debugstr_w(file
) );
1921 return DPROMPT_SKIPFILE
;
1924 /***********************************************************************
1925 * SetupRenameErrorA (SETUPAPI.@)
1928 UINT WINAPI
SetupRenameErrorA( HWND parent
, PCSTR dialogTitle
, PCSTR source
,
1929 PCSTR target
, UINT w32error
, DWORD style
)
1931 FIXME( "stub: (Error Number %d when attempting to rename %s to %s)\n",
1932 w32error
, debugstr_a(source
), debugstr_a(target
));
1933 return DPROMPT_SKIPFILE
;
1936 /***********************************************************************
1937 * SetupRenameErrorW (SETUPAPI.@)
1940 UINT WINAPI
SetupRenameErrorW( HWND parent
, PCWSTR dialogTitle
, PCWSTR source
,
1941 PCWSTR target
, UINT w32error
, DWORD style
)
1943 FIXME( "stub: (Error Number %d when attempting to rename %s to %s)\n",
1944 w32error
, debugstr_w(source
), debugstr_w(target
));
1945 return DPROMPT_SKIPFILE
;
1949 /***********************************************************************
1950 * SetupCopyErrorA (SETUPAPI.@)
1953 UINT WINAPI
SetupCopyErrorA( HWND parent
, PCSTR dialogTitle
, PCSTR diskname
,
1954 PCSTR sourcepath
, PCSTR sourcefile
, PCSTR targetpath
,
1955 UINT w32error
, DWORD style
, PSTR pathbuffer
,
1956 DWORD buffersize
, PDWORD requiredsize
)
1958 FIXME( "stub: (Error Number %d when attempting to copy file %s from %s to %s)\n",
1959 w32error
, debugstr_a(sourcefile
), debugstr_a(sourcepath
) ,debugstr_a(targetpath
));
1960 return DPROMPT_SKIPFILE
;
1963 /***********************************************************************
1964 * SetupCopyErrorW (SETUPAPI.@)
1967 UINT WINAPI
SetupCopyErrorW( HWND parent
, PCWSTR dialogTitle
, PCWSTR diskname
,
1968 PCWSTR sourcepath
, PCWSTR sourcefile
, PCWSTR targetpath
,
1969 UINT w32error
, DWORD style
, PWSTR pathbuffer
,
1970 DWORD buffersize
, PDWORD requiredsize
)
1972 FIXME( "stub: (Error Number %d when attempting to copy file %s from %s to %s)\n",
1973 w32error
, debugstr_w(sourcefile
), debugstr_w(sourcepath
) ,debugstr_w(targetpath
));
1974 return DPROMPT_SKIPFILE
;
1977 /***********************************************************************
1978 * pSetupGetQueueFlags (SETUPAPI.@)
1980 DWORD WINAPI
pSetupGetQueueFlags( HSPFILEQ handle
)
1982 struct file_queue
*queue
= handle
;
1983 return queue
->flags
;
1986 /***********************************************************************
1987 * pSetupSetQueueFlags (SETUPAPI.@)
1989 BOOL WINAPI
pSetupSetQueueFlags( HSPFILEQ handle
, DWORD flags
)
1991 struct file_queue
*queue
= handle
;
1992 queue
->flags
= flags
;