引言:开始尝试使用MarkDown语法写文档,发现图片必须用外链的形式才能插入到文章中,而本身平时最经常使用的插入图片方式就是QQ截屏,以为很不方便因此制做的小工具辅助上传,由于时间和水平有限,其实代码写的很粗糙,之后有时间会不断改进。web
上传用的网址是极简图床 极简图床,这个图床内部使用的是六牛云,由于这个图床的上传不须要身份认证比较简单,因此就用它作的,后期仍是要换到六牛云比较保险。编程
抓包使用的是Fiddler 4 ,开启以后至关于一个代理,电脑几乎全部的网络请求都会被监视到,可是浏览器的包须要设置一下代理,IP写本机,端口号8888
== 注意 ==:这个代理设置会影响到IE浏览器,若是关掉了fiddler没有删掉代理,容易出现的一个奇葩问题就是TFS没法登录。windows
抓包的结果是这样的:
数据包里面有几个须要注意的点:数组
在这里面我遇到了一个问题,就是cookie的获取,我用网上给的那种在爬虫程序中获取cookie 的方式并无成功,后来我想这种字符串类型的cookie不就是http头里面的一部分信息么,而后就把抓包里面的cookie直接以键值对的方式写到了http头里面,这个也不知道之后会有什么弊端,代码以下:浏览器
public static string PostHttp(string url, byte[] body) { HttpWebRequest httpWebRequest = (HttpWebRequest)WebRequest.Create(url); httpWebRequest.ContentType = "text/plain"; httpWebRequest.Method = "POST"; httpWebRequest.Timeout = 20000; httpWebRequest.Headers.Add("Cookie", cookieStr); byte[] btBodys = body; httpWebRequest.ContentLength = btBodys.Length; httpWebRequest.GetRequestStream().Write(btBodys, 0, btBodys.Length); HttpWebResponse httpWebResponse = (HttpWebResponse)httpWebRequest.GetResponse(); StreamReader streamReader = new StreamReader(httpWebResponse.GetResponseStream()); string responseContent = streamReader.ReadToEnd(); httpWebResponse.Close(); streamReader.Close(); httpWebRequest.Abort(); httpWebResponse.Close(); return responseContent; }
HttpClient,HttpWebRequest,HttpWebResponse这三个类是封装的http请求的类,其中HttpClient的封装程度最高,关于这三个类的具体使用和注意事项准备再写一个总结。cookie
返回的值是Json形式,这个在Fiddler抓的包里面能看见,用Json.Net解析一下就能够拿到外链字符串了。网络
这个是目前来讲我以为比较麻烦的地方,由于涉及到了对windows这个操做系统的编程,好比剪贴板的变化,或者快捷键(ctrl+v)的监听,这些有一部分要调用windows操做系统的API,更有一些须要使用一种叫HOOK的技术,甚至能够hook住QQ截屏(ctrl+alt+a)这个函数的地址,这个应该是实现效果的最优解。ide
可是由于本身水平有限,因此选择了最简单的调用Windows API的实现方式。函数
剪贴板是很是方便的进程间通信,下面是引用的一段解释工具
剪贴板是Windows系统一段可连续的。可随存放信息的大小而变化的内存空间,用来临时存放交换信息。内置在windows而且使用系统的内部资源RAM,或虚拟内存来临时保存剪切和复制的信息,能够存放的信息种类是多种多样的。剪切或复制时保存在剪贴板上的信息,只有再剪贴或复制另外的信息,或停电、或退出windows,或有意地清除时,才可能更新或清除其内容,即剪贴或复制一次,就能够粘贴屡次。
C#定义了一个类System.Windows.Forms.Clipboard来简化剪切板操做,要使用剪贴板要先引入三个函数:
[System.Runtime.InteropServices.DllImport("user32")] private static extern IntPtr SetClipboardViewer(IntPtr hwnd); [System.Runtime.InteropServices.DllImport("user32")] private static extern IntPtr ChangeClipboardChain(IntPtr hwnd,IntPtr hWndNext); [System.Runtime.InteropServices.DllImport("user32")] private static extern int SendMessage(IntPtr hwnd,int wMsg,IntPtr wParam,IntPtr lParam);
还有两个常量:
const int WM_DRAWCLIPBOARD = 0x308; const int WM_CHANGECBCHAIN = 0x30D;
IntPtr SetClipboardViewer(IntPtr hwnd):
用于往观察链中添加一个窗口句柄,这个窗口就可成为观察链中的一员了,返回值指向下一个观察者。
IntPtr ChangeClipboardChain(IntPtr hwnd,IntPtr hWndNext): 删除由hwnd指定的观察链成员,这是一个窗口句柄,第二个参数hWndNext是观察链中下一个窗口的句柄
int SendMessage(IntPtr hwnd,int wMsg,IntPtr wParam,IntPtr lParam): 发送消息,还有一个很重要的做用是将WM_DRAWCLIPBOARD 消息传递到下一个观察链中的窗口
观察链:其实有不少程序在一块儿监视剪贴板,好比迅雷在检测到你复制了下载连接的时候,就会自动启动。
定义完成后,能够分三部来使用,第一步把本身的窗口添加到观察链中成为观察者,并保存下一个观察者的句柄;第二步监视剪切板,并把剪切板变化的消息发送给下一个观察者;第三步撤消本身定义的观察者,并通知下一个观察者。
//存放观察链中下一个窗口句柄 IntPtr NextClipHwnd; private void Form1_Load(object sender, System.EventArgs e) { //得到观察链中下一个窗口句柄 NextClipHwnd=SetClipboardViewer(this.Handle); }
这里用到两个消息常量:
const int WM_DRAWCLIPBOARD = 0x308; const int WM_CHANGECBCHAIN = 0x30D; protected override void WndProc(ref System.Windows.Forms.Message m) { switch(m.Msg) { case WM_DRAWCLIPBOARD: //将WM_DRAWCLIPBOARD消息传递到下一个观察链中的窗口 SendMessage(NextClipHwnd,m.Msg,m.WParam,m.LParam); IDataObject iData = Clipboard.GetDataObject(); //检测文本 if(iData.GetDataPresent(DataFormats.Text)|iData.GetDataPresent(DataFormats.OemText)) { this.richTextBox1.Text=(String)iData.GetData(DataFormats.Text); } //检测图像 if (iData.GetDataPresent(DataFormats.Bitmap)) { pictureBox1.Image=Clipboard.GetImage(); NewClipData(); } //检测自定义类型 if (iData.GetDataPresent("myFormat")) { MyObj myobj=(MyObj)iData.GetData("myFormat"); this.richTextBox1.Text=myobj.ObjName; } break; default: base.WndProc(ref m); break; } }
private void Form1_Closed(object sender, System.EventArgs e) { //从观察链中删除本观察窗口(第一个参数:将要删除的窗口的句柄;第二个参数://观察链中下一个窗口的句柄 ) ChangeClipboardChain(this.Handle,NextClipHwnd); //将变更消息WM_CHANGECBCHAIN消息传递到下一个观察链中的窗口 SendMessage(NextClipHwnd,WM_CHANGECBCHAIN,this.Handle,NextClipHwnd); }
我本身的代码并不是彻底按照上面的格式书写。
这一部分主要是编码,字节数组和流的操做,就直接贴代码了。
//读取图片而且进行操做 private void Handler() { Image image = Clipboard.GetImage(); if (image != null) { string base64str = ImageToBase64String(image); byte[] decodedByteArray = Encoding.UTF8.GetBytes(base64str); string responsdata = PostHttp(uri, decodedByteArray); ImageInfo info = JsonConvert.DeserializeObject<ImageInfo>(responsdata); Clipboard.SetDataObject(""); } } //图片转base64编码 private string ImageToBase64String(Image imageData) { string base64; MemoryStream memory = new MemoryStream(); imageData.Save(memory, ImageFormat.Png); base64 = System.Convert.ToBase64String(memory.ToArray()); memory.Close(); memory = null; return base64; }
作的工具虽然小,可是涉及到了好多方面的知识,其中Windows编程这一块是新的领域,http是加深了理解,IO操做和Image操做是学过可是已经不熟悉了,接下来的时间查缺补漏,而后把东西好好完善一下。
下载连接:下载地址