reactos/win32ss/user/user32/windows/message.c

3450 lines
89 KiB
C
Raw Normal View History

/*
* COPYRIGHT: See COPYING in the top level directory
* PROJECT: ReactOS user32.dll
* FILE: win32ss/user/user32/windows/message.c
* PURPOSE: Messages
* PROGRAMMER: Casper S. Hornstrup (chorns@users.sourceforge.net)
* UPDATE HISTORY:
* 06-06-2001 CSH Created
*/
#include <user32.h>
WINE_DEFAULT_DEBUG_CHANNEL(user32);
#ifdef __i386__
/* For bad applications which provide bad (non stdcall) WndProc */
extern
LRESULT
__cdecl
CALL_EXTERN_WNDPROC(
WNDPROC WndProc,
HWND hWnd,
UINT Msg,
WPARAM wParam,
LPARAM lParam);
#else
# define CALL_EXTERN_WNDPROC(proc, h, m, w, l) proc(h, m, w, l)
#endif
/* From wine: */
/* flag for messages that contain pointers */
/* 32 messages per entry, messages 0..31 map to bits 0..31 */
#define SET(msg) (1 << ((msg) & 31))
static const unsigned int message_pointer_flags[] =
{
/* 0x00 - 0x1f */
SET(WM_CREATE) | SET(WM_SETTEXT) | SET(WM_GETTEXT) |
SET(WM_WININICHANGE) | SET(WM_DEVMODECHANGE),
/* 0x20 - 0x3f */
SET(WM_GETMINMAXINFO) | SET(WM_DRAWITEM) | SET(WM_MEASUREITEM) | SET(WM_DELETEITEM) |
SET(WM_COMPAREITEM),
/* 0x40 - 0x5f */
SET(WM_WINDOWPOSCHANGING) | SET(WM_WINDOWPOSCHANGED) | SET(WM_COPYDATA) | SET(WM_COPYGLOBALDATA) | SET(WM_HELP),
/* 0x60 - 0x7f */
SET(WM_STYLECHANGING) | SET(WM_STYLECHANGED),
/* 0x80 - 0x9f */
SET(WM_NCCREATE) | SET(WM_NCCALCSIZE) | SET(WM_GETDLGCODE),
/* 0xa0 - 0xbf */
SET(EM_GETSEL) | SET(EM_GETRECT) | SET(EM_SETRECT) | SET(EM_SETRECTNP),
/* 0xc0 - 0xdf */
SET(EM_REPLACESEL) | SET(EM_GETLINE) | SET(EM_SETTABSTOPS),
/* 0xe0 - 0xff */
SET(SBM_GETRANGE) | SET(SBM_SETSCROLLINFO) | SET(SBM_GETSCROLLINFO) | SET(SBM_GETSCROLLBARINFO),
/* 0x100 - 0x11f */
0,
/* 0x120 - 0x13f */
0,
/* 0x140 - 0x15f */
SET(CB_GETEDITSEL) | SET(CB_ADDSTRING) | SET(CB_DIR) | SET(CB_GETLBTEXT) |
SET(CB_INSERTSTRING) | SET(CB_FINDSTRING) | SET(CB_SELECTSTRING) |
SET(CB_GETDROPPEDCONTROLRECT) | SET(CB_FINDSTRINGEXACT),
/* 0x160 - 0x17f */
0,
/* 0x180 - 0x19f */
SET(LB_ADDSTRING) | SET(LB_INSERTSTRING) | SET(LB_GETTEXT) | SET(LB_SELECTSTRING) |
SET(LB_DIR) | SET(LB_FINDSTRING) |
SET(LB_GETSELITEMS) | SET(LB_SETTABSTOPS) | SET(LB_ADDFILE) | SET(LB_GETITEMRECT),
/* 0x1a0 - 0x1bf */
SET(LB_FINDSTRINGEXACT),
/* 0x1c0 - 0x1df */
0,
/* 0x1e0 - 0x1ff */
0,
/* 0x200 - 0x21f */
SET(WM_NEXTMENU) | SET(WM_SIZING) | SET(WM_MOVING) | SET(WM_DEVICECHANGE),
/* 0x220 - 0x23f */
SET(WM_MDICREATE) | SET(WM_MDIGETACTIVE) | SET(WM_DROPOBJECT) |
SET(WM_QUERYDROPOBJECT) | SET(WM_DRAGLOOP) | SET(WM_DRAGSELECT) | SET(WM_DRAGMOVE),
/* 0x240 - 0x25f */
0,
/* 0x260 - 0x27f */
0,
/* 0x280 - 0x29f */
0,
/* 0x2a0 - 0x2bf */
0,
/* 0x2c0 - 0x2df */
0,
/* 0x2e0 - 0x2ff */
0,
/* 0x300 - 0x31f */
SET(WM_ASKCBFORMATNAME)
};
/* check whether a given message type includes pointers */
static inline int is_pointer_message( UINT message, WPARAM wparam )
{
if (message >= 8*sizeof(message_pointer_flags)) return FALSE;
if (message == WM_DEVICECHANGE && !(wparam & 0x8000)) return FALSE;
return (message_pointer_flags[message / 32] & SET(message)) != 0;
}
#undef SET
/* check whether a combobox expects strings or ids in CB_ADDSTRING/CB_INSERTSTRING */
static BOOL FASTCALL combobox_has_strings( HWND hwnd )
{
DWORD style = GetWindowLongA( hwnd, GWL_STYLE );
return (!(style & (CBS_OWNERDRAWFIXED | CBS_OWNERDRAWVARIABLE)) || (style & CBS_HASSTRINGS));
}
/* check whether a listbox expects strings or ids in LB_ADDSTRING/LB_INSERTSTRING */
static BOOL FASTCALL listbox_has_strings( HWND hwnd )
{
DWORD style = GetWindowLongA( hwnd, GWL_STYLE );
return (!(style & (LBS_OWNERDRAWFIXED | LBS_OWNERDRAWVARIABLE)) || (style & LBS_HASSTRINGS));
}
/* DDE message exchange
*
* - Session initialization
* Client sends a WM_DDE_INITIATE message, usually a broadcast message. lParam of
* this message contains a pair of global atoms, the Application and Topic atoms.
* The client must destroy the atoms.
* Server window proc handles the WM_DDE_INITIATE message and if the Application
* and Topic atoms are recognized sends a WM_DDE_ACK message to the client. lParam
* of the reply message contains another pair of global atoms (Application and
* Topic again), which must be destroyed by the server.
*
* - Execute
* Client posts a WM_DDE_EXECUTE message to the server window. lParam of that message
* is a global memory handle containing the string to execute. After the command has
* been executed the server posts a WM_DDE_ACK message to the client, which contains
* a packed lParam which in turn contains that global memory handle. The client takes
* ownership of both the packed lParam (meaning it needs to call FreeDDElParam() on
* it and the global memory handle.
* This might work nice and easy in Win3.1, but things are more complicated for NT.
* Global memory handles in NT are not really global, they're still local to the
* process. So, what happens under the hood is that PostMessage must handle the
* WM_DDE_EXECUTE message specially. It will obtain the contents of the global memory
* area, repack that into a new structure together with the original memory handle
* and pass that off to the win32k. Win32k will marshall that data over to the target
* (server) process where it will be unpacked and stored in a newly allocated global
* memory area. The handle of that area will then be sent to the window proc, after
* storing it together with the "original" (client) handle in a table.
* The server will eventually post the WM_DDE_ACK response, containing the global
* memory handle it received. PostMessage must then lookup that memory handle (only
* valid in the server process) and replace it with the corresponding client memory
* handle. To avoid memory leaks, the server-side global memory block must be freed.
* Also, the WM_DDE_ACK lParam (a PackDDElParam() result) is unpacked and the
* individual components are handed to win32k.sys to post to the client side. Since
* the server side app hands over ownership of the packed lParam when it calls
* PostMessage(), the packed lParam needs to be freed on the server side too.
* When the WM_DDE_ACK message (containing the client-side global memory handle)
* arrives at the client side a new lParam is PackDDElParam()'ed and this is handed
* to the client side window proc which is expected to free/reuse it.
*/
/* since the WM_DDE_ACK response to a WM_DDE_EXECUTE message should contain the handle
* to the memory handle, we keep track (in the server side) of all pairs of handle
* used (the client passes its value and the content of the memory handle), and
* the server stored both values (the client, and the local one, created after the
* content). When a ACK message is generated, the list of pair is searched for a
* matching pair, so that the client memory handle can be returned.
*/
typedef struct tagDDEPAIR
{
HGLOBAL ClientMem;
HGLOBAL ServerMem;
} DDEPAIR, *PDDEPAIR;
static PDDEPAIR DdePairs = NULL;
static unsigned DdeNumAlloc = 0;
static unsigned DdeNumUsed = 0;
static CRITICAL_SECTION DdeCrst;
BOOL FASTCALL
DdeAddPair(HGLOBAL ClientMem, HGLOBAL ServerMem)
{
unsigned i;
EnterCriticalSection(&DdeCrst);
/* now remember the pair of hMem on both sides */
if (DdeNumUsed == DdeNumAlloc)
{
#define GROWBY 4
PDDEPAIR New;
if (NULL != DdePairs)
{
New = HeapReAlloc(GetProcessHeap(), 0, DdePairs,
(DdeNumAlloc + GROWBY) * sizeof(DDEPAIR));
}
else
{
New = HeapAlloc(GetProcessHeap(), 0,
(DdeNumAlloc + GROWBY) * sizeof(DDEPAIR));
}
if (NULL == New)
{
LeaveCriticalSection(&DdeCrst);
return FALSE;
}
DdePairs = New;
/* zero out newly allocated part */
memset(&DdePairs[DdeNumAlloc], 0, GROWBY * sizeof(DDEPAIR));
DdeNumAlloc += GROWBY;
#undef GROWBY
}
for (i = 0; i < DdeNumAlloc; i++)
{
if (NULL == DdePairs[i].ServerMem)
{
DdePairs[i].ClientMem = ClientMem;
DdePairs[i].ServerMem = ServerMem;
DdeNumUsed++;
break;
}
}
LeaveCriticalSection(&DdeCrst);
return TRUE;
}
HGLOBAL FASTCALL
DdeGetPair(HGLOBAL ServerMem)
{
unsigned i;
HGLOBAL Ret = NULL;
EnterCriticalSection(&DdeCrst);
for (i = 0; i < DdeNumAlloc; i++)
{
if (DdePairs[i].ServerMem == ServerMem)
{
/* free this pair */
DdePairs[i].ServerMem = 0;
DdeNumUsed--;
Ret = DdePairs[i].ClientMem;
break;
}
}
LeaveCriticalSection(&DdeCrst);
return Ret;
}
DWORD FASTCALL get_input_codepage( void )
{
DWORD cp;
int ret;
HKL hkl = GetKeyboardLayout( 0 );
ret = GetLocaleInfoW( LOWORD(hkl), LOCALE_IDEFAULTANSICODEPAGE | LOCALE_RETURN_NUMBER, (WCHAR *)&cp, sizeof(cp) / sizeof(WCHAR) );
if (!ret) cp = CP_ACP;
return cp;
}
static WPARAM FASTCALL map_wparam_char_WtoA( WPARAM wParam, DWORD len )
{
WCHAR wch = wParam;
BYTE ch[2];
DWORD cp = get_input_codepage();
len = WideCharToMultiByte( cp, 0, &wch, 1, (LPSTR)ch, len, NULL, NULL );
if (len == 2)
return MAKEWPARAM( (ch[0] << 8) | ch[1], HIWORD(wParam) );
else
return MAKEWPARAM( ch[0], HIWORD(wParam) );
}
/***********************************************************************
* map_wparam_AtoW
*
* Convert the wparam of an ASCII message to Unicode.
*/
static WPARAM FASTCALL
map_wparam_AtoW( UINT message, WPARAM wparam )
{
char ch[2];
WCHAR wch[2];
wch[0] = wch[1] = 0;
switch(message)
{
case WM_CHAR:
/* WM_CHAR is magic: a DBCS char can be sent/posted as two consecutive WM_CHAR
* messages, in which case the first char is stored, and the conversion
* to Unicode only takes place once the second char is sent/posted.
*/
#if 0
if (mapping != WMCHAR_MAP_NOMAPPING) // NlsMbCodePageTag
{
PCLIENTINFO pci = GetWin32ClientInfo();
struct wm_char_mapping_data *data = get_user_thread_info()->wmchar_data;
BYTE low = LOBYTE(wparam);
if (HIBYTE(wparam))
{
ch[0] = low;
ch[1] = HIBYTE(wparam);
RtlMultiByteToUnicodeN( wch, sizeof(wch), NULL, ch, 2 );
TRACE( "map %02x,%02x -> %04x mapping %u\n", (BYTE)ch[0], (BYTE)ch[1], wch[0], mapping );
if (data) data->lead_byte[mapping] = 0;
}
else if (data && data->lead_byte[mapping])
{
ch[0] = data->lead_byte[mapping];
ch[1] = low;
RtlMultiByteToUnicodeN( wch, sizeof(wch), NULL, ch, 2 );
TRACE( "map stored %02x,%02x -> %04x mapping %u\n", (BYTE)ch[0], (BYTE)ch[1], wch[0], mapping );
data->lead_byte[mapping] = 0;
}
else if (!IsDBCSLeadByte( low ))
{
ch[0] = low;
RtlMultiByteToUnicodeN( wch, sizeof(wch), NULL, ch, 1 );
TRACE( "map %02x -> %04x\n", (BYTE)ch[0], wch[0] );
if (data) data->lead_byte[mapping] = 0;
}
else /* store it and wait for trail byte */
{
if (!data)
{
if (!(data = HeapAlloc( GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*data) )))
return FALSE;
get_user_thread_info()->wmchar_data = data;
}
TRACE( "storing lead byte %02x mapping %u\n", low, mapping );
data->lead_byte[mapping] = low;
return FALSE;
}
wparam = MAKEWPARAM(wch[0], wch[1]);
break;
}
#endif
/* else fall through */
case WM_CHARTOITEM:
case EM_SETPASSWORDCHAR:
case WM_DEADCHAR:
case WM_SYSCHAR:
case WM_SYSDEADCHAR:
case WM_MENUCHAR:
ch[0] = LOBYTE(wparam);
ch[1] = HIBYTE(wparam);
RtlMultiByteToUnicodeN( wch, sizeof(wch), NULL, ch, 2 );
wparam = MAKEWPARAM(wch[0], wch[1]);
break;
case WM_IME_CHAR:
ch[0] = HIBYTE(wparam);
ch[1] = LOBYTE(wparam);
if (ch[0]) RtlMultiByteToUnicodeN( wch, sizeof(wch[0]), NULL, ch, 2 );
else RtlMultiByteToUnicodeN( wch, sizeof(wch[0]), NULL, ch + 1, 1 );
wparam = MAKEWPARAM(wch[0], HIWORD(wparam));
break;
}
return wparam;
}
static
BOOL FASTCALL
MsgiUMToKMMessage(PMSG UMMsg, PMSG KMMsg, BOOL Posted)
{
*KMMsg = *UMMsg;
switch (UMMsg->message)
{
case WM_COPYDATA:
{
PCOPYDATASTRUCT pUMCopyData = (PCOPYDATASTRUCT)UMMsg->lParam;
PCOPYDATASTRUCT pKMCopyData;
pKMCopyData = HeapAlloc(GetProcessHeap(), 0, sizeof(COPYDATASTRUCT) + pUMCopyData->cbData);
if (!pKMCopyData)
{
SetLastError(ERROR_OUTOFMEMORY);
return FALSE;
}
pKMCopyData->dwData = pUMCopyData->dwData;
pKMCopyData->cbData = pUMCopyData->cbData;
pKMCopyData->lpData = pKMCopyData + 1;
RtlCopyMemory(pKMCopyData + 1, pUMCopyData->lpData, pUMCopyData->cbData);
KMMsg->lParam = (LPARAM)pKMCopyData;
}
break;
case WM_COPYGLOBALDATA:
{
KMMsg->lParam = (LPARAM)GlobalLock((HGLOBAL)UMMsg->lParam);;
TRACE("WM_COPYGLOBALDATA get data ptr %p\n",KMMsg->lParam);
}
break;
default:
break;
}
return TRUE;
}
static
VOID FASTCALL
MsgiUMToKMCleanup(PMSG UMMsg, PMSG KMMsg)
{
switch (KMMsg->message)
{
case WM_COPYDATA:
HeapFree(GetProcessHeap(), 0, (LPVOID) KMMsg->lParam);
break;
case WM_COPYGLOBALDATA:
TRACE("WM_COPYGLOBALDATA cleanup return\n");
GlobalUnlock((HGLOBAL)UMMsg->lParam);
GlobalFree((HGLOBAL)UMMsg->lParam);
break;
default:
break;
}
return;
}
static BOOL FASTCALL
MsgiKMToUMMessage(PMSG KMMsg, PMSG UMMsg)
{
*UMMsg = *KMMsg;
if (KMMsg->lParam == 0) return TRUE;
switch (UMMsg->message)
{
case WM_CREATE:
case WM_NCCREATE:
{
CREATESTRUCTW *Cs = (CREATESTRUCTW *) KMMsg->lParam;
PCHAR Class;
Cs->lpszName = (LPCWSTR) ((PCHAR) Cs + (DWORD_PTR) Cs->lpszName);
Class = (PCHAR) Cs + (DWORD_PTR) Cs->lpszClass;
if (L'A' == *((WCHAR *) Class))
{
Class += sizeof(WCHAR);
Cs->lpszClass = (LPCWSTR)(DWORD_PTR) (*((ATOM *) Class));
}
else
{
ASSERT(L'S' == *((WCHAR *) Class));
Class += sizeof(WCHAR);
Cs->lpszClass = (LPCWSTR) Class;
}
}
break;
case WM_COPYDATA:
{
PCOPYDATASTRUCT pKMCopyData = (PCOPYDATASTRUCT)KMMsg->lParam;
pKMCopyData->lpData = pKMCopyData + 1;
}
break;
case WM_COPYGLOBALDATA:
{
PVOID Data;
HGLOBAL hGlobal = GlobalAlloc(GHND | GMEM_SHARE, KMMsg->wParam);
Data = GlobalLock(hGlobal);
if (Data) RtlCopyMemory(Data, (PVOID)KMMsg->lParam, KMMsg->wParam);
GlobalUnlock(hGlobal);
TRACE("WM_COPYGLOBALDATA to User hGlobal %p\n",hGlobal);
UMMsg->lParam = (LPARAM)hGlobal;
}
break;
default:
break;
}
return TRUE;
}
static VOID FASTCALL
MsgiKMToUMCleanup(PMSG KMMsg, PMSG UMMsg)
{
switch (KMMsg->message)
{
case WM_DDE_EXECUTE:
#ifdef TODO // Kept as historic.
HeapFree(GetProcessHeap(), 0, (LPVOID) KMMsg->lParam);
GlobalUnlock((HGLOBAL) UMMsg->lParam);
#endif
break;
default:
break;
}
return;
}
2002-06-18 David Welch <welch@whitehall1-5.seh.ox.ac.uk> * tools/helper.mk: Make an import library a proper target depending on the .def file. 2002-06-18 David Welch <welch@whitehall1-5.seh.ox.ac.uk> * subsys/win32k/ntuser/window.c (NtUserGetWindowLong): Began implementation. 2002-06-18 David Welch <welch@whitehall1-5.seh.ox.ac.uk> * subsys/win32k/misc/object.c (ObmCreateHandle): Return the correct handle value. 2002-06-18 David Welch <welch@whitehall1-5.seh.ox.ac.uk> * subsys/win32k/makefile: Make win32k depend on the file containing the service table. 2002-06-18 David Welch <welch@whitehall1-5.seh.ox.ac.uk> * ntoskrnl/ke/i386/stkswitch.S (KeSwitchStackAndRet, KePushAndStackSwitchAndSysRet): Push one value only. * ntoskrnl/ps/w32call.c (NtCallbackReturn, NtW32Call): Moved these functions to a new file. Restore the old trap frame after returning from a callback. 2002-06-18 David Welch <welch@whitehall1-5.seh.ox.ac.uk> * lib/user32/windows/message.c (CallWindowProcA, CallWindowProcW): Convert message to Unicode or ASCII if necessary. 2002-06-18 David Welch <welch@whitehall1-5.seh.ox.ac.uk> * include/user32/callback.h: Added WM_CREATE and WM_NCCALCSIZE callbacks. * lib/user32/windows/window.c (User32SendCREATEMessageForKernel, User32SendNCCREATEMessageForKernel): Implemented. * subsys/win32k/ntuser/callback.c (W32kSendCREATEMessage): Implemented. 2002-06-18 David Welch <welch@whitehall1-5.seh.ox.ac.uk> * include/structs.h: Added Unicode and ASCII versions of CREATESTRUCT. svn path=/trunk/; revision=3118
2002-06-18 21:51:11 +00:00
static BOOL FASTCALL
MsgiKMToUMReply(PMSG KMMsg, PMSG UMMsg, LRESULT *Result)
{
MsgiKMToUMCleanup(KMMsg, UMMsg);
return TRUE;
}
//
// Ansi to Unicode -> callout
//
static BOOL FASTCALL
MsgiAnsiToUnicodeMessage(HWND hwnd, LPMSG UnicodeMsg, LPMSG AnsiMsg)
{
UNICODE_STRING UnicodeString;
*UnicodeMsg = *AnsiMsg;
switch (AnsiMsg->message)
2002-06-18 David Welch <welch@whitehall1-5.seh.ox.ac.uk> * tools/helper.mk: Make an import library a proper target depending on the .def file. 2002-06-18 David Welch <welch@whitehall1-5.seh.ox.ac.uk> * subsys/win32k/ntuser/window.c (NtUserGetWindowLong): Began implementation. 2002-06-18 David Welch <welch@whitehall1-5.seh.ox.ac.uk> * subsys/win32k/misc/object.c (ObmCreateHandle): Return the correct handle value. 2002-06-18 David Welch <welch@whitehall1-5.seh.ox.ac.uk> * subsys/win32k/makefile: Make win32k depend on the file containing the service table. 2002-06-18 David Welch <welch@whitehall1-5.seh.ox.ac.uk> * ntoskrnl/ke/i386/stkswitch.S (KeSwitchStackAndRet, KePushAndStackSwitchAndSysRet): Push one value only. * ntoskrnl/ps/w32call.c (NtCallbackReturn, NtW32Call): Moved these functions to a new file. Restore the old trap frame after returning from a callback. 2002-06-18 David Welch <welch@whitehall1-5.seh.ox.ac.uk> * lib/user32/windows/message.c (CallWindowProcA, CallWindowProcW): Convert message to Unicode or ASCII if necessary. 2002-06-18 David Welch <welch@whitehall1-5.seh.ox.ac.uk> * include/user32/callback.h: Added WM_CREATE and WM_NCCALCSIZE callbacks. * lib/user32/windows/window.c (User32SendCREATEMessageForKernel, User32SendNCCREATEMessageForKernel): Implemented. * subsys/win32k/ntuser/callback.c (W32kSendCREATEMessage): Implemented. 2002-06-18 David Welch <welch@whitehall1-5.seh.ox.ac.uk> * include/structs.h: Added Unicode and ASCII versions of CREATESTRUCT. svn path=/trunk/; revision=3118
2002-06-18 21:51:11 +00:00
{
case WM_GETTEXT:
case WM_ASKCBFORMATNAME:
{
LPWSTR Buffer;
if (!AnsiMsg->lParam) break;
Buffer = RtlAllocateHeap(GetProcessHeap(), HEAP_ZERO_MEMORY, AnsiMsg->wParam * sizeof(WCHAR));
//ERR("WM_GETTEXT A2U Size %d\n",AnsiMsg->wParam);
if (!Buffer) return FALSE;
UnicodeMsg->lParam = (LPARAM)Buffer;
break;
}
case LB_GETTEXT:
{
DWORD Size = 1024 * sizeof(WCHAR);
if (!AnsiMsg->lParam || !listbox_has_strings( AnsiMsg->hwnd )) break;
/*Size = SendMessageW( AnsiMsg->hwnd, LB_GETTEXTLEN, AnsiMsg->wParam, 0 );
if (Size == LB_ERR)
{
ERR("LB_GETTEXT LB_ERR\n");
Size = sizeof(ULONG_PTR);
}
Size = (Size + 1) * sizeof(WCHAR);*/
UnicodeMsg->lParam = (LPARAM) RtlAllocateHeap(GetProcessHeap(), HEAP_ZERO_MEMORY, Size);
if (!UnicodeMsg->lParam) return FALSE;
break;
}
case CB_GETLBTEXT:
{
DWORD Size = 1024 * sizeof(WCHAR);
if (!AnsiMsg->lParam || !combobox_has_strings( AnsiMsg->hwnd )) break;
/*Size = SendMessageW( AnsiMsg->hwnd, CB_GETLBTEXTLEN, AnsiMsg->wParam, 0 );
if (Size == LB_ERR)
{
ERR("CB_GETTEXT LB_ERR\n");
Size = sizeof(ULONG_PTR);
}
Size = (Size + 1) * sizeof(WCHAR);*/
UnicodeMsg->lParam = (LPARAM) RtlAllocateHeap(GetProcessHeap(), HEAP_ZERO_MEMORY, Size);
if (!UnicodeMsg->lParam) return FALSE;
break;
}
/* AnsiMsg->lParam is string (0-terminated) */
case WM_SETTEXT:
case WM_WININICHANGE:
case WM_DEVMODECHANGE:
case CB_DIR:
case LB_DIR:
case LB_ADDFILE:
case EM_REPLACESEL:
{
if (!AnsiMsg->lParam) break;
RtlCreateUnicodeStringFromAsciiz(&UnicodeString, (LPSTR)AnsiMsg->lParam);
UnicodeMsg->lParam = (LPARAM)UnicodeString.Buffer;
break;
}
case LB_ADDSTRING:
case LB_ADDSTRING_LOWER:
case LB_ADDSTRING_UPPER:
case LB_INSERTSTRING:
case LB_INSERTSTRING_UPPER:
case LB_INSERTSTRING_LOWER:
case LB_FINDSTRING:
case LB_FINDSTRINGEXACT:
case LB_SELECTSTRING:
{
if (AnsiMsg->lParam && listbox_has_strings(AnsiMsg->hwnd))
{
RtlCreateUnicodeStringFromAsciiz(&UnicodeString, (LPSTR)AnsiMsg->lParam);
UnicodeMsg->lParam = (LPARAM)UnicodeString.Buffer;
}
break;
}
case CB_ADDSTRING:
case CB_INSERTSTRING:
case CB_FINDSTRING:
case CB_FINDSTRINGEXACT:
case CB_SELECTSTRING:
{
if (AnsiMsg->lParam && combobox_has_strings(AnsiMsg->hwnd))
{
RtlCreateUnicodeStringFromAsciiz(&UnicodeString, (LPSTR)AnsiMsg->lParam);
UnicodeMsg->lParam = (LPARAM)UnicodeString.Buffer;
}
break;
}
2002-06-18 David Welch <welch@whitehall1-5.seh.ox.ac.uk> * tools/helper.mk: Make an import library a proper target depending on the .def file. 2002-06-18 David Welch <welch@whitehall1-5.seh.ox.ac.uk> * subsys/win32k/ntuser/window.c (NtUserGetWindowLong): Began implementation. 2002-06-18 David Welch <welch@whitehall1-5.seh.ox.ac.uk> * subsys/win32k/misc/object.c (ObmCreateHandle): Return the correct handle value. 2002-06-18 David Welch <welch@whitehall1-5.seh.ox.ac.uk> * subsys/win32k/makefile: Make win32k depend on the file containing the service table. 2002-06-18 David Welch <welch@whitehall1-5.seh.ox.ac.uk> * ntoskrnl/ke/i386/stkswitch.S (KeSwitchStackAndRet, KePushAndStackSwitchAndSysRet): Push one value only. * ntoskrnl/ps/w32call.c (NtCallbackReturn, NtW32Call): Moved these functions to a new file. Restore the old trap frame after returning from a callback. 2002-06-18 David Welch <welch@whitehall1-5.seh.ox.ac.uk> * lib/user32/windows/message.c (CallWindowProcA, CallWindowProcW): Convert message to Unicode or ASCII if necessary. 2002-06-18 David Welch <welch@whitehall1-5.seh.ox.ac.uk> * include/user32/callback.h: Added WM_CREATE and WM_NCCALCSIZE callbacks. * lib/user32/windows/window.c (User32SendCREATEMessageForKernel, User32SendNCCREATEMessageForKernel): Implemented. * subsys/win32k/ntuser/callback.c (W32kSendCREATEMessage): Implemented. 2002-06-18 David Welch <welch@whitehall1-5.seh.ox.ac.uk> * include/structs.h: Added Unicode and ASCII versions of CREATESTRUCT. svn path=/trunk/; revision=3118
2002-06-18 21:51:11 +00:00
case WM_NCCREATE:
case WM_CREATE:
2002-06-18 David Welch <welch@whitehall1-5.seh.ox.ac.uk> * tools/helper.mk: Make an import library a proper target depending on the .def file. 2002-06-18 David Welch <welch@whitehall1-5.seh.ox.ac.uk> * subsys/win32k/ntuser/window.c (NtUserGetWindowLong): Began implementation. 2002-06-18 David Welch <welch@whitehall1-5.seh.ox.ac.uk> * subsys/win32k/misc/object.c (ObmCreateHandle): Return the correct handle value. 2002-06-18 David Welch <welch@whitehall1-5.seh.ox.ac.uk> * subsys/win32k/makefile: Make win32k depend on the file containing the service table. 2002-06-18 David Welch <welch@whitehall1-5.seh.ox.ac.uk> * ntoskrnl/ke/i386/stkswitch.S (KeSwitchStackAndRet, KePushAndStackSwitchAndSysRet): Push one value only. * ntoskrnl/ps/w32call.c (NtCallbackReturn, NtW32Call): Moved these functions to a new file. Restore the old trap frame after returning from a callback. 2002-06-18 David Welch <welch@whitehall1-5.seh.ox.ac.uk> * lib/user32/windows/message.c (CallWindowProcA, CallWindowProcW): Convert message to Unicode or ASCII if necessary. 2002-06-18 David Welch <welch@whitehall1-5.seh.ox.ac.uk> * include/user32/callback.h: Added WM_CREATE and WM_NCCALCSIZE callbacks. * lib/user32/windows/window.c (User32SendCREATEMessageForKernel, User32SendNCCREATEMessageForKernel): Implemented. * subsys/win32k/ntuser/callback.c (W32kSendCREATEMessage): Implemented. 2002-06-18 David Welch <welch@whitehall1-5.seh.ox.ac.uk> * include/structs.h: Added Unicode and ASCII versions of CREATESTRUCT. svn path=/trunk/; revision=3118
2002-06-18 21:51:11 +00:00
{
struct s
{
CREATESTRUCTW cs; /* new structure */
MDICREATESTRUCTW mdi_cs; /* MDI info */
LPCWSTR lpszName; /* allocated Name */
LPCWSTR lpszClass; /* allocated Class */
};
struct s *xs = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(struct s));
if (!xs)
{
return FALSE;
}
xs->cs = *(CREATESTRUCTW *)AnsiMsg->lParam;
if (!IS_INTRESOURCE(xs->cs.lpszName))
{
RtlCreateUnicodeStringFromAsciiz(&UnicodeString, (LPSTR)xs->cs.lpszName);
xs->lpszName = xs->cs.lpszName = UnicodeString.Buffer;
}
if (!IS_ATOM(xs->cs.lpszClass))
{
RtlCreateUnicodeStringFromAsciiz(&UnicodeString, (LPSTR)xs->cs.lpszClass);
xs->lpszClass = xs->cs.lpszClass = UnicodeString.Buffer;
}
if (GetWindowLongW(hwnd, GWL_EXSTYLE) & WS_EX_MDICHILD)
{
xs->mdi_cs = *(MDICREATESTRUCTW *)xs->cs.lpCreateParams;
xs->mdi_cs.szTitle = xs->cs.lpszName;
xs->mdi_cs.szClass = xs->cs.lpszClass;
xs->cs.lpCreateParams = &xs->mdi_cs;
}
UnicodeMsg->lParam = (LPARAM)xs;
break;
}
2002-06-18 David Welch <welch@whitehall1-5.seh.ox.ac.uk> * tools/helper.mk: Make an import library a proper target depending on the .def file. 2002-06-18 David Welch <welch@whitehall1-5.seh.ox.ac.uk> * subsys/win32k/ntuser/window.c (NtUserGetWindowLong): Began implementation. 2002-06-18 David Welch <welch@whitehall1-5.seh.ox.ac.uk> * subsys/win32k/misc/object.c (ObmCreateHandle): Return the correct handle value. 2002-06-18 David Welch <welch@whitehall1-5.seh.ox.ac.uk> * subsys/win32k/makefile: Make win32k depend on the file containing the service table. 2002-06-18 David Welch <welch@whitehall1-5.seh.ox.ac.uk> * ntoskrnl/ke/i386/stkswitch.S (KeSwitchStackAndRet, KePushAndStackSwitchAndSysRet): Push one value only. * ntoskrnl/ps/w32call.c (NtCallbackReturn, NtW32Call): Moved these functions to a new file. Restore the old trap frame after returning from a callback. 2002-06-18 David Welch <welch@whitehall1-5.seh.ox.ac.uk> * lib/user32/windows/message.c (CallWindowProcA, CallWindowProcW): Convert message to Unicode or ASCII if necessary. 2002-06-18 David Welch <welch@whitehall1-5.seh.ox.ac.uk> * include/user32/callback.h: Added WM_CREATE and WM_NCCALCSIZE callbacks. * lib/user32/windows/window.c (User32SendCREATEMessageForKernel, User32SendNCCREATEMessageForKernel): Implemented. * subsys/win32k/ntuser/callback.c (W32kSendCREATEMessage): Implemented. 2002-06-18 David Welch <welch@whitehall1-5.seh.ox.ac.uk> * include/structs.h: Added Unicode and ASCII versions of CREATESTRUCT. svn path=/trunk/; revision=3118
2002-06-18 21:51:11 +00:00
case WM_MDICREATE:
{
MDICREATESTRUCTW *cs =
(MDICREATESTRUCTW *)HeapAlloc(GetProcessHeap(), 0, sizeof(*cs));
if (!cs)
{
return FALSE;
}
*cs = *(MDICREATESTRUCTW *)AnsiMsg->lParam;
if (!IS_ATOM(cs->szClass))
{
RtlCreateUnicodeStringFromAsciiz(&UnicodeString, (LPSTR)cs->szClass);
cs->szClass = UnicodeString.Buffer;
}
RtlCreateUnicodeStringFromAsciiz(&UnicodeString, (LPSTR)cs->szTitle);
cs->szTitle = UnicodeString.Buffer;
UnicodeMsg->lParam = (LPARAM)cs;
break;
2002-06-18 David Welch <welch@whitehall1-5.seh.ox.ac.uk> * tools/helper.mk: Make an import library a proper target depending on the .def file. 2002-06-18 David Welch <welch@whitehall1-5.seh.ox.ac.uk> * subsys/win32k/ntuser/window.c (NtUserGetWindowLong): Began implementation. 2002-06-18 David Welch <welch@whitehall1-5.seh.ox.ac.uk> * subsys/win32k/misc/object.c (ObmCreateHandle): Return the correct handle value. 2002-06-18 David Welch <welch@whitehall1-5.seh.ox.ac.uk> * subsys/win32k/makefile: Make win32k depend on the file containing the service table. 2002-06-18 David Welch <welch@whitehall1-5.seh.ox.ac.uk> * ntoskrnl/ke/i386/stkswitch.S (KeSwitchStackAndRet, KePushAndStackSwitchAndSysRet): Push one value only. * ntoskrnl/ps/w32call.c (NtCallbackReturn, NtW32Call): Moved these functions to a new file. Restore the old trap frame after returning from a callback. 2002-06-18 David Welch <welch@whitehall1-5.seh.ox.ac.uk> * lib/user32/windows/message.c (CallWindowProcA, CallWindowProcW): Convert message to Unicode or ASCII if necessary. 2002-06-18 David Welch <welch@whitehall1-5.seh.ox.ac.uk> * include/user32/callback.h: Added WM_CREATE and WM_NCCALCSIZE callbacks. * lib/user32/windows/window.c (User32SendCREATEMessageForKernel, User32SendNCCREATEMessageForKernel): Implemented. * subsys/win32k/ntuser/callback.c (W32kSendCREATEMessage): Implemented. 2002-06-18 David Welch <welch@whitehall1-5.seh.ox.ac.uk> * include/structs.h: Added Unicode and ASCII versions of CREATESTRUCT. svn path=/trunk/; revision=3118
2002-06-18 21:51:11 +00:00
}
case WM_GETDLGCODE:
if (UnicodeMsg->lParam)
{
MSG newmsg = *(MSG *)UnicodeMsg->lParam;
newmsg.wParam = map_wparam_AtoW( newmsg.message, newmsg.wParam);
}
break;
case WM_CHARTOITEM:
case WM_MENUCHAR:
case WM_CHAR:
case WM_DEADCHAR:
case WM_SYSCHAR:
case WM_SYSDEADCHAR:
case EM_SETPASSWORDCHAR:
case WM_IME_CHAR:
UnicodeMsg->wParam = map_wparam_AtoW( AnsiMsg->message, AnsiMsg->wParam );
break;
case EM_GETLINE:
ERR("FIXME EM_GETLINE A2U\n");
break;
2002-06-18 David Welch <welch@whitehall1-5.seh.ox.ac.uk> * tools/helper.mk: Make an import library a proper target depending on the .def file. 2002-06-18 David Welch <welch@whitehall1-5.seh.ox.ac.uk> * subsys/win32k/ntuser/window.c (NtUserGetWindowLong): Began implementation. 2002-06-18 David Welch <welch@whitehall1-5.seh.ox.ac.uk> * subsys/win32k/misc/object.c (ObmCreateHandle): Return the correct handle value. 2002-06-18 David Welch <welch@whitehall1-5.seh.ox.ac.uk> * subsys/win32k/makefile: Make win32k depend on the file containing the service table. 2002-06-18 David Welch <welch@whitehall1-5.seh.ox.ac.uk> * ntoskrnl/ke/i386/stkswitch.S (KeSwitchStackAndRet, KePushAndStackSwitchAndSysRet): Push one value only. * ntoskrnl/ps/w32call.c (NtCallbackReturn, NtW32Call): Moved these functions to a new file. Restore the old trap frame after returning from a callback. 2002-06-18 David Welch <welch@whitehall1-5.seh.ox.ac.uk> * lib/user32/windows/message.c (CallWindowProcA, CallWindowProcW): Convert message to Unicode or ASCII if necessary. 2002-06-18 David Welch <welch@whitehall1-5.seh.ox.ac.uk> * include/user32/callback.h: Added WM_CREATE and WM_NCCALCSIZE callbacks. * lib/user32/windows/window.c (User32SendCREATEMessageForKernel, User32SendNCCREATEMessageForKernel): Implemented. * subsys/win32k/ntuser/callback.c (W32kSendCREATEMessage): Implemented. 2002-06-18 David Welch <welch@whitehall1-5.seh.ox.ac.uk> * include/structs.h: Added Unicode and ASCII versions of CREATESTRUCT. svn path=/trunk/; revision=3118
2002-06-18 21:51:11 +00:00
}
return TRUE;
}
static BOOL FASTCALL
MsgiAnsiToUnicodeCleanup(LPMSG UnicodeMsg, LPMSG AnsiMsg)
{
UNICODE_STRING UnicodeString;
switch (AnsiMsg->message)
{
case LB_GETTEXT:
if (!listbox_has_strings( UnicodeMsg->hwnd )) break;
case CB_GETLBTEXT:
if (UnicodeMsg->message == CB_GETLBTEXT && !combobox_has_strings( UnicodeMsg->hwnd )) break;
case WM_GETTEXT:
case WM_ASKCBFORMATNAME:
{
if (!UnicodeMsg->lParam) break;
RtlFreeHeap(GetProcessHeap(), 0, (PVOID) UnicodeMsg->lParam);
break;
}
case WM_SETTEXT:
case WM_WININICHANGE:
case WM_DEVMODECHANGE:
case CB_DIR:
case LB_DIR:
case LB_ADDFILE:
case EM_REPLACESEL:
{
if (!UnicodeMsg->lParam) break;
RtlInitUnicodeString(&UnicodeString, (PCWSTR)UnicodeMsg->lParam);
RtlFreeUnicodeString(&UnicodeString);
break;
}
case LB_ADDSTRING:
case LB_ADDSTRING_LOWER:
case LB_ADDSTRING_UPPER:
case LB_INSERTSTRING:
case LB_INSERTSTRING_UPPER:
case LB_INSERTSTRING_LOWER:
case LB_FINDSTRING:
case LB_FINDSTRINGEXACT:
case LB_SELECTSTRING:
{
if (UnicodeMsg->lParam && listbox_has_strings(AnsiMsg->hwnd))
{
RtlInitUnicodeString(&UnicodeString, (PCWSTR)UnicodeMsg->lParam);
RtlFreeUnicodeString(&UnicodeString);
}
break;
}
case CB_ADDSTRING:
case CB_INSERTSTRING:
case CB_FINDSTRING:
case CB_FINDSTRINGEXACT:
case CB_SELECTSTRING:
{
if (UnicodeMsg->lParam && combobox_has_strings(AnsiMsg->hwnd))
{
RtlInitUnicodeString(&UnicodeString, (PCWSTR)UnicodeMsg->lParam);
RtlFreeUnicodeString(&UnicodeString);
}
break;
}
case WM_NCCREATE:
case WM_CREATE:
{
struct s
{
CREATESTRUCTW cs; /* new structure */
MDICREATESTRUCTW mdi_cs; /* MDI info */
LPWSTR lpszName; /* allocated Name */
LPWSTR lpszClass; /* allocated Class */
};
struct s *xs = (struct s *)UnicodeMsg->lParam;
if (xs->lpszName)
{
RtlInitUnicodeString(&UnicodeString, (PCWSTR)xs->lpszName);
RtlFreeUnicodeString(&UnicodeString);
}
if (xs->lpszClass)
{
RtlInitUnicodeString(&UnicodeString, (PCWSTR)xs->lpszClass);
RtlFreeUnicodeString(&UnicodeString);
}
HeapFree(GetProcessHeap(), 0, xs);
break;
}
case WM_MDICREATE:
{
MDICREATESTRUCTW *cs = (MDICREATESTRUCTW *)UnicodeMsg->lParam;
RtlInitUnicodeString(&UnicodeString, (PCWSTR)cs->szTitle);
RtlFreeUnicodeString(&UnicodeString);
if (!IS_ATOM(cs->szClass))
{
RtlInitUnicodeString(&UnicodeString, (PCWSTR)cs->szClass);
RtlFreeUnicodeString(&UnicodeString);
}
HeapFree(GetProcessHeap(), 0, cs);
break;
}
}
return(TRUE);
}
/*
* callout return -> Unicode Result to Ansi Result
*/
static BOOL FASTCALL
MsgiAnsiToUnicodeReply(LPMSG UnicodeMsg, LPMSG AnsiMsg, LRESULT *Result)
{
LPWSTR Buffer = (LPWSTR)UnicodeMsg->lParam;
LPSTR AnsiBuffer = (LPSTR)AnsiMsg->lParam;
switch (AnsiMsg->message)
{
case WM_GETTEXT:
case WM_ASKCBFORMATNAME:
{
if (UnicodeMsg->wParam)
{
DWORD len = 0;
if (*Result) RtlUnicodeToMultiByteN( AnsiBuffer, UnicodeMsg->wParam - 1, &len, Buffer, strlenW(Buffer) * sizeof(WCHAR));
AnsiBuffer[len] = 0;
*Result = len;
//ERR("WM_GETTEXT U2A Result %d Size %d\n",*Result,AnsiMsg->wParam);
}
break;
}
case LB_GETTEXT:
{
if (!AnsiBuffer || !listbox_has_strings( UnicodeMsg->hwnd )) break;
if (*Result >= 0)
{
DWORD len;
RtlUnicodeToMultiByteN( AnsiBuffer, ~0u, &len, Buffer, (strlenW(Buffer) + 1) * sizeof(WCHAR) );
*Result = len - 1;
}
break;
}
case CB_GETLBTEXT:
{
if (!AnsiBuffer || !combobox_has_strings( UnicodeMsg->hwnd )) break;
if (*Result >= 0)
{
DWORD len;
RtlUnicodeToMultiByteN( AnsiBuffer, ~0u, &len, Buffer, (strlenW(Buffer) + 1) * sizeof(WCHAR) );
*Result = len - 1;
}
break;
}
}
MsgiAnsiToUnicodeCleanup(UnicodeMsg, AnsiMsg);
return TRUE;
}
//
// Unicode to Ansi callout ->
//
static BOOL FASTCALL
MsgiUnicodeToAnsiMessage(HWND hwnd, LPMSG AnsiMsg, LPMSG UnicodeMsg)
{
ANSI_STRING AnsiString;
UNICODE_STRING UnicodeString;
*AnsiMsg = *UnicodeMsg;
switch(UnicodeMsg->message)
2002-06-18 David Welch <welch@whitehall1-5.seh.ox.ac.uk> * tools/helper.mk: Make an import library a proper target depending on the .def file. 2002-06-18 David Welch <welch@whitehall1-5.seh.ox.ac.uk> * subsys/win32k/ntuser/window.c (NtUserGetWindowLong): Began implementation. 2002-06-18 David Welch <welch@whitehall1-5.seh.ox.ac.uk> * subsys/win32k/misc/object.c (ObmCreateHandle): Return the correct handle value. 2002-06-18 David Welch <welch@whitehall1-5.seh.ox.ac.uk> * subsys/win32k/makefile: Make win32k depend on the file containing the service table. 2002-06-18 David Welch <welch@whitehall1-5.seh.ox.ac.uk> * ntoskrnl/ke/i386/stkswitch.S (KeSwitchStackAndRet, KePushAndStackSwitchAndSysRet): Push one value only. * ntoskrnl/ps/w32call.c (NtCallbackReturn, NtW32Call): Moved these functions to a new file. Restore the old trap frame after returning from a callback. 2002-06-18 David Welch <welch@whitehall1-5.seh.ox.ac.uk> * lib/user32/windows/message.c (CallWindowProcA, CallWindowProcW): Convert message to Unicode or ASCII if necessary. 2002-06-18 David Welch <welch@whitehall1-5.seh.ox.ac.uk> * include/user32/callback.h: Added WM_CREATE and WM_NCCALCSIZE callbacks. * lib/user32/windows/window.c (User32SendCREATEMessageForKernel, User32SendNCCREATEMessageForKernel): Implemented. * subsys/win32k/ntuser/callback.c (W32kSendCREATEMessage): Implemented. 2002-06-18 David Welch <welch@whitehall1-5.seh.ox.ac.uk> * include/structs.h: Added Unicode and ASCII versions of CREATESTRUCT. svn path=/trunk/; revision=3118
2002-06-18 21:51:11 +00:00
{
case WM_CREATE:
case WM_NCCREATE:
{
MDICREATESTRUCTA *pmdi_cs;
CREATESTRUCTA* CsA;
CREATESTRUCTW* CsW;
ULONG NameSize, ClassSize;
NTSTATUS Status;
CsW = (CREATESTRUCTW*)(UnicodeMsg->lParam);
RtlInitUnicodeString(&UnicodeString, CsW->lpszName);
NameSize = RtlUnicodeStringToAnsiSize(&UnicodeString);
if (NameSize == 0)
{
return FALSE;
}
ClassSize = 0;
if (!IS_ATOM(CsW->lpszClass))
{
RtlInitUnicodeString(&UnicodeString, CsW->lpszClass);
ClassSize = RtlUnicodeStringToAnsiSize(&UnicodeString);
if (ClassSize == 0)
{
return FALSE;
}
}
CsA = RtlAllocateHeap(GetProcessHeap(), 0, sizeof(CREATESTRUCTA) + sizeof(MDICREATESTRUCTA) + NameSize + ClassSize);
if (NULL == CsA)
{
return FALSE;
}
memcpy(CsA, CsW, sizeof(CREATESTRUCTW));
/* pmdi_cs starts right after CsA */
pmdi_cs = (MDICREATESTRUCTA*)(CsA + 1);
RtlInitUnicodeString(&UnicodeString, CsW->lpszName);
RtlInitEmptyAnsiString(&AnsiString, (PCHAR)(pmdi_cs + 1), NameSize);
Status = RtlUnicodeStringToAnsiString(&AnsiString, &UnicodeString, FALSE);
if (! NT_SUCCESS(Status))
{
RtlFreeHeap(GetProcessHeap(), 0, CsA);
return FALSE;
}
CsA->lpszName = AnsiString.Buffer;
if (!IS_ATOM(CsW->lpszClass))
{
RtlInitUnicodeString(&UnicodeString, CsW->lpszClass);
RtlInitEmptyAnsiString(&AnsiString, (PCHAR)(pmdi_cs + 1) + NameSize, ClassSize);
Status = RtlUnicodeStringToAnsiString(&AnsiString, &UnicodeString, FALSE);
if (! NT_SUCCESS(Status))
{
RtlFreeHeap(GetProcessHeap(), 0, CsA);
return FALSE;
}
CsA->lpszClass = AnsiString.Buffer;
}
if (GetWindowLongW(hwnd, GWL_EXSTYLE) & WS_EX_MDICHILD)
{
*pmdi_cs = *(MDICREATESTRUCTA *)CsW->lpCreateParams;
pmdi_cs->szTitle = CsA->lpszName;
pmdi_cs->szClass = CsA->lpszClass;
CsA->lpCreateParams = pmdi_cs;
}
AnsiMsg->lParam = (LPARAM)CsA;
break;
}
case WM_GETTEXT:
case WM_ASKCBFORMATNAME:
{
if (!UnicodeMsg->lParam) break;
/* Ansi string might contain MBCS chars so we need 2 * the number of chars */
AnsiMsg->lParam = (LPARAM) RtlAllocateHeap(GetProcessHeap(), HEAP_ZERO_MEMORY, UnicodeMsg->wParam * 2);
//ERR("WM_GETTEXT U2A Size %d\n",AnsiMsg->wParam);
if (!AnsiMsg->lParam) return FALSE;
break;
}
case LB_GETTEXT:
{
DWORD Size = 1024;
if (!UnicodeMsg->lParam || !listbox_has_strings( UnicodeMsg->hwnd )) break;
/*Size = SendMessageA( UnicodeMsg->hwnd, LB_GETTEXTLEN, UnicodeMsg->wParam, 0 );
if (Size == LB_ERR)
{
ERR("LB_GETTEXT LB_ERR\n");
Size = sizeof(ULONG_PTR);
}
Size = (Size + 1) * sizeof(WCHAR);*/
AnsiMsg->lParam = (LPARAM) RtlAllocateHeap(GetProcessHeap(), HEAP_ZERO_MEMORY, Size);
if (!AnsiMsg->lParam) return FALSE;
break;
}
case CB_GETLBTEXT:
{
DWORD Size = 1024;
if (!UnicodeMsg->lParam || !combobox_has_strings( UnicodeMsg->hwnd )) break;
/*Size = SendMessageA( UnicodeMsg->hwnd, CB_GETLBTEXTLEN, UnicodeMsg->wParam, 0 );
if (Size == LB_ERR)
{
ERR("CB_GETTEXT LB_ERR\n");
Size = sizeof(ULONG_PTR);
}
Size = (Size + 1) * sizeof(WCHAR);*/
AnsiMsg->lParam = (LPARAM) RtlAllocateHeap(GetProcessHeap(), HEAP_ZERO_MEMORY, Size);
if (!AnsiMsg->lParam) return FALSE;
break;
}
case WM_SETTEXT:
case WM_WININICHANGE:
case WM_DEVMODECHANGE:
case CB_DIR:
case LB_DIR:
case LB_ADDFILE:
case EM_REPLACESEL:
{
if (!UnicodeMsg->lParam) break;
RtlInitUnicodeString(&UnicodeString, (PWSTR) UnicodeMsg->lParam);
if (! NT_SUCCESS(RtlUnicodeStringToAnsiString(&AnsiString,
&UnicodeString,
TRUE)))
{
return FALSE;
}
AnsiMsg->lParam = (LPARAM) AnsiString.Buffer;
break;
}
case LB_ADDSTRING:
case LB_ADDSTRING_LOWER:
case LB_ADDSTRING_UPPER:
case LB_INSERTSTRING:
case LB_INSERTSTRING_UPPER:
case LB_INSERTSTRING_LOWER:
case LB_FINDSTRING:
case LB_FINDSTRINGEXACT:
case LB_SELECTSTRING:
{
if (UnicodeMsg->lParam && listbox_has_strings(AnsiMsg->hwnd))
{
RtlInitUnicodeString(&UnicodeString, (PWSTR) UnicodeMsg->lParam);
if (! NT_SUCCESS(RtlUnicodeStringToAnsiString(&AnsiString,
&UnicodeString,
TRUE)))
{
return FALSE;
}
AnsiMsg->lParam = (LPARAM) AnsiString.Buffer;
}
break;
}
case CB_ADDSTRING:
case CB_INSERTSTRING:
case CB_FINDSTRING:
case CB_FINDSTRINGEXACT:
case CB_SELECTSTRING:
{
if (UnicodeMsg->lParam && combobox_has_strings(AnsiMsg->hwnd))
{
RtlInitUnicodeString(&UnicodeString, (PWSTR) UnicodeMsg->lParam);
if (! NT_SUCCESS(RtlUnicodeStringToAnsiString(&AnsiString,
&UnicodeString,
TRUE)))
{
return FALSE;
}
AnsiMsg->lParam = (LPARAM) AnsiString.Buffer;
}
break;
}
case WM_MDICREATE:
{
MDICREATESTRUCTA *cs =
(MDICREATESTRUCTA *)HeapAlloc(GetProcessHeap(), 0, sizeof(*cs));
if (!cs)
{
return FALSE;
}
*cs = *(MDICREATESTRUCTA *)UnicodeMsg->lParam;
if (!IS_ATOM(cs->szClass))
{
RtlInitUnicodeString(&UnicodeString, (LPCWSTR)cs->szClass);
if (! NT_SUCCESS(RtlUnicodeStringToAnsiString(&AnsiString,
&UnicodeString,
TRUE)))
{
HeapFree(GetProcessHeap(), 0, cs);
return FALSE;
}
cs->szClass = AnsiString.Buffer;
}
RtlInitUnicodeString(&UnicodeString, (LPCWSTR)cs->szTitle);
if (! NT_SUCCESS(RtlUnicodeStringToAnsiString(&AnsiString,
&UnicodeString,
TRUE)))
{
if (!IS_ATOM(cs->szClass))
{
RtlInitAnsiString(&AnsiString, cs->szClass);
RtlFreeAnsiString(&AnsiString);
}
HeapFree(GetProcessHeap(), 0, cs);
return FALSE;
}
cs->szTitle = AnsiString.Buffer;
AnsiMsg->lParam = (LPARAM)cs;
break;
}
case WM_GETDLGCODE:
if (UnicodeMsg->lParam)
{
MSG newmsg = *(MSG *)UnicodeMsg->lParam;
switch(newmsg.message)
{
case WM_CHAR:
case WM_DEADCHAR:
case WM_SYSCHAR:
case WM_SYSDEADCHAR:
newmsg.wParam = map_wparam_char_WtoA( newmsg.wParam, 1 );
break;
case WM_IME_CHAR:
newmsg.wParam = map_wparam_char_WtoA( newmsg.wParam, 2 );
break;
}
}
break;
case WM_CHAR:
{
WCHAR wch = UnicodeMsg->wParam;
char ch[2];
DWORD cp = get_input_codepage();
DWORD len = WideCharToMultiByte( cp, 0, &wch, 1, ch, 2, NULL, NULL );
AnsiMsg->wParam = (BYTE)ch[0];
if (len == 2) AnsiMsg->wParam = (BYTE)ch[1];
}
break;
case WM_CHARTOITEM:
case WM_MENUCHAR:
case WM_DEADCHAR:
case WM_SYSCHAR:
case WM_SYSDEADCHAR:
case EM_SETPASSWORDCHAR:
AnsiMsg->wParam = map_wparam_char_WtoA(UnicodeMsg->wParam,1);
break;
case WM_IME_CHAR:
AnsiMsg->wParam = map_wparam_char_WtoA(UnicodeMsg->wParam,2);
break;
case EM_GETLINE:
ERR("FIXME EM_GETLINE U2A\n");
break;
}
return TRUE;
}
static BOOL FASTCALL
MsgiUnicodeToAnsiCleanup(LPMSG AnsiMsg, LPMSG UnicodeMsg)
{
ANSI_STRING AnsiString;
switch(UnicodeMsg->message)
{
case LB_GETTEXT:
if (!listbox_has_strings( AnsiMsg->hwnd )) break;
case CB_GETLBTEXT:
if (AnsiMsg->message == CB_GETLBTEXT && !combobox_has_strings( AnsiMsg->hwnd )) break;
case WM_GETTEXT:
case WM_ASKCBFORMATNAME:
{
if (!AnsiMsg->lParam) break;
RtlFreeHeap(GetProcessHeap(), 0, (PVOID) AnsiMsg->lParam);
break;
}
case WM_CREATE:
case WM_NCCREATE:
{
CREATESTRUCTA* Cs;
Cs = (CREATESTRUCTA*) AnsiMsg->lParam;
RtlFreeHeap(GetProcessHeap(), 0, Cs);
break;
}
case WM_SETTEXT:
case WM_WININICHANGE:
case WM_DEVMODECHANGE:
case CB_DIR:
case LB_DIR:
case LB_ADDFILE:
case EM_REPLACESEL:
{
if (!AnsiMsg->lParam) break;
RtlInitAnsiString(&AnsiString, (PSTR) AnsiMsg->lParam);
RtlFreeAnsiString(&AnsiString);
break;
}
case LB_ADDSTRING:
case LB_ADDSTRING_LOWER:
case LB_ADDSTRING_UPPER:
case LB_INSERTSTRING:
case LB_INSERTSTRING_UPPER:
case LB_INSERTSTRING_LOWER:
case LB_FINDSTRING:
case LB_FINDSTRINGEXACT:
case LB_SELECTSTRING:
{
if (AnsiMsg->lParam && listbox_has_strings(AnsiMsg->hwnd))
{
RtlInitAnsiString(&AnsiString, (PSTR) AnsiMsg->lParam);
RtlFreeAnsiString(&AnsiString);
}
break;
}
case CB_ADDSTRING:
case CB_INSERTSTRING:
case CB_FINDSTRING:
case CB_FINDSTRINGEXACT:
case CB_SELECTSTRING:
{
if (AnsiMsg->lParam && combobox_has_strings(AnsiMsg->hwnd))
{
RtlInitAnsiString(&AnsiString, (PSTR) AnsiMsg->lParam);
RtlFreeAnsiString(&AnsiString);
}
break;
}
case WM_MDICREATE:
{
MDICREATESTRUCTA *cs = (MDICREATESTRUCTA *)AnsiMsg->lParam;
RtlInitAnsiString(&AnsiString, (PCSTR)cs->szTitle);
RtlFreeAnsiString(&AnsiString);
if (!IS_ATOM(cs->szClass))
{
RtlInitAnsiString(&AnsiString, (PCSTR)cs->szClass);
RtlFreeAnsiString(&AnsiString);
}
HeapFree(GetProcessHeap(), 0, cs);
break;
}
2002-06-18 David Welch <welch@whitehall1-5.seh.ox.ac.uk> * tools/helper.mk: Make an import library a proper target depending on the .def file. 2002-06-18 David Welch <welch@whitehall1-5.seh.ox.ac.uk> * subsys/win32k/ntuser/window.c (NtUserGetWindowLong): Began implementation. 2002-06-18 David Welch <welch@whitehall1-5.seh.ox.ac.uk> * subsys/win32k/misc/object.c (ObmCreateHandle): Return the correct handle value. 2002-06-18 David Welch <welch@whitehall1-5.seh.ox.ac.uk> * subsys/win32k/makefile: Make win32k depend on the file containing the service table. 2002-06-18 David Welch <welch@whitehall1-5.seh.ox.ac.uk> * ntoskrnl/ke/i386/stkswitch.S (KeSwitchStackAndRet, KePushAndStackSwitchAndSysRet): Push one value only. * ntoskrnl/ps/w32call.c (NtCallbackReturn, NtW32Call): Moved these functions to a new file. Restore the old trap frame after returning from a callback. 2002-06-18 David Welch <welch@whitehall1-5.seh.ox.ac.uk> * lib/user32/windows/message.c (CallWindowProcA, CallWindowProcW): Convert message to Unicode or ASCII if necessary. 2002-06-18 David Welch <welch@whitehall1-5.seh.ox.ac.uk> * include/user32/callback.h: Added WM_CREATE and WM_NCCALCSIZE callbacks. * lib/user32/windows/window.c (User32SendCREATEMessageForKernel, User32SendNCCREATEMessageForKernel): Implemented. * subsys/win32k/ntuser/callback.c (W32kSendCREATEMessage): Implemented. 2002-06-18 David Welch <welch@whitehall1-5.seh.ox.ac.uk> * include/structs.h: Added Unicode and ASCII versions of CREATESTRUCT. svn path=/trunk/; revision=3118
2002-06-18 21:51:11 +00:00
}
return TRUE;
2002-06-18 David Welch <welch@whitehall1-5.seh.ox.ac.uk> * tools/helper.mk: Make an import library a proper target depending on the .def file. 2002-06-18 David Welch <welch@whitehall1-5.seh.ox.ac.uk> * subsys/win32k/ntuser/window.c (NtUserGetWindowLong): Began implementation. 2002-06-18 David Welch <welch@whitehall1-5.seh.ox.ac.uk> * subsys/win32k/misc/object.c (ObmCreateHandle): Return the correct handle value. 2002-06-18 David Welch <welch@whitehall1-5.seh.ox.ac.uk> * subsys/win32k/makefile: Make win32k depend on the file containing the service table. 2002-06-18 David Welch <welch@whitehall1-5.seh.ox.ac.uk> * ntoskrnl/ke/i386/stkswitch.S (KeSwitchStackAndRet, KePushAndStackSwitchAndSysRet): Push one value only. * ntoskrnl/ps/w32call.c (NtCallbackReturn, NtW32Call): Moved these functions to a new file. Restore the old trap frame after returning from a callback. 2002-06-18 David Welch <welch@whitehall1-5.seh.ox.ac.uk> * lib/user32/windows/message.c (CallWindowProcA, CallWindowProcW): Convert message to Unicode or ASCII if necessary. 2002-06-18 David Welch <welch@whitehall1-5.seh.ox.ac.uk> * include/user32/callback.h: Added WM_CREATE and WM_NCCALCSIZE callbacks. * lib/user32/windows/window.c (User32SendCREATEMessageForKernel, User32SendNCCREATEMessageForKernel): Implemented. * subsys/win32k/ntuser/callback.c (W32kSendCREATEMessage): Implemented. 2002-06-18 David Welch <welch@whitehall1-5.seh.ox.ac.uk> * include/structs.h: Added Unicode and ASCII versions of CREATESTRUCT. svn path=/trunk/; revision=3118
2002-06-18 21:51:11 +00:00
}
/*
* callout return -> Ansi Result to Unicode Result
*/
static BOOL FASTCALL
MsgiUnicodeToAnsiReply(LPMSG AnsiMsg, LPMSG UnicodeMsg, LRESULT *Result)
2002-06-18 David Welch <welch@whitehall1-5.seh.ox.ac.uk> * tools/helper.mk: Make an import library a proper target depending on the .def file. 2002-06-18 David Welch <welch@whitehall1-5.seh.ox.ac.uk> * subsys/win32k/ntuser/window.c (NtUserGetWindowLong): Began implementation. 2002-06-18 David Welch <welch@whitehall1-5.seh.ox.ac.uk> * subsys/win32k/misc/object.c (ObmCreateHandle): Return the correct handle value. 2002-06-18 David Welch <welch@whitehall1-5.seh.ox.ac.uk> * subsys/win32k/makefile: Make win32k depend on the file containing the service table. 2002-06-18 David Welch <welch@whitehall1-5.seh.ox.ac.uk> * ntoskrnl/ke/i386/stkswitch.S (KeSwitchStackAndRet, KePushAndStackSwitchAndSysRet): Push one value only. * ntoskrnl/ps/w32call.c (NtCallbackReturn, NtW32Call): Moved these functions to a new file. Restore the old trap frame after returning from a callback. 2002-06-18 David Welch <welch@whitehall1-5.seh.ox.ac.uk> * lib/user32/windows/message.c (CallWindowProcA, CallWindowProcW): Convert message to Unicode or ASCII if necessary. 2002-06-18 David Welch <welch@whitehall1-5.seh.ox.ac.uk> * include/user32/callback.h: Added WM_CREATE and WM_NCCALCSIZE callbacks. * lib/user32/windows/window.c (User32SendCREATEMessageForKernel, User32SendNCCREATEMessageForKernel): Implemented. * subsys/win32k/ntuser/callback.c (W32kSendCREATEMessage): Implemented. 2002-06-18 David Welch <welch@whitehall1-5.seh.ox.ac.uk> * include/structs.h: Added Unicode and ASCII versions of CREATESTRUCT. svn path=/trunk/; revision=3118
2002-06-18 21:51:11 +00:00
{
LPSTR Buffer = (LPSTR) AnsiMsg->lParam;
LPWSTR UBuffer = (LPWSTR) UnicodeMsg->lParam;
switch (UnicodeMsg->message)
{
case WM_GETTEXT:
case WM_ASKCBFORMATNAME:
{
DWORD len = AnsiMsg->wParam;// * 2;
if (len)
{
if (*Result)
{
RtlMultiByteToUnicodeN( UBuffer, AnsiMsg->wParam*sizeof(WCHAR), &len, Buffer, strlen(Buffer)+1 );
*Result = len/sizeof(WCHAR) - 1; /* do not count terminating null */
//ERR("WM_GETTEXT U2A Result %d Size %d\n",*Result,AnsiMsg->wParam);
}
UBuffer[*Result] = 0;
}
break;
}
case LB_GETTEXT:
{
if (!UBuffer || !listbox_has_strings( UnicodeMsg->hwnd )) break;
if (*Result >= 0)
{
DWORD len;
RtlMultiByteToUnicodeN( UBuffer, ~0u, &len, Buffer, strlen(Buffer) + 1 );
*Result = len / sizeof(WCHAR) - 1;
}
break;
}
case CB_GETLBTEXT:
{
if (!UBuffer || !combobox_has_strings( UnicodeMsg->hwnd )) break;
if (*Result >= 0)
{
DWORD len;
RtlMultiByteToUnicodeN( UBuffer, ~0u, &len, Buffer, strlen(Buffer) + 1 );
*Result = len / sizeof(WCHAR) - 1;
}
break;
}
}
MsgiUnicodeToAnsiCleanup(AnsiMsg, UnicodeMsg);
return TRUE;
}
LRESULT
WINAPI
DesktopWndProcA( HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam )
{
LRESULT Result;
MSG AnsiMsg, UcMsg;
TRACE("Desktop A Class Atom! hWnd 0x%x, Msg %d\n", hwnd, message);
AnsiMsg.hwnd = hwnd;
AnsiMsg.message = message;
AnsiMsg.wParam = wParam;
AnsiMsg.lParam = lParam;
AnsiMsg.time = 0;
AnsiMsg.pt.x = 0;
AnsiMsg.pt.y = 0;
// Desktop is always Unicode so convert Ansi here.
if (!MsgiAnsiToUnicodeMessage(hwnd, &UcMsg, &AnsiMsg))
{
return FALSE;
}
Result = DesktopWndProcW(hwnd, message, UcMsg.wParam, UcMsg.lParam);
MsgiAnsiToUnicodeCleanup(&UcMsg, &AnsiMsg);
return Result;
}
/*
* @implemented
*/
LPARAM
WINAPI
GetMessageExtraInfo(VOID)
{
return NtUserxGetMessageExtraInfo();
}
/*
* @implemented
*/
DWORD
WINAPI
GetMessagePos(VOID)
{
return NtUserxGetMessagePos();
}
/*
* @implemented
*/
LONG WINAPI
GetMessageTime(VOID)
{
return NtUserGetThreadState(THREADSTATE_GETMESSAGETIME);
}
/*
* @implemented
*/
BOOL
WINAPI
InSendMessage(VOID)
{
PCLIENTTHREADINFO pcti = GetWin32ClientInfo()->pClientThreadInfo;
if ( pcti )
{
if (pcti->CTI_flags & CTI_INSENDMESSAGE)
{
return TRUE;
}
}
return(NtUserGetThreadState(THREADSTATE_INSENDMESSAGE) != ISMEX_NOSEND);
}
/*
* @implemented
*/
DWORD
WINAPI
InSendMessageEx(
LPVOID lpReserved)
{
PCLIENTTHREADINFO pcti = GetWin32ClientInfo()->pClientThreadInfo;
if (pcti && !(pcti->CTI_flags & CTI_INSENDMESSAGE))
return ISMEX_NOSEND;
else
return NtUserGetThreadState(THREADSTATE_INSENDMESSAGE);
}
/*
* @implemented
*/
BOOL
WINAPI
ReplyMessage(LRESULT lResult)
{
return NtUserxReplyMessage(lResult);
}
/*
* @implemented
*/
LPARAM
WINAPI
SetMessageExtraInfo(
LPARAM lParam)
{
return NtUserxSetMessageExtraInfo(lParam);
2002-06-18 David Welch <welch@whitehall1-5.seh.ox.ac.uk> * tools/helper.mk: Make an import library a proper target depending on the .def file. 2002-06-18 David Welch <welch@whitehall1-5.seh.ox.ac.uk> * subsys/win32k/ntuser/window.c (NtUserGetWindowLong): Began implementation. 2002-06-18 David Welch <welch@whitehall1-5.seh.ox.ac.uk> * subsys/win32k/misc/object.c (ObmCreateHandle): Return the correct handle value. 2002-06-18 David Welch <welch@whitehall1-5.seh.ox.ac.uk> * subsys/win32k/makefile: Make win32k depend on the file containing the service table. 2002-06-18 David Welch <welch@whitehall1-5.seh.ox.ac.uk> * ntoskrnl/ke/i386/stkswitch.S (KeSwitchStackAndRet, KePushAndStackSwitchAndSysRet): Push one value only. * ntoskrnl/ps/w32call.c (NtCallbackReturn, NtW32Call): Moved these functions to a new file. Restore the old trap frame after returning from a callback. 2002-06-18 David Welch <welch@whitehall1-5.seh.ox.ac.uk> * lib/user32/windows/message.c (CallWindowProcA, CallWindowProcW): Convert message to Unicode or ASCII if necessary. 2002-06-18 David Welch <welch@whitehall1-5.seh.ox.ac.uk> * include/user32/callback.h: Added WM_CREATE and WM_NCCALCSIZE callbacks. * lib/user32/windows/window.c (User32SendCREATEMessageForKernel, User32SendNCCREATEMessageForKernel): Implemented. * subsys/win32k/ntuser/callback.c (W32kSendCREATEMessage): Implemented. 2002-06-18 David Welch <welch@whitehall1-5.seh.ox.ac.uk> * include/structs.h: Added Unicode and ASCII versions of CREATESTRUCT. svn path=/trunk/; revision=3118
2002-06-18 21:51:11 +00:00
}
LRESULT FASTCALL
IntCallWindowProcW(BOOL IsAnsiProc,
WNDPROC WndProc,
PWND pWnd,
HWND hWnd,
UINT Msg,
WPARAM wParam,
LPARAM lParam)
{
MSG AnsiMsg;
MSG UnicodeMsg;
BOOL Hook = FALSE, MsgOverride = FALSE, Dialog, DlgOverride = FALSE;
LRESULT Result = 0, PreResult = 0;
DWORD Data = 0;
if (WndProc == NULL)
{
WARN("IntCallWindowsProcW() called with WndProc = NULL!\n");
return FALSE;
}
if (pWnd)
Dialog = (pWnd->fnid == FNID_DIALOG);
else
Dialog = FALSE;
Hook = BeginIfHookedUserApiHook();
if (Hook)
{
if (Dialog)
DlgOverride = IsMsgOverride( Msg, &guah.DlgProcArray);
MsgOverride = IsMsgOverride( Msg, &guah.WndProcArray);
}
if (IsAnsiProc)
{
UnicodeMsg.hwnd = hWnd;
UnicodeMsg.message = Msg;
UnicodeMsg.wParam = wParam;
UnicodeMsg.lParam = lParam;
UnicodeMsg.time = 0;
UnicodeMsg.pt.x = 0;
UnicodeMsg.pt.y = 0;
if (! MsgiUnicodeToAnsiMessage(hWnd, &AnsiMsg, &UnicodeMsg))
{
goto Exit;
}
if (Hook && (MsgOverride || DlgOverride))
{
_SEH2_TRY
{
if (!DlgOverride)
PreResult = guah.PreWndProc(AnsiMsg.hwnd, AnsiMsg.message, AnsiMsg.wParam, AnsiMsg.lParam, (ULONG_PTR)&Result, &Data );
else
PreResult = guah.PreDefDlgProc(AnsiMsg.hwnd, AnsiMsg.message, AnsiMsg.wParam, AnsiMsg.lParam, (ULONG_PTR)&Result, &Data );
}
_SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
{
ERR("Got exception in hooked PreWndProc, dlg:%d!\n", DlgOverride);
}
_SEH2_END;
}
if (PreResult) goto Exit;
if (!Dialog)
Result = CALL_EXTERN_WNDPROC(WndProc, AnsiMsg.hwnd, AnsiMsg.message, AnsiMsg.wParam, AnsiMsg.lParam);
else
{
_SEH2_TRY
{
Result = CALL_EXTERN_WNDPROC(WndProc, AnsiMsg.hwnd, AnsiMsg.message, AnsiMsg.wParam, AnsiMsg.lParam);
}
_SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
{
ERR("Exception Dialog Ansi %p Msg %d pti %p Wndpti %p\n",WndProc,Msg,GetW32ThreadInfo(),pWnd->head.pti);
}
_SEH2_END;
}
if (Hook && (MsgOverride || DlgOverride))
{
_SEH2_TRY
{
if (!DlgOverride)
guah.PostWndProc(AnsiMsg.hwnd, AnsiMsg.message, AnsiMsg.wParam, AnsiMsg.lParam, (ULONG_PTR)&Result, &Data );
else
guah.PostDefDlgProc(AnsiMsg.hwnd, AnsiMsg.message, AnsiMsg.wParam, AnsiMsg.lParam, (ULONG_PTR)&Result, &Data );
}
_SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
{
ERR("Got exception in hooked PostWndProc, dlg:%d!\n", DlgOverride);
}
_SEH2_END;
}
if (! MsgiUnicodeToAnsiReply(&AnsiMsg, &UnicodeMsg, &Result))
{
goto Exit;
}
}
else
{
if (Hook && (MsgOverride || DlgOverride))
{
_SEH2_TRY
{
if (!DlgOverride)
PreResult = guah.PreWndProc(hWnd, Msg, wParam, lParam, (ULONG_PTR)&Result, &Data );
else
PreResult = guah.PreDefDlgProc(hWnd, Msg, wParam, lParam, (ULONG_PTR)&Result, &Data );
}
_SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
{
ERR("Got exception in hooked PreWndProc, dlg:%d!\n", DlgOverride);
}
_SEH2_END;
}
if (PreResult) goto Exit;
if (!Dialog)
Result = CALL_EXTERN_WNDPROC(WndProc, hWnd, Msg, wParam, lParam);
else
{
_SEH2_TRY
{
Result = CALL_EXTERN_WNDPROC(WndProc, hWnd, Msg, wParam, lParam);
}
_SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
{
ERR("Exception Dialog unicode %p Msg %d pti %p Wndpti %p\n",WndProc, Msg,GetW32ThreadInfo(),pWnd->head.pti);
}
_SEH2_END;
}
if (Hook && (MsgOverride || DlgOverride))
{
_SEH2_TRY
{
if (!DlgOverride)
guah.PostWndProc(hWnd, Msg, wParam, lParam, (ULONG_PTR)&Result, &Data );
else
guah.PostDefDlgProc(hWnd, Msg, wParam, lParam, (ULONG_PTR)&Result, &Data );
}
_SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
{
ERR("Got exception in hooked PostWndProc, dlg:%d!\n", DlgOverride);
}
_SEH2_END;
}
}
Exit:
if (Hook) EndUserApiHook();
return Result;
}
static LRESULT FASTCALL
IntCallWindowProcA(BOOL IsAnsiProc,
WNDPROC WndProc,
PWND pWnd,
HWND hWnd,
UINT Msg,
WPARAM wParam,
LPARAM lParam)
{
MSG AnsiMsg;
MSG UnicodeMsg;
BOOL Hook = FALSE, MsgOverride = FALSE, Dialog, DlgOverride = FALSE;
LRESULT Result = 0, PreResult = 0;
DWORD Data = 0;
TRACE("IntCallWindowProcA: IsAnsiProc : %s, WndProc %p, pWnd %p, hWnd %p, Msg %u, wParam %Iu, lParam %Iu.\n",
IsAnsiProc ? "TRUE" : "FALSE", WndProc, pWnd, hWnd, Msg, wParam, lParam);
if (WndProc == NULL)
{
WARN("IntCallWindowsProcA() called with WndProc = NULL!\n");
return FALSE;
}
if (pWnd)
Dialog = (pWnd->fnid == FNID_DIALOG);
else
Dialog = FALSE;
Hook = BeginIfHookedUserApiHook();
if (Hook)
{
if (Dialog)
DlgOverride = IsMsgOverride( Msg, &guah.DlgProcArray);
MsgOverride = IsMsgOverride( Msg, &guah.WndProcArray);
}
if (IsAnsiProc)
{
if (Hook && (MsgOverride || DlgOverride))
{
_SEH2_TRY
{
if (!DlgOverride)
PreResult = guah.PreWndProc(hWnd, Msg, wParam, lParam, (ULONG_PTR)&Result, &Data );
else
PreResult = guah.PreDefDlgProc(hWnd, Msg, wParam, lParam, (ULONG_PTR)&Result, &Data );
}
_SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
{
ERR("Got exception in hooked PreWndProc, dlg:%d!\n", DlgOverride);
}
_SEH2_END;
}
if (PreResult) goto Exit;
if (!Dialog)
Result = CALL_EXTERN_WNDPROC(WndProc, hWnd, Msg, wParam, lParam);
else
{
_SEH2_TRY
{
Result = CALL_EXTERN_WNDPROC(WndProc, hWnd, Msg, wParam, lParam);
}
_SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
{
ERR("Exception Dialog Ansi %p Msg %d pti %p Wndpti %p\n",WndProc,Msg,GetW32ThreadInfo(),pWnd->head.pti);
}
_SEH2_END;
}
if (Hook && (MsgOverride || DlgOverride))
{
_SEH2_TRY
{
if (!DlgOverride)
guah.PostWndProc(hWnd, Msg, wParam, lParam, (ULONG_PTR)&Result, &Data );
else
guah.PostDefDlgProc(hWnd, Msg, wParam, lParam, (ULONG_PTR)&Result, &Data );
}
_SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
{
ERR("Got exception in hooked PostWndProc, dlg:%d!\n", DlgOverride);
}
_SEH2_END;
}
}
else
{
AnsiMsg.hwnd = hWnd;
AnsiMsg.message = Msg;
AnsiMsg.wParam = wParam;
AnsiMsg.lParam = lParam;
AnsiMsg.time = 0;
AnsiMsg.pt.x = 0;
AnsiMsg.pt.y = 0;
if (! MsgiAnsiToUnicodeMessage(hWnd, &UnicodeMsg, &AnsiMsg))
{
goto Exit;
}
if (Hook && (MsgOverride || DlgOverride))
{
_SEH2_TRY
{
if (!DlgOverride)
PreResult = guah.PreWndProc(UnicodeMsg.hwnd, UnicodeMsg.message, UnicodeMsg.wParam, UnicodeMsg.lParam, (ULONG_PTR)&Result, &Data );
else
PreResult = guah.PreDefDlgProc(UnicodeMsg.hwnd, UnicodeMsg.message, UnicodeMsg.wParam, UnicodeMsg.lParam, (ULONG_PTR)&Result, &Data );
}
_SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
{
ERR("Got exception in hooked PreWndProc, dlg:%d!\n", DlgOverride);
}
_SEH2_END;
}
if (PreResult) goto Exit;
if (!Dialog)
Result = CALL_EXTERN_WNDPROC(WndProc, UnicodeMsg.hwnd, UnicodeMsg.message, UnicodeMsg.wParam, UnicodeMsg.lParam);
else
{
_SEH2_TRY
{
Result = CALL_EXTERN_WNDPROC(WndProc, UnicodeMsg.hwnd, UnicodeMsg.message, UnicodeMsg.wParam, UnicodeMsg.lParam);
}
_SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
{
ERR("Exception Dialog unicode %p Msg %d pti %p Wndpti %p\n",WndProc, Msg,GetW32ThreadInfo(),pWnd->head.pti);
}
_SEH2_END;
}
if (Hook && (MsgOverride || DlgOverride))
{
_SEH2_TRY
{
if (!DlgOverride)
guah.PostWndProc(UnicodeMsg.hwnd, UnicodeMsg.message, UnicodeMsg.wParam, UnicodeMsg.lParam, (ULONG_PTR)&Result, &Data );
else
guah.PostDefDlgProc(UnicodeMsg.hwnd, UnicodeMsg.message, UnicodeMsg.wParam, UnicodeMsg.lParam, (ULONG_PTR)&Result, &Data );
}
_SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
{
ERR("Got exception in hooked PostWndProc, dlg:%d!\n", DlgOverride);
}
_SEH2_END;
}
if (! MsgiAnsiToUnicodeReply(&UnicodeMsg, &AnsiMsg, &Result))
{
goto Exit;
}
}
Exit:
if (Hook) EndUserApiHook();
return Result;
}
static LRESULT WINAPI
IntCallMessageProc(IN PWND Wnd, IN HWND hWnd, IN UINT Msg, IN WPARAM wParam, IN LPARAM lParam, IN BOOL Ansi)
{
WNDPROC WndProc;
BOOL IsAnsi;
PCLS Class;
Class = DesktopPtrToUser(Wnd->pcls);
WndProc = NULL;
if ( Wnd->head.pti != GetW32ThreadInfo())
{ // Must be inside the same thread!
SetLastError( ERROR_MESSAGE_SYNC_ONLY );
return 0;
}
/*
This is the message exchange for user32. If there's a need to monitor messages,
do it here!
*/
TRACE("HWND %p, MSG %u, WPARAM %p, LPARAM %p, Ansi %d\n", hWnd, Msg, wParam, lParam, Ansi);
// if (Class->fnid <= FNID_GHOST && Class->fnid >= FNID_BUTTON )
if (Class->fnid <= FNID_GHOST && Class->fnid >= FNID_FIRST )
{
if (Ansi)
{
if (GETPFNCLIENTW(Class->fnid) == Wnd->lpfnWndProc)
WndProc = GETPFNCLIENTA(Class->fnid);
}
else
{
if (GETPFNCLIENTA(Class->fnid) == Wnd->lpfnWndProc)
WndProc = GETPFNCLIENTW(Class->fnid);
}
IsAnsi = Ansi;
if (!WndProc)
{
IsAnsi = !Wnd->Unicode;
WndProc = Wnd->lpfnWndProc;
}
}
else
{
IsAnsi = !Wnd->Unicode;
WndProc = Wnd->lpfnWndProc;
}
/*
Message caller can be Ansi/Unicode and the receiver can be Unicode/Ansi or
the same.
*/
if (!Ansi)
return IntCallWindowProcW(IsAnsi, WndProc, Wnd, hWnd, Msg, wParam, lParam);
else
return IntCallWindowProcA(IsAnsi, WndProc, Wnd, hWnd, Msg, wParam, lParam);
}
/*
* @implemented
*/
LRESULT WINAPI
2002-06-18 David Welch <welch@whitehall1-5.seh.ox.ac.uk> * tools/helper.mk: Make an import library a proper target depending on the .def file. 2002-06-18 David Welch <welch@whitehall1-5.seh.ox.ac.uk> * subsys/win32k/ntuser/window.c (NtUserGetWindowLong): Began implementation. 2002-06-18 David Welch <welch@whitehall1-5.seh.ox.ac.uk> * subsys/win32k/misc/object.c (ObmCreateHandle): Return the correct handle value. 2002-06-18 David Welch <welch@whitehall1-5.seh.ox.ac.uk> * subsys/win32k/makefile: Make win32k depend on the file containing the service table. 2002-06-18 David Welch <welch@whitehall1-5.seh.ox.ac.uk> * ntoskrnl/ke/i386/stkswitch.S (KeSwitchStackAndRet, KePushAndStackSwitchAndSysRet): Push one value only. * ntoskrnl/ps/w32call.c (NtCallbackReturn, NtW32Call): Moved these functions to a new file. Restore the old trap frame after returning from a callback. 2002-06-18 David Welch <welch@whitehall1-5.seh.ox.ac.uk> * lib/user32/windows/message.c (CallWindowProcA, CallWindowProcW): Convert message to Unicode or ASCII if necessary. 2002-06-18 David Welch <welch@whitehall1-5.seh.ox.ac.uk> * include/user32/callback.h: Added WM_CREATE and WM_NCCALCSIZE callbacks. * lib/user32/windows/window.c (User32SendCREATEMessageForKernel, User32SendNCCREATEMessageForKernel): Implemented. * subsys/win32k/ntuser/callback.c (W32kSendCREATEMessage): Implemented. 2002-06-18 David Welch <welch@whitehall1-5.seh.ox.ac.uk> * include/structs.h: Added Unicode and ASCII versions of CREATESTRUCT. svn path=/trunk/; revision=3118
2002-06-18 21:51:11 +00:00
CallWindowProcA(WNDPROC lpPrevWndFunc,
HWND hWnd,
UINT Msg,
WPARAM wParam,
LPARAM lParam)
{
PWND pWnd;
PCALLPROCDATA CallProc;
if (lpPrevWndFunc == NULL)
{
WARN("CallWindowProcA: lpPrevWndFunc == NULL!\n");
return 0;
}
pWnd = ValidateHwnd(hWnd);
if (!IsCallProcHandle(lpPrevWndFunc))
return IntCallWindowProcA(TRUE, lpPrevWndFunc, pWnd, hWnd, Msg, wParam, lParam);
else
2002-06-18 David Welch <welch@whitehall1-5.seh.ox.ac.uk> * tools/helper.mk: Make an import library a proper target depending on the .def file. 2002-06-18 David Welch <welch@whitehall1-5.seh.ox.ac.uk> * subsys/win32k/ntuser/window.c (NtUserGetWindowLong): Began implementation. 2002-06-18 David Welch <welch@whitehall1-5.seh.ox.ac.uk> * subsys/win32k/misc/object.c (ObmCreateHandle): Return the correct handle value. 2002-06-18 David Welch <welch@whitehall1-5.seh.ox.ac.uk> * subsys/win32k/makefile: Make win32k depend on the file containing the service table. 2002-06-18 David Welch <welch@whitehall1-5.seh.ox.ac.uk> * ntoskrnl/ke/i386/stkswitch.S (KeSwitchStackAndRet, KePushAndStackSwitchAndSysRet): Push one value only. * ntoskrnl/ps/w32call.c (NtCallbackReturn, NtW32Call): Moved these functions to a new file. Restore the old trap frame after returning from a callback. 2002-06-18 David Welch <welch@whitehall1-5.seh.ox.ac.uk> * lib/user32/windows/message.c (CallWindowProcA, CallWindowProcW): Convert message to Unicode or ASCII if necessary. 2002-06-18 David Welch <welch@whitehall1-5.seh.ox.ac.uk> * include/user32/callback.h: Added WM_CREATE and WM_NCCALCSIZE callbacks. * lib/user32/windows/window.c (User32SendCREATEMessageForKernel, User32SendNCCREATEMessageForKernel): Implemented. * subsys/win32k/ntuser/callback.c (W32kSendCREATEMessage): Implemented. 2002-06-18 David Welch <welch@whitehall1-5.seh.ox.ac.uk> * include/structs.h: Added Unicode and ASCII versions of CREATESTRUCT. svn path=/trunk/; revision=3118
2002-06-18 21:51:11 +00:00
{
CallProc = ValidateCallProc((HANDLE)lpPrevWndFunc);
if (CallProc != NULL)
{
return IntCallWindowProcA(!(CallProc->wType & UserGetCPDA2U),
CallProc->pfnClientPrevious,
pWnd,
hWnd,
Msg,
wParam,
lParam);
}
else
{
WARN("CallWindowProcA: can not dereference WndProcHandle\n");
return 0;
}
2002-06-18 David Welch <welch@whitehall1-5.seh.ox.ac.uk> * tools/helper.mk: Make an import library a proper target depending on the .def file. 2002-06-18 David Welch <welch@whitehall1-5.seh.ox.ac.uk> * subsys/win32k/ntuser/window.c (NtUserGetWindowLong): Began implementation. 2002-06-18 David Welch <welch@whitehall1-5.seh.ox.ac.uk> * subsys/win32k/misc/object.c (ObmCreateHandle): Return the correct handle value. 2002-06-18 David Welch <welch@whitehall1-5.seh.ox.ac.uk> * subsys/win32k/makefile: Make win32k depend on the file containing the service table. 2002-06-18 David Welch <welch@whitehall1-5.seh.ox.ac.uk> * ntoskrnl/ke/i386/stkswitch.S (KeSwitchStackAndRet, KePushAndStackSwitchAndSysRet): Push one value only. * ntoskrnl/ps/w32call.c (NtCallbackReturn, NtW32Call): Moved these functions to a new file. Restore the old trap frame after returning from a callback. 2002-06-18 David Welch <welch@whitehall1-5.seh.ox.ac.uk> * lib/user32/windows/message.c (CallWindowProcA, CallWindowProcW): Convert message to Unicode or ASCII if necessary. 2002-06-18 David Welch <welch@whitehall1-5.seh.ox.ac.uk> * include/user32/callback.h: Added WM_CREATE and WM_NCCALCSIZE callbacks. * lib/user32/windows/window.c (User32SendCREATEMessageForKernel, User32SendNCCREATEMessageForKernel): Implemented. * subsys/win32k/ntuser/callback.c (W32kSendCREATEMessage): Implemented. 2002-06-18 David Welch <welch@whitehall1-5.seh.ox.ac.uk> * include/structs.h: Added Unicode and ASCII versions of CREATESTRUCT. svn path=/trunk/; revision=3118
2002-06-18 21:51:11 +00:00
}
}
/*
* @implemented
*/
LRESULT WINAPI
2002-06-18 David Welch <welch@whitehall1-5.seh.ox.ac.uk> * tools/helper.mk: Make an import library a proper target depending on the .def file. 2002-06-18 David Welch <welch@whitehall1-5.seh.ox.ac.uk> * subsys/win32k/ntuser/window.c (NtUserGetWindowLong): Began implementation. 2002-06-18 David Welch <welch@whitehall1-5.seh.ox.ac.uk> * subsys/win32k/misc/object.c (ObmCreateHandle): Return the correct handle value. 2002-06-18 David Welch <welch@whitehall1-5.seh.ox.ac.uk> * subsys/win32k/makefile: Make win32k depend on the file containing the service table. 2002-06-18 David Welch <welch@whitehall1-5.seh.ox.ac.uk> * ntoskrnl/ke/i386/stkswitch.S (KeSwitchStackAndRet, KePushAndStackSwitchAndSysRet): Push one value only. * ntoskrnl/ps/w32call.c (NtCallbackReturn, NtW32Call): Moved these functions to a new file. Restore the old trap frame after returning from a callback. 2002-06-18 David Welch <welch@whitehall1-5.seh.ox.ac.uk> * lib/user32/windows/message.c (CallWindowProcA, CallWindowProcW): Convert message to Unicode or ASCII if necessary. 2002-06-18 David Welch <welch@whitehall1-5.seh.ox.ac.uk> * include/user32/callback.h: Added WM_CREATE and WM_NCCALCSIZE callbacks. * lib/user32/windows/window.c (User32SendCREATEMessageForKernel, User32SendNCCREATEMessageForKernel): Implemented. * subsys/win32k/ntuser/callback.c (W32kSendCREATEMessage): Implemented. 2002-06-18 David Welch <welch@whitehall1-5.seh.ox.ac.uk> * include/structs.h: Added Unicode and ASCII versions of CREATESTRUCT. svn path=/trunk/; revision=3118
2002-06-18 21:51:11 +00:00
CallWindowProcW(WNDPROC lpPrevWndFunc,
HWND hWnd,
UINT Msg,
WPARAM wParam,
LPARAM lParam)
{
PWND pWnd;
PCALLPROCDATA CallProc;
/* FIXME - can the first parameter be NULL? */
if (lpPrevWndFunc == NULL)
{
WARN("CallWindowProcA: lpPrevWndFunc == NULL!\n");
return 0;
}
pWnd = ValidateHwnd(hWnd);
if (!IsCallProcHandle(lpPrevWndFunc))
return IntCallWindowProcW(FALSE, lpPrevWndFunc, pWnd, hWnd, Msg, wParam, lParam);
else
{
CallProc = ValidateCallProc((HANDLE)lpPrevWndFunc);
if (CallProc != NULL)
{
return IntCallWindowProcW(!(CallProc->wType & UserGetCPDA2U),
CallProc->pfnClientPrevious,
pWnd,
hWnd,
Msg,
wParam,
lParam);
}
else
{
WARN("CallWindowProcW: can not dereference WndProcHandle\n");
return 0;
}
}
}
/*
* @implemented
*/
LRESULT
WINAPI
DECLSPEC_HOTPATCH
DispatchMessageA(CONST MSG *lpmsg)
{
LRESULT Ret = 0;
MSG UnicodeMsg;
PWND Wnd;
if ( lpmsg->message & ~WM_MAXIMUM )
{
SetLastError( ERROR_INVALID_PARAMETER );
return 0;
}
if (lpmsg->hwnd != NULL)
{
Wnd = ValidateHwnd(lpmsg->hwnd);
if (!Wnd) return 0;
}
else
Wnd = NULL;
if (is_pointer_message(lpmsg->message, lpmsg->wParam))
{
SetLastError( ERROR_MESSAGE_SYNC_ONLY );
return 0;
}
if ((lpmsg->message == WM_TIMER || lpmsg->message == WM_SYSTIMER) && lpmsg->lParam != 0)
{
WNDPROC WndProc = (WNDPROC)lpmsg->lParam;
if ( lpmsg->message == WM_SYSTIMER )
return NtUserDispatchMessage( (PMSG)lpmsg );
if (!NtUserValidateTimerCallback(lpmsg->lParam))
{
WARN("Validating Timer Callback failed!\n");
return 0;
}
_SEH2_TRY // wine does this. Hint: Prevents call to another thread....
{
Ret = WndProc(lpmsg->hwnd,
lpmsg->message,
lpmsg->wParam,
GetTickCount());
}
_SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
{
ERR("Exception in Timer Callback!\n");
}
_SEH2_END;
}
else if (Wnd != NULL)
{
if ( (lpmsg->message != WM_PAINT) && !(Wnd->state & WNDS_SERVERSIDEWINDOWPROC) )
{
Ret = IntCallMessageProc(Wnd,
lpmsg->hwnd,
lpmsg->message,
lpmsg->wParam,
lpmsg->lParam,
TRUE);
}
else
{
if (!MsgiAnsiToUnicodeMessage(lpmsg->hwnd, &UnicodeMsg, (LPMSG)lpmsg))
{
return FALSE;
}
Ret = NtUserDispatchMessage(&UnicodeMsg);
if (!MsgiAnsiToUnicodeReply(&UnicodeMsg, (LPMSG)lpmsg, &Ret))
{
return FALSE;
}
}
}
return Ret;
}
/*
* @implemented
*/
LRESULT
WINAPI
DECLSPEC_HOTPATCH
DispatchMessageW(CONST MSG *lpmsg)
{
LRESULT Ret = 0;
PWND Wnd;
BOOL Hit = FALSE;
if ( lpmsg->message & ~WM_MAXIMUM )
{
SetLastError( ERROR_INVALID_PARAMETER );
return 0;
}
if (lpmsg->hwnd != NULL)
{
Wnd = ValidateHwnd(lpmsg->hwnd);
if (!Wnd) return 0;
}
else
Wnd = NULL;
if (is_pointer_message(lpmsg->message, lpmsg->wParam))
{
SetLastError( ERROR_MESSAGE_SYNC_ONLY );
return 0;
}
if ((lpmsg->message == WM_TIMER || lpmsg->message == WM_SYSTIMER) && lpmsg->lParam != 0)
{
WNDPROC WndProc = (WNDPROC)lpmsg->lParam;
if ( lpmsg->message == WM_SYSTIMER )
return NtUserDispatchMessage( (PMSG) lpmsg );
if (!NtUserValidateTimerCallback(lpmsg->lParam))
{
WARN("Validating Timer Callback failed!\n");
return 0;
}
_SEH2_TRY
{
Ret = WndProc(lpmsg->hwnd,
lpmsg->message,
lpmsg->wParam,
GetTickCount());
}
_SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
{
Hit = TRUE;
}
_SEH2_END;
}
else if (Wnd != NULL)
{
if ( (lpmsg->message != WM_PAINT) && !(Wnd->state & WNDS_SERVERSIDEWINDOWPROC) )
{
Ret = IntCallMessageProc(Wnd,
lpmsg->hwnd,
lpmsg->message,
lpmsg->wParam,
lpmsg->lParam,
FALSE);
}
else
Ret = NtUserDispatchMessage( (PMSG) lpmsg );
}
if (Hit)
{
WARN("Exception in Timer Callback WndProcW!\n");
}
return Ret;
}
static VOID
IntConvertMsgToAnsi(LPMSG lpMsg)
{
CHAR ch[2];
WCHAR wch[2];
switch (lpMsg->message)
{
case WM_CHAR:
case WM_DEADCHAR:
case WM_SYSCHAR:
case WM_SYSDEADCHAR:
case WM_MENUCHAR:
wch[0] = LOWORD(lpMsg->wParam);
wch[1] = HIWORD(lpMsg->wParam);
ch[0] = ch[1] = 0;
WideCharToMultiByte(CP_THREAD_ACP, 0, wch, 2, ch, 2, NULL, NULL);
lpMsg->wParam = MAKEWPARAM(ch[0] | (ch[1] << 8), 0);
break;
}
}
/*
* @implemented
*/
BOOL
WINAPI
DECLSPEC_HOTPATCH
GetMessageA(LPMSG lpMsg,
HWND hWnd,
UINT wMsgFilterMin,
UINT wMsgFilterMax)
{
BOOL Res;
if ( (wMsgFilterMin|wMsgFilterMax) & ~WM_MAXIMUM )
{
SetLastError( ERROR_INVALID_PARAMETER );
return FALSE;
}
Res = NtUserGetMessage(lpMsg, hWnd, wMsgFilterMin, wMsgFilterMax);
if (-1 == (int) Res)
{
return Res;
}
IntConvertMsgToAnsi(lpMsg);
return Res;
}
/*
* @implemented
*/
BOOL
WINAPI
DECLSPEC_HOTPATCH
GetMessageW(LPMSG lpMsg,
HWND hWnd,
UINT wMsgFilterMin,
UINT wMsgFilterMax)
{
BOOL Res;
if ( (wMsgFilterMin|wMsgFilterMax) & ~WM_MAXIMUM )
{
SetLastError( ERROR_INVALID_PARAMETER );
return FALSE;
}
Res = NtUserGetMessage(lpMsg, hWnd, wMsgFilterMin, wMsgFilterMax);
if (-1 == (int) Res)
{
return Res;
}
return Res;
}
BOOL WINAPI
PeekMessageWorker( PMSG pMsg,
HWND hWnd,
UINT wMsgFilterMin,
UINT wMsgFilterMax,
UINT wRemoveMsg)
{
PCLIENTINFO pci;
PCLIENTTHREADINFO pcti;
pci = GetWin32ClientInfo();
pcti = pci->pClientThreadInfo;
if (!hWnd && pci && pcti)
{
pci->cSpins++;
if ((pci->cSpins >= 100) && (pci->dwTIFlags & TIF_SPINNING))
{ // Yield after 100 spin cycles and ready to swap vinyl.
if (!(pci->dwTIFlags & TIF_WAITFORINPUTIDLE))
{ // Not waiting for idle event.
if (!pcti->fsChangeBits && !pcti->fsWakeBits)
{ // No messages are available.
[WIN32SS:USER] Some minimal work and fixes concerning message queues timeouts. CORE-15147 - Rename CLIENTTHREADINFO::tickLastMsgChecked into timeLastRead as documented in https://reactos.org/wiki/Techwiki:Win32k/CLIENTTHREADINFO . This is the last time the message queue was read. - This is the structure member one must compare against the current tick count timestamp in order to heuristically determine whether a message queue thread is hung!! Fix MsqIsHung() in accordance, add extra debug logging in order to help us determining which of our code present regular GUI hangs, and add as well an extra "TimeOut" parameter so as not to hardcode a fixed value within that function but instead allowing its caller to specify possible different values. - THREADINFO::timeLast is on the contrary the last message time stamp, and will definitively differ from CLIENTTHREADINFO::timeLastRead . It should only be used for information purposes! - Accordingly, in NtUserGetThreadState()::THREADSTATE_UPTIMELASTREAD and in InitThreadCallback(), only (re-)initialize the timeLastRead member of the CLIENTTHREADINFO structure of the THREADINFO of interest. - In co_IntPeekMessage(), update more often the timeLastRead timestamp whenever the current message queue has been read (but NOT timeLast!! That one will be updated ONLY WHEN a message is found!). - In co_IntSendMessageTimeoutSingle() first check whether the window to which we send the message is being destroyed, before checking for queue hangs etc. Collapse the logic checks for queue hang and increase the hang timeout check to 4 times MSQ_HUNG (== 4 * 5 seconds) and display a debug trace.
2019-12-29 14:10:19 +00:00
if ((GetTickCount() - pcti->timeLastRead) > 1000)
{ // Up the msg read count if over 1 sec.
NtUserGetThreadState(THREADSTATE_UPTIMELASTREAD);
}
pci->cSpins = 0;
ZwYieldExecution();
FIXME("seeSpins!\n");
return FALSE;
}
}
}
}
return NtUserPeekMessage(pMsg, hWnd, wMsgFilterMin, wMsgFilterMax, wRemoveMsg);
}
/*
* @implemented
*/
BOOL
WINAPI
DECLSPEC_HOTPATCH
PeekMessageA(LPMSG lpMsg,
HWND hWnd,
UINT wMsgFilterMin,
UINT wMsgFilterMax,
UINT wRemoveMsg)
{
BOOL Res;
Res = PeekMessageWorker(lpMsg, hWnd, wMsgFilterMin, wMsgFilterMax, wRemoveMsg);
if (-1 == (int) Res || !Res)
{
return FALSE;
}
IntConvertMsgToAnsi(lpMsg);
return Res;
}
/*
* @implemented
*/
BOOL
WINAPI
DECLSPEC_HOTPATCH
PeekMessageW(
LPMSG lpMsg,
HWND hWnd,
UINT wMsgFilterMin,
UINT wMsgFilterMax,
UINT wRemoveMsg)
{
BOOL Res;
Res = PeekMessageWorker(lpMsg, hWnd, wMsgFilterMin, wMsgFilterMax, wRemoveMsg);
if (-1 == (int) Res || !Res)
{
return FALSE;
}
return Res;
}
/*
* @implemented
*/
BOOL
WINAPI
PostMessageA(
HWND hWnd,
UINT Msg,
WPARAM wParam,
LPARAM lParam)
{
LRESULT Ret;
/* Check for combo box or a list box to send names. */
if (Msg == CB_DIR || Msg == LB_DIR)
{
/*
Set DDL_POSTMSGS, so use the PostMessage function to send messages to the
combo/list box. Forces a call like DlgDirListComboBox.
*/
//wParam |= DDL_POSTMSGS;
return NtUserPostMessage(hWnd, Msg, wParam, lParam);
}
/* No drop files or current Process, just post message. */
if ( (Msg != WM_DROPFILES) ||
( NtUserQueryWindow( hWnd, QUERY_WINDOW_UNIQUE_PROCESS_ID) ==
PtrToUint(NtCurrentTeb()->ClientId.UniqueProcess) ) )
{
return NtUserPostMessage(hWnd, Msg, wParam, lParam);
}
/* We have drop files and this is not the same process for this window. */
/* Just incase, check wParam for Global memory handle and send size. */
Ret = SendMessageA( hWnd,
WM_COPYGLOBALDATA,
(WPARAM)GlobalSize((HGLOBAL)wParam), // Zero if not a handle.
(LPARAM)wParam); // Send wParam as lParam.
if ( Ret ) return NtUserPostMessage(hWnd, Msg, (WPARAM)Ret, lParam);
return FALSE;
}
/*
* @implemented
*/
BOOL
WINAPI
PostMessageW(
HWND hWnd,
UINT Msg,
WPARAM wParam,
LPARAM lParam)
{
LRESULT Ret;
/* Check for combo box or a list box to send names. */
if (Msg == CB_DIR || Msg == LB_DIR)
{
/*
Set DDL_POSTMSGS, so use the PostMessage function to send messages to the
combo/list box. Forces a call like DlgDirListComboBox.
*/
//wParam |= DDL_POSTMSGS;
return NtUserPostMessage(hWnd, Msg, wParam, lParam);
}
/* No drop files or current Process, just post message. */
if ( (Msg != WM_DROPFILES) ||
( NtUserQueryWindow( hWnd, QUERY_WINDOW_UNIQUE_PROCESS_ID) ==
PtrToUint(NtCurrentTeb()->ClientId.UniqueProcess) ) )
{
return NtUserPostMessage(hWnd, Msg, wParam, lParam);
}
/* We have drop files and this is not the same process for this window. */
/* Just incase, check wParam for Global memory handle and send size. */
Ret = SendMessageW( hWnd,
WM_COPYGLOBALDATA,
(WPARAM)GlobalSize((HGLOBAL)wParam), // Zero if not a handle.
(LPARAM)wParam); // Send wParam as lParam.
if ( Ret ) return NtUserPostMessage(hWnd, Msg, (WPARAM)Ret, lParam);
return FALSE;
}
/*
* @implemented
*/
VOID
WINAPI
PostQuitMessage(
int nExitCode)
{
NtUserxPostQuitMessage(nExitCode);
}
/*
* @implemented
*/
BOOL
WINAPI
PostThreadMessageA(
DWORD idThread,
UINT Msg,
WPARAM wParam,
LPARAM lParam)
{
return NtUserPostThreadMessage(idThread, Msg, wParam, lParam);
}
/*
* @implemented
*/
BOOL
WINAPI
PostThreadMessageW(
DWORD idThread,
UINT Msg,
WPARAM wParam,
LPARAM lParam)
{
return NtUserPostThreadMessage(idThread, Msg, wParam, lParam);
}
/*
* @implemented
*/
LRESULT WINAPI
SendMessageW(HWND Wnd,
UINT Msg,
WPARAM wParam,
LPARAM lParam)
{
MSG UMMsg, KMMsg;
LRESULT Result;
BOOL Ret;
PWND Window;
PTHREADINFO ti = GetW32ThreadInfo();
if ( Msg & ~WM_MAXIMUM )
{
SetLastError( ERROR_INVALID_PARAMETER );
return 0;
}
if (Wnd != HWND_TOPMOST && Wnd != HWND_BROADCAST && (Msg < WM_DDE_FIRST || Msg > WM_DDE_LAST))
{
Window = ValidateHwnd(Wnd);
if ( Window != NULL &&
Window->head.pti == ti &&
!ISITHOOKED(WH_CALLWNDPROC) &&
!ISITHOOKED(WH_CALLWNDPROCRET) &&
!(Window->state & WNDS_SERVERSIDEWINDOWPROC) )
{
/* NOTE: We can directly send messages to the window procedure
if *all* the following conditions are met:
* Window belongs to calling thread
* The calling thread is not being hooked for CallWndProc
* Not calling a server side proc:
Desktop, Switch, ScrollBar, Menu, IconTitle, or hWndMessage
*/
return IntCallMessageProc(Window, Wnd, Msg, wParam, lParam, FALSE);
}
}
UMMsg.hwnd = Wnd;
UMMsg.message = Msg;
UMMsg.wParam = wParam;
UMMsg.lParam = lParam;
UMMsg.time = 0;
UMMsg.pt.x = 0;
UMMsg.pt.y = 0;
if (! MsgiUMToKMMessage(&UMMsg, &KMMsg, FALSE))
{
return FALSE;
}
Ret = NtUserMessageCall( Wnd,
KMMsg.message,
KMMsg.wParam,
KMMsg.lParam,
(ULONG_PTR)&Result,
FNID_SENDMESSAGE,
FALSE);
if (!Ret)
{
ERR("SendMessageW Error\n");
}
MsgiUMToKMCleanup(&UMMsg, &KMMsg);
return Result;
}
/*
* @implemented
*/
LRESULT WINAPI
SendMessageA(HWND Wnd, UINT Msg, WPARAM wParam, LPARAM lParam)
{
MSG AnsiMsg, UcMsg, KMMsg;
LRESULT Result;
BOOL Ret;
PWND Window;
PTHREADINFO ti = GetW32ThreadInfo();
if ( Msg & ~WM_MAXIMUM )
{
SetLastError( ERROR_INVALID_PARAMETER );
return 0;
}
if (Wnd != HWND_TOPMOST && Wnd != HWND_BROADCAST && (Msg < WM_DDE_FIRST || Msg > WM_DDE_LAST))
{
Window = ValidateHwnd(Wnd);
if ( Window != NULL &&
Window->head.pti == ti &&
!ISITHOOKED(WH_CALLWNDPROC) &&
!ISITHOOKED(WH_CALLWNDPROCRET) &&
!(Window->state & WNDS_SERVERSIDEWINDOWPROC) )
{
/* NOTE: We can directly send messages to the window procedure
if *all* the following conditions are met:
* Window belongs to calling thread
* The calling thread is not being hooked for CallWndProc
* Not calling a server side proc:
Desktop, Switch, ScrollBar, Menu, IconTitle, or hWndMessage
*/
return IntCallMessageProc(Window, Wnd, Msg, wParam, lParam, TRUE);
}
}
AnsiMsg.hwnd = Wnd;
AnsiMsg.message = Msg;
AnsiMsg.wParam = wParam;
AnsiMsg.lParam = lParam;
AnsiMsg.time = 0;
AnsiMsg.pt.x = 0;
AnsiMsg.pt.y = 0;
if (!MsgiAnsiToUnicodeMessage(Wnd, &UcMsg, &AnsiMsg))
{
return FALSE;
}
if (!MsgiUMToKMMessage(&UcMsg, &KMMsg, FALSE))
{
MsgiAnsiToUnicodeCleanup(&UcMsg, &AnsiMsg);
return FALSE;
}
Ret = NtUserMessageCall( Wnd,
KMMsg.message,
KMMsg.wParam,
KMMsg.lParam,
(ULONG_PTR)&Result,
FNID_SENDMESSAGE,
TRUE);
if (!Ret)
{
ERR("SendMessageA Error\n");
}
MsgiUMToKMCleanup(&UcMsg, &KMMsg);
MsgiAnsiToUnicodeReply(&UcMsg, &AnsiMsg, &Result);
return Result;
}
/*
* @implemented
*/
BOOL
WINAPI
SendMessageCallbackA(
HWND hWnd,
UINT Msg,
WPARAM wParam,
LPARAM lParam,
SENDASYNCPROC lpCallBack,
ULONG_PTR dwData)
{
BOOL Result;
MSG AnsiMsg, UcMsg;
CALL_BACK_INFO CallBackInfo;
if (is_pointer_message(Msg, wParam))
{
SetLastError( ERROR_MESSAGE_SYNC_ONLY );
return FALSE;
}
CallBackInfo.CallBack = lpCallBack;
CallBackInfo.Context = dwData;
AnsiMsg.hwnd = hWnd;
AnsiMsg.message = Msg;
AnsiMsg.wParam = wParam;
AnsiMsg.lParam = lParam;
AnsiMsg.time = 0;
AnsiMsg.pt.x = 0;
AnsiMsg.pt.y = 0;
if (!MsgiAnsiToUnicodeMessage(hWnd, &UcMsg, &AnsiMsg))
{
return FALSE;
}
Result = NtUserMessageCall( hWnd,
UcMsg.message,
UcMsg.wParam,
UcMsg.lParam,
(ULONG_PTR)&CallBackInfo,
FNID_SENDMESSAGECALLBACK,
TRUE);
MsgiAnsiToUnicodeCleanup(&UcMsg, &AnsiMsg);
return Result;
}
/*
* @implemented
*/
BOOL
WINAPI
SendMessageCallbackW(
HWND hWnd,
UINT Msg,
WPARAM wParam,
LPARAM lParam,
SENDASYNCPROC lpCallBack,
ULONG_PTR dwData)
{
CALL_BACK_INFO CallBackInfo;
if (is_pointer_message(Msg, wParam))
{
SetLastError( ERROR_MESSAGE_SYNC_ONLY );
return FALSE;
}
CallBackInfo.CallBack = lpCallBack;
CallBackInfo.Context = dwData;
return NtUserMessageCall(hWnd,
Msg,
wParam,
lParam,
(ULONG_PTR)&CallBackInfo,
FNID_SENDMESSAGECALLBACK,
FALSE);
}
/*
* @implemented
*/
LRESULT
WINAPI
SendMessageTimeoutA(
HWND hWnd,
UINT Msg,
WPARAM wParam,
LPARAM lParam,
UINT fuFlags,
UINT uTimeout,
PDWORD_PTR lpdwResult)
{
MSG AnsiMsg, UcMsg, KMMsg;
LRESULT Result;
DOSENDMESSAGE dsm;
if ( Msg & ~WM_MAXIMUM || fuFlags & ~(SMTO_NOTIMEOUTIFNOTHUNG|SMTO_ABORTIFHUNG|SMTO_BLOCK))
{
SetLastError( ERROR_INVALID_PARAMETER );
return 0;
}
if (lpdwResult) *lpdwResult = 0;
SPY_EnterMessage(SPY_SENDMESSAGE, hWnd, Msg, wParam, lParam);
dsm.uFlags = fuFlags;
dsm.uTimeout = uTimeout;
dsm.Result = 0;
AnsiMsg.hwnd = hWnd;
AnsiMsg.message = Msg;
AnsiMsg.wParam = wParam;
AnsiMsg.lParam = lParam;
AnsiMsg.time = 0;
AnsiMsg.pt.x = 0;
AnsiMsg.pt.y = 0;
if (! MsgiAnsiToUnicodeMessage(hWnd, &UcMsg, &AnsiMsg))
{
return FALSE;
}
if (!MsgiUMToKMMessage(&UcMsg, &KMMsg, FALSE))
{
MsgiAnsiToUnicodeCleanup(&UcMsg, &AnsiMsg);
return FALSE;
}
Result = NtUserMessageCall( hWnd,
KMMsg.message,
KMMsg.wParam,
KMMsg.lParam,
(ULONG_PTR)&dsm,
FNID_SENDMESSAGEWTOOPTION,
TRUE);
MsgiUMToKMCleanup(&UcMsg, &KMMsg);
MsgiAnsiToUnicodeReply(&UcMsg, &AnsiMsg, &Result);
if (lpdwResult) *lpdwResult = dsm.Result;
SPY_ExitMessage(SPY_RESULT_OK, hWnd, Msg, Result, wParam, lParam);
return Result;
}
/*
* @implemented
*/
LRESULT
WINAPI
SendMessageTimeoutW(
HWND hWnd,
UINT Msg,
WPARAM wParam,
LPARAM lParam,
UINT fuFlags,
UINT uTimeout,
PDWORD_PTR lpdwResult)
{
LRESULT Result;
DOSENDMESSAGE dsm;
MSG UMMsg, KMMsg;
if ( Msg & ~WM_MAXIMUM || fuFlags & ~(SMTO_NOTIMEOUTIFNOTHUNG|SMTO_ABORTIFHUNG|SMTO_BLOCK))
{
SetLastError( ERROR_INVALID_PARAMETER );
return 0;
}
if (lpdwResult) *lpdwResult = 0;
SPY_EnterMessage(SPY_SENDMESSAGE, hWnd, Msg, wParam, lParam);
dsm.uFlags = fuFlags;
dsm.uTimeout = uTimeout;
dsm.Result = 0;
UMMsg.hwnd = hWnd;
UMMsg.message = Msg;
UMMsg.wParam = wParam;
UMMsg.lParam = lParam;
UMMsg.time = 0;
UMMsg.pt.x = 0;
UMMsg.pt.y = 0;
if (! MsgiUMToKMMessage(&UMMsg, &KMMsg, TRUE))
{
return FALSE;
}
Result = NtUserMessageCall( hWnd,
KMMsg.message,
KMMsg.wParam,
KMMsg.lParam,
(ULONG_PTR)&dsm,
FNID_SENDMESSAGEWTOOPTION,
FALSE);
MsgiUMToKMCleanup(&UMMsg, &KMMsg);
if (lpdwResult) *lpdwResult = dsm.Result;
SPY_ExitMessage(SPY_RESULT_OK, hWnd, Msg, Result, wParam, lParam);
return Result;
}
/*
* @implemented
*/
BOOL
WINAPI
SendNotifyMessageA(
HWND hWnd,
UINT Msg,
WPARAM wParam,
LPARAM lParam)
{
BOOL Ret;
MSG AnsiMsg, UcMsg;
if (is_pointer_message(Msg, wParam))
{
SetLastError( ERROR_MESSAGE_SYNC_ONLY );
return FALSE;
}
AnsiMsg.hwnd = hWnd;
AnsiMsg.message = Msg;
AnsiMsg.wParam = wParam;
AnsiMsg.lParam = lParam;
AnsiMsg.time = 0;
AnsiMsg.pt.x = 0;
AnsiMsg.pt.y = 0;
if (! MsgiAnsiToUnicodeMessage(hWnd, &UcMsg, &AnsiMsg))
{
return FALSE;
}
Ret = SendNotifyMessageW(hWnd, UcMsg.message, UcMsg.wParam, UcMsg.lParam);
MsgiAnsiToUnicodeCleanup(&UcMsg, &AnsiMsg);
return Ret;
}
/*
* @implemented
*/
BOOL
WINAPI
SendNotifyMessageW(
HWND hWnd,
UINT Msg,
WPARAM wParam,
LPARAM lParam)
{
LRESULT Result;
if (is_pointer_message(Msg, wParam))
{
SetLastError( ERROR_MESSAGE_SYNC_ONLY );
return FALSE;
}
Result = NtUserMessageCall( hWnd,
Msg,
wParam,
lParam,
0,
FNID_SENDNOTIFYMESSAGE,
FALSE);
return Result;
}
/*
* @implemented
*/
BOOL WINAPI
TranslateMessageEx(CONST MSG *lpMsg, UINT Flags)
{
switch (lpMsg->message)
{
case WM_KEYDOWN:
case WM_KEYUP:
case WM_SYSKEYDOWN:
case WM_SYSKEYUP:
return(NtUserTranslateMessage((LPMSG)lpMsg, Flags));
default:
if ( lpMsg->message & ~WM_MAXIMUM )
SetLastError(ERROR_INVALID_PARAMETER);
return FALSE;
}
}
/*
* @implemented
*/
BOOL WINAPI
TranslateMessage(CONST MSG *lpMsg)
{
BOOL ret;
// http://msdn.microsoft.com/en-us/library/aa912145.aspx
if (LOWORD(lpMsg->wParam) == VK_PROCESSKEY)
{
ret = IMM_FN(ImmTranslateMessage)(lpMsg->hwnd,
lpMsg->message,
lpMsg->wParam,
lpMsg->lParam);
if (ret)
return ret;
}
ret = TranslateMessageEx((LPMSG)lpMsg, 0);
return ret;
}
/*
* @implemented
*/
UINT WINAPI
RegisterWindowMessageA(LPCSTR lpString)
{
UNICODE_STRING String;
UINT Atom;
if (!RtlCreateUnicodeStringFromAsciiz(&String, (PCSZ)lpString))
{
return(0);
}
Atom = NtUserRegisterWindowMessage(&String);
RtlFreeUnicodeString(&String);
return(Atom);
}
/*
* @implemented
*/
UINT WINAPI
RegisterWindowMessageW(LPCWSTR lpString)
{
UNICODE_STRING String;
RtlInitUnicodeString(&String, lpString);
return(NtUserRegisterWindowMessage(&String));
}
/*
* @implemented
*/
HWND WINAPI
GetCapture(VOID)
{
return (HWND)NtUserGetThreadState(THREADSTATE_CAPTUREWINDOW);
}
/*
* @implemented
*/
BOOL WINAPI
ReleaseCapture(VOID)
{
return NtUserxReleaseCapture();
}
/*
* @implemented
*/
DWORD
WINAPI
RealGetQueueStatus(UINT flags)
{
2021-11-19 23:45:35 +00:00
if (flags & ~(QS_ALLINPUT|QS_ALLPOSTMESSAGE|QS_SMRESULT))
{
SetLastError( ERROR_INVALID_FLAGS );
return 0;
}
2021-11-19 23:45:35 +00:00
/** ATM, we do not support QS_RAWINPUT, but we need to support apps that pass
** this flag along, while also working around QS_RAWINPUT checks in winetests.
** Just set the last error to ERROR_INVALID_FLAGS but do not fail the call.
**/
if (flags & QS_RAWINPUT)
{
SetLastError(ERROR_INVALID_FLAGS);
flags &= ~QS_RAWINPUT;
}
/**/
return NtUserxGetQueueStatus(flags);
}
/*
* @implemented
*/
BOOL WINAPI GetInputState(VOID)
{
PCLIENTTHREADINFO pcti = GetWin32ClientInfo()->pClientThreadInfo;
if ((!pcti) || (pcti->fsChangeBits & (QS_KEY|QS_MOUSEBUTTON)))
return (BOOL)NtUserGetThreadState(THREADSTATE_GETINPUTSTATE);
return FALSE;
}
NTSTATUS WINAPI
User32CallWindowProcFromKernel(PVOID Arguments, ULONG ArgumentLength)
{
PWINDOWPROC_CALLBACK_ARGUMENTS CallbackArgs;
MSG KMMsg, UMMsg;
PWND pWnd = NULL;
PCLIENTINFO pci = GetWin32ClientInfo();
/* Make sure we don't try to access mem beyond what we were given */
if (ArgumentLength < sizeof(WINDOWPROC_CALLBACK_ARGUMENTS))
{
return STATUS_INFO_LENGTH_MISMATCH;
}
CallbackArgs = (PWINDOWPROC_CALLBACK_ARGUMENTS) Arguments;
KMMsg.hwnd = CallbackArgs->Wnd;
KMMsg.message = CallbackArgs->Msg;
KMMsg.wParam = CallbackArgs->wParam;
KMMsg.time = 0;
KMMsg.pt.x = 0;
KMMsg.pt.y = 0;
/* Check if lParam is really a pointer and adjust it if it is */
if (0 <= CallbackArgs->lParamBufferSize)
{
if (ArgumentLength != sizeof(WINDOWPROC_CALLBACK_ARGUMENTS)
+ CallbackArgs->lParamBufferSize)
{
return STATUS_INFO_LENGTH_MISMATCH;
}
KMMsg.lParam = (LPARAM) ((char *) CallbackArgs + sizeof(WINDOWPROC_CALLBACK_ARGUMENTS));
switch(KMMsg.message)
{
case WM_CREATE:
{
TRACE("WM_CREATE CB %p lParam %p\n",CallbackArgs, KMMsg.lParam);
break;
}
case WM_NCCREATE:
{
TRACE("WM_NCCREATE CB %p lParam %p\n",CallbackArgs, KMMsg.lParam);
break;
}
case WM_SYSTIMER:
{
TRACE("WM_SYSTIMER %p\n",KMMsg.hwnd);
break;
}
case WM_SIZING:
{
PRECT prect = (PRECT) KMMsg.lParam;
TRACE("WM_SIZING 1 t %d l %d r %d b %d\n",prect->top,prect->left,prect->right,prect->bottom);
break;
}
default:
break;
}
}
else
{
if (ArgumentLength != sizeof(WINDOWPROC_CALLBACK_ARGUMENTS))
{
return STATUS_INFO_LENGTH_MISMATCH;
}
KMMsg.lParam = CallbackArgs->lParam;
}
if (WM_NCCALCSIZE == CallbackArgs->Msg && CallbackArgs->wParam)
{
NCCALCSIZE_PARAMS *Params = (NCCALCSIZE_PARAMS *) KMMsg.lParam;
Params->lppos = (PWINDOWPOS) (Params + 1);
}
if (! MsgiKMToUMMessage(&KMMsg, &UMMsg))
{
}
if (pci->CallbackWnd.hWnd == UMMsg.hwnd)
pWnd = pci->CallbackWnd.pWnd;
CallbackArgs->Result = IntCallWindowProcW( CallbackArgs->IsAnsiProc,
CallbackArgs->Proc,
pWnd,
UMMsg.hwnd,
UMMsg.message,
UMMsg.wParam,
UMMsg.lParam);
if (! MsgiKMToUMReply(&KMMsg, &UMMsg, &CallbackArgs->Result))
{
}
if (0 <= CallbackArgs->lParamBufferSize)
{
switch(KMMsg.message)
{
case WM_SIZING:
{
PRECT prect = (PRECT) KMMsg.lParam;
TRACE("WM_SIZING 2 t %d l %d r %d b %d\n",prect->top,prect->left,prect->right,prect->bottom);
break;
}
default:
break;
}
}
return ZwCallbackReturn(CallbackArgs, ArgumentLength, STATUS_SUCCESS);
}
/*
* @implemented
*/
BOOL WINAPI SetMessageQueue(int cMessagesMax)
{
/* Function does nothing on 32 bit windows */
return TRUE;
}
typedef DWORD (WINAPI * RealGetQueueStatusProc)(UINT flags);
typedef DWORD (WINAPI * RealMsgWaitForMultipleObjectsExProc)(DWORD nCount, CONST HANDLE *lpHandles, DWORD dwMilliseconds, DWORD dwWakeMask, DWORD dwFlags);
typedef BOOL (WINAPI * RealInternalGetMessageProc)(LPMSG,HWND,UINT,UINT,UINT,BOOL);
typedef BOOL (WINAPI * RealWaitMessageExProc)(DWORD,UINT);
typedef struct _USER_MESSAGE_PUMP_ADDRESSES {
DWORD cbSize;
RealInternalGetMessageProc NtUserRealInternalGetMessage;
RealWaitMessageExProc NtUserRealWaitMessageEx;
RealGetQueueStatusProc RealGetQueueStatus;
RealMsgWaitForMultipleObjectsExProc RealMsgWaitForMultipleObjectsEx;
} USER_MESSAGE_PUMP_ADDRESSES, * PUSER_MESSAGE_PUMP_ADDRESSES;
DWORD
WINAPI
RealMsgWaitForMultipleObjectsEx(
DWORD nCount,
CONST HANDLE *pHandles,
DWORD dwMilliseconds,
DWORD dwWakeMask,
DWORD dwFlags);
typedef BOOL (WINAPI * MESSAGEPUMPHOOKPROC)(BOOL Unregistering,PUSER_MESSAGE_PUMP_ADDRESSES MessagePumpAddresses);
CRITICAL_SECTION gcsMPH;
MESSAGEPUMPHOOKPROC gpfnInitMPH;
DWORD gcLoadMPH = 0;
USER_MESSAGE_PUMP_ADDRESSES gmph = {sizeof(USER_MESSAGE_PUMP_ADDRESSES),
NtUserRealInternalGetMessage,
NtUserRealWaitMessageEx,
RealGetQueueStatus,
RealMsgWaitForMultipleObjectsEx
};
DWORD gfMessagePumpHook = 0;
BOOL WINAPI IsInsideMessagePumpHook()
{ // FF uses this and polls it when Min/Max
PCLIENTTHREADINFO pcti = GetWin32ClientInfo()->pClientThreadInfo;
return (gfMessagePumpHook && pcti && (pcti->dwcPumpHook > 0));
}
void WINAPI ResetMessagePumpHook(PUSER_MESSAGE_PUMP_ADDRESSES Addresses)
{
Addresses->cbSize = sizeof(USER_MESSAGE_PUMP_ADDRESSES);
Addresses->NtUserRealInternalGetMessage = NtUserRealInternalGetMessage;
Addresses->NtUserRealWaitMessageEx = NtUserRealWaitMessageEx;
Addresses->RealGetQueueStatus = RealGetQueueStatus;
Addresses->RealMsgWaitForMultipleObjectsEx = RealMsgWaitForMultipleObjectsEx;
}
BOOL WINAPI RegisterMessagePumpHook(MESSAGEPUMPHOOKPROC Hook)
{
EnterCriticalSection(&gcsMPH);
if(!Hook) {
SetLastError(ERROR_INVALID_PARAMETER);
LeaveCriticalSection(&gcsMPH);
return FALSE;
}
if(!gcLoadMPH) {
USER_MESSAGE_PUMP_ADDRESSES Addresses;
gpfnInitMPH = Hook;
ResetMessagePumpHook(&Addresses);
if(!Hook(FALSE, &Addresses) || !Addresses.cbSize) {
LeaveCriticalSection(&gcsMPH);
return FALSE;
}
memcpy(&gmph, &Addresses, Addresses.cbSize);
} else {
if(gpfnInitMPH != Hook) {
LeaveCriticalSection(&gcsMPH);
return FALSE;
}
}
if(NtUserxInitMessagePump()) {
LeaveCriticalSection(&gcsMPH);
return FALSE;
}
if (!gcLoadMPH++) {
InterlockedExchange((PLONG)&gfMessagePumpHook, 1);
}
LeaveCriticalSection(&gcsMPH);
return TRUE;
}
BOOL WINAPI UnregisterMessagePumpHook(VOID)
{
EnterCriticalSection(&gcsMPH);
if(gcLoadMPH > 0) {
if(NtUserxUnInitMessagePump()) {
gcLoadMPH--;
if(!gcLoadMPH) {
InterlockedExchange((PLONG)&gfMessagePumpHook, 0);
gpfnInitMPH(TRUE, NULL);
ResetMessagePumpHook(&gmph);
gpfnInitMPH = 0;
}
LeaveCriticalSection(&gcsMPH);
return TRUE;
}
}
LeaveCriticalSection(&gcsMPH);
return FALSE;
}
DWORD WINAPI GetQueueStatus(UINT flags)
{
return IsInsideMessagePumpHook() ? gmph.RealGetQueueStatus(flags) : RealGetQueueStatus(flags);
}
/**
* @name RealMsgWaitForMultipleObjectsEx
*
* Wait either for either message arrival or for one of the passed events
* to be signalled.
*
* @param nCount
* Number of handles in the pHandles array.
* @param pHandles
* Handles of events to wait for.
* @param dwMilliseconds
* Timeout interval.
* @param dwWakeMask
* Mask specifying on which message events we should wakeup.
* @param dwFlags
* Wait type (see MWMO_* constants).
*
* @implemented
*/
DWORD WINAPI
RealMsgWaitForMultipleObjectsEx(
DWORD nCount,
const HANDLE *pHandles,
DWORD dwMilliseconds,
DWORD dwWakeMask,
DWORD dwFlags)
{
LPHANDLE RealHandles;
HANDLE MessageQueueHandle;
DWORD Result;
PCLIENTINFO pci;
PCLIENTTHREADINFO pcti;
if (dwFlags & ~(MWMO_WAITALL | MWMO_ALERTABLE | MWMO_INPUTAVAILABLE))
{
SetLastError(ERROR_INVALID_PARAMETER);
return WAIT_FAILED;
}
pci = GetWin32ClientInfo();
if (!pci) return WAIT_FAILED;
pcti = pci->pClientThreadInfo;
if (pcti && ( !nCount || !(dwFlags & MWMO_WAITALL) ))
{
if ( (pcti->fsChangeBits & LOWORD(dwWakeMask)) ||
( (dwFlags & MWMO_INPUTAVAILABLE) && (pcti->fsWakeBits & LOWORD(dwWakeMask)) ) )
{
//FIXME("Return Chg 0x%x Wake 0x%x Mask 0x%x nCnt %d\n",pcti->fsChangeBits, pcti->fsWakeBits, dwWakeMask, nCount);
return nCount;
}
}
MessageQueueHandle = NtUserxMsqSetWakeMask(MAKELONG(dwWakeMask, dwFlags));
if (MessageQueueHandle == NULL)
{
SetLastError(0); /* ? */
return WAIT_FAILED;
}
RealHandles = HeapAlloc(GetProcessHeap(), 0, (nCount + 1) * sizeof(HANDLE));
if (RealHandles == NULL)
{
NtUserxMsqClearWakeMask();
SetLastError(ERROR_NOT_ENOUGH_MEMORY);
return WAIT_FAILED;
}
RtlCopyMemory(RealHandles, pHandles, nCount * sizeof(HANDLE));
RealHandles[nCount] = MessageQueueHandle;
//FIXME("1 Chg 0x%x Wake 0x%x Mask 0x%x nCnt %d\n",pcti->fsChangeBits, pcti->fsWakeBits, dwWakeMask, nCount);
Result = WaitForMultipleObjectsEx( nCount + 1,
RealHandles,
dwFlags & MWMO_WAITALL,
dwMilliseconds,
dwFlags & MWMO_ALERTABLE );
//FIXME("2 Chg 0x%x Wake 0x%x Mask 0x%x nCnt %d\n",pcti->fsChangeBits, pcti->fsWakeBits, dwWakeMask, nCount);
HeapFree(GetProcessHeap(), 0, RealHandles);
NtUserxMsqClearWakeMask();
// wine hack! MSDN: If dwMilliseconds is zero,,specified objects are not signaled; it always returns immediately.
if (!Result && !nCount && !dwMilliseconds) Result = WAIT_TIMEOUT;
//FIXME("Result 0X%x\n",Result);
return Result;
}
/*
* @implemented
*/
DWORD WINAPI
MsgWaitForMultipleObjectsEx(
DWORD nCount,
CONST HANDLE *lpHandles,
DWORD dwMilliseconds,
DWORD dwWakeMask,
DWORD dwFlags)
{
return IsInsideMessagePumpHook() ? gmph.RealMsgWaitForMultipleObjectsEx(nCount, lpHandles, dwMilliseconds, dwWakeMask, dwFlags) : RealMsgWaitForMultipleObjectsEx(nCount, lpHandles,dwMilliseconds, dwWakeMask, dwFlags);
}
/*
* @implemented
*/
DWORD WINAPI
MsgWaitForMultipleObjects(
DWORD nCount,
CONST HANDLE *lpHandles,
BOOL fWaitAll,
DWORD dwMilliseconds,
DWORD dwWakeMask)
{
return MsgWaitForMultipleObjectsEx(nCount, lpHandles, dwMilliseconds,
dwWakeMask, fWaitAll ? MWMO_WAITALL : 0);
}
BOOL FASTCALL MessageInit(VOID)
{
InitializeCriticalSection(&DdeCrst);
InitializeCriticalSection(&gcsMPH);
return TRUE;
}
VOID FASTCALL MessageCleanup(VOID)
{
DeleteCriticalSection(&DdeCrst);
DeleteCriticalSection(&gcsMPH);
}
/*
* @implemented
*/
BOOL WINAPI
IsDialogMessageA( HWND hwndDlg, LPMSG pmsg )
{
MSG msg = *pmsg;
msg.wParam = map_wparam_AtoW( msg.message, msg.wParam );
return IsDialogMessageW( hwndDlg, &msg );
}
LONG
WINAPI
IntBroadcastSystemMessage(
DWORD dwflags,
LPDWORD lpdwRecipients,
UINT uiMessage,
WPARAM wParam,
LPARAM lParam,
PBSMINFO pBSMInfo,
BOOL Ansi)
{
BROADCASTPARM parm;
DWORD recips = BSM_ALLCOMPONENTS;
BOOL ret = -1; // Set to return fail
static const DWORD all_flags = ( BSF_QUERY | BSF_IGNORECURRENTTASK | BSF_FLUSHDISK | BSF_NOHANG
| BSF_POSTMESSAGE | BSF_FORCEIFHUNG | BSF_NOTIMEOUTIFNOTHUNG
| BSF_ALLOWSFW | BSF_SENDNOTIFYMESSAGE | BSF_RETURNHDESK | BSF_LUID );
if ((dwflags & ~all_flags) ||
(!pBSMInfo && (dwflags & (BSF_RETURNHDESK|BSF_LUID))) )
{
SetLastError(ERROR_INVALID_PARAMETER);
return 0;
}
if(uiMessage >= WM_USER && uiMessage < 0xC000)
{
SetLastError(ERROR_INVALID_PARAMETER);
return 0;
}
if (dwflags & BSF_FORCEIFHUNG) dwflags |= BSF_NOHANG;
if (dwflags & BSF_QUERY) dwflags &= ~BSF_SENDNOTIFYMESSAGE|BSF_POSTMESSAGE;
if (!lpdwRecipients)
lpdwRecipients = &recips;
if (*lpdwRecipients & ~(BSM_APPLICATIONS|BSM_ALLDESKTOPS|BSM_INSTALLABLEDRIVERS|BSM_NETDRIVER|BSM_VXDS))
{
SetLastError(ERROR_INVALID_PARAMETER);
return 0;
}
if ( pBSMInfo && (dwflags & BSF_QUERY) )
{
if (pBSMInfo->cbSize != sizeof(BSMINFO))
{
SetLastError(ERROR_INVALID_PARAMETER);
return 0;
}
}
parm.hDesk = NULL;
parm.hWnd = NULL;
parm.flags = dwflags;
parm.recipients = *lpdwRecipients;
if (dwflags & BSF_LUID) parm.luid = pBSMInfo->luid;
ret = NtUserMessageCall(GetDesktopWindow(),
uiMessage,
wParam,
lParam,
(ULONG_PTR)&parm,
FNID_BROADCASTSYSTEMMESSAGE,
Ansi);
if (!ret)
{
if ( pBSMInfo && (dwflags & BSF_QUERY) )
{
pBSMInfo->hdesk = parm.hDesk;
pBSMInfo->hwnd = parm.hWnd;
}
}
return ret;
}
/*
* @implemented
*/
LONG
WINAPI
BroadcastSystemMessageA(
DWORD dwFlags,
LPDWORD lpdwRecipients,
UINT uiMessage,
WPARAM wParam,
LPARAM lParam)
{
return IntBroadcastSystemMessage( dwFlags, lpdwRecipients, uiMessage, wParam, lParam, NULL, TRUE );
}
/*
* @implemented
*/
LONG
WINAPI
BroadcastSystemMessageW(
DWORD dwFlags,
LPDWORD lpdwRecipients,
UINT uiMessage,
WPARAM wParam,
LPARAM lParam)
{
return IntBroadcastSystemMessage( dwFlags, lpdwRecipients, uiMessage, wParam, lParam, NULL, FALSE );
}
/*
* @implemented
*/
LONG
WINAPI
BroadcastSystemMessageExA(
DWORD dwflags,
LPDWORD lpdwRecipients,
UINT uiMessage,
WPARAM wParam,
LPARAM lParam,
PBSMINFO pBSMInfo)
{
return IntBroadcastSystemMessage( dwflags, lpdwRecipients, uiMessage, wParam, lParam , pBSMInfo, TRUE );
}
/*
* @implemented
*/
LONG
WINAPI
BroadcastSystemMessageExW(
DWORD dwflags,
LPDWORD lpdwRecipients,
UINT uiMessage,
WPARAM wParam,
LPARAM lParam,
PBSMINFO pBSMInfo)
{
return IntBroadcastSystemMessage( dwflags, lpdwRecipients, uiMessage, wParam, lParam , pBSMInfo, FALSE );
}