You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
3073 lines
88 KiB
3073 lines
88 KiB
/**************************************************************************\
|
|
* Module Name: ntstubs.c
|
|
*
|
|
* Copyright (c) 1985 - 1999, Microsoft Corporation
|
|
*
|
|
* client side API stubs
|
|
*
|
|
* History:
|
|
* 03-19-95 JimA Created.
|
|
\**************************************************************************/
|
|
|
|
#include "precomp.h"
|
|
#pragma hdrstop
|
|
|
|
#define CLIENTSIDE 1
|
|
|
|
#include <dbt.h>
|
|
|
|
#include "ntsend.h"
|
|
#include "cfgmgr32.h"
|
|
#include "csrhlpr.h"
|
|
|
|
WINUSERAPI
|
|
BOOL
|
|
WINAPI
|
|
SetSysColors(
|
|
int cElements,
|
|
CONST INT * lpaElements,
|
|
CONST COLORREF * lpaRgbValues)
|
|
{
|
|
|
|
return NtUserSetSysColors(cElements,
|
|
lpaElements,
|
|
lpaRgbValues,
|
|
SSCF_NOTIFY | SSCF_FORCESOLIDCOLOR | SSCF_SETMAGICCOLORS);
|
|
}
|
|
|
|
|
|
HWND WOWFindWindow(
|
|
LPCSTR pClassName,
|
|
LPCSTR pWindowName)
|
|
{
|
|
return InternalFindWindowExA(NULL, NULL, pClassName, pWindowName, FW_16BIT);
|
|
}
|
|
|
|
#ifdef IMM_PER_LOGON
|
|
VOID UpdatePerUserImmEnabling(
|
|
VOID)
|
|
{
|
|
BOOL fRet = (BOOL)NtUserCallNoParam(SFI_UPDATEPERUSERIMMENABLING);
|
|
|
|
if (fRet) {
|
|
if (IS_IME_ENABLED()) {
|
|
/*
|
|
* hen ImmEnable flag is update and it gets enabled during
|
|
* the last logon, we need to load Imm32.dll.
|
|
*/
|
|
HMODULE hModule = GetModuleHandleW(L"imm32.dll");
|
|
if (hModule == NULL) {
|
|
LoadLibraryW(L"imm32.dll");
|
|
}
|
|
}
|
|
}
|
|
}
|
|
#endif
|
|
|
|
|
|
FUNCLOG2(LOG_GENERAL, BOOL, DUMMYCALLINGTYPE, UpdatePerUserSystemParameters, HANDLE, hToken, DWORD, dwFlags)
|
|
BOOL UpdatePerUserSystemParameters(
|
|
HANDLE hToken,
|
|
DWORD dwFlags)
|
|
{
|
|
TAGMSGF0(DBGTAG_KBD, "entering");
|
|
BEGINCALL()
|
|
if ((dwFlags & UPUSP_USERLOGGEDON) || (dwFlags & (UPUSP_POLICYCHANGE | UPUSP_REMOTESETTINGS)) == 0) {
|
|
/*
|
|
* This is the first logon, need to initialize
|
|
* the input locale.
|
|
*/
|
|
LANGID langidKbd;
|
|
WCHAR wszKLName[KL_NAMELENGTH];
|
|
UINT uKlFlags = KLF_ACTIVATE | KLF_RESET;
|
|
|
|
#ifdef IMM_PER_LOGON
|
|
/*
|
|
* Update the per user portion of the system metrics.
|
|
* Continues even if this update fails.
|
|
*/
|
|
UpdatePerUserImmEnabling();
|
|
#endif
|
|
|
|
/*
|
|
* Initialize IME hotkeys before loading keyboard
|
|
* layouts.
|
|
*/
|
|
CliImmInitializeHotKeys(ISHK_INITIALIZE, NULL);
|
|
|
|
/*
|
|
* Try to get the remote input locale first.
|
|
*/
|
|
if (!GetRemoteKeyboardLayout(wszKLName, &langidKbd)) {
|
|
/*
|
|
* If this is not a remote connection,
|
|
* let's handle the input locale substition.
|
|
*/
|
|
uKlFlags |= KLF_SUBSTITUTE_OK;
|
|
langidKbd = MAKELANGID(LANG_NEUTRAL, SUBLANG_NEUTRAL);
|
|
/*
|
|
* Get the active keyboard layout from the registry.
|
|
*/
|
|
GetActiveKeyboardName(wszKLName);
|
|
}
|
|
|
|
LoadKeyboardLayoutWorker(NULL, wszKLName, langidKbd, uKlFlags, TRUE);
|
|
|
|
/*
|
|
* Now load the remaining preload keyboard layouts.
|
|
*/
|
|
LoadPreloadKeyboardLayouts();
|
|
}
|
|
|
|
/*
|
|
* Only if not just a policy change.
|
|
*/
|
|
if (dwFlags != UPUSP_POLICYCHANGE) {
|
|
/*
|
|
* FLush any MUI cach to be able to load strings latter for the new UIlangID.
|
|
*/
|
|
LdrFlushAlternateResourceModules();
|
|
}
|
|
|
|
retval = (DWORD)NtUserUpdatePerUserSystemParameters(hToken, dwFlags);
|
|
|
|
/*
|
|
* Cause the wallpaper to be changed.
|
|
*/
|
|
SystemParametersInfo(SPI_SETDESKWALLPAPER, 0, 0, 0);
|
|
|
|
ERRORTRAP(0);
|
|
ENDCALL(BOOL);
|
|
}
|
|
|
|
DWORD Event(
|
|
PEVENT_PACKET pep)
|
|
{
|
|
BEGINCALL()
|
|
|
|
CheckDDECritOut;
|
|
|
|
retval = (DWORD)NtUserEvent(
|
|
pep);
|
|
|
|
ERRORTRAP(0);
|
|
ENDCALL(DWORD);
|
|
}
|
|
|
|
LONG GetClassWOWWords(
|
|
HINSTANCE hInstance,
|
|
LPCTSTR pString)
|
|
{
|
|
IN_STRING strClassName;
|
|
PCLS pcls;
|
|
|
|
/*
|
|
* Make sure cleanup will work successfully
|
|
*/
|
|
strClassName.fAllocated = FALSE;
|
|
|
|
BEGINCALL()
|
|
|
|
FIRSTCOPYLPSTRW(&strClassName, pString);
|
|
|
|
pcls = NtUserGetWOWClass(hInstance, strClassName.pstr);
|
|
|
|
if (pcls == NULL) {
|
|
MSGERRORCODE(ERROR_CLASS_DOES_NOT_EXIST);
|
|
}
|
|
|
|
pcls = (PCLS)((KPBYTE)pcls - GetClientInfo()->ulClientDelta);
|
|
retval = _GetClassData(pcls, NULL, GCLP_WOWWORDS, TRUE);
|
|
|
|
ERRORTRAP(0);
|
|
CLEANUPLPSTRW(strClassName);
|
|
ENDCALL(LONG);
|
|
}
|
|
|
|
/***************************************************************************\
|
|
* InitTask
|
|
*
|
|
* Initialize a WOW task. This is the first call a WOW thread makes to user.
|
|
* NtUserInitTask returns NTSTATUS because if the thread fails to convert
|
|
* to a GUI thread, STATUS_INVALID_SYSTEM_SERVICE is returned.
|
|
*
|
|
* 11-03-95 JimA Modified to use NTSTATUS.
|
|
\***************************************************************************/
|
|
|
|
BOOL InitTask(
|
|
UINT wVersion,
|
|
DWORD dwAppCompatFlags,
|
|
DWORD dwUserWOWCompatFlags,
|
|
LPCSTR pszModName,
|
|
LPCSTR pszBaseFileName,
|
|
DWORD hTaskWow,
|
|
DWORD dwHotkey,
|
|
DWORD idTask,
|
|
DWORD dwX,
|
|
DWORD dwY,
|
|
DWORD dwXSize,
|
|
DWORD dwYSize)
|
|
{
|
|
IN_STRING strModName;
|
|
IN_STRING strBaseFileName;
|
|
NTSTATUS Status;
|
|
|
|
/*
|
|
* Make sure cleanup will work successfully
|
|
*/
|
|
strModName.fAllocated = FALSE;
|
|
strBaseFileName.fAllocated = FALSE;
|
|
|
|
BEGINCALL()
|
|
|
|
FIRSTCOPYLPSTRW(&strModName, pszModName);
|
|
COPYLPSTRW(&strBaseFileName, pszBaseFileName);
|
|
|
|
Status = NtUserInitTask(
|
|
wVersion,
|
|
dwAppCompatFlags,
|
|
dwUserWOWCompatFlags,
|
|
strModName.pstr,
|
|
strBaseFileName.pstr,
|
|
hTaskWow,
|
|
dwHotkey,
|
|
idTask,
|
|
dwX,
|
|
dwY,
|
|
dwXSize,
|
|
dwYSize);
|
|
retval = (Status == STATUS_SUCCESS);
|
|
|
|
CLEANUPLPSTRW(strModName);
|
|
CLEANUPLPSTRW(strBaseFileName);
|
|
|
|
ERRORTRAP(FALSE);
|
|
ENDCALL(BOOL);
|
|
}
|
|
|
|
HANDLE ConvertMemHandle(
|
|
HANDLE hData,
|
|
UINT cbNULL)
|
|
{
|
|
UINT cbData;
|
|
LPBYTE lpData;
|
|
|
|
BEGINCALL()
|
|
|
|
if (GlobalFlags(hData) == GMEM_INVALID_HANDLE) {
|
|
RIPMSG0(RIP_WARNING, "ConvertMemHandle hMem is not valid");
|
|
MSGERROR();
|
|
}
|
|
|
|
if (!(cbData = (UINT)GlobalSize(hData))) {
|
|
MSGERROR();
|
|
}
|
|
|
|
USERGLOBALLOCK(hData, lpData);
|
|
if (lpData == NULL) {
|
|
MSGERROR();
|
|
}
|
|
|
|
/*
|
|
* Make sure text formats are NULL terminated.
|
|
*/
|
|
switch (cbNULL) {
|
|
case 2:
|
|
lpData[cbData - 2] = 0;
|
|
// FALL THROUGH
|
|
case 1:
|
|
lpData[cbData - 1] = 0;
|
|
}
|
|
|
|
retval = (ULONG_PTR)NtUserConvertMemHandle(lpData, cbData);
|
|
|
|
USERGLOBALUNLOCK(hData);
|
|
|
|
ERRORTRAP(NULL);
|
|
ENDCALL(HANDLE);
|
|
}
|
|
|
|
HANDLE CreateLocalMemHandle(
|
|
HANDLE hMem)
|
|
{
|
|
UINT cbData;
|
|
NTSTATUS Status;
|
|
|
|
BEGINCALL()
|
|
|
|
Status = NtUserCreateLocalMemHandle(hMem, NULL, 0, &cbData);
|
|
if (Status != STATUS_BUFFER_TOO_SMALL) {
|
|
RIPMSG0(RIP_WARNING, "__CreateLocalMemHandle server returned failure");
|
|
MSGERROR();
|
|
}
|
|
|
|
if (!(retval = (ULONG_PTR)GlobalAlloc(GMEM_FIXED, cbData))) {
|
|
MSGERROR();
|
|
}
|
|
|
|
Status = NtUserCreateLocalMemHandle(hMem, (LPBYTE)retval, cbData, NULL);
|
|
if (!NT_SUCCESS(Status)) {
|
|
RIPMSG0(RIP_WARNING, "__CreateLocalMemHandle server returned failure");
|
|
UserGlobalFree((HANDLE)retval);
|
|
MSGERROR();
|
|
}
|
|
|
|
ERRORTRAP(0);
|
|
ENDCALL(HANDLE);
|
|
}
|
|
|
|
HHOOK _SetWindowsHookEx(
|
|
HANDLE hmod,
|
|
LPTSTR pszLib,
|
|
DWORD idThread,
|
|
int nFilterType,
|
|
PROC pfnFilterProc,
|
|
DWORD dwFlags)
|
|
{
|
|
IN_STRING strLib;
|
|
|
|
/*
|
|
* Make sure cleanup will work successfully
|
|
*/
|
|
strLib.fAllocated = FALSE;
|
|
|
|
BEGINCALL()
|
|
|
|
FIRSTCOPYLPWSTROPT(&strLib, pszLib);
|
|
|
|
retval = (ULONG_PTR)NtUserSetWindowsHookEx(
|
|
hmod,
|
|
strLib.pstr,
|
|
idThread,
|
|
nFilterType,
|
|
pfnFilterProc,
|
|
dwFlags);
|
|
|
|
ERRORTRAP(0);
|
|
CLEANUPLPWSTR(strLib);
|
|
ENDCALL(HHOOK);
|
|
}
|
|
|
|
/***************************************************************************\
|
|
* SetWinEventHook
|
|
*
|
|
* History:
|
|
* 1996-09-23 IanJa Created
|
|
\***************************************************************************/
|
|
WINUSERAPI
|
|
HWINEVENTHOOK
|
|
WINAPI
|
|
SetWinEventHook(
|
|
DWORD eventMin,
|
|
DWORD eventMax,
|
|
HMODULE hmodWinEventProc, // Must pass this if global!
|
|
WINEVENTPROC lpfnWinEventProc,
|
|
DWORD idProcess, // Can be zero; all processes
|
|
DWORD idThread, // Can be zero; all threads
|
|
DWORD dwFlags)
|
|
{
|
|
UNICODE_STRING str;
|
|
PUNICODE_STRING pstr;
|
|
WCHAR awchLib[MAX_PATH];
|
|
|
|
BEGINCALL()
|
|
|
|
if ((dwFlags & WINEVENT_INCONTEXT) && (hmodWinEventProc != NULL)) {
|
|
/*
|
|
* If we're passing an hmod, we need to grab the file name of the
|
|
* module while we're still on the client since module handles
|
|
* are NOT global.
|
|
*/
|
|
USHORT cb;
|
|
cb = (USHORT)(sizeof(WCHAR) * GetModuleFileNameW(hmodWinEventProc, awchLib, sizeof(awchLib)/sizeof(WCHAR)));
|
|
if (cb == 0) {
|
|
/*
|
|
* hmod is bogus - return NULL.
|
|
*/
|
|
return NULL;
|
|
}
|
|
str.Buffer = awchLib;
|
|
str.Length = cb - sizeof(UNICODE_NULL);
|
|
str.MaximumLength = cb;
|
|
pstr = &str;
|
|
} else {
|
|
pstr = NULL;
|
|
}
|
|
|
|
retval = (ULONG_PTR)NtUserSetWinEventHook(
|
|
eventMin,
|
|
eventMax,
|
|
hmodWinEventProc,
|
|
pstr,
|
|
lpfnWinEventProc,
|
|
idProcess,
|
|
idThread,
|
|
dwFlags);
|
|
|
|
ERRORTRAP(0);
|
|
ENDCALL(HWINEVENTHOOK);
|
|
};
|
|
|
|
|
|
FUNCLOGVOID4(LOG_GENERAL, WINAPI, NotifyWinEvent, DWORD, dwEvent, HWND, hwnd, LONG, idObject, LONG, idChild)
|
|
WINUSERAPI
|
|
VOID
|
|
WINAPI
|
|
NotifyWinEvent(
|
|
DWORD dwEvent,
|
|
HWND hwnd,
|
|
LONG idObject,
|
|
LONG idChild)
|
|
{
|
|
BEGINCALLVOID()
|
|
|
|
if (FEVENTHOOKED(dwEvent)) {
|
|
NtUserNotifyWinEvent(dwEvent, hwnd, idObject, idChild);
|
|
}
|
|
|
|
ERRORTRAPVOID();
|
|
ENDCALLVOID();
|
|
}
|
|
|
|
/***************************************************************************\
|
|
* RegisterUserApiHook
|
|
*
|
|
* History:
|
|
* 03-Mar-2000 JerrySh Created.
|
|
\***************************************************************************/
|
|
|
|
FUNCLOG2(LOG_GENERAL, BOOL, DUMMYCALLINGTYPE, RegisterUserApiHook, HINSTANCE, hmod, INITUSERAPIHOOK, pfnUserApiHook)
|
|
BOOL RegisterUserApiHook(
|
|
HINSTANCE hmod,
|
|
INITUSERAPIHOOK pfnUserApiHook)
|
|
{
|
|
WCHAR pwszLibFileName[MAX_PATH];
|
|
ULONG_PTR offPfnProc;
|
|
IN_STRING strLib;
|
|
|
|
/*
|
|
* If we're passing an hmod, we need to grab the file name of the
|
|
* module while we're still on the client since module handles
|
|
* are NOT global.
|
|
*/
|
|
if (!GetModuleFileNameW(hmod, pwszLibFileName, ARRAY_SIZE(pwszLibFileName))) {
|
|
return FALSE;
|
|
}
|
|
|
|
/*
|
|
* Libraries are loaded at different linear addresses in different
|
|
* process contexts. For this reason, we need to convert the window
|
|
* proc address into an offset while setting the hook, and then convert
|
|
* it back to a real per-process function pointer when calling a
|
|
* hook. Do this by subtracting the 'hmod' (which is a pointer to the
|
|
* linear and contiguous .exe header) from the function index.
|
|
*/
|
|
offPfnProc = (ULONG_PTR)pfnUserApiHook - (ULONG_PTR)hmod;
|
|
|
|
/*
|
|
* Make sure cleanup will work successfully
|
|
*/
|
|
strLib.fAllocated = FALSE;
|
|
|
|
BEGINCALL()
|
|
|
|
COPYLPWSTR(&strLib, pwszLibFileName);
|
|
|
|
retval = (ULONG_PTR)NtUserRegisterUserApiHook(
|
|
strLib.pstr,
|
|
offPfnProc);
|
|
|
|
ERRORTRAP(0);
|
|
CLEANUPLPWSTR(strLib);
|
|
ENDCALL(BOOL);
|
|
}
|
|
|
|
|
|
#ifdef MESSAGE_PUMP_HOOK
|
|
|
|
/***************************************************************************\
|
|
* ResetMessagePumpHook
|
|
*
|
|
* ResetMessagePumpHook() resets the MessagePumpHook function pointers
|
|
* to the internal "real" implementations.
|
|
*
|
|
* History:
|
|
* 12-13-2000 JStall Created
|
|
\***************************************************************************/
|
|
|
|
void ResetMessagePumpHook(MESSAGEPUMPHOOK * pwmh)
|
|
{
|
|
pwmh->cbSize = sizeof(MESSAGEPUMPHOOK);
|
|
pwmh->pfnInternalGetMessage = NtUserRealInternalGetMessage;
|
|
pwmh->pfnWaitMessageEx = NtUserRealWaitMessageEx;
|
|
pwmh->pfnGetQueueStatus = RealGetQueueStatus;
|
|
pwmh->pfnMsgWaitForMultipleObjectsEx
|
|
= RealMsgWaitForMultipleObjectsEx;
|
|
}
|
|
|
|
|
|
/***************************************************************************\
|
|
* RegisterMessagePumpHook
|
|
*
|
|
* RegisterMessagePumpHook() sets up MPH's on the current thread. If this is
|
|
* the first thread to be initialized in the process, the process-wide
|
|
* initialization is also performed. If a thread has already been
|
|
* initialized with MPH's, its "ref-count" is incremented on the existing
|
|
* MPH's.
|
|
*
|
|
* NOTE: Unlike UserApiHook's, we make a callback while holding a critical
|
|
* section. This is because it is infinitely easier to synchronize this
|
|
* inside USER32.DLL rather than allowing re-entrancy in the DLL. It is
|
|
* designed after DllMain(), where the loader also has a lock that is
|
|
* sychronized.
|
|
*
|
|
* NOTE: Under the current implementation of MPH's, only one set of MPH's
|
|
* per process can be installed. Each process may have a different set of
|
|
* WMH's.
|
|
*
|
|
* History:
|
|
* 12-13-2000 JStall Created
|
|
\***************************************************************************/
|
|
|
|
BOOL RegisterMessagePumpHook(
|
|
INITMESSAGEPUMPHOOK pfnInitMPH)
|
|
{
|
|
BOOL fInit = FALSE;
|
|
|
|
BEGINCALL()
|
|
retval = FALSE;
|
|
|
|
RtlEnterCriticalSection(&gcsMPH);
|
|
|
|
if (pfnInitMPH == NULL) {
|
|
RIPERR0(ERROR_INVALID_PARAMETER, RIP_VERBOSE, "Need valid pfnInitMPH");
|
|
goto errorexit;
|
|
}
|
|
|
|
if (gcLoadMPH == 0) {
|
|
MESSAGEPUMPHOOK mphTemp;
|
|
|
|
/*
|
|
* First time we are initializing.
|
|
*/
|
|
UserAssertMsg0(gpfnInitMPH == NULL, "MPH callback should not already be initialized");
|
|
gpfnInitMPH = pfnInitMPH;
|
|
|
|
ResetMessagePumpHook(&mphTemp);
|
|
if (!(gpfnInitMPH)(UIAH_INITIALIZE, &mphTemp) || (mphTemp.cbSize == 0)) {
|
|
goto errorexit;
|
|
}
|
|
|
|
CopyMemory(&gmph, &mphTemp, mphTemp.cbSize);
|
|
fInit = TRUE;
|
|
} else {
|
|
if (gpfnInitMPH == pfnInitMPH) {
|
|
/*
|
|
* Initializing a second time with the same callback.
|
|
*/
|
|
fInit = TRUE;
|
|
}
|
|
}
|
|
|
|
if (fInit) {
|
|
/*
|
|
* Initialize MPH's on this thread.
|
|
*/
|
|
if (NtUserCallNoParam(SFI__DOINITMESSAGEPUMPHOOK)) {
|
|
if (gcLoadMPH++ == 0) {
|
|
InterlockedExchange(&gfMessagePumpHook, TRUE);
|
|
}
|
|
retval = TRUE;
|
|
}
|
|
}
|
|
|
|
ERRORTRAP(0);
|
|
RtlLeaveCriticalSection(&gcsMPH);
|
|
ENDCALL(BOOL);
|
|
}
|
|
|
|
|
|
/***************************************************************************\
|
|
* UnregisterMessagePumpHook
|
|
*
|
|
* UnregisterMessagePumpHook() decrements the count of WMH's on the current
|
|
* thread. When this count reaches 0, WMH's are uninstalled from the
|
|
* current thread. When the global WMH count reaches 0, WMH's are uninstalled
|
|
* from the entire process.
|
|
*
|
|
* NOTE: See RegisterMessagePumpHook() about use of the critical section.
|
|
*
|
|
* History:
|
|
* 12-13-2000 JStall Created
|
|
\***************************************************************************/
|
|
BOOL UnregisterMessagePumpHook(
|
|
VOID)
|
|
{
|
|
BEGINCALL()
|
|
RtlEnterCriticalSection(&gcsMPH);
|
|
|
|
if (gcLoadMPH <= 0) {
|
|
RIPMSG0(RIP_ERROR, "UninitMessagePumpHook: Called without matching Init()");
|
|
goto errorexit;
|
|
}
|
|
|
|
/*
|
|
* Uninitialize this thread's WMH. When the reference count reaches 0, the
|
|
* thread will no longer be hooked.
|
|
*/
|
|
if (!NtUserCallNoParam(SFI__DOUNINITMESSAGEPUMPHOOK)) {
|
|
goto errorexit;
|
|
}
|
|
|
|
if (--gcLoadMPH == 0) {
|
|
/*
|
|
* Final unload: make callback and reset
|
|
*/
|
|
|
|
InterlockedExchange(&gfMessagePumpHook, FALSE);
|
|
|
|
(gpfnInitMPH)(UIAH_UNINITIALIZE, NULL);
|
|
|
|
ResetMessagePumpHook(&gmph);
|
|
gpfnInitMPH = NULL;
|
|
}
|
|
retval = TRUE;
|
|
|
|
ERRORTRAP(0);
|
|
RtlLeaveCriticalSection(&gcsMPH);
|
|
ENDCALL(BOOL);
|
|
}
|
|
|
|
#endif // MESSAGE_PUMP_HOOK
|
|
|
|
|
|
|
|
/***************************************************************************\
|
|
* ThunkedMenuItemInfo
|
|
*
|
|
* History:
|
|
* 07-22-96 GerardoB - Added header and Fixed up for 5.0
|
|
\***************************************************************************/
|
|
BOOL ThunkedMenuItemInfo(
|
|
HMENU hMenu,
|
|
UINT nPosition,
|
|
BOOL fByPosition,
|
|
BOOL fInsert,
|
|
LPMENUITEMINFOW lpmii,
|
|
BOOL fAnsi)
|
|
{
|
|
MENUITEMINFOW mii;
|
|
IN_STRING strItem;
|
|
|
|
/*
|
|
* Make sure cleanup will work successfully
|
|
*/
|
|
strItem.fAllocated = FALSE;
|
|
|
|
BEGINCALL()
|
|
|
|
/*
|
|
* Make a local copy so we can make changes
|
|
*/
|
|
mii = *(LPMENUITEMINFO)(lpmii);
|
|
|
|
strItem.pstr = NULL;
|
|
if (mii.fMask & MIIM_BITMAP) {
|
|
if (((HBITMAP)LOWORD(HandleToUlong(mii.hbmpItem)) < HBMMENU_MAX) && IS_PTR(mii.hbmpItem)) {
|
|
/*
|
|
* Looks like the user was trying to insert one of the
|
|
* HBMMENU_* bitmaps, but stuffed some data in the HIWORD.
|
|
* We know the HIWORD data is invalid because the LOWORD
|
|
* handle is below the GDI minimum.
|
|
*/
|
|
RIPMSG1(RIP_WARNING, "Invalid HIWORD data (0x%04X) for HBMMENU_* bitmap.", HIWORD(HandleToUlong(mii.hbmpItem)));
|
|
mii.hbmpItem = (HBITMAP)LOWORD(HandleToUlong(mii.hbmpItem));
|
|
} else if (!IS_PTR(mii.hbmpItem) && mii.hbmpItem >= HBMMENU_MAX) {
|
|
/*
|
|
* The app is passing a 16-bit GDI handle. GDI handles this
|
|
* on the client-side, but not on the kernel side. So
|
|
* convert it to 32-bits. This fixes bug 201493 in
|
|
* Macromedia Director.
|
|
*/
|
|
HBITMAP hbmNew = GdiFixUpHandle(mii.hbmpItem);
|
|
if (hbmNew) {
|
|
RIPMSGF2(RIP_WARNING,
|
|
"Fix 16-bit bitmap handle 0x%x to 0x%x",
|
|
mii.hbmpItem,
|
|
hbmNew);
|
|
mii.hbmpItem = hbmNew;
|
|
}
|
|
}
|
|
}
|
|
|
|
if (mii.fMask & MIIM_STRING) {
|
|
if (fAnsi) {
|
|
FIRSTCOPYLPSTROPTW(&strItem, mii.dwTypeData);
|
|
} else {
|
|
FIRSTCOPYLPWSTROPT(&strItem, mii.dwTypeData);
|
|
}
|
|
}
|
|
|
|
retval = (DWORD)NtUserThunkedMenuItemInfo(hMenu,
|
|
nPosition,
|
|
fByPosition,
|
|
fInsert,
|
|
&mii,
|
|
strItem.pstr);
|
|
|
|
ERRORTRAP(FALSE);
|
|
CLEANUPLPSTRW(strItem);
|
|
ENDCALL(BOOL);
|
|
}
|
|
|
|
/***************************************************************************\
|
|
* DrawCaption
|
|
*
|
|
* History:
|
|
* 16-April-2001 Mohamed Hooked API and created this wrapper.
|
|
\***************************************************************************/
|
|
FUNCLOG4(
|
|
LOG_GENERAL,
|
|
BOOL,
|
|
DUMMYCALLINGTYPE,
|
|
DrawCaption,
|
|
HWND,
|
|
hwnd,
|
|
HDC,
|
|
hdc,
|
|
CONST RECT*,
|
|
lprc,
|
|
UINT,
|
|
flags)
|
|
BOOL DrawCaption(
|
|
HWND hwnd,
|
|
HDC hdc,
|
|
CONST RECT *lprc,
|
|
UINT flags)
|
|
{
|
|
BOOL bRet;
|
|
|
|
BEGIN_USERAPIHOOK()
|
|
bRet = guah.pfnDrawCaption(hwnd, hdc, lprc, flags);
|
|
END_USERAPIHOOK()
|
|
|
|
return bRet;
|
|
}
|
|
|
|
BOOL RealDrawCaption(
|
|
HWND hwnd,
|
|
HDC hdc,
|
|
CONST RECT *lprc,
|
|
UINT flags)
|
|
{
|
|
HDC hdcr;
|
|
BEGINCALL()
|
|
|
|
if (IsMetaFile(hdc)) {
|
|
return FALSE;
|
|
}
|
|
|
|
hdcr = GdiConvertAndCheckDC(hdc);
|
|
if (hdcr == (HDC)0) {
|
|
return FALSE;
|
|
}
|
|
|
|
retval = (DWORD)NtUserDrawCaption(hwnd, hdcr, lprc, flags);
|
|
|
|
ERRORTRAP(0);
|
|
ENDCALL(BOOL);
|
|
}
|
|
|
|
|
|
FUNCLOG1(LOG_GENERAL, SHORT, DUMMYCALLINGTYPE, GetAsyncKeyState, int, vKey)
|
|
SHORT GetAsyncKeyState(
|
|
int vKey)
|
|
{
|
|
BEGINCALLCONNECT()
|
|
|
|
/*
|
|
* Asynchronous key state reports the PHYSICAL mouse button,
|
|
* regardless of whether the buttons have been swapped or not.
|
|
*/
|
|
if ((vKey == VK_RBUTTON || vKey == VK_LBUTTON) && SYSMET(SWAPBUTTON)) {
|
|
vKey ^= (VK_RBUTTON ^ VK_LBUTTON);
|
|
}
|
|
|
|
/*
|
|
* If this is one of the common keys, see if we can pull it out
|
|
* of the cache.
|
|
*/
|
|
if ((UINT)vKey < CVKASYNCKEYCACHE) {
|
|
PCLIENTINFO pci = GetClientInfo();
|
|
if ((pci->dwAsyncKeyCache == gpsi->dwAsyncKeyCache) &&
|
|
!TestKeyRecentDownBit(pci->afAsyncKeyStateRecentDown, vKey)) {
|
|
|
|
if (TestKeyDownBit(pci->afAsyncKeyState, vKey)) {
|
|
retval = 0x8000;
|
|
} else {
|
|
retval = 0;
|
|
}
|
|
|
|
return (SHORT)retval;
|
|
}
|
|
}
|
|
|
|
retval = (DWORD)NtUserGetAsyncKeyState(vKey);
|
|
|
|
ERRORTRAP(0);
|
|
ENDCALL(SHORT);
|
|
}
|
|
|
|
|
|
FUNCLOG1(LOG_GENERAL, SHORT, DUMMYCALLINGTYPE, GetKeyState, int, vKey)
|
|
SHORT GetKeyState(
|
|
int vKey)
|
|
{
|
|
BEGINCALLCONNECT()
|
|
|
|
/*
|
|
* If this is one of the common keys, see if we can pull it out
|
|
* of the cache.
|
|
*/
|
|
if ((UINT)vKey < CVKKEYCACHE) {
|
|
PCLIENTINFO pci = GetClientInfo();
|
|
if (pci->dwKeyCache == gpsi->dwKeyCache) {
|
|
retval = 0;
|
|
if (TestKeyToggleBit(pci->afKeyState, vKey))
|
|
retval |= 0x0001;
|
|
if (TestKeyDownBit(pci->afKeyState, vKey)) {
|
|
/*
|
|
* Used to be retval |= 0x8000.Fix for bug 28820; Ctrl-Enter
|
|
* accelerator doesn't work on Nestscape Navigator Mail 2.0
|
|
*/
|
|
retval |= 0xff80; // This is what 3.1 returned!!!!
|
|
}
|
|
|
|
return (SHORT)retval;
|
|
}
|
|
}
|
|
|
|
retval = (DWORD)NtUserGetKeyState(
|
|
vKey);
|
|
|
|
ERRORTRAP(0);
|
|
ENDCALL(SHORT);
|
|
}
|
|
|
|
|
|
FUNCLOG1(LOG_GENERAL, BOOL, DUMMYCALLINGTYPE, OpenClipboard, HWND, hwnd)
|
|
BOOL OpenClipboard(
|
|
HWND hwnd)
|
|
{
|
|
BOOL fEmptyClient;
|
|
|
|
BEGINCALL()
|
|
|
|
retval = (DWORD)NtUserOpenClipboard(hwnd, &fEmptyClient);
|
|
|
|
if (fEmptyClient)
|
|
ClientEmptyClipboard();
|
|
|
|
ERRORTRAP(0);
|
|
ENDCALL(BOOL);
|
|
}
|
|
|
|
BOOL _PeekMessage(
|
|
LPMSG pmsg,
|
|
HWND hwnd,
|
|
UINT wMsgFilterMin,
|
|
UINT wMsgFilterMax,
|
|
UINT wRemoveMsg,
|
|
BOOL bAnsi)
|
|
{
|
|
BEGINCALL()
|
|
|
|
if (bAnsi) {
|
|
//
|
|
// If we have pushed message for DBCS messaging, we should pass this one
|
|
// to Apps at first...
|
|
//
|
|
GET_DBCS_MESSAGE_IF_EXIST(
|
|
PeekMessage,pmsg,wMsgFilterMin,wMsgFilterMax,((wRemoveMsg & PM_REMOVE) ? TRUE:FALSE));
|
|
}
|
|
|
|
retval = (DWORD)NtUserPeekMessage(
|
|
pmsg,
|
|
hwnd,
|
|
wMsgFilterMin,
|
|
wMsgFilterMax,
|
|
wRemoveMsg);
|
|
|
|
if (retval) {
|
|
// May have a bit more work to do if this MSG is for an ANSI app
|
|
|
|
if (bAnsi) {
|
|
if (RtlWCSMessageWParamCharToMB(pmsg->message, &(pmsg->wParam))) {
|
|
WPARAM dwAnsi = pmsg->wParam;
|
|
//
|
|
// Build DBCS-ware wParam. (for EM_SETPASSWORDCHAR...)
|
|
//
|
|
BUILD_DBCS_MESSAGE_TO_CLIENTA_FROM_SERVER(
|
|
pmsg,dwAnsi,TRUE,((wRemoveMsg & PM_REMOVE) ? TRUE:FALSE));
|
|
} else {
|
|
retval = 0;
|
|
}
|
|
} else {
|
|
//
|
|
// Only LOWORD of WPARAM is valid for WM_CHAR....
|
|
// (Mask off DBCS messaging information.)
|
|
//
|
|
BUILD_DBCS_MESSAGE_TO_CLIENTW_FROM_SERVER(pmsg->message,pmsg->wParam);
|
|
}
|
|
}
|
|
|
|
ExitPeekMessage:
|
|
|
|
ERRORTRAP(0);
|
|
ENDCALL(BOOL);
|
|
}
|
|
|
|
|
|
LONG_PTR _SetWindowLongPtr(
|
|
HWND hwnd,
|
|
int nIndex,
|
|
LONG_PTR dwNewLong,
|
|
BOOL bAnsi)
|
|
{
|
|
PWND pwnd;
|
|
LONG_PTR dwOldLong;
|
|
DWORD dwCPDType = 0;
|
|
|
|
pwnd = ValidateHwnd(hwnd);
|
|
|
|
if (pwnd == NULL)
|
|
return 0;
|
|
|
|
if (TestWF(pwnd, WFDIALOGWINDOW)) {
|
|
switch (nIndex) {
|
|
case DWLP_DLGPROC: // See similar case GWL_WNDPROC
|
|
|
|
/*
|
|
* Hide the window proc from other processes
|
|
*/
|
|
if (!TestWindowProcess(pwnd)) {
|
|
RIPERR1(ERROR_ACCESS_DENIED,
|
|
RIP_WARNING,
|
|
"Access denied to hwnd (%#lx) in _SetWindowLong",
|
|
hwnd);
|
|
|
|
return 0;
|
|
}
|
|
|
|
/*
|
|
* Get the old window proc address
|
|
*/
|
|
dwOldLong = (LONG_PTR)PDLG(pwnd)->lpfnDlg;
|
|
|
|
/*
|
|
* We always store the actual address in the wndproc; We only
|
|
* give the CallProc handles to the application
|
|
*/
|
|
UserAssert(!ISCPDTAG(dwOldLong));
|
|
|
|
/*
|
|
* May need to return a CallProc handle if there is an
|
|
* Ansi/Unicode tranistion
|
|
*/
|
|
|
|
if (bAnsi != ((PDLG(pwnd)->flags & DLGF_ANSI) ? TRUE : FALSE)) {
|
|
dwCPDType |= bAnsi ? CPD_ANSI_TO_UNICODE : CPD_UNICODE_TO_ANSI;
|
|
}
|
|
|
|
/*
|
|
* If we detected a transition create a CallProc handle for
|
|
* this type of transition and this wndproc (dwOldLong)
|
|
*/
|
|
if (dwCPDType) {
|
|
ULONG_PTR cpd;
|
|
|
|
cpd = GetCPD(pwnd, dwCPDType | CPD_DIALOG, dwOldLong);
|
|
|
|
if (cpd) {
|
|
dwOldLong = cpd;
|
|
} else {
|
|
RIPMSGF0(RIP_WARNING,
|
|
"[DWL_DLGPROC]: Unable to alloc CPD handle");
|
|
}
|
|
}
|
|
|
|
/*
|
|
* Convert a possible CallProc Handle into a real address.
|
|
* The app may have kept the CallProc Handle from some
|
|
* previous mixed GetClassinfo or SetWindowLong.
|
|
*
|
|
* WARNING bAnsi is modified here to represent real type of
|
|
* proc rather than if SetWindowLongA or W was called
|
|
*/
|
|
if (ISCPDTAG(dwNewLong)) {
|
|
PCALLPROCDATA pCPD;
|
|
if (pCPD = HMValidateHandleNoRip((HANDLE)dwNewLong, TYPE_CALLPROC)) {
|
|
dwNewLong = KERNEL_ULONG_PTR_TO_ULONG_PTR(pCPD->pfnClientPrevious);
|
|
bAnsi = pCPD->wType & CPD_UNICODE_TO_ANSI;
|
|
}
|
|
}
|
|
|
|
/*
|
|
* If an app 'unsubclasses' a server-side window proc we need to
|
|
* restore everything so SendMessage and friends know that it's
|
|
* a server-side proc again. Need to check against client side
|
|
* stub addresses.
|
|
*/
|
|
PDLG(pwnd)->lpfnDlg = (DLGPROC)dwNewLong;
|
|
if (bAnsi) {
|
|
PDLG(pwnd)->flags |= DLGF_ANSI;
|
|
} else {
|
|
PDLG(pwnd)->flags &= ~DLGF_ANSI;
|
|
}
|
|
|
|
return dwOldLong;
|
|
|
|
case DWLP_USER:
|
|
#ifdef BUILD_WOW6432
|
|
// kernel has special handling of DWLP_USER
|
|
nIndex = sizeof(KERNEL_LRESULT) + sizeof(KERNEL_PVOID);
|
|
#endif
|
|
case DWLP_MSGRESULT:
|
|
break;
|
|
|
|
default:
|
|
if (nIndex >= 0 && nIndex < DLGWINDOWEXTRA) {
|
|
RIPERR0(ERROR_PRIVATE_DIALOG_INDEX, RIP_VERBOSE, "");
|
|
return 0;
|
|
}
|
|
}
|
|
}
|
|
|
|
BEGINCALL()
|
|
|
|
/*
|
|
* If this is a listbox window and the listbox structure has
|
|
* already been initialized, don't allow the app to override the
|
|
* owner draw styles. We need to do this since Windows only
|
|
* used the styles in creating the structure, but we also use
|
|
* them to determine if strings need to be thunked.
|
|
*
|
|
*/
|
|
|
|
if (nIndex == GWL_STYLE &&
|
|
GETFNID(pwnd) == FNID_LISTBOX &&
|
|
((PLBWND)pwnd)->pLBIV != NULL &&
|
|
(!TestWindowProcess(pwnd) || ((PLBWND)pwnd)->pLBIV->fInitialized)) {
|
|
|
|
#if DBG
|
|
LONG_PTR dwDebugLong = dwNewLong;
|
|
#endif
|
|
|
|
dwNewLong &= ~(LBS_OWNERDRAWFIXED |
|
|
LBS_OWNERDRAWVARIABLE |
|
|
LBS_HASSTRINGS);
|
|
|
|
dwNewLong |= pwnd->style & (LBS_OWNERDRAWFIXED |
|
|
LBS_OWNERDRAWVARIABLE |
|
|
LBS_HASSTRINGS);
|
|
|
|
#if DBG
|
|
if (dwDebugLong != dwNewLong) {
|
|
RIPMSG0(RIP_WARNING, "SetWindowLong can't change LBS_OWNERDRAW* or LBS_HASSTRINGS.");
|
|
}
|
|
#endif
|
|
}
|
|
|
|
|
|
retval = (ULONG_PTR)NtUserSetWindowLongPtr(
|
|
hwnd,
|
|
nIndex,
|
|
dwNewLong,
|
|
bAnsi);
|
|
|
|
ERRORTRAP(0);
|
|
ENDCALL(LONG_PTR);
|
|
}
|
|
|
|
#ifdef _WIN64
|
|
LONG _SetWindowLong(
|
|
HWND hwnd,
|
|
int nIndex,
|
|
LONG dwNewLong,
|
|
BOOL bAnsi)
|
|
{
|
|
PWND pwnd;
|
|
|
|
pwnd = ValidateHwnd(hwnd);
|
|
|
|
if (pwnd == NULL)
|
|
return 0;
|
|
|
|
if (TestWF(pwnd, WFDIALOGWINDOW)) {
|
|
switch (nIndex) {
|
|
case DWLP_DLGPROC: // See similar case GWLP_WNDPROC
|
|
RIPERR1(ERROR_INVALID_INDEX, RIP_WARNING, "SetWindowLong: invalid index %d", nIndex);
|
|
return 0;
|
|
|
|
case DWLP_MSGRESULT:
|
|
case DWLP_USER:
|
|
break;
|
|
|
|
default:
|
|
if (nIndex >= 0 && nIndex < DLGWINDOWEXTRA) {
|
|
RIPERR0(ERROR_PRIVATE_DIALOG_INDEX, RIP_VERBOSE, "");
|
|
return 0;
|
|
}
|
|
}
|
|
}
|
|
|
|
BEGINCALL()
|
|
|
|
/*
|
|
* If this is a listbox window and the listbox structure has
|
|
* already been initialized, don't allow the app to override the
|
|
* owner draw styles. We need to do this since Windows only
|
|
* used the styles in creating the structure, but we also use
|
|
* them to determine if strings need to be thunked.
|
|
*
|
|
*/
|
|
|
|
if (nIndex == GWL_STYLE &&
|
|
GETFNID(pwnd) == FNID_LISTBOX &&
|
|
((PLBWND)pwnd)->pLBIV != NULL &&
|
|
(!TestWindowProcess(pwnd) || ((PLBWND)pwnd)->pLBIV->fInitialized)) {
|
|
|
|
#if DBG
|
|
LONG dwDebugLong = dwNewLong;
|
|
#endif
|
|
|
|
dwNewLong &= ~(LBS_OWNERDRAWFIXED |
|
|
LBS_OWNERDRAWVARIABLE |
|
|
LBS_HASSTRINGS);
|
|
|
|
dwNewLong |= pwnd->style & (LBS_OWNERDRAWFIXED |
|
|
LBS_OWNERDRAWVARIABLE |
|
|
LBS_HASSTRINGS);
|
|
|
|
#if DBG
|
|
if (dwDebugLong != dwNewLong) {
|
|
RIPMSG0(RIP_WARNING, "SetWindowLong can't change LBS_OWNERDRAW* or LBS_HASSTRINGS.");
|
|
}
|
|
#endif
|
|
}
|
|
|
|
|
|
retval = (DWORD)NtUserSetWindowLong(
|
|
hwnd,
|
|
nIndex,
|
|
dwNewLong,
|
|
bAnsi);
|
|
|
|
ERRORTRAP(0);
|
|
ENDCALL(LONG);
|
|
}
|
|
#endif
|
|
|
|
BOOL TranslateMessageEx(
|
|
CONST MSG *pmsg,
|
|
UINT flags)
|
|
{
|
|
BEGINCALL()
|
|
|
|
/*
|
|
* Don't bother going over to the kernel if this isn't
|
|
* key message.
|
|
*/
|
|
switch (pmsg->message) {
|
|
case WM_KEYDOWN:
|
|
case WM_KEYUP:
|
|
case WM_SYSKEYDOWN:
|
|
case WM_SYSKEYUP:
|
|
break;
|
|
default:
|
|
if (pmsg->message & RESERVED_MSG_BITS) {
|
|
RIPERR1(ERROR_INVALID_PARAMETER,
|
|
RIP_WARNING,
|
|
"Invalid parameter \"pmsg->message\" (%ld) to TranslateMessageEx",
|
|
pmsg->message);
|
|
}
|
|
MSGERROR();
|
|
}
|
|
|
|
retval = (DWORD)NtUserTranslateMessage(
|
|
pmsg,
|
|
flags);
|
|
|
|
ERRORTRAP(0);
|
|
ENDCALL(BOOL);
|
|
}
|
|
|
|
BOOL TranslateMessage(
|
|
CONST MSG *pmsg)
|
|
{
|
|
//
|
|
// IME special key handling
|
|
//
|
|
if (LOWORD(pmsg->wParam) == VK_PROCESSKEY) {
|
|
BOOL fResult;
|
|
|
|
//
|
|
// This vkey should be processed by IME.
|
|
//
|
|
fResult = fpImmTranslateMessage(pmsg->hwnd,
|
|
pmsg->message,
|
|
pmsg->wParam,
|
|
pmsg->lParam);
|
|
if (fResult) {
|
|
return fResult;
|
|
}
|
|
}
|
|
|
|
return TranslateMessageEx(pmsg, 0);
|
|
}
|
|
|
|
|
|
FUNCLOG3(LOG_GENERAL, BOOL, DUMMYCALLINGTYPE, SetWindowRgn, HWND, hwnd, HRGN, hrgn, BOOL, bRedraw)
|
|
BOOL SetWindowRgn(
|
|
HWND hwnd,
|
|
HRGN hrgn,
|
|
BOOL bRedraw)
|
|
{
|
|
BOOL ret;
|
|
|
|
BEGIN_USERAPIHOOK()
|
|
ret = guah.pfnSetWindowRgn(hwnd, hrgn, bRedraw);
|
|
END_USERAPIHOOK()
|
|
|
|
return ret;
|
|
}
|
|
|
|
|
|
BOOL RealSetWindowRgn(
|
|
HWND hwnd,
|
|
HRGN hrgn,
|
|
BOOL bRedraw)
|
|
{
|
|
BEGINCALL()
|
|
|
|
retval = (DWORD)NtUserSetWindowRgn(
|
|
hwnd,
|
|
hrgn,
|
|
bRedraw);
|
|
|
|
if (retval) {
|
|
DeleteObject(hrgn);
|
|
}
|
|
|
|
ERRORTRAP(0);
|
|
ENDCALL(BOOL);
|
|
}
|
|
|
|
|
|
FUNCLOG3(LOG_GENERAL, BOOL, DUMMYCALLINGTYPE, InternalGetWindowText, HWND, hwnd, LPWSTR, pString, int, cchMaxCount)
|
|
BOOL InternalGetWindowText(
|
|
HWND hwnd,
|
|
LPWSTR pString,
|
|
int cchMaxCount)
|
|
{
|
|
BEGINCALL()
|
|
|
|
retval = (DWORD)NtUserInternalGetWindowText(
|
|
hwnd,
|
|
pString,
|
|
cchMaxCount);
|
|
|
|
if (!retval) {
|
|
*pString = (WCHAR)0;
|
|
}
|
|
|
|
ERRORTRAP(0);
|
|
ENDCALL(BOOL);
|
|
}
|
|
|
|
int ToUnicode(
|
|
UINT wVirtKey,
|
|
UINT wScanCode,
|
|
CONST BYTE *pKeyState,
|
|
LPWSTR pwszBuff,
|
|
int cchBuff,
|
|
UINT wFlags)
|
|
{
|
|
BEGINCALL()
|
|
|
|
retval = (DWORD)NtUserToUnicodeEx(
|
|
wVirtKey,
|
|
wScanCode,
|
|
pKeyState,
|
|
pwszBuff,
|
|
cchBuff,
|
|
wFlags,
|
|
(HKL)NULL);
|
|
|
|
if (!retval) {
|
|
*pwszBuff = L'\0';
|
|
}
|
|
|
|
ERRORTRAP(0);
|
|
ENDCALL(int);
|
|
}
|
|
|
|
int ToUnicodeEx(
|
|
UINT wVirtKey,
|
|
UINT wScanCode,
|
|
CONST BYTE *pKeyState,
|
|
LPWSTR pwszBuff,
|
|
int cchBuff,
|
|
UINT wFlags,
|
|
HKL hkl)
|
|
{
|
|
BEGINCALL()
|
|
|
|
retval = (DWORD)NtUserToUnicodeEx(
|
|
wVirtKey,
|
|
wScanCode,
|
|
pKeyState,
|
|
pwszBuff,
|
|
cchBuff,
|
|
wFlags,
|
|
hkl);
|
|
|
|
if (!retval) {
|
|
*pwszBuff = L'\0';
|
|
}
|
|
|
|
ERRORTRAP(0);
|
|
ENDCALL(int);
|
|
}
|
|
|
|
#if DBG
|
|
|
|
FUNCLOGVOID2(LOG_GENERAL, DUMMYCALLINGTYPE, DbgWin32HeapFail, DWORD, dwFlags, BOOL, bFail)
|
|
VOID DbgWin32HeapFail(
|
|
DWORD dwFlags,
|
|
BOOL bFail)
|
|
{
|
|
if ((dwFlags | WHF_VALID) != WHF_VALID) {
|
|
RIPMSG1(RIP_WARNING, "Invalid flags for DbgWin32HeapFail %x", dwFlags);
|
|
return;
|
|
}
|
|
|
|
if (dwFlags & WHF_CSRSS) {
|
|
// Tell csr about it
|
|
CsrWin32HeapFail(dwFlags, bFail);
|
|
}
|
|
|
|
NtUserDbgWin32HeapFail(dwFlags, bFail);
|
|
}
|
|
|
|
|
|
FUNCLOG3(LOG_GENERAL, DWORD, DUMMYCALLINGTYPE, DbgWin32HeapStat, PDBGHEAPSTAT, phs, DWORD, dwLen, DWORD, dwFlags)
|
|
DWORD DbgWin32HeapStat(
|
|
PDBGHEAPSTAT phs,
|
|
DWORD dwLen,
|
|
DWORD dwFlags)
|
|
{
|
|
if ((dwFlags | WHF_VALID) != WHF_VALID) {
|
|
RIPMSG1(RIP_WARNING, "Invalid flags for DbgWin32HeapFail %x", dwFlags);
|
|
return 0;
|
|
}
|
|
|
|
if (dwFlags & WHF_CSRSS) {
|
|
return CsrWin32HeapStat(phs, dwLen);
|
|
} else if (dwFlags & WHF_DESKTOP) {
|
|
return NtUserDbgWin32HeapStat(phs, dwLen);
|
|
}
|
|
return 0;
|
|
}
|
|
|
|
#endif // DBG
|
|
|
|
|
|
FUNCLOG4(LOG_GENERAL, BOOL, DUMMYCALLINGTYPE, SetWindowStationUser, HWINSTA, hwinsta, PLUID, pluidUser, PSID, psidUser, DWORD, cbsidUser)
|
|
BOOL SetWindowStationUser(
|
|
HWINSTA hwinsta,
|
|
PLUID pluidUser,
|
|
PSID psidUser,
|
|
DWORD cbsidUser)
|
|
{
|
|
LUID luidNone = { 0, 0 };
|
|
|
|
|
|
BEGINCALL()
|
|
|
|
retval = (DWORD)NtUserSetWindowStationUser(hwinsta,
|
|
pluidUser,
|
|
psidUser,
|
|
cbsidUser);
|
|
|
|
/*
|
|
* Load global atoms if the logon succeeded
|
|
*/
|
|
if (retval) {
|
|
|
|
if (!RtlEqualLuid(pluidUser,&luidNone)) {
|
|
/*
|
|
* Reset console and load Nls data.
|
|
*/
|
|
Logon(TRUE);
|
|
} else {
|
|
/*
|
|
* Flush NLS cache.
|
|
*/
|
|
Logon(FALSE);
|
|
}
|
|
|
|
retval = TRUE;
|
|
}
|
|
ERRORTRAP(0);
|
|
ENDCALL(BOOL);
|
|
}
|
|
|
|
|
|
FUNCLOG2(LOG_GENERAL, BOOL, DUMMYCALLINGTYPE, SetSystemCursor, HCURSOR, hcur, DWORD, id)
|
|
BOOL SetSystemCursor(
|
|
HCURSOR hcur,
|
|
DWORD id)
|
|
{
|
|
BEGINCALL()
|
|
|
|
if (hcur == NULL) {
|
|
hcur = (HANDLE)LoadIcoCur(NULL,
|
|
MAKEINTRESOURCE(id),
|
|
RT_CURSOR,
|
|
0,
|
|
0,
|
|
LR_DEFAULTSIZE);
|
|
|
|
if (hcur == NULL)
|
|
MSGERROR();
|
|
}
|
|
|
|
retval = (DWORD)NtUserSetSystemCursor(hcur, id);
|
|
|
|
ERRORTRAP(0);
|
|
ENDCALL(BOOL);
|
|
}
|
|
|
|
HCURSOR FindExistingCursorIcon(
|
|
LPWSTR pszModName,
|
|
LPCWSTR pszResName,
|
|
PCURSORFIND pcfSearch)
|
|
{
|
|
IN_STRING strModName;
|
|
IN_STRING strResName;
|
|
|
|
/*
|
|
* Make sure cleanup will work successfully
|
|
*/
|
|
strModName.fAllocated = FALSE;
|
|
strResName.fAllocated = FALSE;
|
|
|
|
BEGINCALL()
|
|
|
|
if (pszModName == NULL)
|
|
pszModName = szUSER32;
|
|
|
|
COPYLPWSTR(&strModName, pszModName);
|
|
COPYLPWSTRID(&strResName, pszResName);
|
|
|
|
retval = (ULONG_PTR)NtUserFindExistingCursorIcon(strModName.pstr,
|
|
strResName.pstr,
|
|
pcfSearch);
|
|
|
|
ERRORTRAP(0);
|
|
|
|
CLEANUPLPWSTR(strModName);
|
|
CLEANUPLPWSTR(strResName);
|
|
|
|
ENDCALL(HCURSOR);
|
|
}
|
|
|
|
|
|
|
|
BOOL _SetCursorIconData(
|
|
HCURSOR hCursor,
|
|
PCURSORDATA pcur)
|
|
{
|
|
IN_STRING strModName;
|
|
IN_STRING strResName;
|
|
|
|
/*
|
|
* Make sure cleanup will work successfully
|
|
*/
|
|
strModName.fAllocated = FALSE;
|
|
strResName.fAllocated = FALSE;
|
|
|
|
BEGINCALL()
|
|
|
|
COPYLPWSTROPT(&strModName, KPWSTR_TO_PWSTR(pcur->lpModName));
|
|
COPYLPWSTRIDOPT(&strResName, KPWSTR_TO_PWSTR(pcur->lpName));
|
|
|
|
retval = (DWORD)NtUserSetCursorIconData(hCursor,
|
|
strModName.pstr,
|
|
strResName.pstr,
|
|
pcur);
|
|
|
|
ERRORTRAP(0);
|
|
|
|
CLEANUPLPWSTR(strModName);
|
|
CLEANUPLPWSTR(strResName);
|
|
|
|
ENDCALL(BOOL);
|
|
}
|
|
|
|
|
|
|
|
BOOL _DefSetText(
|
|
HWND hwnd,
|
|
LPCWSTR lpszText,
|
|
BOOL bAnsi)
|
|
{
|
|
LARGE_STRING str;
|
|
|
|
BEGINCALL()
|
|
|
|
if (lpszText) {
|
|
if (bAnsi) {
|
|
RtlInitLargeAnsiString((PLARGE_ANSI_STRING)&str,
|
|
(LPSTR)lpszText, (UINT)-1);
|
|
} else {
|
|
RtlInitLargeUnicodeString((PLARGE_UNICODE_STRING)&str,
|
|
lpszText, (UINT)-1);
|
|
}
|
|
}
|
|
|
|
retval = (DWORD)NtUserDefSetText(hwnd, lpszText ? &str : NULL);
|
|
|
|
ERRORTRAP(0);
|
|
ENDCALL(BOOL);
|
|
}
|
|
|
|
HWND _CreateWindowEx(
|
|
DWORD dwExStyle,
|
|
LPCTSTR pClassName,
|
|
LPCTSTR pWindowName,
|
|
DWORD dwStyle,
|
|
int x,
|
|
int y,
|
|
int nWidth,
|
|
int nHeight,
|
|
HWND hwndParent,
|
|
HMENU hmenu,
|
|
HANDLE hModule,
|
|
LPVOID pParam,
|
|
DWORD dwFlags)
|
|
{
|
|
LARGE_IN_STRING strClassName;
|
|
LARGE_STRING strWindowName;
|
|
PLARGE_STRING pstrClassName;
|
|
PLARGE_STRING pstrWindowName;
|
|
DWORD dwExpWinVerAndFlags;
|
|
|
|
/*
|
|
* Make sure cleanup will work successfully
|
|
*/
|
|
strClassName.fAllocated = FALSE;
|
|
|
|
/*
|
|
* To be compatible with Chicago, we test the validity of
|
|
* the ExStyle bits and fail if any invalid bits are found.
|
|
* And for backward compatibilty with NT apps, we only fail for
|
|
* new apps (post NT 3.1).
|
|
*/
|
|
|
|
// BOGUS
|
|
|
|
if (dwExStyle & 0x00000800L) {
|
|
dwExStyle |= WS_EX_TOOLWINDOW;
|
|
dwExStyle &= 0xfffff7ffL;
|
|
}
|
|
|
|
dwExpWinVerAndFlags = (DWORD)(WORD)GETEXPWINVER(hModule);
|
|
if ((dwExStyle & ~WS_EX_ALLVALID) && Is400Compat(dwExpWinVerAndFlags)) {
|
|
RIPMSG1(RIP_WARNING, "Invalid 5.1 ExStyle 0x%x", dwExStyle);
|
|
return NULL;
|
|
}
|
|
|
|
{
|
|
|
|
BOOL fMDIchild = FALSE;
|
|
MDICREATESTRUCT mdics;
|
|
HMENU hSysMenu;
|
|
|
|
BEGINCALL()
|
|
|
|
if ((fMDIchild = (BOOL)(dwExStyle & WS_EX_MDICHILD))) {
|
|
SHORTCREATE sc;
|
|
PWND pwndParent;
|
|
|
|
pwndParent = ValidateHwnd(hwndParent);
|
|
if (pwndParent == NULL || GETFNID(pwndParent) != FNID_MDICLIENT) {
|
|
RIPMSG0(RIP_WARNING, "Invalid parent for MDI child window");
|
|
MSGERROR();
|
|
}
|
|
|
|
mdics.lParam = (LPARAM)pParam;
|
|
pParam = &mdics;
|
|
mdics.x = sc.x = x;
|
|
mdics.y = sc.y = y;
|
|
mdics.cx = sc.cx = nWidth;
|
|
mdics.cy = sc.cy = nHeight;
|
|
mdics.style = sc.style = dwStyle;
|
|
mdics.hOwner = hModule;
|
|
mdics.szClass = pClassName;
|
|
mdics.szTitle = pWindowName;
|
|
|
|
if (!CreateMDIChild(&sc, &mdics, dwExpWinVerAndFlags, &hSysMenu, pwndParent))
|
|
MSGERROR();
|
|
|
|
x = sc.x;
|
|
y = sc.y;
|
|
nWidth = sc.cx;
|
|
nHeight = sc.cy;
|
|
dwStyle = sc.style;
|
|
hmenu = sc.hMenu;
|
|
}
|
|
|
|
/*
|
|
* Set up class and window name. If the window name is an
|
|
* ordinal, make it look like a string so the callback thunk
|
|
* will be able to ensure it is in the correct format.
|
|
*/
|
|
pstrWindowName = NULL;
|
|
if (dwFlags & CW_FLAGS_ANSI) {
|
|
dwExStyle = dwExStyle | WS_EX_ANSICREATOR;
|
|
|
|
if (IS_PTR(pClassName)) {
|
|
RtlCaptureLargeAnsiString(&strClassName,
|
|
(PCHAR)pClassName, TRUE);
|
|
pstrClassName = (PLARGE_STRING)strClassName.pstr;
|
|
} else {
|
|
pstrClassName = (PLARGE_STRING)pClassName;
|
|
}
|
|
|
|
if (pWindowName != NULL) {
|
|
if (*(PBYTE)pWindowName == 0xff) {
|
|
strWindowName.bAnsi = TRUE;
|
|
strWindowName.Buffer = (PVOID)pWindowName;
|
|
strWindowName.Length = 3;
|
|
strWindowName.MaximumLength = 3;
|
|
} else {
|
|
RtlInitLargeAnsiString((PLARGE_ANSI_STRING)&strWindowName,
|
|
(LPSTR)pWindowName,
|
|
(UINT)-1);
|
|
}
|
|
|
|
pstrWindowName = &strWindowName;
|
|
}
|
|
} else {
|
|
if (IS_PTR(pClassName)) {
|
|
RtlInitLargeUnicodeString(
|
|
(PLARGE_UNICODE_STRING)&strClassName.strCapture,
|
|
pClassName, (UINT)-1);
|
|
pstrClassName = (PLARGE_STRING)&strClassName.strCapture;
|
|
} else {
|
|
pstrClassName = (PLARGE_STRING)pClassName;
|
|
}
|
|
|
|
if (pWindowName != NULL) {
|
|
if (pWindowName != NULL &&
|
|
*(PWORD)pWindowName == 0xffff) {
|
|
strWindowName.bAnsi = FALSE;
|
|
strWindowName.Buffer = (PVOID)pWindowName;
|
|
strWindowName.Length = 4;
|
|
strWindowName.MaximumLength = 4;
|
|
} else {
|
|
RtlInitLargeUnicodeString((PLARGE_UNICODE_STRING)&strWindowName,
|
|
pWindowName, (UINT)-1);
|
|
}
|
|
|
|
pstrWindowName = &strWindowName;
|
|
}
|
|
}
|
|
|
|
dwExpWinVerAndFlags |= (dwFlags & (CW_FLAGS_DIFFHMOD | CW_FLAGS_VERSIONCLASS));
|
|
|
|
retval = (ULONG_PTR)VerNtUserCreateWindowEx(
|
|
dwExStyle,
|
|
pstrClassName,
|
|
pstrWindowName,
|
|
dwStyle,
|
|
x,
|
|
y,
|
|
nWidth,
|
|
nHeight,
|
|
hwndParent,
|
|
hmenu,
|
|
hModule,
|
|
pParam,
|
|
dwExpWinVerAndFlags);
|
|
|
|
// If this is an MDI child, we need to do some more to complete the
|
|
// process of creating an MDI child.
|
|
if (retval && fMDIchild) {
|
|
MDICompleteChildCreation((HWND)retval, hSysMenu, ((dwStyle & WS_VISIBLE) != 0L), (BOOL)((dwStyle & WS_DISABLED)!= 0L));
|
|
}
|
|
|
|
|
|
ERRORTRAP(0);
|
|
CLEANUPLPSTRW(strClassName);
|
|
ENDCALL(HWND);
|
|
}
|
|
|
|
}
|
|
|
|
HKL _LoadKeyboardLayoutEx(
|
|
HANDLE hFile,
|
|
UINT offTable,
|
|
PKBDTABLE_MULTI_INTERNAL pKbdTableMulti,
|
|
HKL hkl,
|
|
LPCTSTR pwszKL,
|
|
UINT KbdInputLocale,
|
|
UINT Flags)
|
|
{
|
|
IN_STRING strKL;
|
|
|
|
/*
|
|
* Make sure cleanup will work successfully
|
|
*/
|
|
strKL.fAllocated = FALSE;
|
|
|
|
BEGINCALL()
|
|
|
|
FIRSTCOPYLPWSTR(&strKL, pwszKL);
|
|
|
|
retval = (ULONG_PTR)NtUserLoadKeyboardLayoutEx(
|
|
hFile,
|
|
offTable,
|
|
pKbdTableMulti,
|
|
hkl,
|
|
strKL.pstr,
|
|
KbdInputLocale,
|
|
Flags);
|
|
|
|
ERRORTRAP(0);
|
|
CLEANUPLPWSTR(strKL);
|
|
ENDCALL(HKL);
|
|
}
|
|
|
|
|
|
FUNCLOGVOID5(LOG_GENERAL, DUMMYCALLINGTYPE, mouse_event, DWORD, dwFlags, DWORD, dx, DWORD, dy, DWORD, dwData, ULONG_PTR, dwExtraInfo)
|
|
VOID mouse_event(
|
|
DWORD dwFlags,
|
|
DWORD dx,
|
|
DWORD dy,
|
|
DWORD dwData,
|
|
ULONG_PTR dwExtraInfo)
|
|
{
|
|
INPUT ms;
|
|
|
|
BEGINCALLVOID()
|
|
|
|
ms.type = INPUT_MOUSE;
|
|
ms.mi.dwFlags = dwFlags;
|
|
ms.mi.dx = dx;
|
|
ms.mi.dy = dy;
|
|
ms.mi.mouseData = dwData;
|
|
ms.mi.time = 0;
|
|
ms.mi.dwExtraInfo = dwExtraInfo;
|
|
|
|
NtUserSendInput(1, &ms, sizeof(INPUT));
|
|
|
|
ENDCALLVOID()
|
|
}
|
|
|
|
|
|
FUNCLOGVOID4(LOG_GENERAL, DUMMYCALLINGTYPE, keybd_event, BYTE, bVk, BYTE, bScan, DWORD, dwFlags, ULONG_PTR, dwExtraInfo)
|
|
VOID keybd_event(
|
|
BYTE bVk,
|
|
BYTE bScan,
|
|
DWORD dwFlags,
|
|
ULONG_PTR dwExtraInfo)
|
|
{
|
|
INPUT kbd;
|
|
|
|
BEGINCALLVOID()
|
|
|
|
kbd.type = INPUT_KEYBOARD;
|
|
kbd.ki.dwFlags = dwFlags;
|
|
kbd.ki.wVk = bVk;
|
|
kbd.ki.wScan = bScan;
|
|
kbd.ki.time = 0;
|
|
kbd.ki.dwExtraInfo = dwExtraInfo;
|
|
|
|
NtUserSendInput(1, &kbd, sizeof(INPUT));
|
|
|
|
ENDCALLVOID()
|
|
}
|
|
|
|
/*
|
|
* Message thunks
|
|
*/
|
|
MESSAGECALL(fnINWPARAMDBCSCHAR)
|
|
{
|
|
BEGINCALL()
|
|
|
|
/*
|
|
* The server always expects the characters to be unicode so
|
|
* if this was generated from an ANSI routine convert it to Unicode
|
|
*/
|
|
if (bAnsi) {
|
|
|
|
/*
|
|
* Setup for DBCS Messaging..
|
|
*/
|
|
BUILD_DBCS_MESSAGE_TO_SERVER_FROM_CLIENTA(msg,wParam,TRUE);
|
|
|
|
/*
|
|
* Convert DBCS/SBCS to Unicode...
|
|
*/
|
|
RtlMBMessageWParamCharToWCS(msg, &wParam);
|
|
}
|
|
|
|
retval = (DWORD)NtUserMessageCall(
|
|
hwnd,
|
|
msg,
|
|
wParam,
|
|
lParam,
|
|
xParam,
|
|
xpfnProc,
|
|
bAnsi);
|
|
|
|
ERRORTRAP(0);
|
|
ENDCALL(DWORD);
|
|
}
|
|
|
|
MESSAGECALL(fnCOPYGLOBALDATA)
|
|
{
|
|
PBYTE pData;
|
|
BEGINCALL()
|
|
|
|
if (wParam == 0) {
|
|
MSGERROR();
|
|
}
|
|
|
|
USERGLOBALLOCK((HGLOBAL)lParam, pData);
|
|
if (pData == NULL) {
|
|
MSGERROR();
|
|
}
|
|
retval = NtUserMessageCall(
|
|
hwnd,
|
|
msg,
|
|
wParam,
|
|
(LPARAM)pData,
|
|
xParam,
|
|
xpfnProc,
|
|
bAnsi);
|
|
USERGLOBALUNLOCK((HGLOBAL)lParam);
|
|
UserGlobalFree((HGLOBAL)lParam);
|
|
ERRORTRAP(0);
|
|
ENDCALL(ULONG_PTR);
|
|
}
|
|
|
|
MESSAGECALL(fnINPAINTCLIPBRD)
|
|
{
|
|
LPPAINTSTRUCT lpps;
|
|
|
|
BEGINCALL()
|
|
|
|
USERGLOBALLOCK((HGLOBAL)lParam, lpps);
|
|
if (lpps) {
|
|
retval = (DWORD)NtUserMessageCall(
|
|
hwnd,
|
|
msg,
|
|
wParam,
|
|
(LPARAM)lpps,
|
|
xParam,
|
|
xpfnProc,
|
|
bAnsi);
|
|
USERGLOBALUNLOCK((HGLOBAL)lParam);
|
|
} else {
|
|
RIPMSG1(RIP_WARNING, "MESSAGECALL(fnINPAINTCLIPBRD): USERGLOBALLOCK failed on %p!", lParam);
|
|
MSGERROR();
|
|
}
|
|
|
|
ERRORTRAP(0);
|
|
ENDCALL(DWORD);
|
|
}
|
|
|
|
MESSAGECALL(fnINSIZECLIPBRD)
|
|
{
|
|
LPRECT lprc;
|
|
BEGINCALL()
|
|
|
|
USERGLOBALLOCK((HGLOBAL)lParam, lprc);
|
|
if (lprc) {
|
|
retval = (DWORD)NtUserMessageCall(
|
|
hwnd,
|
|
msg,
|
|
wParam,
|
|
(LPARAM)lprc,
|
|
xParam,
|
|
xpfnProc,
|
|
bAnsi);
|
|
USERGLOBALUNLOCK((HGLOBAL)lParam);
|
|
} else {
|
|
RIPMSG1(RIP_WARNING, "MESSAGECALL(fnINSIZECLIPBRD): USERGLOBALLOCK failed on %p!", lParam);
|
|
MSGERROR();
|
|
}
|
|
|
|
ERRORTRAP(0);
|
|
ENDCALL(DWORD);
|
|
}
|
|
|
|
MESSAGECALL(fnINDEVICECHANGE)
|
|
{
|
|
struct _DEV_BROADCAST_HEADER *pHdr;
|
|
PDEV_BROADCAST_PORT_W pPortW = NULL;
|
|
PDEV_BROADCAST_PORT_A pPortA;
|
|
PDEV_BROADCAST_DEVICEINTERFACE_W pInterfaceW = NULL;
|
|
PDEV_BROADCAST_DEVICEINTERFACE_A pInterfaceA;
|
|
PDEV_BROADCAST_HANDLE pHandleW = NULL;
|
|
PDEV_BROADCAST_HANDLE pHandleA;
|
|
|
|
LPWSTR lpStr;
|
|
int iStr, iSize;
|
|
|
|
BEGINCALL()
|
|
|
|
if (!(wParam &0x8000) || !lParam || !bAnsi)
|
|
goto shipit;
|
|
|
|
pHdr = (struct _DEV_BROADCAST_HEADER *)lParam;
|
|
switch (pHdr->dbcd_devicetype) {
|
|
case DBT_DEVTYP_PORT:
|
|
pPortA = (PDEV_BROADCAST_PORT_A)lParam;
|
|
iStr = strlen(pPortA->dbcp_name);
|
|
iSize = FIELD_OFFSET(DEV_BROADCAST_PORT_W, dbcp_name) + sizeof(WCHAR)*(iStr+1);
|
|
pPortW = UserLocalAlloc(0, iSize);
|
|
if (pPortW == NULL)
|
|
return 0;
|
|
RtlCopyMemory(pPortW, pPortA, sizeof(DEV_BROADCAST_PORT_A));
|
|
lpStr = pPortW->dbcp_name;
|
|
if (iStr) {
|
|
MBToWCS(pPortA->dbcp_name, -1, &lpStr, iStr, FALSE);
|
|
lpStr[iStr] = 0;
|
|
} else {
|
|
lpStr[0] = 0;
|
|
}
|
|
pPortW->dbcp_size = iSize;
|
|
lParam = (LPARAM)pPortW;
|
|
bAnsi = FALSE;
|
|
break;
|
|
|
|
case DBT_DEVTYP_DEVICEINTERFACE:
|
|
pInterfaceA = (PDEV_BROADCAST_DEVICEINTERFACE_A)lParam;
|
|
iStr = strlen(pInterfaceA->dbcc_name);
|
|
iSize = FIELD_OFFSET(DEV_BROADCAST_DEVICEINTERFACE_W, dbcc_name) + sizeof(WCHAR)*(iStr+1);
|
|
pInterfaceW = UserLocalAlloc(0, iSize);
|
|
if (pInterfaceW == NULL)
|
|
return 0;
|
|
RtlCopyMemory(pInterfaceW, pInterfaceA, sizeof(DEV_BROADCAST_DEVICEINTERFACE_A));
|
|
lpStr = pInterfaceW->dbcc_name;
|
|
if (iStr) {
|
|
MBToWCS(pInterfaceA->dbcc_name, -1, &lpStr, iStr, FALSE);
|
|
lpStr[iStr] = 0;
|
|
} else {
|
|
lpStr[0] = 0;
|
|
}
|
|
pInterfaceW->dbcc_size = iSize;
|
|
lParam = (LPARAM)pInterfaceW;
|
|
bAnsi = FALSE;
|
|
break;
|
|
|
|
case DBT_DEVTYP_HANDLE:
|
|
pHandleA = (PDEV_BROADCAST_HANDLE)lParam;
|
|
bAnsi = FALSE;
|
|
if ((wParam != DBT_CUSTOMEVENT) || (pHandleA->dbch_nameoffset < 0)) break;
|
|
iStr = strlen(pHandleA->dbch_data+pHandleA->dbch_nameoffset);
|
|
/*
|
|
* Calculate size of new structure with UNICODE string instead of Ansi string
|
|
*/
|
|
|
|
iSize = FIELD_OFFSET(DEV_BROADCAST_HANDLE, dbch_data)+ pHandleA->dbch_nameoffset + sizeof(WCHAR)*(iStr+1);
|
|
/*
|
|
* Just in case there were an odd number of bytes in the non-text data
|
|
*/
|
|
if (iSize & 1) iSize++;
|
|
pHandleW = UserLocalAlloc(0, iSize);
|
|
if (pHandleW == NULL)
|
|
return 0;
|
|
RtlCopyMemory(pHandleW, pHandleA, FIELD_OFFSET(DEV_BROADCAST_HANDLE, dbch_data)+ pHandleA->dbch_nameoffset);
|
|
|
|
/*
|
|
* Make sure this is even for the UNICODE string.
|
|
*/
|
|
|
|
if (pHandleW->dbch_nameoffset & 1) pHandleW->dbch_nameoffset++;
|
|
|
|
lpStr = (LPWSTR)(pHandleW->dbch_data+pHandleW->dbch_nameoffset);
|
|
if (iStr) {
|
|
MBToWCS(pHandleA->dbch_data+pHandleA->dbch_nameoffset, -1,
|
|
&lpStr, iStr, FALSE);
|
|
}
|
|
lpStr[iStr] = 0;
|
|
pHandleW->dbch_size = iSize;
|
|
lParam = (LPARAM)pHandleW;
|
|
|
|
break;
|
|
}
|
|
|
|
shipit:
|
|
retval = (DWORD)NtUserMessageCall(
|
|
hwnd,
|
|
msg,
|
|
wParam,
|
|
lParam,
|
|
xParam,
|
|
xpfnProc,
|
|
bAnsi);
|
|
|
|
if (pPortW) UserLocalFree(pPortW);
|
|
if (pInterfaceW) UserLocalFree(pInterfaceW);
|
|
if (pHandleW) UserLocalFree(pHandleW);
|
|
|
|
ERRORTRAP(0);
|
|
ENDCALL(DWORD);
|
|
}
|
|
|
|
MESSAGECALL(fnIMECONTROL)
|
|
{
|
|
PVOID pvData = NULL;
|
|
LPARAM lData = lParam;
|
|
|
|
BEGINCALL()
|
|
|
|
/*
|
|
* The server always expects the characters to be unicode so
|
|
* if this was generated from an ANSI routine convert it to Unicode
|
|
*/
|
|
if (bAnsi) {
|
|
switch (wParam) {
|
|
case IMC_GETCOMPOSITIONFONT:
|
|
case IMC_GETSOFTKBDFONT:
|
|
case IMC_SETCOMPOSITIONFONT:
|
|
pvData = UserLocalAlloc(0, sizeof(LOGFONTW));
|
|
if (pvData == NULL)
|
|
MSGERROR();
|
|
|
|
if (wParam == IMC_SETCOMPOSITIONFONT) {
|
|
// Later, we do A/W conversion based on thread hkl/CP.
|
|
CopyLogFontAtoW((PLOGFONTW)pvData, (PLOGFONTA)lParam);
|
|
}
|
|
|
|
lData = (LPARAM)pvData;
|
|
break;
|
|
|
|
case IMC_SETSOFTKBDDATA:
|
|
{
|
|
PSOFTKBDDATA pSoftKbdData;
|
|
PWORD pCodeA;
|
|
PWSTR pCodeW;
|
|
CHAR ch[3];
|
|
DWORD cbSize;
|
|
UINT uCount, i;
|
|
|
|
uCount = ((PSOFTKBDDATA)lParam)->uCount;
|
|
|
|
cbSize = FIELD_OFFSET(SOFTKBDDATA, wCode[0])
|
|
+ uCount * sizeof(WORD) * 256;
|
|
|
|
pvData = UserLocalAlloc(0, cbSize);
|
|
if (pvData == NULL)
|
|
MSGERROR();
|
|
|
|
pSoftKbdData = (PSOFTKBDDATA)pvData;
|
|
|
|
pSoftKbdData->uCount = uCount;
|
|
|
|
ch[2] = (CHAR)'\0';
|
|
|
|
pCodeA = &((PSOFTKBDDATA)lParam)->wCode[0][0];
|
|
pCodeW = &pSoftKbdData->wCode[0][0];
|
|
|
|
i = uCount * 256;
|
|
|
|
while (i--) {
|
|
if (HIBYTE(*pCodeA)) {
|
|
ch[0] = (CHAR)HIBYTE(*pCodeA);
|
|
ch[1] = (CHAR)LOBYTE(*pCodeA);
|
|
} else {
|
|
ch[0] = (CHAR)LOBYTE(*pCodeA);
|
|
ch[1] = (CHAR)'\0';
|
|
}
|
|
MBToWCSEx(THREAD_CODEPAGE(), (LPSTR)&ch, -1, &pCodeW, 1, FALSE);
|
|
pCodeA++; pCodeW++;
|
|
}
|
|
|
|
lData = (LPARAM)pvData;
|
|
}
|
|
break;
|
|
|
|
default:
|
|
break;
|
|
}
|
|
}
|
|
|
|
retval = (DWORD)NtUserMessageCall(
|
|
hwnd,
|
|
msg,
|
|
wParam,
|
|
lData,
|
|
xParam,
|
|
xpfnProc,
|
|
bAnsi);
|
|
|
|
if (bAnsi) {
|
|
switch (wParam) {
|
|
case IMC_GETCOMPOSITIONFONT:
|
|
case IMC_GETSOFTKBDFONT:
|
|
CopyLogFontWtoA((PLOGFONTA)lParam, (PLOGFONTW)pvData);
|
|
break;
|
|
|
|
default:
|
|
break;
|
|
}
|
|
}
|
|
|
|
if (pvData != NULL)
|
|
UserLocalFree(pvData);
|
|
|
|
ERRORTRAP(0);
|
|
ENDCALL(DWORD);
|
|
}
|
|
|
|
DWORD CalcCharacterPositionAtoW(
|
|
DWORD dwCharPosA,
|
|
LPSTR lpszCharStr,
|
|
DWORD dwCodePage)
|
|
{
|
|
DWORD dwCharPosW = 0;
|
|
|
|
while (dwCharPosA != 0) {
|
|
if (IsDBCSLeadByteEx(dwCodePage, *lpszCharStr)) {
|
|
if (dwCharPosA >= 2) {
|
|
dwCharPosA -= 2;
|
|
}
|
|
else {
|
|
dwCharPosA--;
|
|
}
|
|
lpszCharStr += 2;
|
|
}
|
|
else {
|
|
dwCharPosA--;
|
|
lpszCharStr++;
|
|
}
|
|
dwCharPosW++;
|
|
}
|
|
|
|
return dwCharPosW;
|
|
}
|
|
|
|
int UnicodeToMultiByteSize(DWORD dwCodePage, LPCWSTR pwstr)
|
|
{
|
|
char dummy[2], *lpszDummy = dummy;
|
|
return WCSToMBEx((WORD)dwCodePage, pwstr, 1, &lpszDummy, sizeof(WCHAR), FALSE);
|
|
}
|
|
|
|
DWORD CalcCharacterPositionWtoA(
|
|
DWORD dwCharPosW,
|
|
LPWSTR lpwszCharStr,
|
|
DWORD dwCodePage)
|
|
{
|
|
DWORD dwCharPosA = 0;
|
|
ULONG MultiByteSize;
|
|
|
|
while (dwCharPosW != 0) {
|
|
MultiByteSize = UnicodeToMultiByteSize(dwCodePage, lpwszCharStr);
|
|
if (MultiByteSize == 2) {
|
|
dwCharPosA += 2;
|
|
}
|
|
else {
|
|
dwCharPosA++;
|
|
}
|
|
dwCharPosW--;
|
|
lpwszCharStr++;
|
|
}
|
|
|
|
return dwCharPosA;
|
|
}
|
|
|
|
#ifdef LATER
|
|
DWORD WINAPI ImmGetReconvertTotalSize(DWORD dwSize, REQ_CALLER eCaller, BOOL bAnsiTarget)
|
|
{
|
|
if (dwSize < sizeof(RECONVERTSTRING)) {
|
|
return 0;
|
|
}
|
|
if (bAnsiTarget) {
|
|
dwSize -= sizeof(RECONVERTSTRING);
|
|
if (eCaller == FROM_IME) {
|
|
dwSize /= 2;
|
|
} else {
|
|
dwSize *= 2;
|
|
}
|
|
dwSize += sizeof(RECONVERTSTRING);
|
|
}
|
|
return dwSize;
|
|
}
|
|
|
|
|
|
FUNCLOG4(LOG_GENERAL, DWORD, WINAPI, ImmReconversionWorker, LPRECONVERTSTRING, lpRecTo, LPRECONVERTSTRING, lpRecFrom, BOOL, bToAnsi, DWORD, dwCodePage)
|
|
DWORD WINAPI ImmReconversionWorker(
|
|
LPRECONVERTSTRING lpRecTo,
|
|
LPRECONVERTSTRING lpRecFrom,
|
|
BOOL bToAnsi,
|
|
DWORD dwCodePage)
|
|
{
|
|
INT i;
|
|
DWORD dwSize = 0;
|
|
|
|
UserAssert(lpRecTo);
|
|
UserAssert(lpRecFrom);
|
|
|
|
if (lpRecFrom->dwVersion != 0 || lpRecTo->dwVersion != 0) {
|
|
RIPMSG0(RIP_WARNING, "ImmReconversionWorker: dwVersion in lpRecTo or lpRecFrom is incorrect.");
|
|
return 0;
|
|
}
|
|
// Note:
|
|
// In any IME related structures, use the following principal.
|
|
// 1) xxxStrOffset is an actual offset, i.e. byte count.
|
|
// 2) xxxStrLen is a number of characters, i.e. TCHAR count.
|
|
//
|
|
// CalcCharacterPositionXtoY() takes TCHAR count so that we
|
|
// need to adjust xxxStrOffset if it's being converted. But you
|
|
// should be careful, because the actual position of the string
|
|
// is always at something like (LPBYTE)lpStruc + lpStruc->dwStrOffset.
|
|
//
|
|
if (bToAnsi) {
|
|
// Convert W to A
|
|
lpRecTo->dwStrOffset = sizeof *lpRecTo;
|
|
i = WideCharToMultiByte(dwCodePage,
|
|
(DWORD)0,
|
|
(LPWSTR)((LPSTR)lpRecFrom + lpRecFrom->dwStrOffset), // src
|
|
(INT)lpRecFrom->dwStrLen,
|
|
(LPSTR)lpRecTo + lpRecTo->dwStrOffset, // dest
|
|
(INT)lpRecFrom->dwStrLen * DBCS_CHARSIZE,
|
|
(LPSTR)NULL,
|
|
(LPBOOL)NULL);
|
|
lpRecTo->dwCompStrOffset =
|
|
CalcCharacterPositionWtoA(lpRecFrom->dwCompStrOffset / sizeof(WCHAR),
|
|
(LPWSTR)((LPBYTE)lpRecFrom + lpRecFrom->dwStrOffset),
|
|
dwCodePage)
|
|
* sizeof(CHAR);
|
|
|
|
lpRecTo->dwCompStrLen =
|
|
(CalcCharacterPositionWtoA(lpRecFrom->dwCompStrOffset / sizeof(WCHAR) +
|
|
lpRecFrom->dwCompStrLen,
|
|
(LPWSTR)((LPBYTE)lpRecFrom + lpRecFrom->dwStrOffset),
|
|
dwCodePage)
|
|
* sizeof(CHAR))
|
|
- lpRecTo->dwCompStrOffset;
|
|
|
|
lpRecTo->dwTargetStrOffset =
|
|
CalcCharacterPositionWtoA(lpRecFrom->dwTargetStrOffset / sizeof(WCHAR),
|
|
(LPWSTR)((LPBYTE)lpRecFrom +
|
|
lpRecFrom->dwStrOffset),
|
|
dwCodePage)
|
|
* sizeof(CHAR);
|
|
|
|
lpRecTo->dwTargetStrLen =
|
|
(CalcCharacterPositionWtoA(lpRecFrom->dwTargetStrOffset / sizeof(WCHAR) +
|
|
lpRecFrom->dwTargetStrLen,
|
|
(LPWSTR)((LPBYTE)lpRecFrom + lpRecFrom->dwStrOffset),
|
|
dwCodePage)
|
|
* sizeof(CHAR))
|
|
- lpRecTo->dwTargetStrOffset;
|
|
|
|
((LPSTR)lpRecTo)[lpRecTo->dwStrOffset + i] = '\0';
|
|
lpRecTo->dwStrLen = i * sizeof(CHAR);
|
|
|
|
dwSize = sizeof(RECONVERTSTRING) + ((i + 1) * sizeof(CHAR));
|
|
|
|
} else {
|
|
|
|
// AtoW
|
|
lpRecTo->dwStrOffset = sizeof *lpRecTo;
|
|
i = MultiByteToWideChar(dwCodePage,
|
|
(DWORD)MB_PRECOMPOSED,
|
|
(LPSTR)lpRecFrom + lpRecFrom->dwStrOffset, // src
|
|
(INT)lpRecFrom->dwStrLen,
|
|
(LPWSTR)((LPSTR)lpRecTo + lpRecTo->dwStrOffset), // dest
|
|
(INT)lpRecFrom->dwStrLen);
|
|
|
|
lpRecTo->dwCompStrOffset =
|
|
CalcCharacterPositionAtoW(lpRecFrom->dwCompStrOffset,
|
|
(LPSTR)lpRecFrom + lpRecFrom->dwStrOffset,
|
|
dwCodePage) * sizeof(WCHAR);
|
|
|
|
lpRecTo->dwCompStrLen =
|
|
((CalcCharacterPositionAtoW(lpRecFrom->dwCompStrOffset +
|
|
lpRecFrom->dwCompStrLen,
|
|
(LPSTR)lpRecFrom + lpRecFrom->dwStrOffset,
|
|
dwCodePage) * sizeof(WCHAR))
|
|
- lpRecTo->dwCompStrOffset) / sizeof(WCHAR);
|
|
|
|
lpRecTo->dwTargetStrOffset =
|
|
CalcCharacterPositionAtoW(lpRecFrom->dwTargetStrOffset,
|
|
(LPSTR)lpRecFrom + lpRecFrom->dwStrOffset,
|
|
dwCodePage) * sizeof(WCHAR);
|
|
|
|
lpRecTo->dwTargetStrLen =
|
|
((CalcCharacterPositionAtoW(lpRecFrom->dwTargetStrOffset +
|
|
lpRecFrom->dwTargetStrLen,
|
|
(LPSTR)lpRecFrom + lpRecFrom->dwStrOffset,
|
|
dwCodePage) * sizeof(WCHAR))
|
|
- lpRecTo->dwTargetStrOffset) / sizeof(WCHAR);
|
|
|
|
lpRecTo->dwStrLen = i; // Length is TCHAR count.
|
|
if (lpRecTo->dwSize >= (DWORD)(lpRecTo->dwStrOffset + (i + 1)* sizeof(WCHAR))) {
|
|
LPWSTR lpW = (LPWSTR)((LPSTR)lpRecTo + lpRecTo->dwStrOffset);
|
|
lpW[i] = L'\0';
|
|
}
|
|
dwSize = sizeof(RECONVERTSTRING) + ((i + 1) * sizeof(WCHAR));
|
|
}
|
|
return dwSize;
|
|
}
|
|
|
|
#define GETCOMPOSITIONSTRING(hImc, index, buf, buflen) \
|
|
(bAnsi ? fpImmGetCompositionStringA : fpImmGetCompositionStringW)((hImc), (index), (buf), (buflen))
|
|
|
|
MESSAGECALL(fnIMEREQUEST)
|
|
{
|
|
PVOID pvData = NULL;
|
|
LPARAM lData = lParam;
|
|
|
|
BEGINCALL()
|
|
|
|
if (!IS_IME_ENABLED()) {
|
|
// If IME is not enabled, save time.
|
|
MSGERROR();
|
|
}
|
|
|
|
/*
|
|
* The server always expects the characters to be unicode so
|
|
* if this was generated from an ANSI routine convert it to Unicode
|
|
*/
|
|
if (wParam == IMR_QUERYCHARPOSITION) {
|
|
//
|
|
// Store the UNICODE character count in PrivateIMECHARPOSITION.
|
|
//
|
|
// No need to save the original dwCharPos, since dwCharPositionA/W are not
|
|
// overwritten in the kernel.
|
|
//
|
|
if (bAnsi) {
|
|
((LPIMECHARPOSITION)lParam)->dwCharPos = ((LPPrivateIMECHARPOSITION)lParam)->dwCharPositionW;
|
|
}
|
|
}
|
|
else if (bAnsi) {
|
|
switch (wParam) {
|
|
case IMR_COMPOSITIONFONT:
|
|
pvData = UserLocalAlloc(0, sizeof(LOGFONTW));
|
|
if (pvData == NULL)
|
|
MSGERROR();
|
|
lData = (LPARAM)pvData;
|
|
break;
|
|
|
|
case IMR_CONFIRMRECONVERTSTRING:
|
|
case IMR_RECONVERTSTRING:
|
|
case IMR_DOCUMENTFEED:
|
|
if ((LPVOID)lParam != NULL) {
|
|
// IME wants not only the buffer size but the real reconversion information
|
|
DWORD dwSize = ImmGetReconvertTotalSize(((LPRECONVERTSTRING)lParam)->dwSize, FROM_IME, FALSE);
|
|
LPRECONVERTSTRING lpReconv;
|
|
|
|
pvData = UserLocalAlloc(0, dwSize + sizeof(WCHAR));
|
|
if (pvData == NULL) {
|
|
RIPMSG0(RIP_WARNING, "fnIMEREQUEST: failed to allocate a buffer for reconversion.");
|
|
MSGERROR();
|
|
}
|
|
lpReconv = (LPRECONVERTSTRING)pvData;
|
|
// setup the information in the allocated structure
|
|
lpReconv->dwVersion = 0;
|
|
lpReconv->dwSize = dwSize;
|
|
|
|
//
|
|
// if it's confirmation message, we need to translate the contents
|
|
//
|
|
if (wParam == IMR_CONFIRMRECONVERTSTRING) {
|
|
ImmReconversionWorker(lpReconv, (LPRECONVERTSTRING)lParam, FALSE, CP_ACP);
|
|
}
|
|
}
|
|
break;
|
|
|
|
default:
|
|
break;
|
|
}
|
|
}
|
|
|
|
retval = (DWORD)NtUserMessageCall(
|
|
hwnd,
|
|
msg,
|
|
wParam,
|
|
lData,
|
|
xParam,
|
|
xpfnProc,
|
|
bAnsi);
|
|
|
|
if (bAnsi) {
|
|
switch (wParam) {
|
|
case IMR_COMPOSITIONFONT:
|
|
if (retval) {
|
|
CopyLogFontWtoA((PLOGFONTA)lParam, (PLOGFONTW)pvData);
|
|
}
|
|
break;
|
|
|
|
case IMR_QUERYCHARPOSITION:
|
|
((LPIMECHARPOSITION)lParam)->dwCharPos = ((LPPrivateIMECHARPOSITION)lParam)->dwCharPositionA;
|
|
break;
|
|
|
|
case IMR_RECONVERTSTRING:
|
|
case IMR_DOCUMENTFEED:
|
|
//
|
|
// Note: by definition, we don't need back-conversion for IMR_CONFIRMRECONVERTSTRING
|
|
//
|
|
if (retval) {
|
|
// IME wants the buffer size
|
|
retval = ImmGetReconvertTotalSize((DWORD)retval, FROM_APP, FALSE);
|
|
if (retval < sizeof(RECONVERTSTRING)) {
|
|
RIPMSG2(RIP_WARNING, "WM_IME_REQUEST(%x): return value from application %d is invalid.", wParam, retval);
|
|
retval = 0;
|
|
} else if (lParam) {
|
|
// We need to perform the A/W conversion of the contents
|
|
if (!ImmReconversionWorker((LPRECONVERTSTRING)lParam, (LPRECONVERTSTRING)pvData, TRUE, CP_ACP)) {
|
|
MSGERROR();
|
|
}
|
|
}
|
|
}
|
|
break;
|
|
}
|
|
}
|
|
|
|
|
|
ERRORTRAP(0);
|
|
|
|
if (pvData != NULL)
|
|
UserLocalFree(pvData);
|
|
|
|
ENDCALL(DWORD);
|
|
}
|
|
#endif
|
|
|
|
MESSAGECALL(fnEMGETSEL)
|
|
{
|
|
PWND pwnd = ValidateHwnd(hwnd);
|
|
|
|
if (pwnd == NULL)
|
|
return 0;
|
|
|
|
BEGINCALL()
|
|
|
|
retval = (DWORD)NtUserMessageCall(
|
|
hwnd,
|
|
msg,
|
|
wParam,
|
|
lParam,
|
|
xParam,
|
|
xpfnProc,
|
|
bAnsi);
|
|
|
|
//
|
|
// temp for our beta...
|
|
//
|
|
// !!! THIS CODE SHOULD BE IN KERNEL MODE !!!
|
|
//
|
|
// to reduce user <-> kernel mode transition...
|
|
//
|
|
if (bAnsi != ((TestWF(pwnd, WFANSIPROC)) ? TRUE : FALSE)) {
|
|
ULONG cchTextLength;
|
|
LONG lOriginalLengthW;
|
|
LONG lOriginalLengthL;
|
|
LONG wParamLocal;
|
|
LONG lParamLocal;
|
|
|
|
if (wParam) {
|
|
lOriginalLengthW = *(LONG *)wParam;
|
|
} else {
|
|
lOriginalLengthW = (LONG)(LOWORD(retval));
|
|
}
|
|
|
|
if (lParam) {
|
|
lOriginalLengthL = *(LONG *)lParam;
|
|
} else {
|
|
lOriginalLengthL = (LONG)(HIWORD(retval));
|
|
}
|
|
|
|
cchTextLength = (DWORD)NtUserMessageCall(
|
|
hwnd,
|
|
WM_GETTEXTLENGTH,
|
|
(WPARAM)0,
|
|
(LPARAM)0,
|
|
xParam,
|
|
xpfnProc,
|
|
bAnsi);
|
|
|
|
if (cchTextLength) {
|
|
PVOID pvString;
|
|
ULONG cbTextLength;
|
|
|
|
cchTextLength++;
|
|
if (!bAnsi) {
|
|
cbTextLength = cchTextLength * sizeof(WCHAR);
|
|
} else {
|
|
cbTextLength = cchTextLength;
|
|
}
|
|
|
|
pvString = UserLocalAlloc(0,cbTextLength);
|
|
|
|
if (pvString) {
|
|
|
|
retval = (DWORD)NtUserMessageCall(
|
|
hwnd,
|
|
WM_GETTEXT,
|
|
cchTextLength,
|
|
(LPARAM)pvString,
|
|
xParam,
|
|
xpfnProc,
|
|
bAnsi);
|
|
|
|
if (retval) {
|
|
if (bAnsi) {
|
|
/*
|
|
* ansiString/unicodeLenght -> ansiLength
|
|
*/
|
|
CalcAnsiStringLengthA(pvString, lOriginalLengthW, &wParamLocal)
|
|
CalcAnsiStringLengthA(pvString, lOriginalLengthL, &lParamLocal);
|
|
} else {
|
|
/*
|
|
* unicodeString/ansiLenght -> unicodeLength
|
|
*/
|
|
CalcUnicodeStringLengthW(pvString, lOriginalLengthW, &wParamLocal);
|
|
CalcUnicodeStringLengthW(pvString, lOriginalLengthL, &lParamLocal);
|
|
}
|
|
|
|
retval = (DWORD)(((lParamLocal) << 16) | ((wParamLocal) & 0x0000FFFF));
|
|
|
|
if (wParam) {
|
|
*(LONG *)wParam = wParamLocal;
|
|
}
|
|
|
|
if (lParam) {
|
|
*(LONG *)lParam = lParamLocal;
|
|
}
|
|
|
|
} else {
|
|
UserLocalFree(pvString);
|
|
MSGERROR();
|
|
}
|
|
|
|
UserLocalFree(pvString);
|
|
|
|
} else {
|
|
MSGERROR();
|
|
}
|
|
} else {
|
|
MSGERROR();
|
|
}
|
|
}
|
|
|
|
ERRORTRAP(0);
|
|
ENDCALL(DWORD);
|
|
}
|
|
|
|
MESSAGECALL(fnEMSETSEL)
|
|
{
|
|
PWND pwnd = ValidateHwnd(hwnd);
|
|
|
|
if (pwnd == NULL) {
|
|
return 0;
|
|
}
|
|
|
|
BEGINCALL()
|
|
|
|
//
|
|
// temp for our beta...
|
|
//
|
|
// !!! THIS CODE SHOULD BE IN KERNEL MODE !!!
|
|
//
|
|
// to reduce user <-> kernel mode transition...
|
|
//
|
|
if (bAnsi != ((TestWF(pwnd, WFANSIPROC)) ? TRUE : FALSE)) {
|
|
if (((LONG)wParam <= 0) && ((LONG)lParam <=0)) {
|
|
//
|
|
// if (wParam == 0 or wParam == -1)
|
|
// and
|
|
// (lParam == 0 or lParam == -1)
|
|
//
|
|
// In this case, we don't need to convert the value...
|
|
//
|
|
} else {
|
|
ULONG cchTextLength;
|
|
LONG lOriginalLengthW = (LONG)wParam;
|
|
LONG lOriginalLengthL = (LONG)lParam;
|
|
|
|
cchTextLength = (DWORD)NtUserMessageCall(
|
|
hwnd,
|
|
WM_GETTEXTLENGTH,
|
|
(WPARAM)0,
|
|
(LPARAM)0,
|
|
xParam,
|
|
xpfnProc,
|
|
bAnsi);
|
|
|
|
if (cchTextLength) {
|
|
PVOID pvString;
|
|
ULONG cbTextLength;
|
|
|
|
cchTextLength++;
|
|
if (!bAnsi) {
|
|
cbTextLength = cchTextLength * sizeof(WCHAR);
|
|
} else {
|
|
cbTextLength = cchTextLength;
|
|
}
|
|
|
|
pvString = UserLocalAlloc(0,cbTextLength);
|
|
|
|
if (pvString) {
|
|
|
|
retval = (DWORD)NtUserMessageCall(
|
|
hwnd,
|
|
WM_GETTEXT,
|
|
cchTextLength,
|
|
(LPARAM)pvString,
|
|
xParam,
|
|
xpfnProc,
|
|
bAnsi);
|
|
|
|
if (retval) {
|
|
if ((LONG)retval < lOriginalLengthW) {
|
|
lOriginalLengthW = (LONG)retval;
|
|
}
|
|
if ((LONG)retval < lOriginalLengthL) {
|
|
lOriginalLengthL = (LONG)retval;
|
|
}
|
|
if (bAnsi) {
|
|
if (lOriginalLengthW > 0) {
|
|
CalcUnicodeStringLengthA(pvString, lOriginalLengthW, &wParam);
|
|
}
|
|
if (lOriginalLengthL > 0) {
|
|
CalcUnicodeStringLengthA(pvString, lOriginalLengthL, &lParam);
|
|
}
|
|
} else {
|
|
if (lOriginalLengthW > 0) {
|
|
CalcAnsiStringLengthW(pvString, lOriginalLengthW, &wParam);
|
|
}
|
|
if (lOriginalLengthL > 0) {
|
|
CalcAnsiStringLengthW(pvString, lOriginalLengthL, &lParam);
|
|
}
|
|
}
|
|
} else {
|
|
UserLocalFree(pvString);
|
|
MSGERROR();
|
|
}
|
|
|
|
UserLocalFree(pvString);
|
|
|
|
} else {
|
|
MSGERROR();
|
|
}
|
|
} else {
|
|
MSGERROR();
|
|
}
|
|
}
|
|
}
|
|
|
|
retval = (DWORD)NtUserMessageCall(
|
|
hwnd,
|
|
msg,
|
|
wParam,
|
|
lParam,
|
|
xParam,
|
|
xpfnProc,
|
|
bAnsi);
|
|
|
|
ERRORTRAP(0);
|
|
ENDCALL(DWORD);
|
|
}
|
|
|
|
MESSAGECALL(fnCBGETEDITSEL)
|
|
{
|
|
PWND pwnd = ValidateHwnd(hwnd);
|
|
|
|
if (pwnd == NULL)
|
|
return 0;
|
|
|
|
BEGINCALL()
|
|
|
|
retval = (DWORD)NtUserMessageCall(
|
|
hwnd,
|
|
msg,
|
|
wParam,
|
|
lParam,
|
|
xParam,
|
|
xpfnProc,
|
|
bAnsi);
|
|
|
|
//
|
|
// temp for our beta...
|
|
//
|
|
// !!! THIS CODE SHOULD BE IN KERNEL MODE !!!
|
|
//
|
|
// to reduce user <-> kernel mode transition...
|
|
//
|
|
if (bAnsi != ((TestWF(pwnd, WFANSIPROC)) ? TRUE : FALSE)) {
|
|
ULONG cchTextLength;
|
|
LONG lOriginalLengthW = *(LONG *)wParam;
|
|
LONG lOriginalLengthL = *(LONG *)lParam;
|
|
LONG wParamLocal;
|
|
LONG lParamLocal;
|
|
|
|
if (wParam) {
|
|
lOriginalLengthW = *(LONG *)wParam;
|
|
} else {
|
|
lOriginalLengthW = (LONG)(LOWORD(retval));
|
|
}
|
|
|
|
if (lParam) {
|
|
lOriginalLengthL = *(LONG *)lParam;
|
|
} else {
|
|
lOriginalLengthL = (LONG)(HIWORD(retval));
|
|
}
|
|
|
|
cchTextLength = (DWORD)NtUserMessageCall(
|
|
hwnd,
|
|
WM_GETTEXTLENGTH,
|
|
(WPARAM)0,
|
|
(LPARAM)0,
|
|
xParam,
|
|
xpfnProc,
|
|
bAnsi);
|
|
|
|
if (cchTextLength) {
|
|
PVOID pvString;
|
|
ULONG cbTextLength;
|
|
|
|
cchTextLength++;
|
|
if (!bAnsi) {
|
|
cbTextLength = cchTextLength * sizeof(WCHAR);
|
|
} else {
|
|
cbTextLength = cchTextLength;
|
|
}
|
|
|
|
pvString = UserLocalAlloc(0,cbTextLength);
|
|
|
|
if (pvString) {
|
|
|
|
retval = (DWORD)NtUserMessageCall(
|
|
hwnd,
|
|
WM_GETTEXT,
|
|
cchTextLength,
|
|
(LPARAM)pvString,
|
|
xParam,
|
|
xpfnProc,
|
|
bAnsi);
|
|
|
|
if (retval) {
|
|
if (bAnsi) {
|
|
/*
|
|
* ansiString/unicodeLenght -> ansiLength
|
|
*/
|
|
CalcAnsiStringLengthA(pvString, lOriginalLengthW, &wParamLocal);
|
|
CalcAnsiStringLengthA(pvString, lOriginalLengthL, &lParamLocal);
|
|
} else {
|
|
/*
|
|
* unicodeString/ansiLenght -> unicodeLength
|
|
*/
|
|
CalcUnicodeStringLengthW(pvString, lOriginalLengthW, &wParamLocal);
|
|
CalcUnicodeStringLengthW(pvString, lOriginalLengthL, &lParamLocal);
|
|
}
|
|
|
|
retval = (DWORD)(((lParamLocal) << 16) | ((wParamLocal) & 0x0000FFFF));
|
|
|
|
if (wParam) {
|
|
*(LONG *)wParam = wParamLocal;
|
|
}
|
|
|
|
if (lParam) {
|
|
*(LONG *)lParam = lParamLocal;
|
|
}
|
|
|
|
} else {
|
|
UserLocalFree(pvString);
|
|
MSGERROR();
|
|
}
|
|
|
|
UserLocalFree(pvString);
|
|
|
|
} else {
|
|
MSGERROR();
|
|
}
|
|
} else {
|
|
MSGERROR();
|
|
}
|
|
}
|
|
|
|
ERRORTRAP(0);
|
|
ENDCALL(DWORD);
|
|
}
|
|
|
|
LONG BroadcastSystemMessageWorker(
|
|
DWORD dwFlags,
|
|
LPDWORD lpdwRecipients,
|
|
UINT message,
|
|
WPARAM wParam,
|
|
LPARAM lParam,
|
|
PBSMINFO pBSMInfo,
|
|
BOOL fAnsi)
|
|
{
|
|
DWORD dwRecipients;
|
|
|
|
/*
|
|
* Prevent apps from setting hi 16 bits so we can use them internally.
|
|
*/
|
|
if (message & RESERVED_MSG_BITS) {
|
|
RIPERR1(ERROR_INVALID_PARAMETER,
|
|
RIP_WARNING,
|
|
"Invalid message 0x%x for BroadcastSystemMessage",
|
|
message);
|
|
return 0;
|
|
}
|
|
|
|
if (dwFlags & ~BSF_VALID) {
|
|
RIPERR1(ERROR_INVALID_PARAMETER,
|
|
RIP_WARNING,
|
|
"Invalid dwFlags 0x%x for BroadcastSystemMessage",
|
|
dwFlags);
|
|
return 0;
|
|
}
|
|
|
|
if ((dwFlags & (BSF_RETURNHDESK | BSF_LUID)) && pBSMInfo == NULL) {
|
|
RIPERR0(ERROR_INVALID_PARAMETER,
|
|
RIP_WARNING,
|
|
"Invalid BSF_RETURNHDESK or BSF_LUID is set and pBSMInfo is NULL for BroadcastSystemMessageEx");
|
|
return 0;
|
|
}
|
|
|
|
if (pBSMInfo != NULL && pBSMInfo->cbSize != sizeof(BSMINFO)) {
|
|
RIPERR1(ERROR_INVALID_PARAMETER,
|
|
RIP_WARNING,
|
|
"Invalid pBSMInfo->cbSize (%x) for BroadcastSystemMessageEx",
|
|
pBSMInfo->cbSize);
|
|
return 0;
|
|
}
|
|
|
|
//
|
|
// Check if the message number is in the private message range.
|
|
// If so, do not send it to Win4.0 windows.
|
|
// (This is required because apps like SimCity broadcast a message
|
|
// that has the value 0x500 and that confuses MsgSrvr's
|
|
// MSGSRVR_NOTIFY handler.
|
|
//
|
|
if (message >= WM_USER && message < 0xC000) {
|
|
RIPERR1(ERROR_INVALID_PARAMETER, RIP_WARNING, "invalid message (%x) for BroadcastSystemMessage", message);
|
|
return 0;
|
|
}
|
|
|
|
if (dwFlags & BSF_FORCEIFHUNG) {
|
|
dwFlags |= BSF_NOHANG;
|
|
}
|
|
|
|
//
|
|
// If BSF_QUERY or message has a pointer, it can not be posted.
|
|
//
|
|
if (dwFlags & BSF_QUERY) {
|
|
if (dwFlags & BSF_ASYNC) {
|
|
RIPMSGF0(RIP_WARNING, "BSF_QUERY can't be BSF_ASYNC");
|
|
}
|
|
|
|
dwFlags &= ~BSF_ASYNC; // Strip the BSF_ASYNC flags.
|
|
}
|
|
|
|
if (dwFlags & BSF_ASYNC) {
|
|
if (TESTSYNCONLYMESSAGE(message, wParam)) {
|
|
RIPERR0(ERROR_MESSAGE_SYNC_ONLY,
|
|
RIP_WARNING,
|
|
"BSM: Can't post messages with pointers");
|
|
dwFlags &= ~BSF_ASYNC; // Strip the BSF_ASYNC flags.
|
|
}
|
|
}
|
|
|
|
|
|
/*
|
|
* Let us find out who the intended recipients are.
|
|
*/
|
|
if (lpdwRecipients != NULL) {
|
|
dwRecipients = *lpdwRecipients;
|
|
} else {
|
|
dwRecipients = BSM_ALLCOMPONENTS;
|
|
}
|
|
|
|
/*
|
|
* If they want all components, add the corresponding bits.
|
|
*/
|
|
if ((dwRecipients & BSM_COMPONENTS) == BSM_ALLCOMPONENTS) {
|
|
dwRecipients |= (BSM_VXDS | BSM_NETDRIVER | BSM_INSTALLABLEDRIVERS |
|
|
BSM_APPLICATIONS);
|
|
}
|
|
|
|
|
|
if (dwRecipients & ~BSM_VALID) {
|
|
RIPERR1(ERROR_INVALID_PARAMETER,
|
|
RIP_WARNING,
|
|
"BSM: Invalid dwRecipients 0x%x",
|
|
dwRecipients);
|
|
return 0;
|
|
}
|
|
|
|
/*
|
|
* Does this need to be sent to all apps?
|
|
*/
|
|
if (dwRecipients & BSM_APPLICATIONS) {
|
|
BROADCASTSYSTEMMSGPARAMS bsmParams;
|
|
LONG lret;
|
|
|
|
bsmParams.dwFlags = dwFlags;
|
|
bsmParams.dwRecipients = dwRecipients;
|
|
bsmParams.hwnd = NULL;
|
|
bsmParams.hdesk = NULL;
|
|
if (dwFlags & BSF_LUID) {
|
|
bsmParams.luid = pBSMInfo->luid;
|
|
}
|
|
|
|
lret = (LONG)CsSendMessage(GetDesktopWindow(), message, wParam, lParam,
|
|
(ULONG_PTR)&bsmParams, FNID_SENDMESSAGEBSM, fAnsi);
|
|
|
|
/*
|
|
* Give the caller back the recipients that actually receive the message.
|
|
*/
|
|
if (lpdwRecipients != NULL) {
|
|
*lpdwRecipients = bsmParams.dwRecipients;
|
|
}
|
|
|
|
//
|
|
// If the query was denied, then return who denied it.
|
|
//
|
|
if (lret == 0 && (dwFlags & BSF_QUERY) && pBSMInfo != NULL) {
|
|
pBSMInfo->hwnd = bsmParams.hwnd;
|
|
pBSMInfo->hdesk = bsmParams.hdesk;
|
|
}
|
|
|
|
return lret;
|
|
}
|
|
|
|
return -1;
|
|
}
|
|
|
|
HDEVNOTIFY
|
|
RegisterDeviceNotificationWorker(
|
|
IN HANDLE hRecipient,
|
|
IN LPVOID NotificationFilter,
|
|
IN DWORD Flags)
|
|
{
|
|
HINSTANCE hLib;
|
|
FARPROC fpRegisterNotification;
|
|
PVOID Context = NULL;
|
|
HDEVNOTIFY notifyHandle = NULL;
|
|
CONFIGRET Status = CR_SUCCESS;
|
|
|
|
extern
|
|
CONFIGRET
|
|
CMP_RegisterNotification(IN HANDLE hRecipient,
|
|
IN LPBYTE NotificationFilter,
|
|
IN DWORD Flags,
|
|
OUT PVOID *Context);
|
|
|
|
//
|
|
// Load the config manager client dll and retrieve entry pts.
|
|
//
|
|
hLib = LoadLibrary(TEXT("SETUPAPI.DLL"));
|
|
if (hLib != NULL) {
|
|
fpRegisterNotification = GetProcAddress(hLib,
|
|
"CMP_RegisterNotification");
|
|
if (fpRegisterNotification != NULL) {
|
|
Status = (CONFIGRET)(*fpRegisterNotification)(hRecipient,
|
|
NotificationFilter,
|
|
Flags,
|
|
&Context);
|
|
}
|
|
|
|
FreeLibrary(hLib);
|
|
}
|
|
|
|
if (Status != CR_SUCCESS) {
|
|
/*
|
|
* Something went wrong, map the CR errors to a Win32 style error
|
|
* code.
|
|
*/
|
|
switch (Status) {
|
|
case CR_INVALID_POINTER:
|
|
SetLastError(ERROR_INVALID_PARAMETER);
|
|
break;
|
|
case CR_INVALID_DATA:
|
|
SetLastError(ERROR_INVALID_DATA);
|
|
break;
|
|
case CR_OUT_OF_MEMORY:
|
|
SetLastError(ERROR_NOT_ENOUGH_MEMORY);
|
|
break;
|
|
case CR_FAILURE:
|
|
default:
|
|
SetLastError(ERROR_SERVICE_SPECIFIC_ERROR);
|
|
break;
|
|
|
|
}
|
|
}
|
|
|
|
if (Context != NULL && (ULONG_PTR)Context != -1) {
|
|
notifyHandle = (HDEVNOTIFY)Context;
|
|
}
|
|
|
|
return notifyHandle;
|
|
}
|
|
|
|
|
|
BOOL
|
|
UnregisterDeviceNotification(
|
|
IN HDEVNOTIFY Handle)
|
|
{
|
|
HINSTANCE hLib;
|
|
FARPROC fpUnregisterNotification;
|
|
CONFIGRET crStatus = CR_SUCCESS;
|
|
|
|
extern
|
|
CONFIGRET
|
|
CMP_UnregisterNotification(IN ULONG Context);
|
|
|
|
/*
|
|
* Load the config manager client dll and retrieve entry pts.
|
|
*/
|
|
hLib = LoadLibrary(TEXT("SETUPAPI.DLL"));
|
|
if (hLib != NULL) {
|
|
fpUnregisterNotification = GetProcAddress(hLib,
|
|
"CMP_UnregisterNotification");
|
|
if (fpUnregisterNotification != NULL) {
|
|
crStatus = (CONFIGRET)(*fpUnregisterNotification)((ULONG_PTR)Handle);
|
|
}
|
|
|
|
FreeLibrary(hLib);
|
|
}
|
|
|
|
if (crStatus != CR_SUCCESS) {
|
|
/*
|
|
* Something went wrong, map the CR errors to a Win32 style error
|
|
* code.
|
|
*/
|
|
switch (crStatus) {
|
|
case CR_INVALID_POINTER:
|
|
SetLastError(ERROR_INVALID_PARAMETER);
|
|
break;
|
|
case CR_INVALID_DATA:
|
|
SetLastError(ERROR_INVALID_DATA);
|
|
break;
|
|
case CR_FAILURE:
|
|
default:
|
|
SetLastError(ERROR_SERVICE_SPECIFIC_ERROR);
|
|
break;
|
|
}
|
|
}
|
|
|
|
return (BOOL)(crStatus == CR_SUCCESS);
|
|
}
|