3 #include <ndk/cmfuncs.h>
5 #include <wine/debug.h>
6 WINE_DEFAULT_DEBUG_CHANNEL(user32
);
8 #define KEY_LENGTH 1024
10 static ULONG User32TlsIndex
;
11 HINSTANCE User32Instance
;
13 PPROCESSINFO g_ppi
= NULL
;
14 PUSER_HANDLE_TABLE gHandleTable
= NULL
;
15 PUSER_HANDLE_ENTRY gHandleEntries
= NULL
;
16 PSERVERINFO gpsi
= NULL
;
17 SHAREDINFO gSharedInfo
= {0};
18 ULONG_PTR g_ulSharedDelta
;
19 BOOLEAN gfLogonProcess
= FALSE
;
20 BOOLEAN gfServerProcess
= FALSE
;
21 BOOLEAN gfFirstThread
= TRUE
;
22 HICON hIconSmWindows
= NULL
, hIconWindows
= NULL
;
24 WCHAR szAppInit
[KEY_LENGTH
];
30 OBJECT_ATTRIBUTES Attributes
;
35 PKEY_VALUE_PARTIAL_INFORMATION kvpInfo
= NULL
;
37 UNICODE_STRING szKeyName
= RTL_CONSTANT_STRING(L
"\\Registry\\Machine\\Software\\Microsoft\\Windows NT\\CurrentVersion\\Windows");
38 UNICODE_STRING szLoadName
= RTL_CONSTANT_STRING(L
"LoadAppInit_DLLs");
39 UNICODE_STRING szDllsName
= RTL_CONSTANT_STRING(L
"AppInit_DLLs");
41 InitializeObjectAttributes(&Attributes
, &szKeyName
, OBJ_CASE_INSENSITIVE
, NULL
, NULL
);
42 Status
= NtOpenKey(&hKey
, KEY_READ
, &Attributes
);
43 if (NT_SUCCESS(Status
))
45 dwSize
= sizeof(KEY_VALUE_PARTIAL_INFORMATION
) + sizeof(DWORD
);
46 kvpInfo
= HeapAlloc(GetProcessHeap(), 0, dwSize
);
50 Status
= NtQueryValueKey(hKey
,
52 KeyValuePartialInformation
,
56 if (!NT_SUCCESS(Status
))
63 HeapFree(GetProcessHeap(), 0, kvpInfo
);
68 Status
= NtQueryValueKey(hKey
,
70 KeyValuePartialInformation
,
74 if (Status
!= STATUS_BUFFER_TOO_SMALL
)
77 kvpInfo
= HeapAlloc(GetProcessHeap(), 0, dwSize
);
81 Status
= NtQueryValueKey(hKey
,
83 KeyValuePartialInformation
,
87 if (NT_SUCCESS(Status
))
89 LPWSTR lpBuffer
= (LPWSTR
)kvpInfo
->Data
;
90 if (*lpBuffer
!= UNICODE_NULL
)
92 INT bytesToCopy
, nullPos
;
94 bytesToCopy
= min(kvpInfo
->DataLength
, KEY_LENGTH
* sizeof(WCHAR
));
98 RtlMoveMemory(szAppInit
,
102 nullPos
= (bytesToCopy
/ sizeof(WCHAR
)) - 1;
104 /* ensure string is terminated */
105 szAppInit
[nullPos
] = UNICODE_NULL
;
119 HeapFree(GetProcessHeap(), 0, kvpInfo
);
128 szAppInit
[0] = UNICODE_NULL
;
132 WCHAR buffer
[KEY_LENGTH
];
136 RtlCopyMemory(buffer
, szAppInit
, KEY_LENGTH
* sizeof(WCHAR
) );
138 for (i
= 0; i
< KEY_LENGTH
; ++ i
)
140 if(buffer
[i
] == L
' ' || buffer
[i
] == L
',')
144 for (i
= 0; i
< KEY_LENGTH
; )
161 if (szAppInit
[0] != UNICODE_NULL
)
163 WCHAR buffer
[KEY_LENGTH
];
168 RtlCopyMemory(buffer
, szAppInit
, KEY_LENGTH
* sizeof(WCHAR
));
170 for (i
= 0; i
< KEY_LENGTH
; ++ i
)
172 if(buffer
[i
] == L
' ' || buffer
[i
] == L
',')
176 for (i
= 0; i
< KEY_LENGTH
; )
184 hModule
= GetModuleHandleW(ptr
);
185 FreeLibrary(hModule
);
191 PVOID apfnDispatch
[USER32_CALLBACK_MAXIMUM
+ 1] =
193 User32CallWindowProcFromKernel
,
194 User32CallSendAsyncProcForKernel
,
195 User32LoadSysMenuTemplateForKernel
,
196 User32SetupDefaultCursors
,
197 User32CallHookProcFromKernel
,
198 User32CallEventProcFromKernel
,
199 User32CallLoadMenuFromKernel
,
200 User32CallClientThreadSetupFromKernel
,
201 User32CallClientLoadLibraryFromKernel
,
202 User32CallGetCharsetInfo
,
203 User32CallCopyImageFromKernel
,
204 User32CallSetWndIconsFromKernel
,
205 User32DeliverUserAPC
,
206 User32CallDDEPostFromKernel
,
207 User32CallDDEGetFromKernel
,
214 GdiProcessSetup(VOID
);
218 ClientThreadSetupHelper(BOOL IsCallback
)
221 * Normally we are called by win32k so the win32 thread pointers
222 * should be valid as they are set in win32k::InitThreadCallback.
224 PCLIENTINFO ClientInfo
= GetWin32ClientInfo();
225 BOOLEAN IsFirstThread
= _InterlockedExchange8((PCHAR
)&gfFirstThread
, FALSE
);
227 TRACE("In ClientThreadSetup(IsCallback == %s, gfServerProcess = %s, IsFirstThread = %s)\n",
228 IsCallback
? "TRUE" : "FALSE", gfServerProcess
? "TRUE" : "FALSE", IsFirstThread
? "TRUE" : "FALSE");
233 /* Check for already initialized thread, and bail out if so */
234 if (ClientInfo
->CI_flags
& CI_INITTHREAD
)
236 ERR("ClientThreadSetup: Thread already initialized.\n");
241 * CSRSS couldn't use user32::DllMain CSR server-to-server call to connect
242 * to win32k. So it is delayed to a manually-call to ClientThreadSetup.
243 * Also this needs to be done only for the first thread (since the connection
246 if (gfServerProcess
&& IsFirstThread
)
251 RtlZeroMemory(&UserCon
, sizeof(UserCon
));
253 /* Minimal setup of the connect info structure */
254 UserCon
.ulVersion
= USER_VERSION
;
256 /* Connect to win32k */
257 Status
= NtUserProcessConnect(NtCurrentProcess(),
260 if (!NT_SUCCESS(Status
)) return FALSE
;
263 g_ppi
= ClientInfo
->ppi
; // Snapshot PI, used as pointer only!
264 g_ulSharedDelta
= UserCon
.siClient
.ulSharedDelta
;
265 gpsi
= SharedPtrToUser(UserCon
.siClient
.psi
);
266 gHandleTable
= SharedPtrToUser(UserCon
.siClient
.aheList
);
267 gHandleEntries
= SharedPtrToUser(gHandleTable
->handles
);
268 gSharedInfo
= UserCon
.siClient
;
270 // ERR("1 SI 0x%x : HT 0x%x : D 0x%x\n", UserCon.siClient.psi, UserCon.siClient.aheList, g_ulSharedDelta);
273 TRACE("Checkpoint (register PFN)\n");
274 if (!RegisterClientPFN())
276 ERR("RegisterClientPFN failed\n");
280 /* Mark this thread as initialized */
281 ClientInfo
->CI_flags
|= CI_INITTHREAD
;
283 /* Initialization that should be done once per process */
286 TRACE("Checkpoint (Allocating TLS)\n");
288 /* Allocate an index for user32 thread local data */
289 User32TlsIndex
= TlsAlloc();
290 if (User32TlsIndex
== TLS_OUT_OF_INDEXES
)
293 // HAAAAAAAAAACK!!!!!!
295 if (!gpsi
) ERR("AAAAAAAAAAAHHHHHHHHHHHHHH!!!!!!!! gpsi == NULL !!!!\n");
298 TRACE("Checkpoint (MessageInit)\n");
302 TRACE("Checkpoint (MenuInit)\n");
305 TRACE("Checkpoint initialization done OK\n");
306 InitializeCriticalSection(&U32AccelCacheLock
);
313 TlsFree(User32TlsIndex
);
326 ClientThreadSetup(VOID
)
329 // This routine, in Windows, does a lot of what Init does, but in a radically
332 // In Windows, because CSRSS's threads have TIF_CSRSSTHREAD set (we have this
333 // flag in ROS but not sure if we use it), the xxxClientThreadSetup callback
334 // isn't made when CSRSS first loads WINSRV.DLL (which loads USER32.DLL).
336 // However, all the other calls are made as normal, and WINSRV.DLL loads
337 // USER32.dll, the DllMain runs, and eventually the first NtUser system call is
338 // made which initializes Win32k (and initializes the thread, but as mentioned
339 // above, the thread is marked as TIF_CSRSSTHREAD).
341 // In the DllMain of User32, there is also a CsrClientConnectToServer call to
342 // server 2 (winsrv). When this is done from CSRSS, the "InServer" flag is set,
343 // so user32 will remember that it's running inside of CSRSS. Also, another
344 // flag, called "FirstThread" is manually set by DllMain.
346 // Then, WINSRV finishes loading, and CSRSRV starts the API thread/loop. This
347 // code then calls CsrConnectToUser, which calls... ClientThreadStartup. Now
348 // this routine detects that it's in the server process, which means it's CSRSS
349 // and that the callback never happened. It does some first-time-Win32k connection
350 // initialization and caches a bunch of things -- if it's the first thread. It also
351 // acquires a critical section to initialize GDI -- and then resets the first thread
354 // For now, we'll do none of this, but to support Windows' CSRSRV.DLL which calls
355 // CsrConnectToUser, we'll pretend we "did something" here. Then the rest will
356 // continue as normal.
359 // FIXME: Disabling this call is a HACK!! See also User32CallClientThreadSetupFromKernel...
360 // return ClientThreadSetupHelper(FALSE);
366 Init(PUSERCONNECT UserCon
/*PUSERSRV_API_CONNECTINFO*/)
368 NTSTATUS Status
= STATUS_SUCCESS
;
370 TRACE("user32::Init(0x%p) -->\n", UserCon
);
372 RtlInitializeCriticalSection(&gcsUserApiHook
);
374 /* Initialize callback table in PEB data */
375 NtCurrentPeb()->KernelCallbackTable
= apfnDispatch
;
376 NtCurrentPeb()->PostProcessInitRoutine
= NULL
;
378 // This is a HACK!! //
379 gfServerProcess
= FALSE
;
380 gfFirstThread
= TRUE
;
381 //// End of HACK!! ///
384 * Retrieve data from the connect info structure if the initializing
385 * process is not CSRSS. In case it is, this will be done from inside
388 if (!gfServerProcess
)
390 // FIXME: HACK!! We should fixup for the NtUserProcessConnect fixups
391 // because it was made in the context of CSRSS process and not ours!!
392 // So... as long as we don't fix that, we need to redo again a call
393 // to NtUserProcessConnect... How perverse is that?!
395 // HACK(2): This call is necessary since we disabled
396 // the CSR call in DllMain...
398 RtlZeroMemory(UserCon
, sizeof(*UserCon
));
400 /* Minimal setup of the connect info structure */
401 UserCon
->ulVersion
= USER_VERSION
;
403 TRACE("HACK: Hackish NtUserProcessConnect call!!\n");
404 /* Connect to win32k */
405 Status
= NtUserProcessConnect(NtCurrentProcess(),
408 if (!NT_SUCCESS(Status
)) return FALSE
;
412 // We continue as we should do normally...
416 g_ppi
= GetWin32ClientInfo()->ppi
; // Snapshot PI, used as pointer only!
417 g_ulSharedDelta
= UserCon
->siClient
.ulSharedDelta
;
418 gpsi
= SharedPtrToUser(UserCon
->siClient
.psi
);
419 gHandleTable
= SharedPtrToUser(UserCon
->siClient
.aheList
);
420 gHandleEntries
= SharedPtrToUser(gHandleTable
->handles
);
421 gSharedInfo
= UserCon
->siClient
;
424 // FIXME: Yet another hack... This call should normally not be done here, but
425 // instead in ClientThreadSetup, and in User32CallClientThreadSetupFromKernel as well.
426 TRACE("HACK: Using Init-ClientThreadSetupHelper hack!!\n");
427 if (!ClientThreadSetupHelper(FALSE
))
429 TRACE("Init-ClientThreadSetupHelper hack failed!\n");
433 TRACE("<-- user32::Init()\n");
435 return NT_SUCCESS(Status
);
442 DeleteCriticalSection(&U32AccelCacheLock
);
445 TlsFree(User32TlsIndex
);
446 DeleteFrameBrushes();
451 IN PVOID hInstanceDll
,
457 case DLL_PROCESS_ATTACH
:
460 #define WIN_OBJ_DIR L"\\Windows"
461 #define SESSION_DIR L"\\Sessions"
463 USERSRV_API_CONNECTINFO ConnectInfo
; // USERCONNECT
465 #if 0 // Disabling this code is a BIG HACK!!
468 ULONG ConnectInfoSize
= sizeof(ConnectInfo
);
469 WCHAR SessionDir
[256];
471 /* Cache the PEB and Session ID */
472 PPEB Peb
= NtCurrentPeb();
473 ULONG SessionId
= Peb
->SessionId
; // gSessionId
475 TRACE("user32::DllMain\n");
477 /* Don't bother us for each thread */
478 DisableThreadLibraryCalls(hInstanceDll
);
480 RtlZeroMemory(&ConnectInfo
, sizeof(ConnectInfo
));
482 /* Minimal setup of the connect info structure */
483 ConnectInfo
.ulVersion
= USER_VERSION
;
485 /* Setup the Object Directory path */
488 /* Use the raw path */
489 wcscpy(SessionDir
, WIN_OBJ_DIR
);
493 /* Use the session path */
501 TRACE("Checkpoint (call CSR)\n");
503 /* Connect to the USER Server */
504 Status
= CsrClientConnectToServer(SessionDir
,
505 USERSRV_SERVERDLL_INDEX
,
509 if (!NT_SUCCESS(Status
))
511 ERR("Failed to connect to CSR (Status %lx)\n", Status
);
515 TRACE("Checkpoint (CSR called)\n");
519 User32Instance
= hInstanceDll
;
521 /* Finish initialization */
522 TRACE("Checkpoint (call Init)\n");
523 if (!Init(&ConnectInfo
))
526 if (!gfServerProcess
)
528 //InitializeImmEntryTable();
530 // Wine is stub and throws an exception so save this for real Imm32.dll testing!!!!
532 //gImmApiEntries.pImmRegisterClient(&gSharedInfo, ghImm32);
538 case DLL_PROCESS_DETACH
:
541 FreeLibrary(ghImm32
);
548 /* Finally, initialize GDI */
549 return GdiDllInitialize(hInstanceDll
, dwReason
, reserved
);
554 User32CallClientThreadSetupFromKernel(PVOID Arguments
, ULONG ArgumentLength
)
556 TRACE("User32CallClientThreadSetupFromKernel -->\n");
557 // FIXME: Disabling this call is a HACK!! See also ClientThreadSetup...
558 // ClientThreadSetupHelper(TRUE);
559 TRACE("<-- User32CallClientThreadSetupFromKernel\n");
560 return ZwCallbackReturn(NULL
, 0, STATUS_SUCCESS
);
565 User32CallGetCharsetInfo(PVOID Arguments
, ULONG ArgumentLength
)
568 PGET_CHARSET_INFO pgci
= (PGET_CHARSET_INFO
)Arguments
;
570 TRACE("GetCharsetInfo\n");
572 Ret
= TranslateCharsetInfo((DWORD
*)pgci
->Locale
, &pgci
->Cs
, TCI_SRCLOCALE
);
574 return ZwCallbackReturn(Arguments
, ArgumentLength
, Ret
? STATUS_SUCCESS
: STATUS_UNSUCCESSFUL
);
579 User32CallSetWndIconsFromKernel(PVOID Arguments
, ULONG ArgumentLength
)
581 PSETWNDICONS_CALLBACK_ARGUMENTS Common
= Arguments
;
583 if (!gpsi
->hIconSmWindows
)
585 Common
->hIconSample
= LoadImageW(0, IDI_APPLICATION
, IMAGE_ICON
, 0, 0, LR_DEFAULTSIZE
);
586 Common
->hIconHand
= LoadImageW(0, IDI_HAND
, IMAGE_ICON
, 0, 0, LR_DEFAULTSIZE
);
587 Common
->hIconQuestion
= LoadImageW(0, IDI_QUESTION
, IMAGE_ICON
, 0, 0, LR_DEFAULTSIZE
);
588 Common
->hIconBang
= LoadImageW(0, IDI_EXCLAMATION
, IMAGE_ICON
, 0, 0, LR_DEFAULTSIZE
);
589 Common
->hIconNote
= LoadImageW(0, IDI_ASTERISK
, IMAGE_ICON
, 0, 0, LR_DEFAULTSIZE
);
590 Common
->hIconWindows
= LoadImageW(0, IDI_WINLOGO
, IMAGE_ICON
, 0, 0, LR_DEFAULTSIZE
);
591 Common
->hIconSmWindows
= LoadImageW(0, IDI_WINLOGO
, IMAGE_ICON
, GetSystemMetrics(SM_CXSMICON
), GetSystemMetrics(SM_CYSMICON
), 0);
592 hIconWindows
= Common
->hIconWindows
;
593 hIconSmWindows
= Common
->hIconSmWindows
;
595 ERR("hIconSmWindows %p hIconWindows %p \n",hIconSmWindows
,hIconWindows
);
596 return ZwCallbackReturn(Arguments
, ArgumentLength
, STATUS_SUCCESS
);
601 User32DeliverUserAPC(PVOID Arguments
, ULONG ArgumentLength
)
603 return ZwCallbackReturn(0, 0, STATUS_SUCCESS
);