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.
21 #include "TortoiseProc.h"
22 #include "LoglistCommonResource.h"
23 #include "..\version.h"
24 #include "MessageBox.h"
25 #include "CheckForUpdatesDlg.h"
29 #include "SmartHandle.h"
31 #include "PathUtils.h"
32 #include "DirFileEnum.h"
33 #include "UnicodeUtils.h"
34 #include "UpdateCrypto.h"
36 #define SIGNATURE_FILE_ENDING _T(".asc")
38 #define WM_USER_DISPLAYSTATUS (WM_USER + 1)
39 #define WM_USER_ENDDOWNLOAD (WM_USER + 2)
40 #define WM_USER_FILLCHANGELOG (WM_USER + 3)
42 IMPLEMENT_DYNAMIC(CCheckForUpdatesDlg
, CStandAloneDialog
)
43 CCheckForUpdatesDlg::CCheckForUpdatesDlg(CWnd
* pParent
/*=NULL*/)
44 : CStandAloneDialog(CCheckForUpdatesDlg::IDD
, pParent
)
48 , m_pDownloadThread(NULL
)
49 , m_bThreadRunning(FALSE
)
51 m_sUpdateDownloadLink
= _T("http://redir.tortoisegit.org/download");
54 CCheckForUpdatesDlg::~CCheckForUpdatesDlg()
58 void CCheckForUpdatesDlg::DoDataExchange(CDataExchange
* pDX
)
60 CStandAloneDialog::DoDataExchange(pDX
);
61 DDX_Control(pDX
, IDC_LINK
, m_link
);
62 DDX_Control(pDX
, IDC_PROGRESSBAR
, m_progress
);
63 DDX_Control(pDX
, IDC_LIST_DOWNLOADS
, m_ctrlFiles
);
64 DDX_Control(pDX
, IDC_BUTTON_UPDATE
, m_ctrlUpdate
);
65 DDX_Control(pDX
, IDC_LOGMESSAGE
, m_cLogMessage
);
68 BEGIN_MESSAGE_MAP(CCheckForUpdatesDlg
, CStandAloneDialog
)
70 ON_WM_WINDOWPOSCHANGING()
73 ON_BN_CLICKED(IDC_BUTTON_UPDATE
, OnBnClickedButtonUpdate
)
74 ON_MESSAGE(WM_USER_DISPLAYSTATUS
, OnDisplayStatus
)
75 ON_MESSAGE(WM_USER_ENDDOWNLOAD
, OnEndDownload
)
76 ON_MESSAGE(WM_USER_FILLCHANGELOG
, OnFillChangelog
)
79 BOOL
CCheckForUpdatesDlg::OnInitDialog()
81 CStandAloneDialog::OnInitDialog();
82 CAppUtils::MarkWindowAsUnpinnable(m_hWnd
);
85 temp
.Format(IDS_CHECKNEWER_YOURVERSION
, TGIT_VERMAJOR
, TGIT_VERMINOR
, TGIT_VERMICRO
, TGIT_VERBUILD
);
86 SetDlgItemText(IDC_YOURVERSION
, temp
);
88 DialogEnableWindow(IDOK
, FALSE
);
90 // hide download controls
91 m_ctrlFiles
.ShowWindow(SW_HIDE
);
92 GetDlgItem(IDC_GROUP_DOWNLOADS
)->ShowWindow(SW_HIDE
);
93 RECT rectWindow
, rectGroupDownloads
, rectOKButton
;
94 GetWindowRect(&rectWindow
);
95 GetDlgItem(IDC_GROUP_DOWNLOADS
)->GetWindowRect(&rectGroupDownloads
);
96 GetDlgItem(IDOK
)->GetWindowRect(&rectOKButton
);
97 LONG bottomDistance
= rectWindow
.bottom
- rectOKButton
.bottom
;
98 OffsetRect(&rectOKButton
, 0, rectGroupDownloads
.top
- rectOKButton
.top
);
99 rectWindow
.bottom
= rectOKButton
.bottom
+ bottomDistance
;
100 MoveWindow(&rectWindow
);
101 ::MapWindowPoints(NULL
, GetSafeHwnd(), (LPPOINT
)&rectOKButton
, 2);
102 GetDlgItem(IDOK
)->MoveWindow(&rectOKButton
);
104 temp
.LoadString(IDS_STATUSLIST_COLFILE
);
105 m_ctrlFiles
.InsertColumn(0, temp
, 0, -1);
106 m_ctrlFiles
.InsertColumn(1, temp
, 0, -1);
107 m_ctrlFiles
.SetExtendedStyle(LVS_EX_DOUBLEBUFFER
| LVS_EX_CHECKBOXES
);
108 m_ctrlFiles
.SetColumnWidth(0, 350);
109 m_ctrlFiles
.SetColumnWidth(1, 200);
111 ProjectProperties pp
;
112 pp
.SetCheckRe(_T("[Ii]ssues?:?(\\s*(,|and)?\\s*#?\\d+)+"));
113 pp
.SetBugIDRe(_T("(\\d+)"));
114 pp
.lProjectLanguage
= -1;
115 pp
.sUrl
= _T("http://code.google.com/p/tortoisegit/issues/detail?id=%BUGID%");
116 m_cLogMessage
.Init(pp
);
117 m_cLogMessage
.SetFont((CString
)CRegString(_T("Software\\TortoiseGit\\LogFontName"), _T("Courier New")), (DWORD
)CRegDWORD(_T("Software\\TortoiseGit\\LogFontSize"), 8));
118 m_cLogMessage
.Call(SCI_SETREADONLY
, TRUE
);
120 if (AfxBeginThread(CheckThreadEntry
, this)==NULL
)
122 CMessageBox::Show(NULL
, IDS_ERR_THREADSTARTFAILED
, IDS_APPNAME
, MB_OK
| MB_ICONERROR
);
125 SetTimer(100, 1000, NULL
);
129 void CCheckForUpdatesDlg::OnDestroy()
131 for (int i
= 0; i
< m_ctrlFiles
.GetItemCount(); ++i
)
132 delete (CUpdateListCtrl::Entry
*)m_ctrlFiles
.GetItemData(i
);
134 CStandAloneDialog::OnDestroy();
137 void CCheckForUpdatesDlg::OnOK()
139 if (m_bThreadRunning
|| m_pDownloadThread
!= NULL
)
140 return; // Don't exit while downloading
142 CStandAloneDialog::OnOK();
145 void CCheckForUpdatesDlg::OnCancel()
147 if (m_bThreadRunning
|| m_pDownloadThread
!= NULL
)
148 return; // Don't exit while downloading
149 CStandAloneDialog::OnCancel();
152 UINT
CCheckForUpdatesDlg::CheckThreadEntry(LPVOID pVoid
)
154 return ((CCheckForUpdatesDlg
*)pVoid
)->CheckThread();
157 UINT
CCheckForUpdatesDlg::CheckThread()
159 m_bThreadRunning
= TRUE
;
162 CString tempfile
= CTempFiles::Instance().GetTempFilePath(true).GetWinPathString();
164 bool official
= false;
166 CRegString checkurluser
= CRegString(_T("Software\\TortoiseGit\\UpdateCheckURL"), _T(""));
167 CRegString checkurlmachine
= CRegString(_T("Software\\TortoiseGit\\UpdateCheckURL"), _T(""), FALSE
, HKEY_LOCAL_MACHINE
);
168 CString sCheckURL
= checkurluser
;
169 if (sCheckURL
.IsEmpty())
171 sCheckURL
= checkurlmachine
;
172 if (sCheckURL
.IsEmpty())
175 bool checkPreview
= false;
179 CRegStdDWORD
regCheckPreview(L
"Software\\TortoiseGit\\VersionCheckPreview", FALSE
);
180 if (DWORD(regCheckPreview
))
185 sCheckURL
= _T("http://version.tortoisegit.googlecode.com/git/version-preview.txt");
186 SetDlgItemText(IDC_SOURCE
, _T("Using preview release channel"));
189 sCheckURL
= _T("http://version.tortoisegit.googlecode.com/git/version.txt");
194 SetDlgItemText(IDC_SOURCE
, _T("Using (unofficial) release channel: ") + sCheckURL
);
199 DeleteUrlCacheEntry(sCheckURL
);
200 HRESULT res
= URLDownloadToFile(NULL
, sCheckURL
, tempfile
, 0, NULL
);
201 if (res
== S_OK
&& official
)
203 CString signatureTempfile
= CTempFiles::Instance().GetTempFilePath(true).GetWinPathString();
205 DeleteUrlCacheEntry(sCheckURL
+ SIGNATURE_FILE_ENDING
);
206 res
= URLDownloadToFile(nullptr, sCheckURL
+ SIGNATURE_FILE_ENDING
, signatureTempfile
, 0, nullptr);
207 if (res
== S_OK
&& VerifyIntegrity(tempfile
, signatureTempfile
))
209 SetDlgItemText(IDC_CHECKRESULT
, _T("Could not verify digital signature."));
210 DeleteUrlCacheEntry(sCheckURL
);
211 DeleteUrlCacheEntry(sCheckURL
+ SIGNATURE_FILE_ENDING
);
215 else if (FAILED(res
))
217 DeleteUrlCacheEntry(sCheckURL
);
218 if (CRegDWORD(_T("Software\\Microsoft\\Windows\\CurrentVersion\\Internet Settings\\GlobalUserOffline"), 0))
219 errorText
.LoadString(IDS_OFFLINEMODE
); // offline mode enabled
221 errorText
.Format(IDS_CHECKNEWER_NETERROR_FORMAT
, res
);
227 CStdioFile
file(tempfile
, CFile::modeRead
| CFile::shareDenyWrite
);
229 unsigned int major
,minor
,micro
,build
;
230 major
=minor
=micro
=build
=0;
231 unsigned __int64 version
=0;
233 if (file
.ReadString(ver
))
235 CString vertemp
= ver
;
236 // another versionstring for the filename can be provided after a semicolon
237 // this is needed for preview releases
238 int differentFilenamePos
= vertemp
.Find(_T(";"));
239 if (differentFilenamePos
> 0)
241 vertemp
= vertemp
.Left(differentFilenamePos
);
242 ver
= ver
.Mid(differentFilenamePos
+ 1);
245 major
= _ttoi(vertemp
);
246 vertemp
= vertemp
.Mid(vertemp
.Find('.')+1);
247 minor
= _ttoi(vertemp
);
248 vertemp
= vertemp
.Mid(vertemp
.Find('.')+1);
249 micro
= _ttoi(vertemp
);
250 vertemp
= vertemp
.Mid(vertemp
.Find('.')+1);
251 build
= _ttoi(vertemp
);
265 if (major
> TGIT_VERMAJOR
)
267 else if ((minor
> TGIT_VERMINOR
)&&(major
== TGIT_VERMAJOR
))
269 else if ((micro
> TGIT_VERMICRO
)&&(minor
== TGIT_VERMINOR
)&&(major
== TGIT_VERMAJOR
))
271 else if ((build
> TGIT_VERBUILD
)&&(micro
== TGIT_VERMICRO
)&&(minor
== TGIT_VERMINOR
)&&(major
== TGIT_VERMAJOR
))
277 version
.Format(_T("%u.%u.%u.%u"),major
,minor
,micro
,build
);
279 version
+= _T(" (") + ver
+ _T(")");
280 temp
.Format(IDS_CHECKNEWER_CURRENTVERSION
, (LPCTSTR
)version
);
281 SetDlgItemText(IDC_CURRENTVERSION
, temp
);
286 temp
.LoadString(IDS_CHECKNEWER_NETERROR
);
287 SetDlgItemText(IDC_CHECKRESULT
, temp
);
291 if(file
.ReadString(temp
) && !temp
.IsEmpty())
292 { // Read the next line, it could contain a message for the user
294 if(file
.ReadString(tempLink
) && !tempLink
.IsEmpty())
295 { // Read another line to find out the download link-URL, if any
296 m_sUpdateDownloadLink
= tempLink
;
301 temp
.LoadString(IDS_CHECKNEWER_NEWERVERSIONAVAILABLE
);
303 file
.ReadString(tempLink
);
305 SetDlgItemText(IDC_CHECKRESULT
, temp
);
309 FillDownloads(file
, ver
);
311 // Show download controls
312 RECT rectWindow
, rectProgress
, rectGroupDownloads
, rectOKButton
;
313 GetWindowRect(&rectWindow
);
314 m_progress
.GetWindowRect(&rectProgress
);
315 GetDlgItem(IDC_GROUP_DOWNLOADS
)->GetWindowRect(&rectGroupDownloads
);
316 GetDlgItem(IDOK
)->GetWindowRect(&rectOKButton
);
317 LONG bottomDistance
= rectWindow
.bottom
- rectOKButton
.bottom
;
318 OffsetRect(&rectOKButton
, 0, (rectGroupDownloads
.bottom
+ (rectGroupDownloads
.bottom
- rectProgress
.bottom
)) - rectOKButton
.top
);
319 rectWindow
.bottom
= rectOKButton
.bottom
+ bottomDistance
;
320 MoveWindow(&rectWindow
);
321 ::MapWindowPoints(NULL
, GetSafeHwnd(), (LPPOINT
)&rectOKButton
, 2);
322 GetDlgItem(IDOK
)->MoveWindow(&rectOKButton
);
323 m_ctrlFiles
.ShowWindow(SW_SHOW
);
324 GetDlgItem(IDC_GROUP_DOWNLOADS
)->ShowWindow(SW_SHOW
);
329 temp
.LoadString(IDS_CHECKNEWER_YOURUPTODATE
);
330 SetDlgItemText(IDC_CHECKRESULT
, temp
);
331 file
.ReadString(temp
);
332 file
.ReadString(temp
);
337 catch (CException
* e
)
340 temp
.LoadString(IDS_CHECKNEWER_NETERROR
);
341 SetDlgItemText(IDC_CHECKRESULT
, temp
);
346 SetDlgItemText(IDC_CHECKRESULT
, errorText
);
348 if (!m_sUpdateDownloadLink
.IsEmpty())
350 m_link
.ShowWindow(SW_SHOW
);
351 m_link
.SetURL(m_sUpdateDownloadLink
);
356 m_bThreadRunning
= FALSE
;
357 DialogEnableWindow(IDOK
, TRUE
);
361 void CCheckForUpdatesDlg::FillDownloads(CStdioFile
&file
, CString version
)
364 const CString x86x64
= _T("64");
366 const CString x86x64
= _T("32");
369 if (!file
.ReadString(m_sFilesURL
) || m_sFilesURL
.IsEmpty())
370 m_sFilesURL
= _T("http://tortoisegit.googlecode.com/files/");
372 m_ctrlFiles
.InsertItem(0, _T("TortoiseGit"));
374 filename
.Format(_T("TortoiseGit-%s-%sbit.msi"), version
, x86x64
);
375 m_ctrlFiles
.SetItemData(0, (DWORD_PTR
)(new CUpdateListCtrl::Entry(filename
, CUpdateListCtrl::STATUS_NONE
)));
376 m_ctrlFiles
.SetCheck(0 , TRUE
);
378 std::vector
<DWORD
> m_installedLangs
;
380 // set up the language selecting combobox
381 CString path
= CPathUtils::GetAppParentDirectory();
382 path
= path
+ _T("Languages\\");
383 CSimpleFileFind
finder(path
, _T("*.dll"));
384 while (finder
.FindNextFileNoDirectories())
386 CString file
= finder
.GetFilePath();
387 CString filename
= finder
.GetFileName();
388 if (filename
.Left(12).CompareNoCase(_T("TortoiseProc")) == 0)
390 CString sVer
= _T(STRPRODUCTVER
);
391 sVer
= sVer
.Left(sVer
.ReverseFind('.'));
392 CString sFileVer
= CPathUtils::GetVersionFromFile(file
);
393 sFileVer
= sFileVer
.Left(sFileVer
.ReverseFind('.'));
394 CString sLoc
= filename
.Mid(12);
395 sLoc
= sLoc
.Left(sLoc
.GetLength() - 4); // cut off ".dll"
396 if ((sLoc
.Left(2) == L
"32") && (sLoc
.GetLength() > 5))
398 DWORD loc
= _tstoi(filename
.Mid(12));
399 m_installedLangs
.push_back(loc
);
405 while (file
.ReadString(langs
) && !langs
.IsEmpty())
407 CString sLang
= _T("TortoiseGit Language Pack ") + langs
.Mid(5);
409 DWORD loc
= _tstoi(langs
.Mid(0, 4));
411 GetLocaleInfo(loc
, LOCALE_SNATIVELANGNAME
, buf
, _countof(buf
));
413 GetLocaleInfo(loc
, LOCALE_SNATIVECTRYNAME
, buf
, _countof(buf
));
421 int pos
= m_ctrlFiles
.InsertItem(m_ctrlFiles
.GetItemCount(), sLang
);
422 m_ctrlFiles
.SetItemText(pos
, 1, sLang2
);
425 filename
.Format(_T("TortoiseGit-LanguagePack-%s-%sbit-%s.msi"), version
, x86x64
, langs
.Mid(5));
426 m_ctrlFiles
.SetItemData(pos
, (DWORD_PTR
)(new CUpdateListCtrl::Entry(filename
, CUpdateListCtrl::STATUS_NONE
)));
428 if (std::find(m_installedLangs
.begin(), m_installedLangs
.end(), loc
) != m_installedLangs
.end())
429 m_ctrlFiles
.SetCheck(pos
, TRUE
);
431 DialogEnableWindow(IDC_BUTTON_UPDATE
, TRUE
);
434 void CCheckForUpdatesDlg::FillChangelog(CStdioFile
&file
)
436 CString sChangelogURL
;
437 if (!file
.ReadString(sChangelogURL
) || sChangelogURL
.IsEmpty())
438 sChangelogURL
= _T("http://tortoisegit.googlecode.com/git/src/Changelog.txt");
440 CString tempchangelogfile
= CTempFiles::Instance().GetTempFilePath(true).GetWinPathString();
441 HRESULT res
= URLDownloadToFile(NULL
, sChangelogURL
, tempchangelogfile
, 0, NULL
);
445 CStdioFile
file(tempchangelogfile
, CFile::modeRead
|CFile::typeText
);
448 while (file
.ReadString(str
))
453 if (str
.GetLength() > 2 && str
.GetAt(0) == 0xEF && str
.GetAt(1) == 0xBB)
455 if (str
.GetAt(2) == 0xBF)
465 str
= CUnicodeUtils::GetUnicode(CStringA(str
), CP_UTF8
);
466 temp
+= str
+ _T("\n");
468 ::SendMessage(m_hWnd
, WM_USER_FILLCHANGELOG
, 0, reinterpret_cast<LPARAM
>(temp
.GetBuffer()));
471 ::SendMessage(m_hWnd
, WM_USER_FILLCHANGELOG
, 0, reinterpret_cast<LPARAM
>(_T("Could not load changelog.")));
474 void CCheckForUpdatesDlg::OnTimer(UINT_PTR nIDEvent
)
478 if (m_bThreadRunning
== FALSE
)
483 ShowWindow(SW_SHOWNORMAL
);
491 CStandAloneDialog::OnTimer(nIDEvent
);
494 void CCheckForUpdatesDlg::OnWindowPosChanging(WINDOWPOS
* lpwndpos
)
496 CStandAloneDialog::OnWindowPosChanging(lpwndpos
);
497 if (m_bVisible
== FALSE
)
498 lpwndpos
->flags
&= ~SWP_SHOWWINDOW
;
501 BOOL
CCheckForUpdatesDlg::OnSetCursor(CWnd
* pWnd
, UINT nHitTest
, UINT message
)
503 HCURSOR hCur
= LoadCursor(NULL
, MAKEINTRESOURCE(IDC_ARROW
));
505 return CStandAloneDialogTmpl
<CDialog
>::OnSetCursor(pWnd
, nHitTest
, message
);
508 void CCheckForUpdatesDlg::OnBnClickedButtonUpdate()
511 m_ctrlUpdate
.GetWindowText(title
);
512 if (m_pDownloadThread
== NULL
&& title
== CString(MAKEINTRESOURCE(IDS_PROC_DOWNLOAD
)))
514 bool isOneSelected
= false;
515 for (int i
= 0; i
< (int)m_ctrlFiles
.GetItemCount(); ++i
)
517 if (m_ctrlFiles
.GetCheck(i
))
519 isOneSelected
= true;
526 m_eventStop
.ResetEvent();
528 m_pDownloadThread
= ::AfxBeginThread(DownloadThreadEntry
, this, THREAD_PRIORITY_NORMAL
, 0, CREATE_SUSPENDED
);
529 if (m_pDownloadThread
!= NULL
)
531 m_pDownloadThread
->m_bAutoDelete
= FALSE
;
532 m_pDownloadThread
->ResumeThread();
534 GetDlgItem(IDC_BUTTON_UPDATE
)->SetWindowText(CString(MAKEINTRESOURCE(IDS_ABORTBUTTON
)));
538 CMessageBox::Show(NULL
, IDS_ERR_THREADSTARTFAILED
, IDS_APPNAME
, MB_OK
| MB_ICONERROR
);
541 else if (title
== CString(MAKEINTRESOURCE(IDS_ABORTBUTTON
)))
544 m_eventStop
.SetEvent();
548 CString folder
= GetDownloadsDirectory();
549 if (m_ctrlUpdate
.GetCurrentEntry() == 0)
551 for (int i
= 0; i
< (int)m_ctrlFiles
.GetItemCount(); ++i
)
553 CUpdateListCtrl::Entry
*data
= (CUpdateListCtrl::Entry
*)m_ctrlFiles
.GetItemData(i
);
554 if (m_ctrlFiles
.GetCheck(i
) == TRUE
)
555 ShellExecute(NULL
, _T("open"), folder
+ data
->m_filename
, NULL
, NULL
, SW_SHOWNORMAL
);
557 CStandAloneDialog::OnOK();
559 else if (m_ctrlUpdate
.GetCurrentEntry() == 1)
561 ShellExecute(NULL
, _T("open"), folder
, NULL
, NULL
, SW_SHOWNORMAL
);
564 m_ctrlUpdate
.SetCurrentEntry(0);
568 UINT
CCheckForUpdatesDlg::DownloadThreadEntry(LPVOID pVoid
)
570 return ((CCheckForUpdatesDlg
*)pVoid
)->DownloadThread();
573 bool CCheckForUpdatesDlg::Download(CString filename
)
575 CString url
= m_sFilesURL
+ filename
;
576 CString destFilename
= GetDownloadsDirectory() + filename
;
577 if (PathFileExists(destFilename
) && PathFileExists(destFilename
+ SIGNATURE_FILE_ENDING
))
579 if (VerifyIntegrity(destFilename
, destFilename
+ SIGNATURE_FILE_ENDING
) == 0)
583 DeleteFile(destFilename
);
584 DeleteFile(destFilename
+ SIGNATURE_FILE_ENDING
);
585 DeleteUrlCacheEntry(url
);
586 DeleteUrlCacheEntry(url
+ SIGNATURE_FILE_ENDING
);
590 CBSCallbackImpl
bsc(this->GetSafeHwnd(), m_eventStop
);
592 m_progress
.SetRange32(0, 1);
593 m_progress
.SetPos(0);
594 m_progress
.ShowWindow(SW_SHOW
);
596 CString tempfile
= CTempFiles::Instance().GetTempFilePath(true).GetWinPathString();
597 CString signatureTempfile
= CTempFiles::Instance().GetTempFilePath(true).GetWinPathString();
599 DeleteUrlCacheEntry(url
);
600 HRESULT res
= URLDownloadToFile(NULL
, url
, tempfile
, 0, &bsc
);
604 DeleteUrlCacheEntry(url
+ SIGNATURE_FILE_ENDING
);
605 res
= URLDownloadToFile(NULL
, url
+ SIGNATURE_FILE_ENDING
, signatureTempfile
, 0, nullptr);
606 m_progress
.SetPos(m_progress
.GetPos() + 1);
610 if (VerifyIntegrity(tempfile
, signatureTempfile
) == 0)
612 DeleteFile(destFilename
);
613 DeleteFile(destFilename
+ SIGNATURE_FILE_ENDING
);
614 MoveFile(tempfile
, destFilename
);
615 MoveFile(signatureTempfile
, destFilename
+ SIGNATURE_FILE_ENDING
);
618 DeleteUrlCacheEntry(url
);
619 DeleteUrlCacheEntry(url
+ SIGNATURE_FILE_ENDING
);
624 UINT
CCheckForUpdatesDlg::DownloadThread()
626 m_ctrlFiles
.SetExtendedStyle(m_ctrlFiles
.GetExtendedStyle() & ~LVS_EX_CHECKBOXES
);
631 for (int i
= 0; i
< (int)m_ctrlFiles
.GetItemCount(); ++i
)
633 m_ctrlFiles
.EnsureVisible(i
, FALSE
);
635 m_ctrlFiles
.GetItemRect(i
, &rect
, LVIR_BOUNDS
);
636 CUpdateListCtrl::Entry
*data
= (CUpdateListCtrl::Entry
*)m_ctrlFiles
.GetItemData(i
);
637 if (m_ctrlFiles
.GetCheck(i
) == TRUE
)
639 data
->m_status
= CUpdateListCtrl::STATUS_DOWNLOADING
;
640 m_ctrlFiles
.InvalidateRect(rect
);
641 if (Download(data
->m_filename
))
642 data
->m_status
= CUpdateListCtrl::STATUS_SUCCESS
;
645 data
->m_status
= CUpdateListCtrl::STATUS_FAIL
;
650 data
->m_status
= CUpdateListCtrl::STATUS_IGNORE
;
651 m_ctrlFiles
.InvalidateRect(rect
);
654 ::PostMessage(GetSafeHwnd(), WM_USER_ENDDOWNLOAD
, 0, 0);
661 LRESULT
CCheckForUpdatesDlg::OnEndDownload(WPARAM
, LPARAM
)
663 ASSERT(m_pDownloadThread
!= NULL
);
665 // wait until the thread terminates
667 if (::GetExitCodeThread(m_pDownloadThread
->m_hThread
, &dwExitCode
) && dwExitCode
== STILL_ACTIVE
)
668 ::WaitForSingleObject(m_pDownloadThread
->m_hThread
, INFINITE
);
670 // make sure we always have the correct exit code
671 ::GetExitCodeThread(m_pDownloadThread
->m_hThread
, &dwExitCode
);
673 delete m_pDownloadThread
;
674 m_pDownloadThread
= NULL
;
676 m_progress
.ShowWindow(SW_HIDE
);
678 if (dwExitCode
== TRUE
)
680 m_ctrlUpdate
.AddEntry(CString(MAKEINTRESOURCE(IDS_PROC_INSTALL
)));
681 m_ctrlUpdate
.AddEntry(CString(MAKEINTRESOURCE(IDS_CHECKUPDATE_DESTFOLDER
)));
682 m_ctrlUpdate
.Invalidate();
686 m_ctrlUpdate
.SetWindowText(CString(MAKEINTRESOURCE(IDS_PROC_DOWNLOAD
)));
687 CMessageBox::Show(NULL
, IDS_ERR_FAILEDUPDATEDOWNLOAD
, IDS_APPNAME
, MB_ICONERROR
);
693 LRESULT
CCheckForUpdatesDlg::OnFillChangelog(WPARAM
, LPARAM lParam
)
695 ASSERT(lParam
!= NULL
);
697 TCHAR
* changelog
= reinterpret_cast<TCHAR
*>(lParam
);
698 m_cLogMessage
.Call(SCI_SETREADONLY
, FALSE
);
699 m_cLogMessage
.SetText(changelog
);
700 m_cLogMessage
.Call(SCI_SETREADONLY
, TRUE
);
701 m_cLogMessage
.Call(SCI_GOTOPOS
, 0);
706 CString
CCheckForUpdatesDlg::GetDownloadsDirectory()
710 if (SysInfo::Instance().IsVistaOrLater())
712 CAutoLibrary hShell
= AtlLoadSystemLibraryUsingFullPath(_T("shell32.dll"));
715 typedef HRESULT STDAPICALLTYPE
SHGetKnownFolderPathFN(__in REFKNOWNFOLDERID rfid
, __in DWORD dwFlags
, __in_opt HANDLE hToken
, __deref_out PWSTR
*ppszPath
);
716 SHGetKnownFolderPathFN
*pfnSHGetKnownFolderPath
= (SHGetKnownFolderPathFN
*)GetProcAddress(hShell
, "SHGetKnownFolderPath");
717 if (pfnSHGetKnownFolderPath
)
719 wchar_t * wcharPtr
= 0;
720 HRESULT hr
= pfnSHGetKnownFolderPath(FOLDERID_Downloads
, KF_FLAG_CREATE
, NULL
, &wcharPtr
);
724 CoTaskMemFree(static_cast<void*>(wcharPtr
));
725 return folder
.TrimRight(_T("\\")) + _T("\\");
731 TCHAR szPath
[MAX_PATH
];
732 if (SUCCEEDED(SHGetFolderPath(NULL
, CSIDL_PERSONAL
| CSIDL_FLAG_CREATE
, NULL
, SHGFP_TYPE_CURRENT
, szPath
)))
734 CString downloads
= folder
.TrimRight(_T("\\")) + _T("\\Downloads\\");
735 if ((PathFileExists(downloads
) && PathIsDirectory(downloads
)) || (!PathFileExists(downloads
) && CreateDirectory(downloads
, NULL
)))
741 LRESULT
CCheckForUpdatesDlg::OnDisplayStatus(WPARAM
, LPARAM lParam
)
743 const DOWNLOADSTATUS
*const pDownloadStatus
= reinterpret_cast<DOWNLOADSTATUS
*>(lParam
);
744 if (pDownloadStatus
!= NULL
)
746 ASSERT(::AfxIsValidAddress(pDownloadStatus
, sizeof(DOWNLOADSTATUS
)));
748 m_progress
.SetRange32(0, pDownloadStatus
->ulProgressMax
);
749 m_progress
.SetPos(pDownloadStatus
->ulProgress
);
755 CBSCallbackImpl::CBSCallbackImpl(HWND hWnd
, HANDLE hEventStop
)
758 m_hEventStop
= hEventStop
;
763 STDMETHODIMP
CBSCallbackImpl::QueryInterface(REFIID riid
, void **ppvObject
)
768 if (::IsEqualIID(riid
, __uuidof(IUnknown
)))
771 // IBindStatusCallback
772 else if (::IsEqualIID(riid
, __uuidof(IBindStatusCallback
)))
773 *ppvObject
= static_cast<IBindStatusCallback
*>(this);
777 (*reinterpret_cast<LPUNKNOWN
*>(ppvObject
))->AddRef();
781 return E_NOINTERFACE
;
784 STDMETHODIMP_(ULONG
) CBSCallbackImpl::AddRef()
786 return ++m_ulObjRefCount
;
789 STDMETHODIMP_(ULONG
) CBSCallbackImpl::Release()
791 return --m_ulObjRefCount
;
794 // IBindStatusCallback
795 STDMETHODIMP
CBSCallbackImpl::OnStartBinding(DWORD
, IBinding
*)
800 STDMETHODIMP
CBSCallbackImpl::GetPriority(LONG
*)
804 STDMETHODIMP
CBSCallbackImpl::OnLowResource(DWORD
)
809 STDMETHODIMP
CBSCallbackImpl::OnProgress(ULONG ulProgress
, ULONG ulProgressMax
, ULONG ulStatusCode
, LPCWSTR
/* szStatusText */)
811 TRACE(_T("IBindStatusCallback::OnProgress\n"));
812 TRACE(_T("ulProgress: %lu, ulProgressMax: %lu\n"), ulProgress
, ulProgressMax
);
813 UNREFERENCED_PARAMETER(ulStatusCode
);
814 TRACE(_T("ulStatusCode: %lu "), ulStatusCode
);
818 // inform the dialog box to display current status,
819 // don't use PostMessage
820 CCheckForUpdatesDlg::DOWNLOADSTATUS downloadStatus
= { ulProgress
, ulProgressMax
+ 1 }; // + 1 for download of signature file
821 ::SendMessage(m_hWnd
, WM_USER_DISPLAYSTATUS
, 0, reinterpret_cast<LPARAM
>(&downloadStatus
));
824 if (m_hEventStop
!= NULL
&& ::WaitForSingleObject(m_hEventStop
, 0) == WAIT_OBJECT_0
)
826 return E_ABORT
; // canceled by the user
832 STDMETHODIMP
CBSCallbackImpl::OnStopBinding(HRESULT
, LPCWSTR
)
837 STDMETHODIMP
CBSCallbackImpl::GetBindInfo(DWORD
*, BINDINFO
*)
842 STDMETHODIMP
CBSCallbackImpl::OnDataAvailable(DWORD
, DWORD
, FORMATETC
*, STGMEDIUM
*)
847 STDMETHODIMP
CBSCallbackImpl::OnObjectAvailable(REFIID
, IUnknown
*)