diff --git a/Greenshot/Forms/CaptureForm.cs b/Greenshot/Forms/CaptureForm.cs
index 1f4c962a9..550a30a13 100644
--- a/Greenshot/Forms/CaptureForm.cs
+++ b/Greenshot/Forms/CaptureForm.cs
@@ -57,7 +57,6 @@ namespace Greenshot.Forms {
private Rectangle captureRect = Rectangle.Empty;
private ICapture capture = null;
private AppConfig conf = AppConfig.GetInstance();
- private CopyData copyData = null;
private ILanguage lang = Language.GetInstance();
public CaptureForm() {
@@ -65,56 +64,11 @@ namespace Greenshot.Forms {
// The InitializeComponent() call is required for Windows Forms designer support.
//
InitializeComponent();
- // Create a new instance of the class: copyData = new CopyData();
- copyData = new CopyData();
- // Assign the handle:
- copyData.AssignHandle(this.Handle);
- // Create the channel to send on:
- copyData.Channels.Add("Greenshot");
- // Hook up received event:
- copyData.DataReceived += new DataReceivedEventHandler(CopyDataDataReceived);
-
// Make sure the form is hidden (might be overdoing it...)
this.Hide();
}
- ///
- /// DataReceivedEventHandler
- ///
- ///
- ///
- private void CopyDataDataReceived(object sender, DataReceivedEventArgs dataReceivedEventArgs) {
- // Cast the data to the type of object we sent:
- DataTransport dataTransport = (DataTransport)dataReceivedEventArgs.Data;
- HandleDataTransport(dataTransport);
- }
-
- public void HandleDataTransport(DataTransport dataTransport) {
- LOG.Debug("Data received, Command = " + dataTransport.Command + ", Data: " + dataTransport.CommandData);
- switch(dataTransport.Command) {
- case CommandEnum.Exit:
- MainForm.instance.exit();
- break;
- case CommandEnum.ReloadConfig:
- AppConfig.Reload();
- // Even update language when needed
- MainForm.instance.UpdateUI();
- break;
- case CommandEnum.OpenFile:
- string filename = dataTransport.CommandData;
- if (File.Exists(filename)) {
- MakeCapture(filename);
- } else {
- LOG.Warn("No such file: " + filename);
- }
- break;
- default:
- LOG.Error("Unknown command!");
- break;
- }
- }
-
void DoCaptureFeedback() {
if((bool)conf.Ui_Effects_CameraSound) {
SoundHelper.Play();
diff --git a/Greenshot/Forms/MainForm.cs b/Greenshot/Forms/MainForm.cs
index eb6e20543..f78df2d37 100644
--- a/Greenshot/Forms/MainForm.cs
+++ b/Greenshot/Forms/MainForm.cs
@@ -49,11 +49,13 @@ namespace Greenshot {
private static log4net.ILog LOG = null;
private static AppConfig conf;
- static Mutex applicationMutex = null;
+ private static Mutex applicationMutex = null;
[STAThread]
public static void Main(string[] args) {
- DataTransport dataTransport = null;
+ bool isAlreadyRunning = false;
+ List filesToOpen = new List();
+
// Set the Thread name, is better than "1"
Thread.CurrentThread.Name = Application.ProductName;
@@ -74,6 +76,16 @@ namespace Greenshot {
// Log the startup
LOG.Info("Starting: " + EnvironmentInfo.EnvironmentToString(false));
try {
+ // Fix for Bug 2495900, Multi-user Environment
+ // check whether there's an local instance running already
+
+ // 1) Create Mutex
+ applicationMutex = new Mutex(false, @"Local\F48E86D3-E34C-4DB7-8F8F-9A0EA55F0D08");
+ // 2) Get the right to it, this returns false if it's already locked
+ if (!applicationMutex.WaitOne(0, false)) {
+ isAlreadyRunning = true;
+ }
+
for(int argumentNr = 0; argumentNr < args.Length; argumentNr++) {
string argument = args[argumentNr];
@@ -106,8 +118,8 @@ namespace Greenshot {
helpOutput.AppendLine("\t\tA detailed listing of available settings for the configure command.");
helpOutput.AppendLine();
helpOutput.AppendLine();
- helpOutput.AppendLine("\t--uninstall");
- helpOutput.AppendLine("\t\tUnstall is called from the unstaller and tries to close all running instances.");
+ helpOutput.AppendLine("\t--exit");
+ helpOutput.AppendLine("\t\tTries to close all running instances.");
helpOutput.AppendLine();
helpOutput.AppendLine();
helpOutput.AppendLine("\t--configure [property=value] ...");
@@ -120,7 +132,7 @@ namespace Greenshot {
helpOutput.AppendLine("\t\tOpen the bitmap file in the running Greenshot instance or start a new instance");
helpOutput.AppendLine();
helpOutput.AppendLine();
- helpOutput.AppendLine("\t--exit");
+ helpOutput.AppendLine("\t--norun");
helpOutput.AppendLine("\t\tCan be used if someone only wants to change the configuration.");
helpOutput.AppendLine("\t\tAs soon as this option is found Greenshot exits if not and there is no running instance it will stay running.");
helpOutput.AppendLine("\t\tExample: greenshot.exe --configure Output_File_Path=\"C:\\Documents and Settings\\\" --exit");
@@ -131,19 +143,20 @@ namespace Greenshot {
if (!attachedToConsole) {
Console.ReadKey();
}
+ FreeMutex();
return;
}
- // unregister application on uninstall (allow uninstall)
- if (argument.Equals("--uninstall") || argument.Equals("uninstall")) {
+ // exit application
+ if (argument.Equals("--exit")) {
try {
LOG.Info("Sending all instances the exit command.");
// Pass Exit to running instance, if any
- dataTransport = new DataTransport(CommandEnum.Exit, args[0]);
- SendData(dataTransport);
+ SendData(new CopyDataTransport(CommandEnum.Exit));
} catch (Exception e) {
LOG.Warn("Exception by exit.", e);
}
+ FreeMutex();
return;
}
@@ -165,7 +178,7 @@ namespace Greenshot {
conf.SetProperties(properties);
conf.Store();
// Update running instances
- SendData(new DataTransport(CommandEnum.ReloadConfig));
+ SendData(new CopyDataTransport(CommandEnum.ReloadConfig));
LOG.Debug("Configuration modified!");
} else {
LOG.Debug("Configuration NOT modified!");
@@ -173,33 +186,38 @@ namespace Greenshot {
}
// Make an exit possible
- if (argument.Equals("--exit")) {
+ if (argument.Equals("--norun")) {
+ FreeMutex();
return;
}
if (argument.Equals("--openfile")) {
- // Take filename and send it to running instance or take it while opening
- dataTransport = new DataTransport(CommandEnum.OpenFile, args[0]);
+ string filename = args[++argumentNr];
+ filesToOpen.Add(filename);
}
}
- // Fix for Bug 2495900, Multi-user Environment
- // check whether there's an local instance running already
-
- // 1) Create Mutex
- applicationMutex = new Mutex(false, @"Local\F48E86D3-E34C-4DB7-8F8F-9A0EA55F0D08");
- // 2) Get the right to it, this returns false if it's already locked
- if (!applicationMutex.WaitOne(0, false)) {
- if (dataTransport != null) {
- SendData(dataTransport);
- } else {
+ // Finished parsing the command line arguments, see if we need to do anything
+ CopyDataTransport transport = new CopyDataTransport();
+ if (filesToOpen.Count > 0) {
+ foreach(string fileToOpen in filesToOpen) {
+ transport.AddCommand(CommandEnum.OpenFile, fileToOpen);
+ }
+ }
+ if (isAlreadyRunning) {
+ if (filesToOpen.Count > 0) {
+ SendData(transport);
+ } else {
conf = AppConfig.GetInstance();
ILanguage lang = Language.GetInstance();
MessageBox.Show(lang.GetString(LangKey.error_multipleinstances), lang.GetString(LangKey.error));
- }
+ }
+ FreeMutex();
Application.Exit();
return;
}
+
+ // From here on we continue starting Greenshot
Application.EnableVisualStyles();
Application.SetCompatibleTextRenderingDefault(false);
@@ -216,20 +234,11 @@ namespace Greenshot {
// Check if it's the first time launch?
bool firstLaunch = (bool)conf.General_IsFirstLaunch;
if(firstLaunch) {
- // todo: display basic instructions
- try {
- } catch (Exception ex) {
- LOG.Error("Exception in MainForm.", ex);
- } finally {
- conf.General_IsFirstLaunch = false;
- conf.Store();
- }
+ conf.General_IsFirstLaunch = false;
+ conf.Store();
+ transport.AddCommand(CommandEnum.FirstLaunch);
}
- // Pass firstlaunch if it is the firstlaunch and no filename is given
- if (dataTransport == null && firstLaunch) {
- dataTransport = new DataTransport(CommandEnum.FirstLaunch, null);
- }
- MainForm mainForm = new MainForm(dataTransport);
+ MainForm mainForm = new MainForm(transport);
Application.Run(mainForm);
} catch(Exception ex) {
LOG.Error("Exception in startup.", ex);
@@ -241,21 +250,34 @@ namespace Greenshot {
/// Send DataTransport Object via Window-messages
///
/// DataTransport with data for a running instance
- private static void SendData(DataTransport dataTransport) {
+ private static void SendData(CopyDataTransport copyDataTransport) {
string appName = Application.ProductName;
CopyData copyData = new CopyData();
copyData.Channels.Add(appName);
- copyData.Channels[appName].Send(dataTransport);
+ copyData.Channels[appName].Send(copyDataTransport);
}
-
+
+ private static void FreeMutex() {
+ // Remove the application mutex
+ if (applicationMutex != null) {
+ try {
+ applicationMutex.ReleaseMutex();
+ applicationMutex = null;
+ } catch (Exception ex) {
+ LOG.Error("Error releasing Mutex!", ex);
+ }
+ }
+ }
+
public static MainForm instance = null;
private ILanguage lang;
private ToolTip tooltip;
private CaptureForm captureForm = null;
private string lastImagePath = null;
-
- public MainForm(DataTransport dataTransport) {
+ private CopyData copyData = null;
+
+ public MainForm(CopyDataTransport dataTransport) {
instance = this;
//
// The InitializeComponent() call is required for Windows Forms designer support.
@@ -280,21 +302,60 @@ namespace Greenshot {
// Enable the Greenshot icon to be visible, this prevents Problems with the context menu
notifyIcon.Visible = true;
-
+
+ // Create a new instance of the class: copyData = new CopyData();
+ copyData = new CopyData();
+
+ // Assign the handle:
+ copyData.AssignHandle(this.Handle);
+ // Create the channel to send on:
+ copyData.Channels.Add("Greenshot");
+ // Hook up received event:
+ copyData.CopyDataReceived += new CopyDataReceivedEventHandler(CopyDataDataReceived);
+
if (dataTransport != null) {
- // See what the dataTransport from the static main brought us!
- switch (dataTransport.Command) {
- case CommandEnum.FirstLaunch:
- // Show user where Greenshot is, only at first start
- notifyIcon.ShowBalloonTip(3000, "Greenshot", lang.GetString(LangKey.tooltip_firststart), ToolTipIcon.Info);
+ HandleDataTransport(dataTransport);
+ }
+ }
+
+ ///
+ /// DataReceivedEventHandler
+ ///
+ ///
+ ///
+ private void CopyDataDataReceived(object sender, CopyDataReceivedEventArgs copyDataReceivedEventArgs) {
+ // Cast the data to the type of object we sent:
+ CopyDataTransport dataTransport = (CopyDataTransport)copyDataReceivedEventArgs.Data;
+ HandleDataTransport(dataTransport);
+ }
+
+ private void HandleDataTransport(CopyDataTransport dataTransport) {
+ foreach(KeyValuePair command in dataTransport.Commands) {
+ LOG.Debug("Data received, Command = " + command.Key + ", Data: " + command.Value);
+ switch(command.Key) {
+ case CommandEnum.Exit:
+ exit();
+ break;
+ case CommandEnum.ReloadConfig:
+ AppConfig.Reload();
+ // Even update language when needed
+ UpdateUI();
break;
case CommandEnum.OpenFile:
- captureForm.HandleDataTransport(dataTransport);
+ string filename = command.Value;
+ if (File.Exists(filename)) {
+ captureForm.MakeCapture(filename);
+ } else {
+ LOG.Warn("No such file: " + filename);
+ }
+ break;
+ default:
+ LOG.Error("Unknown command!");
break;
}
}
}
-
+
public ContextMenuStrip MainMenu {
get {return contextMenu;}
}
@@ -577,14 +638,7 @@ namespace Greenshot {
LOG.Error("Error storing configuration!", e);
}
// Remove the application mutex
- if (applicationMutex != null) {
- try {
- applicationMutex.ReleaseMutex();
- applicationMutex = null;
- } catch (Exception ex) {
- LOG.Error("Error releasing Mutex!", ex);
- }
- }
+ FreeMutex();
// make the icon invisible otherwise it stays even after exit!!
if (notifyIcon != null) {
diff --git a/Greenshot/releases/additional_files/installer.txt b/Greenshot/releases/additional_files/installer.txt
index a1df72e0e..c1890d2ae 100644
--- a/Greenshot/releases/additional_files/installer.txt
+++ b/Greenshot/releases/additional_files/installer.txt
@@ -3,7 +3,7 @@ Here are some details about Greenshot that might be handy for silent/mass instal
The Greenshot installer is made with Inno Setup, see http://www.jrsoftware.org/isinfo.php
For command line options of the installer see: http://www.jrsoftware.org/ishelp/index.php?topic=setupcmdline
-Since Greenshot build > 0.8.0.700 it is possible to configure Greenshot settings from the command-line.
+Since Greenshot 0.8.1 it is possible to configure Greenshot settings from the command-line.
This will even work when Greenshot is already running!
Greenshot commandline options:
@@ -14,19 +14,21 @@ Greenshot commandline options:
--help configure
A list of the options that can be set
- --uninstall
- Unstall is called from the unstaller and tries to close all running instances.
-
+ --exit
+ Try to close all running instances, could be used for installers
--configure [property=value] ...
Change the configuration of Greenshot via the commandline, multiple properties can be specified after each other.
Example to change the language to English: greenshot.exe --configure Ui_Language=en-US
Example to change the destination: greenshot.exe --configure Output_File_Path="C:\Documents and Settings\"
-
--openfile [filename]
Open the bitmap file in the running Greenshot instance or start a new instance
+ --norun
+ Use as last option if you don't want the started executable to spawn a Greenshot instance.
+ e.g. when you only want to change settings but don't want to have a running Greenshot afterwards.
+
With the --configure option many settings can be change, the --help configure will give a list of all available settings!
Here are some described in detail:
diff --git a/Greenshot/releases/innosetup/setup.iss b/Greenshot/releases/innosetup/setup.iss
index abe135fa2..eea689fa3 100644
--- a/Greenshot/releases/innosetup/setup.iss
+++ b/Greenshot/releases/innosetup/setup.iss
@@ -29,6 +29,8 @@ AppSupportURL=http://getgreenshot.org
AppUpdatesURL=http://getgreenshot.org
AppVerName={#ExeName} {#Version}
AppVersion={#Version}
+; changes associations is used when the installer installs new extensions, it clears the explorer icon cache
+;ChangesAssociations=yes
Compression=lzma/ultra64
InternalCompressLevel=ultra64
LanguageDetectionMethod=uilanguage
@@ -38,7 +40,7 @@ VersionInfoCompany={#ExeName}
VersionInfoTextVersion={#Version}
VersionInfoVersion={#Version}
VersionInfoProductName={#ExeName}
-PrivilegesRequired=admin
+PrivilegesRequired=poweruser
; Reference a bitmap, max size 164x314
WizardImageFile=installer-large.bmp
; Reference a bitmap, max size 55x58
@@ -46,6 +48,11 @@ WizardSmallImageFile=installer-small.bmp
MinVersion=,5.01.2600
[Registry]
Root: HKCU; Subkey: Software\Microsoft\Windows\CurrentVersion\Run; ValueType: string; ValueName: {#ExeName}; ValueData: {app}\{#ExeName}.exe; Permissions: users-modify; Flags: uninsdeletevalue; Tasks: startup
+; Register our own filetype
+;Root: HKCR; Subkey: ".gsb"; ValueType: string; ValueName: ""; ValueData: "GreenshotFile"; Flags: uninsdeletevalue
+;Root: HKCR; Subkey: "GreenshotFile"; ValueType: string; ValueName: ""; ValueData: "Greenshot File"; Flags: uninsdeletekey
+;Root: HKCR; Subkey: "GreenshotFile\DefaultIcon"; ValueType: string; ValueName: ""; ValueData: "{app}\Greenshot.EXE,0"
+;Root: HKCR; Subkey: "GreenshotFile\shell\open\command"; ValueType: string; ValueName: ""; ValueData: """{app}\Greenshot.EXE"" --openfile ""%1"""
[Icons]
Name: {group}\{#ExeName}; Filename: {app}\{#ExeName}.exe; WorkingDir: {app}
Name: {group}\Uninstall {#ExeName}; Filename: {app}\unins000.exe; WorkingDir: {app}
@@ -80,47 +87,49 @@ Name: "plugins\ocr"; Description: {cm:ocr}; Types: Full
Name: "plugins\titlefix"; Description: {cm:titlefix}; Types: Full
;Name: "plugins\flickr"; Description: "Flickr Plugin"; Types: Full
[Code]
-function InitializeSetup(): Boolean;
+function KillGreenshot() : Boolean;
var
- ErrorCode : Integer;
- NetFrameWorkInstalled : Boolean;
- MsgBoxResult : Boolean;
bMutex : Boolean;
resultCode: Integer;
begin
-
- NetFrameWorkInstalled := RegKeyExists(HKLM, 'SOFTWARE\Microsoft\.NETFramework\policy\v2.0');
- if NetFrameWorkInstalled = true then
+ bMutex:= True
+ while bMutex do
begin
bMutex:= CheckForMutexes ('Local\{#Mutex}');
if bMutex = True then
begin
Exec('taskkill.exe', '/F /IM Greenshot.exe', '', SW_HIDE, ewWaitUntilTerminated, ResultCode);
+ Sleep(1200);
end;
- Result := true;
end;
+ Result := True;
+end;
- if NetFrameWorkInstalled = false then
- begin
+function InitializeSetup(): Boolean;
+var
+ ErrorCode : Integer;
+ NetFrameWorkInstalled : Boolean;
+ MsgBoxResult : Boolean;
+begin
+
+ NetFrameWorkInstalled := RegKeyExists(HKLM, 'SOFTWARE\Microsoft\.NETFramework\policy\v2.0');
+ if NetFrameWorkInstalled = true then begin
+ KillGreenshot();
+ Result := true;
+ end
+ else begin
MsgBoxResult := MsgBox(ExpandConstant('{cm:dotnetmissing}'), mbConfirmation, MB_YESNO) = idYes;
Result := false;
if MsgBoxResult = true then
begin
- ShellExec('open', 'http://download.microsoft.com/download/5/6/7/567758a3-759e-473e-bf8f-52154438565a/dotnetfx.exe', '','',SW_SHOWNORMAL,ewNoWait,ErrorCode);
+ ShellExec('open', 'http://download.microsoft.com/download/5/6/7/567758a3-759e-473e-bf8f-52154438565a/dotnetfx.exe', '', '', SW_SHOWNORMAL, ewNoWait, ErrorCode);
end;
end;
end;
function InitializeUninstall():Boolean;
-var
- bMutex : Boolean;
- resultCode: Integer;
begin
- bMutex:= CheckForMutexes ('Local\{#Mutex}');
- if bMutex = True then
- begin
- Exec(ExpandConstant('{app}\{#ExeName}.exe'), '--uninstall', '', SW_HIDE, ewWaitUntilTerminated, ResultCode);
- end;
+ KillGreenshot();
Result := True;
end;
[Run]
diff --git a/GreenshotCore/Helpers/CopyData.cs b/GreenshotCore/Helpers/CopyData.cs
index 78dd0a660..8dfd874de 100644
--- a/GreenshotCore/Helpers/CopyData.cs
+++ b/GreenshotCore/Helpers/CopyData.cs
@@ -20,6 +20,7 @@
*/
using System;
using System.Collections;
+using System.Collections.Generic;
using System.IO;
using System.Runtime.InteropServices;
using System.Runtime.Serialization.Formatters.Binary;
@@ -34,25 +35,32 @@ namespace Greenshot.Helpers {
public enum CommandEnum { OpenFile, Exit, FirstLaunch, ReloadConfig };
[Serializable()]
- public class DataTransport {
- private CommandEnum command;
- private string commandData;
- public CommandEnum Command {
- get {return command;}
+ public class CopyDataTransport {
+ List> commands;
+ public List> Commands {
+ get {return commands;}
}
- public string CommandData {
- get {return commandData;}
+ public CopyDataTransport() {
+ this.commands = new List>();
}
- public DataTransport(CommandEnum command) {
- this.command = command;
+
+ public CopyDataTransport(CommandEnum command) : this() {
+ AddCommand(command, null);
}
- public DataTransport(CommandEnum command, string commandData) : this(command){
- this.commandData = commandData;
+ public CopyDataTransport(CommandEnum command, string commandData) : this() {
+ AddCommand(command, commandData);
}
+ public void AddCommand(CommandEnum command) {
+ this.commands.Add(new KeyValuePair(command, null));
+ }
+ public void AddCommand(CommandEnum command, string commandData) {
+ this.commands.Add(new KeyValuePair(command, commandData));
+ }
+
}
- public delegate void DataReceivedEventHandler(object sender, DataReceivedEventArgs e);
+ public delegate void CopyDataReceivedEventHandler(object sender, CopyDataReceivedEventArgs e);
///
/// A class which wraps using Windows native WM_COPYDATA
@@ -68,7 +76,7 @@ namespace Greenshot.Helpers {
/// Event raised when data is received on any of the channels
/// this class is subscribed to.
///
- public event DataReceivedEventHandler DataReceived;
+ public event CopyDataReceivedEventHandler CopyDataReceived;
[StructLayout(LayoutKind.Sequential)]
private struct COPYDATASTRUCT {
@@ -102,8 +110,8 @@ namespace Greenshot.Helpers {
CopyDataObjectData cdo = (CopyDataObjectData) b.Deserialize(stream);
if (channels.Contains(cdo.Channel)) {
- DataReceivedEventArgs d = new DataReceivedEventArgs(cdo.Channel, cdo.Data, cdo.Sent);
- OnDataReceived(d);
+ CopyDataReceivedEventArgs d = new CopyDataReceivedEventArgs(cdo.Channel, cdo.Data, cdo.Sent);
+ OnCopyDataReceived(d);
m.Result = (IntPtr) 1;
}
}
@@ -121,8 +129,8 @@ namespace Greenshot.Helpers {
/// Raises the DataReceived event from this class.
///
/// The data which has been received.
- protected void OnDataReceived(DataReceivedEventArgs e) {
- DataReceived(this, e);
+ protected void OnCopyDataReceived(CopyDataReceivedEventArgs e) {
+ CopyDataReceived(this, e);
}
///
@@ -180,7 +188,7 @@ namespace Greenshot.Helpers {
/// Contains data and other information associated with data
/// which has been sent from another application.
///
- public class DataReceivedEventArgs {
+ public class CopyDataReceivedEventArgs {
private string channelName = "";
private object data = null;
private DateTime sent;
@@ -226,7 +234,7 @@ namespace Greenshot.Helpers {
/// The channel that the data was received from
/// The data which was sent
/// The date and time the data was sent
- internal DataReceivedEventArgs(string channelName, object data, DateTime sent) {
+ internal CopyDataReceivedEventArgs(string channelName, object data, DateTime sent) {
this.channelName = channelName;
this.data = data;
this.sent = sent;