Read settings from the registry.
[reactos.git] / reactos / subsys / smss / init.c
1 /* $Id: init.c,v 1.34 2002/05/22 15:55:51 ekohl Exp $
2 *
3 * init.c - Session Manager initialization
4 *
5 * ReactOS Operating System
6 *
7 * --------------------------------------------------------------------
8 *
9 * This software is free software; you can redistribute it and/or
10 * modify it under the terms of the GNU General Public License as
11 * published by the Free Software Foundation; either version 2 of the
12 * License, or (at your option) any later version.
13 *
14 * This software is distributed in the hope that it will be useful,
15 * but WITHOUT ANY WARRANTY; without even the implied warranty of
16 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
17 * General Public License for more details.
18 *
19 * You should have received a copy of the GNU General Public License
20 * along with this software; see the file COPYING.LIB. If not, write
21 * to the Free Software Foundation, Inc., 675 Mass Ave, Cambridge,
22 * MA 02139, USA.
23 *
24 * --------------------------------------------------------------------
25 *
26 * 19990530 (Emanuele Aliberti)
27 * Compiled successfully with egcs 1.1.2
28 */
29 #include <ntos.h>
30 #include <ntdll/rtl.h>
31 #include <napi/lpc.h>
32
33 #include "smss.h"
34
35 #define NDEBUG
36
37 /* TYPES ********************************************************************/
38
39
40 /* GLOBAL VARIABLES *********************************************************/
41
42 HANDLE SmApiPort = INVALID_HANDLE_VALUE;
43 HANDLE DbgSsApiPort = INVALID_HANDLE_VALUE;
44 HANDLE DbgUiApiPort = INVALID_HANDLE_VALUE;
45
46 PWSTR SmSystemEnvironment = NULL;
47
48
49 /* FUNCTIONS ****************************************************************/
50
51
52 static NTSTATUS STDCALL
53 SmObjectDirectoryQueryRoutine(PWSTR ValueName,
54 ULONG ValueType,
55 PVOID ValueData,
56 ULONG ValueLength,
57 PVOID Context,
58 PVOID EntryContext)
59 {
60 OBJECT_ATTRIBUTES ObjectAttributes;
61 UNICODE_STRING UnicodeString;
62 HANDLE WindowsDirectory;
63 NTSTATUS Status;
64
65 #ifndef NDEBUG
66 PrintString("ValueName '%S' Type %lu Length %lu\n", ValueName, ValueType, ValueLength);
67 PrintString("ValueData '%S'\n", (PWSTR)ValueData);
68 #endif
69
70 RtlInitUnicodeString(&UnicodeString,
71 (PWSTR)ValueData);
72
73 InitializeObjectAttributes(&ObjectAttributes,
74 &UnicodeString,
75 0,
76 NULL,
77 NULL);
78
79 Status = ZwCreateDirectoryObject(&WindowsDirectory,
80 0,
81 &ObjectAttributes);
82
83 return(Status);
84 }
85
86
87 static NTSTATUS
88 SmCreateObjectDirectories(VOID)
89 {
90 RTL_QUERY_REGISTRY_TABLE QueryTable[2];
91 NTSTATUS Status;
92
93 RtlZeroMemory(&QueryTable,
94 sizeof(QueryTable));
95
96 QueryTable[0].Name = L"ObjectDirectories";
97 QueryTable[0].QueryRoutine = SmObjectDirectoryQueryRoutine;
98
99 Status = RtlQueryRegistryValues(RTL_REGISTRY_CONTROL,
100 L"\\Session Manager",
101 QueryTable,
102 NULL,
103 NULL);
104
105 return(Status);
106 }
107
108
109 static NTSTATUS STDCALL
110 SmDosDevicesQueryRoutine(PWSTR ValueName,
111 ULONG ValueType,
112 PVOID ValueData,
113 ULONG ValueLength,
114 PVOID Context,
115 PVOID EntryContext)
116 {
117 OBJECT_ATTRIBUTES ObjectAttributes;
118 UNICODE_STRING DeviceName;
119 UNICODE_STRING LinkName;
120 HANDLE LinkHandle;
121 WCHAR LinkBuffer[80];
122 NTSTATUS Status = STATUS_SUCCESS;
123
124 #ifndef NDEBUG
125 PrintString("ValueName '%S' Type %lu Length %lu\n", ValueName, ValueType, ValueLength);
126 PrintString("ValueData '%S'\n", (PWSTR)ValueData);
127 #endif
128
129 if (ValueType = REG_SZ)
130 {
131 swprintf(LinkBuffer, L"\\??\\%s",
132 ValueName);
133 RtlInitUnicodeString(&LinkName,
134 LinkBuffer);
135 RtlInitUnicodeString(&DeviceName,
136 (PWSTR)ValueData);
137
138 #ifndef NDEBUG
139 PrintString("SM: Linking %wZ --> %wZ\n",
140 &LinkName,
141 &DeviceName);
142 #endif
143
144 /* create symbolic link */
145 InitializeObjectAttributes(&ObjectAttributes,
146 &LinkName,
147 OBJ_PERMANENT,
148 NULL,
149 NULL);
150 Status = NtCreateSymbolicLinkObject(&LinkHandle,
151 SYMBOLIC_LINK_ALL_ACCESS,
152 &ObjectAttributes,
153 &DeviceName);
154 if (!NT_SUCCESS(Status))
155 {
156 PrintString("SmDosDevicesQueryRoutine: NtCreateSymbolicLink( %wZ --> %wZ ) failed!\n",
157 &LinkName,
158 &DeviceName);
159 }
160 NtClose(LinkHandle);
161 }
162
163 return(Status);
164 }
165
166
167 static NTSTATUS
168 SmInitDosDevices(VOID)
169 {
170 RTL_QUERY_REGISTRY_TABLE QueryTable[2];
171 NTSTATUS Status;
172
173 RtlZeroMemory(&QueryTable,
174 sizeof(QueryTable));
175
176 QueryTable[0].QueryRoutine = SmDosDevicesQueryRoutine;
177
178 Status = RtlQueryRegistryValues(RTL_REGISTRY_CONTROL,
179 L"\\Session Manager\\DOS Devices",
180 QueryTable,
181 NULL,
182 NULL);
183 return(Status);
184 }
185
186
187 static NTSTATUS STDCALL
188 SmRunBootAppsQueryRoutine(PWSTR ValueName,
189 ULONG ValueType,
190 PVOID ValueData,
191 ULONG ValueLength,
192 PVOID Context,
193 PVOID EntryContext)
194 {
195 #if 0
196 PRTL_USER_PROCESS_PARAMETERS ProcessParameters;
197 RTL_PROCESS_INFO ProcessInfo;
198 WCHAR Description[256];
199 WCHAR ImagePath[256];
200 WCHAR CommandLine[256];
201 PWSTR p1, p2;
202 ULONG len;
203 NTSTATUS Status = STATUS_SUCCESS;
204
205 #ifndef NDEBUG
206 PrintString("ValueName '%S' Type %lu Length %lu\n", ValueName, ValueType, ValueLength);
207 PrintString("ValueData '%S'\n", (PWSTR)ValueData);
208 #endif
209
210 /* Extract the description */
211 p1 = wcschr((PWSTR)ValueData, L' ');
212 len = p1 - (PWSTR)ValueData;
213 memcpy(Description,ValueData, len * sizeof(WCHAR));
214 Description[len] = 0;
215
216 /* Extract the full image path */
217 p1++;
218 p2 = wcschr(p1, L' ');
219 if (p2 != NULL)
220 len = p2 - p1;
221 else
222 len = wcslen(p1);
223 memcpy(ImagePath, p1, len * sizeof(WCHAR));
224 ImagePath[len] = 0;
225
226 /* Extract the command line */
227 if (p2 == NULL)
228 {
229 CommandLine[0] = 0;
230 }
231 else
232 {
233 p2++;
234 wcscpy(CommandLine, p2);
235 }
236
237 #ifndef NDEBUG
238 PrintString("Running %S...\n", Description);
239 PrintString("Executable: '%S'\n", ImagePath);
240 PrintString("CommandLine: '%S'\n", CommandLine);
241 #endif
242
243 #if 0
244 /* initialize executable path */
245 wcscpy(UnicodeBuffer, L"\\??\\");
246 wcscat(UnicodeBuffer, SharedUserData->NtSystemRoot);
247 wcscat(UnicodeBuffer, L"\\system32\\csrss.exe");
248 RtlInitUnicodeString(&ImagePathString,
249 UnicodeBuffer);
250
251 RtlInitUnicodeString(&CommandLineString,
252 CommandLine);
253
254 RtlCreateProcessParameters(&ProcessParameters,
255 &ImagePathString,
256 NULL,
257 NULL,
258 &CommandLineString,
259 NULL,
260 NULL,
261 NULL,
262 NULL,
263 NULL);
264
265 Status = RtlCreateUserProcess(&UnicodeString,
266 OBJ_CASE_INSENSITIVE,
267 ProcessParameters,
268 NULL,
269 NULL,
270 NULL,
271 FALSE,
272 NULL,
273 NULL,
274 &ProcessInfo);
275
276 RtlDestroyProcessParameters (ProcessParameters);
277
278 /* FIXME: wait for process termination */
279
280 #endif
281
282 return(Status);
283 #endif
284 return(STATUS_SUCCESS);
285 }
286
287
288 /*
289 * Run native applications listed in the registry.
290 *
291 * Key:
292 * \Registry\Machine\SYSTEM\CurrentControlSet\Control\Session Manager
293 *
294 * Value (format: "<description> <executable> <command line>":
295 * BootExecute = "autocheck autochk *"
296 */
297 static NTSTATUS
298 SmRunBootApps(VOID)
299 {
300 RTL_QUERY_REGISTRY_TABLE QueryTable[2];
301 NTSTATUS Status;
302
303 RtlZeroMemory(&QueryTable,
304 sizeof(QueryTable));
305
306 QueryTable[0].Name = L"BootExecute";
307 QueryTable[0].QueryRoutine = SmRunBootAppsQueryRoutine;
308
309 Status = RtlQueryRegistryValues(RTL_REGISTRY_CONTROL,
310 L"\\Session Manager",
311 QueryTable,
312 NULL,
313 NULL);
314 if (!NT_SUCCESS(Status))
315 {
316 PrintString("SmRunBootApps: RtlQueryRegistryValues() failed! (Status %lx)\n", Status);
317 }
318
319 // PrintString("*** System stopped ***\n");
320 // for(;;);
321
322 return(Status);
323 }
324
325
326 static NTSTATUS
327 SmProcessFileRenameList(VOID)
328 {
329 #ifndef NDEBUG
330 PrintString("SmProcessFileRenameList() called\n");
331 #endif
332
333 #ifndef NDEBUG
334 PrintString("SmProcessFileRenameList() done\n");
335 #endif
336
337 return(STATUS_SUCCESS);
338 }
339
340
341 static NTSTATUS STDCALL
342 SmPagingFilesQueryRoutine(PWSTR ValueName,
343 ULONG ValueType,
344 PVOID ValueData,
345 ULONG ValueLength,
346 PVOID Context,
347 PVOID EntryContext)
348 {
349 UNICODE_STRING FileName;
350 LARGE_INTEGER InitialSize;
351 LARGE_INTEGER MaximumSize;
352 NTSTATUS Status;
353
354 #ifndef NDEBUG
355 PrintString("ValueName '%S' Type %lu Length %lu\n", ValueName, ValueType, ValueLength);
356 PrintString("ValueData '%S'\n", (PWSTR)ValueData);
357 #endif
358
359 RtlInitUnicodeString(&FileName,
360 (PWSTR)ValueData);
361
362 /*
363 * FIXME:
364 * read initial and maximum size from the registry or use default values
365 *
366 * Format: "<path>[ <initial_size>[ <maximum_size>]]"
367 */
368
369 InitialSize.QuadPart = 50 * 4096;
370 MaximumSize.QuadPart = 80 * 4096;
371
372 Status = NtCreatePagingFile(&FileName,
373 &InitialSize,
374 &MaximumSize,
375 0);
376
377 return(STATUS_SUCCESS);
378 }
379
380
381 static NTSTATUS
382 SmCreatePagingFiles(VOID)
383 {
384 RTL_QUERY_REGISTRY_TABLE QueryTable[2];
385 NTSTATUS Status;
386
387 RtlZeroMemory(&QueryTable,
388 sizeof(QueryTable));
389
390 QueryTable[0].Name = L"PagingFiles";
391 QueryTable[0].QueryRoutine = SmPagingFilesQueryRoutine;
392
393 Status = RtlQueryRegistryValues(RTL_REGISTRY_CONTROL,
394 L"\\Session Manager\\Memory Management",
395 QueryTable,
396 NULL,
397 NULL);
398
399 return(Status);
400 }
401
402
403 static NTSTATUS
404 SmSetEnvironmentVariables(VOID)
405 {
406 UNICODE_STRING EnvVariable;
407 UNICODE_STRING EnvValue;
408 UNICODE_STRING EnvExpandedValue;
409 ULONG ExpandedLength;
410 WCHAR ExpandBuffer[512];
411 WCHAR ValueBuffer[MAX_PATH];
412
413 /*
414 * The following environment variables are read from the registry.
415 * Because the registry does not work yet, the environment variables
416 * are set one by one, using information from the shared user page.
417 *
418 * Variables (example):
419 * SystemRoot = C:\reactos
420 * SystemDrive = C:
421 *
422 * OS = ReactOS
423 * Path = %SystemRoot%\system32;%SystemRoot%
424 * windir = %SystemRoot%
425 */
426
427 /* copy system root into value buffer */
428 wcscpy (ValueBuffer, SharedUserData->NtSystemRoot);
429
430 /* set "SystemRoot = C:\reactos" */
431 RtlInitUnicodeString (&EnvVariable,
432 L"SystemRoot");
433 RtlInitUnicodeString (&EnvValue,
434 ValueBuffer);
435 RtlSetEnvironmentVariable (&SmSystemEnvironment,
436 &EnvVariable,
437 &EnvValue);
438
439 /* cut off trailing path */
440 ValueBuffer[2] = 0;
441
442 /* Set "SystemDrive = C:" */
443 RtlInitUnicodeString (&EnvVariable,
444 L"SystemDrive");
445 RtlInitUnicodeString (&EnvValue,
446 ValueBuffer);
447 RtlSetEnvironmentVariable (&SmSystemEnvironment,
448 &EnvVariable,
449 &EnvValue);
450
451
452 /* Set "OS = ReactOS" */
453 RtlInitUnicodeString (&EnvVariable,
454 L"OS");
455 RtlInitUnicodeString (&EnvValue,
456 L"ReactOS");
457 RtlSetEnvironmentVariable (&SmSystemEnvironment,
458 &EnvVariable,
459 &EnvValue);
460
461
462 /* Set "Path = %SystemRoot%\system32;%SystemRoot%" */
463 RtlInitUnicodeString (&EnvVariable,
464 L"Path");
465 RtlInitUnicodeString (&EnvValue,
466 L"%SystemRoot%\\system32;%SystemRoot%");
467 EnvExpandedValue.Length = 0;
468 EnvExpandedValue.MaximumLength = 512 * sizeof(WCHAR);
469 EnvExpandedValue.Buffer = ExpandBuffer;
470 *ExpandBuffer = 0;
471 RtlExpandEnvironmentStrings_U (SmSystemEnvironment,
472 &EnvValue,
473 &EnvExpandedValue,
474 &ExpandedLength);
475 RtlSetEnvironmentVariable (&SmSystemEnvironment,
476 &EnvVariable,
477 &EnvExpandedValue);
478
479 /* Set "windir = %SystemRoot%" */
480 RtlInitUnicodeString (&EnvVariable,
481 L"windir");
482 RtlInitUnicodeString (&EnvValue,
483 L"%SystemRoot%");
484 EnvExpandedValue.Length = 0;
485 EnvExpandedValue.MaximumLength = 512 * sizeof(WCHAR);
486 EnvExpandedValue.Buffer = ExpandBuffer;
487 *ExpandBuffer = 0;
488 RtlExpandEnvironmentStrings_U (SmSystemEnvironment,
489 &EnvValue,
490 &EnvExpandedValue,
491 &ExpandedLength);
492 RtlSetEnvironmentVariable (&SmSystemEnvironment,
493 &EnvVariable,
494 &EnvExpandedValue);
495
496 return(STATUS_SUCCESS);
497 }
498
499
500 NTSTATUS
501 InitSessionManager(HANDLE Children[])
502 {
503 NTSTATUS Status;
504 UNICODE_STRING UnicodeString;
505 OBJECT_ATTRIBUTES ObjectAttributes;
506 UNICODE_STRING CmdLineW;
507 PRTL_USER_PROCESS_PARAMETERS ProcessParameters;
508 RTL_PROCESS_INFO ProcessInfo;
509 HANDLE CsrssInitEvent;
510 WCHAR UnicodeBuffer[MAX_PATH];
511
512 /* Create object directories */
513 Status = SmCreateObjectDirectories();
514 if (!NT_SUCCESS(Status))
515 {
516 PrintString("SM: Failed to create object directories! (Status %lx)\n", Status);
517 return(Status);
518 }
519
520 /* Create the "\SmApiPort" object (LPC) */
521 RtlInitUnicodeString(&UnicodeString,
522 L"\\SmApiPort");
523 InitializeObjectAttributes(&ObjectAttributes,
524 &UnicodeString,
525 PORT_ALL_ACCESS,
526 NULL,
527 NULL);
528
529 Status = NtCreatePort(&SmApiPort,
530 &ObjectAttributes,
531 0,
532 0,
533 0);
534 if (!NT_SUCCESS(Status))
535 {
536 return(Status);
537 }
538
539 #ifndef NDEBUG
540 DisplayString (L"SM: \\SmApiPort created...\n");
541 #endif
542
543 /* Create two threads for "\SmApiPort" */
544 RtlCreateUserThread(NtCurrentProcess(),
545 NULL,
546 FALSE,
547 0,
548 NULL,
549 NULL,
550 (PTHREAD_START_ROUTINE)SmApiThread,
551 (PVOID)SmApiPort,
552 NULL,
553 NULL);
554
555 RtlCreateUserThread(NtCurrentProcess(),
556 NULL,
557 FALSE,
558 0,
559 NULL,
560 NULL,
561 (PTHREAD_START_ROUTINE)SmApiThread,
562 (PVOID)SmApiPort,
563 NULL,
564 NULL);
565
566 /* Create the system environment */
567 Status = RtlCreateEnvironment(FALSE,
568 &SmSystemEnvironment);
569 if (!NT_SUCCESS(Status))
570 {
571 return(Status);
572 }
573 #ifndef NDEBUG
574 DisplayString(L"SM: System Environment created\n");
575 #endif
576
577 /* Define symbolic links to kernel devices (MS-DOS names) */
578 Status = SmInitDosDevices();
579 if (!NT_SUCCESS(Status))
580 {
581 PrintString("SM: Failed to create dos device links! (Status %lx)\n", Status);
582 return(Status);
583 }
584
585 /* Run all programs in the boot execution list */
586 Status = SmRunBootApps();
587 if (!NT_SUCCESS(Status))
588 {
589 PrintString("SM: Failed to run boot applications! (Status %lx)\n", Status);
590 return(Status);
591 }
592
593 /* Process the file rename list */
594 Status = SmProcessFileRenameList();
595 if (!NT_SUCCESS(Status))
596 {
597 PrintString("SM: Failed to process the file rename list (Status %lx)\n", Status);
598 return(Status);
599 }
600
601 /* FIXME: Load the well known DLLs */
602 // SmPreloadDlls();
603
604 /* Create paging files */
605 Status = SmCreatePagingFiles();
606 if (!NT_SUCCESS(Status))
607 {
608 PrintString("SM: Failed to create paging files (Status %lx)\n", Status);
609 return(Status);
610 }
611
612 /* Load remaining registry hives */
613 NtInitializeRegistry(FALSE);
614
615 /* Set environment variables from registry */
616 Status = SmSetEnvironmentVariables();
617 if (!NT_SUCCESS(Status))
618 {
619 PrintString("SM: Failed to initialize the system environment (Status %lx)\n", Status);
620 return(Status);
621 }
622
623 /* Load the kernel mode driver win32k.sys */
624 RtlInitUnicodeString(&CmdLineW,
625 L"\\SystemRoot\\system32\\drivers\\win32k.sys");
626 Status = NtLoadDriver(&CmdLineW);
627 #if 0
628 if (!NT_SUCCESS(Status))
629 {
630 return(Status);
631 }
632 #endif
633
634 /* Run csrss.exe */
635 RtlInitUnicodeString(&UnicodeString,
636 L"\\CsrssInitDone");
637 InitializeObjectAttributes(&ObjectAttributes,
638 &UnicodeString,
639 EVENT_ALL_ACCESS,
640 0,
641 NULL);
642 Status = NtCreateEvent(&CsrssInitEvent,
643 EVENT_ALL_ACCESS,
644 &ObjectAttributes,
645 TRUE,
646 FALSE);
647 if (!NT_SUCCESS(Status))
648 {
649 DbgPrint("Failed to create csrss notification event\n");
650 }
651
652 /*
653 * Start the Win32 subsystem (csrss.exe)
654 */
655
656 /* initialize executable path */
657 wcscpy(UnicodeBuffer, L"\\??\\");
658 wcscat(UnicodeBuffer, SharedUserData->NtSystemRoot);
659 wcscat(UnicodeBuffer, L"\\system32\\csrss.exe");
660 RtlInitUnicodeString(&UnicodeString,
661 UnicodeBuffer);
662
663 RtlCreateProcessParameters(&ProcessParameters,
664 &UnicodeString,
665 NULL,
666 NULL,
667 NULL,
668 SmSystemEnvironment,
669 NULL,
670 NULL,
671 NULL,
672 NULL);
673
674 Status = RtlCreateUserProcess(&UnicodeString,
675 OBJ_CASE_INSENSITIVE,
676 ProcessParameters,
677 NULL,
678 NULL,
679 NULL,
680 FALSE,
681 NULL,
682 NULL,
683 &ProcessInfo);
684
685 RtlDestroyProcessParameters (ProcessParameters);
686
687 if (!NT_SUCCESS(Status))
688 {
689 DisplayString(L"SM: Loading csrss.exe failed!\n");
690 return(Status);
691 }
692
693 NtWaitForSingleObject(CsrssInitEvent,
694 FALSE,
695 NULL);
696
697 Children[CHILD_CSRSS] = ProcessInfo.ProcessHandle;
698
699 /*
700 * Start the logon process (winlogon.exe)
701 */
702
703 /* initialize executable path */
704 wcscpy(UnicodeBuffer, L"\\??\\");
705 wcscat(UnicodeBuffer, SharedUserData->NtSystemRoot);
706 wcscat(UnicodeBuffer, L"\\system32\\winlogon.exe");
707 RtlInitUnicodeString(&UnicodeString,
708 UnicodeBuffer);
709
710 RtlCreateProcessParameters(&ProcessParameters,
711 &UnicodeString,
712 NULL,
713 NULL,
714 NULL,
715 SmSystemEnvironment,
716 NULL,
717 NULL,
718 NULL,
719 NULL);
720
721 Status = RtlCreateUserProcess(&UnicodeString,
722 OBJ_CASE_INSENSITIVE,
723 ProcessParameters,
724 NULL,
725 NULL,
726 NULL,
727 FALSE,
728 NULL,
729 NULL,
730 &ProcessInfo);
731
732 RtlDestroyProcessParameters(ProcessParameters);
733
734 if (!NT_SUCCESS(Status))
735 {
736 DisplayString(L"SM: Loading winlogon.exe failed!\n");
737 NtTerminateProcess(Children[CHILD_CSRSS],
738 0);
739 return(Status);
740 }
741 Children[CHILD_WINLOGON] = ProcessInfo.ProcessHandle;
742
743 /* Create the \DbgSsApiPort object (LPC) */
744 RtlInitUnicodeString(&UnicodeString,
745 L"\\DbgSsApiPort");
746 InitializeObjectAttributes(&ObjectAttributes,
747 &UnicodeString,
748 PORT_ALL_ACCESS,
749 NULL,
750 NULL);
751
752 Status = NtCreatePort(&DbgSsApiPort,
753 &ObjectAttributes,
754 0,
755 0,
756 0);
757
758 if (!NT_SUCCESS(Status))
759 {
760 return(Status);
761 }
762 #ifndef NDEBUG
763 DisplayString(L"SM: DbgSsApiPort created...\n");
764 #endif
765
766 /* Create the \DbgUiApiPort object (LPC) */
767 RtlInitUnicodeString(&UnicodeString,
768 L"\\DbgUiApiPort");
769 InitializeObjectAttributes(&ObjectAttributes,
770 &UnicodeString,
771 PORT_ALL_ACCESS,
772 NULL,
773 NULL);
774
775 Status = NtCreatePort(&DbgUiApiPort,
776 &ObjectAttributes,
777 0,
778 0,
779 0);
780 if (!NT_SUCCESS(Status))
781 {
782 return(Status);
783 }
784 #ifndef NDEBUG
785 DisplayString (L"SM: DbgUiApiPort created...\n");
786 #endif
787
788 return(STATUS_SUCCESS);
789 }
790
791 /* EOF */