1
0
mirror of https://github.com/chylex/TweetDuck.git synced 2025-09-14 10: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.Other.Analytics;
using TweetDuck.Core.Utils; using TweetDuck.Core.Utils;
using TweetDuck.Plugins; using TweetDuck.Plugins;
using TweetDuck.Plugins.Enums;
using TweetDuck.Plugins.Events; using TweetDuck.Plugins.Events;
using TweetDuck.Updates; using TweetDuck.Updates;
@@ -38,6 +39,7 @@ namespace TweetDuck.Core{
public string UpdateInstallerPath { get; private set; } public string UpdateInstallerPath { get; private set; }
public PluginManager PluginManager => plugins;
public AnalyticsFile AnalyticsFile => analytics?.File ?? AnalyticsFile.Dummy; public AnalyticsFile AnalyticsFile => analytics?.File ?? AnalyticsFile.Dummy;
private readonly TweetDeckBrowser browser; private readonly TweetDeckBrowser browser;
@@ -57,17 +59,19 @@ namespace TweetDuck.Core{
InitializeComponent(); InitializeComponent();
Text = Program.BrandName; 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.Reloaded += plugins_Reloaded;
this.plugins.Executed += plugins_Executed; this.plugins.Executed += plugins_Executed;
this.plugins.Reload(); this.plugins.Reload();
this.notification = new FormNotificationTweet(this, plugins); this.notification = new FormNotificationTweet(this, plugins);
this.notification.Show(); 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 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; using TweetDuck.Resources;
namespace TweetDuck.Core.Notification{ namespace TweetDuck.Core.Notification{
abstract partial class FormNotificationMain : FormNotificationBase{ abstract partial class FormNotificationMain : FormNotificationBase, ITweetDeckBrowser{
private const string NotificationScriptFile = "notification.js"; private const string NotificationScriptFile = "notification.js";
private static readonly string NotificationScriptIdentifier = ScriptLoader.GetRootIdentifier(NotificationScriptFile); private static readonly string NotificationScriptIdentifier = ScriptLoader.GetRootIdentifier(NotificationScriptFile);
@@ -81,17 +81,35 @@ namespace TweetDuck.Core.Notification{
this.timerBarHeight = BrowserUtils.Scale(4, DpiScale); this.timerBarHeight = BrowserUtils.Scale(4, DpiScale);
browser.KeyboardHandler = new KeyboardHandlerNotification(this); browser.KeyboardHandler = new KeyboardHandlerNotification(this);
browser.RegisterAsyncJsObject("$TD", new TweetDeckBridge.Notification(owner, this)); browser.RegisterAsyncJsObject("$TD", new TweetDeckBridge.Notification(owner, this));
browser.RegisterAsyncJsObject("$TDP", plugins.Bridge);
browser.LoadingStateChanged += Browser_LoadingStateChanged; browser.LoadingStateChanged += Browser_LoadingStateChanged;
browser.FrameLoadEnd += Browser_FrameLoadEnd; browser.FrameLoadEnd += Browser_FrameLoadEnd;
plugins.Register(this, PluginEnvironment.Notification);
mouseHookDelegate = MouseHookProc; mouseHookDelegate = MouseHookProc;
Disposed += (sender, args) => StopMouseHook(true); 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 // mouse wheel hook
private void StartMouseHook(){ private void StartMouseHook(){
@@ -166,7 +184,6 @@ namespace TweetDuck.Core.Notification{
if (e.Frame.IsMain && NotificationJS != null && browser.Address != "about:blank"){ if (e.Frame.IsMain && NotificationJS != null && browser.Address != "about:blank"){
e.Frame.ExecuteJavaScriptAsync(PropertyBridge.GenerateScript(PropertyBridge.Environment.Notification)); e.Frame.ExecuteJavaScriptAsync(PropertyBridge.GenerateScript(PropertyBridge.Environment.Notification));
ScriptLoader.ExecuteScript(e.Frame, NotificationJS, NotificationScriptIdentifier); 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){ protected override string GetTweetHTML(TweetNotification tweet){
string html = base.GetTweetHTML(tweet); string html = base.GetTweetHTML(tweet);
foreach(InjectedHTML injection in plugins.Bridge.NotificationInjections){ foreach(InjectedHTML injection in plugins.NotificationInjections){
html = injection.Inject(html); html = injection.Inject(html);
} }

View File

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

View File

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

View File

@@ -20,7 +20,7 @@ namespace TweetDuck{
public const string BrandName = "TweetDuck"; public const string BrandName = "TweetDuck";
public const string Website = "https://tweetduck.chylex.com"; 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"); 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++** * **Desktop development with C++**
* VC++ 2017 v141 toolset * 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 CefSharp.WinForms -Version 64.0.0-CI2508 -Source https://www.myget.org/F/cefsharp/api/v3/index.json
PM> Install-Package Microsoft.VC120.CRT.JetBrains
``` ```
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. 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("<style type='text/css'>");
tags.push("body { background: "+getClassStyleProperty("column", "background-color")+" !important }"); // set background color 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("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(".media-item, .media-preview { border-radius: 1px !important }"); // square-ify media
tags.push(".quoted-tweet { border-radius: 0 !important }"); // square-ify quoted tweets tags.push(".quoted-tweet { border-radius: 0 !important }"); // square-ify quoted tweets

View File

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

View File

@@ -1,7 +1,7 @@
<?xml version="1.0" encoding="utf-8"?> <?xml version="1.0" encoding="utf-8"?>
<Project ToolsVersion="12.0" DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003"> <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.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-CI2497\build\CefSharp.Common.props" Condition="Exists('packages\CefSharp.Common.64.0.0-CI2497\build\CefSharp.Common.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.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="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')" /> <Import Project="$(MSBuildExtensionsPath)\$(MSBuildToolsVersion)\Microsoft.Common.props" Condition="Exists('$(MSBuildExtensionsPath)\$(MSBuildToolsVersion)\Microsoft.Common.props')" />
@@ -398,8 +398,6 @@
del "$(TargetDir)LICENSE.txt" del "$(TargetDir)LICENSE.txt"
ren "$(TargetDir)LICENSE.md" "LICENSE.txt" ren "$(TargetDir)LICENSE.md" "LICENSE.txt"
xcopy "$(ProjectDir)bld\Resources\CEFSHARP-LICENSE.txt" "$(TargetDir)" /Y 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 rmdir "$(TargetDir)scripts" /S /Q
mkdir "$(TargetDir)scripts" mkdir "$(TargetDir)scripts"
@@ -444,11 +442,11 @@ powershell -ExecutionPolicy Unrestricted -File "$(ProjectDir)Resources\PostBuild
</PropertyGroup> </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.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\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-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-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.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-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-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-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.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> </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.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-CI2497\build\CefSharp.WinForms.targets" Condition="Exists('packages\CefSharp.WinForms.64.0.0-CI2497\build\CefSharp.WinForms.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> </Project>

View File

@@ -7,6 +7,7 @@
#define MyAppExeName "TweetDuck.exe" #define MyAppExeName "TweetDuck.exe"
#define MyAppVersion GetFileVersion("..\bin\x86\Release\TweetDuck.exe") #define MyAppVersion GetFileVersion("..\bin\x86\Release\TweetDuck.exe")
#define VCRedistLink "releases/download/1.13/vc_redist.x86.exe"
[Setup] [Setup]
AppId={{8C25A716-7E11-4AAD-9992-8B5D0C78AE06} AppId={{8C25A716-7E11-4AAD-9992-8B5D0C78AE06}
@@ -30,6 +31,8 @@ SolidCompression=yes
InternalCompressLevel=max InternalCompressLevel=max
MinVersion=0,6.1 MinVersion=0,6.1
#include <idp.iss>
[Languages] [Languages]
Name: "english"; MessagesFile: "compiler:Default.isl" Name: "english"; MessagesFile: "compiler:Default.isl"
@@ -56,36 +59,44 @@ Type: filesandordirs; Name: "{localappdata}\{#MyAppName}\GPUCache"
[Code] [Code]
var UpdatePath: String; var UpdatePath: String;
var ForceRedistPrompt: String;
function TDGetNetFrameworkVersion: Cardinal; forward; 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. } { Check .NET Framework version on startup, ask user if they want to proceed if older than 4.5.2. }
function InitializeSetup: Boolean; function InitializeSetup: Boolean;
begin begin
UpdatePath := ExpandConstant('{param:UPDATEPATH}') UpdatePath := ExpandConstant('{param:UPDATEPATH}')
ForceRedistPrompt := ExpandConstant('{param:PROMPTREDIST}')
if TDGetNetFrameworkVersion() >= 379893 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 := 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
begin begin
Result := False; Result := False;
Exit; Exit;
end; 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; Result := True;
end; 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(); procedure InitializeWizard();
begin begin
if (UpdatePath <> '') then if (UpdatePath <> '') then
begin begin
WizardForm.DirEdit.Text := UpdatePath; WizardForm.DirEdit.Text := UpdatePath;
end; end;
if idpFilesCount <> 0 then
begin
idpDownloadAfter(wpReady);
end;
end; end;
{ Skip the install path selection page if running from an update installer. } { Skip the install path selection page if running from an update installer. }
@@ -94,7 +105,7 @@ begin
Result := (PageID = wpSelectDir) and (UpdatePath <> '') Result := (PageID = wpSelectDir) and (UpdatePath <> '')
end; 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); procedure CurStepChanged(CurStep: TSetupStep);
begin begin
if CurStep = ssInstall then if CurStep = ssInstall then
@@ -103,6 +114,8 @@ begin
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) MsgBox('Detected a profile from an old TweetDeck installation, you may uninstall the old client to free up some space.', mbInformation, MB_OK)
end; end;
TDInstallVCRedist();
end; end;
end; end;
@@ -145,3 +158,65 @@ begin
Result := 0; Result := 0;
end; 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 MyAppExeName "TweetDuck.exe"
#define MyAppVersion GetFileVersion("..\bin\x86\Release\TweetDuck.exe") #define MyAppVersion GetFileVersion("..\bin\x86\Release\TweetDuck.exe")
#define VCRedistLink "releases/download/1.13/vc_redist.x86.exe"
[Setup] [Setup]
AppId={{8C25A716-7E11-4AAD-9992-8B5D0C78AE06} AppId={{8C25A716-7E11-4AAD-9992-8B5D0C78AE06}
@@ -30,6 +31,8 @@ SolidCompression=yes
InternalCompressLevel=max InternalCompressLevel=max
MinVersion=0,6.1 MinVersion=0,6.1
#include <idp.iss>
[Languages] [Languages]
Name: "english"; MessagesFile: "compiler:Default.isl" Name: "english"; MessagesFile: "compiler:Default.isl"
@@ -42,36 +45,44 @@ Filename: "{app}\{#MyAppExeName}"; Description: "{cm:LaunchProgram,{#StringChang
[Code] [Code]
var UpdatePath: String; var UpdatePath: String;
var ForceRedistPrompt: String;
function TDGetNetFrameworkVersion: Cardinal; forward; 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. } { Check .NET Framework version on startup, ask user if they want to proceed if older than 4.5.2. }
function InitializeSetup: Boolean; function InitializeSetup: Boolean;
begin begin
UpdatePath := ExpandConstant('{param:UPDATEPATH}') UpdatePath := ExpandConstant('{param:UPDATEPATH}')
ForceRedistPrompt := ExpandConstant('{param:PROMPTREDIST}')
if TDGetNetFrameworkVersion() >= 379893 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 := 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
begin begin
Result := False; Result := False;
Exit; Exit;
end; 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; Result := True;
end; 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(); procedure InitializeWizard();
begin begin
if (UpdatePath <> '') then if (UpdatePath <> '') then
begin begin
WizardForm.DirEdit.Text := UpdatePath; WizardForm.DirEdit.Text := UpdatePath;
end; end;
if idpFilesCount <> 0 then
begin
idpDownloadAfter(wpReady);
end;
end; end;
{ Skip the install path selection page if running from an update installer. } { Skip the install path selection page if running from an update installer. }
@@ -80,6 +91,24 @@ begin
Result := (PageID = wpSelectDir) and (UpdatePath <> '') Result := (PageID = wpSelectDir) and (UpdatePath <> '')
end; 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. } { Return DWORD value containing the build version of .NET Framework. }
function TDGetNetFrameworkVersion: Cardinal; function TDGetNetFrameworkVersion: Cardinal;
var FrameworkVersion: Cardinal; var FrameworkVersion: Cardinal;
@@ -94,17 +123,64 @@ begin
Result := 0; Result := 0;
end; end;
{ Create a 'makeportable' file if running in portable mode. } { Check if Visual C++ 2015 or 2017 is installed. }
procedure CurStepChanged(CurStep: TSetupStep); function TDIsVCMissing: Boolean;
var Keys: TArrayOfString;
var Index: Integer;
var Key: String;
var DisplayName: String;
begin begin
if CurStep = ssPostInstall then if RegGetSubkeyNames(HKEY_LOCAL_MACHINE, 'Software\Classes\Installer\Dependencies', Keys) then
begin begin
while not SaveStringToFile(ExpandConstant('{app}\makeportable'), '', False) do for Index := 0 to GetArrayLength(Keys)-1 do
begin 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 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; 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; end;

View File

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

View File

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

View File

@@ -24,9 +24,9 @@
<StartupObject /> <StartupObject />
</PropertyGroup> </PropertyGroup>
<ItemGroup> <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> <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>
<Reference Include="System" /> <Reference Include="System" />
</ItemGroup> </ItemGroup>