mirror of
https://github.com/chylex/TweetDuck.git
synced 2025-09-14 19:32:10 +02:00
Compare commits
13 Commits
Author | SHA1 | Date | |
---|---|---|---|
b6b26142f8 | |||
4ee99376fd | |||
b0261342ff | |||
87fd2a521e | |||
334793c6f6 | |||
3e70d991bb | |||
feec96fc5c | |||
765984709e | |||
c7c9931f68 | |||
ae64573510 | |||
d675af5aa4 | |||
9480d17cfc | |||
5ac1df2283 |
1
.gitignore
vendored
1
.gitignore
vendored
@@ -21,6 +21,7 @@ x86/
|
|||||||
[Oo]bj/
|
[Oo]bj/
|
||||||
bld/*
|
bld/*
|
||||||
!bld/gen_full.iss
|
!bld/gen_full.iss
|
||||||
|
!bld/gen_port.iss
|
||||||
!bld/gen_upd.iss
|
!bld/gen_upd.iss
|
||||||
!bld/Resources
|
!bld/Resources
|
||||||
|
|
||||||
|
@@ -58,7 +58,7 @@ namespace TweetDck.Configuration{
|
|||||||
Process foundProcess = Process.GetProcessById(pid);
|
Process foundProcess = Process.GetProcessById(pid);
|
||||||
|
|
||||||
using(Process currentProcess = Process.GetCurrentProcess()){
|
using(Process currentProcess = Process.GetCurrentProcess()){
|
||||||
if (foundProcess.ProcessName == currentProcess.ProcessName){
|
if (foundProcess.ProcessName == currentProcess.ProcessName || foundProcess.MainWindowTitle == Program.BrandName){
|
||||||
LockingProcess = foundProcess;
|
LockingProcess = foundProcess;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@@ -1,6 +1,7 @@
|
|||||||
using System;
|
using System;
|
||||||
using System.Drawing;
|
using System.Drawing;
|
||||||
using System.Windows.Forms;
|
using System.Windows.Forms;
|
||||||
|
using TweetDck.Core.Utils;
|
||||||
|
|
||||||
namespace TweetDck.Core.Controls{
|
namespace TweetDck.Core.Controls{
|
||||||
static class ControlExtensions{
|
static class ControlExtensions{
|
||||||
@@ -35,6 +36,12 @@ namespace TweetDck.Core.Controls{
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public static void SetElevated(this Button button){
|
||||||
|
button.Text = " "+button.Text;
|
||||||
|
button.FlatStyle = FlatStyle.System;
|
||||||
|
NativeMethods.SendMessage(button.Handle, NativeMethods.BCM_SETSHIELD, 0, new IntPtr(1));
|
||||||
|
}
|
||||||
|
|
||||||
public static void EnableMultilineShortcuts(this TextBox textBox){
|
public static void EnableMultilineShortcuts(this TextBox textBox){
|
||||||
textBox.KeyDown += (sender, args) => {
|
textBox.KeyDown += (sender, args) => {
|
||||||
if (args.Control && args.KeyCode == Keys.A){
|
if (args.Control && args.KeyCode == Keys.A){
|
||||||
|
@@ -62,6 +62,7 @@ namespace TweetDck.Core{
|
|||||||
public bool FreezeTimer { get; set; }
|
public bool FreezeTimer { get; set; }
|
||||||
public bool ContextMenuOpen { get; set; }
|
public bool ContextMenuOpen { get; set; }
|
||||||
public string CurrentUrl { get; private set; }
|
public string CurrentUrl { get; private set; }
|
||||||
|
public string CurrentQuotedTweetUrl { get; set; }
|
||||||
|
|
||||||
public EventHandler Initialized;
|
public EventHandler Initialized;
|
||||||
private bool isInitialized;
|
private bool isInitialized;
|
||||||
@@ -277,6 +278,7 @@ namespace TweetDck.Core{
|
|||||||
|
|
||||||
private void LoadTweet(TweetNotification tweet){
|
private void LoadTweet(TweetNotification tweet){
|
||||||
CurrentUrl = tweet.Url;
|
CurrentUrl = tweet.Url;
|
||||||
|
CurrentQuotedTweetUrl = string.Empty; // load from JS
|
||||||
|
|
||||||
timerProgress.Stop();
|
timerProgress.Stop();
|
||||||
totalTime = timeLeft = tweet.GetDisplayDuration(Program.UserConfig.NotificationDurationValue);
|
totalTime = timeLeft = tweet.GetDisplayDuration(Program.UserConfig.NotificationDurationValue);
|
||||||
|
@@ -7,7 +7,7 @@ namespace TweetDck.Core.Handling{
|
|||||||
private const int MenuSkipTweet = 26600;
|
private const int MenuSkipTweet = 26600;
|
||||||
private const int MenuFreeze = 26601;
|
private const int MenuFreeze = 26601;
|
||||||
private const int MenuCopyTweetUrl = 26602;
|
private const int MenuCopyTweetUrl = 26602;
|
||||||
private const int MenuCopyTweetEmbeddedUrl = 26603;
|
private const int MenuCopyQuotedTweetUrl = 26603;
|
||||||
|
|
||||||
private readonly FormNotification form;
|
private readonly FormNotification form;
|
||||||
private readonly bool enableCustomMenu;
|
private readonly bool enableCustomMenu;
|
||||||
@@ -29,8 +29,8 @@ namespace TweetDck.Core.Handling{
|
|||||||
if (!string.IsNullOrEmpty(form.CurrentUrl)){
|
if (!string.IsNullOrEmpty(form.CurrentUrl)){
|
||||||
model.AddItem((CefMenuCommand)MenuCopyTweetUrl, "Copy tweet address");
|
model.AddItem((CefMenuCommand)MenuCopyTweetUrl, "Copy tweet address");
|
||||||
|
|
||||||
if (!string.IsNullOrEmpty(TweetDeckBridge.NotificationTweetEmbedded)){
|
if (!string.IsNullOrEmpty(form.CurrentQuotedTweetUrl)){
|
||||||
model.AddItem((CefMenuCommand)MenuCopyTweetEmbeddedUrl, "Copy quoted tweet address");
|
model.AddItem((CefMenuCommand)MenuCopyQuotedTweetUrl, "Copy quoted tweet address");
|
||||||
}
|
}
|
||||||
|
|
||||||
model.AddSeparator();
|
model.AddSeparator();
|
||||||
@@ -61,8 +61,8 @@ namespace TweetDck.Core.Handling{
|
|||||||
Clipboard.SetText(form.CurrentUrl, TextDataFormat.UnicodeText);
|
Clipboard.SetText(form.CurrentUrl, TextDataFormat.UnicodeText);
|
||||||
return true;
|
return true;
|
||||||
|
|
||||||
case MenuCopyTweetEmbeddedUrl:
|
case MenuCopyQuotedTweetUrl:
|
||||||
Clipboard.SetText(TweetDeckBridge.NotificationTweetEmbedded, TextDataFormat.UnicodeText);
|
Clipboard.SetText(form.CurrentQuotedTweetUrl, TextDataFormat.UnicodeText);
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@@ -11,7 +11,6 @@ namespace TweetDck.Core.Handling{
|
|||||||
public static string LastRightClickedLink = string.Empty;
|
public static string LastRightClickedLink = string.Empty;
|
||||||
public static string LastHighlightedTweet = string.Empty;
|
public static string LastHighlightedTweet = string.Empty;
|
||||||
public static string LastHighlightedQuotedTweet = string.Empty;
|
public static string LastHighlightedQuotedTweet = string.Empty;
|
||||||
public static string NotificationTweetEmbedded = string.Empty;
|
|
||||||
public static string ClipboardImagePath = string.Empty;
|
public static string ClipboardImagePath = string.Empty;
|
||||||
|
|
||||||
private readonly FormBrowser form;
|
private readonly FormBrowser form;
|
||||||
@@ -81,8 +80,8 @@ namespace TweetDck.Core.Handling{
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
public void SetNotificationTweetEmbedded(string link){
|
public void SetNotificationQuotedTweet(string link){
|
||||||
form.InvokeSafe(() => NotificationTweetEmbedded = link);
|
notification.InvokeSafe(() => notification.CurrentQuotedTweetUrl = link);
|
||||||
}
|
}
|
||||||
|
|
||||||
public void OpenSettingsMenu(){
|
public void OpenSettingsMenu(){
|
||||||
|
@@ -15,6 +15,7 @@ namespace TweetDck.Core.Utils{
|
|||||||
public const int MOUSEEVENTF_RIGHTUP = 0x10;
|
public const int MOUSEEVENTF_RIGHTUP = 0x10;
|
||||||
|
|
||||||
public const int SB_HORZ = 0;
|
public const int SB_HORZ = 0;
|
||||||
|
public const int BCM_SETSHIELD = 0x160C;
|
||||||
|
|
||||||
public const int WH_MOUSE_LL = 14;
|
public const int WH_MOUSE_LL = 14;
|
||||||
public const int WH_MOUSEWHEEL = 0x020A;
|
public const int WH_MOUSEWHEEL = 0x020A;
|
||||||
|
@@ -8,6 +8,7 @@ using System.Windows.Forms;
|
|||||||
using Microsoft.Win32;
|
using Microsoft.Win32;
|
||||||
using TweetDck.Core.Other;
|
using TweetDck.Core.Other;
|
||||||
using System.Drawing;
|
using System.Drawing;
|
||||||
|
using TweetDck.Core.Controls;
|
||||||
|
|
||||||
namespace TweetDck.Migration{
|
namespace TweetDck.Migration{
|
||||||
static class MigrationManager{
|
static class MigrationManager{
|
||||||
@@ -41,8 +42,9 @@ namespace TweetDck.Migration{
|
|||||||
Button btnMigrate = formQuestion.AddButton("Migrate");
|
Button btnMigrate = formQuestion.AddButton("Migrate");
|
||||||
Button btnMigrateAndPurge = formQuestion.AddButton("Migrate && Purge");
|
Button btnMigrateAndPurge = formQuestion.AddButton("Migrate && Purge");
|
||||||
|
|
||||||
btnMigrateAndPurge.Location = new Point(btnMigrateAndPurge.Location.X-18, btnMigrateAndPurge.Location.Y);
|
btnMigrateAndPurge.Location = new Point(btnMigrateAndPurge.Location.X-20, btnMigrateAndPurge.Location.Y);
|
||||||
btnMigrateAndPurge.Width += 18;
|
btnMigrateAndPurge.Width += 20;
|
||||||
|
btnMigrateAndPurge.SetElevated();
|
||||||
|
|
||||||
if (formQuestion.ShowDialog() == DialogResult.OK){
|
if (formQuestion.ShowDialog() == DialogResult.OK){
|
||||||
decision = formQuestion.ClickedButton == btnMigrateAndPurge ? MigrationDecision.MigratePurge :
|
decision = formQuestion.ClickedButton == btnMigrateAndPurge ? MigrationDecision.MigratePurge :
|
||||||
@@ -86,10 +88,20 @@ namespace TweetDck.Migration{
|
|||||||
else if (!Program.UserConfig.IgnoreUninstallCheck){
|
else if (!Program.UserConfig.IgnoreUninstallCheck){
|
||||||
string guid = MigrationUtils.FindProgramGuidByDisplayName("TweetDeck");
|
string guid = MigrationUtils.FindProgramGuidByDisplayName("TweetDeck");
|
||||||
|
|
||||||
if (guid != null && MessageBox.Show("TweetDeck is still installed on your computer, do you want to uninstall it?", "Uninstall TweetDeck", MessageBoxButtons.YesNo, MessageBoxIcon.Question, MessageBoxDefaultButton.Button2) == DialogResult.Yes){
|
if (guid != null){
|
||||||
MigrationUtils.RunUninstaller(guid, 0);
|
const string prompt = "TweetDeck is still installed on your computer, do you want to uninstall it?";
|
||||||
|
|
||||||
|
using(FormMessage formQuestion = new FormMessage("Uninstall TweetDeck", prompt, MessageBoxIcon.Question)){
|
||||||
|
formQuestion.AddButton("No");
|
||||||
|
|
||||||
|
Button btnYes = formQuestion.AddButton("Yes");
|
||||||
|
btnYes.SetElevated();
|
||||||
|
|
||||||
|
if (formQuestion.ShowDialog() == DialogResult.OK && formQuestion.ClickedButton == btnYes && MigrationUtils.RunUninstaller(guid, 0)){
|
||||||
CleanupTweetDeck();
|
CleanupTweetDeck();
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
Program.UserConfig.IgnoreUninstallCheck = true;
|
Program.UserConfig.IgnoreUninstallCheck = true;
|
||||||
Program.UserConfig.Save();
|
Program.UserConfig.Save();
|
||||||
@@ -155,8 +167,8 @@ namespace TweetDck.Migration{
|
|||||||
// uninstall in the background
|
// uninstall in the background
|
||||||
string guid = MigrationUtils.FindProgramGuidByDisplayName("TweetDeck");
|
string guid = MigrationUtils.FindProgramGuidByDisplayName("TweetDeck");
|
||||||
|
|
||||||
if (guid != null){
|
if (guid != null && !MigrationUtils.RunUninstaller(guid, 5000)){
|
||||||
MigrationUtils.RunUninstaller(guid, 5000);
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
// registry cleanup
|
// registry cleanup
|
||||||
|
@@ -5,8 +5,13 @@ using Microsoft.Win32;
|
|||||||
|
|
||||||
namespace TweetDck.Migration{
|
namespace TweetDck.Migration{
|
||||||
static class MigrationUtils{
|
static class MigrationUtils{
|
||||||
public static void RunUninstaller(string guid, int timeout){
|
public static bool RunUninstaller(string guid, int timeout){
|
||||||
Process uninstaller = Process.Start("msiexec.exe", "/x "+guid+" /quiet /qn");
|
try{
|
||||||
|
Process uninstaller = Process.Start(new ProcessStartInfo{
|
||||||
|
FileName = "msiexec.exe",
|
||||||
|
Arguments = "/x "+guid+" /quiet /qn",
|
||||||
|
Verb = "runas"
|
||||||
|
});
|
||||||
|
|
||||||
if (uninstaller != null){
|
if (uninstaller != null){
|
||||||
if (timeout > 0){
|
if (timeout > 0){
|
||||||
@@ -15,6 +20,11 @@ namespace TweetDck.Migration{
|
|||||||
|
|
||||||
uninstaller.Close();
|
uninstaller.Close();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}catch(Exception){
|
||||||
|
return false;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public static string FindProgramGuidByDisplayName(string displayName){
|
public static string FindProgramGuidByDisplayName(string displayName){
|
||||||
|
@@ -23,8 +23,8 @@ namespace TweetDck{
|
|||||||
|
|
||||||
public const string BrowserSubprocess = BrandName+".Browser.exe";
|
public const string BrowserSubprocess = BrandName+".Browser.exe";
|
||||||
|
|
||||||
public const string VersionTag = "1.4.2";
|
public const string VersionTag = "1.4.3";
|
||||||
public const string VersionFull = "1.4.2.0";
|
public const string VersionFull = "1.4.3.0";
|
||||||
|
|
||||||
public static readonly Version Version = new Version(VersionTag);
|
public static readonly Version Version = new Version(VersionTag);
|
||||||
|
|
||||||
@@ -120,6 +120,7 @@ namespace TweetDck{
|
|||||||
Locale = Args.GetValue("-locale", "en"),
|
Locale = Args.GetValue("-locale", "en"),
|
||||||
CachePath = StoragePath,
|
CachePath = StoragePath,
|
||||||
BrowserSubprocessPath = File.Exists(BrowserSubprocess) ? BrowserSubprocess : "CefSharp.BrowserSubprocess.exe",
|
BrowserSubprocessPath = File.Exists(BrowserSubprocess) ? BrowserSubprocess : "CefSharp.BrowserSubprocess.exe",
|
||||||
|
LogFile = Path.Combine(StoragePath, "TD_Console.txt"),
|
||||||
#if !DEBUG
|
#if !DEBUG
|
||||||
LogSeverity = Args.HasFlag("-log") ? LogSeverity.Info : LogSeverity.Disable
|
LogSeverity = Args.HasFlag("-log") ? LogSeverity.Info : LogSeverity.Disable
|
||||||
#endif
|
#endif
|
||||||
@@ -147,7 +148,7 @@ namespace TweetDck{
|
|||||||
if (mainForm.UpdateInstallerPath != null){
|
if (mainForm.UpdateInstallerPath != null){
|
||||||
ExitCleanup();
|
ExitCleanup();
|
||||||
|
|
||||||
Process.Start(mainForm.UpdateInstallerPath, "/SP- /SILENT /NOICONS /CLOSEAPPLICATIONS");
|
Process.Start(mainForm.UpdateInstallerPath, "/SP- /SILENT /CLOSEAPPLICATIONS /UPDATEPATH=\""+ProgramPath+"\""+(IsPortable ? " /PORTABLE=1" : "")); // ProgramPath has a trailing backslash
|
||||||
Application.Exit();
|
Application.Exit();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@@ -114,7 +114,7 @@
|
|||||||
var account = embedded[0].getElementsByClassName("account-link");
|
var account = embedded[0].getElementsByClassName("account-link");
|
||||||
if (account.length === 0)return;
|
if (account.length === 0)return;
|
||||||
|
|
||||||
$TD.setNotificationTweetEmbedded(account[0].getAttribute("href")+"/status/"+tweetId);
|
$TD.setNotificationQuotedTweet(account[0].getAttribute("href")+"/status/"+tweetId);
|
||||||
})();
|
})();
|
||||||
|
|
||||||
//
|
//
|
||||||
|
@@ -23,6 +23,7 @@ OutputBaseFilename={#MyAppName}
|
|||||||
VersionInfoVersion={#MyAppVersion}
|
VersionInfoVersion={#MyAppVersion}
|
||||||
LicenseFile=.\Resources\LICENSE
|
LicenseFile=.\Resources\LICENSE
|
||||||
SetupIconFile=.\Resources\icon.ico
|
SetupIconFile=.\Resources\icon.ico
|
||||||
|
Uninstallable=TDIsUninstallable
|
||||||
UninstallDisplayName={#MyAppName}
|
UninstallDisplayName={#MyAppName}
|
||||||
UninstallDisplayIcon={app}\{#MyAppExeName}
|
UninstallDisplayIcon={app}\{#MyAppExeName}
|
||||||
Compression=lzma
|
Compression=lzma
|
||||||
@@ -41,11 +42,11 @@ Source: "..\bin\x86\Release\{#MyAppExeName}"; DestDir: "{app}"; Flags: ignorever
|
|||||||
Source: "..\bin\x86\Release\*"; DestDir: "{app}"; Flags: ignoreversion recursesubdirs createallsubdirs; Excludes: "*.xml,devtools_resources.pak,d3dcompiler_43.dll"
|
Source: "..\bin\x86\Release\*"; DestDir: "{app}"; Flags: ignoreversion recursesubdirs createallsubdirs; Excludes: "*.xml,devtools_resources.pak,d3dcompiler_43.dll"
|
||||||
|
|
||||||
[Icons]
|
[Icons]
|
||||||
Name: "{group}\{#MyAppName}"; Filename: "{app}\{#MyAppExeName}"
|
Name: "{group}\{#MyAppName}"; Filename: "{app}\{#MyAppExeName}"; Check: TDIsUninstallable
|
||||||
Name: "{commondesktop}\{#MyAppName}"; Filename: "{app}\{#MyAppExeName}"; Tasks: desktopicon
|
Name: "{commondesktop}\{#MyAppName}"; Filename: "{app}\{#MyAppExeName}"; Tasks: desktopicon
|
||||||
|
|
||||||
[Run]
|
[Run]
|
||||||
Filename: "{app}\{#MyAppExeName}"; Description: "{cm:LaunchProgram,{#StringChange(MyAppName, '&', '&&')}}"; Flags: nowait postinstall skipifsilent
|
Filename: "{app}\{#MyAppExeName}"; Description: "{cm:LaunchProgram,{#StringChange(MyAppName, '&', '&&')}}"; Flags: nowait postinstall shellexec skipifsilent
|
||||||
|
|
||||||
[InstallDelete]
|
[InstallDelete]
|
||||||
Type: files; Name: "{app}\td-log.txt"
|
Type: files; Name: "{app}\td-log.txt"
|
||||||
@@ -56,11 +57,24 @@ Type: filesandordirs; Name: "{localappdata}\{#MyAppName}\Cache"
|
|||||||
Type: filesandordirs; Name: "{localappdata}\{#MyAppName}\GPUCache"
|
Type: filesandordirs; Name: "{localappdata}\{#MyAppName}\GPUCache"
|
||||||
|
|
||||||
[Code]
|
[Code]
|
||||||
|
var IsPortableInstallation: Boolean;
|
||||||
|
var UpdatePath: String;
|
||||||
|
|
||||||
function TDGetNetFrameworkVersion: Cardinal; forward;
|
function TDGetNetFrameworkVersion: Cardinal; 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
|
||||||
|
IsPortableInstallation := ExpandConstant('{param:PORTABLEINSTALL}') = '1'
|
||||||
|
UpdatePath := ExpandConstant('{param:UPDATEPATH}')
|
||||||
|
|
||||||
|
if IsPortableInstallation and (UpdatePath = '') then
|
||||||
|
begin
|
||||||
|
MsgBox('The /PORTABLEINSTALL flag requires the /UPDATEPATH parameter.', mbCriticalError, MB_OK);
|
||||||
|
Result := False;
|
||||||
|
Exit;
|
||||||
|
end;
|
||||||
|
|
||||||
if TDGetNetFrameworkVersion() >= 379893 then
|
if TDGetNetFrameworkVersion() >= 379893 then
|
||||||
begin
|
begin
|
||||||
Result := True;
|
Result := True;
|
||||||
@@ -76,6 +90,21 @@ begin
|
|||||||
Result := True;
|
Result := True;
|
||||||
end;
|
end;
|
||||||
|
|
||||||
|
{ Set the installation path if updating. }
|
||||||
|
procedure InitializeWizard();
|
||||||
|
begin
|
||||||
|
if (UpdatePath <> '') then
|
||||||
|
begin
|
||||||
|
WizardForm.DirEdit.Text := UpdatePath;
|
||||||
|
end;
|
||||||
|
end;
|
||||||
|
|
||||||
|
{ Skip the install path selection page if running from an update installer. }
|
||||||
|
function ShouldSkipPage(PageID: Integer): Boolean;
|
||||||
|
begin
|
||||||
|
Result := (PageID = wpSelectDir) and (UpdatePath <> '')
|
||||||
|
end;
|
||||||
|
|
||||||
{ Ask user if they want to delete 'AppData\TweetDuck' and 'plugins' folders after uninstallation. }
|
{ Ask user if they want to delete 'AppData\TweetDuck' and 'plugins' folders after uninstallation. }
|
||||||
procedure CurUninstallStepChanged(CurUninstallStep: TUninstallStep);
|
procedure CurUninstallStepChanged(CurUninstallStep: TUninstallStep);
|
||||||
var ProfileDataFolder: String;
|
var ProfileDataFolder: String;
|
||||||
@@ -96,6 +125,27 @@ begin
|
|||||||
end;
|
end;
|
||||||
end;
|
end;
|
||||||
|
|
||||||
|
{ Create a 'makeportable' file if running in portable mode. }
|
||||||
|
procedure CurStepChanged(CurStep: TSetupStep);
|
||||||
|
begin
|
||||||
|
if (CurStep = ssPostInstall) and IsPortableInstallation 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;
|
||||||
|
|
||||||
|
{ Returns true if the installer should create uninstallation entries (i.e. not running in portable or full update mode). }
|
||||||
|
function TDIsUninstallable: Boolean;
|
||||||
|
begin
|
||||||
|
Result := (UpdatePath = '') and not IsPortableInstallation
|
||||||
|
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;
|
||||||
|
150
bld/gen_port.iss
Normal file
150
bld/gen_port.iss
Normal file
@@ -0,0 +1,150 @@
|
|||||||
|
; Script generated by the Inno Script Studio Wizard.
|
||||||
|
; SEE THE DOCUMENTATION FOR DETAILS ON CREATING INNO SETUP SCRIPT FILES!
|
||||||
|
|
||||||
|
#define MyAppName "TweetDuck"
|
||||||
|
#define MyAppPublisher "chylex"
|
||||||
|
#define MyAppURL "https://tweetduck.chylex.com"
|
||||||
|
#define MyAppExeName "TweetDuck.exe"
|
||||||
|
|
||||||
|
#define MyAppVersion GetFileVersion("..\bin\x86\Release\TweetDuck.exe")
|
||||||
|
|
||||||
|
[Setup]
|
||||||
|
AppId={{8C25A716-7E11-4AAD-9992-8B5D0C78AE06}
|
||||||
|
AppName={#MyAppName}
|
||||||
|
AppVersion={#MyAppVersion}
|
||||||
|
AppVerName={#MyAppName} {#MyAppVersion}
|
||||||
|
AppPublisher={#MyAppPublisher}
|
||||||
|
AppPublisherURL={#MyAppURL}
|
||||||
|
AppSupportURL={#MyAppURL}
|
||||||
|
AppUpdatesURL={#MyAppURL}
|
||||||
|
DefaultDirName={pf}\{#MyAppName}
|
||||||
|
DefaultGroupName={#MyAppName}
|
||||||
|
OutputBaseFilename={#MyAppName}.Portable
|
||||||
|
VersionInfoVersion={#MyAppVersion}
|
||||||
|
LicenseFile=.\Resources\LICENSE
|
||||||
|
SetupIconFile=.\Resources\icon.ico
|
||||||
|
Uninstallable=no
|
||||||
|
UsePreviousAppDir=no
|
||||||
|
Compression=lzma
|
||||||
|
SolidCompression=yes
|
||||||
|
InternalCompressLevel=max
|
||||||
|
MinVersion=0,6.1
|
||||||
|
|
||||||
|
#include <idp.iss>
|
||||||
|
|
||||||
|
[Languages]
|
||||||
|
Name: "english"; MessagesFile: "compiler:Default.isl"
|
||||||
|
|
||||||
|
[Files]
|
||||||
|
Source: "..\bin\x86\Release\{#MyAppExeName}"; DestDir: "{app}"; Flags: ignoreversion
|
||||||
|
|
||||||
|
[Run]
|
||||||
|
Filename: "{app}\{#MyAppExeName}"; Description: "{cm:LaunchProgram,{#StringChange(MyAppName, '&', '&&')}}"; Flags: nowait postinstall shellexec
|
||||||
|
|
||||||
|
[Code]
|
||||||
|
function TDGetNetFrameworkVersion: Cardinal; forward;
|
||||||
|
function TDGetAppVersionClean: String; forward;
|
||||||
|
procedure TDExecuteFullDownload; forward;
|
||||||
|
|
||||||
|
{ Check .NET Framework version on startup, ask user if they want to proceed if older than 4.5.2, and prepare full download package. }
|
||||||
|
function InitializeSetup: Boolean;
|
||||||
|
begin
|
||||||
|
idpAddFile('https://github.com/{#MyAppPublisher}/{#MyAppName}/releases/download/'+TDGetAppVersionClean()+'/{#MyAppName}.exe', ExpandConstant('{tmp}\{#MyAppName}.Full.exe'));
|
||||||
|
|
||||||
|
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
|
||||||
|
begin
|
||||||
|
Result := False;
|
||||||
|
Exit;
|
||||||
|
end;
|
||||||
|
|
||||||
|
Result := True;
|
||||||
|
end;
|
||||||
|
|
||||||
|
{ Prepare download plugin if there are any files to download, and set the installation path. }
|
||||||
|
procedure InitializeWizard();
|
||||||
|
begin
|
||||||
|
idpDownloadAfter(wpReady);
|
||||||
|
end;
|
||||||
|
|
||||||
|
{ Remove uninstallation data and application to force them to be replaced with updated ones. }
|
||||||
|
procedure CurStepChanged(CurStep: TSetupStep);
|
||||||
|
begin
|
||||||
|
if CurStep = ssInstall then
|
||||||
|
begin
|
||||||
|
TDExecuteFullDownload();
|
||||||
|
end;
|
||||||
|
end;
|
||||||
|
|
||||||
|
{ Return DWORD value containing the build version of .NET Framework. }
|
||||||
|
function TDGetNetFrameworkVersion: Cardinal;
|
||||||
|
var FrameworkVersion: Cardinal;
|
||||||
|
|
||||||
|
begin
|
||||||
|
if RegQueryDWordValue(HKEY_LOCAL_MACHINE, 'Software\Microsoft\NET Framework Setup\NDP\v4\Full', 'Release', FrameworkVersion) then
|
||||||
|
begin
|
||||||
|
Result := FrameworkVersion;
|
||||||
|
Exit;
|
||||||
|
end;
|
||||||
|
|
||||||
|
Result := 0;
|
||||||
|
end;
|
||||||
|
|
||||||
|
{ Return a cleaned up form of the app version string (removes all .0 suffixes). }
|
||||||
|
function TDGetAppVersionClean: String;
|
||||||
|
var Substr: String;
|
||||||
|
var CleanVersion: String;
|
||||||
|
|
||||||
|
begin
|
||||||
|
CleanVersion := '{#MyAppVersion}'
|
||||||
|
|
||||||
|
while True do
|
||||||
|
begin
|
||||||
|
Substr := Copy(CleanVersion, Length(CleanVersion)-1, 2);
|
||||||
|
|
||||||
|
if (CompareStr(Substr, '.0') <> 0) then
|
||||||
|
begin
|
||||||
|
break;
|
||||||
|
end;
|
||||||
|
|
||||||
|
CleanVersion := Copy(CleanVersion, 1, Length(CleanVersion)-2);
|
||||||
|
end;
|
||||||
|
|
||||||
|
Result := CleanVersion;
|
||||||
|
end;
|
||||||
|
|
||||||
|
{ Run the full package installer if downloaded. }
|
||||||
|
procedure TDExecuteFullDownload;
|
||||||
|
var InstallFile: String;
|
||||||
|
var ResultCode: Integer;
|
||||||
|
|
||||||
|
begin
|
||||||
|
InstallFile := ExpandConstant('{tmp}\{#MyAppName}.Full.exe')
|
||||||
|
WizardForm.ProgressGauge.Style := npbstMarquee;
|
||||||
|
|
||||||
|
try
|
||||||
|
if Exec(InstallFile, '/SP- /SILENT /MERGETASKS="!desktopicon" /UPDATEPATH="'+ExpandConstant('{app}\')+'" /PORTABLEINSTALL=1', '', SW_SHOW, ewWaitUntilTerminated, ResultCode) then begin
|
||||||
|
if ResultCode <> 0 then
|
||||||
|
begin
|
||||||
|
DeleteFile(InstallFile);
|
||||||
|
Abort();
|
||||||
|
Exit;
|
||||||
|
end;
|
||||||
|
end else
|
||||||
|
begin
|
||||||
|
MsgBox('Could not run the full installer in portable mode. Error: '+SysErrorMessage(ResultCode), mbCriticalError, MB_OK);
|
||||||
|
|
||||||
|
DeleteFile(InstallFile);
|
||||||
|
Abort();
|
||||||
|
Exit;
|
||||||
|
end;
|
||||||
|
finally
|
||||||
|
WizardForm.ProgressGauge.Style := npbstNormal;
|
||||||
|
DeleteFile(InstallFile);
|
||||||
|
end;
|
||||||
|
end;
|
@@ -25,6 +25,7 @@ OutputBaseFilename={#MyAppName}.Update
|
|||||||
VersionInfoVersion={#MyAppVersion}
|
VersionInfoVersion={#MyAppVersion}
|
||||||
LicenseFile=.\Resources\LICENSE
|
LicenseFile=.\Resources\LICENSE
|
||||||
SetupIconFile=.\Resources\icon.ico
|
SetupIconFile=.\Resources\icon.ico
|
||||||
|
Uninstallable=TDIsUninstallable
|
||||||
UninstallDisplayName={#MyAppName}
|
UninstallDisplayName={#MyAppName}
|
||||||
UninstallDisplayIcon={app}\{#MyAppExeName}
|
UninstallDisplayIcon={app}\{#MyAppExeName}
|
||||||
Compression=lzma
|
Compression=lzma
|
||||||
@@ -45,7 +46,7 @@ Source: "..\bin\x86\Release\*"; DestDir: "{app}"; Flags: ignoreversion recursesu
|
|||||||
Name: "{group}\{#MyAppName}"; Filename: "{app}\{#MyAppExeName}"
|
Name: "{group}\{#MyAppName}"; Filename: "{app}\{#MyAppExeName}"
|
||||||
|
|
||||||
[Run]
|
[Run]
|
||||||
Filename: "{app}\{#MyAppExeName}"; Description: "{cm:LaunchProgram,{#StringChange(MyAppName, '&', '&&')}}"; Flags: nowait postinstall
|
Filename: "{app}\{#MyAppExeName}"; Description: "{cm:LaunchProgram,{#StringChange(MyAppName, '&', '&&')}}"; Flags: nowait postinstall shellexec
|
||||||
|
|
||||||
[InstallDelete]
|
[InstallDelete]
|
||||||
Type: files; Name: "{app}\*.xml"
|
Type: files; Name: "{app}\*.xml"
|
||||||
@@ -54,6 +55,8 @@ Type: files; Name: "{app}\d3dcompiler_43.dll"
|
|||||||
Type: files; Name: "{app}\devtools_resources.pak"
|
Type: files; Name: "{app}\devtools_resources.pak"
|
||||||
Type: files; Name: "{app}\CefSharp.BrowserSubprocess.exe"
|
Type: files; Name: "{app}\CefSharp.BrowserSubprocess.exe"
|
||||||
Type: files; Name: "{app}\td-log.txt"
|
Type: files; Name: "{app}\td-log.txt"
|
||||||
|
Type: files; Name: "{app}\debug.log"
|
||||||
|
Type: files; Name: "{localappdata}\{#MyAppName}\ChromeDWriteFontCache"
|
||||||
|
|
||||||
[UninstallDelete]
|
[UninstallDelete]
|
||||||
Type: files; Name: "{app}\*.*"
|
Type: files; Name: "{app}\*.*"
|
||||||
@@ -63,22 +66,34 @@ Type: filesandordirs; Name: "{localappdata}\{#MyAppName}\Cache"
|
|||||||
Type: filesandordirs; Name: "{localappdata}\{#MyAppName}\GPUCache"
|
Type: filesandordirs; Name: "{localappdata}\{#MyAppName}\GPUCache"
|
||||||
|
|
||||||
[Code]
|
[Code]
|
||||||
|
function TDIsUninstallable: Boolean; forward;
|
||||||
|
function TDFindUpdatePath: String; forward;
|
||||||
function TDGetNetFrameworkVersion: Cardinal; forward;
|
function TDGetNetFrameworkVersion: Cardinal; forward;
|
||||||
function TDGetAppVersionClean: String; forward;
|
function TDGetAppVersionClean: String; forward;
|
||||||
function TDIsMatchingCEFVersion(InstallPath: String): Boolean; forward;
|
function TDIsMatchingCEFVersion: Boolean; forward;
|
||||||
function TDPrepareFullDownloadIfNeeded: Boolean; forward;
|
|
||||||
procedure TDExecuteFullDownload; forward;
|
procedure TDExecuteFullDownload; forward;
|
||||||
|
|
||||||
|
var IsPortable: Boolean;
|
||||||
|
var UpdatePath: String;
|
||||||
|
|
||||||
{ Check .NET Framework version on startup, ask user if they want to proceed if older than 4.5.2. Prepare full download package if required. }
|
{ Check .NET Framework version on startup, ask user if they want to proceed if older than 4.5.2. Prepare full download package if required. }
|
||||||
function InitializeSetup: Boolean;
|
function InitializeSetup: Boolean;
|
||||||
begin
|
begin
|
||||||
if not TDPrepareFullDownloadIfNeeded() then
|
IsPortable := ExpandConstant('{param:PORTABLE}') = '1'
|
||||||
|
UpdatePath := TDFindUpdatePath()
|
||||||
|
|
||||||
|
if UpdatePath = '' then
|
||||||
begin
|
begin
|
||||||
MsgBox('{#MyAppName} installation could not be found on your system.', mbCriticalError, MB_OK);
|
MsgBox('{#MyAppName} installation could not be found on your system.', mbCriticalError, MB_OK);
|
||||||
Result := False;
|
Result := False;
|
||||||
Exit;
|
Exit;
|
||||||
end;
|
end;
|
||||||
|
|
||||||
|
if not TDIsMatchingCEFVersion() then
|
||||||
|
begin
|
||||||
|
idpAddFile('https://github.com/{#MyAppPublisher}/{#MyAppName}/releases/download/'+TDGetAppVersionClean()+'/{#MyAppName}.exe', ExpandConstant('{tmp}\{#MyAppName}.Full.exe'));
|
||||||
|
end;
|
||||||
|
|
||||||
if TDGetNetFrameworkVersion() >= 379893 then
|
if TDGetNetFrameworkVersion() >= 379893 then
|
||||||
begin
|
begin
|
||||||
Result := True;
|
Result := True;
|
||||||
@@ -94,9 +109,11 @@ begin
|
|||||||
Result := True;
|
Result := True;
|
||||||
end;
|
end;
|
||||||
|
|
||||||
{ Prepare download plugin if there are any files to download. }
|
{ Prepare download plugin if there are any files to download, and set the installation path. }
|
||||||
procedure InitializeWizard();
|
procedure InitializeWizard();
|
||||||
begin
|
begin
|
||||||
|
WizardForm.DirEdit.Text := UpdatePath;
|
||||||
|
|
||||||
if idpFilesCount <> 0 then
|
if idpFilesCount <> 0 then
|
||||||
begin
|
begin
|
||||||
idpDownloadAfter(wpReady);
|
idpDownloadAfter(wpReady);
|
||||||
@@ -127,13 +144,44 @@ end;
|
|||||||
procedure CurStepChanged(CurStep: TSetupStep);
|
procedure CurStepChanged(CurStep: TSetupStep);
|
||||||
begin
|
begin
|
||||||
if CurStep = ssInstall then
|
if CurStep = ssInstall then
|
||||||
|
begin
|
||||||
|
TDExecuteFullDownload();
|
||||||
|
|
||||||
|
if TDIsUninstallable() then
|
||||||
begin
|
begin
|
||||||
DeleteFile(ExpandConstant('{app}\unins000.dat'));
|
DeleteFile(ExpandConstant('{app}\unins000.dat'));
|
||||||
DeleteFile(ExpandConstant('{app}\unins000.exe'));
|
DeleteFile(ExpandConstant('{app}\unins000.exe'));
|
||||||
|
|
||||||
TDExecuteFullDownload();
|
|
||||||
end;
|
end;
|
||||||
end;
|
end;
|
||||||
|
end;
|
||||||
|
|
||||||
|
{ Returns true if the installer should create uninstallation entries (i.e. not running in portable mode). }
|
||||||
|
function TDIsUninstallable: Boolean;
|
||||||
|
begin
|
||||||
|
Result := not IsPortable
|
||||||
|
end;
|
||||||
|
|
||||||
|
{ Returns a validated installation path (including trailing backslash) using the /UPDATEPATH parameter or installation info in registry. Returns empty string on failure. }
|
||||||
|
function TDFindUpdatePath: String;
|
||||||
|
var Path: String;
|
||||||
|
|
||||||
|
begin
|
||||||
|
Path := ExpandConstant('{param:UPDATEPATH}')
|
||||||
|
|
||||||
|
if (Path = '') and not IsPortable and not RegQueryStringValue(HKEY_LOCAL_MACHINE, 'Software\Microsoft\Windows\CurrentVersion\Uninstall\{{#MyAppID}}_is1', 'InstallLocation', Path) then
|
||||||
|
begin
|
||||||
|
Result := ''
|
||||||
|
Exit
|
||||||
|
end;
|
||||||
|
|
||||||
|
if not FileExists(Path+'{#MyAppExeName}') then
|
||||||
|
begin
|
||||||
|
Result := ''
|
||||||
|
Exit
|
||||||
|
end;
|
||||||
|
|
||||||
|
Result := Path
|
||||||
|
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;
|
||||||
@@ -150,11 +198,11 @@ begin
|
|||||||
end;
|
end;
|
||||||
|
|
||||||
{ Return whether the version of the installed libcef.dll library matches internal one. }
|
{ Return whether the version of the installed libcef.dll library matches internal one. }
|
||||||
function TDIsMatchingCEFVersion(InstallPath: String): Boolean;
|
function TDIsMatchingCEFVersion: Boolean;
|
||||||
var CEFVersion: String;
|
var CEFVersion: String;
|
||||||
|
|
||||||
begin
|
begin
|
||||||
Result := (GetVersionNumbersString(InstallPath+'\libcef.dll', CEFVersion) and (CompareStr(CEFVersion, '{#CefVersion}') = 0))
|
Result := (GetVersionNumbersString(UpdatePath+'libcef.dll', CEFVersion) and (CompareStr(CEFVersion, '{#CefVersion}') = 0))
|
||||||
end;
|
end;
|
||||||
|
|
||||||
{ Return a cleaned up form of the app version string (removes all .0 suffixes). }
|
{ Return a cleaned up form of the app version string (removes all .0 suffixes). }
|
||||||
@@ -180,25 +228,6 @@ begin
|
|||||||
Result := CleanVersion;
|
Result := CleanVersion;
|
||||||
end;
|
end;
|
||||||
|
|
||||||
{ Prepare the full package installer to run if the CEF version is not matching. Return False if the app is not installed. }
|
|
||||||
function TDPrepareFullDownloadIfNeeded: Boolean;
|
|
||||||
var InstallPath: String;
|
|
||||||
|
|
||||||
begin
|
|
||||||
if not RegQueryStringValue(HKEY_LOCAL_MACHINE, 'Software\Microsoft\Windows\CurrentVersion\Uninstall\{{#MyAppID}}_is1', 'InstallLocation', InstallPath) then
|
|
||||||
begin
|
|
||||||
Result := False;
|
|
||||||
Exit;
|
|
||||||
end;
|
|
||||||
|
|
||||||
if not TDIsMatchingCEFVersion(InstallPath) then
|
|
||||||
begin
|
|
||||||
idpAddFile('https://github.com/{#MyAppPublisher}/{#MyAppName}/releases/download/'+TDGetAppVersionClean()+'/{#MyAppName}.exe', ExpandConstant('{tmp}\{#MyAppName}.Full.exe'));
|
|
||||||
end;
|
|
||||||
|
|
||||||
Result := True;
|
|
||||||
end;
|
|
||||||
|
|
||||||
{ Run the full package installer if downloaded. }
|
{ Run the full package installer if downloaded. }
|
||||||
procedure TDExecuteFullDownload;
|
procedure TDExecuteFullDownload;
|
||||||
var InstallFile: String;
|
var InstallFile: String;
|
||||||
@@ -212,10 +241,18 @@ begin
|
|||||||
WizardForm.ProgressGauge.Style := npbstMarquee;
|
WizardForm.ProgressGauge.Style := npbstMarquee;
|
||||||
|
|
||||||
try
|
try
|
||||||
if not Exec(InstallFile, '/SP- /SILENT /MERGETASKS="!desktopicon"', '', SW_SHOW, ewWaitUntilTerminated, ResultCode) then begin
|
if Exec(InstallFile, '/SP- /SILENT /MERGETASKS="!desktopicon" /UPDATEPATH="'+UpdatePath+'"', '', SW_SHOW, ewWaitUntilTerminated, ResultCode) then begin
|
||||||
MsgBox('Could not run the full installer, please visit {#MyAppURL} and download the latest version manually. Error: '+SysErrorMessage(ResultCode), mbCriticalError, MB_OK);
|
if ResultCode <> 0 then
|
||||||
|
begin
|
||||||
DeleteFile(InstallFile);
|
DeleteFile(InstallFile);
|
||||||
|
Abort();
|
||||||
|
Exit;
|
||||||
|
end;
|
||||||
|
end else
|
||||||
|
begin
|
||||||
|
MsgBox('Could not run the full installer, please visit {#MyAppURL} and download the latest version manually. Error: '+SysErrorMessage(ResultCode), mbCriticalError, MB_OK);
|
||||||
|
|
||||||
|
DeleteFile(InstallFile);
|
||||||
Abort();
|
Abort();
|
||||||
Exit;
|
Exit;
|
||||||
end;
|
end;
|
||||||
|
Reference in New Issue
Block a user