DaoMail - путь письма
социальная почтовая служба (beta-версия)
весь DaoMail
вход / регистрация
Гость
ваша подписка (0
реклама
.NET / [Из песочницы] И снова скриншоты в один клик (C#)
| text | html

web-архив: карантин » хостинг » это письмо

2011-11-14 16:42:59

Синопсис

Не так давно начал изучать C# и очень скоро эксперименты переросли в желание написать какое-нибудь легкое, простое, но вместе с тем полезное и удобное приложение. Постепенно родилась идея программы, предназначенной для быстрого снятия скриншотов и автоматической загрузки их на хостинг. Беглое гугление показало, что, как ни странно, приложений, аналогичных моей задумке, нет, поэтому я решил все же сделать его, а уже после этого один хороший человек подал идею написать статью об этом.

Суть

Итак, что моя программа умеет?

Снимает скриншоты в один клик: по нажатию «горячих клавиш» (Ctrl+Print Screen) либо по клику на иконке в трее.

Сохраняет изображения (очевидно) с именами файлов, содержащими дату и время.

Тут же автоматически загружает их на Imgur.com и выдает ссылку во всплывающем окне.

При нажатии на всплывающее окно загруженная картинка открывается в браузере.

Есть возможность скопировать ссылку в буфер обмена (через контекстное меню программы).

Можно, тоже из контекстного меню, открыть папку с сохраненными скриншотами в Проводнике.

И наконец, легко и быстро включаемый автозапуск приложения при загрузке системы.

Трудности

А теперь часть, которая, возможно, кому-то покажется очевидной и банальной, а кому-то может помочь. Даже при разработке такого небольшого приложения, как оказалось, невозможно избежать сложных моментов.

Загрузка изображения на хостинг

Первым, с чем я столкнулся, была ошибка с использованием API хостинга: изображение загружалось, но куда-то девались последние несколько килобайт файла. Вначале использовал следующий код, найденный среди примеров использования API на самом хостинге:

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(); } }

В коде были ошибки, но даже после их исправления проблема не исчезла. После долгих и мучительных поисков ошибки и множества перепробованных вариантов я пришел к гипотезе, что файл может обрезаться после кодирования из-за слешей, используемых в base64. Возможно, они интерпретировались как escape-символы, но точно выяснять это было уже лень: пришлось бы сниффером ловить, что именно уходит в сеть (в отладчике все было отлично вплоть до вызова streamWriter.Write(uploadRequestString)), сравнивать base64-последовательности и т.п. В интернете эта проблема конкретно не освещалась, но попалась пара постов, в которых тоже были подозрения на слеши.

В итоге я использовал второй вариант кода, найденный на 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))); }">

Он уже работал как часы, потребовалось только адаптировать его под свои нужды — функция должна была возвращать только ссылку, а не весь ответ.

Горячие клавиши

Вторая сложность возникла с горячими клавишами. Везде предлагается для перехвата глобальных горячих клавиш вешать хук функцией RegisterHotKey, а затем переопределять WndProc и в ней уже воспринимать сообщение. Казалось бы, в чем может быть сложность здесь? Сложность возникла в том, что мое приложение безоконное (хоть и WinForms), стало быть, нет ни дескриптора окна для передачи в RegisterHotKey, ни самого окна, в котором можно было бы переопределить WndProc. После напряженного курения мануалов выяснилось, что дескриптор передавать необязательно — в этом случае сообщения будут передавать не окну, а вызвавшему RegisterHotKey потоку. Первая часть проблемы была решена, но ловить само сообщение все еще было нечем. После еще пары стаканов кофе нашел решение и для этой проблемы: Application.AddMessageFilter(). Для того, чтобы ею воспользоваться, необходимо реализовать «фильтр» сообщений, в моем случае, он ловил WM_HOTKEY и вызывал соответствующую процедуру для обратки нажатия в контексте приложения. Больше препятствий для разработки не было.

Fin

Приложение, разумеется, freeware и исходники я тоже решил сделать открытыми. Комментарии оставлял в тех местах кода, которые, по моему мнению, неочевидны сами по себе. Поддержки локализаций нет, язык интерфейса английский. Приложение написано в VS2010 под .NET 4.0, никаких сторонних библиотек использовано не было. Иконка была найдена на iconfinder.com.

Источник



web-архив: карантин » хостинг » это письмо








© 2004-2024 DaoMail.ru