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