source: branches/1.9-appstore/aux/cocotron/win32/cocotron/WaltConsole/WaltConsole.c

Last change on this file was 13177, checked in by Gary Byers, 15 years ago

PeekNamedPipe() isn't detecting EOF on Win7, so do a timed wait for
the parent process handle to be signaled (rather than just sleeping)
to detect termination.

When reading console input, don't do a blocking read when a key event
is detected unless that key event produces a character. (Win7 at least
seems to report things like shift-key events.)

Dear god windows sucks.

File size: 4.7 KB
Line 
1#include <windows.h>
2#include <psapi.h>
3#include <stdio.h>
4#include <string.h>
5
6
7struct ProcessBasicInformation {
8 DWORD ExitStatus;
9 PVOID PebBaseAddress;
10 DWORD AffinityMask;
11 DWORD BasePriority;
12 ULONG UniqueProcessId;
13 ULONG InheritedFromUniqueProcessId;
14};
15
16/* Try to get the (Windows) pid of the parent process; return it, or
17 return 0 on failure. There doesn't seem to be a higher-level way
18 to do this.
19*/
20
21typedef LONG (__stdcall *FPTR_NtQueryInformationProcess ) (HANDLE, INT, PVOID, ULONG, PULONG);
22
23ULONG
24getppid()
25{
26 ULONG ppid = 0, pid = GetCurrentProcessId();
27 HANDLE hcurrent = OpenProcess(PROCESS_QUERY_INFORMATION,FALSE,pid);
28 if (hcurrent) {
29 FPTR_NtQueryInformationProcess NtQueryInformationProcess = (FPTR_NtQueryInformationProcess) GetProcAddress(GetModuleHandleA("ntdll"), "NtQueryInformationProcess");
30 if (NtQueryInformationProcess != NULL) {
31 struct ProcessBasicInformation pbi;
32 if (NtQueryInformationProcess(hcurrent, 0, (void *)&pbi, sizeof(pbi), NULL) == 0) {
33 ppid = pbi.InheritedFromUniqueProcessId;
34 }
35 }
36 CloseHandle(hcurrent);
37 }
38 return ppid;
39}
40
41char *
42parent_process_name(ULONG ppid)
43{
44 char procname[1024], *result = NULL;
45 DWORD namelen;
46 HANDLE hprocess = OpenProcess(PROCESS_QUERY_INFORMATION|PROCESS_VM_READ, FALSE, ppid);
47
48 if (hprocess) {
49 namelen = GetModuleBaseNameA(hprocess, NULL, procname, sizeof(procname)-1);
50 if (namelen && (namelen <= sizeof(procname))) {
51 result = strdup(procname);
52 }
53 CloseHandle(hprocess);
54 }
55 return result;
56}
57
58
59int
60write_pending_console_input(HANDLE input, HANDLE output)
61{
62 DWORD ninput_events, i, n, nread, nwritten;
63 char buf[1024];
64 INPUT_RECORD ir;
65
66 switch (WaitForSingleObject(input, 100)) {
67 case WAIT_TIMEOUT:
68 return 0;
69 break;
70 case WAIT_OBJECT_0:
71 ninput_events = 0;
72 if (GetNumberOfConsoleInputEvents(input, &ninput_events)) {
73 for (i = 0; i < ninput_events; i++) {
74 PeekConsoleInput(input, &ir, 1, &n);
75 if ((ir.EventType == KEY_EVENT) &&
76 (ir.Event.KeyEvent.uChar.UnicodeChar != 0)) {
77 if (!ReadFile(input, buf, sizeof(buf), &nread, NULL)) {
78 return -1;
79 }
80 if (!WriteFile(output, buf, nread, &nwritten, NULL)) {
81 return -1;
82 }
83 return 0;
84 } else {
85 ReadConsoleInput(input, &ir, 1, &n);
86 }
87 }
88 }
89 return 0;
90 break;
91
92 default:
93 return -1;
94 break;
95 }
96}
97
98
99int
100write_pipe_input_to_console(HANDLE hpipe, HANDLE conout)
101{
102 unsigned char buf[1024];
103 DWORD navail, n, m;
104
105 while (PeekNamedPipe(hpipe, NULL, 0, NULL, &navail, NULL) != 0) {
106 if (navail == 0) {
107 return 0;
108 }
109 if (navail > sizeof(buf)) {
110 n = sizeof(buf);
111 } else {
112 n = navail;
113 }
114 if (!ReadFile(hpipe, buf, n, &m, NULL)) {
115 return -1;
116 }
117 if (!WriteFile(conout, buf, m, &n, NULL)) {
118 return -1;
119 }
120 }
121 return -1;
122}
123
124int APIENTRY WinMain(HINSTANCE a,HINSTANCE b,LPSTR c,int d)
125{
126 HANDLE in, out, conin, conout, hppid;
127 DWORD navail, err, exitcode;
128 ULONG ppid;
129 HWND window;
130 HMENU menu;
131 char title[2048], *procname, buf[1024];
132
133 in = GetStdHandle(STD_INPUT_HANDLE);
134 out = GetStdHandle(STD_OUTPUT_HANDLE);
135 ppid = getppid();
136 hppid = OpenProcess(PROCESS_QUERY_INFORMATION|SYNCHRONIZE,FALSE,ppid);
137
138 while (1) {
139 navail = 0;
140 if (PeekNamedPipe(in, NULL, 0, NULL, &navail, NULL) == 0) {
141 exit(0); /* error or EOF */
142 }
143 if (navail != 0) {
144 break;
145 }
146 if (WaitForSingleObject(hppid,100)==WAIT_OBJECT_0) {
147 exit(0);
148 }
149 }
150
151 AllocConsole();
152
153 conin = CreateFileA("CONIN$",GENERIC_READ|GENERIC_WRITE,FILE_SHARE_READ,NULL,OPEN_EXISTING,FILE_ATTRIBUTE_NORMAL,0);
154 conout = CreateFileA("CONOUT$",GENERIC_WRITE,FILE_SHARE_WRITE,NULL,OPEN_EXISTING,FILE_ATTRIBUTE_NORMAL,0);
155
156 procname = parent_process_name(ppid);
157 if (!procname) {
158 procname = "<Unknown>";
159 }
160 sprintf(title, "WaltConsole for %s (pid 0x%x)", procname, ppid);
161 SetConsoleTitleA(title);
162
163 window = GetConsoleWindow();
164 menu = GetSystemMenu(window, FALSE);
165 EnableMenuItem(menu, SC_CLOSE, MF_BYCOMMAND|MF_GRAYED);
166
167 ShowWindow(window, SW_SHOW);
168 ShowWindow(window, SW_SHOW);
169
170 do {
171 if (WaitForSingleObject(hppid, 0) == WAIT_OBJECT_0) {
172 break;
173 }
174 if (write_pipe_input_to_console(in, conout) < 0) {
175 break;
176 }
177 write_pending_console_input(conin, out);
178 } while (1);
179
180 EnableMenuItem(menu, SC_CLOSE, MF_BYCOMMAND|MF_ENABLED);
181 sprintf(buf,"\n\nProcess %s (pid 0x%x) has exited; press any key to close this window.", procname, ppid);
182 WriteFile(conout, buf, strlen(buf), &navail, NULL);
183 FlushConsoleInputBuffer(conin);
184 ReadConsoleA(conin,buf,1,&navail,NULL);
185
186}
Note: See TracBrowser for help on using the repository browser.