/*
* Greenshot - a free and open source screenshot tool
* Copyright (C) 2007-2010 Thomas Braun, Jens Klingen, Robin Krom
*
* For more information see: http://getgreenshot.org/
* The Greenshot project is hosted on Sourceforge: http://sourceforge.net/projects/greenshot/
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 1 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see .
*/
using System;
using System.Collections;
using System.Collections.Generic;
using System.Diagnostics;
using System.Drawing;
using System.Drawing.Drawing2D;
using System.Drawing.Printing;
using System.IO;
using System.Reflection;
using System.Text;
using System.Threading;
using System.Windows.Forms;
using Greenshot.Capturing;
using Greenshot.Configuration;
using Greenshot.Drawing;
using Greenshot.Forms;
using Greenshot.Help;
using Greenshot.Helpers;
using Greenshot.Plugin;
using Greenshot.UnmanagedHelpers;
using GreenshotPlugin.Core;
namespace Greenshot {
///
/// Description of MainForm.
///
public partial class MainForm : Form {
private const string LOG4NET_FILE = "log4net.xml";
private static log4net.ILog LOG = null;
private static AppConfig conf;
static Mutex applicationMutex = null;
[STAThread]
public static void Main(string[] args) {
DataTransport dataTransport = null;
// Set the Thread name, is better than "1"
Thread.CurrentThread.Name = Application.ProductName;
Application.ThreadException += new System.Threading.ThreadExceptionEventHandler(Application_ThreadException);
AppDomain.CurrentDomain.UnhandledException += new UnhandledExceptionEventHandler(CurrentDomain_UnhandledException);
// Setup log4j, currently the file is called log4net.xml
string log4netFilename = Path.Combine(Application.StartupPath, LOG4NET_FILE);
if (File.Exists(log4netFilename)) {
log4net.Config.XmlConfigurator.ConfigureAndWatch(new FileInfo(log4netFilename));
} else {
MessageBox.Show("Can't find file " + LOG4NET_FILE);
}
// Setup the LOG
LOG = log4net.LogManager.GetLogger(typeof(MainForm));
// Log the startup
LOG.Info("Starting: " + EnvironmentInfo.EnvironmentToString(false));
try {
for(int argumentNr = 0; argumentNr < args.Length; argumentNr++) {
string argument = args[argumentNr];
// Help
if (argument.Equals("--help")) {
// Try to attach to the console
bool attachedToConsole = User32.AttachConsole(User32.ATTACH_PARENT_PROCESS);
// If attach didn't work, open a console
if (!attachedToConsole) {
User32.AllocConsole();
}
StringBuilder helpOutput = new StringBuilder();
helpOutput.AppendLine();
if (argumentNr + 1 < args.Length && args[argumentNr + 1].Equals("config")) {
helpOutput.AppendLine("Available configuration settings:");
Properties properties = AppConfig.GetAvailableProperties();
foreach(string key in properties.Keys) {
helpOutput.AppendLine("\t\t" + key + "=" + properties.GetProperty(key));
}
} else {
helpOutput.AppendLine("Greenshot commandline options:");
helpOutput.AppendLine();
helpOutput.AppendLine();
helpOutput.AppendLine("\t--help [config]");
helpOutput.AppendLine("\t\tThis help.");
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();
helpOutput.AppendLine();
helpOutput.AppendLine("\t--config [property=value] ...");
helpOutput.AppendLine("\t\tChange the configuration of Greenshot via the commandline.");
helpOutput.AppendLine("\t\tExample to change the language to English: greenshot.exe --config Ui_Language=en-US");
helpOutput.AppendLine("\t\tExample to change the destination: greenshot.exe --config Output_File_Path=\"C:\\Documents and Settings\\\"");
helpOutput.AppendLine();
helpOutput.AppendLine();
helpOutput.AppendLine("\t--openfile [filename]");
helpOutput.AppendLine("\t\tOpen the bitmap file in the running Greenshot instance or start a new instance");
}
Console.WriteLine(helpOutput.ToString());
// If attach didn't work, wait for key otherwise the console will close to quickly
if (!attachedToConsole) {
Console.ReadKey();
}
return;
}
// unregister application on uninstall (allow uninstall)
if (argument.Equals("--uninstall") || argument.Equals("uninstall")) {
try {
// Pass Exit to running instance, if any
dataTransport = new DataTransport(CommandEnum.Exit, args[0]);
SendData(dataTransport);
} catch (Exception e) {
LOG.Warn("Exception by exit.", e);
}
return;
}
// Modify configuration
if (argument.Equals("--config")) {
LOG.Debug("Setting configuration!");
conf = AppConfig.GetInstance();
Properties properties = new Properties();
int propertyNr = argumentNr + 1;
while(propertyNr < args.Length && args[propertyNr].Contains("=")) {
// "Remove" the argument from the list as we used it
argumentNr++;
string [] splitargument = args[propertyNr].Split(new Char[] {'='});
LOG.Debug("Found property: " + splitargument[0] +"="+ splitargument[1]);
properties.AddProperty(splitargument[0], splitargument[1]);
propertyNr++;
}
if (properties.Count > 0) {
conf.SetProperties(properties);
conf.Store();
// Update running instances
SendData(new DataTransport(CommandEnum.ReloadConfig));
LOG.Debug("Configuration modified!");
} else {
LOG.Debug("Configuration NOT modified!");
}
}
// Make an exit possible
if (argument.Equals("--exit")) {
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]);
}
}
// 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 {
conf = AppConfig.GetInstance();
ILanguage lang = Language.GetInstance();
MessageBox.Show(lang.GetString(LangKey.error_multipleinstances), lang.GetString(LangKey.error));
}
Application.Exit();
return;
}
Application.EnableVisualStyles();
Application.SetCompatibleTextRenderingDefault(false);
conf = AppConfig.GetInstance();
// if language is not set, show language dialog
if(conf.Ui_Language.Equals("")) {
LanguageDialog ld = LanguageDialog.GetInstance();
ld.ShowDialog();
conf.Ui_Language = ld.Language;
conf.Store();
}
// 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();
}
}
// 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);
Application.Run();
} catch(Exception ex) {
LOG.Error("Exception in startup.", ex);
Application_ThreadException(MainForm.ActiveForm, new ThreadExceptionEventArgs(ex));
}
}
///
/// Send DataTransport Object via Window-messages
///
/// DataTransport with data for a running instance
private static void SendData(DataTransport dataTransport) {
string appName = Application.ProductName;
CopyData copyData = new CopyData();
copyData.Channels.Add(appName);
copyData.Channels[appName].Send(dataTransport);
}
public static MainForm instance = null;
private ILanguage lang;
private ToolTip tooltip;
private CaptureForm captureForm = null;
private string lastImagePath = null;
public MainForm(DataTransport dataTransport) {
instance = this;
//
// The InitializeComponent() call is required for Windows Forms designer support.
//
InitializeComponent();
lang = Language.GetInstance();
if((bool)conf.General_RegisterHotkeys) {
RegisterHotkeys();
}
tooltip = new ToolTip();
UpdateUI();
InitializeQuickSettingsMenu();
captureForm = new CaptureForm();
// Load all the plugins
PluginHelper.instance.LoadPlugins(this, captureForm);
PluginHelper.instance.OnImageOutput += new OnImageOutputHandler(ImageWritten);
SoundHelper.Initialize();
// Enable the Greenshot icon to be visible, this prevents Problems with the context menu
notifyIcon.Visible = true;
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);
break;
case CommandEnum.OpenFile:
captureForm.HandleDataTransport(dataTransport);
break;
}
}
}
public ContextMenuStrip MainMenu {
get {return contextMenu;}
}
#region hotkeys
protected override void WndProc(ref Message m) {
HotkeyHelper.HandleMessages(ref m);
base.WndProc(ref m);
}
private void RegisterHotkeys() {
bool suc = true;
suc &= HotkeyHelper.RegisterHotKey((int)this.Handle, (int)HotkeyHelper.Modifiers.NONE, HotkeyHelper.VK_SNAPSHOT, new HotKeyHandler(CaptureRegion));
suc &= HotkeyHelper.RegisterHotKey((int)this.Handle, (int)HotkeyHelper.Modifiers.ALT, HotkeyHelper.VK_SNAPSHOT, new HotKeyHandler(CaptureWindow));
suc &= HotkeyHelper.RegisterHotKey((int)this.Handle, (int)HotkeyHelper.Modifiers.CTRL, HotkeyHelper.VK_SNAPSHOT, new HotKeyHandler(CaptureFullScreen));
suc &= HotkeyHelper.RegisterHotKey((int)this.Handle, (int)HotkeyHelper.Modifiers.SHIFT, HotkeyHelper.VK_SNAPSHOT, new HotKeyHandler(CaptureLastRegion));
if (!suc) {
MessageBox.Show(lang.GetString(LangKey.warning_hotkeys),lang.GetString(LangKey.warning));
}
}
#endregion
public void UpdateUI() {
this.Text = lang.GetString(LangKey.application_title);
this.contextmenu_settings.Text = lang.GetString(LangKey.contextmenu_settings);
this.contextmenu_capturearea.Text = lang.GetString(LangKey.contextmenu_capturearea);
this.contextmenu_capturelastregion.Text = lang.GetString(LangKey.contextmenu_capturelastregion);
this.contextmenu_capturewindow.Text = lang.GetString(LangKey.contextmenu_capturewindow);
this.contextmenu_capturefullscreen.Text = lang.GetString(LangKey.contextmenu_capturefullscreen);
this.contextmenu_captureclipboard.Text = lang.GetString(LangKey.contextmenu_captureclipboard);
this.contextmenu_openfile.Text = lang.GetString(LangKey.contextmenu_openfile);
this.contextmenu_quicksettings.Text = lang.GetString(LangKey.contextmenu_quicksettings);
this.contextmenu_help.Text = lang.GetString(LangKey.contextmenu_help);
this.contextmenu_about.Text = lang.GetString(LangKey.contextmenu_about);
this.contextmenu_donate.Text = lang.GetString(LangKey.contextmenu_donate);
this.contextmenu_exit.Text = lang.GetString(LangKey.contextmenu_exit);
}
#region mainform events
void MainFormFormClosing(object sender, FormClosingEventArgs e) {
LOG.Info("Closing with reason: " + e.CloseReason);
// Inform all registed plugins
PluginHelper.instance.Shutdown();
conf.Store();
HotkeyHelper.UnregisterHotkeys((int)this.Handle);
SoundHelper.Deinitialize();
if (applicationMutex != null) {
try {
applicationMutex.ReleaseMutex();
} catch (Exception ex) {
LOG.Error("Error releasing Mutex!", ex);
}
}
}
#endregion
#region key handlers
void CaptureRegion() {
captureForm.MakeCapture(CaptureMode.Region, true);
}
void CaptureClipboard() {
captureForm.MakeCapture(CaptureMode.Clipboard, false);
}
void CaptureFile() {
OpenFileDialog openFileDialog = new OpenFileDialog();
openFileDialog.Filter = "Image files (*.png, *.jpg, *.gif, *.bmp, *.ico)|*.png; *.jpg; *.jpeg; *.gif; *.bmp; *.ico";
if (openFileDialog.ShowDialog() == DialogResult.OK) {
if (File.Exists(openFileDialog.FileName)) {
captureForm.MakeCapture(openFileDialog.FileName);
}
}
}
void CaptureFullScreen() {
captureForm.MakeCapture(CaptureMode.FullScreen, true);
}
void CaptureLastRegion() {
captureForm.MakeCapture(CaptureMode.LastRegion, true);
}
void CaptureWindow() {
CaptureMode captureMode = CaptureMode.None;
if ((conf.Capture_Windows_Interactive.HasValue && conf.Capture_Windows_Interactive.Value)) {
captureMode = CaptureMode.Window;
} else {
captureMode = CaptureMode.ActiveWindow;
}
captureForm.MakeCapture(captureMode, true);
}
#endregion
#region contextmenu
void ContextMenuOpening(object sender, System.ComponentModel.CancelEventArgs e) {
string text = Clipboard.GetText();
if ((text != null && text.StartsWith("http://")) || Clipboard.ContainsImage() || ClipboardHelper.GetFormats().Contains("HTML Format")) {
contextmenu_captureclipboard.Enabled = true;
} else {
contextmenu_captureclipboard.Enabled = false;
}
contextmenu_capturelastregion.Enabled = RuntimeConfig.LastCapturedRegion != Rectangle.Empty;
}
void CaptureAreaToolStripMenuItemClick(object sender, EventArgs e) {
captureForm.MakeCapture(CaptureMode.Region, false);
}
void CaptureClipboardToolStripMenuItemClick(object sender, System.EventArgs e) {
CaptureClipboard();
}
void OpenFileToolStripMenuItemClick(object sender, System.EventArgs e) {
CaptureFile();
}
void CaptureFullScreenToolStripMenuItemClick(object sender, System.EventArgs e) {
captureForm.MakeCapture(CaptureMode.FullScreen, false);
}
void Contextmenu_capturelastregionClick(object sender, System.EventArgs e) {
captureForm.MakeCapture(CaptureMode.LastRegion, false);
}
void Contextmenu_donateClick(object sender, System.EventArgs e) {
Process.Start("http://getgreenshot.org/support/");
}
void CaptureWindowToolStripMenuItemClick(object sender, System.EventArgs e) {
captureForm.MakeCapture(CaptureMode.Window, false);
}
void Contextmenu_settingsClick(object sender, System.EventArgs e) {
SettingsForm settings = new SettingsForm();
settings.ShowDialog();
InitializeQuickSettingsMenu();
this.Hide();
}
void Contextmenu_aboutClick(object sender, EventArgs e) {
new AboutForm().Show();
}
void Contextmenu_helpClick(object sender, System.EventArgs e) {
HelpBrowserForm hpf = new HelpBrowserForm(conf.Ui_Language);
hpf.Show();
}
void Contextmenu_exitClick(object sender, EventArgs e) {
Application.Exit();
}
private void InitializeQuickSettingsMenu() {
this.contextmenu_quicksettings.DropDownItems.Clear();
// screenshot destination
ToolStripMenuSelectList sel = new ToolStripMenuSelectList("destination",true);
sel.Text = lang.GetString(LangKey.settings_destination);
sel.AddItem(lang.GetString(LangKey.settings_destination_editor), ScreenshotDestinations.Editor, (conf.Output_Destinations&ScreenshotDestinations.Editor)==ScreenshotDestinations.Editor);
sel.AddItem(lang.GetString(LangKey.settings_destination_clipboard), ScreenshotDestinations.Clipboard, (conf.Output_Destinations&ScreenshotDestinations.Clipboard)==ScreenshotDestinations.Clipboard);
sel.AddItem(lang.GetString(LangKey.quicksettings_destination_file), ScreenshotDestinations.FileDefault, (conf.Output_Destinations&ScreenshotDestinations.FileDefault)==ScreenshotDestinations.FileDefault);
sel.AddItem(lang.GetString(LangKey.settings_destination_fileas), ScreenshotDestinations.FileWithDialog, (conf.Output_Destinations&ScreenshotDestinations.FileWithDialog)==ScreenshotDestinations.FileWithDialog);
sel.AddItem(lang.GetString(LangKey.settings_destination_printer), ScreenshotDestinations.Printer, (conf.Output_Destinations&ScreenshotDestinations.Printer)==ScreenshotDestinations.Printer);
sel.CheckedChanged += new EventHandler(this.QuickSettingItemChanged);
this.contextmenu_quicksettings.DropDownItems.Add(sel);
// print options
sel = new ToolStripMenuSelectList("printoptions",true);
sel.Text = lang.GetString(LangKey.settings_printoptions);
sel.AddItem(lang.GetString(LangKey.printoptions_allowshrink), "AllowPrintShrink", (bool)conf.Output_Print_AllowShrink);
sel.AddItem(lang.GetString(LangKey.printoptions_allowenlarge), "AllowPrintEnlarge", (bool)conf.Output_Print_AllowEnlarge);
sel.AddItem(lang.GetString(LangKey.printoptions_allowrotate), "AllowPrintRotate", (bool)conf.Output_Print_AllowRotate);
sel.AddItem(lang.GetString(LangKey.printoptions_allowcenter), "AllowPrintCenter", (bool)conf.Output_Print_Center);
sel.CheckedChanged += new EventHandler(this.QuickSettingItemChanged);
this.contextmenu_quicksettings.DropDownItems.Add(sel);
// effects
sel = new ToolStripMenuSelectList("effects",true);
sel.Text = lang.GetString(LangKey.settings_visualization);
sel.AddItem(lang.GetString(LangKey.settings_playsound), "PlaySound", (bool)conf.Ui_Effects_CameraSound);
sel.AddItem(lang.GetString(LangKey.settings_showflashlight), "ShowFlashlight", (bool)conf.Ui_Effects_Flashlight);
sel.CheckedChanged += new EventHandler(this.QuickSettingItemChanged);
this.contextmenu_quicksettings.DropDownItems.Add(sel);
}
void QuickSettingItemChanged(object sender, EventArgs e) {
ToolStripMenuSelectList selectList = (ToolStripMenuSelectList)sender;
ToolStripMenuSelectListItem item = ((ItemCheckedChangedEventArgs)e).Item;;
if(selectList.Identifier.Equals("destination")) {
IEnumerator en = selectList.DropDownItems.GetEnumerator();
ScreenshotDestinations dest = 0;
while(en.MoveNext()) {
ToolStripMenuSelectListItem i = (ToolStripMenuSelectListItem)en.Current;
if(i.Checked) dest |= (ScreenshotDestinations)i.Data;
}
conf.Output_Destinations = dest;
conf.Store();
} else if(selectList.Identifier.Equals("printoptions")) {
if(item.Data.Equals("AllowPrintShrink")) conf.Output_Print_AllowShrink = (bool?)item.Checked;
else if(item.Data.Equals("AllowPrintEnlarge")) conf.Output_Print_AllowEnlarge = (bool?)item.Checked;
else if(item.Data.Equals("AllowPrintRotate")) conf.Output_Print_AllowRotate = (bool?)item.Checked;
else if(item.Data.Equals("AllowPrintCenter")) conf.Output_Print_Center = (bool?)item.Checked;
conf.Store();
} else if(selectList.Identifier.Equals("effects")) {
if(item.Data.Equals("PlaySound")) conf.Ui_Effects_CameraSound = (bool?)item.Checked;
else if(item.Data.Equals("ShowFlashlight")) conf.Ui_Effects_Flashlight = (bool?)item.Checked;
conf.Store();
}
}
#endregion
private static void CurrentDomain_UnhandledException(object sender, UnhandledExceptionEventArgs e) {
string exceptionText = EnvironmentInfo.BuildReport(e.ExceptionObject as Exception);
LOG.Error(exceptionText);
new BugReportForm(exceptionText).ShowDialog();
}
private static void Application_ThreadException(object sender, ThreadExceptionEventArgs e) {
string exceptionText = EnvironmentInfo.BuildReport(e.Exception);
LOG.Error(exceptionText);
new BugReportForm(exceptionText).ShowDialog();
}
///
/// The ContextMenu DoubleClick currently opens the last know save location
///
private void ContextMenuDoubleClick(object sender, EventArgs eventArgs) {
string path;
if (lastImagePath != null && Directory.Exists(lastImagePath)) {
path = lastImagePath;
} else if (Directory.Exists(conf.Output_File_Path)) {
path = conf.Output_File_Path;
} else {
// What do I open when nothing can be found? Right, nothing...
return;
}
LOG.Debug("DoubleClick was called! Starting: " + path);
try {
System.Diagnostics.Process.Start(path);
} catch (Exception e) {
// Make sure we show what we tried to open in the exception
e.Data.Add("path", path);
throw e;
}
}
///
/// Handling of the OnImageOutputHandler event, stores the save location
///
/// Has the full path
private void ImageWritten(object sender, ImageOutputEventArgs eventArgs) {
lastImagePath = Path.GetDirectoryName(eventArgs.FullPath);
}
}
}