jdk/src/windows/native/sun/jkernel/DownloadDialog.cpp
changeset 8197 e45f21c2a40b
parent 7867 f83cd8bd35c6
child 8198 aca2f99e4b52
equal deleted inserted replaced
7867:f83cd8bd35c6 8197:e45f21c2a40b
     1 /*
       
     2  * Copyright (c) 2008, 2010, Oracle and/or its affiliates. All rights reserved.
       
     3  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
       
     4  *
       
     5  * This code is free software; you can redistribute it and/or modify it
       
     6  * under the terms of the GNU General Public License version 2 only, as
       
     7  * published by the Free Software Foundation.  Oracle designates this
       
     8  * particular file as subject to the "Classpath" exception as provided
       
     9  * by Oracle in the LICENSE file that accompanied this code.
       
    10  *
       
    11  * This code is distributed in the hope that it will be useful, but WITHOUT
       
    12  * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
       
    13  * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
       
    14  * version 2 for more details (a copy is included in the LICENSE file that
       
    15  * accompanied this code).
       
    16  *
       
    17  * You should have received a copy of the GNU General Public License version
       
    18  * 2 along with this work; if not, write to the Free Software Foundation,
       
    19  * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
       
    20  *
       
    21  * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
       
    22  * or visit www.oracle.com if you need additional information or have any
       
    23  * questions.
       
    24  */
       
    25 
       
    26 #if _MSC_VER > 1000
       
    27 #pragma once
       
    28 #endif // _MSC_VER > 1000
       
    29 
       
    30 #define STRICT
       
    31 #ifndef _WIN32_WINNT
       
    32 /* REMIND : 0x500 means Windows 2000 .. seems like we can update
       
    33  * for Windows XP when we move the SDK and build platform
       
    34  */
       
    35 #define _WIN32_WINNT 0x0500
       
    36 #endif
       
    37 #define _ATL_APARTMENT_THREADED
       
    38 
       
    39 #include <atlbase.h>
       
    40 //You may derive a class from CComModule and use it if you want to override
       
    41 //something, but do not change the name of _Module
       
    42 extern CComModule _Module;
       
    43 #include <atlcom.h>
       
    44 #include <atlwin.h>
       
    45 
       
    46 #include <atlhost.h>
       
    47 #include <commdlg.h>
       
    48 #include <commctrl.h>
       
    49 #include <windowsx.h>
       
    50 #include <urlmon.h>
       
    51 #include <wininet.h>
       
    52 #include <shellapi.h>
       
    53 #include <time.h>
       
    54 #include <math.h>
       
    55 #include <stdio.h>
       
    56 #include <jni.h>
       
    57 
       
    58 #include "DownloadDialog.h"
       
    59 
       
    60 #define UPDATE_INTERVAL 500
       
    61 #define INITIAL_DELAY 2000
       
    62 #define POST_DELAY 1000
       
    63 
       
    64 /////////////////////////////////////////////////////////////////////////////
       
    65 // CDownloadDialog
       
    66 
       
    67 typedef BOOL (WINAPI * InitCommonControlsType)();
       
    68 
       
    69 CDownloadDialog::CDownloadDialog()
       
    70 {
       
    71     m_numDownloadThreadsRunning = 0;
       
    72 
       
    73     m_destroyWindowTimerStarted = FALSE;
       
    74     m_pszFileName = NULL;
       
    75     m_jvm = NULL;
       
    76 
       
    77     m_ulProgress = 0;
       
    78     m_ulProgressMax = 0;
       
    79     m_iProgressFactor = 0;
       
    80     m_iMaxProgressFactor = 1;
       
    81 
       
    82 
       
    83     m_hCancelEvent = ::CreateEvent(NULL, TRUE, FALSE, NULL);
       
    84     m_hDownloadThreadExitEvent = ::CreateEvent(NULL, TRUE, FALSE, NULL);
       
    85     m_hDialogInitializedEvent = ::CreateEvent(NULL, TRUE, FALSE, NULL);
       
    86 
       
    87     // Load up commctrl.dll
       
    88     // Loading dll dynamically we can use latest available version
       
    89     // (i.e. latest native components and extended API)
       
    90     HMODULE hModComCtl32 = ::LoadLibrary(TEXT("comctl32.dll"));
       
    91     if (hModComCtl32 != NULL) {
       
    92         /* Initialize controls to ensure proper appearance */
       
    93         InitCommonControlsType fn_InitCommonControls = (InitCommonControlsType)
       
    94             ::GetProcAddress(hModComCtl32, "InitCommonControls");
       
    95         fn_InitCommonControls();
       
    96 
       
    97         /* MessageBox replacement introduced in Vista */
       
    98         taskDialogFn = (TaskDialogIndirectFn)
       
    99             ::GetProcAddress(hModComCtl32, "TaskDialogIndirect");
       
   100     }
       
   101 }
       
   102 
       
   103 
       
   104 CDownloadDialog::~CDownloadDialog()
       
   105 {
       
   106     ::CloseHandle(m_hCancelEvent);
       
   107     ::CloseHandle(m_hDownloadThreadExitEvent);
       
   108     ::CloseHandle(m_hDialogInitializedEvent);
       
   109 }
       
   110 
       
   111 void CDownloadDialog::addToTotalContentLength(DWORD contentLength) {
       
   112      __try
       
   113     {
       
   114         m_csDownload.Lock();
       
   115         if (m_ulProgressMax == 0) {
       
   116             // first download this session, initialize start time
       
   117             time(&m_startTime);
       
   118         }
       
   119 
       
   120         m_ulProgressMax = m_ulProgressMax + contentLength;
       
   121         logProgress();
       
   122     }
       
   123     __finally
       
   124     {
       
   125         m_csDownload.Unlock();
       
   126     }
       
   127 }
       
   128 
       
   129 
       
   130 
       
   131 void CDownloadDialog::initDialogText(LPCTSTR downloadURL, LPCTSTR bundleName) {
       
   132 
       
   133     // reset status text
       
   134     HWND hStatusWnd = GetDlgItem(IDC_TIME_REMAINING);
       
   135     ::SetWindowText(hStatusWnd, "");
       
   136 
       
   137     // reset progress bar
       
   138     HWND hProgressWnd = GetDlgItem(IDC_DOWNLOAD_PROGRESS);
       
   139 
       
   140     ::PostMessage(hProgressWnd, PBM_SETPOS, (WPARAM) 0, NULL);
       
   141 
       
   142     m_hMastheadFont = NULL;
       
   143     m_hDialogFont = NULL;
       
   144     m_hSixPointFont = NULL;
       
   145 
       
   146     m_hMemDC = NULL;
       
   147 
       
   148     TCHAR szDownloadText[BUFFER_SIZE];
       
   149 
       
   150     HWND hWndDownloadText = GetDlgItem(IDC_DOWNLOAD_TEXT);
       
   151     ::LoadString(_Module.GetModuleInstance(), IDS_DOWNLOAD_TEXT, szDownloadText, BUFFER_SIZE);
       
   152     ::SetWindowText(hWndDownloadText, szDownloadText);
       
   153 
       
   154     TCHAR szMasthead[BUFFER_SIZE];
       
   155 
       
   156     HWND hWndMastheadText = GetDlgItem(IDC_MASTHEAD_TEXT);
       
   157     ::LoadString(_Module.GetModuleInstance(), IDS_DOWNLOAD, szMasthead, BUFFER_SIZE);
       
   158     ::SetWindowText(hWndMastheadText, szMasthead);
       
   159 
       
   160 
       
   161 }
       
   162 
       
   163 BOOL CDownloadDialog::isDownloading() {
       
   164     return m_numDownloadThreadsRunning > 0;
       
   165 }
       
   166 
       
   167 
       
   168 void CDownloadDialog::bundleInstallStart() {
       
   169     __try
       
   170     {
       
   171         m_csNumDownloadThreads.Lock();
       
   172         m_numDownloadThreadsRunning++;
       
   173         // another download request has came in, kill the destroyWindowTimer
       
   174         KillTimer(destroyWindowTimerID);
       
   175         m_destroyWindowTimerStarted = FALSE;
       
   176     }
       
   177     __finally
       
   178     {
       
   179         m_csNumDownloadThreads.Unlock();
       
   180     }
       
   181 }
       
   182 
       
   183 void CDownloadDialog::bundleInstallComplete() {
       
   184     __try
       
   185     {
       
   186         m_csNumDownloadThreads.Lock();
       
   187         m_numDownloadThreadsRunning = max(m_numDownloadThreadsRunning - 1, 0);
       
   188         if (m_numDownloadThreadsRunning == 0) {
       
   189             m_ulProgress = m_ulProgressMax;
       
   190             logProgress();
       
   191         }
       
   192         // Signal main thread
       
   193         ::SetEvent(m_hDownloadThreadExitEvent);
       
   194     }
       
   195     __finally
       
   196     {
       
   197         m_csNumDownloadThreads.Unlock();
       
   198     }
       
   199 }
       
   200 
       
   201 
       
   202 //=--------------------------------------------------------------------------=
       
   203 // CDownloadDialog::OnInitDialog
       
   204 //=--------------------------------------------------------------------------=
       
   205 // Message handler for WM_INITDIALOG
       
   206 //
       
   207 // Parameters:
       
   208 //      uMsg        Windows Message
       
   209 //      wParam      WPARAM
       
   210 //      lParam      LPARAM
       
   211 //      bHandled    FALSE if not handled
       
   212 //
       
   213 // Output:
       
   214 //      LRESULT
       
   215 //
       
   216 // Notes:
       
   217 //
       
   218 LRESULT CDownloadDialog::OnInitDialog(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL& bHandled)
       
   219 {
       
   220      __try
       
   221     {
       
   222         m_csDownload.Lock();
       
   223     }
       
   224     __finally
       
   225     {
       
   226         m_csDownload.Unlock();
       
   227     }
       
   228     // Set timer
       
   229     SetTimer(iTimerID, UPDATE_INTERVAL);
       
   230 
       
   231     m_hMastheadFont = NULL;
       
   232     m_hDialogFont = NULL;
       
   233     m_hSixPointFont = NULL;
       
   234     m_feedbackOnCancel = TRUE;
       
   235 
       
   236     m_hMemDC = NULL;
       
   237 
       
   238     TCHAR szDownloadText[BUFFER_SIZE];
       
   239 
       
   240     HWND hWndDownloadText = GetDlgItem(IDC_DOWNLOAD_TEXT);
       
   241     ::LoadString(_Module.GetModuleInstance(), IDS_DOWNLOAD_TEXT, szDownloadText, BUFFER_SIZE);
       
   242     ::SetWindowText(hWndDownloadText, szDownloadText);
       
   243 
       
   244     TCHAR szMasthead[BUFFER_SIZE];
       
   245 
       
   246     HWND hWndMastheadText = GetDlgItem(IDC_MASTHEAD_TEXT);
       
   247     ::LoadString(_Module.GetModuleInstance(), IDS_DOWNLOAD, szMasthead, BUFFER_SIZE);
       
   248     ::SetWindowText(hWndMastheadText, szMasthead);
       
   249 
       
   250     HICON javaCupIcon = ::LoadIcon(_Module.GetModuleInstance(), MAKEINTRESOURCE(IDI_JAVA));
       
   251     SetIcon(javaCupIcon, FALSE);
       
   252 
       
   253     ::SetEvent(m_hDialogInitializedEvent);
       
   254 
       
   255     return 0;  // do not set initial focus to cancel button
       
   256 }
       
   257 
       
   258 
       
   259 //=--------------------------------------------------------------------------=
       
   260 // CDownloadDialog::OnOK
       
   261 //=--------------------------------------------------------------------------=
       
   262 // Message handler for WM_COMMAND with IDOK
       
   263 //
       
   264 // Parameters:
       
   265 //      wNotifyCode Notify Code
       
   266 //      wID         ID of control
       
   267 //      hWndCtl     HWND of control
       
   268 //      bHandled    FALSE if not handled
       
   269 //
       
   270 // Output:
       
   271 //      LRESULT
       
   272 //
       
   273 // Notes:
       
   274 //
       
   275 LRESULT CDownloadDialog::OnOK(WORD wNotifyCode, WORD wID, HWND hWndCtl, BOOL& bHandled)
       
   276 {
       
   277     // do nothing for now
       
   278     return 0;
       
   279 }
       
   280 
       
   281 
       
   282 
       
   283 //=--------------------------------------------------------------------------=
       
   284 // CDownloadDialog::OnCancel
       
   285 //=--------------------------------------------------------------------------=
       
   286 // Message handler for WM_COMMAND with IDCANCEL
       
   287 //
       
   288 // Parameters:
       
   289 //      wNotifyCode Notify Code
       
   290 //      wID         ID of control
       
   291 //      hWndCtl     HWND of control
       
   292 //      bHandled    FALSE if not handled
       
   293 //
       
   294 // Output:
       
   295 //      LRESULT
       
   296 //
       
   297 // Notes:
       
   298 //
       
   299 LRESULT CDownloadDialog::OnCancel(WORD wNotifyCode, WORD wID, HWND hWndCtl, BOOL& bHandled)
       
   300 {
       
   301     // Disable window first to avoid any keyboard input
       
   302     EnableWindow(FALSE);
       
   303 
       
   304     if (m_feedbackOnCancel) {
       
   305       int r = SafeMessageBox(IDS_DOWNLOAD_CANCEL_MESSAGE,
       
   306                        IDS_DOWNLOAD_CANCEL_INSTRUCTION,
       
   307                        IDS_DOWNLOAD_CANCEL_CAPTION,
       
   308                        DIALOG_WARNING_CANCELOK,
       
   309                        NULL, NULL);
       
   310       if (!::IsWindow(hWndCtl)) {
       
   311          /* It is possible that download was finished and download
       
   312             window hidden by the time user close this message box.
       
   313             If such case we should simply return. */
       
   314          return 0;
       
   315       }
       
   316       if (r == IDCANCEL) {
       
   317         EnableWindow(TRUE);
       
   318         return 0;
       
   319       }
       
   320     }
       
   321 
       
   322     __try
       
   323     {
       
   324         m_csDownload.Lock();
       
   325         // if we are downloading, signal download thread to stop downloading
       
   326         if (m_numDownloadThreadsRunning > 0) {
       
   327             SetEvent(m_hCancelEvent);
       
   328         }
       
   329     }
       
   330     __finally
       
   331     {
       
   332         m_csDownload.Unlock();
       
   333     }
       
   334 
       
   335     // Kill timer
       
   336     KillTimer(iTimerID);
       
   337     KillTimer(destroyWindowTimerID);
       
   338 
       
   339     FreeGDIResources();
       
   340 
       
   341     // Destroy dialog
       
   342     EndDialog(wID);
       
   343 
       
   344     return 0;
       
   345 }
       
   346 
       
   347 void CDownloadDialog::destroyDialog() {
       
   348     m_feedbackOnCancel = FALSE;
       
   349     ::PostMessage(m_hWnd, WM_COMMAND, IDCANCEL, NULL);
       
   350 }
       
   351 
       
   352 
       
   353 void CDownloadDialog::delayedDoModal() {
       
   354      __try
       
   355     {
       
   356          __try
       
   357         {
       
   358             m_csMessageBox.Lock();
       
   359             m_dialogUp = true;
       
   360             Sleep(INITIAL_DELAY);
       
   361         }
       
   362         __finally
       
   363         {
       
   364             m_csMessageBox.Unlock();
       
   365         }
       
   366 
       
   367         if (isDownloading())
       
   368             DoModal();
       
   369     }
       
   370     __finally
       
   371     {
       
   372         m_dialogUp = false;
       
   373     }
       
   374 }
       
   375 
       
   376 
       
   377 //=--------------------------------------------------------------------------=
       
   378 // CDownloadDialog::SafeMessageBox
       
   379 //=--------------------------------------------------------------------------=
       
   380 // Helper method that uses best availble API to show native error/information
       
   381 // dialog. In particular, it uses TaskDialog if availble (Vista specific)
       
   382 // and MessageBox otherwise.
       
   383 //
       
   384 // It also ensures that the message box is always displayed on top of
       
   385 // the progress dialog instead of underneath
       
   386 //
       
   387 
       
   388 //helper structures to define XP vs Vista style differences
       
   389 static TASKDIALOG_COMMON_BUTTON_FLAGS vistaDialogButtons[] = {
       
   390     TDCBF_RETRY_BUTTON | TDCBF_CANCEL_BUTTON,
       
   391     TDCBF_OK_BUTTON | TDCBF_CANCEL_BUTTON
       
   392 };
       
   393 static PCWSTR vistaIcons[] = {
       
   394     TD_ERROR_ICON,
       
   395     TD_WARNING_ICON
       
   396 };
       
   397 
       
   398 static UINT xpStyle[] = {
       
   399     MB_ICONERROR | MB_RETRYCANCEL,
       
   400     MB_ICONWARNING | MB_OKCANCEL | MB_DEFBUTTON2
       
   401 };
       
   402 
       
   403 int CDownloadDialog::SafeMessageBox(UINT details, UINT mainInstruction, UINT caption, DialogType type, LPCWSTR instructionArg, LPCWSTR detailsArg) {
       
   404     WCHAR textCaption[BUFFER_SIZE+1];
       
   405     WCHAR textDetails[BUFFER_SIZE+1];
       
   406     WCHAR textInstruction[BUFFER_SIZE+1];
       
   407     WCHAR tmpBuffer[BUFFER_SIZE+1];
       
   408 
       
   409     /* make sure buffers are terminated */
       
   410     textCaption[BUFFER_SIZE] = textDetails[BUFFER_SIZE] = 0;
       
   411     textInstruction[BUFFER_SIZE] = tmpBuffer[BUFFER_SIZE] = 0;
       
   412 
       
   413     if (detailsArg != NULL) {
       
   414         ::LoadStringW(_Module.GetResourceInstance(),
       
   415                  details,
       
   416                  tmpBuffer,
       
   417                  BUFFER_SIZE);
       
   418         _snwprintf(textDetails, BUFFER_SIZE, tmpBuffer, detailsArg);
       
   419     } else {
       
   420         ::LoadStringW(_Module.GetResourceInstance(),
       
   421                  details,
       
   422                  textDetails,
       
   423                  BUFFER_SIZE);
       
   424     }
       
   425 
       
   426     if (instructionArg != NULL) {
       
   427         ::LoadStringW(_Module.GetResourceInstance(),
       
   428                  mainInstruction,
       
   429                  tmpBuffer,
       
   430                  BUFFER_SIZE);
       
   431         _snwprintf(textInstruction, BUFFER_SIZE, tmpBuffer, instructionArg);
       
   432      } else {
       
   433         ::LoadStringW(_Module.GetResourceInstance(),
       
   434                  mainInstruction,
       
   435                  textInstruction,
       
   436                  BUFFER_SIZE);
       
   437      }
       
   438 
       
   439     ::LoadStringW(_Module.GetResourceInstance(),
       
   440                  caption,
       
   441                  textCaption,
       
   442                  BUFFER_SIZE);
       
   443 
       
   444     __try
       
   445     {
       
   446         m_csMessageBox.Lock();
       
   447         if (m_dialogUp) {
       
   448             waitUntilInitialized();
       
   449         }
       
   450         /* If TaskDialog availble - use it! */
       
   451         if (taskDialogFn != NULL) {
       
   452               TASKDIALOGCONFIG tc = { 0 };
       
   453               int nButton;
       
   454 
       
   455               tc.cbSize = sizeof(tc);
       
   456               tc.hwndParent = ::IsWindow(m_hWnd) ? m_hWnd : NULL;
       
   457               tc.dwCommonButtons = vistaDialogButtons[type];
       
   458               tc.pszWindowTitle = textCaption;
       
   459               tc.pszMainInstruction = textInstruction;
       
   460               tc.pszContent = textDetails;
       
   461               tc.pszMainIcon = vistaIcons[type];
       
   462               /* workaround: we need to make sure Cancel is default
       
   463                              for this type of Dialog */
       
   464               if (type == DIALOG_WARNING_CANCELOK) {
       
   465                   tc.nDefaultButton = IDCANCEL;
       
   466               }
       
   467 
       
   468               taskDialogFn(&tc, &nButton, NULL, NULL);
       
   469               return nButton;
       
   470         } else { /* default: use MessageBox */
       
   471             /* Note that MessageBox API expects content as single string
       
   472                and therefore we need to concatenate instruction
       
   473                and details as 2 paragraphs.
       
   474 
       
   475                The only exception is empty instruction. */
       
   476             if (wcslen(textInstruction) > 0) {
       
   477                 wcsncat(textInstruction, L"\n\n",
       
   478                         BUFFER_SIZE - wcslen(textInstruction));
       
   479             }
       
   480             wcsncat(textInstruction, textDetails,
       
   481                     BUFFER_SIZE - wcslen(textInstruction));
       
   482 
       
   483             return ::MessageBoxW(::IsWindow(m_hWnd) ? m_hWnd : NULL,
       
   484                 textInstruction, textCaption, xpStyle[type]);
       
   485         }
       
   486     }
       
   487     __finally
       
   488     {
       
   489         m_csMessageBox.Unlock();
       
   490     }
       
   491 }
       
   492 
       
   493 
       
   494 //=--------------------------------------------------------------------------=
       
   495 // CDownloadDialog::OnTimer
       
   496 //=--------------------------------------------------------------------------=
       
   497 // Message handler for WM_TIMER
       
   498 //
       
   499 // Parameters:
       
   500 //      uMsg        Windows Message
       
   501 //      wParam      WPARAM
       
   502 //      lParam      LPARAM
       
   503 //      bHandled    FALSE if not handled
       
   504 //
       
   505 // Output:
       
   506 //      LRESULT
       
   507 //
       
   508 // Notes:
       
   509 //
       
   510 LRESULT CDownloadDialog::OnTimer(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL& bHandled)
       
   511 {
       
   512     if (destroyWindowTimerID == (int)wParam) {
       
   513         KillTimer(destroyWindowTimerID);
       
   514         m_destroyWindowTimerStarted = FALSE;
       
   515         m_ulProgressMax = max(0, m_ulProgressMax - m_ulProgress);
       
   516         logProgress();
       
   517         m_ulProgress = 0;
       
   518         logProgress();
       
   519         m_feedbackOnCancel = FALSE;
       
   520         ::PostMessage(m_hWnd, WM_COMMAND, IDCANCEL, NULL);
       
   521     }
       
   522 
       
   523     if (iTimerID == (int)wParam)
       
   524     {
       
   525 
       
   526         __try
       
   527         {
       
   528             m_csDownload.Lock();
       
   529 
       
   530             HWND hStatusWnd = GetDlgItem(IDC_TIME_REMAINING);
       
   531             HWND hProgressWnd = GetDlgItem(IDC_DOWNLOAD_PROGRESS);
       
   532 
       
   533             if (m_ulProgress && m_ulProgressMax)
       
   534             {
       
   535                 ::PostMessage(hProgressWnd, PBM_SETPOS,
       
   536                      (WPARAM) (m_ulProgress * 100
       
   537                         / m_ulProgressMax), NULL);
       
   538 
       
   539                 time_t currentTime;
       
   540                 time(&currentTime);
       
   541 
       
   542                 double elapsed_time = difftime(currentTime, m_startTime);
       
   543                 double remain_time = (elapsed_time / m_ulProgress) *
       
   544                                       (m_ulProgressMax - m_ulProgress);
       
   545                 int hr = 0, min = 0;
       
   546 
       
   547                 if (remain_time > 60 * 60)
       
   548                 {
       
   549                     hr = int(remain_time / (60 * 60));
       
   550                     remain_time = remain_time - hr * 60 * 60;
       
   551                 }
       
   552 
       
   553                 if (remain_time > 60)
       
   554                 {
       
   555                     min = int(remain_time / 60);
       
   556                     remain_time = remain_time - min * 60;
       
   557                 }
       
   558 
       
   559                 TCHAR szBuffer[BUFFER_SIZE];
       
   560                 TCHAR szTimeBuffer[BUFFER_SIZE];
       
   561 
       
   562                 if (hr > 0)
       
   563                 {
       
   564                     if (hr > 1)
       
   565                         LoadString(_Module.GetResourceInstance(), IDS_HOURSMINUTESECOND,
       
   566                                    szTimeBuffer, BUFFER_SIZE);
       
   567                     else
       
   568                         LoadString(_Module.GetResourceInstance(), IDS_HOURMINUTESECOND,
       
   569                                    szTimeBuffer, BUFFER_SIZE);
       
   570 
       
   571                     sprintf(szBuffer, szTimeBuffer, hr, min, remain_time);
       
   572                 }
       
   573                 else
       
   574                 {
       
   575                     if (min > 0)
       
   576                     {
       
   577                         LoadString(_Module.GetResourceInstance(), IDS_MINUTESECOND,
       
   578                                    szTimeBuffer, BUFFER_SIZE);
       
   579                         sprintf(szBuffer, szTimeBuffer, min, remain_time);
       
   580 
       
   581                     }
       
   582                     else
       
   583                     {
       
   584                         LoadString(_Module.GetResourceInstance(), IDS_SECOND,
       
   585                                    szTimeBuffer, BUFFER_SIZE);
       
   586                         sprintf(szBuffer, szTimeBuffer, remain_time);
       
   587 
       
   588                     }
       
   589                 }
       
   590 
       
   591                 if (m_ulProgress == m_ulProgressMax) {
       
   592                     // download is done, unpacking bundle now, and waiting
       
   593                     // for another download to take place
       
   594                     ::LoadString(_Module.GetResourceInstance(),
       
   595                             IDS_DOWNLOAD_UNPACKING, szBuffer, BUFFER_SIZE);
       
   596                     __try
       
   597                     {
       
   598                         m_csNumDownloadThreads.Lock();
       
   599                         // both download and unpacking is done, start
       
   600                         // timer to destroy the progress window in 500ms
       
   601                         if (!m_destroyWindowTimerStarted &&
       
   602                                m_numDownloadThreadsRunning == 0) {
       
   603                             SetTimer(destroyWindowTimerID, POST_DELAY);
       
   604                             m_destroyWindowTimerStarted = TRUE;
       
   605                         }
       
   606                     }
       
   607                     __finally
       
   608                     {
       
   609                         m_csNumDownloadThreads.Unlock();
       
   610                     }
       
   611                 }
       
   612 
       
   613                 // Update status message
       
   614                 ::SetWindowText(hStatusWnd, szBuffer);
       
   615             }
       
   616         }
       
   617         __finally
       
   618         {
       
   619            m_csDownload.Unlock();
       
   620         }
       
   621     }
       
   622 
       
   623     return 0;
       
   624 }
       
   625 
       
   626 // Message handler for WM_ONCTLCOLORSTATIC.
       
   627 // this message is sent each time a static control is drawn.
       
   628 // we get the Control ID and then set background color and font
       
   629 // as appropriate for that control.
       
   630 LRESULT CDownloadDialog::OnCtlColorStatic(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL& bHandled)
       
   631 {
       
   632     HDC hdc = (HDC) wParam;
       
   633     HWND hwnd = (HWND) lParam;
       
   634 
       
   635     int DlgCtrlID = ::GetDlgCtrlID(hwnd);
       
   636 
       
   637     if (DlgCtrlID == IDC_DOWNLOAD_TEXT )
       
   638     {
       
   639         if (m_hDialogFont == NULL)
       
   640         {
       
   641             m_hDialogFont = CreateDialogFont(hdc, TEXT("MS Shell Dlg"), 8);
       
   642         }
       
   643 
       
   644         ::SelectObject(hdc, m_hDialogFont);
       
   645         return 0;
       
   646     }
       
   647     else if (DlgCtrlID == IDC_TIME_REMAINING)
       
   648     {
       
   649         if (m_hSixPointFont == NULL)
       
   650         {
       
   651             m_hSixPointFont = CreateDialogFont(hdc, TEXT("MS Shell Dlg"), 8);
       
   652         }
       
   653 
       
   654         ::SelectObject(hdc, m_hSixPointFont);
       
   655         return 0;
       
   656     }
       
   657     else if (DlgCtrlID == IDC_MASTHEAD_TEXT)
       
   658     {
       
   659         if (m_hMastheadFont == NULL)
       
   660         {
       
   661             m_hMastheadFont = CreateDialogFont(hdc, TEXT("MS Shell Dlg"), 12, 1);
       
   662         }
       
   663 
       
   664         ::SelectObject(hdc, m_hMastheadFont);
       
   665         return (LRESULT) GetStockObject(WHITE_BRUSH);
       
   666     }
       
   667     else if (DlgCtrlID == IDC_DOWNLOAD_MASTHEAD)
       
   668     {
       
   669         if (m_hMemDC == NULL)
       
   670         {
       
   671             m_hBitmap = LoadBitmap(_Module.GetModuleInstance(),
       
   672                                    MAKEINTRESOURCE(IDI_MASTHEAD));
       
   673             GetObject(m_hBitmap, sizeof(BITMAP), &m_bmMasthead);
       
   674             m_hMemDC = CreateCompatibleDC(NULL);
       
   675             SelectObject(m_hMemDC, m_hBitmap);
       
   676         }
       
   677 
       
   678         RECT rect;
       
   679         ::GetClientRect(hwnd, &rect);
       
   680 
       
   681         StretchBlt(hdc, rect.left, rect.top, (rect.right - rect.left), (rect.bottom - rect.top),
       
   682                    m_hMemDC, 0, 0, m_bmMasthead.bmWidth, m_bmMasthead.bmHeight, SRCCOPY);
       
   683 
       
   684         return (LRESULT) GetStockObject(NULL_BRUSH);
       
   685     }
       
   686 
       
   687 
       
   688     return 0;
       
   689 }
       
   690 
       
   691 
       
   692 //=--------------------------------------------------------------------------=
       
   693 // CDownloadDialog::OnStartBinding
       
   694 //=--------------------------------------------------------------------------=
       
   695 // Called when download is started
       
   696 //
       
   697 // Parameters:
       
   698 //
       
   699 // Output:
       
   700 //      HRESULT
       
   701 //
       
   702 // Notes:
       
   703 //
       
   704 STDMETHODIMP CDownloadDialog::OnStartBinding()
       
   705 {
       
   706     __try
       
   707     {
       
   708         m_csDownload.Lock();
       
   709         time(&m_startTime);
       
   710     }
       
   711     __finally
       
   712     {
       
   713         m_csDownload.Unlock();
       
   714     }
       
   715 
       
   716     return S_OK;
       
   717 }
       
   718 
       
   719 
       
   720 //=--------------------------------------------------------------------------=
       
   721 // CDownloadDialog::OnProgress
       
   722 //=--------------------------------------------------------------------------=
       
   723 // Called when download is in progress
       
   724 //
       
   725 // Parameters: ULONG ulProgress
       
   726 //
       
   727 // Output:
       
   728 //      HRESULT
       
   729 //
       
   730 // Notes:
       
   731 //
       
   732 STDMETHODIMP CDownloadDialog::OnProgress(ULONG ulProgress)
       
   733 {
       
   734     __try
       
   735     {
       
   736         m_csDownload.Lock();
       
   737         m_ulProgress = m_ulProgress + ulProgress;
       
   738         logProgress();
       
   739 
       
   740     }
       
   741     __finally
       
   742     {
       
   743         m_csDownload.Unlock();
       
   744     }
       
   745 
       
   746     return S_OK;
       
   747 }
       
   748 
       
   749 void CDownloadDialog::decrementProgressMax(ULONG contentLength, ULONG readSoFar) {
       
   750     __try
       
   751     {
       
   752         m_csDownload.Lock();
       
   753         m_ulProgressMax = m_ulProgressMax - contentLength;
       
   754         m_ulProgress = m_ulProgress - readSoFar;
       
   755         logProgress();
       
   756     }
       
   757     __finally
       
   758     {
       
   759         m_csDownload.Unlock();
       
   760     }
       
   761 
       
   762 }
       
   763 
       
   764 void CDownloadDialog::waitUntilInitialized() {
       
   765     // wait until download progress dialog is initialized and ready to show
       
   766     WaitForSingleObject(m_hDialogInitializedEvent, INFINITE);
       
   767     ResetEvent(m_hDialogInitializedEvent);
       
   768 
       
   769 }
       
   770 
       
   771 // Check if download has been cancelled
       
   772 BOOL CDownloadDialog::isDownloadCancelled() {
       
   773     if (WAIT_OBJECT_0 == WaitForSingleObject(m_hCancelEvent, 0)) {
       
   774         return TRUE;
       
   775     }
       
   776     return FALSE;
       
   777 }
       
   778 
       
   779 
       
   780 
       
   781 // Create the fonts we need for the download and
       
   782 // install UE
       
   783 HFONT CDownloadDialog::CreateDialogFont(HDC hdc, LPCTSTR lpszFaceName, int ptSize, int isBold)
       
   784 {
       
   785     POINT pt;
       
   786     FLOAT cxDPI, cyDPI;
       
   787     HFONT hFont;
       
   788     LOGFONT lf;
       
   789 
       
   790     int iDeciPtWidth = 0;
       
   791     int iDeciPtHeight = 10 * ptSize;
       
   792 
       
   793     int iSavedDC = SaveDC(hdc);
       
   794 
       
   795     SetGraphicsMode (hdc, GM_ADVANCED);
       
   796     ModifyWorldTransform(hdc, NULL, MWT_IDENTITY);
       
   797     SetViewportOrgEx (hdc, 0,0, NULL);
       
   798     SetWindowOrgEx (hdc, 0,0, NULL);
       
   799 
       
   800     cxDPI = (FLOAT) GetDeviceCaps(hdc, LOGPIXELSX);
       
   801     cyDPI = (FLOAT) GetDeviceCaps(hdc, LOGPIXELSY);
       
   802 
       
   803     pt.x = (int) (iDeciPtWidth * cxDPI / 72);
       
   804     pt.y = (int) (iDeciPtHeight * cyDPI / 72);
       
   805 
       
   806     DPtoLP(hdc, &pt, 1);
       
   807 
       
   808     lf.lfHeight = - (int) (fabs ((double) pt.y) / 10.0 + 0.5);
       
   809     lf.lfWidth = 0;
       
   810     lf.lfEscapement = 0;
       
   811     lf.lfOrientation = 0;
       
   812     lf.lfWeight = (isBold > 0) ? FW_BOLD : 0;
       
   813     lf.lfItalic = 0;
       
   814     lf.lfUnderline = 0;
       
   815     lf.lfStrikeOut = 0;
       
   816     lf.lfCharSet = 0;
       
   817     lf.lfOutPrecision = 0;
       
   818     lf.lfClipPrecision = 0;
       
   819     lf.lfQuality = 0;
       
   820     lf.lfPitchAndFamily = 0;
       
   821 
       
   822     TCHAR szLocaleData[BUFFER_SIZE];
       
   823     GetLocaleInfo(LOCALE_SYSTEM_DEFAULT, LOCALE_SENGCOUNTRY,
       
   824                   szLocaleData, BUFFER_SIZE);
       
   825 
       
   826     if (strncmp(szLocaleData, "Japan", 5) == 0) {
       
   827         // need special font for _ja locale
       
   828         strcpy (lf.lfFaceName, TEXT("MS UI Gothic"));
       
   829     } else {
       
   830         strcpy (lf.lfFaceName, lpszFaceName);
       
   831     }
       
   832 
       
   833     hFont = CreateFontIndirect(&lf);
       
   834 
       
   835     RestoreDC (hdc, iSavedDC);
       
   836     return hFont;
       
   837 }
       
   838 
       
   839 void CDownloadDialog::FreeGDIResources ()
       
   840 {
       
   841     ::DeleteObject(m_hMastheadFont);
       
   842     m_hMastheadFont = NULL;
       
   843 
       
   844     ::DeleteObject(m_hDialogFont);
       
   845     m_hDialogFont = NULL;
       
   846 
       
   847     ::DeleteObject(m_hSixPointFont);
       
   848     m_hSixPointFont = NULL;
       
   849 
       
   850     ::DeleteObject(m_hBitmap);
       
   851     m_hBitmap = NULL;
       
   852 
       
   853     ::DeleteDC(m_hMemDC);
       
   854     m_hMemDC = NULL;
       
   855 }
       
   856 
       
   857 
       
   858 JNIEnv* CDownloadDialog::getJNIEnv() {
       
   859     if (m_jvm == NULL)
       
   860         return NULL;
       
   861     JNIEnv *env;
       
   862     m_jvm->AttachCurrentThread((void**) &env, NULL);
       
   863     return env;
       
   864 }
       
   865 
       
   866 
       
   867 void CDownloadDialog::log(char *msg) {
       
   868     JNIEnv *env = getJNIEnv();
       
   869     if (env != NULL) {
       
   870         jclass dm = env->FindClass("sun/jkernel/DownloadManager");
       
   871         if (dm == NULL) {
       
   872             printf("Cound not find class sun.jkernel.DownloadManager\n");
       
   873             return;
       
   874         }
       
   875         jmethodID log = env->GetStaticMethodID(dm, "log", "(Ljava/lang/String;)V");
       
   876         if (log == NULL) {
       
   877             printf("Could not find method sun.jkernel.DownloadManager.log(String)\n");
       
   878             return;
       
   879         }
       
   880         jstring string = env->NewStringUTF(msg);
       
   881         if (string == NULL) {
       
   882             printf("Error creating log string\n");
       
   883             return;
       
   884         }
       
   885         env->CallStaticVoidMethod(dm, log, string);
       
   886     }
       
   887 }
       
   888 
       
   889 
       
   890 void CDownloadDialog::logProgress() {
       
   891     char msg[256];
       
   892     sprintf(msg, "Progress: %d / %d", m_ulProgress, m_ulProgressMax);
       
   893     log(msg);
       
   894 }