Release 980301
[wine.git] / ipc / dde_proc.c
bloba08b0696bcecec78f33e1ce25637a5c276660de6
1 /***************************************************************************
2 * Copyright 1995, Technion, Israel Institute of Technology
3 * Electrical Eng, Software Lab.
4 * Author: Michael Veksler.
5 ***************************************************************************
6 * File: dde_proc.c
7 * Purpose : DDE signals and processes functionality for DDE
8 ***************************************************************************
9 */
10 #ifdef CONFIG_IPC
12 #if defined(__FreeBSD__) || defined(__NetBSD__) || defined(__OpenBSD__)
13 #define msgbuf mymsg
14 #endif
16 #include <sys/time.h>
17 #include <unistd.h>
18 #include <stdlib.h>
19 #include <signal.h>
20 #include <errno.h>
21 #include <sys/msg.h>
22 #include "wintypes.h"
23 #include "win.h"
24 #include "shm_semaph.h"
25 #include "shm_main_blk.h"
26 #include "dde_proc.h"
27 #include "dde_mem.h"
28 #include "dde.h"
29 #include "debug.h"
30 #include "xmalloc.h"
32 int curr_proc_idx= -1;
34 enum stop_wait_op stop_wait_op=CONT;
35 int had_SIGUSR2 = 0;
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))
44 #define DDE_SEND 1
45 #define DDE_POST 2
46 #define DDE_ACK 3
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"};
52 struct msg_dat {
53 struct msgbuf dat;
54 char filler[DDE_MSG_SIZE];
55 } ;
57 typedef struct fifo_element {
58 int value;
59 struct fifo_element *next;
60 } fifo_element;
62 struct fifo {
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) );
75 created->value = val;
76 created->next = NULL;
78 if (fifo.first==NULL)
79 fifo.first= created;
80 else
81 fifo.last->next= created;
82 fifo.last = created;
85 /* get an item from the fifo, and return it.
86 * If fifo is empty, return -1
88 int dde_proc_shift_fifo()
90 int val;
91 fifo_element *deleted;
93 if (fifo.first == NULL)
94 return -1;
96 deleted= fifo.first;
97 val= deleted->value;
98 fifo.first= deleted->next;
99 if (fifo.first == NULL)
100 fifo.last= NULL;
102 free(deleted);
103 return val;
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)
111 int proc_num;
113 for (proc_num=0 ; proc_num<DDE_PROCS ; proc_num++, proc++) {
114 proc->msg=-1;
115 proc->sem=-1;
116 proc->shmid=-1;
117 proc->pid=-1;
121 /* add current process to the list of processes */
122 void dde_proc_add(dde_proc procs)
124 dde_proc proc;
125 int proc_idx;
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++)
131 if (proc->pid==-1)
132 break; /* found! */
134 if (proc_idx<DDE_PROCS) { /* got here beacuse a free was found ? */
135 dde_msg_setup(&proc->msg);
136 proc->pid=getpid();
137 curr_proc_idx=proc_idx;
138 shm_sem_init(&proc->sem);
140 else {
141 fflush(stdout);
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;
151 int size;
152 struct msg_dat ack_buff;
154 /* timeout after exactly one seconf */
155 timeout.tv_sec = 1;
156 timeout.tv_usec = 0;
158 sigsetjmp(env_get_ack, 1);
159 /* get here after normal execution, or after siglongjmp */
161 do { /* loop to wait for DDE_ACK */
162 had_SIGUSR2=0;
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);
166 if (size>=0) {
167 dprintf_info(msg,"get_ack: received DDE_ACK message\n");
168 return TRUE;
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) */
182 return FALSE;
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)
192 return FALSE;
194 if (kill(proc->pid,0) < 0) {
195 /* pid does not exist, or not our */
196 dde_proc_delete(proc_idx);
197 return FALSE;
200 if (debugging_info(dde) || debugging_warn_dde) {
201 MSG16 *msg=(MSG16*) &msgbuf->mtext;
202 char *title;
203 if (msgbuf->mtype==DDE_SEND)
204 title="sending dde:";
205 else if (msgbuf->mtype==DDE_POST)
206 title="posting dde:";
207 else
208 title=NULL;
209 if (title)
210 print_dde_message(title, msg);
211 else
212 dprintf_warn(dde, "Unknown message type=0x%lx\n", msgbuf->mtype);
214 dprintf_info(msg,
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);
222 if (size<0) {
223 fflush(stdout);
224 perror("msgsnd");
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",
230 proc->msg);
231 Yield16(); /* force task switch, and */
232 /* acknowledgment sending */
233 if (get_ack()) {
234 return TRUE;
235 } else {
236 fflush(stdout);
237 fprintf(stderr,"get_ack: DDE_DoOneMessage: timeout\n");
238 return FALSE;
241 else {
242 dprintf_warn(msg, "DDE_DoOneMessage: message not sent, "
243 "target has no message queue\n");
244 return FALSE;
248 /* Do some sort of premitive hash table */
249 static HWND16 HWND_Local2Remote(HWND16 orig)
251 int dde_wnd_idx;
252 int deleted_idx= -1;
253 WND_DATA *tested;
254 WND_DATA *deleted= NULL;
255 int i;
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)
264 break;
266 if (deleted == NULL && tested->proc_idx == DELETED_WND) {
267 deleted= tested;
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;
276 deleted->wnd = orig;
277 return IDX_TO_HWND(deleted_idx);
279 if (tested->proc_idx == FREE_WND) {
280 tested->proc_idx= curr_proc_idx;
281 tested->wnd = orig;
282 return IDX_TO_HWND(dde_wnd_idx);
285 fprintf(stderr,
286 "HWND_Local2Remote: Can't map any more windows to DDE windows\n");
287 return 0;
290 static BOOL32 DDE_DoMessage( MSG16 *msg, int type )
292 int proc_idx;
294 MSG16 *remote_message;
295 struct msg_dat msg_dat;
296 BOOL32 success;
298 if (msg->wParam == 0)
299 return FALSE;
301 if (main_block==NULL) {
302 if (msg->message >= WM_DDE_FIRST && msg->message <= WM_DDE_LAST)
303 DDE_IPC_init();
304 else
305 return FALSE;
309 if (msg->wParam == (HWND16)-1)
310 return FALSE;
312 if ( ! DDE_IsRemoteWindow(msg->hwnd) && msg->hwnd!= (HWND16)-1)
313 return FALSE;
315 dprintf_info(msg, "%s: DDE_DoMessage(hwnd=0x%x,msg=0x%x,..)\n",
316 msg_type[type], (int)msg->hwnd,(int)msg->message);
319 dprintf_info(msg,
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)
327 return FALSE;
329 msg_dat.dat.mtype=type;
331 if (msg->hwnd == (HWND16)-1) {
332 success= FALSE;
333 for ( proc_idx=0; proc_idx < DDE_PROCS ; proc_idx++) {
334 if (proc_idx == curr_proc_idx)
335 continue;
336 if (main_block->proc[ proc_idx ].msg != -1)
337 success|=DDE_DoOneMessage(proc_idx, DDE_MSG_SIZE, &msg_dat.dat);
339 return success;
340 } else {
341 return DDE_DoOneMessage(DDE_WIN2PROC(msg->hwnd), DDE_MSG_SIZE,
342 &msg_dat.dat);
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) {
358 int proc,msg;
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;
382 int size;
383 struct msg_dat msg_dat;
384 BOOL32 was_sent; /* sent/received */
385 BOOL32 passed;
386 WND *wndPtr;
388 if (curr_proc_idx==-1) /* do we have DDE initialized ? */
389 return 0;
391 if (nesting>10) {
392 fflush(stdout);
393 fprintf(stderr,"DDE_GetRemoteMessage: suspecting infinite recursion, exiting");
394 return 0;
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) ?*/
404 was_sent=TRUE;
405 dprintf_info(msg,
406 "DDE:receive sent message. msg=%04x wPar=%04x"
407 " lPar=%08lx\n",
408 remote_message->message, remote_message->wParam,
409 remote_message->lParam);
410 } else {
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) ?*/
415 was_sent=FALSE;
416 dprintf_info(msg,
417 "DDE:receive posted message. "
418 "msg=%04x wPar=%04x lPar=%08lx\n",
419 remote_message->message, remote_message->wParam,
420 remote_message->lParam);
422 else
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
430 nesting++;
432 if (debugging_info(dde)) {
433 char *title;
434 if (was_sent)
435 title="receive sent dde:";
436 else
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)*/
444 if (was_sent) {
445 dprintf_info(dde,
446 "SendMessage(wnd=0x%04x, msg=0x%04x, wPar=0x%04x,"
447 "lPar=0x%08x\n",
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);
458 else {
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);
465 else {
466 /* ack will be sent later, at the first peek/get message */
467 dde_proc_add_fifo(remote_message->wParam);
470 nesting--;
471 return 1;
474 /* iterate through all the windows */
475 for (wndPtr = WIN_FindWndPtr(GetTopWindow32(GetDesktopWindow32()));
476 wndPtr != NULL;
477 wndPtr = wndPtr->next)
479 if (wndPtr->dwStyle & WS_POPUP || wndPtr->dwStyle & WS_CAPTION) {
480 if (was_sent)
481 SendMessage16( wndPtr->hwndSelf, remote_message->message,
482 remote_message->wParam, remote_message->lParam );
483 else
484 PostMessage16( wndPtr->hwndSelf, remote_message->message,
485 remote_message->wParam, remote_message->lParam );
486 } /* if */
487 } /* for */
489 /* replay with DDE_ACK after broadcasting in DDE_GetRemoteMessage */
490 dde_proc_send_ack(remote_message->wParam, TRUE);
492 nesting--;
493 return 1;
496 int dde_reschedule()
498 int ack_wnd;
500 ack_wnd= dde_proc_shift_fifo();
501 if (ack_wnd != -1) {
502 dde_proc_send_ack(ack_wnd, TRUE);
503 usleep(10000); /* force unix task switch */
504 return 1;
506 return 0;
508 void dde_msg_setup(int *msg_ptr)
510 *msg_ptr= msgget (IPC_PRIVATE, IPC_CREAT | 0700);
511 if (*msg_ptr==-1)
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
517 * it's IPC stuff.
519 void DDE_TestDDE(HWND16 hwnd)
521 static in_test = 0;
522 if (in_test++) return;
523 if (main_block != NULL) {
524 in_test--;
525 return;
527 dprintf_info(msg,"DDE_TestDDE(0x%04x)\n", hwnd);
528 if (hwnd==0)
529 hwnd=-1;
530 /* just send a message to see how things are going */
531 SendMessage16( hwnd, WM_DDE_INITIATE, 0, 0);
532 in_test--;
535 void dde_proc_delete(int proc_idx)
537 dde_proc_done(&main_block->proc[proc_idx]);
539 void stop_wait(int a)
542 had_SIGUSR2=1;
543 switch(stop_wait_op) {
544 case STOP_WAIT_ACK:
545 siglongjmp(env_get_ack,1);
546 break; /* never reached */
547 case STOP_WAIT_X:
548 siglongjmp(env_wait_x,1);
549 break; /* never reached */
550 case CONT:
551 /* do nothing */
555 static void print_dde_message(char *desc, MSG16 *msg)
557 /* extern const char *MessageTypeNames[];*/
558 extern int debug_last_handle_size;
559 WORD wStatus,hWord;
560 void *ptr;
561 DDEACK *ddeack;
562 DDEADVISE *ddeadvise;
563 DDEDATA *ddedata;
564 DDEPOKE *ddepoke;
565 dbg_decl_str(dde, 2048);
567 if (is_dde_handle(msg->lParam & 0xffff) )
568 ptr=DDE_AttachHandle(msg->lParam&0xffff, NULL);
569 else
570 ptr =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:
580 case WM_DDE_REQUEST:
581 case WM_DDE_EXECUTE:
582 case WM_DDE_TERMINATE:
583 /* nothing to do */
584 break;
585 case WM_DDE_ADVISE:
586 /* DDEADVISE: hOptions in WM_DDE_ADVISE message */
587 if (ptr) {
588 ddeadvise=ptr;
589 dsprintf(dde,"fDeferUpd=%d,fAckReq=%d,cfFormat=0x%x",
590 ddeadvise->fDeferUpd, ddeadvise->fAckReq,
591 ddeadvise->cfFormat);
592 } else
593 dsprintf(dde,"NO-DATA");
594 dsprintf(dde," atom=0x%x",hWord);
595 break;
597 case WM_DDE_UNADVISE:
598 dsprintf(dde,"format=0x%x, atom=0x%x",wStatus,hWord);
599 break;
600 case WM_DDE_ACK:
601 ddeack=(DDEACK*)&wStatus;
602 dsprintf(dde,"bAppReturnCode=%d,fBusy=%d,fAck=%d",
603 ddeack->bAppReturnCode, ddeack->fBusy, ddeack->fAck);
604 if (ddeack->fAck)
605 dsprintf(dde,"(True)");
606 else
607 dsprintf(dde,"(False)");
608 break;
610 case WM_DDE_DATA:
611 if (ptr) {
612 ddedata=ptr;
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,
618 ddedata->Value);
619 } else
620 dsprintf(dde,"NO-DATA");
621 dsprintf(dde," atom=0x%04x",hWord);
622 break;
624 case WM_DDE_POKE:
625 if (ptr) {
626 ddepoke=ptr;
627 dsprintf(dde,"fRelease=%d,cfFormat=0x%x,value[0]='%c'",
628 ddepoke->fRelease, ddepoke->cfFormat, ddepoke->Value[0]);
629 } else
630 dsprintf(dde,"NO-DATA");
631 dsprintf(dde," atom=0x%04x",hWord);
632 break;
634 dprintf_info(dde,"%s\n", dbg_str(dde));
637 void dde_proc_done(dde_proc proc)
639 if (proc->msg != -1)
640 msgctl(proc->msg, IPC_RMID, NULL);
641 proc->msg=-1;
642 proc->pid=-1;
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)
650 if (proc->pid == -1)
651 return;
653 if (kill(proc->pid, 0) != -1)
654 return;
656 /* get here if entry non empty, and the process does not exist */
657 dde_proc_done(proc);
660 void dde_wnd_setup()
662 int i;
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)
670 WND_DATA *tested;
671 int i;
673 for ( i=0 ; i < DDE_WINDOWS ; i++) {
674 tested= &main_block->windows[ i ];
676 if (tested->proc_idx == proc_idx)
677 return TRUE;
679 return FALSE;
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
687 * operation...
689 void DDE_DestroyWindow(HWND16 hwnd)
691 int dde_wnd_idx;
692 WND_DATA *tested;
693 int i;
695 if (main_block == NULL)
696 return;
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) {
709 dde_reschedule();
710 tested->proc_idx= DELETED_WND;
711 if (DDE_ProcHasWindows( curr_proc_idx ))
712 return;
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)
718 shm_delete_all(-1);
719 else {
720 shmdt( (void *) main_block);
721 main_block= NULL;
723 return;
728 #endif /* CONFIG_IPC */