55e8d645bc27315edfaea8c72a7b975acb4814b4
[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 IN PUNICODE_STRING ImagePathName)
113 {
114 STARTUPINFOW si;
115 SIZE_T Length;
116
117 /* Get the startup information */
118 GetStartupInfoW(&si);
119
120 /* Initialize the fields */
121 ConsoleStartInfo->dwStartupFlags = si.dwFlags;
122 if (si.dwFlags & STARTF_USEFILLATTRIBUTE)
123 {
124 ConsoleStartInfo->FillAttribute = si.dwFillAttribute;
125 }
126 if (si.dwFlags & STARTF_USECOUNTCHARS)
127 {
128 ConsoleStartInfo->ScreenBufferSize.X = (SHORT)(si.dwXCountChars);
129 ConsoleStartInfo->ScreenBufferSize.Y = (SHORT)(si.dwYCountChars);
130 }
131 if (si.dwFlags & STARTF_USESHOWWINDOW)
132 {
133 ConsoleStartInfo->ShowWindow = si.wShowWindow;
134 }
135 if (si.dwFlags & STARTF_USEPOSITION)
136 {
137 ConsoleStartInfo->ConsoleWindowOrigin.x = (LONG)(si.dwX);
138 ConsoleStartInfo->ConsoleWindowOrigin.y = (LONG)(si.dwY);
139 }
140 if (si.dwFlags & STARTF_USESIZE)
141 {
142 ConsoleStartInfo->ConsoleWindowSize.cx = (LONG)(si.dwXSize);
143 ConsoleStartInfo->ConsoleWindowSize.cy = (LONG)(si.dwYSize);
144 }
145
146 /* Set up the title for the console */
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 /* Retrieve the application path name */
157 Length = min(sizeof(ConsoleStartInfo->AppPath) / sizeof(ConsoleStartInfo->AppPath[0]) - 1,
158 ImagePathName->Length / sizeof(WCHAR));
159 wcsncpy(ConsoleStartInfo->AppPath, ImagePathName->Buffer, Length);
160 ConsoleStartInfo->AppPath[Length] = L'\0';
161
162 /* The Console Server will use these fields to set up the console icon */
163 ConsoleStartInfo->IconPath[0] = L'\0';
164 ConsoleStartInfo->IconIndex = 0;
165 }
166
167
168 BOOL
169 WINAPI
170 BasepInitConsole(VOID)
171 {
172 NTSTATUS Status;
173 PRTL_USER_PROCESS_PARAMETERS Parameters = NtCurrentPeb()->ProcessParameters;
174 WCHAR SessionDir[256];
175 ULONG SessionId = NtCurrentPeb()->SessionId;
176 BOOLEAN InServer;
177
178 CONSRV_API_CONNECTINFO ConnectInfo;
179 ULONG ConnectInfoSize = sizeof(ConnectInfo);
180
181 DPRINT("BasepInitConsole for : %wZ\n", &Parameters->ImagePathName);
182 DPRINT("Our current console handles are: %lx, %lx, %lx %lx\n",
183 Parameters->ConsoleHandle, Parameters->StandardInput,
184 Parameters->StandardOutput, Parameters->StandardError);
185
186 /* Initialize our global console DLL lock */
187 Status = RtlInitializeCriticalSection(&ConsoleLock);
188 if (!NT_SUCCESS(Status)) return FALSE;
189 ConsoleInitialized = TRUE;
190
191 /* Do nothing if this isn't a console app... */
192 if (RtlImageNtHeader(GetModuleHandle(NULL))->OptionalHeader.Subsystem !=
193 IMAGE_SUBSYSTEM_WINDOWS_CUI)
194 {
195 DPRINT("Image is not a console application\n");
196 Parameters->ConsoleHandle = NULL;
197 ConnectInfo.ConsoleNeeded = FALSE; // ConsoleNeeded is used for knowing whether or not this is a CUI app.
198
199 ConnectInfo.ConsoleStartInfo.ConsoleTitle[0] = L'\0';
200 ConnectInfo.ConsoleStartInfo.AppPath[0] = L'\0';
201 }
202 else
203 {
204 LPCWSTR ExeName;
205
206 InitConsoleInfo(&ConnectInfo.ConsoleStartInfo,
207 &Parameters->ImagePathName);
208
209 /* Initialize Input EXE name */
210 ExeName = wcsrchr(Parameters->ImagePathName.Buffer, L'\\');
211 if (ExeName) SetConsoleInputExeNameW(ExeName + 1);
212
213 /* Assume one is needed */
214 ConnectInfo.ConsoleNeeded = TRUE;
215
216 /* Handle the special flags given to us by BasePushProcessParameters */
217 if (Parameters->ConsoleHandle == HANDLE_DETACHED_PROCESS)
218 {
219 /* No console to create */
220 DPRINT("No console to create\n");
221 Parameters->ConsoleHandle = NULL;
222 ConnectInfo.ConsoleNeeded = FALSE;
223 }
224 else if (Parameters->ConsoleHandle == HANDLE_CREATE_NEW_CONSOLE)
225 {
226 /* We'll get the real one soon */
227 DPRINT("Creating new console\n");
228 Parameters->ConsoleHandle = NULL;
229 }
230 else if (Parameters->ConsoleHandle == HANDLE_CREATE_NO_WINDOW)
231 {
232 /* We'll get the real one soon */
233 DPRINT("Creating new invisible console\n");
234 Parameters->ConsoleHandle = NULL;
235 ConnectInfo.ConsoleStartInfo.ShowWindow = SW_HIDE;
236 }
237 else
238 {
239 if (Parameters->ConsoleHandle == INVALID_HANDLE_VALUE)
240 {
241 Parameters->ConsoleHandle = NULL;
242 }
243 DPRINT("Using existing console: %x\n", Parameters->ConsoleHandle);
244 }
245 }
246
247 /* Now use the proper console handle */
248 ConnectInfo.ConsoleHandle = Parameters->ConsoleHandle;
249
250 /* Initialize the Console Ctrl Handler */
251 InitConsoleCtrlHandling();
252 ConnectInfo.CtrlDispatcher = ConsoleControlDispatcher;
253
254 /* Initialize the Property Dialog Handler */
255 ConnectInfo.PropDispatcher = PropDialogHandler;
256
257 /* Setup the right Object Directory path */
258 if (!SessionId)
259 {
260 /* Use the raw path */
261 wcscpy(SessionDir, WIN_OBJ_DIR);
262 }
263 else
264 {
265 /* Use the session path */
266 swprintf(SessionDir,
267 L"%ws\\%ld%ws",
268 SESSION_DIR,
269 SessionId,
270 WIN_OBJ_DIR);
271 }
272
273 /* Connect to the Console Server */
274 DPRINT("Connecting to the Console Server in BasepInitConsole...\n");
275 Status = CsrClientConnectToServer(SessionDir,
276 CONSRV_SERVERDLL_INDEX,
277 &ConnectInfo,
278 &ConnectInfoSize,
279 &InServer);
280 if (!NT_SUCCESS(Status))
281 {
282 DPRINT1("Failed to connect to the Console Server (Status %lx)\n", Status);
283 return FALSE;
284 }
285
286 /* Nothing to do for server-to-server */
287 if (InServer) return TRUE;
288
289 /* Nothing to do if not a console app */
290 if (!ConnectInfo.ConsoleNeeded) return TRUE;
291
292 /* We got the handles, let's set them */
293 if ((Parameters->ConsoleHandle = ConnectInfo.ConsoleHandle))
294 {
295 /* If we already had some, don't use the new ones */
296 if (!Parameters->StandardInput)
297 {
298 Parameters->StandardInput = ConnectInfo.InputHandle;
299 }
300 if (!Parameters->StandardOutput)
301 {
302 Parameters->StandardOutput = ConnectInfo.OutputHandle;
303 }
304 if (!Parameters->StandardError)
305 {
306 Parameters->StandardError = ConnectInfo.ErrorHandle;
307 }
308 }
309
310 InputWaitHandle = ConnectInfo.InputWaitHandle;
311
312 DPRINT("Console setup: %lx, %lx, %lx, %lx\n",
313 Parameters->ConsoleHandle,
314 Parameters->StandardInput,
315 Parameters->StandardOutput,
316 Parameters->StandardError);
317 return TRUE;
318 }
319
320
321 VOID
322 WINAPI
323 BasepUninitConsole(VOID)
324 {
325 /* Delete our critical section if we were initialized */
326 if (ConsoleInitialized == TRUE)
327 {
328 if (ConsoleLibrary) FreeLibrary(ConsoleLibrary);
329
330 ConsoleInitialized = FALSE;
331 RtlDeleteCriticalSection(&ConsoleLock);
332 }
333 }
334
335 /* EOF */