2 * COPYRIGHT: See COPYING in the top level directory
3 * PROJECT: ReactOS CSR Sub System
4 * FILE: subsys/csr/csrsrv/init.c
5 * PURPOSE: CSR Server DLL Initialization
6 * PROGRAMMERS: ReactOS Portable Systems Group
9 /* INCLUDES *******************************************************************/
15 /* DATA ***********************************************************************/
17 HANDLE CsrHeap
= (HANDLE
) 0;
18 HANDLE CsrObjectDirectory
= (HANDLE
) 0;
19 UNICODE_STRING CsrDirectoryName
;
20 extern HANDLE CsrssApiHeap
;
21 static unsigned InitCompleteProcCount
;
22 static CSRPLUGIN_INIT_COMPLETE_PROC
*InitCompleteProcs
= NULL
;
23 static unsigned HardErrorProcCount
;
24 static CSRPLUGIN_HARDERROR_PROC
*HardErrorProcs
= NULL
;
25 HANDLE hSbApiPort
= (HANDLE
) 0;
26 HANDLE hBootstrapOk
= (HANDLE
) 0;
27 HANDLE hSmApiPort
= (HANDLE
) 0;
28 HANDLE hApiPort
= (HANDLE
) 0;
30 /* PRIVATE FUNCTIONS **********************************************************/
33 InitializeVideoAddressSpace(VOID
)
35 OBJECT_ATTRIBUTES ObjectAttributes
;
36 UNICODE_STRING PhysMemName
= RTL_CONSTANT_STRING(L
"\\Device\\PhysicalMemory");
42 CHAR IVTAndBda
[1024+256];
44 /* Open the physical memory section */
45 InitializeObjectAttributes(&ObjectAttributes
,
50 Status
= ZwOpenSection(&PhysMemHandle
,
53 if (!NT_SUCCESS(Status
))
55 DPRINT1("Couldn't open \\Device\\PhysicalMemory\n");
59 /* Map the BIOS and device registers into the address space */
60 Offset
.QuadPart
= 0xa0000;
61 ViewSize
= 0x100000 - 0xa0000;
62 BaseAddress
= (PVOID
)0xa0000;
63 Status
= ZwMapViewOfSection(PhysMemHandle
,
72 PAGE_EXECUTE_READWRITE
);
73 if (!NT_SUCCESS(Status
))
75 DPRINT1("Couldn't map physical memory (%x)\n", Status
);
76 ZwClose(PhysMemHandle
);
80 /* Close physical memory section handle */
81 ZwClose(PhysMemHandle
);
83 if (BaseAddress
!= (PVOID
)0xa0000)
85 DPRINT1("Couldn't map physical memory at the right address (was %x)\n",
90 /* Allocate some low memory to use for the non-BIOS
91 * parts of the v86 mode address space
93 BaseAddress
= (PVOID
)0x1;
94 ViewSize
= 0xa0000 - 0x1000;
95 Status
= ZwAllocateVirtualMemory(NtCurrentProcess(),
100 PAGE_EXECUTE_READWRITE
);
101 if (!NT_SUCCESS(Status
))
103 DPRINT1("Failed to allocate virtual memory (Status %x)\n", Status
);
106 if (BaseAddress
!= (PVOID
)0x0)
108 DPRINT1("Failed to allocate virtual memory at right address (was %x)\n",
113 /* Get the real mode IVT and BDA from the kernel */
114 Status
= NtVdmControl(VdmInitialize
, IVTAndBda
);
115 if (!NT_SUCCESS(Status
))
117 DPRINT1("NtVdmControl failed (status %x)\n", Status
);
126 static NTSTATUS FASTCALL
127 CsrpAddInitCompleteProc(CSRPLUGIN_INIT_COMPLETE_PROC Proc
)
129 CSRPLUGIN_INIT_COMPLETE_PROC
*NewProcs
;
131 DPRINT("CSR: %s called\n", __FUNCTION__
);
133 NewProcs
= RtlAllocateHeap(CsrssApiHeap
, 0,
134 (InitCompleteProcCount
+ 1)
135 * sizeof(CSRPLUGIN_INIT_COMPLETE_PROC
));
136 if (NULL
== NewProcs
)
138 return STATUS_NO_MEMORY
;
140 if (0 != InitCompleteProcCount
)
142 RtlCopyMemory(NewProcs
, InitCompleteProcs
,
143 InitCompleteProcCount
* sizeof(CSRPLUGIN_INIT_COMPLETE_PROC
));
144 RtlFreeHeap(CsrssApiHeap
, 0, InitCompleteProcs
);
146 NewProcs
[InitCompleteProcCount
] = Proc
;
147 InitCompleteProcs
= NewProcs
;
148 InitCompleteProcCount
++;
150 return STATUS_SUCCESS
;
153 static NTSTATUS FASTCALL
154 CsrpAddHardErrorProc(CSRPLUGIN_HARDERROR_PROC Proc
)
156 CSRPLUGIN_HARDERROR_PROC
*NewProcs
;
158 DPRINT("CSR: %s called\n", __FUNCTION__
);
160 NewProcs
= RtlAllocateHeap(CsrssApiHeap
, 0,
161 (HardErrorProcCount
+ 1)
162 * sizeof(CSRPLUGIN_HARDERROR_PROC
));
163 if (NULL
== NewProcs
)
165 return STATUS_NO_MEMORY
;
167 if (0 != HardErrorProcCount
)
169 RtlCopyMemory(NewProcs
, HardErrorProcs
,
170 HardErrorProcCount
* sizeof(CSRPLUGIN_HARDERROR_PROC
));
171 RtlFreeHeap(CsrssApiHeap
, 0, HardErrorProcs
);
174 NewProcs
[HardErrorProcCount
] = Proc
;
175 HardErrorProcs
= NewProcs
;
176 HardErrorProcCount
++;
178 return STATUS_SUCCESS
;
181 /**********************************************************************
185 CallInitComplete(void)
190 DPRINT("CSR: %s called\n", __FUNCTION__
);
193 if (0 != InitCompleteProcCount
)
195 for (i
= 0; i
< InitCompleteProcCount
&& Ok
; i
++)
197 Ok
= (*(InitCompleteProcs
[i
]))();
199 RtlFreeHeap(CsrssApiHeap
, 0, InitCompleteProcs
);
206 CallHardError(IN PCSRSS_PROCESS_DATA ProcessData
,
207 IN PHARDERROR_MSG HardErrorMessage
)
212 DPRINT("CSR: %s called\n", __FUNCTION__
);
215 if (0 != HardErrorProcCount
)
217 for (i
= 0; i
< HardErrorProcCount
&& Ok
; i
++)
219 Ok
= (*(HardErrorProcs
[i
]))(ProcessData
, HardErrorMessage
);
227 InitializeVideoAddressSpace(VOID
);
229 /**********************************************************************
230 * CsrpCreateObjectDirectory/3
233 CsrpCreateObjectDirectory (int argc
, char ** argv
, char ** envp
)
236 OBJECT_ATTRIBUTES Attributes
;
238 DPRINT("CSR: %s called\n", __FUNCTION__
);
241 /* create object directory ('\Windows') */
242 RtlCreateUnicodeString (&CsrDirectoryName
,
245 InitializeObjectAttributes (&Attributes
,
251 Status
= NtOpenDirectoryObject(&CsrObjectDirectory
,
252 DIRECTORY_ALL_ACCESS
,
257 /**********************************************************************
260 * TODO: we need a virtual device for sessions other than
261 * TODO: the console one
264 CsrpInitVideo (int argc
, char ** argv
, char ** envp
)
266 OBJECT_ATTRIBUTES ObjectAttributes
;
267 UNICODE_STRING DeviceName
= RTL_CONSTANT_STRING(L
"\\??\\DISPLAY1");
268 IO_STATUS_BLOCK Iosb
;
269 HANDLE VideoHandle
= (HANDLE
) 0;
270 NTSTATUS Status
= STATUS_SUCCESS
;
272 DPRINT("CSR: %s called\n", __FUNCTION__
);
274 InitializeVideoAddressSpace();
276 InitializeObjectAttributes(&ObjectAttributes
,
281 Status
= NtOpenFile(&VideoHandle
,
287 if (NT_SUCCESS(Status
))
289 NtClose(VideoHandle
);
294 /**********************************************************************
297 * TODO: this function should be turned more general to load an
298 * TODO: hosted server DLL as received from the command line;
299 * TODO: for instance: ServerDll=winsrv:ConServerDllInitialization,2
300 * TODO: ^method ^dll ^api ^sid
302 * TODO: CsrpHostServerDll (LPWSTR DllName,
303 * TODO: LPWSTR ApiName,
304 * TODO: DWORD ServerId)
307 CsrpInitWin32Csr (int argc
, char ** argv
, char ** envp
)
310 UNICODE_STRING DllName
;
312 ANSI_STRING ProcName
;
313 CSRPLUGIN_INITIALIZE_PROC InitProc
;
314 CSRSS_EXPORTED_FUNCS Exports
;
315 PCSRSS_API_DEFINITION ApiDefinitions
;
316 PCSRSS_OBJECT_DEFINITION ObjectDefinitions
;
317 CSRPLUGIN_INIT_COMPLETE_PROC InitCompleteProc
;
318 CSRPLUGIN_HARDERROR_PROC HardErrorProc
;
320 DPRINT("CSR: %s called\n", __FUNCTION__
);
322 RtlInitUnicodeString(&DllName
, L
"win32csr.dll");
323 Status
= LdrLoadDll(NULL
, 0, &DllName
, (PVOID
*) &hInst
);
324 if (! NT_SUCCESS(Status
))
328 RtlInitAnsiString(&ProcName
, "Win32CsrInitialization");
329 Status
= LdrGetProcedureAddress(hInst
, &ProcName
, 0, (PVOID
*) &InitProc
);
330 if (! NT_SUCCESS(Status
))
334 Exports
.CsrInsertObjectProc
= CsrInsertObject
;
335 Exports
.CsrGetObjectProc
= CsrGetObject
;
336 Exports
.CsrReleaseObjectByPointerProc
= CsrReleaseObjectByPointer
;
337 Exports
.CsrReleaseObjectProc
= CsrReleaseObject
;
338 Exports
.CsrEnumProcessesProc
= CsrEnumProcesses
;
339 if (! (*InitProc
)(&ApiDefinitions
, &ObjectDefinitions
, &InitCompleteProc
,
340 &HardErrorProc
, &Exports
, CsrssApiHeap
))
342 return STATUS_UNSUCCESSFUL
;
345 Status
= CsrApiRegisterDefinitions(ApiDefinitions
);
346 if (! NT_SUCCESS(Status
))
350 Status
= CsrRegisterObjectDefinitions(ObjectDefinitions
);
351 if (! NT_SUCCESS(Status
))
355 if (NULL
!= InitCompleteProc
)
357 Status
= CsrpAddInitCompleteProc(InitCompleteProc
);
359 if (HardErrorProc
) Status
= CsrpAddHardErrorProc(HardErrorProc
);
364 CSRSS_API_DEFINITION NativeDefinitions
[] =
366 CSRSS_DEFINE_API(CREATE_PROCESS
, CsrCreateProcess
),
367 CSRSS_DEFINE_API(CREATE_THREAD
, CsrSrvCreateThread
),
368 CSRSS_DEFINE_API(TERMINATE_PROCESS
, CsrTerminateProcess
),
369 CSRSS_DEFINE_API(CONNECT_PROCESS
, CsrConnectProcess
),
370 CSRSS_DEFINE_API(REGISTER_SERVICES_PROCESS
, CsrRegisterServicesProcess
),
371 CSRSS_DEFINE_API(GET_SHUTDOWN_PARAMETERS
, CsrGetShutdownParameters
),
372 CSRSS_DEFINE_API(SET_SHUTDOWN_PARAMETERS
, CsrSetShutdownParameters
),
373 CSRSS_DEFINE_API(GET_INPUT_HANDLE
, CsrGetInputHandle
),
374 CSRSS_DEFINE_API(GET_OUTPUT_HANDLE
, CsrGetOutputHandle
),
375 CSRSS_DEFINE_API(CLOSE_HANDLE
, CsrCloseHandle
),
376 CSRSS_DEFINE_API(VERIFY_HANDLE
, CsrVerifyHandle
),
377 CSRSS_DEFINE_API(DUPLICATE_HANDLE
, CsrDuplicateHandle
),
378 CSRSS_DEFINE_API(GET_INPUT_WAIT_HANDLE
, CsrGetInputWaitHandle
),
382 static NTSTATUS WINAPI
383 CsrpCreateListenPort (IN LPWSTR Name
,
385 IN PTHREAD_START_ROUTINE ListenThread
)
387 NTSTATUS Status
= STATUS_SUCCESS
;
388 OBJECT_ATTRIBUTES PortAttributes
;
389 UNICODE_STRING PortName
;
393 DPRINT("CSR: %s called\n", __FUNCTION__
);
395 RtlInitUnicodeString (& PortName
, Name
);
396 InitializeObjectAttributes (& PortAttributes
,
401 Status
= NtCreatePort ( Port
,
403 LPC_MAX_DATA_LENGTH
, /* TODO: make caller set it*/
404 LPC_MAX_MESSAGE_LENGTH
, /* TODO: make caller set it*/
405 0); /* TODO: make caller set it*/
406 if(!NT_SUCCESS(Status
))
408 DPRINT1("CSR: %s: NtCreatePort failed (Status=%08lx)\n",
409 __FUNCTION__
, Status
);
412 Status
= RtlCreateUserThread(NtCurrentProcess(),
418 (PTHREAD_START_ROUTINE
) ListenThread
,
423 if (ListenThread
== (PVOID
)ClientConnectionThread
)
425 CsrAddStaticServerThread(ServerThread
, &ClientId
, 0);
428 NtResumeThread(ServerThread
, NULL
);
429 NtClose(ServerThread
);
433 /* === INIT ROUTINES === */
435 /**********************************************************************
436 * CsrpCreateBNODirectory/3
438 * These used to be part of kernel32 startup, but that clearly wasn't a good
439 * idea, as races were definately possible. These are moved (as in the
443 CsrpCreateBNODirectory (int argc
, char ** argv
, char ** envp
)
446 OBJECT_ATTRIBUTES ObjectAttributes
;
447 UNICODE_STRING Name
= RTL_CONSTANT_STRING(L
"\\BaseNamedObjects");
448 UNICODE_STRING SymName
= RTL_CONSTANT_STRING(L
"Local");
449 UNICODE_STRING SymName2
= RTL_CONSTANT_STRING(L
"Global");
450 HANDLE DirHandle
, SymHandle
;
452 /* Seems like a good place to create these objects which are needed by
454 InitializeObjectAttributes(&ObjectAttributes
,
456 OBJ_CASE_INSENSITIVE
,
460 Status
= NtCreateDirectoryObject(&DirHandle
,
461 DIRECTORY_ALL_ACCESS
,
463 if (!NT_SUCCESS(Status
))
465 DPRINT1("NtCreateDirectoryObject() failed %08x\n", Status
);
468 /* Create the "local" Symbolic Link.
469 * FIXME: CSR should do this -- Fixed */
470 InitializeObjectAttributes(&ObjectAttributes
,
472 OBJ_CASE_INSENSITIVE
,
475 Status
= NtCreateSymbolicLinkObject(&SymHandle
,
476 SYMBOLIC_LINK_ALL_ACCESS
,
479 if (!NT_SUCCESS(Status
))
481 DPRINT1("NtCreateDirectoryObject() failed %08x\n", Status
);
484 /* Create the "global" Symbolic Link. */
485 InitializeObjectAttributes(&ObjectAttributes
,
487 OBJ_CASE_INSENSITIVE
,
490 Status
= NtCreateSymbolicLinkObject(&SymHandle
,
491 SYMBOLIC_LINK_ALL_ACCESS
,
494 if (!NT_SUCCESS(Status
))
496 DPRINT1("NtCreateDirectoryObject() failed %08x\n", Status
);
502 /**********************************************************************
506 CsrpCreateHeap (int argc
, char ** argv
, char ** envp
)
508 DPRINT("CSR: %s called\n", __FUNCTION__
);
510 CsrssApiHeap
= RtlCreateHeap(HEAP_GROWABLE
,
516 if (CsrssApiHeap
== NULL
)
518 return STATUS_UNSUCCESSFUL
;
520 return STATUS_SUCCESS
;
523 /**********************************************************************
524 * CsrpCreateCallbackPort/3
527 CsrpCreateCallbackPort (int argc
, char ** argv
, char ** envp
)
529 DPRINT("CSR: %s called\n", __FUNCTION__
);
531 return CsrpCreateListenPort (L
"\\Windows\\SbApiPort",
533 ServerSbApiPortThread
);
536 /**********************************************************************
537 * CsrpRegisterSubsystem/3
540 CsrpRegisterSubsystem (int argc
, char ** argv
, char ** envp
)
542 NTSTATUS Status
= STATUS_SUCCESS
;
543 OBJECT_ATTRIBUTES BootstrapOkAttributes
;
546 DPRINT("CSR: %s called\n", __FUNCTION__
);
549 * Create the event object the callback port
550 * thread will signal *if* the SM will
551 * authorize us to bootstrap.
553 RtlInitUnicodeString (& Name
, L
"\\CsrssBooting");
554 InitializeObjectAttributes(& BootstrapOkAttributes
,
557 Status
= NtCreateEvent (& hBootstrapOk
,
559 & BootstrapOkAttributes
,
560 SynchronizationEvent
,
562 if(!NT_SUCCESS(Status
))
564 DPRINT("CSR: %s: NtCreateEvent failed (Status=0x%08lx)\n",
565 __FUNCTION__
, Status
);
569 * Let's tell the SM a new environment
570 * subsystem server is in the system.
572 RtlInitUnicodeString (& Name
, L
"\\Windows\\SbApiPort");
573 DPRINT("CSR: %s: registering with SM for\n IMAGE_SUBSYSTEM_WINDOWS_CUI == 3\n", __FUNCTION__
);
574 Status
= SmConnectApiPort (& Name
,
576 IMAGE_SUBSYSTEM_WINDOWS_CUI
,
578 if(!NT_SUCCESS(Status
))
580 DPRINT("CSR: %s unable to connect to the SM (Status=0x%08lx)\n",
581 __FUNCTION__
, Status
);
582 NtClose (hBootstrapOk
);
586 * Wait for SM to reply OK... If the SM
587 * won't answer, we hang here forever!
589 DPRINT("CSR: %s: waiting for SM to OK boot...\n", __FUNCTION__
);
590 Status
= NtWaitForSingleObject (hBootstrapOk
,
593 NtClose (hBootstrapOk
);
597 /**********************************************************************
598 * CsrpLoadKernelModeDriver/3
601 CsrpLoadKernelModeDriver (int argc
, char ** argv
, char ** envp
)
603 NTSTATUS Status
= STATUS_SUCCESS
;
604 WCHAR Data
[MAX_PATH
+ 1];
605 ULONG DataLength
= sizeof Data
;
607 //UNICODE_STRING Environment;
610 DPRINT1("SM: %s called\n", __FUNCTION__
);
613 //EnvpToUnicodeString (envp, & Environment);
614 Status
= SmLookupSubsystem (L
"Kmode",
619 //RtlFreeUnicodeString (& Environment);
620 if((STATUS_SUCCESS
== Status
) && (DataLength
> sizeof Data
[0]))
622 WCHAR ImagePath
[MAX_PATH
+ 1] = {0};
623 UNICODE_STRING ModuleName
;
625 wcscpy (ImagePath
, L
"\\??\\c:\\reactos\\system32\\win32k.sys");
626 // wcscat (ImagePath, Data);
627 RtlInitUnicodeString (& ModuleName
, ImagePath
);
628 Status
= NtSetSystemInformation(/* FIXME: SystemLoadAndCallImage */
629 SystemExtendServiceTableInformation
,
632 if(!NT_SUCCESS(Status
))
634 DPRINT1("WIN: %s: loading Kmode failed (Status=0x%08lx)\n",
635 __FUNCTION__
, Status
);
641 /**********************************************************************
642 * CsrpCreateApiPort/2
645 CsrpCreateApiPort (int argc
, char ** argv
, char ** envp
)
647 DPRINT("CSR: %s called\n", __FUNCTION__
);
649 CsrInitProcessData();
651 return CsrpCreateListenPort(L
"\\Windows\\ApiPort", &hApiPort
,
652 (PTHREAD_START_ROUTINE
)ClientConnectionThread
);
655 /**********************************************************************
656 * CsrpApiRegisterDef/0
659 CsrpApiRegisterDef (int argc
, char ** argv
, char ** envp
)
661 return CsrApiRegisterDefinitions(NativeDefinitions
);
664 /**********************************************************************
668 CsrpCCTS (int argc
, char ** argv
, char ** envp
)
671 ULONG DummyLength
= sizeof(Dummy
);
672 return CsrClientConnectToServer(L
"\\Windows",
673 0, &Dummy
, &DummyLength
, NULL
);
676 /**********************************************************************
679 * Start the logon process (winlogon.exe).
681 * TODO: this should be moved in CsrpCreateSession/x (one per session)
682 * TODO: in its own desktop (one logon desktop per winstation).
685 CsrpRunWinlogon (int argc
, char ** argv
, char ** envp
)
687 NTSTATUS Status
= STATUS_SUCCESS
;
688 UNICODE_STRING ImagePath
;
689 UNICODE_STRING CommandLine
;
690 PRTL_USER_PROCESS_PARAMETERS ProcessParameters
= NULL
;
691 RTL_USER_PROCESS_INFORMATION ProcessInfo
;
694 DPRINT("CSR: %s called\n", __FUNCTION__
);
696 /* initialize the process parameters */
697 RtlInitUnicodeString (& ImagePath
, L
"\\SystemRoot\\system32\\winlogon.exe");
698 RtlInitUnicodeString (& CommandLine
, L
"");
699 RtlCreateProcessParameters(& ProcessParameters
,
709 /* Create the winlogon process */
710 Status
= RtlCreateUserProcess (& ImagePath
,
711 OBJ_CASE_INSENSITIVE
,
721 RtlDestroyProcessParameters (ProcessParameters
);
722 if (!NT_SUCCESS(Status
))
724 DPRINT1("SM: %s: loading winlogon.exe failed (Status=%08lx)\n",
725 __FUNCTION__
, Status
);
728 ZwResumeThread(ProcessInfo
.ThreadHandle
, NULL
);
733 CsrpCreateHardErrorPort (int argc
, char ** argv
, char ** envp
)
735 return NtSetDefaultHardErrorPort(hApiPort
);
738 typedef NTSTATUS (* CSR_INIT_ROUTINE
)(int,char**,char**);
742 CSR_INIT_ROUTINE EntryPoint
;
745 {TRUE
, CsrpCreateBNODirectory
, "create base named objects directory"},
746 {TRUE
, CsrpCreateCallbackPort
, "create the callback port \\Windows\\SbApiPort"},
747 {TRUE
, CsrpRegisterSubsystem
, "register with SM"},
748 {TRUE
, CsrpCreateHeap
, "create the CSR heap"},
749 {TRUE
, CsrpCreateApiPort
, "create the api port \\Windows\\ApiPort"},
750 {TRUE
, CsrpCreateHardErrorPort
, "create the hard error port"},
751 {TRUE
, CsrpCreateObjectDirectory
,"create the object directory \\Windows"},
752 {TRUE
, CsrpLoadKernelModeDriver
, "load Kmode driver"},
753 {TRUE
, CsrpInitVideo
, "initialize video"},
754 {TRUE
, CsrpApiRegisterDef
, "initialize api definitions"},
755 {TRUE
, CsrpCCTS
, "connect client to server"},
756 {TRUE
, CsrpInitWin32Csr
, "load usermode dll"},
757 {TRUE
, CsrpRunWinlogon
, "run WinLogon"},
760 /* PUBLIC FUNCTIONS ***********************************************************/
764 CsrServerInitialization(ULONG ArgumentCount
,
768 NTSTATUS Status
= STATUS_SUCCESS
;
770 DPRINT("CSR: %s called\n", __FUNCTION__
);
772 for (i
=0; i
< (sizeof InitRoutine
/ sizeof InitRoutine
[0]); i
++)
774 Status
= InitRoutine
[i
].EntryPoint(ArgumentCount
,Arguments
,NULL
);
775 if(!NT_SUCCESS(Status
))
777 DPRINT1("CSR: %s: failed to %s (Status=%08lx)\n",
779 InitRoutine
[i
].ErrorMessage
,
781 if (InitRoutine
[i
].Required
)
787 if (CallInitComplete())
789 Status
= SmCompleteSession (hSmApiPort
,hSbApiPort
,hApiPort
);
790 return STATUS_SUCCESS
;
793 return STATUS_UNSUCCESSFUL
;
798 DllMainCRTStartup(HANDLE hDll
,
802 /* We don't do much */
803 UNREFERENCED_PARAMETER(hDll
);
804 UNREFERENCED_PARAMETER(dwReason
);
805 UNREFERENCED_PARAMETER(lpReserved
);