最近在写curses程序,但是发现在一台机器上可以运行的程序在另一台电脑上就打不开,同时也没有出现缺少dll的消息提示。正百思不得其解时发现在闪退的一瞬间控制台输出了几行字,于是在cmd上运行下,发现这行字是:
LINES value must be >= 2 and <= 29: got 30
initscr(): Unable to create SP
看到这个报错信息后解决办法就不辩自明了,报错的意思是行数太多无法调用initscr。所以只需要在intiscr前执行下面语句:
HANDLE hOut = GetStdHandle(STD_OUTPUT_HANDLE);
SMALL_RECT rc = {0, 0, 80, 20};
SetConsoleWindowInfo(hOut,true ,&rc);
//CloseHandle(hOut); // 这句要放在整个程序的末尾,或者不加
即更改控制台行数,这样就可以成功运行了。
需要注意的是,在程序结束前,不要把标准输出的句柄close掉,这样不论是c的运行库(如printf)还是initscr都无法执行。
不过看到这里肯定有人会想能否在initscr前获取一下该电脑的curses所支持的行数范围,笔者也想到这一点,不过由于自身才浅,并不能找到很好的方式在程序开始时获得这串错误码。
笔者想到通过CreateProcess调用自身,在子进程中先close掉标准输出的句柄,再调用initscr以触发报错,最后在父进程中通过获取子进程输出来获取错误码。可是笔者自身能力有限,无论是通过匿名管道读写还是重定向标准输出的方法,都无法在父进程中获得这串代码(父进程中获得的输出总为空)。甚至通过创建一个子进程,子进程用system打开输出错误码的程序,都无法获得错误码,无论是子进程还是父进程。
下面放出了我在尝试时用到的代码,读者可以在此基础上继续探索这个新问题的解决办法。如有高人精通此道,还请指点一二。
#define PDC_DLL_BUILD true
#pragma comment(lib,"pdcurses.lib")
#define _CRT_SECURE_NO_WARNINGS
#define DEBUG
#include <stdlib.h>
#include <string.h>
#include <Windows.h>
#include <iostream>
#include <ctime>
#include <string>
#include <conio.h>
#include "curses.h"
using std::string;
int SetSupportedLines()
{
// 创建匿名管道
SECURITY_ATTRIBUTES sa;
HANDLE hRead, hWrite;
sa.nLength = sizeof(SECURITY_ATTRIBUTES);
sa.lpSecurityDescriptor = NULL;
sa.bInheritHandle = TRUE;
if (!CreatePipe(&hRead, &hWrite, &sa, 0))
{
printf("Error On CreatePipe()");
return -1;
}
STARTUPINFO si;
PROCESS_INFORMATION pi;
si.cb = sizeof(STARTUPINFO);
GetStartupInfo(&si);
si.hStdError = hWrite;
si.hStdOutput = hWrite;
si.wShowWindow = SW_HIDE;
si.dwFlags = STARTF_USESHOWWINDOW | STARTF_USESTDHANDLES;
TCHAR cmd[256];
strcpy_s(cmd, (string(_pgmptr) + " systemcall").c_str());
BOOL bRet = ::CreateProcess(NULL, cmd, NULL, NULL, TRUE, NORMAL_PRIORITY_CLASS, NULL, NULL, &si, &pi);
if (bRet == FALSE)
{
printf("Error on CreateProcess()");
return -2;
}
CloseHandle(hWrite);
char buffer[4096] = { 0 };
DWORD bytesRead;
printf("################################################################################\n");
while (TRUE)
{
if (!ReadFile(hRead, buffer, 4095, &bytesRead, NULL))
break;
printf("%s\n", buffer);
}
CloseHandle(hRead);
return 0;
}
int main(int argc, char **argv)
{
if (argc > 1 )
{
if (strcmp(argv[1], "outputerr") == 0)
{
printf("outputerr proc\n"); DEBUG;
CloseHandle(GetStdHandle(STD_OUTPUT_HANDLE));
initscr();
endwin();
return 0;
}
if (strcmp(argv[1], "systemcall") == 0)
{
printf("systemcall proc\n"); DEBUG;
TCHAR cmd[256];
strcpy_s(cmd, (string(_pgmptr) + " outputerr").c_str());
system(cmd);
return 0;
}
}
SetSupportedLines();
getchar(); DEBUG;
initscr();
printw("curses startup successfully!");
refresh();
getch();
endwin();
return (0);
}
如上图,只有systemcall的输出,而没有outputerr的输出,可见outputerr部分的输出并未被捕获。