402 lines
12 KiB
C++
402 lines
12 KiB
C++
|
|
#include "stdafx.h"
|
|
#include <stdio.h>
|
|
#include <stdlib.h>
|
|
#include <string.h>
|
|
#include <io.h>
|
|
#include <fcntl.h>
|
|
#include <dos.h>
|
|
#include "cabfunc.h"
|
|
#include "resource.h"
|
|
#include "filestuff.h"
|
|
#include "fdi.h"
|
|
#include "setupapi.h"
|
|
|
|
|
|
|
|
|
|
CString g_strExpandToDirectory;
|
|
|
|
|
|
LRESULT WINAPI CabinetCallbackToExpand ( IN PVOID pMyInstallData, IN UINT Notification, IN UINT_PTR Param1, IN UINT_PTR Param2 )
|
|
{
|
|
LRESULT lRetVal = NO_ERROR;
|
|
|
|
FILE_IN_CABINET_INFO *pInfo = NULL;
|
|
CString strTargetName = g_strExpandToDirectory;
|
|
strTargetName += '\\';
|
|
switch(Notification)
|
|
{
|
|
|
|
case SPFILENOTIFY_FILEINCABINET:
|
|
|
|
pInfo = (FILE_IN_CABINET_INFO *) Param1;
|
|
lRetVal = FILEOP_DOIT; // Extract the file.
|
|
strTargetName += pInfo->NameInCabinet;
|
|
//pInfo->FullTargetName is define as TCHAR FullTargetName[MAX_PATH];
|
|
_tcsncpy(pInfo->FullTargetName,strTargetName.GetBuffer(strTargetName.GetLength()),MAX_PATH);
|
|
|
|
break;
|
|
case SPFILENOTIFY_FILEEXTRACTED:
|
|
|
|
lRetVal = NO_ERROR;
|
|
break;
|
|
case SPFILENOTIFY_NEEDNEWCABINET: // Cab file in the cab file we're looking at. Ignore it.
|
|
lRetVal = NO_ERROR;
|
|
break;
|
|
}
|
|
return lRetVal;
|
|
}
|
|
|
|
BOOL OpenCABFile(const CString& strCabPath,const CString& strExpandToDirectory)
|
|
{
|
|
|
|
g_strExpandToDirectory = strExpandToDirectory;
|
|
if (!SetupIterateCabinet(strCabPath,0,(PSP_FILE_CALLBACK)CabinetCallbackToExpand,0))
|
|
{
|
|
return FALSE;
|
|
}
|
|
else
|
|
{
|
|
return TRUE;
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
//---------------------------------------------------------------------------
|
|
// This function looks in the specified directory for an NFO file. If it
|
|
// finds one, it assigns it to filename and returns TRUE. This function
|
|
// will only find the first NFO file in a directory.
|
|
//
|
|
// If an NFO file cannot be found, then we'll look for another file type
|
|
// to open. Grab the string entry in the registry = "cabdefaultopen". An
|
|
// example value would be "*.nfo|hwinfo.dat|*.dat|*.txt" which would be
|
|
// interpreted as follows:
|
|
//
|
|
// 1. First look for any NFO file to open.
|
|
// 2. Then try to open a file called "hwinfo.dat".
|
|
// 3. Then try to open any file with a DAT extension.
|
|
// 4. Then try for any TXT file.
|
|
// 5. Finally, if none of these can be found, present an open dialog
|
|
// to the user.
|
|
//---------------------------------------------------------------------------
|
|
|
|
LPCTSTR VAL_CABDEFAULTOPEN = _T("cabdefaultopen");
|
|
LPCTSTR cszDirSeparator = _T("\\");
|
|
|
|
BOOL IsDataspecFilePresent(CString strCabExplodedDir)
|
|
{
|
|
CStringList filesfound;
|
|
DirectorySearch(_T("dataspec.xml"), strCabExplodedDir, filesfound);
|
|
if (filesfound.GetHeadPosition() != NULL)
|
|
{
|
|
return TRUE;
|
|
}
|
|
return FALSE;
|
|
}
|
|
|
|
BOOL IsIncidentXMLFilePresent(CString strCabExplodedDir, CString strIncidentFileName)
|
|
{
|
|
CStringList filesfound;
|
|
DirectorySearch(strIncidentFileName, strCabExplodedDir, filesfound);
|
|
if (filesfound.GetHeadPosition() != NULL)
|
|
{
|
|
return TRUE;
|
|
}
|
|
return FALSE;
|
|
|
|
}
|
|
|
|
BOOL FindFileToOpen(const CString & destination, CString & filename)
|
|
{
|
|
CString strCABDefaultOpen, strRegBase, strDirectory;
|
|
HKEY hkey;
|
|
|
|
filename.Empty();
|
|
strDirectory = destination;
|
|
if (strDirectory.Right(1) != CString(cszDirSeparator))
|
|
strDirectory += CString(cszDirSeparator);
|
|
|
|
// Set up a fallback string of the NFO file type, in case we can't
|
|
// find the registry entry.
|
|
|
|
strCABDefaultOpen.LoadString(IDS_DEFAULTEXTENSION);
|
|
strCABDefaultOpen = CString("*.") + strCABDefaultOpen;
|
|
|
|
// Load the string of files and file types to open from the registry.
|
|
|
|
strRegBase.LoadString(IDS_MSI_REG_BASE);
|
|
if (RegOpenKeyEx(HKEY_LOCAL_MACHINE, strRegBase, 0, KEY_READ, &hkey) == ERROR_SUCCESS)
|
|
{
|
|
char szData[MAX_PATH];
|
|
DWORD dwType, dwSize = MAX_PATH;
|
|
|
|
if (RegQueryValueEx(hkey, VAL_CABDEFAULTOPEN, NULL, &dwType, (LPBYTE) szData, &dwSize) == ERROR_SUCCESS)
|
|
if (dwType == REG_SZ)
|
|
strCABDefaultOpen = szData;
|
|
RegCloseKey(hkey);
|
|
}
|
|
|
|
// Look through each of the potential files and file types. If we find
|
|
// a match, return TRUE after setting filename appropriately. Note that
|
|
// we need to recurse down through directories.
|
|
|
|
CString strFileSpec;
|
|
CStringList filesfound;
|
|
POSITION pos;
|
|
|
|
while (!strCABDefaultOpen.IsEmpty())
|
|
{
|
|
if (strCABDefaultOpen.Find('|') == -1)
|
|
strFileSpec = strCABDefaultOpen;
|
|
else
|
|
strFileSpec = strCABDefaultOpen.Left(strCABDefaultOpen.Find('|'));
|
|
|
|
filesfound.RemoveAll();
|
|
DirectorySearch(strFileSpec, strDirectory, filesfound);
|
|
pos = filesfound.GetHeadPosition();
|
|
|
|
if (pos != NULL)
|
|
{
|
|
filename = filesfound.GetNext(pos);
|
|
return TRUE;
|
|
}
|
|
|
|
strCABDefaultOpen = strCABDefaultOpen.Right(strCABDefaultOpen.GetLength() - strFileSpec.GetLength());
|
|
if (strCABDefaultOpen.Find('|') == 0)
|
|
strCABDefaultOpen = strCABDefaultOpen.Right(strCABDefaultOpen.GetLength() - 1);
|
|
}
|
|
|
|
|
|
|
|
//a-kjaw
|
|
////Look for incident.xml file. It has to be an unicode file.
|
|
strCABDefaultOpen = _T("*.XML");
|
|
|
|
TCHAR pBuf[MAX_PATH];
|
|
WCHAR pwBuf[MAX_PATH];
|
|
HANDLE handle;
|
|
DWORD dw;
|
|
|
|
|
|
while (!strCABDefaultOpen.IsEmpty())
|
|
{
|
|
if (strCABDefaultOpen.Find('|') == -1)
|
|
strFileSpec = strCABDefaultOpen;
|
|
else
|
|
strFileSpec = strCABDefaultOpen.Left(strCABDefaultOpen.Find('|'));
|
|
|
|
filesfound.RemoveAll();
|
|
DirectorySearch(strFileSpec, strDirectory, filesfound);
|
|
pos = filesfound.GetHeadPosition();
|
|
|
|
while (pos != NULL)
|
|
{
|
|
filename = filesfound.GetNext(pos);
|
|
|
|
handle = CreateFile(filename, GENERIC_READ, FILE_SHARE_READ, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL);
|
|
if (INVALID_HANDLE_VALUE == handle)
|
|
continue;
|
|
|
|
ReadFile(handle , pBuf , 1 , &dw , NULL);
|
|
|
|
if( pBuf[0] == _T('<'))
|
|
{
|
|
do
|
|
{
|
|
ReadFile(handle , pBuf , _tcslen(_T("MachineID")) * sizeof(TCHAR) , &dw , NULL);
|
|
if(_tcsicmp(pBuf , _T("MachineID")) == 0)
|
|
{
|
|
CloseHandle( handle );
|
|
return TRUE;
|
|
}
|
|
else
|
|
{
|
|
SetFilePointer(handle , (1 - _tcslen(_T("MachineID")) )* sizeof(TCHAR) , 0 , FILE_CURRENT );
|
|
}
|
|
}while( dw == _tcslen(_T("MachineID")) );
|
|
|
|
}
|
|
else //Unicode?
|
|
{
|
|
|
|
ReadFile(handle , pwBuf , 1 , &dw , NULL);
|
|
do
|
|
{
|
|
|
|
ReadFile(handle , pwBuf , lstrlenW(L"MachineID") * sizeof(WCHAR) , &dw , NULL);
|
|
pwBuf[ lstrlenW(L"MachineID") ] = L'\0';
|
|
if(lstrcmpiW(pwBuf , L"MachineID") == 0)
|
|
{
|
|
CloseHandle( handle );
|
|
return TRUE;
|
|
}
|
|
else
|
|
{
|
|
SetFilePointer(handle , (1 - lstrlenW(L"MachineID"))* sizeof(WCHAR) , 0 , FILE_CURRENT );
|
|
}
|
|
}while( dw == _tcslen(_T("MachineID")) * sizeof(WCHAR) );
|
|
}
|
|
CloseHandle( handle );
|
|
}
|
|
|
|
strCABDefaultOpen = strCABDefaultOpen.Right(strCABDefaultOpen.GetLength() - strFileSpec.GetLength());
|
|
if (strCABDefaultOpen.Find('|') == 0)
|
|
strCABDefaultOpen = strCABDefaultOpen.Right(strCABDefaultOpen.GetLength() - 1);
|
|
}
|
|
|
|
|
|
|
|
return FALSE;
|
|
}
|
|
|
|
|
|
//---------------------------------------------------------------------------
|
|
// DirectorySearch is used to locate all of the files in a directory or
|
|
// one of its subdirectories which match a file spec.
|
|
//---------------------------------------------------------------------------
|
|
|
|
void DirectorySearch(const CString & strSpec, const CString & strDir, CStringList &results)
|
|
{
|
|
// Look for all of the files which match the file spec in the directory
|
|
// specified by strDir.
|
|
|
|
WIN32_FIND_DATA finddata;
|
|
CString strSearch, strDirectory;
|
|
|
|
strDirectory = strDir;
|
|
if (strDirectory.Right(1) != CString(cszDirSeparator)) strDirectory += CString(cszDirSeparator);
|
|
|
|
strSearch = strDirectory + strSpec;
|
|
HANDLE hFind = FindFirstFile(strSearch, &finddata);
|
|
if (hFind != INVALID_HANDLE_VALUE)
|
|
{
|
|
do
|
|
{
|
|
results.AddHead(strDirectory + CString(finddata.cFileName));
|
|
} while (FindNextFile(hFind, &finddata));
|
|
FindClose(hFind);
|
|
}
|
|
|
|
// Now call this function recursively, with each of the subdirectories.
|
|
|
|
strSearch = strDirectory + CString(_T("*"));
|
|
hFind = FindFirstFile(strSearch, &finddata);
|
|
if (hFind != INVALID_HANDLE_VALUE)
|
|
{
|
|
do
|
|
{
|
|
if (finddata.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY)
|
|
if (::_tcscmp(finddata.cFileName, _T(".")) != 0 && ::_tcscmp(finddata.cFileName, _T("..")) != 0)
|
|
DirectorySearch(strSpec, strDirectory + CString(finddata.cFileName), results);
|
|
} while (FindNextFile(hFind, &finddata));
|
|
FindClose(hFind);
|
|
}
|
|
}
|
|
|
|
//---------------------------------------------------------------------------
|
|
// This function gets the directory in which to put exploded CAB files.
|
|
// This will be the same directory each time, so this function will create
|
|
// the directory (if necessary) and delete any files in the directory.
|
|
//---------------------------------------------------------------------------
|
|
|
|
BOOL GetCABExplodeDir(CString &destination, BOOL fDeleteFiles, const CString & strDontDelete)
|
|
{
|
|
CString strMSInfoDir, strExplodeTo, strSubDirName;
|
|
|
|
// Determine the temporary path and add on a subdir name.
|
|
|
|
TCHAR szTempDir[MAX_PATH];
|
|
|
|
if (::GetTempPath(MAX_PATH, szTempDir) > MAX_PATH)
|
|
{
|
|
destination = _T("");
|
|
return FALSE;
|
|
}
|
|
|
|
strSubDirName.LoadString(IDS_CAB_DIR_NAME);
|
|
strExplodeTo = szTempDir;
|
|
if (strExplodeTo.Right(1) == CString(cszDirSeparator))
|
|
strExplodeTo = strExplodeTo + strSubDirName;
|
|
else
|
|
strExplodeTo = strExplodeTo + CString(cszDirSeparator) + strSubDirName;
|
|
|
|
// Kill the directory if it already exists.
|
|
|
|
if (fDeleteFiles)
|
|
KillDirectory(strExplodeTo, strDontDelete);
|
|
|
|
// Create the subdirectory.
|
|
|
|
if (!CreateDirectoryEx(szTempDir, strExplodeTo, NULL))
|
|
{
|
|
if (GetLastError() != ERROR_ALREADY_EXISTS)
|
|
{
|
|
// MSIError(IDS_GENERAL_ERROR, "couldn't create the target directory");
|
|
destination = "";
|
|
return FALSE;
|
|
}
|
|
}
|
|
|
|
destination = strExplodeTo;
|
|
return TRUE;
|
|
}
|
|
|
|
//---------------------------------------------------------------------------
|
|
// This functions kills a directory by recursively deleting files and
|
|
// subdirectories.
|
|
//---------------------------------------------------------------------------
|
|
|
|
void KillDirectory(const CString & strDir, const CString & strDontDelete)
|
|
{
|
|
CString strDirectory = strDir;
|
|
|
|
if (strDirectory.Right(1) == CString(cszDirSeparator))
|
|
strDirectory = strDirectory.Left(strDirectory.GetLength() - 1);
|
|
|
|
// Delete any files in directory.
|
|
|
|
CString strFilesToDelete = strDirectory + CString(_T("\\*.*"));
|
|
CString strDeleteFile;
|
|
WIN32_FIND_DATA filedata;
|
|
BOOL bFound = TRUE;
|
|
|
|
HANDLE hFindFile = FindFirstFile(strFilesToDelete, &filedata);
|
|
while (hFindFile != INVALID_HANDLE_VALUE && bFound)
|
|
{
|
|
if ((filedata.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) == 0L)
|
|
{
|
|
strDeleteFile = strDirectory + CString(cszDirSeparator) + filedata.cFileName;
|
|
|
|
if (strDontDelete.CompareNoCase(strDeleteFile) != 0)
|
|
{
|
|
::SetFileAttributes(strDeleteFile, FILE_ATTRIBUTE_NORMAL);
|
|
::DeleteFile(strDeleteFile);
|
|
}
|
|
}
|
|
|
|
bFound = FindNextFile(hFindFile, &filedata);
|
|
}
|
|
FindClose(hFindFile);
|
|
|
|
// Now call this function on any subdirectories in this directory.
|
|
|
|
CString strSearch = strDirectory + CString(_T("\\*"));
|
|
hFindFile = FindFirstFile(strSearch, &filedata);
|
|
if (hFindFile != INVALID_HANDLE_VALUE)
|
|
{
|
|
do
|
|
{
|
|
if (filedata.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY)
|
|
if (::_tcscmp(filedata.cFileName, _T(".")) != 0 && ::_tcscmp(filedata.cFileName, _T("..")) != 0)
|
|
KillDirectory(strDirectory + CString(cszDirSeparator) + CString(filedata.cFileName));
|
|
} while (FindNextFile(hFindFile, &filedata));
|
|
FindClose(hFindFile);
|
|
}
|
|
|
|
// Finally, remove this directory.
|
|
|
|
::RemoveDirectory(strDirectory);
|
|
} |