將一個EXE程序嵌入MFC運行


原文:http://www.codeproject.com/Articles/18724/Hosting-exe-applications-into-a-dialog

 

HANDLE hProcess;
HWND apphWnd = NULL;
int CALLBACK EnumWindowsProc(HWND hwnd, LPARAM lParam)
{
	DWORD pID;
	DWORD tpID = GetWindowThreadProcessId(hwnd,&pID);
	if(tpID == (DWORD)lParam)
	{
		apphWnd = hwnd;
		return false;
	}
	return true;
}

HANDLE StartProcess(LPCTSTR program, LPCTSTR args)
{
	 HANDLE hPro = NULL;
     PROCESS_INFORMATION processInfo;
     STARTUPINFO startupInfo;
     ::ZeroMemory(&startupInfo, sizeof(startupInfo));
     startupInfo.cb = sizeof(startupInfo);
	 //設置進程創建時不顯示窗口
	 startupInfo.dwFlags = /*STARTF_USEPOSITION*/STARTF_USESHOWWINDOW;
	 /*startupInfo.dwX = 600;
	 startupInfo.dwY = 900;*/
	 startupInfo.wShowWindow = SW_HIDE;
     if(::CreateProcess(program, (LPTSTR)args, 
                        NULL,  // process security
                        NULL,  // thread security
                        FALSE, // no inheritance
                        0,     // no startup flags
                        NULL,  // no special environment
                        NULL,  // default startup directory
                        &startupInfo,
                        &processInfo))
        {
			//延遲0.5s,等待進程創建成功
			Sleep(500);
			while(true)
			{
				::EnumWindows(&EnumWindowsProc, processInfo.dwThreadId);//Iterate all windows
				if(NULL != apphWnd)
					break;
			}
	        hPro = processInfo.hProcess;
			
        } 
     return hPro;
}


void CExeInsetMFCDlg::OnNew()
{
	if(apphWnd != NULL)
	{
		OnQuit();
	}

	CRect rect;
	GetClientRect(&rect);//get our dialog size into rect

//	hProcess=StartProcess("C:\\Program Files\\Microsoft Games\\Minesweeper\\MineSweeper.exe","");//Start ms paint
	hProcess=StartProcess("C:\\Users\\Administrator\\Documents\\Visual Studio 2010\\Projects\\AStar算法\\Debug\\AStar算法.exe","");//Start ms paint
	
	if(apphWnd!=NULL)//check for window handle
		{
			
			::SetParent(apphWnd,m_hWnd);//set parent of ms paint to our dialog.
			SetWindowLong(apphWnd, GWL_STYLE, WS_VISIBLE);//eraze title of ms paint window.
			//Positioning ms paint.
			::MoveWindow(apphWnd, rect.left, rect.top,rect.right, rect.bottom, true);
			//窗口重繪,(因創建exe時,設置為SW_HIDE,導致exe窗口會被父窗口覆蓋一部分)
			Invalidate();
			::UpdateWindow(apphWnd);
			::ShowWindow(apphWnd,SW_SHOW);
		}
	else
		MessageBox("Cannot find Window");
		
}


void CExeInsetMFCDlg::OnQuit()
{
	TerminateProcess(hProcess,0);
	apphWnd = NULL;
}

 

轉:http://www.cnblogs.com/Tisty/archive/2008/05/31/1211395.html

STARTUPINFO解讀

 

typedef struct _STARTUPINFO {   

DWORD cb;            //包含STARTUPINFO結構中的字節數.如果Microsoft將來擴展該結構,它可用作版本控制手段.                        

           應用程序必須將cb初始化為sizeof(STARTUPINFO)   

PSTR lpReserved;      //保留。必須初始化為N U L L   

PSTR lpDesktop;    //用於標識啟動應用程序所在的桌面的名字。如果該桌面存在,新進程便與指定的桌面相關聯。                      

           如果桌面不存在,便創建一個帶有默認屬性的桌面,並使用為新進程指定的名字。                     

           如果lpDesktop是NULL(這是最常見的情況),那么該進程將與當前桌面相關聯   

PSTR lpTitle;    //用於設定控制台窗口的名稱。如果l p Ti t l e 是N U L L ,則可執行文件的名字將用作窗口名   

DWORD dwX;       //用於設定應用程序窗口在屏幕上應該放置的位置的x 和y 坐標(以像素為單位)。   

DWORD dwY;       只有當子進程用CW_USEDEFAULT作為CreateWindow的x參數來創建它的第一個重疊窗口時,                    

          才使用這兩個坐標。若是創建控制台窗口的應用程序,這些成員用於指明控制台窗口的左上角

DWORD dwXSize;  //用於設定應用程序窗口的寬度和長度(以像素為單位)只有dwYsize    

DWORD dwYSize;   當子進程將C W _ U S E D E FA U LT 用作C r e a t e Wi n d o w 的             

          n Wi d t h參數來創建它的第一個重疊窗口時,才使用這些值。                     

          若是創建控制台窗口的應用程序,這些成員將用於指明控制台窗口的寬度   

DWORD dwXCountChars;  //用於設定子應用程序的控制台窗口的寬度和高度(以字符為單位)   

DWORD dwYCountChars;   

DWORD dwFillAttribute;   //用於設定子應用程序的控制台窗口使用的文本和背景顏色   

DWORD dwFlags;           //請參見下一段和表4 - 7 的說明   

WORD wShowWindow;        //用於設定如果子應用程序初次調用的S h o w Wi n d o w 將S W _ S H O W D E FA U LT 作為                              

                n C m d S h o w 參數傳遞時,該應用程序的第一個重疊窗口應該如何出現。                              

                本成員可以是通常用於Show Wi n d o w 函數的任何一個S W _ *標識符   

WORD cbReserved2;        //保留。必須被初始化為0   

PBYTE lpReserved2;       //保留。必須被初始化為N U L L   

HANDLE hStdInput;        //用於設定供控制台輸入和輸出用的緩存的句柄。                            

              按照默認設置,h S t d I n p u t 用於標識鍵盤緩存,                            

              h S t d O u t p u t 和h S t d E r r o r用於標識控制台窗口的緩存   

HANDLE hStdOutput;    HANDLE hStdError; } STARTUPINFO, *LPSTARTUPINFO;

 

當Wi n d o w s 創建新進程時,它將使用該結構的有關成員。大多數應用程序將要求生成的應用程序僅僅使用默認值。至少應該將該結構中的所有成員初始化為零,然后將c b 成員設置為該結構的大小:

STARTUPINFO si = { sizeof(si) }; CreateProcess(...,&si,...);

表4-7 dwFlags 使用標志及含義

標志                                    含義

STARTF_USESIZE                 // 使用d w X S i z e 和d w Y S i z e 成員

STARTF_USESHOWWINDOW              //使用w S h o w Wi n d o w 成員

STARTF_USEPOSITION              //使用d w X 和d w Y 成員

STARTF_USECOUNTCHARS                //使用d w X C o u n t C h a r s 和dwYCount Chars 成員

STARTF_USEFILLATTRIBUTE          //使用d w F i l l A t t r i b u t e 成員

STARTF_USESTDHANDLES              //使用h S t d I n p u t 、h S t d O u t p u t 和h S t d E r r o r 成員

STARTF_RUN_FULLSCREEN              //強制在x 8 6 計算機上運行的控制台應用程序以全屏幕方式啟動運行

 

另外還有兩個標志,即STARTF_FORCEONFEEDBACK 和STARTF_+FORCEOFFF -EEDBACK ,當啟動一個新進程時,它們可以用來控制鼠標的光標。

由於Windows支持真正的多任務搶占式運行方式,因此可以啟動一個應用程序,然后在進程初始化時,使用另一個程序。為了向用戶提供直觀的反饋信息,

C r e a t e P r o c e s s 能夠臨時將系統的箭頭光標改為一個新光標,即沙漏箭頭光標:

該光標表示可以等待出現某種情況,也可以繼續使用系統。當啟動另一個進程時,CreateProcess函數使你能夠更好地控制光標。

當設定STARTF_FORCEONFEEDBACK標志時,C r e a t e P r o c e s s 並不將光標改為沙漏。

STARTF_FORCEONFEEDBACK可使CreateProcess能夠監控新進程的初始化,並可根據結果來改變光標。當使用該標志來調用CreateProcess時,光標改為沙漏。

過2 s 后,如果新進程沒有調用G U I ,CreateProcess 將光標恢復為箭頭。

如果該進程在2 s 內調用了GUI ,CreateProcess將等待該應用程序顯示一個窗口。這必須在進程調用G U I 后5 s 內發生。如果沒有顯示窗口,CreateProcess就會恢復原來的光標。

如果顯示了一個窗口,CreateProcess將使沙漏光標繼續保留5 s 。如果某個時候該應用程序調用了G e t M e s s a g e 函數,指明它完成了初始化,

那么C r e a t e P r o c e s s 就會立即恢復原來的光標,並且停止監控新進程。

在結束這一節內容的介紹之前,我想講一講S TA RT U P I N F O 的w S h o w Wi n d o w 成員。你將該成員初始化為傳遞給( w ) Wi n M a i n 的最后一個參數n C m d S h o w 的值。

該成員顯示你想要傳遞給新進程的( w ) Wi n M a i n 函數的最后一個參數n C m d S h o w 的值。它是可以傳遞給S h o w Wi n d o w 函數的標識符之一。

通常,n C m d S h o w 的值既可以是S W _ S H O W N O R M A L ,也可以是SW_ SHOWMINNOACTIVE 。但是,它有時可以是S W _ S H O W D E FA U LT 。

當在E x p l o r e r 中啟動一個應用程序時,該應用程序的( w ) Wi n M a i n 函數被調用,而S W _ S H O W N O R M A L 則作為n C m d S h o w 參數來傳遞。

如果為該應用程序創建了一個快捷方式,可以使用快捷方式的屬性頁來告訴系統,應用程序的窗口最初應該如何顯示。圖4 - 3 顯示了運行N o t e p a d 的快捷方式的屬性頁。

注意,使用R u n 選項的組合框,就能夠設定如何顯示N o t e p a d 的窗口。

當使用E x p l o r e r 來啟動該快捷方式時,E x p l o r e r 會正確地准備S TA RT U P I N F O 結構並調用C r e a t e P r o c e s s 。

這時N o t e p a d 開始運行,並且為n C m d S h o w 參數將S W _ S H O W M I N N O A C T I V E傳遞給它的( w ) Wi n M a i n 函數。

運用這樣的方法,用戶能夠很容易地啟動一個應用程序,其主窗口可以用正常狀態、最小或最大狀態進行顯示。

最后,應用程序可以調用下面的函數,以便獲取由父進程初始化的S TA RT U P I N F O 結構的拷貝。子進程可以查看該結構,並根據該結構的成員的值來改變它的行為特性。

VOID GetStartupInfo(LPSTARTUPINFO pStartupInfo);

注意雖然Wi n d o w s 文檔沒有明確地說明,但是在調用G e t S t a r t I n f o 函數之前,必須像下面這樣對該結構的c b 成員進行初始化:

STARTUPINFO si = { sizeof(si) };

GetStartupInfo(&si);

 

轉:http://www.cnblogs.com/wangliang651/archive/2007/05/25/760057.html

CreateProcess函數用法

 

1.函數說明:

WIN32API函數CreateProcess用來創建一個新的進程和它的主線程,這個新進程運行指定的可執行文件。

2.函數原型: BOOL CreateProcess (     LPCTSTR lpApplicationName,            LPTSTR lpCommandLine,            LPSECURITY_ATTRIBUTES lpProcessAttributes     LPSECURITY_ATTRIBUTES lpThreadAttributes,            BOOL bInheritHandles,            DWORD dwCreationFlags,     LPVOID lpEnvironment,            LPCTSTR lpCurrentDirectory,            LPSTARTUPINFO lpStartupInfo,            LPPROCESS_INFORMATION lpProcessInformation ); 3.參數:

lpApplicationName

指向一個NULL結尾的、用來指定可執行模塊的字符串。

     這個字符串可以使可執行模塊的絕對路徑,也可以是相對路徑,在后一種情況下,函數使用當前驅動器和目錄建立可執行模塊的路徑。     這個參數可以被設為NULL,在這種情況下,可執行模塊的名字必須處於 lpCommandLine 參數的最前面並由空格符與后面的字符分開。     這個被指定的模塊可以是一個Win32應用程序。如果適當的子系統在當前計算機上可用的話,它也可以是其他類型的模塊(如MS-DOS OS/2)。

 Windows NT,如果可執行模塊是一個16位的應用程序,那么這個參數應該被設置為NULL,並且因該在lpCommandLine參數中指定可執行模塊的名稱。16位的應用程序是以DOS虛擬機或Win32上的WindowsWOW為進程的方式運行。

lpCommandLine

指向一個NULL結尾的、用來指定要運行的命令行。

 這個參數可以為空,那么函數將使用參數指定的字符串當作要運行的程序的命令行。

 如果lpApplicationNamelpCommandLine參數都不為空,那么lpApplicationName參數指定將要被運行的模塊,lpCommandLine參數指定將被運行的模塊的命令行。新運行的進程可以使用GetCommandLine函數獲得整個命令行。C語言程序可以使用argcargv參數。

如果lpApplicationName參數為空,那么這個字符串中的第一個被空格分隔的要素指定可執行模塊名。如果文件名不包含擴展名,那么.exe將被假定為默認的擴展名。如果文件名以一個點(.)結尾且沒有擴展名,或文件名中包含路徑,.exe將不會被加到后面。如果文件名中不包含路徑,Windows將按照如下順序尋找這個可執行文件: 1.當前應用程序的目錄。 2.父進程的目錄。

3.Windows目錄。可以使用GetWindowsDirectory函數獲得這個目錄。  4.列在PATH環境變量中的目錄。      如果被創建的進程是一個以MS-DOS16Windows為基礎的應用程序,lpCommandLine參數應該是一個以可執行文件的文件名作為第一個要素的絕對路徑,因為這樣做可以使32Windows程序工作的很好,這樣設置lpCommandLine參數是最強壯的。

lpProcessAttributes

指向一個SECURITY_ATTRIBUTES結構體,這個結構體決定是否返回的句柄可以被子進程繼承。如果lpProcessAttributes參數為空(NULL),那么句柄不能被繼承。

lpThreadAttributes

指向一個SECURITY_ATTRIBUTES結構體,這個結構體決定是否返回的句柄可以被子進程繼承。如果lpThreadAttributes參數為空(NULL),那么句柄不能被繼承。

bInheritHandles

指示新進程是否從調用進程處繼承了句柄。如果參數的值為真,調用進程中的每一個可繼承的打開句柄都將被子進程繼承。被繼承的句柄與原進程擁有完全相同的值和訪問權限。

dwCreationFlags

指定附加的、用來控制優先類和進程的創建的標志。以下的創建標志可以以除下面列出的方式外的任何方式組合后指定。

下面是一些常用的標志.

值:CREATE_DEFAULT_ERROR_MODE含義:新的進程不繼承調用進程的錯誤模式。CreateProcess函數賦予新進程當前的默認錯誤模式作為替代。應用程序可以調用SetErrorMode函數設置當前的默認錯誤模式。這個標志對於那些運行在沒有硬件錯誤環境下的多線程外殼程序是十分有用的。對於CreateProcess函數,默認的行為是為新進程繼承調用者的錯誤模式。設置這個標志以改變默認的處理方式。值:CREATE_NEW_CONSOLE含義:新的進程將使用一個新的控制台,而不是繼承父進程的控制台。這個標志不能與DETACHED_PROCESS標志一起使用。值:CREATE_NEW_PROCESS_GROUP含義:新進程將使一個進程樹的根進程。進程樹種的全部進程都是根進程的子進程。新進程樹的用戶標識符與這個進程的標識符是相同的,由lpProcessInformation參數返回。進程樹經常使用GenerateConsoleCtrlEvent函數允許發送CTRL+CCTRL+BREAK信號到一組控制台進程。值:CREATE_SEPARATE_WOW_VDM含義:(只適用於Windows NT這個標志只有當運行一個16位的Windows應用程序時才是有效的。如果被設置,新進程將會在一個私有的虛擬DOS機(VDM)中運行。另外,默認情況下所有的16Windows應用程序都會在同一個共享的VDM中以線程的方式運行。單獨運行一個16位程序的優點是一個應用程序的崩潰只會結束這一個VDM的運行;其他那些在不同VDM中運行的程序會繼續正常的運行。同樣的,在不同VDM中運行的16Windows應用程序擁有不同的輸入隊列,這意味着如果一個程序暫時失去響應,在獨立的VDM中的應用程序能夠繼續獲得輸入。值:CREATE_SHARED_WOW_VDM含義:(只適用於Windows NT這個標志只有當運行一個16位的Windows應用程序時才是有效的。如果WIN.INI中的Windows段的DefaultSeparateVDM選項被設置為真,這個標識使得CreateProcess函數越過這個選項並在共享的虛擬DOS機中運行新進程。值:CREATE_SUSPENDED含義:新進程的主線程會以暫停的狀態被創建,直到調用ResumeThread函數被調用時才運行。值:CREATE_UNICODE_ENVIRONMENT含義:如果被設置,由lpEnvironment參數指定的環境塊使用Unicode字符,如果為空,環境塊使用ANSI字符。值:DEBUG_PROCESS含義:如果這個標志被設置,調用進程將被當作一個調試程序,並且新進程會被當作被調試的進程。系統把被調試程序發生的所有調試事件通知給調試器。如果你使用這個標志創建進程,只有調用進程(調用CreateProcess函數的進程)可以調用WaitForDebugEvent函數。值:DEBUG_ONLY_THIS_PROCESS含義:如果此標志沒有被設置且調用進程正在被調試,新進程將成為調試調用進程的調試器的另一個調試對象。如果調用進程沒有被調試,有關調試的行為就不會產生。值:DETACHED_PROCESS含義:對於控制台進程,新進程沒有訪問父進程控制台的權限。新進程可以通過AllocConsole函數自己創建一個新的控制台。這個標志不可以與CREATE_NEW_CONSOLE標志一起使用。 dwCreationFlags參數還用來控制新進程的優先類,優先類用來決定此進程的線程調度的優先級。如果下面的優先級類標志都沒有被指定,那么默認的優先類是NORMAL_PRIORITY_CLASS,除非被創建的進程是IDLE_PRIORITY_CLASS。在這種情況下子進程的默認優先類是IDLE_PRIORITY_CLASS可以下面的標志中的一個:優先級:HIGH_PRIORITY_CLASS        含義:指示這個進程將執行時間臨界的任務,所以它必須被立即運行以保證正確。這個優先級的程序優先於正常優先級或空閑優先級的程序。一個例子是Windows任務列表,為了保證當用戶調用時可以立刻響應,放棄了對系統負荷的考慮。確保在使用高優先級時應該足夠謹慎,因為一個高優先級的CPU關聯應用程序可以占用幾乎全部的CPU可用時間。優先級:IDLE_PRIORITY_CLASS        含義:指示這個進程的線程只有在系統空閑時才會運行並且可以被任何高優先級的任務打斷。例如屏幕保護程序。空閑優先級會被子進程繼承。優先級:NORMAL_PRIORITY_CLASS        含義:指示這個進程沒有特殊的任務調度要求。優先級:REALTIME_PRIORITY_CLASS        含義:指示這個進程擁有可用的最高優先級。一個擁有實時優先級的進程的線程可以打斷所有其他進程線程的執行,包括正在執行重要任務的系統進程。例如,一個執行時間稍長一點的實時進程可能導致磁盤緩存不足或鼠標反映遲鈍。 lpEnvironment

指向一個新進程的環境塊。如果此參數為空,新進程使用調用進程的環境。  一個環境塊存在於一個由以NULL結尾的字符串組成的塊中,這個塊也是以NULL結尾的。每個字符串都是name=value的形式。     因為相等標志被當作分隔符,所以它不能被環境變量當作變量名。與其使用應用程序提供的環境塊,不如直接把這個參數設為空,系統驅動器上的當前目錄信息不會被自動傳遞給新創建的進程。對於這個情況的探討和如何處理,請參見注釋一節。      環境塊可以包含UnicodeANSI字符。如果lpEnvironment指向的環境塊包含Unicode字符,那么dwCreationFlags字段的CREATE_UNICODE_ENVIRONMENT標志將被設置。如果塊包含ANSI字符,該標志將被清空。      請注意一個ANSI環境塊是由兩個零字節結束的:一個是字符串的結尾,另一個用來結束這個快。一個Unicode環境塊石油四個零字節結束的:兩個代表字符串結束,另兩個用來結束塊。

lpCurrentDirectory

指向一個以NULL結尾的字符串,這個字符串用來指定子進程的工作路徑。這個字符串必須是一個包含驅動器名的絕對路徑。如果這個參數為空,新進程將使用與調用進程相同的驅動器和目錄。這個選項是一個需要啟動啟動應用程序並指定它們的驅動器和工作目錄的外殼程序的主要條件。

lpStartupInfo

指向一個用於決定新進程的主窗體如何顯示的STARTUPINFO結構體。

lpProcessInformation

指向一個用來接收新進程的識別信息的PROCESS_INFORMATION結構體。

返回值:如果函數執行成功,返回非零值。如果函數執行失敗,返回零,可以使用GetLastError函數獲得錯誤的附加信息。

4.注釋:    CreateProcess函數用來運行一個新程序。WinExecLoadModule函數依舊可用,但是它們同樣通過調用CreateProcess函數實現。

    另外CreateProcess函數除了創建一個進程,還創建一個線程對象。這個線程將連同一個已初始化了的堆棧一起被創建,堆棧的大小由可執行文件的文件頭中的描述決定。線程由文件頭處開始執行。

新進程和新線程的句柄被以全局訪問權限創建。對於這兩個句柄中的任一個,如果沒有安全描述符,那么這個句柄就可以在任何需要句柄類型作為參數的函數中被使用。當提供安全描述符時,在接下來的時候當句柄被使用時,總是會先進行訪問權限的檢查,如果訪問權限檢查拒絕訪問,請求的進程將不能使用這個句柄訪問這個進程。

這個進程會被分配給一個32位的進程標識符。直到進程中止這個標識符都是有效的。它可以被用來標識這個進程,或在OpenProcess函數中被指定以打開這個進程的句柄。進程中被初始化了的線程一樣會被分配一個32位的線程標識符。這個標識符直到縣城中止都是有效的且可以用來在系統中唯一標識這個線程。這些標識符在PROCESS_INFORMATION結構體中返回。

當在lpApplicationNamelpCommandLine參數中指定應用程序名時,應用程序名中是否包含擴展名都不會影響運行,只有一種情況例外:一個以.com為擴展名的MS-DOS程序或Windows程序必須包含.com擴展名。

 調用進程可以通過WaitForInputIdle函數來等待新進程完成它的初始化並等待用戶輸入。這對於父進程和子進程之間的同步是極其有用的,因為CreateProcess函數不會等待新進程完成它的初始化工作。舉例來說,在試圖與新進程關聯的窗口之前,進程應該先調用WaitForInputIdle

首選的結束一個進程的方式是調用ExitProcess函數,因為這個函數通知這個進程的所有動態鏈接庫(DLLs)程序已進入結束狀態。其他的結束進程的方法不會通知關聯的動態鏈接庫。注意當一個進程調用ExitProcess時,這個進程的其他縣城沒有機會運行其他任何代碼(包括關聯動態鏈接庫的終止代碼)。

 ExitProcess, ExitThread, CreateThread, CreateRemoteThread,當一個進程啟動時(調用了CreateProcess的結果)是在進程中序列化進行的。在一段地址空間中,同一時間內這些事件中只有一個可以發生。這意味着下面的限制將保留:

  *在進程啟動和DLL初始化階段,新的線程可以被創建,但是直到進程的DLL初始化完成前它們都不能開始運行。      *DLL初始化或卸下例程中進程中只能有一個線程。      *直到所有的線程都完成DLL初始化或卸下后,ExitProcess函數才返回。

在進程中的所有線程都終止且進程所有的句柄和它們的線程被通過調用CloseHandle函數終止前,進程會留在系統中。進程和主線程的句柄都必須通過調用CloseHandle函數關閉。如果不再需要這些句柄,最好在創建進程后立刻關閉它們。

當進程中最后一個線程終止時,下列的事件發生:   *所有由進程打開的對象都會關閉。   *進程的終止狀態(由GetExitCodeProcess函數返回)從它的初始值STILL_ACTIVE變為最后一個結束的線程的結束狀態。   *主線程的線程對象被設置為標志狀態,供其他等待這個對象的線程使用。   *進程對象被設置為標志狀態,供其他等待這個對象的線程使用。

假設當前在C盤上的目錄是\MSVC\MFC且有一個環境變量叫做C:,它的值是C:\MSVC\MFC,就像前面lpEnvironment中提到過的那樣,這樣的系統驅動器上的目錄信息在CreateProcess函數的lpEnvironment參數不為空時不會被自動傳遞到新進程里。一個應用程序必須手動地把當前目錄信息傳遞到新的進程中。為了這樣做,應用程序必須直接創建環境字符串,並把它們按字母順序排列(因為Windows NTWindows 95使用一種簡略的環境變量),並把它們放進lpEnvironment中指定的環境塊中。類似的,他們要找到環境塊的開頭,又要重復一次前面提到的環境塊的排序。

一種獲得驅動器X的當前目錄變量的方法是調用GetFullPathName("x:",..)。這避免了一個應用程序必須去掃描環境塊。如果返回的絕對路徑是X:\,就不需要把這個值當作一個環境數據去傳遞了,因為根目錄是驅動器X上的新進程的默認當前目錄。

CreateProcess函數返回的句柄對於進程對象具有PROCESS_ALL_ACCESS的訪問權限.

lpcurrentDirectory參數指定的當前目錄室子進程對象的當前目錄。lpCommandLine參數指定的第二個項目是父進程的當前目錄。

5.使用示例:

char chPath[301];

   ::GetCurrentDirectory(300,(LPTSTR)chPath);//得到當前目錄

   char path[200]= "\\123.exe";

   strcat(chPath,path);

STARTUPINFO si;

PROCESS_INFORMATION pi;

ZeroMemory( &pi, sizeof(pi) );

ZeroMemory( &si, sizeof(si) );

si.cb = sizeof(si);

// Start the child process

 if(CreateProcess(chPath, "", NULL, NULL, FALSE, 0, NULL, NULL, &si, &pi))

 {

  CloseHandle( pi.hProcess );

  CloseHandle( pi.hThread );

}

 else 

 {

    AfxMessageBox(“創建失敗!”);

    HANDLE hProcess = GetCurrentProcess();//get current process

    TerminateProcess(hProcess,0);         //close process

 }

 

 

轉:http://blog.csdn.net/kevin_samuel/article/details/8159200

MFC 窗口重繪

 

在刷新窗口時經常要調用重繪函數 MFC提供了三個函數用於窗口重繪 InvalidateRect(&Rect) Invalidate() UpdateWindow() 當需要更新或者重繪窗口時,一般系統會發出兩個消息WM_PAINT(通知客戶區有變化)和WM_NCPAINT(通知非客戶區有變化) –WM_NVPAINT系統會自己搞定 –WM_PAINT消息對應的函數是OnPaint(),它是系統默認的接受WM_PAINT消息的函數,但我們一般在程序中做重繪時都在OnDraw函數中進行的,因為在ONPAIN函數中調用了ONDRAW函數。 ///CView默認的標准的重畫函數 void CView::OnPaint() { CPaintDC dc(this); OnPreparDC(&dc); OnDraw(&dc); //調用了OnDraw }

上面講到 InvalidateRect(&Rect) Invalidate()兩個函數形式和功能差不多,但Invalidate是使得整個窗口無效,形成無效矩形,而InvalidateRect(&Rect)是使得指定的區域無效。
Invalidate()申明無效,等待WM_PAINT消息以便重繪,隊列中無其他消息時系統會自動發送 UpdateWindow()會立即發送WM_PAINT,不過在它發送前,先調用GetUpdateRect(hWnd,NULL,TRUE)看有無可繪制區域,如果沒有則不發送消息RedrawWindow()RedrawWindow()則是具有Invalidate()和UpdateWindow()的雙特性。聲明窗口的狀態為無效,並立即更新窗口,立即調用WM_PAINT消息處理。
 
      系統為什么不在調用Invalidate時發送WM_PAINT消息呢?又為什么非要等應用消息隊列為空時才發送WM_PAINT消息呢?這是因為系統把在窗口中的繪制操作當作一種低優先級的操作,於是盡可能地推后做。不過這樣也有利於提高繪制的效率:兩個WM_PAINT消息之間通過InvalidateRect和InvaliateRgn使之失效的區域就會被累加起來,然后在一個WM_PAINT消息中一次得到 更新,不僅能避免多次重復地更新同一區域,也優化了應用的更新操作。像這種通過InvalidateRect和InvalidateRgn來使窗口區域無效,依賴於系統。在合適的時機發送WM_PAINT消息的機 制實際上是一種異步工作方式,也就是說,在無效化窗口區域和發送WM_PAINT消息之間是有延遲的;有時候這種延遲並不是我們希望的,這時我們當然可以在無效化窗口區域后利用SendMessage 發送一條WM_PAINT消息來強制立即重畫,但不如使用Windows GDI為我們提供的更方便和強大的函數:UpdateWindow和RedrawWindow。UpdateWindow會檢查窗口的Update Region,當其不為空時才發送WM_PAINT消息;RedrawWindow則給我們更多的控制:是否重畫非客戶區和背景,是否總是發送WM_PAINT消息而不管Update Region是否為空等。 BeginPaint和WM_PAINT消息緊密相關。試一試在WM_PAINT處理函數中不寫BeginPaint會怎樣?程序會像進入了一個死循環一樣達到驚人的CPU占用率,你會發現程序總在處理一個接 一個的WM_PAINT消息。這是因為在通常情況下,當應用收到WM_PAINT消息時,窗口的Update Region都是非空的(如果為空就不需要發送WM_PAINT消息了),BeginPaint的一個作用就是把該Update Region置為空,這樣如果不調用BeginPaint,窗口的Update Region就一直不為空,如前所述,系統就會一直發送WM_PAINT消息。
BeginPaint和WM_ERASEBKGND消息也有關系。當窗口的Update Region被標志為需要擦除背景時,BeginPaint會發送WM_ERASEBKGND消息來重畫背景,同時在其返回信息里有一個標志表明窗口背景是否被重畫過。當我們用InvalidateRect和InvalidateRgn來把指定區域加到Update Region中時,可以設置該區域是否需要被擦除背景,這樣下一個BeginPaint就知道是否需要發送WM_ERASEBKGND消息了。
 
另外要注意的一點是,BeginPaint只能在WM_PAINT處理函數中使用。
 
以下是Invalidate函數的作用::
void Invalidate( BOOL bErase = TRUE ); 該函數的作用是使整個窗口客戶區無效。窗口的客戶區無效意味着需要重繪,例如,如果一個被其它窗口遮住的窗口變成了前台窗口,那么原來被遮住的部分就是無效的,需要重繪。這時Windows會在應用程序的消息隊列中放置WM_PAINT消息。MFC為窗口類提供了WM_PAINT的消息處理函數OnPaint,OnPaint負責重繪窗口。視圖類有一些例外,在視圖類的OnPaint函數中調用了OnDraw函數,實際的重繪工作由OnDraw來完成。參數bErase為TRUE時,重繪區域內的背景將被擦除,否則,背景將保持不變。      和  UpdateWindow( )區別在於:UpdateWindow( )的作用是使窗口立即重繪。調用Invalidate等函數后窗口不會立即重繪,這是由於WM_PAINT消息的優先級很低,它需要等消息隊列中的其它消息發送完后才能被處理。調用UpdateWindow函數可使WM_PAINT被直接發送到目標窗口,從而導致窗口立即重繪.


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM