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