/* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements . See the NOTICE file distributed with
* this work for additional information regarding copyright ownership .
* The ASF licenses this file to You under the Apache License , Version 2 . 0
* ( the " License " ) ; you may not use this file except in compliance with
* the License . You may obtain a copy of the License at
*
* http : //www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing , software
* distributed under the License is distributed on an " AS IS " BASIS ,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND , either express or implied .
* See the License for the specific language governing permissions and
* limitations under the License .
*/
/* --------------------------------------------------------------------
*
* wintty : a Apache / WinNT support utility for monitoring and
* reflecting user feedback from the Apache process via
* stdin / stdout , even as running within the service context .
*
* Originally contributed by William Rowe < wrowe covalent . net >
*
* Note : this implementation is _ very_ experimental , and error handling
* is far from complete . Using it as a cgi or pipe process allows the
* programmer to discover if facilities such as reliable piped logs
* are working as expected , or answer operator prompts that would
* otherwise be discarded by the service process .
*
* Also note the isservice detection semantics , which far exceed any
* mechanism we have discovered thus far .
*
* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
*/
#define WIN32_LEAN_AND_MEAN
#include <windows.h>
#include <stdlib.h>
#include <stdio.h>
#if defined (_MSC_VER) && _MSC_VER >= 1400
#define _CRT_SECURE_NO_DEPRECATE
#pragma warning(disable: 4996 )
#endif
const char *options =
"\nwintty: a utility for echoing the stdin stream to a new console window,\n"
"\teven when invoked from within a service (such as the Apache server.)\n"
"\tAlso reflects the console input back to the stdout stream, allowing\n"
"\tthe operator to respond to prompts from the context of a service.\n\n"
"Syntax: %s [opts] [-t \" Window Title\"]\n\n"
" opts: -c{haracter} or -l{ine} input\n"
"\t-q{uiet} or -e{cho} input\n"
"\t-u{nprocessed} or -p{rocessed} input\n"
"\t-n{owrap} or -w{rap} output lines\n"
"\t-f{ormatted} or -r{aw} output lines\n"
"\t-O{output} [number of seconds]\n"
"\t-v{erbose} error reporting (for debugging)\n"
"\t-? for this message\n\n" ;
BOOL verbose = FALSE ;
void printerr(char *fmt, ...)
{
char str[1024 ];
va_list args;
if (!verbose)
return ;
va_start(args, fmt);
wvsprintf(str, fmt, args);
OutputDebugString(str);
}
DWORD WINAPI feedback(LPVOID args);
typedef struct feedback_args_t {
HANDLE in;
HANDLE out;
} feedback_args_t;
int main(int argc, char ** argv)
{
char str[1024 ], *contitle = NULL;
HANDLE hproc, thread;
HANDLE hwinsta = NULL, hsavewinsta;
HANDLE hdesk = NULL, hsavedesk = NULL;
HANDLE conin, conout;
HANDLE hstdin, hstdout, hstderr, hdup;
feedback_args_t feed;
DWORD conmode;
DWORD newinmode = 0 , notinmode = 0 ;
DWORD newoutmode = 0 , notoutmode = 0 ;
DWORD tid;
DWORD len;
DWORD timeout = INFINITE;
BOOL isservice = FALSE ;
char *arg0 = argv[0 ];
while (--argc) {
++argv;
if (**argv == '/' || **argv == '-' ) {
switch (tolower((*argv)[1 ])) {
case 'c' :
notinmode |= ENABLE_LINE_INPUT; break ;
case 'l' :
newinmode |= ENABLE_LINE_INPUT; break ;
case 'q' :
notinmode |= ENABLE_ECHO_INPUT; break ;
case 'e' :
newinmode |= ENABLE_ECHO_INPUT; break ;
case 'u' :
notinmode |= ENABLE_PROCESSED_INPUT; break ;
case 'p' :
newinmode |= ENABLE_PROCESSED_INPUT; break ;
case 'n' :
notoutmode |= ENABLE_WRAP_AT_EOL_OUTPUT; break ;
case 'w' :
newoutmode |= ENABLE_WRAP_AT_EOL_OUTPUT; break ;
case 'r' :
notoutmode |= ENABLE_PROCESSED_OUTPUT; break ;
case 'f' :
newoutmode |= ENABLE_PROCESSED_OUTPUT; break ;
case 'o' :
if (*(argv + 1 ) && *(argv + 1 )[0 ] != '-' ) {
*(++argv);
timeout = atoi(*argv) / 1000 ;
--argc;
}
else {
timeout = 0 ;
}
break ;
case 'v' :
verbose = TRUE ;
break ;
case 't' :
contitle = *(++argv);
--argc;
break ;
case '?' :
printf(options, arg0);
exit (1 );
default :
printf("wintty option %s not recognized, use -? for help.\n\n" , *argv);
exit (1 );
}
}
else {
printf("wintty argument %s not understood, use -? for help.\n\n" , *argv);
exit (1 );
}
}
hproc = GetCurrentProcess();
hsavewinsta = GetProcessWindowStation();
if (!hsavewinsta || hsavewinsta == INVALID_HANDLE_VALUE) {
printerr("GetProcessWindowStation() failed (%d)\n" , GetLastError());
}
else if (!GetUserObjectInformation(hsavewinsta, UOI_NAME, str, sizeof (str), &len)) {
printerr("GetUserObjectInfoformation(hWinSta) failed (%d)\n" , GetLastError());
}
else if (strnicmp(str, "Service-" , 8 ) == 0 ) {
printerr("WindowStation Name %s is a service\n" , str);
isservice = TRUE ;
}
SetLastError(0 );
hstdin = GetStdHandle(STD_INPUT_HANDLE);
if (!hstdin || hstdin == INVALID_HANDLE_VALUE) {
printerr("GetStdHandle(STD_INPUT_HANDLE) failed (%d)\n" ,
GetLastError());
}
else if (DuplicateHandle(hproc, hstdin, hproc, &hdup, 0 ,
isservice, DUPLICATE_SAME_ACCESS)) {
CloseHandle(hstdin);
hstdin = hdup;
}
else {
printerr("DupHandle(stdin [%x]) failed (%d)\n" ,
hstdin, GetLastError());
}
hstdout = GetStdHandle(STD_OUTPUT_HANDLE);
if (!hstdout || hstdout == INVALID_HANDLE_VALUE) {
printerr("GetStdHandle(STD_OUTPUT_HANDLE) failed (%d)\n" ,
GetLastError());
}
else if (DuplicateHandle(hproc, hstdout, hproc, &hdup, 0 ,
isservice, DUPLICATE_SAME_ACCESS)) {
CloseHandle(hstdout);
hstdout = hdup;
}
else {
printerr("DupHandle(stdout [%x]) failed (%d)\n" ,
hstdout, GetLastError());
}
hstderr = GetStdHandle(STD_ERROR_HANDLE);
if (!hstderr || hstderr == INVALID_HANDLE_VALUE) {
printerr("GetStdHandle(STD_ERROR_HANDLE) failed (%d)\n" ,
GetLastError());
}
else if (DuplicateHandle(hproc, hstderr, hproc, &hdup, 0 ,
isservice, DUPLICATE_SAME_ACCESS)) {
CloseHandle(hstderr);
hstderr = hdup;
}
else {
printerr("DupHandle(stderr [%x]) failed (%d)\n" ,
hstderr, GetLastError());
}
/* You can't close the console till all the handles above were
* rescued by DuplicateHandle ( )
*/
if (!FreeConsole())
printerr("FreeConsole() failed (%d)\n" , GetLastError());
if (isservice) {
#ifdef WE_EVER_FIGURE_OUT_WHY_THIS_DOESNT_WORK
hsavedesk = GetThreadDesktop(GetCurrentThreadId());
if (!hsavedesk || hsavedesk == INVALID_HANDLE_VALUE) {
printerr("GetThreadDesktop(GetTID()) failed (%d)\n" , GetLastError());
}
CloseWindowStation(hwinsta);
hwinsta = OpenWindowStation("WinSta0" , TRUE , MAXIMUM_ALLOWED);
if (!hwinsta || hwinsta == INVALID_HANDLE_VALUE) {
printerr("OpenWinSta(WinSta0) failed (%d)\n" , GetLastError());
}
else if (!SetProcessWindowStation(hwinsta)) {
printerr("SetProcWinSta(WinSta0) failed (%d)\n" , GetLastError());
}
hdesk = OpenDesktop("Default" , 0 , TRUE , MAXIMUM_ALLOWED);
if (!hdesk || hdesk == INVALID_HANDLE_VALUE) {
printerr("OpenDesktop(Default) failed (%d)\n" , GetLastError());
}
else if (!SetThreadDesktop(hdesk)) {
printerr("SetThreadDesktop(Default) failed (%d)\n" , GetLastError());
}
#else
PROCESS_INFORMATION pi;
STARTUPINFO si;
DWORD exitcode = 1 ;
char appbuff[MAX_PATH];
char *appname = NULL;
char *cmdline = GetCommandLine();
if (!GetModuleFileName(NULL, appbuff, sizeof (appbuff))) {
appname = appbuff;
}
memset(&si, 0 , sizeof (si));
si.cb = sizeof (si);
si.dwFlags = STARTF_USESHOWWINDOW
| STARTF_USESTDHANDLES;
si.lpDesktop = "WinSta0\\Default" ;
si.wShowWindow = 1 ; /* SW_SHOWNORMAL */
si.hStdInput = hstdin;
si.hStdOutput = hstdout;
si.hStdError = hstderr;
/* Instantly, upon creating the new process, we will close our
* copies of the handles so our parent isn ' t confused when the
* child closes their copy of the handle . Without this action ,
* we would hold a copy of the handle , and the parent would not
* receive their EOF notification .
*/
if (CreateProcess(appname, cmdline, NULL, NULL, TRUE ,
CREATE_SUSPENDED | CREATE_NEW_CONSOLE,
NULL, NULL, &si, &pi)) {
CloseHandle(si.hStdInput);
CloseHandle(si.hStdOutput);
CloseHandle(si.hStdError);
ResumeThread(pi.hThread);
CloseHandle(pi.hThread);
WaitForSingleObject(pi.hProcess, INFINITE);
GetExitCodeProcess(pi.hProcess, &exitcode);
CloseHandle(pi.hProcess);
return exitcode;
}
return 1 ;
#endif
}
if (!AllocConsole()) {
printerr("AllocConsole(Default) failed (%d)\n" , GetLastError());
}
if (contitle && !SetConsoleTitle(contitle)) {
printerr("SetConsoleTitle() failed (%d)\n" , GetLastError());
}
conout = CreateFile("CONOUT$" , GENERIC_READ | GENERIC_WRITE,
FILE_SHARE_READ | FILE_SHARE_WRITE,
FALSE , OPEN_EXISTING, 0 , NULL);
if (!conout || conout == INVALID_HANDLE_VALUE) {
printerr("CreateFile(CONOUT$) failed (%d)\n" , GetLastError());
}
else if (!GetConsoleMode(conout, &conmode)) {
printerr("GetConsoleMode(CONOUT) failed (%d)\n" , GetLastError());
}
else if (!SetConsoleMode(conout, conmode = ((conmode | newoutmode)
& ~notoutmode))) {
printerr("SetConsoleMode(CONOUT, 0x%x) failed (%d)\n" ,
conmode, GetLastError());
}
conin = CreateFile("CONIN$" , GENERIC_READ | GENERIC_WRITE,
FILE_SHARE_READ | FILE_SHARE_WRITE,
FALSE , OPEN_EXISTING, 0 , NULL);
if (!conin || conin == INVALID_HANDLE_VALUE) {
printerr("CreateFile(CONIN$) failed (%d)\n" , GetLastError());
}
else if (!GetConsoleMode(conin, &conmode)) {
printerr("GetConsoleMode(CONIN) failed (%d)\n" , GetLastError());
}
else if (!SetConsoleMode(conin, conmode = ((conmode | newinmode)
& ~notinmode))) {
printerr("SetConsoleMode(CONIN, 0x%x) failed (%d)\n" ,
conmode, GetLastError());
}
feed.in = conin;
feed.out = hstdout;
thread = CreateThread(NULL, 0 , feedback, (LPVOID)&feed, 0 , &tid);
while (ReadFile(hstdin, str, sizeof (str), &len, NULL))
if (!len || !WriteFile(conout, str, len, &len, NULL))
break ;
printerr("[EOF] from stdin (%d)\n" , GetLastError());
CloseHandle(stdout);
if (!GetConsoleTitle(str, sizeof (str))) {
printerr("SetConsoleTitle() failed (%d)\n" , GetLastError());
}
else {
strcat(str, " - [Finished]" );
if (!SetConsoleTitle(str)) {
printerr("SetConsoleTitle() failed (%d)\n" , GetLastError());
}
}
WaitForSingleObject(thread, timeout);
FreeConsole();
if (isservice) {
if (!SetProcessWindowStation(hsavewinsta)) {
len = GetLastError();
}
if (!SetThreadDesktop(hsavedesk)) {
len = GetLastError();
}
CloseDesktop(hdesk);
CloseWindowStation(hwinsta);
}
return 0 ;
}
DWORD WINAPI feedback(LPVOID arg)
{
feedback_args_t *feed = (feedback_args_t*)arg;
char *str[1024 ];
DWORD len;
while (ReadFile(feed->in, str, sizeof (str), &len, NULL))
if (!len || !WriteFile(feed->out, str, len, &len, NULL))
break ;
printerr("[EOF] from Console (%d)\n" , GetLastError());
return 0 ;
}
Messung V0.5 in Prozent C=99 H=96 G=97
¤ Dauer der Verarbeitung: 0.13 Sekunden
(vorverarbeitet am 2026-09-29)
¤
*© Formatika GbR, Deutschland