应用程序的启动过程

转载 2013年12月03日 18:21:50

http://wenku.baidu.com/link?url=HDPsq1Rvo8biDQ4ZyYEzO3-Bn9fU2PWCvGtkFCKty9Y2_2BEfAleMhQ7M4B_cb11lQtfKGQXGeW0mkVDe_XSzqHL8sxxqcj6X5tU4aYOEiK

应用程序都会有一个入口函数,它在程序运行时才被调用。 因此,创建控制应用程序时,此入口函数将会是main。    int main(int argc,char* argv[]); 

操作系统实际上不是真调用main函数,而是去调用了C/C++运行期启动函数, 
此函数会初始化C/C++运行期库。因此,在程序中可以调用malloc和free之类函数。     如果,我们在控制台上省去了main函数,那么连接器将返回一个"unresolved external symbol"错误。 
    Win32程序启动过程,实际上是线程去调用一个CreateProcess函数的时候,系统会创建一个进程内核对象, 
其使用计数被初始化为1.此进程内核对象不是进程本身,仅仅是一个系统用来管理这个进程的小的数据结构。 
系统然后为新的进程创建一个虚拟地址空间,加载应用程序运行时所需要的代码和数据。     系统接着会为新进程创建一个主线程,这个主线程通过执行C/C++运行期启动代码开始运行,C/C++ 
运行期启动代码又会调用main函数。如果系统能成功创建新的进程和进程的主线程,CreateProcess函数会返回TRUE, 否则返回FALSE。 
     一般将创建进程称为父进程,被创建的进程称为子进程。系统在创建新的进程时会为新进程指定一个STARTUPINFO 
类型的变量,这个结构保护了父进程传递给子进程的一些显示信息。对图形界面应用程序来说,这些信息将影响新进程中 
主线程的主窗口显示:对控制台应用程序来说,如果有一个新的控制窗口被创建的话,这些信息将影响这个控制台窗口。 STARTUPINFO结构定义如下。        typedef struct{ 
              DWORD    cb;                // 本结构的长度,总是应该被设为 sizeof(STARTUPINFO) 
              LPSTR        lpReserved;   // 保留(Reserve)字段,即程序不使用这个参数               LPSTR        lpDesktop;    // 指定桌面名称 
              LPSTR        lpTitle;           // 控制台应用程序使用,指定控制台窗口标题 
              DWORD    dwX;              //                DWORD    dwY;              //               DWORD    dwXSize;                       DWORD    dwYSize; 
              DWORD    dwXCountChars;   // 控制台程序使用,指定控制台窗口的行数                DWORD    dwYCountChars; 
              DWORD    dwFillAttribute;      //控制台程序使用,指定控制台窗口的背景色 
              DWORD    dwFlags;           // 标志。它的值决定了STARTUPINFO结构中哪些成员的值是有效的。 
              WORD       wShowWindow;   // 窗口的显示方式               WORD       cbReserved2;               LPBYTE       lpReserved2; 












              HANDLE     hStdInput;       // 控制台程序使用,几个标准句柄               HANDLE     hStdOutput;               HANDLE     hStdError;         }STARTUPINFO, *LPSTARTUPINFO;          
   一个进程可以调用GetStartupInfo函数来取得父进程创建自己时使用的STARTUPINFO结构。    事实上,Windows系统就是通过调用这个函数来取得当前进程的创建信息,以便对新进程中主窗口的属性设置默认值。    函数定义如下。 
   VOID GetStrtupInfo(LPSTARTUPINFO lpStartupInfo);    // 取得当前进程被创建时指定的STARTUPINFO结构。 
    定义一个STARTUPINFO结构的对象以后,总要在使用此对象之前将对象的cb成员初始化为STARTUPINFO结构大小。     如下所示: 
    STARTUPINFO si = [ sizeof(si)];      //将cb成员初始化为sizeof(si),其他成员初始化为0 
    ::GetStrartupInfo(&si); 
     初始化cb成员这一步是必须的。因为随着WIndows版本的改变,API函数支持的结构体的成员有可能增加, 
     但又要兼容以前的版本,所以WIndows要通过结构体的大小来确定其成员的数目。       
    CreateProcess 函数 
    CreateProcess 函数创建一个新的进程和该进程的主线程。新的进程会在父进程的安全上下文中运行指定的可执行文件。     函数用法如下:     CreateProcess( 
          LPCSTR lpApplicationName,    // 可执行文件的名称 
          LPCSTR lpCommandLine,        // 指定了要传递执行模块的参数。 
          LPSECURITY_ATTRIBUTES lpProcessAttributes,   // 进程安全性,值为NULL的话表示使用默认的安全属性。 
          LPSECURITY_ATTRIBUTES lpThreadAttributes,    // 线程安全性,值为NULL的话表示使用默认的安全属性。 
          BOOL bInheritHandles,      // 指定了当前进程中的可继承句柄是否可被新进程继承。 
          DWORD dwCreationFlags,   // 指定了新进程的优先级以及其他创建标志           LPVOID lpCurrentDirectory, // 新进程使用的当前目录 
          LPSTARTUPINFO lpStartupInfo,    // 指定新进程中窗口的位置、大小和标准句柄等。 
          LPPROCESS_INFORMATION lpProcessInformation // [out] 返回新进程的标志信息,如ID号、句柄等     );      
    lpApplicationName 和 lpCommandLine参数指定了新的进程将要使用的可执行文件的名称和传递给新进程的参数。 












     例如,下面代码了Windows自带的记事本程序。            STARTUPINFO si = {sizdof(si)};            PROCESS_INFORMATION pi; 
           char* szCommandLine="notepad";   // 也可以是"notepad.exe" 
           ::CreateProcess(NULL,szCommandLine,NULL,NULL,FALSE,NULL,NULL,NULL,&si,&pi); 
     执行这段代码,Windows自带的记事本程序将被会被被打开。           lpCommandLine参数为新的进程指定了以一个完整命令行。 
      当CreateProcess函数复制此字符串的时候,它首先检查字符串中的第一个单词,病假设此单词是你想要运行的可执行 
      文件的名字。如果可执行文件名字中没有后缀,那么一个".exe"后缀将被添加进来。            CreateProcess函数会按照以下路径去搜索可执行文件:            (1)调用进程的可执行文件所在的目录。            (2)调用进程的当前目录。 
           (3)Windows的系统目录(System32目录)            (5)在名称为PATH的环境变量中列出的目录。             
    当然,如果文件名种包含了目录的话,系统会直接在这个目录中查找可执行文件,而不会去再去其他目录中搜索你了。 
    如果系统找到了指定的可执行文件。它会创建一个新的进程并将该执行中的代码和数据映射到新进程的地址空间。 
    之后系统会调用C/C++运行期启动函数,这个函数检查新检查新进程的命令行,将文件名后第一个参数的地址传给新进程     的入口函数。 
      若将上述代码的第3行修改成了下面这样下面这样,则会看到给记事本进程传递参数后的效果。 
         char* szCommandLine="notepad ReadMe.txt";   //指定了一个ReadMe.txt参数,将促使记事本打开此文件           
    再次运行程序,记事本进程打开后,还会试图打开父进程当前目录下的ReadMe.txt文件。     此时lpApplicationName参数为NULL,也可以再此参数中指定可执行文件的文件名。     注意必须为文件名指定后缀,系统不会自己假死文件名有一个".exe"后缀的。 如果文件名不包含目录, 
    系统仅仅假设此文件在调用进程的当前目录下。     所以最常用的做法是将作此参数设为NULL 
        dwCreationFlags 参数指定的标记会影响新的进程如何创建。         lpStartupInfo 参数是一个指向STARTUPINFO结构的指针。 
        lpProcessInformation 参数是一个指向PROCESS_INFORMATION 结构的指针。          
     CreateProcess函数在返回之前会初始化此结构的成员。      结构定义如下如下。         typedef struct{ 
             HANDLE hProcess,    //新建进程的内核句柄 
             HANDLE hThread:     // 新建进程中主线程的内核句柄 












             DWORD dwProcessId; // 新建进程的ID 
             DWORD dwThreadld;    // 新建进程的主线程ID      } PROCESS_INFORMATION, *LPPROCESS_INFORMATION;       
    创建一个新的进程将促使系统创建一个进程内核对象和一个线程内核对象。     在创建它们的时候,系统会将每个对象使用计数初始化为1. 
    然后CreateProcess返回之前,这个函数打开此进程内核对象和线程内核对象的句柄,并将它们的值传给上述结构的     hProcess和hThread成员。 
     CreateProcess在内部打开这些对象的时候,对象的使用计数将会增加到2。 
     因此,父进程中必须有一个线程调用调用CloseHandle关闭CreateProcess函数返回的两个内核对象的句柄。 
     否则即便是子进程已经终止了,该进程的进程内涵对象和主线程的内核对象仍然没有释放。      当一个进程创建一个内核对象时,会分配一个ID。但是ID是可以被重用的。 
     当 第一个进程死亡后,它的ID号可能分配第二个进程...但是两个进程是互不相同的。      
    #include "stdafx.h" #include <windows.h> #include <stdio.h>  
int main(int argc, char* argv[]) { 
char szCommandLine[] = "cmd"; STARTUPINFO si = { sizeof(si) }; PROCESS_INFORMATION pi; 
si.dwFlags = STARTF_USESHOWWINDOW; // 指定wShowWindow成员有效 
si.wShowWindow = TRUE;    // 此成员设为TRUE的话则显示新建进程的主窗口,        // 为FALSE的话则不显示 BOOL bRet = ::CreateProcess ( 
   NULL,    // 不在此指定可执行文件的文件名    szCommandLine,   // 命令行参数    NULL,    // 默认进程安全性    NULL,    // 默认线程安全性 
   FALSE,    // 指定当前进程内的句柄不可以被子进程继承    CREATE_NEW_CONSOLE, // 为新进程创建一个新的控制台窗口    NULL,    // 使用本进程的环境变量    NULL,    // 使用本进程的驱动器和目录    &si,    &pi); if(bRet) { 
   // 既然我们不使用两个句柄,最好是立刻将它们关闭 












   ::CloseHandle (pi.hThread);    ::CloseHandle (pi.hProcess); 
   printf(" 新进程的进程ID号:%d \n", pi.dwProcessId);    printf(" 新进程的主线程ID号:%d \n", pi.dwThreadId);  } 
return 0; } 
CreateProcess 函数的第6个参数被设为CREATE_NEW_CONSOLE,意思是创建一个新的控制台。 其在Winbase.h 中有如下定义。 
      #define CREATE_NEW_CONSOLE   0x00000010 这个标识告诉Windows为新的进程创建一个新的控制台。  如果不使用这个标识,则新建进程就同父进程公用一个控制台。 
      不要以为CREATE_NEW_CONSOLE 这样的宏名长,不容易记忆。 实事上就是因为它长,所以 
表达的意思才明确,比单单记忆几个数字容易多了。 
       可以指定新创建进程的主窗口是否显示,如果需要隐藏则将相应代码改下如下。        si.dwFlags = STARTF_USESHOWWINDOW;        si.wShowWindow = 0; 
   dwFlags 成员指定了要使用STARTUPINFO 结构中的哪一个成员。 
    比如令dwFlags = STARTF_USESIZE|STARTF_USESHOWWINDOW,则si的成员dwXSize 和 dwYSize 也会有效。 
    要使wShowWindow成员有效,dwFlags中必要保护STARTF_USESHOWWINDOW标记。         注意,Windows先通过dwFlags参数查看哪一个成员的值。如果还要用dwX,dwY成员来指定新窗口的显示坐标, 
     就必须将参数dwFlags设为。 
          si.dwFlags = STARTF_USESHOWWINDOW|STARTF_USEPOSITION; 

Android应用启动流程分析

版权声明:本文图文为博主原创,未经博主允许不得转载。 大家有没有好奇过点击 Launcher 图标时,到唤起一个应用页面,这个流程会是怎么样的?本文的目的就是尽可能梳理清楚流程,能够让大家对整个流程...
  • bfboys
  • bfboys
  • 2016年09月17日 19:13
  • 163

一个win32应用程序文件的启动过程

学习windows 编程从mfc角度来说可分为两部分那就是WinMain函数以前的,和WinMain函数以后的。前者涉及很多windows操作系统内部的知识,后者需要看mfc源码。虽然大多数程序不需要...
  • hczhiyue
  • hczhiyue
  • 2014年02月08日 19:17
  • 1326

嵌入式系统启动过程

++++++++++++++++++++++++++++++++++++++++++ 本文系本站原创,欢迎转载! 转载请注明出处: http://blog.csdn.net/mr_raptor/a...
  • sunheshan
  • sunheshan
  • 2014年09月11日 16:23
  • 2332

iOS 应用程序的启动过程

平时在使用iPhone手机的时候,我们打开一个应用程序,很简单,点击应用图标即可;然而很多人并不知道应用程序是怎么启动的! 那么从点击了应用程序到我们见到应用程序的主界面,这个过程中,发生了哪些...
  • tobyotenma
  • tobyotenma
  • 2016年05月06日 22:51
  • 402

Andorid App程序启动流程

Native进程的运行过程   一般程序的启动步骤,可以用下图描述。程序由内核加载分析,使用linker链接需要的共享库,然后从c运行库的入口开始执行。   通常,na...
  • mp624183768
  • mp624183768
  • 2017年02月10日 23:51
  • 149

iOS应用程序的启动过程

#import #import "AppDelegate.h" /** 应用程序启动过程 1. 执行main函数 2. 执行UIApplicationMain函数, 创...
  • yaoliangjun306
  • yaoliangjun306
  • 2016年11月26日 12:36
  • 142

Symbian应用程序的启动过程

考虑到Symbian作为一个商业的开放操作系统,它的UI框架结构和功能必须达到易用、强大和可靠的统一,不是简简单单完成人机交互而已。所以它的结构必须是经过精心设计的。因此,要想详细描述其内在的运行过程...
  • kafeiwuzhuren
  • kafeiwuzhuren
  • 2008年12月17日 12:53
  • 1052

Windows应用程序的启动过程

Windows应用程序的启动过程 操作系统实际上并不调用你编写的进入点函数。它调用的是C/C++ run-time startup function。该函数负责对C/C++ run-time libr...
  • laruence
  • laruence
  • 2006年11月06日 21:37
  • 1345

C++应用程序的启动过程

一个C++应用程序的启动过程:  其实是系统调用CRT,然后CRT调用的WinMain. a.shell调用CreateProcess激活App.exe b.系统产生一个进程内核对象,使用...
  • LaoWu_
  • LaoWu_
  • 2010年01月05日 12:42
  • 538

Android应用程序进程启动过程(前篇)

在此前我讲过Android系统的启动流程,系统启动后,我们就比较关心应用程序是如何启动的,这一篇我们来一起学习Android7.0 应用程序进程启动过程,需要注意的是“应用程序进程启动过程”,而不是应...
  • itachi85
  • itachi85
  • 2017年03月20日 11:06
  • 2937
内容举报
返回顶部
收藏助手
不良信息举报
您举报文章:应用程序的启动过程
举报原因:
原因补充:

(最多只允许输入30个字)