# 操作系统实验一

# 前情提要:

其实这篇文章并不会完全告诉你操作系统实验一的全部答案,只会记录一些该实验的坑爹点

如果你的实验一开头和下面这段文字一样,那么,强烈建议你看看这篇文章,最重要的一点,不要一开始点击 1-1.cpp 的编译运行,如果你点了。。。那我会为你默哀一秒钟,然后你可以重启电脑了

好了,说了这么多废话,先看看实验一的开头:

1. 背景知识

Windows 所创建的每个进程都从调用 CreateProcess () API 函数开始,该函数的任务是在对象管理器子系统内初始化进程对象。每一进程都以调用 ExitProcess () 或 TerminateProcess () API 函数终止。通常应用程序的框架负责调用 ExitProcess () 函数,对于 C++ 运行库来说,这一调用发生在应用程序的 main () 函数返回之后。

1. 创建进程

CreateProcess () 调用的核心参数是可执行文件运行时的文件名及其命令行。表 1-1 详细地列出了每个参数的类型和名称。

表 1-1 实验记录表

参数名称使用目的
LPCTSTR lpApplivationNAME全部或部分地指明包括可执行代码的 EXE 文件的文件名
LPCTSTR lpCommandLine向可执行文件发送的参数
LPSECURIITY_ATTRIBUTESlpProcessAttributes返回进程句柄的安全属性,主要指明这一句柄是否应该由其他子进程所继承。
LPSECURIITY_ATTRIBUTESlpThreadAttributes返回进程的主线程的句柄的安全属性
BOOL bInheritHandle一种标志,告诉系统允许新进程继承创建者进程的句柄
DWORD dwCreationFlage特殊的创建标志(如 CREATE_SUSPENDED)的位标记
LPVOID lpEnvironment向新进程发送的一套环境变量;如为 null 值则发送调用者环境
LPCTSTR lpCurrentDirectory新进程的启动目录
STARTUPINFO lpStartupInfoSTARTUPINFO 结构,包括新进程的输入和输出配置的详情
LPPROCESS_INFORMATION lpProcessInformation调用的结果块;发送新应用程序的进程和主线程的句柄和 ID

OK,假如到这里都是一模一样的,那么接着往下看吧,如果没有,慢走不送

# 一、执行如下指令 C:\ CL 1-1.cpp,给出运行结果,并进行分析

看起来是不是很简单,只要在命令行里输入上面的句子就结束了,那我只能说你太天真了。

cl 指令是 VS(全名 Visual Studio)才包含的,也就是如果你的电脑上没有下 VS,那么这个问题你没法做

# 1、第一步,下载 VS,找到 cl.exe 所在文件夹

在安装 VS 时,你需要选择安装有关 C/C++ 开发有关的库才可以

笔者本人的 cl.exe F:\dev C\VS\VC\Tools\MSVC\14.37.32822\bin\Hostx64\x64

将这个目录添加到你系统变量的 Path 中,然后你打开 cmd 可以尝试一下输入以下命令:

C:\Users\asus>cl

如果出现了以下界面:

运行结果

那么证明你的 cl.exe 已经放入系统路径中了

# 2、第二步,将你的系统中的一些库添加到系统变量中

记住,是添加到系统变量中,而不是系统变量的 Path

新建变量 Lib:

添加路径包含:C:\Program Files (x86)\Windows Kits\10\Lib\10.0.22621.0\ucrt\x64

C:\Program Files (x86)\Windows Kits\10\Lib\10.0.22621.0\ucrt_enclave\x64

C:\Program Files (x86)\Windows Kits\10\Lib\10.0.22621.0\um\x64

F:\dev C\VS\VC\Tools\MSVC\14.37.32822\lib\x64

新建变量 Include:

添加路径包含:F:\dev C\VS\VC\Tools\MSVC\14.37.32822\include

C:\Program Files (x86)\Windows Kits\10\Include\10.0.22621.0\cppwinrt

C:\Program Files (x86)\Windows Kits\10\Include\10.0.22621.0\shared

C:\Program Files (x86)\Windows Kits\10\Include\10.0.22621.0\ucrt

C:\Program Files (x86)\Windows Kits\10\Include\10.0.22621.0\um

C:\Program Files (x86)\Windows Kits\10\Include\10.0.22621.0\winrt

# 3、第三步,如果你再次运行 CL 1-1.cpp 后出现了问题

问题描述大概就是找不到 mspdbcore.dll 文件,那么按照一下步骤解决

进入文件夹 F:\dev C\VS\Common7\IDE

将四个文件复制 msobj140.dllmspdb140.dllmspdbcore.dllmspdbsrv.exe

到文件夹 F:\dev C\VS\VC\Tools\MSVC\14.37.32822\bin\Hostx64\x64 中,选择覆盖文件

# 4、第四步,正常运行,不出意外的话可以得到以下结果:

运行结果

到这里第一问才完整解决,那么剩下的问题我不会记录答案,下面会记录 1-1.cpp 的完整代码,如果你的和下面不一样,说明你的代码可能有 bug

// proccreate项目
#include <windows.h>
#include <iostream>
#include <stdio.h>

// 创建传递过来的进程的克隆过程并赋于其ID值
void StartClone(int nCloneID)
{
    // 提取用于当前可执行文件的文件名
    TCHAR szFilename[MAX_PATH] ;
    :: GetModuleFileName(NULL, szFilename, MAX_PATH) ;

    // 格式化用于子进程的命令行并通知其EXE文件名和克隆ID
    TCHAR szCmdLine[MAX_PATH];
	:: sprintf(szCmdLine,"\"%s\" %d",szFilename,nCloneID);

	// 用于子进程的STARTUPINFO结构
    STARTUPINFO si;
    :: ZeroMemory(reinterpret_cast <void*> (&si) , sizeof(si) ) ;
    si.cb = sizeof(si) ;				// 必须是本结构的大小

    // 返回的用于子进程的进程信息
    PROCESS_INFORMATION pi;

    // 利用同样的可执行文件和命令行创建进程,并赋于其子进程的性质
    BOOL bCreateOK=::CreateProcess(
        szFilename,					// 产生这个EXE的应用程序的名称
        szCmdLine,					// 告诉其行为像一个子进程的标志
        NULL,						// 缺省的进程安全性
        NULL,						// 缺省的线程安全性
        FALSE,						// 不继承句柄
        CREATE_NEW_CONSOLE,			// 使用新的控制台
        NULL,						// 新的环境
        NULL,						// 当前目录
        &si,						// 启动信息
        &pi) ;						// 返回的进程信息

    // 对子进程释放引用
    if (bCreateOK)
    {
        :: CloseHandle(pi.hProcess) ;
        :: CloseHandle(pi.hThread) ;
    }
    return;
}

int main(int argc, char* argv[] )
{
    // 确定进程在列表中的位置
    int nClone(0) ; // 等价于 int nClone = 0 
    if (argc > 1)
    {
        // 从第二个参数中提取克隆ID
        :: sscanf(argv[1] , "%d" , &nClone) ;
    }

    // 显示进程位置
    std :: cout << "Process ID:" << :: GetCurrentProcessId()
                << ", Clone ID:" << nClone
                << std :: endl;

    // 检查是否有创建子进程的需要
    const int c_nCloneMax=25;
    if (nClone < c_nCloneMax)
    {	
        // 发送新进程的命令行和克隆号
        StartClone(++nClone) ;
    }
    // 在终止之前暂停一下 (l/2秒)
    :: Sleep(500) ;

    return 0;
}