首页 > 代码库 > python socket-framework 1

python socket-framework 1

进程

1 进程的含义:

1.1   一个是操作系统用来管理进程的内核对象。内核对象也是系统用来存放关于进程的统计信息的地方。

1.2   另一个是地址空间,它包含所有可执行模块或DL L 模块的代码和数据。它还包含动态内存分配的空间。如线程堆栈和堆分配空间。

2 操作系统启动应用程序的步骤

2.1 调用C/c++运行时的启动函数

         启动函数总共4种,WinMainCRTStartup,wWinMainCRTStartup,mainCRTStartup,wmainCRTStartup。

         启动函数完成如下任务:

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

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

<3>对C/ C + +运行期的全局变量进行初始化。如果包含了S t d L i b . h 文件,代码就能访问这些变量

<4>对C运行期内存单元分配函数(m a l l o c 和c a l l o c )和其他低层输入/输出例程使用的内存栈进行初始化。

<5>为所有全局和静态C+ +类对象调用构造函数。

<6>调用入口点函数

如:int nMainRetVal = wmain(__argc, __wargv, _wenviron); 

<7>当进入点函数返回时,启动函数便调用C 运行期的ex i t 函数,将返回值(nMainRetVal )传递给它。

<8>调用由_onexit函数的调用而注册的任何函数

<9>为所有全局的和静态的C++类对象调用析构函数

<10>调用操作系统的ExitProcess函数,将nMainRetVal传递给它。这使得该操作系统能够撤消进程并设置它的e x i t 代码

 

3 进程的实例句柄

3.1 进程的当前实例句柄

         加载到进程地址空间的每个exe或者dll文件都会被赋予一个独一无二的句柄。

获取加载的模块(exe,dll)的方法:

GetModuleFileName(HMOUDLEhModule,LPTSTR lpFileName,DWROD nSize);

当hModule的值为NULL 的时候,会返回当前调用模块的全部路径名字。

3.2 进程的前一个实例句柄

         C++代码总是将NULL赋值给WinMain函数的第二个参数HINSTANCEhPreInstance,这样的原因是在16位的程序中对这个参数有保留使用,那么保留它就方便转用16位程序。

4 进程的命令行

LPTSTR GetCommandLine();获取命令行字符串

5  进程的环境变量

         每个进程都有一个与它相关的环境变量块,环境块是进程的地址空间中分配的一个内存块。每个环境块都包含一组字符串,形式如下所示:

VarName1=VarValue1\0

VarName2=VarValue2\0

VarName3=VarValue3\0

         其中要注意变脸等号前有没有空格,有空格和没空格代表的是完全不同的环境变量,如:

XYZ=xxx;和XYZ =xxx;这就是两个完全不同的环境变量了。

         操作华景变量相关的 函数

<1>

LPVOIDGetEnvironmentStrings(VOID);

<2>

BOOL SetEnvironmentVariable(
 LPCTSTR lpName,  // environment variable name
 LPCTSTR lpValue  // new value for variable);

<3>

DWORD GetEnvironmentVariable(  LPCTSTR lpName,  // environment variable name
 LPTSTR lpBuffer, // buffer for variable value
 DWORD nSize      // size ofbuffer);

<4>

BOOL FreeEnvironmentStrings(LPTSTRlpszEnvironmentBlock  // environmentstrings);

 

6 进程的当前目录

         程序的当前目录是可以进行改变的,当前目录和进程的启动目录是不同的,启动目录就是exe或者dll被调用的目录,我们可以通过GetModuleFineName函数进行处理。

<1>

DWORD GetCurrentDirectory(
 DWORD nBufferLength,    //size of directory buffer
 LPTSTR lpBuffer            //directory buffer);

<2>

BOOL SetCurrentDirectory(  LPCTSTR lpPathName   // new directory name);

7 系统的版本信息获得

GetVersion()

但是这个函数有bug,就是程序员把主版本号,次版本号放错了高低字节。

BOOL GetVersionEx(  LPOSVERSIONINFO lpVersionInfo // versioninformation);

这个是新的修正过来的。

8 创建进程

BOOL WINAPI CreateProcess(
  _In_opt_     LPCTSTR lpApplicationName,
  _Inout_opt_   LPTSTR lpCommandLine,
  _In_opt_     LPSECURITY_ATTRIBUTES lpProcessAttributes,
  _In_opt_     LPSECURITY_ATTRIBUTES lpThreadAttributes,
  _In_         BOOL bInheritHandles,
  _In_         DWORD dwCreationFlags,
  _In_opt_     LPVOID lpEnvironment,
  _In_opt_     LPCTSTR lpCurrentDirectory,
  _In_         LPSTARTUPINFO lpStartupInfo,
  _Out_        LPPROCESS_INFORMATION lpProcessInformation
);


参数解释:

<1> lpApplicationName

         被加载模块的名字,必须制定模块的格式,比如exe,因为系统不会默认为exe,模块的名字可以是部门名字,那么系统就会在当前目录去寻找该模块。

         通常将其设置为NULL,因为lpCommandLine具有比它更加强大的功能来完成模块的调用。

<2> lpCommandLine

         系统寻找可执行文件exe的顺序是:

应用程序加载的目录;

父进程的当前目录;

Windows System 目录;

Windows目录;

环境变量列出的目录;

注意:当字符集是Unicode时候,参数类型不能是const类型的,若是就会报错。

<3> lpProcessAttributes 

       指向 SECURITY_ATTRIBUTES的指针,决定进程创建函数返回的的新进程对象的句柄是否能被子进程继承。

         当为NULL的时候,获取的是默认安全描述符

<4> lpThreadAttributes

       指向SECURITY_ATTRIBUTES 的指针,决定进程创建函数范湖的新线程对象的句柄是否能被子进程继承。

         当为NULL的时候,获取的是默认安全描述符。

<5> bInheritHandles 

       如果为True,那么任何可以被继承的句柄都会别新创建的进程所继承。如果为FALSE,那么则不会被新进程继承。

<6>dwCreationFlags 

       新创建的进程的创建标志位设置,决定是父子进程调试信息的反馈,子进程窗口的产生等行为。

<7> lpEnvironment 

新进程中指向的环境块。如果该值为NULL,那么就表示新进程继承了父进程的环境块。

<8>lpCurrentDirectory 

指向新进程的当前目录的指针。如果为NULL,那么则就和调用进程(父进程)具有相同的当前目录。

<9> lpStartupInfo

       指向 STARTUPINFO or STARTUPINFOEX的指针。主要指定窗口的状态,外观,标准句柄。当Wi n d o w s 创建新进程时,它将使用该结构的有关成员。大多数应用程序将要求生成的应用程序仅仅使用默认值。至少应该将该结构中的所有成员初始化为零,然后将cb 成员设置为该结构的大小。

       当里面创建的句柄不在是用的使用,要通过CloseHandle来关闭。

<10> lpProcessInformation 

指向PROCESS_INFORMATION结构体的指针。

typedef struct _PROCESS_INFORMATION {
  HANDLE hProcess;
  HANDLE hThread;
  DWORD  dwProcessId;
  DWORD  dwThreadId;
} PROCESS_INFORMATION, *LPPROCESS_INFORMATION;


里面是用的句柄不在使用的时候,要通过CloseHandle函数来关闭。

       当进程内核对象创建后,系统赋予该对象一个独一无二的标识号,系统中的其他任何进程内核对象都不能使用这个相同的ID号。线程内核对象的情况也一样。当一个线程内核对象创建时,该对象被赋予一个独一无二的、系统范围的ID号。进程ID和线程ID共享相同的号码池。这意味着进程和线程不可能拥有相同的ID 。


9 创建进程的实例:

#include <Windows.h>
#include <iostream>
using namespace std;

void main()
{
    STARTUPINFO si;
    PROCESS_INFORMATION pi;

    ZeroMemory( &si, sizeof(si) );
    si.cb = sizeof(si);
    ZeroMemory( &pi, sizeof(pi) );

    // Start the child process. 
    if( !CreateProcess( NULL, // No module name (use command line). 
        TEXT("Notepad++"),	// Command line. 
        NULL,             // Process handle not inheritable. 
        NULL,             // Thread handle not inheritable. 
        FALSE,            // Set handle inheritance to FALSE. 
        0,                // No creation flags. 
        NULL,             // Use parent's environment block. 
        NULL,             // Use parent's starting directory. 
        &si,              // Pointer to STARTUPINFO structure.
        &pi )             // Pointer to PROCESS_INFORMATION structure.
    ) 
    {
        cout<<TEXT("CreateProcess failed.");
    }

    // Wait until child process exits.
    WaitForSingleObject( pi.hProcess, INFINITE );

    // Close process and thread handles. 
    CloseHandle( pi.hProcess );
    CloseHandle( pi.hThread );
}