Synopsis
Not so long ago I began to study C # and very soon the experiments turned into a desire to write some easy, simple, but at the same time useful and convenient application. The idea of a program designed to quickly take screenshots and automatically upload them to hosting was gradually born. I did not find any analogues that met my requirements, so I decided to do it myself, and after that one good person gave the idea to write an article about it.
The essence
So what does my program do?
- It takes screenshots in one click: by pressing "hot keys" (Ctrl + Print Screen) or by clicking on the tray icon.
- Saves images (obviously) with file names containing the date and time.
- Immediately uploads them to Imgur.com and displays a link in a pop-up window.
- When you click on the pop-up window, the downloaded image opens in the browser.
- It is possible to copy the link to the clipboard (via the context menu of the program).
- You can, also from the context menu, open the folder with the saved screenshots in Explorer.
- And finally, the quick and easy autorun of the application when the system boots.
Difficulties
And now the part which, probably, will seem obvious and banal to someone, and can help someone. Even with the development of such a small application, as it turned out, it is impossible to avoid difficult moments.
Upload image to hosting
The first thing I encountered was an error using the hosting API: the image was loaded, but the last few kilobytes of the file had disappeared. Initially I used the following code, found among the
examples of using the API on the hosting itself:
using System; using System.IO; using System.Net; using System.Text; namespace ImgurExample { class Program { static void Main(string[] args) { PostToImgur(@"C:\Users\ashwin\Desktop\image.jpg", IMGUR_ANONYMOUS_API_KEY); } public static void PostToImgur(string imagFilePath, string apiKey) { byte[] imageData; FileStream fileStream = File.OpenRead(imagFilePath); imageData = new byte[fileStream.Length]; fileStream.Read(imageData, 0, imageData.Length); fileStream.Close(); string uploadRequestString = "image=" + Uri.EscapeDataString(System.Convert.ToBase64String(imageData)) + "&key=" + apiKey; HttpWebRequest webRequest = (HttpWebRequest)WebRequest.Create("http://api.imgur.com/2/upload"); webRequest.Method = "POST"; webRequest.ContentType = "application/x-www-form-urlencoded"; webRequest.ServicePoint.Expect100Continue = false; StreamWriter streamWriter = new StreamWriter(webRequest.GetRequestStream()); streamWriter.Write(uploadRequestString); streamWriter.Close(); WebResponse response = webRequest.GetResponse(); Stream responseStream = response.GetResponseStream(); StreamReader responseReader = new StreamReader(responseStream); string responseString = responseReader.ReadToEnd(); } }
There were errors in the code, but even after fixing them, the problem did not disappear. After a long and painful search for errors and a lot of tried and tested options, I came to the hypothesis that the file may be cut off after encoding due to the slashes used in base64. They may have been interpreted as escape characters, but it was already too lazy to find out exactly: I would have to catch a sniffer about what was going on the network (everything was fine in the debugger up to streamWriter.Write (uploadRequestString)), compare base64 sequences, and so on .P. On the Internet, this problem was not specifically covered, but there were a couple of posts that were also suspected of slashes.
In the end, I used the second version of the code found on
StackOverflow :
using (var w = new WebClient()) { var values = new NameValueCollection { { "key", "433a1bf4743dd8d7845629b95b5ca1b4" }, { "image", Convert.ToBase64String(File.ReadAllBytes(@"hello.png")) } }; byte[] response = w.UploadValues("http://imgur.com/api/upload.xml", values); Console.WriteLine(XDocument.Load(new MemoryStream(response))); }">
He was already working like a clock, it only took to adapt it to his needs - the function was to return only the link, and not the entire answer.
')
Hotkeys
The second difficulty arose with hotkeys. Everywhere it is proposed to intercept global hotkeys by hanging the hook with the RegisterHotKey function, and then redefining WndProc and already perceive the message in it. It would seem, what could be the difficulty here? The difficulty arose in the fact that my application is windowless (although WinForms), therefore, there is neither a window handle for transmission to RegisterHotKey, nor the window itself, in which WndProc could be redefined. After intense smoking, the manuals revealed that it is not necessary to transfer the descriptor - in this case, the messages will be sent not to the window, but to the stream that caused RegisterHotKey. The first part of the problem was solved, but there was still nothing to catch the message itself. After a couple more glasses of coffee, I found a solution for this problem:
Application.AddMessageFilter () . In order to use it, you need to implement a "filter" of messages, in my case, he caught WM_HOTKEY and called the appropriate procedure for pushing back in the context of the application. There were no more obstacles to the development.
Fin
The application, of course, freeware and source I also decided to make
open . Comments left in those parts of the code, which, in my opinion, are not obvious by themselves. There is no localization support, the interface language is English. The application is written in VS2010 under .NET 4.0, no third-party libraries were used. The icon was found at
iconfinder.com . I do not pretend to the uniqueness of the idea, the program was written to get a hand in the process of which I ran into certain tasks and described their solution in the article.
UPD. Filled the binaries separately so that you can use without downloading the entire repository:
ScreenPaste.exe