diff --git a/Greenshot/releases/additional_files/readme.txt.template b/Greenshot/releases/additional_files/readme.txt.template index 802efa9fa..14d9343da 100644 --- a/Greenshot/releases/additional_files/readme.txt.template +++ b/Greenshot/releases/additional_files/readme.txt.template @@ -9,6 +9,21 @@ All details to our tickets can be found here: https://greenshot.atlassian.net @DETAILVERSION@ +Bugs fixed: +* [BUG-2235] - Imgur authentication issues due to imgur api change +* [BUG-2227] - NullReferenceException when accessing the Imgur History +* [BUG-2225] - NullReferenceException when changing the color of text +* [BUG-2219] - Korean is spelled incorrectly in the installer +* [BUG-2213] - NullReferenceException in the Freehand tool +* [BUG-2203] - ArgumentNullException in the Freehand tool +* [BUG-2141] - Imgur authentication issues due to old embedded IE + +Features: +* [FEATURE-1064] - Added CTRL+Backspace & CTRL+A to the text tool + + +Greenshot 1.2.9.129-569de71 RELEASE + Bugs fixed: * [BUG-2051] - Scroll-lock button not usable as hotkey * [BUG-2056] - Cannot export to external command Paint.NET if .greenshot format is used diff --git a/GreenshotPlugin/Controls/OAuthLoginForm.cs b/GreenshotPlugin/Controls/OAuthLoginForm.cs index 12fd68b6e..a3c5ffea2 100644 --- a/GreenshotPlugin/Controls/OAuthLoginForm.cs +++ b/GreenshotPlugin/Controls/OAuthLoginForm.cs @@ -39,6 +39,9 @@ namespace GreenshotPlugin.Controls { public bool IsOk => DialogResult == DialogResult.OK; public OAuthLoginForm(string browserTitle, Size size, string authorizationLink, string callbackUrl) { + // Make sure Greenshot uses the correct browser version + IEHelper.FixBrowserVersion(false); + _callbackUrl = callbackUrl; // Fix for BUG-2071 if (callbackUrl.EndsWith("/")) diff --git a/GreenshotPlugin/Core/IEHelper.cs b/GreenshotPlugin/Core/IEHelper.cs index 01a806422..92ffa2816 100644 --- a/GreenshotPlugin/Core/IEHelper.cs +++ b/GreenshotPlugin/Core/IEHelper.cs @@ -18,7 +18,12 @@ * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ + +using System; using System.Collections.Generic; +using System.IO; +using System.Reflection; +using log4net; using Microsoft.Win32; namespace GreenshotPlugin.Core { @@ -26,24 +31,124 @@ namespace GreenshotPlugin.Core { /// Description of IEHelper. /// public static class IEHelper { + private static readonly ILog Log = LogManager.GetLogger(typeof(IEHelper)); // Internet explorer Registry key - private const string IE_KEY = @"Software\Microsoft\Internet Explorer"; + private const string IeKey = @"Software\Microsoft\Internet Explorer"; + /// - /// Helper method to get the IE version + /// Get the current browser version /// - /// - public static int IEVersion() { - int version = 7; - // Seeing if IE 9 is used, here we need another offset! - using (RegistryKey ieKey = Registry.LocalMachine.OpenSubKey(IE_KEY, false)) { - object versionKey = ieKey?.GetValue("Version"); - if (versionKey != null) { - int.TryParse(versionKey.ToString().Substring(0,1), out version); + /// int with browser version + public static int IEVersion + { + get + { + var maxVer = 7; + using (var ieKey = Registry.LocalMachine.OpenSubKey(IeKey, false)) + { + foreach (var value in new[] { "svcVersion", "svcUpdateVersion", "Version", "W2kVersion" }) + { + var objVal = ieKey.GetValue(value, "0"); + var strVal = Convert.ToString(objVal); + + var iPos = strVal.IndexOf('.'); + if (iPos > 0) + { + strVal = strVal.Substring(0, iPos); + } + + int res; + if (int.TryParse(strVal, out res)) + { + maxVer = Math.Max(maxVer, res); + } + } } + + return maxVer; } - return version; } - + + /// + /// Get the highest possible version for the embedded browser + /// + /// true to ignore the doctype when loading a page + /// IE Feature + public static int GetEmbVersion(bool ignoreDoctype = true) + { + var ieVersion = IEVersion; + + if (ieVersion > 9) + { + return ieVersion * 1000 + (ignoreDoctype ? 1 : 0); + } + + if (ieVersion > 7) + { + return ieVersion * 1111; + } + + return 7000; + } + + /// + /// Fix browser version to the highest possible + /// + /// true to ignore the doctype when loading a page + public static void FixBrowserVersion(bool ignoreDoctype = true) + { + var applicationName = Path.GetFileNameWithoutExtension(Assembly.GetEntryAssembly().Location); + FixBrowserVersion(applicationName, ignoreDoctype); + } + + /// + /// Fix the browser version for the specified application + /// + /// Name of the process + /// true to ignore the doctype when loading a page + public static void FixBrowserVersion(string applicationName, bool ignoreDoctype = true) + { + FixBrowserVersion(applicationName, GetEmbVersion(ignoreDoctype)); + } + + /// + /// Fix the browser version for the specified application + /// + /// Name of the process + /// + /// Version, see + /// Browser Emulation + /// + public static void FixBrowserVersion(string applicationName, int ieVersion) + { + ModifyRegistry("HKEY_CURRENT_USER", applicationName + ".exe", ieVersion); +#if DEBUG + ModifyRegistry("HKEY_CURRENT_USER", applicationName + ".vshost.exe", ieVersion); +#endif + } + + /// + /// Make the change to the registry + /// + /// HKEY_CURRENT_USER or something + /// Name of the executable + /// Version to use + private static void ModifyRegistry(string root, string applicationName, int ieFeatureVersion) + { + var regKey = root + @"\Software\Microsoft\Internet Explorer\Main\FeatureControl\FEATURE_BROWSER_EMULATION"; + try + { + Registry.SetValue(regKey, applicationName, ieFeatureVersion); + } + catch (Exception ex) + { + // some config will hit access rights exceptions + // this is why we try with both LOCAL_MACHINE and CURRENT_USER + Log.Error(ex); + Log.ErrorFormat("couldn't modify the registry key {0}", regKey); + } + } + /// /// Find the DirectUI window for MSAA (Accessible) /// @@ -55,7 +160,7 @@ namespace GreenshotPlugin.Core { } WindowDetails tmpWd = browserWindowDetails; // Since IE 9 the TabBandClass is less deep! - if (IEVersion() < 9) { + if (IEVersion < 9) { tmpWd = tmpWd.GetChild("CommandBarClass"); tmpWd = tmpWd?.GetChild("ReBarWindow32"); } diff --git a/GreenshotPlugin/Core/ImageOutput.cs b/GreenshotPlugin/Core/ImageOutput.cs index cbd4cec9b..125ec0dda 100644 --- a/GreenshotPlugin/Core/ImageOutput.cs +++ b/GreenshotPlugin/Core/ImageOutput.cs @@ -127,26 +127,20 @@ namespace GreenshotPlugin.Core { imageFormat = ImageFormat.Icon; break; default: - // Problem with non-seekable streams most likely doesn't happen with Windows 7 (OS Version 6.1 and later) - // http://stackoverflow.com/questions/8349260/generic-gdi-error-on-one-machine-but-not-the-other - if (!stream.CanSeek) { - if (!Environment.OSVersion.IsWindows7OrLater()) - { - useMemoryStream = true; - Log.Warn("Using memorystream prevent an issue with saving to a non seekable stream."); - } - } imageFormat = ImageFormat.Png; break; } Log.DebugFormat("Saving image to stream with Format {0} and PixelFormat {1}", imageFormat, imageToSave.PixelFormat); - // Check if we want to use a memory stream, to prevent a issue which happens with Windows before "7". + // Check if we want to use a memory stream, to prevent issues with non seakable streams // The save is made to the targetStream, this is directed to either the MemoryStream or the original Stream targetStream = stream; - if (useMemoryStream) { - memoryStream = new MemoryStream(); - targetStream = memoryStream; + if (!stream.CanSeek) + { + useMemoryStream = true; + Log.Warn("Using memorystream prevent an issue with saving to a non seekable stream."); + memoryStream = new MemoryStream(); + targetStream = memoryStream; } if (Equals(imageFormat, ImageFormat.Jpeg)) @@ -213,18 +207,20 @@ namespace GreenshotPlugin.Core { } // Output the surface elements, size and marker to the stream - if (outputSettings.Format == OutputFormat.greenshot) { - using (MemoryStream tmpStream = new MemoryStream()) { - long bytesWritten = surface.SaveElementsToStream(tmpStream); - using (BinaryWriter writer = new BinaryWriter(tmpStream)) { - writer.Write(bytesWritten); - Version v = Assembly.GetExecutingAssembly().GetName().Version; - byte[] marker = Encoding.ASCII.GetBytes($"Greenshot{v.Major:00}.{v.Minor:00}"); - writer.Write(marker); - tmpStream.WriteTo(stream); - } - } - } + if (outputSettings.Format != OutputFormat.greenshot) + { + return; + } + using (MemoryStream tmpStream = new MemoryStream()) { + long bytesWritten = surface.SaveElementsToStream(tmpStream); + using (BinaryWriter writer = new BinaryWriter(tmpStream)) { + writer.Write(bytesWritten); + Version v = Assembly.GetExecutingAssembly().GetName().Version; + byte[] marker = Encoding.ASCII.GetBytes($"Greenshot{v.Major:00}.{v.Minor:00}"); + writer.Write(marker); + tmpStream.WriteTo(stream); + } + } } finally { diff --git a/GreenshotPlugin/Core/OAuthHelper.cs b/GreenshotPlugin/Core/OAuthHelper.cs index 39cab8081..eb0f90353 100644 --- a/GreenshotPlugin/Core/OAuthHelper.cs +++ b/GreenshotPlugin/Core/OAuthHelper.cs @@ -1002,12 +1002,21 @@ 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[AccessToken]; - settings.RefreshToken = (string)refreshTokenResult[RefreshToken]; - - object seconds = refreshTokenResult[ExpiresIn]; - if (seconds != null) { - settings.AccessTokenExpires = DateTimeOffset.Now.AddSeconds((double)seconds); + if (refreshTokenResult.ContainsKey(AccessToken)) + { + settings.AccessToken = (string)refreshTokenResult[AccessToken]; + } + if (refreshTokenResult.ContainsKey(RefreshToken)) + { + settings.RefreshToken = (string)refreshTokenResult[RefreshToken]; + } + if (refreshTokenResult.ContainsKey(ExpiresIn)) + { + object seconds = refreshTokenResult[ExpiresIn]; + if (seconds != null) + { + settings.AccessTokenExpires = DateTimeOffset.Now.AddSeconds((double)seconds); + } } settings.Code = null; } @@ -1029,14 +1038,17 @@ Greenshot received information from CloudServiceName. You can close this browser // Refresh the refresh token :) settings.RefreshToken = callbackParameters[RefreshToken]; } - var expiresIn = callbackParameters[ExpiresIn]; - settings.AccessTokenExpires = DateTimeOffset.MaxValue; - if (expiresIn != null) + if (callbackParameters.ContainsKey(ExpiresIn)) { - double seconds; - if (double.TryParse(expiresIn, out seconds)) + var expiresIn = callbackParameters[ExpiresIn]; + settings.AccessTokenExpires = DateTimeOffset.MaxValue; + if (expiresIn != null) { - settings.AccessTokenExpires = DateTimeOffset.Now.AddSeconds(seconds); + double seconds; + if (double.TryParse(expiresIn, out seconds)) + { + settings.AccessTokenExpires = DateTimeOffset.Now.AddSeconds(seconds); + } } } settings.AccessToken = callbackParameters[AccessToken]; @@ -1085,16 +1097,22 @@ Greenshot received information from CloudServiceName. You can close this browser } } - settings.AccessToken = (string)accessTokenResult[AccessToken]; + if (accessTokenResult.ContainsKey(AccessToken)) + { + settings.AccessToken = (string) accessTokenResult[AccessToken]; + settings.AccessTokenExpires = DateTimeOffset.MaxValue; + } if (accessTokenResult.ContainsKey(RefreshToken)) { // Refresh the refresh token :) settings.RefreshToken = (string)accessTokenResult[RefreshToken]; } - object seconds = accessTokenResult[ExpiresIn]; - if (seconds != null) { - settings.AccessTokenExpires = DateTimeOffset.Now.AddSeconds((double)seconds); - } else { - settings.AccessTokenExpires = DateTimeOffset.MaxValue; + if (accessTokenResult.ContainsKey(ExpiresIn)) + { + object seconds = accessTokenResult[ExpiresIn]; + if (seconds != null) + { + settings.AccessTokenExpires = DateTimeOffset.Now.AddSeconds((double) seconds); + } } } diff --git a/appveyor12.yml b/appveyor12.yml index 9d03aa8fc..9d63fd246 100644 --- a/appveyor12.yml +++ b/appveyor12.yml @@ -38,7 +38,7 @@ environment: secure: bjKXhFZkDqaq98XBrz5oQKQfT8CLpuv2ZAiBIwkzloaAPUs97b5yx6h/xFaE4NLS credentials_picasa_consumer_secret: secure: yNptTpmJWypbu9alOQtetxU66drr2FKxoPflNgRJdag= - build_type: RC + build_type: RC1 rsakey: secure: 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 before_build: