mirror of
https://github.com/reactos/reactos.git
synced 2024-11-01 04:11:30 +00:00
477 lines
11 KiB
C
477 lines
11 KiB
C
/*
|
|
* COPYRIGHT: See COPYING in the top level directory
|
|
* PROJECT: ReactOS Win32k subsystem
|
|
* PURPOSE: Dynamic Data Exchange
|
|
* FILE: win32ss/user/ntuser/dde.c
|
|
* PROGRAMER:
|
|
*/
|
|
|
|
#include <win32k.h>
|
|
|
|
#include <dde.h>
|
|
|
|
DBG_DEFAULT_CHANNEL(UserMisc);
|
|
|
|
//
|
|
// Default information used to support client impersonation.
|
|
//
|
|
SECURITY_QUALITY_OF_SERVICE gqosDefault = {sizeof(SECURITY_QUALITY_OF_SERVICE),SecurityImpersonation,SECURITY_STATIC_TRACKING,TRUE};
|
|
|
|
typedef struct _DDEIMP
|
|
{
|
|
SECURITY_QUALITY_OF_SERVICE qos;
|
|
SECURITY_CLIENT_CONTEXT ClientContext;
|
|
WORD cRefInit;
|
|
WORD cRefConv;
|
|
} DDEIMP, *PDDEIMP;
|
|
|
|
typedef struct _DDE_DATA
|
|
{
|
|
LPARAM lParam;
|
|
int cbSize;
|
|
PVOID pvBuffer;
|
|
} DDE_DATA, *PDDE_DATA;
|
|
|
|
typedef struct _DDE_PROP
|
|
{
|
|
PWND spwnd;
|
|
PWND spwndPartner;
|
|
PDDEIMP pddei;
|
|
} DDE_PROP, *PDDE_PROP;
|
|
|
|
|
|
//
|
|
// DDE Posting message callback to user side.
|
|
//
|
|
int
|
|
APIENTRY
|
|
IntDDEPostCallback(
|
|
IN PWND pWnd,
|
|
IN UINT Msg,
|
|
IN WPARAM wParam,
|
|
IN OUT LPARAM *lParam,
|
|
IN OUT PVOID *Buffer)
|
|
{
|
|
NTSTATUS Status;
|
|
ULONG ArgumentLength, ResultLength;
|
|
PVOID Argument, ResultPointer;
|
|
PDDEPOSTGET_CALLBACK_ARGUMENTS Common;
|
|
int size = 0;
|
|
ResultPointer = NULL;
|
|
ResultLength = ArgumentLength = sizeof(DDEPOSTGET_CALLBACK_ARGUMENTS);
|
|
|
|
Argument = IntCbAllocateMemory(ArgumentLength);
|
|
if (NULL == Argument)
|
|
{
|
|
return FALSE;
|
|
}
|
|
|
|
Common = (PDDEPOSTGET_CALLBACK_ARGUMENTS) Argument;
|
|
|
|
Common->pvData = 0;
|
|
Common->size = 0;
|
|
Common->hwnd = UserHMGetHandle(pWnd);
|
|
Common->message = Msg;
|
|
Common->wParam = wParam;
|
|
Common->lParam = *lParam;
|
|
|
|
UserLeaveCo();
|
|
|
|
Status = KeUserModeCallback(USER32_CALLBACK_DDEPOST,
|
|
Argument,
|
|
ArgumentLength,
|
|
&ResultPointer,
|
|
&ResultLength);
|
|
|
|
UserEnterCo();
|
|
|
|
if (!NT_SUCCESS(Status) || ResultPointer == NULL )
|
|
{
|
|
ERR("DDE Post callback failed!\n");
|
|
IntCbFreeMemory(Argument);
|
|
return 0;
|
|
}
|
|
|
|
RtlCopyMemory(Common, ResultPointer, ArgumentLength);
|
|
|
|
size = Common->size;
|
|
*lParam = Common->lParam;
|
|
*Buffer = Common->pvData;
|
|
|
|
IntCbFreeMemory(Argument);
|
|
|
|
return size ? size : -1;
|
|
}
|
|
|
|
//
|
|
// DDE Get/Peek message callback to user side.
|
|
//
|
|
BOOL
|
|
APIENTRY
|
|
IntDDEGetCallback(
|
|
IN PWND pWnd,
|
|
IN OUT PMSG pMsg,
|
|
IN PVOID Buffer,
|
|
IN int size)
|
|
{
|
|
NTSTATUS Status;
|
|
ULONG ArgumentLength, ResultLength;
|
|
PVOID Argument, ResultPointer;
|
|
PDDEPOSTGET_CALLBACK_ARGUMENTS Common;
|
|
|
|
ResultPointer = NULL;
|
|
ResultLength = ArgumentLength = sizeof(DDEPOSTGET_CALLBACK_ARGUMENTS)+size;
|
|
|
|
Argument = IntCbAllocateMemory(ArgumentLength);
|
|
if (NULL == Argument)
|
|
{
|
|
return FALSE;
|
|
}
|
|
|
|
Common = (PDDEPOSTGET_CALLBACK_ARGUMENTS) Argument;
|
|
|
|
Common->size = size;
|
|
Common->hwnd = pMsg->hwnd;
|
|
Common->message = pMsg->message;
|
|
Common->wParam = pMsg->wParam;
|
|
Common->lParam = pMsg->lParam;
|
|
|
|
if (size && Buffer) RtlCopyMemory(&Common->buffer, Buffer, size);
|
|
|
|
UserLeaveCo();
|
|
|
|
Status = KeUserModeCallback(USER32_CALLBACK_DDEGET,
|
|
Argument,
|
|
ArgumentLength,
|
|
&ResultPointer,
|
|
&ResultLength);
|
|
|
|
UserEnterCo();
|
|
|
|
if (!NT_SUCCESS(Status) || ResultPointer == NULL )
|
|
{
|
|
ERR("DDE Get callback failed!\n");
|
|
IntCbFreeMemory(Argument);
|
|
return FALSE;
|
|
}
|
|
|
|
RtlMoveMemory(Common, ResultPointer, ArgumentLength);
|
|
|
|
pMsg->lParam = Common->lParam;
|
|
|
|
IntCbFreeMemory(Argument);
|
|
|
|
return TRUE;
|
|
}
|
|
|
|
//
|
|
// DDE Post message hook, intercept DDE messages before going on to the target Processes Thread queue.
|
|
//
|
|
BOOL
|
|
APIENTRY
|
|
IntDdePostMessageHook(
|
|
IN PWND pWnd,
|
|
IN UINT Msg,
|
|
IN WPARAM wParam,
|
|
IN OUT LPARAM *lParam,
|
|
IN OUT LONG_PTR *ExtraInfo)
|
|
{
|
|
PWND pWndClient;
|
|
PDDE_DATA pddeData;
|
|
int size;
|
|
HGDIOBJ Object = NULL;
|
|
PVOID userBuf = NULL;
|
|
PVOID Buffer = NULL;
|
|
LPARAM lp = *lParam;
|
|
|
|
if (pWnd->head.pti->ppi != gptiCurrent->ppi)
|
|
{
|
|
TRACE("Posting long DDE 0x%x\n",Msg);
|
|
// Initiate is sent only across borders.
|
|
if (Msg == WM_DDE_INITIATE)
|
|
{
|
|
return FALSE;
|
|
}
|
|
|
|
pWndClient = UserGetWindowObject((HWND)wParam);
|
|
if (pWndClient == NULL)
|
|
{
|
|
// This is terminating so post it.
|
|
if ( Msg == WM_DDE_TERMINATE)
|
|
{
|
|
TRACE("DDE Posted WM_DDE_TERMINATE\n");
|
|
return TRUE;
|
|
}
|
|
TRACE("Invalid DDE Client Window handle\n");
|
|
return FALSE;
|
|
}
|
|
|
|
if ( Msg == WM_DDE_REQUEST || Msg == WM_DDE_UNADVISE )
|
|
{
|
|
// Do not bother to callback after validation.
|
|
return TRUE;
|
|
}
|
|
|
|
if ( Msg == WM_DDE_TERMINATE )
|
|
{
|
|
//// FIXME Remove Stuff if any...
|
|
|
|
// Do not bother to callback.
|
|
return TRUE;
|
|
}
|
|
|
|
if ( Msg == WM_DDE_EXECUTE && *lParam == 0)
|
|
{
|
|
// Do not bother to do a callback.
|
|
TRACE("DDE Post EXECUTE lParam 0\n");
|
|
return FALSE;
|
|
}
|
|
|
|
// Callback.
|
|
if ((size = IntDDEPostCallback(pWnd, Msg, wParam, &lp, &userBuf)) == 0)
|
|
{
|
|
ERR("DDE Post Callback return 0 0x%x\n", Msg);
|
|
return FALSE;
|
|
}
|
|
|
|
// No error HACK.
|
|
if (size == -1)
|
|
{
|
|
size = 0;
|
|
}
|
|
else
|
|
{
|
|
// Set buffer with users data size.
|
|
Buffer = ExAllocatePoolWithTag(PagedPool, size, USERTAG_DDE);
|
|
if (Buffer == NULL)
|
|
{
|
|
ERR("Failed to allocate %i bytes.\n", size);
|
|
return FALSE;
|
|
}
|
|
// No SEH? Yes, the user memory is freed after the Acknowledgment or at Termination.
|
|
RtlCopyMemory(Buffer, userBuf, size);
|
|
}
|
|
|
|
TRACE("DDE Post size %d 0x%x\n",size, Msg);
|
|
|
|
switch(Msg)
|
|
{
|
|
case WM_DDE_POKE:
|
|
{
|
|
DDEPOKE *pddePoke = Buffer;
|
|
NT_ASSERT(pddePoke != NULL);
|
|
switch(pddePoke->cfFormat)
|
|
{
|
|
case CF_BITMAP:
|
|
case CF_DIB:
|
|
case CF_PALETTE:
|
|
RtlCopyMemory(&Object, pddePoke->Value, sizeof(HGDIOBJ));
|
|
break;
|
|
default:
|
|
break;
|
|
}
|
|
break;
|
|
}
|
|
case WM_DDE_DATA:
|
|
{
|
|
DDEDATA *pddeData2 = Buffer;
|
|
NT_ASSERT(pddeData2 != NULL);
|
|
switch(pddeData2->cfFormat)
|
|
{
|
|
case CF_BITMAP:
|
|
case CF_DIB:
|
|
case CF_PALETTE:
|
|
RtlCopyMemory(&Object, pddeData2->Value, sizeof(HGDIOBJ));
|
|
break;
|
|
default:
|
|
break;
|
|
}
|
|
break;
|
|
}
|
|
default:
|
|
break;
|
|
}
|
|
|
|
if (Object)
|
|
{
|
|
// Give gdi object to the other process.
|
|
GreSetObjectOwner(Object, pWnd->head.pti->ppi->W32Pid);
|
|
}
|
|
|
|
pddeData = ExAllocatePoolWithTag(PagedPool, sizeof(DDE_DATA), USERTAG_DDE5);
|
|
if (pddeData == NULL)
|
|
{
|
|
ERR("Failed to allocate DDE_DATA\n");
|
|
ExFreePoolWithTag(Buffer, USERTAG_DDE);
|
|
return FALSE;
|
|
}
|
|
|
|
pddeData->cbSize = size;
|
|
pddeData->pvBuffer = Buffer;
|
|
pddeData->lParam = lp;
|
|
|
|
TRACE("DDE Post lParam c=%08lx\n",lp);
|
|
*lParam = lp;
|
|
|
|
// Attach this data packet to the user message.
|
|
*ExtraInfo = (LONG_PTR)pddeData;
|
|
}
|
|
return TRUE;
|
|
}
|
|
|
|
//
|
|
// DDE Get/Peek message hook, take preprocessed information and recombined it for the current Process Thread.
|
|
//
|
|
BOOL APIENTRY
|
|
IntDdeGetMessageHook(PMSG pMsg, LONG_PTR ExtraInfo)
|
|
{
|
|
PWND pWnd, pWndClient;
|
|
PDDE_DATA pddeData;
|
|
PDDE_PROP pddeProp;
|
|
BOOL Ret;
|
|
|
|
pWnd = UserGetWindowObject(pMsg->hwnd);
|
|
if (pWnd == NULL)
|
|
{
|
|
ERR("DDE Get Window is dead. %p\n", pMsg->hwnd);
|
|
return TRUE;
|
|
}
|
|
|
|
if (pMsg->message == WM_DDE_TERMINATE)
|
|
{
|
|
pddeProp = (PDDE_PROP)UserGetProp(pWnd, AtomDDETrack, TRUE);
|
|
if (pddeProp)
|
|
{
|
|
pWndClient = UserGetWindowObject((HWND)pMsg->wParam);
|
|
if (pWndClient == NULL)
|
|
{
|
|
ERR("DDE Get Client WM_DDE_TERMINATE\n");
|
|
}
|
|
|
|
UserRemoveProp(pWnd, AtomDDETrack, TRUE);
|
|
ExFreePoolWithTag(pddeProp, USERTAG_DDE1);
|
|
}
|
|
return TRUE;
|
|
}
|
|
|
|
TRACE("DDE Get Msg 0x%x\n",pMsg->message);
|
|
|
|
pddeData = (PDDE_DATA)ExtraInfo;
|
|
|
|
if ( pddeData )
|
|
{
|
|
TRACE("DDE Get size %d lParam c=%08lx lp c=%08lx\n",pddeData->cbSize, pMsg->lParam, pddeData->lParam);
|
|
|
|
// Callback.
|
|
Ret = IntDDEGetCallback( pWnd, pMsg, pddeData->pvBuffer, pddeData->cbSize);
|
|
if (!Ret)
|
|
{
|
|
ERR("DDE Get CB failed\n");
|
|
}
|
|
|
|
if (pddeData->pvBuffer) ExFreePoolWithTag(pddeData->pvBuffer, USERTAG_DDE);
|
|
|
|
ExFreePoolWithTag(pddeData, USERTAG_DDE5);
|
|
|
|
return Ret;
|
|
}
|
|
TRACE("DDE Get No DDE Data found!\n");
|
|
return TRUE;
|
|
}
|
|
|
|
//
|
|
// DDE Send message hook, intercept DDE messages and associate them in a partnership with property.
|
|
//
|
|
BOOL FASTCALL
|
|
IntDdeSendMessageHook(PWND pWnd, UINT Msg, WPARAM wParam, LPARAM lParam)
|
|
{
|
|
PWND pWndServer;
|
|
PDDE_PROP pddeProp;
|
|
|
|
if (pWnd->head.pti->ppi != gptiCurrent->ppi)
|
|
{
|
|
TRACE("Sending long DDE 0x%x\n",Msg);
|
|
|
|
// Allow only Acknowledge and Initiate to be sent across borders.
|
|
if (Msg != WM_DDE_ACK )
|
|
{
|
|
if (Msg == WM_DDE_INITIATE) return TRUE;
|
|
return FALSE;
|
|
}
|
|
|
|
TRACE("Sending long WM_DDE_ACK\n");
|
|
|
|
pWndServer = UserGetWindowObject((HWND)wParam);
|
|
if (pWndServer == NULL)
|
|
{
|
|
ERR("Invalid DDE Server Window handle\n");
|
|
return FALSE;
|
|
}
|
|
|
|
// Setup property so this conversation can be tracked.
|
|
pddeProp = ExAllocatePoolWithTag(PagedPool, sizeof(DDE_PROP), USERTAG_DDE1);
|
|
if (pddeProp == NULL)
|
|
{
|
|
ERR("failed to allocate DDE_PROP\n");
|
|
return FALSE;
|
|
}
|
|
|
|
pddeProp->spwnd = pWndServer;
|
|
pddeProp->spwndPartner = pWnd;
|
|
|
|
UserSetProp(pWndServer, AtomDDETrack, (HANDLE)pddeProp, TRUE);
|
|
}
|
|
return TRUE;
|
|
}
|
|
|
|
|
|
BOOL
|
|
APIENTRY
|
|
NtUserDdeGetQualityOfService(
|
|
IN HWND hwndClient,
|
|
IN HWND hWndServer,
|
|
OUT PSECURITY_QUALITY_OF_SERVICE pqosPrev)
|
|
{
|
|
STUB
|
|
|
|
return 0;
|
|
}
|
|
|
|
BOOL
|
|
APIENTRY
|
|
NtUserDdeSetQualityOfService(
|
|
IN HWND hwndClient,
|
|
IN PSECURITY_QUALITY_OF_SERVICE pqosNew,
|
|
OUT PSECURITY_QUALITY_OF_SERVICE pqosPrev)
|
|
{
|
|
STUB
|
|
|
|
return 0;
|
|
}
|
|
|
|
BOOL
|
|
APIENTRY
|
|
NtUserImpersonateDdeClientWindow(
|
|
HWND hWndClient,
|
|
HWND hWndServer)
|
|
{
|
|
STUB
|
|
|
|
return 0;
|
|
}
|
|
|
|
DWORD
|
|
APIENTRY
|
|
NtUserDdeInitialize(
|
|
DWORD Unknown0,
|
|
DWORD Unknown1,
|
|
DWORD Unknown2,
|
|
DWORD Unknown3,
|
|
DWORD Unknown4)
|
|
{
|
|
STUB
|
|
|
|
return 0;
|
|
}
|
|
|