Files
reactos/win32ss/user/user32/misc/dllmain.c
T
Amine Khaldi 121bde3b83 * Sync up to trunk HEAD (r62286).
svn path=/branches/ntvdm/; revision=62287
2014-02-22 10:50:51 +00:00

425 lines
11 KiB
C

#include <user32.h>
#include <ndk/cmfuncs.h>
#include <wine/debug.h>
WINE_DEFAULT_DEBUG_CHANNEL(user32);
#define KEY_LENGTH 1024
static ULONG User32TlsIndex;
HINSTANCE User32Instance;
PPROCESSINFO g_ppi = NULL;
PUSER_HANDLE_TABLE gHandleTable = NULL;
PUSER_HANDLE_ENTRY gHandleEntries = NULL;
PSERVERINFO gpsi = NULL;
ULONG_PTR g_ulSharedDelta;
BOOLEAN gfLogonProcess = FALSE;
BOOLEAN gfServerProcess = FALSE;
HICON hIconSmWindows = NULL, hIconWindows = NULL;
WCHAR szAppInit[KEY_LENGTH];
BOOL
GetDllList()
{
NTSTATUS Status;
OBJECT_ATTRIBUTES Attributes;
BOOL bRet = FALSE;
BOOL bLoad;
HANDLE hKey = NULL;
DWORD dwSize;
PKEY_VALUE_PARTIAL_INFORMATION kvpInfo = NULL;
UNICODE_STRING szKeyName = RTL_CONSTANT_STRING(L"\\Registry\\Machine\\Software\\Microsoft\\Windows NT\\CurrentVersion\\Windows");
UNICODE_STRING szLoadName = RTL_CONSTANT_STRING(L"LoadAppInit_DLLs");
UNICODE_STRING szDllsName = RTL_CONSTANT_STRING(L"AppInit_DLLs");
InitializeObjectAttributes(&Attributes, &szKeyName, OBJ_CASE_INSENSITIVE, NULL, NULL);
Status = NtOpenKey(&hKey, KEY_READ, &Attributes);
if (NT_SUCCESS(Status))
{
dwSize = sizeof(KEY_VALUE_PARTIAL_INFORMATION) + sizeof(DWORD);
kvpInfo = HeapAlloc(GetProcessHeap(), 0, dwSize);
if (!kvpInfo)
goto end;
Status = NtQueryValueKey(hKey,
&szLoadName,
KeyValuePartialInformation,
kvpInfo,
dwSize,
&dwSize);
if (!NT_SUCCESS(Status))
goto end;
RtlMoveMemory(&bLoad,
kvpInfo->Data,
kvpInfo->DataLength);
HeapFree(GetProcessHeap(), 0, kvpInfo);
kvpInfo = NULL;
if (bLoad)
{
Status = NtQueryValueKey(hKey,
&szDllsName,
KeyValuePartialInformation,
NULL,
0,
&dwSize);
if (Status != STATUS_BUFFER_TOO_SMALL)
goto end;
kvpInfo = HeapAlloc(GetProcessHeap(), 0, dwSize);
if (!kvpInfo)
goto end;
Status = NtQueryValueKey(hKey,
&szDllsName,
KeyValuePartialInformation,
kvpInfo,
dwSize,
&dwSize);
if (NT_SUCCESS(Status))
{
LPWSTR lpBuffer = (LPWSTR)kvpInfo->Data;
if (*lpBuffer != UNICODE_NULL)
{
INT bytesToCopy, nullPos;
bytesToCopy = min(kvpInfo->DataLength, KEY_LENGTH * sizeof(WCHAR));
if (bytesToCopy != 0)
{
RtlMoveMemory(szAppInit,
kvpInfo->Data,
bytesToCopy);
nullPos = (bytesToCopy / sizeof(WCHAR)) - 1;
/* ensure string is terminated */
szAppInit[nullPos] = UNICODE_NULL;
bRet = TRUE;
}
}
}
}
}
end:
if (hKey)
NtClose(hKey);
if (kvpInfo)
HeapFree(GetProcessHeap(), 0, kvpInfo);
return bRet;
}
VOID
LoadAppInitDlls()
{
szAppInit[0] = UNICODE_NULL;
if (GetDllList())
{
WCHAR buffer[KEY_LENGTH];
LPWSTR ptr;
size_t i;
RtlCopyMemory(buffer, szAppInit, KEY_LENGTH);
for (i = 0; i < KEY_LENGTH; ++ i)
{
if(buffer[i] == L' ' || buffer[i] == L',')
buffer[i] = 0;
}
for (i = 0; i < KEY_LENGTH; )
{
if(buffer[i] == 0)
++ i;
else
{
ptr = buffer + i;
i += wcslen(ptr);
LoadLibraryW(ptr);
}
}
}
}
VOID
UnloadAppInitDlls()
{
if (szAppInit[0] != UNICODE_NULL)
{
WCHAR buffer[KEY_LENGTH];
HMODULE hModule;
LPWSTR ptr;
size_t i;
RtlCopyMemory(buffer, szAppInit, KEY_LENGTH * sizeof(WCHAR));
for (i = 0; i < KEY_LENGTH; ++ i)
{
if(buffer[i] == L' ' || buffer[i] == L',')
buffer[i] = 0;
}
for (i = 0; i < KEY_LENGTH; )
{
if(buffer[i] == 0)
++ i;
else
{
ptr = buffer + i;
i += wcslen(ptr);
hModule = GetModuleHandleW(ptr);
FreeLibrary(hModule);
}
}
}
}
BOOL
InitThread(VOID)
{
return TRUE;
}
VOID
CleanupThread(VOID)
{
}
PVOID apfnDispatch[USER32_CALLBACK_MAXIMUM + 1] =
{
User32CallWindowProcFromKernel,
User32CallSendAsyncProcForKernel,
User32LoadSysMenuTemplateForKernel,
User32SetupDefaultCursors,
User32CallHookProcFromKernel,
User32CallEventProcFromKernel,
User32CallLoadMenuFromKernel,
User32CallClientThreadSetupFromKernel,
User32CallClientLoadLibraryFromKernel,
User32CallGetCharsetInfo,
User32CallCopyImageFromKernel,
User32CallSetWndIconsFromKernel,
};
/*
* @unimplemented
*/
BOOL
WINAPI
ClientThreadSetup(VOID)
{
//
// This routine, in Windows, does a lot of what Init does, but in a radically
// different way.
//
// In Windows, because CSRSS's threads have TIF_CSRSSTHREAD set (we have this
// flag in ROS but not sure if we use it), the xxxClientThreadSetup callback
// isn't made when CSRSS first loads WINSRV.DLL (which loads USER32.DLL).
//
// However, all the other calls are made as normal, and WINSRV.DLL loads
// USER32.dll, the DllMain runs, and eventually the first NtUser system call is
// made which initializes Win32k (and initializes the thread, but as mentioned
// above, the thread is marked as TIF_CSRSSTHREAD.
//
// In the DllMain of User32, there is also a CsrClientConnectToServer call to
// server 2 (winsrv). When this is done from CSRSS, the "InServer" flag is set,
// so user32 will remember that it's running inside of CSRSS. Also, another
// flag, called "FirstThread" is manually set by DllMain.
//
// Then, WINSRV finishes loading, and CSRSRV starts the API thread/loop. This
// code then calls CsrConnectToUser, which calls... ClientThreadStartup. Now
// this routine detects that it's in the server process, which means it's CSRSS
// and that the callback never happened. It does some first-time-Win32k connection
// initialization and caches a bunch of things -- if it's the first thread. It also
// acquires a critical section to initialize GDI -- and then resets the first thread
// flag.
//
// For now, we'll do none of this, but to support Windows' CSRSRV.DLL which calls
// CsrConnectToUser, we'll pretend we "did something" here. Then the rest will
// continue as normal.
//
UNIMPLEMENTED;
return TRUE;
}
BOOL
Init(VOID)
{
USERCONNECT UserCon;
/* Set PEB data */
NtCurrentPeb()->KernelCallbackTable = apfnDispatch;
NtCurrentPeb()->PostProcessInitRoutine = NULL;
NtUserProcessConnect( NtCurrentProcess(),
&UserCon,
sizeof(USERCONNECT));
g_ppi = GetWin32ClientInfo()->ppi; // Snapshot PI, used as pointer only!
g_ulSharedDelta = UserCon.siClient.ulSharedDelta;
gpsi = SharedPtrToUser(UserCon.siClient.psi);
gHandleTable = SharedPtrToUser(UserCon.siClient.aheList);
gHandleEntries = SharedPtrToUser(gHandleTable->handles);
RtlInitializeCriticalSection(&gcsUserApiHook);
gfServerProcess = FALSE; // FIXME HAX! Used in CsrClientConnectToServer(,,,,&gfServerProcess);
//CsrClientConnectToServer(L"\\Windows", 0, NULL, 0, &gfServerProcess);
//ERR("1 SI 0x%x : HT 0x%x : D 0x%x\n", UserCon.siClient.psi, UserCon.siClient.aheList, g_ulSharedDelta);
/* Allocate an index for user32 thread local data. */
User32TlsIndex = TlsAlloc();
if (User32TlsIndex != TLS_OUT_OF_INDEXES)
{
if (MessageInit())
{
if (MenuInit())
{
InitializeCriticalSection(&U32AccelCacheLock);
GdiDllInitialize(NULL, DLL_PROCESS_ATTACH, NULL);
LoadAppInitDlls();
return TRUE;
}
MessageCleanup();
}
TlsFree(User32TlsIndex);
}
return FALSE;
}
VOID
Cleanup(VOID)
{
DeleteCriticalSection(&U32AccelCacheLock);
MenuCleanup();
MessageCleanup();
DeleteFrameBrushes();
UnloadAppInitDlls();
GdiDllInitialize(NULL, DLL_PROCESS_DETACH, NULL);
TlsFree(User32TlsIndex);
}
INT WINAPI
DllMain(
IN PVOID hInstanceDll,
IN ULONG dwReason,
IN PVOID reserved)
{
switch (dwReason)
{
case DLL_PROCESS_ATTACH:
User32Instance = hInstanceDll;
if (!RegisterClientPFN())
{
return FALSE;
}
if (!Init())
return FALSE;
if (!InitThread())
{
Cleanup();
return FALSE;
}
break;
case DLL_THREAD_ATTACH:
if (!InitThread())
return FALSE;
break;
case DLL_THREAD_DETACH:
CleanupThread();
break;
case DLL_PROCESS_DETACH:
if (hImmInstance) FreeLibrary(hImmInstance);
CleanupThread();
Cleanup();
break;
}
return TRUE;
}
VOID
FASTCALL
GetConnected(VOID)
{
USERCONNECT UserCon;
// ERR("GetConnected\n");
if ((PTHREADINFO)NtCurrentTeb()->Win32ThreadInfo == NULL)
NtUserGetThreadState(THREADSTATE_GETTHREADINFO);
if (gpsi && g_ppi) return;
// FIXME HAX: Due to the "Dll Initialization Bug" we have to call this too.
GdiDllInitialize(NULL, DLL_PROCESS_ATTACH, NULL);
NtUserProcessConnect( NtCurrentProcess(),
&UserCon,
sizeof(USERCONNECT));
g_ppi = GetWin32ClientInfo()->ppi;
g_ulSharedDelta = UserCon.siClient.ulSharedDelta;
gpsi = SharedPtrToUser(UserCon.siClient.psi);
gHandleTable = SharedPtrToUser(UserCon.siClient.aheList);
gHandleEntries = SharedPtrToUser(gHandleTable->handles);
}
NTSTATUS
WINAPI
User32CallClientThreadSetupFromKernel(PVOID Arguments, ULONG ArgumentLength)
{
ERR("ClientThreadSetup\n");
ClientThreadSetup();
return ZwCallbackReturn(NULL, 0, STATUS_SUCCESS);
}
NTSTATUS
WINAPI
User32CallGetCharsetInfo(PVOID Arguments, ULONG ArgumentLength)
{
BOOL Ret;
PGET_CHARSET_INFO pgci = (PGET_CHARSET_INFO)Arguments;
TRACE("GetCharsetInfo\n");
Ret = TranslateCharsetInfo((DWORD *)pgci->Locale, &pgci->Cs, TCI_SRCLOCALE);
return ZwCallbackReturn(Arguments, ArgumentLength, Ret ? STATUS_SUCCESS : STATUS_UNSUCCESSFUL);
}
NTSTATUS
WINAPI
User32CallSetWndIconsFromKernel(PVOID Arguments, ULONG ArgumentLength)
{
PSETWNDICONS_CALLBACK_ARGUMENTS Common = Arguments;
if (!hIconSmWindows)
{
hIconSmWindows = LoadImageW(0, IDI_WINLOGO, IMAGE_ICON, GetSystemMetrics(SM_CXSMICON), GetSystemMetrics(SM_CYSMICON), LR_DEFAULTCOLOR);
hIconWindows = LoadImageW(0, IDI_WINLOGO, IMAGE_ICON, 0, 0, LR_DEFAULTCOLOR);
}
Common->hIconSmWindows = hIconSmWindows;
Common->hIconWindows = hIconWindows;
ERR("hIconSmWindows %p hIconWindows %p \n",hIconSmWindows,hIconWindows);
return ZwCallbackReturn(Arguments, ArgumentLength, STATUS_SUCCESS);
}