/*---------------------------------------------------------------------------- download.cpp Download handling for Signup Copyright (C) 1995 Microsoft Corporation All rights reserved. Authors: ArulM --------------------------------------------------------------------------*/ #include "pch.hpp" #include #include #include #include #include #include #include #include "icwdl.h" // 12/4/96 jmazner Normandy #12193 // path to icwconn1.exe registry key from HKEY_LOCAL_MACHINE #define ICWCONN1PATHKEY TEXT("SOFTWARE\\Microsoft\\Windows\\CurrentVersion\\App Paths\\CONNWIZ.EXE") #define PATHKEYNAME TEXT("Path") #include // Cabbing up. extern HRESULT HandleCab(LPTSTR pszPath); extern void CleanupCabHandler(); // all global data is static shared, read-only // (written only during DLL-load) HANDLE g_hDLLHeap; // private Win32 heap HINSTANCE g_hInst; // our DLL hInstance HWND g_hWndMain; // hwnd of icwconn1 parent window #define DllExport extern "C" __declspec(dllexport) #define MAX_RES_LEN 255 // max length of string resources #define SMALL_BUF_LEN 48 // convenient size for small text buffers LPTSTR LoadSz(UINT idString,LPTSTR lpszBuf,UINT cbBuf); //+--------------------------------------------------------------------------- // // Function: MyGetTempPath() // // Synopsis: Gets the path to temporary directory // - Use GetTempFileName to get a file name // and strips off the filename portion to get the temp path // // Arguments: [uiLength - Length of buffer to contain the temp path] // [szPath - Buffer in which temp path will be returned] // // Returns: Length of temp path if successful // 0 otherwise // // History: 7/6/96 VetriV Created // 8/23/96 VetriV Delete the temp file // 12/4/96 jmazner Modified to serve as a wrapper of sorts; // if TMP or TEMP don't exist, setEnv our own // vars that point to conn1's installed path // (Normandy #12193) // //---------------------------------------------------------------------------- DWORD MyGetTempPath(UINT uiLength, LPTSTR szPath) { TCHAR szEnvVarName[SMALL_BUF_LEN + 1] = TEXT("\0unitialized szEnvVarName\0"); DWORD dwFileAttr = 0; lstrcpyn( szPath, TEXT("\0unitialized szPath\0"), 20 ); // is the TMP variable set? LoadSz(IDS_TMPVAR,szEnvVarName,sizeof(szEnvVarName)); if( GetEnvironmentVariable( szEnvVarName, szPath, uiLength ) ) { // 1/7/96 jmazner Normandy #12193 // verify validity of directory name dwFileAttr = GetFileAttributes(szPath); // if there was any error, this directory isn't valid. if( 0xFFFFFFFF != dwFileAttr ) { if( FILE_ATTRIBUTE_DIRECTORY & dwFileAttr ) { return( lstrlen(szPath) ); } } } lstrcpyn( szEnvVarName, TEXT("\0unitialized again\0"), 19 ); // if not, is the TEMP variable set? LoadSz(IDS_TEMPVAR,szEnvVarName,sizeof(szEnvVarName)); if( GetEnvironmentVariable( szEnvVarName, szPath, uiLength ) ) { // 1/7/96 jmazner Normandy #12193 // verify validity of directory name dwFileAttr = GetFileAttributes(szPath); if( 0xFFFFFFFF != dwFileAttr ) { if( FILE_ATTRIBUTE_DIRECTORY & dwFileAttr ) { return( lstrlen(szPath) ); } } } // neither one is set, so let's use the path to the installed icwconn1.exe // from the registry SOFTWARE\Microsoft\Windows\CurrentVersion\App Paths\ICWCONN1.EXE\Path HKEY hkey = NULL; #ifdef UNICODE uiLength = uiLength*sizeof(TCHAR); #endif if ((RegOpenKeyEx(HKEY_LOCAL_MACHINE,ICWCONN1PATHKEY, 0, KEY_QUERY_VALUE, &hkey)) == ERROR_SUCCESS) RegQueryValueEx(hkey, PATHKEYNAME, NULL, NULL, (BYTE *)szPath, (DWORD *)&uiLength); if (hkey) { RegCloseKey(hkey); } //The path variable is supposed to have a semicolon at the end of it. // if it's there, remove it. if( ';' == szPath[uiLength - 2] ) szPath[uiLength - 2] = '\0'; MyTrace(("ICWDL: using path ")); MyTrace((szPath)); MyTrace(("\r\n")); // go ahead and set the TEMP variable for future reference // (only effects currently running process) if( szEnvVarName[0] ) { SetEnvironmentVariable( szEnvVarName, szPath ); } else { lstrcpyn( szPath, TEXT("\0unitialized again\0"), 19 ); return( 0 ); } return( uiLength ); } extern "C" BOOL _stdcall DllEntryPoint(HINSTANCE hInstance, DWORD dwReason, LPVOID lbv) { switch (dwReason) { case DLL_PROCESS_ATTACH: // Need to use OLE/Com later if (FAILED(CoInitialize(NULL))) return(FALSE); // // ChrisK Olympus 6373 6/13/97 // Disable thread attach calls in order to avoid race condition // on Win95 golden // DisableThreadLibraryCalls(hInstance); g_hInst = hInstance; g_hDLLHeap = HeapCreate(0, 0, 0); MyAssert(g_hDLLHeap); if (g_hDLLHeap == NULL) return FALSE; break; case DLL_PROCESS_DETACH: CoUninitialize(); HeapDestroy(g_hDLLHeap); // Cleanup the cabbing stuff. CleanupCabHandler(); break; } return TRUE; } LPTSTR MyStrDup(LPTSTR pszIn) { int len; LPTSTR pszOut; MyAssert(pszIn); len = lstrlen(pszIn); if(!(pszOut = (LPTSTR)MyAlloc(len+1))) { MyAssert(FALSE); return NULL; } lstrcpy(pszOut, pszIn); pszOut[len] = 0; return pszOut; } #ifdef UNICODE LPTSTR MyStrDup(LPSTR pszIn) { int len; LPTSTR pszOut; MyAssert(pszIn); len = lstrlenA(pszIn); if(!(pszOut = (LPTSTR)MyAlloc(len+1))) { MyAssert(FALSE); return NULL; } mbstowcs(pszOut, pszIn, len); pszOut[len] = 0; return pszOut; } #endif int MyAssertProc(LPTSTR pszFile, int nLine, LPTSTR pszExpr) { TCHAR szBuf[512]; wsprintf(szBuf, TEXT("Assert failed at line %d in file %s. (%s)\r\n"), nLine, pszFile, pszExpr); MyDbgSz((szBuf)); return 0; } void _cdecl MyDprintf(LPCSTR pcsz, ...) { va_list argp; char szBuf[1024]; if ((NULL == pcsz) || ('\0' == pcsz[0])) return; va_start(argp, pcsz); vsprintf(szBuf, pcsz, argp); MyDbgSz((szBuf)); va_end(argp); } // Dprintf() // ############################################################################ // operator new // // This function allocate memory for C++ classes // // Created 3/18/96, Chris Kauffman // ############################################################################ void * MyBaseClass::operator new( size_t cb ) { return MyAlloc(cb); } // ############################################################################ // operator delete // // This function frees memory for C++ classes // // Created 3/18/96, Chris Kauffman // ############################################################################ void MyBaseClass::operator delete( void * p ) { MyFree( p ); } void CDownLoad::AddToFileList(CFileInfo* pfi) { CFileInfo **ppfi; // must add at tail for(ppfi=&m_pfiHead; *ppfi; ppfi = &((*ppfi)->m_pfiNext)) ; *ppfi = pfi; } CDownLoad::CDownLoad(LPTSTR psz) { TCHAR szUserAgent[128]; OSVERSIONINFO osVer; LPTSTR pszOS = TEXT(""); memset(this, 0, sizeof(CDownLoad)); if(psz) m_pszURL = MyStrDup(psz); memset(&osVer, 0, sizeof(osVer)); osVer.dwOSVersionInfoSize = sizeof(osVer); GetVersionEx(&osVer); switch(osVer.dwPlatformId) { case VER_PLATFORM_WIN32_WINDOWS: pszOS = TEXT("Windows95"); break; case VER_PLATFORM_WIN32_NT: pszOS = TEXT("WindowsNT"); } wsprintf(szUserAgent, USERAGENT_FMT, pszOS, osVer.dwMajorVersion, osVer.dwMinorVersion, GetSystemDefaultLangID()); m_hSession = InternetOpen(szUserAgent, 0, NULL, NULL, 0); TCHAR szBuf[MAX_PATH+1]; GetWindowsDirectory(szBuf, MAX_PATH); szBuf[MAX_PATH] = 0; m_pszWindowsDir = MyStrDup(szBuf); m_dwWindowsDirLen = lstrlen(m_pszWindowsDir); GetSystemDirectory(szBuf, MAX_PATH); szBuf[MAX_PATH] = 0; m_pszSystemDir = MyStrDup(szBuf); m_dwSystemDirLen = lstrlen(m_pszSystemDir); MyGetTempPath(MAX_PATH, szBuf); szBuf[MAX_PATH] = 0; m_pszTempDir = MyStrDup(szBuf); m_dwTempDirLen = lstrlen(m_pszTempDir); if(m_pszTempDir[m_dwTempDirLen-1]=='\\') { m_pszTempDir[m_dwTempDirLen-1]=0; m_dwTempDirLen--; } // form the ICW98 dir. It is basically the CWD m_pszICW98Dir = MyAlloc(MAX_PATH +1); GetCurrentDirectory(MAX_PATH, m_pszICW98Dir); m_dwICW98DirLen = lstrlen(m_pszICW98Dir); LPTSTR pszCmdLine = GetCommandLine(); LPTSTR pszTemp = NULL, pszTemp2 = NULL; _tcsncpy(szBuf, pszCmdLine, MAX_PATH); szBuf[MAX_PATH] = 0; pszTemp = _tcstok(szBuf, TEXT(" \t\r\n")); if (NULL != pszTemp) { pszTemp2 = _tcschr(pszTemp, TEXT('\\')); if(!pszTemp2) pszTemp2 = _tcsrchr(pszTemp, TEXT('/')); } if(pszTemp2) { *pszTemp2 = 0; m_pszSignupDir = MyStrDup(pszTemp); } else { MyAssert(FALSE); GetCurrentDirectory(MAX_PATH, szBuf); szBuf[MAX_PATH] = 0; m_pszSignupDir = MyStrDup(szBuf); } m_dwSignupDirLen = lstrlen(m_pszSignupDir); } CDownLoad::~CDownLoad(void) { MyDprintf("ICWDL: CDownLoad::~CDownLoad called\n", this); CFileInfo *pfi, *pfiNext; for(pfi=m_pfiHead; pfi; pfi=pfiNext) { pfiNext = pfi->m_pfiNext; delete pfi; } if(m_pszWindowsDir) MyFree(m_pszWindowsDir); if(m_pszSystemDir) MyFree(m_pszSystemDir); if(m_pszTempDir) MyFree(m_pszTempDir); if(m_pszICW98Dir) MyFree(m_pszICW98Dir); if(m_pszSignupDir) MyFree(m_pszSignupDir); if(m_pszURL) MyFree(m_pszURL); if(m_pszBoundary) MyFree(m_pszBoundary); if(m_hSession) InternetSessionCloseHandle(m_hSession); MyAssert(!m_hRequest); // // 5/23/97 jmazner Olympus #4652 // Make sure that any waiting threads are freed up. // if( m_hCancelSemaphore ) { ReleaseSemaphore( m_hCancelSemaphore, 1, NULL ); CloseHandle( m_hCancelSemaphore ); m_hCancelSemaphore = NULL; } } // perform a file name substitution LPTSTR CDownLoad::FileToPath(LPTSTR pszFile) { TCHAR szBuf[MAX_PATH+1]; for(long j=0; *pszFile; pszFile++) { if(j>=MAX_PATH) return NULL; if(*pszFile=='%') { pszFile++; LPTSTR pszTemp = _tcschr(pszFile, '%'); if(!pszTemp) return NULL; *pszTemp = 0; if(lstrcmpi(pszFile, SIGNUP)==0) { lstrcpy(szBuf+j, m_pszSignupDir); j+= m_dwSignupDirLen; } else if(lstrcmpi(pszFile, WINDOWS)==0) { lstrcpy(szBuf+j, m_pszWindowsDir); j+= m_dwWindowsDirLen; } else if(lstrcmpi(pszFile, SYSTEM)==0) { lstrcpy(szBuf+j, m_pszSystemDir); j+= m_dwSystemDirLen; } else if(lstrcmpi(pszFile, TEMP)==0) { lstrcpy(szBuf+j, m_pszTempDir); j+= m_dwTempDirLen; } else if(lstrcmpi(pszFile, ICW98DIR)==0) { lstrcpy(szBuf+j, m_pszICW98Dir); j+= m_dwICW98DirLen; } else return NULL; pszFile=pszTemp; } else szBuf[j++] = *pszFile; } szBuf[j] = 0; return MyStrDup(szBuf); } // Chops input up into CRLF-delimited chunks // Modifies input LPSTR GetNextLine(LPSTR pszIn) { LPSTR pszNext; while(*pszIn) { pszNext = strchr(pszIn, '\r'); if(!pszNext) return NULL; else if(pszNext[1]=='\n') { pszNext[0] = pszNext[1] = 0; return pszNext+2; } else pszIn = pszNext+1; } return NULL; } // Modifies input. Output is *in-place* LPSTR FindHeaderParam(LPSTR pszIn, LPSTR pszLook) { LPSTR pszEnd = pszIn + lstrlenA(pszIn); BOOL fFound = FALSE; LPSTR pszToken = NULL; while(pszIn= pbBuf); MyAssert(pbBuf+dwValid >= pbNewStart); dwValid -= (DWORD)(pbNewStart-pbBuf); if(dwValid) memmove(pbBuf, pbNewStart, (size_t)dwValid); return FillBuffer(pbBuf, dwLen, dwValid); } //+---------------------------------------------------------------------------- // // Function: HandlwDLFile // // Synopsis: Handle filename: // (1) get full path after macro substituition. (2) Free // pszFile string. // (3) save the file path & inline/attach info internally for // later handling // (4) Create file on disk & return HANDLE // // Aruguments: pszFile - filename // fInLine - value of inline/attached header from the MIME mutli-part // // Returns: phFile - handle of file created // return - ERROR_SUCCESS == success // // History: ArulM Created // 8/8/96 ChrisK Ported from \\TRANGO // //----------------------------------------------------------------------------- HRESULT CDownLoad::HandleDLFile(LPTSTR pszFile, BOOL fInline, LPHANDLE phFile) { TCHAR szdrive[_MAX_DRIVE]; TCHAR szPathName[_MAX_PATH]; // This will be the dir we need to create TCHAR szdir[_MAX_DIR]; TCHAR szfname[_MAX_FNAME]; TCHAR szext[_MAX_EXT]; MyAssert(phFile); *phFile = INVALID_HANDLE_VALUE; LPTSTR pszPath = FileToPath(pszFile); MyFree(pszFile); if(!pszPath) return ERROR_INVALID_DATA; // Split the provided path to get at the drive and path portion _tsplitpath( pszPath, szdrive, szdir, szfname, szext ); wsprintf (szPathName, TEXT("%s%s"), szdrive, szdir); // Create the Directory CreateDirectory(szPathName, NULL); // create the file *phFile = CreateFile(pszPath, GENERIC_WRITE, 0, NULL, OPEN_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL); if(*phFile == INVALID_HANDLE_VALUE) return GetLastError(); CFileInfo* pfi = new CFileInfo(pszPath, fInline); if(!pfi) return GetLastError(); AddToFileList(pfi); return ERROR_SUCCESS; } /******************************************************************* * * NAME: LoadSz * * SYNOPSIS: Loads specified string resource into buffer * * EXIT: returns a pointer to the passed-in buffer * * NOTES: If this function fails (most likely due to low * memory), the returned buffer will have a leading NULL * so it is generally safe to use this without checking for * failure. * ********************************************************************/ LPTSTR LoadSz(UINT idString,LPTSTR lpszBuf,UINT cbBuf) { // Clear the buffer and load the string if ( lpszBuf ) { *lpszBuf = '\0'; LoadString( g_hInst, idString, lpszBuf, cbBuf ); } return lpszBuf; } HRESULT CDownLoad::ProcessRequest(void) { LPBYTE pbData = NULL, pBoundary = NULL; DWORD dwLen = 0; HFIND hFindBoundary = NULL; LPTSTR pszDLFileName = NULL; HANDLE hOutFile = INVALID_HANDLE_VALUE; HRESULT hr = E_FAIL; MyAssert(m_hRequest && m_pszBoundary); MyAssert(m_pszBoundary[0]=='\r' && m_pszBoundary[1]=='\n'); MyAssert(m_pszBoundary[2]=='-' && m_pszBoundary[3]=='-'); // Buf Size must be greater than larget possible block of headers // also must be greater than the OVERLAP, which must be greater // than max size of MIME part boundary (70?) MyAssert(DEFAULT_DATABUF_SIZE > OVERLAP_LEN); MyAssert(OVERLAP_LEN > 80); // init buffer & find-pattern if(! (pbData = (LPBYTE)MyAlloc(DEFAULT_DATABUF_SIZE+SLOP))) { hr = E_OUTOFMEMORY; goto error; } hFindBoundary = SetFindPattern(m_pszBoundary); // find first boundary. If not in first blob, we have too much // white-space. Discard & try again (everything before the first // boundary is discardable) for(pBoundary=NULL; !pBoundary; ) { if(!(dwLen = FillBuffer(pbData, DEFAULT_DATABUF_SIZE, 0))) goto iNetError; pBoundary = (LPBYTE)Find(hFindBoundary, (LPSTR)pbData, dwLen); } for(;;) { MyAssert(pBoundary && pbData && dwLen); MyAssert(pBoundary>=pbData && (pBoundary+m_dwBoundaryLen)<=(pbData+dwLen)); // move remaining data to front of buffer & refill. if(!(dwLen = MoveAndFillBuffer(pbData, DEFAULT_DATABUF_SIZE, dwLen, pBoundary+m_dwBoundaryLen))) goto iNetError; pBoundary = NULL; // look for trailing -- after boundary to indicate end of last part if(pbData[0]=='-' && pbData[1]=='-') break; // skip leading CRLF (alway one after boundary) MyAssert(pbData[0]=='\r' && pbData[1]=='\n'); // reads headers and skips everything until doubleCRLF. assumes all // headers fit in the single buffer. Pass in pbData+2 to skip // leading CRLF. Return value is ptr to first byte past the dbl crlf LPTSTR pszFile = NULL; BOOL fInline = FALSE; LPBYTE pbNext = (LPBYTE)ParseHeaders((LPSTR)pbData+2, NULL, &pszFile, &fInline); if(!pszFile || !pbNext) { hr = ERROR_INVALID_DATA; goto error; } // // Make a copy of the file name - will be used // for displaying error message // pszDLFileName = (LPTSTR) MyAlloc(lstrlen(pszFile) + 1); lstrcpy(pszDLFileName, pszFile); // Handle filename: (1) get full path after macro substituition. // (2) Free pszFile string. (3) save the file path & inline/attach info // internally for later handling (4) Create file on disk &return HANDLE if(hr = HandleDLFile(pszFile, fInline, &hOutFile)) goto error; // move remaining data (after headers) to front of buffer & refill. dwLen = MoveAndFillBuffer(pbData, DEFAULT_DATABUF_SIZE, dwLen, pbNext); pBoundary = NULL; MyAssert(dwLen); while(dwLen) { DWORD dwWriteLen = 0; DWORD dwTemp = 0; // look for boundary. careful of boundary cut across // blocks. Overlapping blocks by 100 bytes to cover this case. if(pBoundary = (LPBYTE)Find(hFindBoundary, (LPSTR)pbData, dwLen)) dwWriteLen = (DWORD)(pBoundary - pbData); else if(dwLen > OVERLAP_LEN) dwWriteLen = dwLen-OVERLAP_LEN; else dwWriteLen = dwLen; MyAssert(dwWriteLen <= dwLen); MyAssert(hOutFile != INVALID_HANDLE_VALUE); if(dwWriteLen) { dwTemp = 0; if(!WriteFile(hOutFile, pbData, dwWriteLen, &dwTemp, NULL) || dwTemp!=dwWriteLen) { hr = GetLastError(); // // If we are out of diskspace, get the drive letter // and display an out of diskspace message // goto error; } } if(pBoundary) break; // move remaining data (after last byte written) to front of buffer & refill dwLen = MoveAndFillBuffer(pbData, DEFAULT_DATABUF_SIZE, dwLen, pbData+dwWriteLen); } // *truncate* file & close MyAssert(hOutFile != INVALID_HANDLE_VALUE); SetEndOfFile(hOutFile); // close file CloseHandle(hOutFile); hOutFile = INVALID_HANDLE_VALUE; if (NULL != pszDLFileName) { MyFree(pszDLFileName); pszDLFileName = NULL; } if(!pBoundary) { MyAssert(dwLen==0); // can only get here on dwLen==0 or found boundary goto iNetError; } // at start of loop we'll discard everything upto and including the boundary // if we loop back with pBoundary==NULL, we'll GPF } return ERROR_SUCCESS; iNetError: hr = InternetGetLastError(m_hSession); if(!hr) hr = ERROR_INVALID_DATA; // goto error; // fall through error: if(pbData) MyFree(pbData); if(hFindBoundary) FreeFindPattern(hFindBoundary); if (NULL != pszDLFileName) { MyFree(pszDLFileName); pszDLFileName = NULL; } if (hOutFile != INVALID_HANDLE_VALUE) { CloseHandle(hOutFile); hOutFile = INVALID_HANDLE_VALUE; } return hr; } HRESULT HandleExe(LPTSTR pszPath, HANDLE hCancelSemaphore) { MyAssert( hCancelSemaphore ); STARTUPINFO si; PROCESS_INFORMATION pi; memset(&pi, 0, sizeof(pi)); memset(&si, 0, sizeof(si)); if(!CreateProcess(pszPath, NULL, NULL, NULL, TRUE, 0, NULL, NULL, &si, &pi)) return GetLastError(); else { HANDLE lpHandles[2] = {hCancelSemaphore, pi.hProcess}; DWORD dwRet = 0xDEAF; MyDprintf("ICWDL: HandleExe about to wait....\n"); // // 5/23/97 jmazner Olympus #4652 // sit here and wait until either // 1) the process we launched terminates, or // 2) the user tells us to cancel // dwRet = WaitForMultipleObjects( 2, lpHandles, FALSE, INFINITE ); MyDprintf("ICWDL: ....HandleExe done waiting -- %s was signalled\n", (0==(dwRet - WAIT_OBJECT_0))?"hCancelSemaphore":"pi.hProcess"); // should we try to kill the process here?? CloseHandle(pi.hThread); CloseHandle(pi.hProcess); return NO_ERROR; } } HRESULT HandleReg(LPTSTR pszPath, HANDLE hCancelSemaphore) { STARTUPINFO si; PROCESS_INFORMATION pi; TCHAR szCmd[MAX_PATH + 1]; MyAssert( pszPath ); MyAssert( hCancelSemaphore ); // 11/20/96 jmazner Normandy #5272 // Wrap quotes around pszPath in a directory or file name includes a space. lstrcpy(szCmd, REGEDIT_CMD); if( '\"' != pszPath[0] ) { // add 2 for two quotes MyAssert( (lstrlen(REGEDIT_CMD) + lstrlen(pszPath)) < MAX_PATH ); lstrcat(szCmd, TEXT("\"")); lstrcat(szCmd, pszPath); int i = lstrlen(szCmd); szCmd[i] = '\"'; szCmd[i+1] = '\0'; } else { MyAssert( (lstrlen(REGEDIT_CMD) + lstrlen(pszPath)) < MAX_PATH ); lstrcat(szCmd, pszPath); } memset(&pi, 0, sizeof(pi)); memset(&si, 0, sizeof(si)); si.dwFlags = STARTF_USESHOWWINDOW; si.wShowWindow = SW_HIDE; if(!CreateProcess(NULL, szCmd, NULL, NULL, TRUE, 0, NULL, NULL, &si, &pi)) return GetLastError(); else { // HRESULT hr = (WaitAndKillRegeditWindow(10) ? NO_ERROR : E_FAIL); HANDLE lpHandles[2] = {hCancelSemaphore, pi.hProcess}; DWORD dwRet = 0xDEAF; MyDprintf("ICWDL: HandleReg about to wait....\n"); // // 5/23/97 jmazner Olympus #4652 // sit here and wait until either // 1) the process we launched terminates, or // 2) the user tells us to cancel // dwRet = WaitForMultipleObjects( 2, lpHandles, FALSE, INFINITE ); MyDprintf("ICWDL: ....HandleReg done waiting -- %s was signalled\n", (0==(dwRet - WAIT_OBJECT_0))?"hCancelSemaphore":"pi.hProcess"); // should we try to kill the process here?? CloseHandle(pi.hThread); CloseHandle(pi.hProcess); return ERROR_SUCCESS; } } HRESULT HandleInf(LPTSTR pszPath, HANDLE hCancelSemaphore) { TCHAR szCmd[MAX_PATH + 1]; MyAssert( pszPath ); MyAssert( hCancelSemaphore ); // add 2 for two quotes, // subtract 70 for approximate length of string in sprintf MyAssert( (lstrlen(pszPath) - 70 + 2) < MAX_PATH ); // 11/20/96 jmazner Normandy #5272 // wrap pszPath in quotes in case it includes a space if( '\"' != pszPath[0] ) { wsprintf(szCmd, TEXT("rundll setupx.dll,InstallHinfSection DefaultInstall 128 \"%s"), pszPath); int i = lstrlen(szCmd); szCmd[i] = '\"'; szCmd[i+1] = '\0'; } else { wsprintf(szCmd, TEXT("rundll setupx.dll,InstallHinfSection DefaultInstall 128 %s"), pszPath); } STARTUPINFO si; PROCESS_INFORMATION pi; memset(&pi, 0, sizeof(pi)); memset(&si, 0, sizeof(si)); si.cb = sizeof(STARTUPINFO); si.dwFlags = STARTF_USESHOWWINDOW; si.wShowWindow = SW_SHOW; if(!CreateProcess(NULL, szCmd, NULL, NULL, TRUE, 0, NULL, NULL, &si, &pi)) return GetLastError(); else { HANDLE lpHandles[2] = {hCancelSemaphore, pi.hProcess}; DWORD dwRet = 0xDEAF; MyDprintf("ICWDL: HandleInf about to wait....\n"); // // 5/23/97 jmazner Olympus #4652 // sit here and wait until either // 1) the process we launched terminates, or // 2) the user tells us to cancel // dwRet = WaitForMultipleObjects( 2, lpHandles, FALSE, INFINITE ); MyDprintf("ICWDL: ....HandleInf done waiting -- %s was signalled\n", (0==(dwRet - WAIT_OBJECT_0))?"hCancelSemaphore":"pi.hProcess"); // should we try to kill the process here?? CloseHandle(pi.hThread); CloseHandle(pi.hProcess); return NO_ERROR; } } #define STR_BSTR 0 #define STR_OLESTR 1 #ifdef UNICODE #define BSTRFROMANSI(x) (BSTR)(x) #define OLESTRFROMANSI(x) (LPCOLESTR)(x) #else #define BSTRFROMANSI(x) (BSTR)MakeWideStrFromAnsi((LPSTR)(x), STR_BSTR) #define OLESTRFROMANSI(x) (LPCOLESTR)MakeWideStrFromAnsi((LPSTR)(x), STR_OLESTR) #endif #define TO_ASCII(x) (TCHAR)((unsigned char)x + 0x30) //=--------------------------------------------------------------------------= // MakeWideFromAnsi //=--------------------------------------------------------------------------= // given a string, make a BSTR out of it. // // Parameters: // LPTSTR - [in] // BYTE - [in] // // Output: // LPWSTR - needs to be cast to final desired result // // Notes: // LPWSTR MakeWideStrFromAnsi (LPSTR psz, BYTE bType) { int i; LPWSTR pwsz; if (!psz) return(NULL); if ((i = MultiByteToWideChar(CP_ACP, 0, psz, -1, NULL, 0)) <= 0) // compute the length of the required BSTR return NULL; switch (bType) { // allocate the widestr, +1 for null case STR_BSTR: pwsz = (LPWSTR)SysAllocStringLen(NULL, (i - 1)); // SysAllocStringLen adds 1 break; case STR_OLESTR: pwsz = (LPWSTR)CoTaskMemAlloc(i * sizeof(WCHAR)); break; default: return(NULL); } if (!pwsz) return(NULL); MultiByteToWideChar(CP_ACP, 0, psz, -1, pwsz, i); pwsz[i - 1] = 0; return(pwsz); } /* MakeWideStrFromAnsi() */ // Get the URL location from the .URL file, and send it to the progress dude HRESULT CDownLoad::HandleURL(LPTSTR pszPath) { MyAssert( pszPath ); LPTSTR pszURL; // Create a IUniformResourceLocator object IUniformResourceLocator * pURL; if (SUCCEEDED(CoCreateInstance(CLSID_InternetShortcut, NULL, CLSCTX_INPROC_SERVER, IID_IUniformResourceLocator, (LPVOID*)&pURL))) { // Get a persist file interface IPersistFile *ppf; if (SUCCEEDED(pURL->QueryInterface(IID_IPersistFile, (LPVOID*)&ppf))) { // Attempt to connect the storage of the IURL to the .URL file we // downloaded if (SUCCEEDED(ppf->Load(OLESTRFROMANSI(pszPath), STGM_READ))) { // OK, have the URL object give us the location if (SUCCEEDED(pURL->GetURL(&pszURL)) && pszURL) { // Notify the callback about the URL location (m_lpfnCB)(m_hRequest,m_lpCDialingDlg, CALLBACK_TYPE_URL, (LPVOID)pszURL, lstrlen(pszURL)); // Free the allocated URL, since the callback made a copy of it IMalloc* pMalloc; HRESULT hres = SHGetMalloc(&pMalloc); if (SUCCEEDED(hres)) { pMalloc->Free(pszURL); pMalloc->Release(); } } } // Release the persist file interface ppf->Release(); } // release the URL object pURL->Release(); } return(NO_ERROR); } #define PHONEBOOK_LIBRARY TEXT("ICWPHBK.DLL") #define PHBK_LOADAPI "PhoneBookLoad" #define PHBK_MERGEAPI "PhoneBookMergeChanges" #define PHBK_UNLOADAPI "PhoneBookUnload" #define PHONEBOOK_SUFFIX TEXT(".PHB") typedef HRESULT (CALLBACK* PFNPHONEBOOKLOAD)(LPCTSTR pszISPCode, DWORD *pdwPhoneID); typedef HRESULT (CALLBACK* PFNPHONEBOOKMERGE)(DWORD dwPhoneID, LPTSTR pszFileName); typedef HRESULT (CALLBACK *PFNPHONEBOOKUNLOAD) (DWORD dwPhoneID); HRESULT HandleChg(LPTSTR pszPath) { TCHAR szPhoneBookPath[MAX_PATH+1]; TCHAR *p; LPTSTR szFilePart; HRESULT hr = ERROR_FILE_NOT_FOUND; HINSTANCE hPHBKDLL = NULL; FARPROC fp; DWORD dwPhoneBook; lstrcpy(szPhoneBookPath,pszPath); if (lstrlen(szPhoneBookPath) > 4) { p = &(szPhoneBookPath[lstrlen(szPhoneBookPath)-4]); } else { hr = ERROR_INVALID_PARAMETER; goto HandleChgExit; } lstrcpy(p,PHONEBOOK_SUFFIX); while (*p != '\\' && p > &szPhoneBookPath[0]) p--; p++; if(!SearchPath(NULL,p,NULL,MAX_PATH,szPhoneBookPath,&szFilePart)) { hr = GetLastError(); goto HandleChgExit; } hPHBKDLL = LoadLibrary(PHONEBOOK_LIBRARY); if (!hPHBKDLL) { hr = GetLastError(); goto HandleChgExit; } fp = GetProcAddress(hPHBKDLL,PHBK_LOADAPI); if (!fp) { hr = GetLastError(); goto HandleChgExit; } hr = ((PFNPHONEBOOKLOAD)fp)(pszPath,&dwPhoneBook); if(hr != ERROR_SUCCESS) goto HandleChgExit; fp = GetProcAddress(hPHBKDLL,PHBK_MERGEAPI); if (!fp) { hr = GetLastError(); goto HandleChgExit; } hr = ((PFNPHONEBOOKMERGE)fp)(dwPhoneBook,pszPath); fp = GetProcAddress(hPHBKDLL,PHBK_UNLOADAPI); if (!fp) { hr = GetLastError(); goto HandleChgExit; } ((PFNPHONEBOOKUNLOAD)fp)(dwPhoneBook); HandleChgExit: return hr; } HRESULT HandleOthers(LPTSTR pszPath) { DWORD_PTR dwErr; TCHAR szCmd[MAX_PATH + 1]; MyAssert( pszPath ); // 11/20/96 jmazner Normandy #5272 // Wrap quotes around pszPath in case it includes a space. // add 2 for two quotes MyAssert( (lstrlen(pszPath) + 2) < MAX_PATH ); if( '\"' != pszPath[0] ) { lstrcpy(szCmd,TEXT("\"")); lstrcat(szCmd, pszPath); int i = lstrlen(szCmd); szCmd[i] = '\"'; szCmd[i+1] = '\0'; } else { lstrcpyn(szCmd, pszPath, lstrlen(pszPath)); } if((dwErr=(DWORD_PTR)ShellExecute(NULL, NULL, szCmd, NULL, NULL, SW_SHOWNORMAL)) < 32) return (DWORD)dwErr; else return ERROR_SUCCESS; } LPTSTR GetExtension(LPTSTR pszPath) { LPTSTR pszRet = _tcsrchr(pszPath, '.'); if(pszRet) return pszRet+1; else return NULL; } // Normandy 12093 - ChrisK 12/3/96 // return the error code for the first error that occurs while processing a file, // but don't stop processing files. // HRESULT CDownLoad::Process(void) { HRESULT hr; HRESULT hrProcess = ERROR_SUCCESS; LPTSTR pszExt; CFileInfo *pfi; for(pfi=m_pfiHead; pfi; pfi=pfi->m_pfiNext) { // Normandy 12093 - ChrisK 12/3/96 hr = ERROR_SUCCESS; if(pfi->m_fInline) { pszExt = GetExtension(pfi->m_pszPath); if(!pszExt) continue; if (lstrcmpi(pszExt, EXT_CAB)==0) hr = HandleCab(pfi->m_pszPath); else if(lstrcmpi(pszExt, EXT_EXE)==0) hr = HandleExe(pfi->m_pszPath, m_hCancelSemaphore); else if(lstrcmpi(pszExt, EXT_REG)==0) hr = HandleReg(pfi->m_pszPath, m_hCancelSemaphore); else if(lstrcmpi(pszExt, EXT_CHG)==0) hr = HandleChg(pfi->m_pszPath); else if(lstrcmpi(pszExt, EXT_INF)==0) hr = HandleInf(pfi->m_pszPath, m_hCancelSemaphore); else if(lstrcmpi(pszExt, EXT_URL)==0) hr = HandleURL(pfi->m_pszPath); else hr = HandleOthers(pfi->m_pszPath); // Normandy 12093 - ChrisK 12/3/96 if ((ERROR_SUCCESS == hrProcess) && (ERROR_SUCCESS != hr)) hrProcess = hr; } } // Normandy 12093 - ChrisK 12/3/96 return hrProcess; } HRESULT CDownLoad::SetStatusCallback (INTERNET_STATUS_CALLBACK lpfnCB) { HRESULT hr; hr = ERROR_SUCCESS; if (!lpfnCB) { hr = ERROR_INVALID_PARAMETER; } else { m_lpfnCB = lpfnCB; } return hr; } #ifdef DEBUG extern "C" HRESULT WINAPI DLTest(LPTSTR pszURL) { CDownLoad* pdl = new CDownLoad(pszURL); HRESULT hr = pdl->Execute(); if(hr) goto done; hr = pdl->Process(); done: delete pdl; return hr; } #endif //DEBUG HRESULT WINAPI DownLoadInit(LPTSTR pszURL, DWORD_PTR FAR *lpCDialingDlg, DWORD_PTR FAR *pdwDownLoad, HWND hWndMain) { g_hWndMain = hWndMain; HRESULT hr = ERROR_NOT_ENOUGH_MEMORY; CDownLoad* pdl = new CDownLoad(pszURL); if (!pdl) goto DownLoadInitExit; *pdwDownLoad = (DWORD_PTR)pdl; // // 5/27/97 jmazner Olympus #4579 // pdl->m_lpCDialingDlg = (DWORD_PTR)lpCDialingDlg; hr = ERROR_SUCCESS; // // 5/23/97 jmazner Olympus #4652 // create a semaphore in non-signaled state. If we ever get a downLoadCancel, we // should signal the semaphore, and any waiting threads should notice that and bail out. // pdl->m_hCancelSemaphore = CreateSemaphore( NULL, 0, 1, TEXT("ICWDL DownloadCancel Semaphore") ); if( !pdl->m_hCancelSemaphore || (ERROR_ALREADY_EXISTS == GetLastError()) ) { MyDprintf("ICWDL: Unable to create CancelSemaphore!!\n"); hr = ERROR_ALREADY_EXISTS; } DownLoadInitExit: return hr; } HRESULT WINAPI DownLoadCancel(DWORD_PTR dwDownLoad) { MyDprintf("ICWDL: DownLoadCancel called\n"); if (dwDownLoad) { MyDprintf("ICWDL: DownLoadCancel releasing m_hCancelSemaphore\n"); MyAssert( ((CDownLoad*)dwDownLoad)->m_hCancelSemaphore ); ReleaseSemaphore( ((CDownLoad*)dwDownLoad)->m_hCancelSemaphore, 1, NULL ); ((CDownLoad*)dwDownLoad)->Cancel(); return ERROR_SUCCESS; } else { return ERROR_INVALID_PARAMETER; } } HRESULT WINAPI DownLoadExecute(DWORD_PTR dwDownLoad) { if (dwDownLoad) { return ((CDownLoad*)dwDownLoad)->Execute(); } else { return ERROR_INVALID_PARAMETER; } } HRESULT WINAPI DownLoadClose(DWORD_PTR dwDownLoad) { MyDprintf("ICWDL: DownLoadClose called \n"); if (dwDownLoad) { // be good and cancel any downloads that are in progress ((CDownLoad*)dwDownLoad)->Cancel(); delete ((CDownLoad*)dwDownLoad); return ERROR_SUCCESS; } else { return ERROR_INVALID_PARAMETER; } } HRESULT WINAPI DownLoadSetStatusCallback ( DWORD_PTR dwDownLoad, INTERNET_STATUS_CALLBACK lpfnCB ) { if (dwDownLoad) { return ((CDownLoad*)dwDownLoad)->SetStatusCallback(lpfnCB); } else { return ERROR_INVALID_PARAMETER; } } HRESULT WINAPI DownLoadProcess(DWORD_PTR dwDownLoad) { MyDprintf("ICWDL: DownLoadProcess\n"); if (dwDownLoad) { return ((CDownLoad*)dwDownLoad)->Process(); } else { return ERROR_INVALID_PARAMETER; } }