瀏覽代碼

Link to Microsoft Store on new version dialog

Source commit: 42b0147450d101a27d0285f00a181eb35503afff
Martin Prikryl 6 年之前
父節點
當前提交
d31377aca4
共有 6 個文件被更改,包括 260 次插入75 次删除
  1. 7 62
      source/forms/About.cpp
  2. 4 1
      source/resource/TextsWin.h
  3. 4 1
      source/resource/TextsWin1.rc
  4. 215 1
      source/windows/GUITools.cpp
  5. 5 0
      source/windows/GUITools.h
  6. 25 10
      source/windows/Setup.cpp

+ 7 - 62
source/forms/About.cpp

@@ -188,56 +188,15 @@ void __fastcall TAboutDialog::LoadThirdParty()
 
   reinterpret_cast<TLabel *>(FThirdPartyWebBrowser)->Color = ThirdPartyPanel->Color;
 
-  NavigateBrowserToUrl(FThirdPartyWebBrowser, L"about:blank");
+  ReadyBrowserForStreaming(FThirdPartyWebBrowser);
   DoLoadThirdParty();
 }
 //---------------------------------------------------------------------------
 void __fastcall TAboutDialog::DoLoadThirdParty()
 {
-  while (FThirdPartyWebBrowser->ReadyState < ::READYSTATE_INTERACTIVE)
-  {
-    Application->ProcessMessages();
-  }
-
-  std::unique_ptr<TFont> DefaultFont(new TFont());
-  DefaultFont->Assign(Application->DefaultFont);
-  DefaultFont->Height = ScaleByPixelsPerInchFromSystem(DefaultFont->Height, this);
+  WaitBrowserToIdle(FThirdPartyWebBrowser);
 
   UnicodeString ThirdParty;
-
-  ThirdParty +=
-    L"<!DOCTYPE html>\n"
-    L"<meta charset=\"utf-8\">\n"
-    L"<html>\n"
-    L"<head>\n"
-    L"<style>\n"
-    L"\n"
-    L"body\n"
-    L"{\n"
-    L"  font-family: '" + DefaultFont->Name + L"';\n"
-    L"  margin: 0.5em;\n"
-    L"  background-color: " + ColorToWebColorStr(ThirdPartyPanel->Color) + L";\n"
-    L"}\n"
-    L"\n"
-    L"body\n"
-    L"{\n"
-    L"    font-size: " + IntToStr(DefaultFont->Size) + L"pt;\n"
-    L"}\n"
-    L"\n"
-    L"p\n"
-    L"{\n"
-    L"    margin-top: 0;\n"
-    L"    margin-bottom: 1em;\n"
-    L"}\n"
-    L"\n"
-    L"a, a:visited, a:hover, a:visited, a:current\n"
-    L"{\n"
-    L"    color: " + ColorToWebColorStr(LinkColor) + L";\n"
-    L"}\n"
-    L"</style>\n"
-    L"</head>\n"
-    L"<body>\n";
-
   UnicodeString Br = "<br/>\n";
 
   if (GUIConfiguration->AppliedLocale != GUIConfiguration->InternalLocale())
@@ -336,27 +295,13 @@ void __fastcall TAboutDialog::DoLoadThirdParty()
     LoadStr(ABOUT_PNG_COPYRIGHT) + Br +
     CreateLink(LoadStr(ABOUT_PNG_URL)));
 
-  ThirdParty +=
-    L"</body>\n"
-    L"</html>\n";
-
-  std::unique_ptr<TMemoryStream> ThirdPartyStream(new TMemoryStream());
-  UTF8String ThirdPartyUTF8 = UTF8String(ThirdParty);
-  ThirdPartyStream->Write(ThirdPartyUTF8.c_str(), ThirdPartyUTF8.Length());
-  ThirdPartyStream->Seek(0, 0);
+  std::unique_ptr<TFont> DefaultFont(new TFont());
+  DefaultFont->Assign(Application->DefaultFont);
+  DefaultFont->Height = ScaleByPixelsPerInchFromSystem(DefaultFont->Height, this);
 
-  // For stream-loaded document, when set only after loading from OnDocumentComplete,
-  // browser stops working
-  SetBrowserDesignModeOff(FThirdPartyWebBrowser);
+  ThirdParty = GenerateAppHtmlPage(DefaultFont.get(), ThirdPartyPanel, ThirdParty, false);
 
-  TStreamAdapter * ThirdPartyStreamAdapter = new TStreamAdapter(ThirdPartyStream.get(), soReference);
-  IPersistStreamInit * PersistStreamInit = NULL;
-  if (DebugAlwaysTrue(FThirdPartyWebBrowser->Document != NULL) &&
-      SUCCEEDED(FThirdPartyWebBrowser->Document->QueryInterface(IID_IPersistStreamInit, (void **)&PersistStreamInit)) &&
-      DebugAlwaysTrue(PersistStreamInit != NULL))
-  {
-    PersistStreamInit->Load(static_cast<_di_IStream>(*ThirdPartyStreamAdapter));
-  }
+  LoadBrowserDocument(FThirdPartyWebBrowser, ThirdParty);
 }
 //---------------------------------------------------------------------------
 void __fastcall TAboutDialog::AddPara(UnicodeString & Text, const UnicodeString & S)

+ 4 - 1
source/resource/TextsWin.h

@@ -556,7 +556,6 @@
 #define CONVERTKEY_SAVE_TITLE   1945
 #define CONVERTKEY_SAVE_FILTER  1946
 #define CONVERTKEY_SAVED        1947
-#define UPDATES_DONATE_LINK     1948
 #define GENERATE_URL_FILE_TITLE 1949
 #define GENERATE_URL_SESSION_TITLE 1950
 #define GENERATE_URL_URL        1951
@@ -616,6 +615,7 @@
 #define SYNCHRONIZE_SUMMARY     6017
 #define PREFERENCES_DRAGEXT_BROKEN 6018
 #define FILE_COLOR_CAPTION      6019
+#define UPDATES_DONATE_HTML     6020
 
 // 2xxx is reserved for TextsFileZilla.h
 
@@ -639,6 +639,9 @@
 #define DOCUMENTATION_SEARCH_URL3 4012
 #define ERROR_REPORT_URL2       4013
 #define UPGRADE_URL             4014
+#define STORE_URL               4015
+#define ABOUT_STORE_URL         4016
+#define STORE_GET_IMG_URL       4017
 
 #define EXTENSION_STRINGS       5000
 

+ 4 - 1
source/resource/TextsWin1.rc

@@ -561,7 +561,6 @@ BEGIN
         CONVERTKEY_SAVE_TITLE, "Save converted private key"
         CONVERTKEY_SAVE_FILTER, "PuTTY Private Key Files (*.ppk)|*.ppk|All files (*.*)|*.*"
         CONVERTKEY_SAVED, "Private key was converted and saved to '%s'."
-        UPDATES_DONATE_LINK, "Please, donate to enable automatic updates"
         GENERATE_URL_FILE_TITLE, "Generate file URL"
         GENERATE_URL_SESSION_TITLE, "Generate session URL/code"
         GENERATE_URL_URL, "URL"
@@ -621,6 +620,7 @@ BEGIN
         SYNCHRONIZE_SUMMARY, "Files uploaded: %s (%s)|Files downloaded: %s (%s)|Local files deleted: %s|Remote files deleted: %s|Comparison time: %s|Synchronization time: %s"
         PREFERENCES_DRAGEXT_BROKEN, "Shell extension cannot work on this system."
         FILE_COLOR_CAPTION, "File color"
+        UPDATES_DONATE_HTML, "To enable automatic updates, please <a href=\"%DONATE_URL%\">donate to WinSCP development</a> or %GET_IMG% WinSCP from <a href=\"%STORE_URL%\">Microsoft Store</a>."
 
         WIN_VARIABLE_STRINGS, "WIN_VARIABLE"
         WINSCP_COPYRIGHT, "Copyright © 2000-2018 Martin Prikryl"
@@ -636,5 +636,8 @@ BEGIN
         DOCUMENTATION_SEARCH_URL3, "https://winscp.net/eng/docs/search.php?ver=%s&lang=%s&q=%s"
         ERROR_REPORT_URL2, "https://winscp.net/forum/posting.php?mode=newtopic&ver=%s&lang=%s&report=%s"
         UPGRADE_URL, "https://winscp.net/eng/upgrade.php"
+        STORE_URL, "https://www.microsoft.com/store/apps/9p0pq8b65n8x?cid=%s"
+        ABOUT_STORE_URL, "https://winscp.net/eng/docs/microsoft_store"
+        STORE_GET_IMG_URL, "https://winscp.net/updatenews.php?store_get_img=1"
 
 END

+ 215 - 1
source/windows/GUITools.cpp

@@ -3,6 +3,7 @@
 #pragma hdrstop
 
 #include <shlobj.h>
+#include <mshtmhst.h>
 #include <Common.h>
 
 #include "GUITools.h"
@@ -962,6 +963,128 @@ void __fastcall HideComponentsPanel(TForm * Form)
   }
 }
 //---------------------------------------------------------------------------
+class TCustomDocHandler : public TComponent, public ::IDocHostUIHandler
+{
+public:
+  __fastcall TCustomDocHandler(TComponent * Owner) : TComponent(Owner)
+  {
+  }
+
+protected:
+  #pragma warn -hid
+  virtual HRESULT STDMETHODCALLTYPE QueryInterface(REFIID ClassId, void ** Intf)
+  {
+    HRESULT Result = S_OK;
+    if (ClassId == IID_IUnknown)
+    {
+      *Intf = (IUnknown *)this;
+    }
+    else if (ClassId == ::IID_IDocHostUIHandler)
+    {
+      *Intf = (::IDocHostUIHandler *)this;
+    }
+    else
+    {
+      Result = E_NOINTERFACE;
+    }
+    return Result;
+  }
+  #pragma warn .hid
+
+  virtual ULONG STDMETHODCALLTYPE AddRef()
+  {
+    return -1;
+  }
+
+  virtual ULONG STDMETHODCALLTYPE Release()
+  {
+    return -1;
+  }
+
+  virtual HRESULT STDMETHODCALLTYPE ShowContextMenu(
+    DWORD dwID, POINT * ppt, IUnknown * pcmdtReserved, IDispatch * pdispReserved)
+  {
+    // No context menu
+    // (implementing IDocHostUIHandler reenabled context menu disabled by TBrowserViewer::DoContextPopup)
+    return S_OK;
+  }
+
+  virtual HRESULT STDMETHODCALLTYPE GetHostInfo(::_DOCHOSTUIINFO * Info)
+  {
+    // Setting ControlBorder is ignored with IDocHostUIHandler.
+    // DOCHOSTUIFLAG_DPI_AWARE does not seem to have any effect
+    Info->dwFlags |= DOCHOSTUIFLAG_SCROLL_NO | DOCHOSTUIFLAG_NO3DBORDER | DOCHOSTUIFLAG_DPI_AWARE;
+    return S_OK;
+  }
+
+  virtual HRESULT STDMETHODCALLTYPE ShowUI(
+    DWORD dwID, IOleInPlaceActiveObject * pActiveObject, IOleCommandTarget * pCommandTarget, IOleInPlaceFrame * pFrame,
+    IOleInPlaceUIWindow * pDoc)
+  {
+    return E_NOTIMPL;
+  }
+
+  virtual HRESULT STDMETHODCALLTYPE HideUI()
+  {
+    return E_NOTIMPL;
+  }
+
+  virtual HRESULT STDMETHODCALLTYPE UpdateUI()
+  {
+    return E_NOTIMPL;
+  }
+
+  virtual HRESULT STDMETHODCALLTYPE EnableModeless(BOOL fEnable)
+  {
+    return E_NOTIMPL;
+  }
+
+  virtual HRESULT STDMETHODCALLTYPE OnDocWindowActivate(BOOL fActivate)
+  {
+    return E_NOTIMPL;
+  }
+
+  virtual HRESULT STDMETHODCALLTYPE OnFrameWindowActivate(BOOL fActivate)
+  {
+    return E_NOTIMPL;
+  }
+
+  virtual HRESULT STDMETHODCALLTYPE ResizeBorder(LPCRECT prcBorder, IOleInPlaceUIWindow * pUIWindow, BOOL fRameWindow)
+  {
+    return E_NOTIMPL;
+  }
+
+  virtual HRESULT STDMETHODCALLTYPE TranslateAccelerator(LPMSG lpMsg, const GUID * pguidCmdGroup, DWORD nCmdID)
+  {
+    return E_NOTIMPL;
+  }
+
+  virtual HRESULT STDMETHODCALLTYPE GetOptionKeyPath(LPOLESTR * pchKey, DWORD dw)
+  {
+    return E_NOTIMPL;
+  }
+
+  virtual HRESULT STDMETHODCALLTYPE GetDropTarget(IDropTarget * pDropTarget, IDropTarget ** ppDropTarget)
+  {
+    return E_NOTIMPL;
+  }
+
+  virtual HRESULT STDMETHODCALLTYPE GetExternal(IDispatch ** ppDispatch)
+  {
+    return E_NOTIMPL;
+  }
+
+  virtual HRESULT STDMETHODCALLTYPE TranslateUrl(DWORD dwTranslate, OLECHAR * pchURLIn, OLECHAR ** ppchURLOut)
+  {
+    return E_NOTIMPL;
+  }
+
+  virtual HRESULT STDMETHODCALLTYPE FilterDataObject(IDataObject * pDO, IDataObject ** ppDORet)
+  {
+    return E_NOTIMPL;
+  }
+};
+//---------------------------------------------------------------------------
 class TBrowserViewer : public TWebBrowserEx
 {
 public:
@@ -1004,7 +1127,8 @@ void __fastcall TBrowserViewer::AddLinkHandler(
 //---------------------------------------------------------------------------
 void __fastcall TBrowserViewer::DoContextPopup(const TPoint & MousePos, bool & Handled)
 {
-  // suppress built-in context menu
+  // Suppress built-in context menu.
+  // Is ignored with IDocHostUIHandler. Needs to be overriden by ShowContextMenu.
   Handled = true;
   TWebBrowserEx::DoContextPopup(MousePos, Handled);
 }
@@ -1070,6 +1194,7 @@ TWebBrowserEx * __fastcall CreateBrowserViewer(TPanel * Parent, const UnicodeStr
   static_cast<TWinControl *>(Result)->Name = L"BrowserViewer";
   static_cast<TWinControl *>(Result)->Parent = Parent;
   Result->Align = alClient;
+  // Is ignored with IDocHostUIHandler. Needs to be overriden by DOCHOSTUIFLAG_NO3DBORDER in GetHostInfo.
   Result->ControlBorder = cbNone;
 
   Result->LoadingPanel = CreateLabelPanel(Parent, LoadingLabel);
@@ -1104,6 +1229,95 @@ void __fastcall NavigateBrowserToUrl(TWebBrowserEx * WebBrowser, const UnicodeSt
   }
 }
 //---------------------------------------------------------------------------
+void ReadyBrowserForStreaming(TWebBrowserEx * WebBrowser)
+{
+  // This creates TWebBrowserEx::Document, which we need to stream in an in-memory document
+  NavigateBrowserToUrl(WebBrowser, L"about:blank");
+  // Needs to be followed by WaitBrowserToIdle
+}
+//---------------------------------------------------------------------------
+void WaitBrowserToIdle(TWebBrowserEx * WebBrowser)
+{
+  while (WebBrowser->ReadyState < ::READYSTATE_INTERACTIVE)
+  {
+    Application->ProcessMessages();
+  }
+}
+//---------------------------------------------------------------------------
+void HideBrowserScrollbars(TWebBrowserEx * WebBrowser)
+{
+  ICustomDoc * CustomDoc = NULL;
+  if (DebugAlwaysTrue(WebBrowser->Document != NULL) &&
+      SUCCEEDED(WebBrowser->Document->QueryInterface(&CustomDoc)) &&
+      DebugAlwaysTrue(CustomDoc != NULL))
+  {
+    TCustomDocHandler * Handler = new TCustomDocHandler(WebBrowser);
+    CustomDoc->SetUIHandler(Handler);
+  }
+}
+//---------------------------------------------------------------------------
+UnicodeString GenerateAppHtmlPage(TFont * Font, TPanel * Parent, const UnicodeString & Body, bool Seamless)
+{
+  UnicodeString Result =
+    L"<!DOCTYPE html>\n"
+    L"<meta charset=\"utf-8\">\n"
+    L"<html>\n"
+    L"<head>\n"
+    L"<style>\n"
+    L"\n"
+    L"body\n"
+    L"{\n"
+    L"    font-family: '" + Font->Name + L"';\n"
+    L"    margin: " + UnicodeString(Seamless ? L"0" : L"0.5em") + L";\n"
+    L"    background-color: " + ColorToWebColorStr(Parent->Color) + L";\n" +
+    UnicodeString(Seamless ? L"    overflow: hidden;\n" : L"") +
+    L"}\n"
+    L"\n"
+    L"body\n"
+    L"{\n"
+    L"    font-size: " + IntToStr(Font->Size) + L"pt;\n"
+    L"}\n"
+    L"\n"
+    L"p\n"
+    L"{\n"
+    L"    margin-top: 0;\n"
+    L"    margin-bottom: 1em;\n"
+    L"}\n"
+    L"\n"
+    L"a, a:visited, a:hover, a:visited, a:current\n"
+    L"{\n"
+    L"    color: " + ColorToWebColorStr(LinkColor) + L";\n"
+    L"}\n"
+    L"</style>\n"
+    L"</head>\n"
+    L"<body>\n" +
+    Body +
+    L"</body>\n"
+    L"</html>\n";
+  return Result;
+}
+//---------------------------------------------------------------------------
+void LoadBrowserDocument(TWebBrowserEx * WebBrowser, const UnicodeString & Document)
+{
+  std::unique_ptr<TMemoryStream> DocumentStream(new TMemoryStream());
+  UTF8String DocumentUTF8 = UTF8String(Document);
+  DocumentStream->Write(DocumentUTF8.c_str(), DocumentUTF8.Length());
+  DocumentStream->Seek(0, 0);
+
+  // For stream-loaded document, when set only after loading from OnDocumentComplete,
+  // browser stops working
+  SetBrowserDesignModeOff(WebBrowser);
+
+  TStreamAdapter * DocumentStreamAdapter = new TStreamAdapter(DocumentStream.get(), soReference);
+  IPersistStreamInit * PersistStreamInit = NULL;
+  if (DebugAlwaysTrue(WebBrowser->Document != NULL) &&
+      SUCCEEDED(WebBrowser->Document->QueryInterface(IID_IPersistStreamInit, (void **)&PersistStreamInit)) &&
+      DebugAlwaysTrue(PersistStreamInit != NULL))
+  {
+    PersistStreamInit->Load(static_cast<_di_IStream>(*DocumentStreamAdapter));
+  }
+}
+//---------------------------------------------------------------------------
 TComponent * __fastcall FindComponentRecursively(TComponent * Root, const UnicodeString & Name)
 {
   for (int Index = 0; Index < Root->ComponentCount; Index++)

+ 5 - 0
source/windows/GUITools.h

@@ -52,6 +52,11 @@ void __fastcall SetBrowserDesignModeOff(TWebBrowserEx * WebBrowser);
 void __fastcall AddBrowserLinkHandler(TWebBrowserEx * WebBrowser,
   const UnicodeString & Url, TNotifyEvent Handler);
 void __fastcall NavigateBrowserToUrl(TWebBrowserEx * WebBrowser, const UnicodeString & Url);
+void ReadyBrowserForStreaming(TWebBrowserEx * WebBrowser);
+void WaitBrowserToIdle(TWebBrowserEx * WebBrowser);
+void HideBrowserScrollbars(TWebBrowserEx * WebBrowser);
+UnicodeString GenerateAppHtmlPage(TFont * Font, TPanel * Parent, const UnicodeString & Body, bool Seamless);
+void LoadBrowserDocument(TWebBrowserEx * WebBrowser, const UnicodeString & Document);
 TComponent * __fastcall FindComponentRecursively(TComponent * Root, const UnicodeString & Name);
 void __fastcall GetInstrutionsTheme(
   TColor & MainInstructionColor, HFONT & MainInstructionFont, HFONT & InstructionFont);

+ 25 - 10
source/windows/Setup.cpp

@@ -1527,22 +1527,37 @@ static void __fastcall InsertDonateLink(void * /*Data*/, TObject * Sender)
     Panel->Name = DonatePanelName;
     Panel->Caption = UnicodeString(); // override default use of Name
 
-    TStaticText * StaticText = new TStaticText(Panel);
-    StaticText->Top = 0;
-    StaticText->Left = 0;
-    StaticText->AutoSize = true;
-    StaticText->Caption = LoadStr(UPDATES_DONATE_LINK);
-    StaticText->Parent = Panel;
-    StaticText->OnClick = MakeMethod<TNotifyEvent>(NULL, UpdatesDonateClick);
-    StaticText->TabStop = true;
+    TWebBrowserEx * DonateBrowser = CreateBrowserViewer(Panel, UnicodeString());
+    ReadyBrowserForStreaming(DonateBrowser);
+    WaitBrowserToIdle(DonateBrowser);
 
-    LinkLabel(StaticText);
+    DonateBrowser->Height = ScaleByTextHeight(Dialog, 36);
 
-    Panel->Height = StaticText->Height;
+    DonateBrowser->Top = 0;
+    DonateBrowser->Left = 0;
+
+    Panel->Height = DonateBrowser->Height;
 
     // Currently this is noop (will fail assertion), if MoreMessagesUrl is not set
     // (what should not happen)
     InsertPanelToMessageDialog(Dialog, Panel);
+
+    UnicodeString DocumentBody = LoadStr(UPDATES_DONATE_HTML);
+    DocumentBody = ReplaceStr(DocumentBody, L"%DONATE_URL%", GetEnableAutomaticUpdatesUrl());
+    UnicodeString AboutStoreUrl = LoadStr(ABOUT_STORE_URL);
+    DocumentBody = ReplaceStr(DocumentBody, L"%STORE_URL%", AboutStoreUrl);
+    UnicodeString StoreButtonUrl = ProgramUrl(LoadStr(STORE_GET_IMG_URL));
+    UnicodeString StoreButton =
+      FORMAT(L"<img src=\"%s\" style=\"height: 1.8em; vertical-align: -0.4em; padding-top: 0.2em; border: 0;\">", (StoreButtonUrl));
+    UnicodeString StoreUrl = FMTLOAD(STORE_URL, (L"update"));
+    UnicodeString StoreLink = FORMAT(L"<a href=\"%s\">%s</a>", (StoreUrl, StoreButton));
+    DocumentBody = ReplaceStr(DocumentBody, L"%GET_IMG% ", FORMAT(L"%s&nbsp;", (StoreLink)));
+
+    DocumentBody = FORMAT(L"<p>%s</p>", (DocumentBody));
+
+    UnicodeString Document = GenerateAppHtmlPage(Dialog->Font, Panel, DocumentBody, true);
+    LoadBrowserDocument(DonateBrowser, Document);
+    HideBrowserScrollbars(DonateBrowser);
   }
 }
 //---------------------------------------------------------------------------