Send(handle(this), 274, 61458, 0)
Send = SendMessage
handle(this) = 當前控件的句柄
274 = WM_SYSCOMMAND = 0x112
61458 = SC_MOVE = 0xf012
這裡僅僅寫了一行代碼,發送了一個消息,就實現拖動的效果。
Amazing..........
在MouseDown,MouseMove,MouseUp裏寫各種移動代碼都弱爆了。
驚歎完了,在看看轉成C#的坑爹代碼
在ST鼠標拖放事件裏(由於各種原因,PB裏拖放處理是關聯到MouseDown事件的,到C#就直接成了MouseDrag事件)
SendMessage(this.hwnd, WM_SYSCOMMAND, SC_MOVE, 0);
然後就是........拖動沒反應,經過一輪百度、谷歌搜索資料。
我們把上面SendMessage放到MouseDown裏,失敗,放到MouseMove,MouseUp也不行。
瞬間心情低落......迷失在浩瀚的代碼海裏。(按照一般劇情,這個時候我們會遇到新的希望)
有篇文章提到使用這句代碼
SendMessage(hwnd, WM_LBUTTONUP, 0, 0);WM_LBUTTONUP = 0x202 我們試著把下面兩句代碼放在MouseMove裏,結果令人振奮啊,它終於動了.......
SendMessage(pictureBox1.Handle, WM_SYSCOMMAND, SC_MOVE, 0); SendMessage(pictureBox1.Handle, WM_LBUTTONUP, 0, 0);這裡說個題外話,我們把上面兩句調換了執行順序,然後放在MouseDown裏也可以正常執行
趕緊向上級報告。
“嗯~我們不僅僅要找出解決方法,還要找到為什麼要加多一句。.Net在處理鼠標事件的時候肯定做了些處理,你們可能要去反編譯下.Net的源碼,看下其中做了哪些處理,把結果寫個報告給我。”上級再次下達指令。
找到解決方法 - 支線任務【完成】 找到原因 - 主線任務【未完成】【新任務】不經不覺一個上午已經過去了,吃飯先,星期一到星期五加班沒工資。
時間來到第二天早上,昨天下午一直在看反編譯出來的源碼。
我們在System.Windows.Control裏找到一個似乎很關鍵的東西
internal bool CaptureInternal由於這東東屬於內部,非公開的,無法從外部直接改變他的值,我們不得不用反射來改變。
Type t = this.ST.GetType(); PropertyInfo property = t.GetProperty("CaptureInternal",BindingFlags.GetProperty | BindingFlags.Instance | BindingFlags.NonPublic); object obj = property.GetValue(ST, null);// 查看 原始值 property.SetValue(ST, false, null);// 设置为 false obj = property.GetValue(ST, null);// 查看 设置后的值 SendMessage(this.ST.Handle, WM_SYSCOMMAND, SC_MOVE, 0);
現在把上面代碼放到控件的MouseDown,要注意上面也只發送了一次消息。
哈哈....還有誰,成功拖動,我們的目的不僅僅是這個。
來看看CaptureInternal內部都做哪些操作。
internal bool CaptureInternal { [TargetedPatchingOptOut("Performance critical to inline across NGen image boundaries")] get { return (this.IsHandleCreated && (UnsafeNativeMethods.GetCapture() == this.Handle)); } set { if (this.CaptureInternal != value) { if (value) { UnsafeNativeMethods.SetCapture(new HandleRef(this, this.Handle)); } else { SafeNativeMethods.ReleaseCapture(); } } } }嗯.....關鍵在下面這句,趕緊百度下SetCapture
UnsafeNativeMethods.SetCapture(new HandleRef(this, this.Handle));
函数功能:该函数在属于当前线程的指定窗口里设置鼠标捕获。一旦窗口捕获了鼠标,所有鼠标输入都针对该窗口,无论光标是否在窗口的边界内。同一时刻只能有一个窗口捕获鼠标。如果鼠标光标在另一个线程创建的窗口上,只有当鼠标键按下时系统才将鼠标输入指向指定的窗口。
结论: 这是由于设置鼠标捕获后,系统无法再次实现捕获鼠标拖动的控件后果。我們取消掉捕获在当前进程后,就可以只使用一句代碼,就可以实现鼠标拖动。反过来,也就是说,PB中是没有设置鼠标捕获为当前的进程,所以在PB中也可以只使用一句代碼即可实现鼠标拖动。