You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
495 lines
15 KiB
495 lines
15 KiB
// advpext.cpp : Defines the entry point for the DLL application.
|
|
//
|
|
#include <windows.h>
|
|
#include <wininet.h>
|
|
#include "util.h"
|
|
#include "download.h"
|
|
#include "patchapi.h"
|
|
#include "resource.h"
|
|
#include "patchdownload.h"
|
|
#include "sdsutils.h"
|
|
|
|
|
|
|
|
#define FILECOUNT 50
|
|
|
|
PDOWNLOAD_FILEINFO g_pDownloadFileList = NULL;
|
|
DWORD g_dwFileCount = 0;
|
|
DWORD g_dwArraySize = 0;
|
|
|
|
HRESULT g_hResult;
|
|
HINF g_hInf;
|
|
BOOL g_fPreparingDir;
|
|
BOOL g_QuietMode = FALSE;
|
|
BOOL g_fAbort = FALSE;
|
|
HWND g_hProgressDlg = NULL;
|
|
HINSTANCE g_hInstance;
|
|
HINSTANCE g_hSetupLibrary = NULL;
|
|
|
|
PFSetupDefaultQueueCallback pfSetupDefaultQueueCallback = NULL;
|
|
PFSetupInstallFromInfSection pfSetupInstallFromInfSection = NULL;
|
|
PFSetupInitDefaultQueueCallbackEx pfSetupInitDefaultQueueCallbackEx = NULL;
|
|
PFSetupTermDefaultQueueCallback pfSetupTermDefaultQueueCallback = NULL;
|
|
PFSetupGetLineText pfSetupGetLineText = NULL;
|
|
PFSetupFindFirstLine pfSetupFindFirstLine = NULL;
|
|
PFSetupFindNextLine pfSetupFindNextLine = NULL;
|
|
PFSetupGetStringField pfSetupGetStringField = NULL;
|
|
PFSetupDecompressOrCopyFile pfSetupDecompressOrCopyFile = NULL;
|
|
|
|
|
|
|
|
|
|
BOOL APIENTRY DllMain( HANDLE hModule, DWORD ul_reason_for_call, LPVOID lpReserved)
|
|
{
|
|
if(DLL_PROCESS_ATTACH == ul_reason_for_call)
|
|
{
|
|
InitLogFile();
|
|
g_hInstance = (HINSTANCE)hModule;
|
|
}
|
|
|
|
if(DLL_PROCESS_DETACH == ul_reason_for_call)
|
|
{
|
|
if(g_hLogFile)
|
|
CloseHandle(g_hLogFile);
|
|
if(g_hSetupLibrary)
|
|
FreeLibrary(g_hSetupLibrary);
|
|
}
|
|
|
|
return TRUE;
|
|
}
|
|
|
|
|
|
|
|
HRESULT WINAPI ProcessFileSection(HINF hInf, HWND hWnd, BOOL fQuietMode, LPCSTR lpszSection, LPCSTR lpszSourceDir,
|
|
PATCH_DOWNLOAD_CALLBACK pfn, LPVOID lpvContext)
|
|
{
|
|
HRESULT hr = S_OK;
|
|
PDOWNLOAD_FILEINFO pFileList = NULL;
|
|
char szUserName[MAX_PATH] = "", szPassword[MAX_PATH] = "", szUrl[INTERNET_MAX_URL_LENGTH];
|
|
TCHAR szSrcDir[MAX_PATH];
|
|
DWORD dwFileCount=0;
|
|
|
|
|
|
WriteToLog("ProcessFileSection: InfHandle= %1!lx!, Source Directory = %2\n", hInf, lpszSourceDir);
|
|
g_hInf = hInf;
|
|
g_fPreparingDir = FALSE;
|
|
|
|
if(fQuietMode)
|
|
{
|
|
g_QuietMode = TRUE;
|
|
}
|
|
|
|
|
|
if(!g_QuietMode)
|
|
{
|
|
g_hProgressDlg = CreateDialog(g_hInstance, MAKEINTRESOURCE(IDD_PROGRESSDLG), hWnd, ProgressDlgProc);
|
|
if (g_hProgressDlg)
|
|
{
|
|
ShowWindow(g_hProgressDlg, SW_SHOWNORMAL);
|
|
UpdateWindow(g_hProgressDlg);
|
|
}
|
|
}
|
|
|
|
SetProgressText(IDS_FILELIST);
|
|
hr = GetFileList(hInf, lpszSection, &pFileList, &dwFileCount);
|
|
if(FAILED(hr))
|
|
{
|
|
goto done;
|
|
}
|
|
|
|
if(dwFileCount)
|
|
{
|
|
if(!pfSetupGetLineText(NULL, hInf, lpszSection, "Url", szUrl, sizeof(szUrl), NULL))
|
|
{
|
|
hr = HRESULT_FROM_SETUPAPI(GetLastError());
|
|
goto done;
|
|
}
|
|
|
|
hr = DownloadAndPatchFiles(dwFileCount, pFileList, szUrl, lpszSourceDir, pfn, lpvContext);
|
|
|
|
if(FAILED(hr) || g_fAbort)
|
|
{
|
|
goto done;
|
|
}
|
|
}
|
|
|
|
hr = PrepareInstallDirectory(hInf, lpszSection);
|
|
|
|
|
|
done:
|
|
|
|
if(pFileList)
|
|
{
|
|
FreeFileList(pFileList);
|
|
}
|
|
|
|
if(g_hProgressDlg)
|
|
{
|
|
DestroyWindow(g_hProgressDlg);
|
|
}
|
|
return hr;
|
|
|
|
}
|
|
|
|
HRESULT WINAPI GetFileList(HINF hInf, LPCSTR lpszSection, PDOWNLOAD_FILEINFO* pFileList, DWORD* pdwFileCount)
|
|
{
|
|
|
|
HRESULT hr = LoadSetupAPIFuncs();
|
|
if(FAILED(hr))
|
|
{
|
|
return hr;
|
|
}
|
|
|
|
WriteToLog("\nGetting the list of files\n");
|
|
g_hResult = S_OK;
|
|
//initially we allocate around 50 entries. We reallocate as and when needed
|
|
g_dwArraySize = FILECOUNT;
|
|
g_pDownloadFileList = (PDOWNLOAD_FILEINFO)ResizeBuffer(NULL, FILECOUNT*sizeof(DOWNLOAD_FILEINFO), FALSE);
|
|
|
|
if(!g_pDownloadFileList)
|
|
{
|
|
return HRESULT_FROM_WIN32(GetLastError());
|
|
}
|
|
|
|
g_dwFileCount = 0;
|
|
|
|
|
|
PVOID pContext = pfSetupInitDefaultQueueCallbackEx( NULL, (HWND)INVALID_HANDLE_VALUE, 0, 0, NULL );
|
|
|
|
if ( pContext == INVALID_HANDLE_VALUE )
|
|
{
|
|
return HRESULT_FROM_SETUPAPI(GetLastError());
|
|
}
|
|
|
|
WriteToLog("Adding the Following Files\n");
|
|
if (!pfSetupInstallFromInfSection( NULL, hInf, lpszSection, SPINST_FILES, NULL,
|
|
NULL, SP_COPY_NEWER, (PSP_FILE_CALLBACK)MyFileQueueCallback,
|
|
pContext, NULL, NULL ) )
|
|
{
|
|
pfSetupTermDefaultQueueCallback( pContext );
|
|
return HRESULT_FROM_SETUPAPI(GetLastError());
|
|
}
|
|
|
|
pfSetupTermDefaultQueueCallback( pContext );
|
|
|
|
if(SUCCEEDED(g_hResult))
|
|
{
|
|
*pFileList = g_pDownloadFileList;
|
|
*pdwFileCount = g_dwFileCount;
|
|
}
|
|
|
|
return g_hResult;
|
|
}
|
|
|
|
|
|
|
|
UINT WINAPI MyFileQueueCallback( PVOID Context,UINT Notification,UINT_PTR parm1,UINT_PTR parm2 )
|
|
{
|
|
UINT retVal = FILEOP_SKIP;
|
|
|
|
switch(Notification)
|
|
{
|
|
case SPFILENOTIFY_STARTDELETE:
|
|
case SPFILENOTIFY_STARTRENAME:
|
|
case SPFILENOTIFY_COPYERROR:
|
|
case SPFILENOTIFY_DELETEERROR:
|
|
case SPFILENOTIFY_RENAMEERROR:
|
|
break;
|
|
|
|
case SPFILENOTIFY_STARTCOPY:
|
|
{
|
|
FILEPATHS *pFilePath;
|
|
|
|
pFilePath = (FILEPATHS *)parm1;
|
|
|
|
if (!MyFileSize(pFilePath->Source))
|
|
{
|
|
DeleteFile(pFilePath->Source);
|
|
|
|
//If we are preparing the dir for installaion then copy the file to the current path.
|
|
//else we are in download mode, add it to the file list if required
|
|
if(g_fPreparingDir)
|
|
{
|
|
|
|
if(CopyFile(pFilePath->Target, pFilePath->Source, TRUE))
|
|
WriteToLog("Copying %1 file to %2\n", pFilePath->Target, pFilePath->Source);
|
|
}
|
|
else
|
|
{
|
|
//Check in the version in inf to see if we need to download
|
|
if(IsDownloadedNeeded(pFilePath->Source, pFilePath->Target))
|
|
AddToFileList(pFilePath->Source, pFilePath->Target);
|
|
}
|
|
}
|
|
|
|
}
|
|
break;
|
|
|
|
case SPFILENOTIFY_NEEDMEDIA:
|
|
{
|
|
char szFileName[MAX_PATH];
|
|
PSOURCE_MEDIA psrcMed;
|
|
|
|
psrcMed = (PSOURCE_MEDIA)parm1;
|
|
wsprintf(szFileName, "%s\\%s", psrcMed->SourcePath, psrcMed->SourceFile);
|
|
|
|
if(GetFileAttributes(szFileName) == 0xFFFFFFFF )
|
|
{
|
|
if(g_fPreparingDir)
|
|
{
|
|
if(GetFileAttributes(szFileName) != 0xFFFFFFFF)
|
|
return retVal;
|
|
}
|
|
|
|
|
|
HANDLE hTempFile = CreateFile(szFileName, GENERIC_WRITE, 0, NULL,
|
|
CREATE_NEW, FILE_ATTRIBUTE_TEMPORARY, NULL );
|
|
|
|
|
|
if (hTempFile != INVALID_HANDLE_VALUE)
|
|
{
|
|
CloseHandle( hTempFile );
|
|
}
|
|
}
|
|
|
|
|
|
}
|
|
|
|
default:
|
|
return (pfSetupDefaultQueueCallback( Context, Notification, parm1, parm2 ) );
|
|
}
|
|
|
|
return( retVal );
|
|
}
|
|
|
|
|
|
BOOL IsDownloadedNeeded(LPCTSTR lpszSrcFilePath, LPCTSTR lpszFilePath)
|
|
{
|
|
char szVersion[MAX_PATH], szSrcFilePath[MAX_PATH];
|
|
INFCONTEXT InfContext;
|
|
LPTSTR lp;
|
|
|
|
LPTSTR lpszSrcName = PathFindFileName(lpszSrcFilePath);
|
|
|
|
|
|
if (!pfSetupFindFirstLine(g_hInf, "SourceDisksFiles", lpszSrcName, &InfContext ))
|
|
{
|
|
//No SourceDisksFiles entry. Assume that this file needs to be downloaded
|
|
return TRUE;
|
|
}
|
|
|
|
DWORD dwMSVer = 0, dwLSVer = 0, dwMSNewFileVer = 0, dwLSNewFileVer = 0;
|
|
|
|
if(pfSetupGetStringField(&InfContext, 4, szVersion, sizeof(szVersion), NULL))
|
|
{
|
|
//Get version of file on the machine
|
|
ConvertVersionStrToDwords(szVersion, &dwMSNewFileVer, &dwLSNewFileVer);
|
|
MyGetVersionFromFile((LPTSTR)lpszFilePath, &dwMSVer, &dwLSVer, TRUE);
|
|
}
|
|
|
|
if(dwMSVer == dwMSNewFileVer && dwLSVer == dwLSNewFileVer)
|
|
{
|
|
TCHAR szHashFromInf[40], szHashFromFile[40];
|
|
|
|
if(GetHashidFromINF(lpszSrcName, szHashFromInf, sizeof(szHashFromInf)) &&
|
|
GetFilePatchSignatureA(lpszFilePath, PATCH_OPTION_SIGNATURE_MD5, NULL, 0, 0, 0, 0,
|
|
sizeof(szHashFromFile), szHashFromFile))
|
|
{
|
|
if (lstrcmpi(szHashFromFile, szHashFromInf) == 0 )
|
|
{
|
|
return FALSE;
|
|
}
|
|
}
|
|
|
|
return TRUE;
|
|
}
|
|
|
|
if(dwMSVer < dwMSNewFileVer || ((dwMSVer == dwMSNewFileVer) && dwLSVer < dwLSNewFileVer))
|
|
{
|
|
return TRUE;
|
|
}
|
|
return FALSE;
|
|
}
|
|
|
|
void AddToFileList(LPCSTR lpszSrc, LPCSTR lpszTarget)
|
|
{
|
|
TCHAR Signature[40] = ""; // MD5 is 32 hex characters plus terminator
|
|
|
|
|
|
if(g_dwFileCount >= g_dwArraySize)
|
|
{
|
|
g_dwArraySize = g_dwArraySize + FILECOUNT;
|
|
g_pDownloadFileList = (PDOWNLOAD_FILEINFO)ResizeBuffer(g_pDownloadFileList,
|
|
g_dwArraySize*sizeof(DOWNLOAD_FILEINFO), FALSE);
|
|
|
|
if(!g_pDownloadFileList)
|
|
{
|
|
g_hResult = HRESULT_FROM_WIN32(GetLastError());
|
|
return;
|
|
}
|
|
}
|
|
|
|
|
|
GetFilePatchSignatureA(lpszTarget, PATCH_OPTION_USE_LZX_BEST, NULL, 0 , 0, 0, 0,
|
|
sizeof(Signature), Signature);
|
|
if ( *Signature )
|
|
{
|
|
g_pDownloadFileList[g_dwFileCount].lpszExistingFilePatchSignature = StrDup(Signature);
|
|
}
|
|
else
|
|
{
|
|
g_pDownloadFileList[g_dwFileCount].lpszExistingFilePatchSignature = NULL;
|
|
}
|
|
|
|
|
|
WriteToLog("%1 Destination:%2 Patch Signature:%3\n", PathFindFileName(lpszSrc), lpszTarget, Signature);
|
|
g_pDownloadFileList[g_dwFileCount].lpszFileNameToDownload = StrDup(PathFindFileName(lpszSrc));
|
|
g_pDownloadFileList[g_dwFileCount].lpszExistingFileToPatchFrom = StrDup(lpszTarget);
|
|
g_pDownloadFileList[g_dwFileCount].dwFlags = PATCHFLAG_DOWNLOAD_NEEDED;
|
|
g_dwFileCount++;
|
|
|
|
}
|
|
|
|
void FreeFileList(PDOWNLOAD_FILEINFO pFileList)
|
|
{
|
|
int i = g_dwFileCount;
|
|
while(i--)
|
|
{
|
|
if(pFileList[i].lpszFileNameToDownload)
|
|
{
|
|
LocalFree(pFileList[i].lpszFileNameToDownload);
|
|
}
|
|
|
|
if(pFileList[i].lpszExistingFileToPatchFrom)
|
|
{
|
|
LocalFree(pFileList[i].lpszExistingFileToPatchFrom);
|
|
}
|
|
|
|
if(pFileList[i].lpszExistingFilePatchSignature)
|
|
{
|
|
LocalFree(pFileList[i].lpszExistingFilePatchSignature);
|
|
}
|
|
}
|
|
ResizeBuffer(pFileList, 0, 0);
|
|
|
|
}
|
|
|
|
|
|
HRESULT PrepareInstallDirectory(HINF hInf, LPCSTR lpszSection)
|
|
{
|
|
g_hResult = S_OK;
|
|
g_fPreparingDir = TRUE;
|
|
|
|
PVOID pContext = pfSetupInitDefaultQueueCallbackEx( NULL, (HWND)INVALID_HANDLE_VALUE, 0, 0, NULL );
|
|
if ( pContext == INVALID_HANDLE_VALUE )
|
|
{
|
|
return HRESULT_FROM_SETUPAPI(GetLastError());
|
|
}
|
|
|
|
WriteToLog("Copying the Following Files from src dir\n");
|
|
if (!pfSetupInstallFromInfSection( NULL, hInf, lpszSection, SPINST_FILES, NULL,
|
|
NULL, SP_COPY_NEWER, (PSP_FILE_CALLBACK)MyFileQueueCallback,
|
|
pContext, NULL, NULL ) )
|
|
{
|
|
pfSetupTermDefaultQueueCallback( pContext );
|
|
return HRESULT_FROM_SETUPAPI(GetLastError());
|
|
}
|
|
|
|
pfSetupTermDefaultQueueCallback( pContext );
|
|
|
|
return g_hResult;
|
|
}
|
|
|
|
|
|
INT_PTR CALLBACK ProgressDlgProc(HWND hDlg, UINT uMsg, WPARAM wParam, LPARAM lParam )
|
|
{
|
|
|
|
switch (uMsg)
|
|
{
|
|
case WM_INITDIALOG:
|
|
{
|
|
CenterWindow (hDlg, GetDesktopWindow());
|
|
}
|
|
|
|
break;
|
|
|
|
case WM_COMMAND:
|
|
if(LOWORD(wParam) == IDCANCEL)
|
|
{
|
|
g_fAbort = TRUE;
|
|
}
|
|
|
|
default:
|
|
return(FALSE);
|
|
}
|
|
return(TRUE);
|
|
}
|
|
|
|
BOOL SetProgressText(LPCTSTR lpszText)
|
|
{
|
|
if(g_hProgressDlg)
|
|
{
|
|
SetDlgItemText(g_hProgressDlg, IDC_PROGRESSTEXT, lpszText);
|
|
}
|
|
return TRUE;
|
|
}
|
|
|
|
BOOL SetProgressText(UINT uID)
|
|
{
|
|
if(g_hProgressDlg)
|
|
{
|
|
TCHAR szBuffer[MAX_PATH];
|
|
LoadString(g_hInstance, uID, szBuffer, sizeof(szBuffer));
|
|
SetDlgItemText(g_hProgressDlg, IDC_PROGRESSTEXT, szBuffer);
|
|
}
|
|
return TRUE;
|
|
}
|
|
|
|
HRESULT LoadSetupAPIFuncs()
|
|
{
|
|
static BOOL fSetupLibLoaded = -1;
|
|
HRESULT hr = S_OK;
|
|
|
|
if(fSetupLibLoaded != -1)
|
|
{
|
|
return hr;
|
|
}
|
|
|
|
g_hSetupLibrary = LoadLibrary("SETUPAPI.DLL");
|
|
|
|
if(!g_hSetupLibrary)
|
|
{
|
|
hr = HRESULT_FROM_WIN32(GetLastError());
|
|
WriteToLog("LoadLibrary for Setuapi.dll failed with error code:%1!lx!\n", hr);
|
|
return hr;
|
|
}
|
|
|
|
|
|
pfSetupGetStringField = (PFSetupGetStringField) GetProcAddress(g_hSetupLibrary, c_szSetupGetStringField );
|
|
pfSetupDefaultQueueCallback = (PFSetupDefaultQueueCallback) GetProcAddress(g_hSetupLibrary, c_szSetupDefaultQueueCallback );
|
|
pfSetupInstallFromInfSection = (PFSetupInstallFromInfSection) GetProcAddress(g_hSetupLibrary, c_szSetupInstallFromInfSection );
|
|
pfSetupInitDefaultQueueCallbackEx = (PFSetupInitDefaultQueueCallbackEx) GetProcAddress(g_hSetupLibrary, c_szSetupInitDefaultQueueCallbackEx );
|
|
pfSetupTermDefaultQueueCallback = (PFSetupTermDefaultQueueCallback) GetProcAddress(g_hSetupLibrary, c_szSetupTermDefaultQueueCallback );
|
|
pfSetupGetLineText = (PFSetupGetLineText) GetProcAddress(g_hSetupLibrary, c_szSetupGetLineText );
|
|
pfSetupFindFirstLine = (PFSetupFindFirstLine) GetProcAddress(g_hSetupLibrary, c_szSetupFindFirstLine );
|
|
pfSetupFindNextLine = (PFSetupFindNextLine) GetProcAddress(g_hSetupLibrary, c_szSetupFindNextLine );
|
|
pfSetupDecompressOrCopyFile = (PFSetupDecompressOrCopyFile) GetProcAddress(g_hSetupLibrary, c_szSetupDecompressOrCopyFile );
|
|
|
|
if (pfSetupDefaultQueueCallback == NULL
|
|
|| pfSetupInstallFromInfSection == NULL
|
|
|| pfSetupInitDefaultQueueCallbackEx == NULL
|
|
|| pfSetupTermDefaultQueueCallback == NULL
|
|
|| pfSetupGetLineText == NULL
|
|
|| pfSetupFindFirstLine == NULL
|
|
|| pfSetupFindNextLine == NULL
|
|
|| pfSetupDecompressOrCopyFile == NULL
|
|
|| pfSetupGetStringField == NULL )
|
|
{
|
|
return HRESULT_FROM_WIN32(ERROR_PROC_NOT_FOUND);
|
|
}
|
|
|
|
fSetupLibLoaded = TRUE;
|
|
WriteToLog("Setupapi.dll loaded successfully\n");
|
|
return hr;
|
|
|
|
}
|