1
0
mirror of https://github.com/chylex/TweetDuck.git synced 2025-09-14 19:32:10 +02:00

Compare commits

..

6 Commits

14 changed files with 246 additions and 76 deletions

View File

@@ -12,6 +12,7 @@ using TweetDuck.Core.Other;
using TweetDuck.Core.Other.Analytics;
using TweetDuck.Core.Utils;
using TweetDuck.Plugins;
using TweetDuck.Plugins.Enums;
using TweetDuck.Plugins.Events;
using TweetDuck.Updates;
@@ -38,6 +39,7 @@ namespace TweetDuck.Core{
public string UpdateInstallerPath { get; private set; }
public PluginManager PluginManager => plugins;
public AnalyticsFile AnalyticsFile => analytics?.File ?? AnalyticsFile.Dummy;
private readonly TweetDeckBrowser browser;
@@ -57,17 +59,19 @@ namespace TweetDuck.Core{
InitializeComponent();
Text = Program.BrandName;
this.browser = new TweetDeckBrowser(this, new TweetDeckBridge.Browser(this, notification));
this.contextMenu = ContextMenuBrowser.CreateMenu(this);
this.plugins = new PluginManager(browser, Program.PluginPath, Program.PluginConfigFilePath);
this.plugins = new PluginManager(Program.PluginPath, Program.PluginConfigFilePath);
this.plugins.Reloaded += plugins_Reloaded;
this.plugins.Executed += plugins_Executed;
this.plugins.Reload();
this.notification = new FormNotificationTweet(this, plugins);
this.notification.Show();
this.browser = new TweetDeckBrowser(this, new TweetDeckBridge.Browser(this, notification));
this.contextMenu = ContextMenuBrowser.CreateMenu(this);
this.plugins.Register(browser, PluginEnvironment.Browser, true);
Controls.Add(new MenuStrip{ Visible = false }); // fixes Alt freezing the program in Win 10 Anniversary Update

View File

@@ -12,7 +12,7 @@ using TweetDuck.Plugins.Enums;
using TweetDuck.Resources;
namespace TweetDuck.Core.Notification{
abstract partial class FormNotificationMain : FormNotificationBase{
abstract partial class FormNotificationMain : FormNotificationBase, ITweetDeckBrowser{
private const string NotificationScriptFile = "notification.js";
private static readonly string NotificationScriptIdentifier = ScriptLoader.GetRootIdentifier(NotificationScriptFile);
@@ -81,17 +81,35 @@ namespace TweetDuck.Core.Notification{
this.timerBarHeight = BrowserUtils.Scale(4, DpiScale);
browser.KeyboardHandler = new KeyboardHandlerNotification(this);
browser.RegisterAsyncJsObject("$TD", new TweetDeckBridge.Notification(owner, this));
browser.RegisterAsyncJsObject("$TDP", plugins.Bridge);
browser.LoadingStateChanged += Browser_LoadingStateChanged;
browser.FrameLoadEnd += Browser_FrameLoadEnd;
plugins.Register(this, PluginEnvironment.Notification);
mouseHookDelegate = MouseHookProc;
Disposed += (sender, args) => StopMouseHook(true);
}
void ITweetDeckBrowser.RegisterBridge(string name, object obj){
browser.RegisterAsyncJsObject(name, obj);
}
void ITweetDeckBrowser.OnFrameLoaded(Action<IFrame> callback){
browser.FrameLoadEnd += (sender, args) => {
IFrame frame = args.Frame;
if (frame.IsMain && NotificationJS != null && browser.Address != "about:blank"){
callback(frame);
}
};
}
void ITweetDeckBrowser.ExecuteFunction(string name, params object[] args){
browser.ExecuteScriptAsync(name, args);
}
// mouse wheel hook
private void StartMouseHook(){
@@ -166,7 +184,6 @@ namespace TweetDuck.Core.Notification{
if (e.Frame.IsMain && NotificationJS != null && browser.Address != "about:blank"){
e.Frame.ExecuteJavaScriptAsync(PropertyBridge.GenerateScript(PropertyBridge.Environment.Notification));
ScriptLoader.ExecuteScript(e.Frame, NotificationJS, NotificationScriptIdentifier);
plugins.ExecutePlugins(e.Frame, PluginEnvironment.Notification);
}
}
@@ -232,7 +249,7 @@ namespace TweetDuck.Core.Notification{
protected override string GetTweetHTML(TweetNotification tweet){
string html = base.GetTweetHTML(tweet);
foreach(InjectedHTML injection in plugins.Bridge.NotificationInjections){
foreach(InjectedHTML injection in plugins.NotificationInjections){
html = injection.Inject(html);
}

View File

@@ -33,7 +33,7 @@ namespace TweetDuck.Core.Notification.Screenshot{
protected override string GetTweetHTML(TweetNotification tweet){
string html = tweet.GenerateHtml("td-screenshot", false);
foreach(InjectedHTML injection in plugins.Bridge.NotificationInjections){
foreach(InjectedHTML injection in plugins.NotificationInjections){
html = injection.Inject(html);
}

View File

@@ -5,6 +5,7 @@ using System.Diagnostics;
using System.IO;
using System.Linq;
using TweetDuck.Core;
using TweetDuck.Data;
using TweetDuck.Plugins.Enums;
using TweetDuck.Plugins.Events;
using TweetDuck.Resources;
@@ -21,42 +22,46 @@ namespace TweetDuck.Plugins{
public string PathCustomPlugins => Path.Combine(rootPath, "user");
public IEnumerable<Plugin> Plugins => plugins;
public IEnumerable<InjectedHTML> NotificationInjections => bridge.NotificationInjections;
public PluginConfig Config { get; }
public PluginBridge Bridge { get; }
public event EventHandler<PluginErrorEventArgs> Reloaded;
public event EventHandler<PluginErrorEventArgs> Executed;
private readonly ITweetDeckBrowser browser;
private readonly string rootPath;
private readonly string configPath;
private readonly PluginBridge bridge;
private readonly HashSet<Plugin> plugins = new HashSet<Plugin>();
private readonly Dictionary<int, Plugin> tokens = new Dictionary<int, Plugin>();
private readonly Random rand = new Random();
public PluginManager(ITweetDeckBrowser browser, string rootPath, string configPath){
this.browser = browser;
private ITweetDeckBrowser mainBrowser;
public PluginManager(string rootPath, string configPath){
this.rootPath = rootPath;
this.configPath = configPath;
this.Config = new PluginConfig();
this.Bridge = new PluginBridge(this);
this.browser.OnFrameLoaded(OnFrameLoaded);
this.browser.RegisterBridge("$TDP", Bridge);
this.bridge = new PluginBridge(this);
Config.Load(configPath);
Config.PluginChangedState += Config_PluginChangedState;
}
private void Config_PluginChangedState(object sender, PluginChangedStateEventArgs e){
browser.ExecuteFunction("TDPF_setPluginState", e.Plugin, e.IsEnabled);
Config.Save(configPath);
public void Register(ITweetDeckBrowser browser, PluginEnvironment environment, bool asMainBrowser = false){
browser.OnFrameLoaded(frame => ExecutePlugins(frame, environment));
browser.RegisterBridge("$TDP", bridge);
if (asMainBrowser){
mainBrowser = browser;
}
}
private void OnFrameLoaded(IFrame frame){
ExecutePlugins(frame, PluginEnvironment.Browser);
private void Config_PluginChangedState(object sender, PluginChangedStateEventArgs e){
mainBrowser?.ExecuteFunction("TDPF_setPluginState", e.Plugin, e.IsEnabled);
Config.Save(configPath);
}
public bool IsPluginInstalled(string identifier){
@@ -68,12 +73,12 @@ namespace TweetDuck.Plugins{
}
public bool IsPluginConfigurable(Plugin plugin){
return plugin.HasConfig || Bridge.WithConfigureFunction.Contains(plugin);
return plugin.HasConfig || bridge.WithConfigureFunction.Contains(plugin);
}
public void ConfigurePlugin(Plugin plugin){
if (Bridge.WithConfigureFunction.Contains(plugin)){
browser.ExecuteFunction("TDPF_configurePlugin", plugin);
if (bridge.WithConfigureFunction.Contains(plugin)){
mainBrowser?.ExecuteFunction("TDPF_configurePlugin", plugin);
}
else if (plugin.HasConfig){
if (File.Exists(plugin.ConfigPath)){
@@ -143,7 +148,7 @@ namespace TweetDuck.Plugins{
Reloaded?.Invoke(this, new PluginErrorEventArgs(loadErrors));
}
public void ExecutePlugins(IFrame frame, PluginEnvironment environment){
private void ExecutePlugins(IFrame frame, PluginEnvironment environment){
if (!HasAnyPlugin(environment)){
return;
}

View File

@@ -20,7 +20,7 @@ namespace TweetDuck{
public const string BrandName = "TweetDuck";
public const string Website = "https://tweetduck.chylex.com";
public const string VersionTag = "1.13";
public const string VersionTag = "1.13.0.1";
public static readonly bool IsPortable = File.Exists("makeportable");

View File

@@ -12,10 +12,9 @@ The program was built using Visual Studio 2017. Before opening the solution, ple
* **Desktop development with C++**
* VC++ 2017 v141 toolset
After opening the solution, download the following NuGet packages by right-clicking on the solution and selecting **Restore NuGet Packages**, or manually running these commands in the **Package Manager Console**:
After opening the solution, download the following NuGet packages by right-clicking on the solution and selecting **Restore NuGet Packages**, or manually running this command in the **Package Manager Console**:
```
PM> Install-Package CefSharp.WinForms -Version 63.0.0-pre01 -Source https://www.myget.org/F/cefsharp/api/v3/index.json
PM> Install-Package Microsoft.VC120.CRT.JetBrains
PM> Install-Package CefSharp.WinForms -Version 64.0.0-CI2508 -Source https://www.myget.org/F/cefsharp/api/v3/index.json
```
Note that some pre-release builds of CefSharp are not available on NuGet. To correctly restore packages in that case, open **Package Manager Settings**, and add `https://www.myget.org/F/cefsharp/api/v3/index.json` to the list of package sources.

View File

@@ -294,6 +294,8 @@
tags.push("<style type='text/css'>");
tags.push("body { background: "+getClassStyleProperty("column", "background-color")+" !important }"); // set background color
tags.push("body::before { content: none !important }"); // remove background gradient
tags.push(".column { background: transparent !important }"); // remove background color from columns
tags.push("a[data-full-url] { word-break: break-all !important }"); // break long urls
tags.push(".media-item, .media-preview { border-radius: 1px !important }"); // square-ify media
tags.push(".quoted-tweet { border-radius: 0 !important }"); // square-ify quoted tweets

View File

@@ -2,18 +2,10 @@
/* General */
/***********/
body:before {
content: none !important;
}
body {
overflow-y: auto !important;
}
.column {
background: transparent !important;
}
.scroll-styled-v::-webkit-scrollbar {
width: 7px !important;
}

View File

@@ -1,7 +1,7 @@
<?xml version="1.0" encoding="utf-8"?>
<Project ToolsVersion="12.0" DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<Import Project="packages\CefSharp.WinForms.64.0.0-CI2497\build\CefSharp.WinForms.props" Condition="Exists('packages\CefSharp.WinForms.64.0.0-CI2497\build\CefSharp.WinForms.props')" />
<Import Project="packages\CefSharp.Common.64.0.0-CI2497\build\CefSharp.Common.props" Condition="Exists('packages\CefSharp.Common.64.0.0-CI2497\build\CefSharp.Common.props')" />
<Import Project="packages\CefSharp.WinForms.64.0.0-CI2508\build\CefSharp.WinForms.props" Condition="Exists('packages\CefSharp.WinForms.64.0.0-CI2508\build\CefSharp.WinForms.props')" />
<Import Project="packages\CefSharp.Common.64.0.0-CI2508\build\CefSharp.Common.props" Condition="Exists('packages\CefSharp.Common.64.0.0-CI2508\build\CefSharp.Common.props')" />
<Import Project="packages\cef.redist.x86.3.3282.1731\build\cef.redist.x86.props" Condition="Exists('packages\cef.redist.x86.3.3282.1731\build\cef.redist.x86.props')" />
<Import Project="packages\cef.redist.x64.3.3282.1731\build\cef.redist.x64.props" Condition="Exists('packages\cef.redist.x64.3.3282.1731\build\cef.redist.x64.props')" />
<Import Project="$(MSBuildExtensionsPath)\$(MSBuildToolsVersion)\Microsoft.Common.props" Condition="Exists('$(MSBuildExtensionsPath)\$(MSBuildToolsVersion)\Microsoft.Common.props')" />
@@ -398,8 +398,6 @@
del "$(TargetDir)LICENSE.txt"
ren "$(TargetDir)LICENSE.md" "LICENSE.txt"
xcopy "$(ProjectDir)bld\Resources\CEFSHARP-LICENSE.txt" "$(TargetDir)" /Y
xcopy "$(ProjectDir)packages\Microsoft.VC120.CRT.JetBrains.12.0.21005.2\DotFiles\msvcp120.dll" "$(TargetDir)" /Y
xcopy "$(ProjectDir)packages\Microsoft.VC120.CRT.JetBrains.12.0.21005.2\DotFiles\msvcr120.dll" "$(TargetDir)" /Y
rmdir "$(TargetDir)scripts" /S /Q
mkdir "$(TargetDir)scripts"
@@ -444,11 +442,11 @@ powershell -ExecutionPolicy Unrestricted -File "$(ProjectDir)Resources\PostBuild
</PropertyGroup>
<Error Condition="!Exists('packages\cef.redist.x64.3.3282.1731\build\cef.redist.x64.props')" Text="$([System.String]::Format('$(ErrorText)', 'packages\cef.redist.x64.3.3282.1731\build\cef.redist.x64.props'))" />
<Error Condition="!Exists('packages\cef.redist.x86.3.3282.1731\build\cef.redist.x86.props')" Text="$([System.String]::Format('$(ErrorText)', 'packages\cef.redist.x86.3.3282.1731\build\cef.redist.x86.props'))" />
<Error Condition="!Exists('packages\CefSharp.Common.64.0.0-CI2497\build\CefSharp.Common.props')" Text="$([System.String]::Format('$(ErrorText)', 'packages\CefSharp.Common.64.0.0-CI2497\build\CefSharp.Common.props'))" />
<Error Condition="!Exists('packages\CefSharp.Common.64.0.0-CI2497\build\CefSharp.Common.targets')" Text="$([System.String]::Format('$(ErrorText)', 'packages\CefSharp.Common.64.0.0-CI2497\build\CefSharp.Common.targets'))" />
<Error Condition="!Exists('packages\CefSharp.WinForms.64.0.0-CI2497\build\CefSharp.WinForms.props')" Text="$([System.String]::Format('$(ErrorText)', 'packages\CefSharp.WinForms.64.0.0-CI2497\build\CefSharp.WinForms.props'))" />
<Error Condition="!Exists('packages\CefSharp.WinForms.64.0.0-CI2497\build\CefSharp.WinForms.targets')" Text="$([System.String]::Format('$(ErrorText)', 'packages\CefSharp.WinForms.64.0.0-CI2497\build\CefSharp.WinForms.targets'))" />
<Error Condition="!Exists('packages\CefSharp.Common.64.0.0-CI2508\build\CefSharp.Common.props')" Text="$([System.String]::Format('$(ErrorText)', 'packages\CefSharp.Common.64.0.0-CI2508\build\CefSharp.Common.props'))" />
<Error Condition="!Exists('packages\CefSharp.Common.64.0.0-CI2508\build\CefSharp.Common.targets')" Text="$([System.String]::Format('$(ErrorText)', 'packages\CefSharp.Common.64.0.0-CI2508\build\CefSharp.Common.targets'))" />
<Error Condition="!Exists('packages\CefSharp.WinForms.64.0.0-CI2508\build\CefSharp.WinForms.props')" Text="$([System.String]::Format('$(ErrorText)', 'packages\CefSharp.WinForms.64.0.0-CI2508\build\CefSharp.WinForms.props'))" />
<Error Condition="!Exists('packages\CefSharp.WinForms.64.0.0-CI2508\build\CefSharp.WinForms.targets')" Text="$([System.String]::Format('$(ErrorText)', 'packages\CefSharp.WinForms.64.0.0-CI2508\build\CefSharp.WinForms.targets'))" />
</Target>
<Import Project="packages\CefSharp.Common.64.0.0-CI2497\build\CefSharp.Common.targets" Condition="Exists('packages\CefSharp.Common.64.0.0-CI2497\build\CefSharp.Common.targets')" />
<Import Project="packages\CefSharp.WinForms.64.0.0-CI2497\build\CefSharp.WinForms.targets" Condition="Exists('packages\CefSharp.WinForms.64.0.0-CI2497\build\CefSharp.WinForms.targets')" />
<Import Project="packages\CefSharp.Common.64.0.0-CI2508\build\CefSharp.Common.targets" Condition="Exists('packages\CefSharp.Common.64.0.0-CI2508\build\CefSharp.Common.targets')" />
<Import Project="packages\CefSharp.WinForms.64.0.0-CI2508\build\CefSharp.WinForms.targets" Condition="Exists('packages\CefSharp.WinForms.64.0.0-CI2508\build\CefSharp.WinForms.targets')" />
</Project>

View File

@@ -7,6 +7,7 @@
#define MyAppExeName "TweetDuck.exe"
#define MyAppVersion GetFileVersion("..\bin\x86\Release\TweetDuck.exe")
#define VCRedistLink "releases/download/1.13/vc_redist.x86.exe"
[Setup]
AppId={{8C25A716-7E11-4AAD-9992-8B5D0C78AE06}
@@ -30,6 +31,8 @@ SolidCompression=yes
InternalCompressLevel=max
MinVersion=0,6.1
#include <idp.iss>
[Languages]
Name: "english"; MessagesFile: "compiler:Default.isl"
@@ -56,36 +59,44 @@ Type: filesandordirs; Name: "{localappdata}\{#MyAppName}\GPUCache"
[Code]
var UpdatePath: String;
var ForceRedistPrompt: String;
function TDGetNetFrameworkVersion: Cardinal; forward;
function TDIsVCMissing: Boolean; forward;
procedure TDInstallVCRedist; forward;
{ Check .NET Framework version on startup, ask user if they want to proceed if older than 4.5.2. }
function InitializeSetup: Boolean;
begin
UpdatePath := ExpandConstant('{param:UPDATEPATH}')
ForceRedistPrompt := ExpandConstant('{param:PROMPTREDIST}')
if TDGetNetFrameworkVersion() >= 379893 then
begin
Result := True;
Exit;
end;
if (MsgBox('{#MyAppName} requires .NET Framework 4.5.2 or newer,'+#13+#10+'please download it from {#MyAppURL}'+#13+#10+#13+#10'Do you want to proceed with the setup anyway?', mbCriticalError, MB_YESNO or MB_DEFBUTTON2) = IDNO) then
if (TDGetNetFrameworkVersion() < 379893) and (MsgBox('{#MyAppName} requires .NET Framework 4.5.2 or newer,'+#13+#10+'please download it from {#MyAppURL}'+#13+#10+#13+#10'Do you want to proceed with the setup anyway?', mbCriticalError, MB_YESNO or MB_DEFBUTTON2) = IDNO) then
begin
Result := False;
Exit;
end;
if (TDIsVCMissing() or (ForceRedistPrompt = '1')) and (MsgBox('Microsoft Visual C++ 2015 appears to be missing, would you like to automatically install it?', mbConfirmation, MB_YESNO) = IDYES) then
begin
idpAddFile('https://github.com/{#MyAppPublisher}/{#MyAppName}/{#VCRedistLink}', ExpandConstant('{tmp}\{#MyAppName}.VC.exe'));
end;
Result := True;
end;
{ Set the installation path if updating. }
{ Set the installation path if updating, and prepare download plugin if there are any files to download. }
procedure InitializeWizard();
begin
if (UpdatePath <> '') then
begin
WizardForm.DirEdit.Text := UpdatePath;
end;
if idpFilesCount <> 0 then
begin
idpDownloadAfter(wpReady);
end;
end;
{ Skip the install path selection page if running from an update installer. }
@@ -94,7 +105,7 @@ begin
Result := (PageID = wpSelectDir) and (UpdatePath <> '')
end;
{ Check for an old TweetDeck profile and show a warning before installation. }
{ Check for an old TweetDeck profile and show a warning before installation, and install VC++ if downloaded. }
procedure CurStepChanged(CurStep: TSetupStep);
begin
if CurStep = ssInstall then
@@ -103,6 +114,8 @@ begin
begin
MsgBox('Detected a profile from an old TweetDeck installation, you may uninstall the old client to free up some space.', mbInformation, MB_OK)
end;
TDInstallVCRedist();
end;
end;
@@ -145,3 +158,65 @@ begin
Result := 0;
end;
{ Check if Visual C++ 2015 or 2017 is installed. }
function TDIsVCMissing: Boolean;
var Keys: TArrayOfString;
var Index: Integer;
var Key: String;
var DisplayName: String;
begin
if RegGetSubkeyNames(HKEY_LOCAL_MACHINE, 'Software\Classes\Installer\Dependencies', Keys) then
begin
for Index := 0 to GetArrayLength(Keys)-1 do
begin
Key := Keys[Index];
if RegQueryStringValue(HKEY_LOCAL_MACHINE, 'Software\Classes\Installer\Dependencies\'+Key, 'DisplayName', DisplayName) then
begin
if (Pos('Microsoft Visual C++', DisplayName) = 1) and (Pos('(x86)', DisplayName) > 1) and ((Pos(' 2015 ', DisplayName) > 1) or (Pos(' 2017 ', DisplayName) > 1)) then
begin
Result := False;
Exit;
end;
end;
end;
end;
Result := True;
end;
{ Run the Visual C++ installer if downloaded. }
procedure TDInstallVCRedist;
var InstallFile: String;
var ResultCode: Integer;
begin
InstallFile := ExpandConstant('{tmp}\{#MyAppName}.VC.exe')
if FileExists(InstallFile) then
begin
WizardForm.ProgressGauge.Style := npbstMarquee;
try
if Exec(InstallFile, '/passive /norestart', '', SW_SHOW, ewWaitUntilTerminated, ResultCode) then
begin
if ResultCode <> 0 then
begin
DeleteFile(InstallFile);
Exit;
end;
end else
begin
MsgBox('Could not run the Visual C++ installer, please visit https://github.com/{#MyAppPublisher}/{#MyAppName}/{#VCRedistLink} and download the latest version manually. Error: '+SysErrorMessage(ResultCode), mbCriticalError, MB_OK);
DeleteFile(InstallFile);
Exit;
end;
finally
WizardForm.ProgressGauge.Style := npbstNormal;
DeleteFile(InstallFile);
end;
end;
end;

View File

@@ -7,6 +7,7 @@
#define MyAppExeName "TweetDuck.exe"
#define MyAppVersion GetFileVersion("..\bin\x86\Release\TweetDuck.exe")
#define VCRedistLink "releases/download/1.13/vc_redist.x86.exe"
[Setup]
AppId={{8C25A716-7E11-4AAD-9992-8B5D0C78AE06}
@@ -30,6 +31,8 @@ SolidCompression=yes
InternalCompressLevel=max
MinVersion=0,6.1
#include <idp.iss>
[Languages]
Name: "english"; MessagesFile: "compiler:Default.isl"
@@ -42,36 +45,44 @@ Filename: "{app}\{#MyAppExeName}"; Description: "{cm:LaunchProgram,{#StringChang
[Code]
var UpdatePath: String;
var ForceRedistPrompt: String;
function TDGetNetFrameworkVersion: Cardinal; forward;
function TDIsVCMissing: Boolean; forward;
procedure TDInstallVCRedist; forward;
{ Check .NET Framework version on startup, ask user if they want to proceed if older than 4.5.2. }
function InitializeSetup: Boolean;
begin
UpdatePath := ExpandConstant('{param:UPDATEPATH}')
ForceRedistPrompt := ExpandConstant('{param:PROMPTREDIST}')
if TDGetNetFrameworkVersion() >= 379893 then
begin
Result := True;
Exit;
end;
if (MsgBox('{#MyAppName} requires .NET Framework 4.5.2 or newer,'+#13+#10+'please download it from {#MyAppURL}'+#13+#10+#13+#10'Do you want to proceed with the setup anyway?', mbCriticalError, MB_YESNO or MB_DEFBUTTON2) = IDNO) then
if (TDGetNetFrameworkVersion() < 379893) and (MsgBox('{#MyAppName} requires .NET Framework 4.5.2 or newer,'+#13+#10+'please download it from {#MyAppURL}'+#13+#10+#13+#10'Do you want to proceed with the setup anyway?', mbCriticalError, MB_YESNO or MB_DEFBUTTON2) = IDNO) then
begin
Result := False;
Exit;
end;
if (TDIsVCMissing() or (ForceRedistPrompt = '1')) and (MsgBox('Microsoft Visual C++ 2015 appears to be missing, would you like to automatically install it?', mbConfirmation, MB_YESNO) = IDYES) then
begin
idpAddFile('https://github.com/{#MyAppPublisher}/{#MyAppName}/{#VCRedistLink}', ExpandConstant('{tmp}\{#MyAppName}.VC.exe'));
end;
Result := True;
end;
{ Set the installation path if updating. }
{ Set the installation path if updating, and prepare download plugin if there are any files to download. }
procedure InitializeWizard();
begin
if (UpdatePath <> '') then
begin
WizardForm.DirEdit.Text := UpdatePath;
end;
if idpFilesCount <> 0 then
begin
idpDownloadAfter(wpReady);
end;
end;
{ Skip the install path selection page if running from an update installer. }
@@ -80,6 +91,24 @@ begin
Result := (PageID = wpSelectDir) and (UpdatePath <> '')
end;
{ Install VC++ if downloaded, and create a 'makeportable' file for portable installs. }
procedure CurStepChanged(CurStep: TSetupStep);
begin
if CurStep = ssInstall then
begin
TDInstallVCRedist();
end else if CurStep = ssPostInstall then
begin
while not SaveStringToFile(ExpandConstant('{app}\makeportable'), '', False) do
begin
if MsgBox('Could not create a ''makeportable'' file in the installation folder. If the file is not present, the installation will not be fully portable.', mbCriticalError, MB_RETRYCANCEL) <> IDRETRY then
begin
break;
end;
end;
end;
end;
{ Return DWORD value containing the build version of .NET Framework. }
function TDGetNetFrameworkVersion: Cardinal;
var FrameworkVersion: Cardinal;
@@ -94,17 +123,64 @@ begin
Result := 0;
end;
{ Create a 'makeportable' file if running in portable mode. }
procedure CurStepChanged(CurStep: TSetupStep);
{ Check if Visual C++ 2015 or 2017 is installed. }
function TDIsVCMissing: Boolean;
var Keys: TArrayOfString;
var Index: Integer;
var Key: String;
var DisplayName: String;
begin
if CurStep = ssPostInstall then
if RegGetSubkeyNames(HKEY_LOCAL_MACHINE, 'Software\Classes\Installer\Dependencies', Keys) then
begin
while not SaveStringToFile(ExpandConstant('{app}\makeportable'), '', False) do
for Index := 0 to GetArrayLength(Keys)-1 do
begin
if MsgBox('Could not create a ''makeportable'' file in the installation folder. If the file is not present, the installation will not be fully portable.', mbCriticalError, MB_RETRYCANCEL) <> IDRETRY then
Key := Keys[Index];
if RegQueryStringValue(HKEY_LOCAL_MACHINE, 'Software\Classes\Installer\Dependencies\'+Key, 'DisplayName', DisplayName) then
begin
break;
if (Pos('Microsoft Visual C++', DisplayName) = 1) and (Pos('(x86)', DisplayName) > 1) and ((Pos(' 2015 ', DisplayName) > 1) or (Pos(' 2017 ', DisplayName) > 1)) then
begin
Result := False;
Exit;
end;
end;
end;
end;
Result := True;
end;
{ Run the Visual C++ installer if downloaded. }
procedure TDInstallVCRedist;
var InstallFile: String;
var ResultCode: Integer;
begin
InstallFile := ExpandConstant('{tmp}\{#MyAppName}.VC.exe')
if FileExists(InstallFile) then
begin
WizardForm.ProgressGauge.Style := npbstMarquee;
try
if Exec(InstallFile, '/passive /norestart', '', SW_SHOW, ewWaitUntilTerminated, ResultCode) then
begin
if ResultCode <> 0 then
begin
DeleteFile(InstallFile);
Exit;
end;
end else
begin
MsgBox('Could not run the Visual C++ installer, please visit https://github.com/{#MyAppPublisher}/{#MyAppName}/{#VCRedistLink} and download the latest version manually. Error: '+SysErrorMessage(ResultCode), mbCriticalError, MB_OK);
DeleteFile(InstallFile);
Exit;
end;
finally
WizardForm.ProgressGauge.Style := npbstNormal;
DeleteFile(InstallFile);
end;
end;
end;

View File

@@ -59,6 +59,8 @@ Type: filesandordirs; Name: "{localappdata}\{#MyAppName}\Cache"
Type: filesandordirs; Name: "{localappdata}\{#MyAppName}\GPUCache"
[InstallDelete]
Type: files; Name: "{app}\msvcp120.dll"
Type: files; Name: "{app}\msvcr120.dll"
Type: files; Name: "{app}\TweetLib.Audio.dll"
Type: filesandordirs; Name: "{app}\scripts"
Type: filesandordirs; Name: "{app}\plugins\official"

View File

@@ -2,7 +2,7 @@
<packages>
<package id="cef.redist.x64" version="3.3282.1731" targetFramework="net452" xmlns="" />
<package id="cef.redist.x86" version="3.3282.1731" targetFramework="net452" xmlns="" />
<package id="CefSharp.Common" version="64.0.0-CI2497" targetFramework="net452" xmlns="" />
<package id="CefSharp.WinForms" version="64.0.0-CI2497" targetFramework="net452" xmlns="" />
<package id="CefSharp.Common" version="64.0.0-CI2508" targetFramework="net452" xmlns="" />
<package id="CefSharp.WinForms" version="64.0.0-CI2508" targetFramework="net452" xmlns="" />
<package id="Microsoft.VC120.CRT.JetBrains" version="12.0.21005.2" targetFramework="net452" xmlns="" />
</packages>

View File

@@ -24,9 +24,9 @@
<StartupObject />
</PropertyGroup>
<ItemGroup>
<Reference Include="CefSharp.BrowserSubprocess.Core, Version=63.0.0.0, Culture=neutral, PublicKeyToken=40c4b6fc221f4138, processorArchitecture=x86">
<Reference Include="CefSharp.BrowserSubprocess.Core, Version=64.0.0.0, Culture=neutral, PublicKeyToken=40c4b6fc221f4138, processorArchitecture=x86">
<SpecificVersion>False</SpecificVersion>
<HintPath>..\packages\CefSharp.Common.64.0.0-CI2497\CefSharp\x86\CefSharp.BrowserSubprocess.Core.dll</HintPath>
<HintPath>..\packages\CefSharp.Common.64.0.0-CI2508\CefSharp\x86\CefSharp.BrowserSubprocess.Core.dll</HintPath>
</Reference>
<Reference Include="System" />
</ItemGroup>