mirror of
https://github.com/greenshot/greenshot
synced 2025-08-21 14:03:23 -07:00
Code quality changes
This commit is contained in:
parent
f07ed83722
commit
610f45d082
189 changed files with 4609 additions and 5203 deletions
|
@ -33,8 +33,8 @@ namespace GreenshotPlugin.Core {
|
|||
/// Description of AbstractDestination.
|
||||
/// </summary>
|
||||
public abstract class AbstractDestination : IDestination {
|
||||
private static readonly ILog LOG = LogManager.GetLogger(typeof(AbstractDestination));
|
||||
private static readonly CoreConfiguration configuration = IniConfig.GetIniSection<CoreConfiguration>();
|
||||
private static readonly ILog Log = LogManager.GetLogger(typeof(AbstractDestination));
|
||||
private static readonly CoreConfiguration CoreConfig = IniConfig.GetIniSection<CoreConfiguration>();
|
||||
|
||||
public virtual int CompareTo(object obj) {
|
||||
IDestination other = obj as IDestination;
|
||||
|
@ -42,7 +42,7 @@ namespace GreenshotPlugin.Core {
|
|||
return 1;
|
||||
}
|
||||
if (Priority == other.Priority) {
|
||||
return Description.CompareTo(other.Description);
|
||||
return String.Compare(Description, other.Description, StringComparison.Ordinal);
|
||||
}
|
||||
return Priority - other.Priority;
|
||||
}
|
||||
|
@ -55,23 +55,11 @@ namespace GreenshotPlugin.Core {
|
|||
get;
|
||||
}
|
||||
|
||||
public virtual int Priority {
|
||||
get {
|
||||
return 10;
|
||||
}
|
||||
}
|
||||
|
||||
public virtual Image DisplayIcon {
|
||||
get {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
public virtual int Priority => 10;
|
||||
|
||||
public virtual Keys EditorShortcutKeys {
|
||||
get {
|
||||
return Keys.None;
|
||||
}
|
||||
}
|
||||
public virtual Image DisplayIcon => null;
|
||||
|
||||
public virtual Keys EditorShortcutKeys => Keys.None;
|
||||
|
||||
public virtual IEnumerable<IDestination> DynamicDestinations() {
|
||||
yield break;
|
||||
|
@ -86,27 +74,15 @@ namespace GreenshotPlugin.Core {
|
|||
//if (disposing) {}
|
||||
}
|
||||
|
||||
public virtual bool isDynamic {
|
||||
get {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
public virtual bool IsDynamic => false;
|
||||
|
||||
public virtual bool useDynamicsOnly {
|
||||
get {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
public virtual bool UseDynamicsOnly => false;
|
||||
|
||||
public virtual bool isLinkable {
|
||||
get {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
public virtual bool IsLinkable => false;
|
||||
|
||||
public virtual bool isActive {
|
||||
public virtual bool IsActive {
|
||||
get {
|
||||
if (configuration.ExcludeDestinations != null && configuration.ExcludeDestinations.Contains(Designation)) {
|
||||
if (CoreConfig.ExcludeDestinations != null && CoreConfig.ExcludeDestinations.Contains(Designation)) {
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
|
@ -132,7 +108,7 @@ namespace GreenshotPlugin.Core {
|
|||
surface.SendMessageEvent(this, SurfaceMessageTyp.Info, Language.GetFormattedString("exported_to", exportInformation.DestinationDescription));
|
||||
}
|
||||
surface.Modified = false;
|
||||
} else if (exportInformation != null && !string.IsNullOrEmpty(exportInformation.ErrorMessage)) {
|
||||
} else if (!string.IsNullOrEmpty(exportInformation?.ErrorMessage)) {
|
||||
surface.SendMessageEvent(this, SurfaceMessageTyp.Error, Language.GetFormattedString("exported_to_error", exportInformation.DestinationDescription) + " " + exportInformation.ErrorMessage);
|
||||
}
|
||||
}
|
||||
|
@ -149,12 +125,14 @@ namespace GreenshotPlugin.Core {
|
|||
/// <param name="tagValue">Value for the tag</param>
|
||||
private void AddTagEvents(ToolStripMenuItem menuItem, ContextMenuStrip menu, string tagValue) {
|
||||
if (menuItem != null && menu != null) {
|
||||
menuItem.MouseDown += delegate(object source, MouseEventArgs eventArgs) {
|
||||
LOG.DebugFormat("Setting tag to '{0}'", tagValue);
|
||||
menuItem.MouseDown += delegate
|
||||
{
|
||||
Log.DebugFormat("Setting tag to '{0}'", tagValue);
|
||||
menu.Tag = tagValue;
|
||||
};
|
||||
menuItem.MouseUp += delegate(object source, MouseEventArgs eventArgs) {
|
||||
LOG.Debug("Deleting tag");
|
||||
menuItem.MouseUp += delegate
|
||||
{
|
||||
Log.Debug("Deleting tag");
|
||||
menu.Tag = null;
|
||||
};
|
||||
}
|
||||
|
@ -171,19 +149,21 @@ namespace GreenshotPlugin.Core {
|
|||
public ExportInformation ShowPickerMenu(bool addDynamics, ISurface surface, ICaptureDetails captureDetails, IEnumerable<IDestination> destinations) {
|
||||
// Generate an empty ExportInformation object, for when nothing was selected.
|
||||
ExportInformation exportInformation = new ExportInformation(Designation, Language.GetString("settings_destination_picker"));
|
||||
ContextMenuStrip menu = new ContextMenuStrip();
|
||||
menu.ImageScalingSize = configuration.IconSize;
|
||||
menu.Tag = null;
|
||||
var menu = new ContextMenuStrip
|
||||
{
|
||||
ImageScalingSize = CoreConfig.IconSize,
|
||||
Tag = null
|
||||
};
|
||||
|
||||
menu.Closing += delegate(object source, ToolStripDropDownClosingEventArgs eventArgs) {
|
||||
LOG.DebugFormat("Close reason: {0}", eventArgs.CloseReason);
|
||||
Log.DebugFormat("Close reason: {0}", eventArgs.CloseReason);
|
||||
switch (eventArgs.CloseReason) {
|
||||
case ToolStripDropDownCloseReason.AppFocusChange:
|
||||
if (menu.Tag == null) {
|
||||
// Do not allow the close if the tag is not set, this means the user clicked somewhere else.
|
||||
eventArgs.Cancel = true;
|
||||
} else {
|
||||
LOG.DebugFormat("Letting the menu 'close' as the tag is set to '{0}'", menu.Tag);
|
||||
Log.DebugFormat("Letting the menu 'close' as the tag is set to '{0}'", menu.Tag);
|
||||
}
|
||||
break;
|
||||
case ToolStripDropDownCloseReason.ItemClicked:
|
||||
|
@ -202,7 +182,8 @@ namespace GreenshotPlugin.Core {
|
|||
break;
|
||||
}
|
||||
};
|
||||
menu.MouseEnter += delegate(object source, EventArgs eventArgs) {
|
||||
menu.MouseEnter += delegate
|
||||
{
|
||||
// in case the menu has been unfocused, focus again so that dropdown menus will still open on mouseenter
|
||||
if(!menu.ContainsFocus) menu.Focus();
|
||||
};
|
||||
|
@ -211,10 +192,7 @@ namespace GreenshotPlugin.Core {
|
|||
ToolStripMenuItem item = destination.GetMenuItem(addDynamics, menu,
|
||||
delegate(object sender, EventArgs e) {
|
||||
ToolStripMenuItem toolStripMenuItem = sender as ToolStripMenuItem;
|
||||
if (toolStripMenuItem == null) {
|
||||
return;
|
||||
}
|
||||
IDestination clickedDestination = (IDestination)toolStripMenuItem.Tag;
|
||||
IDestination clickedDestination = (IDestination) toolStripMenuItem?.Tag;
|
||||
if (clickedDestination == null) {
|
||||
return;
|
||||
}
|
||||
|
@ -222,7 +200,7 @@ namespace GreenshotPlugin.Core {
|
|||
// Export
|
||||
exportInformation = clickedDestination.ExportCapture(true, surface, captureDetails);
|
||||
if (exportInformation != null && exportInformation.ExportMade) {
|
||||
LOG.InfoFormat("Export to {0} success, closing menu", exportInformation.DestinationDescription);
|
||||
Log.InfoFormat("Export to {0} success, closing menu", exportInformation.DestinationDescription);
|
||||
// close menu if the destination wasn't the editor
|
||||
menu.Close();
|
||||
|
||||
|
@ -232,7 +210,7 @@ namespace GreenshotPlugin.Core {
|
|||
surface = null;
|
||||
}
|
||||
} else {
|
||||
LOG.Info("Export cancelled or failed, showing menu again");
|
||||
Log.Info("Export cancelled or failed, showing menu again");
|
||||
|
||||
// Make sure a click besides the menu don't close it.
|
||||
menu.Tag = null;
|
||||
|
@ -248,8 +226,10 @@ namespace GreenshotPlugin.Core {
|
|||
}
|
||||
// Close
|
||||
menu.Items.Add(new ToolStripSeparator());
|
||||
ToolStripMenuItem closeItem = new ToolStripMenuItem(Language.GetString("editor_close"));
|
||||
closeItem.Image = GreenshotResources.getImage("Close.Image");
|
||||
ToolStripMenuItem closeItem = new ToolStripMenuItem(Language.GetString("editor_close"))
|
||||
{
|
||||
Image = GreenshotResources.getImage("Close.Image")
|
||||
};
|
||||
closeItem.Click += delegate {
|
||||
// This menu entry is the close itself, we can dispose the surface
|
||||
menu.Close();
|
||||
|
@ -314,7 +294,7 @@ namespace GreenshotPlugin.Core {
|
|||
basisMenuItem.Click -= destinationClickHandler;
|
||||
basisMenuItem.Click += destinationClickHandler;
|
||||
|
||||
if (isDynamic && addDynamics) {
|
||||
if (IsDynamic && addDynamics) {
|
||||
basisMenuItem.DropDownOpening += delegate
|
||||
{
|
||||
if (basisMenuItem.DropDownItems.Count == 0) {
|
||||
|
@ -323,21 +303,21 @@ namespace GreenshotPlugin.Core {
|
|||
try {
|
||||
subDestinations.AddRange(DynamicDestinations());
|
||||
} catch (Exception ex) {
|
||||
LOG.ErrorFormat("Skipping {0}, due to the following error: {1}", Description, ex.Message);
|
||||
Log.ErrorFormat("Skipping {0}, due to the following error: {1}", Description, ex.Message);
|
||||
}
|
||||
if (subDestinations.Count > 0) {
|
||||
ToolStripMenuItem destinationMenuItem = null;
|
||||
|
||||
if (useDynamicsOnly && subDestinations.Count == 1) {
|
||||
if (UseDynamicsOnly && subDestinations.Count == 1) {
|
||||
basisMenuItem.Tag = subDestinations[0];
|
||||
basisMenuItem.Text = subDestinations[0].Description;
|
||||
basisMenuItem.Click -= destinationClickHandler;
|
||||
basisMenuItem.Click += destinationClickHandler;
|
||||
} else {
|
||||
foreach (IDestination subDestination in subDestinations) {
|
||||
destinationMenuItem = new ToolStripMenuItem(subDestination.Description);
|
||||
destinationMenuItem.Tag = subDestination;
|
||||
destinationMenuItem.Image = subDestination.DisplayIcon;
|
||||
var destinationMenuItem = new ToolStripMenuItem(subDestination.Description)
|
||||
{
|
||||
Tag = subDestination,
|
||||
Image = subDestination.DisplayIcon
|
||||
};
|
||||
destinationMenuItem.Click += destinationClickHandler;
|
||||
AddTagEvents(destinationMenuItem, menu, subDestination.Description);
|
||||
basisMenuItem.DropDownItems.Add(destinationMenuItem);
|
||||
|
|
|
@ -33,11 +33,11 @@ namespace GreenshotPlugin.Core {
|
|||
/// Maybe move the basic Accessible functions to WindowDetails!?
|
||||
/// </summary>
|
||||
public class Accessible {
|
||||
private static ILog LOG = LogManager.GetLogger(typeof(Accessible));
|
||||
private static readonly ILog Log = LogManager.GetLogger(typeof(Accessible));
|
||||
|
||||
#region Interop
|
||||
private static int AccessibleObjectFromWindow(IntPtr hWnd, OBJID idObject, ref IAccessible acc) {
|
||||
Guid guid = new Guid("{618736e0-3c3d-11cf-810c-00aa00389b71}"); // IAccessible
|
||||
var guid = new Guid("{618736e0-3c3d-11cf-810c-00aa00389b71}"); // IAccessible
|
||||
object obj = null;
|
||||
int num = AccessibleObjectFromWindow(hWnd, (uint)idObject, ref guid, ref obj);
|
||||
acc = (IAccessible)obj;
|
||||
|
|
|
@ -30,11 +30,11 @@ namespace GreenshotPlugin.Core {
|
|||
/// <typeparam name="TK">Type of key</typeparam>
|
||||
/// <typeparam name="TV">Type of value</typeparam>
|
||||
public class Cache<TK, TV> {
|
||||
private static readonly ILog LOG = LogManager.GetLogger(typeof(Cache<TK, TV>));
|
||||
private readonly IDictionary<TK, TV> internalCache = new Dictionary<TK, TV>();
|
||||
private readonly object lockObject = new object();
|
||||
private readonly int secondsToExpire = 10;
|
||||
private readonly CacheObjectExpired expiredCallback;
|
||||
private static readonly ILog Log = LogManager.GetLogger(typeof(Cache<TK, TV>));
|
||||
private readonly IDictionary<TK, TV> _internalCache = new Dictionary<TK, TV>();
|
||||
private readonly object _lockObject = new object();
|
||||
private readonly int _secondsToExpire = 10;
|
||||
private readonly CacheObjectExpired _expiredCallback;
|
||||
public delegate void CacheObjectExpired(TK key, TV cacheValue);
|
||||
|
||||
/// <summary>
|
||||
|
@ -47,7 +47,7 @@ namespace GreenshotPlugin.Core {
|
|||
/// </summary>
|
||||
/// <param name="expiredCallback"></param>
|
||||
public Cache(CacheObjectExpired expiredCallback) : this() {
|
||||
this.expiredCallback = expiredCallback;
|
||||
_expiredCallback = expiredCallback;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
|
@ -55,7 +55,7 @@ namespace GreenshotPlugin.Core {
|
|||
/// </summary>
|
||||
/// <param name="secondsToExpire"></param>
|
||||
public Cache(int secondsToExpire) : this() {
|
||||
this.secondsToExpire = secondsToExpire;
|
||||
_secondsToExpire = secondsToExpire;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
|
@ -64,7 +64,7 @@ namespace GreenshotPlugin.Core {
|
|||
/// <param name="secondsToExpire"></param>
|
||||
/// <param name="expiredCallback"></param>
|
||||
public Cache(int secondsToExpire, CacheObjectExpired expiredCallback) : this(expiredCallback) {
|
||||
this.secondsToExpire = secondsToExpire;
|
||||
_secondsToExpire = secondsToExpire;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
|
@ -74,9 +74,9 @@ namespace GreenshotPlugin.Core {
|
|||
get {
|
||||
List<TV> elements = new List<TV>();
|
||||
|
||||
lock (lockObject)
|
||||
lock (_lockObject)
|
||||
{
|
||||
foreach (TV element in internalCache.Values) {
|
||||
foreach (TV element in _internalCache.Values) {
|
||||
elements.Add(element);
|
||||
}
|
||||
}
|
||||
|
@ -94,9 +94,9 @@ namespace GreenshotPlugin.Core {
|
|||
public TV this[TK key] {
|
||||
get {
|
||||
TV result = default(TV);
|
||||
lock (lockObject) {
|
||||
if (internalCache.ContainsKey(key)) {
|
||||
result = internalCache[key];
|
||||
lock (_lockObject) {
|
||||
if (_internalCache.ContainsKey(key)) {
|
||||
result = _internalCache[key];
|
||||
}
|
||||
}
|
||||
return result;
|
||||
|
@ -110,9 +110,9 @@ namespace GreenshotPlugin.Core {
|
|||
/// <returns>true if the cache contains the key</returns>
|
||||
public bool Contains(TK key)
|
||||
{
|
||||
lock (lockObject)
|
||||
lock (_lockObject)
|
||||
{
|
||||
return internalCache.ContainsKey(key);
|
||||
return _internalCache.ContainsKey(key);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -130,28 +130,26 @@ namespace GreenshotPlugin.Core {
|
|||
/// </summary>
|
||||
/// <param name="key"></param>
|
||||
/// <param name="value"></param>
|
||||
/// <param name="secondsToExpire?">optional value for the seconds to expire</param>
|
||||
/// <param name="secondsToExpire">optional value for the seconds to expire</param>
|
||||
public void Add(TK key, TV value, int? secondsToExpire) {
|
||||
lock (lockObject) {
|
||||
var cachedItem = new CachedItem(key, value, secondsToExpire.HasValue ? secondsToExpire.Value : this.secondsToExpire);
|
||||
lock (_lockObject) {
|
||||
var cachedItem = new CachedItem(key, value, secondsToExpire ?? _secondsToExpire);
|
||||
cachedItem.Expired += delegate(TK cacheKey, TV cacheValue) {
|
||||
if (internalCache.ContainsKey(cacheKey)) {
|
||||
LOG.DebugFormat("Expiring object with Key: {0}", cacheKey);
|
||||
if (expiredCallback != null) {
|
||||
expiredCallback(cacheKey, cacheValue);
|
||||
}
|
||||
if (_internalCache.ContainsKey(cacheKey)) {
|
||||
Log.DebugFormat("Expiring object with Key: {0}", cacheKey);
|
||||
_expiredCallback?.Invoke(cacheKey, cacheValue);
|
||||
Remove(cacheKey);
|
||||
} else {
|
||||
LOG.DebugFormat("Expired old object with Key: {0}", cacheKey);
|
||||
Log.DebugFormat("Expired old object with Key: {0}", cacheKey);
|
||||
}
|
||||
};
|
||||
|
||||
if (internalCache.ContainsKey(key)) {
|
||||
internalCache[key] = value;
|
||||
LOG.DebugFormat("Updated item with Key: {0}", key);
|
||||
if (_internalCache.ContainsKey(key)) {
|
||||
_internalCache[key] = value;
|
||||
Log.DebugFormat("Updated item with Key: {0}", key);
|
||||
} else {
|
||||
internalCache.Add(key, cachedItem);
|
||||
LOG.DebugFormat("Added item with Key: {0}", key);
|
||||
_internalCache.Add(key, cachedItem);
|
||||
Log.DebugFormat("Added item with Key: {0}", key);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -161,12 +159,12 @@ namespace GreenshotPlugin.Core {
|
|||
/// </summary>
|
||||
/// <param name="key"></param>
|
||||
public void Remove(TK key) {
|
||||
lock (lockObject) {
|
||||
if (!internalCache.ContainsKey(key)) {
|
||||
throw new ApplicationException(String.Format("An object with key ‘{0}’ does not exists in cache", key));
|
||||
lock (_lockObject) {
|
||||
if (!_internalCache.ContainsKey(key)) {
|
||||
throw new ApplicationException($"An object with key ‘{key}’ does not exists in cache");
|
||||
}
|
||||
internalCache.Remove(key);
|
||||
LOG.DebugFormat("Removed item with Key: {0}", key);
|
||||
_internalCache.Remove(key);
|
||||
Log.DebugFormat("Removed item with Key: {0}", key);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -175,27 +173,29 @@ namespace GreenshotPlugin.Core {
|
|||
/// </summary>
|
||||
private class CachedItem {
|
||||
public event CacheObjectExpired Expired;
|
||||
private readonly int secondsToExpire;
|
||||
private readonly int _secondsToExpire;
|
||||
private readonly Timer _timerEvent;
|
||||
|
||||
public CachedItem(TK key, TV item, int secondsToExpire) {
|
||||
if (key == null) {
|
||||
throw new ArgumentNullException("key is not valid");
|
||||
throw new ArgumentNullException(nameof(key));
|
||||
}
|
||||
Key = key;
|
||||
Item = item;
|
||||
this.secondsToExpire = secondsToExpire;
|
||||
if (secondsToExpire > 0) {
|
||||
_timerEvent = new Timer(secondsToExpire * 1000) { AutoReset = false };
|
||||
_timerEvent.Elapsed += timerEvent_Elapsed;
|
||||
_timerEvent.Start();
|
||||
_secondsToExpire = secondsToExpire;
|
||||
if (secondsToExpire <= 0)
|
||||
{
|
||||
return;
|
||||
}
|
||||
_timerEvent = new Timer(secondsToExpire * 1000) { AutoReset = false };
|
||||
_timerEvent.Elapsed += timerEvent_Elapsed;
|
||||
_timerEvent.Start();
|
||||
}
|
||||
|
||||
private void ExpireNow() {
|
||||
_timerEvent.Stop();
|
||||
if (secondsToExpire > 0 && Expired != null) {
|
||||
Expired(Key, Item);
|
||||
if (_secondsToExpire > 0) {
|
||||
Expired?.Invoke(Key, Item);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -352,7 +352,7 @@ EndSelection:<<<<<<<4
|
|||
retrieveFormats = new[] { FORMAT_PNG_OFFICEART, FORMAT_PNG, FORMAT_17, FORMAT_JFIF_OFFICEART, FORMAT_JPG, FORMAT_JFIF, DataFormats.Tiff, DataFormats.Dib, FORMAT_BITMAP, FORMAT_FILECONTENTS, FORMAT_GIF };
|
||||
}
|
||||
foreach (string currentFormat in retrieveFormats) {
|
||||
if (formats.Contains(currentFormat)) {
|
||||
if (formats != null && formats.Contains(currentFormat)) {
|
||||
Log.InfoFormat("Found {0}, trying to retrieve.", currentFormat);
|
||||
returnImage = GetImageForFormat(currentFormat, dataObject);
|
||||
} else {
|
||||
|
@ -385,54 +385,57 @@ EndSelection:<<<<<<<4
|
|||
if (format == FORMAT_17 || format == DataFormats.Dib) {
|
||||
Log.Info("Found DIB stream, trying to process it.");
|
||||
try {
|
||||
byte[] dibBuffer = new byte[imageStream.Length];
|
||||
imageStream.Read(dibBuffer, 0, dibBuffer.Length);
|
||||
BITMAPINFOHEADER infoHeader = BinaryStructHelper.FromByteArray<BITMAPINFOHEADER>(dibBuffer);
|
||||
if (!infoHeader.IsDibV5) {
|
||||
Log.InfoFormat("Using special DIB <v5 format reader with biCompression {0}", infoHeader.biCompression);
|
||||
int fileHeaderSize = Marshal.SizeOf(typeof(BITMAPFILEHEADER));
|
||||
uint infoHeaderSize = infoHeader.biSize;
|
||||
int fileSize = (int)(fileHeaderSize + infoHeader.biSize + infoHeader.biSizeImage);
|
||||
if (imageStream != null)
|
||||
{
|
||||
byte[] dibBuffer = new byte[imageStream.Length];
|
||||
imageStream.Read(dibBuffer, 0, dibBuffer.Length);
|
||||
BITMAPINFOHEADER infoHeader = BinaryStructHelper.FromByteArray<BITMAPINFOHEADER>(dibBuffer);
|
||||
if (!infoHeader.IsDibV5) {
|
||||
Log.InfoFormat("Using special DIB <v5 format reader with biCompression {0}", infoHeader.biCompression);
|
||||
int fileHeaderSize = Marshal.SizeOf(typeof(BITMAPFILEHEADER));
|
||||
uint infoHeaderSize = infoHeader.biSize;
|
||||
int fileSize = (int)(fileHeaderSize + infoHeader.biSize + infoHeader.biSizeImage);
|
||||
|
||||
BITMAPFILEHEADER fileHeader = new BITMAPFILEHEADER
|
||||
{
|
||||
bfType = BITMAPFILEHEADER.BM,
|
||||
bfSize = fileSize,
|
||||
bfReserved1 = 0,
|
||||
bfReserved2 = 0,
|
||||
bfOffBits = (int) (fileHeaderSize + infoHeaderSize + infoHeader.biClrUsed*4)
|
||||
};
|
||||
|
||||
byte[] fileHeaderBytes = BinaryStructHelper.ToByteArray(fileHeader);
|
||||
|
||||
using (MemoryStream bitmapStream = new MemoryStream()) {
|
||||
bitmapStream.Write(fileHeaderBytes, 0, fileHeaderSize);
|
||||
bitmapStream.Write(dibBuffer, 0, dibBuffer.Length);
|
||||
bitmapStream.Seek(0, SeekOrigin.Begin);
|
||||
var image = ImageHelper.FromStream(bitmapStream);
|
||||
if (image != null)
|
||||
BITMAPFILEHEADER fileHeader = new BITMAPFILEHEADER
|
||||
{
|
||||
return image;
|
||||
bfType = BITMAPFILEHEADER.BM,
|
||||
bfSize = fileSize,
|
||||
bfReserved1 = 0,
|
||||
bfReserved2 = 0,
|
||||
bfOffBits = (int) (fileHeaderSize + infoHeaderSize + infoHeader.biClrUsed*4)
|
||||
};
|
||||
|
||||
byte[] fileHeaderBytes = BinaryStructHelper.ToByteArray(fileHeader);
|
||||
|
||||
using (MemoryStream bitmapStream = new MemoryStream()) {
|
||||
bitmapStream.Write(fileHeaderBytes, 0, fileHeaderSize);
|
||||
bitmapStream.Write(dibBuffer, 0, dibBuffer.Length);
|
||||
bitmapStream.Seek(0, SeekOrigin.Begin);
|
||||
var image = ImageHelper.FromStream(bitmapStream);
|
||||
if (image != null)
|
||||
{
|
||||
return image;
|
||||
}
|
||||
}
|
||||
}
|
||||
} else {
|
||||
Log.Info("Using special DIBV5 / Format17 format reader");
|
||||
// CF_DIBV5
|
||||
IntPtr gcHandle = IntPtr.Zero;
|
||||
try {
|
||||
GCHandle handle = GCHandle.Alloc(dibBuffer, GCHandleType.Pinned);
|
||||
gcHandle = GCHandle.ToIntPtr(handle);
|
||||
return
|
||||
new Bitmap(infoHeader.biWidth, infoHeader.biHeight,
|
||||
-(int)(infoHeader.biSizeImage / infoHeader.biHeight),
|
||||
infoHeader.biBitCount == 32?PixelFormat.Format32bppArgb: PixelFormat.Format24bppRgb,
|
||||
new IntPtr(handle.AddrOfPinnedObject().ToInt32() + infoHeader.OffsetToPixels + (infoHeader.biHeight - 1) * (int)(infoHeader.biSizeImage / infoHeader.biHeight))
|
||||
);
|
||||
} catch (Exception ex) {
|
||||
Log.Error("Problem retrieving Format17 from clipboard.", ex);
|
||||
} finally {
|
||||
if (gcHandle == IntPtr.Zero) {
|
||||
GCHandle.FromIntPtr(gcHandle).Free();
|
||||
} else {
|
||||
Log.Info("Using special DIBV5 / Format17 format reader");
|
||||
// CF_DIBV5
|
||||
IntPtr gcHandle = IntPtr.Zero;
|
||||
try {
|
||||
GCHandle handle = GCHandle.Alloc(dibBuffer, GCHandleType.Pinned);
|
||||
gcHandle = GCHandle.ToIntPtr(handle);
|
||||
return
|
||||
new Bitmap(infoHeader.biWidth, infoHeader.biHeight,
|
||||
-(int)(infoHeader.biSizeImage / infoHeader.biHeight),
|
||||
infoHeader.biBitCount == 32?PixelFormat.Format32bppArgb: PixelFormat.Format24bppRgb,
|
||||
new IntPtr(handle.AddrOfPinnedObject().ToInt32() + infoHeader.OffsetToPixels + (infoHeader.biHeight - 1) * (int)(infoHeader.biSizeImage / infoHeader.biHeight))
|
||||
);
|
||||
} catch (Exception ex) {
|
||||
Log.Error("Problem retrieving Format17 from clipboard.", ex);
|
||||
} finally {
|
||||
if (gcHandle == IntPtr.Zero) {
|
||||
GCHandle.FromIntPtr(gcHandle).Free();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -454,7 +457,7 @@ EndSelection:<<<<<<<4
|
|||
}
|
||||
}
|
||||
} catch (Exception streamImageEx) {
|
||||
Log.Error(string.Format("Problem retrieving {0} from clipboard.", format), streamImageEx);
|
||||
Log.Error($"Problem retrieving {format} from clipboard.", streamImageEx);
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
@ -495,10 +498,10 @@ EndSelection:<<<<<<<4
|
|||
utf8EncodedHtmlString= utf8EncodedHtmlString.Replace("${file}", filename.Replace("\\","/"));
|
||||
StringBuilder sb=new StringBuilder();
|
||||
sb.Append(utf8EncodedHtmlString);
|
||||
sb.Replace("<<<<<<<1", (utf8EncodedHtmlString.IndexOf("<HTML>") + "<HTML>".Length).ToString("D8"));
|
||||
sb.Replace("<<<<<<<2", (utf8EncodedHtmlString.IndexOf("</HTML>")).ToString("D8"));
|
||||
sb.Replace("<<<<<<<3", (utf8EncodedHtmlString.IndexOf("<!--StartFragment -->")+"<!--StartFragment -->".Length).ToString("D8"));
|
||||
sb.Replace("<<<<<<<4", (utf8EncodedHtmlString.IndexOf("<!--EndFragment -->")).ToString("D8"));
|
||||
sb.Replace("<<<<<<<1", (utf8EncodedHtmlString.IndexOf("<HTML>", StringComparison.Ordinal) + "<HTML>".Length).ToString("D8"));
|
||||
sb.Replace("<<<<<<<2", (utf8EncodedHtmlString.IndexOf("</HTML>", StringComparison.Ordinal)).ToString("D8"));
|
||||
sb.Replace("<<<<<<<3", (utf8EncodedHtmlString.IndexOf("<!--StartFragment -->", StringComparison.Ordinal)+"<!--StartFragment -->".Length).ToString("D8"));
|
||||
sb.Replace("<<<<<<<4", (utf8EncodedHtmlString.IndexOf("<!--EndFragment -->", StringComparison.Ordinal)).ToString("D8"));
|
||||
return sb.ToString();
|
||||
}
|
||||
|
||||
|
@ -510,13 +513,14 @@ EndSelection:<<<<<<<4
|
|||
utf8EncodedHtmlString = utf8EncodedHtmlString.Replace("${data}", Convert.ToBase64String(pngStream.GetBuffer(),0, (int)pngStream.Length));
|
||||
StringBuilder sb=new StringBuilder();
|
||||
sb.Append(utf8EncodedHtmlString);
|
||||
sb.Replace("<<<<<<<1", (utf8EncodedHtmlString.IndexOf("<HTML>") + "<HTML>".Length).ToString("D8"));
|
||||
sb.Replace("<<<<<<<2", (utf8EncodedHtmlString.IndexOf("</HTML>")).ToString("D8"));
|
||||
sb.Replace("<<<<<<<3", (utf8EncodedHtmlString.IndexOf("<!--StartFragment -->")+"<!--StartFragment -->".Length).ToString("D8"));
|
||||
sb.Replace("<<<<<<<4", (utf8EncodedHtmlString.IndexOf("<!--EndFragment -->")).ToString("D8"));
|
||||
sb.Replace("<<<<<<<1", (utf8EncodedHtmlString.IndexOf("<HTML>", StringComparison.Ordinal) + "<HTML>".Length).ToString("D8"));
|
||||
sb.Replace("<<<<<<<2", (utf8EncodedHtmlString.IndexOf("</HTML>", StringComparison.Ordinal)).ToString("D8"));
|
||||
sb.Replace("<<<<<<<3", (utf8EncodedHtmlString.IndexOf("<!--StartFragment -->", StringComparison.Ordinal)+"<!--StartFragment -->".Length).ToString("D8"));
|
||||
sb.Replace("<<<<<<<4", (utf8EncodedHtmlString.IndexOf("<!--EndFragment -->", StringComparison.Ordinal)).ToString("D8"));
|
||||
return sb.ToString();
|
||||
}
|
||||
|
||||
private const int BITMAPFILEHEADER_LENGTH = 14;
|
||||
/// <summary>
|
||||
/// Set an Image to the clipboard
|
||||
/// This method will place images to the clipboard depending on the ClipboardFormats setting.
|
||||
|
@ -526,7 +530,6 @@ EndSelection:<<<<<<<4
|
|||
/// When pasting a Dib in PP 2003 the Bitmap is somehow shifted left!
|
||||
/// For this problem the user should not use the direct paste (=Dib), but select Bitmap
|
||||
/// </summary>
|
||||
private const int BITMAPFILEHEADER_LENGTH = 14;
|
||||
public static void SetClipboardData(ISurface surface) {
|
||||
DataObject dataObject = new DataObject();
|
||||
|
||||
|
@ -553,8 +556,8 @@ EndSelection:<<<<<<<4
|
|||
// Set the PNG stream
|
||||
dataObject.SetData(FORMAT_PNG, false, pngStream);
|
||||
}
|
||||
} catch (Exception pngEX) {
|
||||
Log.Error("Error creating PNG for the Clipboard.", pngEX);
|
||||
} catch (Exception pngEx) {
|
||||
Log.Error("Error creating PNG for the Clipboard.", pngEx);
|
||||
}
|
||||
|
||||
try {
|
||||
|
@ -650,20 +653,10 @@ EndSelection:<<<<<<<4
|
|||
// Place the DataObject to the clipboard
|
||||
SetDataObject(dataObject, true);
|
||||
}
|
||||
|
||||
if (pngStream != null) {
|
||||
pngStream.Dispose();
|
||||
pngStream = null;
|
||||
}
|
||||
|
||||
if (dibStream != null) {
|
||||
dibStream.Dispose();
|
||||
dibStream = null;
|
||||
}
|
||||
if (dibV5Stream != null) {
|
||||
dibV5Stream.Dispose();
|
||||
dibV5Stream = null;
|
||||
}
|
||||
pngStream?.Dispose();
|
||||
dibStream?.Dispose();
|
||||
dibV5Stream?.Dispose();
|
||||
// cleanup if needed
|
||||
if (disposeImage) {
|
||||
imageToSave?.Dispose();
|
||||
|
|
|
@ -287,9 +287,7 @@ namespace GreenshotPlugin.Core {
|
|||
}
|
||||
if (_iconSize != newSize) {
|
||||
_iconSize = value;
|
||||
if (PropertyChanged != null) {
|
||||
PropertyChanged(this, new PropertyChangedEventArgs("IconSize"));
|
||||
}
|
||||
PropertyChanged?.Invoke(this, new PropertyChangedEventArgs("IconSize"));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -317,18 +315,14 @@ namespace GreenshotPlugin.Core {
|
|||
}
|
||||
}
|
||||
|
||||
public bool UseLargeIcons {
|
||||
get {
|
||||
return IconSize.Width >= 32 || IconSize.Height >= 32;
|
||||
}
|
||||
}
|
||||
public bool UseLargeIcons => IconSize.Width >= 32 || IconSize.Height >= 32;
|
||||
|
||||
/// <summary>
|
||||
/// A helper method which returns true if the supplied experimental feature is enabled
|
||||
/// </summary>
|
||||
/// <param name="experimentalFeature"></param>
|
||||
/// <returns></returns>
|
||||
public bool isExperimentalFeatureEnabled(string experimentalFeature) {
|
||||
public bool IsExperimentalFeatureEnabled(string experimentalFeature) {
|
||||
return (ExperimentalFeatures != null && ExperimentalFeatures.Contains(experimentalFeature));
|
||||
}
|
||||
|
||||
|
@ -367,23 +361,11 @@ namespace GreenshotPlugin.Core {
|
|||
case "DWMBackgroundColor":
|
||||
return Color.Transparent;
|
||||
case "ActiveTitleFixes":
|
||||
List<string> activeDefaults = new List<string>();
|
||||
activeDefaults.Add("Firefox");
|
||||
activeDefaults.Add("IE");
|
||||
activeDefaults.Add("Chrome");
|
||||
return activeDefaults;
|
||||
return new List<string> {"Firefox", "IE", "Chrome"};
|
||||
case "TitleFixMatcher":
|
||||
Dictionary<string, string> matcherDefaults = new Dictionary<string, string>();
|
||||
matcherDefaults.Add("Firefox", " - Mozilla Firefox.*");
|
||||
matcherDefaults.Add("IE", " - (Microsoft|Windows) Internet Explorer.*");
|
||||
matcherDefaults.Add("Chrome", " - Google Chrome.*");
|
||||
return matcherDefaults;
|
||||
return new Dictionary<string, string> {{"Firefox", " - Mozilla Firefox.*"}, {"IE", " - (Microsoft|Windows) Internet Explorer.*"}, {"Chrome", " - Google Chrome.*"}};
|
||||
case "TitleFixReplacer":
|
||||
Dictionary<string, string> replacerDefaults = new Dictionary<string, string>();
|
||||
replacerDefaults.Add("Firefox", "");
|
||||
replacerDefaults.Add("IE", "");
|
||||
replacerDefaults.Add("Chrome", "");
|
||||
return replacerDefaults;
|
||||
return new Dictionary<string, string> {{"Firefox", ""}, {"IE", ""}, {"Chrome", ""}};
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
@ -417,7 +399,10 @@ namespace GreenshotPlugin.Core {
|
|||
try {
|
||||
// Store version, this can be used later to fix settings after an update
|
||||
LastSaveWithVersion = Assembly.GetEntryAssembly().GetName().Version.ToString();
|
||||
} catch {
|
||||
}
|
||||
catch
|
||||
{
|
||||
// ignored
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -432,8 +417,10 @@ namespace GreenshotPlugin.Core {
|
|||
try {
|
||||
// Store version, this can be used later to fix settings after an update
|
||||
LastSaveWithVersion = Assembly.GetEntryAssembly().GetName().Version.ToString();
|
||||
} catch {
|
||||
|
||||
}
|
||||
catch
|
||||
{
|
||||
// ignored
|
||||
}
|
||||
// Disable the AutoReduceColors as it causes issues with Mozzila applications and some others
|
||||
OutputFileAutoReduceColors = false;
|
||||
|
@ -465,10 +452,7 @@ namespace GreenshotPlugin.Core {
|
|||
|
||||
// Make sure we have clipboard formats, otherwise a paste doesn't make sense!
|
||||
if (ClipboardFormats == null || ClipboardFormats.Count == 0) {
|
||||
ClipboardFormats = new List<ClipboardFormat>();
|
||||
ClipboardFormats.Add(ClipboardFormat.PNG);
|
||||
ClipboardFormats.Add(ClipboardFormat.HTML);
|
||||
ClipboardFormats.Add(ClipboardFormat.DIB);
|
||||
ClipboardFormats = new List<ClipboardFormat> {ClipboardFormat.PNG, ClipboardFormat.HTML, ClipboardFormat.DIB};
|
||||
}
|
||||
|
||||
// Make sure the lists are lowercase, to speedup the check
|
||||
|
|
|
@ -114,7 +114,7 @@ namespace GreenshotPlugin.Core {
|
|||
/// <summary>Gets or sets if the credentials are to be persisted in the credential manager.</summary>
|
||||
public bool Persist { get; set; } = true;
|
||||
|
||||
/// <summary>Gets or sets if the incorrect password balloontip needs to be shown. Introduced AFTER Windows XP</summary>Gets></summary>
|
||||
/// <summary>Gets or sets if the incorrect password balloontip needs to be shown. Introduced AFTER Windows XP</summary>
|
||||
public bool IncorrectPassword { get; set; }
|
||||
|
||||
/// <summary>Gets or sets if the name is read-only.</summary>
|
||||
|
@ -127,14 +127,12 @@ namespace GreenshotPlugin.Core {
|
|||
return _name;
|
||||
}
|
||||
set {
|
||||
if (value != null) {
|
||||
if (value.Length > CREDUI.MAX_USERNAME_LENGTH) {
|
||||
string message = string.Format(
|
||||
Thread.CurrentThread.CurrentUICulture,
|
||||
"The name has a maximum length of {0} characters.",
|
||||
CREDUI.MAX_USERNAME_LENGTH);
|
||||
throw new ArgumentException(message, nameof(Name));
|
||||
}
|
||||
if (value?.Length > CredUi.MAX_USERNAME_LENGTH) {
|
||||
string message = string.Format(
|
||||
Thread.CurrentThread.CurrentUICulture,
|
||||
"The name has a maximum length of {0} characters.",
|
||||
CredUi.MAX_USERNAME_LENGTH);
|
||||
throw new ArgumentException(message, nameof(Name));
|
||||
}
|
||||
_name = value;
|
||||
}
|
||||
|
@ -147,14 +145,12 @@ namespace GreenshotPlugin.Core {
|
|||
return _password;
|
||||
}
|
||||
set {
|
||||
if (value != null) {
|
||||
if (value.Length > CREDUI.MAX_PASSWORD_LENGTH) {
|
||||
string message = string.Format(
|
||||
Thread.CurrentThread.CurrentUICulture,
|
||||
"The password has a maximum length of {0} characters.",
|
||||
CREDUI.MAX_PASSWORD_LENGTH);
|
||||
throw new ArgumentException(message, nameof(Password));
|
||||
}
|
||||
if (value?.Length > CredUi.MAX_PASSWORD_LENGTH) {
|
||||
string message = string.Format(
|
||||
Thread.CurrentThread.CurrentUICulture,
|
||||
"The password has a maximum length of {0} characters.",
|
||||
CredUi.MAX_PASSWORD_LENGTH);
|
||||
throw new ArgumentException(message, nameof(Password));
|
||||
}
|
||||
_password = value;
|
||||
}
|
||||
|
@ -175,13 +171,13 @@ namespace GreenshotPlugin.Core {
|
|||
}
|
||||
set {
|
||||
if (value == null) {
|
||||
throw new ArgumentException("The target cannot be a null value.", "Target");
|
||||
throw new ArgumentException("The target cannot be a null value.", nameof(Target));
|
||||
}
|
||||
if (value.Length > CREDUI.MAX_GENERIC_TARGET_LENGTH) {
|
||||
if (value.Length > CredUi.MAX_GENERIC_TARGET_LENGTH) {
|
||||
string message = string.Format(
|
||||
Thread.CurrentThread.CurrentUICulture,
|
||||
"The target has a maximum length of {0} characters.",
|
||||
CREDUI.MAX_GENERIC_TARGET_LENGTH);
|
||||
CredUi.MAX_GENERIC_TARGET_LENGTH);
|
||||
throw new ArgumentException(message, nameof(Target));
|
||||
}
|
||||
_target = value;
|
||||
|
@ -196,14 +192,12 @@ namespace GreenshotPlugin.Core {
|
|||
return _caption;
|
||||
}
|
||||
set {
|
||||
if (value != null) {
|
||||
if (value.Length > CREDUI.MAX_CAPTION_LENGTH) {
|
||||
string message = string.Format(
|
||||
Thread.CurrentThread.CurrentUICulture,
|
||||
"The caption has a maximum length of {0} characters.",
|
||||
CREDUI.MAX_CAPTION_LENGTH);
|
||||
throw new ArgumentException(message, nameof(Caption));
|
||||
}
|
||||
if (value?.Length > CredUi.MAX_CAPTION_LENGTH) {
|
||||
string message = string.Format(
|
||||
Thread.CurrentThread.CurrentUICulture,
|
||||
"The caption has a maximum length of {0} characters.",
|
||||
CredUi.MAX_CAPTION_LENGTH);
|
||||
throw new ArgumentException(message, nameof(Caption));
|
||||
}
|
||||
_caption = value;
|
||||
}
|
||||
|
@ -217,14 +211,12 @@ namespace GreenshotPlugin.Core {
|
|||
return _message;
|
||||
}
|
||||
set {
|
||||
if (value != null) {
|
||||
if (value.Length > CREDUI.MAX_MESSAGE_LENGTH) {
|
||||
string message = string.Format(
|
||||
Thread.CurrentThread.CurrentUICulture,
|
||||
"The message has a maximum length of {0} characters.",
|
||||
CREDUI.MAX_MESSAGE_LENGTH);
|
||||
throw new ArgumentException(message, nameof(Message));
|
||||
}
|
||||
if (value?.Length > CredUi.MAX_MESSAGE_LENGTH) {
|
||||
string message = string.Format(
|
||||
Thread.CurrentThread.CurrentUICulture,
|
||||
"The message has a maximum length of {0} characters.",
|
||||
CredUi.MAX_MESSAGE_LENGTH);
|
||||
throw new ArgumentException(message, nameof(Message));
|
||||
}
|
||||
_message = value;
|
||||
}
|
||||
|
@ -331,11 +323,11 @@ namespace GreenshotPlugin.Core {
|
|||
/// <summary>Confirmation action to be applied.</summary>
|
||||
/// <param name="value">True if the credentials should be persisted.</param>
|
||||
public void Confirm(bool value) {
|
||||
switch (CREDUI.CredUIConfirmCredentials(Target, value)) {
|
||||
case CREDUI.ReturnCodes.NO_ERROR:
|
||||
switch (CredUi.CredUIConfirmCredentials(Target, value)) {
|
||||
case CredUi.ReturnCodes.NO_ERROR:
|
||||
break;
|
||||
|
||||
case CREDUI.ReturnCodes.ERROR_INVALID_PARAMETER:
|
||||
case CredUi.ReturnCodes.ERROR_INVALID_PARAMETER:
|
||||
// for some reason, this is encountered when credentials are overwritten
|
||||
break;
|
||||
|
||||
|
@ -351,26 +343,26 @@ namespace GreenshotPlugin.Core {
|
|||
/// </remarks>
|
||||
private DialogResult ShowDialog(IWin32Window owner) {
|
||||
// set the api call parameters
|
||||
StringBuilder name = new StringBuilder(CREDUI.MAX_USERNAME_LENGTH);
|
||||
StringBuilder name = new StringBuilder(CredUi.MAX_USERNAME_LENGTH);
|
||||
name.Append(Name);
|
||||
|
||||
StringBuilder password = new StringBuilder(CREDUI.MAX_PASSWORD_LENGTH);
|
||||
StringBuilder password = new StringBuilder(CredUi.MAX_PASSWORD_LENGTH);
|
||||
password.Append(Password);
|
||||
|
||||
int saveChecked = Convert.ToInt32(SaveChecked);
|
||||
|
||||
CREDUI.INFO info = GetInfo(owner);
|
||||
CREDUI.FLAGS flags = GetFlags();
|
||||
CredUi.INFO info = GetInfo(owner);
|
||||
CredUi.CredFlags credFlags = GetFlags();
|
||||
|
||||
// make the api call
|
||||
CREDUI.ReturnCodes code = CREDUI.CredUIPromptForCredentials(
|
||||
CredUi.ReturnCodes code = CredUi.CredUIPromptForCredentials(
|
||||
ref info,
|
||||
Target,
|
||||
IntPtr.Zero, 0,
|
||||
name, CREDUI.MAX_USERNAME_LENGTH,
|
||||
password, CREDUI.MAX_PASSWORD_LENGTH,
|
||||
name, CredUi.MAX_USERNAME_LENGTH,
|
||||
password, CredUi.MAX_PASSWORD_LENGTH,
|
||||
ref saveChecked,
|
||||
flags
|
||||
credFlags
|
||||
);
|
||||
|
||||
// clean up resources
|
||||
|
@ -388,8 +380,8 @@ namespace GreenshotPlugin.Core {
|
|||
|
||||
/// <summary>Returns the info structure for dialog display settings.</summary>
|
||||
/// <param name="owner">The System.Windows.Forms.IWin32Window the dialog will display in front of.</param>
|
||||
private CREDUI.INFO GetInfo(IWin32Window owner) {
|
||||
CREDUI.INFO info = new CREDUI.INFO();
|
||||
private CredUi.INFO GetInfo(IWin32Window owner) {
|
||||
CredUi.INFO info = new CredUi.INFO();
|
||||
if (owner != null) info.hwndParent = owner.Handle;
|
||||
info.pszCaptionText = Caption;
|
||||
info.pszMessageText = Message;
|
||||
|
@ -401,61 +393,61 @@ namespace GreenshotPlugin.Core {
|
|||
}
|
||||
|
||||
/// <summary>Returns the flags for dialog display options.</summary>
|
||||
private CREDUI.FLAGS GetFlags() {
|
||||
CREDUI.FLAGS flags = CREDUI.FLAGS.GENERIC_CREDENTIALS;
|
||||
private CredUi.CredFlags GetFlags() {
|
||||
CredUi.CredFlags credFlags = CredUi.CredFlags.GENERIC_CREDENTIALS;
|
||||
|
||||
if (IncorrectPassword) {
|
||||
flags = flags | CREDUI.FLAGS.INCORRECT_PASSWORD;
|
||||
credFlags = credFlags | CredUi.CredFlags.INCORRECT_PASSWORD;
|
||||
}
|
||||
|
||||
if (AlwaysDisplay) {
|
||||
flags = flags | CREDUI.FLAGS.ALWAYS_SHOW_UI;
|
||||
credFlags = credFlags | CredUi.CredFlags.ALWAYS_SHOW_UI;
|
||||
}
|
||||
|
||||
if (ExcludeCertificates) {
|
||||
flags = flags | CREDUI.FLAGS.EXCLUDE_CERTIFICATES;
|
||||
credFlags = credFlags | CredUi.CredFlags.EXCLUDE_CERTIFICATES;
|
||||
}
|
||||
|
||||
if (Persist) {
|
||||
flags = flags | CREDUI.FLAGS.EXPECT_CONFIRMATION;
|
||||
credFlags = credFlags | CredUi.CredFlags.EXPECT_CONFIRMATION;
|
||||
if (SaveDisplayed) {
|
||||
flags = flags | CREDUI.FLAGS.SHOW_SAVE_CHECK_BOX;
|
||||
credFlags = credFlags | CredUi.CredFlags.SHOW_SAVE_CHECK_BOX;
|
||||
} else {
|
||||
flags = flags | CREDUI.FLAGS.PERSIST;
|
||||
credFlags = credFlags | CredUi.CredFlags.PERSIST;
|
||||
}
|
||||
} else {
|
||||
flags = flags | CREDUI.FLAGS.DO_NOT_PERSIST;
|
||||
credFlags = credFlags | CredUi.CredFlags.DO_NOT_PERSIST;
|
||||
}
|
||||
|
||||
if (KeepName) {
|
||||
flags = flags | CREDUI.FLAGS.KEEP_USERNAME;
|
||||
credFlags = credFlags | CredUi.CredFlags.KEEP_USERNAME;
|
||||
}
|
||||
|
||||
return flags;
|
||||
return credFlags;
|
||||
}
|
||||
|
||||
/// <summary>Returns a DialogResult from the specified code.</summary>
|
||||
/// <param name="code">The credential return code.</param>
|
||||
private DialogResult GetDialogResult(CREDUI.ReturnCodes code) {
|
||||
private DialogResult GetDialogResult(CredUi.ReturnCodes code) {
|
||||
DialogResult result;
|
||||
switch (code) {
|
||||
case CREDUI.ReturnCodes.NO_ERROR:
|
||||
case CredUi.ReturnCodes.NO_ERROR:
|
||||
result = DialogResult.OK;
|
||||
break;
|
||||
case CREDUI.ReturnCodes.ERROR_CANCELLED:
|
||||
case CredUi.ReturnCodes.ERROR_CANCELLED:
|
||||
result = DialogResult.Cancel;
|
||||
break;
|
||||
case CREDUI.ReturnCodes.ERROR_NO_SUCH_LOGON_SESSION:
|
||||
case CredUi.ReturnCodes.ERROR_NO_SUCH_LOGON_SESSION:
|
||||
throw new ApplicationException("No such logon session.");
|
||||
case CREDUI.ReturnCodes.ERROR_NOT_FOUND:
|
||||
case CredUi.ReturnCodes.ERROR_NOT_FOUND:
|
||||
throw new ApplicationException("Not found.");
|
||||
case CREDUI.ReturnCodes.ERROR_INVALID_ACCOUNT_NAME:
|
||||
case CredUi.ReturnCodes.ERROR_INVALID_ACCOUNT_NAME:
|
||||
throw new ApplicationException("Invalid account name.");
|
||||
case CREDUI.ReturnCodes.ERROR_INSUFFICIENT_BUFFER:
|
||||
case CredUi.ReturnCodes.ERROR_INSUFFICIENT_BUFFER:
|
||||
throw new ApplicationException("Insufficient buffer.");
|
||||
case CREDUI.ReturnCodes.ERROR_INVALID_PARAMETER:
|
||||
case CredUi.ReturnCodes.ERROR_INVALID_PARAMETER:
|
||||
throw new ApplicationException("Invalid parameter.");
|
||||
case CREDUI.ReturnCodes.ERROR_INVALID_FLAGS:
|
||||
case CredUi.ReturnCodes.ERROR_INVALID_FLAGS:
|
||||
throw new ApplicationException("Invalid flags.");
|
||||
default:
|
||||
throw new ApplicationException("Unknown credential result encountered.");
|
||||
|
@ -464,10 +456,7 @@ namespace GreenshotPlugin.Core {
|
|||
}
|
||||
}
|
||||
|
||||
internal sealed class CREDUI {
|
||||
private CREDUI() {
|
||||
}
|
||||
|
||||
internal static class CredUi {
|
||||
/// <summary>http://msdn.microsoft.com/library/default.asp?url=/library/en-us/secauthn/security/authentication_constants.asp</summary>
|
||||
public const int MAX_MESSAGE_LENGTH = 100;
|
||||
public const int MAX_CAPTION_LENGTH = 100;
|
||||
|
@ -481,7 +470,8 @@ namespace GreenshotPlugin.Core {
|
|||
/// http://msdn.microsoft.com/library/default.asp?url=/library/en-us/dnnetsec/html/dpapiusercredentials.asp
|
||||
/// http://msdn.microsoft.com/library/default.asp?url=/library/en-us/secauthn/security/creduipromptforcredentials.asp
|
||||
/// </summary>
|
||||
[Flags] public enum FLAGS {
|
||||
[Flags]
|
||||
public enum CredFlags {
|
||||
INCORRECT_PASSWORD = 0x1,
|
||||
DO_NOT_PERSIST = 0x2,
|
||||
REQUEST_ADMINISTRATOR = 0x4,
|
||||
|
@ -540,7 +530,7 @@ namespace GreenshotPlugin.Core {
|
|||
StringBuilder password,
|
||||
int maxPassword,
|
||||
ref int iSave,
|
||||
FLAGS flags
|
||||
CredFlags credFlags
|
||||
);
|
||||
|
||||
/// <summary>
|
||||
|
|
|
@ -23,13 +23,10 @@ using System;
|
|||
namespace GreenshotPlugin.Core {
|
||||
[AttributeUsage(AttributeTargets.Field)]
|
||||
public sealed class DisplayKeyAttribute : Attribute {
|
||||
private readonly string value;
|
||||
public string Value {
|
||||
get { return value; }
|
||||
}
|
||||
|
||||
public string Value { get; }
|
||||
|
||||
public DisplayKeyAttribute(string v) {
|
||||
value = v;
|
||||
Value = v;
|
||||
}
|
||||
|
||||
public DisplayKeyAttribute() {
|
||||
|
|
180
GreenshotPlugin/Core/EffectConverter.cs
Normal file
180
GreenshotPlugin/Core/EffectConverter.cs
Normal file
|
@ -0,0 +1,180 @@
|
|||
using System;
|
||||
using System.ComponentModel;
|
||||
using System.Drawing;
|
||||
using System.Globalization;
|
||||
using System.Text;
|
||||
using GreenshotPlugin.Effects;
|
||||
|
||||
namespace Greenshot.Core
|
||||
{
|
||||
public class EffectConverter : TypeConverter {
|
||||
// Fix to prevent BUG-1753
|
||||
private readonly NumberFormatInfo _numberFormatInfo = new NumberFormatInfo();
|
||||
|
||||
public EffectConverter()
|
||||
{
|
||||
_numberFormatInfo.NumberDecimalSeparator = ".";
|
||||
_numberFormatInfo.NumberGroupSeparator = ",";
|
||||
}
|
||||
|
||||
public override bool CanConvertFrom(ITypeDescriptorContext context, Type sourceType) {
|
||||
if (sourceType == typeof(string)) {
|
||||
return true;
|
||||
}
|
||||
return base.CanConvertFrom(context, sourceType);
|
||||
}
|
||||
|
||||
public override bool CanConvertTo(ITypeDescriptorContext context, Type destinationType) {
|
||||
if (destinationType == typeof(string)) {
|
||||
return true;
|
||||
}
|
||||
if (destinationType == typeof(DropShadowEffect)) {
|
||||
return true;
|
||||
}
|
||||
if (destinationType == typeof(TornEdgeEffect)) {
|
||||
return true;
|
||||
}
|
||||
return base.CanConvertTo(context, destinationType);
|
||||
}
|
||||
|
||||
public override object ConvertTo(ITypeDescriptorContext context, CultureInfo culture, object value, Type destinationType) {
|
||||
// to string
|
||||
if (destinationType == typeof(string)) {
|
||||
StringBuilder sb = new StringBuilder();
|
||||
if (value.GetType() == typeof(DropShadowEffect)) {
|
||||
DropShadowEffect effect = value as DropShadowEffect;
|
||||
RetrieveDropShadowEffectValues(effect, sb);
|
||||
return sb.ToString();
|
||||
}
|
||||
if (value.GetType() == typeof(TornEdgeEffect)) {
|
||||
TornEdgeEffect effect = value as TornEdgeEffect;
|
||||
RetrieveDropShadowEffectValues(effect, sb);
|
||||
sb.Append("|");
|
||||
RetrieveTornEdgeEffectValues(effect, sb);
|
||||
return sb.ToString();
|
||||
}
|
||||
}
|
||||
// from string
|
||||
if (value is string) {
|
||||
string settings = value as string;
|
||||
if (destinationType == typeof(DropShadowEffect)) {
|
||||
DropShadowEffect effect = new DropShadowEffect();
|
||||
ApplyDropShadowEffectValues(settings, effect);
|
||||
return effect;
|
||||
}
|
||||
if (destinationType == typeof(TornEdgeEffect)) {
|
||||
TornEdgeEffect effect = new TornEdgeEffect();
|
||||
ApplyDropShadowEffectValues(settings, effect);
|
||||
ApplyTornEdgeEffectValues(settings, effect);
|
||||
return effect;
|
||||
}
|
||||
}
|
||||
return base.ConvertTo(context, culture, value, destinationType);
|
||||
}
|
||||
|
||||
public override object ConvertFrom(ITypeDescriptorContext context, CultureInfo culture, object value) {
|
||||
var settings = value as string;
|
||||
if (settings != null) {
|
||||
if (settings.Contains("ToothHeight")) {
|
||||
return ConvertTo(context, culture, settings, typeof(TornEdgeEffect));
|
||||
}
|
||||
return ConvertTo(context, culture, settings, typeof(DropShadowEffect));
|
||||
}
|
||||
return base.ConvertFrom(context, culture, value);
|
||||
}
|
||||
|
||||
private void ApplyDropShadowEffectValues(string valuesString, DropShadowEffect effect) {
|
||||
string[] values = valuesString.Split('|');
|
||||
foreach(string nameValuePair in values) {
|
||||
string[] pair = nameValuePair.Split(':');
|
||||
switch (pair[0]) {
|
||||
case "Darkness" :
|
||||
float darkness;
|
||||
// Fix to prevent BUG-1753
|
||||
if (pair[1] != null && float.TryParse(pair[1], NumberStyles.Float, _numberFormatInfo, out darkness)) {
|
||||
if (darkness <= 1.0) {
|
||||
effect.Darkness = darkness;
|
||||
}
|
||||
}
|
||||
break;
|
||||
case "ShadowSize":
|
||||
int shadowSize;
|
||||
if (int.TryParse(pair[1], out shadowSize)) {
|
||||
effect.ShadowSize = shadowSize;
|
||||
}
|
||||
break;
|
||||
case "ShadowOffset":
|
||||
Point shadowOffset = new Point();
|
||||
int shadowOffsetX;
|
||||
int shadowOffsetY;
|
||||
string[] coordinates = pair[1].Split(',');
|
||||
if (int.TryParse(coordinates[0], out shadowOffsetX)) {
|
||||
shadowOffset.X = shadowOffsetX;
|
||||
}
|
||||
if (int.TryParse(coordinates[1], out shadowOffsetY)) {
|
||||
shadowOffset.Y = shadowOffsetY;
|
||||
}
|
||||
effect.ShadowOffset = shadowOffset;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void ApplyTornEdgeEffectValues(string valuesString, TornEdgeEffect effect) {
|
||||
string[] values = valuesString.Split('|');
|
||||
foreach (string nameValuePair in values) {
|
||||
string[] pair = nameValuePair.Split(':');
|
||||
switch (pair[0]) {
|
||||
case "GenerateShadow":
|
||||
bool generateShadow;
|
||||
if (bool.TryParse(pair[1], out generateShadow)) {
|
||||
effect.GenerateShadow = generateShadow;
|
||||
}
|
||||
break;
|
||||
case "ToothHeight":
|
||||
int toothHeight;
|
||||
if (int.TryParse(pair[1], out toothHeight)) {
|
||||
effect.ToothHeight = toothHeight;
|
||||
}
|
||||
break;
|
||||
case "HorizontalToothRange":
|
||||
int horizontalToothRange;
|
||||
if (int.TryParse(pair[1], out horizontalToothRange)) {
|
||||
effect.HorizontalToothRange = horizontalToothRange;
|
||||
}
|
||||
break;
|
||||
case "VerticalToothRange":
|
||||
int verticalToothRange;
|
||||
if (int.TryParse(pair[1], out verticalToothRange)) {
|
||||
effect.VerticalToothRange = verticalToothRange;
|
||||
}
|
||||
break;
|
||||
case "Edges":
|
||||
string[] edges = pair[1].Split(',');
|
||||
bool edge;
|
||||
if (bool.TryParse(edges[0], out edge)) {
|
||||
effect.Edges[0] = edge;
|
||||
}
|
||||
if (bool.TryParse(edges[1], out edge)) {
|
||||
effect.Edges[1] = edge;
|
||||
}
|
||||
if (bool.TryParse(edges[2], out edge)) {
|
||||
effect.Edges[2] = edge;
|
||||
}
|
||||
if (bool.TryParse(edges[3], out edge)) {
|
||||
effect.Edges[3] = edge;
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void RetrieveDropShadowEffectValues(DropShadowEffect effect, StringBuilder sb) {
|
||||
// Fix to prevent BUG-1753 is to use the numberFormatInfo
|
||||
sb.AppendFormat("Darkness:{0}|ShadowSize:{1}|ShadowOffset:{2},{3}", effect.Darkness.ToString("F2", _numberFormatInfo), effect.ShadowSize, effect.ShadowOffset.X, effect.ShadowOffset.Y);
|
||||
}
|
||||
private void RetrieveTornEdgeEffectValues(TornEdgeEffect effect, StringBuilder sb) {
|
||||
sb.AppendFormat("GenerateShadow:{0}|ToothHeight:{1}|HorizontalToothRange:{2}|VerticalToothRange:{3}|Edges:{4},{5},{6},{7}", effect.GenerateShadow, effect.ToothHeight, effect.HorizontalToothRange, effect.VerticalToothRange, effect.Edges[0], effect.Edges[1], effect.Edges[2], effect.Edges[3]);
|
||||
}
|
||||
}
|
||||
}
|
|
@ -1,529 +0,0 @@
|
|||
/*
|
||||
* Greenshot - a free and open source screenshot tool
|
||||
* Copyright (C) 2007-2016 Thomas Braun, Jens Klingen, Robin Krom
|
||||
*
|
||||
* For more information see: http://getgreenshot.org/
|
||||
* The Greenshot project is hosted on GitHub https://github.com/greenshot/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 <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
using GreenshotPlugin.Core;
|
||||
using log4net;
|
||||
using System;
|
||||
using System.ComponentModel;
|
||||
using System.Drawing;
|
||||
using System.Drawing.Drawing2D;
|
||||
using System.Drawing.Imaging;
|
||||
using System.Globalization;
|
||||
using System.Text;
|
||||
|
||||
namespace Greenshot.Core {
|
||||
/// <summary>
|
||||
/// Interface to describe an effect
|
||||
/// </summary>
|
||||
public interface IEffect {
|
||||
/// <summary>
|
||||
/// Apply this IEffect to the supplied sourceImage.
|
||||
/// In the process of applying the supplied matrix will be modified to represent the changes.
|
||||
/// </summary>
|
||||
/// <param name="sourceImage">Image to apply the effect to</param>
|
||||
/// <param name="matrix">Matrix with the modifications like rotate, translate etc. this can be used to calculate the new location of elements on a canvas</param>
|
||||
/// <returns>new image with applied effect</returns>
|
||||
Image Apply(Image sourceImage, Matrix matrix);
|
||||
|
||||
/// <summary>
|
||||
/// Reset all values to their defaults
|
||||
/// </summary>
|
||||
void Reset();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// DropShadowEffect
|
||||
/// </summary>
|
||||
[TypeConverter(typeof(EffectConverter))]
|
||||
public class DropShadowEffect : IEffect {
|
||||
public DropShadowEffect() {
|
||||
Reset();
|
||||
}
|
||||
public float Darkness {
|
||||
get;
|
||||
set;
|
||||
}
|
||||
public int ShadowSize {
|
||||
get;
|
||||
set;
|
||||
}
|
||||
public Point ShadowOffset {
|
||||
get;
|
||||
set;
|
||||
}
|
||||
|
||||
public virtual void Reset() {
|
||||
Darkness = 0.6f;
|
||||
ShadowSize = 7;
|
||||
ShadowOffset = new Point(-1, -1);
|
||||
}
|
||||
|
||||
public virtual Image Apply(Image sourceImage, Matrix matrix) {
|
||||
return ImageHelper.CreateShadow(sourceImage, Darkness, ShadowSize, ShadowOffset, matrix, PixelFormat.Format32bppArgb);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// TornEdgeEffect extends on DropShadowEffect
|
||||
/// </summary>
|
||||
[TypeConverter(typeof(EffectConverter))]
|
||||
public class TornEdgeEffect : DropShadowEffect {
|
||||
public TornEdgeEffect()
|
||||
{
|
||||
Reset();
|
||||
}
|
||||
public int ToothHeight {
|
||||
get;
|
||||
set;
|
||||
}
|
||||
public int HorizontalToothRange {
|
||||
get;
|
||||
set;
|
||||
}
|
||||
public int VerticalToothRange {
|
||||
get;
|
||||
set;
|
||||
}
|
||||
public bool[] Edges {
|
||||
get;
|
||||
set;
|
||||
}
|
||||
public bool GenerateShadow {
|
||||
get;
|
||||
set;
|
||||
}
|
||||
|
||||
public override void Reset() {
|
||||
base.Reset();
|
||||
ShadowSize = 7;
|
||||
ToothHeight = 12;
|
||||
HorizontalToothRange = 20;
|
||||
VerticalToothRange = 20;
|
||||
Edges = new[] { true, true, true, true };
|
||||
GenerateShadow = true;
|
||||
}
|
||||
public override Image Apply(Image sourceImage, Matrix matrix) {
|
||||
Image tmpTornImage = ImageHelper.CreateTornEdge(sourceImage, ToothHeight, HorizontalToothRange, VerticalToothRange, Edges);
|
||||
if (GenerateShadow) {
|
||||
using (tmpTornImage) {
|
||||
return ImageHelper.CreateShadow(tmpTornImage, Darkness, ShadowSize, ShadowOffset, matrix, PixelFormat.Format32bppArgb);
|
||||
}
|
||||
}
|
||||
return tmpTornImage;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// GrayscaleEffect
|
||||
/// </summary>
|
||||
public class GrayscaleEffect : IEffect {
|
||||
public Image Apply(Image sourceImage, Matrix matrix) {
|
||||
return ImageHelper.CreateGrayscale(sourceImage);
|
||||
}
|
||||
public void Reset() {
|
||||
// No settings to reset
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// MonochromeEffect
|
||||
/// </summary>
|
||||
public class MonochromeEffect : IEffect {
|
||||
private readonly byte _threshold;
|
||||
/// <param name="threshold">Threshold for monochrome filter (0 - 255), lower value means less black</param>
|
||||
public MonochromeEffect(byte threshold) {
|
||||
_threshold = threshold;
|
||||
}
|
||||
public void Reset() {
|
||||
// TODO: Modify the threshold to have a default, which is reset here
|
||||
}
|
||||
public Image Apply(Image sourceImage, Matrix matrix) {
|
||||
return ImageHelper.CreateMonochrome(sourceImage, _threshold);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// AdjustEffect
|
||||
/// </summary>
|
||||
public class AdjustEffect : IEffect {
|
||||
public AdjustEffect()
|
||||
{
|
||||
Reset();
|
||||
}
|
||||
public float Contrast {
|
||||
get;
|
||||
set;
|
||||
}
|
||||
public float Brightness {
|
||||
get;
|
||||
set;
|
||||
}
|
||||
public float Gamma {
|
||||
get;
|
||||
set;
|
||||
}
|
||||
public void Reset() {
|
||||
Contrast = 1f;
|
||||
Brightness = 1f;
|
||||
Gamma = 1f;
|
||||
}
|
||||
public Image Apply(Image sourceImage, Matrix matrix) {
|
||||
return ImageHelper.Adjust(sourceImage, Brightness, Contrast, Gamma);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// ReduceColorsEffect
|
||||
/// </summary>
|
||||
public class ReduceColorsEffect : IEffect {
|
||||
private static readonly ILog LOG = LogManager.GetLogger(typeof(ReduceColorsEffect));
|
||||
public ReduceColorsEffect()
|
||||
{
|
||||
Reset();
|
||||
}
|
||||
public int Colors {
|
||||
get;
|
||||
set;
|
||||
}
|
||||
public void Reset() {
|
||||
Colors = 256;
|
||||
}
|
||||
public Image Apply(Image sourceImage, Matrix matrix) {
|
||||
using (WuQuantizer quantizer = new WuQuantizer((Bitmap)sourceImage)) {
|
||||
int colorCount = quantizer.GetColorCount();
|
||||
if (colorCount > Colors) {
|
||||
try {
|
||||
return quantizer.GetQuantizedImage(Colors);
|
||||
} catch (Exception e) {
|
||||
LOG.Warn("Error occurred while Quantizing the image, ignoring and using original. Error: ", e);
|
||||
}
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// InvertEffect
|
||||
/// </summary>
|
||||
public class InvertEffect : IEffect {
|
||||
public Image Apply(Image sourceImage, Matrix matrix) {
|
||||
return ImageHelper.CreateNegative(sourceImage);
|
||||
}
|
||||
public void Reset() {
|
||||
// No settings to reset
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// BorderEffect
|
||||
/// </summary>
|
||||
public class BorderEffect : IEffect {
|
||||
public BorderEffect() {
|
||||
Reset();
|
||||
}
|
||||
public Color Color {
|
||||
get;
|
||||
set;
|
||||
}
|
||||
public int Width {
|
||||
get;
|
||||
set;
|
||||
}
|
||||
public void Reset() {
|
||||
Width = 2;
|
||||
Color = Color.Black;
|
||||
}
|
||||
public Image Apply(Image sourceImage, Matrix matrix) {
|
||||
return ImageHelper.CreateBorder(sourceImage, Width, Color, sourceImage.PixelFormat, matrix);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// RotateEffect
|
||||
/// </summary>
|
||||
public class RotateEffect : IEffect {
|
||||
public RotateEffect(int angle) {
|
||||
Angle = angle;
|
||||
}
|
||||
public int Angle {
|
||||
get;
|
||||
set;
|
||||
}
|
||||
public void Reset() {
|
||||
// Angle doesn't have a default value
|
||||
}
|
||||
public Image Apply(Image sourceImage, Matrix matrix) {
|
||||
RotateFlipType flipType;
|
||||
if (Angle == 90) {
|
||||
matrix.Rotate(90, MatrixOrder.Append);
|
||||
matrix.Translate(sourceImage.Height, 0, MatrixOrder.Append);
|
||||
flipType = RotateFlipType.Rotate90FlipNone;
|
||||
} else if (Angle == -90 || Angle == 270) {
|
||||
flipType = RotateFlipType.Rotate270FlipNone;
|
||||
matrix.Rotate(-90, MatrixOrder.Append);
|
||||
matrix.Translate(0, sourceImage.Width, MatrixOrder.Append);
|
||||
} else {
|
||||
throw new NotSupportedException("Currently only an angle of 90 or -90 (270) is supported.");
|
||||
}
|
||||
return ImageHelper.RotateFlip(sourceImage, flipType);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// ResizeEffect
|
||||
/// </summary>
|
||||
public class ResizeEffect : IEffect {
|
||||
public ResizeEffect(int width, int height, bool maintainAspectRatio) {
|
||||
Width = width;
|
||||
Height = height;
|
||||
MaintainAspectRatio = maintainAspectRatio;
|
||||
}
|
||||
public int Width {
|
||||
get;
|
||||
set;
|
||||
}
|
||||
public int Height {
|
||||
get;
|
||||
set;
|
||||
}
|
||||
public bool MaintainAspectRatio {
|
||||
get;
|
||||
set;
|
||||
}
|
||||
public void Reset() {
|
||||
// values don't have a default value
|
||||
}
|
||||
public Image Apply(Image sourceImage, Matrix matrix) {
|
||||
return ImageHelper.ResizeImage(sourceImage, MaintainAspectRatio, Width, Height, matrix);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// ResizeCanvasEffect
|
||||
/// </summary>
|
||||
public class ResizeCanvasEffect : IEffect {
|
||||
public ResizeCanvasEffect(int left, int right, int top, int bottom) {
|
||||
Left = left;
|
||||
Right = right;
|
||||
Top = top;
|
||||
Bottom = bottom;
|
||||
BackgroundColor = Color.Empty; // Uses the default background color depending on the format
|
||||
}
|
||||
public int Left {
|
||||
get;
|
||||
set;
|
||||
}
|
||||
public int Right {
|
||||
get;
|
||||
set;
|
||||
}
|
||||
public int Top {
|
||||
get;
|
||||
set;
|
||||
}
|
||||
public int Bottom {
|
||||
get;
|
||||
set;
|
||||
}
|
||||
public Color BackgroundColor {
|
||||
get;
|
||||
set;
|
||||
}
|
||||
public void Reset() {
|
||||
// values don't have a default value
|
||||
}
|
||||
public Image Apply(Image sourceImage, Matrix matrix) {
|
||||
return ImageHelper.ResizeCanvas(sourceImage, BackgroundColor, Left, Right, Top, Bottom, matrix);
|
||||
}
|
||||
}
|
||||
|
||||
public class EffectConverter : TypeConverter {
|
||||
// Fix to prevent BUG-1753
|
||||
private readonly NumberFormatInfo numberFormatInfo = new NumberFormatInfo();
|
||||
|
||||
public EffectConverter()
|
||||
{
|
||||
numberFormatInfo.NumberDecimalSeparator = ".";
|
||||
numberFormatInfo.NumberGroupSeparator = ",";
|
||||
}
|
||||
|
||||
public override bool CanConvertFrom(ITypeDescriptorContext context, Type sourceType) {
|
||||
if (sourceType == typeof(string)) {
|
||||
return true;
|
||||
}
|
||||
return base.CanConvertFrom(context, sourceType);
|
||||
}
|
||||
|
||||
public override bool CanConvertTo(ITypeDescriptorContext context, Type destinationType) {
|
||||
if (destinationType == typeof(string)) {
|
||||
return true;
|
||||
}
|
||||
if (destinationType == typeof(DropShadowEffect)) {
|
||||
return true;
|
||||
}
|
||||
if (destinationType == typeof(TornEdgeEffect)) {
|
||||
return true;
|
||||
}
|
||||
return base.CanConvertTo(context, destinationType);
|
||||
}
|
||||
|
||||
public override object ConvertTo(ITypeDescriptorContext context, CultureInfo culture, object value, Type destinationType) {
|
||||
// to string
|
||||
if (destinationType == typeof(string)) {
|
||||
StringBuilder sb = new StringBuilder();
|
||||
if (value.GetType() == typeof(DropShadowEffect)) {
|
||||
DropShadowEffect effect = value as DropShadowEffect;
|
||||
RetrieveDropShadowEffectValues(effect, sb);
|
||||
return sb.ToString();
|
||||
}
|
||||
if (value.GetType() == typeof(TornEdgeEffect)) {
|
||||
TornEdgeEffect effect = value as TornEdgeEffect;
|
||||
RetrieveDropShadowEffectValues(effect, sb);
|
||||
sb.Append("|");
|
||||
RetrieveTornEdgeEffectValues(effect, sb);
|
||||
return sb.ToString();
|
||||
}
|
||||
}
|
||||
// from string
|
||||
if (value is string) {
|
||||
string settings = value as string;
|
||||
if (destinationType == typeof(DropShadowEffect)) {
|
||||
DropShadowEffect effect = new DropShadowEffect();
|
||||
ApplyDropShadowEffectValues(settings, effect);
|
||||
return effect;
|
||||
}
|
||||
if (destinationType == typeof(TornEdgeEffect)) {
|
||||
TornEdgeEffect effect = new TornEdgeEffect();
|
||||
ApplyDropShadowEffectValues(settings, effect);
|
||||
ApplyTornEdgeEffectValues(settings, effect);
|
||||
return effect;
|
||||
}
|
||||
}
|
||||
return base.ConvertTo(context, culture, value, destinationType);
|
||||
}
|
||||
|
||||
public override object ConvertFrom(ITypeDescriptorContext context, CultureInfo culture, object value) {
|
||||
if (value != null && value is string) {
|
||||
string settings = value as string;
|
||||
if (settings.Contains("ToothHeight")) {
|
||||
return ConvertTo(context, culture, value, typeof(TornEdgeEffect));
|
||||
}
|
||||
return ConvertTo(context, culture, value, typeof(DropShadowEffect));
|
||||
}
|
||||
return base.ConvertFrom(context, culture, value);
|
||||
}
|
||||
|
||||
private void ApplyDropShadowEffectValues(string valuesString, DropShadowEffect effect) {
|
||||
string[] values = valuesString.Split('|');
|
||||
foreach(string nameValuePair in values) {
|
||||
string[] pair = nameValuePair.Split(':');
|
||||
switch (pair[0]) {
|
||||
case "Darkness" :
|
||||
float darkness;
|
||||
// Fix to prevent BUG-1753
|
||||
if (pair[1] != null && float.TryParse(pair[1], NumberStyles.Float, numberFormatInfo, out darkness)) {
|
||||
if (darkness <= 1.0) {
|
||||
effect.Darkness = darkness;
|
||||
}
|
||||
}
|
||||
break;
|
||||
case "ShadowSize":
|
||||
int shadowSize;
|
||||
if (int.TryParse(pair[1], out shadowSize)) {
|
||||
effect.ShadowSize = shadowSize;
|
||||
}
|
||||
break;
|
||||
case "ShadowOffset":
|
||||
Point shadowOffset = new Point();
|
||||
int shadowOffsetX;
|
||||
int shadowOffsetY;
|
||||
string[] coordinates = pair[1].Split(',');
|
||||
if (int.TryParse(coordinates[0], out shadowOffsetX)) {
|
||||
shadowOffset.X = shadowOffsetX;
|
||||
}
|
||||
if (int.TryParse(coordinates[1], out shadowOffsetY)) {
|
||||
shadowOffset.Y = shadowOffsetY;
|
||||
}
|
||||
effect.ShadowOffset = shadowOffset;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void ApplyTornEdgeEffectValues(string valuesString, TornEdgeEffect effect) {
|
||||
string[] values = valuesString.Split('|');
|
||||
foreach (string nameValuePair in values) {
|
||||
string[] pair = nameValuePair.Split(':');
|
||||
switch (pair[0]) {
|
||||
case "GenerateShadow":
|
||||
bool generateShadow;
|
||||
if (bool.TryParse(pair[1], out generateShadow)) {
|
||||
effect.GenerateShadow = generateShadow;
|
||||
}
|
||||
break;
|
||||
case "ToothHeight":
|
||||
int toothHeight;
|
||||
if (int.TryParse(pair[1], out toothHeight)) {
|
||||
effect.ToothHeight = toothHeight;
|
||||
}
|
||||
break;
|
||||
case "HorizontalToothRange":
|
||||
int horizontalToothRange;
|
||||
if (int.TryParse(pair[1], out horizontalToothRange)) {
|
||||
effect.HorizontalToothRange = horizontalToothRange;
|
||||
}
|
||||
break;
|
||||
case "VerticalToothRange":
|
||||
int verticalToothRange;
|
||||
if (int.TryParse(pair[1], out verticalToothRange)) {
|
||||
effect.VerticalToothRange = verticalToothRange;
|
||||
}
|
||||
break;
|
||||
case "Edges":
|
||||
string[] edges = pair[1].Split(',');
|
||||
bool edge;
|
||||
if (bool.TryParse(edges[0], out edge)) {
|
||||
effect.Edges[0] = edge;
|
||||
}
|
||||
if (bool.TryParse(edges[1], out edge)) {
|
||||
effect.Edges[1] = edge;
|
||||
}
|
||||
if (bool.TryParse(edges[2], out edge)) {
|
||||
effect.Edges[2] = edge;
|
||||
}
|
||||
if (bool.TryParse(edges[3], out edge)) {
|
||||
effect.Edges[3] = edge;
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void RetrieveDropShadowEffectValues(DropShadowEffect effect, StringBuilder sb) {
|
||||
// Fix to prevent BUG-1753 is to use the numberFormatInfo
|
||||
sb.AppendFormat("Darkness:{0}|ShadowSize:{1}|ShadowOffset:{2},{3}", effect.Darkness.ToString("F2", numberFormatInfo), effect.ShadowSize, effect.ShadowOffset.X, effect.ShadowOffset.Y);
|
||||
}
|
||||
private void RetrieveTornEdgeEffectValues(TornEdgeEffect effect, StringBuilder sb) {
|
||||
sb.AppendFormat("GenerateShadow:{0}|ToothHeight:{1}|HorizontalToothRange:{2}|VerticalToothRange:{3}|Edges:{4},{5},{6},{7}", effect.GenerateShadow, effect.ToothHeight, effect.HorizontalToothRange, effect.VerticalToothRange, effect.Edges[0], effect.Edges[1], effect.Edges[2], effect.Edges[3]);
|
||||
}
|
||||
}
|
||||
}
|
|
@ -26,38 +26,32 @@ namespace GreenshotPlugin.Core {
|
|||
/// Description of EmailConfigHelper.
|
||||
/// </summary>
|
||||
public static class EmailConfigHelper {
|
||||
private const string OUTLOOK_PATH_KEY = @"SOFTWARE\Microsoft\Windows\CurrentVersion\App Paths\OUTLOOK.EXE";
|
||||
private const string MAPI_CLIENT_KEY = @"SOFTWARE\Clients\Mail";
|
||||
private const string MAPI_LOCATION_KEY = @"SOFTWARE\Microsoft\Windows Messaging Subsystem";
|
||||
private const string MAPI_KEY = @"MAPI";
|
||||
private const string OutlookPathKey = @"SOFTWARE\Microsoft\Windows\CurrentVersion\App Paths\OUTLOOK.EXE";
|
||||
private const string MapiClientKey = @"SOFTWARE\Clients\Mail";
|
||||
private const string MapiLocationKey = @"SOFTWARE\Microsoft\Windows Messaging Subsystem";
|
||||
private const string MapiKey = @"MAPI";
|
||||
|
||||
public static string GetMapiClient() {
|
||||
using (RegistryKey key = Registry.CurrentUser.OpenSubKey(MAPI_CLIENT_KEY, false)) {
|
||||
using (RegistryKey key = Registry.CurrentUser.OpenSubKey(MapiClientKey, false)) {
|
||||
if (key != null) {
|
||||
return (string)key.GetValue("");
|
||||
}
|
||||
}
|
||||
using (RegistryKey key = Registry.LocalMachine.OpenSubKey(MAPI_CLIENT_KEY, false)) {
|
||||
if (key != null) {
|
||||
return (string)key.GetValue("");
|
||||
} else {
|
||||
return null;
|
||||
}
|
||||
using (RegistryKey key = Registry.LocalMachine.OpenSubKey(MapiClientKey, false))
|
||||
{
|
||||
return (string) key?.GetValue("");
|
||||
}
|
||||
}
|
||||
|
||||
public static bool HasMAPI() {
|
||||
using (RegistryKey key = Registry.LocalMachine.OpenSubKey(MAPI_LOCATION_KEY, false)) {
|
||||
if (key != null) {
|
||||
return "1".Equals(key.GetValue(MAPI_KEY, "0"));
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
public static bool HasMapi() {
|
||||
using (RegistryKey key = Registry.LocalMachine.OpenSubKey(MapiLocationKey, false))
|
||||
{
|
||||
return key != null && "1".Equals(key.GetValue(MapiKey, "0"));
|
||||
}
|
||||
}
|
||||
|
||||
public static string GetOutlookExePath() {
|
||||
using (RegistryKey key = Registry.LocalMachine.OpenSubKey(OUTLOOK_PATH_KEY, false)) {
|
||||
using (RegistryKey key = Registry.LocalMachine.OpenSubKey(OutlookPathKey, false)) {
|
||||
if (key != null) {
|
||||
// "" is the default key, which should point to the outlook location
|
||||
return (string)key.GetValue("");
|
||||
|
|
|
@ -20,8 +20,8 @@
|
|||
*/
|
||||
using System;
|
||||
namespace GreenshotPlugin.Core {
|
||||
public static class EnumerationExtensions {
|
||||
public static bool Has<T>(this Enum type, T value) {
|
||||
public static class EnumerationExtensions {
|
||||
public static bool Has<T>(this Enum type, T value) {
|
||||
Type underlyingType = Enum.GetUnderlyingType(value.GetType());
|
||||
try {
|
||||
if (underlyingType == typeof(int)) {
|
||||
|
@ -29,23 +29,31 @@ namespace GreenshotPlugin.Core {
|
|||
} else if (underlyingType == typeof(uint)) {
|
||||
return (((uint)(object)type & (uint)(object)value) == (uint)(object)value);
|
||||
}
|
||||
} catch {
|
||||
}
|
||||
}
|
||||
catch
|
||||
{
|
||||
// ignored
|
||||
}
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
public static bool Is<T>(this Enum type, T value) {
|
||||
public static bool Is<T>(this Enum type, T value) {
|
||||
Type underlyingType = Enum.GetUnderlyingType(value.GetType());
|
||||
try {
|
||||
try
|
||||
{
|
||||
if (underlyingType == typeof(int)) {
|
||||
return (int)(object)type == (int)(object)value;
|
||||
} else if (underlyingType == typeof(uint)) {
|
||||
}
|
||||
if (underlyingType == typeof(uint)) {
|
||||
return (uint)(object)type == (uint)(object)value;
|
||||
}
|
||||
} catch {
|
||||
}
|
||||
}
|
||||
catch
|
||||
{
|
||||
// ignored
|
||||
}
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Add a flag to an enum
|
||||
|
@ -53,19 +61,21 @@ namespace GreenshotPlugin.Core {
|
|||
/// <param name="type"></param>
|
||||
/// <param name="value"></param>
|
||||
/// <returns></returns>
|
||||
public static T Add<T>(this Enum type, T value) {
|
||||
public static T Add<T>(this Enum type, T value) {
|
||||
Type underlyingType = Enum.GetUnderlyingType(value.GetType());
|
||||
try {
|
||||
try
|
||||
{
|
||||
if (underlyingType == typeof(int)) {
|
||||
return (T)(object)(((int)(object)type | (int)(object)value));
|
||||
} else if (underlyingType == typeof(uint)) {
|
||||
}
|
||||
if (underlyingType == typeof(uint)) {
|
||||
return (T)(object)(((uint)(object)type | (uint)(object)value));
|
||||
}
|
||||
} catch(Exception ex) {
|
||||
throw new ArgumentException(string.Format("Could not append value '{0}' to enumerated type '{1}'.", value, typeof(T).Name), ex);
|
||||
throw new ArgumentException($"Could not append value '{value}' to enumerated type '{typeof(T).Name}'.", ex);
|
||||
}
|
||||
throw new ArgumentException(string.Format("Could not append value '{0}' to enumerated type '{1}'.", value, typeof(T).Name));
|
||||
}
|
||||
throw new ArgumentException($"Could not append value '{value}' to enumerated type '{typeof(T).Name}'.");
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Remove a flag from an enum type
|
||||
|
@ -73,18 +83,20 @@ namespace GreenshotPlugin.Core {
|
|||
/// <param name="type"></param>
|
||||
/// <param name="value"></param>
|
||||
/// <returns></returns>
|
||||
public static T Remove<T>(this Enum type, T value) {
|
||||
public static T Remove<T>(this Enum type, T value) {
|
||||
Type underlyingType = Enum.GetUnderlyingType(value.GetType());
|
||||
try {
|
||||
try
|
||||
{
|
||||
if (underlyingType == typeof(int)) {
|
||||
return (T)(object)(((int)(object)type & ~(int)(object)value));
|
||||
} else if (underlyingType == typeof(uint)) {
|
||||
}
|
||||
if (underlyingType == typeof(uint)) {
|
||||
return (T)(object)(((uint)(object)type & ~(uint)(object)value));
|
||||
}
|
||||
} catch(Exception ex) {
|
||||
throw new ArgumentException(string.Format("Could not remove value '{0}' from enumerated type '{1}'.", value, typeof(T).Name), ex);
|
||||
throw new ArgumentException($"Could not remove value '{value}' from enumerated type '{typeof(T).Name}'.", ex);
|
||||
}
|
||||
throw new ArgumentException(string.Format("Could not remove value '{0}' from enumerated type '{1}'.", value, typeof(T).Name));
|
||||
}
|
||||
}
|
||||
throw new ArgumentException($"Could not remove value '{value}' from enumerated type '{typeof(T).Name}'.");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -22,7 +22,6 @@ using System;
|
|||
using System.Collections.Generic;
|
||||
using System.Drawing;
|
||||
using System.Drawing.Imaging;
|
||||
using log4net;
|
||||
|
||||
namespace GreenshotPlugin.Core {
|
||||
|
||||
|
@ -285,9 +284,7 @@ namespace GreenshotPlugin.Core {
|
|||
/// <summary>
|
||||
/// The base class for the fast bitmap implementation
|
||||
/// </summary>
|
||||
public abstract unsafe class FastBitmap : IFastBitmap, IFastBitmapWithClip, IFastBitmapWithOffset {
|
||||
private static ILog _log = LogManager.GetLogger(typeof(FastBitmap));
|
||||
|
||||
public abstract unsafe class FastBitmap : IFastBitmapWithClip, IFastBitmapWithOffset {
|
||||
protected const int PixelformatIndexA = 3;
|
||||
protected const int PixelformatIndexR = 2;
|
||||
protected const int PixelformatIndexG = 1;
|
||||
|
@ -298,7 +295,7 @@ namespace GreenshotPlugin.Core {
|
|||
public const int ColorIndexB = 2;
|
||||
public const int ColorIndexA = 3;
|
||||
|
||||
protected Rectangle Area = Rectangle.Empty;
|
||||
protected Rectangle Area;
|
||||
/// <summary>
|
||||
/// If this is set to true, the bitmap will be disposed when disposing the IFastBitmap
|
||||
/// </summary>
|
||||
|
@ -354,7 +351,7 @@ namespace GreenshotPlugin.Core {
|
|||
case PixelFormat.Format32bppPArgb:
|
||||
return new Fast32ArgbBitmap(source, area);
|
||||
default:
|
||||
throw new NotSupportedException(string.Format("Not supported Pixelformat {0}", source.PixelFormat));
|
||||
throw new NotSupportedException($"Not supported Pixelformat {source.PixelFormat}");
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -396,9 +393,12 @@ namespace GreenshotPlugin.Core {
|
|||
public static IFastBitmap CreateCloneOf(Image source, PixelFormat pixelFormat, Rectangle area) {
|
||||
Bitmap destination = ImageHelper.CloneArea(source, area, pixelFormat);
|
||||
FastBitmap fastBitmap = Create(destination) as FastBitmap;
|
||||
fastBitmap.NeedsDispose = true;
|
||||
fastBitmap.Left = area.Left;
|
||||
fastBitmap.Top = area.Top;
|
||||
if (fastBitmap != null)
|
||||
{
|
||||
fastBitmap.NeedsDispose = true;
|
||||
fastBitmap.Left = area.Left;
|
||||
fastBitmap.Top = area.Top;
|
||||
}
|
||||
return fastBitmap;
|
||||
}
|
||||
|
||||
|
@ -529,20 +529,12 @@ namespace GreenshotPlugin.Core {
|
|||
/// <summary>
|
||||
/// Return the right of the fastbitmap
|
||||
/// </summary>
|
||||
public int Right {
|
||||
get {
|
||||
return Left + Width;
|
||||
}
|
||||
}
|
||||
public int Right => Left + Width;
|
||||
|
||||
/// <summary>
|
||||
/// Return the bottom of the fastbitmap
|
||||
/// </summary>
|
||||
public int Bottom {
|
||||
get {
|
||||
return Top + Height;
|
||||
}
|
||||
}
|
||||
public int Bottom => Top + Height;
|
||||
|
||||
/// <summary>
|
||||
/// Returns the underlying bitmap, unlocks it and prevents that it will be disposed
|
||||
|
@ -555,11 +547,7 @@ namespace GreenshotPlugin.Core {
|
|||
return Bitmap;
|
||||
}
|
||||
|
||||
public virtual bool HasAlphaChannel {
|
||||
get {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
public virtual bool HasAlphaChannel => false;
|
||||
|
||||
/// <summary>
|
||||
/// Destructor
|
||||
|
@ -600,14 +588,16 @@ namespace GreenshotPlugin.Core {
|
|||
/// Lock the bitmap so we have direct access to the memory
|
||||
/// </summary>
|
||||
public void Lock() {
|
||||
if (Width > 0 && Height > 0 && !BitsLocked) {
|
||||
BmData = Bitmap.LockBits(Area, ImageLockMode.ReadWrite, Bitmap.PixelFormat);
|
||||
BitsLocked = true;
|
||||
|
||||
IntPtr scan0 = BmData.Scan0;
|
||||
Pointer = (byte*)(void*)scan0;
|
||||
Stride = BmData.Stride;
|
||||
if (Width <= 0 || Height <= 0 || BitsLocked)
|
||||
{
|
||||
return;
|
||||
}
|
||||
BmData = Bitmap.LockBits(Area, ImageLockMode.ReadWrite, Bitmap.PixelFormat);
|
||||
BitsLocked = true;
|
||||
|
||||
IntPtr scan0 = BmData.Scan0;
|
||||
Pointer = (byte*)(void*)scan0;
|
||||
Stride = BmData.Stride;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
|
@ -635,7 +625,6 @@ namespace GreenshotPlugin.Core {
|
|||
/// </summary>
|
||||
/// <param name="graphics"></param>
|
||||
/// <param name="destinationRect"></param>
|
||||
/// <param name="destination"></param>
|
||||
public void DrawTo(Graphics graphics, Rectangle destinationRect) {
|
||||
// Make sure this.bitmap is unlocked, if it was locked
|
||||
bool isLocked = BitsLocked;
|
||||
|
@ -944,11 +933,7 @@ namespace GreenshotPlugin.Core {
|
|||
/// This is the implementation of the IFastBitmap for 32 bit images with Alpha
|
||||
/// </summary>
|
||||
public unsafe class Fast32ArgbBitmap : FastBitmap, IFastBitmapWithBlend {
|
||||
public override bool HasAlphaChannel {
|
||||
get {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
public override bool HasAlphaChannel => true;
|
||||
|
||||
public Color BackgroundBlendColor {
|
||||
get;
|
||||
|
|
|
@ -30,27 +30,27 @@ using System.Collections.Generic;
|
|||
|
||||
namespace GreenshotPlugin.Core {
|
||||
public static class FilenameHelper {
|
||||
private static readonly ILog LOG = LogManager.GetLogger(typeof(FilenameHelper));
|
||||
private static readonly ILog Log = LogManager.GetLogger(typeof(FilenameHelper));
|
||||
// Specify the regular expression for the filename formatting:
|
||||
// Starting with ${
|
||||
// than the varname, which ends with a : or }
|
||||
// If a parameters needs to be supplied, than a ":" should follow the name... everything from the : until the } is considered to be part of the parameters.
|
||||
// The parameter format is a single alpha followed by the value belonging to the parameter, e.g. :
|
||||
// ${capturetime:d"yyyy-MM-dd HH_mm_ss"}
|
||||
private static readonly Regex VAR_REGEXP = new Regex(@"\${(?<variable>[^:}]+)[:]?(?<parameters>[^}]*)}", RegexOptions.Compiled);
|
||||
private static readonly Regex CMD_VAR_REGEXP = new Regex(@"%(?<variable>[^%]+)%", RegexOptions.Compiled);
|
||||
private static readonly Regex VarRegexp = new Regex(@"\${(?<variable>[^:}]+)[:]?(?<parameters>[^}]*)}", RegexOptions.Compiled);
|
||||
private static readonly Regex CmdVarRegexp = new Regex(@"%(?<variable>[^%]+)%", RegexOptions.Compiled);
|
||||
|
||||
private static readonly Regex SPLIT_REGEXP = new Regex(";(?=(?:[^\"]*\"[^\"]*\")*[^\"]*$)", RegexOptions.Compiled);
|
||||
private const int MAX_TITLE_LENGTH = 80;
|
||||
private static readonly CoreConfiguration conf = IniConfig.GetIniSection<CoreConfiguration>();
|
||||
private const string UNSAFE_REPLACEMENT = "_";
|
||||
private static readonly Regex SplitRegexp = new Regex(";(?=(?:[^\"]*\"[^\"]*\")*[^\"]*$)", RegexOptions.Compiled);
|
||||
private const int MaxTitleLength = 80;
|
||||
private static readonly CoreConfiguration CoreConfig = IniConfig.GetIniSection<CoreConfiguration>();
|
||||
private const string UnsafeReplacement = "_";
|
||||
|
||||
/// <summary>
|
||||
/// Remove invalid characters from the fully qualified filename
|
||||
/// </summary>
|
||||
/// <param name="fullPath">string with the full path to a file</param>
|
||||
/// <returns>string with the full path to a file, without invalid characters</returns>
|
||||
public static string MakeFQFilenameSafe(string fullPath) {
|
||||
public static string MakeFqFilenameSafe(string fullPath) {
|
||||
string path = MakePathSafe(Path.GetDirectoryName(fullPath));
|
||||
string filename = MakeFilenameSafe(Path.GetFileName(fullPath));
|
||||
// Make the fullpath again and return
|
||||
|
@ -66,7 +66,7 @@ namespace GreenshotPlugin.Core {
|
|||
// Make the filename save!
|
||||
if (filename != null) {
|
||||
foreach (char disallowed in Path.GetInvalidFileNameChars()) {
|
||||
filename = filename.Replace(disallowed.ToString(), UNSAFE_REPLACEMENT);
|
||||
filename = filename.Replace(disallowed.ToString(), UnsafeReplacement);
|
||||
}
|
||||
}
|
||||
return filename;
|
||||
|
@ -81,7 +81,7 @@ namespace GreenshotPlugin.Core {
|
|||
// Make the path save!
|
||||
if (path != null) {
|
||||
foreach (char disallowed in Path.GetInvalidPathChars()) {
|
||||
path = path.Replace(disallowed.ToString(), UNSAFE_REPLACEMENT);
|
||||
path = path.Replace(disallowed.ToString(), UnsafeReplacement);
|
||||
}
|
||||
}
|
||||
return path;
|
||||
|
@ -108,15 +108,16 @@ namespace GreenshotPlugin.Core {
|
|||
/// that is specified in the configuration
|
||||
/// </summary>
|
||||
/// <param name="format">A string with the format</param>
|
||||
/// <param name="captureDetails"></param>
|
||||
/// <returns>The filename which should be used to save the image</returns>
|
||||
public static string GetFilename(OutputFormat format, ICaptureDetails captureDetails) {
|
||||
string pattern = conf.OutputFileFilenamePattern;
|
||||
if (pattern == null || string.IsNullOrEmpty(pattern.Trim())) {
|
||||
string pattern = CoreConfig.OutputFileFilenamePattern;
|
||||
if (string.IsNullOrEmpty(pattern?.Trim())) {
|
||||
pattern = "greenshot ${capturetime}";
|
||||
}
|
||||
return GetFilenameFromPattern(pattern, format, captureDetails);
|
||||
}
|
||||
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// This method will be called by the regexp.replace as a MatchEvaluator delegate!
|
||||
|
@ -127,14 +128,15 @@ namespace GreenshotPlugin.Core {
|
|||
/// <param name="processVars">Variables from the process</param>
|
||||
/// <param name="userVars">Variables from the user</param>
|
||||
/// <param name="machineVars">Variables from the machine</param>
|
||||
/// <param name="filenameSafeMode"></param>
|
||||
/// <returns>string with the match replacement</returns>
|
||||
private static string MatchVarEvaluator(Match match, ICaptureDetails captureDetails, IDictionary processVars, IDictionary userVars, IDictionary machineVars, bool filenameSafeMode) {
|
||||
try {
|
||||
return MatchVarEvaluatorInternal(match, captureDetails, processVars, userVars, machineVars, filenameSafeMode);
|
||||
} catch (Exception e) {
|
||||
LOG.Error("Error in MatchVarEvaluatorInternal", e);
|
||||
Log.Error("Error in MatchVarEvaluatorInternal", e);
|
||||
}
|
||||
return "";
|
||||
return string.Empty;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
|
@ -159,17 +161,20 @@ namespace GreenshotPlugin.Core {
|
|||
string variable = match.Groups["variable"].Value;
|
||||
string parameters = match.Groups["parameters"].Value;
|
||||
|
||||
if (parameters != null && parameters.Length > 0) {
|
||||
string[] parms = SPLIT_REGEXP.Split(parameters);
|
||||
if (parameters.Length > 0) {
|
||||
string[] parms = SplitRegexp.Split(parameters);
|
||||
foreach (string parameter in parms) {
|
||||
switch (parameter.Substring(0, 1)) {
|
||||
// Padding p<width>[,pad-character]
|
||||
case "p":
|
||||
string[] padParams = parameter.Substring(1).Split(new[] { ',' });
|
||||
string[] padParams = parameter.Substring(1).Split(',');
|
||||
try {
|
||||
padWidth = int.Parse(padParams[0]);
|
||||
} catch {
|
||||
};
|
||||
}
|
||||
catch
|
||||
{
|
||||
// ignored
|
||||
}
|
||||
if (padParams.Length > 1) {
|
||||
padChar = padParams[1][0];
|
||||
}
|
||||
|
@ -177,7 +182,7 @@ namespace GreenshotPlugin.Core {
|
|||
// replace
|
||||
// r<old string>,<new string>
|
||||
case "r":
|
||||
string[] replaceParameters = parameter.Substring(1).Split(new[] { ',' });
|
||||
string[] replaceParameters = parameter.Substring(1).Split(',');
|
||||
if (replaceParameters != null && replaceParameters.Length == 2) {
|
||||
replacements.Add(replaceParameters[0], replaceParameters[1]);
|
||||
}
|
||||
|
@ -197,7 +202,7 @@ namespace GreenshotPlugin.Core {
|
|||
// s<start>[,length]
|
||||
case "s":
|
||||
string range = parameter.Substring(1);
|
||||
string[] rangelist = range.Split(new[] { ',' });
|
||||
string[] rangelist = range.Split(',');
|
||||
if (rangelist.Length > 0) {
|
||||
try {
|
||||
startIndex = int.Parse(rangelist[0]);
|
||||
|
@ -231,7 +236,7 @@ namespace GreenshotPlugin.Core {
|
|||
if (filenameSafeMode) {
|
||||
replaceValue = MakePathSafe(replaceValue);
|
||||
}
|
||||
} else if (captureDetails != null && captureDetails.MetaData != null && captureDetails.MetaData.ContainsKey(variable)) {
|
||||
} else if (captureDetails?.MetaData != null && captureDetails.MetaData.ContainsKey(variable)) {
|
||||
replaceValue = captureDetails.MetaData[variable];
|
||||
if (filenameSafeMode) {
|
||||
replaceValue = MakePathSafe(replaceValue);
|
||||
|
@ -248,8 +253,8 @@ namespace GreenshotPlugin.Core {
|
|||
capturetime = captureDetails.DateTime;
|
||||
if (captureDetails.Title != null) {
|
||||
title = captureDetails.Title;
|
||||
if (title.Length > MAX_TITLE_LENGTH) {
|
||||
title = title.Substring(0, MAX_TITLE_LENGTH);
|
||||
if (title.Length > MaxTitleLength) {
|
||||
title = title.Substring(0, MaxTitleLength);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -318,9 +323,9 @@ namespace GreenshotPlugin.Core {
|
|||
}
|
||||
break;
|
||||
case "NUM":
|
||||
conf.OutputFileIncrementingNumber++;
|
||||
CoreConfig.OutputFileIncrementingNumber++;
|
||||
IniConfig.Save();
|
||||
replaceValue = conf.OutputFileIncrementingNumber.ToString();
|
||||
replaceValue = CoreConfig.OutputFileIncrementingNumber.ToString();
|
||||
if (padWidth == 0) {
|
||||
padWidth = -6;
|
||||
padChar = '0';
|
||||
|
@ -412,7 +417,7 @@ namespace GreenshotPlugin.Core {
|
|||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
LOG.Error("Error retrieving EnvironmentVariableTarget.Process", e);
|
||||
Log.Error("Error retrieving EnvironmentVariableTarget.Process", e);
|
||||
}
|
||||
|
||||
try
|
||||
|
@ -421,7 +426,7 @@ namespace GreenshotPlugin.Core {
|
|||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
LOG.Error("Error retrieving EnvironmentVariableTarget.User", e);
|
||||
Log.Error("Error retrieving EnvironmentVariableTarget.User", e);
|
||||
}
|
||||
|
||||
try
|
||||
|
@ -430,13 +435,11 @@ namespace GreenshotPlugin.Core {
|
|||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
LOG.Error("Error retrieving EnvironmentVariableTarget.Machine", e);
|
||||
Log.Error("Error retrieving EnvironmentVariableTarget.Machine", e);
|
||||
}
|
||||
|
||||
return CMD_VAR_REGEXP.Replace(pattern,
|
||||
delegate (Match m) {
|
||||
return MatchVarEvaluator(m, null, processVars, userVars, machineVars, filenameSafeMode);
|
||||
}
|
||||
return CmdVarRegexp.Replace(pattern,
|
||||
m => MatchVarEvaluator(m, null, processVars, userVars, machineVars, filenameSafeMode)
|
||||
);
|
||||
}
|
||||
|
||||
|
@ -453,25 +456,23 @@ namespace GreenshotPlugin.Core {
|
|||
try {
|
||||
processVars = Environment.GetEnvironmentVariables(EnvironmentVariableTarget.Process);
|
||||
} catch (Exception e) {
|
||||
LOG.Error("Error retrieving EnvironmentVariableTarget.Process", e);
|
||||
Log.Error("Error retrieving EnvironmentVariableTarget.Process", e);
|
||||
}
|
||||
|
||||
try {
|
||||
userVars = Environment.GetEnvironmentVariables(EnvironmentVariableTarget.User);
|
||||
} catch (Exception e) {
|
||||
LOG.Error("Error retrieving EnvironmentVariableTarget.User", e);
|
||||
Log.Error("Error retrieving EnvironmentVariableTarget.User", e);
|
||||
}
|
||||
|
||||
try {
|
||||
machineVars = Environment.GetEnvironmentVariables(EnvironmentVariableTarget.Machine);
|
||||
} catch (Exception e) {
|
||||
LOG.Error("Error retrieving EnvironmentVariableTarget.Machine", e);
|
||||
Log.Error("Error retrieving EnvironmentVariableTarget.Machine", e);
|
||||
}
|
||||
|
||||
return VAR_REGEXP.Replace(pattern,
|
||||
delegate(Match m) {
|
||||
return MatchVarEvaluator(m, null, processVars, userVars, machineVars, filenameSafeMode);
|
||||
}
|
||||
return VarRegexp.Replace(pattern,
|
||||
m => MatchVarEvaluator(m, null, processVars, userVars, machineVars, filenameSafeMode)
|
||||
);
|
||||
}
|
||||
|
||||
|
@ -489,26 +490,24 @@ namespace GreenshotPlugin.Core {
|
|||
try {
|
||||
processVars = Environment.GetEnvironmentVariables(EnvironmentVariableTarget.Process);
|
||||
} catch (Exception e) {
|
||||
LOG.Error("Error retrieving EnvironmentVariableTarget.Process", e);
|
||||
Log.Error("Error retrieving EnvironmentVariableTarget.Process", e);
|
||||
}
|
||||
|
||||
try {
|
||||
userVars = Environment.GetEnvironmentVariables(EnvironmentVariableTarget.User);
|
||||
} catch (Exception e) {
|
||||
LOG.Error("Error retrieving EnvironmentVariableTarget.User", e);
|
||||
Log.Error("Error retrieving EnvironmentVariableTarget.User", e);
|
||||
}
|
||||
|
||||
try {
|
||||
machineVars = Environment.GetEnvironmentVariables(EnvironmentVariableTarget.Machine);
|
||||
} catch (Exception e) {
|
||||
LOG.Error("Error retrieving EnvironmentVariableTarget.Machine", e);
|
||||
Log.Error("Error retrieving EnvironmentVariableTarget.Machine", e);
|
||||
}
|
||||
|
||||
try {
|
||||
return VAR_REGEXP.Replace(pattern,
|
||||
delegate(Match m) {
|
||||
return MatchVarEvaluator(m, captureDetails, processVars, userVars, machineVars, filenameSafeMode);
|
||||
}
|
||||
return VarRegexp.Replace(pattern,
|
||||
m => MatchVarEvaluator(m, captureDetails, processVars, userVars, machineVars, filenameSafeMode)
|
||||
);
|
||||
} catch (Exception e) {
|
||||
// adding additional data for bug tracking
|
||||
|
|
|
@ -29,6 +29,7 @@ using Greenshot.IniFile;
|
|||
using GreenshotPlugin.UnmanagedHelpers;
|
||||
using Greenshot.Core;
|
||||
using Greenshot.Plugin;
|
||||
using GreenshotPlugin.Effects;
|
||||
using log4net;
|
||||
|
||||
namespace GreenshotPlugin.Core {
|
||||
|
|
|
@ -167,7 +167,6 @@ namespace GreenshotPlugin.Core {
|
|||
AddTag(nonAlphaImage);
|
||||
nonAlphaImage.Save(targetStream, imageCodec, parameters);
|
||||
nonAlphaImage.Dispose();
|
||||
nonAlphaImage = null;
|
||||
}
|
||||
else
|
||||
{
|
||||
|
@ -205,7 +204,6 @@ namespace GreenshotPlugin.Core {
|
|||
}
|
||||
if (needsDispose) {
|
||||
imageToSave.Dispose();
|
||||
imageToSave = null;
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -221,7 +219,7 @@ namespace GreenshotPlugin.Core {
|
|||
using (BinaryWriter writer = new BinaryWriter(tmpStream)) {
|
||||
writer.Write(bytesWritten);
|
||||
Version v = Assembly.GetExecutingAssembly().GetName().Version;
|
||||
byte[] marker = Encoding.ASCII.GetBytes(String.Format("Greenshot{0:00}.{1:00}", v.Major, v.Minor));
|
||||
byte[] marker = Encoding.ASCII.GetBytes($"Greenshot{v.Major:00}.{v.Minor:00}");
|
||||
writer.Write(marker);
|
||||
tmpStream.WriteTo(stream);
|
||||
}
|
||||
|
@ -407,7 +405,7 @@ namespace GreenshotPlugin.Core {
|
|||
/// Saves image to specific path with specified quality
|
||||
/// </summary>
|
||||
public static void Save(ISurface surface, string fullPath, bool allowOverwrite, SurfaceOutputSettings outputSettings, bool copyPathToClipboard) {
|
||||
fullPath = FilenameHelper.MakeFQFilenameSafe(fullPath);
|
||||
fullPath = FilenameHelper.MakeFqFilenameSafe(fullPath);
|
||||
string path = Path.GetDirectoryName(fullPath);
|
||||
|
||||
// check whether path exists - if not create it
|
||||
|
@ -549,7 +547,7 @@ namespace GreenshotPlugin.Core {
|
|||
/// <param name="destinationPath"></param>
|
||||
/// <returns></returns>
|
||||
public static string SaveToTmpFile(ISurface surface, SurfaceOutputSettings outputSettings, string destinationPath) {
|
||||
string tmpFile = Path.GetRandomFileName() + "." + outputSettings.Format.ToString();
|
||||
string tmpFile = Path.GetRandomFileName() + "." + outputSettings.Format;
|
||||
// Prevent problems with "other characters", which could cause problems
|
||||
tmpFile = Regex.Replace(tmpFile, @"[^\d\w\.]", "");
|
||||
if (destinationPath == null) {
|
||||
|
|
|
@ -7,7 +7,7 @@ The above copyright notice and this permission notice shall be included in all c
|
|||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||
*/
|
||||
using System;
|
||||
|
||||
using System.Collections.Generic;
|
||||
using System.Globalization;
|
||||
using System.Text;
|
||||
|
@ -173,12 +173,11 @@ namespace GreenshotPlugin.Core {
|
|||
|
||||
protected static string ParseString(char[] json, ref int index, ref bool success) {
|
||||
StringBuilder s = new StringBuilder(BUILDER_CAPACITY);
|
||||
char c;
|
||||
|
||||
EatWhitespace(json, ref index);
|
||||
|
||||
// "
|
||||
c = json[index++];
|
||||
var c = json[index++];
|
||||
|
||||
bool complete = false;
|
||||
while (!complete) {
|
||||
|
@ -218,11 +217,11 @@ namespace GreenshotPlugin.Core {
|
|||
if (remainingLength >= 4) {
|
||||
// parse the 32 bit hex into an integer codepoint
|
||||
uint codePoint;
|
||||
if (!(success = UInt32.TryParse(new string(json, index, 4), NumberStyles.HexNumber, CultureInfo.InvariantCulture, out codePoint))) {
|
||||
if (!(success = uint.TryParse(new string(json, index, 4), NumberStyles.HexNumber, CultureInfo.InvariantCulture, out codePoint))) {
|
||||
return "";
|
||||
}
|
||||
// convert the integer codepoint to a unicode char and add to string
|
||||
s.Append(Char.ConvertFromUtf32((int)codePoint));
|
||||
s.Append(char.ConvertFromUtf32((int)codePoint));
|
||||
// skip 4 chars
|
||||
index += 4;
|
||||
} else {
|
||||
|
@ -251,7 +250,7 @@ namespace GreenshotPlugin.Core {
|
|||
int charLength = (lastIndex - index) + 1;
|
||||
|
||||
double number;
|
||||
success = Double.TryParse(new string(json, index, charLength), NumberStyles.Any, CultureInfo.InvariantCulture, out number);
|
||||
success = double.TryParse(new string(json, index, charLength), NumberStyles.Any, CultureInfo.InvariantCulture, out number);
|
||||
|
||||
index = lastIndex + 1;
|
||||
return number;
|
||||
|
|
|
@ -35,21 +35,20 @@ namespace GreenshotPlugin.Core {
|
|||
/// The language resources are loaded from the language files found on fixed or supplied paths
|
||||
/// </summary>
|
||||
public class Language {
|
||||
private static readonly ILog LOG = LogManager.GetLogger(typeof(Language));
|
||||
private static readonly List<string> languagePaths = new List<string>();
|
||||
private static readonly IDictionary<string, List<LanguageFile>> languageFiles = new Dictionary<string, List<LanguageFile>>();
|
||||
private static readonly IDictionary<string, string> helpFiles = new Dictionary<string, string>();
|
||||
private const string DEFAULT_LANGUAGE = "en-US";
|
||||
private const string HELP_FILENAME_PATTERN = @"help-*.html";
|
||||
private const string LANGUAGE_FILENAME_PATTERN = @"language*.xml";
|
||||
private static readonly Regex PREFIX_REGEXP = new Regex(@"language_([a-zA-Z0-9]+).*");
|
||||
private static readonly Regex IETF_CLEAN_REGEXP = new Regex(@"[^a-zA-Z]+");
|
||||
private static readonly Regex IETF_REGEXP = new Regex(@"^.*([a-zA-Z]{2}-[a-zA-Z]{2})\.xml$");
|
||||
private const string LANGUAGE_GROUPS_KEY = @"SYSTEM\CurrentControlSet\Control\Nls\Language Groups";
|
||||
private static readonly List<string> unsupportedLanguageGroups = new List<string>();
|
||||
private static readonly IDictionary<string, string> resources = new Dictionary<string, string>();
|
||||
private static string currentLanguage;
|
||||
private static readonly CoreConfiguration coreConfig;
|
||||
private static readonly ILog Log = LogManager.GetLogger(typeof(Language));
|
||||
private static readonly IList<string> LanguagePaths = new List<string>();
|
||||
private static readonly IDictionary<string, List<LanguageFile>> LanguageFiles = new Dictionary<string, List<LanguageFile>>();
|
||||
private static readonly IDictionary<string, string> HelpFiles = new Dictionary<string, string>();
|
||||
private const string DefaultLanguage = "en-US";
|
||||
private const string HelpFilenamePattern = @"help-*.html";
|
||||
private const string LanguageFilenamePattern = @"language*.xml";
|
||||
private static readonly Regex PrefixRegexp = new Regex(@"language_([a-zA-Z0-9]+).*");
|
||||
private static readonly Regex IetfCleanRegexp = new Regex(@"[^a-zA-Z]+");
|
||||
private static readonly Regex IetfRegexp = new Regex(@"^.*([a-zA-Z]{2}-[a-zA-Z]{2})\.xml$");
|
||||
private const string LanguageGroupsKey = @"SYSTEM\CurrentControlSet\Control\Nls\Language Groups";
|
||||
private static readonly IList<string> UnsupportedLanguageGroups = new List<string>();
|
||||
private static readonly IDictionary<string, string> Resources = new Dictionary<string, string>();
|
||||
private static string _currentLanguage;
|
||||
|
||||
public static event LanguageChangedHandler LanguageChanged;
|
||||
|
||||
|
@ -57,49 +56,55 @@ namespace GreenshotPlugin.Core {
|
|||
/// Static initializer for the language code
|
||||
/// </summary>
|
||||
static Language() {
|
||||
if (!IniConfig.isInitialized) {
|
||||
LOG.Warn("IniConfig hasn't been initialized yet! (Design mode?)");
|
||||
if (!IniConfig.IsInitialized) {
|
||||
Log.Warn("IniConfig hasn't been initialized yet! (Design mode?)");
|
||||
IniConfig.Init("greenshot", "greenshot");
|
||||
}
|
||||
if (!LogHelper.IsInitialized) {
|
||||
LOG.Warn("Log4net hasn't been initialized yet! (Design mode?)");
|
||||
LogHelper.InitializeLog4NET();
|
||||
Log.Warn("Log4net hasn't been initialized yet! (Design mode?)");
|
||||
LogHelper.InitializeLog4Net();
|
||||
}
|
||||
|
||||
try {
|
||||
string applicationDataFolder = Environment.GetFolderPath(Environment.SpecialFolder.ApplicationData);
|
||||
string applicationFolder = Path.GetDirectoryName(Assembly.GetExecutingAssembly().Location);
|
||||
|
||||
// PAF Path
|
||||
AddPath(Path.Combine(applicationFolder, @"App\Greenshot\Languages"));
|
||||
|
||||
if (applicationFolder != null)
|
||||
{
|
||||
AddPath(Path.Combine(applicationFolder, @"App\Greenshot\Languages"));
|
||||
}
|
||||
// Application data path
|
||||
string applicationDataFolder = Environment.GetFolderPath(Environment.SpecialFolder.ApplicationData);
|
||||
AddPath(Path.Combine(applicationDataFolder, @"Greenshot\Languages\"));
|
||||
|
||||
|
||||
// Startup path
|
||||
AddPath(Path.Combine(applicationFolder, @"Languages"));
|
||||
} catch (Exception pathException) {
|
||||
LOG.Error(pathException);
|
||||
if (applicationFolder != null)
|
||||
{
|
||||
AddPath(Path.Combine(applicationFolder, @"Languages"));
|
||||
}
|
||||
}
|
||||
catch (Exception pathException) {
|
||||
Log.Error(pathException);
|
||||
}
|
||||
|
||||
try {
|
||||
using (RegistryKey languageGroupsKey = Registry.LocalMachine.OpenSubKey(LANGUAGE_GROUPS_KEY, false)) {
|
||||
using (RegistryKey languageGroupsKey = Registry.LocalMachine.OpenSubKey(LanguageGroupsKey, false)) {
|
||||
if (languageGroupsKey != null) {
|
||||
string [] groups = languageGroupsKey.GetValueNames();
|
||||
foreach(string group in groups) {
|
||||
string groupValue = (string)languageGroupsKey.GetValue(group);
|
||||
bool isGroupNotInstalled = "0".Equals(groupValue);
|
||||
if (isGroupNotInstalled) {
|
||||
unsupportedLanguageGroups.Add(group.ToLower());
|
||||
UnsupportedLanguageGroups.Add(group.ToLower());
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
} catch(Exception e) {
|
||||
LOG.Warn("Couldn't read the installed language groups.", e);
|
||||
Log.Warn("Couldn't read the installed language groups.", e);
|
||||
}
|
||||
|
||||
coreConfig = IniConfig.GetIniSection<CoreConfiguration>();
|
||||
var coreConfig = IniConfig.GetIniSection<CoreConfiguration>();
|
||||
ScanFiles();
|
||||
if (!string.IsNullOrEmpty(coreConfig.Language)) {
|
||||
CurrentLanguage = coreConfig.Language;
|
||||
|
@ -109,15 +114,15 @@ namespace GreenshotPlugin.Core {
|
|||
}
|
||||
|
||||
if (CurrentLanguage == null) {
|
||||
LOG.Warn("Couldn't set language from configuration, changing to default. Installation problem?");
|
||||
CurrentLanguage = DEFAULT_LANGUAGE;
|
||||
Log.Warn("Couldn't set language from configuration, changing to default. Installation problem?");
|
||||
CurrentLanguage = DefaultLanguage;
|
||||
if (CurrentLanguage != null) {
|
||||
coreConfig.Language = CurrentLanguage;
|
||||
}
|
||||
}
|
||||
|
||||
if (CurrentLanguage == null) {
|
||||
LOG.Error("Couldn't set language, installation problem?");
|
||||
Log.Error("Couldn't set language, installation problem?");
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -127,13 +132,13 @@ namespace GreenshotPlugin.Core {
|
|||
/// <param name="path"></param>
|
||||
/// <returns>true if the path exists and is added</returns>
|
||||
private static bool AddPath(string path) {
|
||||
if (!languagePaths.Contains(path)) {
|
||||
if (!LanguagePaths.Contains(path)) {
|
||||
if (Directory.Exists(path)) {
|
||||
LOG.DebugFormat("Adding language path {0}", path);
|
||||
languagePaths.Add(path);
|
||||
Log.DebugFormat("Adding language path {0}", path);
|
||||
LanguagePaths.Add(path);
|
||||
return true;
|
||||
} else {
|
||||
LOG.InfoFormat("Not adding non existing language path {0}", path);
|
||||
Log.InfoFormat("Not adding non existing language path {0}", path);
|
||||
}
|
||||
}
|
||||
return false;
|
||||
|
@ -145,8 +150,8 @@ namespace GreenshotPlugin.Core {
|
|||
/// <param name="path"></param>
|
||||
/// <returns>true if the path exists and is added</returns>
|
||||
public static bool AddLanguageFilePath(string path) {
|
||||
if (!languagePaths.Contains(path)) {
|
||||
LOG.DebugFormat("New language path {0}", path);
|
||||
if (!LanguagePaths.Contains(path)) {
|
||||
Log.DebugFormat("New language path {0}", path);
|
||||
if (AddPath(path)) {
|
||||
ScanFiles();
|
||||
Reload();
|
||||
|
@ -163,11 +168,11 @@ namespace GreenshotPlugin.Core {
|
|||
/// <param name="ietf"></param>
|
||||
private static void LoadFiles(string ietf) {
|
||||
ietf = ReformatIETF(ietf);
|
||||
if (!languageFiles.ContainsKey(ietf)) {
|
||||
LOG.ErrorFormat("No language {0} available.", ietf);
|
||||
if (!LanguageFiles.ContainsKey(ietf)) {
|
||||
Log.ErrorFormat("No language {0} available.", ietf);
|
||||
return;
|
||||
}
|
||||
List<LanguageFile> filesToLoad = languageFiles[ietf];
|
||||
List<LanguageFile> filesToLoad = LanguageFiles[ietf];
|
||||
foreach (LanguageFile fileToLoad in filesToLoad) {
|
||||
LoadResources(fileToLoad);
|
||||
}
|
||||
|
@ -177,10 +182,10 @@ namespace GreenshotPlugin.Core {
|
|||
/// Load the language resources from the scanned files
|
||||
/// </summary>
|
||||
private static void Reload() {
|
||||
resources.Clear();
|
||||
LoadFiles(DEFAULT_LANGUAGE);
|
||||
if (currentLanguage != null && !currentLanguage.Equals(DEFAULT_LANGUAGE)) {
|
||||
LoadFiles(currentLanguage);
|
||||
Resources.Clear();
|
||||
LoadFiles(DefaultLanguage);
|
||||
if (_currentLanguage != null && !_currentLanguage.Equals(DefaultLanguage)) {
|
||||
LoadFiles(_currentLanguage);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -189,26 +194,31 @@ namespace GreenshotPlugin.Core {
|
|||
/// </summary>
|
||||
public static string CurrentLanguage {
|
||||
get {
|
||||
return currentLanguage;
|
||||
return _currentLanguage;
|
||||
}
|
||||
set {
|
||||
string ietf = FindBestIETFMatch(value);
|
||||
if (!languageFiles.ContainsKey(ietf)) {
|
||||
LOG.WarnFormat("No match for language {0} found!", ietf);
|
||||
if (!LanguageFiles.ContainsKey(ietf)) {
|
||||
Log.WarnFormat("No match for language {0} found!", ietf);
|
||||
} else {
|
||||
if (currentLanguage == null || !currentLanguage.Equals(ietf)) {
|
||||
currentLanguage = ietf;
|
||||
if (_currentLanguage == null || !_currentLanguage.Equals(ietf)) {
|
||||
_currentLanguage = ietf;
|
||||
Reload();
|
||||
if (LanguageChanged != null) {
|
||||
try {
|
||||
LanguageChanged(null, null);
|
||||
} catch {
|
||||
}
|
||||
if (LanguageChanged == null)
|
||||
{
|
||||
return;
|
||||
}
|
||||
try {
|
||||
LanguageChanged(null, null);
|
||||
}
|
||||
catch
|
||||
{
|
||||
// ignored
|
||||
}
|
||||
return;
|
||||
}
|
||||
}
|
||||
LOG.Debug("CurrentLanguage not changed!");
|
||||
Log.Debug("CurrentLanguage not changed!");
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -220,17 +230,17 @@ namespace GreenshotPlugin.Core {
|
|||
private static string FindBestIETFMatch(string inputIETF) {
|
||||
string returnIETF = inputIETF;
|
||||
if (string.IsNullOrEmpty(returnIETF)) {
|
||||
returnIETF = DEFAULT_LANGUAGE;
|
||||
returnIETF = DefaultLanguage;
|
||||
}
|
||||
returnIETF = ReformatIETF(returnIETF);
|
||||
if (!languageFiles.ContainsKey(returnIETF)) {
|
||||
LOG.WarnFormat("Unknown language {0}, trying best match!", returnIETF);
|
||||
if (!LanguageFiles.ContainsKey(returnIETF)) {
|
||||
Log.WarnFormat("Unknown language {0}, trying best match!", returnIETF);
|
||||
if (returnIETF.Length == 5) {
|
||||
returnIETF = returnIETF.Substring(0, 2);
|
||||
}
|
||||
foreach (string availableIETF in languageFiles.Keys) {
|
||||
foreach (string availableIETF in LanguageFiles.Keys) {
|
||||
if (availableIETF.StartsWith(returnIETF)) {
|
||||
LOG.InfoFormat("Found language {0}, best match for {1}!", availableIETF, returnIETF);
|
||||
Log.InfoFormat("Found language {0}, best match for {1}!", availableIETF, returnIETF);
|
||||
returnIETF = availableIETF;
|
||||
break;
|
||||
}
|
||||
|
@ -249,7 +259,7 @@ namespace GreenshotPlugin.Core {
|
|||
string returnIETF = null;
|
||||
if (!string.IsNullOrEmpty(inputIETF)) {
|
||||
returnIETF = inputIETF.ToLower();
|
||||
returnIETF = IETF_CLEAN_REGEXP.Replace(returnIETF, "");
|
||||
returnIETF = IetfCleanRegexp.Replace(returnIETF, "");
|
||||
if (returnIETF.Length == 4) {
|
||||
returnIETF = returnIETF.Substring(0, 2) + "-" + returnIETF.Substring(2, 2).ToUpper();
|
||||
}
|
||||
|
@ -264,7 +274,7 @@ namespace GreenshotPlugin.Core {
|
|||
get {
|
||||
IList<LanguageFile> languages = new List<LanguageFile>();
|
||||
// Loop over all languages with all the files in there
|
||||
foreach (List<LanguageFile> langs in languageFiles.Values) {
|
||||
foreach (List<LanguageFile> langs in LanguageFiles.Values) {
|
||||
// Loop over all the files for a language
|
||||
foreach (LanguageFile langFile in langs) {
|
||||
// Only take the ones without prefix, these are the "base" language files
|
||||
|
@ -283,10 +293,10 @@ namespace GreenshotPlugin.Core {
|
|||
/// </summary>
|
||||
public static string HelpFilePath {
|
||||
get {
|
||||
if (helpFiles.ContainsKey(currentLanguage)) {
|
||||
return helpFiles[currentLanguage];
|
||||
if (HelpFiles.ContainsKey(_currentLanguage)) {
|
||||
return HelpFiles[_currentLanguage];
|
||||
}
|
||||
return helpFiles[DEFAULT_LANGUAGE];
|
||||
return HelpFiles[DefaultLanguage];
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -295,7 +305,7 @@ namespace GreenshotPlugin.Core {
|
|||
/// </summary>
|
||||
/// <param name="languageFile">File to load from</param>
|
||||
private static void LoadResources(LanguageFile languageFile) {
|
||||
LOG.InfoFormat("Loading language file {0}", languageFile.Filepath);
|
||||
Log.InfoFormat("Loading language file {0}", languageFile.Filepath);
|
||||
try {
|
||||
XmlDocument xmlDocument = new XmlDocument();
|
||||
xmlDocument.Load(languageFile.Filepath);
|
||||
|
@ -309,14 +319,14 @@ namespace GreenshotPlugin.Core {
|
|||
if (!string.IsNullOrEmpty(text)) {
|
||||
text = text.Trim();
|
||||
}
|
||||
if (!resources.ContainsKey(key)) {
|
||||
resources.Add(key, text);
|
||||
if (!Resources.ContainsKey(key)) {
|
||||
Resources.Add(key, text);
|
||||
} else {
|
||||
resources[key] = text;
|
||||
Resources[key] = text;
|
||||
}
|
||||
}
|
||||
} catch (Exception e) {
|
||||
LOG.Error("Could not load language file " + languageFile.Filepath, e);
|
||||
Log.Error("Could not load language file " + languageFile.Filepath, e);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -334,26 +344,28 @@ namespace GreenshotPlugin.Core {
|
|||
LanguageFile languageFile = new LanguageFile();
|
||||
languageFile.Filepath = languageFilePath;
|
||||
XmlNode node = nodes.Item(0);
|
||||
languageFile.Description = node.Attributes["description"].Value;
|
||||
if (node.Attributes["ietf"] != null) {
|
||||
languageFile.Ietf = ReformatIETF(node.Attributes["ietf"].Value);
|
||||
}
|
||||
if (node.Attributes["version"] != null) {
|
||||
languageFile.Version = new Version(node.Attributes["version"].Value);
|
||||
}
|
||||
if (node.Attributes["prefix"] != null) {
|
||||
languageFile.Prefix = node.Attributes["prefix"].Value.ToLower();
|
||||
}
|
||||
if (node.Attributes["languagegroup"] != null) {
|
||||
string languageGroup = node.Attributes["languagegroup"].Value;
|
||||
languageFile.LanguageGroup = languageGroup.ToLower();
|
||||
if (node?.Attributes != null)
|
||||
{
|
||||
languageFile.Description = node.Attributes["description"].Value;
|
||||
if (node.Attributes["ietf"] != null) {
|
||||
languageFile.Ietf = ReformatIETF(node.Attributes["ietf"].Value);
|
||||
}
|
||||
if (node.Attributes["version"] != null) {
|
||||
languageFile.Version = new Version(node.Attributes["version"].Value);
|
||||
}
|
||||
if (node.Attributes["prefix"] != null) {
|
||||
languageFile.Prefix = node.Attributes["prefix"].Value.ToLower();
|
||||
}
|
||||
if (node.Attributes["languagegroup"] != null) {
|
||||
string languageGroup = node.Attributes["languagegroup"].Value;
|
||||
languageFile.LanguageGroup = languageGroup.ToLower();
|
||||
}
|
||||
}
|
||||
return languageFile;
|
||||
} else {
|
||||
throw new XmlException("Root element <language> is missing");
|
||||
}
|
||||
throw new XmlException("Root element <language> is missing");
|
||||
} catch (Exception e) {
|
||||
LOG.Error("Could not load language file " + languageFilePath, e);
|
||||
Log.Error("Could not load language file " + languageFilePath, e);
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
@ -362,63 +374,63 @@ namespace GreenshotPlugin.Core {
|
|||
/// Scan the files in all directories
|
||||
/// </summary>
|
||||
private static void ScanFiles() {
|
||||
languageFiles.Clear();
|
||||
helpFiles.Clear();
|
||||
foreach (string languagePath in languagePaths) {
|
||||
LanguageFiles.Clear();
|
||||
HelpFiles.Clear();
|
||||
foreach (string languagePath in LanguagePaths) {
|
||||
if (!Directory.Exists(languagePath)) {
|
||||
LOG.InfoFormat("Skipping non existing language path {0}", languagePath);
|
||||
Log.InfoFormat("Skipping non existing language path {0}", languagePath);
|
||||
continue;
|
||||
}
|
||||
LOG.InfoFormat("Searching language directory '{0}' for language files with pattern '{1}'", languagePath, LANGUAGE_FILENAME_PATTERN);
|
||||
Log.InfoFormat("Searching language directory '{0}' for language files with pattern '{1}'", languagePath, LanguageFilenamePattern);
|
||||
try {
|
||||
foreach (string languageFilepath in Directory.GetFiles(languagePath, LANGUAGE_FILENAME_PATTERN, SearchOption.AllDirectories)) {
|
||||
foreach (string languageFilepath in Directory.GetFiles(languagePath, LanguageFilenamePattern, SearchOption.AllDirectories)) {
|
||||
//LOG.DebugFormat("Found language file: {0}", languageFilepath);
|
||||
LanguageFile languageFile = LoadFileInfo(languageFilepath);
|
||||
if (languageFile == null) {
|
||||
continue;
|
||||
}
|
||||
if (string.IsNullOrEmpty(languageFile.Ietf)) {
|
||||
LOG.WarnFormat("Fixing missing ietf in language-file {0}", languageFilepath);
|
||||
Log.WarnFormat("Fixing missing ietf in language-file {0}", languageFilepath);
|
||||
string languageFilename = Path.GetFileName(languageFilepath);
|
||||
if (IETF_REGEXP.IsMatch(languageFilename)) {
|
||||
string replacementIETF = IETF_REGEXP.Replace(languageFilename, "$1");
|
||||
if (IetfRegexp.IsMatch(languageFilename)) {
|
||||
string replacementIETF = IetfRegexp.Replace(languageFilename, "$1");
|
||||
languageFile.Ietf = ReformatIETF(replacementIETF);
|
||||
LOG.InfoFormat("Fixed IETF to {0}", languageFile.Ietf);
|
||||
Log.InfoFormat("Fixed IETF to {0}", languageFile.Ietf);
|
||||
} else {
|
||||
LOG.ErrorFormat("Missing ietf , no recover possible... skipping language-file {0}!", languageFilepath);
|
||||
Log.ErrorFormat("Missing ietf , no recover possible... skipping language-file {0}!", languageFilepath);
|
||||
continue;
|
||||
}
|
||||
}
|
||||
|
||||
// Check if we can display the file
|
||||
if (!string.IsNullOrEmpty(languageFile.LanguageGroup) && unsupportedLanguageGroups.Contains(languageFile.LanguageGroup)) {
|
||||
LOG.InfoFormat("Skipping unsuported (not able to display) language {0} from file {1}", languageFile.Description, languageFilepath);
|
||||
if (!string.IsNullOrEmpty(languageFile.LanguageGroup) && UnsupportedLanguageGroups.Contains(languageFile.LanguageGroup)) {
|
||||
Log.InfoFormat("Skipping unsuported (not able to display) language {0} from file {1}", languageFile.Description, languageFilepath);
|
||||
continue;
|
||||
}
|
||||
|
||||
// build prefix, based on the filename, but only if it's not set in the file itself.
|
||||
if (string.IsNullOrEmpty(languageFile.Prefix)) {
|
||||
string languageFilename = Path.GetFileNameWithoutExtension(languageFilepath);
|
||||
if (PREFIX_REGEXP.IsMatch(languageFilename)) {
|
||||
languageFile.Prefix = PREFIX_REGEXP.Replace(languageFilename, "$1");
|
||||
if (PrefixRegexp.IsMatch(languageFilename)) {
|
||||
languageFile.Prefix = PrefixRegexp.Replace(languageFilename, "$1");
|
||||
if (!string.IsNullOrEmpty(languageFile.Prefix)) {
|
||||
languageFile.Prefix = languageFile.Prefix.Replace("plugin", "").ToLower();
|
||||
}
|
||||
}
|
||||
}
|
||||
List<LanguageFile> currentFiles = null;
|
||||
if (languageFiles.ContainsKey(languageFile.Ietf)) {
|
||||
currentFiles = languageFiles[languageFile.Ietf];
|
||||
if (LanguageFiles.ContainsKey(languageFile.Ietf)) {
|
||||
currentFiles = LanguageFiles[languageFile.Ietf];
|
||||
bool needToAdd = true;
|
||||
List<LanguageFile> deleteList = new List<LanguageFile>();
|
||||
foreach (LanguageFile compareWithLangfile in currentFiles) {
|
||||
if ((languageFile.Prefix == null && compareWithLangfile.Prefix == null) || (languageFile.Prefix != null && languageFile.Prefix.Equals(compareWithLangfile.Prefix))) {
|
||||
if (compareWithLangfile.Version > languageFile.Version) {
|
||||
LOG.WarnFormat("Skipping {0}:{1}:{2} as {3}:{4}:{5} is newer", languageFile.Filepath, languageFile.Prefix, languageFile.Version, compareWithLangfile.Filepath, compareWithLangfile.Prefix, compareWithLangfile.Version);
|
||||
Log.WarnFormat("Skipping {0}:{1}:{2} as {3}:{4}:{5} is newer", languageFile.Filepath, languageFile.Prefix, languageFile.Version, compareWithLangfile.Filepath, compareWithLangfile.Prefix, compareWithLangfile.Version);
|
||||
needToAdd = false;
|
||||
break;
|
||||
} else {
|
||||
LOG.WarnFormat("Found {0}:{1}:{2} and deleting {3}:{4}:{5}", languageFile.Filepath, languageFile.Prefix, languageFile.Version, compareWithLangfile.Filepath, compareWithLangfile.Prefix, compareWithLangfile.Version);
|
||||
Log.WarnFormat("Found {0}:{1}:{2} and deleting {3}:{4}:{5}", languageFile.Filepath, languageFile.Prefix, languageFile.Version, compareWithLangfile.Filepath, compareWithLangfile.Prefix, compareWithLangfile.Version);
|
||||
deleteList.Add(compareWithLangfile);
|
||||
}
|
||||
}
|
||||
|
@ -427,39 +439,38 @@ namespace GreenshotPlugin.Core {
|
|||
foreach (LanguageFile deleteFile in deleteList) {
|
||||
currentFiles.Remove(deleteFile);
|
||||
}
|
||||
LOG.InfoFormat("Added language definition {0} from: {1}", languageFile.Description, languageFile.Filepath);
|
||||
Log.InfoFormat("Added language definition {0} from: {1}", languageFile.Description, languageFile.Filepath);
|
||||
currentFiles.Add(languageFile);
|
||||
}
|
||||
} else {
|
||||
currentFiles = new List<LanguageFile>();
|
||||
currentFiles.Add(languageFile);
|
||||
languageFiles.Add(languageFile.Ietf, currentFiles);
|
||||
LOG.InfoFormat("Added language definition {0} from: {1}", languageFile.Description, languageFile.Filepath);
|
||||
currentFiles = new List<LanguageFile> {languageFile};
|
||||
LanguageFiles.Add(languageFile.Ietf, currentFiles);
|
||||
Log.InfoFormat("Added language definition {0} from: {1}", languageFile.Description, languageFile.Filepath);
|
||||
}
|
||||
}
|
||||
} catch (DirectoryNotFoundException) {
|
||||
LOG.InfoFormat("Non existing language directory: {0}", languagePath);
|
||||
Log.InfoFormat("Non existing language directory: {0}", languagePath);
|
||||
} catch (Exception e) {
|
||||
LOG.Error("Error trying for read directory " + languagePath, e);
|
||||
Log.Error("Error trying for read directory " + languagePath, e);
|
||||
}
|
||||
|
||||
// Now find the help files
|
||||
LOG.InfoFormat("Searching language directory '{0}' for help files with pattern '{1}'", languagePath, HELP_FILENAME_PATTERN);
|
||||
Log.InfoFormat("Searching language directory '{0}' for help files with pattern '{1}'", languagePath, HelpFilenamePattern);
|
||||
try {
|
||||
foreach (string helpFilepath in Directory.GetFiles(languagePath, HELP_FILENAME_PATTERN, SearchOption.AllDirectories)) {
|
||||
LOG.DebugFormat("Found help file: {0}", helpFilepath);
|
||||
foreach (string helpFilepath in Directory.GetFiles(languagePath, HelpFilenamePattern, SearchOption.AllDirectories)) {
|
||||
Log.DebugFormat("Found help file: {0}", helpFilepath);
|
||||
string helpFilename = Path.GetFileName(helpFilepath);
|
||||
string ietf = ReformatIETF(helpFilename.Replace(".html", "").Replace("help-", ""));
|
||||
if (!helpFiles.ContainsKey(ietf)) {
|
||||
helpFiles.Add(ietf, helpFilepath);
|
||||
if (!HelpFiles.ContainsKey(ietf)) {
|
||||
HelpFiles.Add(ietf, helpFilepath);
|
||||
} else {
|
||||
LOG.WarnFormat("skipping help file {0}, already a file with the same IETF {1} found!", helpFilepath, ietf);
|
||||
Log.WarnFormat("skipping help file {0}, already a file with the same IETF {1} found!", helpFilepath, ietf);
|
||||
}
|
||||
}
|
||||
} catch (DirectoryNotFoundException) {
|
||||
LOG.InfoFormat("Non existing language directory: {0}", languagePath);
|
||||
Log.InfoFormat("Non existing language directory: {0}", languagePath);
|
||||
} catch (Exception e) {
|
||||
LOG.Error("Error trying for read directory " + languagePath, e);
|
||||
Log.Error("Error trying for read directory " + languagePath, e);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -470,11 +481,11 @@ namespace GreenshotPlugin.Core {
|
|||
/// <param name="prefix"></param>
|
||||
/// <param name="key"></param>
|
||||
/// <returns>true if available</returns>
|
||||
public static bool hasKey(string prefix, Enum key) {
|
||||
public static bool HasKey(string prefix, Enum key) {
|
||||
if (key == null) {
|
||||
return false;
|
||||
}
|
||||
return hasKey(prefix + "." + key);
|
||||
return HasKey(prefix + "." + key);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
|
@ -482,11 +493,11 @@ namespace GreenshotPlugin.Core {
|
|||
/// </summary>
|
||||
/// <param name="key"></param>
|
||||
/// <returns>true if available</returns>
|
||||
public static bool hasKey(Enum key) {
|
||||
public static bool HasKey(Enum key) {
|
||||
if (key == null) {
|
||||
return false;
|
||||
}
|
||||
return hasKey(key.ToString());
|
||||
return HasKey(key.ToString());
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
|
@ -495,8 +506,8 @@ namespace GreenshotPlugin.Core {
|
|||
/// <param name="prefix"></param>
|
||||
/// <param name="key"></param>
|
||||
/// <returns>true if available</returns>
|
||||
public static bool hasKey(string prefix, string key) {
|
||||
return hasKey(prefix + "." + key);
|
||||
public static bool HasKey(string prefix, string key) {
|
||||
return HasKey(prefix + "." + key);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
|
@ -504,36 +515,36 @@ namespace GreenshotPlugin.Core {
|
|||
/// </summary>
|
||||
/// <param name="key"></param>
|
||||
/// <returns>true if available</returns>
|
||||
public static bool hasKey(string key) {
|
||||
public static bool HasKey(string key) {
|
||||
if (key == null) {
|
||||
return false;
|
||||
}
|
||||
return resources.ContainsKey(key);
|
||||
return Resources.ContainsKey(key);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// TryGet method which combines hasKey & GetString
|
||||
/// TryGet method which combines HasKey & GetString
|
||||
/// </summary>
|
||||
/// <param name="key"></param>
|
||||
/// <param name="languageString">out string</param>
|
||||
/// <returns></returns>
|
||||
public static bool TryGetString(string key, out string languageString) {
|
||||
return resources.TryGetValue(key, out languageString);
|
||||
return Resources.TryGetValue(key, out languageString);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// TryGet method which combines hasKey & GetString
|
||||
/// TryGet method which combines HasKey & GetString
|
||||
/// </summary>
|
||||
/// <param name="prefix">string with prefix</param>
|
||||
/// <param name="key">string with key</param>
|
||||
/// <param name="languageString">out string</param>
|
||||
/// <returns></returns>
|
||||
public static bool TryGetString(string prefix, string key, out string languageString) {
|
||||
return resources.TryGetValue(prefix + "." + key, out languageString);
|
||||
return Resources.TryGetValue(prefix + "." + key, out languageString);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// TryGet method which combines hasKey & GetString
|
||||
/// TryGet method which combines HasKey & GetString
|
||||
/// </summary>
|
||||
/// <param name="prefix">string with prefix</param>
|
||||
/// <param name="key">Enum with key</param>
|
||||
|
@ -541,14 +552,14 @@ namespace GreenshotPlugin.Core {
|
|||
/// <returns></returns>
|
||||
public static bool TryGetString(string prefix, Enum key, out string languageString)
|
||||
{
|
||||
return resources.TryGetValue(prefix + "." + key, out languageString);
|
||||
return Resources.TryGetValue(prefix + "." + key, out languageString);
|
||||
}
|
||||
|
||||
|
||||
public static string Translate(object key) {
|
||||
string typename = key.GetType().Name;
|
||||
string enumKey = typename + "." + key;
|
||||
if (hasKey(enumKey)) {
|
||||
if (HasKey(enumKey)) {
|
||||
return GetString(enumKey);
|
||||
}
|
||||
return key.ToString();
|
||||
|
@ -599,7 +610,7 @@ namespace GreenshotPlugin.Core {
|
|||
return null;
|
||||
}
|
||||
string returnValue;
|
||||
if (!resources.TryGetValue(key, out returnValue)) {
|
||||
if (!Resources.TryGetValue(key, out returnValue)) {
|
||||
return "string ###" + key + "### not found";
|
||||
}
|
||||
return returnValue;
|
||||
|
@ -645,7 +656,7 @@ namespace GreenshotPlugin.Core {
|
|||
/// <returns>formatted resource or a "string ###key### not found"</returns>
|
||||
public static string GetFormattedString(string key, object param) {
|
||||
string returnValue;
|
||||
if (!resources.TryGetValue(key, out returnValue)) {
|
||||
if (!Resources.TryGetValue(key, out returnValue)) {
|
||||
return "string ###" + key + "### not found";
|
||||
}
|
||||
return string.Format(returnValue, param);
|
||||
|
@ -693,31 +704,31 @@ namespace GreenshotPlugin.Core {
|
|||
/// <returns></returns>
|
||||
public bool Equals(LanguageFile other) {
|
||||
if (Prefix != null) {
|
||||
if (!Prefix.Equals(other.Prefix)) {
|
||||
if (other != null && !Prefix.Equals(other.Prefix)) {
|
||||
return false;
|
||||
}
|
||||
} else if (other.Prefix != null) {
|
||||
} else if (other?.Prefix != null) {
|
||||
return false;
|
||||
}
|
||||
if (Ietf != null) {
|
||||
if (!Ietf.Equals(other.Ietf)) {
|
||||
if (other != null && !Ietf.Equals(other.Ietf)) {
|
||||
return false;
|
||||
}
|
||||
} else if (other.Ietf != null) {
|
||||
} else if (other?.Ietf != null) {
|
||||
return false;
|
||||
}
|
||||
if (Version != null) {
|
||||
if (!Version.Equals(other.Version)) {
|
||||
if (other != null && !Version.Equals(other.Version)) {
|
||||
return false;
|
||||
}
|
||||
} else if (other.Version != null) {
|
||||
} else if (other != null && other.Version != null) {
|
||||
return false;
|
||||
}
|
||||
if (Filepath != null) {
|
||||
if (!Filepath.Equals(other.Filepath)) {
|
||||
if (other != null && !Filepath.Equals(other.Filepath)) {
|
||||
return false;
|
||||
}
|
||||
} else if (other.Filepath != null) {
|
||||
} else if (other?.Filepath != null) {
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
|
|
|
@ -37,16 +37,12 @@ namespace GreenshotPlugin.Core {
|
|||
/// </summary>
|
||||
public class LogHelper {
|
||||
private static bool _isLog4NetConfigured;
|
||||
private const string INIT_MESSAGE = "Greenshot initialization of log system failed";
|
||||
private const string InitMessage = "Greenshot initialization of log system failed";
|
||||
|
||||
public static bool IsInitialized {
|
||||
get {
|
||||
return _isLog4NetConfigured;
|
||||
}
|
||||
}
|
||||
public static bool IsInitialized => _isLog4NetConfigured;
|
||||
|
||||
// Initialize Log4J
|
||||
public static string InitializeLog4NET() {
|
||||
public static string InitializeLog4Net() {
|
||||
// Setup log4j, currently the file is called log4net.xml
|
||||
foreach (var logName in new[] { "log4net.xml" , @"App\Greenshot\log4net-portable.xml"})
|
||||
{
|
||||
|
@ -60,7 +56,7 @@ namespace GreenshotPlugin.Core {
|
|||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
MessageBox.Show(ex.Message, INIT_MESSAGE, MessageBoxButtons.OK, MessageBoxIcon.Warning);
|
||||
MessageBox.Show(ex.Message, InitMessage, MessageBoxButtons.OK, MessageBoxIcon.Warning);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -74,7 +70,7 @@ namespace GreenshotPlugin.Core {
|
|||
IniConfig.ForceIniInStartupPath();
|
||||
}
|
||||
} catch (Exception ex){
|
||||
MessageBox.Show(ex.Message, INIT_MESSAGE, MessageBoxButtons.OK, MessageBoxIcon.Warning);
|
||||
MessageBox.Show(ex.Message, InitMessage, MessageBoxButtons.OK, MessageBoxIcon.Warning);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -82,13 +78,19 @@ namespace GreenshotPlugin.Core {
|
|||
// Get the logfile name
|
||||
try {
|
||||
if (((Hierarchy)LogManager.GetRepository()).Root.Appenders.Count > 0) {
|
||||
foreach (IAppender appender in ((Hierarchy)LogManager.GetRepository()).Root.Appenders) {
|
||||
if (appender is FileAppender) {
|
||||
return ((FileAppender)appender).File;
|
||||
foreach (IAppender appender in ((Hierarchy)LogManager.GetRepository()).Root.Appenders)
|
||||
{
|
||||
var fileAppender = appender as FileAppender;
|
||||
if (fileAppender != null) {
|
||||
return fileAppender.File;
|
||||
}
|
||||
}
|
||||
}
|
||||
} catch {}
|
||||
}
|
||||
catch
|
||||
{
|
||||
// ignored
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
|
|
@ -47,7 +47,7 @@ namespace GreenshotPlugin.Core {
|
|||
/// Description of NetworkHelper.
|
||||
/// </summary>
|
||||
public static class NetworkHelper {
|
||||
private static readonly ILog LOG = LogManager.GetLogger(typeof(NetworkHelper));
|
||||
private static readonly ILog Log = LogManager.GetLogger(typeof(NetworkHelper));
|
||||
private static readonly CoreConfiguration Config = IniConfig.GetIniSection<CoreConfiguration>();
|
||||
|
||||
static NetworkHelper() {
|
||||
|
@ -60,7 +60,7 @@ namespace GreenshotPlugin.Core {
|
|||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
LOG.Warn("An error has occured while allowing self-signed certificates:", ex);
|
||||
Log.Warn("An error has occured while allowing self-signed certificates:", ex);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -99,7 +99,7 @@ namespace GreenshotPlugin.Core {
|
|||
}
|
||||
}
|
||||
} catch (Exception e) {
|
||||
LOG.Error("Problem downloading the FavIcon from: " + baseUri, e);
|
||||
Log.Error("Problem downloading the FavIcon from: " + baseUri, e);
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
@ -114,9 +114,7 @@ namespace GreenshotPlugin.Core {
|
|||
using (HttpWebResponse response = (HttpWebResponse)request.GetResponse()) {
|
||||
MemoryStream memoryStream = new MemoryStream();
|
||||
using (Stream responseStream = response.GetResponseStream()) {
|
||||
if (responseStream != null) {
|
||||
responseStream.CopyTo(memoryStream);
|
||||
}
|
||||
responseStream?.CopyTo(memoryStream);
|
||||
// Make sure it can be used directly
|
||||
memoryStream.Seek(0, SeekOrigin.Begin);
|
||||
}
|
||||
|
@ -178,7 +176,7 @@ namespace GreenshotPlugin.Core {
|
|||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
LOG.Error("Problem downloading the image from: " + url, e);
|
||||
Log.Error("Problem downloading the image from: " + url, e);
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
@ -246,21 +244,21 @@ namespace GreenshotPlugin.Core {
|
|||
proxyToUse = WebRequest.DefaultWebProxy;
|
||||
if (proxyToUse != null) {
|
||||
proxyToUse.Credentials = CredentialCache.DefaultCredentials;
|
||||
if (LOG.IsDebugEnabled) {
|
||||
if (Log.IsDebugEnabled) {
|
||||
// check the proxy for the Uri
|
||||
if (!proxyToUse.IsBypassed(uri)) {
|
||||
Uri proxyUri = proxyToUse.GetProxy(uri);
|
||||
if (proxyUri != null) {
|
||||
LOG.Debug("Using proxy: " + proxyUri + " for " + uri);
|
||||
Log.Debug("Using proxy: " + proxyUri + " for " + uri);
|
||||
} else {
|
||||
LOG.Debug("No proxy found!");
|
||||
Log.Debug("No proxy found!");
|
||||
}
|
||||
} else {
|
||||
LOG.Debug("Proxy bypass for: " + uri);
|
||||
Log.Debug("Proxy bypass for: " + uri);
|
||||
}
|
||||
}
|
||||
} else {
|
||||
LOG.Debug("No proxy found!");
|
||||
Log.Debug("No proxy found!");
|
||||
}
|
||||
}
|
||||
return proxyToUse;
|
||||
|
@ -350,7 +348,7 @@ namespace GreenshotPlugin.Core {
|
|||
|
||||
StringBuilder sb = new StringBuilder();
|
||||
foreach(string key in queryParameters.Keys) {
|
||||
sb.AppendFormat(CultureInfo.InvariantCulture, "{0}={1}&", key, UrlEncode(string.Format("{0}",queryParameters[key])));
|
||||
sb.AppendFormat(CultureInfo.InvariantCulture, "{0}={1}&", key, UrlEncode($"{queryParameters[key]}"));
|
||||
}
|
||||
sb.Remove(sb.Length-1,1);
|
||||
|
||||
|
@ -363,7 +361,7 @@ namespace GreenshotPlugin.Core {
|
|||
/// <param name="webRequest">HttpWebRequest to write the multipart form data to</param>
|
||||
/// <param name="postParameters">Parameters to include in the multipart form data</param>
|
||||
public static void WriteMultipartFormData(HttpWebRequest webRequest, IDictionary<string, object> postParameters) {
|
||||
string boundary = string.Format("----------{0:N}", Guid.NewGuid());
|
||||
string boundary = $"----------{Guid.NewGuid():N}";
|
||||
webRequest.ContentType = "multipart/form-data; boundary=" + boundary;
|
||||
using (Stream formDataStream = webRequest.GetRequestStream()) {
|
||||
WriteMultipartFormData(formDataStream, boundary, postParameters);
|
||||
|
@ -376,7 +374,7 @@ namespace GreenshotPlugin.Core {
|
|||
/// <param name="response">HttpListenerResponse</param>
|
||||
/// <param name="postParameters">Parameters to include in the multipart form data</param>
|
||||
public static void WriteMultipartFormData(HttpListenerResponse response, IDictionary<string, object> postParameters) {
|
||||
string boundary = string.Format("----------{0:N}", Guid.NewGuid());
|
||||
string boundary = $"----------{Guid.NewGuid():N}";
|
||||
response.ContentType = "multipart/form-data; boundary=" + boundary;
|
||||
WriteMultipartFormData(response.OutputStream, boundary, postParameters);
|
||||
}
|
||||
|
@ -398,14 +396,11 @@ namespace GreenshotPlugin.Core {
|
|||
|
||||
needsClrf = true;
|
||||
|
||||
if (param.Value is IBinaryContainer) {
|
||||
IBinaryContainer binaryParameter = (IBinaryContainer)param.Value;
|
||||
binaryParameter.WriteFormDataToStream(boundary, param.Key, formDataStream);
|
||||
var binaryContainer = param.Value as IBinaryContainer;
|
||||
if (binaryContainer != null) {
|
||||
binaryContainer.WriteFormDataToStream(boundary, param.Key, formDataStream);
|
||||
} else {
|
||||
string postData = string.Format("--{0}\r\nContent-Disposition: form-data; name=\"{1}\"\r\n\r\n{2}",
|
||||
boundary,
|
||||
param.Key,
|
||||
param.Value);
|
||||
string postData = $"--{boundary}\r\nContent-Disposition: form-data; name=\"{param.Key}\"\r\n\r\n{param.Value}";
|
||||
formDataStream.Write(Encoding.UTF8.GetBytes(postData), 0, Encoding.UTF8.GetByteCount(postData));
|
||||
}
|
||||
}
|
||||
|
@ -435,12 +430,12 @@ namespace GreenshotPlugin.Core {
|
|||
/// </summary>
|
||||
/// <param name="response">WebResponse</param>
|
||||
private static void DebugHeaders(WebResponse response) {
|
||||
if (!LOG.IsDebugEnabled) {
|
||||
if (!Log.IsDebugEnabled) {
|
||||
return;
|
||||
}
|
||||
LOG.DebugFormat("Debug information on the response from {0} :", response.ResponseUri);
|
||||
Log.DebugFormat("Debug information on the response from {0} :", response.ResponseUri);
|
||||
foreach (string key in response.Headers.AllKeys) {
|
||||
LOG.DebugFormat("Reponse-header: {0}={1}", key, response.Headers[key]);
|
||||
Log.DebugFormat("Reponse-header: {0}={1}", key, response.Headers[key]);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -492,17 +487,17 @@ namespace GreenshotPlugin.Core {
|
|||
bool isHttpError = false;
|
||||
try {
|
||||
response = (HttpWebResponse)webRequest.GetResponse();
|
||||
LOG.InfoFormat("Response status: {0}", response.StatusCode);
|
||||
Log.InfoFormat("Response status: {0}", response.StatusCode);
|
||||
isHttpError = (int)response.StatusCode >= 300;
|
||||
if (isHttpError)
|
||||
{
|
||||
LOG.ErrorFormat("HTTP error {0}", response.StatusCode);
|
||||
Log.ErrorFormat("HTTP error {0}", response.StatusCode);
|
||||
}
|
||||
DebugHeaders(response);
|
||||
responseData = GetResponseAsString(response);
|
||||
if (isHttpError)
|
||||
{
|
||||
LOG.ErrorFormat("HTTP response {0}", responseData);
|
||||
Log.ErrorFormat("HTTP response {0}", responseData);
|
||||
}
|
||||
}
|
||||
catch (WebException e) {
|
||||
|
@ -510,15 +505,15 @@ namespace GreenshotPlugin.Core {
|
|||
HttpStatusCode statusCode = HttpStatusCode.Unused;
|
||||
if (response != null) {
|
||||
statusCode = response.StatusCode;
|
||||
LOG.ErrorFormat("HTTP error {0}", statusCode);
|
||||
Log.ErrorFormat("HTTP error {0}", statusCode);
|
||||
string errorContent = GetResponseAsString(response);
|
||||
if (alsoReturnContentOnError)
|
||||
{
|
||||
return errorContent;
|
||||
}
|
||||
LOG.ErrorFormat("Content: {0}", errorContent);
|
||||
Log.ErrorFormat("Content: {0}", errorContent);
|
||||
}
|
||||
LOG.Error("WebException: ", e);
|
||||
Log.Error("WebException: ", e);
|
||||
if (statusCode == HttpStatusCode.Unauthorized)
|
||||
{
|
||||
throw new UnauthorizedAccessException(e.Message);
|
||||
|
@ -531,7 +526,7 @@ namespace GreenshotPlugin.Core {
|
|||
{
|
||||
if (isHttpError)
|
||||
{
|
||||
LOG.ErrorFormat("HTTP error {0} with content: {1}", response.StatusCode, responseData);
|
||||
Log.ErrorFormat("HTTP error {0} with content: {1}", response.StatusCode, responseData);
|
||||
}
|
||||
response.Close();
|
||||
}
|
||||
|
@ -550,12 +545,12 @@ namespace GreenshotPlugin.Core {
|
|||
webRequest.Method = HTTPMethod.HEAD.ToString();
|
||||
using (HttpWebResponse webResponse = (HttpWebResponse)webRequest.GetResponse())
|
||||
{
|
||||
LOG.DebugFormat("RSS feed was updated at {0}", webResponse.LastModified);
|
||||
Log.DebugFormat("RSS feed was updated at {0}", webResponse.LastModified);
|
||||
return webResponse.LastModified;
|
||||
}
|
||||
} catch (Exception wE) {
|
||||
LOG.WarnFormat("Problem requesting HTTP - HEAD on uri {0}", uri);
|
||||
LOG.Warn(wE.Message);
|
||||
Log.WarnFormat("Problem requesting HTTP - HEAD on uri {0}", uri);
|
||||
Log.Warn(wE.Message);
|
||||
// Pretend it is old
|
||||
return DateTime.MinValue;
|
||||
}
|
||||
|
@ -620,11 +615,7 @@ namespace GreenshotPlugin.Core {
|
|||
/// <param name="formDataStream">Stream to write to</param>
|
||||
public void WriteFormDataToStream(string boundary, string name, Stream formDataStream) {
|
||||
// Add just the first part of this param, since we will write the file data directly to the Stream
|
||||
string header = string.Format("--{0}\r\nContent-Disposition: form-data; name=\"{1}\"; filename=\"{2}\";\r\nContent-Type: {3}\r\n\r\n",
|
||||
boundary,
|
||||
name,
|
||||
Filename ?? name,
|
||||
_contentType ?? "application/octet-stream");
|
||||
string header = $"--{boundary}\r\nContent-Disposition: form-data; name=\"{name}\"; filename=\"{Filename ?? name}\";\r\nContent-Type: {_contentType ?? "application/octet-stream"}\r\n\r\n";
|
||||
|
||||
formDataStream.Write(Encoding.UTF8.GetBytes(header), 0, Encoding.UTF8.GetByteCount(header));
|
||||
|
||||
|
@ -702,11 +693,7 @@ namespace GreenshotPlugin.Core {
|
|||
/// <param name="formDataStream">Stream to write to</param>
|
||||
public void WriteFormDataToStream(string boundary, string name, Stream formDataStream) {
|
||||
// Add just the first part of this param, since we will write the file data directly to the Stream
|
||||
string header = string.Format("--{0}\r\nContent-Disposition: form-data; name=\"{1}\"; filename=\"{2}\";\r\nContent-Type: {3}\r\n\r\n",
|
||||
boundary,
|
||||
name,
|
||||
Filename ?? name,
|
||||
ContentType);
|
||||
string header = $"--{boundary}\r\nContent-Disposition: form-data; name=\"{name}\"; filename=\"{Filename ?? name}\";\r\nContent-Type: {ContentType}\r\n\r\n";
|
||||
|
||||
formDataStream.Write(Encoding.UTF8.GetBytes(header), 0, Encoding.UTF8.GetByteCount(header));
|
||||
ImageOutput.SaveToStream(_bitmap, null, formDataStream, _outputSettings);
|
||||
|
@ -782,11 +769,7 @@ namespace GreenshotPlugin.Core {
|
|||
/// <param name="formDataStream">Stream to write to</param>
|
||||
public void WriteFormDataToStream(string boundary, string name, Stream formDataStream) {
|
||||
// Add just the first part of this param, since we will write the file data directly to the Stream
|
||||
string header = string.Format("--{0}\r\nContent-Disposition: form-data; name=\"{1}\"; filename=\"{2}\";\r\nContent-Type: {3}\r\n\r\n",
|
||||
boundary,
|
||||
name,
|
||||
Filename ?? name,
|
||||
ContentType);
|
||||
string header = $"--{boundary}\r\nContent-Disposition: form-data; name=\"{name}\"; filename=\"{Filename ?? name}\";\r\nContent-Type: {ContentType}\r\n\r\n";
|
||||
|
||||
formDataStream.Write(Encoding.UTF8.GetBytes(header), 0, Encoding.UTF8.GetByteCount(header));
|
||||
ImageOutput.SaveToStream(_surface, formDataStream, _outputSettings);
|
||||
|
|
|
@ -30,7 +30,6 @@ using System.Globalization;
|
|||
using System.Net;
|
||||
using System.Net.Sockets;
|
||||
using System.Security.Cryptography;
|
||||
using System.Security.Cryptography.X509Certificates;
|
||||
using System.Text;
|
||||
using System.Threading;
|
||||
|
||||
|
@ -41,7 +40,6 @@ namespace GreenshotPlugin.Core {
|
|||
public enum OAuthSignatureTypes {
|
||||
HMACSHA1,
|
||||
PLAINTEXT,
|
||||
RSASHA1
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
|
@ -124,11 +122,7 @@ namespace GreenshotPlugin.Core {
|
|||
/// <summary>
|
||||
/// Get formatted Auth url (this will call a FormatWith(this) on the AuthUrlPattern
|
||||
/// </summary>
|
||||
public string FormattedAuthUrl {
|
||||
get {
|
||||
return AuthUrlPattern.FormatWith(this);
|
||||
}
|
||||
}
|
||||
public string FormattedAuthUrl => AuthUrlPattern.FormatWith(this);
|
||||
|
||||
/// <summary>
|
||||
/// The URL to get a Token
|
||||
|
@ -170,7 +164,7 @@ namespace GreenshotPlugin.Core {
|
|||
public bool IsAccessTokenExpired {
|
||||
get {
|
||||
bool expired = true;
|
||||
if (!string.IsNullOrEmpty(AccessToken) && AccessTokenExpires != null) {
|
||||
if (!string.IsNullOrEmpty(AccessToken)) {
|
||||
expired = DateTimeOffset.Now.AddSeconds(60) > AccessTokenExpires;
|
||||
}
|
||||
// Make sure the token is not usable
|
||||
|
@ -211,7 +205,7 @@ namespace GreenshotPlugin.Core {
|
|||
/// An OAuth 1 session object
|
||||
/// </summary>
|
||||
public class OAuthSession {
|
||||
private static readonly ILog LOG = LogManager.GetLogger(typeof(OAuthSession));
|
||||
private static readonly ILog Log = LogManager.GetLogger(typeof(OAuthSession));
|
||||
protected const string OAUTH_VERSION = "1.0";
|
||||
protected const string OAUTH_PARAMETER_PREFIX = "oauth_";
|
||||
|
||||
|
@ -231,47 +225,30 @@ namespace GreenshotPlugin.Core {
|
|||
|
||||
protected const string HMACSHA1SignatureType = "HMAC-SHA1";
|
||||
protected const string PlainTextSignatureType = "PLAINTEXT";
|
||||
protected const string RSASHA1SignatureType = "RSA-SHA1";
|
||||
|
||||
|
||||
protected static Random random = new Random();
|
||||
|
||||
protected const string UNRESERVED_CHARS = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789-_.~";
|
||||
protected const string UnreservedChars = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789-_.~";
|
||||
|
||||
private string _userAgent = "Greenshot";
|
||||
private string _callbackUrl = "http://getgreenshot.org";
|
||||
private bool _checkVerifier = true;
|
||||
private bool _useHttpHeadersForAuthorization = true;
|
||||
private IDictionary<string, string> _accessTokenResponseParameters;
|
||||
private IDictionary<string, string> _requestTokenResponseParameters;
|
||||
private readonly IDictionary<string, object> _requestTokenParameters = new Dictionary<string, object>();
|
||||
|
||||
public IDictionary<string, object> RequestTokenParameters {
|
||||
get { return _requestTokenParameters; }
|
||||
}
|
||||
|
||||
public IDictionary<string, object> RequestTokenParameters { get; } = new Dictionary<string, object>();
|
||||
|
||||
/// <summary>
|
||||
/// Parameters of the last called getAccessToken
|
||||
/// </summary>
|
||||
public IDictionary<string, string> AccessTokenResponseParameters {
|
||||
get {
|
||||
return _accessTokenResponseParameters;
|
||||
}
|
||||
}
|
||||
public IDictionary<string, string> AccessTokenResponseParameters { get; private set; }
|
||||
|
||||
/// <summary>
|
||||
/// Parameters of the last called getRequestToken
|
||||
/// </summary>
|
||||
public IDictionary<string, string> RequestTokenResponseParameters {
|
||||
get {
|
||||
return _requestTokenResponseParameters;
|
||||
}
|
||||
}
|
||||
public IDictionary<string, string> RequestTokenResponseParameters => _requestTokenResponseParameters;
|
||||
|
||||
private readonly string _consumerKey;
|
||||
private readonly string _consumerSecret;
|
||||
|
||||
// default _browser size
|
||||
private Size _browserSize = new Size(864, 587);
|
||||
private string _loginTitle = "Authorize Greenshot access";
|
||||
|
||||
#region PublicProperties
|
||||
public HTTPMethod RequestTokenMethod {
|
||||
|
@ -320,48 +297,15 @@ namespace GreenshotPlugin.Core {
|
|||
_userAgent = value;
|
||||
}
|
||||
}
|
||||
public string CallbackUrl {
|
||||
get {
|
||||
return _callbackUrl;
|
||||
}
|
||||
set {
|
||||
_callbackUrl = value;
|
||||
}
|
||||
}
|
||||
public bool CheckVerifier {
|
||||
get {
|
||||
return _checkVerifier;
|
||||
}
|
||||
set {
|
||||
_checkVerifier = value;
|
||||
}
|
||||
}
|
||||
public string CallbackUrl { get; set; } = "http://getgreenshot.org";
|
||||
|
||||
public Size BrowserSize {
|
||||
get {
|
||||
return _browserSize;
|
||||
}
|
||||
set {
|
||||
_browserSize = value;
|
||||
}
|
||||
}
|
||||
public bool CheckVerifier { get; set; } = true;
|
||||
|
||||
public string LoginTitle {
|
||||
get {
|
||||
return _loginTitle;
|
||||
}
|
||||
set {
|
||||
_loginTitle = value;
|
||||
}
|
||||
}
|
||||
public bool UseHTTPHeadersForAuthorization {
|
||||
get {
|
||||
return _useHttpHeadersForAuthorization;
|
||||
}
|
||||
set {
|
||||
_useHttpHeadersForAuthorization = value;
|
||||
}
|
||||
}
|
||||
public Size BrowserSize { get; set; } = new Size(864, 587);
|
||||
|
||||
public string LoginTitle { get; set; } = "Authorize Greenshot access";
|
||||
|
||||
public bool UseHttpHeadersForAuthorization { get; set; } = true;
|
||||
|
||||
public bool AutoLogin {
|
||||
get;
|
||||
|
@ -393,11 +337,11 @@ namespace GreenshotPlugin.Core {
|
|||
/// <returns>a Base64 string of the hash value</returns>
|
||||
private static string ComputeHash(HashAlgorithm hashAlgorithm, string data) {
|
||||
if (hashAlgorithm == null) {
|
||||
throw new ArgumentNullException("hashAlgorithm");
|
||||
throw new ArgumentNullException(nameof(hashAlgorithm));
|
||||
}
|
||||
|
||||
if (string.IsNullOrEmpty(data)) {
|
||||
throw new ArgumentNullException("data");
|
||||
throw new ArgumentNullException(nameof(data));
|
||||
}
|
||||
|
||||
byte[] dataBuffer = Encoding.UTF8.GetBytes(data);
|
||||
|
@ -421,7 +365,7 @@ namespace GreenshotPlugin.Core {
|
|||
StringBuilder sb = new StringBuilder();
|
||||
foreach (string key in queryParameters.Keys) {
|
||||
if (queryParameters[key] is string) {
|
||||
sb.AppendFormat(CultureInfo.InvariantCulture, "{0}={1}&", key, UrlEncode3986(string.Format("{0}",queryParameters[key])));
|
||||
sb.AppendFormat(CultureInfo.InvariantCulture, "{0}={1}&", key, UrlEncode3986($"{queryParameters[key]}"));
|
||||
}
|
||||
}
|
||||
sb.Remove(sb.Length - 1, 1);
|
||||
|
@ -440,7 +384,7 @@ namespace GreenshotPlugin.Core {
|
|||
StringBuilder result = new StringBuilder();
|
||||
|
||||
foreach (char symbol in value) {
|
||||
if (UNRESERVED_CHARS.IndexOf(symbol) != -1) {
|
||||
if (UnreservedChars.IndexOf(symbol) != -1) {
|
||||
result.Append(symbol);
|
||||
} else {
|
||||
byte[] utf8Bytes = Encoding.UTF8.GetBytes(symbol.ToString());
|
||||
|
@ -478,14 +422,14 @@ namespace GreenshotPlugin.Core {
|
|||
/// <returns>response, this doesn't need to be used!!</returns>
|
||||
private string GetRequestToken() {
|
||||
IDictionary<string, object> parameters = new Dictionary<string, object>();
|
||||
foreach(var value in _requestTokenParameters) {
|
||||
foreach(var value in RequestTokenParameters) {
|
||||
parameters.Add(value);
|
||||
}
|
||||
Sign(RequestTokenMethod, RequestTokenUrl, parameters);
|
||||
string response = MakeRequest(RequestTokenMethod, RequestTokenUrl, null, parameters, null);
|
||||
if (!string.IsNullOrEmpty(response)) {
|
||||
response = NetworkHelper.UrlDecode(response);
|
||||
LOG.DebugFormat("Request token response: {0}", response);
|
||||
Log.DebugFormat("Request token response: {0}", response);
|
||||
_requestTokenResponseParameters = NetworkHelper.ParseQueryString(response);
|
||||
string value;
|
||||
if (_requestTokenResponseParameters.TryGetValue(OAUTH_TOKEN_KEY, out value)) {
|
||||
|
@ -506,7 +450,7 @@ namespace GreenshotPlugin.Core {
|
|||
Exception e = new Exception("The request token is not set, service responded with: " + requestTokenResponse);
|
||||
throw e;
|
||||
}
|
||||
LOG.DebugFormat("Opening AuthorizationLink: {0}", AuthorizationLink);
|
||||
Log.DebugFormat("Opening AuthorizationLink: {0}", AuthorizationLink);
|
||||
OAuthLoginForm oAuthLoginForm = new OAuthLoginForm(LoginTitle, BrowserSize, AuthorizationLink, CallbackUrl);
|
||||
oAuthLoginForm.ShowDialog();
|
||||
if (oAuthLoginForm.IsOk) {
|
||||
|
@ -545,14 +489,14 @@ namespace GreenshotPlugin.Core {
|
|||
string response = MakeRequest(AccessTokenMethod, AccessTokenUrl, null, parameters, null);
|
||||
if (!string.IsNullOrEmpty(response)) {
|
||||
response = NetworkHelper.UrlDecode(response);
|
||||
LOG.DebugFormat("Access token response: {0}", response);
|
||||
_accessTokenResponseParameters = NetworkHelper.ParseQueryString(response);
|
||||
Log.DebugFormat("Access token response: {0}", response);
|
||||
AccessTokenResponseParameters = NetworkHelper.ParseQueryString(response);
|
||||
string tokenValue;
|
||||
if (_accessTokenResponseParameters.TryGetValue(OAUTH_TOKEN_KEY, out tokenValue) && tokenValue != null) {
|
||||
if (AccessTokenResponseParameters.TryGetValue(OAUTH_TOKEN_KEY, out tokenValue) && tokenValue != null) {
|
||||
Token = tokenValue;
|
||||
}
|
||||
string secretValue;
|
||||
if (_accessTokenResponseParameters.TryGetValue(OAUTH_TOKEN_SECRET_KEY, out secretValue) && secretValue != null) {
|
||||
if (AccessTokenResponseParameters.TryGetValue(OAUTH_TOKEN_SECRET_KEY, out secretValue) && secretValue != null) {
|
||||
TokenSecret = secretValue;
|
||||
}
|
||||
}
|
||||
|
@ -568,23 +512,23 @@ namespace GreenshotPlugin.Core {
|
|||
Token = null;
|
||||
TokenSecret = null;
|
||||
Verifier = null;
|
||||
LOG.Debug("Creating Token");
|
||||
Log.Debug("Creating Token");
|
||||
string requestTokenResponse;
|
||||
try {
|
||||
try {
|
||||
requestTokenResponse = GetRequestToken();
|
||||
} catch (Exception ex) {
|
||||
LOG.Error(ex);
|
||||
Log.Error(ex);
|
||||
throw new NotSupportedException("Service is not available: " + ex.Message);
|
||||
}
|
||||
if (string.IsNullOrEmpty(GetAuthorizeToken(requestTokenResponse))) {
|
||||
LOG.Debug("User didn't authenticate!");
|
||||
Log.Debug("User didn't authenticate!");
|
||||
return false;
|
||||
}
|
||||
try {
|
||||
Thread.Sleep(1000);
|
||||
return GetAccessToken() != null;
|
||||
} catch (Exception ex) {
|
||||
LOG.Error(ex);
|
||||
Log.Error(ex);
|
||||
throw;
|
||||
}
|
||||
}
|
||||
|
@ -593,37 +537,33 @@ namespace GreenshotPlugin.Core {
|
|||
/// Get the link to the authorization page for this application.
|
||||
/// </summary>
|
||||
/// <returns>The url with a valid request token, or a null string.</returns>
|
||||
private string AuthorizationLink {
|
||||
get {
|
||||
return AuthorizeUrl + "?" + OAUTH_TOKEN_KEY + "=" + Token + "&" + OAUTH_CALLBACK_KEY + "=" + UrlEncode3986(CallbackUrl);
|
||||
}
|
||||
}
|
||||
private string AuthorizationLink => AuthorizeUrl + "?" + OAUTH_TOKEN_KEY + "=" + Token + "&" + OAUTH_CALLBACK_KEY + "=" + UrlEncode3986(CallbackUrl);
|
||||
|
||||
/// <summary>
|
||||
/// Submit a web request using oAuth.
|
||||
/// </summary>
|
||||
/// <param name="method">GET or POST</param>
|
||||
/// <param name="requestURL">The full url, including the querystring for the signing/request</param>
|
||||
/// <param name="requestUrl">The full url, including the querystring for the signing/request</param>
|
||||
/// <param name="parametersToSign">Parameters for the request, which need to be signed</param>
|
||||
/// <param name="additionalParameters">Parameters for the request, which do not need to be signed</param>
|
||||
/// <param name="postData">Data to post (MemoryStream)</param>
|
||||
/// <returns>The web server response.</returns>
|
||||
public string MakeOAuthRequest(HTTPMethod method, string requestURL, IDictionary<string, object> parametersToSign, IDictionary<string, object> additionalParameters, IBinaryContainer postData) {
|
||||
return MakeOAuthRequest(method, requestURL, requestURL, null, parametersToSign, additionalParameters, postData);
|
||||
public string MakeOAuthRequest(HTTPMethod method, string requestUrl, IDictionary<string, object> parametersToSign, IDictionary<string, object> additionalParameters, IBinaryContainer postData) {
|
||||
return MakeOAuthRequest(method, requestUrl, requestUrl, null, parametersToSign, additionalParameters, postData);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Submit a web request using oAuth.
|
||||
/// </summary>
|
||||
/// <param name="method">GET or POST</param>
|
||||
/// <param name="requestURL">The full url, including the querystring for the signing/request</param>
|
||||
/// <param name="requestUrl">The full url, including the querystring for the signing/request</param>
|
||||
/// <param name="headers">Header values</param>
|
||||
/// <param name="parametersToSign">Parameters for the request, which need to be signed</param>
|
||||
/// <param name="additionalParameters">Parameters for the request, which do not need to be signed</param>
|
||||
/// <param name="postData">Data to post (MemoryStream)</param>
|
||||
/// <returns>The web server response.</returns>
|
||||
public string MakeOAuthRequest(HTTPMethod method, string requestURL, IDictionary<string, string> headers, IDictionary<string, object> parametersToSign, IDictionary<string, object> additionalParameters, IBinaryContainer postData) {
|
||||
return MakeOAuthRequest(method, requestURL, requestURL, headers, parametersToSign, additionalParameters, postData);
|
||||
public string MakeOAuthRequest(HTTPMethod method, string requestUrl, IDictionary<string, string> headers, IDictionary<string, object> parametersToSign, IDictionary<string, object> additionalParameters, IBinaryContainer postData) {
|
||||
return MakeOAuthRequest(method, requestUrl, requestUrl, headers, parametersToSign, additionalParameters, postData);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
|
@ -631,13 +571,13 @@ namespace GreenshotPlugin.Core {
|
|||
/// </summary>
|
||||
/// <param name="method">GET or POST</param>
|
||||
/// <param name="signUrl">The full url, including the querystring for the signing</param>
|
||||
/// <param name="requestURL">The full url, including the querystring for the request</param>
|
||||
/// <param name="requestUrl">The full url, including the querystring for the request</param>
|
||||
/// <param name="parametersToSign">Parameters for the request, which need to be signed</param>
|
||||
/// <param name="additionalParameters">Parameters for the request, which do not need to be signed</param>
|
||||
/// <param name="postData">Data to post (MemoryStream)</param>
|
||||
/// <returns>The web server response.</returns>
|
||||
public string MakeOAuthRequest(HTTPMethod method, string signUrl, string requestURL, IDictionary<string, object> parametersToSign, IDictionary<string, object> additionalParameters, IBinaryContainer postData) {
|
||||
return MakeOAuthRequest(method, signUrl, requestURL, null, parametersToSign, additionalParameters, postData);
|
||||
public string MakeOAuthRequest(HTTPMethod method, string signUrl, string requestUrl, IDictionary<string, object> parametersToSign, IDictionary<string, object> additionalParameters, IBinaryContainer postData) {
|
||||
return MakeOAuthRequest(method, signUrl, requestUrl, null, parametersToSign, additionalParameters, postData);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
|
@ -645,13 +585,13 @@ namespace GreenshotPlugin.Core {
|
|||
/// </summary>
|
||||
/// <param name="method">GET or POST</param>
|
||||
/// <param name="signUrl">The full url, including the querystring for the signing</param>
|
||||
/// <param name="requestURL">The full url, including the querystring for the request</param>
|
||||
/// <param name="requestUrl">The full url, including the querystring for the request</param>
|
||||
/// <param name="headers">Headers for the request</param>
|
||||
/// <param name="parametersToSign">Parameters for the request, which need to be signed</param>
|
||||
/// <param name="additionalParameters">Parameters for the request, which do not need to be signed</param>
|
||||
/// <param name="postData">Data to post (MemoryStream)</param>
|
||||
/// <returns>The web server response.</returns>
|
||||
public string MakeOAuthRequest(HTTPMethod method, string signUrl, string requestURL, IDictionary<string, string> headers, IDictionary<string, object> parametersToSign, IDictionary<string, object> additionalParameters, IBinaryContainer postData) {
|
||||
public string MakeOAuthRequest(HTTPMethod method, string signUrl, string requestUrl, IDictionary<string, string> headers, IDictionary<string, object> parametersToSign, IDictionary<string, object> additionalParameters, IBinaryContainer postData) {
|
||||
if (parametersToSign == null) {
|
||||
parametersToSign = new Dictionary<string, object>();
|
||||
}
|
||||
|
@ -677,7 +617,7 @@ namespace GreenshotPlugin.Core {
|
|||
newParameters.Add(parameter);
|
||||
}
|
||||
}
|
||||
return MakeRequest(method, requestURL, headers, newParameters, postData);
|
||||
return MakeRequest(method, requestUrl, headers, newParameters, postData);
|
||||
} catch (UnauthorizedAccessException uaEx) {
|
||||
lastException = uaEx;
|
||||
Token = null;
|
||||
|
@ -695,7 +635,6 @@ namespace GreenshotPlugin.Core {
|
|||
{
|
||||
parametersToSign.Remove(keyToDelete);
|
||||
}
|
||||
continue;
|
||||
}
|
||||
}
|
||||
if (lastException != null) {
|
||||
|
@ -735,13 +674,9 @@ namespace GreenshotPlugin.Core {
|
|||
parameters.Add(OAUTH_NONCE_KEY, GenerateNonce());
|
||||
parameters.Add(OAUTH_TIMESTAMP_KEY, GenerateTimeStamp());
|
||||
switch(SignatureType) {
|
||||
case OAuthSignatureTypes.RSASHA1:
|
||||
parameters.Add(OAUTH_SIGNATURE_METHOD_KEY, RSASHA1SignatureType);
|
||||
break;
|
||||
case OAuthSignatureTypes.PLAINTEXT:
|
||||
parameters.Add(OAUTH_SIGNATURE_METHOD_KEY, PlainTextSignatureType);
|
||||
break;
|
||||
case OAuthSignatureTypes.HMACSHA1:
|
||||
default:
|
||||
parameters.Add(OAUTH_SIGNATURE_METHOD_KEY, HMACSHA1SignatureType);
|
||||
break;
|
||||
|
@ -757,41 +692,15 @@ namespace GreenshotPlugin.Core {
|
|||
parameters.Add(OAUTH_TOKEN_KEY, Token);
|
||||
}
|
||||
signatureBase.Append(UrlEncode3986(GenerateNormalizedParametersString(parameters)));
|
||||
LOG.DebugFormat("Signature base: {0}", signatureBase);
|
||||
Log.DebugFormat("Signature base: {0}", signatureBase);
|
||||
string key = string.Format(CultureInfo.InvariantCulture, "{0}&{1}", UrlEncode3986(_consumerSecret), string.IsNullOrEmpty(TokenSecret) ? string.Empty : UrlEncode3986(TokenSecret));
|
||||
switch (SignatureType) {
|
||||
case OAuthSignatureTypes.RSASHA1:
|
||||
// Code comes from here: http://www.dotnetfunda.com/articles/article1932-rest-service-call-using-oauth-10-authorization-with-rsa-sha1.aspx
|
||||
// Read the .P12 file to read Private/Public key Certificate
|
||||
string certFilePath = _consumerKey; // The .P12 certificate file path Example: "C:/mycertificate/MCOpenAPI.p12
|
||||
string password = _consumerSecret; // password to read certificate .p12 file
|
||||
// Read the Certification from .P12 file.
|
||||
X509Certificate2 cert = new X509Certificate2(certFilePath.ToString(), password);
|
||||
// Retrieve the Private key from Certificate.
|
||||
RSACryptoServiceProvider RSAcrypt = (RSACryptoServiceProvider)cert.PrivateKey;
|
||||
// Create a RSA-SHA1 Hash object
|
||||
using (SHA1Managed shaHASHObject = new SHA1Managed()) {
|
||||
// Create Byte Array of Signature base string
|
||||
byte[] data = Encoding.ASCII.GetBytes(signatureBase.ToString());
|
||||
// Create Hashmap of Signature base string
|
||||
byte[] hash = shaHASHObject.ComputeHash(data);
|
||||
// Create Sign Hash of base string
|
||||
// NOTE - 'SignHash' gives correct data. Don't use SignData method
|
||||
byte[] rsaSignature = RSAcrypt.SignHash(hash, CryptoConfig.MapNameToOID("SHA1"));
|
||||
// Convert to Base64 string
|
||||
string base64string = Convert.ToBase64String(rsaSignature);
|
||||
// Return the Encoded UTF8 string
|
||||
parameters.Add(OAUTH_SIGNATURE_KEY, UrlEncode3986(base64string));
|
||||
}
|
||||
break;
|
||||
case OAuthSignatureTypes.PLAINTEXT:
|
||||
parameters.Add(OAUTH_SIGNATURE_KEY, key);
|
||||
break;
|
||||
case OAuthSignatureTypes.HMACSHA1:
|
||||
default:
|
||||
// Generate Signature and add it to the parameters
|
||||
HMACSHA1 hmacsha1 = new HMACSHA1();
|
||||
hmacsha1.Key = Encoding.UTF8.GetBytes(key);
|
||||
HMACSHA1 hmacsha1 = new HMACSHA1 {Key = Encoding.UTF8.GetBytes(key)};
|
||||
string signature = ComputeHash(hmacsha1, signatureBase.ToString());
|
||||
parameters.Add(OAUTH_SIGNATURE_KEY, signature);
|
||||
break;
|
||||
|
@ -803,24 +712,24 @@ namespace GreenshotPlugin.Core {
|
|||
/// Any additional parameters added after the Sign call are not in the signature, this could be by design!
|
||||
/// </summary>
|
||||
/// <param name="method"></param>
|
||||
/// <param name="requestURL"></param>
|
||||
/// <param name="requestUrl"></param>
|
||||
/// <param name="headers"></param>
|
||||
/// <param name="parameters"></param>
|
||||
/// <param name="postData">IBinaryParameter</param>
|
||||
/// <returns>Response from server</returns>
|
||||
private string MakeRequest(HTTPMethod method, string requestURL, IDictionary<string, string> headers, IDictionary<string, object> parameters, IBinaryContainer postData) {
|
||||
private string MakeRequest(HTTPMethod method, string requestUrl, IDictionary<string, string> headers, IDictionary<string, object> parameters, IBinaryContainer postData) {
|
||||
if (parameters == null) {
|
||||
throw new ArgumentNullException(nameof(parameters));
|
||||
}
|
||||
IDictionary<string, object> requestParameters;
|
||||
// Add oAuth values as HTTP headers, if this is allowed
|
||||
StringBuilder authHeader = null;
|
||||
if (UseHTTPHeadersForAuthorization) {
|
||||
if (UseHttpHeadersForAuthorization) {
|
||||
authHeader = new StringBuilder();
|
||||
requestParameters = new Dictionary<string, object>();
|
||||
foreach (string parameterKey in parameters.Keys) {
|
||||
if (parameterKey.StartsWith(OAUTH_PARAMETER_PREFIX)) {
|
||||
authHeader.AppendFormat(CultureInfo.InvariantCulture, "{0}=\"{1}\", ", parameterKey, UrlEncode3986(string.Format("{0}",parameters[parameterKey])));
|
||||
authHeader.AppendFormat(CultureInfo.InvariantCulture, "{0}=\"{1}\", ", parameterKey, UrlEncode3986($"{parameters[parameterKey]}"));
|
||||
} else if (!requestParameters.ContainsKey(parameterKey)) {
|
||||
requestParameters.Add(parameterKey, parameters[parameterKey]);
|
||||
}
|
||||
|
@ -836,16 +745,16 @@ namespace GreenshotPlugin.Core {
|
|||
if (HTTPMethod.GET == method || postData != null) {
|
||||
if (requestParameters.Count > 0) {
|
||||
// Add the parameters to the request
|
||||
requestURL += "?" + NetworkHelper.GenerateQueryParameters(requestParameters);
|
||||
requestUrl += "?" + NetworkHelper.GenerateQueryParameters(requestParameters);
|
||||
}
|
||||
}
|
||||
// Create webrequest
|
||||
HttpWebRequest webRequest = NetworkHelper.CreateWebRequest(requestURL, method);
|
||||
HttpWebRequest webRequest = NetworkHelper.CreateWebRequest(requestUrl, method);
|
||||
webRequest.ServicePoint.Expect100Continue = false;
|
||||
webRequest.UserAgent = _userAgent;
|
||||
|
||||
if (UseHTTPHeadersForAuthorization && authHeader != null) {
|
||||
LOG.DebugFormat("Authorization: OAuth {0}", authHeader);
|
||||
if (UseHttpHeadersForAuthorization && authHeader != null) {
|
||||
Log.DebugFormat("Authorization: OAuth {0}", authHeader);
|
||||
webRequest.Headers.Add("Authorization: OAuth " + authHeader);
|
||||
}
|
||||
|
||||
|
@ -860,13 +769,10 @@ namespace GreenshotPlugin.Core {
|
|||
NetworkHelper.WriteMultipartFormData(webRequest, requestParameters);
|
||||
} else {
|
||||
StringBuilder form = new StringBuilder();
|
||||
foreach (string parameterKey in requestParameters.Keys) {
|
||||
if (parameters[parameterKey] is IBinaryContainer) {
|
||||
IBinaryContainer binaryParameter = parameters[parameterKey] as IBinaryContainer;
|
||||
form.AppendFormat(CultureInfo.InvariantCulture, "{0}={1}&", UrlEncode3986(parameterKey), UrlEncode3986(binaryParameter.ToBase64String(Base64FormattingOptions.None)));
|
||||
} else {
|
||||
form.AppendFormat(CultureInfo.InvariantCulture, "{0}={1}&", UrlEncode3986(parameterKey), UrlEncode3986(string.Format("{0}",parameters[parameterKey])));
|
||||
}
|
||||
foreach (string parameterKey in requestParameters.Keys)
|
||||
{
|
||||
var binaryParameter = parameters[parameterKey] as IBinaryContainer;
|
||||
form.AppendFormat(CultureInfo.InvariantCulture, "{0}={1}&", UrlEncode3986(parameterKey), binaryParameter != null ? UrlEncode3986(binaryParameter.ToBase64String(Base64FormattingOptions.None)) : UrlEncode3986($"{parameters[parameterKey]}"));
|
||||
}
|
||||
// Remove trailing &
|
||||
if (form.Length > 0) {
|
||||
|
@ -887,12 +793,10 @@ namespace GreenshotPlugin.Core {
|
|||
string responseData;
|
||||
try {
|
||||
responseData = NetworkHelper.GetResponseAsString(webRequest);
|
||||
LOG.DebugFormat("Response: {0}", responseData);
|
||||
Log.DebugFormat("Response: {0}", responseData);
|
||||
} catch (Exception ex) {
|
||||
LOG.Error("Couldn't retrieve response: ", ex);
|
||||
Log.Error("Couldn't retrieve response: ", ex);
|
||||
throw;
|
||||
} finally {
|
||||
webRequest = null;
|
||||
}
|
||||
|
||||
return responseData;
|
||||
|
@ -904,52 +808,34 @@ namespace GreenshotPlugin.Core {
|
|||
/// and waits for a call with the authorization verification code.
|
||||
/// </summary>
|
||||
public class LocalServerCodeReceiver {
|
||||
private static readonly ILog LOG = LogManager.GetLogger(typeof(LocalServerCodeReceiver));
|
||||
private static readonly ILog Log = LogManager.GetLogger(typeof(LocalServerCodeReceiver));
|
||||
private readonly ManualResetEvent _ready = new ManualResetEvent(true);
|
||||
|
||||
private string _loopbackCallback = "http://localhost:{0}/authorize/";
|
||||
/// <summary>
|
||||
/// The call back format. Expects one port parameter.
|
||||
/// Default: http://localhost:{0}/authorize/
|
||||
/// </summary>
|
||||
public string LoopbackCallbackUrl {
|
||||
get {
|
||||
return _loopbackCallback;
|
||||
}
|
||||
set {
|
||||
_loopbackCallback = value;
|
||||
}
|
||||
}
|
||||
|
||||
private string _closePageResponse =
|
||||
@"<html>
|
||||
<head><title>OAuth 2.0 Authentication CloudServiceName</title></head>
|
||||
<body>
|
||||
Greenshot received information from CloudServiceName. You can close this browser / tab if it is not closed itself...
|
||||
<script type='text/javascript'>
|
||||
window.setTimeout(function() {
|
||||
window.open('', '_self', '');
|
||||
window.close();
|
||||
}, 1000);
|
||||
if (window.opener) {
|
||||
window.opener.checkToken();
|
||||
}
|
||||
</script>
|
||||
</body>
|
||||
</html>";
|
||||
public string LoopbackCallbackUrl { get; set; } = "http://localhost:{0}/authorize/";
|
||||
|
||||
/// <summary>
|
||||
/// HTML code to to return the _browser, default it will try to close the _browser / tab, this won't always work.
|
||||
/// You can use CloudServiceName where you want to show the CloudServiceName from your OAuth2 settings
|
||||
/// </summary>
|
||||
public string ClosePageResponse {
|
||||
get {
|
||||
return _closePageResponse;
|
||||
}
|
||||
set {
|
||||
_closePageResponse = value;
|
||||
}
|
||||
}
|
||||
public string ClosePageResponse { get; set; } = @"<html>
|
||||
<head><title>OAuth 2.0 Authentication CloudServiceName</title></head>
|
||||
<body>
|
||||
Greenshot received information from CloudServiceName. You can close this browser / tab if it is not closed itself...
|
||||
<script type='text/javascript'>
|
||||
window.setTimeout(function() {
|
||||
window.open('', '_self', '');
|
||||
window.close();
|
||||
}, 1000);
|
||||
if (window.opener) {
|
||||
window.opener.checkToken();
|
||||
}
|
||||
</script>
|
||||
</body>
|
||||
</html>";
|
||||
|
||||
private string _redirectUri;
|
||||
/// <summary>
|
||||
|
@ -961,7 +847,7 @@ Greenshot received information from CloudServiceName. You can close this browser
|
|||
return _redirectUri;
|
||||
}
|
||||
|
||||
return _redirectUri = string.Format(_loopbackCallback, GetRandomUnusedPort());
|
||||
return _redirectUri = string.Format(LoopbackCallbackUrl, GetRandomUnusedPort());
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -973,7 +859,7 @@ Greenshot received information from CloudServiceName. You can close this browser
|
|||
/// <summary>
|
||||
/// The OAuth code receiver
|
||||
/// </summary>
|
||||
/// <param name="authorizationUrl"></param>
|
||||
/// <param name="oauth2Settings"></param>
|
||||
/// <returns>Dictionary with values</returns>
|
||||
public IDictionary<string, string> ReceiveCode(OAuth2Settings oauth2Settings) {
|
||||
// Set the redirect URL on the settings
|
||||
|
@ -986,7 +872,7 @@ Greenshot received information from CloudServiceName. You can close this browser
|
|||
|
||||
// Get the formatted FormattedAuthUrl
|
||||
string authorizationUrl = oauth2Settings.FormattedAuthUrl;
|
||||
LOG.DebugFormat("Open a browser with: {0}", authorizationUrl);
|
||||
Log.DebugFormat("Open a browser with: {0}", authorizationUrl);
|
||||
Process.Start(authorizationUrl);
|
||||
|
||||
// Wait to get the authorization code response.
|
||||
|
@ -994,7 +880,7 @@ Greenshot received information from CloudServiceName. You can close this browser
|
|||
_ready.Reset();
|
||||
|
||||
while (!context.AsyncWaitHandle.WaitOne(1000, true)) {
|
||||
LOG.Debug("Waiting for response");
|
||||
Log.Debug("Waiting for response");
|
||||
}
|
||||
} catch (Exception) {
|
||||
// Make sure we can clean up, also if the thead is aborted
|
||||
|
@ -1072,15 +958,15 @@ Greenshot received information from CloudServiceName. You can close this browser
|
|||
/// Code to simplify OAuth 2
|
||||
/// </summary>
|
||||
public static class OAuth2Helper {
|
||||
private const string REFRESH_TOKEN = "refresh_token";
|
||||
private const string ACCESS_TOKEN = "access_token";
|
||||
private const string CODE = "code";
|
||||
private const string CLIENT_ID = "client_id";
|
||||
private const string CLIENT_SECRET = "client_secret";
|
||||
private const string GRANT_TYPE = "grant_type";
|
||||
private const string AUTHORIZATION_CODE = "authorization_code";
|
||||
private const string REDIRECT_URI = "redirect_uri";
|
||||
private const string EXPIRES_IN = "expires_in";
|
||||
private const string RefreshToken = "refresh_token";
|
||||
private const string AccessToken = "access_token";
|
||||
private const string Code = "code";
|
||||
private const string ClientId = "client_id";
|
||||
private const string ClientSecret = "client_secret";
|
||||
private const string GrantType = "grant_type";
|
||||
private const string AuthorizationCode = "authorization_code";
|
||||
private const string RedirectUri = "redirect_uri";
|
||||
private const string ExpiresIn = "expires_in";
|
||||
|
||||
/// <summary>
|
||||
/// Generate an OAuth 2 Token by using the supplied code
|
||||
|
@ -1089,11 +975,11 @@ Greenshot received information from CloudServiceName. You can close this browser
|
|||
public static void GenerateRefreshToken(OAuth2Settings settings) {
|
||||
IDictionary<string, object> data = new Dictionary<string, object>();
|
||||
// Use the returned code to get a refresh code
|
||||
data.Add(CODE, settings.Code);
|
||||
data.Add(CLIENT_ID, settings.ClientId);
|
||||
data.Add(REDIRECT_URI, settings.RedirectUrl);
|
||||
data.Add(CLIENT_SECRET, settings.ClientSecret);
|
||||
data.Add(GRANT_TYPE, AUTHORIZATION_CODE);
|
||||
data.Add(Code, settings.Code);
|
||||
data.Add(ClientId, settings.ClientId);
|
||||
data.Add(RedirectUri, settings.RedirectUrl);
|
||||
data.Add(ClientSecret, settings.ClientSecret);
|
||||
data.Add(GrantType, AuthorizationCode);
|
||||
foreach (string key in settings.AdditionalAttributes.Keys) {
|
||||
data.Add(key, settings.AdditionalAttributes[key]);
|
||||
}
|
||||
|
@ -1103,12 +989,12 @@ Greenshot received information from CloudServiceName. You can close this browser
|
|||
string accessTokenJsonResult = NetworkHelper.GetResponseAsString(webRequest, true);
|
||||
|
||||
IDictionary<string, object> refreshTokenResult = JSONHelper.JsonDecode(accessTokenJsonResult);
|
||||
if (refreshTokenResult.ContainsKey("error")) {
|
||||
if (refreshTokenResult.ContainsKey("error"))
|
||||
{
|
||||
if (refreshTokenResult.ContainsKey("error_description")) {
|
||||
throw new Exception(string.Format("{0} - {1}", refreshTokenResult["error"], refreshTokenResult["error_description"]));
|
||||
} else {
|
||||
throw new Exception((string)refreshTokenResult["error"]);
|
||||
throw new Exception($"{refreshTokenResult["error"]} - {refreshTokenResult["error_description"]}");
|
||||
}
|
||||
throw new Exception((string)refreshTokenResult["error"]);
|
||||
}
|
||||
|
||||
// gives as described here: https://developers.google.com/identity/protocols/OAuth2InstalledApp
|
||||
|
@ -1116,10 +1002,10 @@ Greenshot received information from CloudServiceName. You can close this browser
|
|||
// "expires_in":3920,
|
||||
// "token_type":"Bearer",
|
||||
// "refresh_token":"1/xEoDL4iW3cxlI7yDbSRFYNG01kVKM2C-259HOF2aQbI"
|
||||
settings.AccessToken = (string)refreshTokenResult[ACCESS_TOKEN] as string;
|
||||
settings.RefreshToken = (string)refreshTokenResult[REFRESH_TOKEN] as string;
|
||||
settings.AccessToken = (string)refreshTokenResult[AccessToken];
|
||||
settings.RefreshToken = (string)refreshTokenResult[RefreshToken];
|
||||
|
||||
object seconds = refreshTokenResult[EXPIRES_IN];
|
||||
object seconds = refreshTokenResult[ExpiresIn];
|
||||
if (seconds != null) {
|
||||
settings.AccessTokenExpires = DateTimeOffset.Now.AddSeconds((double)seconds);
|
||||
}
|
||||
|
@ -1133,10 +1019,10 @@ Greenshot received information from CloudServiceName. You can close this browser
|
|||
/// <param name="settings"></param>
|
||||
public static void GenerateAccessToken(OAuth2Settings settings) {
|
||||
IDictionary<string, object> data = new Dictionary<string, object>();
|
||||
data.Add(REFRESH_TOKEN, settings.RefreshToken);
|
||||
data.Add(CLIENT_ID, settings.ClientId);
|
||||
data.Add(CLIENT_SECRET, settings.ClientSecret);
|
||||
data.Add(GRANT_TYPE, REFRESH_TOKEN);
|
||||
data.Add(RefreshToken, settings.RefreshToken);
|
||||
data.Add(ClientId, settings.ClientId);
|
||||
data.Add(ClientSecret, settings.ClientSecret);
|
||||
data.Add(GrantType, RefreshToken);
|
||||
foreach (string key in settings.AdditionalAttributes.Keys) {
|
||||
data.Add(key, settings.AdditionalAttributes[key]);
|
||||
}
|
||||
|
@ -1161,19 +1047,19 @@ Greenshot received information from CloudServiceName. You can close this browser
|
|||
return;
|
||||
} else {
|
||||
if (accessTokenResult.ContainsKey("error_description")) {
|
||||
throw new Exception(string.Format("{0} - {1}", accessTokenResult["error"], accessTokenResult["error_description"]));
|
||||
throw new Exception($"{accessTokenResult["error"]} - {accessTokenResult["error_description"]}");
|
||||
} else {
|
||||
throw new Exception((string)accessTokenResult["error"]);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
settings.AccessToken = (string)accessTokenResult[ACCESS_TOKEN] as string;
|
||||
if (accessTokenResult.ContainsKey(REFRESH_TOKEN)) {
|
||||
settings.AccessToken = (string)accessTokenResult[AccessToken];
|
||||
if (accessTokenResult.ContainsKey(RefreshToken)) {
|
||||
// Refresh the refresh token :)
|
||||
settings.RefreshToken = (string)accessTokenResult[REFRESH_TOKEN] as string;
|
||||
settings.RefreshToken = (string)accessTokenResult[RefreshToken];
|
||||
}
|
||||
object seconds = accessTokenResult[EXPIRES_IN];
|
||||
object seconds = accessTokenResult[ExpiresIn];
|
||||
if (seconds != null) {
|
||||
settings.AccessTokenExpires = DateTimeOffset.Now.AddSeconds((double)seconds);
|
||||
} else {
|
||||
|
@ -1187,7 +1073,7 @@ Greenshot received information from CloudServiceName. You can close this browser
|
|||
/// <param name="settings">OAuth2Settings</param>
|
||||
/// <returns>false if it was canceled, true if it worked, exception if not</returns>
|
||||
public static bool Authenticate(OAuth2Settings settings) {
|
||||
bool completed = true;
|
||||
bool completed;
|
||||
switch (settings.AuthorizeMode) {
|
||||
case OAuth2AuthorizeMode.LocalServer:
|
||||
completed = AuthenticateViaLocalServer(settings);
|
||||
|
@ -1196,7 +1082,7 @@ Greenshot received information from CloudServiceName. You can close this browser
|
|||
completed = AuthenticateViaEmbeddedBrowser(settings);
|
||||
break;
|
||||
default:
|
||||
throw new NotImplementedException(string.Format("Authorize mode '{0}' is not 'yet' implemented.", settings.AuthorizeMode));
|
||||
throw new NotImplementedException($"Authorize mode '{settings.AuthorizeMode}' is not 'yet' implemented.");
|
||||
}
|
||||
return completed;
|
||||
}
|
||||
|
@ -1209,16 +1095,16 @@ Greenshot received information from CloudServiceName. You can close this browser
|
|||
/// <returns>true if completed, false if canceled</returns>
|
||||
private static bool AuthenticateViaEmbeddedBrowser(OAuth2Settings settings) {
|
||||
if (string.IsNullOrEmpty(settings.CloudServiceName)) {
|
||||
throw new ArgumentNullException("CloudServiceName");
|
||||
throw new ArgumentNullException(nameof(settings.CloudServiceName));
|
||||
}
|
||||
if (settings.BrowserSize == Size.Empty) {
|
||||
throw new ArgumentNullException("BrowserSize");
|
||||
throw new ArgumentNullException(nameof(settings.BrowserSize));
|
||||
}
|
||||
OAuthLoginForm loginForm = new OAuthLoginForm(string.Format("Authorize {0}", settings.CloudServiceName), settings.BrowserSize, settings.FormattedAuthUrl, settings.RedirectUrl);
|
||||
OAuthLoginForm loginForm = new OAuthLoginForm($"Authorize {settings.CloudServiceName}", settings.BrowserSize, settings.FormattedAuthUrl, settings.RedirectUrl);
|
||||
loginForm.ShowDialog();
|
||||
if (loginForm.IsOk) {
|
||||
string code;
|
||||
if (loginForm.CallbackParameters.TryGetValue(CODE, out code) && !string.IsNullOrEmpty(code)) {
|
||||
if (loginForm.CallbackParameters.TryGetValue(Code, out code) && !string.IsNullOrEmpty(code)) {
|
||||
settings.Code = code;
|
||||
GenerateRefreshToken(settings);
|
||||
return true;
|
||||
|
@ -1238,7 +1124,7 @@ Greenshot received information from CloudServiceName. You can close this browser
|
|||
IDictionary<string, string> result = codeReceiver.ReceiveCode(settings);
|
||||
|
||||
string code;
|
||||
if (result.TryGetValue(CODE, out code) && !string.IsNullOrEmpty(code)) {
|
||||
if (result.TryGetValue(Code, out code) && !string.IsNullOrEmpty(code)) {
|
||||
settings.Code = code;
|
||||
GenerateRefreshToken(settings);
|
||||
return true;
|
||||
|
@ -1251,9 +1137,8 @@ Greenshot received information from CloudServiceName. You can close this browser
|
|||
}
|
||||
if ("access_denied" == error) {
|
||||
throw new UnauthorizedAccessException("Access denied");
|
||||
} else {
|
||||
throw new Exception(error);
|
||||
}
|
||||
throw new Exception(error);
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
|
|
@ -36,13 +36,13 @@ namespace GreenshotPlugin.Core {
|
|||
/// Description of PluginUtils.
|
||||
/// </summary>
|
||||
public static class PluginUtils {
|
||||
private static readonly ILog LOG = LogManager.GetLogger(typeof(PluginUtils));
|
||||
private static readonly CoreConfiguration conf = IniConfig.GetIniSection<CoreConfiguration>();
|
||||
private const string PATH_KEY = @"SOFTWARE\Microsoft\Windows\CurrentVersion\App Paths\";
|
||||
private static readonly IDictionary<string, Image> exeIconCache = new Dictionary<string, Image>();
|
||||
private static readonly ILog Log = LogManager.GetLogger(typeof(PluginUtils));
|
||||
private static readonly CoreConfiguration CoreConfig = IniConfig.GetIniSection<CoreConfiguration>();
|
||||
private const string PathKey = @"SOFTWARE\Microsoft\Windows\CurrentVersion\App Paths\";
|
||||
private static readonly IDictionary<string, Image> ExeIconCache = new Dictionary<string, Image>();
|
||||
|
||||
static PluginUtils() {
|
||||
conf.PropertyChanged += OnIconSizeChanged;
|
||||
CoreConfig.PropertyChanged += OnIconSizeChanged;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
|
@ -61,16 +61,15 @@ namespace GreenshotPlugin.Core {
|
|||
private static void OnIconSizeChanged(object sender, PropertyChangedEventArgs e) {
|
||||
if (e.PropertyName == "IconSize") {
|
||||
List<Image> cachedImages = new List<Image>();
|
||||
lock (exeIconCache) {
|
||||
foreach (string key in exeIconCache.Keys) {
|
||||
cachedImages.Add(exeIconCache[key]);
|
||||
lock (ExeIconCache) {
|
||||
foreach (string key in ExeIconCache.Keys) {
|
||||
cachedImages.Add(ExeIconCache[key]);
|
||||
}
|
||||
exeIconCache.Clear();
|
||||
ExeIconCache.Clear();
|
||||
}
|
||||
foreach (Image cachedImage in cachedImages) {
|
||||
if (cachedImage != null) {
|
||||
cachedImage.Dispose();
|
||||
}
|
||||
foreach (Image cachedImage in cachedImages)
|
||||
{
|
||||
cachedImage?.Dispose();
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -82,7 +81,7 @@ namespace GreenshotPlugin.Core {
|
|||
/// <param name="exeName">e.g. cmd.exe</param>
|
||||
/// <returns>Path to file</returns>
|
||||
public static string GetExePath(string exeName) {
|
||||
using (RegistryKey key = Registry.LocalMachine.OpenSubKey(PATH_KEY + exeName, false)) {
|
||||
using (RegistryKey key = Registry.LocalMachine.OpenSubKey(PathKey + exeName, false)) {
|
||||
if (key != null) {
|
||||
// "" is the default key, which should point to the requested location
|
||||
return (string)key.GetValue("");
|
||||
|
@ -91,11 +90,11 @@ namespace GreenshotPlugin.Core {
|
|||
foreach (string pathEntry in (Environment.GetEnvironmentVariable("PATH") ?? "").Split(';')) {
|
||||
try {
|
||||
string path = pathEntry.Trim();
|
||||
if (!String.IsNullOrEmpty(path) && File.Exists(path = Path.Combine(path, exeName))) {
|
||||
if (!string.IsNullOrEmpty(path) && File.Exists(path = Path.Combine(path, exeName))) {
|
||||
return Path.GetFullPath(path);
|
||||
}
|
||||
} catch (Exception) {
|
||||
LOG.WarnFormat("Problem with path entry '{0}'.", pathEntry);
|
||||
Log.WarnFormat("Problem with path entry '{0}'.", pathEntry);
|
||||
}
|
||||
}
|
||||
return null;
|
||||
|
@ -108,18 +107,22 @@ namespace GreenshotPlugin.Core {
|
|||
/// <param name="index">index of the icon</param>
|
||||
/// <returns>Bitmap with the icon or null if something happended</returns>
|
||||
public static Image GetCachedExeIcon(string path, int index) {
|
||||
string cacheKey = string.Format("{0}:{1}", path, index);
|
||||
string cacheKey = $"{path}:{index}";
|
||||
Image returnValue;
|
||||
lock (exeIconCache)
|
||||
lock (ExeIconCache)
|
||||
{
|
||||
if (!exeIconCache.TryGetValue(cacheKey, out returnValue)) {
|
||||
lock (exeIconCache) {
|
||||
if (!exeIconCache.TryGetValue(cacheKey, out returnValue)) {
|
||||
returnValue = GetExeIcon(path, index);
|
||||
if (returnValue != null) {
|
||||
exeIconCache.Add(cacheKey, returnValue);
|
||||
}
|
||||
}
|
||||
if (ExeIconCache.TryGetValue(cacheKey, out returnValue))
|
||||
{
|
||||
return returnValue;
|
||||
}
|
||||
lock (ExeIconCache) {
|
||||
if (ExeIconCache.TryGetValue(cacheKey, out returnValue))
|
||||
{
|
||||
return returnValue;
|
||||
}
|
||||
returnValue = GetExeIcon(path, index);
|
||||
if (returnValue != null) {
|
||||
ExeIconCache.Add(cacheKey, returnValue);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -137,18 +140,18 @@ namespace GreenshotPlugin.Core {
|
|||
return null;
|
||||
}
|
||||
try {
|
||||
using (Icon appIcon = ImageHelper.ExtractAssociatedIcon(path, index, conf.UseLargeIcons)) {
|
||||
using (Icon appIcon = ImageHelper.ExtractAssociatedIcon(path, index, CoreConfig.UseLargeIcons)) {
|
||||
if (appIcon != null) {
|
||||
return appIcon.ToBitmap();
|
||||
}
|
||||
}
|
||||
using (Icon appIcon = Shell32.GetFileIcon(path, conf.UseLargeIcons ? Shell32.IconSize.Large : Shell32.IconSize.Small, false)) {
|
||||
using (Icon appIcon = Shell32.GetFileIcon(path, CoreConfig.UseLargeIcons ? Shell32.IconSize.Large : Shell32.IconSize.Small, false)) {
|
||||
if (appIcon != null) {
|
||||
return appIcon.ToBitmap();
|
||||
}
|
||||
}
|
||||
} catch (Exception exIcon) {
|
||||
LOG.Error("error retrieving icon: ", exIcon);
|
||||
Log.Error("error retrieving icon: ", exIcon);
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
@ -163,10 +166,12 @@ namespace GreenshotPlugin.Core {
|
|||
/// <param name="shortcutKeys">Keys which can be used as shortcut</param>
|
||||
/// <param name="handler">The onclick handler</param>
|
||||
public static void AddToFileMenu(IImageEditor imageEditor, Image image, string text, object tag, Keys? shortcutKeys, EventHandler handler) {
|
||||
ToolStripMenuItem item = new ToolStripMenuItem();
|
||||
item.Image = image;
|
||||
item.Text = text;
|
||||
item.Tag = tag;
|
||||
var item = new ToolStripMenuItem
|
||||
{
|
||||
Image = image,
|
||||
Text = text,
|
||||
Tag = tag
|
||||
};
|
||||
if (shortcutKeys.HasValue) {
|
||||
item.ShortcutKeys = shortcutKeys.Value;
|
||||
}
|
||||
|
@ -228,9 +233,11 @@ namespace GreenshotPlugin.Core {
|
|||
if (contextMenu.Items[i].GetType() == typeof(ToolStripSeparator)) {
|
||||
// Check if we need to add a new separator, which is done if the first found has a Tag with the value "PluginsAreAddedBefore"
|
||||
if ("PluginsAreAddedBefore".Equals(contextMenu.Items[i].Tag)) {
|
||||
ToolStripSeparator separator = new ToolStripSeparator();
|
||||
separator.Tag = "PluginsAreAddedAfter";
|
||||
separator.Size = new Size(305, 6);
|
||||
var separator = new ToolStripSeparator
|
||||
{
|
||||
Tag = "PluginsAreAddedAfter",
|
||||
Size = new Size(305, 6)
|
||||
};
|
||||
contextMenu.Items.Insert(i, separator);
|
||||
} else if (!"PluginsAreAddedAfter".Equals(contextMenu.Items[i].Tag)) {
|
||||
continue;
|
||||
|
|
|
@ -337,7 +337,6 @@ namespace GreenshotPlugin.Core {
|
|||
using (IFastBitmap src = FastBitmap.Create(sourceBitmap)) {
|
||||
IFastBitmapWithBlend srcBlend = src as IFastBitmapWithBlend;
|
||||
Dictionary<Color, byte> lookup = new Dictionary<Color, byte>();
|
||||
byte bestMatch;
|
||||
for (int y = 0; y < src.Height; y++) {
|
||||
for (int x = 0; x < src.Width; x++) {
|
||||
Color color;
|
||||
|
@ -349,6 +348,7 @@ namespace GreenshotPlugin.Core {
|
|||
}
|
||||
|
||||
// Check if we already matched the color
|
||||
byte bestMatch;
|
||||
if (!lookup.ContainsKey(color)) {
|
||||
// If not we need to find the best match
|
||||
|
||||
|
@ -678,5 +678,5 @@ namespace GreenshotPlugin.Core {
|
|||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
|
@ -29,65 +29,49 @@ using log4net;
|
|||
|
||||
namespace GreenshotPlugin.Core {
|
||||
public class RssFile {
|
||||
private readonly string _file;
|
||||
public string File {
|
||||
get {return _file;}
|
||||
}
|
||||
public string File { get; }
|
||||
private readonly DateTime _pubdate;
|
||||
public DateTime Pubdate {
|
||||
get {return _pubdate;}
|
||||
}
|
||||
private readonly string _link;
|
||||
public string Link {
|
||||
get {return _link;}
|
||||
}
|
||||
private Version _version;
|
||||
public Version Version {
|
||||
get {return _version;}
|
||||
set {
|
||||
_version = value;
|
||||
}
|
||||
}
|
||||
private string _language;
|
||||
public string Language {
|
||||
get {return _language;}
|
||||
set {_language = value;}
|
||||
}
|
||||
public DateTime Pubdate => _pubdate;
|
||||
|
||||
public bool isExe {
|
||||
public string Link { get; }
|
||||
public Version Version { get; set; }
|
||||
|
||||
public string Language { get; set; }
|
||||
|
||||
public bool IsExe {
|
||||
get {
|
||||
if (_file != null) {
|
||||
return _file.ToLower().EndsWith(".exe");
|
||||
if (File != null) {
|
||||
return File.ToLower().EndsWith(".exe");
|
||||
}
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
public bool isUnstable {
|
||||
public bool IsUnstable {
|
||||
get {
|
||||
if (_file != null) {
|
||||
return _file.ToLower().Contains("unstable");
|
||||
if (File != null) {
|
||||
return File.ToLower().Contains("unstable");
|
||||
}
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
public bool isReleaseCandidate {
|
||||
public bool IsReleaseCandidate {
|
||||
get {
|
||||
if (_file != null) {
|
||||
return Regex.IsMatch(_file.ToLower(), "rc[0-9]+");
|
||||
if (File != null) {
|
||||
return Regex.IsMatch(File.ToLower(), "rc[0-9]+");
|
||||
}
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
public RssFile(string file, string pubdate, string link) {
|
||||
_file = file;
|
||||
File = file;
|
||||
if (!DateTime.TryParse(pubdate, out _pubdate))
|
||||
{
|
||||
DateTime.TryParseExact(pubdate.Replace(" UT", ""), "ddd, dd MMM yyyy HH:mm:ss", CultureInfo.InvariantCulture, DateTimeStyles.AssumeLocal, out _pubdate);
|
||||
}
|
||||
_link = link;
|
||||
Link = link;
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -95,16 +79,16 @@ namespace GreenshotPlugin.Core {
|
|||
/// Description of RssHelper.
|
||||
/// </summary>
|
||||
public class RssHelper {
|
||||
private static ILog LOG = LogManager.GetLogger(typeof(RssHelper));
|
||||
private const string RSSFEED = "http://getgreenshot.org/project-feed/";
|
||||
private static readonly ILog Log = LogManager.GetLogger(typeof(RssHelper));
|
||||
private const string Rssfeed = "http://getgreenshot.org/project-feed/";
|
||||
|
||||
/// <summary>
|
||||
/// This is using the HTTP HEAD Method to check if the RSS Feed is modified after the supplied date
|
||||
/// </summary>
|
||||
/// <param name="updateTime">DateTime</param>
|
||||
/// <returns>true if the feed is newer</returns>
|
||||
public static bool IsRSSModifiedAfter(DateTime updateTime) {
|
||||
DateTime lastModified = NetworkHelper.GetLastModified(new Uri(RSSFEED));
|
||||
public static bool IsRssModifiedAfter(DateTime updateTime) {
|
||||
DateTime lastModified = NetworkHelper.GetLastModified(new Uri(Rssfeed));
|
||||
if (lastModified == DateTime.MinValue)
|
||||
{
|
||||
// Time could not be read, just take now and add one hour to it.
|
||||
|
@ -118,17 +102,17 @@ namespace GreenshotPlugin.Core {
|
|||
/// Read the Greenshot RSS feed, so we can use this information to check for updates
|
||||
/// </summary>
|
||||
/// <returns>List with RssFile(s)</returns>
|
||||
public static IList<RssFile> readRSS() {
|
||||
public static IList<RssFile> ReadRss() {
|
||||
XmlDocument rssDoc = new XmlDocument();
|
||||
try {
|
||||
HttpWebRequest webRequest = NetworkHelper.CreateWebRequest(RSSFEED);
|
||||
HttpWebRequest webRequest = NetworkHelper.CreateWebRequest(Rssfeed);
|
||||
XmlTextReader rssReader = new XmlTextReader(webRequest.GetResponse().GetResponseStream());
|
||||
|
||||
// Load the XML content into a XmlDocument
|
||||
rssDoc.Load(rssReader);
|
||||
} catch (Exception wE) {
|
||||
LOG.WarnFormat("Problem reading RSS from {0}", RSSFEED);
|
||||
LOG.Warn(wE.Message);
|
||||
Log.WarnFormat("Problem reading RSS from {0}", Rssfeed);
|
||||
Log.Warn(wE.Message);
|
||||
return null;
|
||||
}
|
||||
|
||||
|
@ -143,7 +127,7 @@ namespace GreenshotPlugin.Core {
|
|||
}
|
||||
|
||||
if (nodeRss == null) {
|
||||
LOG.Debug("No RSS Feed!");
|
||||
Log.Debug("No RSS Feed!");
|
||||
return null;
|
||||
}
|
||||
|
||||
|
@ -158,7 +142,7 @@ namespace GreenshotPlugin.Core {
|
|||
}
|
||||
|
||||
if (nodeChannel == null) {
|
||||
LOG.Debug("No channel in RSS feed!");
|
||||
Log.Debug("No channel in RSS feed!");
|
||||
return null;
|
||||
}
|
||||
|
||||
|
@ -168,41 +152,49 @@ namespace GreenshotPlugin.Core {
|
|||
for (int i = 0; i < nodeChannel.ChildNodes.Count; i++) {
|
||||
// If it is the item tag, then it has children tags which we will add as items to the ListView
|
||||
|
||||
if (nodeChannel.ChildNodes[i].Name == "item") {
|
||||
XmlNode nodeItem = nodeChannel.ChildNodes[i];
|
||||
string link = nodeItem["link"].InnerText;
|
||||
string pubdate = nodeItem["pubDate"].InnerText;
|
||||
try {
|
||||
Match match= Regex.Match(Uri.UnescapeDataString(link), @"^.*\/(Greenshot.+)\/download$");
|
||||
if (match.Success) {
|
||||
string file = match.Groups[1].Value;
|
||||
if (nodeChannel.ChildNodes[i].Name != "item")
|
||||
{
|
||||
continue;
|
||||
}
|
||||
XmlNode nodeItem = nodeChannel.ChildNodes[i];
|
||||
string link = nodeItem["link"]?.InnerText;
|
||||
string pubdate = nodeItem["pubDate"]?.InnerText;
|
||||
try {
|
||||
if (link == null)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
Match match = Regex.Match(Uri.UnescapeDataString(link), @"^.*\/(Greenshot.+)\/download$");
|
||||
if (!match.Success)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
string file = match.Groups[1].Value;
|
||||
|
||||
RssFile rssFile = new RssFile(file, pubdate, link);
|
||||
if (file.EndsWith(".exe") ||file.EndsWith(".zip")) {
|
||||
string version = Regex.Replace(file, @".*[a-zA-Z_]\-", "");
|
||||
version = version.Replace(@"\-[a-zA-Z]+.*","");
|
||||
version = Regex.Replace(version, @"\.exe$", "");
|
||||
version = Regex.Replace(version, @"\.zip$", "");
|
||||
version = Regex.Replace(version, @"RC[0-9]+", "");
|
||||
if (version.Trim().Length > 0) {
|
||||
version = version.Replace('-','.');
|
||||
version = version.Replace(',','.');
|
||||
version = Regex.Replace(version, @"^[a-zA-Z_]*\.", "");
|
||||
version = Regex.Replace(version, @"\.[a-zA-Z_]*$", "");
|
||||
RssFile rssFile = new RssFile(file, pubdate, link);
|
||||
if (file.EndsWith(".exe") ||file.EndsWith(".zip")) {
|
||||
string version = Regex.Replace(file, @".*[a-zA-Z_]\-", "");
|
||||
version = version.Replace(@"\-[a-zA-Z]+.*","");
|
||||
version = Regex.Replace(version, @"\.exe$", "");
|
||||
version = Regex.Replace(version, @"\.zip$", "");
|
||||
version = Regex.Replace(version, @"RC[0-9]+", "");
|
||||
if (version.Trim().Length > 0) {
|
||||
version = version.Replace('-','.');
|
||||
version = version.Replace(',','.');
|
||||
version = Regex.Replace(version, @"^[a-zA-Z_]*\.", "");
|
||||
version = Regex.Replace(version, @"\.[a-zA-Z_]*$", "");
|
||||
|
||||
try {
|
||||
rssFile.Version = new Version(version);
|
||||
} catch (Exception) {
|
||||
LOG.DebugFormat("Found invalid version {0} in file {1}", version, file);
|
||||
}
|
||||
}
|
||||
rssFiles.Add(rssFile);
|
||||
try {
|
||||
rssFile.Version = new Version(version);
|
||||
} catch (Exception) {
|
||||
Log.DebugFormat("Found invalid version {0} in file {1}", version, file);
|
||||
}
|
||||
}
|
||||
} catch (Exception ex) {
|
||||
LOG.WarnFormat("Couldn't read RSS entry for: {0}", nodeChannel["title"].InnerText);
|
||||
LOG.Warn("Reason: ", ex);
|
||||
rssFiles.Add(rssFile);
|
||||
}
|
||||
} catch (Exception ex) {
|
||||
Log.WarnFormat("Couldn't read RSS entry for: {0}", nodeChannel["title"]?.InnerText);
|
||||
Log.Warn("Reason: ", ex);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -52,7 +52,7 @@ namespace GreenshotPlugin.Core {
|
|||
/// <returns>Formatted string</returns>
|
||||
public static string FormatWith(this string format, IFormatProvider provider, object source) {
|
||||
if (format == null) {
|
||||
throw new ArgumentNullException("format");
|
||||
throw new ArgumentNullException(nameof(format));
|
||||
}
|
||||
|
||||
IDictionary<string, object> properties = new Dictionary<string, object>();
|
||||
|
@ -80,11 +80,7 @@ namespace GreenshotPlugin.Core {
|
|||
Group endGroup = m.Groups["end"];
|
||||
|
||||
object value;
|
||||
if (properties.TryGetValue(propertyGroup.Value, out value)) {
|
||||
values.Add(value);
|
||||
} else {
|
||||
values.Add(source);
|
||||
}
|
||||
values.Add(properties.TryGetValue(propertyGroup.Value, out value) ? value : source);
|
||||
return new string('{', startGroup.Captures.Count) + (values.Count - 1) + formatGroup.Value + new string('}', endGroup.Captures.Count);
|
||||
});
|
||||
|
||||
|
@ -94,12 +90,12 @@ namespace GreenshotPlugin.Core {
|
|||
/// <summary>
|
||||
/// A simply rijndael aes encryption, can be used to store passwords
|
||||
/// </summary>
|
||||
/// <param name="ClearText">the string to call upon</param>
|
||||
/// <param name="clearText">the string to call upon</param>
|
||||
/// <returns>an encryped string in base64 form</returns>
|
||||
public static string Encrypt(this string ClearText) {
|
||||
string returnValue = ClearText;
|
||||
public static string Encrypt(this string clearText) {
|
||||
string returnValue = clearText;
|
||||
try {
|
||||
byte[] clearTextBytes = Encoding.ASCII.GetBytes(ClearText);
|
||||
byte[] clearTextBytes = Encoding.ASCII.GetBytes(clearText);
|
||||
SymmetricAlgorithm rijn = SymmetricAlgorithm.Create();
|
||||
|
||||
using (MemoryStream ms = new MemoryStream()) {
|
||||
|
@ -113,7 +109,7 @@ namespace GreenshotPlugin.Core {
|
|||
}
|
||||
}
|
||||
} catch (Exception ex) {
|
||||
LOG.ErrorFormat("Error encrypting, error: ", ex.Message);
|
||||
LOG.ErrorFormat("Error encrypting, error: {0}", ex.Message);
|
||||
}
|
||||
return returnValue;
|
||||
}
|
||||
|
@ -121,12 +117,12 @@ namespace GreenshotPlugin.Core {
|
|||
/// <summary>
|
||||
/// A simply rijndael aes decryption, can be used to store passwords
|
||||
/// </summary>
|
||||
/// <param name="EncryptedText">a base64 encoded rijndael encrypted string</param>
|
||||
/// <param name="encryptedText">a base64 encoded rijndael encrypted string</param>
|
||||
/// <returns>Decrypeted text</returns>
|
||||
public static string Decrypt(this string EncryptedText) {
|
||||
string returnValue = EncryptedText;
|
||||
public static string Decrypt(this string encryptedText) {
|
||||
string returnValue = encryptedText;
|
||||
try {
|
||||
byte[] encryptedTextBytes = Convert.FromBase64String(EncryptedText);
|
||||
byte[] encryptedTextBytes = Convert.FromBase64String(encryptedText);
|
||||
using (MemoryStream ms = new MemoryStream()) {
|
||||
SymmetricAlgorithm rijn = SymmetricAlgorithm.Create();
|
||||
|
||||
|
@ -142,7 +138,7 @@ namespace GreenshotPlugin.Core {
|
|||
|
||||
}
|
||||
} catch (Exception ex) {
|
||||
LOG.ErrorFormat("Error decrypting {0}, error: ", EncryptedText, ex.Message);
|
||||
LOG.ErrorFormat("Error decrypting {0}, error: {1}", encryptedText, ex.Message);
|
||||
}
|
||||
|
||||
return returnValue;
|
||||
|
|
|
@ -62,16 +62,13 @@ namespace GreenshotPlugin.Core {
|
|||
set;
|
||||
}
|
||||
|
||||
private readonly Dictionary<string, string> metaData = new Dictionary<string, string>();
|
||||
public Dictionary<string, string> MetaData {
|
||||
get {return metaData;}
|
||||
}
|
||||
|
||||
public Dictionary<string, string> MetaData { get; } = new Dictionary<string, string>();
|
||||
|
||||
public void AddMetaData(string key, string value) {
|
||||
if (metaData.ContainsKey(key)) {
|
||||
metaData[key] = value;
|
||||
if (MetaData.ContainsKey(key)) {
|
||||
MetaData[key] = value;
|
||||
} else {
|
||||
metaData.Add(key, value);
|
||||
MetaData.Add(key, value);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -117,10 +114,10 @@ namespace GreenshotPlugin.Core {
|
|||
/// Having the Bitmap, eventually the Windows Title and cursor all together.
|
||||
/// </summary>
|
||||
public class Capture : ICapture {
|
||||
private static readonly ILog LOG = LogManager.GetLogger(typeof(Capture));
|
||||
private static readonly ILog Log = LogManager.GetLogger(typeof(Capture));
|
||||
private List<ICaptureElement> _elements = new List<ICaptureElement>();
|
||||
|
||||
private Rectangle _screenBounds = Rectangle.Empty;
|
||||
private Rectangle _screenBounds;
|
||||
/// <summary>
|
||||
/// Get/Set the Screenbounds
|
||||
/// </summary>
|
||||
|
@ -141,13 +138,11 @@ namespace GreenshotPlugin.Core {
|
|||
public Image Image {
|
||||
get {return _image;}
|
||||
set {
|
||||
if (_image != null) {
|
||||
_image.Dispose();
|
||||
}
|
||||
_image?.Dispose();
|
||||
_image = value;
|
||||
if (value != null) {
|
||||
if (value.PixelFormat.Equals(PixelFormat.Format8bppIndexed) || value.PixelFormat.Equals(PixelFormat.Format1bppIndexed) || value.PixelFormat.Equals(PixelFormat.Format4bppIndexed)) {
|
||||
LOG.Debug("Converting Bitmap to PixelFormat.Format32bppArgb as we don't support: " + value.PixelFormat);
|
||||
Log.Debug("Converting Bitmap to PixelFormat.Format32bppArgb as we don't support: " + value.PixelFormat);
|
||||
try {
|
||||
// Default Bitmap PixelFormat is Format32bppArgb
|
||||
_image = new Bitmap(value);
|
||||
|
@ -156,9 +151,9 @@ namespace GreenshotPlugin.Core {
|
|||
value.Dispose();
|
||||
}
|
||||
}
|
||||
LOG.DebugFormat("Image is set with the following specifications: {0} - {1}", _image.Size, _image.PixelFormat);
|
||||
Log.DebugFormat("Image is set with the following specifications: {0} - {1}", _image.Size, _image.PixelFormat);
|
||||
} else {
|
||||
LOG.Debug("Image is removed.");
|
||||
Log.Debug("Image is removed.");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -174,21 +169,15 @@ namespace GreenshotPlugin.Core {
|
|||
public Icon Cursor {
|
||||
get {return _cursor;}
|
||||
set {
|
||||
if (_cursor != null) {
|
||||
_cursor.Dispose();
|
||||
}
|
||||
_cursor?.Dispose();
|
||||
_cursor = (Icon)value.Clone();
|
||||
}
|
||||
}
|
||||
|
||||
private bool _cursorVisible;
|
||||
|
||||
/// <summary>
|
||||
/// Set if the cursor is visible
|
||||
/// </summary>
|
||||
public bool CursorVisible {
|
||||
get {return _cursorVisible;}
|
||||
set {_cursorVisible = value;}
|
||||
}
|
||||
public bool CursorVisible { get; set; }
|
||||
|
||||
private Point _cursorLocation = Point.Empty;
|
||||
/// <summary>
|
||||
|
@ -257,12 +246,8 @@ namespace GreenshotPlugin.Core {
|
|||
/// <param name="disposing"></param>
|
||||
protected virtual void Dispose(bool disposing) {
|
||||
if (disposing) {
|
||||
if (_image != null) {
|
||||
_image.Dispose();
|
||||
}
|
||||
if (_cursor != null) {
|
||||
_cursor.Dispose();
|
||||
}
|
||||
_image?.Dispose();
|
||||
_cursor?.Dispose();
|
||||
}
|
||||
_image = null;
|
||||
_cursor = null;
|
||||
|
@ -273,27 +258,28 @@ namespace GreenshotPlugin.Core {
|
|||
/// </summary>
|
||||
/// <param name="cropRectangle">Rectangle with bitmap coordinates</param>
|
||||
public bool Crop(Rectangle cropRectangle) {
|
||||
LOG.Debug("Cropping to: " + cropRectangle.ToString());
|
||||
if (ImageHelper.Crop(ref _image, ref cropRectangle)) {
|
||||
_location = cropRectangle.Location;
|
||||
// Change mouse location according to the cropRegtangle (including screenbounds) offset
|
||||
MoveMouseLocation(-cropRectangle.Location.X, -cropRectangle.Location.Y);
|
||||
// Move all the elements
|
||||
// TODO: Enable when the elements are usable again.
|
||||
// MoveElements(-cropRectangle.Location.X, -cropRectangle.Location.Y);
|
||||
|
||||
// Remove invisible elements
|
||||
List <ICaptureElement> newElements = new List<ICaptureElement>();
|
||||
foreach(ICaptureElement captureElement in _elements) {
|
||||
if (captureElement.Bounds.IntersectsWith(cropRectangle)) {
|
||||
newElements.Add(captureElement);
|
||||
}
|
||||
}
|
||||
_elements = newElements;
|
||||
|
||||
return true;
|
||||
Log.Debug("Cropping to: " + cropRectangle);
|
||||
if (!ImageHelper.Crop(ref _image, ref cropRectangle))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
return false;
|
||||
_location = cropRectangle.Location;
|
||||
// Change mouse location according to the cropRegtangle (including screenbounds) offset
|
||||
MoveMouseLocation(-cropRectangle.Location.X, -cropRectangle.Location.Y);
|
||||
// Move all the elements
|
||||
// TODO: Enable when the elements are usable again.
|
||||
// MoveElements(-cropRectangle.Location.X, -cropRectangle.Location.Y);
|
||||
|
||||
// Remove invisible elements
|
||||
var newElements = new List<ICaptureElement>();
|
||||
foreach(var captureElement in _elements) {
|
||||
if (captureElement.Bounds.IntersectsWith(cropRectangle)) {
|
||||
newElements.Add(captureElement);
|
||||
}
|
||||
}
|
||||
_elements = newElements;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
|
@ -370,17 +356,9 @@ namespace GreenshotPlugin.Core {
|
|||
Name = name;
|
||||
Bounds = bounds;
|
||||
}
|
||||
|
||||
private List<ICaptureElement> _children = new List<ICaptureElement>();
|
||||
public List<ICaptureElement> Children {
|
||||
get {
|
||||
return _children;
|
||||
}
|
||||
set {
|
||||
_children = value;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
public List<ICaptureElement> Children { get; set; } = new List<ICaptureElement>();
|
||||
|
||||
public string Name {
|
||||
get;
|
||||
set;
|
||||
|
@ -392,17 +370,16 @@ namespace GreenshotPlugin.Core {
|
|||
|
||||
// CaptureElements are regarded equal if their bounds are equal. this should be sufficient.
|
||||
public override bool Equals(object obj) {
|
||||
bool ret = false;
|
||||
if (obj != null && GetType() == obj.GetType()) {
|
||||
CaptureElement other = obj as CaptureElement;
|
||||
if (other != null && Bounds.Equals(other.Bounds)) {
|
||||
ret = true;
|
||||
}
|
||||
if (obj == null || GetType() != obj.GetType())
|
||||
{
|
||||
return false;
|
||||
}
|
||||
return ret;
|
||||
CaptureElement other = obj as CaptureElement;
|
||||
return other != null && Bounds.Equals(other.Bounds);
|
||||
}
|
||||
|
||||
public override int GetHashCode() {
|
||||
// TODO: Fix this, this is not right...
|
||||
return Bounds.GetHashCode();
|
||||
}
|
||||
}
|
||||
|
@ -410,7 +387,7 @@ namespace GreenshotPlugin.Core {
|
|||
/// The Window Capture code
|
||||
/// </summary>
|
||||
public class WindowCapture {
|
||||
private static readonly ILog LOG = LogManager.GetLogger(typeof(WindowCapture));
|
||||
private static readonly ILog Log = LogManager.GetLogger(typeof(WindowCapture));
|
||||
private static readonly CoreConfiguration Configuration = IniConfig.GetIniSection<CoreConfiguration>();
|
||||
|
||||
/// <summary>
|
||||
|
@ -472,22 +449,22 @@ namespace GreenshotPlugin.Core {
|
|||
/// </summary>
|
||||
/// <returns>A Capture Object with the Mouse Cursor information in it.</returns>
|
||||
public static ICapture CaptureCursor(ICapture capture) {
|
||||
LOG.Debug("Capturing the mouse cursor.");
|
||||
Log.Debug("Capturing the mouse cursor.");
|
||||
if (capture == null) {
|
||||
capture = new Capture();
|
||||
}
|
||||
int x,y;
|
||||
CursorInfo cursorInfo = new CursorInfo();
|
||||
IconInfo iconInfo;
|
||||
CursorInfo cursorInfo = new CursorInfo();
|
||||
cursorInfo.cbSize = Marshal.SizeOf(cursorInfo);
|
||||
if (User32.GetCursorInfo(out cursorInfo)) {
|
||||
if (cursorInfo.flags == User32.CURSOR_SHOWING) {
|
||||
using (SafeIconHandle safeIcon = User32.CopyIcon(cursorInfo.hCursor)) {
|
||||
using (SafeIconHandle safeIcon = User32.CopyIcon(cursorInfo.hCursor))
|
||||
{
|
||||
IconInfo iconInfo;
|
||||
if (User32.GetIconInfo(safeIcon, out iconInfo)) {
|
||||
Point cursorLocation = User32.GetCursorLocation();
|
||||
// Allign cursor location to Bitmap coordinates (instead of Screen coordinates)
|
||||
x = cursorLocation.X - iconInfo.xHotspot - capture.ScreenBounds.X;
|
||||
y = cursorLocation.Y - iconInfo.yHotspot - capture.ScreenBounds.Y;
|
||||
var x = cursorLocation.X - iconInfo.xHotspot - capture.ScreenBounds.X;
|
||||
var y = cursorLocation.Y - iconInfo.yHotspot - capture.ScreenBounds.Y;
|
||||
// Set the location
|
||||
capture.CursorLocation = new Point(x, y);
|
||||
|
||||
|
@ -548,7 +525,7 @@ namespace GreenshotPlugin.Core {
|
|||
return false;
|
||||
}
|
||||
} catch (Exception ex) {
|
||||
LOG.Warn(ex.Message);
|
||||
Log.Warn(ex.Message);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -569,7 +546,7 @@ namespace GreenshotPlugin.Core {
|
|||
return false;
|
||||
}
|
||||
} catch (Exception ex) {
|
||||
LOG.Warn(ex.Message);
|
||||
Log.Warn(ex.Message);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -591,7 +568,10 @@ namespace GreenshotPlugin.Core {
|
|||
if (CaptureHandler.CaptureScreenRectangle != null) {
|
||||
try {
|
||||
capturedImage = CaptureHandler.CaptureScreenRectangle(captureBounds);
|
||||
} catch {
|
||||
}
|
||||
catch
|
||||
{
|
||||
// ignored
|
||||
}
|
||||
}
|
||||
// If no capture, use the normal screen capture
|
||||
|
@ -626,10 +606,10 @@ namespace GreenshotPlugin.Core {
|
|||
public static Bitmap CaptureRectangle(Rectangle captureBounds) {
|
||||
Bitmap returnBitmap = null;
|
||||
if (captureBounds.Height <= 0 || captureBounds.Width <= 0) {
|
||||
LOG.Warn("Nothing to capture, ignoring!");
|
||||
Log.Warn("Nothing to capture, ignoring!");
|
||||
return null;
|
||||
}
|
||||
LOG.Debug("CaptureRectangle Called!");
|
||||
Log.Debug("CaptureRectangle Called!");
|
||||
|
||||
// .NET GDI+ Solution, according to some post this has a GDI+ leak...
|
||||
// See http://connect.microsoft.com/VisualStudio/feedback/details/344752/gdi-object-leak-when-calling-graphics-copyfromscreen
|
||||
|
@ -640,8 +620,8 @@ namespace GreenshotPlugin.Core {
|
|||
// capture.Image = capturedBitmap;
|
||||
// capture.Location = captureBounds.Location;
|
||||
|
||||
using (SafeWindowDCHandle desktopDCHandle = SafeWindowDCHandle.FromDesktop()) {
|
||||
if (desktopDCHandle.IsInvalid) {
|
||||
using (var desktopDcHandle = SafeWindowDcHandle.FromDesktop()) {
|
||||
if (desktopDcHandle.IsInvalid) {
|
||||
// Get Exception before the error is lost
|
||||
Exception exceptionToThrow = CreateCaptureException("desktopDCHandle", captureBounds);
|
||||
// throw exception
|
||||
|
@ -649,9 +629,9 @@ namespace GreenshotPlugin.Core {
|
|||
}
|
||||
|
||||
// create a device context we can copy to
|
||||
using (SafeCompatibleDCHandle safeCompatibleDCHandle = GDI32.CreateCompatibleDC(desktopDCHandle)) {
|
||||
using (SafeCompatibleDCHandle safeCompatibleDcHandle = GDI32.CreateCompatibleDC(desktopDcHandle)) {
|
||||
// Check if the device context is there, if not throw an error with as much info as possible!
|
||||
if (safeCompatibleDCHandle.IsInvalid) {
|
||||
if (safeCompatibleDcHandle.IsInvalid) {
|
||||
// Get Exception before the error is lost
|
||||
Exception exceptionToThrow = CreateCaptureException("CreateCompatibleDC", captureBounds);
|
||||
// throw exception
|
||||
|
@ -665,20 +645,21 @@ namespace GreenshotPlugin.Core {
|
|||
|
||||
// create a bitmap we can copy it to, using GetDeviceCaps to get the width/height
|
||||
IntPtr bits0; // not used for our purposes. It returns a pointer to the raw bits that make up the bitmap.
|
||||
using (SafeDibSectionHandle safeDibSectionHandle = GDI32.CreateDIBSection(desktopDCHandle, ref bmi, BITMAPINFOHEADER.DIB_RGB_COLORS, out bits0, IntPtr.Zero, 0)) {
|
||||
using (SafeDibSectionHandle safeDibSectionHandle = GDI32.CreateDIBSection(desktopDcHandle, ref bmi, BITMAPINFOHEADER.DIB_RGB_COLORS, out bits0, IntPtr.Zero, 0)) {
|
||||
if (safeDibSectionHandle.IsInvalid) {
|
||||
// Get Exception before the error is lost
|
||||
Exception exceptionToThrow = CreateCaptureException("CreateDIBSection", captureBounds);
|
||||
exceptionToThrow.Data.Add("hdcDest", safeCompatibleDCHandle.DangerousGetHandle().ToInt32());
|
||||
exceptionToThrow.Data.Add("hdcSrc", desktopDCHandle.DangerousGetHandle().ToInt32());
|
||||
exceptionToThrow.Data.Add("hdcDest", safeCompatibleDcHandle.DangerousGetHandle().ToInt32());
|
||||
exceptionToThrow.Data.Add("hdcSrc", desktopDcHandle.DangerousGetHandle().ToInt32());
|
||||
|
||||
// Throw so people can report the problem
|
||||
throw exceptionToThrow;
|
||||
}
|
||||
// select the bitmap object and store the old handle
|
||||
using (safeCompatibleDCHandle.SelectObject(safeDibSectionHandle)) {
|
||||
using (safeCompatibleDcHandle.SelectObject(safeDibSectionHandle)) {
|
||||
// bitblt over (make copy)
|
||||
GDI32.BitBlt(safeCompatibleDCHandle, 0, 0, captureBounds.Width, captureBounds.Height, desktopDCHandle, captureBounds.X, captureBounds.Y, CopyPixelOperation.SourceCopy | CopyPixelOperation.CaptureBlt);
|
||||
// ReSharper disable once BitwiseOperatorOnEnumWithoutFlags
|
||||
GDI32.BitBlt(safeCompatibleDcHandle, 0, 0, captureBounds.Width, captureBounds.Height, desktopDcHandle, captureBounds.X, captureBounds.Y, CopyPixelOperation.SourceCopy | CopyPixelOperation.CaptureBlt);
|
||||
}
|
||||
|
||||
// get a .NET image object for it
|
||||
|
@ -731,12 +712,12 @@ namespace GreenshotPlugin.Core {
|
|||
success = true;
|
||||
break;
|
||||
} catch (ExternalException ee) {
|
||||
LOG.Warn("Problem getting bitmap at try " + i + " : ", ee);
|
||||
Log.Warn("Problem getting bitmap at try " + i + " : ", ee);
|
||||
exception = ee;
|
||||
}
|
||||
}
|
||||
if (!success) {
|
||||
LOG.Error("Still couldn't create Bitmap!");
|
||||
Log.Error("Still couldn't create Bitmap!");
|
||||
if (exception != null) {
|
||||
throw exception;
|
||||
}
|
||||
|
|
|
@ -680,12 +680,10 @@ namespace GreenshotPlugin.Core {
|
|||
RECT rect = new RECT(screen.Bounds);
|
||||
IntPtr monitor = User32.MonitorFromRect(ref rect, User32.MONITOR_DEFAULTTONULL);
|
||||
if (monitor != IntPtr.Zero) {
|
||||
if (AppVisibility != null) {
|
||||
MONITOR_APP_VISIBILITY monitorAppVisibility = AppVisibility.GetAppVisibilityOnMonitor(monitor);
|
||||
//LOG.DebugFormat("App {0} visible: {1} on {2}", Text, monitorAppVisibility, screen.Bounds);
|
||||
if (monitorAppVisibility == MONITOR_APP_VISIBILITY.MAV_APP_VISIBLE) {
|
||||
return true;
|
||||
}
|
||||
MONITOR_APP_VISIBILITY? monitorAppVisibility = AppVisibility?.GetAppVisibilityOnMonitor(monitor);
|
||||
//LOG.DebugFormat("App {0} visible: {1} on {2}", Text, monitorAppVisibility, screen.Bounds);
|
||||
if (monitorAppVisibility == MONITOR_APP_VISIBILITY.MAV_APP_VISIBLE) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue