source: trunk/src/setupapi/queue.c

Last change on this file was 21916, checked in by dmik, 14 years ago

Merge branch gcc-kmk to trunk.

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