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