程序師世界是廣大編程愛好者互助、分享、學習的平台,程序師世界有你更精彩!
首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫知識
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
 程式師世界 >> 編程語言 >> 更多編程語言 >> Delphi >> 制作QQ消息炸彈

制作QQ消息炸彈

編輯:Delphi

    前幾日,看到雜志上有一篇關於開發QQ聊天機器人的文章。談到了對QQ循環發送消息內容,感覺倒也很好玩,於是拿起Delphi開始了我的QQ聊天機器人之路。
  首先要明白自己要做什麼,大家都用過QQ,知道給別人發送消息的整個過程吧!要實現循環發送消息的功能該有以下幾個條件:
  1.必須是在聊天模式裡進行。這樣發送完一條消息後,QQ窗體還存在。
  2.其次是要找到QQ文本窗體的句柄。
  3.向QQ文本窗體中貼上你想說的話。然後自己點擊發送按鈕。
  思路很簡單,接著我們就要開始實施了。
  首先要找到QQ文本窗體的句柄。這時我用到了SPY來查看QQ的窗體。結果如下圖:這樣思路就出來了。要找到QQ文本窗體的句柄就得先找到它的父類即:標志為00620252 Class Name:AfxWnd42 Control ID:00000000。而要找到它就必須找到QQ消息對話框即:006B294“冷問梅 - 發送消息”#32770〔Dialog〕的句柄。
  這時要用到幾個Api函數:
  1.FindWindowEx(
      hWnd1:Long, //在其中查找子的父窗口,如設為0,表示使用桌面窗口(通常說的頂級窗口都認為是桌面的子窗口)
      hWnd2:Long, //從這個窗口後開始查找。如設為0,表示對第一個子窗口開始搜索。
      Lpsz1:String, //欲搜索的類名,0表示忽略。
      Lpsz2:String //欲搜索的類名,0表示忽略。
    );
  2.GetWindow(
      hWnd:Long, //源窗口。
      wCmd:Long //指定結果窗口與源窗口的關系(這裡用GW_CHILD)表示尋找源窗口的第一個子窗口。
        );
  3. GetDlgItem(
       hWnd:Long, //源窗口的句柄。
       Int: nIDDlgItem //要在其中查找的窗口的ID號
     );
  
  其實剛開始找QQ對話窗口時,我先想到的是FindWindow(),這個函數可以直接通過窗口標題名來查找窗體句柄。
  
  我是這樣找的:
  var hparent:HWND;
  hparent:=FindWindow(nil, '發送信息'); //這對2003以前的版本還是很有效的^_^
  結果卻是返回錯誤。Why?
  後來仔細一看,發現每次QQ2003的標題都在變:如上圖是:冷問梅 - 發送消息,要是你又對一個人發信息就會變成:藍色的風 – 發送消息(舉個例子)。
  這也許是QQ2003采取的一種安全措施吧!呵呵!你們也許會看見網上針對QQ2003發送消息炸彈的工具有時要是輸入對方的昵稱的原因。(便於通過昵稱得到窗體句柄)。
  
  不過有沒有更好的方法呢!有!這時就要用到FindWindowEx()了。仔細看一下它的參數,關鍵是第二個hWnd2——我們可以通過它來多次調用FindWindowEx找到符合條件的子窗口。以下是我的代碼:
  var hparent:HWND; //定義為全局變量。來記錄每次調用FindWindowEx()後找到的窗體的句柄。
  procedure TForm1.FormCreate(Sender: TObject);
  begin
    hparent:=0; //初始化,查找桌面所有的頂級窗口開始。
  end;
  procedure TForm1.Timer1Timer(Sender: TObject);
  var hbutton,hbutton1:HWND;
  begin
    repeat
      hparent:=findwindowex(0,hparent,'#32770',nil); //QQ對話框的類為#32770,這樣循環調用FindWindowEx()就能每次時鐘生效時更新hparent的值。從已查找的句柄為hparent的窗體後查找符合要求的窗體。
      hbutton:=findwindowEX(hparent,0,nil,'發送(&S)'); //每次判斷找到的窗口的句柄,看這個窗體中是否存在'發送(&S)'按鈕。存在即找到了正確的QQ對話框。
    until  hbutton<>0; //找到QQ對話框後跳出循環。
    hbutton1:=findwindowex(hparent,0,nil,'聊天模式(&T)') ; //找到QQ對話窗體後,查找聊天模式按鈕句柄。  
    if hbutton1<>0 then //若此時存在聊天模式按鈕即現在QQ窗體處於消息模式狀態。
      sendmessage(hbutton1,BM_CLICK,0,0); //給聊天模式按鈕發送單擊消息。將窗體轉換為聊天模式。
  end;
  
  這樣我們就成功的找到的QQ對話框。和成功設置對話框為聊天模式了。任務總算先完成了一些,呵呵!更郁悶我的還在後頭了。
  
  接著,就要開始查找QQ輸入文本的那個窗體的句柄了。這時我用到的是GetDlgItem()大家知道一個窗體中某一類控件的Control ID在這個窗體類中是不變的(除去一些靜態文體外)過SPY我獲知QQ輸入文本的那個窗體的Control ID為0000037E。於是我寫了下面的語句。
  Var hmemo:HWND;
  hmemo:=GetDlgItem(hparent,$0000037E);
  
  結果發現寫得東東完全沒有自己預想的效果。呵呵!還是拿起SPY,哈!發現竟然不止一個控件的ID為0000037E。並且我們想要得到QQ輸入文本的那個窗體的位置也不是最前一個(要是最前一個,通過上面的語句也是可以找到的^_^)。郁悶了不是。沒辦法還是從它的父類開始吧!可不能在一步求成了。仔細看看上圖。發現了吧!
  
  標志為00620252 Class Name:AfxWnd42 Control ID:00000000的即是QQ輸入文本的那個窗體的父類,並且它是所有Class Name:AfxWnd42中位置最前的那一個。於是我們就可以找到它的句柄。跑不掉了。有了它,QQ輸入文本的那個窗體的句柄也就很容易找到了,哈哈!以下是我的代碼:
  Var hmemo,hmemo1:HWND;
  hmemo=GetDlgItem(hparent,$00000000); //找到父類。
  hmemo1=GetWindow(hmemo1,GW_CHILD); //得到父類下的第一個子窗口句柄(hmemo1即QQ輸入文本的那個窗體的句柄^_^大功告成)
  
  這裡順便說一下GetWindow()用法:
  GetWindow(
    Hwnd:Long, //源窗口句柄。
    wCnd:Long //指定結果窗口與源窗口的關系。(GW_CHILD為得到源窗體下的第一個子窗口句柄)
  )
  
  更多的常數關系你們就去查看MSDN吧!這裡就不必占用寒泉的空間了。哈!
  
  到此,QQ對話框和QQ輸入文本窗口的句柄我們都已經得到了,以下的步驟就是把你要寫的話,貼進QQ輸入文本窗口,點一下發送,就郁悶別人吧!
  
  現在貼出我的一段代碼以供大家參考:
  procedure TForm1.FormCreate(Sender: TObject);
  begin
    i:=0;
    //導入文件內容到combobox控件。
    combobox1.Items.LoadFromFile(extractfilepath(application.ExeName)+'text.txt');
    combobox1.Text:=combobox1.Items.Strings[0];
  end;
  procedure TForm1.Timer1Timer(Sender: TObject);
  var hmemo1:HWND; //hmemo1為找到的QQ文本輸入框句柄
  begin
    if checkbox1.Checked then //點擊了循環發送復選框。
    begin
      if i>combobox1.Items.Count-1 then
        i:=0;
      edit1.Text:=combobox1.Items.Strings[i];
      edit1.SelectAll;
      edit1.CopyToClipboard; //拷貝到剪切板
      sendmessage(hmemo1,WM_PASTE,0,0); //對QQ輸入文本窗體發送粘貼消息。
      sendmessage(hbutton,BM_CLICK,0,0); //點擊發送按鈕
      i:=i+1;   
    end;
    if checkbox1.Checked=false then  //沒有點擊了循環發送復選框。
    begin
      edit1.Text:=combobox1.Text;
      edit1.SelectAll;
      edit1.CopyToClipboard;
      sendmessage(hmemo1,WM_PASTE,0,0);
      sendmessage(hbutton,BM_CLICK,0,0);
    end;
  end;
  
  附上簡要說明:由於本人所知有限,不太會用剪切板函數對將已知字串拷貝到剪切板的方法還不知道。所以只能借道於控件上。因為所有文本類控件都有一個方法即——edit1.CopyToClipboard,所以只能先將Edit1變為不可見控件。每次先將要發送的內容傳給Edit1,而後在將Edit1的內容CopyToClipboard。哈!這只是一個取巧的法子,大家要是知道有什麼更好的方法還望告知在下,呵!
  後記:
  
  以上代碼是針對QQ2003版本。雖然網上有如:飄葉千夫指的好工具。不過作為一個小小菜鳥。但又喜歡編程的人來說。自己DIY(do it youtself)一個也是很爽的一件事吧!我自己也參照飄葉千夫指做了一個,感覺具備了它的使用功能吧!還不錯。其實也沒有太多技術性的東西,只是運用了幾個API函數而已。只希望對剛剛學Delphi的朋友有所幫助,當然高手是用不著的了。

  注明:QQ2004有些改動.為了方便我把新改的代碼帖上來:

  procedure TForm1.Timer1Timer(Sender: TObject);
  var hbutton,hbutton1,hmemo,hmemo1,hparent1:HWND;
  begin
    repeat
       hparent:=findwindowex(0,hparent,'#32770',nil);

  //QQ2004就是多了下面這句,Memo上又多了一層窗口
       hparent1:=findwindowex(hparent,0,'#32770',nil);
    until  hparent1<>0;
    hbutton:=findwindowEX(hparent1,0,nil,'發送(&S)');
    hbutton1:=findwindowex(hparent1,0,nil,'聊天模式(&T)');
    if hbutton1<>0 then
       sendmessage(hbutton1,BM_CLICK,0,0);
       hmemo1:=GetDlgItem(hparent1,$00000000);
       hmemo:=getwindow(hmemo1,GW_CHILD);
    if hmemo<>0 then
    begin
    if  checkbox1.Checked then
    begin
      if i>combobox1.Items.Count-1 then
         i:=0;
         edit1.Text:=combobox1.Items.Strings[i];
         edit1.SelectAll;
         edit1.CopyToClipboard;
         sendmessage(hmemo,WM_SETTEXT,0,0);
         sendmessage(hmemo,WM_PASTE,0,0);
         sendmessage(hbutton,BM_CLICK,0,0);
         i:=i+1;  
    end;
    if checkbox1.Checked=false then
    begin
      edit1.Text:=combobox1.Text;
      edit1.SelectAll;
      edit1.CopyToClipboard;
      sendmessage(hmemo,WM_SETTEXT,0,0);
      sendmessage(hmemo,WM_PASTE,0,0);
      sendmessage(hbutton,BM_CLICK,0,0);
    end;
  end;
  end;
  
  有需要的朋友請到我的網站去下載(位於我的作品裡):
  
  作者網站:http://ASP.itdrp.com/hottey 

  1. 上一頁:
  2. 下一頁:
Copyright © 程式師世界 All Rights Reserved