Leaked source code of windows server 2003
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

/**************************************************************************\
* 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);
}