将一个EXE程序嵌入MFC运行

MFC 专栏收录该内容
83 篇文章 3 订阅

原文: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上的Windows(WOW)为进程的方式运行。

lpCommandLine

指向一个NULL结尾的、用来指定要运行的命令行。

 这个参数可以为空,那么函数将使用参数指定的字符串当作要运行的程序的命令行。

 如果lpApplicationName和lpCommandLine参数都不为空,那么lpApplicationName参数指定将要被运行的模块,lpCommandLine参数指定将被运行的模块的命令行。新运行的进程可以使用GetCommandLine函数获得整个命令行。C语言程序可以使用argc和argv参数。

如果lpApplicationName参数为空,那么这个字符串中的第一个被空格分隔的要素指定可执行模块名。如果文件名不包含扩展名,那么.exe将被假定为默认的扩展名。如果文件名以一个点(.)结尾且没有扩展名,或文件名中包含路径,.exe将不会被加到后面。如果文件名中不包含路径,Windows将按照如下顺序寻找这个可执行文件: 1.当前应用程序的目录。 2.父进程的目录。

3.Windows目录。可以使用GetWindowsDirectory函数获得这个目录。  4.列在PATH环境变量中的目录。      如果被创建的进程是一个以MS-DOS或16位Windows为基础的应用程序,lpCommandLine参数应该是一个以可执行文件的文件名作为第一个要素的绝对路径,因为这样做可以使32位Windows程序工作的很好,这样设置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+C或CTRL+BREAK信号到一组控制台进程。值:CREATE_SEPARATE_WOW_VDM含义:(只适用于Windows NT这个标志只有当运行一个16位的Windows应用程序时才是有效的。如果被设置,新进程将会在一个私有的虚拟DOS机(VDM)中运行。另外,默认情况下所有的16位Windows应用程序都会在同一个共享的VDM中以线程的方式运行。单独运行一个16位程序的优点是一个应用程序的崩溃只会结束这一个VDM的运行;其他那些在不同VDM中运行的程序会继续正常的运行。同样的,在不同VDM中运行的16位Windows应用程序拥有不同的输入队列,这意味着如果一个程序暂时失去响应,在独立的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的形式。     因为相等标志被当作分隔符,所以它不能被环境变量当作变量名。与其使用应用程序提供的环境块,不如直接把这个参数设为空,系统驱动器上的当前目录信息不会被自动传递给新创建的进程。对于这个情况的探讨和如何处理,请参见注释一节。      环境块可以包含Unicode或ANSI字符。如果lpEnvironment指向的环境块包含Unicode字符,那么dwCreationFlags字段的CREATE_UNICODE_ENVIRONMENT标志将被设置。如果块包含ANSI字符,该标志将被清空。      请注意一个ANSI环境块是由两个零字节结束的:一个是字符串的结尾,另一个用来结束这个快。一个Unicode环境块石油四个零字节结束的:两个代表字符串结束,另两个用来结束块。

lpCurrentDirectory

指向一个以NULL结尾的字符串,这个字符串用来指定子进程的工作路径。这个字符串必须是一个包含驱动器名的绝对路径。如果这个参数为空,新进程将使用与调用进程相同的驱动器和目录。这个选项是一个需要启动启动应用程序并指定它们的驱动器和工作目录的外壳程序的主要条件。

lpStartupInfo

指向一个用于决定新进程的主窗体如何显示的STARTUPINFO结构体。

lpProcessInformation

指向一个用来接收新进程的识别信息的PROCESS_INFORMATION结构体。

返回值:如果函数执行成功,返回非零值。如果函数执行失败,返回零,可以使用GetLastError函数获得错误的附加信息。

4.注释:    CreateProcess函数用来运行一个新程序。WinExec和LoadModule函数依旧可用,但是它们同样通过调用CreateProcess函数实现。

    另外CreateProcess函数除了创建一个进程,还创建一个线程对象。这个线程将连同一个已初始化了的堆栈一起被创建,堆栈的大小由可执行文件的文件头中的描述决定。线程由文件头处开始执行。

新进程和新线程的句柄被以全局访问权限创建。对于这两个句柄中的任一个,如果没有安全描述符,那么这个句柄就可以在任何需要句柄类型作为参数的函数中被使用。当提供安全描述符时,在接下来的时候当句柄被使用时,总是会先进行访问权限的检查,如果访问权限检查拒绝访问,请求的进程将不能使用这个句柄访问这个进程。

这个进程会被分配给一个32位的进程标识符。直到进程中止这个标识符都是有效的。它可以被用来标识这个进程,或在OpenProcess函数中被指定以打开这个进程的句柄。进程中被初始化了的线程一样会被分配一个32位的线程标识符。这个标识符直到县城中止都是有效的且可以用来在系统中唯一标识这个线程。这些标识符在PROCESS_INFORMATION结构体中返回。

当在lpApplicationName或lpCommandLine参数中指定应用程序名时,应用程序名中是否包含扩展名都不会影响运行,只有一种情况例外:一个以.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 NT和Windows 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被直接发送到目标窗口,从而导致窗口立即重绘.

 

  • 0
    点赞
  • 0
    评论
  • 2
    收藏
  • 打赏
    打赏
  • 扫一扫,分享海报

参与评论 您还未登录,请先 登录 后发表或查看评论
©️2022 CSDN 皮肤主题:大白 设计师:CSDN官方博客 返回首页

打赏作者

bmjhappy

你的鼓励将是我创作的最大动力

¥2 ¥4 ¥6 ¥10 ¥20
输入1-500的整数
余额支付 (余额:-- )
扫码支付
扫码支付:¥2
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、C币套餐、付费专栏及课程。

余额充值