/*++ Copyright (c) 1999 Microsoft Corporation Module Name: cablib.c Abstract: Implements wrappers for cabinet APIs Author: Calin Negreanu (calinn) 27-Apr-2000 Revision History: --*/ #include "pch.h" #include #include #include #include #include // // Includes // // None #define DBG_CABLIB "CabLib" // // Strings // // None // // Constants // #define VERIFY_HANDLE ((HANDLE) (-2)) // // Macros // // None // // Types // typedef struct { PCSTR CabPath; PCSTR CabFileFormat; PCSTR CabDiskFormat; PCABGETCABINETNAMESA CabGetCabinetNames; HFCI FciHandle; ERF FciErrorStruct; CCAB FciCabParams; UINT FileCount; UINT CabCount; LONGLONG FileSize; LONGLONG CompressedSize; } FCI_CAB_HANDLEA, *PFCI_CAB_HANDLEA; typedef struct { PCWSTR CabPath; PCWSTR CabFileFormat; PCWSTR CabDiskFormat; PCABGETCABINETNAMESW CabGetCabinetNames; HFCI FciHandle; ERF FciErrorStruct; CCAB FciCabParams; UINT FileCount; UINT CabCount; LONGLONG FileSize; LONGLONG CompressedSize; } FCI_CAB_HANDLEW, *PFCI_CAB_HANDLEW; typedef struct { PCSTR CabPath; PCSTR CabFile; HFDI FdiHandle; ERF FdiErrorStruct; FDICABINETINFO FdiCabinetInfo; } FDI_CAB_HANDLEA, *PFDI_CAB_HANDLEA; typedef struct { PCWSTR CabPath; PCWSTR CabFile; HFDI FdiHandle; ERF FdiErrorStruct; FDICABINETINFO FdiCabinetInfo; } FDI_CAB_HANDLEW, *PFDI_CAB_HANDLEW; typedef struct { PCSTR ExtractPath; PCABNOTIFICATIONA CabNotificationA; } CAB_DATAA, *PCAB_DATAA; typedef struct { PCWSTR ExtractPath; PCABNOTIFICATIONW CabNotificationW; BOOL VerifyMode; } CAB_DATAW, *PCAB_DATAW; // // Globals // // None // // Macro expansion list // // None // // Private function prototypes // // None // // Macro expansion definition // // None // // Code // INT DIAMONDAPI pCabFilePlacedA ( IN PCCAB FciCabParams, IN PSTR FileName, IN LONG FileSize, IN BOOL Continuation, IN PVOID Context ) /*++ Routine Description: Callback for cabinet compression/decompression. For more information see fci.h/fdi.h --*/ { PFCI_CAB_HANDLEA cabHandle; cabHandle = (PFCI_CAB_HANDLEA) Context; if (!cabHandle) { return 0; } cabHandle->FileCount++; cabHandle->FileSize += FileSize; return 0; } INT DIAMONDAPI pCabFilePlacedW ( IN PCCAB FciCabParams, IN PSTR FileName, IN LONG FileSize, IN BOOL Continuation, IN PVOID Context ) /*++ Routine Description: Callback for cabinet compression/decompression. For more information see fci.h/fdi.h --*/ { PFCI_CAB_HANDLEW cabHandle; cabHandle = (PFCI_CAB_HANDLEW) Context; if (!cabHandle) { return 0; } cabHandle->FileCount++; cabHandle->FileSize += FileSize; return 0; } PVOID DIAMONDAPI pCabAlloc ( IN ULONG Size ) /*++ Routine Description: Callback for cabinet compression/decompression. For more information see fci.h/fdi.h --*/ { return MemAlloc (g_hHeap, 0, Size); } VOID DIAMONDAPI pCabFree ( IN PVOID Memory ) /*++ Routine Description: Callback for cabinet compression/decompression. For more information see fci.h/fdi.h --*/ { MemFree (g_hHeap, 0, Memory); } INT_PTR DIAMONDAPI pCabOpenA ( IN PSTR FileName, IN INT oFlag, IN INT pMode, OUT PINT Error, IN PVOID Context ) /*++ Routine Description: Callback for cabinet compression/decompression. For more information see fci.h/fdi.h --*/ { HANDLE fileHandle; // oFlag and pMode are prepared for using _open. We won't do that // and it's a terrible waste of time to check each individual flags // We'll just assert these values. MYASSERT ((oFlag == (_O_CREAT | _O_TRUNC | _O_BINARY | _O_RDWR)) || (oFlag == (_O_CREAT | _O_EXCL | _O_BINARY | _O_RDWR))); MYASSERT (pMode == (_S_IREAD | _S_IWRITE)); fileHandle = CreateFileA ( FileName, GENERIC_READ | GENERIC_WRITE, 0, NULL, CREATE_ALWAYS, FILE_ATTRIBUTE_ARCHIVE, NULL ); if (fileHandle == INVALID_HANDLE_VALUE) { *Error = GetLastError (); return -1; } *Error = 0; return (INT_PTR)fileHandle; } INT_PTR DIAMONDAPI pCabOpen1A ( IN PSTR FileName, IN INT oFlag, IN INT pMode ) /*++ Routine Description: Callback for cabinet compression/decompression. For more information see fci.h/fdi.h --*/ { HANDLE fileHandle; // oFlag and pMode are prepared for using _open. We won't do that // and it's a terrible waste of time to check each individual flags // We'll just assert these values. MYASSERT (oFlag == _O_BINARY); fileHandle = CreateFileA ( FileName, GENERIC_READ, FILE_SHARE_READ, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_ARCHIVE, NULL ); if (fileHandle == INVALID_HANDLE_VALUE) { return -1; } return (INT_PTR)fileHandle; } UINT DIAMONDAPI pCabRead ( IN INT_PTR FileHandle, IN PVOID Buffer, IN UINT Size, OUT PINT Error, IN PVOID Context ) /*++ Routine Description: Callback for cabinet compression/decompression. For more information see fci.h/fdi.h --*/ { BOOL result; UINT bytesRead; result = ReadFile ((HANDLE)FileHandle, Buffer, Size, &bytesRead, NULL); if (!result) { *Error = GetLastError (); return ((UINT)(-1)); } *Error = 0; return bytesRead; } UINT DIAMONDAPI pCabRead1 ( IN INT_PTR FileHandle, IN PVOID Buffer, IN UINT Size ) /*++ Routine Description: Callback for cabinet compression/decompression. For more information see fci.h/fdi.h --*/ { BOOL result; UINT bytesRead; result = ReadFile ((HANDLE)FileHandle, Buffer, Size, &bytesRead, NULL); if (!result) { return ((UINT)(-1)); } return bytesRead; } UINT DIAMONDAPI pCabWrite ( IN INT_PTR FileHandle, IN PVOID Buffer, IN UINT Size, OUT PINT Error, IN PVOID Context ) /*++ Routine Description: Callback for cabinet compression/decompression. For more information see fci.h/fdi.h --*/ { BOOL result; DWORD dontCare; if (FileHandle == (INT_PTR) VERIFY_HANDLE) { return Size; } result = WriteFile ((HANDLE)FileHandle, Buffer, Size, &dontCare, NULL); if (!result) { *Error = GetLastError (); return ((UINT)(-1)); } *Error = 0; return Size; } UINT DIAMONDAPI pCabWrite1 ( IN INT_PTR FileHandle, IN PVOID Buffer, IN UINT Size ) /*++ Routine Description: Callback for cabinet compression/decompression. For more information see fci.h/fdi.h --*/ { BOOL result; DWORD dontCare; if (FileHandle == (INT_PTR) VERIFY_HANDLE) { return Size; } result = WriteFile ((HANDLE)FileHandle, Buffer, Size, &dontCare, NULL); if (!result) { return ((UINT)(-1)); } return Size; } INT DIAMONDAPI pCabClose ( IN INT_PTR FileHandle, OUT PINT Error, IN PVOID Context ) /*++ Routine Description: Callback for cabinet compression/decompression. For more information see fci.h/fdi.h --*/ { CloseHandle ((HANDLE)FileHandle); *Error = 0; return 0; } INT DIAMONDAPI pCabClose1 ( IN INT_PTR FileHandle ) /*++ Routine Description: Callback for cabinet compression/decompression. For more information see fci.h/fdi.h --*/ { CloseHandle ((HANDLE)FileHandle); return 0; } LONG DIAMONDAPI pCabSeek ( IN INT_PTR FileHandle, IN LONG Distance, IN INT SeekType, OUT PINT Error, IN PVOID Context ) /*++ Routine Description: Callback for cabinet compression/decompression. For more information see fci.h/fdi.h --*/ { DWORD result; DWORD seekType = FILE_BEGIN; switch (SeekType) { case SEEK_SET: seekType = FILE_BEGIN; break; case SEEK_CUR: seekType = FILE_CURRENT; break; case SEEK_END: seekType = FILE_END; break; } result = SetFilePointer ((HANDLE)FileHandle, Distance, NULL, seekType); if (result == INVALID_SET_FILE_POINTER) { *Error = GetLastError (); return -1; } *Error = 0; return ((LONG)(result)); } LONG DIAMONDAPI pCabSeek1 ( IN INT_PTR FileHandle, IN LONG Distance, IN INT SeekType ) /*++ Routine Description: Callback for cabinet compression/decompression. For more information see fci.h/fdi.h --*/ { DWORD result; DWORD seekType = FILE_BEGIN; switch (SeekType) { case SEEK_SET: seekType = FILE_BEGIN; break; case SEEK_CUR: seekType = FILE_CURRENT; break; case SEEK_END: seekType = FILE_END; break; } result = SetFilePointer ((HANDLE)FileHandle, Distance, NULL, seekType); if (result == INVALID_SET_FILE_POINTER) { return -1; } return ((LONG)(result)); } INT DIAMONDAPI pCabDeleteA ( IN PSTR FileName, OUT PINT Error, IN PVOID Context ) /*++ Routine Description: Callback for cabinet compression/decompression. For more information see fci.h/fdi.h --*/ { if (!DeleteFileA (FileName)) { *Error = GetLastError (); return -1; } *Error = 0; return 0; } BOOL DIAMONDAPI pCabGetTempFileA ( OUT PSTR FileName, IN INT FileNameLen, IN PVOID Context ) /*++ Routine Description: Callback for cabinet compression/decompression. For more information see fci.h/fdi.h --*/ { CHAR tempPath[MAX_PATH]; PSTR p; if (!GetTempPathA (ARRAYSIZE(tempPath), tempPath)) { return FALSE; } p = _mbsrchr (tempPath, '\\'); if (p && !p[1]) { *p = 0; } if (!DoesFileExistA (tempPath)) { CreateDirectoryA (tempPath, NULL); } if (!GetTempFileNameA (tempPath, "cab", 0, FileName)) { return FALSE; } return TRUE; } BOOL DIAMONDAPI pCabGetNextCabinetA ( IN PCCAB FciCabParams, IN ULONG PrevCabinetSize, IN PVOID Context ) /*++ Routine Description: Callback for cabinet compression/decompression. For more information see fci.h/fdi.h --*/ { PFCI_CAB_HANDLEA cabHandle; CHAR cabFile [1024]; CHAR cabDisk [1024]; cabHandle = (PFCI_CAB_HANDLEA) Context; if (!cabHandle) { return FALSE; } if (cabHandle->CabGetCabinetNames) { return cabHandle->CabGetCabinetNames ( FciCabParams->szCabPath, CB_MAX_CAB_PATH, FciCabParams->szCab, CB_MAX_CABINET_NAME, FciCabParams->szDisk, CB_MAX_DISK_NAME, FciCabParams->iCab, &FciCabParams->iDisk ); } else { FciCabParams->iDisk = FciCabParams->iCab; if (cabHandle->CabFileFormat) { wsprintfA (cabFile, cabHandle->CabFileFormat, FciCabParams->iCab); StringCopyByteCountA (FciCabParams->szCab, cabFile, CB_MAX_CABINET_NAME * sizeof (CHAR)); } if (cabHandle->CabDiskFormat) { wsprintfA (cabDisk, cabHandle->CabDiskFormat, FciCabParams->iDisk); StringCopyByteCountA (FciCabParams->szDisk, cabDisk, CB_MAX_DISK_NAME * sizeof (CHAR)); } } return TRUE; } BOOL DIAMONDAPI pCabGetNextCabinetW ( IN PCCAB FciCabParams, IN ULONG PrevCabinetSize, IN PVOID Context ) /*++ Routine Description: Callback for cabinet compression/decompression. For more information see fci.h/fdi.h --*/ { PFCI_CAB_HANDLEW cabHandle; WCHAR cabPath [1024]; WCHAR cabFile [1024]; WCHAR cabDisk [1024]; BOOL result; cabHandle = (PFCI_CAB_HANDLEW) Context; if (!cabHandle) { return FALSE; } if (cabHandle->CabGetCabinetNames) { result = cabHandle->CabGetCabinetNames ( cabPath, CB_MAX_CAB_PATH, cabFile, CB_MAX_CABINET_NAME, cabDisk, CB_MAX_DISK_NAME, FciCabParams->iCab, &FciCabParams->iDisk ); if (result) { KnownSizeUnicodeToDbcs (FciCabParams->szCabPath, cabPath); KnownSizeUnicodeToDbcs (FciCabParams->szCab, cabFile); KnownSizeUnicodeToDbcs (FciCabParams->szDisk, cabDisk); return TRUE; } return FALSE; } else { FciCabParams->iDisk = FciCabParams->iCab; if (cabHandle->CabFileFormat) { wsprintfW (cabFile, cabHandle->CabFileFormat, FciCabParams->iCab); KnownSizeUnicodeToDbcs (FciCabParams->szCab, cabFile); } if (cabHandle->CabDiskFormat) { wsprintfW (cabDisk, cabHandle->CabDiskFormat, FciCabParams->iDisk); KnownSizeUnicodeToDbcs (FciCabParams->szDisk, cabDisk); } } return TRUE; } LONG DIAMONDAPI pCabStatusA ( IN UINT StatusType, IN ULONG Size1, IN ULONG Size2, IN PVOID Context ) /*++ Routine Description: Callback for cabinet compression/decompression. For more information see fci.h/fdi.h --*/ { PFCI_CAB_HANDLEA cabHandle; if (StatusType == statusCabinet) { cabHandle = (PFCI_CAB_HANDLEA) Context; if (!cabHandle) { return 0; } cabHandle->CabCount++; cabHandle->CompressedSize += (LONGLONG) Size2; } return 0; } LONG DIAMONDAPI pCabStatusW ( IN UINT StatusType, IN ULONG Size1, IN ULONG Size2, IN PVOID Context ) /*++ Routine Description: Callback for cabinet compression/decompression. For more information see fci.h/fdi.h --*/ { PFCI_CAB_HANDLEW cabHandle; if (StatusType == statusCabinet) { cabHandle = (PFCI_CAB_HANDLEW) Context; if (!cabHandle) { return 0; } cabHandle->CabCount++; cabHandle->CompressedSize += (LONGLONG) Size2; } return 0; } INT_PTR DIAMONDAPI pCabGetOpenInfoA ( IN PSTR FileName, OUT USHORT *Date, OUT USHORT *Time, OUT USHORT *Attributes, OUT PINT Error, IN PVOID Context ) /*++ Routine Description: Callback for cabinet compression/decompression. For more information see fci.h/fdi.h --*/ { WIN32_FIND_DATAA findData; FILETIME fileTime; HANDLE fileHandle; if (DoesFileExistExA (FileName, &findData)) { FileTimeToLocalFileTime (&findData.ftLastWriteTime, &fileTime); FileTimeToDosDateTime (&fileTime, Date, Time); /* * Mask out all other bits except these four, since other * bits are used by the cabinet format to indicate a * special meaning. */ *Attributes = (USHORT) (findData.dwFileAttributes & (FILE_ATTRIBUTE_READONLY | FILE_ATTRIBUTE_SYSTEM | FILE_ATTRIBUTE_HIDDEN | FILE_ATTRIBUTE_ARCHIVE)); fileHandle = CreateFileA ( FileName, GENERIC_READ, FILE_SHARE_READ|FILE_SHARE_WRITE, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL ); if (fileHandle == INVALID_HANDLE_VALUE) { *Error = GetLastError (); return -1; } *Error = 0; return (INT_PTR)fileHandle; } else { *Error = GetLastError (); return -1; } } BOOL pIsFullPathA ( IN PCSTR PathToTest ) { MBCHAR ch1; MBCHAR ch2; ch1 = _mbsnextc (PathToTest); _mbsinc (PathToTest); ch2 = _mbsnextc (PathToTest); if ((ch1 == '\\' && ch2 == '\\') || (isalpha (ch1) && ch2 == '\\') ) { return TRUE; } return FALSE; } BOOL pIsFullPathW ( IN PCWSTR PathToTest ) { WCHAR ch1; WCHAR ch2; ch1 = *PathToTest++; ch2 = *PathToTest; if ((ch1 == '\\' && ch2 == '\\') || (isalpha (ch1) && ch2 == '\\') ) { return TRUE; } return FALSE; } PCSTR pComputeDestPathA ( IN PCSTR ExtractPath, OPTIONAL IN PCSTR PathStoredInCab ) { PCSTR destFile; // // If ExtractPath is NULL, then use the path stored in the cab. // If the path stored in the cab is a full path, use only the file name. // Otherwise join ExtractPath with PathStoredInCab. // if (!ExtractPath) { destFile = DuplicatePathStringA (PathStoredInCab, 0); } else if (pIsFullPathA (PathStoredInCab)) { destFile = JoinPathsA (ExtractPath, GetFileNameFromPathA (PathStoredInCab)); } else { destFile = JoinPathsA (ExtractPath, PathStoredInCab); } return destFile; } PCWSTR pComputeDestPathW ( IN PCWSTR ExtractPath, OPTIONAL IN PCWSTR PathStoredInCab ) { PCWSTR destFile; // // If ExtractPath is NULL, then use the path stored in the cab. // If the path stored in the cab is a full path, use only the file name. // Otherwise join ExtractPath with PathStoredInCab. // if (!ExtractPath) { destFile = DuplicatePathStringW (PathStoredInCab, 0); } else if (pIsFullPathW (PathStoredInCab)) { destFile = JoinPathsW (ExtractPath, GetFileNameFromPathW (PathStoredInCab)); } else { destFile = JoinPathsW (ExtractPath, PathStoredInCab); } return destFile; } INT_PTR DIAMONDAPI pCabNotificationA ( IN FDINOTIFICATIONTYPE FdiNotificationType, IN OUT PFDINOTIFICATION FdiNotification ) /*++ Routine Description: Callback for cabinet compression/decompression. For more information see fci.h/fdi.h --*/ { PCSTR destFile = NULL; HANDLE destHandle = NULL; DWORD attributes; FILETIME localFileTime; FILETIME fileTime; PCAB_DATAA cabData; INT createFlag; switch (FdiNotificationType) { case fdintCABINET_INFO: // General information about cabinet return 0; case fdintCOPY_FILE: // File to be copied cabData = (PCAB_DATAA)FdiNotification->pv; destFile = pComputeDestPathA (cabData->ExtractPath, FdiNotification->psz1); createFlag = TRUE; if (cabData->CabNotificationA) { createFlag = cabData->CabNotificationA (destFile); } if(-1 == createFlag){ FreePathStringA (destFile); return -1; } if (createFlag) { MakeSurePathExistsA (FdiNotification->psz1, FALSE); SetFileAttributesA (destFile, FILE_ATTRIBUTE_NORMAL); destHandle = CreateFileA ( destFile, GENERIC_READ|GENERIC_WRITE, 0, NULL, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL ); } FreePathStringA (destFile); return (INT_PTR)destHandle; case fdintCLOSE_FILE_INFO: // close the file, set relevant info cabData = (PCAB_DATAA)FdiNotification->pv; if (DosDateTimeToFileTime (FdiNotification->date, FdiNotification->time, &localFileTime)) { if (LocalFileTimeToFileTime (&localFileTime, &fileTime)) { SetFileTime ((HANDLE)FdiNotification->hf, &fileTime, &fileTime, &fileTime); } } destFile = pComputeDestPathA (cabData->ExtractPath, FdiNotification->psz1); CloseHandle ((HANDLE)FdiNotification->hf); attributes = (FdiNotification->attribs & (FILE_ATTRIBUTE_READONLY | FILE_ATTRIBUTE_SYSTEM | FILE_ATTRIBUTE_HIDDEN | FILE_ATTRIBUTE_ARCHIVE)); SetFileAttributesA (destFile, attributes); FreePathStringA (destFile); return TRUE; case fdintPARTIAL_FILE: // First file in cabinet is continuation return 0; case fdintENUMERATE: // Enumeration status return 0; case fdintNEXT_CABINET: // File continued to next cabinet return 0; } return 0; } INT_PTR DIAMONDAPI pCabNotificationW ( IN FDINOTIFICATIONTYPE FdiNotificationType, IN OUT PFDINOTIFICATION FdiNotification ) /*++ Routine Description: Callback for cabinet compression/decompression. For more information see fci.h/fdi.h --*/ { PCWSTR destFile = NULL; HANDLE destHandle = NULL; DWORD attributes; FILETIME localFileTime; FILETIME fileTime; PCAB_DATAW cabData; INT createFlag; PCWSTR cabFileSpecW; switch (FdiNotificationType) { case fdintCABINET_INFO: // General information about cabinet return 0; case fdintCOPY_FILE: // File to be copied cabFileSpecW = ConvertAtoW (FdiNotification->psz1); cabData = (PCAB_DATAW)FdiNotification->pv; destFile = pComputeDestPathW (cabData->ExtractPath, cabFileSpecW); FreeConvertedStr (cabFileSpecW); createFlag = TRUE; if (cabData->CabNotificationW) { createFlag = cabData->CabNotificationW (destFile); } if(-1 == createFlag){ FreePathStringW (destFile); return -1; } if (createFlag) { if (!cabData->VerifyMode) { MakeSurePathExistsW (cabFileSpecW, FALSE); SetFileAttributesW (destFile, FILE_ATTRIBUTE_NORMAL); destHandle = CreateFileW ( destFile, GENERIC_READ|GENERIC_WRITE, 0, NULL, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL ); } else { destHandle = VERIFY_HANDLE; } } FreePathStringW (destFile); return (INT_PTR)destHandle; case fdintCLOSE_FILE_INFO: // close the file, set relevant info cabData = (PCAB_DATAW)FdiNotification->pv; if (DosDateTimeToFileTime (FdiNotification->date, FdiNotification->time, &localFileTime)) { if (LocalFileTimeToFileTime (&localFileTime, &fileTime)) { SetFileTime ((HANDLE)FdiNotification->hf, &fileTime, &fileTime, &fileTime); } } cabFileSpecW = ConvertAtoW (FdiNotification->psz1); destFile = pComputeDestPathW (cabData->ExtractPath, cabFileSpecW); FreeConvertedStr (cabFileSpecW); CloseHandle ((HANDLE)FdiNotification->hf); attributes = (FdiNotification->attribs & (FILE_ATTRIBUTE_READONLY | FILE_ATTRIBUTE_SYSTEM | FILE_ATTRIBUTE_HIDDEN | FILE_ATTRIBUTE_ARCHIVE)); SetFileAttributesW (destFile, attributes); FreePathStringW (destFile); return TRUE; case fdintPARTIAL_FILE: // First file in cabinet is continuation return 0; case fdintENUMERATE: // Enumeration status return 0; case fdintNEXT_CABINET: // File continued to next cabinet return 0; } return 0; } CCABHANDLE CabCreateCabinetA ( IN PCSTR CabPath, IN PCSTR CabFileFormat, IN PCSTR CabDiskFormat, IN LONG MaxFileSize ) /*++ Routine Description: Creates a cabinet context. Caller may use this context for subsequent calls to CabAddFile. Arguments: CabPath - Specifies the path where the new cabinet file will be. CabFileFormat - Specifies (as for wsprintf) the format of the cabinet file name. CabDiskFormat - Specifies (as for wsprintf) the format of the cabinet disk name. MaxFileSize - Specifies maximum size of the cabinet file (limited to 2GB). if 0 => 2GB Return Value: a valid CCABHANDLE if successful, NULL otherwise. --*/ { PFCI_CAB_HANDLEA cabHandle; CHAR cabFile [1024]; CHAR cabDisk [1024]; if (!CabFileFormat) { return NULL; } if (MaxFileSize < 0) { return NULL; } if (MaxFileSize == 0) { MaxFileSize = 0x7FFFFFFF; } cabHandle = (PFCI_CAB_HANDLEA) MemAlloc (g_hHeap, 0, sizeof (FCI_CAB_HANDLEA)); ZeroMemory (cabHandle, sizeof (FCI_CAB_HANDLEA)); if (CabPath) { cabHandle->CabPath = DuplicatePathStringA (CabPath, 0); } cabHandle->CabFileFormat = DuplicatePathStringA (CabFileFormat, 0); if (CabDiskFormat) { cabHandle->CabDiskFormat = DuplicatePathStringA (CabDiskFormat, 0); } // fill out the CCAB structure cabHandle->FciCabParams.cb = MaxFileSize; cabHandle->FciCabParams.cbFolderThresh = MaxFileSize; cabHandle->FciCabParams.cbReserveCFHeader = 0; cabHandle->FciCabParams.cbReserveCFFolder = 0; cabHandle->FciCabParams.cbReserveCFData = 0; cabHandle->FciCabParams.iCab = 1; cabHandle->FciCabParams.iDisk = 1; cabHandle->FciCabParams.setID = 0; if (CabPath) { StringCopyByteCountA (cabHandle->FciCabParams.szCabPath, CabPath, CB_MAX_CAB_PATH - 1); AppendWackA (cabHandle->FciCabParams.szCabPath); } if (CabDiskFormat) { wsprintfA (cabDisk, CabDiskFormat, cabHandle->FciCabParams.iDisk); StringCopyByteCountA (cabHandle->FciCabParams.szDisk, cabDisk, CB_MAX_DISK_NAME * sizeof (CHAR)); } wsprintfA (cabFile, CabFileFormat, cabHandle->FciCabParams.iCab); StringCopyByteCountA (cabHandle->FciCabParams.szCab, cabFile, CB_MAX_CABINET_NAME * sizeof (CHAR)); cabHandle->FciHandle = FCICreate ( &cabHandle->FciErrorStruct, pCabFilePlacedA, pCabAlloc, pCabFree, pCabOpenA, pCabRead, pCabWrite, pCabClose, pCabSeek, pCabDeleteA, pCabGetTempFileA, &cabHandle->FciCabParams, cabHandle ); if (!cabHandle->FciHandle) { if (cabHandle->CabPath) { FreePathStringA (cabHandle->CabPath); } if (cabHandle->CabFileFormat) { FreePathStringA (cabHandle->CabFileFormat); } if (cabHandle->CabDiskFormat) { FreePathStringA (cabHandle->CabDiskFormat); } MemFree (g_hHeap, 0, cabHandle); return NULL; } return ((CCABHANDLE)(cabHandle)); } CCABHANDLE CabCreateCabinetW ( IN PCWSTR CabPath, IN PCWSTR CabFileFormat, IN PCWSTR CabDiskFormat, IN LONG MaxFileSize ) /*++ Routine Description: Creates a cabinet context. Caller may use this context for subsequent calls to CabAddFile. Arguments: CabPath - Specifies the path where the new cabinet file will be. CabFileFormat - Specifies (as for wsprintf) the format of the cabinet file name. CabDiskFormat - Specifies (as for wsprintf) the format of the cabinet disk name. MaxFileSize - Specifies maximum size of the cabinet file (limited to 2GB). if 0 => 2GB Return Value: a valid CCABHANDLE if successful, NULL otherwise. --*/ { PFCI_CAB_HANDLEW cabHandle; WCHAR cabFile [1024]; WCHAR cabDisk [1024]; if (!CabFileFormat) { return NULL; } if (MaxFileSize < 0) { return NULL; } if (MaxFileSize == 0) { MaxFileSize = 0x7FFFFFFF; } cabHandle = (PFCI_CAB_HANDLEW) MemAlloc (g_hHeap, 0, sizeof (FCI_CAB_HANDLEW)); ZeroMemory (cabHandle, sizeof (FCI_CAB_HANDLEW)); if (CabPath) { cabHandle->CabPath = DuplicatePathStringW (CabPath, 0); } cabHandle->CabFileFormat = DuplicatePathStringW (CabFileFormat, 0); if (CabDiskFormat) { cabHandle->CabDiskFormat = DuplicatePathStringW (CabDiskFormat, 0); } // fill out the CCAB structure cabHandle->FciCabParams.cb = MaxFileSize; cabHandle->FciCabParams.cbFolderThresh = MaxFileSize; cabHandle->FciCabParams.cbReserveCFHeader = 0; cabHandle->FciCabParams.cbReserveCFFolder = 0; cabHandle->FciCabParams.cbReserveCFData = 0; cabHandle->FciCabParams.iCab = 1; cabHandle->FciCabParams.iDisk = 1; cabHandle->FciCabParams.setID = 0; if (CabPath) { KnownSizeUnicodeToDbcs (cabHandle->FciCabParams.szCabPath, CabPath); AppendWackA (cabHandle->FciCabParams.szCabPath); } if (CabDiskFormat) { wsprintfW (cabDisk, CabDiskFormat, cabHandle->FciCabParams.iDisk); KnownSizeUnicodeToDbcs (cabHandle->FciCabParams.szDisk, cabDisk); } wsprintfW (cabFile, CabFileFormat, cabHandle->FciCabParams.iCab); KnownSizeUnicodeToDbcs (cabHandle->FciCabParams.szCab, cabFile); cabHandle->FciHandle = FCICreate ( &cabHandle->FciErrorStruct, pCabFilePlacedW, pCabAlloc, pCabFree, pCabOpenA, pCabRead, pCabWrite, pCabClose, pCabSeek, pCabDeleteA, pCabGetTempFileA, &cabHandle->FciCabParams, cabHandle ); if (!cabHandle->FciHandle) { if (cabHandle->CabPath) { FreePathStringW (cabHandle->CabPath); } if (cabHandle->CabFileFormat) { FreePathStringW (cabHandle->CabFileFormat); } if (cabHandle->CabDiskFormat) { FreePathStringW (cabHandle->CabDiskFormat); } MemFree (g_hHeap, 0, cabHandle); return NULL; } return ((CCABHANDLE)(cabHandle)); } CCABHANDLE CabCreateCabinetExA ( IN PCABGETCABINETNAMESA CabGetCabinetNames, IN LONG MaxFileSize ) /*++ Routine Description: Creates a cabinet context. Caller may use this context for subsequent calls to CabAddFile. Arguments: CabGetCabinetNames - Specifies a callback used to decide cabinet path, cabinet name and disk name. MaxFileSize - Specifies maximum size of the cabinet file (limited to 2GB). if 0 => 2GB Return Value: a valid CCABHANDLE if successful, NULL otherwise. --*/ { PFCI_CAB_HANDLEA cabHandle; if (!CabGetCabinetNames) { return NULL; } if (MaxFileSize < 0) { return NULL; } if (MaxFileSize == 0) { MaxFileSize = 0x80000000; } cabHandle = MemAlloc (g_hHeap, 0, sizeof (FCI_CAB_HANDLEA)); ZeroMemory (cabHandle, sizeof (FCI_CAB_HANDLEA)); cabHandle->CabGetCabinetNames = CabGetCabinetNames; // fill out the CCAB structure cabHandle->FciCabParams.cb = MaxFileSize; cabHandle->FciCabParams.cbFolderThresh = MaxFileSize; cabHandle->FciCabParams.cbReserveCFHeader = 0; cabHandle->FciCabParams.cbReserveCFFolder = 0; cabHandle->FciCabParams.cbReserveCFData = 0; cabHandle->FciCabParams.iCab = 1; cabHandle->FciCabParams.iDisk = 1; cabHandle->FciCabParams.setID = 0; if (!CabGetCabinetNames ( cabHandle->FciCabParams.szCabPath, CB_MAX_CAB_PATH, cabHandle->FciCabParams.szCab, CB_MAX_CABINET_NAME, cabHandle->FciCabParams.szDisk, CB_MAX_DISK_NAME, cabHandle->FciCabParams.iCab, &cabHandle->FciCabParams.iDisk )) { return NULL; } cabHandle->FciHandle = FCICreate ( &cabHandle->FciErrorStruct, pCabFilePlacedA, pCabAlloc, pCabFree, pCabOpenA, pCabRead, pCabWrite, pCabClose, pCabSeek, pCabDeleteA, pCabGetTempFileA, &cabHandle->FciCabParams, cabHandle ); if (!cabHandle->FciHandle) { if (cabHandle->CabPath) { FreePathStringA (cabHandle->CabPath); } if (cabHandle->CabFileFormat) { FreePathStringA (cabHandle->CabFileFormat); } if (cabHandle->CabDiskFormat) { FreePathStringA (cabHandle->CabDiskFormat); } MemFree (g_hHeap, 0, cabHandle); return NULL; } return ((CCABHANDLE)(cabHandle)); } CCABHANDLE CabCreateCabinetExW ( IN PCABGETCABINETNAMESW CabGetCabinetNames, IN LONG MaxFileSize ) /*++ Routine Description: Creates a cabinet context. Caller may use this context for subsequent calls to CabAddFile. Arguments: CabGetCabinetNames - Specifies a callback used to decide cabinet path, cabinet name and disk name. MaxFileSize - Specifies maximum size of the cabinet file (limited to 2GB). if 0 => 2GB Return Value: a valid CCABHANDLE if successful, NULL otherwise. --*/ { PFCI_CAB_HANDLEW cabHandle; WCHAR cabPath [1024]; WCHAR cabFile [1024]; WCHAR cabDisk [1024]; if (!CabGetCabinetNames) { return NULL; } if (MaxFileSize < 0) { return NULL; } if (MaxFileSize == 0) { MaxFileSize = 0x80000000; } cabHandle = MemAlloc (g_hHeap, 0, sizeof (FCI_CAB_HANDLEW)); ZeroMemory (cabHandle, sizeof (FCI_CAB_HANDLEW)); cabHandle->CabGetCabinetNames = CabGetCabinetNames; // fill out the CCAB structure cabHandle->FciCabParams.cb = MaxFileSize; cabHandle->FciCabParams.cbFolderThresh = MaxFileSize; cabHandle->FciCabParams.cbReserveCFHeader = 0; cabHandle->FciCabParams.cbReserveCFFolder = 0; cabHandle->FciCabParams.cbReserveCFData = 0; cabHandle->FciCabParams.iCab = 1; cabHandle->FciCabParams.iDisk = 1; cabHandle->FciCabParams.setID = 0; if (!CabGetCabinetNames ( cabPath, CB_MAX_CAB_PATH, cabFile, CB_MAX_CABINET_NAME, cabDisk, CB_MAX_DISK_NAME, cabHandle->FciCabParams.iCab, &cabHandle->FciCabParams.iDisk )) { return NULL; } KnownSizeUnicodeToDbcs (cabHandle->FciCabParams.szCabPath, cabPath); KnownSizeUnicodeToDbcs (cabHandle->FciCabParams.szCab, cabFile); KnownSizeUnicodeToDbcs (cabHandle->FciCabParams.szDisk, cabDisk); cabHandle->FciHandle = FCICreate ( &cabHandle->FciErrorStruct, pCabFilePlacedW, pCabAlloc, pCabFree, pCabOpenA, pCabRead, pCabWrite, pCabClose, pCabSeek, pCabDeleteA, pCabGetTempFileA, &cabHandle->FciCabParams, cabHandle ); if (!cabHandle->FciHandle) { if (cabHandle->CabPath) { FreePathStringW (cabHandle->CabPath); } if (cabHandle->CabFileFormat) { FreePathStringW (cabHandle->CabFileFormat); } if (cabHandle->CabDiskFormat) { FreePathStringW (cabHandle->CabDiskFormat); } MemFree (g_hHeap, 0, cabHandle); return NULL; } return ((CCABHANDLE)(cabHandle)); } BOOL CabAddFileToCabinetA ( IN CCABHANDLE CabHandle, IN PCSTR FileName, IN PCSTR StoredName ) /*++ Routine Description: Compresses and adds a file to a cabinet context. Arguments: CabHandle - Specifies cabinet context. FileName - Specifies the file to be added. StoredName - Specifies the name to be stored in the cabinet file. Return Value: TRUE if successful, FALSE otherwise. --*/ { PFCI_CAB_HANDLEA cabHandle; cabHandle = (PFCI_CAB_HANDLEA) CabHandle; if (cabHandle == NULL) { return FALSE; } if (cabHandle->FciHandle == NULL) { return FALSE; } return FCIAddFile ( cabHandle->FciHandle, (PSTR)FileName, (PSTR)StoredName, FALSE, pCabGetNextCabinetA, pCabStatusA, pCabGetOpenInfoA, tcompTYPE_MSZIP ); } BOOL CabAddFileToCabinetW ( IN CCABHANDLE CabHandle, IN PCWSTR FileName, IN PCWSTR StoredName ) /*++ Routine Description: Compresses and adds a file to a cabinet context. Arguments: CabHandle - Specifies cabinet context. FileName - Specifies the file to be added. StoredName - Specifies the name to be stored in the cabinet file. FileCount - Specifies a count of files, receives the updated count when cabinet files are created FileSize - Specifies the number of bytes used by the file, receives the updated size Return Value: TRUE if successful, FALSE otherwise. --*/ { PFCI_CAB_HANDLEW cabHandle; CHAR ansiFileName [1024]; CHAR ansiStoredName [1024]; cabHandle = (PFCI_CAB_HANDLEW) CabHandle; if (cabHandle == NULL) { return FALSE; } if (cabHandle->FciHandle == NULL) { return FALSE; } KnownSizeUnicodeToDbcs (ansiFileName, FileName); KnownSizeUnicodeToDbcs (ansiStoredName, StoredName); return FCIAddFile ( cabHandle->FciHandle, ansiFileName, ansiStoredName, FALSE, pCabGetNextCabinetW, pCabStatusW, pCabGetOpenInfoA, tcompTYPE_MSZIP ); } BOOL CabFlushAndCloseCabinetExA ( IN CCABHANDLE CabHandle, OUT PUINT FileCount, OPTIONAL OUT PLONGLONG FileSize, OPTIONAL OUT PUINT CabFileCount, OPTIONAL OUT PLONGLONG CabFileSize OPTIONAL ) /*++ Routine Description: Completes a cabinet file and closes its context. Arguments: CabHandle - Specifies cabinet context. FileCount - Receives the number of files added to the cab FileSize - Receives the size of all files before compression CabFileCount - Receives the number of cabinet files created CabFileSize - Receives the size of all cabinet files Return Value: TRUE if successful, FALSE otherwise. --*/ { PFCI_CAB_HANDLEA cabHandle; BOOL result = FALSE; cabHandle = (PFCI_CAB_HANDLEA) CabHandle; if (cabHandle == NULL) { return FALSE; } if (cabHandle->FciHandle == NULL) { return FALSE; } if (FCIFlushCabinet ( cabHandle->FciHandle, FALSE, pCabGetNextCabinetA, pCabStatusA )) { if (cabHandle->CabPath) { FreePathStringA (cabHandle->CabPath); } if (cabHandle->CabFileFormat) { FreePathStringA (cabHandle->CabFileFormat); } if (cabHandle->CabDiskFormat) { FreePathStringA (cabHandle->CabDiskFormat); } result = FCIDestroy (cabHandle->FciHandle); if (FileCount) { *FileCount = cabHandle->FileCount; } if (FileSize) { *FileSize = cabHandle->FileSize; } if (CabFileCount) { *CabFileCount = cabHandle->CabCount; } if (CabFileSize) { *CabFileSize = cabHandle->CompressedSize; } MemFree (g_hHeap, 0, cabHandle); } return result; } BOOL CabFlushAndCloseCabinetExW ( IN CCABHANDLE CabHandle, OUT PUINT FileCount, OPTIONAL OUT PLONGLONG FileSize, OPTIONAL OUT PUINT CabFileCount, OPTIONAL OUT PLONGLONG CabFileSize OPTIONAL ) /*++ Routine Description: Completes a cabinet file and closes its context. Arguments: CabHandle - Specifies cabinet context. FileCount - Receives the number of files added to the cab FileSize - Receives the size of all files before compression CabFileCount - Receives the number of cabinet files created CabFileSize - Receives the size of all cabinet files Return Value: TRUE if successful, FALSE otherwise. --*/ { PFCI_CAB_HANDLEW cabHandle; BOOL result = FALSE; cabHandle = (PFCI_CAB_HANDLEW) CabHandle; if (cabHandle == NULL) { return FALSE; } if (cabHandle->FciHandle == NULL) { return FALSE; } if (FCIFlushCabinet ( cabHandle->FciHandle, FALSE, pCabGetNextCabinetW, pCabStatusW )) { if (cabHandle->CabPath) { FreePathStringW (cabHandle->CabPath); } if (cabHandle->CabFileFormat) { FreePathStringW (cabHandle->CabFileFormat); } if (cabHandle->CabDiskFormat) { FreePathStringW (cabHandle->CabDiskFormat); } result = FCIDestroy (cabHandle->FciHandle); if (FileCount) { *FileCount = cabHandle->FileCount; } if (FileSize) { *FileSize = cabHandle->FileSize; } if (CabFileCount) { *CabFileCount = cabHandle->CabCount; } if (CabFileSize) { *CabFileSize = cabHandle->CompressedSize; } MemFree (g_hHeap, 0, cabHandle); } return result; } OCABHANDLE CabOpenCabinetA ( IN PCSTR FileName ) /*++ Routine Description: Creates a cabinet context for an existent cabinet file. Arguments: FileName - Specifies cabinet file name. Return Value: a valid OCABHANDLE if successful, NULL otherwise. --*/ { PFDI_CAB_HANDLEA cabHandle; PSTR filePtr; HANDLE fileHandle; PCSTR fileName; cabHandle = (PFDI_CAB_HANDLEA) MemAlloc (g_hHeap, 0, sizeof (FDI_CAB_HANDLEA)); ZeroMemory (cabHandle, sizeof (FDI_CAB_HANDLEA)); cabHandle->FdiHandle = FDICreate ( pCabAlloc, pCabFree, pCabOpen1A, pCabRead1, pCabWrite1, pCabClose1, pCabSeek1, cpuUNKNOWN, &cabHandle->FdiErrorStruct ); if (!cabHandle->FdiHandle) { MemFree (g_hHeap, 0, cabHandle); return NULL; } fileName = DuplicatePathStringA (FileName, 0); fileHandle = CreateFileA ( fileName, GENERIC_READ|GENERIC_WRITE, 0, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL ); if (fileHandle == INVALID_HANDLE_VALUE) { FreePathStringA (fileName); MemFree (g_hHeap, 0, cabHandle); return NULL; } if (!FDIIsCabinet (cabHandle->FdiHandle, (INT_PTR)fileHandle, &cabHandle->FdiCabinetInfo)) { FreePathStringA (fileName); CloseHandle (fileHandle); MemFree (g_hHeap, 0, cabHandle); return NULL; } CloseHandle (fileHandle); filePtr = (PSTR)GetFileNameFromPathA (fileName); if (!filePtr) { FreePathStringA (fileName); MemFree (g_hHeap, 0, cabHandle); return NULL; } cabHandle->CabFile = DuplicatePathStringA (filePtr, 0); *filePtr = 0; cabHandle->CabPath = DuplicatePathStringA (fileName, 0); FreePathStringA (fileName); return ((CCABHANDLE)(cabHandle)); } OCABHANDLE CabOpenCabinetW ( IN PCWSTR FileName ) /*++ Routine Description: Creates a cabinet context for an existent cabinet file. Arguments: FileName - Specifies cabinet file name. Return Value: a valid OCABHANDLE if successful, NULL otherwise. --*/ { PFDI_CAB_HANDLEW cabHandle; PWSTR filePtr; HANDLE fileHandle; PCWSTR fileName; cabHandle = (PFDI_CAB_HANDLEW) MemAlloc (g_hHeap, 0, sizeof (FDI_CAB_HANDLEW)); ZeroMemory (cabHandle, sizeof (FDI_CAB_HANDLEW)); cabHandle->FdiHandle = FDICreate ( pCabAlloc, pCabFree, pCabOpen1A, pCabRead1, pCabWrite1, pCabClose1, pCabSeek1, cpuUNKNOWN, &cabHandle->FdiErrorStruct ); if (!cabHandle->FdiHandle) { MemFree (g_hHeap, 0, cabHandle); return NULL; } fileName = DuplicatePathStringW (FileName, 0); fileHandle = CreateFileW ( fileName, GENERIC_READ|GENERIC_WRITE, 0, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL ); if (fileHandle == INVALID_HANDLE_VALUE) { FreePathStringW (fileName); MemFree (g_hHeap, 0, cabHandle); return NULL; } if (!FDIIsCabinet (cabHandle->FdiHandle, (INT_PTR)fileHandle, &cabHandle->FdiCabinetInfo)) { FreePathStringW (fileName); CloseHandle (fileHandle); MemFree (g_hHeap, 0, cabHandle); return NULL; } CloseHandle (fileHandle); filePtr = (PWSTR)GetFileNameFromPathW (fileName); if (!filePtr) { FreePathStringW (fileName); MemFree (g_hHeap, 0, cabHandle); return NULL; } cabHandle->CabFile = DuplicatePathStringW (filePtr, 0); *filePtr = 0; cabHandle->CabPath = DuplicatePathStringW (fileName, 0); FreePathStringW (fileName); return ((CCABHANDLE)(cabHandle)); } BOOL CabExtractAllFilesExA ( IN OCABHANDLE CabHandle, IN PCSTR ExtractPath, OPTIONAL IN PCABNOTIFICATIONA CabNotification OPTIONAL ) /*++ Routine Description: Extracts all files from a cabinet file. Arguments: CabHandle - Specifies cabinet context. ExtractPath - Specifies the path to extract the files to. Return Value: TRUE if successful, FALSE otherwise. --*/ { PFDI_CAB_HANDLEA cabHandle; CAB_DATAA cabData; cabHandle = (PFDI_CAB_HANDLEA)CabHandle; if (!cabHandle) { return FALSE; } if (!cabHandle->FdiHandle) { return FALSE; } cabData.ExtractPath = ExtractPath; cabData.CabNotificationA = CabNotification; return FDICopy ( cabHandle->FdiHandle, (PSTR)cabHandle->CabFile, (PSTR)cabHandle->CabPath, 0, pCabNotificationA, NULL, (PVOID)(&cabData) ); } BOOL pCabExtractAllFilesExWorkerW ( IN OCABHANDLE CabHandle, IN PCWSTR ExtractPath, OPTIONAL IN PCABNOTIFICATIONW CabNotificationW, OPTIONAL IN BOOL VerifyMode ) /*++ Routine Description: Extracts all files from a cabinet file. Arguments: CabHandle - Specifies cabinet context. ExtractPath - Specifies the path to extract the files to. CabNotification - Specifies the notification callback function that is called for every file in the cab VerifyMode - Specifies TRUE if the cab should be verified, FALSE if it should be extracted Return Value: TRUE if successful, FALSE otherwise. --*/ { PFDI_CAB_HANDLEW cabHandle; CAB_DATAW cabData; BOOL result; PCSTR cabFileAnsi; PCSTR cabPathAnsi; cabHandle = (PFDI_CAB_HANDLEW)CabHandle; if (!cabHandle) { return FALSE; } if (!cabHandle->FdiHandle) { return FALSE; } cabData.ExtractPath = ExtractPath; cabData.CabNotificationW = CabNotificationW; cabData.VerifyMode = VerifyMode; cabFileAnsi = ConvertWtoA (cabHandle->CabFile); cabPathAnsi = ConvertWtoA (cabHandle->CabPath); result = FDICopy ( cabHandle->FdiHandle, (PSTR) cabFileAnsi, (PSTR) cabPathAnsi, 0, pCabNotificationW, NULL, (PVOID)(&cabData) ); FreeConvertedStr (cabFileAnsi); FreeConvertedStr (cabPathAnsi); return result; } BOOL CabExtractAllFilesExW ( IN OCABHANDLE CabHandle, IN PCWSTR ExtractPath, OPTIONAL IN PCABNOTIFICATIONW CabNotificationW OPTIONAL ) { return pCabExtractAllFilesExWorkerW (CabHandle, ExtractPath, CabNotificationW, FALSE); } BOOL CabVerifyCabinet ( IN OCABHANDLE CabHandle ) { return pCabExtractAllFilesExWorkerW (CabHandle, NULL, NULL, TRUE); } BOOL CabCloseCabinetA ( IN OCABHANDLE CabHandle ) /*++ Routine Description: Closes a cabinet file context. Arguments: CabHandle - Specifies cabinet context. Return Value: TRUE if successful, FALSE otherwise. --*/ { PFDI_CAB_HANDLEA cabHandle; cabHandle = (PFDI_CAB_HANDLEA) CabHandle; if (!cabHandle) { return FALSE; } if (!cabHandle->FdiHandle) { return FALSE; } if (FDIDestroy (cabHandle->FdiHandle)) { if (cabHandle->CabPath) { FreePathStringA (cabHandle->CabPath); } if (cabHandle->CabFile) { FreePathStringA (cabHandle->CabFile); } MemFree (g_hHeap, 0, cabHandle); return TRUE; } return FALSE; } BOOL CabCloseCabinetW ( IN OCABHANDLE CabHandle ) /*++ Routine Description: Closes a cabinet file context. Arguments: CabHandle - Specifies cabinet context. Return Value: TRUE if successful, FALSE otherwise. --*/ { PFDI_CAB_HANDLEW cabHandle; cabHandle = (PFDI_CAB_HANDLEW) CabHandle; if (!cabHandle) { return FALSE; } if (!cabHandle->FdiHandle) { return FALSE; } if (FDIDestroy (cabHandle->FdiHandle)) { if (cabHandle->CabPath) { FreePathStringW (cabHandle->CabPath); } if (cabHandle->CabFile) { FreePathStringW (cabHandle->CabFile); } MemFree (g_hHeap, 0, cabHandle); return TRUE; } return FALSE; }