???? 我之前是一個只會編寫數值計算的程序的OIer,但我并不甘于這種現狀,于是 我 編寫了我 的第一個使用API函數的C++程序 , 開發平臺是VS2012 :

// ConsoleApplication.cpp : 定義控制臺應用程序的入口點。 // #include <stdio.h> #include " stdafx.h " #include <Windows.h> int _tmain( int argc, _TCHAR* argv[]) { HWND wnd; wnd =FindWindowA(NULL, " 無標題 - 記事本 " ); SendMessage(wnd,WM_CLOSE, 0 , 0 ); system( " pause " ); return 0 ; }
????之前有在看谷夕寫的HACK編程實例精講,第一節有介紹API函數,他的書上用的是hDesk=OpenDesktop(lpszDesktop,0,FALSE,DESKTOP_ENUMERATE);在這之前我連如何調用API函數都不知道,嘗試過#include<stdafx.h>等等亂七八糟的東西,結果都不行.后來百度了一下,才發現原來是要加#include<windows.h>
????明白如何才能可以調用API函數之后,嘗試使用書上介紹的OpenDesktop函數,因為我什么都不知道,于是程序我就這么寫了:

// ConsoleApplication.cpp : 定義控制臺應用程序的入口點。 // #include <stdio.h> #include " stdafx.h " #include <Windows.h> int _tmain( int argc, _TCHAR* argv[]) { int hDesk=OpenDesktop(lpszDesktop, 0 ,FALSE,DESKTOP_ENUMERATE); system( " pause " ); return 0 ; }
?結果是關于lpszDesktop發生了某種我理解不了的錯誤.于是再次百度API函數應用實例,就找到了第一個程序.
一開始仍然編譯不過,編譯器提示錯誤.
我也不知道LPCWSTR是 什么 ,不過看網上關于FindWindow函數的介紹是這么說的: 函數的定義:HWND?WINAPI?FindWindow(LPCSTR?lpClassName?,LPCSTR?lpWindowName); 這上邊居然是LPCSTR,于是我試了試類似的函數,發現FindWindowA函數上是LPCWSTR,于是改成FindWindowA終于編譯過了,實現的功能就是把名為無標題?-?記事本的窗口關閉.
我學習這類東西一向喜歡先弄出來一個能正確運行的樣例,然后再弄明白有問題的地方,這次也不例外.關于這個程序我主要有這幾個方面不太明白:1.句柄是個啥玩意;2.LPCSTR和LPCWSTR又是什么東西;3.FindWindow函數還有啥其他調用方式.
先搞明白句柄是什么東西,當然還要靠百度.
句柄 , 是整個windows編程的基礎 . 一個句柄是指使用的一個唯一的整數值 , 即一個四字節長的數值 , 來標志應用程序中的不同對象和同類對象中的不同的實例 , 諸如 , 一個窗口 , 按鈕 , 圖標 , 滾動條 , 輸出設備 , 控件或者文件等 . 應用程序能夠通過句柄訪問相應的對象的信息 , 但是句柄不是一個 指針, 程序不能利用句柄來直接閱讀文件中的信息 . 如果句柄不用在I/O文件中 , 它是毫無用處的 . 句柄是windows用來標志應用程序中建立的或是使用的唯一整數 , windows使用了大量的句柄來標志很多對象 .
關于句柄我是這樣理解的:它有點類似于算法中的哈希值,對于一個對象系統分配給它一個唯一的值來標記存儲該對象變動情況的位置.
LPCWSTR是一個指向unicode編碼字符串的32位指針 , 所指向字符串是wchar型 , 而不是char型 .
原來LPCWSTR是 unicode 字符串指針,那unicode又是什么東西呢(請原諒我的無知,我真的連 unicode 是啥都不知道)?看過 這篇文章 之后才大概有了個了解.比較特別之處在于定義unicode字符串時要在左邊加一個L,就像這樣:
wchar_t wStr[] = L"中文";
除此之外,我又了解到在VS2005以后,編碼方式默認為unicode,部分函數在使用時默認調用unicode方式(函數名加W),而非ansi方式(函數名加A).之前那個程序由于"無標題 - 記事本"是編碼為ansi的字符串,所以調用默認的unicode方式時出現錯誤,而使用FindWindowA之后采用ansi方式才編譯通過.然后我又把剛才的調用方式改為wnd=FindWindow(NULL,L"無標題 - 記事本");終于編譯通過.wchar_t的輸出:一般說來有兩種方式,一個是wcout,還有是wprintf()之類的函數,悲劇的是無論哪種方法都沒編譯過.后來看一個博客里說要在main函數里加上_tsetlocale(LC_ALL, L"CHS");于是wcout能用了,wprintf仍然不行.先不管它,繼續往后看.
第二個API函數:SendMessage函數.SendMessage函數能向指定句柄所對應的對象發送信息,示例程序:

POINT curpos; while ( 1 ) { GetCursorPos( & curpos); HWND hWnd = WindowFromPoint(curpos); SendMessage(hWnd,WM_CHAR,WPARAM( ' g ' ), 0 ); Sleep( 300 ); }
該程序實現的功能是向鼠標所指向的編輯窗口輸入g.
POINT就是表示坐標的數據類型.GetCursorPos(&curpos)表示取當前鼠標的坐標.WindowFromPoint(curpos)表示獲得curpos處的對象的句柄.
WM_CHAR表示輸出字符.
接著,我想寫一個程序給自己發送標準輸入數據:

while ( 1 ) { GetCursorPos( & curpos); HWND hWnd = WindowFromPoint(curpos); SendMessage(hWnd,WM_CHAR,WPARAM( ' g ' ), 0 ); SendMessage(hWnd,WM_CHAR,WPARAM( ' \r ' ), 0 ); Sleep( 300 ); char ch; cerr << " waiting for reading " << endl; cin >> ch; if (ch== ' g ' ) break ; }
意思就是當通過SendMessage函數向程序窗口發送一個g,如果被成功讀入就跳出循環,一開始我第2個SendMessage里發送的是 ’ \n ’ ,結果沒法觸發讀入,接著改成 ’ \0 ’ ,還是不行,又改成 ’ \r ’ ,這次終于成功了,原來回車鍵輸入的是一個 ’ \r ’ 啊,之前一直以為是 ’ \n ’ 呢...
再往下又看到一個更有趣的:模擬鼠標動作

void RightClick(HWND wnd) { SendMessage(wnd,WM_RBUTTONDOWN, 0 , 0 ); Sleep( 100 ); SendMessage(wnd,WM_RBUTTONUP, 0 , 0 ); }
其中,WM_RBUTTONDOWN表示鼠標右鍵按下,WM_RBUTTONUP表示鼠標右鍵抬起.測試了一下運行沒什么大問題,不過看起開必須等我再單擊一下鼠標左鍵才能讓程序繼續執行.這樣感覺用起來很不舒服,而且也沒有什么應用價值.后來有看到專門有一個函數mouse_event能模擬鼠標的點擊.關于這個函數的詳細信息我看不太懂,就只用了一個最簡單的應用:鼠標左擊.再結合剛才的SendMessage函數,做了一個刷屏軟件,雖然功能很弱,但做完的時候還是感覺很激動.弱弱地貼一下我的代碼:

// 刷屏軟件.cpp : 定義控制臺應用程序的入口點。 // #include<math.h> #include <stdio.h> #include <stdlib.h> #include < string .h> #include " stdafx.h " #include <Windows.h> #include <iostream> #include <cstdio> #include <cstdlib> #include <cmath> #include <locale> #include <cstring> using namespace std; void Home_Page() { printf( " 1.使用說明.\n " ); printf( " 2.開始運行.\n " ); printf( " 3.退出程序.\n " ); } void Left_Click() { mouse_event(MOUSEEVENTF_LEFTDOWN, 0 , 0 , 0 , 0 ); mouse_event(MOUSEEVENTF_LEFTUP, 0 , 0 , 0 , 0 ); } void Software_Description() { printf( " 本軟件使用很簡單,只要按提示一步一步操作即可.\n " ); printf( " 也許有些使用者覺得軟件寫的太腦殘,請原諒,我剛接觸這方面,這個程序純屬練手.\n " ); printf( " 特別提示:由于作者水平問題,請您在所有信息發送完成之前不要移動您的鼠標,否則可能會產生難以預料的結果.\n " ); printf( " 同樣由于作者的水平問題,目前只支持英文文本(Ansi字符集)的發送.\n " ); printf( " 如果發送內容中包含多個單詞,建議用下劃線\'_\'連接\n " ); printf( " 聯系作者:winifred.oier@gmail.com\n " ); system( " pause " ); } void Main_Program() { printf( " 請輸入您希望發送的內容(一行):\n " ); string TexttobeSend; cin >> TexttobeSend; printf( " 請輸入您希望每隔多長時間發送一次(單位:毫秒):\n " ); int DelayTime; cin >> DelayTime; printf( " 您希望將該信息發送多少遍:\n " ); int SendTime; cin >> SendTime; printf( " 請在5秒內將鼠標放在發送信息的編輯框里\n " ); HWND InputBox; POINT curpos; Sleep( 5000 ); GetCursorPos( & curpos); InputBox = WindowFromPoint(curpos); cerr << " The Input Box has been engaged " << endl; printf( " 請在5秒內將鼠標放在發送按鈕上.再次提示:由于作者水平太爛,執行完之前千萬別亂動鼠標.\n " ); Sleep( 5000 ); for ( int i= 1 ;i<=SendTime;i++ ) { for ( int j= 0 ;j<TexttobeSend.length();j++ ) SendMessage(InputBox,WM_CHAR,WPARAM(TexttobeSend[j]), 0 ); Left_Click(); Sleep(DelayTime); } } int _tmain( int argc, _TCHAR* argv[]) { int Command_Code; while ( true ) { Home_Page(); cin >> Command_Code; switch (Command_Code) { case 1 : Software_Description(); break ; case 2 : Main_Program(); break ; case 3 : return 0 ; } system( " cls " ); } return 0 ; }
不過在寫代碼的時候發現一個問題,不同的頭文件包含順序可能會影響能否編譯,還有就是編譯出來的可執行文件只能在我的電腦上執行,我用同學的電腦測試發現缺少一個MS...的動態鏈接庫,不明白為什么.
更多文章、技術交流、商務合作、聯系博主
微信掃碼或搜索:z360901061

微信掃一掃加我為好友
QQ號聯系: 360901061
您的支持是博主寫作最大的動力,如果您喜歡我的文章,感覺我的文章對您有幫助,請用微信掃描下面二維碼支持博主2元、5元、10元、20元等您想捐的金額吧,狠狠點擊下面給點支持吧,站長非常感激您!手機微信長按不能支付解決辦法:請將微信支付二維碼保存到相冊,切換到微信,然后點擊微信右上角掃一掃功能,選擇支付二維碼完成支付。
【本文對您有幫助就好】元
