API入門系列之四 -一個相當簡單的SDK程序

原創文章,轉載請註明作者及出處。
首發

http://blog.csdn.net/beyondcode

http://www.cnblogs.com/beyond-code/

大家好,還是我beyondcode,再次見面,前面介紹的那麼多'理論知識',你們都懂了嗎? 就算還沒有徹底領悟,但至少還是有那麼一點意識了吧,知道有那麼一回事了吧。這一篇我打算通過一個小小小例子,來回憶一下我們以前介紹的相關知識,如Windows的數據類型,特別是和字符和字符串操作相關的數據類型,還有就是Unicode和ASCII在API函數上的具體體現。

另外,SDK編程交流羣已經建立,很多朋友踊躍參加,系列文章和羣的發展離不開你們。羣號:81543028。

Ok,我們正式開始,我打算從一個簡單的SDK程序開始,別怕,就幾行代碼而已··

/* BY beyondcode */

#include <windows.h>

int WINAPI WinMainHINSTANCE hInstanceHINSTANCE hPrevInstanceLPSTR lpCmdLineint nShowCmd)

{

MessageBoxANULL"Hello beyondcode""Title"MB_OK );

return 0;

}

程序你已經看到了,這恐怕就是一個最簡單的帶窗口的SDK程序了吧,如果你能寫出代碼行數比這個還少,又帶窗口顯示字符串的SDK程序,歡迎交流,呵呵,開個玩笑。

程序倒是簡單,可是我還是要問一問,這個程序,你通過觀察我在字符串的處理,還是在API函數的調用,還是主函數的參數寫法,你能看出什麼問題呢?.....................................對,就是我全部明確指出是單字節版本的,WinMain的第三個參數是LPSTR類型,調用的MessageBox是帶A後綴的單字節版本,字符串常量"Hello beyondcode"和"Title"都沒有使用L前綴。那麼第二個問題來了, 如果我告訴你我現在的工程環境是 使用Unicode字符集 (工程使用的字符集可以在 【項目】->工程屬性 彈出的屬性頁中的 【配置屬性】中的【常規】左邊的【字符集】中設置),那麼我上面的程序能正常通過編譯嗎? 當然能,因爲我已經試過了,不信你也可以試試,可是爲什麼呢? 這是因爲我指定的參數和函數需要的參數都是單字節版本的,也就是說他們相互匹配。要是我這裏將MessageBoxA改成MessageBoxW呢? 就會出錯吧,因爲MessageBoxW的第二個,和第三個參數是需要LPCWSTR,通過上一篇學習,我們知道也就是const wchar_t*, 而我給出的兩個字符串常量卻沒有用L前綴.也就是說他們是單字節的,傳給寬字節版本的MessageBoxW當然就類型不匹配了啊,所以就通不過編譯了吧。

通過上面的學習,我再出一個問題,如果我此時的工程環境是使用Unicode字符集,而這裏我不用MessageBoxA,也不用MessageBoxW,而是用MessageBox,其他的都不變,結果會怎麼樣呢?   不能理解的可以加羣討論喲~~~

好了,單字節版本的程序,我們已經看到了,我們再來看看我們怎麼才能把它改成寬字節版本的呢?

其實需要改的地方不多,也就5處WinMain改成wWinMain, WinMain的第三個參數改成LPWSTR,MessageBoxA改成W,兩個字符串常量加L就ok了。

/* BY beyondcode */

#include <windows.h>

int WINAPI wWinMainHINSTANCE hInstanceHINSTANCE hPrevInstanceLPWSTR lpCmdLineint nShowCmd )

{

MessageBoxWNULLL"Hello Beyondcode"L"Title"MB_OK );

return 0;

}

如果我想寫一個代碼比較通用的版本,也就是可以不用改動代碼,就能編譯出Unicode和ASCII的兩個版本的程序,我應該怎麼寫呢?  其實就是我上一篇重點討論的,凡是涉及到字符串的都不明確指出是Unicode還是ASCII版本的,調用的API函數凡是涉及到字符串參數的都不明確指出調用是A後綴的還是W後綴的函數,而是調用沒有後綴的函數,如上面的MessageBox,這樣就能寫出代碼比較通用的程序了。那麼我們現在來把我們上面的程序改一改,讓它通用

/* BY beyondcode */

#include <windows.h>

#include <tchar.h>

int WINAPI _tWinMainHINSTANCE hInstanceHINSTANCE hPrevInstanceLPTSTR lpCmdLineint nShowCmd )

{

MessageBoxNULL_T("Hello Beyondcode"), _T("Title"), MB_OK );

return 0;

}

WinMain被改成了_tWinMain ,_tWinMain也是一個宏,根據UNICODE這個宏被設置與否而被定義成WinMain或wWinMain,和LPTSTR是一樣的,這裏還需要注意的是要包含tchar.h這個頭文件,因爲_tWinMain和_T()這些宏是被定義在裏面的。經過上面我們就寫出了第一個SDK的可以編譯出兩個版本的比較通用的程序代碼了。是不是有點成就感了呢。。

下面,我們繼續在上面的程序中加一些功能,讓它計算1到10的和,然後把結果顯示給我們看,這個地方,很多SDK初學者就不知所措了,因爲一個和是一個整數,怎麼顯示這個整數給我們呢,通過對話框? MessageBox,可是MessageBox顯示的是字符串。而我們這裏又不是控制檯程序可以使用printf之類的格式化輸出函數來輸出數字,也不能使用cout之類的C++對象來輸出,那我們怎麼辦呢? 通過對話框來顯示結果是不錯的選擇,但是對話框需要的是字符串,那我們就把我們的結果格式化到一個字符串裏面,然後傳送給MessageBox讓它顯示出來。那麼就需要用到格式化字符串函數,下面我們就介紹wsprintf這個函數

#ifdef UNICODE

#define wsprintf  wsprintfW

#else

#define wsprintf  wsprintfA

#endif // !UNICODE

說它是函數,是不確切的。因爲它實際是一個宏,根據環境被定義成不同的函數名wsprintfW或者wsprintfA, 而我們爲了程序的通用性,直接使用wsprintf,傳遞的參數凡是涉及到字符串常量的我們都是用_T()宏,字符串指針的我們都使用LPTSTR和LPCTSTR。

下面我就先貼出添加了功能的程序代碼,然後在做分析,你可以先不看分析,自己看一看代碼,不懂的猜一猜它的意思。

/* BY beyondcode */

#include <windows.h>

#include <tchar.h>

int WINAPI _tWinMainHINSTANCE hInstanceHINSTANCE hPrevInstanceLPTSTR lpCmdLineint nShowCmd )

{

int sum = 0;

forint i = 1; i<=10; i++ )

sum += i;

TCHAR strSum[256] = { 0 };

wsprintfstrSum_T("%d"), sum );

MessageBoxNULLstrSum_T("Title"), MB_OK );

return 0;

}

怎麼樣,也還不算複雜吧,計算1到10的那部分不用我講了吧,最後的結果存放在sum這個變量裏,我們現在的目的就是要讓它顯示在MessageBox彈出的對話框上面。

首先我們定義一個字符數組,我使用的是通用類型TCHAR,然後把它全部初始化爲0。接着調用格式化字符函數wsprintf,它的第一個參數是LPTSTR類型的,指定經過格式化的字符串存放的地方,第二個參數是指定以什麼格式來格式化後面的數據,這裏我們要格式化一個整數,所以指定%d,這個和printf這些函數是一樣的, 後面的參數就是我們要格式化的數據了。

這裏還有一點可能有些新手朋友們不太懂,那就是,wsprintf要求的第一個參數是LPTSTR,而我傳遞的是一個TCHAR的數組名,這裏我就在囉嗦一次咯,我們假設我們的環境是UNICODE的,那麼LPTSTR相當於什麼類型呢? 上一篇就講過的啊,就是wchar_t* 就是寬字符指針,而我們知道數組名就是代表這個數組元素類型的指針,那麼這裏TCHAR數組的元素類型就是TCHAR,在Unicode環境下,TCHAR就是wchar_t也就是說strSum代表的是wchar_t類型的指針,也就是wchar_t*,所以看到了嗎,他們是一樣的類型。

通過上面的wsprintf函數的調用strSum這個字符數組中就包含了計算結果的字符串表示,然後我們通過MessageBox講這個字符數組中的內容顯示出來。在這裏MessageBox的第二個參數類型是LPCTSTR,也就是const wchar_t*, 而我們上面說過我們的strSum代表的是 wchar_t*,這裏同樣可以傳遞給它又是爲什麼呢?這是因爲阿,這裏strSum在傳遞給MessageBox的時候就隱式轉換成了const wchar_t*了。

有關格式化字符串的函數還有如下,詳細用法各位可以查看MSDN,和上面所介紹的都差不多

sprintf 單字節版本的C/C++庫函數

swprintf 寬字節版本的C/C++庫函數

而我們上面的wsprintf和上面兩個函數看起來很相似,大家不要搞混淆了啊,wsprintf最前面的w不是代表Wide,寬字節的意思了,而是Windows的W,代表是windows的API函數了,其實它是一個宏這在上面已經說過了,真正的API函數其實是wsprintfA和wsprintfW這兩個,在不嚴格的情況下通常我們也說wsprintf是函數,只要大家懂就行了~

OK, 這一篇文章就到這裏了,源代碼就這麼點,我也不上傳了,各位有興趣自己敲一下。下一篇,我講會就怎麼自己創建窗口進行介紹,謝謝大家的支持。

請記住我 beyondcode 。  

SDK編程羣已經建立,歡迎有共同興趣愛好的朋友加入。羣號:81543028

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章