STARTUPINFO结构体

本文深入探讨了STARTUPINFO结构在Windows系统中创建和管理进程时的作用,包括其成员变量的用途、如何初始化以及如何在创建进程时使用。详细解释了dwFlags标志的使用和STARTF_USESTDHANDLES成员的功能,提供了创建应用时窗口显示和位置调整的指导,以及获取父进程初始化的STARTUPINFO结构的方法。
typedef struct _STARTUPINFO
{
    DWORD cb;            //包含STARTUPINFO结构中的字节数.如果Microsoft将来扩展该结构,它可用作版本控制手段.应用程序必须将cb初始化为sizeof ( STARTUPINFO )
    PSTR lpReserved;      //保留。必须初始化为N U L L
    PSTR lpDesktop;    //用于标识启动应用程序所在的桌面的名字。如果该桌面存在,新进程便与指定的桌面相关联。如果桌面不存在,便创建一个带有默认属性的桌面,并使用为新进程指定的名字。    如果lpDesktop是NULL(这是最常见的情况 ),那么该进程将与当前桌面相关联
    PSTR lpTitle;    //用于设定控制台窗口的名称。如果l p Ti t l e 是N U L L ,则可执行文件的名字将用作窗口名
    DWORD dwX;       //用于设定应用程序窗口在屏幕上应该放置的位置的x 和y 坐标(以像素为单位)。
    DWORD dwY;       //只有当子进程用CW_USEDEFAULT作为CreateWindow的x参数来创建它的第一个重叠窗口时,    才使用这两个坐标。若是创建控制台窗口的应用程序,这些成员用于指明控制台窗口的左上角

    DWORD dwXSize;  //用于设定应用程序窗口的宽度和长度(以像素为单位)只有dwYsize
    DWORD dwYSize;  // 当子进程将CW_USEDEFAULT 用作CreateWindow 的nWidth参数来创建它的第一个重叠窗口时,才使用这些值。若是创建控制台窗口的应用程序,这些成员将用于指明控制台窗口的宽度
    DWORD dwXCountChars;  //用于设定子应用程序的控制台窗口的宽度和高度(以字符为单位)
    DWORD dwYCountChars;
    DWORD dwFillAttribute;   //用于设定子应用程序的控制台窗口使用的文本和背景颜色
    DWORD dwFlags;           //请参见下一段和表4 - 7 的说明
    WORD wShowWindow;        //用于设定如果子应用程序初次调用的ShowWindow 将SW_SHOWDEFAULT 作为    nCmdShow 参数传递时,该应用程序的第一个重叠窗口应该如何出现。本成员可以是通常用于ShowWindow 函数的任何一个SW_*标识符
    WORD cbReserved2;        //保留。必须被初始化为0
    PBYTE lpReserved2;       //保留。必须被初始化为N U L L
    HANDLE hStdInput;        //用于设定供控制台输入和输出用的缓存的句柄。按照默认设置,hStdInput 用于标识键盘缓存,hStdOutput 和hStdError用于标识控制台窗口的缓存
    HANDLE hStdOutput;
    HANDLE hStdError;
} STARTUPINFO, *LPSTARTUPINFO;

当Windows 创建新进程时,它将使用该结构的有关成员。大多数应用程序将要求生成的应用程序仅仅使用默认值。至少应该将该结构中的所有成员初始化为零,然后将c b 成员设置为该结构的大小:
STARTUPINFO si = { sizeof(si) };
CreateProcess(...,&si,...);

表4-7 dwFlags 使用标志及含义
标志                                    含义

STARTF_USESIZE                 // 使用dwXSize 和dwYSize 成员
STARTF_USESHOWWINDOW              //使用wShowWindow 成员
STARTF_USEPOSITION              //使用dwX 和dwY 成员
STARTF_USECOUNTCHARS                //使用dwXCountChars 和dwYCount Chars 成员
STARTF_USEFILLATTRIBUTE          //使用dwFillAttribute 成员
STARTF_USESTDHANDLES              //使用hStdInput 、hStdOutput 和hStdError 成员
STARTF_RUN_FULLSCREEN              //强制在x86 计算机上运行的控制台应用程序以全屏幕方式启动运行



另外还有两个标志,即STARTF_FORCEONFEEDBACKSTARTF_+FORCEOFFF -EEDBACK ,当启动一个新进程时,它们可以用来控制鼠标的光标。由于Windows支持真正的多任务抢占式运行方式,因此可以启动一个应用程序,然后在进程初始化时,使用另一个程序。为了向用户提供直观的反馈信息,CreateProcess 能够临时将系统的箭头光标改为一个新光标,即沙漏箭头光标:

该光标表示可以等待出现某种情况,也可以继续使用系统。当启动另一个进程时,CreateProcess函数使你能够更好地控制光标。当设定 STARTF_FORCEONFEEDBACK标志时,CreateProcess 并不将光标改为沙漏。

STARTF_FORCEONFEEDBACK可使CreateProcess能够监控新进程的初始化,并可根据结果来改变光标。当使用该标志来调用CreateProcess时,光标改为沙漏。过2 s 后,如果新进程没有调用GUI ,CreateProcess 将光标恢复为箭头。

如果该进程在2 s 内调用了GUI ,CreateProcess将等待该应用程序显示一个窗口。这必须在进程调用GUI 后5s 内发生。如果没有显示窗口,CreateProcess就会恢复原来的光标。如果显示了一个窗口,CreateProcess将使沙漏光标继续保留5 s 。如果某个时候该应用程序调用了GetMessage 函数,指明它完成了初始化,那么CreateProcess 就会立即恢复原来的光标,并且停止监控新进程。

在结束这一节内容的介绍之前,我想讲一讲STARTUPINFO 的wShowWindow 成员。你将该成员初始化为传递给(w)WinMain 的最后一个参数nCmdShow 的值。该成员显示你想要传递给新进程的(w)WinMain 函数的最后一个参数nCmdShow 的值。它是可以传递给ShowWindow 函数的标识符之一。通常,nCmdShow 的值既可以是SW_SHOWNORMAL ,也可以是SW_ SHOWMINNOACTIVE 。但是,它有时可以是SW_SHOWDEFAULT 。

当在Explorer中启动一个应用程序时,该应用程序的(w)WinMain 函数被调用,而SW_SHOWNORMAL 则作为nCmdShow 参数来传递。如果为该应用程序创建了一个快捷方式,可以使用快捷方式的属性页来告诉系统,应用程序的窗口最初应该如何显示。图4 - 3 显示了运行Notepad 的快捷方式的属性页。注意,使用Run 选项的组合框,就能够设定如何显示Notepad 的窗口。

当使用Explorer 来启动该快捷方式时,Explorer 会正确地准备STARTUPINFO 结构并调用CreateProcess 。这时Notepad 开始运行,并且为nCmdShow 参数将SW_SHOWMINNOACTIVE传递给它的(w)WinMain 函数。

运用这样的方法,用户能够很容易地启动一个应用程序,其主窗口可以用正常状态、最小或最大状态进行显示。

最后,应用程序可以调用下面的函数,以便获取由父进程初始化的STARTUPINFO 结构的拷贝。子进程可以查看该结构,并根据该结构的成员的值来改变它的行为特性。

VOID GetStartupInfo(LPSTARTUPINFO pStartupInfo);
注意虽然Windows 文档没有明确地说明,但是在调用GetStartInfo 函数之前,必须像下面这样对该结构的cb 成员进行初始化:
STARTUPINFO si = { sizeof(si) };
GetStartupInfo(&si);


static void CreateSubProcessor(std::string exePath) { HANDLE g_hChildStd_OUT_Rd = NULL; // 子进程标准输出读取端 HANDLE g_hChildStd_OUT_Wr = NULL; // 子进程标准输出写入端 SECURITY_ATTRIBUTES saAttr; // 设置安全属性,允许句柄继承 saAttr.nLength = sizeof(SECURITY_ATTRIBUTES); saAttr.bInheritHandle = TRUE; saAttr.lpSecurityDescriptor = NULL; // 创建匿名管道 if (!CreatePipe(&g_hChildStd_OUT_Rd, &g_hChildStd_OUT_Wr, &saAttr, 0)) { } // 确保读取端不会被子进程继承 if (!SetHandleInformation(g_hChildStd_OUT_Rd, HANDLE_FLAG_INHERIT, 0)) { } STARTUPINFO siStartInfo; PROCESS_INFORMATION piProcInfo; // 初始化 STARTUPINFO ZeroMemory(&siStartInfo, sizeof(STARTUPINFO)); siStartInfo.cb = sizeof(STARTUPINFO); siStartInfo.hStdError = g_hChildStd_OUT_Wr; siStartInfo.hStdOutput = g_hChildStd_OUT_Wr; siStartInfo.hStdInput = GetStdHandle(STD_INPUT_HANDLE); siStartInfo.dwFlags |= STARTF_USESTDHANDLES; // 要运行的程序及其参数 LPSTR commandLine = new CHAR[exePath.size() + 1]; memset(commandLine, 0, exePath.size() + 1); // 初始化内存 strncpy_s(commandLine, exePath.size() + 1, exePath.c_str(), exePath.size());// 创建子进程 if (!CreateProcess(NULL, // 可执行文件名 (LPWSTR)commandLine, // 命令行参数 NULL, // 进程安全属性 NULL, // 线程安全属性 TRUE, // 继承句柄 0, // 创建标志 NULL, // 使用父进程的环境变量 NULL, // 使用父进程的当前目录 &siStartInfo, // STARTUPINFO 结构体 &piProcInfo)) // PROCESS_INFORMATION 结构体 { } // 关闭写入端,因为父进程不需要它 CloseHandle(g_hChildStd_OUT_Wr); // 从管道读取子进程的输出 DWORD dwRead; CHAR chBuf[BUFSIZE] = {0}; BOOL bSuccess = FALSE; while (bSuccess = ReadFile(g_hChildStd_OUT_Rd, chBuf, BUFSIZE, &dwRead, NULL)) { if (dwRead == 0) break; chBuf[dwRead] = '\0'; // 确保字符串以空字符结尾 std::cout << chBuf << std::endl; } // 等待子进程结束 WaitForSingleObject(piProcInfo.hProcess, INFINITE); // 关闭句柄 CloseHandle(piProcInfo.hProcess); CloseHandle(piProcInfo.hThread); CloseHandle(g_hChildStd_OUT_Rd); } 我这读出来的内容是空 的检查下为什么并改正
05-24
#include <windows.h> #include <tchar.h> #include <stdio.h> #include <strsafe.h> #define BUFSIZE 4096 int _tmain() { HANDLE g_hChildStd_OUT_Rd = NULL; // 子进程标准输出读取端 HANDLE g_hChildStd_OUT_Wr = NULL; // 子进程标准输出写入端 SECURITY_ATTRIBUTES saAttr; // 设置安全属性,允许句柄继承 saAttr.nLength = sizeof(SECURITY_ATTRIBUTES); saAttr.bInheritHandle = TRUE; saAttr.lpSecurityDescriptor = NULL; // 创建匿名管道 if (!CreatePipe(&g_hChildStd_OUT_Rd, &g_hChildStd_OUT_Wr, &saAttr, 0)) { _tprintf(_T("CreatePipe failed (%d)\n"), GetLastError()); return 1; } // 确保写入端可以被子进程继承 if (!SetHandleInformation(g_hChildStd_OUT_Rd, HANDLE_FLAG_INHERIT, 0)) { _tprintf(_T("SetHandleInformation failed (%d)\n"), GetLastError()); return 1; } STARTUPINFO siStartInfo; PROCESS_INFORMATION piProcInfo; // 初始化 STARTUPINFO ZeroMemory(&siStartInfo, sizeof(STARTUPINFO)); siStartInfo.cb = sizeof(STARTUPINFO); siStartInfo.hStdError = g_hChildStd_OUT_Wr; siStartInfo.hStdOutput = g_hChildStd_OUT_Wr; siStartInfo.hStdInput = GetStdHandle(STD_INPUT_HANDLE); siStartInfo.dwFlags |= STARTF_USESTDHANDLES; // 要运行的程序及其参数 TCHAR szCmdLine[] = _T("B.exe"); // 创建子进程 if (!CreateProcess(NULL, // 可执行文件名 szCmdLine, // 命令行参数 NULL, // 进程安全属性 NULL, // 线程安全属性 TRUE, // 继承句柄 0, // 创建标志 NULL, // 使用父进程的环境变量 NULL, // 使用父进程的当前目录 &siStartInfo, // STARTUPINFO 结构体 &piProcInfo)) // PROCESS_INFORMATION 结构体 { _tprintf(_T("CreateProcess failed (%d)\n"), GetLastError()); return 1; } // 关闭写入端,因为父进程不需要它 CloseHandle(g_hChildStd_OUT_Wr); // 从管道读取子进程的输出 DWORD dwRead; CHAR chBuf[BUFSIZE]; BOOL bSuccess = FALSE; _tprintf(_T("Output from child process:\n")); while (bSuccess = ReadFile(g_hChildStd_OUT_Rd, chBuf, BUFSIZE, &dwRead, NULL)) { if (dwRead == 0) break; chBuf[dwRead] = '\0'; // 确保字符串以空字符结尾 _tprintf(_T("%s"), chBuf); // 输出子进程的输出内容 } // 等待子进程结束 WaitForSingleObject(piProcInfo.hProcess, INFINITE); // 关闭句柄 CloseHandle(piProcInfo.hProcess); CloseHandle(piProcInfo.hThread); CloseHandle(g_hChildStd_OUT_Rd); return 0; }这个代码适配下多字节符的exe控制台 vs2010环境
05-24
#include <windows.h> #include <tchar.h> #include <stdio.h> #include <strsafe.h> #include <iostream> #include <string> #define BUFSIZE 4096 static void CreateSubProcessor(std::string exePath) { HANDLE g_hChildStd_OUT_Rd = NULL; // 子进程标准输出读取端 HANDLE g_hChildStd_OUT_Wr = NULL; // 子进程标准输出写入端 SECURITY_ATTRIBUTES saAttr; // 设置安全属性,允许句柄继承 saAttr.nLength = sizeof(SECURITY_ATTRIBUTES); saAttr.bInheritHandle = TRUE; saAttr.lpSecurityDescriptor = NULL; // 创建匿名管道 if (!CreatePipe(&g_hChildStd_OUT_Rd, &g_hChildStd_OUT_Wr, &saAttr, 0)) { std::cerr << "CreatePipe failed (" << GetLastError() << ")\n"; return; } // 确保读取端不会被子进程继承 if (!SetHandleInformation(g_hChildStd_OUT_Rd, HANDLE_FLAG_INHERIT, 0)) { std::cerr << "SetHandleInformation failed (" << GetLastError() << ")\n"; CloseHandle(g_hChildStd_OUT_Rd); CloseHandle(g_hChildStd_OUT_Wr); return; } STARTUPINFO siStartInfo; PROCESS_INFORMATION piProcInfo; // 初始化 STARTUPINFO ZeroMemory(&siStartInfo, sizeof(STARTUPINFO)); siStartInfo.cb = sizeof(STARTUPINFO); siStartInfo.hStdError = g_hChildStd_OUT_Wr; siStartInfo.hStdOutput = g_hChildStd_OUT_Wr; siStartInfo.hStdInput = GetStdHandle(STD_INPUT_HANDLE); siStartInfo.dwFlags |= STARTF_USESTDHANDLES; // 要运行的程序及其参数 std::wstring commandLine = std::wstring(exePath.begin(), exePath.end()); // 创建子进程 if (!CreateProcess(NULL, // 可执行文件名 (LPWSTR)commandLine.c_str(), // 命令行参数 NULL, // 进程安全属性 NULL, // 线程安全属性 TRUE, // 继承句柄 0, // 创建标志 NULL, // 使用父进程的环境变量 NULL, // 使用父进程的当前目录 &siStartInfo, // STARTUPINFO 结构体 &piProcInfo)) // PROCESS_INFORMATION 结构体 { std::cerr << "CreateProcess failed (" << GetLastError() << ")\n"; CloseHandle(g_hChildStd_OUT_Rd); CloseHandle(g_hChildStd_OUT_Wr); return; } // 关闭写入端,因为父进程不需要它 CloseHandle(g_hChildStd_OUT_Wr); // 从管道读取子进程的输出 DWORD dwRead; CHAR chBuf[BUFSIZE] = { 0 }; BOOL bSuccess = FALSE; while (bSuccess = ReadFile(g_hChildStd_OUT_Rd, chBuf, BUFSIZE, &dwRead, NULL)) { if (dwRead == 0) break; chBuf[dwRead] = '\0'; // 确保字符串以空字符结尾 std::cout << chBuf << std::flush; // 输出子进程的输出内容 } if (!bSuccess && GetLastError() != ERROR_BROKEN_PIPE) { std::cerr << "ReadFile failed (" << GetLastError() << ")\n"; } // 等待子进程结束 WaitForSingleObject(piProcInfo.hProcess, INFINITE); // 关闭句柄 CloseHandle(piProcInfo.hProcess); CloseHandle(piProcInfo.hThread); CloseHandle(g_hChildStd_OUT_Rd); }将代码中 的管道读取内容改为按行输出
05-24
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值