source: trunk/src/setupapi/queue.c@ 10367

Last change on this file since 10367 was 9403, checked in by sandervl, 23 years ago

Wine resync

File size: 41.0 KB
Line 
1/*
2 * Setupapi file queue routines
3 *
4 * Copyright 2002 Alexandre Julliard for CodeWeavers
5 *
6 * This library is free software; you can redistribute it and/or
7 * modify it under the terms of the GNU Lesser General Public
8 * License as published by the Free Software Foundation; either
9 * version 2.1 of the License, or (at your option) any later version.
10 *
11 * This library is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14 * Lesser General Public License for more details.
15 *
16 * You should have received a copy of the GNU Lesser General Public
17 * License along with this library; if not, write to the Free Software
18 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
19 */
20
21#include "windef.h"
22#include "winbase.h"
23#include "winternl.h"
24#include "winerror.h"
25#include "setupapi.h"
26#include "wine/unicode.h"
27#include "setupapi_private.h"
28#include "wine/debug.h"
29
30WINE_DEFAULT_DEBUG_CHANNEL(setupapi);
31
32/* context structure for the default queue callback */
33struct default_callback_context
34{
35 HWND owner;
36 HWND progress;
37 UINT message;
38};
39
40struct file_op
41{
42 struct file_op *next;
43 UINT style;
44 WCHAR *src_root;
45 WCHAR *src_path;
46 WCHAR *src_file;
47 WCHAR *src_descr;
48 WCHAR *src_tag;
49 WCHAR *dst_path;
50 WCHAR *dst_file;
51};
52
53struct file_op_queue
54{
55 struct file_op *head;
56 struct file_op *tail;
57 unsigned int count;
58};
59
60struct file_queue
61{
62 struct file_op_queue copy_queue;
63 struct file_op_queue delete_queue;
64 struct file_op_queue rename_queue;
65 DWORD flags;
66};
67
68
69inline static WCHAR *strdupW( const WCHAR *str )
70{
71 WCHAR *ret = NULL;
72 if (str)
73 {
74 int len = (strlenW(str) + 1) * sizeof(WCHAR);
75 if ((ret = HeapAlloc( GetProcessHeap(), 0, len ))) memcpy( ret, str, len );
76 }
77 return ret;
78}
79
80
81inline static WCHAR *strdupAtoW( const char *str )
82{
83 WCHAR *ret = NULL;
84 if (str)
85 {
86 DWORD len = MultiByteToWideChar( CP_ACP, 0, str, -1, NULL, 0 );
87 if ((ret = HeapAlloc( GetProcessHeap(), 0, len * sizeof(WCHAR) )))
88 MultiByteToWideChar( CP_ACP, 0, str, -1, ret, len );
89 }
90 return ret;
91}
92
93inline static char *strdupWtoA( const WCHAR *str )
94{
95 char *ret = NULL;
96 if (str)
97 {
98 DWORD len = WideCharToMultiByte( CP_ACP, 0, str, -1, NULL, 0, NULL, NULL );
99 if ((ret = HeapAlloc( GetProcessHeap(), 0, len )))
100 WideCharToMultiByte( CP_ACP, 0, str, -1, ret, len, NULL, NULL );
101 }
102 return ret;
103}
104
105/* append a file operation to a queue */
106inline static void queue_file_op( struct file_op_queue *queue, struct file_op *op )
107{
108 op->next = NULL;
109 if (queue->tail) queue->tail->next = op;
110 else queue->head = op;
111 queue->tail = op;
112 queue->count++;
113}
114
115/* free all the file operations on a given queue */
116static void free_file_op_queue( struct file_op_queue *queue )
117{
118 struct file_op *t, *op = queue->head;
119
120 while( op )
121 {
122 HeapFree( GetProcessHeap(), 0, op->src_root );
123 HeapFree( GetProcessHeap(), 0, op->src_path );
124 HeapFree( GetProcessHeap(), 0, op->src_file );
125 HeapFree( GetProcessHeap(), 0, op->src_descr );
126 HeapFree( GetProcessHeap(), 0, op->src_tag );
127 HeapFree( GetProcessHeap(), 0, op->dst_path );
128 if (op->dst_file != op->src_file) HeapFree( GetProcessHeap(), 0, op->dst_file );
129 t = op;
130 op = op->next;
131 HeapFree( GetProcessHeap(), 0, t );
132 }
133}
134
135/* concat 3 strings to make a path, handling separators correctly */
136static void concat_W( WCHAR *buffer, const WCHAR *src1, const WCHAR *src2, const WCHAR *src3 )
137{
138 *buffer = 0;
139 if (src1 && *src1)
140 {
141 strcpyW( buffer, src1 );
142 buffer += strlenW(buffer );
143 if (buffer[-1] != '\\') *buffer++ = '\\';
144 if (src2) while (*src2 == '\\') src2++;
145 }
146
147 if (src2)
148 {
149 strcpyW( buffer, src2 );
150 buffer += strlenW(buffer );
151 if (buffer[-1] != '\\') *buffer++ = '\\';
152 if (src3) while (*src3 == '\\') src3++;
153 }
154 if (src3)
155 {
156 strcpyW( buffer, src3 );
157 buffer += strlenW(buffer );
158 }
159}
160
161
162/***********************************************************************
163 * build_filepathsW
164 *
165 * Build a FILEPATHS_W structure for a given file operation.
166 */
167static BOOL build_filepathsW( const struct file_op *op, FILEPATHS_W *paths )
168{
169 int src_len = 1, dst_len = 1;
170 WCHAR *source = (PWSTR)paths->Source, *target = (PWSTR)paths->Target;
171
172 if (op->src_root) src_len += strlenW(op->src_root) + 1;
173 if (op->src_path) src_len += strlenW(op->src_path) + 1;
174 if (op->src_file) src_len += strlenW(op->src_file) + 1;
175 if (op->dst_path) dst_len += strlenW(op->dst_path) + 1;
176 if (op->dst_file) dst_len += strlenW(op->dst_file) + 1;
177 src_len *= sizeof(WCHAR);
178 dst_len *= sizeof(WCHAR);
179
180 if (!source || HeapSize( GetProcessHeap(), 0, source ) < src_len )
181 {
182 HeapFree( GetProcessHeap(), 0, source );
183 paths->Source = source = HeapAlloc( GetProcessHeap(), 0, src_len );
184 }
185 if (!target || HeapSize( GetProcessHeap(), 0, target ) < dst_len )
186 {
187 HeapFree( GetProcessHeap(), 0, target );
188 paths->Target = target = HeapAlloc( GetProcessHeap(), 0, dst_len );
189 }
190 if (!source || !target) return FALSE;
191 concat_W( source, op->src_root, op->src_path, op->src_file );
192 concat_W( target, NULL, op->dst_path, op->dst_file );
193 paths->Win32Error = 0;
194 paths->Flags = 0;
195 return TRUE;
196}
197
198
199/***********************************************************************
200 * QUEUE_callback_WtoA
201 *
202 * Map a file callback parameters from W to A and call the A callback.
203 */
204UINT CALLBACK QUEUE_callback_WtoA( void *context, UINT notification,
205 UINT_PTR param1, UINT_PTR param2 )
206{
207 struct callback_WtoA_context *callback_ctx = context;
208 char buffer[MAX_PATH];
209 UINT ret;
210 UINT_PTR old_param2 = param2;
211
212 switch(notification)
213 {
214 case SPFILENOTIFY_COPYERROR:
215 param2 = (UINT_PTR)&buffer;
216 /* fall through */
217 case SPFILENOTIFY_STARTDELETE:
218 case SPFILENOTIFY_ENDDELETE:
219 case SPFILENOTIFY_DELETEERROR:
220 case SPFILENOTIFY_STARTRENAME:
221 case SPFILENOTIFY_ENDRENAME:
222 case SPFILENOTIFY_RENAMEERROR:
223 case SPFILENOTIFY_STARTCOPY:
224 case SPFILENOTIFY_ENDCOPY:
225 {
226 FILEPATHS_W *pathsW = (FILEPATHS_W *)param1;
227 FILEPATHS_A pathsA;
228
229 pathsA.Source = strdupWtoA( pathsW->Source );
230 pathsA.Target = strdupWtoA( pathsW->Target );
231 pathsA.Win32Error = pathsW->Win32Error;
232 pathsA.Flags = pathsW->Flags;
233 ret = callback_ctx->orig_handler( callback_ctx->orig_context, notification,
234 (UINT_PTR)&pathsA, param2 );
235 HeapFree( GetProcessHeap(), 0, (void *)pathsA.Source );
236 HeapFree( GetProcessHeap(), 0, (void *)pathsA.Target );
237 }
238 if (notification == SPFILENOTIFY_COPYERROR)
239 MultiByteToWideChar( CP_ACP, 0, buffer, -1, (WCHAR *)old_param2, MAX_PATH );
240 break;
241
242 case SPFILENOTIFY_NEEDMEDIA:
243 case SPFILENOTIFY_QUEUESCAN:
244 FIXME("mapping for %d not implemented\n",notification);
245 case SPFILENOTIFY_STARTQUEUE:
246 case SPFILENOTIFY_ENDQUEUE:
247 case SPFILENOTIFY_STARTSUBQUEUE:
248 case SPFILENOTIFY_ENDSUBQUEUE:
249 default:
250 ret = callback_ctx->orig_handler( callback_ctx->orig_context, notification, param1, param2 );
251 break;
252 }
253 return ret;
254}
255
256
257/***********************************************************************
258 * get_src_file_info
259 *
260 * Retrieve the source file information for a given file.
261 */
262static void get_src_file_info( HINF hinf, struct file_op *op )
263{
264 static const WCHAR SourceDisksNames[] =
265 {'S','o','u','r','c','e','D','i','s','k','s','N','a','m','e','s',0};
266 static const WCHAR SourceDisksFiles[] =
267 {'S','o','u','r','c','e','D','i','s','k','s','F','i','l','e','s',0};
268
269 INFCONTEXT file_ctx, disk_ctx;
270 INT id, diskid;
271 DWORD len, len2;
272
273 /* find the SourceDisksFiles entry */
274 if (!SetupFindFirstLineW( hinf, SourceDisksFiles, op->src_file, &file_ctx ))
275 {
276 const WCHAR *dir;
277
278 if ((op->style & (SP_COPY_SOURCE_ABSOLUTE|SP_COPY_SOURCEPATH_ABSOLUTE))) return;
279 /* no specific info, use .inf file source directory */
280 if (!op->src_root && (dir = DIRID_get_string( hinf, DIRID_SRCPATH )))
281 op->src_root = strdupW( dir );
282 return;
283 }
284 if (!SetupGetIntField( &file_ctx, 1, &diskid )) return;
285
286 /* now find the diskid in the SourceDisksNames section */
287 if (!SetupFindFirstLineW( hinf, SourceDisksNames, NULL, &disk_ctx )) return;
288 for (;;)
289 {
290 if (SetupGetIntField( &disk_ctx, 0, &id ) && (id == diskid)) break;
291 if (!SetupFindNextLine( &disk_ctx, &disk_ctx )) return;
292 }
293
294 /* and fill in the missing info */
295
296 if (!op->src_descr)
297 {
298 if (SetupGetStringFieldW( &disk_ctx, 1, NULL, 0, &len ) &&
299 (op->src_descr = HeapAlloc( GetProcessHeap(), 0, len*sizeof(WCHAR) )))
300 SetupGetStringFieldW( &disk_ctx, 1, op->src_descr, len, NULL );
301 }
302 if (!op->src_tag)
303 {
304 if (SetupGetStringFieldW( &disk_ctx, 2, NULL, 0, &len ) &&
305 (op->src_tag = HeapAlloc( GetProcessHeap(), 0, len*sizeof(WCHAR) )))
306 SetupGetStringFieldW( &disk_ctx, 2, op->src_tag, len, NULL );
307 }
308 if (!op->src_path && !(op->style & SP_COPY_SOURCE_ABSOLUTE))
309 {
310 if (!(op->style & SP_COPY_SOURCEPATH_ABSOLUTE))
311 {
312 /* retrieve relative path for this disk */
313 if (!SetupGetStringFieldW( &disk_ctx, 4, NULL, 0, &len )) len = 0;
314 }
315 /* retrieve relative path for this file */
316 if (!SetupGetStringFieldW( &file_ctx, 2, NULL, 0, &len2 )) len2 = 0;
317
318 if ((len || len2) &&
319 (op->src_path = HeapAlloc( GetProcessHeap(), 0, (len+len2)*sizeof(WCHAR) )))
320 {
321 WCHAR *ptr = op->src_path;
322 if (len)
323 {
324 SetupGetStringFieldW( &disk_ctx, 4, op->src_path, len, NULL );
325 ptr = op->src_path + strlenW(op->src_path);
326 if (len2 && ptr > op->src_path && ptr[-1] != '\\') *ptr++ = '\\';
327 }
328 if (!SetupGetStringFieldW( &disk_ctx, 4, ptr, len2, NULL )) *ptr = 0;
329 }
330 }
331 if (!op->src_root) op->src_root = strdupW( PARSER_get_src_root(hinf) );
332}
333
334
335/***********************************************************************
336 * get_destination_dir
337 *
338 * Retrieve the destination dir for a given section.
339 */
340static WCHAR *get_destination_dir( HINF hinf, const WCHAR *section )
341{
342 static const WCHAR Dest[] = {'D','e','s','t','i','n','a','t','i','o','n','D','i','r','s',0};
343 static const WCHAR Def[] = {'D','e','f','a','u','l','t','D','e','s','t','D','i','r',0};
344
345 const WCHAR *dir;
346 WCHAR *ptr, *ret;
347 INFCONTEXT context;
348 INT dirid;
349 DWORD len1, len2;
350
351 if (!SetupFindFirstLineW( hinf, Dest, section, &context ) &&
352 !SetupFindFirstLineW( hinf, Dest, Def, &context )) return NULL;
353 if (!SetupGetIntField( &context, 1, &dirid )) return NULL;
354 if (!(dir = DIRID_get_string( hinf, dirid ))) return NULL;
355 len1 = strlenW(dir) + 1;
356 if (!SetupGetStringFieldW( &context, 2, NULL, 0, &len2 )) len2 = 0;
357 if (!(ret = HeapAlloc( GetProcessHeap(), 0, (len1+len2) * sizeof(WCHAR) ))) return NULL;
358 strcpyW( ret, dir );
359 ptr = ret + strlenW(ret);
360 if (len2 && ptr > ret && ptr[-1] != '\\') *ptr++ = '\\';
361 if (!SetupGetStringFieldW( &context, 2, ptr, len2, NULL )) *ptr = 0;
362 return ret;
363}
364
365
366#ifdef __WIN32OS2__
367static void (* WINAPI pExtractFiles)( LPSTR, LPSTR, DWORD, DWORD, DWORD, DWORD );
368#else
369static void (WINAPI *pExtractFiles)( LPSTR, LPSTR, DWORD, DWORD, DWORD, DWORD );
370#endif
371
372/***********************************************************************
373 * extract_cabinet_file
374 *
375 * Extract a file from a .cab file.
376 */
377static BOOL extract_cabinet_file( const WCHAR *cabinet, const WCHAR *root,
378 const WCHAR *src, const WCHAR *dst )
379{
380 static const WCHAR extW[] = {'.','c','a','b',0};
381 static HMODULE advpack;
382
383 char *cab_path, *cab_file;
384 int len = strlenW( cabinet );
385
386 /* make sure the cabinet file has a .cab extension */
387 if (len <= 4 || strcmpiW( cabinet + len - 4, extW )) return FALSE;
388 if (!pExtractFiles)
389 {
390 if (!advpack && !(advpack = LoadLibraryA( "advpack.dll" )))
391 {
392 ERR( "could not load advpack.dll\n" );
393 return FALSE;
394 }
395 if (!(pExtractFiles = (void *)GetProcAddress( advpack, "ExtractFiles" )))
396 {
397 ERR( "could not find ExtractFiles in advpack.dll\n" );
398 return FALSE;
399 }
400 }
401
402 if (!(cab_path = strdupWtoA( root ))) return FALSE;
403 len = WideCharToMultiByte( CP_ACP, 0, cabinet, -1, NULL, 0, NULL, NULL );
404 if (!(cab_file = HeapAlloc( GetProcessHeap(), 0, strlen(cab_path) + len + 1 )))
405 {
406 HeapFree( GetProcessHeap(), 0, cab_path );
407 return FALSE;
408 }
409 strcpy( cab_file, cab_path );
410 if (cab_file[0] && cab_file[strlen(cab_file)-1] != '\\') strcat( cab_file, "\\" );
411 WideCharToMultiByte( CP_ACP, 0, cabinet, -1, cab_file + strlen(cab_file), len, NULL, NULL );
412 FIXME( "awful hack: extracting cabinet %s\n", debugstr_a(cab_file) );
413 pExtractFiles( cab_file, cab_path, 0, 0, 0, 0 );
414 HeapFree( GetProcessHeap(), 0, cab_file );
415 HeapFree( GetProcessHeap(), 0, cab_path );
416 return CopyFileW( src, dst, FALSE /*FIXME*/ );
417}
418
419
420/***********************************************************************
421 * SetupOpenFileQueue (SETUPAPI.@)
422 */
423HSPFILEQ WINAPI SetupOpenFileQueue(void)
424{
425 struct file_queue *queue;
426
427 if (!(queue = HeapAlloc( GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*queue))))
428 return (HSPFILEQ)INVALID_HANDLE_VALUE;
429 return queue;
430}
431
432
433/***********************************************************************
434 * SetupCloseFileQueue (SETUPAPI.@)
435 */
436BOOL WINAPI SetupCloseFileQueue( HSPFILEQ handle )
437{
438 struct file_queue *queue = handle;
439
440 free_file_op_queue( &queue->copy_queue );
441 free_file_op_queue( &queue->rename_queue );
442 free_file_op_queue( &queue->delete_queue );
443 HeapFree( GetProcessHeap(), 0, queue );
444 return TRUE;
445}
446
447
448/***********************************************************************
449 * SetupQueueCopyIndirectA (SETUPAPI.@)
450 */
451BOOL WINAPI SetupQueueCopyIndirectA( PSP_FILE_COPY_PARAMS_A params )
452{
453 struct file_queue *queue = params->QueueHandle;
454 struct file_op *op;
455
456 if (!(op = HeapAlloc( GetProcessHeap(), 0, sizeof(*op) ))) return FALSE;
457 op->style = params->CopyStyle;
458 op->src_root = strdupAtoW( params->SourceRootPath );
459 op->src_path = strdupAtoW( params->SourcePath );
460 op->src_file = strdupAtoW( params->SourceFilename );
461 op->src_descr = strdupAtoW( params->SourceDescription );
462 op->src_tag = strdupAtoW( params->SourceTagfile );
463 op->dst_path = strdupAtoW( params->TargetDirectory );
464 op->dst_file = strdupAtoW( params->TargetFilename );
465
466 /* some defaults */
467 if (!op->src_file) op->src_file = op->dst_file;
468 if (params->LayoutInf)
469 {
470 get_src_file_info( params->LayoutInf, op );
471 if (!op->dst_path) op->dst_path = get_destination_dir( params->LayoutInf, op->dst_file );
472 }
473
474 TRACE( "root=%s path=%s file=%s -> dir=%s file=%s descr=%s tag=%s\n",
475 debugstr_w(op->src_root), debugstr_w(op->src_path), debugstr_w(op->src_file),
476 debugstr_w(op->dst_path), debugstr_w(op->dst_file),
477 debugstr_w(op->src_descr), debugstr_w(op->src_tag) );
478
479 queue_file_op( &queue->copy_queue, op );
480 return TRUE;
481}
482
483
484/***********************************************************************
485 * SetupQueueCopyIndirectW (SETUPAPI.@)
486 */
487BOOL WINAPI SetupQueueCopyIndirectW( PSP_FILE_COPY_PARAMS_W params )
488{
489 struct file_queue *queue = params->QueueHandle;
490 struct file_op *op;
491
492 if (!(op = HeapAlloc( GetProcessHeap(), 0, sizeof(*op) ))) return FALSE;
493 op->style = params->CopyStyle;
494 op->src_root = strdupW( params->SourceRootPath );
495 op->src_path = strdupW( params->SourcePath );
496 op->src_file = strdupW( params->SourceFilename );
497 op->src_descr = strdupW( params->SourceDescription );
498 op->src_tag = strdupW( params->SourceTagfile );
499 op->dst_path = strdupW( params->TargetDirectory );
500 op->dst_file = strdupW( params->TargetFilename );
501
502 /* some defaults */
503 if (!op->src_file) op->src_file = op->dst_file;
504 if (params->LayoutInf)
505 {
506 get_src_file_info( params->LayoutInf, op );
507 if (!op->dst_path) op->dst_path = get_destination_dir( params->LayoutInf, op->dst_file );
508 }
509
510 TRACE( "root=%s path=%s file=%s -> dir=%s file=%s descr=%s tag=%s\n",
511 debugstr_w(op->src_root), debugstr_w(op->src_path), debugstr_w(op->src_file),
512 debugstr_w(op->dst_path), debugstr_w(op->dst_file),
513 debugstr_w(op->src_descr), debugstr_w(op->src_tag) );
514
515 queue_file_op( &queue->copy_queue, op );
516 return TRUE;
517}
518
519
520/***********************************************************************
521 * SetupQueueCopyA (SETUPAPI.@)
522 */
523BOOL WINAPI SetupQueueCopyA( HSPFILEQ queue, PCSTR src_root, PCSTR src_path, PCSTR src_file,
524 PCSTR src_descr, PCSTR src_tag, PCSTR dst_dir, PCSTR dst_file,
525 DWORD style )
526{
527 SP_FILE_COPY_PARAMS_A params;
528
529 params.cbSize = sizeof(params);
530 params.QueueHandle = queue;
531 params.SourceRootPath = src_root;
532 params.SourcePath = src_path;
533 params.SourceFilename = src_file;
534 params.SourceDescription = src_descr;
535 params.SourceTagfile = src_tag;
536 params.TargetDirectory = dst_dir;
537 params.TargetFilename = dst_file;
538 params.CopyStyle = style;
539 params.LayoutInf = 0;
540 params.SecurityDescriptor = NULL;
541 return SetupQueueCopyIndirectA( &params );
542}
543
544
545/***********************************************************************
546 * SetupQueueCopyW (SETUPAPI.@)
547 */
548BOOL WINAPI SetupQueueCopyW( HSPFILEQ queue, PCWSTR src_root, PCWSTR src_path, PCWSTR src_file,
549 PCWSTR src_descr, PCWSTR src_tag, PCWSTR dst_dir, PCWSTR dst_file,
550 DWORD style )
551{
552 SP_FILE_COPY_PARAMS_W params;
553
554 params.cbSize = sizeof(params);
555 params.QueueHandle = queue;
556 params.SourceRootPath = src_root;
557 params.SourcePath = src_path;
558 params.SourceFilename = src_file;
559 params.SourceDescription = src_descr;
560 params.SourceTagfile = src_tag;
561 params.TargetDirectory = dst_dir;
562 params.TargetFilename = dst_file;
563 params.CopyStyle = style;
564 params.LayoutInf = 0;
565 params.SecurityDescriptor = NULL;
566 return SetupQueueCopyIndirectW( &params );
567}
568
569
570/***********************************************************************
571 * SetupQueueDefaultCopyA (SETUPAPI.@)
572 */
573BOOL WINAPI SetupQueueDefaultCopyA( HSPFILEQ queue, HINF hinf, PCSTR src_root, PCSTR src_file,
574 PCSTR dst_file, DWORD style )
575{
576 SP_FILE_COPY_PARAMS_A params;
577
578 params.cbSize = sizeof(params);
579 params.QueueHandle = queue;
580 params.SourceRootPath = src_root;
581 params.SourcePath = NULL;
582 params.SourceFilename = src_file;
583 params.SourceDescription = NULL;
584 params.SourceTagfile = NULL;
585 params.TargetDirectory = NULL;
586 params.TargetFilename = dst_file;
587 params.CopyStyle = style;
588 params.LayoutInf = hinf;
589 params.SecurityDescriptor = NULL;
590 return SetupQueueCopyIndirectA( &params );
591}
592
593
594/***********************************************************************
595 * SetupQueueDefaultCopyW (SETUPAPI.@)
596 */
597BOOL WINAPI SetupQueueDefaultCopyW( HSPFILEQ queue, HINF hinf, PCWSTR src_root, PCWSTR src_file,
598 PCWSTR dst_file, DWORD style )
599{
600 SP_FILE_COPY_PARAMS_W params;
601
602 params.cbSize = sizeof(params);
603 params.QueueHandle = queue;
604 params.SourceRootPath = src_root;
605 params.SourcePath = NULL;
606 params.SourceFilename = src_file;
607 params.SourceDescription = NULL;
608 params.SourceTagfile = NULL;
609 params.TargetDirectory = NULL;
610 params.TargetFilename = dst_file;
611 params.CopyStyle = style;
612 params.LayoutInf = hinf;
613 params.SecurityDescriptor = NULL;
614 return SetupQueueCopyIndirectW( &params );
615}
616
617
618/***********************************************************************
619 * SetupQueueDeleteA (SETUPAPI.@)
620 */
621BOOL WINAPI SetupQueueDeleteA( HSPFILEQ handle, PCSTR part1, PCSTR part2 )
622{
623 struct file_queue *queue = handle;
624 struct file_op *op;
625
626 if (!(op = HeapAlloc( GetProcessHeap(), 0, sizeof(*op) ))) return FALSE;
627 op->style = 0;
628 op->src_root = NULL;
629 op->src_path = NULL;
630 op->src_file = NULL;
631 op->src_descr = NULL;
632 op->src_tag = NULL;
633 op->dst_path = strdupAtoW( part1 );
634 op->dst_file = strdupAtoW( part2 );
635 queue_file_op( &queue->delete_queue, op );
636 return TRUE;
637}
638
639
640/***********************************************************************
641 * SetupQueueDeleteW (SETUPAPI.@)
642 */
643BOOL WINAPI SetupQueueDeleteW( HSPFILEQ handle, PCWSTR part1, PCWSTR part2 )
644{
645 struct file_queue *queue = handle;
646 struct file_op *op;
647
648 if (!(op = HeapAlloc( GetProcessHeap(), 0, sizeof(*op) ))) return FALSE;
649 op->style = 0;
650 op->src_root = NULL;
651 op->src_path = NULL;
652 op->src_file = NULL;
653 op->src_descr = NULL;
654 op->src_tag = NULL;
655 op->dst_path = strdupW( part1 );
656 op->dst_file = strdupW( part2 );
657 queue_file_op( &queue->delete_queue, op );
658 return TRUE;
659}
660
661
662/***********************************************************************
663 * SetupQueueRenameA (SETUPAPI.@)
664 */
665BOOL WINAPI SetupQueueRenameA( HSPFILEQ handle, PCSTR SourcePath, PCSTR SourceFilename,
666 PCSTR TargetPath, PCSTR TargetFilename )
667{
668 struct file_queue *queue = handle;
669 struct file_op *op;
670
671 if (!(op = HeapAlloc( GetProcessHeap(), 0, sizeof(*op) ))) return FALSE;
672 op->style = 0;
673 op->src_root = NULL;
674 op->src_path = strdupAtoW( SourcePath );
675 op->src_file = strdupAtoW( SourceFilename );
676 op->src_descr = NULL;
677 op->src_tag = NULL;
678 op->dst_path = strdupAtoW( TargetPath );
679 op->dst_file = strdupAtoW( TargetFilename );
680 queue_file_op( &queue->rename_queue, op );
681 return TRUE;
682}
683
684
685/***********************************************************************
686 * SetupQueueRenameW (SETUPAPI.@)
687 */
688BOOL WINAPI SetupQueueRenameW( HSPFILEQ handle, PCWSTR SourcePath, PCWSTR SourceFilename,
689 PCWSTR TargetPath, PCWSTR TargetFilename )
690{
691 struct file_queue *queue = handle;
692 struct file_op *op;
693
694 if (!(op = HeapAlloc( GetProcessHeap(), 0, sizeof(*op) ))) return FALSE;
695 op->style = 0;
696 op->src_root = NULL;
697 op->src_path = strdupW( SourcePath );
698 op->src_file = strdupW( SourceFilename );
699 op->src_descr = NULL;
700 op->src_tag = NULL;
701 op->dst_path = strdupW( TargetPath );
702 op->dst_file = strdupW( TargetFilename );
703 queue_file_op( &queue->rename_queue, op );
704 return TRUE;
705}
706
707
708/***********************************************************************
709 * SetupQueueCopySectionA (SETUPAPI.@)
710 */
711BOOL WINAPI SetupQueueCopySectionA( HSPFILEQ queue, PCSTR src_root, HINF hinf, HINF hlist,
712 PCSTR section, DWORD style )
713{
714 UNICODE_STRING sectionW;
715 BOOL ret = FALSE;
716
717 if (!RtlCreateUnicodeStringFromAsciiz( &sectionW, section ))
718 {
719 SetLastError( ERROR_NOT_ENOUGH_MEMORY );
720 return FALSE;
721 }
722 if (!src_root)
723 ret = SetupQueueCopySectionW( queue, NULL, hinf, hlist, sectionW.Buffer, style );
724 else
725 {
726 UNICODE_STRING srcW;
727 if (RtlCreateUnicodeStringFromAsciiz( &srcW, src_root ))
728 {
729 ret = SetupQueueCopySectionW( queue, srcW.Buffer, hinf, hlist, sectionW.Buffer, style );
730 RtlFreeUnicodeString( &srcW );
731 }
732 else SetLastError( ERROR_NOT_ENOUGH_MEMORY );
733 }
734 RtlFreeUnicodeString( &sectionW );
735 return ret;
736}
737
738
739/***********************************************************************
740 * SetupQueueCopySectionW (SETUPAPI.@)
741 */
742BOOL WINAPI SetupQueueCopySectionW( HSPFILEQ queue, PCWSTR src_root, HINF hinf, HINF hlist,
743 PCWSTR section, DWORD style )
744{
745 SP_FILE_COPY_PARAMS_W params;
746 INFCONTEXT context;
747 WCHAR dest[MAX_PATH], src[MAX_PATH];
748 INT flags;
749
750 TRACE( "hinf=%p/%p section=%s root=%s\n",
751 hinf, hlist, debugstr_w(section), debugstr_w(src_root) );
752
753 params.cbSize = sizeof(params);
754 params.QueueHandle = queue;
755 params.SourceRootPath = src_root;
756 params.SourcePath = NULL;
757 params.SourceDescription = NULL;
758 params.SourceTagfile = NULL;
759 params.TargetFilename = dest;
760 params.CopyStyle = style;
761 params.LayoutInf = hinf;
762 params.SecurityDescriptor = NULL;
763
764 if (!hlist) hlist = hinf;
765 if (!SetupFindFirstLineW( hlist, section, NULL, &context )) return FALSE;
766 if (!(params.TargetDirectory = get_destination_dir( hinf, section ))) return FALSE;
767 do
768 {
769 if (!SetupGetStringFieldW( &context, 1, dest, sizeof(dest)/sizeof(WCHAR), NULL ))
770 return FALSE;
771 if (!SetupGetStringFieldW( &context, 2, src, sizeof(src)/sizeof(WCHAR), NULL )) *src = 0;
772 if (!SetupGetIntField( &context, 4, &flags )) flags = 0; /* FIXME */
773
774 params.SourceFilename = *src ? src : NULL;
775 if (!SetupQueueCopyIndirectW( &params )) return FALSE;
776 } while (SetupFindNextLine( &context, &context ));
777 return TRUE;
778}
779
780
781/***********************************************************************
782 * SetupQueueDeleteSectionA (SETUPAPI.@)
783 */
784BOOL WINAPI SetupQueueDeleteSectionA( HSPFILEQ queue, HINF hinf, HINF hlist, PCSTR section )
785{
786 UNICODE_STRING sectionW;
787 BOOL ret = FALSE;
788
789 if (RtlCreateUnicodeStringFromAsciiz( &sectionW, section ))
790 {
791 ret = SetupQueueDeleteSectionW( queue, hinf, hlist, sectionW.Buffer );
792 RtlFreeUnicodeString( &sectionW );
793 }
794 else SetLastError( ERROR_NOT_ENOUGH_MEMORY );
795 return ret;
796}
797
798
799/***********************************************************************
800 * SetupQueueDeleteSectionW (SETUPAPI.@)
801 */
802BOOL WINAPI SetupQueueDeleteSectionW( HSPFILEQ queue, HINF hinf, HINF hlist, PCWSTR section )
803{
804 INFCONTEXT context;
805 WCHAR *dest_dir;
806 WCHAR buffer[MAX_PATH];
807 BOOL ret = FALSE;
808 INT flags;
809
810 TRACE( "hinf=%p/%p section=%s\n", hinf, hlist, debugstr_w(section) );
811
812 if (!hlist) hlist = hinf;
813 if (!SetupFindFirstLineW( hlist, section, NULL, &context )) return FALSE;
814 if (!(dest_dir = get_destination_dir( hinf, section ))) return FALSE;
815 do
816 {
817 if (!SetupGetStringFieldW( &context, 1, buffer, sizeof(buffer)/sizeof(WCHAR), NULL ))
818 goto done;
819 if (!SetupGetIntField( &context, 4, &flags )) flags = 0;
820 if (!SetupQueueDeleteW( queue, dest_dir, buffer )) goto done;
821 } while (SetupFindNextLine( &context, &context ));
822
823 ret = TRUE;
824 done:
825 HeapFree( GetProcessHeap(), 0, dest_dir );
826 return ret;
827}
828
829
830/***********************************************************************
831 * SetupQueueRenameSectionA (SETUPAPI.@)
832 */
833BOOL WINAPI SetupQueueRenameSectionA( HSPFILEQ queue, HINF hinf, HINF hlist, PCSTR section )
834{
835 UNICODE_STRING sectionW;
836 BOOL ret = FALSE;
837
838 if (RtlCreateUnicodeStringFromAsciiz( &sectionW, section ))
839 {
840 ret = SetupQueueRenameSectionW( queue, hinf, hlist, sectionW.Buffer );
841 RtlFreeUnicodeString( &sectionW );
842 }
843 else SetLastError( ERROR_NOT_ENOUGH_MEMORY );
844 return ret;
845}
846
847
848/***********************************************************************
849 * SetupQueueRenameSectionW (SETUPAPI.@)
850 */
851BOOL WINAPI SetupQueueRenameSectionW( HSPFILEQ queue, HINF hinf, HINF hlist, PCWSTR section )
852{
853 INFCONTEXT context;
854 WCHAR *dest_dir;
855 WCHAR src[MAX_PATH], dst[MAX_PATH];
856 BOOL ret = FALSE;
857
858 TRACE( "hinf=%p/%p section=%s\n", hinf, hlist, debugstr_w(section) );
859
860 if (!hlist) hlist = hinf;
861 if (!SetupFindFirstLineW( hlist, section, NULL, &context )) return FALSE;
862 if (!(dest_dir = get_destination_dir( hinf, section ))) return FALSE;
863 do
864 {
865 if (!SetupGetStringFieldW( &context, 1, dst, sizeof(dst)/sizeof(WCHAR), NULL ))
866 goto done;
867 if (!SetupGetStringFieldW( &context, 2, src, sizeof(src)/sizeof(WCHAR), NULL ))
868 goto done;
869 if (!SetupQueueRenameW( queue, dest_dir, src, NULL, dst )) goto done;
870 } while (SetupFindNextLine( &context, &context ));
871
872 ret = TRUE;
873 done:
874 HeapFree( GetProcessHeap(), 0, dest_dir );
875 return ret;
876}
877
878
879/***********************************************************************
880 * SetupCommitFileQueueA (SETUPAPI.@)
881 */
882BOOL WINAPI SetupCommitFileQueueA( HWND owner, HSPFILEQ queue, PSP_FILE_CALLBACK_A handler,
883 PVOID context )
884{
885 struct callback_WtoA_context ctx;
886
887 ctx.orig_context = context;
888 ctx.orig_handler = handler;
889 return SetupCommitFileQueueW( owner, queue, QUEUE_callback_WtoA, &ctx );
890}
891
892
893/***********************************************************************
894 * create_full_pathW
895 *
896 * Recursively create all directories in the path.
897 */
898static BOOL create_full_pathW(const WCHAR *path)
899{
900 BOOL ret = TRUE;
901 int len;
902 WCHAR *new_path;
903
904 new_path = HeapAlloc(GetProcessHeap(), 0, (strlenW(path) + 1) * sizeof(WCHAR));
905 strcpyW(new_path, path);
906
907 while((len = strlenW(new_path)) && new_path[len - 1] == '\\')
908 new_path[len - 1] = 0;
909
910 while(!CreateDirectoryW(new_path, NULL))
911 {
912 WCHAR *slash;
913 DWORD last_error = GetLastError();
914
915 if(last_error == ERROR_ALREADY_EXISTS)
916 break;
917
918 if(last_error != ERROR_PATH_NOT_FOUND)
919 {
920 ret = FALSE;
921 break;
922 }
923
924 if(!(slash = strrchrW(new_path, '\\')))
925 {
926 ret = FALSE;
927 break;
928 }
929
930 len = slash - new_path;
931 new_path[len] = 0;
932 if(!create_full_pathW(new_path))
933 {
934 ret = FALSE;
935 break;
936 }
937 new_path[len] = '\\';
938 }
939
940 HeapFree(GetProcessHeap(), 0, new_path);
941 return ret;
942}
943
944
945/***********************************************************************
946 * SetupCommitFileQueueW (SETUPAPI.@)
947 */
948BOOL WINAPI SetupCommitFileQueueW( HWND owner, HSPFILEQ handle, PSP_FILE_CALLBACK_W handler,
949 PVOID context )
950{
951 struct file_queue *queue = handle;
952 struct file_op *op;
953 BOOL result = FALSE;
954 FILEPATHS_W paths;
955 UINT op_result;
956
957 paths.Source = paths.Target = NULL;
958
959 if (!queue->copy_queue.count && !queue->delete_queue.count && !queue->rename_queue.count)
960 return TRUE; /* nothing to do */
961
962 if (!handler( context, SPFILENOTIFY_STARTQUEUE, (UINT)owner, 0 )) return FALSE;
963
964 /* perform deletes */
965
966 if (queue->delete_queue.count)
967 {
968 if (!(handler( context, SPFILENOTIFY_STARTSUBQUEUE, FILEOP_DELETE,
969 queue->delete_queue.count ))) goto done;
970 for (op = queue->delete_queue.head; op; op = op->next)
971 {
972 build_filepathsW( op, &paths );
973 op_result = handler( context, SPFILENOTIFY_STARTDELETE, (UINT_PTR)&paths, FILEOP_DELETE);
974 if (op_result == FILEOP_ABORT) goto done;
975 while (op_result == FILEOP_DOIT)
976 {
977 TRACE( "deleting file %s\n", debugstr_w(paths.Target) );
978 if (DeleteFileW( paths.Target )) break; /* success */
979 paths.Win32Error = GetLastError();
980 op_result = handler( context, SPFILENOTIFY_DELETEERROR, (UINT_PTR)&paths, 0 );
981 if (op_result == FILEOP_ABORT) goto done;
982 }
983 handler( context, SPFILENOTIFY_ENDDELETE, (UINT_PTR)&paths, 0 );
984 }
985 handler( context, SPFILENOTIFY_ENDSUBQUEUE, FILEOP_DELETE, 0 );
986 }
987
988 /* perform renames */
989
990 if (queue->rename_queue.count)
991 {
992 if (!(handler( context, SPFILENOTIFY_STARTSUBQUEUE, FILEOP_RENAME,
993 queue->rename_queue.count ))) goto done;
994 for (op = queue->rename_queue.head; op; op = op->next)
995 {
996 build_filepathsW( op, &paths );
997 op_result = handler( context, SPFILENOTIFY_STARTRENAME, (UINT_PTR)&paths, FILEOP_RENAME);
998 if (op_result == FILEOP_ABORT) goto done;
999 while (op_result == FILEOP_DOIT)
1000 {
1001 TRACE( "renaming file %s -> %s\n",
1002 debugstr_w(paths.Source), debugstr_w(paths.Target) );
1003 if (MoveFileW( paths.Source, paths.Target )) break; /* success */
1004 paths.Win32Error = GetLastError();
1005 op_result = handler( context, SPFILENOTIFY_RENAMEERROR, (UINT_PTR)&paths, 0 );
1006 if (op_result == FILEOP_ABORT) goto done;
1007 }
1008 handler( context, SPFILENOTIFY_ENDRENAME, (UINT_PTR)&paths, 0 );
1009 }
1010 handler( context, SPFILENOTIFY_ENDSUBQUEUE, FILEOP_RENAME, 0 );
1011 }
1012
1013 /* perform copies */
1014
1015 if (queue->copy_queue.count)
1016 {
1017 if (!(handler( context, SPFILENOTIFY_STARTSUBQUEUE, FILEOP_COPY,
1018 queue->copy_queue.count ))) goto done;
1019 for (op = queue->copy_queue.head; op; op = op->next)
1020 {
1021 WCHAR newpath[MAX_PATH];
1022
1023 build_filepathsW( op, &paths );
1024 op_result = handler( context, SPFILENOTIFY_STARTCOPY, (UINT_PTR)&paths, FILEOP_COPY );
1025 if (op_result == FILEOP_ABORT) goto done;
1026 if (op_result == FILEOP_NEWPATH) op_result = FILEOP_DOIT;
1027 while (op_result == FILEOP_DOIT || op_result == FILEOP_NEWPATH)
1028 {
1029 TRACE( "copying file %s -> %s\n",
1030 debugstr_w( op_result == FILEOP_NEWPATH ? newpath : paths.Source ),
1031 debugstr_w(paths.Target) );
1032 if (op->dst_path)
1033 {
1034 if (!create_full_pathW( op->dst_path ))
1035 {
1036 paths.Win32Error = GetLastError();
1037 op_result = handler( context, SPFILENOTIFY_COPYERROR,
1038 (UINT_PTR)&paths, (UINT_PTR)newpath );
1039 if (op_result == FILEOP_ABORT) goto done;
1040 }
1041 }
1042 if (CopyFileW( op_result == FILEOP_NEWPATH ? newpath : paths.Source,
1043 paths.Target, FALSE /*FIXME*/ )) break; /* success */
1044 /* try to extract it from the cabinet file */
1045 if (op->src_tag)
1046 {
1047 if (extract_cabinet_file( op->src_tag, op->src_root,
1048 paths.Source, paths.Target )) break;
1049 }
1050 paths.Win32Error = GetLastError();
1051 op_result = handler( context, SPFILENOTIFY_COPYERROR,
1052 (UINT_PTR)&paths, (UINT_PTR)newpath );
1053 if (op_result == FILEOP_ABORT) goto done;
1054 }
1055 handler( context, SPFILENOTIFY_ENDCOPY, (UINT_PTR)&paths, 0 );
1056 }
1057 handler( context, SPFILENOTIFY_ENDSUBQUEUE, FILEOP_COPY, 0 );
1058 }
1059
1060
1061 result = TRUE;
1062
1063 done:
1064 handler( context, SPFILENOTIFY_ENDQUEUE, result, 0 );
1065 HeapFree( GetProcessHeap(), 0, (void *)paths.Source );
1066 HeapFree( GetProcessHeap(), 0, (void *)paths.Target );
1067 return result;
1068}
1069
1070
1071/***********************************************************************
1072 * SetupScanFileQueueA (SETUPAPI.@)
1073 */
1074BOOL WINAPI SetupScanFileQueueA( HSPFILEQ queue, DWORD flags, HWND window,
1075 PSP_FILE_CALLBACK_A callback, PVOID context, PDWORD result )
1076{
1077 FIXME("stub\n");
1078 return FALSE;
1079}
1080
1081
1082/***********************************************************************
1083 * SetupScanFileQueueW (SETUPAPI.@)
1084 */
1085BOOL WINAPI SetupScanFileQueueW( HSPFILEQ queue, DWORD flags, HWND window,
1086 PSP_FILE_CALLBACK_W callback, PVOID context, PDWORD result )
1087{
1088 FIXME("stub\n");
1089 return FALSE;
1090}
1091
1092
1093/***********************************************************************
1094 * SetupGetFileQueueCount (SETUPAPI.@)
1095 */
1096BOOL WINAPI SetupGetFileQueueCount( HSPFILEQ handle, UINT op, PUINT result )
1097{
1098 struct file_queue *queue = handle;
1099
1100 switch(op)
1101 {
1102 case FILEOP_COPY:
1103 *result = queue->copy_queue.count;
1104 return TRUE;
1105 case FILEOP_RENAME:
1106 *result = queue->rename_queue.count;
1107 return TRUE;
1108 case FILEOP_DELETE:
1109 *result = queue->delete_queue.count;
1110 return TRUE;
1111 }
1112 return FALSE;
1113}
1114
1115
1116/***********************************************************************
1117 * SetupGetFileQueueFlags (SETUPAPI.@)
1118 */
1119BOOL WINAPI SetupGetFileQueueFlags( HSPFILEQ handle, PDWORD flags )
1120{
1121 struct file_queue *queue = handle;
1122 *flags = queue->flags;
1123 return TRUE;
1124}
1125
1126
1127/***********************************************************************
1128 * SetupSetFileQueueFlags (SETUPAPI.@)
1129 */
1130BOOL WINAPI SetupSetFileQueueFlags( HSPFILEQ handle, DWORD mask, DWORD flags )
1131{
1132 struct file_queue *queue = handle;
1133 queue->flags = (queue->flags & ~mask) | flags;
1134 return TRUE;
1135}
1136
1137
1138/***********************************************************************
1139 * SetupInitDefaultQueueCallback (SETUPAPI.@)
1140 */
1141PVOID WINAPI SetupInitDefaultQueueCallback( HWND owner )
1142{
1143 return SetupInitDefaultQueueCallbackEx( owner, 0, 0, 0, NULL );
1144}
1145
1146
1147/***********************************************************************
1148 * SetupInitDefaultQueueCallbackEx (SETUPAPI.@)
1149 */
1150PVOID WINAPI SetupInitDefaultQueueCallbackEx( HWND owner, HWND progress, UINT msg,
1151 DWORD reserved1, PVOID reserved2 )
1152{
1153 struct default_callback_context *context;
1154
1155 if ((context = HeapAlloc( GetProcessHeap(), 0, sizeof(*context) )))
1156 {
1157 context->owner = owner;
1158 context->progress = progress;
1159 context->message = msg;
1160 }
1161 return context;
1162}
1163
1164
1165/***********************************************************************
1166 * SetupTermDefaultQueueCallback (SETUPAPI.@)
1167 */
1168void WINAPI SetupTermDefaultQueueCallback( PVOID context )
1169{
1170 HeapFree( GetProcessHeap(), 0, context );
1171}
1172
1173
1174/***********************************************************************
1175 * SetupDefaultQueueCallbackA (SETUPAPI.@)
1176 */
1177UINT WINAPI SetupDefaultQueueCallbackA( PVOID context, UINT notification,
1178 UINT_PTR param1, UINT_PTR param2 )
1179{
1180 FILEPATHS_A *paths = (FILEPATHS_A *)param1;
1181
1182 switch(notification)
1183 {
1184 case SPFILENOTIFY_STARTQUEUE:
1185 TRACE( "start queue\n" );
1186 return TRUE;
1187 case SPFILENOTIFY_ENDQUEUE:
1188 TRACE( "end queue\n" );
1189 return 0;
1190 case SPFILENOTIFY_STARTSUBQUEUE:
1191 TRACE( "start subqueue %d count %d\n", param1, param2 );
1192 return TRUE;
1193 case SPFILENOTIFY_ENDSUBQUEUE:
1194 TRACE( "end subqueue %d\n", param1 );
1195 return 0;
1196 case SPFILENOTIFY_STARTDELETE:
1197 TRACE( "start delete %s\n", debugstr_a(paths->Target) );
1198 return FILEOP_DOIT;
1199 case SPFILENOTIFY_ENDDELETE:
1200 TRACE( "end delete %s\n", debugstr_a(paths->Target) );
1201 return 0;
1202 case SPFILENOTIFY_DELETEERROR:
1203 ERR( "delete error %d %s\n", paths->Win32Error, debugstr_a(paths->Target) );
1204 return FILEOP_SKIP;
1205 case SPFILENOTIFY_STARTRENAME:
1206 TRACE( "start rename %s -> %s\n", debugstr_a(paths->Source), debugstr_a(paths->Target) );
1207 return FILEOP_DOIT;
1208 case SPFILENOTIFY_ENDRENAME:
1209 TRACE( "end rename %s -> %s\n", debugstr_a(paths->Source), debugstr_a(paths->Target) );
1210 return 0;
1211 case SPFILENOTIFY_RENAMEERROR:
1212 ERR( "rename error %d %s -> %s\n", paths->Win32Error,
1213 debugstr_a(paths->Source), debugstr_a(paths->Target) );
1214 return FILEOP_SKIP;
1215 case SPFILENOTIFY_STARTCOPY:
1216 TRACE( "start copy %s -> %s\n", debugstr_a(paths->Source), debugstr_a(paths->Target) );
1217 return FILEOP_DOIT;
1218 case SPFILENOTIFY_ENDCOPY:
1219 TRACE( "end copy %s -> %s\n", debugstr_a(paths->Source), debugstr_a(paths->Target) );
1220 return 0;
1221 case SPFILENOTIFY_COPYERROR:
1222 ERR( "copy error %d %s -> %s\n", paths->Win32Error,
1223 debugstr_a(paths->Source), debugstr_a(paths->Target) );
1224 return FILEOP_SKIP;
1225 case SPFILENOTIFY_NEEDMEDIA:
1226 TRACE( "need media\n" );
1227 return FILEOP_SKIP;
1228 default:
1229 FIXME( "notification %d params %x,%x\n", notification, param1, param2 );
1230 break;
1231 }
1232 return 0;
1233}
1234
1235
1236/***********************************************************************
1237 * SetupDefaultQueueCallbackW (SETUPAPI.@)
1238 */
1239UINT WINAPI SetupDefaultQueueCallbackW( PVOID context, UINT notification,
1240 UINT_PTR param1, UINT_PTR param2 )
1241{
1242 FIXME( "notification %d params %x,%x\n", notification, param1, param2 );
1243 return FILEOP_SKIP;
1244}
Note: See TracBrowser for help on using the repository browser.