Add try-catch blocks and critical sections to wrap libgit functions in CLogDataVector...
[TortoiseGit.git] / src / TortoiseProc / CheckForUpdatesDlg.cpp
blob1ea64ae38856dd1e55635e8c74cf26055888de28
1 // TortoiseGit - a Windows shell extension for easy version control
3 // Copyright (C) 2003-2008 - TortoiseSVN
4 // Copyright (C) 2008-2013 - TortoiseGit
6 // This program is free software; you can redistribute it and/or
7 // modify it under the terms of the GNU General Public License
8 // as published by the Free Software Foundation; either version 2
9 // of the License, or (at your option) any later version.
11 // This program is distributed in the hope that it will be useful,
12 // but WITHOUT ANY WARRANTY; without even the implied warranty of
13 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 // GNU General Public License for more details.
16 // You should have received a copy of the GNU General Public License
17 // along with this program; if not, write to the Free Software Foundation,
18 // 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
20 #include "stdafx.h"
21 #include "TortoiseProc.h"
22 #include "LoglistCommonResource.h"
23 #include "..\version.h"
24 #include "MessageBox.h"
25 #include ".\checkforupdatesdlg.h"
26 #include "registry.h"
27 #include "AppUtils.h"
28 #include "TempFile.h"
29 #include <wintrust.h>
30 #include <Softpub.h>
31 #include "SmartHandle.h"
32 #include "SysInfo.h"
33 #include "PathUtils.h"
34 #include "DirFileEnum.h"
35 #include "ProjectProperties.h"
36 #include "UniCodeUtils.h"
38 // Link with Wintrust.lib
39 #pragma comment (lib, "wintrust")
41 #define WM_USER_DISPLAYSTATUS (WM_USER + 1)
42 #define WM_USER_ENDDOWNLOAD (WM_USER + 2)
43 #define WM_USER_FILLCHANGELOG (WM_USER + 3)
45 IMPLEMENT_DYNAMIC(CCheckForUpdatesDlg, CStandAloneDialog)
46 CCheckForUpdatesDlg::CCheckForUpdatesDlg(CWnd* pParent /*=NULL*/)
47 : CStandAloneDialog(CCheckForUpdatesDlg::IDD, pParent)
48 , m_bShowInfo(FALSE)
49 , m_bForce(FALSE)
50 , m_bVisible(FALSE)
51 , m_pDownloadThread(NULL)
52 , m_bThreadRunning(FALSE)
54 m_sUpdateDownloadLink = _T("http://code.google.com/p/tortoisegit/wiki/Download?tm=2");
57 CCheckForUpdatesDlg::~CCheckForUpdatesDlg()
61 void CCheckForUpdatesDlg::DoDataExchange(CDataExchange* pDX)
63 CStandAloneDialog::DoDataExchange(pDX);
64 DDX_Control(pDX, IDC_LINK, m_link);
65 DDX_Control(pDX, IDC_PROGRESSBAR, m_progress);
66 DDX_Control(pDX, IDC_LIST_DOWNLOADS, m_ctrlFiles);
67 DDX_Control(pDX, IDC_BUTTON_UPDATE, m_ctrlUpdate);
68 DDX_Control(pDX, IDC_LOGMESSAGE, m_cLogMessage);
71 BEGIN_MESSAGE_MAP(CCheckForUpdatesDlg, CStandAloneDialog)
72 ON_STN_CLICKED(IDC_CHECKRESULT, OnStnClickedCheckresult)
73 ON_WM_TIMER()
74 ON_WM_WINDOWPOSCHANGING()
75 ON_WM_SETCURSOR()
76 ON_BN_CLICKED(IDC_BUTTON_UPDATE, OnBnClickedButtonUpdate)
77 ON_MESSAGE(WM_USER_DISPLAYSTATUS, OnDisplayStatus)
78 ON_MESSAGE(WM_USER_ENDDOWNLOAD, OnEndDownload)
79 ON_MESSAGE(WM_USER_FILLCHANGELOG, OnFillChangelog)
80 END_MESSAGE_MAP()
82 BOOL CCheckForUpdatesDlg::OnInitDialog()
84 CStandAloneDialog::OnInitDialog();
85 CAppUtils::MarkWindowAsUnpinnable(m_hWnd);
87 CString temp;
88 temp.Format(IDS_CHECKNEWER_YOURVERSION, TGIT_VERMAJOR, TGIT_VERMINOR, TGIT_VERMICRO, TGIT_VERBUILD);
89 SetDlgItemText(IDC_YOURVERSION, temp);
91 DialogEnableWindow(IDOK, FALSE);
93 // hide download controls
94 m_ctrlFiles.ShowWindow(SW_HIDE);
95 GetDlgItem(IDC_GROUP_DOWNLOADS)->ShowWindow(SW_HIDE);
96 RECT rectWindow, rectGroupDownloads, rectOKButton;
97 GetWindowRect(&rectWindow);
98 GetDlgItem(IDC_GROUP_DOWNLOADS)->GetWindowRect(&rectGroupDownloads);
99 GetDlgItem(IDOK)->GetWindowRect(&rectOKButton);
100 LONG bottomDistance = rectWindow.bottom - rectOKButton.bottom;
101 OffsetRect(&rectOKButton, 0, rectGroupDownloads.top - rectOKButton.top);
102 rectWindow.bottom = rectOKButton.bottom + bottomDistance;
103 MoveWindow(&rectWindow);
104 ::MapWindowPoints(NULL, GetSafeHwnd(), (LPPOINT)&rectOKButton, 2);
105 GetDlgItem(IDOK)->MoveWindow(&rectOKButton);
107 temp.LoadString(IDS_STATUSLIST_COLFILE);
108 m_ctrlFiles.InsertColumn(0, temp, 0, -1);
109 m_ctrlFiles.InsertColumn(1, temp, 0, -1);
110 m_ctrlFiles.SetExtendedStyle(LVS_EX_DOUBLEBUFFER | LVS_EX_CHECKBOXES);
111 m_ctrlFiles.SetColumnWidth(0, 350);
112 m_ctrlFiles.SetColumnWidth(1, 200);
114 ProjectProperties pp;
115 pp.SetCheckRe(_T("[Ii]ssues?:?(\\s*(,|and)?\\s*#?\\d+)+"));
116 pp.SetBugIDRe(_T("(\\d+)"));
117 pp.lProjectLanguage = -1;
118 pp.sUrl = _T("http://code.google.com/p/tortoisegit/issues/detail?id=%BUGID%");
119 m_cLogMessage.Init(pp);
120 m_cLogMessage.SetFont((CString)CRegString(_T("Software\\TortoiseGit\\LogFontName"), _T("Courier New")), (DWORD)CRegDWORD(_T("Software\\TortoiseGit\\LogFontSize"), 8));
121 m_cLogMessage.Call(SCI_SETREADONLY, TRUE);
123 if (AfxBeginThread(CheckThreadEntry, this)==NULL)
125 CMessageBox::Show(NULL, IDS_ERR_THREADSTARTFAILED, IDS_APPNAME, MB_OK | MB_ICONERROR);
128 SetTimer(100, 1000, NULL);
129 return TRUE;
132 void CCheckForUpdatesDlg::OnOK()
134 if (m_bThreadRunning || m_pDownloadThread != NULL)
135 return; // Don't exit while downloading
137 CStandAloneDialog::OnOK();
140 void CCheckForUpdatesDlg::OnCancel()
142 if (m_bThreadRunning || m_pDownloadThread != NULL)
143 return; // Don't exit while downloading
144 CStandAloneDialog::OnCancel();
147 UINT CCheckForUpdatesDlg::CheckThreadEntry(LPVOID pVoid)
149 return ((CCheckForUpdatesDlg*)pVoid)->CheckThread();
152 UINT CCheckForUpdatesDlg::CheckThread()
154 m_bThreadRunning = TRUE;
156 CString temp;
157 CString tempfile = CTempFiles::Instance().GetTempFilePath(true).GetWinPathString();
159 CRegString checkurluser = CRegString(_T("Software\\TortoiseGit\\UpdateCheckURL"), _T(""));
160 CRegString checkurlmachine = CRegString(_T("Software\\TortoiseGit\\UpdateCheckURL"), _T(""), FALSE, HKEY_LOCAL_MACHINE);
161 CString sCheckURL = checkurluser;
162 if (sCheckURL.IsEmpty())
164 sCheckURL = checkurlmachine;
165 if (sCheckURL.IsEmpty())
167 bool checkPreview = false;
168 #if PREVIEW
169 checkPreview = true;
170 #else
171 CRegStdDWORD regCheckPreview(L"Software\\TortoiseGit\\VersionCheckPreview", FALSE);
172 if (DWORD(regCheckPreview))
173 checkPreview = true;
174 #endif
175 if (checkPreview)
176 sCheckURL = _T("http://version.tortoisegit.googlecode.com/git/version-preview.txt");
177 else
178 sCheckURL = _T("http://version.tortoisegit.googlecode.com/git/version.txt");
181 CoInitialize(NULL);
182 HRESULT res = URLDownloadToFile(NULL, sCheckURL, tempfile, 0, NULL);
183 if (res == S_OK)
187 CStdioFile file(tempfile, CFile::modeRead | CFile::shareDenyWrite);
188 CString ver;
189 unsigned int major,minor,micro,build;
190 major=minor=micro=build=0;
191 unsigned __int64 version=0;
193 if (file.ReadString(ver))
195 CString vertemp = ver;
196 // another versionstring for the filename can be provided after a semicolon
197 // this is needed for preview releases
198 int differentFilenamePos = vertemp.Find(_T(";"));
199 if (differentFilenamePos > 0)
201 vertemp = vertemp.Left(differentFilenamePos);
202 ver = ver.Mid(differentFilenamePos + 1);
205 major = _ttoi(vertemp);
206 vertemp = vertemp.Mid(vertemp.Find('.')+1);
207 minor = _ttoi(vertemp);
208 vertemp = vertemp.Mid(vertemp.Find('.')+1);
209 micro = _ttoi(vertemp);
210 vertemp = vertemp.Mid(vertemp.Find('.')+1);
211 build = _ttoi(vertemp);
212 version = major;
213 version <<= 16;
214 version += minor;
215 version <<= 16;
216 version += micro;
217 version <<= 16;
218 version += build;
222 BOOL bNewer = FALSE;
223 if (m_bForce)
224 bNewer = TRUE;
225 if (major > TGIT_VERMAJOR)
226 bNewer = TRUE;
227 else if ((minor > TGIT_VERMINOR)&&(major == TGIT_VERMAJOR))
228 bNewer = TRUE;
229 else if ((micro > TGIT_VERMICRO)&&(minor == TGIT_VERMINOR)&&(major == TGIT_VERMAJOR))
230 bNewer = TRUE;
231 else if ((build > TGIT_VERBUILD)&&(micro == TGIT_VERMICRO)&&(minor == TGIT_VERMINOR)&&(major == TGIT_VERMAJOR))
232 bNewer = TRUE;
234 if (version != 0)
236 CString version;
237 version.Format(_T("%d.%d.%d.%d"),major,minor,micro,build);
238 if (version != ver)
239 version += _T(" (") + ver + _T(")");
240 temp.Format(IDS_CHECKNEWER_CURRENTVERSION, (LPCTSTR)version);
241 SetDlgItemText(IDC_CURRENTVERSION, temp);
244 if (version == 0)
246 temp.LoadString(IDS_CHECKNEWER_NETERROR);
247 SetDlgItemText(IDC_CHECKRESULT, temp);
249 else if (bNewer)
251 if(file.ReadString(temp) && !temp.IsEmpty())
252 { // Read the next line, it could contain a message for the user
253 CString tempLink;
254 if(file.ReadString(tempLink) && !tempLink.IsEmpty())
255 { // Read another line to find out the download link-URL, if any
256 m_sUpdateDownloadLink = tempLink;
259 else
261 temp.LoadString(IDS_CHECKNEWER_NEWERVERSIONAVAILABLE);
262 CString tempLink;
263 file.ReadString(tempLink);
265 SetDlgItemText(IDC_CHECKRESULT, temp);
266 m_bShowInfo = TRUE;
268 FillChangelog(file);
269 FillDownloads(file, ver);
271 // Show download controls
272 RECT rectWindow, rectProgress, rectGroupDownloads, rectOKButton;
273 GetWindowRect(&rectWindow);
274 m_progress.GetWindowRect(&rectProgress);
275 GetDlgItem(IDC_GROUP_DOWNLOADS)->GetWindowRect(&rectGroupDownloads);
276 GetDlgItem(IDOK)->GetWindowRect(&rectOKButton);
277 LONG bottomDistance = rectWindow.bottom - rectOKButton.bottom;
278 OffsetRect(&rectOKButton, 0, (rectGroupDownloads.bottom + (rectGroupDownloads.bottom - rectProgress.bottom)) - rectOKButton.top);
279 rectWindow.bottom = rectOKButton.bottom + bottomDistance;
280 MoveWindow(&rectWindow);
281 ::MapWindowPoints(NULL, GetSafeHwnd(), (LPPOINT)&rectOKButton, 2);
282 GetDlgItem(IDOK)->MoveWindow(&rectOKButton);
283 m_ctrlFiles.ShowWindow(SW_SHOW);
284 GetDlgItem(IDC_GROUP_DOWNLOADS)->ShowWindow(SW_SHOW);
285 CenterWindow();
287 else
289 temp.LoadString(IDS_CHECKNEWER_YOURUPTODATE);
290 SetDlgItemText(IDC_CHECKRESULT, temp);
291 file.ReadString(temp);
292 file.ReadString(temp);
293 FillChangelog(file);
297 catch (CException * e)
299 e->Delete();
300 temp.LoadString(IDS_CHECKNEWER_NETERROR);
301 SetDlgItemText(IDC_CHECKRESULT, temp);
304 else
306 // Try to cache web page;
308 temp.LoadString(IDS_CHECKNEWER_NETERROR);
309 SetDlgItemText(IDC_CHECKRESULT, temp);
311 if (!m_sUpdateDownloadLink.IsEmpty())
313 m_link.ShowWindow(SW_SHOW);
314 m_link.SetURL(m_sUpdateDownloadLink);
317 DeleteFile(tempfile);
318 m_bThreadRunning = FALSE;
319 DialogEnableWindow(IDOK, TRUE);
320 return 0;
323 void CCheckForUpdatesDlg::FillDownloads(CStdioFile &file, CString version)
325 #if WIN64
326 const CString x86x64 = _T("64");
327 #else
328 const CString x86x64 = _T("32");
329 #endif
331 if (!file.ReadString(m_sFilesURL) || m_sFilesURL.IsEmpty())
332 m_sFilesURL = _T("http://tortoisegit.googlecode.com/files/");
334 m_ctrlFiles.InsertItem(0, _T("TortoiseGit"));
335 CString filename;
336 filename.Format(_T("TortoiseGit-%s-%sbit.msi"), version, x86x64);
337 m_ctrlFiles.SetItemData(0, (DWORD_PTR)(new CUpdateListCtrl::Entry(filename, CUpdateListCtrl::STATUS_NONE)));
338 m_ctrlFiles.SetCheck(0 , TRUE);
340 std::vector<DWORD> m_installedLangs;
342 // set up the language selecting combobox
343 CString path = CPathUtils::GetAppParentDirectory();
344 path = path + _T("Languages\\");
345 CSimpleFileFind finder(path, _T("*.dll"));
346 while (finder.FindNextFileNoDirectories())
348 CString file = finder.GetFilePath();
349 CString filename = finder.GetFileName();
350 if (filename.Left(12).CompareNoCase(_T("TortoiseProc")) == 0)
352 CString sVer = _T(STRPRODUCTVER);
353 sVer = sVer.Left(sVer.ReverseFind('.'));
354 CString sFileVer = CPathUtils::GetVersionFromFile(file);
355 sFileVer = sFileVer.Left(sFileVer.ReverseFind('.'));
356 CString sLoc = filename.Mid(12);
357 sLoc = sLoc.Left(sLoc.GetLength() - 4); // cut off ".dll"
358 if ((sLoc.Left(2) == L"32") && (sLoc.GetLength() > 5))
359 continue;
360 DWORD loc = _tstoi(filename.Mid(12));
361 m_installedLangs.push_back(loc);
366 CString langs;
367 while (file.ReadString(langs) && !langs.IsEmpty())
369 CString sLang = _T("TortoiseGit Language Pack ") + langs.Mid(5);
371 DWORD loc = _tstoi(langs.Mid(0, 4));
372 TCHAR buf[MAX_PATH];
373 GetLocaleInfo(loc, LOCALE_SNATIVELANGNAME, buf, _countof(buf));
374 CString sLang2(buf);
375 GetLocaleInfo(loc, LOCALE_SNATIVECTRYNAME, buf, _countof(buf));
376 if (buf[0])
378 sLang2 += _T(" (");
379 sLang2 += buf;
380 sLang2 += _T(")");
383 int pos = m_ctrlFiles.InsertItem(m_ctrlFiles.GetItemCount(), sLang);
384 m_ctrlFiles.SetItemText(pos, 1, sLang2);
386 CString filename;
387 filename.Format(_T("TortoiseGit-LanguagePack-%s-%sbit-%s.msi"), version, x86x64, langs.Mid(5));
388 m_ctrlFiles.SetItemData(pos, (DWORD_PTR)(new CUpdateListCtrl::Entry(filename, CUpdateListCtrl::STATUS_NONE)));
390 if (std::find(m_installedLangs.begin(), m_installedLangs.end(), loc) != m_installedLangs.end())
391 m_ctrlFiles.SetCheck(pos , TRUE);
393 DialogEnableWindow(IDC_BUTTON_UPDATE, TRUE);
396 void CCheckForUpdatesDlg::FillChangelog(CStdioFile &file)
398 CString sChangelogURL;
399 if (!file.ReadString(sChangelogURL) || sChangelogURL.IsEmpty())
400 sChangelogURL = _T("http://tortoisegit.googlecode.com/git/src/Changelog.txt");
402 CString tempchangelogfile = CTempFiles::Instance().GetTempFilePath(true).GetWinPathString();
403 HRESULT res = URLDownloadToFile(NULL, sChangelogURL, tempchangelogfile, 0, NULL);
404 if (SUCCEEDED(res))
406 CString temp;
407 CStdioFile file(tempchangelogfile, CFile::modeRead|CFile::typeText);
408 CString str;
409 bool first = true;
410 while (file.ReadString(str))
412 if (first)
414 first = false;
415 if (str.GetLength() > 2 && str.GetAt(0) == 0xEF && str.GetAt(1) == 0xBB)
417 if (str.GetAt(2) == 0xBF)
419 str = str.Mid(3);
421 else
423 str = str.Mid(2);
427 str = CUnicodeUtils::GetUnicode(CStringA(str), CP_UTF8);
428 temp += str + _T("\n");
430 ::SendMessage(m_hWnd, WM_USER_FILLCHANGELOG, 0, reinterpret_cast<LPARAM>(temp.GetBuffer()));
432 else
433 ::SendMessage(m_hWnd, WM_USER_FILLCHANGELOG, 0, reinterpret_cast<LPARAM>(_T("Could not load changelog.")));
436 void CCheckForUpdatesDlg::OnStnClickedCheckresult()
438 // user clicked on the label, start the browser with our web page
439 HINSTANCE result = ShellExecute(NULL, _T("opennew"), m_sUpdateDownloadLink, NULL,NULL, SW_SHOWNORMAL);
440 if ((UINT)result <= HINSTANCE_ERROR)
442 result = ShellExecute(NULL, _T("open"), m_sUpdateDownloadLink, NULL,NULL, SW_SHOWNORMAL);
446 void CCheckForUpdatesDlg::OnTimer(UINT_PTR nIDEvent)
448 if (nIDEvent == 100)
450 if (m_bThreadRunning == FALSE)
452 if (m_bShowInfo)
454 m_bVisible = TRUE;
455 ShowWindow(SW_SHOWNORMAL);
457 else
459 EndDialog(0);
463 CStandAloneDialog::OnTimer(nIDEvent);
466 void CCheckForUpdatesDlg::OnWindowPosChanging(WINDOWPOS* lpwndpos)
468 CStandAloneDialog::OnWindowPosChanging(lpwndpos);
469 if (m_bVisible == FALSE)
470 lpwndpos->flags &= ~SWP_SHOWWINDOW;
473 BOOL CCheckForUpdatesDlg::OnSetCursor(CWnd* pWnd, UINT nHitTest, UINT message)
475 if ((!m_sUpdateDownloadLink.IsEmpty())&&(pWnd)&&(pWnd == GetDlgItem(IDC_CHECKRESULT)))
477 HCURSOR hCur = LoadCursor(NULL, MAKEINTRESOURCE(IDC_HAND));
478 SetCursor(hCur);
479 return TRUE;
482 HCURSOR hCur = LoadCursor(NULL, MAKEINTRESOURCE(IDC_ARROW));
483 SetCursor(hCur);
484 return CStandAloneDialogTmpl<CDialog>::OnSetCursor(pWnd, nHitTest, message);
487 void CCheckForUpdatesDlg::OnBnClickedButtonUpdate()
489 CString title;
490 m_ctrlUpdate.GetWindowText(title);
491 if (m_pDownloadThread == NULL && title == CString(MAKEINTRESOURCE(IDS_PROC_DOWNLOAD)))
493 bool isOneSelected = false;
494 for (int i = 0; i < (int)m_ctrlFiles.GetItemCount(); ++i)
496 if (m_ctrlFiles.GetCheck(i))
498 isOneSelected = true;
499 break;
502 if (!isOneSelected)
503 return;
505 m_eventStop.ResetEvent();
507 m_pDownloadThread = ::AfxBeginThread(DownloadThreadEntry, this, THREAD_PRIORITY_NORMAL, 0, CREATE_SUSPENDED);
508 if (m_pDownloadThread != NULL)
510 m_pDownloadThread->m_bAutoDelete = FALSE;
511 m_pDownloadThread->ResumeThread();
513 GetDlgItem(IDC_BUTTON_UPDATE)->SetWindowText(CString(MAKEINTRESOURCE(IDS_ABORTBUTTON)));
515 else
517 CMessageBox::Show(NULL, IDS_ERR_THREADSTARTFAILED, IDS_APPNAME, MB_OK | MB_ICONERROR);
520 else if (title == CString(MAKEINTRESOURCE(IDS_ABORTBUTTON)))
522 // Abort
523 m_eventStop.SetEvent();
525 else
527 CString folder = GetDownloadsDirectory();
528 if (m_ctrlUpdate.GetCurrentEntry() == 0)
530 for (int i = 0; i < (int)m_ctrlFiles.GetItemCount(); ++i)
532 CUpdateListCtrl::Entry *data = (CUpdateListCtrl::Entry *)m_ctrlFiles.GetItemData(i);
533 if (m_ctrlFiles.GetCheck(i) == TRUE)
534 ShellExecute(NULL, _T("open"), folder + data->m_filename, NULL, NULL, SW_SHOWNORMAL);
536 CStandAloneDialog::OnOK();
538 else if (m_ctrlUpdate.GetCurrentEntry() == 1)
540 ShellExecute(NULL, _T("open"), folder, NULL, NULL, SW_SHOWNORMAL);
543 m_ctrlUpdate.SetCurrentEntry(0);
547 UINT CCheckForUpdatesDlg::DownloadThreadEntry(LPVOID pVoid)
549 return ((CCheckForUpdatesDlg*)pVoid)->DownloadThread();
552 bool CCheckForUpdatesDlg::Download(CString filename)
554 CString destFilename = GetDownloadsDirectory() + filename;
555 if (PathFileExists(destFilename))
557 if (VerifySignature(destFilename))
558 return true;
559 else
560 DeleteFile(destFilename);
563 CBSCallbackImpl bsc(this->GetSafeHwnd(), m_eventStop);
565 CString url = m_sFilesURL + filename;
567 m_progress.SetRange32(0, 1);
568 m_progress.SetPos(0);
569 m_progress.ShowWindow(SW_SHOW);
571 CString tempfile = CTempFiles::Instance().GetTempFilePath(true).GetWinPathString();
572 HRESULT res = URLDownloadToFile(NULL, url, tempfile, 0, &bsc);
573 if (res == S_OK)
575 if (VerifySignature(tempfile))
577 if (PathFileExists(destFilename))
578 DeleteFile(destFilename);
579 MoveFile(tempfile, destFilename);
580 return true;
583 return false;
586 UINT CCheckForUpdatesDlg::DownloadThread()
588 m_ctrlFiles.SetExtendedStyle(m_ctrlFiles.GetExtendedStyle() & ~LVS_EX_CHECKBOXES);
590 BOOL result = TRUE;
591 for (int i = 0; i < (int)m_ctrlFiles.GetItemCount(); ++i)
593 m_ctrlFiles.EnsureVisible(i, FALSE);
594 CRect rect;
595 m_ctrlFiles.GetItemRect(i, &rect, LVIR_BOUNDS);
596 CUpdateListCtrl::Entry *data = (CUpdateListCtrl::Entry *)m_ctrlFiles.GetItemData(i);
597 if (m_ctrlFiles.GetCheck(i) == TRUE)
599 data->m_status = CUpdateListCtrl::STATUS_DOWNLOADING;
600 m_ctrlFiles.InvalidateRect(rect);
601 if (Download(data->m_filename))
602 data->m_status = CUpdateListCtrl::STATUS_SUCCESS;
603 else
605 data->m_status = CUpdateListCtrl::STATUS_FAIL;
606 result = FALSE;
609 else
610 data->m_status = CUpdateListCtrl::STATUS_IGNORE;
611 m_ctrlFiles.InvalidateRect(rect);
614 ::PostMessage(GetSafeHwnd(), WM_USER_ENDDOWNLOAD, 0, 0);
616 return result;
619 LRESULT CCheckForUpdatesDlg::OnEndDownload(WPARAM, LPARAM)
621 ASSERT(m_pDownloadThread != NULL);
623 // wait until the thread terminates
624 DWORD dwExitCode;
625 if (::GetExitCodeThread(m_pDownloadThread->m_hThread, &dwExitCode) && dwExitCode == STILL_ACTIVE)
626 ::WaitForSingleObject(m_pDownloadThread->m_hThread, INFINITE);
628 // make sure we always have the correct exit code
629 ::GetExitCodeThread(m_pDownloadThread->m_hThread, &dwExitCode);
631 delete m_pDownloadThread;
632 m_pDownloadThread = NULL;
634 m_progress.ShowWindow(SW_HIDE);
636 if (dwExitCode == TRUE)
638 m_ctrlUpdate.AddEntry(CString(MAKEINTRESOURCE(IDS_PROC_INSTALL)));
639 m_ctrlUpdate.AddEntry(CString(MAKEINTRESOURCE(IDS_CHECKUPDATE_DESTFOLDER)));
640 m_ctrlUpdate.Invalidate();
642 else
644 m_ctrlUpdate.SetWindowText(CString(MAKEINTRESOURCE(IDS_PROC_DOWNLOAD)));
645 CMessageBox::Show(NULL, IDS_ERR_FAILEDUPDATEDOWNLOAD, IDS_APPNAME, MB_ICONERROR);
648 return 0;
651 LRESULT CCheckForUpdatesDlg::OnFillChangelog(WPARAM, LPARAM lParam)
653 ASSERT(lParam != NULL);
655 TCHAR * changelog = reinterpret_cast<TCHAR *>(lParam);
656 m_cLogMessage.Call(SCI_SETREADONLY, FALSE);
657 m_cLogMessage.SetText(changelog);
658 m_cLogMessage.Call(SCI_SETREADONLY, TRUE);
659 m_cLogMessage.Call(SCI_GOTOPOS, 0);
661 return 0;
664 CString CCheckForUpdatesDlg::GetDownloadsDirectory()
666 CString folder;
668 if (SysInfo::Instance().IsVistaOrLater())
670 CAutoLibrary hShell = AtlLoadSystemLibraryUsingFullPath(_T("shell32.dll"));
671 if (hShell)
673 typedef HRESULT STDAPICALLTYPE SHGetKnownFolderPathFN(__in REFKNOWNFOLDERID rfid, __in DWORD dwFlags, __in_opt HANDLE hToken, __deref_out PWSTR *ppszPath);
674 SHGetKnownFolderPathFN *pfnSHGetKnownFolderPath = (SHGetKnownFolderPathFN*)GetProcAddress(hShell, "SHGetKnownFolderPath");
675 if (pfnSHGetKnownFolderPath)
677 wchar_t * wcharPtr = 0;
678 HRESULT hr = pfnSHGetKnownFolderPath(FOLDERID_Downloads, KF_FLAG_CREATE, NULL, &wcharPtr);
679 if (SUCCEEDED(hr))
681 folder = wcharPtr;
682 CoTaskMemFree(static_cast<void*>(wcharPtr));
683 return folder.TrimRight(_T("\\")) + _T("\\");
689 TCHAR szPath[MAX_PATH];
690 if (SUCCEEDED(SHGetFolderPath(NULL, CSIDL_PERSONAL | CSIDL_FLAG_CREATE, NULL, SHGFP_TYPE_CURRENT, szPath)))
691 folder = szPath;
692 CString downloads = folder.TrimRight(_T("\\")) + _T("\\Downloads\\");
693 if ((PathFileExists(downloads) && PathIsDirectory(downloads)) || (!PathFileExists(downloads) && CreateDirectory(downloads, NULL)))
694 return downloads;
696 return folder;
699 LRESULT CCheckForUpdatesDlg::OnDisplayStatus(WPARAM, LPARAM lParam)
701 const DOWNLOADSTATUS *const pDownloadStatus = reinterpret_cast<DOWNLOADSTATUS *>(lParam);
702 if (pDownloadStatus != NULL)
704 ASSERT(::AfxIsValidAddress(pDownloadStatus, sizeof(DOWNLOADSTATUS)));
706 m_progress.SetRange32(0, pDownloadStatus->ulProgressMax);
707 m_progress.SetPos(pDownloadStatus->ulProgress);
710 return 0;
713 CBSCallbackImpl::CBSCallbackImpl(HWND hWnd, HANDLE hEventStop)
715 m_hWnd = hWnd;
716 m_hEventStop = hEventStop;
717 m_ulObjRefCount = 1;
720 // IUnknown
721 STDMETHODIMP CBSCallbackImpl::QueryInterface(REFIID riid, void **ppvObject)
723 *ppvObject = NULL;
725 // IUnknown
726 if (::IsEqualIID(riid, __uuidof(IUnknown)))
727 *ppvObject = this;
729 // IBindStatusCallback
730 else if (::IsEqualIID(riid, __uuidof(IBindStatusCallback)))
731 *ppvObject = static_cast<IBindStatusCallback *>(this);
733 if (*ppvObject)
735 (*reinterpret_cast<LPUNKNOWN *>(ppvObject))->AddRef();
736 return S_OK;
739 return E_NOINTERFACE;
742 STDMETHODIMP_(ULONG) CBSCallbackImpl::AddRef()
744 return ++m_ulObjRefCount;
747 STDMETHODIMP_(ULONG) CBSCallbackImpl::Release()
749 return --m_ulObjRefCount;
752 // IBindStatusCallback
753 STDMETHODIMP CBSCallbackImpl::OnStartBinding(DWORD, IBinding *)
755 return S_OK;
758 STDMETHODIMP CBSCallbackImpl::GetPriority(LONG *)
760 return E_NOTIMPL;
762 STDMETHODIMP CBSCallbackImpl::OnLowResource(DWORD)
764 return S_OK;
767 STDMETHODIMP CBSCallbackImpl::OnProgress(ULONG ulProgress, ULONG ulProgressMax, ULONG ulStatusCode, LPCWSTR /* szStatusText */)
769 TRACE(_T("IBindStatusCallback::OnProgress\n"));
770 TRACE(_T("ulProgress: %lu, ulProgressMax: %lu\n"), ulProgress, ulProgressMax);
771 UNREFERENCED_PARAMETER(ulStatusCode);
772 TRACE(_T("ulStatusCode: %lu "), ulStatusCode);
774 if (m_hWnd != NULL)
776 // inform the dialog box to display current status,
777 // don't use PostMessage
778 CCheckForUpdatesDlg::DOWNLOADSTATUS downloadStatus = { ulProgress, ulProgressMax };
779 ::SendMessage(m_hWnd, WM_USER_DISPLAYSTATUS, 0, reinterpret_cast<LPARAM>(&downloadStatus));
782 if (m_hEventStop != NULL && ::WaitForSingleObject(m_hEventStop, 0) == WAIT_OBJECT_0)
784 return E_ABORT; // canceled by the user
787 return S_OK;
790 STDMETHODIMP CBSCallbackImpl::OnStopBinding(HRESULT, LPCWSTR)
792 return S_OK;
795 STDMETHODIMP CBSCallbackImpl::GetBindInfo(DWORD *, BINDINFO *)
797 return S_OK;
800 STDMETHODIMP CBSCallbackImpl::OnDataAvailable(DWORD, DWORD, FORMATETC *, STGMEDIUM *)
802 return S_OK;
805 STDMETHODIMP CBSCallbackImpl::OnObjectAvailable(REFIID, IUnknown *)
807 return S_OK;
810 BOOL CCheckForUpdatesDlg::VerifySignature(CString fileName)
812 WINTRUST_FILE_INFO fileInfo;
813 memset(&fileInfo, 0, sizeof(fileInfo));
814 fileInfo.cbStruct = sizeof(WINTRUST_FILE_INFO);
815 fileInfo.pcwszFilePath = fileName;
817 WINTRUST_DATA data;
818 memset(&data, 0, sizeof(data));
819 data.cbStruct = sizeof(data);
821 data.dwUIChoice = WTD_UI_NONE;
822 data.fdwRevocationChecks = WTD_REVOKE_NONE;
823 data.dwUnionChoice = WTD_CHOICE_FILE;
824 data.pFile = &fileInfo;
826 GUID policyGUID = WINTRUST_ACTION_GENERIC_VERIFY_V2;
828 return (WinVerifyTrust(NULL, &policyGUID, &data) == ERROR_SUCCESS);