青青草原综合久久大伊人导航_色综合久久天天综合_日日噜噜夜夜狠狠久久丁香五月_热久久这里只有精品

xi52qian  
xi52qian
日歷
<2025年11月>
2627282930311
2345678
9101112131415
16171819202122
23242526272829
30123456
統(tǒng)計
  • 隨筆 - 4
  • 文章 - 0
  • 評論 - 1
  • 引用 - 0

導航

常用鏈接

留言簿

隨筆檔案

搜索

  •  

最新評論

閱讀排行榜

評論排行榜

 

2011年3月7日

進程由兩部分組成:

  • 操作系統(tǒng)管理進程的內(nèi)核對象。存放該進程 的統(tǒng)計信息的地方。
  • 地址空間,包含可執(zhí)行模塊和DLL模塊的代碼和數(shù)據(jù)。動態(tài)分配的內(nèi)存(線程堆棧和堆)。

進程是不活潑的,進程當中至少要有一個線程,每個線程要有自己的堆棧和自己的CPU寄存器。CPU通過算法給每個線程分配時間片的辦法來造成假象是在同時工作(多核通過自己的算法實現(xiàn)同時運行)。

4.1 編寫第一個Windiws應用程序

Windows兩種類型的程序:

  • CUI程序,比如CMD.EXE等等。Microsoft Visual C++連接開關(guān)為/SUBSYSTEM:CONDOLE(程序啟動時不能創(chuàng)建GUI程序)。
  • GUI程序,圖形用戶程序,比如Notepad,Word等等。Microsoft Visual C++連接開關(guān)為/SUBSYSTEM:WINDOWS(程序啟動時不能創(chuàng)建CUI程序)。

注意:倆者的概念其實是很模糊的,CUI可以創(chuàng)建GUI圖形界面,反之GUI程序可能用CUI程序。

Windows進入點函數(shù)(區(qū)分在于CUI和GUI程序,ANSI碼和UNICODE碼)

int WINAPI WinMain(
HINSTANCE hinstExe,
HINSTANCE,
PSTR pszCmdLine,
int nCmdShow);

int WINAPI wWinMain(
HINSTANCE hinstExe,
HINSTANCE,
PWSTR pszCmdLine,
int nCmdShow);

int __cdecl main(
int argc,
char *argv[],
char *envp[]);

int __cdecl wmain(
int argc,
wchar_t *argv[],
wchar_t *envp[]);

其實Windows程序啟動時最開始并不調(diào)用自己寫的入口函數(shù),而是調(diào)用系統(tǒng)的幾個入口函數(shù),以便可以調(diào)用malloc和free之類的函數(shù),初始化全局和靜態(tài)C++對象等。

  • 檢索指向新進程的完整命令行的指針。
  • 檢索指向新進程的環(huán)境變量的指針。
  • 對C/C++運行期的全局變量進行初始化。如果包含StdLib.h文件,代碼就可以訪問這些變量。
  • 對C運行期的malloc和callo和其他底層輸入/輸出例程使用的內(nèi)存棧進行初始化。
  • 為所有全局和靜態(tài)C++類對象調(diào)用構(gòu)造函數(shù)。

  應用程序類型                            進入點                                                     嵌入可執(zhí)行文件的啟動函數(shù)


ANSI碼GUI應用程序                   WinMain                                               WinMainCRTStattup

UNICODE碼GUI應用程序           wWinMain                                            wWinMainCRTStattup

ANSI碼CUI應用程序                   main                                                       mainCRTStattup

UNICODE碼CUI應用程序           wmain                                                    wmainCRTStattup


注意:應用程序會根據(jù)SUBSYSTEM開關(guān)來查找嵌入可執(zhí)行啟動函數(shù),如果進入點函數(shù)和啟動函數(shù)不匹配則顯示鏈接錯誤。可以刪除SUBSYSTEM(VS Project Settings)開關(guān),這樣應用程序會自動需找匹配的函數(shù)。

進入點函數(shù)返回時調(diào)用系統(tǒng)的exit函數(shù),將返回值傳遞給它。exit函數(shù)負責下面操作:

  • 調(diào)用由_onexit函數(shù)的調(diào)用而注冊的任何函數(shù)。
  • 為所有全局的和靜態(tài)的C++類對象調(diào)用析構(gòu)函數(shù)
  • 調(diào)用操作系統(tǒng)的ExitProcess,并將返回值傳遞給他,關(guān)閉進程。

4.1.1 進程的實例句柄

WinMain/wWinMain函數(shù)的第一個參數(shù)表示進程加載的可執(zhí)行文件的基地址/句柄。對于加載資源的調(diào)用都要使用此句柄,比如HICON LoadIcon(HINSTANCE, PCTSTR)。有的函數(shù)需要使用HMODULE,和HINSTANCE是一個意思(區(qū)分主要在于16位的操作系統(tǒng)中)。

HMODULE GetModuleHandle(PCTSTR pszModele);

函數(shù)作用,返回加載調(diào)用進程中的可執(zhí)行文件或者DLL的基地址/句柄,參數(shù)是可執(zhí)行文件或者DLL的名稱。給pszModule賦值NULL,則返回的是進程中可執(zhí)行文件的句柄。

注意:如果找不到則返回NULL。如果在DLL中傳遞NULL,返回的仍然是進程加載的可執(zhí)行文件的句柄。

4.1.2 進程的前一個實例句柄

第二個參數(shù)都傳遞NULL,是為16位系統(tǒng)所保留的。

4.1.3 進程的命令行

注意:不要試圖修改命令行內(nèi)部內(nèi)存的值,要使用修改先拷貝出來。

PTSTR GetCommandLine(); // 返回命令行字符串
 
PTSTR CommandLineToArgv(PTSTR pszCmdLine, int *pNumArgs); // 拆分命令行字符串函數(shù)

Demo:

int nNumargs;
PTSTR *ppArgv = CommandLineToArgv(GetCommandLine(), &nNumargs);
if ('x' == *ppArgv[1]) {
// TODO:
}

// 手動釋放內(nèi)存,一般不需要釋放,系統(tǒng)會進程關(guān)閉時候自動釋放
HeapFree(GetProcessHeap, 0, ppArgv);


4.1.4 進程的環(huán)境變量

環(huán)境塊是進程地址空間中分配的內(nèi)存塊每個環(huán)境塊都包含一組字符串,格式如下:

VarName1=VarVarlue1\0

VarName2=VarVarlue2\0

VarName3=VarVarlue3\0

…..

VarNameX=VarVarlueX\0

\0

注意:

  • 排序必須按照字母順序。
  • ‘=’號不能是變量名的一部分。
  • 等號左右兩邊的空格將被算做名稱或者值。
  • 最后必須加個’\0’表示結(jié)束。
  • 子進程和父進程不共用環(huán)境塊,修改不會影響父/子進程。
DWORD GetEnvironmentVariable(PCTSTR pszName, PTSTR pszValue, DWORD cchValue);


pszName指變量名,pszValue指向變量值的緩存區(qū),cchValue緩存區(qū)的大小。找不到變量名或者設置的長度不夠存放就返回0。

 

ExpandEnvironmentStrings(PCSTR pszSrc, PSTR pszDst, DWORD nSize);

用來用現(xiàn)實出可替換的環(huán)境變量的字符串。

BOOL SetEnvironmentVariable(PCTSTR pszName, PCTSTR pszValue);

設置環(huán)境變量的值,如果不存在則創(chuàng)建,如果存在則替換他的值。

4.1.5 進程的親緣性

子進程繼承父進程的親緣性。(具體什么意思沒明白)

4.1.6 進程的錯誤模式

進程可以設置如何處理一些錯誤。

UINT SetErrorMode(UINT fuErrorMode);


各個模式用OR連接


      標志                                                                                                               說明

SEM_FAILCRITICALERRORS                                                                    系統(tǒng)不顯示關(guān)鍵錯誤句柄消息框,并將錯誤返回給調(diào)用進程

SEM_NOGOFAULTERRORBOX                                                               系統(tǒng)不顯示一般保護故障消息框。本標志只應該由采用異常情況處理程序來處理一般保護(GP)故障的調(diào)式應用程式來設定

SEM_NOOPENFILEERRORBOX                                                               當系統(tǒng)找不到文件時,它不顯示消息框。

SEM_NOALIGNMENTFAULTEXCEPT                                                    系統(tǒng)自動排除內(nèi)存沒有對其的故障,并使應用程序看不到這些故障。本標志對X86處理器不起作用。


子進程繼承父進程的錯誤模式,如果不想讓子進程繼承父進程的錯誤模式的話,可以再調(diào)用CreateProcess時設定CREATE_DEFAULT_ERROR_MODE標志。

4.1.7 進程的當前驅(qū)動器和目錄

默認情況下不提供全路徑的話,系統(tǒng)就會在當前驅(qū)動器和目錄中查找文件,比如CreateFile,因為驅(qū)動器和目錄是每個進程來維護的,所以某個線程改變了目錄和驅(qū)動器會改變整個進程的目錄和驅(qū)動器。

下面兩個函數(shù)讀取和設置:

DWORD GetCurrentDirectory(DWORD cchCurDir, PTSTR pszCurDir);

BOOL SetCurrentDirectory(PCTSTR pszCurDir);

4.1.8 進程的當前目錄

驅(qū)動器環(huán)境塊的格式:

=C:=C:\Utility\Bin

程序查找驅(qū)動器環(huán)境塊,如果沒有則按驅(qū)動器名查找。

子進程不能繼承父進程的驅(qū)動器塊,如果想繼承必須寫到環(huán)境變量中去。(好像是這樣,如果有不對請高人指點)。

DWORD GetFullPathName(PCTSTR pszFile, DWORD cchPath, PTSTR pszPath, PTSTR *ppszFilePart);

獲取驅(qū)動器的當前目錄,比如:

TCHAR szCurDir[MAX_PATH];
DWORD GetFullPathName(TEXT("C:"), MAX_PATH, szCurDir, NULL);


4.1.9 系統(tǒng)版本

DWORD GetVersion();此函數(shù)存在高地位的混論BUG,所以盡量不要使用。

BOOL GetVersion(POSVERSIONINFOEX pVersionInfomation);
typedef struct _OSVERSIONINFOEXA {
    DWORD dwOSVersionInfoSize;    // 在調(diào)用GetVersionEx函數(shù)之前,必必須置為sizeof(OSVERSIONINFOEX)
    DWORD dwMajorVersion;         // 主系統(tǒng)的主要版本號
     DWORD dwMinorVersion;         // 主系統(tǒng)的次要版本號
     DWORD dwBuildNumber;          // 當前系統(tǒng)的構(gòu)建號
     DWORD dwPlatformId;           // 識別當前系統(tǒng)的平臺。可以使VER_PLATFORM_WIN32(WIN32),VER_PLATFORM_WIN32_WINDOWS(WINDOWS 95/WINDOWS 98),VER_PLATFORM_WIN32_NT(WINDOWS NT/WINDOWS 2000)或VER_PLATFORM_WIN32_CEHH(WINDOWS CE)
    CHAR   szCSDVersion[ 128 ];     // Maintenance string for PSS usage 本域包含了附加文本,用于提供關(guān)于已經(jīng)安裝的操作系統(tǒng)的詳細信息
     WORD   wServicePackMajor;       // 最新安裝的服務程序包的主要版本號
     WORD   wServicePackMinor;       // 最新安裝的服務程序包的次要版本號
     WORD   wSuiteMask;              // 用于標識系統(tǒng)上存在那個程序組(VER_SUITE_SMALLBUSINESS,VER_SUITE_ENTERPRISE,VER_SUITE_BACKOFFICE,VER_SUITE_COMMUNICATIONS,VER_SUITE_TERMINAL,VER_SUITE_SMALLBUSINESS_RESTRICTED,VER_SUITE_EMBEDDEDNT和VER_SUITE_DATACENTER)
     BYTE  wProductType;             // 用于標識安裝了下面的哪個操作系統(tǒng):VER_NT_WORKSTATION,VER_NT_SERVER或VER_NT_DOMAIN_CONTROLLER
    BYTE  wReserved;                // 留作將來使用
} OSVERSIONINFOEXA, *POSVERSIONINFOEXA, *LPOSVERSIONINFOEXA;

這個是擴展版本。
 
4.2 CreateProcess函數(shù)
終于看到正題了~大笑
BOOL CreateProcess(
    LPCSTR lpApplicationName,
    LPSTR lpCommandLine,
    LPSECURITY_ATTRIBUTES lpProcessAttributes,
    LPSECURITY_ATTRIBUTES lpThreadAttributes,
    BOOL bInheritHandles,
    DWORD dwCreationFlags,
    LPVOID lpEnvironment,
    LPCSTR lpCurrentDirectory,
    LPSTARTUPINFOA lpStartupInfo,
    LPPROCESS_INFORMATION lpProcessInformation
    );

  1. 進程啟動時,首先創(chuàng)建一個進程內(nèi)核對象,該內(nèi)核對象不是進程,是一個管理進程存儲進程信息的小型數(shù)據(jù)結(jié)構(gòu)。(計數(shù)為1)
  2. 創(chuàng)建一個虛擬地址空間,加載可執(zhí)行文件和DLL。
  3. 為進程創(chuàng)建個主線程的內(nèi)核對象,和進程內(nèi)核對象一樣,是用來管理和存儲線程信息的小型數(shù)據(jù)結(jié)構(gòu)。(計數(shù)為1)
  4. 調(diào)用C/C++運行期啟動代碼,主線程開始運行,最終調(diào)用啟動函數(shù),成功返回TRUE(未能正確加載DLL也返回TRUE,所以父進程無法查看)。

4.2.1 pszApplicationName和pszCommandLine

pszCommandLine參數(shù):用來創(chuàng)建進程的命令行參數(shù)。查看第一個標記,如果沒有”.exe”會自動添加”.exe”上去。(如果pszApplicationName參數(shù)NULL)

  1. 包含調(diào)用進程的”.exe”文件的目錄。
  2. 調(diào)用進程的當前目錄。
  3. windows系統(tǒng)目錄
  4. windows目錄
  5. PATH環(huán)境變量中列出的目錄。

如果pszApplicationName參數(shù)不為NULL,系統(tǒng)將在當前目錄中查找.exe文件(不會自動添加“.exe”),如果找不到將失敗,此時pszCommandLine作為參數(shù)傳遞給可執(zhí)行程序的進程。

4.2.2 psaProcess,psaThread和binHeritHandles

psaProcess,psaThread是進程和進程主線程內(nèi)核對象的安全屬性。默認值為NULL。

binHeritHandles設置為TRUE表示父進程在創(chuàng)建子進程可以繼承安全屬性標志里設置為TRUE的任何可繼承的內(nèi)核對象。如果設置為FALSE子進程將不繼承任何內(nèi)核對象。

4.2.3 fdwCreate

用于標識標志,定義規(guī)則如何創(chuàng)建新進程。我一般寫默認值NULL。具體的太多了,請查看MSDN吧,不想寫了。

4.2.4 pvEnvironment

設置子進程使用的環(huán)境內(nèi)存塊,一般默認值為NULL,表示子進程繼承父進程的環(huán)境塊。

PVOID GetEnvironmentString(); // 獲取當前內(nèi)存塊的地址
BOOL FreeEnvironmentStrings(PTSTR pszEnvironmentBlock); // 不用的時候調(diào)用此函數(shù)釋放內(nèi)存塊


4.2.5 pszCurDir

設定工作目錄和驅(qū)動器號,如果為NULL則和應用程序的目錄相同,如果設置比如以’\0’結(jié)尾的包含驅(qū)動器名的路徑。

4.2.6 psiStartInfo

typedef struct _STARTUPINFO {
    DWORD   cb;             //(兩者兼有,控制臺和窗口程序) 
    LPSTR   lpReserved;     // (兩者兼有)保留,必須初始化為NULL
    LPSTR   lpDesktop;      // (兩者兼有)用于標識啟動應用程序所在的桌面的名字。如果該桌面存在,新進程便與指定的桌面相關(guān)聯(lián)。如果桌面不存在,便創(chuàng)建一個帶有默認屬性的桌面,并使用為新進程指定的名字。如果lpDesktop是NULL(這是最常見的情況),那么該進程將與當前桌面相關(guān)聯(lián)。
    LPSTR   lpTitle;        // (控制臺)用于設定控制臺窗口名稱。如果lpTitle是NULL,則可執(zhí)行文件的名字將用作窗口名
    DWORD   dwX;            // x,y坐標,只有當子進程用CW_USEDEFAULT作為CreateWindows的x參數(shù)來創(chuàng)建它的第一個重疊窗口時,才使用這兩個坐標。若是創(chuàng)建控制臺窗口的應用程序,這些成員用于指明控制臺窗口的左上角。
    DWORD   dwY;          
    DWORD   dwXSize;        //(兩者兼有)設定窗口寬度和長度,只有子進程用WM_USEDEFAULT作為CreateWIndows的nWidth參數(shù)來創(chuàng)建它的第一個重疊窗口時才是用這個值。控制臺就是控制臺的寬和長
    DWORD   dwYSize;
    DWORD   dwXCountChars;  //(控制臺)用于設定子應用程序控制臺的長度和寬度(字符表示)
    DWORD   dwYCountChars;
    DWORD   dwFillAttribute;// (控制臺)用于設定子應用程序的控制臺背影顏色和文本。
    DWORD   dwFlags;        // (兩者兼有)參見下一段
    WORD    wShowWindow;    // (窗口)用于設定子應用程序初次調(diào)用ShowWindow將SW_SHOWDEFAULT作為nCmdShow參數(shù)傳遞時,該應用程序的第一個重疊窗口應該如何出現(xiàn)。本成員可以是通常用于ShowWindow函數(shù)的任何一個SW_*標識符
    WORD    cbReserved2;    // 保留,必須初始化為0
    LPBYTE  lpReserved2;    // 保留,必須初始化為NULL
    HANDLE  hStdInput;      // (控制臺)用于設定控制臺輸入和輸出用的緩存的句柄。默認設置hStdInput是鍵盤緩存,hStdOutput和hStdError窗口的緩存。
    HANDLE  hStdOutput;     // 
    HANDLE  hStdError;
} STARTUPINFO, *LPSTARTUPINFO;


設置某些值,大部分需要默認值,必須初始化為0都。

STARTUPINFO si = {sizeof(si)};

dwFlags標志,用于修改如何來創(chuàng)建子進程。


標志
STARTF_USESIZE                                                                              使用dwXSize和dwYSize成員

STARTF_USESHOWWINDOW                                                         使用wShowWIndow成員

STARTF_USEPOSITION                                                                    使用dwX和dwY成員

STARTF_USECOUNTCHARS                                                            使用dwXCountChars和dwYCountChars成員

STARTF_USEFILLATTRIBUTE                                                           使用dwFillAttribute成員

STARTF_USESTDHANDLES                                                             使用hStdInput,hStdOutput和hStdError成員

STARTF_RUN_FULLSCREEN                                                            強制再x86計算機上運行的控制臺應用程序以全屏幕方式啟動運行

STARTF_FORCEONFEEDBACK                                                        光標設置為沙漏,過了2秒如果進程沒啟動GUI,CreateProcess程序?qū)⒐鈽嗽O置為箭頭,5秒內(nèi)顯示一個窗口,成功調(diào)用GetMessage則反復箭頭,如果沒有成功,等待5秒 變?yōu)榧^

STARTF_FORCEOFFFEEDBACK                                                                                      


4.2.7 ppiProcInfo

typedef struct _PROCESS_INFORMATION {
    HANDLE hProcess;
    HANDLE hThread;
    DWORD dwProcessId;
    DWORD dwThreadId;
} PROCESS_INFORMATION, *PPROCESS_INFORMATION, *LPPROCESS_INFORMATION;

返回的分別是,子進程進程句柄,子進程中主線程的線程句柄,子進程ID,子進程中主線程的ID。

注意:

  1. hProcess和hThread被賦值后,內(nèi)核對象的計數(shù)器分別被+1。
  2. 系統(tǒng)為每個進程和線程分配的ID值都是不同的,但是當某進程退出后,新進程很可能會使用退出進程的ID。

 

4.3 終止進程的運行

4.3.1 主線程的進入點函數(shù)返回

最好強力推薦使用這種方式。

  1. 調(diào)用C++析構(gòu)函數(shù)。
  2. 釋放堆棧內(nèi)存。
  3. 將進程退出代碼(進程內(nèi)核對象中維護)設置為進入點函數(shù)返回值。
  4. 系統(tǒng)將進程內(nèi)核對象的返回值減去1。

4.3.2 ExitProcess函數(shù)

避免使用這個方法。

VOID ExitProcess(UINT fuExitCode);

終止進程運行,并將退出碼設置為fuExitCode。

注意:

  1. 調(diào)用ExitProcess后,所有的代碼都將不會執(zhí)行,關(guān)閉進程。
  2. 調(diào)用ExitProcess后,不會釋放C++析構(gòu)函數(shù)資源,有系統(tǒng)清理進程時候直接釋放內(nèi)存。
  3. 進程的主線程直接return退出后,啟動函數(shù)中也會調(diào)用ExitProcess函數(shù),進程終止,其他線程也會關(guān)閉。
  4. 進程的主線程調(diào)用_endThreadex或者EndThread函數(shù)關(guān)閉主線程后,進程沒有被關(guān)閉,子線程繼續(xù)運行。

 

4.3.3 TerminiateProcess函數(shù)

能不用就別用。

BOOL TerminiateProcess(HANDLE hProcess, UINT fuExitCode;)

關(guān)閉指定為hProcess句柄的進程,推出代碼為fuExitCode。

注意:

  1. 關(guān)閉進程將丟失所有需要保存到硬盤的數(shù)據(jù),因為進程關(guān)閉時候最后會自己釋放內(nèi)存資源,關(guān)閉內(nèi)核對象的句柄值,所以不會造成內(nèi)存泄露。
  2. 此函數(shù)是個異步函數(shù),它返回的時候無法知道,需要關(guān)閉的進程是否已經(jīng)被強制關(guān)閉了。

4.3.4 進程終止運行時出現(xiàn)的情況

  1. 進程中剩余的所有線程全部終止運行。
  2. 釋放該進程引用的GDI和用戶對象,內(nèi)核對象被關(guān)閉(別的進程有引用則計數(shù)器減1,如果沒有引用則關(guān)閉內(nèi)核對象)。
  3. 推出代碼將從STILL_ACTIVE(后面章節(jié)線程將介紹該結(jié)構(gòu))改為傳遞給ExitProcess和TerminiateProcess代碼。
  4. 內(nèi)核對象狀態(tài)變?yōu)槭盏酵ㄖ獱顟B(tài)(線程中介紹),其他線程掛起,知道進程終止。
  5. 進程內(nèi)核對象計數(shù)減去1,或者關(guān)閉。

注意:

進程內(nèi)核對象的壽命可能遠遠大于進程本身,父進程保留子進程內(nèi)核對象可以查看它的推出代碼調(diào)用下面函數(shù):

BOOL GetExitCodeProcess(HANDLE hProcess, PDWORD pdwExitCode);


可以調(diào)用這個函數(shù)來判斷子進程是否關(guān)閉,如果子進程沒有關(guān)閉,它的STILL_ACTIVE標識符定義為0x103。但是這么作效率不是很高。

 

4.4 子進程

沒什么好說的,前面的都說了,用CloseHandle關(guān)閉子進程和子進程中主線程的句柄值來切斷父進程和子進程的所有聯(lián)系。

 

4.5 每局系統(tǒng)中運行的進程

利用ToolHelp函數(shù)族來開發(fā)管理操作系統(tǒng)上的進程。打算自己也寫個試試。

 

本文章的內(nèi)容是本人學習Windows核心編程第四章后的總結(jié),有錯誤請大家糾正,轉(zhuǎn)載注明出處:

http://www.cnblogs.com/xi52qian/

posted @ 2011-03-07 09:40 xi52qian 閱讀(400) | 評論 (0)編輯 收藏

2011年3月4日

進程由兩部分組成:

  • 操作系統(tǒng)管理進程的內(nèi)核對象。存放該進程 的統(tǒng)計信息的地方。
  • 地址空間,包含可執(zhí)行模塊和DLL模塊的代碼和數(shù)據(jù)。動態(tài)分配的內(nèi)存(線程堆棧和堆)。

進程是不活潑的,進程當中至少要有一個線程,每個線程要有自己的堆棧和自己的CPU寄存器。CPU通過算法給每個線程分配時間片的辦法來造成假象是在同時工作(多核通過自己的算法實現(xiàn)同時運行)。

4.1 編寫第一個Windiws應用程序

Windows兩種類型的程序:

  • CUI程序,比如CMD.EXE等等。Microsoft Visual C++連接開關(guān)為/SUBSYSTEM:CONDOLE(程序啟動時不能創(chuàng)建GUI程序)。
  • GUI程序,圖形用戶程序,比如Notepad,Word等等。Microsoft Visual C++連接開關(guān)為/SUBSYSTEM:WINDOWS(程序啟動時不能創(chuàng)建CUI程序)。

注意:倆者的概念其實是很模糊的,CUI可以創(chuàng)建GUI圖形界面,反之GUI程序可能用CUI程序。

Windows進入點函數(shù)(區(qū)分在于CUI和GUI程序,ANSI碼和UNICODE碼)

int WINAPI WinMain(
HINSTANCE hinstExe,
HINSTANCE,
PSTR pszCmdLine,
int nCmdShow);

int WINAPI wWinMain(
HINSTANCE hinstExe,
HINSTANCE,
PWSTR pszCmdLine,
int nCmdShow);

int __cdecl main(
int argc,
char *argv[],
char *envp[]);

int __cdecl wmain(
int argc,
wchar_t *argv[],
wchar_t *envp[]);

其實Windows程序啟動時最開始并不調(diào)用自己寫的入口函數(shù),而是調(diào)用系統(tǒng)的幾個入口函數(shù),以便可以調(diào)用malloc和free之類的函數(shù),初始化全局和靜態(tài)C++對象等。

  • 檢索指向新進程的完整命令行的指針。
  • 檢索指向新進程的環(huán)境變量的指針。
  • 對C/C++運行期的全局變量進行初始化。如果包含StdLib.h文件,代碼就可以訪問這些變量。
  • 對C運行期的malloc和callo和其他底層輸入/輸出例程使用的內(nèi)存棧進行初始化。
  • 為所有全局和靜態(tài)C++類對象調(diào)用構(gòu)造函數(shù)。

  應用程序類型                            進入點                                                     嵌入可執(zhí)行文件的啟動函數(shù)


ANSI碼GUI應用程序                   WinMain                                               WinMainCRTStattup

UNICODE碼GUI應用程序           wWinMain                                            wWinMainCRTStattup

ANSI碼CUI應用程序                   main                                                       mainCRTStattup

UNICODE碼CUI應用程序           wmain                                                    wmainCRTStattup


注意:應用程序會根據(jù)SUBSYSTEM開關(guān)來查找嵌入可執(zhí)行啟動函數(shù),如果進入點函數(shù)和啟動函數(shù)不匹配則顯示鏈接錯誤。可以刪除SUBSYSTEM(VS Project Settings)開關(guān),這樣應用程序會自動需找匹配的函數(shù)。

進入點函數(shù)返回時調(diào)用系統(tǒng)的exit函數(shù),將返回值傳遞給它。exit函數(shù)負責下面操作:

  • 調(diào)用由_onexit函數(shù)的調(diào)用而注冊的任何函數(shù)。
  • 為所有全局的和靜態(tài)的C++類對象調(diào)用析構(gòu)函數(shù)
  • 調(diào)用操作系統(tǒng)的ExitProcess,并將返回值傳遞給他,關(guān)閉進程。

4.1.1 進程的實例句柄

WinMain/wWinMain函數(shù)的第一個參數(shù)表示進程加載的可執(zhí)行文件的基地址/句柄。對于加載資源的調(diào)用都要使用此句柄,比如HICON LoadIcon(HINSTANCE, PCTSTR)。有的函數(shù)需要使用HMODULE,和HINSTANCE是一個意思(區(qū)分主要在于16位的操作系統(tǒng)中)。

HMODULE GetModuleHandle(PCTSTR pszModele);

函數(shù)作用,返回加載調(diào)用進程中的可執(zhí)行文件或者DLL的基地址/句柄,參數(shù)是可執(zhí)行文件或者DLL的名稱。給pszModule賦值NULL,則返回的是進程中可執(zhí)行文件的句柄。

注意:如果找不到則返回NULL。如果在DLL中傳遞NULL,返回的仍然是進程加載的可執(zhí)行文件的句柄。

4.1.2 進程的前一個實例句柄

第二個參數(shù)都傳遞NULL,是為16位系統(tǒng)所保留的。

4.1.3 進程的命令行

注意:不要試圖修改命令行內(nèi)部內(nèi)存的值,要使用修改先拷貝出來。

PTSTR GetCommandLine(); // 返回命令行字符串
 
PTSTR CommandLineToArgv(PTSTR pszCmdLine, int *pNumArgs); // 拆分命令行字符串函數(shù)

Demo:

int nNumargs;
PTSTR *ppArgv = CommandLineToArgv(GetCommandLine(), &nNumargs);
if ('x' == *ppArgv[1]) {
// TODO:
}

// 手動釋放內(nèi)存,一般不需要釋放,系統(tǒng)會進程關(guān)閉時候自動釋放
HeapFree(GetProcessHeap, 0, ppArgv);


4.1.4 進程的環(huán)境變量

環(huán)境塊是進程地址空間中分配的內(nèi)存塊每個環(huán)境塊都包含一組字符串,格式如下:

VarName1=VarVarlue1\0

VarName2=VarVarlue2\0

VarName3=VarVarlue3\0

…..

VarNameX=VarVarlueX\0

\0

注意:

  • 排序必須按照字母順序。
  • ‘=’號不能是變量名的一部分。
  • 等號左右兩邊的空格將被算做名稱或者值。
  • 最后必須加個’\0’表示結(jié)束。
  • 子進程和父進程不共用環(huán)境塊,修改不會影響父/子進程。
DWORD GetEnvironmentVariable(PCTSTR pszName, PTSTR pszValue, DWORD cchValue);


pszName指變量名,pszValue指向變量值的緩存區(qū),cchValue緩存區(qū)的大小。找不到變量名或者設置的長度不夠存放就返回0。

 

ExpandEnvironmentStrings(PCSTR pszSrc, PSTR pszDst, DWORD nSize);

用來用現(xiàn)實出可替換的環(huán)境變量的字符串。

BOOL SetEnvironmentVariable(PCTSTR pszName, PCTSTR pszValue);

設置環(huán)境變量的值,如果不存在則創(chuàng)建,如果存在則替換他的值。

4.1.5 進程的親緣性

子進程繼承父進程的親緣性。(具體什么意思沒明白)

4.1.6 進程的錯誤模式

進程可以設置如何處理一些錯誤。

UINT SetErrorMode(UINT fuErrorMode);


各個模式用OR連接


      標志                                                                                                               說明

SEM_FAILCRITICALERRORS                                                                    系統(tǒng)不顯示關(guān)鍵錯誤句柄消息框,并將錯誤返回給調(diào)用進程

SEM_NOGOFAULTERRORBOX                                                               系統(tǒng)不顯示一般保護故障消息框。本標志只應該由采用異常情況處理程序來處理一般保護(GP)故障的調(diào)式應用程式來設定

SEM_NOOPENFILEERRORBOX                                                               當系統(tǒng)找不到文件時,它不顯示消息框。

SEM_NOALIGNMENTFAULTEXCEPT                                                    系統(tǒng)自動排除內(nèi)存沒有對其的故障,并使應用程序看不到這些故障。本標志對X86處理器不起作用。


子進程繼承父進程的錯誤模式,如果不想讓子進程繼承父進程的錯誤模式的話,可以再調(diào)用CreateProcess時設定CREATE_DEFAULT_ERROR_MODE標志。

4.1.7 進程的當前驅(qū)動器和目錄

默認情況下不提供全路徑的話,系統(tǒng)就會在當前驅(qū)動器和目錄中查找文件,比如CreateFile,因為驅(qū)動器和目錄是每個進程來維護的,所以某個線程改變了目錄和驅(qū)動器會改變整個進程的目錄和驅(qū)動器。

下面兩個函數(shù)讀取和設置:

DWORD GetCurrentDirectory(DWORD cchCurDir, PTSTR pszCurDir);

BOOL SetCurrentDirectory(PCTSTR pszCurDir);

4.1.8 進程的當前目錄

驅(qū)動器環(huán)境塊的格式:

=C:=C:\Utility\Bin

程序查找驅(qū)動器環(huán)境塊,如果沒有則按驅(qū)動器名查找。

子進程不能繼承父進程的驅(qū)動器塊,如果想繼承必須寫到環(huán)境變量中去。(好像是這樣,如果有不對請高人指點)。

DWORD GetFullPathName(PCTSTR pszFile, DWORD cchPath, PTSTR pszPath, PTSTR *ppszFilePart);

獲取驅(qū)動器的當前目錄,比如:

TCHAR szCurDir[MAX_PATH];
DWORD GetFullPathName(TEXT("C:"), MAX_PATH, szCurDir, NULL);


4.1.9 系統(tǒng)版本

DWORD GetVersion();此函數(shù)存在高地位的混論BUG,所以盡量不要使用。

BOOL GetVersion(POSVERSIONINFOEX pVersionInfomation);
typedef struct _OSVERSIONINFOEXA {
    DWORD dwOSVersionInfoSize;    // 在調(diào)用GetVersionEx函數(shù)之前,必必須置為sizeof(OSVERSIONINFOEX)
    DWORD dwMajorVersion;         // 主系統(tǒng)的主要版本號
     DWORD dwMinorVersion;         // 主系統(tǒng)的次要版本號
     DWORD dwBuildNumber;          // 當前系統(tǒng)的構(gòu)建號
     DWORD dwPlatformId;           // 識別當前系統(tǒng)的平臺。可以使VER_PLATFORM_WIN32(WIN32),VER_PLATFORM_WIN32_WINDOWS(WINDOWS 95/WINDOWS 98),VER_PLATFORM_WIN32_NT(WINDOWS NT/WINDOWS 2000)或VER_PLATFORM_WIN32_CEHH(WINDOWS CE)
    CHAR   szCSDVersion[ 128 ];     // Maintenance string for PSS usage 本域包含了附加文本,用于提供關(guān)于已經(jīng)安裝的操作系統(tǒng)的詳細信息
     WORD   wServicePackMajor;       // 最新安裝的服務程序包的主要版本號
     WORD   wServicePackMinor;       // 最新安裝的服務程序包的次要版本號
     WORD   wSuiteMask;              // 用于標識系統(tǒng)上存在那個程序組(VER_SUITE_SMALLBUSINESS,VER_SUITE_ENTERPRISE,VER_SUITE_BACKOFFICE,VER_SUITE_COMMUNICATIONS,VER_SUITE_TERMINAL,VER_SUITE_SMALLBUSINESS_RESTRICTED,VER_SUITE_EMBEDDEDNT和VER_SUITE_DATACENTER)
     BYTE  wProductType;             // 用于標識安裝了下面的哪個操作系統(tǒng):VER_NT_WORKSTATION,VER_NT_SERVER或VER_NT_DOMAIN_CONTROLLER
    BYTE  wReserved;                // 留作將來使用
} OSVERSIONINFOEXA, *POSVERSIONINFOEXA, *LPOSVERSIONINFOEXA;

這個是擴展版本。
 
4.2 CreateProcess函數(shù)
終于看到正題了~大笑
BOOL CreateProcess(
    LPCSTR lpApplicationName,
    LPSTR lpCommandLine,
    LPSECURITY_ATTRIBUTES lpProcessAttributes,
    LPSECURITY_ATTRIBUTES lpThreadAttributes,
    BOOL bInheritHandles,
    DWORD dwCreationFlags,
    LPVOID lpEnvironment,
    LPCSTR lpCurrentDirectory,
    LPSTARTUPINFOA lpStartupInfo,
    LPPROCESS_INFORMATION lpProcessInformation
    );

  1. 進程啟動時,首先創(chuàng)建一個進程內(nèi)核對象,該內(nèi)核對象不是進程,是一個管理進程存儲進程信息的小型數(shù)據(jù)結(jié)構(gòu)。(計數(shù)為1)
  2. 創(chuàng)建一個虛擬地址空間,加載可執(zhí)行文件和DLL。
  3. 為進程創(chuàng)建個主線程的內(nèi)核對象,和進程內(nèi)核對象一樣,是用來管理和存儲線程信息的小型數(shù)據(jù)結(jié)構(gòu)。(計數(shù)為1)
  4. 調(diào)用C/C++運行期啟動代碼,主線程開始運行,最終調(diào)用啟動函數(shù),成功返回TRUE(未能正確加載DLL也返回TRUE,所以父進程無法查看)。

4.2.1 pszApplicationName和pszCommandLine

pszCommandLine參數(shù):用來創(chuàng)建進程的命令行參數(shù)。查看第一個標記,如果沒有”.exe”會自動添加”.exe”上去。(如果pszApplicationName參數(shù)NULL)

  1. 包含調(diào)用進程的”.exe”文件的目錄。
  2. 調(diào)用進程的當前目錄。
  3. windows系統(tǒng)目錄
  4. windows目錄
  5. PATH環(huán)境變量中列出的目錄。

如果pszApplicationName參數(shù)不為NULL,系統(tǒng)將在當前目錄中查找.exe文件(不會自動添加“.exe”),如果找不到將失敗,此時pszCommandLine作為參數(shù)傳遞給可執(zhí)行程序的進程。

4.2.2 psaProcess,psaThread和binHeritHandles

psaProcess,psaThread是進程和進程主線程內(nèi)核對象的安全屬性。默認值為NULL。

binHeritHandles設置為TRUE表示父進程在創(chuàng)建子進程可以繼承安全屬性標志里設置為TRUE的任何可繼承的內(nèi)核對象。如果設置為FALSE子進程將不繼承任何內(nèi)核對象。

4.2.3 fdwCreate

用于標識標志,定義規(guī)則如何創(chuàng)建新進程。我一般寫默認值NULL。具體的太多了,請查看MSDN吧,不想寫了。

4.2.4 pvEnvironment

設置子進程使用的環(huán)境內(nèi)存塊,一般默認值為NULL,表示子進程繼承父進程的環(huán)境塊。

PVOID GetEnvironmentString(); // 獲取當前內(nèi)存塊的地址
BOOL FreeEnvironmentStrings(PTSTR pszEnvironmentBlock); // 不用的時候調(diào)用此函數(shù)釋放內(nèi)存塊


4.2.5 pszCurDir

設定工作目錄和驅(qū)動器號,如果為NULL則和應用程序的目錄相同,如果設置比如以’\0’結(jié)尾的包含驅(qū)動器名的路徑。

4.2.6 psiStartInfo

typedef struct _STARTUPINFO {
    DWORD   cb;             //(兩者兼有,控制臺和窗口程序) 
    LPSTR   lpReserved;     // (兩者兼有)保留,必須初始化為NULL
    LPSTR   lpDesktop;      // (兩者兼有)用于標識啟動應用程序所在的桌面的名字。如果該桌面存在,新進程便與指定的桌面相關(guān)聯(lián)。如果桌面不存在,便創(chuàng)建一個帶有默認屬性的桌面,并使用為新進程指定的名字。如果lpDesktop是NULL(這是最常見的情況),那么該進程將與當前桌面相關(guān)聯(lián)。
    LPSTR   lpTitle;        // (控制臺)用于設定控制臺窗口名稱。如果lpTitle是NULL,則可執(zhí)行文件的名字將用作窗口名
    DWORD   dwX;            // x,y坐標,只有當子進程用CW_USEDEFAULT作為CreateWindows的x參數(shù)來創(chuàng)建它的第一個重疊窗口時,才使用這兩個坐標。若是創(chuàng)建控制臺窗口的應用程序,這些成員用于指明控制臺窗口的左上角。
    DWORD   dwY;          
    DWORD   dwXSize;        //(兩者兼有)設定窗口寬度和長度,只有子進程用WM_USEDEFAULT作為CreateWIndows的nWidth參數(shù)來創(chuàng)建它的第一個重疊窗口時才是用這個值。控制臺就是控制臺的寬和長
    DWORD   dwYSize;
    DWORD   dwXCountChars;  //(控制臺)用于設定子應用程序控制臺的長度和寬度(字符表示)
    DWORD   dwYCountChars;
    DWORD   dwFillAttribute;// (控制臺)用于設定子應用程序的控制臺背影顏色和文本。
    DWORD   dwFlags;        // (兩者兼有)參見下一段
    WORD    wShowWindow;    // (窗口)用于設定子應用程序初次調(diào)用ShowWindow將SW_SHOWDEFAULT作為nCmdShow參數(shù)傳遞時,該應用程序的第一個重疊窗口應該如何出現(xiàn)。本成員可以是通常用于ShowWindow函數(shù)的任何一個SW_*標識符
    WORD    cbReserved2;    // 保留,必須初始化為0
    LPBYTE  lpReserved2;    // 保留,必須初始化為NULL
    HANDLE  hStdInput;      // (控制臺)用于設定控制臺輸入和輸出用的緩存的句柄。默認設置hStdInput是鍵盤緩存,hStdOutput和hStdError窗口的緩存。
    HANDLE  hStdOutput;     // 
    HANDLE  hStdError;
} STARTUPINFO, *LPSTARTUPINFO;


設置某些值,大部分需要默認值,必須初始化為0都。

STARTUPINFO si = {sizeof(si)};

dwFlags標志,用于修改如何來創(chuàng)建子進程。


標志


STARTF_USESIZE                                                                              使用dwXSize和dwYSize成員

STARTF_USESHOWWINDOW                                                         使用wShowWIndow成員

STARTF_USEPOSITION                                                                    使用dwX和dwY成員

STARTF_USECOUNTCHARS                                                            使用dwXCountChars和dwYCountChars成員

STARTF_USEFILLATTRIBUTE                                                           使用dwFillAttribute成員

STARTF_USESTDHANDLES                                                             使用hStdInput,hStdOutput和hStdError成員

STARTF_RUN_FULLSCREEN                                                            強制再x86計算機上運行的控制臺應用程序以全屏幕方式啟動運行

STARTF_FORCEONFEEDBACK                                                        光標設置為沙漏,過了2秒如果進程沒啟動GUI,CreateProcess程序?qū)⒐鈽嗽O置為箭頭,5秒內(nèi)顯示一個窗口,成功調(diào)用GetMessage則反復箭頭,如果沒有成功,等待5秒 變?yōu)榧^

STARTF_FORCEOFFFEEDBACK                                                                                      


4.2.7 ppiProcInfo

typedef struct _PROCESS_INFORMATION {
    HANDLE hProcess;
    HANDLE hThread;
    DWORD dwProcessId;
    DWORD dwThreadId;
} PROCESS_INFORMATION, *PPROCESS_INFORMATION, *LPPROCESS_INFORMATION;

返回的分別是,子進程進程句柄,子進程中主線程的線程句柄,子進程ID,子進程中主線程的ID。

注意:

  1. hProcess和hThread被賦值后,內(nèi)核對象的計數(shù)器分別被+1。
  2. 系統(tǒng)為每個進程和線程分配的ID值都是不同的,但是當某進程退出后,新進程很可能會使用退出進程的ID。

 

4.3 終止進程的運行

4.3.1 主線程的進入點函數(shù)返回

最好強力推薦使用這種方式。

  1. 調(diào)用C++析構(gòu)函數(shù)。
  2. 釋放堆棧內(nèi)存。
  3. 將進程退出代碼(進程內(nèi)核對象中維護)設置為進入點函數(shù)返回值。
  4. 系統(tǒng)將進程內(nèi)核對象的返回值減去1。

4.3.2 ExitProcess函數(shù)

避免使用這個方法。

VOID ExitProcess(UINT fuExitCode);

終止進程運行,并將退出碼設置為fuExitCode。

注意:

  1. 調(diào)用ExitProcess后,所有的代碼都將不會執(zhí)行,關(guān)閉進程。
  2. 調(diào)用ExitProcess后,不會釋放C++析構(gòu)函數(shù)資源,有系統(tǒng)清理進程時候直接釋放內(nèi)存。
  3. 進程的主線程直接return退出后,啟動函數(shù)中也會調(diào)用ExitProcess函數(shù),進程終止,其他線程也會關(guān)閉。
  4. 進程的主線程調(diào)用_endThreadex或者EndThread函數(shù)關(guān)閉主線程后,進程沒有被關(guān)閉,子線程繼續(xù)運行。

 

4.3.3 TerminiateProcess函數(shù)

能不用就別用。

BOOL TerminiateProcess(HANDLE hProcess, UINT fuExitCode;)

關(guān)閉指定為hProcess句柄的進程,推出代碼為fuExitCode。

注意:

  1. 關(guān)閉進程將丟失所有需要保存到硬盤的數(shù)據(jù),因為進程關(guān)閉時候最后會自己釋放內(nèi)存資源,關(guān)閉內(nèi)核對象的句柄值,所以不會造成內(nèi)存泄露。
  2. 此函數(shù)是個異步函數(shù),它返回的時候無法知道,需要關(guān)閉的進程是否已經(jīng)被強制關(guān)閉了。

4.3.4 進程終止運行時出現(xiàn)的情況

  1. 進程中剩余的所有線程全部終止運行。
  2. 釋放該進程引用的GDI和用戶對象,內(nèi)核對象被關(guān)閉(別的進程有引用則計數(shù)器減1,如果沒有引用則關(guān)閉內(nèi)核對象)。
  3. 推出代碼將從STILL_ACTIVE(后面章節(jié)線程將介紹該結(jié)構(gòu))改為傳遞給ExitProcess和TerminiateProcess代碼。
  4. 內(nèi)核對象狀態(tài)變?yōu)槭盏酵ㄖ獱顟B(tài)(線程中介紹),其他線程掛起,知道進程終止。
  5. 進程內(nèi)核對象計數(shù)減去1,或者關(guān)閉。

注意:

進程內(nèi)核對象的壽命可能遠遠大于進程本身,父進程保留子進程內(nèi)核對象可以查看它的推出代碼調(diào)用下面函數(shù):

BOOL GetExitCodeProcess(HANDLE hProcess, PDWORD pdwExitCode);


可以調(diào)用這個函數(shù)來判斷子進程是否關(guān)閉,如果子進程沒有關(guān)閉,它的STILL_ACTIVE標識符定義為0x103。但是這么作效率不是很高。

 

4.4 子進程

沒什么好說的,前面的都說了,用CloseHandle關(guān)閉子進程和子進程中主線程的句柄值來切斷父進程和子進程的所有聯(lián)系。

 

4.5 每局系統(tǒng)中運行的進程

利用ToolHelp函數(shù)族來開發(fā)管理操作系統(tǒng)上的進程。打算自己也寫個試試。

 

本文章的內(nèi)容是本人學習Windows核心編程第四章后的總結(jié),有錯誤請大家糾正,轉(zhuǎn)載注明出處:

http://www.cnblogs.com/xi52qian/

posted @ 2011-03-04 16:45 xi52qian 閱讀(284) | 評論 (0)編輯 收藏

2011年3月3日

頭文件 <iostream>
一. 對終端的操作
相關(guān)頭文件#include <iostream>
1. 輸入istream
2. 輸出ostream
3. iostream繼承istream和ostream 所以它具有輸入輸出功能。
為了方便這個庫定義了下列三個標準流對象:
1. cin  代表標準輸入istream類對象一般地cin使我們能夠從用戶終端讀入數(shù)據(jù)。
2. cout 代表標準輸出ostream類對象一般地cout使我們能夠向用戶終端寫數(shù)據(jù)。
3. cerr 代表標準錯誤ostream類對象一般地cerr是導出程序錯誤消息的地方。
另外,輸出主要由重載的左移操作符<< 來完成類似地輸入主要由重載的右移操作符>>來完成。
Demo1:

#include <iostream>
#include <string>
int main() {
    string in_string;
    // 向用戶終端寫字符串
    std::cout << "Please enter your name: ";
    // 把用戶輸入的讀取到 in_string 中
    std::cin >> in_string;
    if ( in_string.empty() )
    // 產(chǎn)生一個錯誤消息輸出到用戶終端
    std::cerr << "error: input string is empty!\n";
    else std::cout << "hello, " << in_string << "!\n";
}

二. 對文件的操作
相關(guān)頭#include <fstream>
1. ifstream 從istream 派生把一個文件綁到程序上從文件讀取數(shù)據(jù)用來輸入。
2. ofstream 從ostream 派生把一個文件綁到程序上用來向文件寫入數(shù)據(jù)。
3. fstream 從iostream 派生把一個文件綁到程序上用來輸入和輸出。
注:由于在fstream 頭文件中也包含了iostream 頭文件所以我們不需要同時包含這兩個文
件C++對于文件的輸入輸出也支持同樣的輸入和輸出操作符。
Demo2:

#include <fstream>
#include <string>
#include <vector>
#include <algorithm>
int main()
{
    string ifile;
    cout << "Please enter file to sort: ";
    cin >> ifile;
    // 構(gòu)造一個 ifstream 輸入文件對象
    ifstream infile( ifile.c_str() );
    if( ! infile ) {
        cerr << "error: unable to open input file: " << ifile << endl;
        return -1;
    }
    string ofile = ifile + ".sort";
    // 構(gòu)造一個 ofstream 輸出文件對象
    ofstream outfile( ofile.c_str() );
    if( !outfile ) {
      cerr << "error: unable to open output file: " << ofile << endl;
      return -2;
    }
    string buffer;
    vector<string> text;
    int cnt = 1;
    while ( infile >> buffer ) {
        text.push_back( buffer );
        cout << buffer << ( cnt++ % 8 ? " " : "\n" );
    }
    sort( text.begin(), text.end() );
    // ok: 把排序后的詞打印到 outfile
    vector<string>::iterator iter = text.begin();
    for ( cnt = 1; iter != text.end(); ++iter, ++cnt )
        outfile << *iter << (cnt%8 ? " " : "\n" );
    return 0;
}

三. 對字符流操作
相關(guān)的頭文件#include <sstream>
1 istringstream 從istream 派生從一個字符串中讀取數(shù)據(jù)。
2 ostringstream 從ostream 派生寫入到一個字符串中。
3 stringstream 從iostream 派生從字符串中讀取或者寫入到字符串中。
Demo3:

#include <sstream>
string program_name( "our_program" );
string version( "0.01" );
// ...
string mumble( int *array, int size )
{
    if ( ! array ) {
        ostringstream out_message;
        out_message << "error: "
        << program_name << "--" << version
        << ": " << __FILE__ << ": " << __LINE__
        <<" -- ptr is set to 0; "
        << " must address some array.\n";
        // 返回底層 string 對象
        return out_message.str();
}

四. wchar_t型
支持wchar_t類型的流讀寫操作
wcin wcout wcerr wiostream 等等....

20.1 輸出操作符<<
1. 支持所有的內(nèi)置數(shù)據(jù)類型 包括string ,const char* 和complex。以及函數(shù)的調(diào)用。
2. endl等價于輸出換行操作符,然后再刷新緩存區(qū)。cout << '\n' << flush;
3. <<可以連接使用,因為operator<<的返回值是ostream&。
4. cout << p << &i << endl;會輸出指針的地址(p是int *,i是int)。如果是const char * pcStr不會輸出指針地址值,
輸出的是字符串。轉(zhuǎn)換為cout << static_cast<void *>(const_cast<char *>(pcStr));
5. <<運算符的優(yōu)先級高于?:所以和?:使用時注意加括號。
6. ostream_iterator和cout的使用。
Demo4:

#include <iostream>
#include <algorithm>
#include <vector>
#include <string>
string pooh_pals[] = {
"Tigger", "Piglet", "Eeyore", "Rabbit"
};
int main()
{
    vector<string> ppals( pooh_pals, pooh_pals+4 );
    vector<string>::iterator iter = ppals.begin();
    vector<string>::iterator iter_end = ppals.end();
    cout << "These are Pooh's pals: ";
    // 把每個元素拷貝到 cout ...
    ostream_iterator< string > output( cout, " " );
    copy( iter, iter_end, output );
    cout << endl;
}

7. cout << 遇到‘\0’會定制輸出。

20.2 輸入操作符>>
1. while(cin >> 變量)的時候有兩種情況會讓循環(huán)停止(false):
(1) 讀到文件結(jié)束在這種情況下我們已經(jīng)正確地讀完文件中所有的值。
(2) 遇到一個無效的值比如3.14159小數(shù)點是非法的1e-1字符文字e是非法的或者一般的任意字符串文字在讀入一個無效值的
情況下istream對象被放置到一種錯誤的狀態(tài)中并且對于值的所有讀入動作都將停止。
2. 預定義的輸入操作符可以接受任何的內(nèi)置數(shù)據(jù)類型包括C 風格字符由以及標準庫string和complex 類類型。
3. 缺省情況下輸入操作符丟棄任何中間空白空格制表符換行符走紙以及回車。
Demo5:

#include <iostream>
#include <string>
int main()
{
    int item_number;
    string item_name;
    double item_price;
    cout << "Please enter the item_number, item_name, and price: " << endl;
    cin >> item_number;
    cin >> item_name;
    cin >> item_price;
    cout << "The values entered are: item# "
        << item_number << " "
        << item_name << " @$"
        << item_price << endl;
}

4. 如果希望讀入空白符號可以利用cin.get()方法一個個讀入,或者設置skipws和noskipws選項(后面介紹)。
5. isream_iterator和cin關(guān)聯(lián)使用。
Demo6:
#include <algorithm>
#include <string>
#include <vector>
#include <iostream>
int main()
{
    istream_iterator< string > in( cin ), eos ;
    vector< string > text ;
    // 從標準輸入向 text 拷貝值
    copy( in , eos , back_inserter( text ) ) ;
    sort( text.begin() , text.end() ) ;
    // 刪除所有重復的值
    vector< string >::iterator it ;
    it = unique( text.begin() , text.end() ) ;
    text.erase( it , text.end() ) ;
    // 顯示結(jié)果 vector
    int line_cnt = 1 ;
    for ( vector< string >::iterator iter = text.begin();
    iter != text.end() ; ++iter , ++line_cnt )
    cout << *iter
        << ( line_cnt % 9 ? " " : "\n" ) ;
    cout << endl;
}

20.2.1 字符串輸入
1. setw函數(shù):防止讀入字符串益處(char[4],輸入4個以上字節(jié)),while ( cin >> setw( bufSize ) >> buf )
這里bufSize是字符數(shù)組buf的長度setw()把長度等于或大于bufSize 的字符串分成最大長度為bufSize - 1的兩個
或多個字符串,在每個新串的末尾放一個空字符為了使用setw()要求程序包含iomanip頭文件#include <iomanip>。
2. 用string沒有char *那些長度和內(nèi)存溢出問題,更容易使用。

20.3 其他輸入輸出操作符
一. istream的成員get()一次讀入一個字節(jié)。屬于istream
1. get(char& ch)從輸入流中提取一個字符包括空白字符并將它存儲在ch中它返回被應用的istream對象。
與之對應的是ostream的put()方法,每次讀入一個字節(jié),然后返回ostream。
2. get()的第二個版本也從輸入流讀入一個字符區(qū)別是它返回該字符值而不是被應用的istream 對象它的返回類型
是int 而不是char 因為它也返回文件尾的標志end-of-file該標志通常用-1 來表示以便與字符集區(qū)分開為測試返回
值是否為文件尾我們將它與iostream 頭文件中定義的常量EOF 做比較。
Demo7:

#include <iostream>
int main()
{
    int ch;
    // 或使用:
    // while (( ch = cin.get() ) && ch != EOF)
    while (( ch = cin.get()) != EOF)
    cout.put(ch);
    return 0;
}

3. get(char *sink, streamsize size, char delimiter='\n')
(1) sink 代表一個字符數(shù)組用來存放被讀取到的字符。
(2) size 代表可以從istream 中讀入的字符的最大數(shù)目。
(3) delimiter 表示如果遇到它就結(jié)束讀取字符的動作delimiter 字符本身不會被讀入而是留在istream 中作為istream 的
下一個字符一種常見的錯誤是在執(zhí)行第二個get()之前忘了去掉delimiter。

二. ignore( streamsize length = 1, int delim = traits::eof )函數(shù): 屬于istream
我們用istream 成員函數(shù)ignore()來去掉delimiter
缺省情況下?lián)Q行符被用作delimiter。

三. gcount()函數(shù): 屬于istream
它返回由最后的get()或getline()調(diào)用實際提取的字符數(shù)。
Demo8:

#include <iostream>
int main()
{
    const int max_line = 1024;
    char line[ max_line ];
    while ( cin.get( line, max_line ))
    {
        // 最大讀取數(shù)量 max_line - 1, 也可以為 null
        int get_count = cin.gcount();
        cout << "characters actually read: "
        << get_count << endl;
        // 處理每一行
        // 如果遇到換行符
        // 在讀下一行之前去掉它
        if ( get_count & max_line-1 )
            cin.ignore();
     }
}

四. getline(char *sink, streamsize size, char delimiter='\n')屬于istream

五. write( const char *sink, streamsize length )屬于ostream
提供了另外一種方法可以輸出字符數(shù)組”它不是輸出直到終止空字符為止的所有字符“而是輸出某個長度的字符序列包括內(nèi)含的
空字符它的函數(shù)。length 指定要顯示的字符個數(shù)write()返回當前被調(diào)用的ostream 類對象。

六. read( char* addr, streamsize size )屬于istream
read()從輸入流中提取size 個連續(xù)的字節(jié)并將其放在地址從addr 開始的內(nèi)存中g(shù)count()返回由最后一個read()調(diào)用提取的字
節(jié)數(shù)而read()返回當前被調(diào)用的istream 類對象。
Demo9:

#include <iostream>
int main()
{
    const lineSize = 1024;
    int lcnt = 0; // 讀入多少行
    int max = -1; // 最長行的長度
    char inBuf[ lineSize ];
    // 讀取 1024 個字符或者遇到換行符
    while (cin.getline( inBuf, lineSize ))
    {
         // 實際讀入多少字符
         int readin = cin.gcount();
         // 統(tǒng)計: 行數(shù)最長行
         ++lcnt;
         if ( readin > max )
             max = readin;
         cout << "Line #" << lcnt
             << "\tChars read: " << readin << endl;
         cout.write( inBuf, readin).put('\n').put('\n');
     }
     cout << "Total lines read: " << lcnt << endl;
     cout << "Longest line read: " << max << endl;
}

七. getline( istream &is, string str, char delimiter );                         
這個getline()實例的行為如下讀入最大數(shù)目為str::max_size-1 個字符如果輸入序列超出這個限制則讀操作失敗
并且istream 對象被設置為錯誤狀態(tài)否則當讀到delimiter 它被從istream 中丟棄但沒有被插入到string 中或遇
到文件結(jié)束符時輸入結(jié)束。

八. putback( char c ); 將字符放回 iostream。

九. unget();往回重置下一個 istream 項。

十. peek(); 返回下一個字符或 EOF,但不要提取出來。
Demo10:

char ch, next, lookahead;
while ( cin.get( ch ))
{
    switch (ch) {
    case '/':
     // 是注釋行嗎? 用 peek() 看一看:
     // 是的? ignore() 余下的行
     next = cin.peek();
     if ( next == '/' )
         cin.ignore( lineSize, '\n' );
     break;
     case '>':
     // 查找 >>=
     next = cin.peek();
     if ( next == '>' ) {
         lookahead = cin.get();
         next = cin.peek();
     if ( next != '=' )
     cin.putback( lookahead );
}

20.4 重載輸出操作符<<
輸出操作符是一個雙目操作符它返回一個ostream 引用重載定義的通用框架如下
// 重載 output 操作符的通用框架
ostream&
operator <<( ostream& os, const ClassType &object )
{
// 準備對象的特定邏輯
// 成員的實際輸出
os << // ...
// 返回 ostream 對象
return os;
}
注:因為第一個實參是一個ostream 引用所以輸出操作符必須定義為非成員函數(shù),當輸出操作符要求訪問非公有成員
時必須將它聲明為該類的友元。

20.5 重載輸入操作符>>
1 由于不正確的格式而導致失敗istream 應該把狀態(tài)標記為fail。setstate( ios_base::failbit )。
2 對于錯誤狀態(tài)中的iostream 插入和提取操作沒有影響。
Demo11:

#include <iostream>
#include "WordCount.h"
/* 必須修改 WordCount, 指定輸入操作符為友元
class WordCount {
    friend ostream& operator<<( ostream&, const WordCount& );
    friend istream& operator>>( istream&, WordCount& );
*/
istream&
operator>>( istream &is, WordCount &wd )
{
/* WordCount 對象被讀入的格式:
 * <2> string
 * <7,3> <12,36>
 */
int ch;
/* 讀入小于符號, 如果不存在
 * 則設置 istream 為失敗狀態(tài)并退出
 */
if ((ch = is.get()) != '<' )
{
    is.setstate( ios_base::failbit );
    return is;
}
 // 讀入多少個
 int occurs;
 is >> occurs;
 // 取 >; 不檢查錯誤
 while ( is && (ch = is.get()) != '>' );
 is >> wd._word;
 // 讀入位置
 // 每個位置的格式: < line, col >
 for ( int ix = 0; ix < occurs; ++ix )
 {
  int line, col;
  // 提取值
  while (is && (ch = is.get())!= '<' );
  is >> line;
  while (is && (ch = is.get())!= ',' );
  is >> col;
  while (is && (ch = is.get())!= '>' );
  wd.occurList.push_back( Location( line, col ));
 }
 return is;
}

20.6 文件輸入和輸出
包含頭文件#include <fstream>
1. ofstream的構(gòu)造函數(shù)要制定打開模式
輸出模式ios_base::out 或附加模式ios_base::app 等等。在缺省情況下ostream文件以輸出模式打開。
注:如果在輸出模式下打開已經(jīng)存在的文件則所有存儲在該文件中的數(shù)據(jù)都將被丟棄如果我們希望增加而不是替換現(xiàn)
有文件中的數(shù)據(jù)則應該以附加模式打開文件于是新寫到文件中的數(shù)據(jù)將添加到文件尾部在這兩種模式下如果文件不存
在程序都會創(chuàng)建一個新文件。
2. 判斷是否打開if (!outFile /*ofstream對象*/)
3. 因為ofstream派生于ostream,所以ofstream擁有ostream的操作,比如put()等等。
4. 自定義<<操作輸入到ofstream中。
5. 用ifstream讀入一個文件,派生于istream,所有擁有istream的操作,比如get()等等。
6. close()函數(shù)斷開和文件的關(guān)聯(lián)。
7. fstream派生于iostream,它具有對文件的讀寫操作。
8. seekg和seekp標記當前位置,g是在讀文件中使用,p再寫文件中使用。
注:第二個參數(shù)標示定位標記:
(1) ios_base::beg 文件的開始
(2) ios_base::cur 文件的當前位置
(3) ios_base::end 文件的結(jié)尾
9. tellg()或tellp()返回當前位置,g和p意義同seekg和seekp。返回值是ios_base::pos_type。
10. clear()函數(shù):清除狀態(tài)。

20.7 條件狀態(tài)
一. 條件狀態(tài)
1 如果一個流遇到文件結(jié)束符則eof()返回true。
2 如果試圖做一個無效的操作比如seeking 重定位操作超出了文件尾則bad()返回true,一般地這表示該流由于某種
未定義的方式而被破壞了。
3 如果操作不成功比如打開一個文件流對象失敗或遇到一種無效的輸入格式則fail()
返回true 例如
ifstream iFile( filename, ios_base::in );
if ( iFile.fail() ) // 不能打開
error_message( ... );
4 如果其他條件都不為true 則good()返回true

二. 改變狀態(tài)
1. clear()函數(shù),狀態(tài)變?yōu)轱@示。
2. setstate()函數(shù),添加狀態(tài)。參數(shù)設置為:
ios_base::badbit
ios_base::eofbit
ios_base::failbit
ios_base::goodbit
3. rdstate()獲取成員狀態(tài),返回值ios_base::iostate。

20.8 string 流
1. 包括頭文件#include <sstream>
2. str()返回與ostringstream 類對象相關(guān)聯(lián)的string 對象。

20.9 格式狀態(tài)
操 作 符                    含 義
boolalpha               把true 和false 表示為字符串
*noboolalpha            把true 和false 表示為0 1
showbase                產(chǎn)生前綴指示數(shù)值的進制基數(shù)
*noshowbase             不產(chǎn)生進制基數(shù)前綴
showpoint               總是顯示小數(shù)點
*noshowpoint            只有當小數(shù)部分存在時才顯示小數(shù)點
Showpos                 在非負數(shù)值中顯示+
*noshowpos              在非負數(shù)值中不顯示+
*skipws                 輸入操作符跳過空白字符
noskipws                輸入操作符不跳過空白字符
uppercase               在十六進制下顯示0X 科學計數(shù)法中顯示E
*nouppercase            在十六進制下顯示0x 科學計數(shù)法中顯示e
*dec                    以十進制顯示
hex                     以十六進制顯示
oct                     以八進制顯示
left                    將填充字符加到數(shù)值的右邊
right                   將填充字符加到數(shù)值的左邊
Internal                將填充字符加到符號和數(shù)值的中間
*fixed                  以小數(shù)形式顯示浮點數(shù)
scientific              以科學計數(shù)法形式顯示浮點數(shù)
flush                   刷新ostream 緩沖區(qū)
ends                    插入空字符然后刷新ostream 緩沖區(qū)
endl                    插入換行符然后刷新ostream 緩沖區(qū)
ws                      吃掉 空白字符
// 以下這些要求 #include <iomanip>
setfill(ch)            用ch 填充空白字符
setprecision(n)        將浮點精度設置為n
setw(w)                按照w 個字符來讀或者寫數(shù)值
setbase(b)             以進制基數(shù)b 輸出整數(shù)值
注*表示缺省的流狀態(tài)

20.10 強類型庫
iostream庫是強類型的例如試圖從一個ostream 讀數(shù)據(jù)或者寫數(shù)據(jù)到一個istream都會在編譯時刻被捕獲到并標記為類型違例。

posted @ 2011-03-03 08:37 xi52qian 閱讀(353) | 評論 (0)編輯 收藏
 

3.1 什么是內(nèi)核對象

內(nèi)核對象就是內(nèi)核中的一塊內(nèi)存,是一個結(jié)構(gòu),并且只能由內(nèi)核對象訪問,應用程序只能通過調(diào)用Windows提供的函數(shù)來操作內(nèi)核對象。每個內(nèi)核對象都有相同的部分比如安全屬性和使用計數(shù)器。

3.1.1 內(nèi)核對象的使用計數(shù)

內(nèi)核對象中的使用計數(shù)和進程無關(guān),當進程第一次創(chuàng)建某個內(nèi)核對象時候使用計數(shù)變?yōu)?,當另一個進程也調(diào)用此內(nèi)核對象時計數(shù)變?yōu)?。當進程釋放時或者關(guān)閉內(nèi)核對象時(CloseHandle),內(nèi)核的使用計數(shù)減去1,如果使用計數(shù)不為0的話,內(nèi)核不會釋放此內(nèi)核對象。

3.2.2 安全性

內(nèi)核對象能夠得到安全描述符的保護,安全描述符定義了誰能夠創(chuàng)建,訪問和使用該對象,一般在服務器代碼中使用,客戶端可以忽略。

所有創(chuàng)建內(nèi)核對象的函數(shù)的參數(shù)都有一個指向SECURITY_ATTRIBUTES結(jié)構(gòu)的指針。

typedef struct _SECURITY_ATTRIBUTES {
    DWORD nLength;
    LPVOID lpSecurityDescriptor;
    BOOL bInheritHandle;
} SECURITY_ATTRIBUTES, *PSECURITY_ATTRIBUTES, *LPSECURITY_ATTRIBUTES;
只有lpSecurityDescriptor成員和安全屬性有關(guān)。一般此參數(shù)傳遞NULL,表示默認的安全描述。
如果需要:
SECURITY_ATTRIBUTES sa;
sa.nLength = sizeof(sa);
sa.lpSecurityDescriptor = NULL;
sa.bInheritHandle = FALSE;
HANDLE h = CreateMutex(&sa, FALSE, "XI");
其余進程可用用OpenMutex函數(shù)打開,如果權(quán)限可以就返回句柄,如果失敗返回NULL,GetLastError被設置為ERROR_ACCESS_DENIED。
Windows除了內(nèi)核對象之外還有GDI和用戶對象,區(qū)分它們的簡單辦法就是,創(chuàng)建函數(shù)中帶有安全描述符參數(shù)的就是內(nèi)核對象。
 
3.2 進程的內(nèi)核對象句柄表

索引                         內(nèi)核對象內(nèi)存塊得指針                             訪問屏蔽(標志位的DWORD)                      標志(標志位的DWORD)


1                               0x????????                                                0x????????                                                        0x????????
2                               0x????????                                                0x????????                                                        0x????????
…                               …                                                               …                                                                       …

3.2.1 創(chuàng)建內(nèi)核對象

調(diào)用Create&函數(shù)族來創(chuàng)建相應的內(nèi)核對象,返回的是內(nèi)核對象的句柄(也有個說法就是句柄表的索引),如果創(chuàng)建失敗一般會返回0(NULL),也有的會返回INVALID_HANDLE_VALUE=-1,比如CreateFile失敗后會返回后者,失敗的原因有可能是內(nèi)存不足或者是安全問題等等。其他對內(nèi)核操作的函數(shù)都需要此句柄值作為參數(shù)傳遞進去,如果傳遞一個無效的句柄進去,那么GetLastError函數(shù)的值將被置為6(ERROR_INVALID_HANDLE)。

3.2.2 關(guān)閉內(nèi)核對象

BOOL CloseHandle(HANDLE hobj);

調(diào)用此函數(shù),系統(tǒng)會了清理進程的句柄表中的對應項目,如果使用計數(shù)器為0,內(nèi)核釋放該內(nèi)核對象的資源,如果使用計數(shù)器不為0,說明其他進程還在使用此內(nèi)核對象,則不釋放資源。

當進程忘記調(diào)用CloseHandle函數(shù),可能造成內(nèi)存泄露,但是當進程結(jié)束的時候資源一樣會被釋放。

如果傳遞的參數(shù)無效,則函數(shù)返回FALSE,并且GetLastError函數(shù)的值被設置成ERROR_INVALID_HANDLE。如果是DEBUG階段,則返回錯誤信息。

 
3.3 跨越進程邊界共享內(nèi)核對象
3.3.1 對象句柄的繼承性
  1. 在父進程創(chuàng)建子進程的時候,將參數(shù)SECURITY_ATTRIBUTES結(jié)構(gòu)的Inherithandle字段設置為TRUE的話,再父進程句柄表中標示該內(nèi)核對象的項的標志位的值將會變成TRUE,標示該內(nèi)核對象是可以讓子進程繼承的,具有可繼承性(僅僅標示 該句柄值具有可繼承性,而內(nèi)核對象沒有可繼承性)。
  2. 將CreateProcess的參數(shù)bInherithandle參數(shù)的值設置為TRUE,標示創(chuàng)建的進程可以繼承有繼承性的父進程句柄。
  3. 子進程創(chuàng)建后不會先加載程序,它先搜索父進程的句柄表將有繼承性的項目原封不動的拷貝給自己(索引也沒有變,所以句柄值也不變)。
  4. 父進程可以有3種方式將句柄值傳遞給子進程,參數(shù)傳遞,進程間通信和環(huán)境變量(GetEnvironmentVariavle函數(shù)解析)。
BOOL
WINAPI
CreateProcess(
    __in_opt    LPCSTR lpApplicationName,
    __inout_opt LPSTR lpCommandLine,
    __in_opt    LPSECURITY_ATTRIBUTES lpProcessAttributes,
    __in_opt    LPSECURITY_ATTRIBUTES lpThreadAttributes,
    __in        BOOL bInheritHandles,
    __in        DWORD dwCreationFlags,
    __in_opt    LPVOID lpEnvironment,
    __in_opt    LPCSTR lpCurrentDirectory,
    __in        LPSTARTUPINFOA lpStartupInfo,
    __out       LPPROCESS_INFORMATION lpProcessInformation
    );
注意:
子進程再創(chuàng)建其子進程,如果滿足上面方式,可以繼續(xù)繼承。
如果父進程再創(chuàng)建子進程后,再創(chuàng)建句柄,子進程不會被繼承。
3.3.2 改變句柄標志
BOOL SetHandleInformation(HANDLE hObject, DWORD dwMask, DWORD dwFlags);
改變句柄的標志,目前可改變的標志有兩種
#define HANDLE_FLAG_INHERIT   0x00000001  // 繼承標志
#define HANDLE_FLAG_PROJECT_FROM_CLOSE   0x00000001 // 保護不允許關(guān)閉句柄標志
可以用OR操作同時設置2個標志。第一個參數(shù)是要設置的句柄值,第二個就是要改變的標志,第三個參數(shù)是將標志改編成什么值。
BOOL GetHandleInformation(HANDLE hObkect, PDWORD pdwFlags);
獲取當前句柄的標志的值。
// 設置句柄值可繼承:
SetHandleInformation(hObject, HANDLE_FLAG_INHERIT, HANDLE_FLAG_INHERIT);
// 設置句柄不可繼承:
SetHandleInformation(hObject, HANDLE_FLAG_INHERIT, 0);
// 設置句柄值不可關(guān)閉,受保護:
SetHandleInformation(hObject, HANDLE_FLAG_PROJECT_FROM_CLOSE, HANDLE_FLAG_PROJECT_FROM_CLOSE);
// 設置句柄值可關(guān)閉,不受保護:
SetHandleInformation(hObject, HANDLE_FLAG_PROJECT_FROM_CLOSE, 0);
3.3.3 命名對象
創(chuàng)建內(nèi)核對象函數(shù)族Create&中的最后一個參數(shù)是pszName,該參數(shù)是如果傳遞NULL,表示是匿名內(nèi)核對象,可以通過其他倆種方式來使用其他進程的內(nèi)核對象。當pszName參數(shù)傳遞以’\0’(最多長度為MAX_PATH 260字符)結(jié)尾的字符串時,表示啟用命名對象,比如進程A調(diào)用CreateMutex(NULL, FALSE, “XI”)的時候,他將創(chuàng)建內(nèi)核對象名字為“XI”,之后某一時刻如果進程B也調(diào)用CreateMutex(NULL, FALSE, “XI”)函數(shù)他將經(jīng)過以下幾步:
  1. 判斷內(nèi)核對象名稱是否相同。
  2. 判斷內(nèi)核對象類型是否相同,如果名字相同但是類型不相同則Create&函數(shù)族返回NULL,GetLastError函數(shù)值為6(ERROR_INVALID_HANDLE)。
  3. 判斷安全性,返回同2步,GetLastError值同2步。
  4. 如果驗證通過則返回句柄(返回句柄的值和該內(nèi)核對象其他句柄的值不一定相同),GetLastError的值等于ERROR_ALREADY_EXISTS。

也可以用Open&函數(shù)族來打開已經(jīng)創(chuàng)建的句柄,成功后GetLastError也不會被設置。具體如下

HANDLE Open&(DWORD, BOOL, PCSTR);

第一個參數(shù):表示訪問權(quán)限。

第二個參數(shù):表示新創(chuàng)建的句柄是否有繼承性(注意不是內(nèi)核對象!)。

第三個參數(shù):不能傳遞NULL。如果該句柄不存在則返回NULL,GetLastError被設置為2(ERROR_FILE_NOT_FOUND)。

3.3.4 終端服務器的名字空間

Globad,Local,Session程序保留關(guān)鍵字,具體的沒弄明白,理解的就是說當服務器的時候,客戶端可以訪問以這些名字開頭的內(nèi)核對象。

3.3.5 復制對象句柄

BOOL DuplicateHandle(
HANDLE hSourceProcessHandle,
HANDLE hSourceHandle,
HANDLE TargetProcessHandle,
PHANDLE phTargetHandle,
DWORD dwDesiredAccess,
BOOL bInheritHandle,
DWORD dwOptions);

執(zhí)行DuplicateHandle函數(shù)的進程為ProcessC,原進程為ProcessS,目標進程為ProcessT。則hSourceProcessHandle為進程ProcessS的進程句柄,TargetProcessHandle為進程ProcessT的進程句柄,ProcessC將句柄hSourceHandle從ProcessC拷貝到ProcessT中,值存在phTargetHandle中,dwDesiredAccess新句柄的反問權(quán)限,bInheritHandle新句柄的繼承性,參數(shù)dwOptions有兩種類型分別是:

DUPLICATE_SAME_ACCESS忽略參數(shù)dwDesiredAccess,新句柄和原進程句柄具有相同的反問權(quán)限。

DUPLICATE_CLOSE_SOURCE關(guān)閉ProcessS中的拷貝句柄,內(nèi)核對象的計數(shù)不變。

HANDLE hObjProcessS = CreateMutex(NULL, FALSE, NULL);
HANDLE hProcessT = OpenProcess(PROCESS_ALL_ACCESS, FALSE, dwProcessIdT);
HANDLE hObjProcessT;
DuplicateHandle(GetCurrentProcess(), hObjProcessS, hProcessT , &hObjProcessT, 0, FALSE, DUPLICATE_SAME_ACCESS);
CloseHandle(hObjProcessS);
CloseHandle(hProcessT);
注意:
一般DuplicateHandle函數(shù)沒有在三個進程中使用,因為很難知道原進程的句柄值。
要使用IPC機制通知目標進程,新句柄已經(jīng)拷貝過去。
posted @ 2011-03-03 08:35 xi52qian 閱讀(341) | 評論 (1)編輯 收藏
 
Copyright © xi52qian Powered by: 博客園 模板提供:滬江博客
青青草原综合久久大伊人导航_色综合久久天天综合_日日噜噜夜夜狠狠久久丁香五月_热久久这里只有精品
  • <ins id="pjuwb"></ins>
    <blockquote id="pjuwb"><pre id="pjuwb"></pre></blockquote>
    <noscript id="pjuwb"></noscript>
          <sup id="pjuwb"><pre id="pjuwb"></pre></sup>
            <dd id="pjuwb"></dd>
            <abbr id="pjuwb"></abbr>
            亚洲免费福利视频| 欧美中文在线字幕| 久久久久久久久久看片| 另类尿喷潮videofree| 亚洲综合清纯丝袜自拍| 狠狠色狠狠色综合系列| 久久大综合网| 免费观看一区| 亚洲视频1区2区| 一区二区三区免费观看| 欧美视频精品一区| 亚洲国产精品成人va在线观看| 久久福利资源站| 久久久av水蜜桃| 亚洲国产精品久久精品怡红院| 久久久亚洲国产美女国产盗摄| 欧美一区二区精品在线| 亚洲国产精品久久精品怡红院| 亚洲国产美女| 欧美黄网免费在线观看| 一区二区三区久久| 亚洲综合色丁香婷婷六月图片| 国产日韩精品一区二区| 久久阴道视频| 欧美日本不卡高清| 久久久久欧美精品| 国产精品99一区二区| 久久久亚洲精品一区二区三区| 美女网站在线免费欧美精品| 亚洲永久精品大片| 欧美激情国产日韩| 麻豆九一精品爱看视频在线观看免费 | 国产精品久久一卡二卡| 久久这里只有精品视频首页| 欧美高清在线一区| 麻豆成人在线观看| 国产专区综合网| 一区二区欧美激情| 欧美高清日韩| 亚洲视频香蕉人妖| 国产农村妇女精品一区二区| 亚洲成色www8888| 在线观看亚洲精品| 久久久国产精品一区| 久久国产精品黑丝| 国产精品视频1区| 午夜精品福利一区二区蜜股av| 亚洲手机在线| 国产精品自在欧美一区| 亚洲欧美在线一区| 久久久久久网| 在线成人av网站| 免费不卡在线观看| 亚洲精选一区二区| 艳妇臀荡乳欲伦亚洲一区| 欧美日本在线视频| 亚洲精品日韩在线| 欧美一区二区三区在线观看视频| 国产精品久久久久一区| 亚洲一区二区高清| 噜噜噜噜噜久久久久久91 | 亚洲精品综合在线| 欧美主播一区二区三区| 欧美xart系列高清| 亚洲专区一二三| 国产视频在线观看一区二区| 欧美大片免费| 午夜在线一区二区| 亚洲精品一区二区三区av| 国产精品免费福利| 欧美巨乳在线| 欧美高清视频| 久久久久久国产精品一区| 亚洲国产精品久久久| 国产精品一区久久| 亚洲二区免费| 久久激情视频免费观看| 一区二区三区欧美在线| 亚洲国产精品久久91精品| 国产亚洲精品美女| 国产亚洲精品一区二555| 欧美日韩亚洲精品内裤| 欧美成人一区在线| 免费高清在线一区| 美女爽到呻吟久久久久| 久久这里只有| 亚洲激情二区| 欧美激情一区二区三区蜜桃视频| 久热精品视频在线| 米奇777在线欧美播放| 久久综合五月| 亚洲第一页在线| 亚洲精品1234| 日韩视频久久| 亚洲欧美中文另类| 在线一区二区视频| 性欧美超级视频| 你懂的国产精品| 国产精品无码专区在线观看 | 亚洲欧美精品中文字幕在线| 亚洲美女黄色片| 亚洲欧美综合网| 欧美黄在线观看| 国产日产亚洲精品系列| 日韩午夜在线电影| 欧美自拍偷拍午夜视频| 老色批av在线精品| 日韩一二在线观看| 免费在线日韩av| 欧美日韩精品福利| 国产欧美日本在线| 亚洲线精品一区二区三区八戒| 国产亚洲在线观看| 99视频精品| 久久一区二区三区超碰国产精品| 国产日产欧产精品推荐色| 亚洲第一黄色网| 欧美一区二区| 亚洲黄色尤物视频| 久热精品视频在线免费观看| 国产精品推荐精品| 亚洲人成在线观看网站高清| 欧美一区二视频在线免费观看| 亚洲人成网站777色婷婷| 午夜视黄欧洲亚洲| 日韩亚洲欧美高清| 欧美激情小视频| 日韩一级网站| 欧美主播一区二区三区美女 久久精品人| 亚洲国产精品国自产拍av秋霞| 久久久久久亚洲精品杨幂换脸 | 国产精品一级| 亚洲视频在线一区观看| 亚洲黄色免费网站| 欧美精品1区2区| 亚洲一区二区三区四区在线观看| 亚洲三级观看| 国产精品网站视频| 久久久91精品国产一区二区三区| 久久激情视频久久| 日韩写真视频在线观看| 久久人人97超碰国产公开结果| 久久成人免费电影| 亚洲精品久久久蜜桃| 夜夜嗨av色综合久久久综合网 | 亚洲砖区区免费| 欧美日韩亚洲一区二区三区在线观看 | 狠狠久久亚洲欧美| 欧美亚洲综合另类| 亚洲制服av| 欧美日韩99| 亚洲精选在线| 欧美精品v国产精品v日韩精品| 欧美成人亚洲| 欧美激情第1页| 国产一区清纯| 欧美一区二区视频在线观看2020 | 亚洲茄子视频| 国语自产精品视频在线看| 亚洲欧美成人综合| 久久精品国产第一区二区三区最新章节 | 国内精品久久久久久久97牛牛| 91久久久久久久久久久久久| 亚洲国产精品久久久| 久久天堂av综合合色| 欧美 日韩 国产 一区| 在线电影欧美日韩一区二区私密| 久久成人免费电影| 欧美高清视频| 亚洲一区二区三区乱码aⅴ蜜桃女| 欧美日韩在线播放三区| 亚洲一区二区三区乱码aⅴ| 欧美尤物巨大精品爽| 亚洲福利视频网站| 欧美电影美腿模特1979在线看| 国产一区二区成人久久免费影院| 久久色在线播放| 亚洲一区二区三区在线视频| 亚洲三级毛片| 99视频一区| 99日韩精品| 亚洲男人影院| 亚洲精品综合精品自拍| 国产一区二区三区不卡在线观看 | 裸体一区二区| 久久久九九九九| 亚洲午夜精品久久久久久app| 欧美成人在线网站| 久久躁狠狠躁夜夜爽| 亚洲欧美国产制服动漫| 亚洲视频高清| 亚洲国产美女久久久久| 美国成人直播| 免费欧美视频| 欧美h视频在线| 欧美成人嫩草网站| 亚洲精品视频免费观看| 99国产精品久久| 中文日韩欧美| 亚洲国产精品传媒在线观看 |