extern "C" int WINAPI wWinMain(HINSTANCE hInstance,
    HINSTANCE /*hPrevInstance*/, __in LPWSTR lpCmdLine, int /*nShowCmd*/)
{
    lpCmdLine = GetCommandLine(); //this line necessary for _ATL_MIN_CRT

    CoInitialize(0);
    _Module.Init( ObjectMap, hInstance, &LIBID_ATLLib );

    ::InitCommonControls();

    RECT rcPos = { CW_USEDEFAULT, 0, 0, 0 };
    HMENU hMenu = LoadMenu(_Module.GetResourceInstance(), MAKEINTRESOURCE(IDR_MENU1));
    HICON hIcon = LoadIcon(_Module.GetResourceInstance(), MAKEINTRESOURCE(IDI_ICON1));

    CWMPHost frame;
    frame.GetWndClassInfo().m_wc.hIcon = hIcon;
    frame.Create(GetDesktopWindow(), rcPos, L"WMP Host Container", 0, 0, (UINT)hMenu);
    frame.ShowWindow(SW_SHOWNORMAL);

    MSG msg;
    while (GetMessage(&msg, 0, 0, 0))
    {
        TranslateMessage(&msg);
        DispatchMessage(&msg);
    }
    _Module.Term();
    CoUninitialize();
    return 0;
}
Beispiel #2
0
HRESULT  CObjectFeatureScript2::SetLong (CebThread & Thread, BOOL fBreak, BOOL fAuto, LPCSTR lpcstr)
{
	ASSERT(lpcstr);

	if (NULL == lpcstr) return E_POINTER;

	long lName = (long)(LPSTR)lpcstr;
	
	Thread.SetLong (SETLONG_BREAK, fBreak);		// BreakFlag voreinstellen
	Thread.SetLong (SETLONG_AUTO, fAuto);		// Auto voreinstellen
	Thread.SetLong (SETLONG_NAME, lName);		// Name voreinstellen
	Thread.SetLong (SETLONG_HPROJECT, reinterpret_cast<LONG>(DEX_GetDataSourceHandle()));		// Datenquelle voreinstellen
	Thread.SetLong (SETLONG_HINSTANCE, reinterpret_cast<LONG>(_Module.GetResourceInstance()));	

	return S_OK;
}
HRESULT DownloadHelper::DownloadFile(const TCHAR* szURL, 
        const TCHAR* szLocalFile, BOOL bResumable, BOOL bUIFeedback) {
    HINTERNET hOpen = NULL;
    HINTERNET hConnect = NULL;
    HINTERNET hRequest = NULL;
    HANDLE hFile = INVALID_HANDLE_VALUE;
    DWORD dwDownloadError = 0;
    DWORD nContentLength = 0;

    /* Some of error messages use drive letter.
       Result is something like "(C:)".
       NB: Parentheses are added here because in some other places
           we same message but can not provide disk label info */
    TCHAR drivePath[5];
    /* assuming szLocalFile is not NULL */
    _sntprintf(drivePath, 5, "(%c:)", szLocalFile[0]);
    WCHAR* wName = CT2CW(drivePath);
    
    __try {
        m_csDownload.Lock();
        
        time(&m_startTime);
        
    }
    __finally {
        m_csDownload.Unlock();
    }
    
    __try {
        // block potential security hole
        if (strstr(szURL, TEXT("file://")) != NULL) {
            dwDownloadError = 1;
            __leave;
        }
        
        HWND hProgressInfo = NULL;
        TCHAR szStatus[BUFFER_SIZE];
        
        if (bUIFeedback) {
            // init download dialg text
            m_dlg->initDialogText(m_pszURL, m_pszNameText);
        }
        
        // Open Internet Call
        hOpen = ::InternetOpen("deployHelper", INTERNET_OPEN_TYPE_PRECONFIG, 
                NULL, NULL, NULL);
        
        if (hOpen == NULL) {
            dwDownloadError = 1;
            __leave;
        }
        
        // URL components
        URL_COMPONENTS url_components;
        ::ZeroMemory(&url_components, sizeof(URL_COMPONENTS));
        
        TCHAR szHostName[BUFFER_SIZE], szUrlPath[BUFFER_SIZE], 
                szExtraInfo[BUFFER_SIZE];
        url_components.dwStructSize = sizeof(URL_COMPONENTS);
        url_components.lpszHostName = szHostName;
        url_components.dwHostNameLength = BUFFER_SIZE;
        url_components.nPort = NULL;
        url_components.lpszUrlPath = szUrlPath;
        url_components.dwUrlPathLength = BUFFER_SIZE;
        url_components.lpszExtraInfo = szExtraInfo;
        url_components.dwExtraInfoLength = BUFFER_SIZE;
        
        // Crack the URL into pieces
        ::InternetCrackUrl(szURL, lstrlen(szURL), NULL, &url_components);
        
        // Open Internet Connection
        hConnect = ::InternetConnect(hOpen, url_components.lpszHostName, 
                url_components.nPort, "", "", INTERNET_SERVICE_HTTP, NULL,
                NULL);
        
        if (hConnect == NULL) {
            dwDownloadError = 1;
            __leave;
        }
        
        // Determine the relative URL path by combining
        // Path and ExtraInfo
        char szURL[4096];
        
        if (url_components.dwUrlPathLength !=  0)
            lstrcpy(szURL, url_components.lpszUrlPath);
        else
            lstrcpy(szURL, "/");
        
        if (url_components.dwExtraInfoLength != 0)
            lstrcat(szURL, url_components.lpszExtraInfo);
        
        BOOL bRetryHttpRequest = FALSE;
        int numberOfRetry = 0;
        long secondsToWait = 60;
        
        do {
            bRetryHttpRequest = FALSE;
            
            // Make a HTTP GET request
            hRequest = ::HttpOpenRequest(hConnect, "GET", szURL, "HTTP/1.1", 
                    "", NULL, 
                    INTERNET_FLAG_KEEP_CONNECTION | INTERNET_FLAG_DONT_CACHE,
                    0);
            
            if (hRequest == NULL) {
                dwDownloadError = 1;
                __leave;
            }
            
            // Create or open existing destination file
            hFile = ::CreateFile(szLocalFile, GENERIC_WRITE, 0, NULL,
                    OPEN_ALWAYS, FILE_ATTRIBUTE_ARCHIVE, NULL);

            if (hFile == INVALID_HANDLE_VALUE) {
                if (bUIFeedback) {
                    if (IDRETRY == m_dlg->SafeMessageBox(
                                            IDS_DISK_WRITE_ERROR, 
                                            IDS_DISK_WRITE_ERROR_CAPTION, 
                                            IDS_ERROR_CAPTION, 
                                            DIALOG_ERROR_RETRYCANCEL,
                                            wName)) {
                         bRetryHttpRequest = TRUE;
                         continue;
                    }
                }
                dwDownloadError = 1;
                __leave;
            }
            DWORD fileSize = GetFileSize(hFile, NULL);
            
            // Check if resumable download is enabled
            if (bResumable == FALSE) {
                // Start from scratch
                fileSize = 0;
            }
            
            FILETIME tWrite;
            BOOL rangereq = FALSE;
            if ((fileSize != 0) && (fileSize != 0xFFFFFFFF) &&
                    GetFileTime(hFile, NULL, NULL, &tWrite)) {
                char szHead[100];
                SYSTEMTIME tLocal;
                char buf[INTERNET_RFC1123_BUFSIZE];
                
                FileTimeToSystemTime(&tWrite, &tLocal);
                InternetTimeFromSystemTime(&tLocal, INTERNET_RFC1123_FORMAT,
                        buf, INTERNET_RFC1123_BUFSIZE);
                sprintf(szHead, "Range: bytes=%d-\r\nIf-Range: %s\r\n", 
                        fileSize, buf);
                HttpAddRequestHeaders(hRequest, szHead, lstrlen(szHead),
                        HTTP_ADDREQ_FLAG_ADD|HTTP_ADDREQ_FLAG_REPLACE);
                rangereq = TRUE;
            }
            
            // This is a loop to handle various potential error when the
            // connection is made
            BOOL bCont = TRUE;
            
            while ((FALSE == ::HttpSendRequest(hRequest, NULL, NULL, NULL, NULL))
            && bCont ) {
                // We might have an invalid CA.
                DWORD dwErrorCode = GetLastError();
                
                switch(dwErrorCode) {
                    case E_JDHELPER_TIMEOUT:
                    case E_JDHELPER_NAME_NOT_RESOLVED:
                    case E_JDHELPER_CANNOT_CONNECT: {
                        bCont = FALSE;
                        // Display the information dialog
                        if (bUIFeedback) {
                            // decrement download counter to prevent progress
                            // dialog from popping up while the message box is
                            // up
                            m_dlg->bundleInstallComplete();
                            if (dwErrorCode == E_JDHELPER_TIMEOUT) {
                                bRetryHttpRequest = 
                                    (IDRETRY == m_dlg->SafeMessageBox(
                                       IDS_HTTP_STATUS_REQUEST_TIMEOUT, 
                                       IDS_HTTP_INSTRUCTION_REQUEST_TIMEOUT, 
                                       IDS_ERROR_CAPTION, 
                                       DIALOG_ERROR_RETRYCANCEL));
                            } else {
                                bRetryHttpRequest = 
                                    (IDRETRY == m_dlg->SafeMessageBox(
                                       IDS_HTTP_STATUS_SERVER_NOT_REACHABLE, 
                                       IDS_HTTP_INSTRUCTION_SERVER_NOT_REACHABLE, 
                                       IDS_ERROR_CAPTION, 
                                       DIALOG_ERROR_RETRYCANCEL));
                            }
                            // re-increment counter because it will be decremented
                            // again upon return
                            m_dlg->bundleInstallStart();
                            bCont = bRetryHttpRequest;
                        }
                        break;
                    }
                    case ERROR_INTERNET_INVALID_CA:
                    case ERROR_INTERNET_SEC_CERT_CN_INVALID:
                    case ERROR_INTERNET_SEC_CERT_DATE_INVALID:
                    case ERROR_INTERNET_HTTP_TO_HTTPS_ON_REDIR:
                    case ERROR_INTERNET_INCORRECT_PASSWORD:
                    case ERROR_INTERNET_CLIENT_AUTH_CERT_NEEDED:
                    default: {
                        // Unless the user agrees to continue, we just 
                        // abandon now !
                        bCont = FALSE;
                        
                        // Make sure to test the return code from 
                        // InternetErrorDlg user may click OK or Cancel. In 
                        // case of Cancel, request should not be resubmitted
                        if (bUIFeedback) {
                            if (ERROR_SUCCESS == ::InternetErrorDlg(
                                    NULL, hRequest,
                                    dwErrorCode,
                                    FLAGS_ERROR_UI_FILTER_FOR_ERRORS |
                                    FLAGS_ERROR_UI_FLAGS_GENERATE_DATA |
                                    FLAGS_ERROR_UI_FLAGS_CHANGE_OPTIONS,
                                    NULL))
                                bCont = TRUE;
                        }
                    }
                }
            }
            
            if (bCont == FALSE) {
                // User has denied the request
                dwDownloadError = 1;
                __leave;
            }
            
            //
            // Read HTTP status code
            //
            DWORD dwErrorCode = GetLastError();
            DWORD dwStatus=0;
            DWORD dwStatusSize = sizeof(DWORD);
            
            if (FALSE == ::HttpQueryInfo(hRequest, HTTP_QUERY_FLAG_NUMBER |
                    HTTP_QUERY_STATUS_CODE, &dwStatus, &dwStatusSize, NULL)) {
                dwErrorCode = GetLastError();
            }
            
            bCont = TRUE;
            while ((dwStatus == HTTP_STATUS_PROXY_AUTH_REQ ||
                    dwStatus == HTTP_STATUS_DENIED) &&
                    bCont) {
                int result = ::InternetErrorDlg(GetDesktopWindow(), hRequest, ERROR_INTERNET_INCORRECT_PASSWORD,
                        FLAGS_ERROR_UI_FILTER_FOR_ERRORS |
                        FLAGS_ERROR_UI_FLAGS_CHANGE_OPTIONS |
                        FLAGS_ERROR_UI_FLAGS_GENERATE_DATA,
                        NULL);
                if (ERROR_CANCELLED == result) {
                    bCont = FALSE;
                }
                else {
                    ::HttpSendRequest(hRequest, NULL, 0, NULL, 0);
                    
                    // Reset buffer length
                    dwStatusSize = sizeof(DWORD);
                    
                    ::HttpQueryInfo(hRequest, HTTP_QUERY_FLAG_NUMBER |
                            HTTP_QUERY_STATUS_CODE, &dwStatus, &dwStatusSize,
                            NULL);
                }
            }
            
            if (dwStatus == HTTP_STATUS_OK || 
                    dwStatus == HTTP_STATUS_PARTIAL_CONTENT) {
                // Determine content length, so we may show the progress bar
                // meaningfully
                //
                nContentLength = 0;
                DWORD nLengthSize = sizeof(DWORD);
                ::HttpQueryInfo(hRequest, 
                        HTTP_QUERY_CONTENT_LENGTH | HTTP_QUERY_FLAG_NUMBER,
                        &nContentLength, &nLengthSize, NULL);
                
                if (nContentLength <= 0) {
                    // If can't estimate content length, estimate it
                    // to be 6MB
                    nContentLength = 15000000;
                }
                else if (rangereq && (fileSize != 0) &&
                        (nContentLength == fileSize)) {
                    // If the file is already downloaded completely and then
                    // we send a range request, the whole file is sent instead
                    // of nothing. So avoid downloading again.
                    // Some times return value is 206, even when whole file
                    // is sent. So check if "Content-range:" is present in the 
                    // reply
                    char buffer[256];
                    DWORD length = sizeof(buffer);
                    if(!HttpQueryInfo(hRequest, HTTP_QUERY_CONTENT_RANGE, 
                            buffer, &length, NULL)) {
                        if(HttpQueryInfo(hRequest, HTTP_QUERY_LAST_MODIFIED,
                                buffer, &length, NULL)) {
                            SYSTEMTIME systime;
                            FILETIME filtime;
                            InternetTimeToSystemTime(buffer, &systime, NULL);
                            SystemTimeToFileTime(&systime, &filtime);
                            if ((CompareFileTime(&tWrite, &filtime)) == 1) {
                                // no need to download
                                dwDownloadError = 0;
                                __leave;
                            }
                        }
                        else {
                            ::SetFilePointer(hFile, 0, 0, FILE_BEGIN);
                            ::SetEndOfFile(hFile); // truncate the file
                        }
                    }
                    
                }
                
                TCHAR szBuffer[8096];
                DWORD dwBufferSize = 8096;
                
                // Read from HTTP connection and write into
                // destination file
                //
                DWORD nRead = 0;
                DWORD dwTotalRead = 0;
                BOOL bCancel = FALSE;
                
                if (dwStatus == HTTP_STATUS_PARTIAL_CONTENT) {
                    // If we are using resumable download, fake
                    // start time so it looks like we have begun
                    // the download several minutes again.
                    //
                    m_startTime = m_startTime - 100;
                    
                    ::SetFilePointer(hFile, 0, 0, FILE_END); // seek to end
                }
                else {
                    ::SetFilePointer(hFile, 0, 0, FILE_BEGIN);
                    ::SetEndOfFile(hFile); // truncate the file
                }
                
                do {
                    nRead=0;
                    
                    if (::InternetReadFile(hRequest, szBuffer, dwBufferSize, 
                            &nRead)) {
                        if (nRead) {
                            DWORD dwNumberOfBytesWritten = NULL;
                            
                            BOOL ret = WriteFile(hFile, szBuffer, nRead,
                                    &dwNumberOfBytesWritten, NULL);
                            
                            if (!ret) {
                                // WriteFile failed
                                if (bUIFeedback) {
                                    if (GetLastError() == ERROR_DISK_FULL) {
                                       bRetryHttpRequest = 
                                            (IDRETRY == m_dlg->SafeMessageBox(
                                            IDS_DISK_FULL_ERROR, 
                                            IDS_DISK_FULL_ERROR_CAPTION, 
                                            IDS_ERROR_CAPTION, 
                                            DIALOG_ERROR_RETRYCANCEL, 
                                            wName));
                                    } else {
                                        bRetryHttpRequest = 
                                            (IDRETRY == m_dlg->SafeMessageBox(
                                            IDS_DISK_WRITE_ERROR, 
                                            IDS_DISK_WRITE_ERROR_CAPTION, 
                                            IDS_ERROR_CAPTION, 
                                            DIALOG_ERROR_RETRYCANCEL,
                                            wName));
                                    }
                                    if (!bRetryHttpRequest) {
                                        dwDownloadError = 1;
                                        break;
                                    }
                                }
                                continue;
                            }
                        }
                        
                        dwTotalRead += nRead;
                        
                        // update download progress dialog
                        m_dlg->OnProgress(nRead);
                        // Check if download has been cancelled
                        if (m_dlg->isDownloadCancelled()) {
                            m_dlg->decrementProgressMax(nContentLength, 
                                    dwTotalRead);
                            bCancel = TRUE;
                            break;
                        }
                        
                    }
                    else {
                        bCancel = TRUE;
                        break;
                    }
                }
                while (nRead);
                
                
                if (bCancel) {
                    // User has cancelled the operation or InternetRead failed
                    // don't do return here, we need to cleanup
                    dwDownloadError = 1;
                    __leave;
                }
            }
            else if (dwStatus == 416 && (fileSize != 0) &&
                    (fileSize != 0xFFFFFFFF)) {
                // This error could be returned, When the full file exists
                // and a range request is sent with range beyond filessize.
                // The best way to fix this is in future is, to send HEAD
                // request and get filelength before sending range request.
                dwDownloadError = 0;
                __leave;
            }
            else if (dwStatus == 403) { // Forbidden from Akamai means we need to get a new download token
                JNIEnv *env = m_dlg->getJNIEnv();
                jclass exceptionClass = env->FindClass("java/net/HttpRetryException");
                if (exceptionClass == NULL) {
                    /* Unable to find the exception class, give up. */
                    __leave;
                }
                jmethodID constructor;
                constructor = env->GetMethodID(exceptionClass,
                               "<init>", "(Ljava/lang/String;I)V");
                if (constructor != NULL) {
                    jobject exception = env->NewObject(exceptionClass, 
                            constructor, env->NewStringUTF("Forbidden"), 
                            403);
                    env->Throw((jthrowable) exception);
                }
                __leave;
            }
            else if(dwStatus >= 400 && dwStatus < 600) {
                /* NB: Following case seems to be never used!

                   HTTP_STATUS_FORBIDDEN is the same as 403 and
                   403 was specially handled few lines above! */ 
                if (dwStatus == HTTP_STATUS_FORBIDDEN) {
                    if (bUIFeedback) {
                        bRetryHttpRequest = (IDRETRY == m_dlg->SafeMessageBox(
                                            IDS_HTTP_STATUS_FORBIDDEN, 
                                            IDS_HTTP_INSTRUCTION_FORBIDDEN, 
                                            IDS_ERROR_CAPTION, 
                                            DIALOG_ERROR_RETRYCANCEL, 
                                            L"403"));
                    }
                }
                else if (dwStatus == HTTP_STATUS_SERVER_ERROR) {
                    if (bUIFeedback) {
                       bRetryHttpRequest = (IDRETRY == m_dlg->SafeMessageBox(
                                            IDS_HTTP_STATUS_SERVER_ERROR, 
                                            IDS_HTTP_INSTRUCTION_UNKNOWN_ERROR, 
                                            IDS_ERROR_CAPTION, 
                                            DIALOG_ERROR_RETRYCANCEL, 
                                            L"500"));
                    }
                }
                else if (dwStatus == HTTP_STATUS_SERVICE_UNAVAIL) {
                    if (numberOfRetry < 5) {
                        // If the server is busy, automatically retry
                        
                        // We wait couple seconds before retry to avoid 
                        // congestion
                        for (long i = (long) secondsToWait; i >= 0; i--) {
                            // Update status
                            if (bUIFeedback) {
                                char szBuffer[BUFFER_SIZE];
                                ::LoadString(_Module.GetResourceInstance(), 
                                        IDS_DOWNLOAD_STATUS_RETRY, szStatus, 
                                        BUFFER_SIZE);
                                wsprintf(szBuffer, szStatus, i);
                                
                                ::SetWindowText(hProgressInfo, szBuffer);
                            }
                            
                            // Sleep 1 second
                            ::Sleep(1000);
                        }
                        
                        // We use a semi-binary backoff algorithm to
                        // determine seconds to wait
                        numberOfRetry += 1;
                        secondsToWait = secondsToWait + 30;
                        bRetryHttpRequest = TRUE;
                        
                        continue;
                    }
                    else {
                        if (bUIFeedback) {
                            bRetryHttpRequest = (IDRETRY == m_dlg->SafeMessageBox(
                                            IDS_HTTP_STATUS_SERVICE_UNAVAIL, 
                                            IDS_HTTP_INSTRUCTION_SERVICE_UNAVAIL,
                                            IDS_ERROR_CAPTION, 
                                            DIALOG_ERROR_RETRYCANCEL,
                                            L"503"));

                            if (bRetryHttpRequest) {
                                numberOfRetry = 0;
                                secondsToWait = 60;
                                continue;
                            }
                        }
                    }
                }
                else {
                    if (bUIFeedback) {
                        WCHAR szBuffer[10];
                        _snwprintf(szBuffer, 10, L"%d", dwStatus);
                        bRetryHttpRequest = (IDRETRY == m_dlg->SafeMessageBox(
                                            IDS_HTTP_STATUS_OTHER, 
                                            IDS_HTTP_INSTRUCTION_UNKNOWN_ERROR, 
                                            IDS_ERROR_CAPTION, 
                                            DIALOG_ERROR_RETRYCANCEL,
                                            szBuffer));
                    }
                }
                if (!bRetryHttpRequest) {                
                    dwDownloadError = 1;
                }
            }
            else {
                if (bUIFeedback) {
                    WCHAR szBuffer[10];
                    _snwprintf(szBuffer, 10, L"%d", dwStatus);
                    bRetryHttpRequest = (IDRETRY == m_dlg->SafeMessageBox(
                                            IDS_HTTP_STATUS_OTHER, 
                                            IDS_HTTP_INSTRUCTION_UNKNOWN_ERROR, 
                                            IDS_ERROR_CAPTION, 
                                            DIALOG_ERROR_RETRYCANCEL,
                                            szBuffer));
                }
                if (!bRetryHttpRequest) {
                    dwDownloadError = 1;
                }
            }
            
            
            
            // Close HTTP request
            //
            // This is necessary if the HTTP request
            // is retried
            if (hRequest)
                ::InternetCloseHandle(hRequest);
            if (hFile != INVALID_HANDLE_VALUE) {
                ::CloseHandle(hFile);
                hFile = INVALID_HANDLE_VALUE;
            }
        }
        while (bRetryHttpRequest);
    }
    __finally {
        if (hRequest)
            ::InternetCloseHandle(hRequest);
        
        if (hConnect)
            ::InternetCloseHandle(hConnect);
        
        if (hOpen)
            ::InternetCloseHandle(hOpen);
        
        if (hFile != INVALID_HANDLE_VALUE)
            ::CloseHandle(hFile);
    }
    
    
    
    // Exit dialog
    if (dwDownloadError == 0) {
        return S_OK;
    } else {
        DeleteFile(szLocalFile);
        return E_FAIL;
    }
}
extern "C" int WINAPI _tWinMain(HINSTANCE hInstance,
                                HINSTANCE /*hPrevInstance*/, LPTSTR lpCmdLine, int /*nShowCmd*/)
{
#if _WIN32_WINNT >= 0x0400 & defined(_ATL_FREE_THREADED)
    HRESULT hRes = CoInitializeEx(NULL, COINIT_MULTITHREADED);
#else
    HRESULT hRes = CoInitialize(NULL);
#endif
    _ASSERTE(SUCCEEDED(hRes));
    _Module.Init(ObjectMap, hInstance, NULL);

    int nRet = 0;

    // Various mode of operation
    BOOL bSilentMode = FALSE;


    TCHAR szTargetBaseVersionInfo[256];
    TCHAR szTargetNewVersionInfo[256];

    // Open patch trace file
    OPEN_PATCH_TRACEFILE();

    do
    {
        TCHAR szDirectory[BUFFER_SIZE];
        szDirectory[0] = NULL;

        //---------------------------------------------------
        // Parse parameters from command line
        //
        if ((__argc == 2) ||
                (__argc == 3 && lstrcmpi(__argv[1], TEXT("-s")) == 0))
        {
            // jupdate [-s] dir (Apply patch)
            //
            wsprintf(szDirectory, "%s", __argv[__argc - 1]);

            //---------------------------------------------------
            // Remove trailing '\' in path (#4689837)
            //
            int iPathLen = lstrlen(szDirectory);

            if (szDirectory[iPathLen - 1] == '\\' || szDirectory[iPathLen - 1] == '\"')
                szDirectory[iPathLen - 1] = NULL;

            if (__argc == 3)
                bSilentMode = TRUE;
        }
        else
        {
            // Invalid options
            nRet = UPDATE_ERROR_OPTIONS;
            break;
        }

        //---------------------------------------------------
        // Check if VM is running
        //
        UINT uRet = IDRETRY;

        while (IsVMRunning(szDirectory) && uRet == IDRETRY)
        {
            /*
            	    // Should not ask user if we are in silent mode
            	    if (bSilentMode)
            	    {
            		nRet = UPDATE_ERROR_VM_RUNNING;
            		break;
            	    }
            	    else
            */	    {
                TCHAR szBuffer[BUFFER_SIZE], szMessage[BUFFER_SIZE], szCaption[BUFFER_SIZE];
                ::LoadString(_Module.GetResourceInstance(), IDS_ERROR_VM_RUNNING, szBuffer, BUFFER_SIZE);
                ::LoadString(_Module.GetResourceInstance(), IDS_CAPTION_WARNING, szCaption, BUFFER_SIZE);

                wsprintf(szMessage, szBuffer, NEW_IMAGE_FULLVERSION);

                uRet = MessageBox(NULL, szMessage, szCaption, MB_RETRYCANCEL | MB_ICONWARNING);
            }
        }

        // Make sure we break out of the loop
        if (nRet == UPDATE_ERROR_VM_RUNNING)
            break;

        if (uRet == IDCANCEL)
        {
            nRet = UPDATE_ERROR_VM_RUNNING;
            break;
        }


        //---------------------------------------------------
        // Retrieve version info of patched image and base image
        //
        // Retrieve version info of base image
        if (RetrievePatchInfo(szDirectory, szTargetBaseVersionInfo) == FALSE)
        {
            // Cannot locate version.dat
            nRet = UPDATE_ERROR_VERSIONINFO;
            break;
        }

        wsprintf(szTargetNewVersionInfo, "%s", szTargetBaseVersionInfo);

        // Check if directory has been patched
        //
        /*	if (stricmp(szTargetNewVersionInfo, NEW_IMAGE_FULLVERSION) == 0)
        	{
        	    nRet = UPDATE_ERROR_SAME_VERSION_INSTALLED;
        	    break;

        	    // Check if a newer patch has been installed
        	    else if (stricmp(szTargetNewBuildNumber, NEW_IMAGE_BUILD_NUMBER) > 0)
        	    {
        		nRet = UPDATE_ERROR_NEWER_VERSION_INSTALLED;
        		break;
        	    }
        	}
        */

        //-----------------------------------------
        // Perform actual patching
        //

        // If we can't found the base image, see if the targeted directory
        // can be used as the base image
        if (stricmp(szTargetBaseVersionInfo, BASE_IMAGE_FULLVERSION) != 0
                && stricmp(szTargetBaseVersionInfo, NEW_IMAGE_FULLVERSION) != 0)
        {
            // Cannot locate any valid base image
            nRet = UPDATE_ERROR_INVALID_BASE_IMAGE;
            break;
        }


        if (bSilentMode)
        {
            // Patch silently
            if (ApplyPatch(szDirectory, "", SilentUpdateCallBack) == FALSE)
            {
                nRet = UPDATE_ERROR_PATCH;
                break;
            }
        }
        else
        {
            // Patch installer dialog
            CPatchDialog dlg;

            // Set directory to apply the patch
            dlg.setCommandLine(szDirectory, NULL);

            // Execute Installation ...
            if (dlg.DoModal() != IDOK)
            {
                nRet = UPDATE_ERROR_PATCH;
                break;
            }
        }
    }
    while (0);


    // Show dialogs for success/failure
    //
    TCHAR szBuffer[BUFFER_SIZE], szMessage[BUFFER_SIZE], szCaption[BUFFER_SIZE];

    switch (nRet)
    {
    case 0:
    {
        ::LoadString(_Module.GetResourceInstance(), IDS_INSTALL_SUCCESS, szBuffer, BUFFER_SIZE);
        ::LoadString(_Module.GetResourceInstance(), IDS_CAPTION_SUCCEEDED, szCaption, BUFFER_SIZE);

        wsprintf(szMessage, szBuffer, NEW_IMAGE_FULLVERSION);

        DisplayInfo(bSilentMode, szMessage, szCaption);

        break;
    }
    case UPDATE_ERROR_OPTIONS:
    {
        ::LoadString(_Module.GetResourceInstance(), IDS_OPTIONS, szBuffer, BUFFER_SIZE);
        ::LoadString(_Module.GetResourceInstance(), IDS_CAPTION_ERROR, szCaption, BUFFER_SIZE);

        char* lpszPath = strrchr(__argv[0], '\\');

        if (lpszPath != NULL)
            wsprintf(szMessage, szBuffer, lpszPath + 1);
        else
            wsprintf(szMessage, szBuffer, __argv[0]);

        DisplayError(bSilentMode, szMessage, szCaption);

        break;
    }

    case UPDATE_ERROR_PATCH:
    {
        ::LoadString(_Module.GetResourceInstance(), IDS_ERROR_UPDATE, szMessage, BUFFER_SIZE);
        ::LoadString(_Module.GetResourceInstance(), IDS_CAPTION_ERROR, szCaption, BUFFER_SIZE);

        DisplayError(bSilentMode, szMessage, szCaption);

        break;
    }
    case UPDATE_ERROR_VERSIONINFO:
    {
        ::LoadString(_Module.GetResourceInstance(), IDS_ERROR_VERSIONINFO, szMessage, BUFFER_SIZE);
        ::LoadString(_Module.GetResourceInstance(), IDS_CAPTION_ERROR, szCaption, BUFFER_SIZE);

        DisplayError(bSilentMode, szMessage, szCaption);

        break;
    }
    case UPDATE_ERROR_INVALID_BASE_IMAGE:
    {
        ::LoadString(_Module.GetResourceInstance(), IDS_ERROR_BASE_IMAGE_NOT_FOUND, szBuffer, BUFFER_SIZE);
        ::LoadString(_Module.GetResourceInstance(), IDS_CAPTION_ERROR, szCaption, BUFFER_SIZE);

        wsprintf(szMessage, szBuffer, NEW_IMAGE_FULLVERSION, BASE_IMAGE_FULLVERSION);

        DisplayError(bSilentMode, szMessage, szCaption);

        break;
    }
    case UPDATE_ERROR_SAME_VERSION_INSTALLED:
    {
        ::LoadString(_Module.GetResourceInstance(), IDS_ERROR_INSTALLED_SAME_VERSION, szBuffer, BUFFER_SIZE);
        ::LoadString(_Module.GetResourceInstance(), IDS_CAPTION_SUCCEEDED, szCaption, BUFFER_SIZE);

        wsprintf(szMessage, szBuffer, NEW_IMAGE_FULLVERSION);

        DisplayInfo(bSilentMode, szMessage, szCaption);

        break;
    }
    case UPDATE_ERROR_NEWER_VERSION_INSTALLED:
    {
        ::LoadString(_Module.GetResourceInstance(), IDS_ERROR_INSTALLED_NEWER_VERSION, szBuffer, BUFFER_SIZE);
        ::LoadString(_Module.GetResourceInstance(), IDS_CAPTION_ERROR, szCaption, BUFFER_SIZE);

        wsprintf(szMessage, szBuffer, NEW_IMAGE_FULLVERSION, szTargetNewVersionInfo);

        DisplayError(bSilentMode, szMessage, szCaption);

        break;
    }
    case UPDATE_ERROR_WRONG_VERSION_UNINSTALLED:
    {
        ::LoadString(_Module.GetResourceInstance(), IDS_ERROR_UNINSTALL_WRONG_VERSION, szBuffer, BUFFER_SIZE);
        ::LoadString(_Module.GetResourceInstance(), IDS_CAPTION_ERROR, szCaption, BUFFER_SIZE);

        wsprintf(szMessage, szBuffer, NEW_IMAGE_FULLVERSION, szTargetNewVersionInfo);

        DisplayError(bSilentMode, szMessage, szCaption);

        break;
    }
    case UPDATE_ERROR_VM_RUNNING:
    {
        PATCH_TRACE("FAIL: VM is currently running.\n");
        break;
    }
    };


    // Close patch trace file
    CLOSE_PATCH_TRACEFILE();


    _Module.Term();
    CoUninitialize();

    if (nRet == 0)
        return 0;
    else
        return ERROR_INSTALL_FAILURE;
}