1 /***************************************************************************
2 * Copyright 1995, Technion, Israel Institute of Technology
3 * Electrical Eng, Software Lab.
4 * Author: Michael Veksler.
5 ***************************************************************************
7 * Purpose : DDE signals and processes functionality for DDE
8 ***************************************************************************
12 #if defined(__FreeBSD__) || defined(__NetBSD__) || defined(__OpenBSD__)
24 #include "shm_semaph.h"
25 #include "shm_main_blk.h"
32 int curr_proc_idx
= -1;
34 enum stop_wait_op stop_wait_op
=CONT
;
36 sigjmp_buf env_get_ack
;
37 sigjmp_buf env_wait_x
;
39 #define IDX_TO_HWND(idx) (0xfffe - (idx))
40 #define HWND_TO_IDX(wnd) (0xfffe - (wnd))
41 #define DDE_WIN_INFO(win) ( main_block->windows[HWND_TO_IDX(win)] )
42 #define DDE_WIN2PROC(win) ( DDE_WIN_INFO(win).proc_idx )
43 #define DDE_IsRemoteWindow(win) ( (win)<0xffff && (win)>=(0xffff-DDE_PROCS))
47 #define DDE_MSG_SIZE sizeof(MSG16)
48 #define FREE_WND (WORD)(-2)
49 #define DELETED_WND (WORD)(-3)
50 static char *msg_type
[4]={"********", "DDE_SEND", "DDE_POST", "DDE_ACK"};
54 char filler
[DDE_MSG_SIZE
];
57 typedef struct fifo_element
{
59 struct fifo_element
*next
;
63 fifo_element
*first
; /* first element in the fifo or NULL */
64 fifo_element
*last
; /* last element in the fifo or NULL */
66 static struct fifo fifo
= {NULL
,NULL
};
68 void dde_proc_delete(int proc_idx
);
70 void dde_proc_add_fifo(int val
)
72 fifo_element
*created
;
74 created
= (fifo_element
*) xmalloc( sizeof(fifo_element
) );
81 fifo
.last
->next
= created
;
85 /* get an item from the fifo, and return it.
86 * If fifo is empty, return -1
88 int dde_proc_shift_fifo()
91 fifo_element
*deleted
;
93 if (fifo
.first
== NULL
)
98 fifo
.first
= deleted
->next
;
99 if (fifo
.first
== NULL
)
106 static void print_dde_message(char *desc
, MSG16
*msg
);
108 /* This should be run only when main_block is first allocated. */
109 void dde_proc_init(dde_proc proc
)
113 for (proc_num
=0 ; proc_num
<DDE_PROCS
; proc_num
++, proc
++) {
121 /* add current process to the list of processes */
122 void dde_proc_add(dde_proc procs
)
126 dprintf_info(dde
,"dde_proc_add(..)\n");
127 shm_write_wait(main_block
->sem
);
129 /* find free proc_idx and allocate it */
130 for (proc_idx
=0, proc
=procs
; proc_idx
<DDE_PROCS
; proc_idx
++, proc
++)
134 if (proc_idx
<DDE_PROCS
) { /* got here beacuse a free was found ? */
135 dde_msg_setup(&proc
->msg
);
137 curr_proc_idx
=proc_idx
;
138 shm_sem_init(&proc
->sem
);
142 fprintf(stderr
,"dde_proc_add: Can't allocate process\n");
144 shm_write_signal(main_block
->sem
);
147 /* wait for dde - acknowledge message - or timout */
148 static BOOL32
get_ack()
150 struct timeval timeout
;
152 struct msg_dat ack_buff
;
154 /* timeout after exactly one seconf */
158 sigsetjmp(env_get_ack
, 1);
159 /* get here after normal execution, or after siglongjmp */
161 do { /* loop to wait for DDE_ACK */
163 stop_wait_op
=CONT
; /* sensitive code: disallow siglongjmp */
164 size
= msgrcv( main_block
->proc
[curr_proc_idx
].msg
, &ack_buff
.dat
,
165 1, DDE_ACK
, IPC_NOWAIT
);
167 dprintf_info(msg
,"get_ack: received DDE_ACK message\n");
170 if (DDE_GetRemoteMessage()) {
171 had_SIGUSR2
=1; /* might have recieved SIGUSR2 */
173 stop_wait_op
=STOP_WAIT_ACK
; /* allow siglongjmp */
175 } while (had_SIGUSR2
); /* loop if SIGUSR2 was recieved */
177 /* siglongjmp should be enabled at this moment */
178 select( 0, NULL
, NULL
, NULL
, &timeout
);
179 stop_wait_op
=CONT
; /* disallow further siglongjmp */
181 /* timeout !! (otherwise there would have been a siglongjmp) */
185 /* Transfer one message to a given process */
186 static BOOL32
DDE_DoOneMessage (int proc_idx
, int size
, struct msgbuf
*msgbuf
)
188 dde_proc proc
= &main_block
->proc
[ proc_idx
];
191 if (proc_idx
== curr_proc_idx
)
194 if (kill(proc
->pid
,0) < 0) {
195 /* pid does not exist, or not our */
196 dde_proc_delete(proc_idx
);
200 if (debugging_info(dde
) || debugging_warn_dde
) {
201 MSG16
*msg
=(MSG16
*) &msgbuf
->mtext
;
203 if (msgbuf
->mtype
==DDE_SEND
)
204 title
="sending dde:";
205 else if (msgbuf
->mtype
==DDE_POST
)
206 title
="posting dde:";
210 print_dde_message(title
, msg
);
212 dprintf_warn(dde
, "Unknown message type=0x%lx\n", msgbuf
->mtype
);
215 "DDE_DoOneMessage: to proc_idx=%d (pid=%d), queue=%u\n",
216 proc_idx
, proc
->pid
, (unsigned)proc
->msg
);
217 if ( proc
->msg
!= -1) {
218 dprintf_info(msg
, "DDE_DoOneMessage: doing...(type=%s)\n",
219 msg_type
[msgbuf
->mtype
]);
220 size
=msgsnd (proc
->msg
, msgbuf
, size
, 0);
226 kill(proc
->pid
,SIGUSR2
); /* tell the process there is a message */
228 dprintf_info(msg
,"DDE_DoOneMessage: "
229 "Trying to get acknowledgment from msg queue=%d\n",
231 Yield16(); /* force task switch, and */
232 /* acknowledgment sending */
237 fprintf(stderr
,"get_ack: DDE_DoOneMessage: timeout\n");
242 dprintf_warn(msg
, "DDE_DoOneMessage: message not sent, "
243 "target has no message queue\n");
248 /* Do some sort of premitive hash table */
249 static HWND16
HWND_Local2Remote(HWND16 orig
)
254 WND_DATA
*deleted
= NULL
;
257 dde_wnd_idx
= orig
% DDE_WINDOWS
;
258 for ( i
=0 ; i
< DDE_WINDOWS
; i
++, dde_wnd_idx
++) {
259 if (dde_wnd_idx
>= DDE_WINDOWS
)
260 dde_wnd_idx
-= DDE_WINDOWS
; /* wrap-around */
262 tested
= &main_block
->windows
[ dde_wnd_idx
];
263 if (tested
->proc_idx
== FREE_WND
)
266 if (deleted
== NULL
&& tested
->proc_idx
== DELETED_WND
) {
268 deleted_idx
= dde_wnd_idx
;
269 } else if (tested
->wnd
== orig
&& tested
->proc_idx
== curr_proc_idx
) {
270 return IDX_TO_HWND(dde_wnd_idx
);
273 if (deleted
!= NULL
) { /* deleted is preferable */
274 /* free item, allocate it */
275 deleted
->proc_idx
= curr_proc_idx
;
277 return IDX_TO_HWND(deleted_idx
);
279 if (tested
->proc_idx
== FREE_WND
) {
280 tested
->proc_idx
= curr_proc_idx
;
282 return IDX_TO_HWND(dde_wnd_idx
);
286 "HWND_Local2Remote: Can't map any more windows to DDE windows\n");
290 static BOOL32
DDE_DoMessage( MSG16
*msg
, int type
)
294 MSG16
*remote_message
;
295 struct msg_dat msg_dat
;
298 if (msg
->wParam
== 0)
301 if (main_block
==NULL
) {
302 if (msg
->message
>= WM_DDE_FIRST
&& msg
->message
<= WM_DDE_LAST
)
309 if (msg
->wParam
== (HWND16
)-1)
312 if ( ! DDE_IsRemoteWindow(msg
->hwnd
) && msg
->hwnd
!= (HWND16
)-1)
315 dprintf_info(msg
, "%s: DDE_DoMessage(hwnd=0x%x,msg=0x%x,..)\n",
316 msg_type
[type
], (int)msg
->hwnd
,(int)msg
->message
);
320 "DDE_DoMessage(hwnd=0x%x,msg=0x%x,..) // HWND_BROADCAST !\n",
321 (int)msg
->hwnd
,(int)msg
->message
);
322 remote_message
=(void*)&msg_dat
.dat
.mtext
;
324 memcpy(remote_message
, msg
, sizeof(*msg
));
325 remote_message
->wParam
= HWND_Local2Remote(msg
->wParam
);
326 if (remote_message
->wParam
== 0)
329 msg_dat
.dat
.mtype
=type
;
331 if (msg
->hwnd
== (HWND16
)-1) {
333 for ( proc_idx
=0; proc_idx
< DDE_PROCS
; proc_idx
++) {
334 if (proc_idx
== curr_proc_idx
)
336 if (main_block
->proc
[ proc_idx
].msg
!= -1)
337 success
|=DDE_DoOneMessage(proc_idx
, DDE_MSG_SIZE
, &msg_dat
.dat
);
341 return DDE_DoOneMessage(DDE_WIN2PROC(msg
->hwnd
), DDE_MSG_SIZE
,
346 BOOL32
DDE_SendMessage( MSG16
*msg
)
348 return DDE_DoMessage(msg
, DDE_SEND
);
351 BOOL32
DDE_PostMessage( MSG16
*msg
)
353 return DDE_DoMessage(msg
, DDE_POST
);
357 void dde_proc_send_ack(HWND16 wnd
, BOOL32 val
) {
360 static struct msgbuf msg_ack
={DDE_ACK
,{'0'}};
362 proc
=DDE_WIN2PROC(wnd
);
363 msg
=main_block
->proc
[proc
].msg
;
364 dprintf_info(msg
,"DDE_GetRemoteMessage: sending ACK "
365 "to wnd=%4x, proc=%d,msg=%d, pid=%d\n",wnd
,proc
,msg
,
366 main_block
->proc
[proc
].pid
369 msg_ack
.mtext
[0]=val
;
370 msgsnd (msg
, &msg_ack
, 1, 0);
371 kill(main_block
->proc
[proc
].pid
, SIGUSR2
);
374 /* return true (non zero) if had a remote message */
375 #undef DDE_GetRemoteMessage
377 int DDE_GetRemoteMessage()
379 static int nesting
=0; /* to avoid infinite recursion */
381 MSG16
*remote_message
;
383 struct msg_dat msg_dat
;
384 BOOL32 was_sent
; /* sent/received */
388 if (curr_proc_idx
==-1) /* do we have DDE initialized ? */
393 fprintf(stderr
,"DDE_GetRemoteMessage: suspecting infinite recursion, exiting");
397 remote_message
=(void*)&msg_dat
.dat
.mtext
;
399 /* test for SendMessage */
400 size
= msgrcv( main_block
->proc
[curr_proc_idx
].msg
, &msg_dat
.dat
,
401 DDE_MSG_SIZE
, DDE_SEND
, IPC_NOWAIT
);
403 if (size
==DDE_MSG_SIZE
) { /* is this a correct message (if any) ?*/
406 "DDE:receive sent message. msg=%04x wPar=%04x"
408 remote_message
->message
, remote_message
->wParam
,
409 remote_message
->lParam
);
411 size
= msgrcv( main_block
->proc
[curr_proc_idx
].msg
, &msg_dat
.dat
,
412 DDE_MSG_SIZE
, DDE_POST
, IPC_NOWAIT
);
414 if (size
==DDE_MSG_SIZE
) { /* is this a correct message (if any) ?*/
417 "DDE:receive posted message. "
418 "msg=%04x wPar=%04x lPar=%08lx\n",
419 remote_message
->message
, remote_message
->wParam
,
420 remote_message
->lParam
);
423 return 0; /* no DDE message found */
426 /* At this point we are sure that there is a DDE message,
427 * was_sent is TRUE is the message was sent, and false if it was posted
432 if (debugging_info(dde
)) {
435 title
="receive sent dde:";
437 title
="receive posted dde:";
438 print_dde_message(title
, remote_message
);
441 if (remote_message
->hwnd
!= (HWND16
) -1 ) {
442 HWND16 dde_window
= DDE_WIN_INFO(remote_message
->hwnd
).wnd
;
443 /* we should know exactly where to send the message (locally)*/
446 "SendMessage(wnd=0x%04x, msg=0x%04x, wPar=0x%04x,"
448 dde_window
, remote_message
->message
,
449 remote_message
->wParam
, (int)remote_message
->lParam
);
451 /* execute the recieved message */
452 passed
= SendMessage16(dde_window
, remote_message
->message
,
453 remote_message
->wParam
, remote_message
->lParam
);
455 /* Tell the sended, that the message is here */
456 dde_proc_send_ack(remote_message
->wParam
, passed
);
459 passed
= PostMessage16(dde_window
, remote_message
->message
,
460 remote_message
->wParam
, remote_message
->lParam
);
461 if (passed
== FALSE
) {
462 /* Tell the sender, that the message is here, and failed */
463 dde_proc_send_ack(remote_message
->wParam
, FALSE
);
466 /* ack will be sent later, at the first peek/get message */
467 dde_proc_add_fifo(remote_message
->wParam
);
474 /* iterate through all the windows */
475 for (wndPtr
= WIN_FindWndPtr(GetTopWindow32(GetDesktopWindow32()));
477 wndPtr
= wndPtr
->next
)
479 if (wndPtr
->dwStyle
& WS_POPUP
|| wndPtr
->dwStyle
& WS_CAPTION
) {
481 SendMessage16( wndPtr
->hwndSelf
, remote_message
->message
,
482 remote_message
->wParam
, remote_message
->lParam
);
484 PostMessage16( wndPtr
->hwndSelf
, remote_message
->message
,
485 remote_message
->wParam
, remote_message
->lParam
);
489 /* replay with DDE_ACK after broadcasting in DDE_GetRemoteMessage */
490 dde_proc_send_ack(remote_message
->wParam
, TRUE
);
500 ack_wnd
= dde_proc_shift_fifo();
502 dde_proc_send_ack(ack_wnd
, TRUE
);
503 usleep(10000); /* force unix task switch */
508 void dde_msg_setup(int *msg_ptr
)
510 *msg_ptr
= msgget (IPC_PRIVATE
, IPC_CREAT
| 0700);
512 perror("dde_msg_setup fails to get message queue");
515 /* do we have dde handling in the window ?
516 * If we have, atom usage will make this instance of wine set up
519 void DDE_TestDDE(HWND16 hwnd
)
522 if (in_test
++) return;
523 if (main_block
!= NULL
) {
527 dprintf_info(msg
,"DDE_TestDDE(0x%04x)\n", hwnd
);
530 /* just send a message to see how things are going */
531 SendMessage16( hwnd
, WM_DDE_INITIATE
, 0, 0);
535 void dde_proc_delete(int proc_idx
)
537 dde_proc_done(&main_block
->proc
[proc_idx
]);
539 void stop_wait(int a
)
543 switch(stop_wait_op
) {
545 siglongjmp(env_get_ack
,1);
546 break; /* never reached */
548 siglongjmp(env_wait_x
,1);
549 break; /* never reached */
555 static void print_dde_message(char *desc
, MSG16
*msg
)
557 /* extern const char *MessageTypeNames[];*/
558 extern int debug_last_handle_size
;
562 DDEADVISE
*ddeadvise
;
565 dbg_decl_str(dde
, 2048);
567 if (is_dde_handle(msg
->lParam
& 0xffff) )
568 ptr
=DDE_AttachHandle(msg
->lParam
&0xffff, NULL
);
571 wStatus
=LOWORD(msg
->lParam
);
572 hWord
=HIWORD(msg
->lParam
);
574 dsprintf(dde
,"%s", desc
);
575 dsprintf(dde
,"%04x %04x==%s %04x %08lx ",
576 msg
->hwnd
, msg
->message
,"",/*MessageTypeNames[msg->message],*/
577 msg
->wParam
, msg
->lParam
);
578 switch(msg
->message
) {
579 case WM_DDE_INITIATE
:
582 case WM_DDE_TERMINATE
:
586 /* DDEADVISE: hOptions in WM_DDE_ADVISE message */
589 dsprintf(dde
,"fDeferUpd=%d,fAckReq=%d,cfFormat=0x%x",
590 ddeadvise
->fDeferUpd
, ddeadvise
->fAckReq
,
591 ddeadvise
->cfFormat
);
593 dsprintf(dde
,"NO-DATA");
594 dsprintf(dde
," atom=0x%x",hWord
);
597 case WM_DDE_UNADVISE
:
598 dsprintf(dde
,"format=0x%x, atom=0x%x",wStatus
,hWord
);
601 ddeack
=(DDEACK
*)&wStatus
;
602 dsprintf(dde
,"bAppReturnCode=%d,fBusy=%d,fAck=%d",
603 ddeack
->bAppReturnCode
, ddeack
->fBusy
, ddeack
->fAck
);
605 dsprintf(dde
,"(True)");
607 dsprintf(dde
,"(False)");
613 dsprintf(dde
,"fResponse=%d,fRelease=%d,"
614 "fAckReq=%d,cfFormat=0x%x,value=\"%.*s\"",
615 ddedata
->fResponse
, ddedata
->fRelease
,
616 ddedata
->fAckReq
, ddedata
->cfFormat
,
617 debug_last_handle_size
- (int)sizeof(*ddedata
)+1,
620 dsprintf(dde
,"NO-DATA");
621 dsprintf(dde
," atom=0x%04x",hWord
);
627 dsprintf(dde
,"fRelease=%d,cfFormat=0x%x,value[0]='%c'",
628 ddepoke
->fRelease
, ddepoke
->cfFormat
, ddepoke
->Value
[0]);
630 dsprintf(dde
,"NO-DATA");
631 dsprintf(dde
," atom=0x%04x",hWord
);
634 dprintf_info(dde
,"%s\n", dbg_str(dde
));
637 void dde_proc_done(dde_proc proc
)
640 msgctl(proc
->msg
, IPC_RMID
, NULL
);
643 shm_delete_chain(&proc
->shmid
);
644 shm_sem_done(&proc
->sem
);
647 /* delete entry, if old junk */
648 void dde_proc_refresh(dde_proc proc
)
653 if (kill(proc
->pid
, 0) != -1)
656 /* get here if entry non empty, and the process does not exist */
664 for (i
=0 ; i
< DDE_WINDOWS
; i
++)
665 main_block
->windows
[i
].proc_idx
= FREE_WND
;
668 static BOOL32
DDE_ProcHasWindows(int proc_idx
)
673 for ( i
=0 ; i
< DDE_WINDOWS
; i
++) {
674 tested
= &main_block
->windows
[ i
];
676 if (tested
->proc_idx
== proc_idx
)
681 /* Look for hwnd in the hash table of DDE windows,
682 * Delete it from there. If there are no more windows for this
683 * process, remove the process from the DDE data-structure.
684 * If there are no more processes - delete the whole DDE struff.
686 * This is inefficient, but who cares for the efficiency of this rare
689 void DDE_DestroyWindow(HWND16 hwnd
)
695 if (main_block
== NULL
)
698 dde_wnd_idx
= hwnd
% DDE_WINDOWS
;
700 for ( i
=0 ; i
< DDE_WINDOWS
; i
++, dde_wnd_idx
++) {
701 if (dde_wnd_idx
>= DDE_WINDOWS
)
702 dde_wnd_idx
-= DDE_WINDOWS
; /* wrap-around */
704 tested
= &main_block
->windows
[ dde_wnd_idx
];
705 if (tested
->proc_idx
== FREE_WND
)
706 return; /* No window will get deleted here */
708 if (tested
->wnd
== hwnd
&& tested
->proc_idx
== curr_proc_idx
) {
710 tested
->proc_idx
= DELETED_WND
;
711 if (DDE_ProcHasWindows( curr_proc_idx
))
713 while (dde_reschedule()) /* make sure there are no other */
714 /* processes waiting for acknowledgment */
716 dde_proc_delete( curr_proc_idx
);
717 if (DDE_no_of_attached() == 1)
720 shmdt( (void *) main_block
);
728 #endif /* CONFIG_IPC */