1 /*
   2  * Copyright (c) 2008, 2009, 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 }