欧美大屁股bbbbxxxx,狼人大香伊蕉国产www亚洲,男ji大巴进入女人的视频小说,男人把ji大巴放进女人免费视频,免费情侣作爱视频

歡迎來到入門教程網(wǎng)!

C#教程

當(dāng)前位置:主頁 > 軟件編程 > C#教程 >

C#向無窗口的進程發(fā)送消息

來源:本站原創(chuàng)|時間:2020-01-10|欄目:C#教程|點擊: 次

注:本文適用.net2.0+的winform程序
一個winform程序,我希望它不能多開,那么在用戶啟動第二個實例的時候,作為第二個實例來說,大概可以有這么幾種做法:

1.彈個窗告知用戶【程序已運行】之類,用戶點擊彈窗后,退出自身

2.什么都不做,默默退出自身

3.讓已運行的第一個實例把它的窗體顯示出來,完了退出自身

顯然第3種做法更地道,實現(xiàn)該效果的核心問題其實是:如何顯示指定進程的窗口?

首先想到的是調(diào)用ShowWindow、SetForegroundWindow等API,配合使用可以將被遮擋、最小化的窗口前排顯示出來,這也是很多涉及到這種案例的網(wǎng)文介紹的方法,此法的局限在于,目標進程的主窗口必須存在,準確說是要有有效的主窗口句柄,表現(xiàn)在訪問Process.MainWindowHandle能得到一個非IntPtr.Zero的值,即有效的句柄;或者用spy類工具能看到該進程下有至少一個窗口;或者按alt+tab能將它的窗口切換出來。

那如果進程沒窗口怎么辦?先說一下什么情況下進程會沒窗口,很簡單,讓Form.Visible=false(或者Form.Hide(),等價的)就行,此時窗體就消失了,既不可見,也沒有對應(yīng)的任務(wù)欄按鈕,alt+tab也切不出來。當(dāng)程序中的所有Form都Hide后,訪問該進程的MainWindowHandle會得到IntPtr.Zero,這就是無窗口進程。那什么樣的程序會這么干,太多了好吧,各種音樂 器,殺軟什么的,都允許【關(guān)閉/最小化到系統(tǒng)托盤】,在你點叉或者最小化后,窗體就會隱藏,只留一個圖標在托盤區(qū)。由于這種進程的MainWindowHandle拿不到有效句柄,所以上面那些API是用不了的,只能另想辦法。

回到問題【如何顯示指定進程的窗口】,如果你的程序不允許關(guān)閉到托盤區(qū),始終存在窗口的話(最小化也是存在),那你愉快的用ShowWindow、SetForegroundWindow等API就好,不用繼續(xù)。但如果你的程序要像 器殺軟那樣允許用戶隱藏窗口的話,那還得繼續(xù)折騰,此時問題變成【如何讓無窗口的進程顯示窗口】,我的思路是這樣:既然目標進程沒窗口,我沒辦法純粹用外部手段操作到它的窗體,但因為程序是我自己寫的,可不可以來個里應(yīng)外合,辦了這事。比如向它發(fā)一條特定消息,它在收到該消息后,心領(lǐng)神會,把自己的窗口顯示出來~到時候榮華富貴享之sorry入戲了。這個思路主要涉及兩個問題,怎么發(fā)和怎么收,至于收到后如何前排顯示窗口之類,小case。

怎么發(fā)

SendMessage/PostMessage自然是指不上的,因為這倆貨也是基于窗口的,其實我一度懷疑走消息這條路是否可行,這涉及到一個原理問題,就是如果消息一定是只能發(fā)送給窗口的話,那注定此路不通,只能考慮別的進程間通信方案。好在了解到PostThreadMessage這個API,解決了我的問題。該API是向指定線程發(fā)送消息(MSDN文檔在此),這也說明在原理上,消息并非只可以發(fā)給窗口,還可以發(fā)給線程,至于還能不能發(fā)給別的什么東西就不知道了。先看一下發(fā)送語句:

void Main()
{
...
//向目標進程的主線程發(fā)送消息
PostThreadMessage(Process.GetProcessById(pid).Threads[0].Id, 0x80F0, IntPtr.Zero, IntPtr.Zero);
...
}
[return: MarshalAs(UnmanagedType.Bool)]
[DllImport("user32.dll", SetLastError = true)]
public static extern bool PostThreadMessage(int threadId, uint msg, IntPtr wParam, IntPtr lParam); 

API的第1個參數(shù)是目標線程的ID。注意兩點:①此ID是系統(tǒng)全局的線程ID,并非Thread.ManagedThreadId這種“假”ID;②目標線程必須存在消息循環(huán)。winform的主線程往往就是UI線程,天然存在消息循環(huán),所以無需考慮這個問題。第2個參數(shù)是要發(fā)送的消息ID。我們的目的是發(fā)一條收發(fā)雙方約定的消息,所以這個消息要夠特別,不能跟系統(tǒng)消息撞衫,所以范圍最好介于0x8001~0xBFFF之間,這是系統(tǒng)留給應(yīng)用程序自用的消息段(WM_APP)。后面?zhèn)z參數(shù)我沒用,你想讓消息更特別一點,或想攜帶其它信息的話也可以用上。方法返回true/false分別代表發(fā)送成功/失敗。

另外,目標進程也許有多個線程,其中哪個才是能收消息的主線程我沒有科學(xué)的判斷方法,大膽臆測就是Process.Threads集合中的第1項,這個猜測至今工作良好,不管它。若您有科學(xué)判斷法,請告知~謝謝。

怎么收

由于消息是走線程過來的,所以別想著在主窗口的WndProc中去收,再說消息過來的時候,主窗口存不存在都是個問題。要用應(yīng)用程序級別的消息篩選器來收,篩選器是個實現(xiàn)System.Windows.Forms.IMessageFilter接口的類(MSDN),該接口只需實現(xiàn)一個方法:bool PreFilterMessage(ref Message m),方法邏輯是,如果收到的消息m是你要處理并吃掉的,就返回true,其余消息則返回false放行。整個篩選器像這樣:

class MsgFilter : IMessageFilter
{
public bool PreFilterMessage(ref Message m)
{
if (m.Msg == 0x80F0)
{
DoSomething(); //顯示窗口或其它事
return true;
}
return false;
}
}

事實上我收到消息后并不是直接做顯示窗口相關(guān)的事,而是引發(fā)一個事件,主窗體注冊該事件,在事件處理方法中再寫顯示窗口相關(guān)的代碼。這是設(shè)計上的考量,與本文主旨無關(guān),不多說。

篩選器寫好后,還得把它添加到一個地方它才能工作,什么時候添加就什么時候才開始發(fā)揮作用,所以最好盡早添加,例如在main的開頭。像這樣:

void Main()
{
Application.AddMessageFilter(new MsgFilter());
...
}

至此,收發(fā)的問題解決。這實質(zhì)上是一個進程間通信問題,所以其實任何進程通信手段都可以應(yīng)用在本文的案例,走消息只是其中一種手段。

以上所述是小編給大家介紹的C#向無窗口的進程發(fā)送消息的相關(guān)知識,希望對大家有所幫助,如果大家有任何疑問請給我留言,小編會及時回復(fù)大家的。在此也非常感謝大家對我們網(wǎng)站的支持!

網(wǎng)頁制作CMS教程網(wǎng)絡(luò)編程軟件編程腳本語言數(shù)據(jù)庫服務(wù)器

如果侵犯了您的權(quán)利,請與我們聯(lián)系,我們將在24小時內(nèi)進行處理、任何非本站因素導(dǎo)致的法律后果,本站均不負任何責(zé)任。

聯(lián)系QQ:835971066 | 郵箱:835971066#qq.com(#換成@)

Copyright © 2002-2020 腳本教程網(wǎng) 版權(quán)所有