Implemented interprocess DDE message posting.
This commit is contained in:
parent
9e99d2b763
commit
0faceb05fc
|
@ -512,7 +512,6 @@ static size_t pack_message( HWND hwnd, UINT message, WPARAM wparam, LPARAM lpara
|
|||
case WM_MDIGETACTIVE:
|
||||
if (lparam) return sizeof(BOOL);
|
||||
return 0;
|
||||
|
||||
case WM_WINE_SETWINDOWPOS:
|
||||
push_data( data, (WINDOWPOS *)lparam, sizeof(WINDOWPOS) );
|
||||
return 0;
|
||||
|
@ -537,13 +536,6 @@ static size_t pack_message( HWND hwnd, UINT message, WPARAM wparam, LPARAM lpara
|
|||
/* these contain an HGLOBAL */
|
||||
case WM_PAINTCLIPBOARD:
|
||||
case WM_SIZECLIPBOARD:
|
||||
case WM_DDE_INITIATE:
|
||||
case WM_DDE_ADVISE:
|
||||
case WM_DDE_UNADVISE:
|
||||
case WM_DDE_DATA:
|
||||
case WM_DDE_REQUEST:
|
||||
case WM_DDE_POKE:
|
||||
case WM_DDE_EXECUTE:
|
||||
/* these contain pointers */
|
||||
case WM_DROPOBJECT:
|
||||
case WM_QUERYDROPOBJECT:
|
||||
|
@ -763,7 +755,6 @@ static BOOL unpack_message( HWND hwnd, UINT message, WPARAM *wparam, LPARAM *lpa
|
|||
if (!*lparam) return TRUE;
|
||||
if (!get_buffer_space( buffer, sizeof(BOOL) )) return FALSE;
|
||||
break;
|
||||
|
||||
/* these contain an HFONT */
|
||||
case WM_SETFONT:
|
||||
case WM_GETFONT:
|
||||
|
@ -784,13 +775,6 @@ static BOOL unpack_message( HWND hwnd, UINT message, WPARAM *wparam, LPARAM *lpa
|
|||
/* these contain an HGLOBAL */
|
||||
case WM_PAINTCLIPBOARD:
|
||||
case WM_SIZECLIPBOARD:
|
||||
case WM_DDE_INITIATE:
|
||||
case WM_DDE_ADVISE:
|
||||
case WM_DDE_UNADVISE:
|
||||
case WM_DDE_DATA:
|
||||
case WM_DDE_REQUEST:
|
||||
case WM_DDE_POKE:
|
||||
case WM_DDE_EXECUTE:
|
||||
/* these contain pointers */
|
||||
case WM_DROPOBJECT:
|
||||
case WM_QUERYDROPOBJECT:
|
||||
|
@ -944,7 +928,7 @@ static void unpack_reply( HWND hwnd, UINT message, WPARAM wparam, LPARAM lparam,
|
|||
memcpy( (RECT *)lparam, buffer, min( sizeof(RECT), size ));
|
||||
break;
|
||||
case EM_GETLINE:
|
||||
size = min( size, *(WORD *)lparam );
|
||||
size = min( size, (size_t)*(WORD *)lparam );
|
||||
memcpy( (WCHAR *)lparam, buffer, size );
|
||||
break;
|
||||
case LB_GETSELITEMS:
|
||||
|
@ -1065,6 +1049,271 @@ static LRESULT handle_internal_message( HWND hwnd, UINT msg, WPARAM wparam, LPAR
|
|||
}
|
||||
}
|
||||
|
||||
/* 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.
|
||||
*/
|
||||
struct DDE_pair {
|
||||
HGLOBAL client_hMem;
|
||||
HGLOBAL server_hMem;
|
||||
};
|
||||
|
||||
static struct DDE_pair* dde_pairs;
|
||||
static int dde_num_alloc;
|
||||
static int dde_num_used;
|
||||
static CRITICAL_SECTION dde_crst = CRITICAL_SECTION_INIT("Raw_DDE_CritSect");
|
||||
|
||||
static BOOL dde_add_pair(HGLOBAL chm, HGLOBAL shm)
|
||||
{
|
||||
int i;
|
||||
#define GROWBY 4
|
||||
|
||||
EnterCriticalSection(&dde_crst);
|
||||
|
||||
/* now remember the pair of hMem on both sides */
|
||||
if (dde_num_used == dde_num_alloc)
|
||||
{
|
||||
struct DDE_pair* tmp = HeapReAlloc( GetProcessHeap(), 0, dde_pairs,
|
||||
(dde_num_alloc + GROWBY) * sizeof(struct DDE_pair));
|
||||
if (!tmp)
|
||||
{
|
||||
LeaveCriticalSection(&dde_crst);
|
||||
return FALSE;
|
||||
}
|
||||
dde_pairs = tmp;
|
||||
/* zero out newly allocated part */
|
||||
memset(&dde_pairs[dde_num_alloc], 0, GROWBY * sizeof(struct DDE_pair));
|
||||
dde_num_alloc += GROWBY;
|
||||
}
|
||||
#undef GROWBY
|
||||
for (i = 0; i < dde_num_alloc; i++)
|
||||
{
|
||||
if (dde_pairs[i].server_hMem == 0)
|
||||
{
|
||||
dde_pairs[i].client_hMem = chm;
|
||||
dde_pairs[i].server_hMem = shm;
|
||||
dde_num_used++;
|
||||
break;
|
||||
}
|
||||
}
|
||||
LeaveCriticalSection(&dde_crst);
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
static HGLOBAL dde_get_pair(HGLOBAL shm)
|
||||
{
|
||||
int i;
|
||||
HGLOBAL ret = 0;
|
||||
|
||||
EnterCriticalSection(&dde_crst);
|
||||
for (i = 0; i < dde_num_alloc; i++)
|
||||
{
|
||||
if (dde_pairs[i].server_hMem == shm)
|
||||
{
|
||||
/* free this pair */
|
||||
dde_pairs[i].server_hMem = 0;
|
||||
dde_num_used--;
|
||||
ret = dde_pairs[i].client_hMem;
|
||||
break;
|
||||
}
|
||||
}
|
||||
LeaveCriticalSection(&dde_crst);
|
||||
return ret;
|
||||
}
|
||||
|
||||
/***********************************************************************
|
||||
* post_dde_message
|
||||
*
|
||||
* Post a DDE messag
|
||||
*/
|
||||
static BOOL post_dde_message( DWORD dest_tid, struct packed_message *data, const struct send_message_info *info )
|
||||
{
|
||||
void* ptr = NULL;
|
||||
int size = 0;
|
||||
UINT uiLo, uiHi;
|
||||
LPARAM lp = 0;
|
||||
HGLOBAL hunlock = 0;
|
||||
int i;
|
||||
DWORD res;
|
||||
|
||||
if (!UnpackDDElParam( info->msg, info->lparam, &uiLo, &uiHi ))
|
||||
return FALSE;
|
||||
|
||||
lp = info->lparam;
|
||||
switch (info->msg)
|
||||
{
|
||||
/* DDE messages which don't require packing are:
|
||||
* WM_DDE_INITIATE
|
||||
* WM_DDE_TERMINATE
|
||||
* WM_DDE_REQUEST
|
||||
* WM_DDE_UNADVISE
|
||||
*/
|
||||
case WM_DDE_ACK:
|
||||
if (HIWORD(uiHi))
|
||||
{
|
||||
/* uiHi should contain a hMem from WM_DDE_EXECUTE */
|
||||
HGLOBAL h = dde_get_pair( uiHi );
|
||||
if (h)
|
||||
{
|
||||
/* send back the value of h on the other side */
|
||||
push_data( data, &h, sizeof(HGLOBAL) );
|
||||
lp = uiLo;
|
||||
TRACE( "send dde-ack %x %08x => %08lx\n", uiLo, uiHi, (DWORD)h );
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
/* uiHi should contain either an atom or 0 */
|
||||
TRACE( "send dde-ack %x atom=%x\n", uiLo, uiHi );
|
||||
lp = MAKELONG( uiLo, uiHi );
|
||||
}
|
||||
break;
|
||||
case WM_DDE_ADVISE:
|
||||
case WM_DDE_DATA:
|
||||
case WM_DDE_POKE:
|
||||
size = 0;
|
||||
if (uiLo)
|
||||
{
|
||||
size = GlobalSize( (HGLOBAL)uiLo ) ;
|
||||
if ((info->msg == WM_DDE_ADVISE && size < sizeof(DDEADVISE)) ||
|
||||
(info->msg == WM_DDE_DATA && size < sizeof(DDEDATA)) ||
|
||||
(info->msg == WM_DDE_POKE && size < sizeof(DDEPOKE))
|
||||
)
|
||||
return FALSE;
|
||||
}
|
||||
else if (info->msg != WM_DDE_DATA) return FALSE;
|
||||
|
||||
lp = uiHi;
|
||||
if (uiLo)
|
||||
{
|
||||
if ((ptr = GlobalLock( (HGLOBAL)uiLo) ))
|
||||
{
|
||||
push_data( data, ptr, size );
|
||||
hunlock = (HGLOBAL)uiLo;
|
||||
}
|
||||
}
|
||||
TRACE( "send ddepack %u %x\n", size, uiHi );
|
||||
break;
|
||||
case WM_DDE_EXECUTE:
|
||||
if (info->lparam)
|
||||
{
|
||||
if ((ptr = GlobalLock( (HGLOBAL)info->lparam) ))
|
||||
{
|
||||
push_data(data, ptr, GlobalSize( (HGLOBAL)info->lparam ));
|
||||
/* so that the other side can send it back on ACK */
|
||||
lp = info->lparam;
|
||||
hunlock = (HGLOBAL)info->lparam;
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
SERVER_START_REQ( send_message )
|
||||
{
|
||||
req->id = (void *)dest_tid;
|
||||
req->type = info->type;
|
||||
req->win = info->hwnd;
|
||||
req->msg = info->msg;
|
||||
req->wparam = info->wparam;
|
||||
req->lparam = lp;
|
||||
req->time = GetCurrentTime();
|
||||
req->timeout = -1;
|
||||
for (i = 0; i < data->count; i++)
|
||||
wine_server_add_data( req, data->data[i], data->size[i] );
|
||||
if ((res = wine_server_call( req )))
|
||||
{
|
||||
if (res == STATUS_INVALID_PARAMETER)
|
||||
/* FIXME: find a STATUS_ value for this one */
|
||||
SetLastError( ERROR_INVALID_THREAD_ID );
|
||||
else
|
||||
SetLastError( RtlNtStatusToDosError(res) );
|
||||
}
|
||||
else
|
||||
FreeDDElParam(info->msg, info->lparam);
|
||||
}
|
||||
SERVER_END_REQ;
|
||||
if (hunlock) GlobalUnlock(hunlock);
|
||||
|
||||
return !res;
|
||||
}
|
||||
|
||||
/***********************************************************************
|
||||
* unpack_dde_message
|
||||
*
|
||||
* Unpack a posted DDE message received from another process.
|
||||
*/
|
||||
static BOOL unpack_dde_message( HWND hwnd, UINT message, WPARAM *wparam, LPARAM *lparam,
|
||||
void **buffer, size_t size )
|
||||
{
|
||||
UINT uiLo, uiHi;
|
||||
HGLOBAL hMem = 0;
|
||||
void* ptr;
|
||||
|
||||
switch (message)
|
||||
{
|
||||
case WM_DDE_ACK:
|
||||
if (size)
|
||||
{
|
||||
/* hMem is being passed */
|
||||
if (size != sizeof(HGLOBAL)) return FALSE;
|
||||
if (!buffer || !*buffer) return FALSE;
|
||||
uiLo = *lparam;
|
||||
memcpy( &hMem, *buffer, size );
|
||||
uiHi = hMem;
|
||||
TRACE("recv dde-ack %u mem=%x[%lx]\n", uiLo, uiHi, GlobalSize( uiHi ));
|
||||
}
|
||||
else
|
||||
{
|
||||
uiLo = LOWORD( *lparam );
|
||||
uiHi = HIWORD( *lparam );
|
||||
TRACE("recv dde-ack %x atom=%x\n", uiLo, uiHi);
|
||||
}
|
||||
*lparam = PackDDElParam( WM_DDE_ACK, uiLo, uiHi );
|
||||
break;
|
||||
case WM_DDE_ADVISE:
|
||||
case WM_DDE_DATA:
|
||||
case WM_DDE_POKE:
|
||||
if ((!buffer || !*buffer) && message != WM_DDE_DATA) return FALSE;
|
||||
uiHi = *lparam;
|
||||
TRACE( "recv ddepack %u %x\n", size, uiHi );
|
||||
if (size)
|
||||
{
|
||||
hMem = GlobalAlloc( GMEM_MOVEABLE|GMEM_DDESHARE, size );
|
||||
if (hMem && (ptr = GlobalLock( hMem )))
|
||||
{
|
||||
memcpy( ptr, *buffer, size );
|
||||
GlobalUnlock( hMem );
|
||||
}
|
||||
else return FALSE;
|
||||
}
|
||||
uiLo = hMem;
|
||||
|
||||
*lparam = PackDDElParam( message, uiLo, uiHi );
|
||||
break;
|
||||
case WM_DDE_EXECUTE:
|
||||
if (size)
|
||||
{
|
||||
if (!buffer || !*buffer) return FALSE;
|
||||
hMem = GlobalAlloc( GMEM_MOVEABLE|GMEM_DDESHARE, size );
|
||||
if (hMem && (ptr = GlobalLock( hMem )))
|
||||
{
|
||||
memcpy( ptr, *buffer, size );
|
||||
GlobalUnlock( hMem );
|
||||
TRACE( "exec: pairing c=%08lx s=%08lx\n", *lparam, (DWORD)hMem );
|
||||
if (!dde_add_pair( *lparam, hMem ))
|
||||
{
|
||||
GlobalFree( hMem );
|
||||
return FALSE;
|
||||
}
|
||||
}
|
||||
} else return FALSE;
|
||||
*lparam = hMem;
|
||||
break;
|
||||
}
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
/***********************************************************************
|
||||
* call_window_proc
|
||||
|
@ -1222,6 +1471,18 @@ BOOL MSG_peek_message( MSG *msg, HWND hwnd, UINT first, UINT last, int flags )
|
|||
/* fall through */
|
||||
case MSG_POSTED:
|
||||
queue->GetMessageExtraInfoVal = extra_info;
|
||||
if (info.msg.message >= WM_DDE_FIRST && info.msg.message <= WM_DDE_LAST)
|
||||
{
|
||||
if (!unpack_dde_message( info.msg.hwnd, info.msg.message, &info.msg.wParam,
|
||||
&info.msg.lParam, &buffer, size ))
|
||||
{
|
||||
ERR( "invalid packed dde-message %x (%s) hwnd %x wp %x lp %lx size %d\n",
|
||||
info.msg.message, SPY_GetMsgName(info.msg.message, info.msg.hwnd),
|
||||
info.msg.hwnd, info.msg.wParam, info.msg.lParam, size );
|
||||
/* ignore it */
|
||||
continue;
|
||||
}
|
||||
}
|
||||
*msg = info.msg;
|
||||
if (buffer) HeapFree( GetProcessHeap(), 0, buffer );
|
||||
return TRUE;
|
||||
|
@ -1321,6 +1582,10 @@ static BOOL put_message_in_queue( DWORD dest_tid, const struct send_message_info
|
|||
return FALSE;
|
||||
}
|
||||
}
|
||||
else if (info->type == MSG_POSTED && info->msg >= WM_DDE_FIRST && info->msg <= WM_DDE_LAST)
|
||||
{
|
||||
return post_dde_message( dest_tid, &data, info );
|
||||
}
|
||||
|
||||
SERVER_START_REQ( send_message )
|
||||
{
|
||||
|
|
|
@ -749,7 +749,7 @@ DECL_HANDLER(send_message)
|
|||
|
||||
switch(msg->type)
|
||||
{
|
||||
case MSG_OTHER_PROCESS:
|
||||
case MSG_OTHER_PROCESS:
|
||||
msg->data_size = get_req_data_size();
|
||||
if (msg->data_size && !(msg->data = memdup( get_req_data(), msg->data_size )))
|
||||
{
|
||||
|
@ -771,6 +771,13 @@ DECL_HANDLER(send_message)
|
|||
set_queue_bits( recv_queue, QS_SENDMESSAGE );
|
||||
break;
|
||||
case MSG_POSTED:
|
||||
/* needed for posted DDE messages */
|
||||
msg->data_size = get_req_data_size();
|
||||
if (msg->data_size && !(msg->data = memdup( get_req_data(), msg->data_size )))
|
||||
{
|
||||
free( msg );
|
||||
break;
|
||||
}
|
||||
append_message( &recv_queue->msg_list[POST_MESSAGE], msg );
|
||||
set_queue_bits( recv_queue, QS_POSTMESSAGE );
|
||||
break;
|
||||
|
@ -803,8 +810,12 @@ static void return_message_to_app( struct msg_queue *queue, int flags,
|
|||
struct get_message_reply *reply,
|
||||
struct message *msg, enum message_kind kind )
|
||||
{
|
||||
assert( !msg->data_size ); /* posted messages can't have data */
|
||||
|
||||
reply->total = msg->data_size;
|
||||
if (msg->data_size > get_reply_max_size())
|
||||
{
|
||||
set_error( STATUS_BUFFER_OVERFLOW );
|
||||
return;
|
||||
}
|
||||
reply->type = msg->type;
|
||||
reply->win = msg->win;
|
||||
reply->msg = msg->msg;
|
||||
|
@ -814,16 +825,22 @@ static void return_message_to_app( struct msg_queue *queue, int flags,
|
|||
reply->y = msg->y;
|
||||
reply->time = msg->time;
|
||||
reply->info = msg->info;
|
||||
reply->total = 0;
|
||||
|
||||
/* raw messages always get removed */
|
||||
if ((msg->type == MSG_HARDWARE_RAW) || (flags & GET_MSG_REMOVE))
|
||||
{
|
||||
queue->last_msg = NULL;
|
||||
if (msg->data)
|
||||
{
|
||||
set_reply_data_ptr( msg->data, msg->data_size );
|
||||
msg->data = NULL;
|
||||
msg->data_size = 0;
|
||||
}
|
||||
remove_queue_message( queue, msg, kind );
|
||||
}
|
||||
else /* remember it as the last returned message */
|
||||
{
|
||||
if (msg->data) set_reply_data( msg->data, msg->data_size );
|
||||
queue->last_msg = msg;
|
||||
queue->last_msg_kind = kind;
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue