rtworkq: Add RtwqJoinWorkQueue()/RtwqUnjoinWorkQueue() stubs.
[wine.git] / dlls / setupapi / setupcab.c
blobb9783b8135660265970c23b6e4f6bd87b48f792f
1 /*
2 * Setupapi cabinet routines
4 * Copyright 2003 Gregory M. Turner
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
21 * Many useful traces are commented in code, uncomment them if you have
22 * trouble and run with WINEDEBUG=+setupapi
26 #include <stdarg.h>
27 #include <string.h>
28 #include <stdlib.h>
30 #include "windef.h"
31 #include "winbase.h"
32 #include "wingdi.h"
33 #include "winuser.h"
34 #include "winnls.h"
35 #include "winreg.h"
36 #include "setupapi.h"
37 #include "setupapi_private.h"
38 #include "fdi.h"
39 #include "wine/debug.h"
41 /* from msvcrt */
42 #define _O_RDONLY 0
43 #define _O_WRONLY 1
44 #define _O_RDWR 2
45 #define _O_ACCMODE (_O_RDONLY|_O_WRONLY|_O_RDWR)
46 #define _O_APPEND 0x0008
47 #define _O_RANDOM 0x0010
48 #define _O_SEQUENTIAL 0x0020
49 #define _O_TEMPORARY 0x0040
50 #define _O_NOINHERIT 0x0080
51 #define _O_CREAT 0x0100
52 #define _O_TRUNC 0x0200
53 #define _O_EXCL 0x0400
54 #define _O_SHORT_LIVED 0x1000
55 #define _O_TEXT 0x4000
56 #define _O_BINARY 0x8000
58 #define _SH_COMPAT 0x00
59 #define _SH_DENYRW 0x10
60 #define _SH_DENYWR 0x20
61 #define _SH_DENYRD 0x30
62 #define _SH_DENYNO 0x40
64 OSVERSIONINFOW OsVersionInfo;
66 static HINSTANCE CABINET_hInstance = 0;
67 HINSTANCE SETUPAPI_hInstance = 0;
69 static HFDI (__cdecl *sc_FDICreate)(PFNALLOC, PFNFREE, PFNOPEN,
70 PFNREAD, PFNWRITE, PFNCLOSE, PFNSEEK, int, PERF);
72 static BOOL (__cdecl *sc_FDICopy)(HFDI, char *, char *, int,
73 PFNFDINOTIFY, PFNFDIDECRYPT, void *);
75 static BOOL (__cdecl *sc_FDIDestroy)(HFDI);
77 #define SC_HSC_A_MAGIC 0xACABFEED
78 typedef struct {
79 UINT magic;
80 HFDI hfdi;
81 PSP_FILE_CALLBACK_A msghandler;
82 PVOID context;
83 CHAR most_recent_cabinet_name[MAX_PATH];
84 CHAR most_recent_target[MAX_PATH];
85 } SC_HSC_A, *PSC_HSC_A;
87 #define SC_HSC_W_MAGIC 0x0CABFEED
88 typedef struct {
89 UINT magic;
90 HFDI hfdi;
91 PSP_FILE_CALLBACK_W msghandler;
92 PVOID context;
93 WCHAR most_recent_cabinet_name[MAX_PATH];
94 WCHAR most_recent_target[MAX_PATH];
95 } SC_HSC_W, *PSC_HSC_W;
97 WINE_DEFAULT_DEBUG_CHANNEL(setupapi);
99 static BOOL LoadCABINETDll(void)
101 if (!CABINET_hInstance) {
102 CABINET_hInstance = LoadLibraryA("cabinet.dll");
103 if (CABINET_hInstance) {
104 sc_FDICreate = (void *)GetProcAddress(CABINET_hInstance, "FDICreate");
105 sc_FDICopy = (void *)GetProcAddress(CABINET_hInstance, "FDICopy");
106 sc_FDIDestroy = (void *)GetProcAddress(CABINET_hInstance, "FDIDestroy");
107 return TRUE;
108 } else {
109 ERR("load cabinet dll failed.\n");
110 return FALSE;
112 } else
113 return TRUE;
116 /* FDICreate callbacks */
118 static void * CDECL sc_cb_alloc(ULONG cb)
120 return HeapAlloc(GetProcessHeap(), 0, cb);
123 static void CDECL sc_cb_free(void *pv)
125 HeapFree(GetProcessHeap(), 0, pv);
128 static INT_PTR CDECL sc_cb_open(char *pszFile, int oflag, int pmode)
130 DWORD creation = 0, sharing = 0;
131 int ioflag = 0;
132 INT_PTR ret = 0;
133 SECURITY_ATTRIBUTES sa;
135 /* TRACE("(pszFile == %s, oflag == %d, pmode == %d)\n", debugstr_a(pszFile), oflag, pmode); */
137 switch(oflag & (_O_RDONLY | _O_WRONLY | _O_RDWR)) {
138 case _O_RDONLY:
139 ioflag |= GENERIC_READ;
140 break;
141 case _O_WRONLY:
142 ioflag |= GENERIC_WRITE;
143 break;
144 case _O_RDWR:
145 ioflag |= GENERIC_READ | GENERIC_WRITE;
146 break;
147 case _O_WRONLY | _O_RDWR: /* hmmm.. */
148 ERR("_O_WRONLY & _O_RDWR in oflag?\n");
149 return -1;
152 if (oflag & _O_CREAT) {
153 if (oflag & _O_EXCL)
154 creation = CREATE_NEW;
155 else if (oflag & _O_TRUNC)
156 creation = CREATE_ALWAYS;
157 else
158 creation = OPEN_ALWAYS;
159 } else /* no _O_CREAT */ {
160 if (oflag & _O_TRUNC)
161 creation = TRUNCATE_EXISTING;
162 else
163 creation = OPEN_EXISTING;
166 switch( pmode & 0x70 ) {
167 case _SH_DENYRW:
168 sharing = 0L;
169 break;
170 case _SH_DENYWR:
171 sharing = FILE_SHARE_READ;
172 break;
173 case _SH_DENYRD:
174 sharing = FILE_SHARE_WRITE;
175 break;
176 case _SH_COMPAT:
177 case _SH_DENYNO:
178 sharing = FILE_SHARE_READ | FILE_SHARE_WRITE;
179 break;
180 default:
181 ERR("<-- -1 (Unhandled pmode 0x%x)\n", pmode);
182 return -1;
185 if (oflag & ~(_O_BINARY | _O_TRUNC | _O_EXCL | _O_CREAT | _O_RDWR | _O_WRONLY | _O_NOINHERIT))
186 WARN("unsupported oflag 0x%04x\n",oflag);
188 sa.nLength = sizeof( SECURITY_ATTRIBUTES );
189 sa.lpSecurityDescriptor = NULL;
190 sa.bInheritHandle = !(ioflag & _O_NOINHERIT);
192 ret = (INT_PTR) CreateFileA(pszFile, ioflag, sharing, &sa, creation, FILE_ATTRIBUTE_NORMAL, NULL);
194 /* TRACE("<-- %d\n", ret); */
196 return ret;
199 static UINT CDECL sc_cb_read(INT_PTR hf, void *pv, UINT cb)
201 DWORD num_read;
202 BOOL rslt;
204 /* TRACE("(hf == %d, pv == ^%p, cb == %u)\n", hf, pv, cb); */
206 rslt = ReadFile((HANDLE) hf, pv, cb, &num_read, NULL);
209 /* eof and failure both give "-1" return */
210 if ((! rslt) || ((cb > 0) && (num_read == 0))) {
211 /* TRACE("<-- -1\n"); */
212 return -1;
215 /* TRACE("<-- %lu\n", num_read); */
216 return num_read;
219 static UINT CDECL sc_cb_write(INT_PTR hf, void *pv, UINT cb)
221 DWORD num_written;
222 /* BOOL rv; */
224 /* TRACE("(hf == %d, pv == ^%p, cb == %u)\n", hf, pv, cb); */
226 if ( /* (rv = */ WriteFile((HANDLE) hf, pv, cb, &num_written, NULL) /* ) */
227 && (num_written == cb)) {
228 /* TRACE("<-- %lu\n", num_written); */
229 return num_written;
230 } else {
231 /* TRACE("rv == %d, num_written == %lu, cb == %u\n", rv, num_written,cb); */
232 /* TRACE("<-- -1\n"); */
233 return -1;
237 static int CDECL sc_cb_close(INT_PTR hf)
239 /* TRACE("(hf == %d)\n", hf); */
241 if (CloseHandle((HANDLE) hf))
242 return 0;
243 else
244 return -1;
247 static LONG CDECL sc_cb_lseek(INT_PTR hf, LONG dist, int seektype)
249 DWORD ret;
251 /* TRACE("(hf == %d, dist == %ld, seektype == %d)\n", hf, dist, seektype); */
253 if (seektype < 0 || seektype > 2)
254 return -1;
256 if (((ret = SetFilePointer((HANDLE) hf, dist, NULL, seektype)) != INVALID_SET_FILE_POINTER) || !GetLastError()) {
257 /* TRACE("<-- %lu\n", ret); */
258 return ret;
259 } else {
260 /* TRACE("<-- -1\n"); */
261 return -1;
265 #define SIZEOF_MYSTERIO (MAX_PATH*3)
267 /* FDICopy callbacks */
269 static INT_PTR CDECL sc_FNNOTIFY_A(FDINOTIFICATIONTYPE fdint, PFDINOTIFICATION pfdin)
271 FILE_IN_CABINET_INFO_A fici;
272 PSC_HSC_A phsc;
273 CABINET_INFO_A ci;
274 FILEPATHS_A fp;
275 UINT err;
277 CHAR mysterio[SIZEOF_MYSTERIO]; /* how big? undocumented! probably 256... */
279 memset(mysterio, 0, SIZEOF_MYSTERIO);
281 TRACE("(fdint == %d, pfdin == ^%p)\n", fdint, pfdin);
283 if (pfdin && pfdin->pv && (((PSC_HSC_A) pfdin->pv)->magic == SC_HSC_A_MAGIC))
284 phsc = pfdin->pv;
285 else {
286 ERR("pv %p is not an SC_HSC_A.\n", (pfdin) ? pfdin->pv : NULL);
287 return -1;
290 switch (fdint) {
291 case fdintCABINET_INFO:
292 TRACE("Cabinet info notification\n");
293 /* TRACE(" Cabinet name: %s\n", debugstr_a(pfdin->psz1));
294 TRACE(" Cabinet disk: %s\n", debugstr_a(pfdin->psz2));
295 TRACE(" Cabinet path: %s\n", debugstr_a(pfdin->psz3));
296 TRACE(" Cabinet Set#: %d\n", pfdin->setID);
297 TRACE(" Cabinet Cab#: %d\n", pfdin->iCabinet); */
298 WARN("SPFILENOTIFY_CABINETINFO undocumented: guess implementation.\n");
299 ci.CabinetFile = phsc->most_recent_cabinet_name;
300 ci.CabinetPath = pfdin->psz3;
301 ci.DiskName = pfdin->psz2;
302 ci.SetId = pfdin->setID;
303 ci.CabinetNumber = pfdin->iCabinet;
304 phsc->msghandler(phsc->context, SPFILENOTIFY_CABINETINFO, (UINT_PTR) &ci, 0);
305 return 0;
306 case fdintPARTIAL_FILE:
307 TRACE("Partial file notification\n");
308 /* TRACE(" Partial file name: %s\n", debugstr_a(pfdin->psz1)); */
309 return 0;
310 case fdintCOPY_FILE:
311 TRACE("Copy file notification\n");
312 TRACE(" File name: %s\n", debugstr_a(pfdin->psz1));
313 /* TRACE(" File size: %ld\n", pfdin->cb);
314 TRACE(" File date: %u\n", pfdin->date);
315 TRACE(" File time: %u\n", pfdin->time);
316 TRACE(" File attr: %u\n", pfdin->attribs); */
317 fici.NameInCabinet = pfdin->psz1;
318 fici.FileSize = pfdin->cb;
319 fici.Win32Error = 0;
320 fici.DosDate = pfdin->date;
321 fici.DosTime = pfdin->time;
322 fici.DosAttribs = pfdin->attribs;
323 memset(fici.FullTargetName, 0, MAX_PATH);
324 err = phsc->msghandler(phsc->context, SPFILENOTIFY_FILEINCABINET,
325 (UINT_PTR)&fici, (UINT_PTR)pfdin->psz1);
326 if (err == FILEOP_DOIT) {
327 TRACE(" Callback specified filename: %s\n", debugstr_a(fici.FullTargetName));
328 if (!fici.FullTargetName[0]) {
329 WARN(" Empty return string causing abort.\n");
330 SetLastError(ERROR_PATH_NOT_FOUND);
331 return -1;
333 strcpy( phsc->most_recent_target, fici.FullTargetName );
334 return sc_cb_open(fici.FullTargetName, _O_BINARY | _O_CREAT | _O_WRONLY, _S_IREAD | _S_IWRITE);
335 } else {
336 TRACE(" Callback skipped file.\n");
337 return 0;
339 case fdintCLOSE_FILE_INFO:
340 TRACE("Close file notification\n");
341 /* TRACE(" File name: %s\n", debugstr_a(pfdin->psz1));
342 TRACE(" Exec file? %s\n", (pfdin->cb) ? "Yes" : "No");
343 TRACE(" File hndl: %d\n", pfdin->hf); */
344 fp.Source = phsc->most_recent_cabinet_name;
345 fp.Target = phsc->most_recent_target;
346 fp.Win32Error = 0;
347 fp.Flags = 0;
348 /* the following should be a fixme -- but it occurs too many times */
349 WARN("Should set file date/time/attribs (and execute files?)\n");
350 if (sc_cb_close(pfdin->hf))
351 WARN("_close failed.\n");
352 err = phsc->msghandler(phsc->context, SPFILENOTIFY_FILEEXTRACTED, (UINT_PTR)&fp, 0);
353 if (err) {
354 SetLastError(err);
355 return FALSE;
356 } else
357 return TRUE;
358 case fdintNEXT_CABINET:
359 TRACE("Next cabinet notification\n");
360 /* TRACE(" Cabinet name: %s\n", debugstr_a(pfdin->psz1));
361 TRACE(" Cabinet disk: %s\n", debugstr_a(pfdin->psz2));
362 TRACE(" Cabinet path: %s\n", debugstr_a(pfdin->psz3));
363 TRACE(" Cabinet Set#: %d\n", pfdin->setID);
364 TRACE(" Cabinet Cab#: %d\n", pfdin->iCabinet); */
365 ci.CabinetFile = pfdin->psz1;
366 ci.CabinetPath = pfdin->psz3;
367 ci.DiskName = pfdin->psz2;
368 ci.SetId = pfdin->setID;
369 ci.CabinetNumber = pfdin->iCabinet;
370 /* remember the new cabinet name */
371 strcpy(phsc->most_recent_cabinet_name, pfdin->psz1);
372 err = phsc->msghandler(phsc->context, SPFILENOTIFY_NEEDNEWCABINET, (UINT_PTR)&ci, (UINT_PTR)mysterio);
373 if (err) {
374 SetLastError(err);
375 return -1;
376 } else {
377 if (mysterio[0]) {
378 /* some easy paranoia. no such carefulness exists on the wide API IIRC */
379 lstrcpynA(pfdin->psz3, mysterio, SIZEOF_MYSTERIO);
381 return 0;
383 default:
384 FIXME("Unknown notification type %d.\n", fdint);
385 return 0;
389 static INT_PTR CDECL sc_FNNOTIFY_W(FDINOTIFICATIONTYPE fdint, PFDINOTIFICATION pfdin)
391 FILE_IN_CABINET_INFO_W fici;
392 PSC_HSC_W phsc;
393 CABINET_INFO_W ci;
394 FILEPATHS_W fp;
395 UINT err;
396 int len;
398 WCHAR mysterio[SIZEOF_MYSTERIO]; /* how big? undocumented! */
399 WCHAR buf[MAX_PATH], buf2[MAX_PATH];
400 CHAR charbuf[MAX_PATH];
402 memset(mysterio, 0, SIZEOF_MYSTERIO * sizeof(WCHAR));
403 memset(buf, 0, MAX_PATH * sizeof(WCHAR));
404 memset(buf2, 0, MAX_PATH * sizeof(WCHAR));
405 memset(charbuf, 0, MAX_PATH);
407 TRACE("(fdint == %d, pfdin == ^%p)\n", fdint, pfdin);
409 if (pfdin && pfdin->pv && (((PSC_HSC_W) pfdin->pv)->magic == SC_HSC_W_MAGIC))
410 phsc = pfdin->pv;
411 else {
412 ERR("pv %p is not an SC_HSC_W.\n", (pfdin) ? pfdin->pv : NULL);
413 return -1;
416 switch (fdint) {
417 case fdintCABINET_INFO:
418 TRACE("Cabinet info notification\n");
419 /* TRACE(" Cabinet name: %s\n", debugstr_a(pfdin->psz1));
420 TRACE(" Cabinet disk: %s\n", debugstr_a(pfdin->psz2));
421 TRACE(" Cabinet path: %s\n", debugstr_a(pfdin->psz3));
422 TRACE(" Cabinet Set#: %d\n", pfdin->setID);
423 TRACE(" Cabinet Cab#: %d\n", pfdin->iCabinet); */
424 WARN("SPFILENOTIFY_CABINETINFO undocumented: guess implementation.\n");
425 ci.CabinetFile = phsc->most_recent_cabinet_name;
426 len = 1 + MultiByteToWideChar(CP_ACP, 0, pfdin->psz3, -1, buf, MAX_PATH);
427 if ((len > MAX_PATH) || (len <= 1))
428 buf[0] = '\0';
429 ci.CabinetPath = buf;
430 len = 1 + MultiByteToWideChar(CP_ACP, 0, pfdin->psz2, -1, buf2, MAX_PATH);
431 if ((len > MAX_PATH) || (len <= 1))
432 buf2[0] = '\0';
433 ci.DiskName = buf2;
434 ci.SetId = pfdin->setID;
435 ci.CabinetNumber = pfdin->iCabinet;
436 phsc->msghandler(phsc->context, SPFILENOTIFY_CABINETINFO, (UINT_PTR)&ci, 0);
437 return 0;
438 case fdintPARTIAL_FILE:
439 TRACE("Partial file notification\n");
440 /* TRACE(" Partial file name: %s\n", debugstr_a(pfdin->psz1)); */
441 return 0;
442 case fdintCOPY_FILE:
443 TRACE("Copy file notification\n");
444 TRACE(" File name: %s\n", debugstr_a(pfdin->psz1));
445 /* TRACE(" File size: %ld\n", pfdin->cb);
446 TRACE(" File date: %u\n", pfdin->date);
447 TRACE(" File time: %u\n", pfdin->time);
448 TRACE(" File attr: %u\n", pfdin->attribs); */
449 len = 1 + MultiByteToWideChar(CP_ACP, 0, pfdin->psz1, -1, buf2, MAX_PATH);
450 if ((len > MAX_PATH) || (len <= 1))
451 buf2[0] = '\0';
452 fici.NameInCabinet = buf2;
453 fici.FileSize = pfdin->cb;
454 fici.Win32Error = 0;
455 fici.DosDate = pfdin->date;
456 fici.DosTime = pfdin->time;
457 fici.DosAttribs = pfdin->attribs;
458 memset(fici.FullTargetName, 0, MAX_PATH * sizeof(WCHAR));
459 err = phsc->msghandler(phsc->context, SPFILENOTIFY_FILEINCABINET,
460 (UINT_PTR)&fici, (UINT_PTR)pfdin->psz1);
461 if (err == FILEOP_DOIT) {
462 TRACE(" Callback specified filename: %s\n", debugstr_w(fici.FullTargetName));
463 if (fici.FullTargetName[0]) {
464 len = lstrlenW(fici.FullTargetName) + 1;
465 if ((len > MAX_PATH ) || (len <= 1))
466 return 0;
467 if (!WideCharToMultiByte(CP_ACP, 0, fici.FullTargetName, len, charbuf, MAX_PATH, 0, 0))
468 return 0;
469 } else {
470 WARN("Empty buffer string caused abort.\n");
471 SetLastError(ERROR_PATH_NOT_FOUND);
472 return -1;
474 lstrcpyW( phsc->most_recent_target, fici.FullTargetName );
475 return sc_cb_open(charbuf, _O_BINARY | _O_CREAT | _O_WRONLY, _S_IREAD | _S_IWRITE);
476 } else {
477 TRACE(" Callback skipped file.\n");
478 return 0;
480 case fdintCLOSE_FILE_INFO:
481 TRACE("Close file notification\n");
482 /* TRACE(" File name: %s\n", debugstr_a(pfdin->psz1));
483 TRACE(" Exec file? %s\n", (pfdin->cb) ? "Yes" : "No");
484 TRACE(" File hndl: %d\n", pfdin->hf); */
485 fp.Source = phsc->most_recent_cabinet_name;
486 fp.Target = phsc->most_recent_target;
487 fp.Win32Error = 0;
488 fp.Flags = 0;
489 /* a valid fixme -- but occurs too many times */
490 /* FIXME("Should set file date/time/attribs (and execute files?)\n"); */
491 if (sc_cb_close(pfdin->hf))
492 WARN("_close failed.\n");
493 err = phsc->msghandler(phsc->context, SPFILENOTIFY_FILEEXTRACTED, (UINT_PTR)&fp, 0);
494 if (err) {
495 SetLastError(err);
496 return FALSE;
497 } else
498 return TRUE;
499 case fdintNEXT_CABINET:
500 TRACE("Next cabinet notification\n");
501 /* TRACE(" Cabinet name: %s\n", debugstr_a(pfdin->psz1));
502 TRACE(" Cabinet disk: %s\n", debugstr_a(pfdin->psz2));
503 TRACE(" Cabinet path: %s\n", debugstr_a(pfdin->psz3));
504 TRACE(" Cabinet Set#: %d\n", pfdin->setID);
505 TRACE(" Cabinet Cab#: %d\n", pfdin->iCabinet); */
506 /* remember the new cabinet name */
507 len = 1 + MultiByteToWideChar(CP_ACP, 0, pfdin->psz1, -1, phsc->most_recent_cabinet_name, MAX_PATH);
508 if ((len > MAX_PATH) || (len <= 1))
509 phsc->most_recent_cabinet_name[0] = '\0';
510 ci.CabinetFile = phsc->most_recent_cabinet_name;
511 len = 1 + MultiByteToWideChar(CP_ACP, 0, pfdin->psz3, -1, buf, MAX_PATH);
512 if ((len > MAX_PATH) || (len <= 1))
513 buf[0] = '\0';
514 ci.CabinetPath = buf;
515 len = 1 + MultiByteToWideChar(CP_ACP, 0, pfdin->psz2, -1, buf2, MAX_PATH);
516 if ((len > MAX_PATH) || (len <= 1))
517 buf2[0] = '\0';
518 ci.DiskName = buf2;
519 ci.SetId = pfdin->setID;
520 ci.CabinetNumber = pfdin->iCabinet;
521 err = phsc->msghandler(phsc->context, SPFILENOTIFY_NEEDNEWCABINET, (UINT_PTR)&ci, (UINT_PTR)mysterio);
522 if (err) {
523 SetLastError(err);
524 return -1;
525 } else {
526 if (mysterio[0]) {
527 len = lstrlenW(mysterio) + 1;
528 if ((len > 255) || (len <= 1))
529 return 0;
530 if (!WideCharToMultiByte(CP_ACP, 0, mysterio, len, pfdin->psz3, 255, 0, 0))
531 return 0;
533 return 0;
535 default:
536 FIXME("Unknown notification type %d.\n", fdint);
537 return 0;
541 /***********************************************************************
542 * SetupIterateCabinetA (SETUPAPI.@)
544 BOOL WINAPI SetupIterateCabinetA(PCSTR CabinetFile, DWORD Reserved,
545 PSP_FILE_CALLBACK_A MsgHandler, PVOID Context)
548 SC_HSC_A my_hsc;
549 ERF erf;
550 CHAR pszCabinet[MAX_PATH], pszCabPath[MAX_PATH], *p = NULL;
551 DWORD fpnsize;
552 BOOL ret;
554 TRACE("(CabinetFile == %s, Reserved == %u, MsgHandler == ^%p, Context == ^%p)\n",
555 debugstr_a(CabinetFile), Reserved, MsgHandler, Context);
557 if (!LoadCABINETDll())
558 return FALSE;
560 if (!CabinetFile)
562 SetLastError(ERROR_INVALID_PARAMETER);
563 return FALSE;
566 fpnsize = strlen(CabinetFile);
567 if (fpnsize >= MAX_PATH) {
568 SetLastError(ERROR_BAD_PATHNAME);
569 return FALSE;
572 fpnsize = GetFullPathNameA(CabinetFile, MAX_PATH, pszCabPath, &p);
573 if (fpnsize > MAX_PATH) {
574 SetLastError(ERROR_BAD_PATHNAME);
575 return FALSE;
578 if (p) {
579 strcpy(pszCabinet, p);
580 *p = '\0';
581 } else {
582 strcpy(pszCabinet, CabinetFile);
583 pszCabPath[0] = '\0';
586 TRACE("path: %s, cabfile: %s\n", debugstr_a(pszCabPath), debugstr_a(pszCabinet));
588 /* remember the cabinet name */
589 strcpy(my_hsc.most_recent_cabinet_name, pszCabinet);
591 my_hsc.magic = SC_HSC_A_MAGIC;
592 my_hsc.msghandler = MsgHandler;
593 my_hsc.context = Context;
594 my_hsc.hfdi = sc_FDICreate( sc_cb_alloc, sc_cb_free, sc_cb_open, sc_cb_read,
595 sc_cb_write, sc_cb_close, sc_cb_lseek, cpuUNKNOWN, &erf );
597 if (!my_hsc.hfdi) return FALSE;
599 ret = sc_FDICopy(my_hsc.hfdi, pszCabinet, pszCabPath, 0, sc_FNNOTIFY_A, NULL, &my_hsc);
601 sc_FDIDestroy(my_hsc.hfdi);
602 return ret;
606 /***********************************************************************
607 * SetupIterateCabinetW (SETUPAPI.@)
609 BOOL WINAPI SetupIterateCabinetW(PCWSTR CabinetFile, DWORD Reserved,
610 PSP_FILE_CALLBACK_W MsgHandler, PVOID Context)
612 CHAR pszCabinet[MAX_PATH], pszCabPath[MAX_PATH];
613 UINT len;
614 SC_HSC_W my_hsc;
615 ERF erf;
616 WCHAR pszCabPathW[MAX_PATH], *p = NULL;
617 DWORD fpnsize;
618 BOOL ret;
620 TRACE("(CabinetFile == %s, Reserved == %u, MsgHandler == ^%p, Context == ^%p)\n",
621 debugstr_w(CabinetFile), Reserved, MsgHandler, Context);
623 if (!LoadCABINETDll())
624 return FALSE;
626 if (!CabinetFile)
628 SetLastError(ERROR_INVALID_PARAMETER);
629 return FALSE;
632 fpnsize = GetFullPathNameW(CabinetFile, MAX_PATH, pszCabPathW, &p);
633 if (fpnsize > MAX_PATH) {
634 SetLastError(ERROR_BAD_PATHNAME);
635 return FALSE;
638 if (p) {
639 lstrcpyW(my_hsc.most_recent_cabinet_name, p);
640 *p = 0;
641 len = WideCharToMultiByte(CP_ACP, 0, pszCabPathW, -1, pszCabPath,
642 MAX_PATH, 0, 0);
643 if (!len) return FALSE;
644 } else {
645 lstrcpyW(my_hsc.most_recent_cabinet_name, CabinetFile);
646 pszCabPath[0] = '\0';
649 len = WideCharToMultiByte(CP_ACP, 0, my_hsc.most_recent_cabinet_name, -1,
650 pszCabinet, MAX_PATH, 0, 0);
651 if (!len) return FALSE;
653 TRACE("path: %s, cabfile: %s\n",
654 debugstr_a(pszCabPath), debugstr_a(pszCabinet));
656 my_hsc.magic = SC_HSC_W_MAGIC;
657 my_hsc.msghandler = MsgHandler;
658 my_hsc.context = Context;
659 my_hsc.hfdi = sc_FDICreate( sc_cb_alloc, sc_cb_free, sc_cb_open, sc_cb_read,
660 sc_cb_write, sc_cb_close, sc_cb_lseek, cpuUNKNOWN, &erf );
662 if (!my_hsc.hfdi) return FALSE;
664 ret = sc_FDICopy(my_hsc.hfdi, pszCabinet, pszCabPath, 0, sc_FNNOTIFY_W, NULL, &my_hsc);
666 sc_FDIDestroy(my_hsc.hfdi);
667 return ret;
671 /***********************************************************************
672 * DllMain
674 * PARAMS
675 * hinstDLL [I] handle to the DLL's instance
676 * fdwReason [I]
677 * lpvReserved [I] reserved, must be NULL
679 * RETURNS
680 * Success: TRUE
681 * Failure: FALSE
684 BOOL WINAPI DllMain(HINSTANCE hinstDLL, DWORD fdwReason, LPVOID lpvReserved)
686 switch (fdwReason) {
687 case DLL_PROCESS_ATTACH:
688 DisableThreadLibraryCalls(hinstDLL);
689 OsVersionInfo.dwOSVersionInfoSize = sizeof(OSVERSIONINFOW);
690 if (!GetVersionExW(&OsVersionInfo))
691 return FALSE;
692 SETUPAPI_hInstance = hinstDLL;
693 break;
694 case DLL_PROCESS_DETACH:
695 if (lpvReserved) break;
696 SetupCloseLog();
697 if (CABINET_hInstance) FreeLibrary(CABINET_hInstance);
698 break;
701 return TRUE;