程序師世界是廣大編程愛好者互助、分享、學習的平台,程序師世界有你更精彩!
首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫知識
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
 程式師世界 >> 編程語言 >> C語言 >> 關於C語言 >> WINDOWS核心編程學習心得--進程

WINDOWS核心編程學習心得--進程

編輯:關於C語言

WINDOWS的任務管理器打開會有很多的進程,有些是WINDOWS系統的,有些是我們運行的軟件,

WINDOWS支持兩種類型的應用程序,GUI和CUI,也就是圖形用戶界面Graphical User Interface)和

控制台用戶界面Console User Interface),我們所使用的程序一般都是GUI的,CMD.EXE是典型的

CUI程序,這種東西很少了,想想也知道,沒有界面交互,用戶用了不爽!

應用程序必須有一個入口點函數,我們在創建程序的時候VS會幫我們自動判斷我們創建的程序應

該為哪一個子系統,在連接器的/SUBSYSTEM裡可以人為的設置這個連接器開關,其實也就是強制的選

擇一個入口點函數。根據程序所使用的字符集,應用程序的類型的不同,主要有以下四種入口點函

數,這裡就借用WINDOWS核心編程這本書的圖片吧。

103454892.jpg

有人可能會奇怪,後面怎麼還有啟動函數,實際上入口函數不是程序執行的開始,在入口點函數之前

還有一個被稱為啟動函數的函數,這個啟動函數的作用是為程序的開始運行做一些初始化的准備工作。

下面說下如何創建一個進程,一般來講,我們編寫的程序都是單一進程的,但是也有一些程序用到了很多進程,也就是在進程裡創建進程。創建進程的函數式這樣的:

BOOL CreateProcess(
  LPCWSTR pszImageName,
  LPCWSTR pszCmdLine,
  LPSECURITY_ATTRIBUTES psaProcess,
  LPSECURITY_ATTRIBUTES psaThread,
  BOOL fInheritHandles,
  DWORD fdwCreate,
  LPVOID pvEnvironment,
  LPWSTR pszCurDir,
  LPSTARTUPINFOW psiStartInfo,
  LPPROCESS_INFORMATION pProcInfo
);

一個線程調用CreateProcess時,系統將創建一個進程內核對象,其初始化使用計數為1。進程

內核對象不是進程本身,而是操作系統用來管理這個進程的一個小型數據結構。然後,系統為新進程

創建一個虛地址空間,並將可執行文件和所有必要的DLL)的代碼及數據加載到進程的地址空間。

然後,系統為新進程的主線程創建一個線程內核對象其使用計數為1)。和進程內核對象一樣,

線程內核對象也是一個小型數據結構,操作系統用它來管理這個線程。這個主線程一開始就會執行

C/C++運行時的啟動函數,也就是剛才說的一些列的CRT字樣的啟動函數,最終會調用應用程序的入口

函數,也就是一系列帶main,WinMain字樣的函數,這裡寫的東西才是我們真正的程序員寫的東西。

要說明的是,CreateProcess在進程完全初始化好之前就返回TRUE,這意味著系統尚未嘗試定位

所有必要的DLL,如果一個DLL找不到,或者不能正確的初始化,進程就會終止。所以父進程不會注意

到任何初始化問題,下面對這個CreateProcess函數的參數進行一下說明。


pszImageName 新進程要使用的可執行文件的名稱

pszCmdLine 傳給新進程的命令行字符串

psaProcess 該結構為進程制定安全說明符,一般為NULL,默認的安全描述符,也就是不可以繼承。

psaThread 該結構為進程的主線程制定安全說明符。

fInheritHandles 設置為true指示調用進程中的每個可繼承句柄都由已啟動的進程繼承,設置為

false指示不繼承這些句柄

fdwCreate win32進程創建標志)的按位組合,這些標志控制已啟動的進程的優先級數和行為。

pvEnvironment 指向新進程的環境塊的指針。

pszCurDir 指向NULL結尾的字符串的指針,該字符串制定進程當前目錄的完整路徑。為NULL,則新進程具有相同的當前驅動器和目錄。

psiStartInfo 指向WIN32 STARTUPINFOW 結構的指針,該結構為已啟動的進程的主窗口指定窗口站、桌面、標准句柄和外觀。

pProcInfo 指向WIN32 PROCESS_INFORMATION 結構的指針,該結構指定有關要啟動的進程的表示信息。


進程可以通過以下四種方式終止:

1 主線程的入口點函數返回

2 進程中的一個線程調用ExitProcess函數

3 另一個進程中的線程調用TerminateProcess函數

4 進程中的所有線程都“自然死亡"

第一種方式是最好的,可以保證該線程創建的任何C++對象都有這些對象的析構函數正確銷毀,操作系

統將正確釋放線程棧使用的內存,系統將進程的退出代碼設為入口點函數的返回值,系統遞減進程內

核對象的使用計數。

用ExitProcess終止進程,退出代碼被設置為fuExitCode,當主線程的入口點函數返回時,會返回到

C/C++運行庫的啟動代碼,後者將正確清理進程使用的全部C運行時的資源。釋放了C運行時資源之

後,C運行時啟動代碼將顯示調用ExitProcess,並將入口點函數返回的值傳給它。ExitProcess造

成進程“當場終止運行”:C/C++運行時沒有機會執行清理操作。在主線程中應避免使用

ExitProcess,任何時候都不要顯示調用ExitProcess只要確保主線程的入口點函數返回,C/C++運

行時就能執行清理工作。

TerminateProcess被終止自己的進程也可以終止另外一個進程,但是應用程序不能正確清理,雖然

進程沒有機會執行自己的清理工作,但是操作系統會在進程終止後徹底進行清理,確保不會洩露任何

操作系統。進程在終止後絕對不會洩露任何東西,這是操作系統幫我們清理了。當一個進程中的所有

線程都結束了,不管是怎麼結束的,一旦系統檢測到一個進程中沒有任何線程在運行,就會終止這個

進程,進程的退出代碼會被設置為最後一個終止的那個線程的退出代碼。

當一個進程終止時,系統會依次執行以下操作:

1. 終止進程中遺留的任何線程。

2. 釋放進程分配的所有用戶對象的GDI對象,關閉所有內核對象在其它進程中打開的內核對象除外)

3. 進程的退出代碼從STILL_ACTIVE變為ExitProcess或TerminateProcess函數的代碼

4. 進程內核對象的狀態變為已觸發狀態

5. 進程內核對象的使用計數-1.


本文出自 “賣萌程序員” 博客,請務必保留此出處http://7677869.blog.51cto.com/7667869/1297643

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