volcanol的工控博客
Email : lilinly225@126.com 索要资料加QQ 点击进入 或 点击左侧的资料分享专用帖

volcanol ---- View OF Linux Can Appreciate Nature OF Linux

天行健,君子以自强不息

  博客园 :: 首页 :: 博问 :: 闪存 :: 新随笔 :: 联系 :: 订阅 订阅 :: 管理 ::

        哈哈, 今天看书看到了内核对象的进程一章,原来以为进程会很难,结果发现如果用心学习的话

其实也不是很难。嘻嘻我指的不难是入门不难,但是要是要完全掌握甚至精通的话还是相当的有难度的,光

那些什么内核对象的继承特性和什么内核对象句柄表就够让人头疼疼了。

下面我们弄一段娱乐代码来看看如何操作进程:

// 01FirstAPP.cpp : Defines the entry point for the console application.
//

#include
"stdafx.h"
#include
<windows.h>
#include
<stdio.h>
#include
<string.h>


STARTUPINFO startupinfo;
//extern unsigned int _winver;

int main(int argc, char* argv[])
{
int iSelect;

iSelect
=::MessageBox(NULL,"Hello world!","Wellcome",MB_OKCANCEL);

if(IDOK==iSelect)
printf(
"You have select OK\n");
else
printf(
"You have select cancel\n");

startupinfo.cb
=sizeof(STARTUPINFO);
//::GetStartupInfo(&startupinfo);

PROCESS_INFORMATION pi;

/*
char lpCurrentDirectory[100];
GetCurrentDirectory(100,lpCurrentDirectory);
if(strlen(lpCurrentDirectory)< (100-10) )
strcat(lpCurrentDirectory,"01FirstAPP");
*/

//这里可以用GetCommandline来获取应用程序的路径
char *szCommandLine="01FirstAPP.exe";
startupinfo.wShowWindow
=SW_SHOWMINNOACTIVE;
//在调用windows API函数时需要弄明白MSDN中那些 IN 和 OUT 的意义。表示的意义
::CreateProcess(NULL,szCommandLine,NULL,NULL,FALSE,NULL,NULL,NULL,&startupinfo,&pi);

// UINT Exit_hAndle;
if(IDOK==MessageBox(NULL,"You want exit notepad ?","Ask for information",MB_OKCANCEL))
TerminateProcess(pi.hProcess,
0);
else
CloseHandle(pi.hProcess);


char *pcmdline=::GetCommandLine();
puts(pcmdline);

//获取应用程序的当前工作路径
char pdir[100];
::GetCurrentDirectory(
100,pdir);

puts(pdir);


//获取操作系统的版本号
//高字节返回系统的
printf("%d\n",::GetVersion());

printf(
"%8X\n",::GetVersion());

//通过扩展函数获取系统版本号
OSVERSIONINFO osversioninfo;
osversioninfo.dwOSVersionInfoSize
=sizeof OSVERSIONINFO;
::GetVersionEx(
&osversioninfo);
printf(
"os major version is %ld\n",osversioninfo.dwMajorVersion);

printf(
"%p",GetModuleHandle(NULL)); //输出应用程序进程加载到内存空间是的基址。 这个值在GUI中是程序的hInstance句柄。


// printf("%d",_winver);
printf("\nHello World!\n");

getc(stdin);
return 0;
}

      我学C语言一直以来有个疑问,既然非main函数需要通过main函数直接或者间接的来调用,

而main也是一个函数? 那么在应用程序启动的时候main函数是否也要被调用呢? 如果需要那么是

一个怎么样的机制呢? 如果不需要那么是否和函数需要被调用有点矛盾呢?这个问题从2006年春天

接触C语言以来就一直困扰着我,终于今天我明白了,main函数也需要被调用。

1、启动函数

    win下编译程序的时候并不决定C程序将如何执行,而是在链接的过程中决定C程序如何开始执行。

我们知道在win下主要定义了4个入口点函数, 就是通常说的entry point。

他们分别是:

      控制台应用程序(CUI):       mian   和        wmain

      窗口应用程序(GUI):  WinMain   和   wWinMain  (嘻嘻, 原型就不写了)

我们知道在编译完成后会生成obj文件(记得好像应该是COFF格式的,好像谭的书上说过,

这个应该没错), 然后通过链接程序LINK 上系统库文件最终生成exe或者其他PE格式的可执行

文件。 在链接的过程,以前我就知道会连接printf这样的库函数,不知道在这个阶段会做一些与

函数启动执行相关的事情。

      当应用程序被链接的时候,会被嵌入可执行的启动函数到要生成的可执行文件, 在win下有4个

启动函数:

控制台两个:          mainCRTStartup  和     wmainCRTStartup

窗口应用程序:       WinMainCRTStartup  和wWinMainCRTStartup

这两组启动函数可以通过链接程序开关来指定,也可以在IDE环境进行指定。

cmd形式需要指定:

     /SUBSYSTEM:WINDOWS 开关指定链接 WinMainCRTStartup  和wWinMainCRTStartup

     /SUBSYSTEM:CONSOLE开关指定链接 mainCRTStartup  和     wmainCRTStartup

(注: 带前缀w和不带w区别编译ANSI兼容和Unicode兼容代码,w表示支持宽字符语言)

2、启动函数的作用

    1、检索指向新进程的完整的命令行指针

    2、检索指向新进程环境变量的指针

    3、对C运行期的全局变量进行初始化

    4、初始化内存单元分配函数和其他低层输入输出函数使用的栈

    5、为应用程序的全局对象分配内存空间

当完成这些工作后就会以大体下面的形式来调用入口点函数:

     GetStartupInfo(&startupinfo);     //startupinfo 为一个STARTUPINFO结构体

     int nMainRetVal=main(__argc,__argv,_environ);

这与我们的

      int  main(int argc, char **argv)的原型基本相似, 只不过在win下main函数可以需要一个

_environ环境变量参数, _environ不是从命令行串口输入的,而是系统检测的。

    

      当main函数或者winmain函数返回时,通常用return  0;或者  return msg.wParam;

启动函数会利用就调用C运行期函数exit,将返回值nMainRetVal传递给exit函数,就像下面这

样:

       GetStartupInfo(&startupinfo);     //startupinfo 为一个STARTUPINFO结构体

       int nMainRetVal=main(__argc,__argv,_environ);

      /*

     **  main函数代码或其直接、间接调用的代码

     */

       exit(nMainRetVal);

3、进程的建立

      如果在windows资源管理器里面启动一个应用程序,这个过程其实就涉及到了进程的建立过程。

 Explorer.exe 通过调用下面类似的代码来启动应用程序:

char *szCommandLine="01FirstAPP.exe";
startupinfo.wShowWindow
=SW_SHOWMINNOACTIVE;
//在调用windows API函数时需要弄明白MSDN中那些 IN 和 OUT 的意义。表示的意义
::CreateProcess(NULL,szCommandLine,NULL,NULL,FALSE,NULL,NULL,NULL,&startupinfo,&pi);

主要是CreateProcess函数来创建进程,至于这个函数的用法,这里就不多说了,当然为了防止

资源管理器的内存泄露,可能在资源管理器进程里面会调用:

CloseHandle(pi.hProcess); 

通过上面的函数来是内核对象引用计数进行减1操作, 当内核对象的引用计数==0 的时候操作系统就会

回收内核对象占用的系统资源。嘻嘻,进程也是一种内核对象,很神奇吧,内核对象根本不是很神秘,在

taskmgr中就可以看到内核对象。

    至于其他的关于进程的信息,还是慢慢看书吧,还是挺有意思的..............

4、 如何防止应用程序启动两个应用实例

      在VB中可以通过APP全局对象来实现这个功能,在Delphi中也可以通过application全局对象来

实现这个功能,而在C语言中,因为WinMain函数接收的第二参数hPrevInstance参数总是NULL,就需要

利用其他方法来实现这个功能,可以通过创建一个系统可见的内核对象来实现这个功能。

例如可以利用互斥对象实现,也可以通过内存映射文件实现。

      具体代码就不写了,反正大家都会...............

      嘻嘻嘻.............

      

   

      

posted on 2011-09-09 22:56  volcanol  阅读(1720)  评论(1编辑  收藏  举报
volcanol ----View OF Linux Can Appreciate Nature OF Linux。