应用程序的启动过程

转载 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应用程序启动过程源代码分析(2)

Step 9. ActivityStack.startActivityUncheckedLocked         这个函数定义在frameworks/base/services/java/com...

Android 应用程序启动过程分析 (用SysTrace 跟踪分析)

Android 应用程序启动过程分析 Sep 21, 2015 13 minute read 学习并分享 Android 应用启动过程 => 为什么要写这篇文章? 梳理总结 前一段时间...

Android深入四大组件(一)应用程序启动过程

在此前的文章中,我讲过了Android系统启动流程和Android应用进程启动过程,这一篇顺理成章来学习Android 7.0的应用程序的启动过程。分析应用程序的启动过程其实就是分析根Activity...

Android系统默认Home应用程序(Launcher)的启动过程源代码分析

在前面一篇文章中,我们分析了Android系统在启动时安装应用程序的过程,这些应用程序安装好之后,还需要有一个Home应用程序来负责把它们在桌面上展示出来,在Android系统中,这个默认的Home应...
  • sdvch
  • sdvch
  • 2013年12月27日 00:04
  • 941

The Swift Code之应用程序的启动过程

The Swift Code主要是通过编写代码来完成应用程序的实现,使我们更能够深入的了解其编程语言实现的原理.也能够辅助更快的使用XCODE开发应用程序. 这篇文章主要是讲解启动应用程序从代码入口...
  • tenyit
  • tenyit
  • 2015年04月02日 16:03
  • 370

iPhone应用程序的启动过程

博主:易飞扬 原文链接 : http://www.yifeiyang.net/iphone-developer-advanced-3-iphone-application-startup-proce...
  • chun799
  • chun799
  • 2011年10月08日 11:36
  • 815

源码分析之应用程序启动过程

整个应用程序的启动过程要执行很多步骤,但是整体来看,主要分为以下五个阶段: 1、Step1 - Step11:Launcher通过Binder进程间通信机制通知ActivityManag...

Android应用程序的Activity启动过程简要介绍

转自: http://blog.csdn.net/luoshengyang/article/details/6685853 在Android系统中,Activity和Service是应用程序的核心...
  • MyArrow
  • MyArrow
  • 2011年11月30日 12:48
  • 2246

Android应用程序启动过程——Launcher源码分析

当我们在Launcher界面单击一个应用程序图标时就会启动一个程序
  • kinbos
  • kinbos
  • 2014年05月09日 14:15
  • 902

老罗的android之旅-----Android应用程序启动过程源代码分析

源地址:http://blog.csdn.net/luoshengyang/article/details/6689748 前文简要介绍了Android应用程序的Activity的启动过程。在A...
内容举报
返回顶部
收藏助手
不良信息举报
您举报文章:应用程序的启动过程
举报原因:
原因补充:

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