Windows編程

本文整理自百科、知乎與 科學家的世界html

問題一:爲何開發windows應用程序不用c 而用.net,java,c++?

用 c+windows API  開發windows 應用程序  比用.net,java,c++開發有什麼缺點或優勢?java

  • C/C++,如今的軟件公司對這種人才需求更多。用這種語言寫出來的程序是真正的exe可執行文件。是有系統啓動運行的。 而Java和.NET就不同了。
  • Java是基於解釋的,你寫出的程序不是由系統運行的。是由jdk的一個叫java.exe或者javaw.exe的程序運行。速度確定要比前者慢。
  • 而.NET即便看起來是exe文件,可是也是有.NETframework運行的。
    對於初學者Java和C#會簡單些。
    C/C++是調用mfc就是windows的系統基礎類執行的
    Java是用jdk運行的。
    C#是用.NETframework運行的。

問題二(知乎):如何學習 Windows 編程

一、請看《windows程序設計》(很經典的一本書,分上下兩冊,能夠買,能夠下載電子版)更接近 C 語言方式的使用 windows api 的編程方式,好處是,代碼直觀,最適合理解 windows gui 的運做,程序員和系統之間的分工協做職責劃分。缺點是,開發效率低,不易學習。可是學好了,感受是很是爽,很是自由的。不過在今天使用這種方式寫 windows 程序的人,我幾乎見不到。開發成本巨高昂無比。更多請看:Windows 程序設計 複習筆記(共 81 問)linux

《windows 核心編程》:這是一個名家寫的書。算是《windows 程序設計》的進階篇。裏面提到的是一些更專業的技術。是你在掌握了windows 程序設計後應該讀的書。這我的後來好像有寫了《C# via CLR》。
ios

二、Windows編程如今仍然是一坑。
若是你想Win下面用c++編程,那隻能寫原生程序,首先遇到的問題是GUI界面,這個問題很是複雜。由於20多年來,Windows原生GUI程序編程的複雜度沒有下降過,能夠說至關困難。(緣由天然是光頭鮑爾默在技術上的無知,把精力都放在.net上去了,可是.net幾乎沒人待見)
你有幾個選擇:
c++

  • 直接調用windows api繪製界面。很是繁瑣,我建議你不要把生命浪費在這個上面。
  • MFC,20年以上的歷史,一個微軟VC6.0時代老掉牙的C++ gui界面庫,過期並且很差用。
  • QT是一個第三方庫。是一個不錯的選擇,可是它這個框架有點龐大,運行效率不是很高,總得來講是業餘編程最佳選擇了。
  • WTL微軟程序員業餘寫的庫,仍然很是簡陋的庫,大量東西等着你去實現。

因此你看,Windows原生程序編寫最大的問題是找不到合適的界面庫,你想編寫帶界面的原生WIN程序很是吃力,咱們看到這麼多年來Windows上的程序翻來覆去就是QQ等那些老面孔,這根Win平臺原生GUI編程太困難有很大關係。對比之下Mac、ios/安卓編寫GUI程序都簡單的多。程序員

除非,你用.net框架。.net框架不能編寫原生程序,用c#編寫,跟c++關係不大了。web

因此若是你是一個學生,我不建議你學這個,你能夠學習下蘋果/安卓手機平臺編程、或者web編程、或者c++/COCOS2Dx遊戲編程,都比學windows gui編程有意義的多,win平臺已經到頂了,已經不是將來最大的趨勢了。(這觀點此樓主太)算法

三、學Windows編程,最好是將C#和C++結合起來。shell

如今的Windows上,主流的開發方法是:界面和大部分不影響效率的功能是用C#實現的。很是影響效率的部分功能用c++的實現,並做爲程序的動態連接庫調用。編程

最好不要用C++來編寫界面和普通的功能,事倍功半!

 

什麼是Windows編程

所謂Windows編程就是在Windows平臺上開發,而且運行於Windows平臺上的程序,固然,開發的時候運用的東西是Windows API或者封裝以後的Windows API

爲何要學Windows編程

  有人說,我學的是Java,我不須要跟系統打交道。是的,你說的是對的,可是,這並不意味着學習Windows編程是沒必要要的,事實上,Java的底層使用的也是Windows API,好比,Java的Socket模塊使用的確定是Windows的WS2_32.dll導出的API。所謂的高層語言,其實在具體跨平臺的時候用的是相應的本地系統提供的API,好比建立進程,在Java裏面確定有相應的API,這些API底層的實如今Windows上調用的是CreateProcessA(W),在Linux上調用的是fork之類的函數。學習Windows編程能讓你更瞭解操做系統,也讓你更瞭解程序的運行原理。固然,你能夠學習Linux平臺的編程,不過,二者之間其實差很少,在Windows中有的API在Linux中實際上是有與之對應的,我對於Windows平臺和Linux平臺的編程都學過,只是用得最多的是Windows。

我須要什麼基礎才能學習Windows編程

  事實上,我能夠告訴你,你須要的基礎就是C語言,除了這個以外,你不須要什麼其它的基礎,你並不須要什麼C++的基礎,彙編基礎之類的東西,固然,你最好是能理解一些操做系統的相關東西。

我須要什麼工具

  關於工具,事實上你只須要一個Windows操做系統和一個VisualStudio 2012就能夠(若是你使用的是Visual Studio 2008(2010)也能夠)。做爲一個初學者,什麼版本的Windows操做系統無所謂,只要是WindowsXP及之後的版本均可以,雖然有些API只有在NT 6.0以後纔有,不過,那對於初學者是不須要的。

 

Windows程序員須要學什麼

  常常發現有人在網上提出這樣的問題,現實中也確實有很多人在經歷了3-5年的Windows開發以後就開始迷失方向,天天渾渾噩噩混日子,多是由於這個問題粒度太大,沒人願意花時間回答,但願本文能夠拋磚引玉,給你們節省些時間,同時也但願園子裏面的兄弟們能盡力的補充,從而使這篇文章能夠幫助更多的後來人。

首先說明的是,本文提到的各類技術不分前後,沒有順序,雖然先學什麼,再學什麼對某些人來講可能更方便,可是這些都不是絕對的,由於每一個人的狀況不一樣。

Windows開發首先必須學習的就是操做系統的API,由於其餘的一切都是構建於OS之上,所謂九層之臺,起於壘土,若是你對linux的系統調用很熟悉就會發現其實他們大同小異,都是應用程序在使用系統提供的功能。

接下來是MFC,有了MFC你才真正的能夠乾點開發,由於MFC實在是太全了,幾乎封裝了全部的Windows API, 消息循環,COM實現

到了此地,你能夠開始學習調試技術了,熟悉了調試的各類技巧才能夠作到事半功倍,駕輕就熟。

接下來是組建對象模型COM,做爲windows的基石,不懂COM,很難說本身精通windows編程,由於即便如今的.NET framework也是構建於COM之上,不少問題仍是須要SOS到底層去調試

當你懂得了COM的精髓,你應該開始學習ATL了,這個類庫可使你的COM開發更加駕輕就熟。

說到ATL就不能不提到他的前輩STL,這個出自於標準C++的類庫在windows上一樣也獲得了很好的支持,有了STL在你有一天想轉linux開發也一樣會用得上。

Windows 8中的WinRT如今尚未應用於實際開發,現有的技術中.NET 是很是值得學習的,由於.NET 的主旨是提升程序員的開發效率,在這個浮躁的世界,開發效率有時候可以表明一切。

COM.NET只有一步之遙,.NET 實際上是從COM+演化而來,具體細節請參看 Don Box的《.NET 本質論》瞭解了這些會使你對.NET的認識上升到一個新的層面。

接下來是C# 由於這傢伙是.NET的嫡系部隊,除了IL,這傢伙能夠說和.NET 的關係最爲親近,大部分的新功能都會最早在其中加以體現。當你熟悉了C# BCL,《CLR via C#》能夠說這個時候你已經能夠勝任基本的C#開發了,能夠很快寫出一個小工具,完成一個相關的task

接下來WCFWPF,作分佈式開發少不了WCF,一樣華麗的界面少不了XAMLWPF

大概羅列了一些,其實每一個主題仔細探究下去都頗有韻味,還有須要說的是,其實Windows上面好多的東西都和UNIX很像,好比PowerShell明顯是爲了像UNIX同樣,給開發者提供一個更強大的shell, 若是有興趣,舉一反三一下,也非常有趣。

還有:

LINQ改變了咱們的數據操做方式,統一了數據操做模型,常常操做數據的兄弟,你值得擁有。

F#做爲一種函數式編程語言也很值得研究,因爲本人使用很少,在此不做評價。

另外:

做爲基礎的算法;

做爲提高功力的設計模式,UML

做爲改善系統性能的重構;

做爲大部分分佈式核心的TCP/IP

等等主題也是值得你們研究的。

最後借魯迅的話收尾:其實地上本沒有路,走的人多了也便成了路,但願你們不要把時間都浪費了,原來還有好多東西能夠去鑽研。

不當之處望你們批評、指正、拍磚並提出您的寶貴的意見和補充。

轉自:solidmango


練習 

第一個工程

1)打開Visual Studio,以下地建一個工程

2)選擇一個空的工程

3) 新建一個文件  添加一個cpp文件的。

4)輸入以下代碼

#include <windows.h> 
#pragma comment(linker, "/entry:\"main\" /subsystem:\"windows\"") 
int main()
{ 
MessageBox(NULL, TEXT("Hello,World"),TEXT("NULL"), MB_OK);
 }

5)按下 Ctrl + F5

此時能夠運行程序了,是否是看到了一個小窗口呢?是否是這此代碼比較熟悉呢?

是的,事情就是這樣,你看到的就是Windows上開發所須要的一切。

代碼解釋

第一行:第一行是#include <windows.h>,任何Windows平臺上的應用程序確定須要引用一些Windows的函數或者變量,而這些函數或者變量的聲明就在Windows.h裏面,因此咱們須要包含它,這跟你們包含stdio.h同樣的道理。

第二行:也許你們看到的Windows程序是以WinMain開頭的,然而,大家在這裏面看到的是main?有人懷疑我寫錯了,事實上,我沒有寫錯,所謂的main函數是一個邏輯上的概念,也就是告訴連接器,我這個程序要從哪裏開始執行,C(++)裏面的入口函數是main,Windows上是WinMain,這些並無錯,固然,也容許咱們本身設定入口函數。這裏面的#pragma comment(linker, "/entry:\"main\" /subsystem:\"windows\"")裏面的/entry實際上是設置入口函數,/subsystem實際上是設置子系統(gui的或者console的),gui的程序是沒有黑框框的,console的程序是你們平時看到的一個黑框框,你們的第一次hello,world基本上是交給它的,正如你們的第一次上網基本交給了IE同樣。

第三行:第三行是一個函數調用,你們確定知道的對吧,這個函數調用的是MessageBox,即一個Windows裏面的API,定義於user32.dll裏面。爲了方便你們寫程序,我建議你們安裝一個叫作msdn的東西,

細節說明

  • TEXT是什麼

把鼠標放在TEXT上面,而後按下F12,你會看到以下的說明,其定義等價於以下的:

#ifdef UNICODE #define TEXT(queto) L##queto #else #define TEXT(queto) queto #endif

從中能夠從字面地看出來吧

  • UNICODE是什麼

在C語言中咱們能夠通常寫字符串中都是用「Hello,World」這種寫法,而沒有上面的那種TEXT("Hello,World")的寫法,在Windows裏面,爲了便於操做系統的移植,使用了兩種字符表示,一個是多字節碼,一種是UNICODE表示,若是在一個ascii字符串前面加上L,那麼它就變成了UNICODE串,好比L"ABC"

能夠剛纔以下網址:http://baike.baidu.com/view/40801.htm

  • ##是什麼

在Windows平臺的C語言中有##表示串鏈接,好比「ABC」##"DEF"你就獲得了"ABCDEF"了,這個估計不少人都不知道。這個東西在MFC的實現中用得特別多。

  • MessageBox是一個函數?

其實 ,MessageBox不是一個函數,與之相關的函數有兩個,MessageBoxA與MessageBoxW,根據是否使用UNICODE串從而定義MessageBox是MessageBoxA仍是MessageBoxW,而且,在user32.dll裏面同時實現了這兩個API,固然MessageBoxA的實現中會調用MessageBoxW。

經過 dumpbin -exports user32.dll能夠看到以下的結果


dumpbin -exports能夠看出一個dll裏面導出了什麼函數,這個工具是由visual studio sdk提供的,你們安裝完visual sutdio以後就會自動安裝這個工具,不須要單獨下載。

Windows開發的常識

1)窗口

Windows中最基本的概念也許就是窗口了,每個前臺程序都至少有一個窗口,一個窗口也是你能夠看到的部分,好比,QQ的登陸窗口

基本上你在Windows中可見的都是一個窗口,窗口也是Windows中用於用戶直接交互的基本元素(GUI程序)。

2)句柄

窗口、文件、socket、信號量、管道、郵槽(mailslot)……都是Windows平臺中的基本對象,爲了操做這些對象,咱們須要一個可以引用這些對象的東西,這個引用這些對象的東西就是句柄(Handle)。句柄對於資源就像遙控器對於電視機,用遙控器能更好地操做電視機而不用關心內部實現的細節,句柄也是這樣的,用句柄你能更好地操做Windows對象,而不須要關係其內部的實現細節。事實上,你想操做Windows對象也只能經過句柄操做。好比,你想操做一個線程,你看看SuspendThread的原型以下所示:(第一個參數就是一個線程句柄)
 
Syntax
DWORD WINAPI SuspendThread(
  __in  HANDLE hThread
);

又好比,你想讀一個文件,其函數ReadFile的原型以下:(第一個參數就是一個文件的句柄。)

BOOL WINAPI ReadFile(
  __in         HANDLE hFile,
  __out        LPVOID lpBuffer,
  __in         DWORD nNumberOfBytesToRead,
  __out_opt    LPDWORD lpNumberOfBytesRead,
  __inout_opt  LPOVERLAPPED lpOverlapped
);

3)進程

一些操做系統教材上對進程的定義爲:進程是一個程序的一次運行過程。這個定義實際上是對的,可是,也是錯的,爲何呢?在Windows以前還有許多其它的操做系統,好比OS 360、UNIX……進程的概念提出來的時候Windows 還根本沒出生呢。不過,在Windows中,進程的概念徹底不是這樣的,在Windows裏面,進程是程序隔離的基本單元,每個32位應用程序在本身的進程空間裏面運行,進程只爲這個程序提供4G的虛擬地址空間,而且,不一樣的進程之間互相不干擾(固然,後面會講到,進程之間會通訊)。

4)線程

在Windows裏面,真正運行程序的實際上是線程,線程在進程提供的4G虛擬地址空間裏面運行,它執行PE文件的.text段。也就是說,線程纔是真正的執行體。

基本的正常的Windows程序

代碼

建立一個工程,仍是按照上次的方法,在上一節裏面有,而後輸入如下代碼:
 
#include <windows.h>
LRESULT CALLBACK WndProc (HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam);
int WINAPI WinMain (HINSTANCE hInstance, HINSTANCE hPrevInstance, PSTR szCmdLine, int iCmdShow)
{
    static TCHAR szAppName[] = TEXT ("BossJue");
    HWND         hwnd;
    MSG          msg;
    WNDCLASSEX   wndclassex = {0};
    wndclassex.cbSize        = sizeof(WNDCLASSEX);
    wndclassex.style         = CS_HREDRAW | CS_VREDRAW;
    wndclassex.lpfnWndProc   = WndProc;
    wndclassex.cbClsExtra    = 0;
    wndclassex.cbWndExtra    = 0;
    wndclassex.hInstance     = hInstance;
    wndclassex.hIcon         = LoadIcon (NULL, IDI_APPLICATION);
    wndclassex.hCursor       = LoadCursor (NULL, IDC_ARROW);
    wndclassex.hbrBackground = (HBRUSH) GetStockObject (WHITE_BRUSH);
    wndclassex.lpszMenuName  = NULL;
    wndclassex.lpszClassName = szAppName;
    wndclassex.hIconSm       = wndclassex.hIcon;
    
    if (!RegisterClassEx (&wndclassex))
    {
        MessageBox (NULL, TEXT ("RegisterClassEx failed!"), szAppName, MB_ICONERROR);
        return 0;
    }
    hwnd = CreateWindowEx (WS_EX_OVERLAPPEDWINDOW, 
                          szAppName, 
                          TEXT ("WindowTitle"),
                          WS_OVERLAPPEDWINDOW,
                          CW_USEDEFAULT, 
                          CW_USEDEFAULT, 
                          CW_USEDEFAULT, 
                          CW_USEDEFAULT, 
                          NULL, 
                          NULL, 
                          hInstance,
                          NULL); 
                          
    ShowWindow (hwnd, iCmdShow);
    UpdateWindow (hwnd);
    
    while (GetMessage (&msg, NULL, 0, 0))
    {
        TranslateMessage (&msg);
        DispatchMessage (&msg);
    }
    return msg.wParam;
}
LRESULT CALLBACK WndProc (HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
{
    static const LPTSTR text = TEXT("Hello,World");
    HDC hdc;
    PAINTSTRUCT ps;
    switch (message)
    {
    case WM_CREATE:
        return (0);
        
    case WM_PAINT:
        hdc = BeginPaint (hwnd, &ps);
        TextOut (hdc, 0, 0, text, lstrlen(text));
        EndPaint (hwnd, &ps);
        return (0);
        
    case WM_DESTROY:
        PostQuitMessage (0);
        return (0);
    }
    return DefWindowProc (hwnd, message, wParam, lParam);
}
View Code
 

運行,按下Ctrl + F5,你可能會碰到以下的連接錯誤:

不要急,這個錯誤的設置是由於Windows把這個程序看成console程序,而console程序默認入口函數是main,而咱們在這裏面並無定義main,而是定義了一個叫WinMain的入口函數,因此連接器不認,而咱們但願的倒是編譯器認爲咱們這個程序是一個GUI程序,GUI程序的入口函數是WinMain(若是你用#pragma comment(linker…………)修改的話固然也是能夠的,這種方法我在第一章裏面就寫到了。固然,咱們還能夠直接在Visual Studio IDE裏面直接設置,方法是打開項目屬性,而後以下設置:

樣設置以後,再按Ctrl + F5,有沒有看到以下的一個窗口呢?

,就是這樣,你看到的就是一個正常的Windows程序的編寫。

代碼解釋

編寫Windows程序的過程

編寫一個Windows程序,你須要作的是三步,第一步是註冊一個窗口類,第二步是建立窗口,第三步是編寫消息響應函數。其中第一步和第二步是基本固定的,除了個別的參數須要本身調整以外,最重要的是第三步,
一個Windows程序中,代碼量最大的基本都在第三步。在Windows應用程序裏面,若是咱們想要接收用戶的輸入、在窗口上面顯示一些信息……咱們都須要處理相關的消息,Windows把與這個程序相關的事件都以消息告訴程序,至於怎麼處理這些消息,則是咱們本身的事情。上面的RegisterClassEx (&wndclassex)其實就是
註冊窗口類
CreateWindowEx (WS_EX_OVERLAPPEDWINDOW, szAppName, 

                 TEXT ("WindowTitle"),

                 WS_OVERLAPPEDWINDOW,

                 CW_USEDEFAULT, 

                 CW_USEDEFAULT, 

                 CW_USEDEFAULT, 

                 CW_USEDEFAULT, 

                 NULL, 

                 NULL, 

                 hInstance,

                 NULL); 
View Code
其實就是建立窗口,
LRESULT CALLBACK WndProc (HWND hwnd, UINT message,WPARAM wParam, LPARAM lParam)
其實就是那個消息處理函數,只不過,這個消息處理函數不須要咱們本身調用,當有消息的時候,Windows會本身調用這個函數來處理,咱們只須要編寫處理代碼,可是,編寫的代碼不須要咱們本身手動調用(這也許就是Callback函數的緣由)。

剩下的

剩下的若是還有不懂的本身能夠讀msdn,好比,對CreateWindow不熟悉,能夠直接在MSDN裏面搜索CreateWindow,MSDN不只會告訴你這個函數怎麼用,還會告訴你消息循環是什麼之類的,在此我就不仔細展開說明了。

更多資料參考: Windows編程基礎Windows API簡明教程

相關文章
相關標籤/搜索