957827d179ff8e97fccfe2371cfcc1f4762effc5
[reactos.git] / reactos / dll / win32 / kernel32 / client / console / init.c
1 /*
2 * COPYRIGHT: See COPYING in the top level directory
3 * PROJECT: ReactOS system libraries
4 * FILE: dll/win32/kernel32/client/console/init.c
5 * PURPOSE: Console API Client Initialization
6 * PROGRAMMERS: Alex Ionescu (alex.ionescu@reactos.org)
7 * Aleksey Bragin (aleksey@reactos.org)
8 * Hermes Belusca-Maito (hermes.belusca@sfr.fr)
9 */
10
11 /* INCLUDES *******************************************************************/
12
13 #include <k32.h>
14
15 // For Control Panel Applet
16 #include <cpl.h>
17
18 #define NDEBUG
19 #include <debug.h>
20
21
22 /* GLOBALS ********************************************************************/
23
24 RTL_CRITICAL_SECTION ConsoleLock;
25 BOOL ConsoleInitialized = FALSE;
26
27 extern HANDLE InputWaitHandle;
28
29 static HMODULE ConsoleLibrary = NULL;
30 static BOOL AlreadyDisplayingProps = FALSE;
31
32 #define WIN_OBJ_DIR L"\\Windows"
33 #define SESSION_DIR L"\\Sessions"
34
35
36 /* FUNCTIONS ******************************************************************/
37
38 DWORD
39 WINAPI
40 PropDialogHandler(IN LPVOID lpThreadParameter)
41 {
42 // NOTE: lpThreadParameter corresponds to the client shared section handle.
43
44 APPLET_PROC CPLFunc;
45
46 /*
47 * Do not launch more than once the console property dialog applet,
48 * or (albeit less probable), if we are not initialized.
49 */
50 if (!ConsoleInitialized || AlreadyDisplayingProps)
51 {
52 /* Close the associated client shared section handle if needed */
53 if (lpThreadParameter)
54 {
55 CloseHandle((HANDLE)lpThreadParameter);
56 }
57 return STATUS_UNSUCCESSFUL;
58 }
59
60 AlreadyDisplayingProps = TRUE;
61
62 /* Load the Control Applet if needed */
63 if (ConsoleLibrary == NULL)
64 {
65 WCHAR szBuffer[MAX_PATH];
66
67 GetWindowsDirectoryW(szBuffer, MAX_PATH);
68 wcscat(szBuffer, L"\\system32\\console.dll");
69 ConsoleLibrary = LoadLibraryW(szBuffer);
70
71 if (ConsoleLibrary == NULL)
72 {
73 DPRINT1("Failed to load console.dll");
74 AlreadyDisplayingProps = FALSE;
75 return STATUS_UNSUCCESSFUL;
76 }
77 }
78
79 /* Load its main function */
80 CPLFunc = (APPLET_PROC)GetProcAddress(ConsoleLibrary, "CPlApplet");
81 if (CPLFunc == NULL)
82 {
83 DPRINT("Error: Console.dll misses CPlApplet export\n");
84 AlreadyDisplayingProps = FALSE;
85 return STATUS_UNSUCCESSFUL;
86 }
87
88 if (CPLFunc(NULL, CPL_INIT, 0, 0) == FALSE)
89 {
90 DPRINT("Error: failed to initialize console.dll\n");
91 AlreadyDisplayingProps = FALSE;
92 return STATUS_UNSUCCESSFUL;
93 }
94
95 if (CPLFunc(NULL, CPL_GETCOUNT, 0, 0) != 1)
96 {
97 DPRINT("Error: console.dll returned unexpected CPL count\n");
98 AlreadyDisplayingProps = FALSE;
99 return STATUS_UNSUCCESSFUL;
100 }
101
102 CPLFunc(NULL, CPL_DBLCLK, (LPARAM)lpThreadParameter, 0);
103 CPLFunc(NULL, CPL_EXIT , 0, 0);
104
105 AlreadyDisplayingProps = FALSE;
106 return STATUS_SUCCESS;
107 }
108
109
110 VOID
111 InitConsoleInfo(IN OUT PCONSOLE_START_INFO ConsoleStartInfo)
112 {
113 STARTUPINFOW si;
114
115 GetStartupInfoW(&si);
116
117 ConsoleStartInfo->dwStartupFlags = si.dwFlags;
118 if (si.dwFlags & STARTF_USEFILLATTRIBUTE)
119 {
120 ConsoleStartInfo->FillAttribute = si.dwFillAttribute;
121 }
122 if (si.dwFlags & STARTF_USECOUNTCHARS)
123 {
124 ConsoleStartInfo->ScreenBufferSize.X = (SHORT)(si.dwXCountChars);
125 ConsoleStartInfo->ScreenBufferSize.Y = (SHORT)(si.dwYCountChars);
126 }
127 if (si.dwFlags & STARTF_USESHOWWINDOW)
128 {
129 ConsoleStartInfo->ShowWindow = si.wShowWindow;
130 }
131 if (si.dwFlags & STARTF_USEPOSITION)
132 {
133 ConsoleStartInfo->ConsoleWindowOrigin.x = (LONG)(si.dwX);
134 ConsoleStartInfo->ConsoleWindowOrigin.y = (LONG)(si.dwY);
135 }
136 if (si.dwFlags & STARTF_USESIZE)
137 {
138 ConsoleStartInfo->ConsoleWindowSize.cx = (LONG)(si.dwXSize);
139 ConsoleStartInfo->ConsoleWindowSize.cy = (LONG)(si.dwYSize);
140 }
141 /*
142 if (si.dwFlags & STARTF_RUNFULLSCREEN)
143 {
144 }
145 */
146
147 if (si.lpTitle)
148 {
149 wcsncpy(ConsoleStartInfo->ConsoleTitle, si.lpTitle, MAX_PATH + 1);
150 }
151 else
152 {
153 ConsoleStartInfo->ConsoleTitle[0] = L'\0';
154 }
155 }
156
157
158 BOOL
159 WINAPI
160 BasepInitConsole(VOID)
161 {
162 NTSTATUS Status;
163 PRTL_USER_PROCESS_PARAMETERS Parameters = NtCurrentPeb()->ProcessParameters;
164 WCHAR SessionDir[256];
165 ULONG SessionId = NtCurrentPeb()->SessionId;
166 BOOLEAN InServer;
167
168 CONSOLE_CONNECTION_INFO ConnectInfo;
169 ULONG ConnectInfoSize = sizeof(ConnectInfo);
170
171 DPRINT("BasepInitConsole for : %wZ\n", &Parameters->ImagePathName);
172 DPRINT("Our current console handles are: %lx, %lx, %lx %lx\n",
173 Parameters->ConsoleHandle, Parameters->StandardInput,
174 Parameters->StandardOutput, Parameters->StandardError);
175
176 /* Initialize our global console DLL lock */
177 Status = RtlInitializeCriticalSection(&ConsoleLock);
178 if (!NT_SUCCESS(Status)) return FALSE;
179 ConsoleInitialized = TRUE;
180
181 /* Do nothing if this isn't a console app... */
182 if (RtlImageNtHeader(GetModuleHandle(NULL))->OptionalHeader.Subsystem !=
183 IMAGE_SUBSYSTEM_WINDOWS_CUI)
184 {
185 DPRINT("Image is not a console application\n");
186 Parameters->ConsoleHandle = NULL;
187 ConnectInfo.ConsoleNeeded = FALSE; // ConsoleNeeded is used for knowing whether or not this is a CUI app.
188
189 ConnectInfo.ConsoleStartInfo.ConsoleTitle[0] = L'\0';
190 ConnectInfo.ConsoleStartInfo.AppPath[0] = L'\0';
191 }
192 else
193 {
194 SIZE_T Length = 0;
195 LPCWSTR ExeName;
196
197 InitConsoleInfo(&ConnectInfo.ConsoleStartInfo);
198
199 Length = min(sizeof(ConnectInfo.ConsoleStartInfo.AppPath) / sizeof(ConnectInfo.ConsoleStartInfo.AppPath[0]) - 1,
200 Parameters->ImagePathName.Length / sizeof(WCHAR));
201 wcsncpy(ConnectInfo.ConsoleStartInfo.AppPath, Parameters->ImagePathName.Buffer, Length);
202 ConnectInfo.ConsoleStartInfo.AppPath[Length] = L'\0';
203
204 /* Initialize Input EXE name */
205 ExeName = wcsrchr(Parameters->ImagePathName.Buffer, L'\\');
206 if (ExeName) SetConsoleInputExeNameW(ExeName + 1);
207
208 /* Assume one is needed */
209 ConnectInfo.ConsoleNeeded = TRUE;
210
211 /* Handle the special flags given to us by BasePushProcessParameters */
212 if (Parameters->ConsoleHandle == HANDLE_DETACHED_PROCESS)
213 {
214 /* No console to create */
215 DPRINT("No console to create\n");
216 Parameters->ConsoleHandle = NULL;
217 ConnectInfo.ConsoleNeeded = FALSE;
218 }
219 else if (Parameters->ConsoleHandle == HANDLE_CREATE_NEW_CONSOLE)
220 {
221 /* We'll get the real one soon */
222 DPRINT("Creating new console\n");
223 Parameters->ConsoleHandle = NULL;
224 }
225 else if (Parameters->ConsoleHandle == HANDLE_CREATE_NO_WINDOW)
226 {
227 /* We'll get the real one soon */
228 DPRINT("Creating new invisible console\n");
229 Parameters->ConsoleHandle = NULL;
230 ConnectInfo.ConsoleStartInfo.ShowWindow = SW_HIDE;
231 }
232 else
233 {
234 if (Parameters->ConsoleHandle == INVALID_HANDLE_VALUE)
235 {
236 Parameters->ConsoleHandle = NULL;
237 }
238 DPRINT("Using existing console: %x\n", Parameters->ConsoleHandle);
239 }
240 }
241
242 /* Now use the proper console handle */
243 ConnectInfo.Console = Parameters->ConsoleHandle;
244
245 /* Initialize the Console Ctrl Handler */
246 InitConsoleCtrlHandling();
247 ConnectInfo.CtrlDispatcher = ConsoleControlDispatcher;
248
249 /* Initialize the Property Dialog Handler */
250 ConnectInfo.PropDispatcher = PropDialogHandler;
251
252 /* Setup the right Object Directory path */
253 if (!SessionId)
254 {
255 /* Use the raw path */
256 wcscpy(SessionDir, WIN_OBJ_DIR);
257 }
258 else
259 {
260 /* Use the session path */
261 swprintf(SessionDir,
262 L"%ws\\%ld%ws",
263 SESSION_DIR,
264 SessionId,
265 WIN_OBJ_DIR);
266 }
267
268 /* Connect to the Console Server */
269 DPRINT("Connecting to the Console Server in BasepInitConsole...\n");
270 Status = CsrClientConnectToServer(SessionDir,
271 CONSRV_SERVERDLL_INDEX,
272 &ConnectInfo,
273 &ConnectInfoSize,
274 &InServer);
275 if (!NT_SUCCESS(Status))
276 {
277 DPRINT1("Failed to connect to the Console Server (Status %lx)\n", Status);
278 return FALSE;
279 }
280
281 /* Nothing to do for server-to-server */
282 if (InServer) return TRUE;
283
284 /* Nothing to do if not a console app */
285 if (!ConnectInfo.ConsoleNeeded) return TRUE;
286
287 /* We got the handles, let's set them */
288 if ((Parameters->ConsoleHandle = ConnectInfo.Console))
289 {
290 /* If we already had some, don't use the new ones */
291 if (!Parameters->StandardInput)
292 {
293 Parameters->StandardInput = ConnectInfo.InputHandle;
294 }
295 if (!Parameters->StandardOutput)
296 {
297 Parameters->StandardOutput = ConnectInfo.OutputHandle;
298 }
299 if (!Parameters->StandardError)
300 {
301 Parameters->StandardError = ConnectInfo.ErrorHandle;
302 }
303 }
304
305 InputWaitHandle = ConnectInfo.InputWaitHandle;
306
307 DPRINT("Console setup: %lx, %lx, %lx, %lx\n",
308 Parameters->ConsoleHandle,
309 Parameters->StandardInput,
310 Parameters->StandardOutput,
311 Parameters->StandardError);
312 return TRUE;
313 }
314
315
316 VOID
317 WINAPI
318 BasepUninitConsole(VOID)
319 {
320 /* Delete our critical section if we were initialized */
321 if (ConsoleInitialized == TRUE)
322 {
323 if (ConsoleLibrary) FreeLibrary(ConsoleLibrary);
324
325 ConsoleInitialized = FALSE;
326 RtlDeleteCriticalSection(&ConsoleLock);
327 }
328 }
329
330 /* EOF */