1
0
mirror of https://github.com/winscp/winscp.git synced 2026-10-24 02:28:55 +03:00
Files
winscp/source/forms/About.cpp
2026-08-05 01:19:57 +02:00

508 lines
16 KiB
C++

//---------------------------------------------------------------------
#include <FormsPCH.h>
#pragma hdrstop
#include <PuttyTools.h>
#include "About.h"
// must be included before WebBrowserEx.hpp to avoid ambiguity of tagLOGFONTW
#include <TB2Version.hpp>
#include <TBX.hpp>
#include <JclBase.hpp>
#include <JclDebug.hpp>
#include <WebBrowserEx.hpp>
#include <FtpFileSystem.h>
#include <S3FileSystem.h>
//---------------------------------------------------------------------
#pragma link "SHDocVw_OCX"
#pragma resource "*.dfm"
//---------------------------------------------------------------------------
static void __fastcall DoAboutDialog(TConfiguration * Configuration,
bool AllowLicense, TRegistration * Registration, bool LoadThirdParty)
{
TAboutDialog * AboutDialog = NULL;
try
{
AboutDialog = new TAboutDialog(Application, Configuration, AllowLicense,
Registration, LoadThirdParty);
AboutDialog->ShowModal();
}
__finally
{
delete AboutDialog;
}
}
//---------------------------------------------------------------------------
void __fastcall DoAboutDialog(TConfiguration * Configuration,
bool AllowLicense, TRegistration * Registration)
{
try
{
DoAboutDialog(Configuration, AllowLicense, Registration, true);
}
catch (EOleException &)
{
// This happens particularly on Wine that does not support some
// functionality of embedded IE we need.
DoAboutDialog(Configuration, AllowLicense, Registration, false);
}
}
//---------------------------------------------------------------------------
__fastcall TAboutDialog::TAboutDialog(TComponent * AOwner,
TConfiguration * Configuration, bool AllowLicense, TRegistration * Registration,
bool ALoadThirdParty)
: TForm(AOwner)
{
FConfiguration = Configuration;
UseSystemSettings(this);
LinkLabel(HomepageLabel, LoadStr(HOMEPAGE_URL));
LinkLabel(ForumUrlLabel, LoadStr(FORUM_URL));
ApplicationLabel->Caption = AppName;
TColor MainInstructionColor;
HFONT MainInstructionFont;
HFONT InstructionFont;
GetInstrutionsTheme(MainInstructionColor, MainInstructionFont, InstructionFont);
if (MainInstructionFont != 0)
{
int PrevHeight = ApplicationLabel->Height;
ApplicationLabel->Font->Handle = MainInstructionFont;
if (MainInstructionColor != Graphics::clNone)
{
ApplicationLabel->Font->Color = MainInstructionColor;
}
ShiftControls(ApplicationLabel->Top + 1, (ApplicationLabel->Height - PrevHeight));
}
else
{
ApplicationLabel->ParentFont = true;
ApplicationLabel->Font->Style = ApplicationLabel->Font->Style << fsBold;
}
WinSCPCopyrightLabel->Caption = LoadStr(WINSCP_COPYRIGHT);
if (Registration == NULL)
{
RegistrationLabel->Visible = false;
RegistrationBox->Visible = false;
ShiftControls(RegistrationLabel->Top, (RegistrationBox->Top - ThirdPartyPanel->Top));
}
else
{
RegistrationSubjectLabel->Caption = Registration->Subject;
if (Registration->Registered)
{
UnicodeString Text;
Text = FORMAT(LoadStrPart(ABOUT_REGISTRATION_LICENSES, 1),
(Registration->Licenses >= 0 ? IntToStr(Registration->Licenses) :
UnicodeString(LoadStrPart(ABOUT_REGISTRATION_LICENSES, 2))));
if (!Registration->NeverExpires)
{
Text = FMTLOAD(ABOUT_REGISTRATION_EXPIRES,
(Text, FormatDateTime(L"ddddd", Registration->Expiration)));
}
RegistrationLicensesLabel->Caption = Text;
Text = FMTLOAD(ABOUT_REGISTRATION_PRODUCTID, (Registration->ProductId));
if (Registration->EduLicense)
{
Text = FMTLOAD(ABOUT_REGISTRATION_EDULICENSE, (Text));
}
RegistrationProductIdLabel->Caption = Text;
RegistrationProductIdLabel->Font->Style =
RegistrationProductIdLabel->Font->Style << fsBold;
}
else
{
RegistrationLicensesLabel->Visible = false;
FOnRegistrationLink = Registration->OnRegistrationLink;
RegistrationProductIdLabel->Caption = LoadStr(ABOUT_REGISTRATION_LINK);
LinkLabel(RegistrationProductIdLabel, L"");
}
}
LicenseButton->Visible = AllowLicense;
LoadData();
if (ALoadThirdParty)
{
LoadThirdParty();
}
else
{
CreateLabelPanel(ThirdPartyPanel, LoadStr(MESSAGE_DISPLAY_ERROR));
}
int IconSize = ScaleByPixelsPerInch(48, this);
FIconHandle = static_cast<HICON>(LoadImage(MainInstance, L"MAINICON", IMAGE_ICON, IconSize, IconSize, 0));
IconPaintBox->Width = IconSize;
IconPaintBox->Height = IconSize;
}
//---------------------------------------------------------------------------
__fastcall TAboutDialog::~TAboutDialog()
{
DestroyIcon(FIconHandle);
}
//---------------------------------------------------------------------------
void __fastcall TAboutDialog::ShiftControls(int From, int Diff)
{
for (int Index = 0; Index < Panel->ControlCount; Index++)
{
if (Panel->Controls[Index]->Top > From)
{
Panel->Controls[Index]->Top = Panel->Controls[Index]->Top + Diff;
}
}
ClientHeight = ClientHeight + Diff;
}
//---------------------------------------------------------------------------
void __fastcall TAboutDialog::LoadData()
{
UnicodeString Version = FConfiguration->VersionStr;
if (!FConfiguration->ProductName.IsEmpty() &&
(FConfiguration->Version != FConfiguration->ProductVersion))
{
Version = FMTLOAD(ABOUT_BASED_ON_PRODUCT,
(Version, FConfiguration->ProductName, FConfiguration->ProductVersion));
}
VersionLabel->Caption = Version;
}
//---------------------------------------------------------------------------
void __fastcall TAboutDialog::LoadThirdParty()
{
FThirdPartyWebBrowser = CreateBrowserViewer(ThirdPartyPanel, L"");
reinterpret_cast<TLabel *>(FThirdPartyWebBrowser)->Color = ThirdPartyPanel->Color;
ReadyBrowserForStreaming(FThirdPartyWebBrowser);
DoLoadThirdParty();
}
//---------------------------------------------------------------------------
static UnicodeString ExpatLicenseUrl = L"license:expat";
static UnicodeString HtmlBr = "<br/>\n";
UnicodeString TAboutDialog::GenerateThirdParty(bool Html)
{
UnicodeString ThirdParty;
UnicodeString Br = Html ? HtmlBr : L"\n";
if (!GUIConfiguration->UsingInternalTranslation())
{
UnicodeString TranslatorUrl = LoadStr(TRANSLATOR_URL);
UnicodeString TranslatorInfo = LoadStr(TRANSLATOR_INFO2);
wchar_t LocaleNameStr[255];
GetLocaleInfo(
GUIConfiguration->AppliedLocale, LOCALE_SLOCALIZEDLANGUAGENAME,
LocaleNameStr, std::size(LocaleNameStr));
UnicodeString LocaleName(LocaleNameStr);
// The {language} should be present only if we are using an untranslated
// (=english) string
UnicodeString TranslationHeader = ReplaceStr(LoadStr(ABOUT_TRANSLATIONS_HEADER), L"{language}", LocaleName);
AddPara(
Html, ThirdParty,
TranslationHeader + Br +
FMTLOAD(ABOUT_TRANSLATIONS_COPYRIGHT, (GUIConfiguration->AppliedLocaleCopyright())) + Br +
(!TranslatorInfo.IsEmpty() ? TranslatorInfo + Br : EmptyStr) +
(!TranslatorUrl.IsEmpty() ? CreateLink(Html, TranslatorUrl) : EmptyStr));
}
AddPara(Html, ThirdParty, LoadStr(ABOUT_THIRDPARTY_HEADER));
AddPara(
Html, ThirdParty,
FMTLOAD(PUTTY_BASED_ON, (GetPuTTYVersion())) + Br +
LoadStr(PUTTY_COPYRIGHT) + Br +
CreateLicenseLinkLine(Html, LoadStr(PUTTY_LICENSE_URL)) +
CreateLink(Html, LoadStr(PUTTY_URL)));
UnicodeString OpenSSLVersionText = GetOpenSSLVersionText();
CutToChar(OpenSSLVersionText, L' ', true); // "OpenSSL"
UnicodeString OpenSSLVersion = CutToChar(OpenSSLVersionText, L' ', true);
CutToChar(OpenSSLVersionText, L' ', true); // day
CutToChar(OpenSSLVersionText, L' ', true); // month
UnicodeString OpenSSLYear = CutToChar(OpenSSLVersionText, L' ', true);
AddPara(
Html, ThirdParty,
FMTLOAD(OPENSSL_BASED_ON, (OpenSSLVersion)) + Br +
FMTLOAD(OPENSSL_COPYRIGHT2, (OpenSSLYear)) + Br +
CreateLink(Html, LoadStr(OPENSSL_URL)));
AddPara(
Html, ThirdParty,
LoadStr(FILEZILLA_BASED_ON2) + Br +
LoadStr(FILEZILLA_COPYRIGHT2) + Br +
CreateLink(Html, LoadStr(FILEZILLA_URL)));
AddPara(
Html, ThirdParty,
FMTLOAD(NEON_BASED_ON2, (NeonVersion())) + Br +
LoadStr(NEON_COPYRIGHT) + Br +
CreateLink(Html, LoadStr(NEON_URL)));
AddPara(
Html, ThirdParty,
FMTLOAD(S3_BASED_ON, (S3LibVersion())) + Br +
LoadStr(S3_COPYRIGHT) + Br +
CreateLicenseLinkLine(Html, LoadStr(S3_LICENSE_URL)) +
CreateLink(Html, LoadStr(S3_URL)));
AddPara(
Html, ThirdParty,
FMTLOAD(EXPAT_BASED_ON, (ExpatVersion())) + Br +
CreateLicenseLinkLine(Html, ExpatLicenseUrl) +
CreateLink(Html, LoadStr(EXPAT_URL)));
AddPara(
Html, ThirdParty,
FMTLOAD(ABOUT_TOOLBAR2000, (Toolbar2000Version)) + Br +
LoadStr(ABOUT_TOOLBAR2000_COPYRIGHT) + Br +
CreateLink(Html, LoadStr(ABOUT_TOOLBAR2000_URL)));
AddPara(
Html, ThirdParty,
FMTLOAD(ABOUT_TBX, (TBXVersionString)) + Br +
LoadStr(ABOUT_TBX_COPYRIGHT) + Br +
CreateLink(Html, LoadStr(ABOUT_TBX_URL)));
AddPara(
Html, ThirdParty,
LoadStr(ABOUT_FILEMANAGER) + Br +
LoadStr(ABOUT_FILEMANAGER_COPYRIGHT));
UnicodeString JclVersion =
FormatVersion(JclVersionMajor, JclVersionMinor, JclVersionRelease) + L" " + JclCommit;
AddPara(
Html, ThirdParty,
FMTLOAD(ABOUT_JCL, (JclVersion)) + Br +
CreateLink(Html, LoadStr(ABOUT_JCL_URL)));
AddPara(
Html, ThirdParty,
LoadStr(ABOUT_PNG) + Br +
LoadStr(ABOUT_PNG_COPYRIGHT) + Br +
CreateLink(Html, LoadStr(ABOUT_PNG_URL)));
return ThirdParty;
}
//---------------------------------------------------------------------------
void __fastcall TAboutDialog::DoLoadThirdParty()
{
WaitBrowserToIdle(FThirdPartyWebBrowser);
AddBrowserLinkHandler(FThirdPartyWebBrowser, ExpatLicenseUrl, ExpatLicenceHandler);
UnicodeString ThirdParty = GenerateThirdParty(true);
ThirdParty = GenerateAppHtmlPage(Font, ThirdPartyPanel, ThirdParty, false);
LoadBrowserDocument(FThirdPartyWebBrowser, ThirdParty);
}
//---------------------------------------------------------------------------
void TAboutDialog::AddPara(bool Html, UnicodeString & Text, const UnicodeString & S)
{
UnicodeString Para = S;
if (Html)
{
Para = L"<p>" + Para + L"</p>\n";
}
else
{
Para += L"\n\n";
}
Text += Para;
}
//---------------------------------------------------------------------------
UnicodeString TAboutDialog::CreateLicenseLinkLine(bool Html, const UnicodeString & URL)
{
return Html ? (CreateLink(true, URL, LoadStr(ABOUT_THIRDPARTY_LICENSE)) + HtmlBr) : EmptyStr;
}
//---------------------------------------------------------------------------
UnicodeString TAboutDialog::CreateLink(bool Html, const UnicodeString & URL, const UnicodeString & Title)
{
if (Html)
{
return FORMAT(L"<a href=\"%s\">%s</a>", (URL, Title.IsEmpty() ? URL : Title));
}
else
{
DebugAssert(Title.IsEmpty());
return URL;
}
}
//---------------------------------------------------------------------------
void __fastcall TAboutDialog::LicenseButtonClick(TObject * /*Sender*/)
{
DoProductLicense();
}
//---------------------------------------------------------------------------
void __fastcall TAboutDialog::HelpButtonClick(TObject * /*Sender*/)
{
FormHelp(this);
}
//---------------------------------------------------------------------------
void __fastcall TAboutDialog::RegistrationProductIdLabelClick(
TObject * /*Sender*/)
{
if (FOnRegistrationLink != NULL)
{
FOnRegistrationLink(this);
}
}
//---------------------------------------------------------------------------
void __fastcall TAboutDialog::OKButtonMouseDown(TObject * /*Sender*/,
TMouseButton Button, TShiftState Shift, int /*X*/, int /*Y*/)
{
if (Button == mbRight)
{
if (Shift.Contains(ssAlt))
{
AccessViolationTest();
}
else if (Shift.Contains(ssShift))
{
InternalExceptionTest();
}
else if (Shift.Contains(ssCtrl))
{
LookupAddress();
}
}
}
//---------------------------------------------------------------------------
void __fastcall TAboutDialog::LookupAddress()
{
UnicodeString S;
if (InputQuery(L"Address lookup", L"&Address:", S))
{
void * Address = reinterpret_cast<void *>(StrToInt(L"$" + S));
ShowMessage(GetLocationInfoStr(Address, true, true, true, true));
}
}
//---------------------------------------------------------------------------
#ifdef _WIN64
static thread_local EXCEPTION_RECORD ExceptionRecord;
static thread_local bool ExceptionCaptured = false;
//---------------------------------------------------------------------------
LONG WINAPI CaptureException(EXCEPTION_POINTERS * ExceptionInfo)
{
if (ExceptionInfo->ExceptionRecord->ExceptionCode == EXCEPTION_ACCESS_VIOLATION)
{
ExceptionRecord = *(ExceptionInfo->ExceptionRecord);
ExceptionCaptured = true;
}
return EXCEPTION_CONTINUE_SEARCH; // Let the local __except block catch it
}
#endif
//---------------------------------------------------------------------------
[[noreturn]] static void RaiseInternalError(Exception * E)
{
throw ExtException(E, MainInstructions(L"Internal error test."));
}
//---------------------------------------------------------------------------
#ifdef _WIN64
[[noreturn]]
#endif
void TAboutDialog::AccessViolationTest()
{
#ifdef _WIN64
PVOID ExceptionHandler = AddVectoredExceptionHandler(1, CaptureException);
ExceptionCaptured = false;
__try
{
ACCESS_VIOLATION_TEST;
}
#pragma clang diagnostic push
#pragma clang diagnostic ignored "-Wunreachable-code"
__except (EXCEPTION_EXECUTE_HANDLER)
#pragma clang diagnostic pop
{
RemoveVectoredExceptionHandler(ExceptionHandler);
if (ExceptionCaptured)
{
auto VclExceptionRecord = reinterpret_cast<System::PExceptionRecord>(&ExceptionRecord);
Exception * E = static_cast<Exception *>(reinterpret_cast<TExceptObjProc>(ExceptObjProc)(VclExceptionRecord));
RaiseInternalError(E);
}
throw Exception(L"Unknown hardware exception occurred.");
}
#else
try
{
ACCESS_VIOLATION_TEST;
}
catch (Exception & E)
{
RaiseInternalError(&E);
}
#endif
}
//---------------------------------------------------------------------------
void TAboutDialog::InternalExceptionTest()
{
try
{
(new TList())->Error(L"List error", 0);
}
catch (Exception & E)
{
RaiseInternalError(&E);
}
}
//---------------------------------------------------------------------------
void __fastcall TAboutDialog::ExpatLicenceHandler(TObject * /*Sender*/)
{
DoLicenseDialog(lcExpat);
}
//---------------------------------------------------------------------------
void __fastcall TAboutDialog::IconPaintBoxPaint(TObject * /*Sender*/)
{
DrawIconEx(IconPaintBox->Canvas->Handle,
0, 0, FIconHandle, IconPaintBox->Width, IconPaintBox->Height, 0, NULL, DI_NORMAL);
}
//---------------------------------------------------------------------------
void __fastcall TAboutDialog::FormAfterMonitorDpiChanged(TObject *, int OldDPI, int NewDPI)
{
DebugUsedParam2(OldDPI, NewDPI);
if (FThirdPartyWebBrowser != NULL)
{
DoLoadThirdParty();
}
}
//---------------------------------------------------------------------------
void __fastcall TAboutDialog::FormKeyDown(TObject *, WORD & Key, TShiftState Shift)
{
if ((Key == L'C') && Shift.Contains(ssCtrl))
{
if ((FThirdPartyWebBrowser != NULL) &&
FThirdPartyWebBrowser->Focused() &&
(FThirdPartyWebBrowser->SelLength() > 0))
{
// Let the browser handle the Ctrl+C
}
else
{
UnicodeString Text =
ApplicationLabel->Caption + sLineBreak +
VersionLabel->Caption + sLineBreak +
sLineBreak +
WinSCPCopyrightLabel->Caption + sLineBreak +
HomepageLabel->Caption + sLineBreak +
sLineBreak +
ProductSpecificMessageLabel->Caption + sLineBreak +
ForumUrlLabel->Caption + sLineBreak;
Text +=
sLineBreak +
GetDividerLine() + sLineBreak +
Label3->Caption + sLineBreak +
TrimRight(GenerateThirdParty(false)) + sLineBreak;
TInstantOperationVisualizer Visualizer;
CopyToClipboard(Text);
Key = 0;
}
}
}
//---------------------------------------------------------------------------