//+---------------------------------------------------------------------------- // // File: main.cpp // // Module: CMDL32.EXE // // Synopsis: Main source for PhoneBook download connect action // // Copyright (c) 1996-1999 Microsoft Corporation // // Author: nickball Created Header 04/08/98 // //+---------------------------------------------------------------------------- #include "cmmaster.h" #include "shlobj.h" const TCHAR* const c_pszIConnDwnMsg = TEXT("IConnDwn Message"); // for RegisterWindowMessage() for event messages const TCHAR* const c_pszIConnDwnAgent = TEXT("Microsoft Connection Manager"); // agent for InternetOpen() const TCHAR* const c_pszIConnDwnContent = TEXT("application/octet-stream"); // content type for HttpOpenRequest() const TCHAR* const c_pszCmEntryHideDelay = TEXT("HideDelay"); const TCHAR* const c_pszCmEntryDownloadDelay = TEXT("DownLoadDelay"); const TCHAR* const c_pszCmEntryPbUpdateMessage = TEXT("PBUpdateMessage"); #ifdef EXTENDED_CAB_CONTENTS // // SPECIAL NOTE: // // Be careful here. If you re-enable EXTENDED_CAB_CONTENTS, then you must // address the possibility that different instances might be doing updates // simultaneously in which case a common name such as "PBUPDATE.DIR" is not // appropriate. Because we do not implement this feature, we do not concern // ourselves with it for the simple PBK case. Thus we copy the .PBK, .PBR, // etc. directly from the original tmp dir to the profile directory when // updating. // const TCHAR* const c_pszDirName = TEXT("PBUPDATE.DIR"); // directory to expand .CAB into const TCHAR* const c_pszInfInDir = TEXT("PBUPDATE.DIR\\PBUPDATE.INF"); const TCHAR* const c_pszPbdInDir = TEXT("PBUPDATE.DIR\\PBUPDATE.PBD"); static LPVOID MyAdvPackLoadAndLink(ArgsStruct *pArgs, LPCTSTR pszFunc) { LPVOID pvFunc; if (!pArgs->hAdvPack) { pArgs->hAdvPack = LoadLibrary(TEXT("advpack.dll")); if (!pArgs->hAdvPack) { MYDBG(("MyAdvPackLoadAndLink() LoadLibrary() failed, GLE=%u.",GetLastError())); return (NULL); } } pvFunc = GetProcAddress(pArgs->hAdvPack,pszFunc); MYDBGTST(!pvFunc,("MyAdvPackLoadAndLink() GetProcAddress(%s) failed, GLE=%u.",pszFunc,GetLastError())); return (pvFunc); } #define RSC_FLAG_INF 1 static HRESULT MyRunSetupCommand(ArgsStruct *pArgs, HWND hwndParent, LPCSTR pszCmdName, LPCSTR pszInfSection, LPCSTR pszDir, LPCSTR pszTitle, HANDLE *phExe, DWORD dwFlags, LPVOID pvRsvd) { HRESULT (WINAPI *pfn)(HWND,LPCSTR,LPCSTR,LPCSTR,LPCSTR,HANDLE,DWORD,LPVOID); pfn = (HRESULT (WINAPI *)(HWND,LPCSTR,LPCSTR,LPCSTR,LPCSTR,HANDLE,DWORD,LPVOID)) MyAdvPackLoadAndLink(pArgs,TEXT("RunSetupCommand")); if (!pfn) { return (HRESULT_FROM_WIN32(GetLastError())); } return (pfn(hwndParent,pszCmdName,pszInfSection,pszDir,pszTitle,phExe,dwFlags,pvRsvd)); } static DWORD MyNeedRebootInit(ArgsStruct *pArgs) { DWORD (WINAPI *pfn)(VOID); pfn = (DWORD (WINAPI *)(VOID)) MyAdvPackLoadAndLink(pArgs,TEXT("NeedRebootInit")); if (!pfn) { return (0); } return (pfn()); } static BOOL MyNeedReboot(ArgsStruct *pArgs, DWORD dwCookie) { BOOL (WINAPI *pfn)(DWORD); pfn = (BOOL (WINAPI *)(DWORD)) MyAdvPackLoadAndLink(pArgs,TEXT("NeedReboot")); if (!pfn) { return (FALSE); } return (pfn(dwCookie)); } #endif // EXTENDED_CAB_CONTENTS //+---------------------------------------------------------------------------- // // Function: SuppressInetAutoDial // // Synopsis: Sets Inet Option to turn off auto-dial for requests made by this // process. This prevents multiple instances of CM popping up to // service CMDL initiated requests if the user disconnects CM // immediately after getting connected. // // Arguments: None // // Returns: Nothing // // History: nickball Created Header 6/3/99 // //+---------------------------------------------------------------------------- static void SuppressInetAutoDial(HINTERNET hInternet) { DWORD dwTurnOff = 1; // // The flag only exists for IE5, this call // will have no effect if IE5 is not present. // BOOL bTmp = InternetSetOption(hInternet, INTERNET_OPTION_DISABLE_AUTODIAL, &dwTurnOff, sizeof(DWORD)); MYDBGTST(FALSE == bTmp, ("InternetSetOption() returned %d, GLE=%u.", bTmp, GetLastError())); } static BOOL CmFreeIndirect(LPVOID *ppvBuffer) { CmFree(*ppvBuffer); *ppvBuffer = NULL; return TRUE; } static BOOL CmFreeIndirect(LPTSTR *ppszBuffer) { return (CmFreeIndirect((LPVOID *) ppszBuffer)); } static LPURL_COMPONENTS MyInternetCrackUrl(LPTSTR pszUrl, DWORD dwOptions) { struct _sRes { URL_COMPONENTS sUrl; TCHAR szScheme[INTERNET_MAX_SCHEME_LENGTH]; TCHAR szHostName[INTERNET_MAX_HOST_NAME_LENGTH+1]; TCHAR szUserName[INTERNET_MAX_USER_NAME_LENGTH+1]; TCHAR szPassword[INTERNET_MAX_PASSWORD_LENGTH+1]; TCHAR szUrlPath[INTERNET_MAX_PATH_LENGTH+1]; TCHAR szExtraInfo[INTERNET_MAX_PATH_LENGTH+1]; } *psRes; BOOL bRes; UINT nIdx; UINT nSpaces; if (!pszUrl) { MYDBG(("MyInternetCrackUrl() invalid parameter.")); SetLastError(ERROR_INVALID_PARAMETER); return (NULL); } psRes = (struct _sRes *) CmMalloc(sizeof(*psRes)); if (!psRes) { return (NULL); } psRes->sUrl.dwStructSize = sizeof(psRes->sUrl); psRes->sUrl.lpszScheme = psRes->szScheme; psRes->sUrl.dwSchemeLength = sizeof(psRes->szScheme); psRes->sUrl.lpszHostName = psRes->szHostName; psRes->sUrl.dwHostNameLength = sizeof(psRes->szHostName); psRes->sUrl.lpszUserName = psRes->szUserName; psRes->sUrl.dwUserNameLength = sizeof(psRes->szUserName); psRes->sUrl.lpszPassword = psRes->szPassword; psRes->sUrl.dwPasswordLength = sizeof(psRes->szPassword); psRes->sUrl.lpszUrlPath = psRes->szUrlPath; psRes->sUrl.dwUrlPathLength = sizeof(psRes->szUrlPath); psRes->sUrl.lpszExtraInfo = psRes->szExtraInfo; psRes->sUrl.dwExtraInfoLength = sizeof(psRes->szExtraInfo); bRes = InternetCrackUrl(pszUrl,0,dwOptions,&psRes->sUrl); if (!bRes) { MYDBG(("MyInternetCrackUrl() InternetCrackUrl(pszUrl=%s) failed, GLE=%u.",pszUrl,GetLastError())); CmFree(psRes); return (NULL); } nSpaces = 0; for (nIdx=0;psRes->szExtraInfo[nIdx];nIdx++) { if (psRes->szExtraInfo[nIdx] == ' ') { nSpaces++; } } if (nSpaces) { TCHAR szQuoted[sizeof(psRes->szExtraInfo)/sizeof(TCHAR)]; if (lstrlen(psRes->szExtraInfo)+nSpaces*2 > sizeof(psRes->szExtraInfo)/sizeof(TCHAR)-1) { MYDBG(("MyInternetCrackUrl() quoting spaces will exceed buffer size.")); CmFree(psRes); return (NULL); } ZeroMemory(szQuoted,sizeof(szQuoted)); nSpaces = 0; for (nIdx=0,nSpaces=0;psRes->szExtraInfo[nIdx];nIdx++,nSpaces++) { if (psRes->szExtraInfo[nIdx] == ' ') { szQuoted[nSpaces++] = '%'; szQuoted[nSpaces++] = '2'; szQuoted[nSpaces] = '0'; } else { szQuoted[nSpaces] = psRes->szExtraInfo[nIdx]; } } lstrcpy(psRes->szExtraInfo,szQuoted); } return (&psRes->sUrl); } static BOOL DownloadFileFtp(DownloadArgs *pdaArgs, HANDLE hFile) { BOOL bRes = FALSE; WIN32_FIND_DATA wfdData; LPBYTE pbData = NULL; LPTSTR pszObject = (LPTSTR) CmMalloc((INTERNET_MAX_PATH_LENGTH*2) + 1); if (NULL == pszObject) { MYDBG(("DownloadFileFtp() aborted.")); goto done; } pdaArgs->hInet = InternetOpen(c_pszIConnDwnAgent,INTERNET_OPEN_TYPE_PRECONFIG,NULL,NULL,0); if (*(pdaArgs->pbAbort)) { MYDBG(("DownloadFileFtp() aborted.")); goto done; } if (!pdaArgs->hInet) { MYDBG(("DownloadFileFtp() InternetOpen() failed, GLE=%u.",GetLastError())); goto done; } pdaArgs->hConn = InternetConnect(pdaArgs->hInet, pdaArgs->psUrl->lpszHostName, pdaArgs->psUrl->nPort, pdaArgs->psUrl->lpszUserName&&*pdaArgs->psUrl->lpszUserName?pdaArgs->psUrl->lpszUserName:NULL, pdaArgs->psUrl->lpszPassword&&*pdaArgs->psUrl->lpszPassword?pdaArgs->psUrl->lpszPassword:NULL, INTERNET_SERVICE_FTP, 0, 0); if (*(pdaArgs->pbAbort)) { MYDBG(("DownloadFileFtp() aborted.")); goto done; } if (!pdaArgs->hConn) { MYDBG(("DownloadFileFtp() InternetConnect(pszHostName=%s) failed, GLE=%u.",pdaArgs->psUrl->lpszHostName,GetLastError())); goto done; } lstrcpy(pszObject,pdaArgs->psUrl->lpszUrlPath); // lstrcat(pszObject,pdaArgs->psUrl->lpszExtraInfo); ZeroMemory(&wfdData,sizeof(wfdData)); pdaArgs->hReq = FtpFindFirstFile(pdaArgs->hConn,pszObject,&wfdData,INTERNET_FLAG_RELOAD|INTERNET_FLAG_DONT_CACHE,0); if (*(pdaArgs->pbAbort)) { MYDBG(("DownloadFileFtp() aborted.")); goto done; } if (!pdaArgs->hReq) { MYDBG(("DownloadFileFtp() FtpFindFirstFile() failed, GLE=%u.",GetLastError())); goto done; } bRes = InternetFindNextFile(pdaArgs->hReq,&wfdData); if (*(pdaArgs->pbAbort)) { MYDBG(("DownloadFileFtp() aborted.")); goto done; } if (bRes || (GetLastError() != ERROR_NO_MORE_FILES)) { MYDBG(("DownloadFileFtp() InternetFindNextFile() returned unexpected result, bRes=%u, GetLastError()=%u.",bRes,bRes?0:GetLastError())); bRes = FALSE; goto done; } InternetCloseHandle(pdaArgs->hReq); if (*(pdaArgs->pbAbort)) { MYDBG(("DownloadFileFtp() aborted.")); goto done; } pdaArgs->dwTotalSize = wfdData.nFileSizeLow; pdaArgs->hReq = FtpOpenFile(pdaArgs->hConn,pszObject,GENERIC_READ,FTP_TRANSFER_TYPE_BINARY,0); if (*(pdaArgs->pbAbort)) { MYDBG(("DownloadFileFtp() aborted.")); goto done; } if (!pdaArgs->hReq) { MYDBG(("DownloadFileFtp() FtpOpenFile() failed, GLE=%u.",GetLastError())); goto done; } pbData = (LPBYTE) CmMalloc(BUFFER_LENGTH); if (!pbData) { goto done; } while (1) { DWORD dwBytesRead; DWORD dwBytesWritten; bRes = InternetReadFile(pdaArgs->hReq,pbData,BUFFER_LENGTH,&dwBytesRead); if (*(pdaArgs->pbAbort)) { MYDBG(("DownloadFileFtp() aborted.")); goto done; } if (!bRes) { MYDBG(("DownloadFileFtp() InternetReadFile() failed, GLE=%u.",GetLastError())); goto done; } if (!dwBytesRead) { break; } bRes = WriteFile(hFile,pbData,dwBytesRead,&dwBytesWritten,NULL); if (*(pdaArgs->pbAbort)) { MYDBG(("DownloadFileFtp() aborted.")); goto done; } if (!bRes) { MYDBG(("DownloadFileFtp() WriteFile() failed, GLE=%u.",GetLastError())); goto done; } if (dwBytesRead != dwBytesWritten) { MYDBG(("DownloadFileFtp() dwBytesRead=%u, dwBytesWritten=%u.",dwBytesRead,dwBytesWritten)); SetLastError(ERROR_DISK_FULL); goto done; } pdaArgs->dwTransferred += dwBytesRead; if (pdaArgs->pfnEvent) { pdaArgs->pfnEvent(pdaArgs->dwTransferred,pdaArgs->dwTotalSize,pdaArgs->pvEventParam); } if (*(pdaArgs->pbAbort)) { MYDBG(("DownloadFileFtp() aborted.")); goto done; } } bRes = TRUE; done: if (pbData) { CmFree(pbData); } if (pdaArgs->hReq) { InternetCloseHandle(pdaArgs->hReq); pdaArgs->hReq = NULL; } if (pdaArgs->hConn) { InternetCloseHandle(pdaArgs->hConn); pdaArgs->hConn = NULL; } if (pdaArgs->hInet) { InternetCloseHandle(pdaArgs->hInet); pdaArgs->hInet = NULL; } if (pszObject) { CmFree(pszObject); } return (bRes); } static BOOL DownloadFileFile(DownloadArgs *pdaArgs, HANDLE hFile) { BOOL bRes = FALSE; HANDLE hInFile = INVALID_HANDLE_VALUE; LPBYTE pbData = NULL; hInFile = CreateFile(pdaArgs->psUrl->lpszUrlPath,GENERIC_READ,FILE_SHARE_READ,NULL,OPEN_EXISTING,FILE_ATTRIBUTE_NORMAL,NULL); if (*(pdaArgs->pbAbort)) { MYDBG(("DownloadFileFile() aborted.")); goto done; } if (hInFile == INVALID_HANDLE_VALUE) { MYDBG(("DownloadFileFile() CreateFile(pszFile=%s) failed, GLE=%u.",pdaArgs->psUrl->lpszUrlPath,GetLastError())); goto done; } pdaArgs->dwTotalSize = GetFileSize(hInFile,NULL); if (*(pdaArgs->pbAbort)) { MYDBG(("DownloadFileFile() aborted.")); goto done; } if (pdaArgs->dwTotalSize == -1) { MYDBG(("DownloadFileFile() GetFileSize() failed, GLE=%u.",GetLastError())); goto done; } pbData = (LPBYTE) CmMalloc(BUFFER_LENGTH); if (!pbData) { goto done; } while (1) { DWORD dwBytesRead; DWORD dwBytesWritten; bRes = ReadFile(hInFile,pbData,BUFFER_LENGTH,&dwBytesRead,NULL); if (*(pdaArgs->pbAbort)) { MYDBG(("DownloadFileFile() aborted.")); goto done; } if (!bRes) { MYDBG(("DownloadFileFile() ReadFile() failed, GLE=%u.",GetLastError())); goto done; } if (!dwBytesRead) { break; } bRes = WriteFile(hFile,pbData,dwBytesRead,&dwBytesWritten,NULL); if (*(pdaArgs->pbAbort)) { MYDBG(("DownloadFileFile() aborted.")); goto done; } if (!bRes) { MYDBG(("DownloadFileFile() WriteFile() failed, GLE=%u.",GetLastError())); goto done; } if (dwBytesRead != dwBytesWritten) { MYDBG(("DownloadFileFile() dwBytesRead=%u, dwBytesWritten=%u.",dwBytesRead,dwBytesWritten)); SetLastError(ERROR_DISK_FULL); goto done; } pdaArgs->dwTransferred += dwBytesWritten; if (pdaArgs->pfnEvent) { pdaArgs->pfnEvent(pdaArgs->dwTransferred,pdaArgs->dwTotalSize,pdaArgs->pvEventParam); } if (*(pdaArgs->pbAbort)) { MYDBG(("DownloadFileFile() aborted.")); goto done; } } bRes = TRUE; done: if (pbData) { CmFree(pbData); } if (hInFile != INVALID_HANDLE_VALUE) { CloseHandle(hInFile); } return (bRes); } static BOOL DownloadFileHttp(DownloadArgs *pdaArgs, HANDLE hFile) { BOOL bRes = FALSE; LPBYTE pbData = NULL; DWORD dwTmpLen; DWORD dwTmpIdx; DWORD dwStatus; LPCTSTR apszContent[] = {c_pszIConnDwnContent,NULL}; LPTSTR pszObject = (LPTSTR) CmMalloc(INTERNET_MAX_PATH_LENGTH + 1); if (NULL == pszObject) { MYDBG(("DownloadFileHttp() aborted.")); goto done; } pdaArgs->dwBubbledUpError = 0; pdaArgs->hInet = InternetOpen(c_pszIConnDwnAgent,INTERNET_OPEN_TYPE_PRECONFIG,NULL,NULL,0); // // Supress auto-dial calls to CM from WININET now that we have a handle // SuppressInetAutoDial(pdaArgs->hInet); if (*(pdaArgs->pbAbort)) { MYDBG(("DownloadFileHttp() aborted.")); goto done; } if (!pdaArgs->hInet) { pdaArgs->dwBubbledUpError = GetLastError(); MYDBG(("DownloadFileHttp() InternetOpen() failed, GLE=%u.", pdaArgs->dwBubbledUpError)); goto done; } pdaArgs->hConn = InternetConnect(pdaArgs->hInet, pdaArgs->psUrl->lpszHostName, pdaArgs->psUrl->nPort, pdaArgs->psUrl->lpszUserName&&*pdaArgs->psUrl->lpszUserName?pdaArgs->psUrl->lpszUserName:NULL, pdaArgs->psUrl->lpszPassword&&*pdaArgs->psUrl->lpszPassword?pdaArgs->psUrl->lpszPassword:NULL, INTERNET_SERVICE_HTTP, 0, 0); if (*(pdaArgs->pbAbort)) { MYDBG(("DownloadFileHttp() aborted.")); goto done; } if (!pdaArgs->hConn) { pdaArgs->dwBubbledUpError = GetLastError(); MYDBG(("DownloadFileHttp() InternetConnect(pszHostName=%s) failed, GLE=%u.", pdaArgs->psUrl->lpszHostName, pdaArgs->dwBubbledUpError)); goto done; } lstrcpy(pszObject,pdaArgs->psUrl->lpszUrlPath); lstrcat(pszObject,pdaArgs->psUrl->lpszExtraInfo); MYDBG(("DownloadFileHttp() - HttpOpenRequest - %s", pszObject)); pdaArgs->hReq = HttpOpenRequest(pdaArgs->hConn, NULL, pszObject, NULL, NULL, apszContent, INTERNET_FLAG_RELOAD|INTERNET_FLAG_DONT_CACHE|(pdaArgs->psUrl->nScheme==INTERNET_SCHEME_HTTPS?INTERNET_FLAG_SECURE:0), 0); if (*(pdaArgs->pbAbort)) { MYDBG(("DownloadFileHttp() aborted.")); goto done; } if (!pdaArgs->hReq) { pdaArgs->dwBubbledUpError = GetLastError(); MYDBG(("DownloadFileHttp() HttpOpenRequest() failed, GLE=%u.", pdaArgs->dwBubbledUpError)); goto done; } bRes = HttpSendRequest(pdaArgs->hReq,NULL,0,NULL,0); if (*(pdaArgs->pbAbort)) { MYDBG(("DownloadFileHttp() aborted.")); goto done; } if (!bRes) { pdaArgs->dwBubbledUpError = GetLastError(); MYDBG(("DownloadFileHttp() HttpSendRequest() failed, GLE=%u.", pdaArgs->dwBubbledUpError)); goto done; } pbData = (LPBYTE) CmMalloc(BUFFER_LENGTH); if (!pbData) { goto done; } while (1) { DWORD dwBytesRead; DWORD dwBytesWritten; bRes = InternetReadFile(pdaArgs->hReq,pbData,BUFFER_LENGTH,&dwBytesRead); if (*(pdaArgs->pbAbort)) { MYDBG(("DownloadFileHttp() aborted.")); goto done; } if (!bRes) { pdaArgs->dwBubbledUpError = GetLastError(); MYDBG(("DownloadFileHttp() InternetReadFile() failed, GLE=%u.", pdaArgs->dwBubbledUpError)); goto done; } if (!dwBytesRead) { break; } bRes = WriteFile(hFile,pbData,dwBytesRead,&dwBytesWritten,NULL); if (*(pdaArgs->pbAbort)) { MYDBG(("DownloadFileHttp() aborted.")); goto done; } if (!bRes) { pdaArgs->dwBubbledUpError = GetLastError(); MYDBG(("DownloadFileHttp() WriteFile() failed, GLE=%u.", pdaArgs->dwBubbledUpError)); goto done; } if (dwBytesRead != dwBytesWritten) { MYDBG(("DownloadFileHttp() dwBytesRead=%u, dwBytesWritten=%u.",dwBytesRead,dwBytesWritten)); SetLastError(ERROR_DISK_FULL); goto done; } if (!pdaArgs->dwTransferred) { dwTmpLen = sizeof(pdaArgs->dwTotalSize); dwTmpIdx = 0; bRes = HttpQueryInfo(pdaArgs->hReq,HTTP_QUERY_FLAG_NUMBER|HTTP_QUERY_CONTENT_LENGTH,&pdaArgs->dwTotalSize,&dwTmpLen,&dwTmpIdx); if (*(pdaArgs->pbAbort)) { MYDBG(("DownloadFileHttp() aborted.")); goto done; } MYDBGTST(!bRes,("DownloadFileHttp() HttpQueryInfo() failed, GLE=%u.",GetLastError())); if (!bRes) { pdaArgs->dwBubbledUpError = GetLastError(); } } pdaArgs->dwTransferred += dwBytesRead; if (pdaArgs->pfnEvent) { pdaArgs->pfnEvent(pdaArgs->dwTransferred,pdaArgs->dwTotalSize,pdaArgs->pvEventParam); } if (*(pdaArgs->pbAbort)) { MYDBG(("DownloadFileHttp() aborted.")); goto done; } } dwTmpLen = sizeof(dwStatus); dwTmpIdx = 0; bRes = HttpQueryInfo(pdaArgs->hReq,HTTP_QUERY_FLAG_NUMBER|HTTP_QUERY_STATUS_CODE,&dwStatus,&dwTmpLen,&dwTmpIdx); if (!bRes) { pdaArgs->dwBubbledUpError = GetLastError(); MYDBG(("DownloadFileHttp() HttpQueryInfo() failed, GLE=%u.", pdaArgs->dwBubbledUpError)); goto done; } switch (dwStatus) { case HTTP_STATUS_OK: break; case HTTP_STATUS_NO_CONTENT: case HTTP_STATUS_BAD_REQUEST: case HTTP_STATUS_NOT_FOUND: case HTTP_STATUS_SERVER_ERROR: default: pdaArgs->dwBubbledUpError = dwStatus; MYDBG(("DownloadFileHttp() HTTP status code = %u.",dwStatus)); bRes = FALSE; SetLastError(ERROR_FILE_NOT_FOUND); goto done; } bRes = TRUE; done: if ((0 == pdaArgs->dwBubbledUpError) && !*(pdaArgs->pbAbort)) { // // If the error value hasn't been set yet, and isn't the Abort case (which // is logged separately) try to get it from GetLastError(). // pdaArgs->dwBubbledUpError = GetLastError(); } if (pbData) { CmFree(pbData); } if (pdaArgs->hReq) { InternetCloseHandle(pdaArgs->hReq); pdaArgs->hReq = NULL; } if (pdaArgs->hConn) { InternetCloseHandle(pdaArgs->hConn); pdaArgs->hConn = NULL; } if (pdaArgs->hInet) { InternetCloseHandle(pdaArgs->hInet); pdaArgs->hInet = NULL; } if (bRes && (pdaArgs->dwTransferred > pdaArgs->dwTotalSize)) { pdaArgs->dwTotalSize = pdaArgs->dwTransferred; } if (pszObject) { CmFree(pszObject); } return (bRes); } static BOOL DownloadFile(DownloadArgs *pdaArgs, HANDLE hFile) { BOOL bRes = FALSE; pdaArgs->psUrl = MyInternetCrackUrl((LPTSTR) pdaArgs->pszUrl,ICU_ESCAPE); if (!pdaArgs->psUrl) { return (NULL); } switch (pdaArgs->psUrl->nScheme) { case INTERNET_SCHEME_FTP: bRes = DownloadFileFtp(pdaArgs,hFile); break; case INTERNET_SCHEME_HTTP: case INTERNET_SCHEME_HTTPS: bRes = DownloadFileHttp(pdaArgs,hFile); break; case INTERNET_SCHEME_FILE: bRes = DownloadFileFile(pdaArgs,hFile); break; default: MYDBG(("DownloadFile() unhandled scheme (%u).",pdaArgs->psUrl->nScheme)); SetLastError(ERROR_INTERNET_UNRECOGNIZED_SCHEME); break; } // useful for logging lstrcpyn(pdaArgs->szHostName, pdaArgs->psUrl->lpszHostName, MAX_PATH); CmFree(pdaArgs->psUrl); pdaArgs->psUrl = NULL; return (bRes); } typedef struct _EventParam { ArgsStruct *pArgs; DWORD dwIdx; } EventParam; static void EventFunc(DWORD dwCompleted, DWORD dwTotal, LPVOID pvParam) { EventParam *pepParam = (EventParam *) pvParam; MYDBG(("EventFunc() dwCompleted=%u, dwTotal=%u.",dwCompleted,dwTotal)); pepParam->pArgs->dwDataCompleted = dwCompleted; pepParam->pArgs->dwDataTotal = dwTotal; PostMessage(pepParam->pArgs->hwndDlg,pepParam->pArgs->nMsgId,etDataReceived,0); } static BOOL ProcessCabinet(DownloadArgs *pdaArgs, DWORD dwAppFlags) { BOOL fRet = TRUE; if (!pdaArgs->bTransferOk) return (TRUE); // If the transfer failed, just leave the install type as itInvalid. { HFDI hfdi; ERF erf; FDICABINETINFO info; BOOL bRes; NotifyArgs naArgs = {dwAppFlags,pdaArgs}; bRes = CreateTempDir(pdaArgs->szCabDir); if (bRes) { hfdi = FDICreate(fdi_alloc,fdi_free,fdi_open,fdi_read,fdi_write,fdi_close,fdi_seek,cpu80386,&erf); MYDBGTST(!hfdi,("ProcessCabinet() FDICreate() failed, fError=%u, erfOper=%u, erfType=%u.",erf.fError,erf.fError?erf.erfOper:0,erf.fError?erf.erfType:0)); if (hfdi) { // Open the suspected cab file CFDIFileFile fff; bRes = fff.CreateFile(pdaArgs->szFile,GENERIC_READ,FILE_SHARE_READ,OPEN_EXISTING,FILE_ATTRIBUTE_NORMAL,0); if (bRes) { // Verify that this is in fact a cabinet file bRes = FDIIsCabinet(hfdi,(INT_PTR) &fff, &info); MYDBGTST(!bRes,("ProcessCabinet() FDIIsCabinet() failed, fError=%u, erfOper=%u, erfType=%u.",erf.fError,erf.fError?erf.erfOper:0,erf.fError?erf.erfType:0)); fff.Close(); if (bRes) { // Do the FDI copy bRes = FDICopy(hfdi,pdaArgs->szFile,TEXT(""),0,(PFNFDINOTIFY)fdi_notify,NULL,&naArgs); if (!bRes) { MYDBG(("ProcessCabinet() FDICopy() failed, fError=%u, erfOper=%u, erfType=%u.",erf.fError,erf.fError?erf.erfOper:0,erf.fError?erf.erfType:0)); //pdaArgs->itType = itInvalid; } } #ifdef EXTENDED_CAB_CONTENTS else { // Not a Cab file, assume exe if (OS_NT) { BOOL bExe = FALSE; DWORD dwExe = 0; // GetBinaryType() is not supported under Win95. bExe = GetBinaryType(pdaArgs->szFile,&dwExe); MYDBG(("ProcessCabinet() GetBinaryType() return %u, dwExe=%u.",bExe,dwExe)); if (!(bExe && ((dwExe & SCS_32BIT_BINARY) || (dwExe & SCS_DOS_BINARY)))) { fRet = FALSE; // if it's not either a win32 or dos exe, then just cleanup and abort goto destroy_fdi; } } MYDBGASSERT(!pdaArgs->rgfpiFileProcessInfo && !pdaArgs->dwNumFilesToProcess); pdaArgs->rgfpiFileProcessInfo = (PFILEPROCESSINFO)CmMalloc(sizeof(FILEPROCESSINFO)); if (!pdaArgs->rgfpiFileProcessInfo) { MYDBG((TEXT("ProcessCabinet: Malloc() failed."))); fRet = FALSE; goto destroy_fdi; } pdaArgs->dwNumFilesToProcess++; pdaArgs->rgfpiFileProcessInfo[0].itType = itExe; pdaArgs->rgfpiFileProcessInfo[0].pszFile = CmStrCpyAlloc(pdaArgs->szFile); pdaArgs->szCabDir[0] = TEXT('\0'); // pdaArgs->itType = itExe; } destroy_fdi: #endif // EXTENDED_CAB_CONTENTS } // Destroy the FDI context bRes = FDIDestroy(hfdi); MYDBGTST(!bRes,("ProcessCabinet() FDIDestroy() failed.")); } } } return fRet; } // // Recursively deletes the contents of a directory(pszDir). Changes the file // attributes from RO to RW if necessary. // static BOOL ZapDir(LPCTSTR pszDir) { HANDLE hFind = NULL; TCHAR szTmp[MAX_PATH+1]; BOOL bRes; // If pszDir format is not appropriate, bail out if (!pszDir || !*pszDir || (lstrlen(pszDir)+2 > sizeof(szTmp)/sizeof(TCHAR)-1)) { SetLastError(ERROR_BAD_PATHNAME); return (FALSE); } lstrcpy(szTmp,pszDir); if (GetLastChar(szTmp) != '\\') { lstrcat(szTmp,TEXT("\\")); } lstrcat(szTmp,TEXT("*")); // Traverse directory WIN32_FIND_DATA wfdData; hFind = FindFirstFile(szTmp,&wfdData); MYDBGTST((hFind==INVALID_HANDLE_VALUE)&&(GetLastError()!=ERROR_FILE_NOT_FOUND)&&(GetLastError()!=ERROR_NO_MORE_FILES)&&(GetLastError()!=ERROR_PATH_NOT_FOUND),("ZapDir() FindFirstFile() failed, GLE=%u.",GetLastError())); if (hFind != INVALID_HANDLE_VALUE) { while (1) { MYDBGTST(lstrlen(pszDir)+lstrlen(wfdData.cFileName)+1 > sizeof(szTmp)/sizeof(TCHAR)-1,("ZapDir() pszDir=%s+cFileName=%s exceeds %u.",pszDir,wfdData.cFileName,sizeof(szTmp)/sizeof(TCHAR)-1)); if (lstrlen(pszDir)+lstrlen(wfdData.cFileName)+1 <= sizeof(szTmp)/sizeof(TCHAR)-1) { if ((lstrcmp(wfdData.cFileName,TEXT(".")) != 0) && (lstrcmp(wfdData.cFileName,TEXT("..")) != 0)) { lstrcpy(szTmp,pszDir); if (GetLastChar(szTmp) != '\\') { lstrcat(szTmp,TEXT("\\")); } lstrcat(szTmp,wfdData.cFileName); // If the file is read-only, attrib writeable so we can delete it if (wfdData.dwFileAttributes & FILE_ATTRIBUTE_READONLY) { bRes = SetFileAttributes(szTmp,wfdData.dwFileAttributes & ~FILE_ATTRIBUTE_READONLY); MYDBGTST(!bRes,("ZapDir() SetFileAttributes(szTmp=%s) failed, GLE=%u.",szTmp,GetLastError())); } // Found a dir entry, recurse down a level if (wfdData.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) { ZapDir(szTmp); } else { bRes = DeleteFile(szTmp); MYDBGTST(!bRes,("ZapDir() DeleteFile(szTmp=%s) failed, GLE=%u.",szTmp,GetLastError())); } } } // Go to next file bRes = FindNextFile(hFind,&wfdData); if (!bRes) { MYDBGTST((GetLastError()!=ERROR_FILE_NOT_FOUND)&&(GetLastError()!=ERROR_NO_MORE_FILES),("ZapDir() FindNextFile() failed, GLE=%u.",GetLastError())); break; } } bRes = FindClose(hFind); MYDBGTST(!bRes,("ZapDir() FindClose() failed, GLE=%u.",GetLastError())); } // Now that the files have been removed, delete the directory bRes = RemoveDirectory(pszDir); MYDBGTST(!bRes&&(GetLastError()!=ERROR_PATH_NOT_FOUND),("ZapDir() RemoveDirectory(pszDir=%s) failed, GLE=%u.",pszDir,GetLastError())); return (bRes); } #ifdef EXTENDED_CAB_CONTENTS static long MyMsgWaitDlg(HWND hwndMsg, DWORD dwHandles, HANDLE *phHandles, DWORD dwTimeout) { long lRes; if (hwndMsg) { HCURSOR hPrev; MSG msg; hPrev = SetCursor(LoadCursor(NULL,IDC_WAIT)); ShowCursor(TRUE); while (1) { lRes = MsgWaitForMultipleObjects(dwHandles,phHandles,FALSE,dwTimeout,QS_ALLINPUT); if (lRes == WAIT_TIMEOUT) { break; } if (lRes != (long) (WAIT_OBJECT_0+dwHandles)) { MYDBGTST(-1 == lRes,("MyMsgWaitDlg() MsgWaitForMultipleObjects() failed, GLE=%u.",GetLastError())); break; } PeekMessage(&msg,hwndMsg,0,0,PM_NOREMOVE); } ShowCursor(FALSE); SetCursor(hPrev); } else { lRes = WaitForMultipleObjects(dwHandles,phHandles,FALSE,dwTimeout); } return (lRes); } #endif // EXTENDED_CAB_CONTENTS // // Executes installation of phone book update based upon download file // static BOOL DoInstall(ArgsStruct *pArgs, HWND hwndParent, DWORD dwAppFlags) { DWORD dwIdx; // If no install, we are done if (dwAppFlags & AF_NO_INSTALL) { return (TRUE); } // For each arg, handle installation for (dwIdx=0;dwIdxdwArgsCnt;dwIdx++) { DownloadArgs *pdaArgs; UINT i; BOOL bInstallOk = FALSE; BOOL bRes = TRUE; pdaArgs = pArgs->pdaArgs + dwIdx; pdaArgs->dwBubbledUpError = 0; #ifdef EXTENDED_CAB_CONTENTS BOOL fCabDirRenamed = FALSE; // rename the dir the downloaded file is not an EXE if (pdaArgs->szCabDir[0]) { ZapDir(c_pszDirName); bRes = MoveFile(pdaArgs->szCabDir,c_pszDirName); MYDBGTST(!bRes,("DoInstall() MoveFile(szCabDir=%s,c_pszDirName) failed, GLE=%u.",pdaArgs->szCabDir,GetLastError())); if (bRes) { fCabDirRenamed = TRUE; } } #endif // EXTENDED_CAB_CONTENTS // Only perform if the rename worked. if (bRes) { for (i=0; idwNumFilesToProcess; i++) { // // Reset install flag for each file that is processed, // otherwise a single success will cause us to interpret // the entire install as successful. #5887 // bInstallOk = FALSE; switch (pdaArgs->rgfpiFileProcessInfo[i].itType) { #ifdef EXTENDED_CAB_CONTENTS case itExeInCab: case itExe: { STARTUPINFO siInfo; PROCESS_INFORMATION piInfo; ZeroMemory(&siInfo,sizeof(siInfo)); ZeroMemory(&piInfo,sizeof(piInfo)); siInfo.cb = sizeof(siInfo); bRes = CreateProcess(pdaArgs->rgfpiFileProcessInfo[i].pszFile, NULL,NULL,NULL,FALSE,0,NULL,NULL,&siInfo,&piInfo); MYDBGTST(!bRes,("DoInstall() CreateProcess(pszExe=%s) failed, GLE=%u.",pdaArgs->rgfpiFileProcessInfo[i].pszFile,GetLastError())); // If CreateProcess worked, wait for process to terminate before continuing if (bRes) { CloseHandle(piInfo.hThread); MyMsgWaitDlg(hwndParent,1,&piInfo.hProcess,INFINITE); CloseHandle(piInfo.hProcess); bInstallOk = TRUE; } break; } case itInfInCab: // .INF file { TCHAR szCabDir[MAX_PATH+1]; DWORD dwRes; HRESULT hRes; ZeroMemory(szCabDir,sizeof(szCabDir)); dwRes = GetCurrentDirectory(sizeof(szCabDir)/sizeof(TCHAR)-1,szCabDir); MYDBGTST(!dwRes,("DoInstall() GetCurrentDirectory() failed, GLE=%u.",GetLastError())); if (GetLastChar(szCabDir) != '\\') { lstrcat(szCabDir,TEXT("\\")); } lstrcat(szCabDir,c_pszDirName); // Since RunSetupCommand() has problems with long file names, we'll // convert the path just to be sure. dwRes = GetShortPathName(szCabDir,szCabDir,sizeof(szCabDir)/sizeof(TCHAR)-1); MYDBGTST(!dwRes,("DoInstall() GetShortPathName() failed, GLE=%u.",GetLastError())); // TBD: Initialize pArgs->szInstallTitle from service file instead of from resource. LPTSTR pszTmp = CmFmtMsg(pArgs->hInst,IDMSG_PBTITLE); lstrcpy(pArgs->szInstallTitle,pszTmp); CmFree(pszTmp); hRes = MyRunSetupCommand(pArgs, hwndParent, c_pszInfInDir, NULL, szCabDir, pArgs->szInstallTitle, NULL, RSC_FLAG_INF, NULL); if (!HRESULT_SEVERITY(hRes)) { bInstallOk = TRUE; } break; } #endif // EXTENDED_CAB_CONTENTS case itPbdInCab: // Delta phonebook file // if the CAB contains an EXE or an INF, then we don't do PBD if (pdaArgs->fContainsExeOrInf) { continue; } if (pdaArgs->pszCMSFile) { HRESULT hRes; DWORD_PTR dwPb; // Update the Phonebook using API calls hRes = PhoneBookLoad(pdaArgs->pszCMSFile, &dwPb); MYDBGTST(hRes!=ERROR_SUCCESS,("DoInstall() PhoneBookLoad(pszCMSFile=%s) failed, GLE=%u.", pdaArgs->pszCMSFile, hRes)); if (hRes == ERROR_SUCCESS) { #ifdef EXTENDED_CAB_CONTENTS hRes = PhoneBookMergeChanges(dwPb, c_pszPbdInDir); #else // // Build path to delta file, to be passed to phonebook merge // TCHAR szPbd[MAX_PATH+1]; lstrcpy(szPbd, pdaArgs->szCabDir); lstrcat(szPbd, TEXT("\\")); lstrcat(szPbd, c_pszPbdFile); hRes = PhoneBookMergeChanges(dwPb, szPbd); #endif // EXTENDED_CAB_CONTENTS MYDBGTST(hRes!=ERROR_SUCCESS,("DoInstall() PhoneBookMergeChanges() failed, GLE=%u.",hRes)); if (hRes == ERROR_SUCCESS) { bInstallOk = TRUE; } else { pdaArgs->dwBubbledUpError = hRes; } hRes = PhoneBookUnload(dwPb); MYDBGTST(hRes!=ERROR_SUCCESS,("DoInstall() PhoneBookUnload() failed, GLE=%u.",hRes)); } if (!bInstallOk && !(dwAppFlags & AF_NO_VER)) { // We currently zap the version string on any failure. This should cause // the phone book to get completely update the next time around. WritePrivateProfileString(c_pszCmSection, c_pszVersion, TEXT(""), pdaArgs->pszCMSFile); } } break; case itPbkInCab: // Phone book file { TCHAR szPbk[MAX_PATH+1]; // if the CAB contains an EXE or an INF, then we don't do PBK if (pdaArgs->fContainsExeOrInf) { continue; } #ifdef EXTENDED_CAB_CONTENTS lstrcpy(szPbk, c_pszDirName); #else // EXTENDED_CAB_CONTENTS lstrcpy(szPbk, pdaArgs->szCabDir); #endif lstrcat(szPbk, TEXT("\\")); lstrcat(szPbk, pdaArgs->rgfpiFileProcessInfo[i].pszFile); // Try to copy the phonebook file directly if (!CopyFile(szPbk, pdaArgs->pszPbkFile, FALSE)) { pdaArgs->dwBubbledUpError = GetLastError(); MYDBG((TEXT("DoInstall() itPbkInCab, CopyFile() failed, GLE=%u."), pdaArgs->dwBubbledUpError)); } else { bInstallOk = TRUE; } break; } case itPbrInCab: // Region file { TCHAR szPbr[MAX_PATH+1]; // if the CAB contains an EXE or an INF, then we don't do PBD if (pdaArgs->fContainsExeOrInf) { continue; } #ifdef EXTENDED_CAB_CONTENTS lstrcpy(szPbr, c_pszDirName); #else // EXTENDED_CAB_CONTENTS lstrcpy(szPbr, pdaArgs->szCabDir); #endif lstrcat(szPbr, TEXT("\\")); lstrcat(szPbr, pdaArgs->rgfpiFileProcessInfo[i].pszFile); // Try to copy the region file directly if (!CopyFile(szPbr, pdaArgs->pszPbrFile, FALSE)) { MYDBG((TEXT("DoInstall() itPbrInCab, CopyFile() failed, GLE=%u."), GetLastError())); } else { bInstallOk = TRUE; } break; } #ifdef EXTENDED_CAB_CONTENTS case itShlInCab: // Shell execute target { TCHAR szShl[MAX_PATH+1]; lstrcpy(szShl,c_pszDirName); lstrcat(szShl,TEXT("\\")); lstrcat(szShl,pdaArgs->rgfpiFileProcessInfo[i].pszFile); SHELLEXECUTEINFO seiInfo; ZeroMemory(&seiInfo,sizeof(seiInfo)); seiInfo.cbSize = sizeof(seiInfo); seiInfo.fMask = SEE_MASK_NOCLOSEPROCESS; seiInfo.hwnd = hwndParent; seiInfo.lpFile = szShl; seiInfo.nShow = SW_SHOWNORMAL; bRes = ShellExecuteEx(&seiInfo); MYDBGTST(!bRes,("DoInstall() ShellExecuteEx(szShl=%s) failed, GLE=%u.",szShl,GetLastError())); // If it worked, wait for termination if (bRes) { MyMsgWaitDlg(hwndParent,1,&seiInfo.hProcess,INFINITE); CloseHandle(seiInfo.hProcess); bInstallOk = TRUE; } break; } // case itShlInCab #endif // EXTENDED_CAB_CONTENTS } // switch (pdaArgs->rgfpiFileProcessInfo[i].itType) } // for (i=0; idwNumFilesToProcess; i++) } // if (bRes) #ifdef EXTENDED_CAB_CONTENTS if (fCabDirRenamed) { // Copy the Cab directory back to tmp name bRes = MoveFile(c_pszDirName,pdaArgs->szCabDir); MYDBGTST(!bRes,("DoInstall() MoveFile(c_pszDirName,szCabDir=%s) failed, GLE=%u.",pdaArgs->szCabDir,GetLastError())); } #endif // EXTENDED_CAB_CONTENTS // Update version info in CMS if (bInstallOk && !(dwAppFlags & AF_NO_VER) && pdaArgs->pszVerNew && pdaArgs->pszCMSFile) { WritePrivateProfileString(c_pszCmSection, c_pszVersion, pdaArgs->pszVerNew, pdaArgs->pszCMSFile); } } return (TRUE); } //+---------------------------------------------------------------------------- // // Func: CheckFileForPBSErrors // // Desc: Scan the downloaded file for PBS errors // // Args: [hFile] - handle to the already opened tempfile // // Return: LONG (0 = no download needed, +ve = PBS error code, -1 = other error) // // Notes: // // History: 14-Apr-2001 SumitC Created // //----------------------------------------------------------------------------- static LONG CheckFileForPBSErrors(HANDLE hFile) { LONG lRet = -1; MYDBGASSERT(hFile); if (hFile && (INVALID_HANDLE_VALUE != hFile)) { TCHAR szFirstThree[4] = {0}; DWORD dwBytesRead; SetFilePointer(hFile, 0, NULL, FILE_BEGIN); if (ReadFile(hFile, szFirstThree, 3, &dwBytesRead, NULL) && (dwBytesRead >= 3)) { if (0 == lstrcmpi(szFirstThree, TEXT("204"))) { // // "204" => no download necessary // lRet = 0; } else if (0 != lstrcmpi(szFirstThree, TEXT("MSC"))) { // // "MSC" => we have a phonebook. If *not* MSC, get the error number // LONG lVal = 0; for (int i = 0 ; i < 3; ++i) { if ((szFirstThree[i] >= TEXT('0')) && (szFirstThree[i] <= TEXT('9'))) { lVal = (lVal *10) + (szFirstThree[i] - TEXT('0')); } else { break; } } if (lVal) { lRet = lVal; } } } } return lRet; } //static unsigned __stdcall InetThreadFunc(void *pvParam) DWORD WINAPI InetThreadFunc(void *pvParam) { EventParam epParam = {(ArgsStruct *) pvParam,0}; BOOL bRes = FALSE; BOOL bSuccess = FALSE; DWORD dwFileIdx; HANDLE hFile = INVALID_HANDLE_VALUE; RASCONN RasConn, *prgRasConn; DWORD cb, cConnections; PVOID pRasEnumMem = NULL; // Wait for delay period to expire DWORD dwRes = WaitForSingleObject(epParam.pArgs->ahHandles[1], epParam.pArgs->dwDownloadDelay); MYDBGTST(dwRes==WAIT_FAILED,("InetThreadFunc() WaitForMultipleObjects() failed, GLE=%u.",GetLastError())); // // Check if connection is still valid before starting the download // on NT5 we depend on setting the don't autodial flag for InternetSetOptions() // Unless, of course, the /LAN flag was specified in which case we don't want // this connection check to happen because the caller is telling us this is happening // over a LAN connection. // if (!(epParam.pArgs->dwAppFlags & AF_LAN)) { cb = sizeof(RasConn); prgRasConn = &RasConn; prgRasConn->dwSize = cb; dwRes = RasEnumConnections(prgRasConn, &cb, &cConnections); if (dwRes == ERROR_BUFFER_TOO_SMALL) { pRasEnumMem = CmMalloc(cb); if (pRasEnumMem == NULL) { MYDBG(("InetThreadFunc() aborted. Out of memory")); epParam.pArgs->bAbort = TRUE; goto done; } prgRasConn = (RASCONN *) pRasEnumMem; prgRasConn[0].dwSize = sizeof(RASCONN); dwRes = RasEnumConnections(prgRasConn, &cb, &cConnections); } // // Iterate through connections to check if our's is active // if there is a problem getting this list we don't abort? // if (dwRes == ERROR_SUCCESS) { DWORD iConn; BOOL fConnected = FALSE; for (iConn = 0; iConn < cConnections; iConn++) { if (lstrcmpi(epParam.pArgs->pszServiceName, prgRasConn[iConn].szEntryName) == 0) { fConnected = TRUE; break; } } if (fConnected == FALSE) { MYDBG(("InetThreadFunc() aborted. No connection")); epParam.pArgs->bAbort = TRUE; goto done; } } } if (epParam.pArgs->bAbort) { MYDBG(("InetThreadFunc() aborted.")); } for (epParam.dwIdx=0;epParam.dwIdxdwArgsCnt;epParam.dwIdx++) { int i = 0; UINT uReturn = 0; DownloadArgs * pDA = &(epParam.pArgs->pdaArgs[epParam.dwIdx]); while (i++ < 3) { // // On Win9x and/or slow machines, GetTempFileName sometimes fails, // and cmdl32 errors all the way out. In the debugger, if the call // is retried, it will invariably succeed. This sounds like a timing // issue with the OS. We do 3 tries, separated by a 1-second sleep. // uReturn = GetTempFileName(TEXT("."), TEXT("000"), 0, epParam.pArgs->pdaArgs[epParam.dwIdx].szFile); if (uReturn) { break; } Sleep(1000); } if (0 == uReturn) { DWORD dwError = GetLastError(); MYDBG(("InetThreadFunc() GetTempFileName failed, GLE=%u.", dwError)); epParam.pArgs->Log.Log(PB_DOWNLOAD_FAILURE, dwError, pDA->pszPhoneBookName, pDA->szHostName); goto done; } else { hFile = CreateFile(epParam.pArgs->pdaArgs[epParam.dwIdx].szFile, GENERIC_READ | GENERIC_WRITE, FILE_SHARE_READ, NULL, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL); if (INVALID_HANDLE_VALUE == hFile) { DWORD dwError = GetLastError(); MYDBG(("InetThreadFunc() CreateFile(szFile=%s) failed, GLE=%u.", epParam.pArgs->pdaArgs[epParam.dwIdx].szFile, dwError)); epParam.pArgs->Log.Log(PB_DOWNLOAD_FAILURE, dwError, pDA->pszPhoneBookName, pDA->szHostName); goto done; } } // // Check to make sure we haven't been aborted // if (epParam.pArgs->bAbort) { MYDBG(("InetThreadFunc() aborted.")); goto done; } // We have a valid tmp file name, download phonebook update into it. epParam.pArgs->pdaArgs[epParam.dwIdx].pfnEvent = EventFunc; epParam.pArgs->pdaArgs[epParam.dwIdx].pvEventParam = &epParam; epParam.pArgs->pdaArgs[epParam.dwIdx].pbAbort = &epParam.pArgs->bAbort; PostMessage(epParam.pArgs->hwndDlg,epParam.pArgs->nMsgId,etDataBegin,0); bRes = DownloadFile(&epParam.pArgs->pdaArgs[epParam.dwIdx],hFile); FlushFileBuffers(hFile); LONG lResult = CheckFileForPBSErrors(hFile); CloseHandle(hFile); hFile = INVALID_HANDLE_VALUE; if (epParam.pArgs->bAbort) { MYDBG(("InetThreadFunc() aborted.")); goto done; } PostMessage(epParam.pArgs->hwndDlg,epParam.pArgs->nMsgId,etDataEnd,0); #if 0 /* if (!bRes && !epParam.dwIdx) { // TBD: Currently, a failure to update the primary phonebook prevents any // secondary phonebooks from being updated. But a failure to update one // secondary does not prevent other secondaries from being updated. goto done; } */ #endif // // If download failed (either cpserver thinks that we don't need to update // the phone book or the phone book doesn't exist on the server), just keep // on downloading the phone books for other profiles. // if (!bRes) { if (lResult < 0) { // // we parsed the downloaded file and got some error other than // the 2 cases handled below // epParam.pArgs->Log.Log(PB_DOWNLOAD_FAILURE, pDA->dwBubbledUpError, pDA->pszPhoneBookName, pDA->szHostName); } else { // // we contacted the web server successfully, and... // epParam.pArgs->Log.Log(PB_DOWNLOAD_SUCCESS, pDA->pszPhoneBookName, pDA->pszVerCurr, pDA->szHostName); if (lResult > 0) { // // ... (case 1) the web server or PBS reported an error // epParam.pArgs->Log.Log(PB_UPDATE_FAILURE_PBS, lResult, pDA->pszPhoneBookName); } else { // // ... (case 2) PBS said no download necessary // MYDBGASSERT(0 == lResult); LPTSTR pszText = CmFmtMsg(epParam.pArgs->hInst, IDMSG_LOG_NO_UPDATE_REQUIRED); epParam.pArgs->Log.Log(PB_UPDATE_SUCCESS, SAFE_LOG_ARG(pszText), pDA->pszPhoneBookName, pDA->pszVerCurr, pDA->pszVerCurr, // for no-download case, these are the same pDA->szHostName); CmFree(pszText); } } continue; } if (bRes && epParam.pArgs->pdaArgs[epParam.dwIdx].dwTotalSize) { epParam.pArgs->pdaArgs[epParam.dwIdx].bTransferOk = TRUE; } if (epParam.pArgs->bAbort) { MYDBG(("InetThreadFunc() aborted.")); goto done; } // // Phonebook download was successful, log this and proceed to unpack/update // epParam.pArgs->Log.Log(PB_DOWNLOAD_SUCCESS, pDA->pszPhoneBookName, pDA->pszVerCurr, pDA->szHostName); bRes = ProcessCabinet(&epParam.pArgs->pdaArgs[epParam.dwIdx],epParam.pArgs->dwAppFlags); if (bRes && (NULL == pDA->rgfpiFileProcessInfo)) { MYDBGASSERT(FALSE); // strange case. set error here so that we log something sensible later pDA->dwBubbledUpError = ERROR_INVALID_DATA; // yes. we know this is lame. } if (bRes && pDA->rgfpiFileProcessInfo) { // // figure out if this was a full or delta download // BOOL fFoundFullCab = FALSE; BOOL fFoundDeltaCab = FALSE; for (DWORD dwFileIndex = 0; dwFileIndex < pDA->dwNumFilesToProcess; ++dwFileIndex) { switch (pDA->rgfpiFileProcessInfo[dwFileIndex].itType) { case itPbkInCab: fFoundFullCab = TRUE; break; case itPbdInCab: fFoundDeltaCab = TRUE; break; } } if (fFoundFullCab ^ fFoundDeltaCab) { // the cab should contain one or the other, but not both LPTSTR pszTemp = NULL; if (fFoundFullCab) { pszTemp = CmFmtMsg(epParam.pArgs->hInst, IDMSG_LOG_FULL_UPDATE); } else if (fFoundDeltaCab) { pszTemp = CmFmtMsg(epParam.pArgs->hInst, IDMSG_LOG_DELTA_UPDATE); } MYDBGASSERT(pszTemp); if (pszTemp) { epParam.pArgs->Log.Log(PB_UPDATE_SUCCESS, SAFE_LOG_ARG(pszTemp), pDA->pszPhoneBookName, pDA->pszVerCurr, pDA->pszVerNew, pDA->szHostName); CmFree(pszTemp); } } else { // strange cab (or at least, doesn't contain what we expected) // both full and delta CMASSERTMSG(!(fFoundFullCab && fFoundDeltaCab), TEXT("This cab has both full and delta phonebooks!!")); // neither full nor delta CMASSERTMSG(! (!fFoundFullCab && !fFoundDeltaCab), TEXT("This cab has neither a full nor a delta phonebook!!")); pDA->dwBubbledUpError = ERROR_BAD_FORMAT; epParam.pArgs->Log.Log(PB_UPDATE_FAILURE_CMPBK, pDA->dwBubbledUpError, pDA->pszPhoneBookName); } } else { epParam.pArgs->Log.Log(PB_UPDATE_FAILURE_CMPBK, pDA->dwBubbledUpError, pDA->pszPhoneBookName); } if (!bRes) { goto done; } bSuccess = TRUE; // We have at least one successful download #5635 #if 0 /* if (!epParam.dwIdx && epParam.pArgs->pdaArgs[epParam.dwIdx].dwTotalSize && (epParam.pArgs->pdaArgs[epParam.dwIdx].itType != itInvalid) && (epParam.pArgs->pdaArgs[epParam.dwIdx].itType != itPbdInCab)) { // TBD: Currently, if the primary service is being updated in any way other than // a simple phone number delta, we do *not* update any of the secondary phonebooks // this time around. break; } */ #endif } // // If no download attempts succeeded, bail completely // if (!bSuccess) { MYDBG(("InetThreadFunc() no download success.")); goto done; } if (epParam.pArgs->bAbort) { MYDBG(("InetThreadFunc() aborted.")); goto done; } #ifdef EXTENDED_CAB_CONTENTS // At this point, all of the downloads are complete. We post a message to the main // window, asking it to call WinVerifyTrust() as appropriate for all of the downloaded // blobs. The main window will post the event back to us when it is done. PostMessage(epParam.pArgs->hwndDlg,epParam.pArgs->nMsgId,etVerifyTrust,0); dwRes = WaitForSingleObject(epParam.pArgs->ahHandles[IDX_EVENT_HANDLE],INFINITE); if (epParam.pArgs->bAbort) { MYDBG(("InetThreadFunc() aborted.")); goto done; } #endif // EXTENDED_CAB_CONTENTS // At this point, everything is all set - we're ready to perform the actual installs. So // send a message to the main window telling it to do the installs, and wait until it // signals success back. PostMessage(epParam.pArgs->hwndDlg,epParam.pArgs->nMsgId,etInstall,0); dwRes = WaitForSingleObject(epParam.pArgs->ahHandles[IDX_EVENT_HANDLE],INFINITE); if (epParam.pArgs->bAbort) { MYDBG(("InetThreadFunc() aborted.")); goto done; } SetLastError(ERROR_SUCCESS); done: if (epParam.pArgs->bAbort) { epParam.pArgs->Log.Log(PB_ABORTED); } if (hFile != INVALID_HANDLE_VALUE) { CloseHandle(hFile); } if (pRasEnumMem != NULL) { CmFree(pRasEnumMem); } PostMessage(epParam.pArgs->hwndDlg,epParam.pArgs->nMsgId,etDone,0); return (GetLastError()); } // // The main dlg // BOOL CALLBACK MainDlgProc(HWND hwndDlg, UINT uMsg, WPARAM wParam, LPARAM lParam) { ArgsStruct *pArgs = (ArgsStruct *) GetWindowLongPtr(hwndDlg,DWLP_USER); static UINT uTimerID = 0; switch (uMsg) { case WM_INITDIALOG: { RECT rDlg; RECT rWorkArea; DWORD dwThreadId = 0; SetWindowLongPtr(hwndDlg,DWLP_USER,(LONG_PTR)lParam); pArgs = (ArgsStruct *) lParam; pArgs->hwndDlg = hwndDlg; MYDBG(("MainDlgProc() - WM_INITDIALOG.")); // Get the dialog rect and the available work area. GetWindowRect(hwndDlg,&rDlg); if (SystemParametersInfoA(SPI_GETWORKAREA,0,&rWorkArea,0)) { // Move the dialog to the bottom right of the screen MoveWindow(hwndDlg, rWorkArea.left + ((rWorkArea.right-rWorkArea.left) - (rDlg.right-rDlg.left) - GetSystemMetrics(SM_CXBORDER)), rWorkArea.top + ((rWorkArea.bottom-rWorkArea.top) - (rDlg.bottom-rDlg.top) - GetSystemMetrics(SM_CYBORDER)), rDlg.right-rDlg.left, rDlg.bottom-rDlg.top, FALSE); } // Get update message from ini if (pArgs->pszProfile) { TCHAR szTmp1[MAX_PATH+1]; TCHAR szTmp2[MAX_PATH+1]; GetDlgItemText(hwndDlg,IDC_MAIN_MESSAGE,szTmp2,sizeof(szTmp2)/sizeof(TCHAR)-1); GetPrivateProfileString(c_pszCmSection, c_pszCmEntryPbUpdateMessage, szTmp2, szTmp1, sizeof(szTmp1)/sizeof(TCHAR)-1, pArgs->pdaArgs->pszCMSFile); SetDlgItemText(hwndDlg,IDC_MAIN_MESSAGE,szTmp1); } // Spin download thread (InetThreadFunc) pArgs->dwHandles = sizeof(pArgs->ahHandles) / sizeof(pArgs->ahHandles[0]); pArgs->ahHandles[IDX_EVENT_HANDLE] = CreateEvent(NULL,FALSE,FALSE,NULL); if (!pArgs->ahHandles[IDX_EVENT_HANDLE]) { MYDBG(("MainDlgProc() CreateEvent() failed, GLE=%u.",GetLastError())); EndDialog(hwndDlg,FALSE); } //pArgs->ahHandles[IDX_INETTHREAD_HANDLE] = (HANDLE) _beginthreadex(NULL,0,InetThreadFunc,pArgs,0,&nThreadId); pArgs->ahHandles[IDX_INETTHREAD_HANDLE] = (HANDLE) CreateThread(0,0,InetThreadFunc,pArgs,0,&dwThreadId); if (!pArgs->ahHandles[IDX_INETTHREAD_HANDLE]) { MYDBG(("MainDlgProc() CreateThread() failed, GLE=%u.",GetLastError())); EndDialog(hwndDlg,FALSE); } SetFocus((HWND) wParam); return (FALSE); } case WM_WINDOWPOSCHANGING: // Until we set pArgs->bShow to TRUE, we prevent the window from // ever being shown. if (!pArgs->bShow && (((LPWINDOWPOS) lParam)->flags & SWP_SHOWWINDOW)) { ((LPWINDOWPOS) lParam)->flags &= ~SWP_SHOWWINDOW; ((LPWINDOWPOS) lParam)->flags |= SWP_HIDEWINDOW; } break; case WM_INITMENUPOPUP: { HMENU hMenu = (HMENU) wParam; // UINT nPos = (UINT) LOWORD(lParam); BOOL fSysMenu = (BOOL) HIWORD(lParam); if (fSysMenu) { EnableMenuItem(hMenu,SC_MAXIMIZE,MF_BYCOMMAND|MF_GRAYED); } break; } case WM_DESTROY: { // Kill timer if we have one if (uTimerID) { KillTimer(hwndDlg, uTimerID); } // If we have args, set bAbort true if (pArgs) { pArgs->bAbort = TRUE; } else { MYDBGASSERT(FALSE); // should not happen if dailog loads } break; } default: break; } // Check for custom messages if (pArgs && (uMsg == pArgs->nMsgId)) { LPTSTR pszMsg; MYDBG(("Custom arg - %u received.", (DWORD) wParam)); // // Setup FirstEvent time for tracking delays // if (!pArgs->dwFirstEventTime) { pArgs->dwFirstEventTime = GetTickCount(); MYDBG(("Setting FirstEventTime to %u.", pArgs->dwFirstEventTime)); } if (!pArgs->bShow && (GetTickCount() - pArgs->dwFirstEventTime > pArgs->dwHideDelay)) { MYDBG(("HideDelay of %u expired, displaying dlg now.", pArgs->dwHideDelay)); pArgs->bShow = TRUE; ShowWindow(hwndDlg,SW_SHOWNA); } // Handle specific message switch (wParam) { case etDataBegin: pArgs->dwDataStepSize = 0; SendDlgItemMessage(hwndDlg,IDC_MAIN_PROGRESS,PBM_SETRANGE,0,MAKELPARAM(0,100)); SendDlgItemMessage(hwndDlg,IDC_MAIN_PROGRESS,PBM_SETPOS,0,0); pszMsg = CmFmtMsg(pArgs->hInst,IDMSG_PERCENT_COMPLETE,0); SetWindowText(hwndDlg,pszMsg); CmFree(pszMsg); break; case etDataReceived: if (pArgs->dwDataTotal) // PREVENT DIVIDE BY ZERO { if (!pArgs->dwDataStepSize ) { // // Progress controls have a limit to there maximum // integral value so calculate an aproximate step size. // // pArgs->dwDataStepSize = (pArgs->dwDataTotal / 65535) + 1; SendDlgItemMessage(hwndDlg, IDC_MAIN_PROGRESS, PBM_SETRANGE, 0, MAKELPARAM(0,pArgs->dwDataTotal/pArgs->dwDataStepSize)); } if (pArgs->dwDataStepSize) { SendDlgItemMessage(hwndDlg,IDC_MAIN_PROGRESS,PBM_SETPOS,(WORD) (pArgs->dwDataCompleted / pArgs->dwDataStepSize),0); pszMsg = CmFmtMsg(pArgs->hInst,IDMSG_PERCENT_COMPLETE,(pArgs->dwDataCompleted*100)/pArgs->dwDataTotal); SetWindowText(hwndDlg,pszMsg); CmFree(pszMsg); } } break; case etDataEnd: pszMsg = CmFmtMsg(pArgs->hInst,IDMSG_PERCENT_COMPLETE,100); SetWindowText(hwndDlg,pszMsg); CmFree(pszMsg); break; #ifdef EXTENDED_CAB_CONTENTS case etVerifyTrust: { DWORD dwIdx; UINT i; for (dwIdx=0;dwIdxdwArgsCnt;dwIdx++) { DownloadArgs *pdaArgs; LONG lRes = ERROR_INVALID_PARAMETER; WCHAR szPath[MAX_PATH+1]; GUID gCabSubjectType = WIN_TRUST_SUBJTYPE_CABINET; GUID gExeSubjectType = WIN_TRUST_SUBJTYPE_PE_IMAGE; WIN_TRUST_SUBJECT_FILE sSubject = {INVALID_HANDLE_VALUE,szPath}; GUID gActionID = WIN_SPUB_ACTION_PUBLISHED_SOFTWARE; WIN_TRUST_ACTDATA_CONTEXT_WITH_SUBJECT sActionData = {NULL,&gCabSubjectType,&sSubject}; int iRes; BOOL fStandaloneExe; pdaArgs = pArgs->pdaArgs + dwIdx; ZeroMemory(szPath,sizeof(szPath)); pszMsg = CmFmtMsg(pArgs->hInst,IDMSG_PBTITLEMSG); iRes = MultiByteToWideChar(CP_OEMCP,0,pszMsg,-1,szPath,sizeof(szPath)/sizeof(WCHAR)-1); MYDBGTST(!iRes,("MainDlgProc() MultiByteToWideChar() failed, GLE=%u.",GetLastError())); CmFree(pszMsg); fStandaloneExe = (pdaArgs->dwNumFilesToProcess == 1 && pdaArgs->rgfpiFileProcessInfo[0].itType == itExe); if (fStandaloneExe || pdaArgs->fContainsExeOrInf || pdaArgs->fContainsShl) { HRESULT hRes; if (fStandaloneExe) sActionData.SubjectType = &gExeSubjectType; #ifdef DEBUG if (!(pArgs->dwAppFlags & AF_NO_VERIFY)) { #endif sSubject.hFile = CreateFile(pdaArgs->szFile, GENERIC_READ, FILE_SHARE_READ, NULL, OPEN_EXISTING, 0, NULL); MYDBGTST(sSubject.hFile==INVALID_HANDLE_VALUE,("MainDlgProc() CreateFile(szFile=%s) failed, GLE=%u.",pdaArgs->szFile,GetLastError())); if (sSubject.hFile != INVALID_HANDLE_VALUE) { // // Now that we know we're going to do something, show the window #6335 // pArgs->bShow = TRUE; ShowWindow(hwndDlg,SW_SHOWNA); // // Perform verification // hRes = WinVerifyTrust(hwndDlg,&gActionID,&sActionData); if (!HRESULT_SEVERITY(hRes)) { lRes = ERROR_SUCCESS; } else { MYDBG(("MainDlgProc() WinVerifyTrust(pszFile=%s) failed, GLE=%u.",pdaArgs->szFile,hRes)); lRes = HRESULT_CODE(hRes); } CloseHandle(sSubject.hFile); } #ifdef DEBUG } else { lRes = ERROR_SUCCESS; } #endif } else // we don't do signing of other files lRes = ERROR_SUCCESS; if (lRes != ERROR_SUCCESS) { // pdaArgs->itType = itInvalid; pArgs->bAbort = TRUE; } } #ifdef EXTENDED_CAB_CONTENTS pArgs->bVerified = TRUE; #endif // EXTENDED_CAB_CONTENTS ShowWindow(hwndDlg,SW_HIDE); SetEvent(pArgs->ahHandles[IDX_EVENT_HANDLE]); break; } #endif // EXTENDED_CAB_CONTENTS case etInstall: { CNamedMutex PbMutex; // // Hide the window, we're ready to install // pArgs->bShow = TRUE; ShowWindow(hwndDlg,SW_HIDE); // // Grab the mutex before we begin PB updates. If it fails then // abort the install, we'll try again next time the user connects. if (PbMutex.Lock(c_pszCMPhoneBookMutex)) { DoInstall(pArgs,hwndDlg,pArgs->dwAppFlags); PbMutex.Unlock(); } SetEvent(pArgs->ahHandles[IDX_EVENT_HANDLE]); ShowWindow(hwndDlg,SW_HIDE); break; } case etDone: EndDialog(hwndDlg,TRUE); break; case etICMTerm: #ifdef EXTENDED_CAB_CONTENTS if (!pArgs->bVerified) { pArgs->bAbort = TRUE; EndDialog(hwndDlg,FALSE); } #endif // EXTENDED_CAB_CONTENTS SetEvent(pArgs->ahHandles[IDX_EVENT_HANDLE]); break; } } return (FALSE); } static void AddToUrl(LPTSTR pszUrl, LPTSTR pszVersion, LPTSTR pszService) { TCHAR szHttpstr[MAX_PATH]; TCHAR szChar[16]; int i,len; if (!CmStrchr(pszUrl,'?')) { lstrcat(pszUrl,TEXT("?")); } else { if (pszUrl[lstrlen(pszUrl)-1] != '&') { lstrcat(pszUrl,TEXT("&")); } } // TBD Maybe get more info to send to the server. We currently send // OSArch, OSType, LCID, OSVer, CMVer, PBVer, and ServiceName. SYSTEM_INFO siInfo; OSVERSIONINFO oviInfo; GetSystemInfo(&siInfo); ZeroMemory(&oviInfo,sizeof(oviInfo)); oviInfo.dwOSVersionInfoSize = sizeof(oviInfo); GetVersionEx(&oviInfo); // #pragma message("ALERT - Resolution required - need to remove ISBU_VERSION." __FILE__) wsprintf(pszUrl+lstrlen(pszUrl), TEXT("OSArch=%u&OSType=%u&LCID=%u&OSVer=%u.%u.%u&CMVer=%s"), siInfo.wProcessorArchitecture, oviInfo.dwPlatformId, ConvertDefaultLocale(LOCALE_SYSTEM_DEFAULT), oviInfo.dwMajorVersion, oviInfo.dwMinorVersion, (oviInfo.dwPlatformId==VER_PLATFORM_WIN32_WINDOWS)?LOWORD(oviInfo.dwBuildNumber):oviInfo.dwBuildNumber, VER_PRODUCTVERSION_STR); if (pszVersion && *pszVersion) { wsprintf(pszUrl+lstrlen(pszUrl),TEXT("&PBVer=%s"),pszVersion); } if (pszService && *pszService) { // replace spaces with %20 for HTTP - 10216 len = strlen(pszService); szHttpstr[0] = 0; szChar[1] = 0; for (i=0; ipdaArgs,(pArgs->dwArgsCnt+1)*sizeof(DownloadArgs)); if (pdaArgsTmp) { pArgs->pdaArgs = pdaArgsTmp; pdaArgsTmp += pArgs->dwArgsCnt; pdaArgsTmp->pszCMSFile = CmStrCpyAlloc(pszFile); if (pdaArgsTmp->pszCMSFile) { // If get the version number from the CMS file GetPrivateProfileString(c_pszCmSection, c_pszVersion, TEXT(""), szTmp, (sizeof(szTmp)/sizeof(TCHAR))-1, pdaArgsTmp->pszCMSFile); pdaArgsTmp->pszVerCurr = CmStrCpyAlloc(szTmp); // get the PBK filename from the CMS file GetPrivateProfileString(c_pszCmSectionIsp, c_pszCmEntryIspPbFile, TEXT(""), szTmp, sizeof(szTmp)/sizeof(TCHAR)-1, pdaArgsTmp->pszCMSFile); pdaArgsTmp->pszPbkFile = CmStrCpyAlloc(szTmp); // get the PDR filename from the CMS file GetPrivateProfileString(c_pszCmSectionIsp, c_pszCmEntryIspRegionFile, TEXT(""), szTmp, sizeof(szTmp)/sizeof(TCHAR)-1, pdaArgsTmp->pszCMSFile); pdaArgsTmp->pszPbrFile = CmStrCpyAlloc(szTmp); // get the phone book name if (!(pszSlash = CmStrrchr(pdaArgsTmp->pszPbkFile, TEXT('\\')))) { MYDBG((TEXT("RefFunc() bad PBK FILE - no backslash."))); goto parse_err; } if (!(pszDot = CmStrchr(pszSlash, TEXT('.')))) { MYDBG((TEXT("Reffunc() bad PBK FILE - no dot."))); goto parse_err; } *pszDot = TEXT('\0'); if (!(pdaArgsTmp->pszPhoneBookName = CmStrCpyAlloc(pszSlash+1))) { MYDBG((TEXT("Reffunc() out of memory."))); } // restore the slash *pszDot = TEXT('.'); goto next_param; parse_err: pdaArgsTmp->pszPhoneBookName = CmStrCpyAlloc(TEXT("")); next_param: if (pdaArgsTmp->pszVerCurr) { // Build URL with version number and service name pdaArgsTmp->pszUrl = (LPTSTR) CmMalloc((INTERNET_MAX_URL_LENGTH+1)*sizeof(TCHAR)); if (pdaArgsTmp->pszUrl) { lstrcpy(pdaArgsTmp->pszUrl,pszURL); AddToUrl(pdaArgsTmp->pszUrl,pdaArgsTmp->pszVerCurr,pdaArgsTmp->pszPhoneBookName); pArgs->dwArgsCnt++; bOk = TRUE; } } } } // Cleanup if (!bOk && pdaArgsTmp) { CmFreeIndirect(&pdaArgsTmp->pszCMSFile); CmFreeIndirect(&pdaArgsTmp->pszVerCurr); CmFreeIndirect(&pdaArgsTmp->pszUrl); } return (TRUE); } // // cmmgr32.exe passes cmdl32.exe the cmp filename in full path. // static BOOL InitArgs(ArgsStruct *pArgs) { static struct { LPTSTR pszFlag; DWORD dwFlag; } asFlags[] = {{TEXT("/no_delete"),AF_NO_DELETE}, {TEXT("/no_install"),AF_NO_INSTALL}, #ifdef DEBUG {TEXT("/no_verify"),AF_NO_VERIFY}, #endif {TEXT("/url"),AF_URL}, {TEXT("/no_profile"),AF_NO_PROFILE}, {TEXT("/no_exe"),AF_NO_EXE}, {TEXT("/no_exeincab"),AF_NO_EXEINCAB}, {TEXT("/no_infincab"),AF_NO_INFINCAB}, {TEXT("/no_pbdincab"),AF_NO_PBDINCAB}, {TEXT("/no_shlincab"),AF_NO_SHLINCAB}, {TEXT("/no_ver"),AF_NO_VER}, {TEXT("/LAN"),AF_LAN}, {TEXT("/VPN"),AF_VPN}, {NULL,0}}; DWORD dwIdx; BOOL bInUrl; LPTSTR pszUrl = NULL; BOOL bRes = FALSE; TCHAR szPath[MAX_PATH+1]; DWORD dwRes; // LPTSTR pszFileInPath; // // Get simulated ArgV // LPTSTR pszCmdLine = CmStrCpyAlloc(GetCommandLine()); LPTSTR *ppszArgv = GetCmArgV(pszCmdLine); if (!ppszArgv || !ppszArgv[0]) { MYDBG(("InitArgs() invalid parameter.")); goto done; } // // Proces arguments // bInUrl = FALSE; for (dwIdx=1;ppszArgv[dwIdx];dwIdx++) { DWORD dwFlagIdx; for (dwFlagIdx=0;asFlags[dwFlagIdx].pszFlag;dwFlagIdx++) { if (lstrcmpi(asFlags[dwFlagIdx].pszFlag,ppszArgv[dwIdx]) == 0) { if (bInUrl) { MYDBG(("InitArgs() URL expected after AF_URL flag.")); goto done; } switch (asFlags[dwFlagIdx].dwFlag) { case AF_URL: bInUrl = TRUE; break; case AF_NO_PROFILE: if (pArgs->pszProfile) { MYDBG(("InitArgs() argument number %u (%s) is invalid.",dwIdx,ppszArgv[dwIdx])); goto done; } // fall through default: pArgs->dwAppFlags |= asFlags[dwFlagIdx].dwFlag; break; } break; } } if (!asFlags[dwFlagIdx].pszFlag) { if (bInUrl) { if (pszUrl) { MYDBG(("InitArgs() argument number %u (%s) is invalid.",dwIdx,ppszArgv[dwIdx])); goto done; } bInUrl = FALSE; pszUrl = (LPTSTR) CmMalloc((INTERNET_MAX_URL_LENGTH+1)*sizeof(TCHAR)); if (!pszUrl) { goto done; } lstrcpy(pszUrl,ppszArgv[dwIdx]); } else { if (pArgs->pszProfile || (pArgs->dwAppFlags & AF_NO_PROFILE)) { MYDBG(("InitArgs() argument number %u (%s) is invalid.",dwIdx,ppszArgv[dwIdx])); goto done; } /* ZeroMemory(szPath,sizeof(szPath)); dwRes = GetFullPathName(ppszArgv[dwIdx],sizeof(szPath)/sizeof(TCHAR)-1,szPath,&pszFileInPath); MYDBGTST(!dwRes,("InitArgs() GetFullPathName() failed, GLE=%u.",GetLastError())); */ // // the cmp filename is always in full path. // lstrcpy(szPath, ppszArgv[dwIdx]); pArgs->pszProfile = CmStrCpyAlloc(szPath); if (!pArgs->pszProfile) { goto done; } else { // // Set the current dir to the profile dir // If the szPath contains only the file name, then // assume that the current dir is the profile dir // char *pszTemp = NULL; pszTemp = CmStrrchr(szPath, TEXT('\\')); if (NULL != pszTemp) { *pszTemp = TEXT('\0'); MYVERIFY(SetCurrentDirectory(szPath)); } } } } } //////////////////////////////////////////////////////////////////////////////////////////// if (pArgs->dwAppFlags & AF_VPN) { // // They have asked for a VPN download. Let's make sure that the only other flags // they have specified are /LAN or /NO_DELETE // DWORD dwAllowedFlags = AF_VPN | AF_LAN | AF_NO_DELETE; if ((dwAllowedFlags | pArgs->dwAppFlags) != dwAllowedFlags) { CMASSERTMSG(FALSE, TEXT("InitArgs in cmdl32.exe -- VPN flag specified with other non supported flags, exiting.")); goto done; } bRes = TRUE; CMTRACE(TEXT("InitArgs - /VPN flag detected going into VPN file download mode.")); goto done; } //////////////////////////////////////////////////////////////////////////////////////////// if (bInUrl) { MYDBG(("InitArgs() URL expected after AF_URL flag.")); goto done; } if (!pArgs->pszProfile && !(pArgs->dwAppFlags & AF_NO_PROFILE)) { MYDBG(("InitArgs() must use AF_NO_PROFILE if no profile given on command line.")); goto done; } if (pArgs->pszProfile && pszUrl) { MYDBG(("InitArgs() can't give both a profile and a URL on the command line.")); goto done; } pArgs->pdaArgs = (DownloadArgs *) CmMalloc(sizeof(DownloadArgs)); if (!pArgs->pdaArgs) { goto done; } pArgs->dwArgsCnt++; if (!pszUrl) { TCHAR szTmp[MAX_PATH+1]; PhoneBookParseInfoStruct pbpisInfo; LPTSTR pszSlash; LPTSTR pszDot; int nVal = 0; if (!pArgs->pszProfile) { MYDBG(("InitArgs() must give AF_URL on command line when AF_NO_PROFILE is given.")); goto done; } // Get CMS file name GetPrivateProfileString(c_pszCmSection, c_pszCmEntryCmsFile, TEXT(""), szTmp, sizeof(szTmp)/sizeof(TCHAR)-1, pArgs->pszProfile); if (!szTmp[0]) { MYDBG(("InitArgs() [Connection Manager] CMSFile= entry not found in %s.",pArgs->pszProfile)); goto done; } /* ZeroMemory(szPath,sizeof(szPath)); dwRes = GetFullPathName(szTmp,sizeof(szPath)/sizeof(TCHAR)-1,szPath,&pszFileInPath); MYDBGTST(!dwRes,("InitArgs() GetFullPathName() failed, GLE=%u.",GetLastError())); */ // // we simply append the relative path of the cms file to the profile dir to // construct the cms path. // lstrcat(szPath, TEXT("\\")); lstrcat(szPath, szTmp); pArgs->pdaArgs->pszCMSFile = CmStrCpyAlloc(szPath); if (!pArgs->pdaArgs->pszCMSFile) { goto done; } // get the PBK filename from the CMS file GetPrivateProfileString(c_pszCmSectionIsp, c_pszCmEntryIspPbFile, TEXT(""), szTmp, sizeof(szTmp)/sizeof(TCHAR)-1, pArgs->pdaArgs->pszCMSFile); if (!*szTmp) { MYDBG(("InitArgs() [ISP Info] RegionFile= entry not found in %s.",pArgs->pdaArgs->pszCMSFile)); pArgs->pdaArgs->pszPhoneBookName = CmStrCpyAlloc(TEXT("")); } else { if (!(pArgs->pdaArgs->pszPbkFile = CmStrCpyAlloc(szTmp))) goto done; // get the phone book name if (!(pszSlash = CmStrrchr(pArgs->pdaArgs->pszPbkFile, TEXT('\\')))) { MYDBG((TEXT("InitArgs() bad PBKFILE - no backslash."))); goto done; } if (!(pszDot = CmStrchr(pszSlash, TEXT('.')))) { MYDBG((TEXT("InitArgs() bad PBKFILE - no dot."))); goto done; } *pszDot = TEXT('\0'); if (!(pArgs->pdaArgs->pszPhoneBookName = CmStrCpyAlloc(pszSlash+1))) goto done; // restore the slash *pszDot = TEXT('.'); } // get the PBR filename from the CMS file GetPrivateProfileString(c_pszCmSectionIsp, c_pszCmEntryIspRegionFile, TEXT(""), szTmp, sizeof(szTmp)/sizeof(TCHAR)-1, pArgs->pdaArgs->pszCMSFile); MYDBGTST(!*szTmp, ("InitArgs() [ISP Info] RegionFile= entry not found in %s.",pArgs->pdaArgs->pszCMSFile)); if (!(pArgs->pdaArgs->pszPbrFile = CmStrCpyAlloc(szTmp))) goto done; GetPrivateProfileString(c_pszCmSection, c_pszVersion, TEXT(""), szTmp, sizeof(szTmp)/sizeof(TCHAR)-1, pArgs->pdaArgs->pszCMSFile); pArgs->pdaArgs->pszVerCurr = CmStrCpyAlloc(szTmp); if (!pArgs->pdaArgs->pszVerCurr) { goto done; } pArgs->pdaArgs->pszUrl = (LPTSTR) CmMalloc((INTERNET_MAX_URL_LENGTH+1)*sizeof(TCHAR)); if (!pArgs->pdaArgs->pszUrl) { goto done; } ZeroMemory(&pbpisInfo,sizeof(pbpisInfo)); pbpisInfo.dwSize = sizeof(pbpisInfo); pbpisInfo.pszURL = pArgs->pdaArgs->pszUrl; pbpisInfo.dwURL = INTERNET_MAX_URL_LENGTH; pbpisInfo.pfnRef = RefFunc; pbpisInfo.dwRefParam = (DWORD_PTR) pArgs; bRes = PhoneBookParseInfo(pArgs->pdaArgs->pszCMSFile,&pbpisInfo); if (!bRes) { MYDBG(("InitArgs() PhoneBookParseInfo() failed, GLE=%u.",GetLastError())); goto done; } PhoneBookFreeFilter(pbpisInfo.pFilterA); PhoneBookFreeFilter(pbpisInfo.pFilterB); // // Bug fix #3064, a-nichb - HideDelay & DownloadDelay // Use nVal while retrieving entries, then assign to global // // Get Download delay nVal = GetPrivateProfileInt(c_pszCmSection, c_pszCmEntryDownloadDelay, DEFAULT_DELAY, pArgs->pdaArgs->pszCMSFile); // Convert to milliseconds pArgs->dwDownloadDelay = ((DWORD) nVal * (DWORD) 1000); MYDBG(("Download delay is %u millisseconds.", pArgs->dwDownloadDelay)); // Get Hide delay nVal = GetPrivateProfileInt(c_pszCmSection, c_pszCmEntryHideDelay, -1, pArgs->pdaArgs->pszCMSFile); // // Convert to milliseconds // if (nVal < 0) { pArgs->dwHideDelay = DEFAULT_HIDE; } else { pArgs->dwHideDelay = ((DWORD) nVal * (DWORD) 1000); } MYDBG(("Hide delay is %u milliseconds.", pArgs->dwHideDelay)); #if 0 /* // we don't support SuppressUpdates anymore if (GetPrivateProfileInt(c_pszCmSection, //13226 TEXT("SuppressUpdates"), 0, pArgs->pszProfile)) { pArgs->dwAppFlags |= AF_NO_UPDATE; } */ #endif } else { pArgs->pdaArgs[0].pszUrl = pszUrl; pszUrl = NULL; } if (pArgs->pszProfile) { TCHAR szTmp1[MAX_PATH+1]; TCHAR szTmp2[MAX_PATH+1]; pArgs->pszServiceName = (LPTSTR) CmMalloc((MAX_PATH+1)*sizeof(TCHAR)); if (!pArgs->pszServiceName) { goto done; } lstrcpy(szTmp1,pArgs->pdaArgs->pszCMSFile); if (CmStrrchr(szTmp1,'.')) { *CmStrrchr(szTmp1,'.') = 0; } if (CmStrrchr(szTmp1,'\\')) { lstrcpy(szTmp1,CmStrrchr(szTmp1,'\\')+1); } GetPrivateProfileString(c_pszCmSection, c_pszCmEntryServiceName, szTmp1, pArgs->pszServiceName, MAX_PATH, pArgs->pdaArgs->pszCMSFile); // Get the name of the large icon GetPrivateProfileString(c_pszCmSection, c_pszCmEntryBigIcon, TEXT(""), szTmp2, sizeof(szTmp2)/sizeof(TCHAR)-1, pArgs->pdaArgs->pszCMSFile); // If we have a name, load the large icon if (szTmp2[0]) { pArgs->hIcon = CmLoadIcon(pArgs->hInst,szTmp2); } // Get the name of the small icon GetPrivateProfileString(c_pszCmSection, c_pszCmEntrySmallIcon, TEXT(""), szTmp2, sizeof(szTmp2)/sizeof(TCHAR)-1, pArgs->pdaArgs->pszCMSFile); // If we have a name, load the small icon if (szTmp2[0]) { pArgs->hSmallIcon = CmLoadSmallIcon(pArgs->hInst,szTmp2); } } // // If the name based icon loads were not successful, load defaults from EXE // if (!pArgs->hIcon) { pArgs->hIcon = CmLoadIcon(pArgs->hInst, MAKEINTRESOURCE(IDI_APP)); } if (!pArgs->hSmallIcon) { pArgs->hSmallIcon = CmLoadSmallIcon(pArgs->hInst,MAKEINTRESOURCE(IDI_APP)); } AddToUrl(pArgs->pdaArgs->pszUrl,pArgs->pdaArgs->pszVerCurr,pArgs->pdaArgs->pszPhoneBookName); bRes = TRUE; done: // // Cleanup // if (pszUrl) { CmFree(pszUrl); } if (pszCmdLine) { CmFree(pszCmdLine); } if (ppszArgv) { CmFree(ppszArgv); } return (bRes); } static BOOL InitApplication(ArgsStruct *pArgs) { WNDCLASSEX wcDlg; wcDlg.cbSize = sizeof(wcDlg); if (FALSE == GetClassInfoEx(NULL, WC_DIALOG, &wcDlg)) { MYDBG(("InitApplication() GetClassInfoEx() failed, GLE=%u.",GetLastError())); return (FALSE); } wcDlg.lpszClassName = ICONNDWN_CLASS; wcDlg.hIcon = pArgs->hIcon; wcDlg.hIconSm = pArgs->hSmallIcon; wcDlg.hInstance = pArgs->hInst; pArgs->hIcon = NULL; pArgs->hSmallIcon = NULL; // // We have our class data setup, register the class // ATOM aRes = RegisterClassEx(&wcDlg); if (!aRes) { // // We may have more than one instance, so check the error case // DWORD dwError = GetLastError(); if (ERROR_ALREADY_EXISTS != dwError) { MYDBG(("InitApplication() RegisterClassEx() failed, GLE=%u.",GetLastError())); return (FALSE); } } MYDBG(("InitApplication() Class %s is registered.", wcDlg.lpszClassName)); return TRUE; } static BOOL InitInstance(ArgsStruct *pArgs) { pArgs->nMsgId = RegisterWindowMessage(c_pszIConnDwnMsg); if (!pArgs->nMsgId) { MYDBG(("InitInstance() RegisterWindowMessage() failed.")); return (FALSE); } return (TRUE); } //+---------------------------------------------------------------------------- // // Func: InitLogging // // Desc: Initializes logging functionality for the CMDL32 module // // Args: [pArgs] - args struct to pick up stuff from // // Return: BOOL (TRUE for success) // // Notes: IMPORTANT: note that CMDL32 is compiled Ansi whereas CMUTIL, which // contains the logging functionality, is Unicode. CmLogFile exposes both // Ansi and Unicode variants for member functions that take strings. // However, the arguments passed to the Log calls are Ansi - they are // handled correctly by using %S (note, capital S) in the corresponding // format strings in cmlog.rc. // // History: 11-Apr-2001 SumitC Created // //----------------------------------------------------------------------------- static BOOL InitLogging(ArgsStruct * pArgs) { BOOL fAllUser = TRUE; BOOL fEnabled = FALSE; DWORD dwMaxSize = 0; CHAR szFileDir[MAX_PATH + 1] = {0}; // // First figure out if this profile is AllUsers or Single User // if (!OS_W9X) { HMODULE hShell32 = LoadLibraryExA("Shell32.dll", NULL, 0); if (hShell32) { typedef DWORD (WINAPI *pfnSHGetSpecialFolderPathASpec)(HWND, CHAR*, int, BOOL); pfnSHGetSpecialFolderPathASpec pfnSHGetSpecialFolderPathA; pfnSHGetSpecialFolderPathA = (pfnSHGetSpecialFolderPathASpec) GetProcAddress(hShell32, "SHGetSpecialFolderPathA"); if (pfnSHGetSpecialFolderPathA) { CHAR szPath[MAX_PATH+1]; if (TRUE == pfnSHGetSpecialFolderPathA(NULL, szPath, CSIDL_APPDATA, FALSE)) { CHAR szProfile[MAX_PATH + 1]; lstrcpyn(szProfile, pArgs->pszProfile, MAX_PATH); szProfile[ lstrlen(szPath) ] = '\0'; if (0 == lstrcmpi(szProfile, szPath)) { fAllUser = FALSE; } } } FreeLibrary(hShell32); } } // // To get Enabled, we have the code equivalent of IniBoth // fEnabled = c_fEnableLogging; BOOL bGotValueFromReg = FALSE; HKEY hkey; CHAR szRegPath[2 * MAX_PATH]; lstrcpy(szRegPath, fAllUser ? "SOFTWARE\\Microsoft\\Connection Manager\\UserInfo\\" : "SOFTWARE\\Microsoft\\Connection Manager\\SingleUserInfo\\"); if ( (lstrlen(szRegPath) + 1 + lstrlen(pArgs->pszServiceName) + 1) > (2 * MAX_PATH)) { return FALSE; } lstrcat(szRegPath, "\\"); lstrcat(szRegPath, pArgs->pszServiceName); if (ERROR_SUCCESS == RegOpenKeyEx(HKEY_CURRENT_USER, szRegPath, 0, KEY_QUERY_VALUE, &hkey)) { DWORD dwType; DWORD bEnabled; DWORD dwSize = sizeof(DWORD); if (ERROR_SUCCESS == RegQueryValueEx(hkey, c_pszCmEntryEnableLogging, NULL, &dwType, (PBYTE) &bEnabled, &dwSize)) { fEnabled = bEnabled ? TRUE : FALSE; bGotValueFromReg = TRUE; } RegCloseKey(hkey); } // // To *exactly* mimic pIniBoth we should check the .CMP here too. However, // the moment the user brings up the UI we will write this value to the // registry if it was in the .CMP. So, skip the CMP step. // if (FALSE == bGotValueFromReg) { fEnabled = (BOOL ) GetPrivateProfileInt(c_pszCmSection, c_pszCmEntryEnableLogging, c_fEnableLogging, pArgs->pdaArgs->pszCMSFile); } // // To get MaxSize, we have the code equivalent of IniService // dwMaxSize = GetPrivateProfileInt(c_pszCmSectionLogging, c_pszCmEntryMaxLogFileSize, c_dwMaxFileSize, pArgs->pdaArgs->pszCMSFile); // // LogFileDirectory is also obtained via IniService // GetPrivateProfileString(c_pszCmSectionLogging, c_pszCmEntryLogFileDirectory, c_szLogFileDirectory, szFileDir, sizeof(szFileDir) / sizeof(TCHAR) - 1, pArgs->pdaArgs->pszCMSFile); // // Use these values to initialize logging // pArgs->Log.Init(pArgs->hInst, fAllUser, pArgs->pszServiceName); pArgs->Log.SetParams(fEnabled, dwMaxSize, szFileDir); if (pArgs->Log.IsEnabled()) { pArgs->Log.Start(FALSE); // FALSE => no banner } else { pArgs->Log.Stop(); } return TRUE; } int WINAPI WinMain(HINSTANCE, HINSTANCE, LPSTR , int ) { MYDBG(("=====================================================")); MYDBG((" CMDL32.EXE - LOADING - Process ID is 0x%x ", GetCurrentProcessId())); MYDBG(("=====================================================")); INT_PTR iRes = 1; ArgsStruct asArgs; DWORD dwIdx = 0; BOOL bRes = FALSE; // // Initialize app-wide arguments // ZeroMemory(&asArgs,sizeof(asArgs)); // // We can't use hInst param if we're not linked with libc. // libc uses GetModuleHandle(NULL), so we will too. // asArgs.hInst = GetModuleHandleA(NULL); // hInst; MYDBGTST(NULL == asArgs.hInst, ("WinMain - GetModuleHandle(NULL) returned 0x%x, GLE=%u.", asArgs.hInst, GetLastError())); #ifdef EXTENDED_CAB_CONTENTS asArgs.dwRebootCookie = MyNeedRebootInit(&asArgs); //must init flag or else will ask for reboot with no args or other errors #endif // EXTENDED_CAB_CONTENTS if (!InitArgs(&asArgs)) { goto done; } /////////////////////////////////////////////////////////////////////////////////// if (asArgs.dwAppFlags & AF_VPN) { iRes = UpdateVpnFileForProfile(asArgs.pszProfile); goto done; } /////////////////////////////////////////////////////////////////////////////////// // Set UPDATE flag // if (asArgs.dwAppFlags & AF_NO_UPDATE) // { // MYDBG(("WinMain() user has disabled updates.")); // goto done; // } // Initialize the app. if (!InitApplication(&asArgs)) { goto done; } // Setup this instance if (!InitInstance(&asArgs)) { goto done; } InitCommonControls(); #ifdef EXTENDED_CAB_CONTENTS asArgs.dwRebootCookie = MyNeedRebootInit(&asArgs); #endif // EXTENDED_CAB_CONTENTS // // Initialize Logging // if (!InitLogging(&asArgs)) { goto done; } iRes = DialogBoxParam(asArgs.hInst,MAKEINTRESOURCE(IDD_MAIN),NULL, (DLGPROC)MainDlgProc,(LPARAM) &asArgs); MYDBGTST(iRes == -1, ("WinMain() - DialogBoxParam(0x%x, 0x%x, NULL, MainDlgProc, 0x%x) - failed",asArgs.hInst, MAKEINTRESOURCE(IDD_MAIN), &asArgs)); done: // Close any handles created during WININET session for (dwIdx=0;dwIdxhReq) { bRes = InternetCloseHandle(pdaArgs->hReq); MYDBGTST(!bRes,("WinMain() InternetCloseHandle(asArgs.pdaArgs[%u].hReq) failed, GLE=%u.",dwIdx,GetLastError())); pdaArgs->hReq = NULL; } if (pdaArgs->hConn) { bRes = InternetCloseHandle(pdaArgs->hConn); MYDBGTST(!bRes,("WinMain() InternetCloseHandle(asArgs.pdaArgs[%u].hConn) failed, GLE=%u.",dwIdx,GetLastError())); pdaArgs->hConn = NULL; } if (pdaArgs->hInet) { bRes = InternetCloseHandle(pdaArgs->hInet); MYDBGTST(!bRes,("WinMain() InternetCloseHandle(asArgs.pdaArgs[%u].hInet) failed, GLE=%u.",dwIdx,GetLastError())); pdaArgs->hInet = NULL; } } // Wait for thread to terminate if (asArgs.ahHandles[IDX_INETTHREAD_HANDLE]) { long lRes; lRes = WaitForSingleObject(asArgs.ahHandles[IDX_INETTHREAD_HANDLE],45*1000); MYDBGTST(lRes!=WAIT_OBJECT_0,("WinMain() WaitForSingleObject() failed, GLE=%u.",lRes)); } // Free profile and service data if (asArgs.pszProfile) { CmFree(asArgs.pszProfile); asArgs.pszProfile = NULL; } if (asArgs.pszServiceName) { CmFree(asArgs.pszServiceName); asArgs.pszServiceName = NULL; } // Cleanup for each argument for (dwIdx=0;dwIdxpszCMSFile); CmFreeIndirect(&pdaArgs->pszPbkFile); CmFreeIndirect(&pdaArgs->pszPbrFile); CmFreeIndirect(&pdaArgs->pszUrl); CmFreeIndirect(&pdaArgs->pszVerCurr); CmFreeIndirect(&pdaArgs->pszVerNew); //CmFreeIndirect(&pdaArgs->pszNewPbrFile); CmFreeIndirect(&pdaArgs->pszPhoneBookName); if (pdaArgs->psUrl) { CmFree(pdaArgs->psUrl); pdaArgs->psUrl = NULL; } for (i=0; idwNumFilesToProcess; i++) CmFree(pdaArgs->rgfpiFileProcessInfo[i].pszFile); CmFree(pdaArgs->rgfpiFileProcessInfo); // As long as AF_NO_DELETE is NOT set, clean up temp files and dirs if (!(asArgs.dwAppFlags & AF_NO_DELETE)) { if (pdaArgs->szFile[0]) { bRes = DeleteFile(pdaArgs->szFile); MYDBGTST(!bRes,("WinMain() DeleteFile(asArgs[pdaArgs[%lu].szFile=%s) failed, GLE=%u.",dwIdx,pdaArgs->szFile,GetLastError())); } if (pdaArgs->szCabDir[0]) { ZapDir(pdaArgs->szCabDir); } } } // Release download args if (asArgs.pdaArgs) { CmFree(asArgs.pdaArgs); asArgs.pdaArgs = NULL; } for (dwIdx=0;dwIdx