Release 950901
[wine.git] / ipc / dde_proc.c
blobdf6e6a8aff901cdd3116ef6b997817486fdbebb8
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__)
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 "stddebug.h"
30 #include "debug.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(MSG)
48 #define FREE_WND (WORD)(-2)
49 #define DELETED_WND (WORD)(-3)
50 #if defined(DEBUG_MSG) || defined(DEBUG_RUNTIME)
51 static char *msg_type[4]={"********", "DDE_SEND", "DDE_POST", "DDE_ACK"};
52 #endif
54 struct msg_dat {
55 struct msgbuf dat;
56 char filler[DDE_MSG_SIZE];
57 } ;
59 typedef struct fifo_element {
60 int value;
61 struct fifo_element *next;
62 } fifo_element;
64 struct fifo {
65 fifo_element *first; /* first element in the fifo or NULL */
66 fifo_element *last; /* last element in the fifo or NULL */
68 static struct fifo fifo = {NULL,NULL};
70 void dde_proc_delete(int proc_idx);
72 void dde_proc_add_fifo(int val)
74 fifo_element *created;
76 created= (fifo_element*) malloc( sizeof(fifo_element) );
77 created->value = val;
78 created->next = NULL;
80 if (fifo.first==NULL)
81 fifo.first= created;
82 else
83 fifo.last->next= created;
84 fifo.last = created;
87 /* get an item from the fifo, and return it.
88 * If fifo is empty, return -1
90 int dde_proc_shift_fifo()
92 int val;
93 fifo_element *deleted;
95 if (fifo.first == NULL)
96 return -1;
98 deleted= fifo.first;
99 val= deleted->value;
100 fifo.first= deleted->next;
101 if (fifo.first == NULL)
102 fifo.last= NULL;
104 free(deleted);
105 return val;
108 static void print_dde_message(char *desc, MSG *msg);
110 /* This should be run only when main_block is first allocated. */
111 void dde_proc_init(dde_proc proc)
113 int proc_num;
115 for (proc_num=0 ; proc_num<DDE_PROCS ; proc_num++, proc++) {
116 proc->msg=-1;
117 proc->sem=-1;
118 proc->shmid=-1;
119 proc->pid=-1;
123 /* add current process to the list of processes */
124 void dde_proc_add(dde_proc procs)
126 dde_proc proc;
127 int proc_idx;
128 dprintf_dde(stddeb,"dde_proc_add(..)\n");
129 shm_write_wait(main_block->sem);
131 /* find free proc_idx and allocate it */
132 for (proc_idx=0, proc=procs ; proc_idx<DDE_PROCS ; proc_idx++, proc++)
133 if (proc->pid==-1)
134 break; /* found! */
136 if (proc_idx<DDE_PROCS) { /* got here beacuse a free was found ? */
137 dde_msg_setup(&proc->msg);
138 proc->pid=getpid();
139 curr_proc_idx=proc_idx;
140 shm_sem_init(&proc->sem);
142 else {
143 fflush(stdout);
144 fprintf(stderr,"dde_proc_add: Can't allocate process\n");
146 shm_write_signal(main_block->sem);
149 /* wait for dde - acknowledge message - or timout */
150 static BOOL get_ack()
152 struct timeval timeout;
153 int size;
154 struct msg_dat ack_buff;
156 /* timeout after exactly one seconf */
157 timeout.tv_sec = 1;
158 timeout.tv_usec = 0;
160 sigsetjmp(env_get_ack, 1);
161 /* get here after normal execution, or after siglongjmp */
163 do { /* loop to wait for DDE_ACK */
164 had_SIGUSR2=0;
165 stop_wait_op=CONT; /* sensitive code: disallow siglongjmp */
166 size= msgrcv( main_block->proc[curr_proc_idx].msg , &ack_buff.dat,
167 1, DDE_ACK, IPC_NOWAIT);
168 if (size>=0) {
169 dprintf_msg(stddeb,"get_ack: received DDE_ACK message\n");
170 return TRUE;
172 if (DDE_GetRemoteMessage()) {
173 had_SIGUSR2=1; /* might have recieved SIGUSR2 */
175 stop_wait_op=STOP_WAIT_ACK; /* allow siglongjmp */
177 } while (had_SIGUSR2); /* loop if SIGUSR2 was recieved */
179 /* siglongjmp should be enabled at this moment */
180 select( 0, NULL, NULL, NULL, &timeout );
181 stop_wait_op=CONT; /* disallow further siglongjmp */
183 /* timeout !! (otherwise there would have been a siglongjmp) */
184 return FALSE;
187 /* Transfer one message to a given process */
188 static BOOL DDE_DoOneMessage (int proc_idx, int size, struct msgbuf *msgbuf)
190 dde_proc proc= &main_block->proc[ proc_idx ];
193 if (proc_idx == curr_proc_idx)
194 return FALSE;
196 if (kill(proc->pid,0) < 0) {
197 /* pid does not exist, or not our */
198 dde_proc_delete(proc_idx);
199 return FALSE;
202 if (debugging_dde) {
203 MSG *msg=(MSG*) &msgbuf->mtext;
204 char *title;
205 if (msgbuf->mtype==DDE_SEND)
206 title="sending dde:";
207 else if (msgbuf->mtype==DDE_POST)
208 title="posting dde:";
209 else
210 title=NULL;
211 if (title)
212 print_dde_message(title, msg);
213 else
214 fprintf(stddeb,"Unknown message type=0x%lx\n",msgbuf->mtype);
216 dprintf_msg(stddeb,
217 "DDE_DoOneMessage: to proc_idx=%d (pid=%d), queue=%u\n",
218 proc_idx, proc->pid, (unsigned)proc->msg);
219 if ( proc->msg != -1) {
220 dprintf_msg(stddeb, "DDE_DoOneMessage: doing...(type=%s)\n",
221 msg_type[msgbuf->mtype]);
222 size=msgsnd (proc->msg, msgbuf, size, 0);
224 if (size<0) {
225 fflush(stdout);
226 perror("msgsnd");
228 kill(proc->pid,SIGUSR2); /* tell the process there is a message */
230 dprintf_msg(stddeb,"DDE_DoOneMessage: "
231 "Trying to get acknowledgment from msg queue=%d\n",
232 proc->msg);
233 Yield(); /* force task switch, and */
234 /* acknowledgment sending */
235 if (get_ack()) {
236 return TRUE;
237 } else {
238 fflush(stdout);
239 fprintf(stderr,"get_ack: DDE_DoOneMessage: timeout\n");
240 return FALSE;
243 else {
244 dprintf_msg(stddeb,"DDE_DoOneMessage: message not sent, "
245 "target has no message queue\n");
246 return FALSE;
250 /* Do some sort of premitive hash table */
251 static HWND HWND_Local2Remote(HWND orig)
253 int dde_wnd_idx;
254 int deleted_idx= -1;
255 WND_DATA *tested;
256 WND_DATA *deleted= NULL;
257 int i;
259 dde_wnd_idx= orig % DDE_WINDOWS;
260 for ( i=0 ; i < DDE_WINDOWS ; i++, dde_wnd_idx++) {
261 if (dde_wnd_idx >= DDE_WINDOWS)
262 dde_wnd_idx -= DDE_WINDOWS; /* wrap-around */
264 tested= &main_block->windows[ dde_wnd_idx ];
265 if (tested->proc_idx == FREE_WND)
266 break;
268 if (deleted == NULL && tested->proc_idx == DELETED_WND) {
269 deleted= tested;
270 deleted_idx= dde_wnd_idx;
271 } else if (tested->wnd == orig && tested->proc_idx == curr_proc_idx) {
272 return IDX_TO_HWND(dde_wnd_idx);
275 if (deleted != NULL) { /* deleted is preferable */
276 /* free item, allocate it */
277 deleted->proc_idx= curr_proc_idx;
278 deleted->wnd = orig;
279 return IDX_TO_HWND(deleted_idx);
281 if (tested->proc_idx == FREE_WND) {
282 tested->proc_idx= curr_proc_idx;
283 tested->wnd = orig;
284 return IDX_TO_HWND(dde_wnd_idx);
287 fprintf(stderr,
288 "HWND_Local2Remote: Can't map any more windows to DDE windows\n");
289 return 0;
292 static BOOL DDE_DoMessage( MSG *msg, int type )
294 int proc_idx;
296 MSG *remote_message;
297 struct msg_dat msg_dat;
298 BOOL success;
300 if (msg->wParam == 0)
301 return FALSE;
303 if (main_block==NULL) {
304 if (msg->message >= WM_DDE_FIRST && msg->message <= WM_DDE_LAST)
305 DDE_IPC_init();
306 else
307 return FALSE;
311 if (msg->wParam == (HWND)-1)
312 return FALSE;
314 if ( ! DDE_IsRemoteWindow(msg->hwnd) && msg->hwnd!= (HWND)-1)
315 return FALSE;
317 dprintf_msg(stddeb, "%s: DDE_DoMessage(hwnd=0x%x,msg=0x%x,..)\n",
318 msg_type[type], (int)msg->hwnd,(int)msg->message);
321 dprintf_msg(stddeb,
322 "DDE_DoMessage(hwnd=0x%x,msg=0x%x,..) // HWND_BROADCAST !\n",
323 (int)msg->hwnd,(int)msg->message);
324 remote_message=(void*)&msg_dat.dat.mtext;
326 memcpy(remote_message, msg, sizeof(*msg));
327 remote_message->wParam= HWND_Local2Remote(msg->wParam);
328 if (remote_message->wParam == 0)
329 return FALSE;
331 msg_dat.dat.mtype=type;
333 if (msg->hwnd == (HWND)-1) {
334 success= FALSE;
335 for ( proc_idx=0; proc_idx < DDE_PROCS ; proc_idx++) {
336 if (proc_idx == curr_proc_idx)
337 continue;
338 if (main_block->proc[ proc_idx ].msg != -1)
339 success|=DDE_DoOneMessage(proc_idx, DDE_MSG_SIZE, &msg_dat.dat);
341 return success;
342 } else {
343 return DDE_DoOneMessage(DDE_WIN2PROC(msg->hwnd), DDE_MSG_SIZE,
344 &msg_dat.dat);
348 BOOL DDE_SendMessage( MSG *msg)
350 return DDE_DoMessage(msg, DDE_SEND);
353 BOOL DDE_PostMessage( MSG *msg)
355 return DDE_DoMessage(msg, DDE_POST);
359 void dde_proc_send_ack(HWND wnd, BOOL val) {
360 int proc,msg;
362 static struct msgbuf msg_ack={DDE_ACK,{'0'}};
364 proc=DDE_WIN2PROC(wnd);
365 msg=main_block->proc[proc].msg;
366 dprintf_msg(stddeb,"DDE_GetRemoteMessage: sending ACK "
367 "to wnd=%4x, proc=%d,msg=%d, pid=%d\n",wnd,proc,msg,
368 main_block->proc[proc].pid
371 msg_ack.mtext[0]=val;
372 msgsnd (msg, &msg_ack, 1, 0);
373 kill(main_block->proc[proc].pid, SIGUSR2);
376 /* return true (non zero) if had a remote message */
377 #undef DDE_GetRemoteMessage
379 int DDE_GetRemoteMessage()
381 static int nesting=0; /* to avoid infinite recursion */
383 MSG *remote_message;
384 int size;
385 struct msg_dat msg_dat;
386 BOOL was_sent; /* sent/received */
387 BOOL passed;
388 HWND hwnd;
389 WND *window;
391 if (curr_proc_idx==-1) /* do we have DDE initialized ? */
392 return 0;
394 if (nesting>10) {
395 fflush(stdout);
396 fprintf(stderr,"DDE_GetRemoteMessage: suspecting infinite recursion, exiting");
397 return 0;
400 remote_message=(void*)&msg_dat.dat.mtext;
402 /* test for SendMessage */
403 size= msgrcv( main_block->proc[curr_proc_idx].msg , &msg_dat.dat,
404 DDE_MSG_SIZE, DDE_SEND, IPC_NOWAIT);
406 if (size==DDE_MSG_SIZE) { /* is this a correct message (if any) ?*/
407 was_sent=TRUE;
408 dprintf_msg(stddeb,
409 "DDE:receive sent message. msg=%04x wPar=%04x"
410 " lPar=%08lx\n",
411 remote_message->message, remote_message->wParam,
412 remote_message->lParam);
413 } else {
414 size= msgrcv( main_block->proc[curr_proc_idx].msg , &msg_dat.dat,
415 DDE_MSG_SIZE, DDE_POST, IPC_NOWAIT);
417 if (size==DDE_MSG_SIZE) { /* is this a correct message (if any) ?*/
418 was_sent=FALSE;
419 dprintf_msg(stddeb,
420 "DDE:receive posted message. "
421 "msg=%04x wPar=%04x lPar=%08lx\n",
422 remote_message->message, remote_message->wParam,
423 remote_message->lParam);
425 else
426 return 0; /* no DDE message found */
429 /* At this point we are sure that there is a DDE message,
430 * was_sent is TRUE is the message was sent, and false if it was posted
433 nesting++;
435 if (debugging_dde) {
436 char *title;
437 if (was_sent)
438 title="receive sent dde:";
439 else
440 title="receive posted dde:";
441 print_dde_message(title, remote_message);
444 if (remote_message->hwnd != (HWND) -1 ) {
445 HWND dde_window= DDE_WIN_INFO(remote_message->hwnd).wnd;
446 /* we should know exactly where to send the message (locally)*/
447 if (was_sent) {
448 dprintf_dde(stddeb,
449 "SendMessage(wnd=0x%04x, msg=0x%04x, wPar=0x%04x,"
450 "lPar=0x%08x\n",
451 dde_window, remote_message->message,
452 remote_message->wParam, (int)remote_message->lParam);
454 /* execute the recieved message */
455 passed= SendMessage(dde_window, remote_message->message,
456 remote_message->wParam, remote_message->lParam);
458 /* Tell the sended, that the message is here */
459 dde_proc_send_ack(remote_message->wParam, passed);
461 else {
462 passed= PostMessage(dde_window, remote_message->message,
463 remote_message->wParam, remote_message->lParam);
464 if (passed == FALSE) {
465 /* Tell the sender, that the message is here, and failed */
466 dde_proc_send_ack(remote_message->wParam, FALSE);
468 else {
469 /* ack will be sent later, at the first peek/get message */
470 dde_proc_add_fifo(remote_message->wParam);
473 nesting--;
474 return 1;
477 /* iterate through all the windows */
478 for (hwnd = GetTopWindow(GetDesktopWindow());
479 hwnd && (window = WIN_FindWndPtr(hwnd))!=NULL ;
480 hwnd = window->hwndNext) {
481 if (window->dwStyle & WS_POPUP || window->dwStyle & WS_CAPTION) {
482 if (was_sent)
483 SendMessage( hwnd, remote_message->message,
484 remote_message->wParam, remote_message->lParam );
485 else
486 PostMessage( hwnd, remote_message->message,
487 remote_message->wParam, remote_message->lParam );
488 } /* if */
489 } /* for */
491 /* replay with DDE_ACK after broadcasting in DDE_GetRemoteMessage */
492 dde_proc_send_ack(remote_message->wParam, TRUE);
494 nesting--;
495 return 1;
498 int dde_reschedule()
500 int ack_wnd;
502 ack_wnd= dde_proc_shift_fifo();
503 if (ack_wnd != -1) {
504 dde_proc_send_ack(ack_wnd, TRUE);
505 usleep(10000); /* force unix task switch */
506 return 1;
508 return 0;
510 void dde_msg_setup(int *msg_ptr)
512 *msg_ptr= msgget (IPC_PRIVATE, IPC_CREAT | 0700);
513 if (*msg_ptr==-1)
514 perror("dde_msg_setup fails to get message queue");
517 /* do we have dde handling in the window ?
518 * If we have, atom usage will make this instance of wine set up
519 * it's IPC stuff.
521 void DDE_TestDDE(HWND hwnd)
524 if (main_block != NULL)
525 return;
526 dprintf_msg(stddeb,"DDE_TestDDE(0x%04x)\n", hwnd);
527 if (hwnd==0)
528 hwnd=-1;
529 /* just send a message to see how things are going */
530 SendMessage( hwnd, WM_DDE_INITIATE, 0, 0);
533 void dde_proc_delete(int proc_idx)
535 dde_proc_done(&main_block->proc[proc_idx]);
537 void stop_wait(int a)
540 had_SIGUSR2=1;
541 switch(stop_wait_op) {
542 case STOP_WAIT_ACK:
543 siglongjmp(env_get_ack,1);
544 break; /* never reached */
545 case STOP_WAIT_X:
546 siglongjmp(env_wait_x,1);
547 break; /* never reached */
548 case CONT:
549 /* do nothing */
553 static void print_dde_message(char *desc, MSG *msg)
555 extern const char *MessageTypeNames[];
556 extern int debug_last_handle_size;
557 WORD wStatus,hWord;
558 void *ptr;
559 DDEACK *ddeack;
560 DDEADVISE *ddeadvise;
561 DDEDATA *ddedata;
562 DDEPOKE *ddepoke;
564 if (is_dde_handle(msg->lParam & 0xffff) )
565 ptr=DDE_AttachHandle(msg->lParam&0xffff, NULL);
566 else
567 ptr =NULL;
568 wStatus=LOWORD(msg->lParam);
569 hWord=HIWORD(msg->lParam);
571 fprintf(stddeb,"%s", desc);
572 fprintf(stddeb,"%04x %04x==%s %04x %08lx ",
573 msg->hwnd, msg->message,MessageTypeNames[msg->message],
574 msg->wParam, msg->lParam);
575 switch(msg->message) {
576 case WM_DDE_INITIATE:
577 case WM_DDE_REQUEST:
578 case WM_DDE_EXECUTE:
579 case WM_DDE_TERMINATE:
580 /* nothing to do */
581 break;
582 case WM_DDE_ADVISE:
583 /* DDEADVISE: hOptions in WM_DDE_ADVISE message */
584 if (ptr) {
585 ddeadvise=ptr;
586 fprintf(stddeb,"fDeferUpd=%d,fAckReq=%d,cfFormat=0x%x",
587 ddeadvise->fDeferUpd, ddeadvise->fAckReq,
588 ddeadvise->cfFormat);
589 } else
590 fprintf(stddeb,"NO-DATA");
591 fprintf(stddeb," atom=0x%x",hWord);
592 break;
594 case WM_DDE_UNADVISE:
595 fprintf(stddeb,"format=0x%x, atom=0x%x",wStatus,hWord);
596 break;
597 case WM_DDE_ACK:
598 ddeack=(DDEACK*)&wStatus;
599 fprintf(stddeb,"bAppReturnCode=%d,fBusy=%d,fAck=%d",
600 ddeack->bAppReturnCode, ddeack->fBusy, ddeack->fAck);
601 if (ddeack->fAck)
602 fprintf(stddeb,"(True)");
603 else
604 fprintf(stddeb,"(False)");
605 break;
607 case WM_DDE_DATA:
608 if (ptr) {
609 ddedata=ptr;
610 fprintf(stddeb,"fResponse=%d,fRelease=%d,"
611 "fAckReq=%d,cfFormat=0x%x,value=\"%.*s\"",
612 ddedata->fResponse, ddedata->fRelease,
613 ddedata->fAckReq, ddedata->cfFormat,
614 debug_last_handle_size- (int)sizeof(*ddedata)+1,
615 ddedata->Value);
616 } else
617 fprintf(stddeb,"NO-DATA");
618 fprintf(stddeb," atom=0x%04x",hWord);
619 break;
621 case WM_DDE_POKE:
622 if (ptr) {
623 ddepoke=ptr;
624 fprintf(stddeb,"fRelease=%d,cfFormat=0x%x,value[0]='%c'",
625 ddepoke->fRelease, ddepoke->cfFormat, ddepoke->Value[0]);
626 } else
627 fprintf(stddeb,"NO-DATA");
628 fprintf(stddeb," atom=0x%04x",hWord);
629 break;
631 fprintf(stddeb,"\n");
634 void dde_proc_done(dde_proc proc)
636 if (proc->msg != -1)
637 msgctl(proc->msg, IPC_RMID, NULL);
638 proc->msg=-1;
639 proc->pid=-1;
640 shm_delete_chain(&proc->shmid);
641 shm_sem_done(&proc->sem);
644 /* delete entry, if old junk */
645 void dde_proc_refresh(dde_proc proc)
647 if (proc->pid == -1)
648 return;
650 if (kill(proc->pid, 0) != -1)
651 return;
653 /* get here if entry non empty, and the process does not exist */
654 dde_proc_done(proc);
657 void dde_wnd_setup()
659 int i;
661 for (i=0 ; i < DDE_WINDOWS ; i++)
662 main_block->windows[i].proc_idx = FREE_WND;
665 static BOOL DDE_ProcHasWindows(int proc_idx)
667 WND_DATA *tested;
668 int i;
670 for ( i=0 ; i < DDE_WINDOWS ; i++) {
671 tested= &main_block->windows[ i ];
673 if (tested->proc_idx == proc_idx)
674 return TRUE;
676 return FALSE;
678 /* Look for hwnd in the hash table of DDE windows,
679 * Delete it from there. If there are no more windows for this
680 * process, remove the process from the DDE data-structure.
681 * If there are no more processes - delete the whole DDE struff.
683 * This is inefficient, but who cares for the efficiency of this rare
684 * operation...
686 void DDE_DestroyWindow(HWND hwnd)
688 int dde_wnd_idx;
689 WND_DATA *tested;
690 int i;
692 if (main_block == NULL)
693 return;
695 dde_wnd_idx= hwnd % DDE_WINDOWS;
697 for ( i=0 ; i < DDE_WINDOWS ; i++, dde_wnd_idx++) {
698 if (dde_wnd_idx >= DDE_WINDOWS)
699 dde_wnd_idx -= DDE_WINDOWS; /* wrap-around */
701 tested= &main_block->windows[ dde_wnd_idx ];
702 if (tested->proc_idx == FREE_WND)
703 return; /* No window will get deleted here */
705 if (tested->wnd == hwnd && tested->proc_idx == curr_proc_idx) {
706 dde_reschedule();
707 tested->proc_idx= DELETED_WND;
708 if (DDE_ProcHasWindows( curr_proc_idx ))
709 return;
710 while (dde_reschedule()) /* make sure there are no other */
711 /* processes waiting for acknowledgment */
713 dde_proc_delete( curr_proc_idx );
714 if (DDE_no_of_attached() == 1)
715 shm_delete_all(-1);
716 else {
717 shmdt( (void *) main_block);
718 main_block= NULL;
720 return;
725 #endif /* CONFIG_IPC */