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 ***************************************************************************
18 #include "shm_semaph.h"
19 #include "shm_main_blk.h"
26 int curr_proc_idx= -1;
28 enum stop_wait_op stop_wait_op=CONT;
30 sigjmp_buf env_get_ack;
31 sigjmp_buf env_wait_x;
33 #define IDX_TO_HWND(idx) (0xfffe - (idx))
34 #define HWND_TO_IDX(wnd) (0xfffe - (wnd))
35 #define DDE_WIN_INFO(win) ( main_block->windows[HWND_TO_IDX(win)] )
36 #define DDE_WIN2PROC(win) ( DDE_WIN_INFO(win).proc_idx )
37 #define DDE_IsRemoteWindow(win) ( (win)<0xffff && (win)>=(0xffff-DDE_PROCS))
41 #define DDE_MSG_SIZE sizeof(MSG)
42 #define FREE_WND (WORD)(-2)
43 #define DELETED_WND (WORD)(-3)
44 #if defined(DEBUG_MSG) || defined(DEBUG_RUNTIME)
45 static char *msg_type[4]={"********", "DDE_SEND", "DDE_POST", "DDE_ACK"};
50 char filler[DDE_MSG_SIZE];
53 typedef struct fifo_element {
55 struct fifo_element *next;
59 fifo_element *first; /* first element in the fifo or NULL */
60 fifo_element *last; /* last element in the fifo or NULL */
62 static struct fifo fifo = {NULL,NULL};
64 void dde_proc_delete(int proc_idx);
66 void dde_proc_add_fifo(int val)
68 fifo_element *created;
70 created= (fifo_element*) malloc( sizeof(fifo_element) );
77 fifo.last->next= created;
81 /* get an item from the fifo, and return it.
82 * If fifo is empty, return -1
84 int dde_proc_shift_fifo()
87 fifo_element *deleted;
89 if (fifo.first == NULL)
94 fifo.first= deleted->next;
95 if (fifo.first == NULL)
102 static void print_dde_message(char *desc, MSG *msg);
104 /* This should be run only when main_block is first allocated. */
105 void dde_proc_init(dde_proc proc)
109 for (proc_num=0 ; proc_num<DDE_PROCS ; proc_num++, proc++) {
117 /* add current process to the list of processes */
118 void dde_proc_add(dde_proc procs)
122 dprintf_dde(stddeb,"dde_proc_add(..)\n");
123 shm_write_wait(main_block->sem);
125 /* find free proc_idx and allocate it */
126 for (proc_idx=0, proc=procs ; proc_idx<DDE_PROCS ; proc_idx++, proc++)
130 if (proc_idx<DDE_PROCS) { /* got here beacuse a free was found ? */
131 dde_msg_setup(&proc->msg);
133 curr_proc_idx=proc_idx;
134 shm_sem_init(&proc->sem);
138 fprintf(stderr,"dde_proc_add: Can't allocate process\n");
140 shm_write_signal(main_block->sem);
143 /* wait for dde - acknowledge message - or timout */
144 static BOOL get_ack()
146 struct timeval timeout;
148 struct msg_dat ack_buff;
150 /* timeout after exactly one seconf */
154 sigsetjmp(env_get_ack, 1);
155 /* get here after normal execution, or after siglongjmp */
157 do { /* loop to wait for DDE_ACK */
159 stop_wait_op=CONT; /* sensitive code: disallow siglongjmp */
160 size= msgrcv( main_block->proc[curr_proc_idx].msg , &ack_buff.dat,
161 1, DDE_ACK, IPC_NOWAIT);
163 dprintf_msg(stddeb,"get_ack: received DDE_ACK message\n");
166 if (DDE_GetRemoteMessage()) {
167 had_SIGUSR2=1; /* might have recieved SIGUSR2 */
169 stop_wait_op=STOP_WAIT_ACK; /* allow siglongjmp */
171 } while (had_SIGUSR2); /* loop if SIGUSR2 was recieved */
173 /* siglongjmp should be enabled at this moment */
174 select( 0, NULL, NULL, NULL, &timeout );
175 stop_wait_op=CONT; /* disallow further siglongjmp */
177 /* timeout !! (otherwise there would have been a siglongjmp) */
181 /* Transfer one message to a given process */
182 static BOOL DDE_DoOneMessage (int proc_idx, int size, struct msgbuf *msgbuf)
184 dde_proc proc= &main_block->proc[ proc_idx ];
187 if (proc_idx == curr_proc_idx)
190 if (kill(proc->pid,0) < 0) {
191 /* pid does not exist, or not our */
192 dde_proc_delete(proc_idx);
197 MSG *msg=(MSG*) &msgbuf->mtext;
199 if (msgbuf->mtype==DDE_SEND)
200 title="sending dde:";
201 else if (msgbuf->mtype==DDE_POST)
202 title="posting dde:";
206 print_dde_message(title, msg);
208 fprintf(stddeb,"Unknown message type=0x%lx\n",msgbuf->mtype);
211 "DDE_DoOneMessage: to proc_idx=%d (pid=%d), queue=%u\n",
212 proc_idx, proc->pid, (unsigned)proc->msg);
213 if ( proc->msg != -1) {
214 dprintf_msg(stddeb, "DDE_DoOneMessage: doing...(type=%s)\n",
215 msg_type[msgbuf->mtype]);
216 size=msgsnd (proc->msg, msgbuf, size, 0);
222 kill(proc->pid,SIGUSR2); /* tell the process there is a message */
224 dprintf_msg(stddeb,"DDE_DoOneMessage: "
225 "Trying to get acknowledgment from msg queue=%d\n",
227 Yield(); /* force task switch, and */
228 /* acknowledgment sending */
233 fprintf(stderr,"get_ack: DDE_DoOneMessage: timeout\n");
238 dprintf_msg(stddeb,"DDE_DoOneMessage: message not sent, "
239 "target has no message queue\n");
244 /* Do some sort of premitive hash table */
245 static HWND HWND_Local2Remote(HWND orig)
250 WND_DATA *deleted= NULL;
253 dde_wnd_idx= orig % DDE_WINDOWS;
254 for ( i=0 ; i < DDE_WINDOWS ; i++, dde_wnd_idx++) {
255 if (dde_wnd_idx >= DDE_WINDOWS)
256 dde_wnd_idx -= DDE_WINDOWS; /* wrap-around */
258 tested= &main_block->windows[ dde_wnd_idx ];
259 if (tested->proc_idx == FREE_WND)
262 if (deleted == NULL && tested->proc_idx == DELETED_WND) {
264 deleted_idx= dde_wnd_idx;
265 } else if (tested->wnd == orig && tested->proc_idx == curr_proc_idx) {
266 return IDX_TO_HWND(dde_wnd_idx);
269 if (deleted != NULL) { /* deleted is preferable */
270 /* free item, allocate it */
271 deleted->proc_idx= curr_proc_idx;
273 return IDX_TO_HWND(deleted_idx);
275 if (tested->proc_idx == FREE_WND) {
276 tested->proc_idx= curr_proc_idx;
278 return IDX_TO_HWND(dde_wnd_idx);
282 "HWND_Local2Remote: Can't map any more windows to DDE windows\n");
286 static BOOL DDE_DoMessage( MSG *msg, int type )
291 struct msg_dat msg_dat;
294 if (msg->wParam == 0)
297 if (main_block==NULL) {
298 if (msg->message >= WM_DDE_FIRST && msg->message <= WM_DDE_LAST)
305 if (msg->wParam == (HWND)-1)
308 if ( ! DDE_IsRemoteWindow(msg->hwnd) && msg->hwnd!= (HWND)-1)
311 dprintf_msg(stddeb, "%s: DDE_DoMessage(hwnd=0x%x,msg=0x%x,..)\n",
312 msg_type[type], (int)msg->hwnd,(int)msg->message);
316 "DDE_DoMessage(hwnd=0x%x,msg=0x%x,..) // HWND_BROADCAST !\n",
317 (int)msg->hwnd,(int)msg->message);
318 remote_message=(void*)&msg_dat.dat.mtext;
320 memcpy(remote_message, msg, sizeof(*msg));
321 remote_message->wParam= HWND_Local2Remote(msg->wParam);
322 if (remote_message->wParam == 0)
325 msg_dat.dat.mtype=type;
327 if (msg->hwnd == (HWND)-1) {
329 for ( proc_idx=0; proc_idx < DDE_PROCS ; proc_idx++) {
330 if (proc_idx == curr_proc_idx)
332 if (main_block->proc[ proc_idx ].msg != -1)
333 success|=DDE_DoOneMessage(proc_idx, DDE_MSG_SIZE, &msg_dat.dat);
337 return DDE_DoOneMessage(DDE_WIN2PROC(msg->hwnd), DDE_MSG_SIZE,
342 BOOL DDE_SendMessage( MSG *msg)
344 return DDE_DoMessage(msg, DDE_SEND);
347 BOOL DDE_PostMessage( MSG *msg)
349 return DDE_DoMessage(msg, DDE_POST);
353 void dde_proc_send_ack(HWND wnd, BOOL val) {
356 static struct msgbuf msg_ack={DDE_ACK,{'0'}};
358 proc=DDE_WIN2PROC(wnd);
359 msg=main_block->proc[proc].msg;
360 dprintf_msg(stddeb,"DDE_GetRemoteMessage: sending ACK "
361 "to wnd=%4x, proc=%d,msg=%d, pid=%d\n",wnd,proc,msg,
362 main_block->proc[proc].pid
365 msg_ack.mtext[0]=val;
366 msgsnd (msg, &msg_ack, 1, 0);
367 kill(main_block->proc[proc].pid, SIGUSR2);
370 /* return true (non zero) if had a remote message */
371 #undef DDE_GetRemoteMessage
373 int DDE_GetRemoteMessage()
375 static int nesting=0; /* to avoid infinite recursion */
379 struct msg_dat msg_dat;
380 BOOL was_sent; /* sent/received */
385 if (curr_proc_idx==-1) /* do we have DDE initialized ? */
390 fprintf(stderr,"DDE_GetRemoteMessage: suspecting infinite recursion, exiting");
394 remote_message=(void*)&msg_dat.dat.mtext;
396 /* test for SendMessage */
397 size= msgrcv( main_block->proc[curr_proc_idx].msg , &msg_dat.dat,
398 DDE_MSG_SIZE, DDE_SEND, IPC_NOWAIT);
400 if (size==DDE_MSG_SIZE) { /* is this a correct message (if any) ?*/
403 "DDE:receive sent message. msg=%04x wPar=%04x"
405 remote_message->message, remote_message->wParam,
406 remote_message->lParam);
408 size= msgrcv( main_block->proc[curr_proc_idx].msg , &msg_dat.dat,
409 DDE_MSG_SIZE, DDE_POST, IPC_NOWAIT);
411 if (size==DDE_MSG_SIZE) { /* is this a correct message (if any) ?*/
414 "DDE:receive posted message. "
415 "msg=%04x wPar=%04x lPar=%08lx\n",
416 remote_message->message, remote_message->wParam,
417 remote_message->lParam);
420 return 0; /* no DDE message found */
423 /* At this point we are sure that there is a DDE message,
424 * was_sent is TRUE is the message was sent, and false if it was posted
432 title="receive sent dde:";
434 title="receive posted dde:";
435 print_dde_message(title, remote_message);
438 if (remote_message->hwnd != (HWND) -1 ) {
439 HWND dde_window= DDE_WIN_INFO(remote_message->hwnd).wnd;
440 /* we should know exactly where to send the message (locally)*/
443 "SendMessage(wnd=0x%04x, msg=0x%04x, wPar=0x%04x,"
445 dde_window, remote_message->message,
446 remote_message->wParam, (int)remote_message->lParam);
448 /* execute the recieved message */
449 passed= SendMessage(dde_window, remote_message->message,
450 remote_message->wParam, remote_message->lParam);
452 /* Tell the sended, that the message is here */
453 dde_proc_send_ack(remote_message->wParam, passed);
456 passed= PostMessage(dde_window, remote_message->message,
457 remote_message->wParam, remote_message->lParam);
458 if (passed == FALSE) {
459 /* Tell the sender, that the message is here, and failed */
460 dde_proc_send_ack(remote_message->wParam, FALSE);
463 /* ack will be sent later, at the first peek/get message */
464 dde_proc_add_fifo(remote_message->wParam);
471 /* iterate through all the windows */
472 for (hwnd = GetTopWindow(GetDesktopWindow());
473 hwnd && (window = WIN_FindWndPtr(hwnd))!=NULL ;
474 hwnd = window->hwndNext) {
475 if (window->dwStyle & WS_POPUP || window->dwStyle & WS_CAPTION) {
477 SendMessage( hwnd, remote_message->message,
478 remote_message->wParam, remote_message->lParam );
480 PostMessage( hwnd, remote_message->message,
481 remote_message->wParam, remote_message->lParam );
485 /* replay with DDE_ACK after broadcasting in DDE_GetRemoteMessage */
486 dde_proc_send_ack(remote_message->wParam, TRUE);
496 ack_wnd= dde_proc_shift_fifo();
498 dde_proc_send_ack(ack_wnd, TRUE);
499 usleep(10000); /* force unix task switch */
504 void dde_msg_setup(int *msg_ptr)
506 *msg_ptr= msgget (IPC_PRIVATE, IPC_CREAT | 0700);
508 perror("dde_msg_setup fails to get message queue");
511 /* do we have dde handling in the window ?
512 * If we have, atom usage will make this instance of wine set up
515 void DDE_TestDDE(HWND hwnd)
518 if (main_block != NULL)
520 dprintf_msg(stddeb,"DDE_TestDDE(0x%04x)\n", hwnd);
523 /* just send a message to see how things are going */
524 SendMessage( hwnd, WM_DDE_INITIATE, 0, 0);
527 void dde_proc_delete(int proc_idx)
529 dde_proc_done(&main_block->proc[proc_idx]);
531 void stop_wait(int a)
535 switch(stop_wait_op) {
537 siglongjmp(env_get_ack,1);
538 break; /* never reached */
540 siglongjmp(env_wait_x,1);
541 break; /* never reached */
547 static void print_dde_message(char *desc, MSG *msg)
549 extern const char *MessageTypeNames[];
550 extern int debug_last_handle_size;
554 DDEADVISE *ddeadvise;
558 if (is_dde_handle(msg->lParam & 0xffff) )
559 ptr=DDE_AttachHandle(msg->lParam&0xffff, NULL);
562 wStatus=LOWORD(msg->lParam);
563 hWord=HIWORD(msg->lParam);
565 fprintf(stddeb,"%s", desc);
566 fprintf(stddeb,"%04x %04x==%s %04x %08lx ",
567 msg->hwnd, msg->message,MessageTypeNames[msg->message],
568 msg->wParam, msg->lParam);
569 switch(msg->message) {
570 case WM_DDE_INITIATE:
573 case WM_DDE_TERMINATE:
577 /* DDEADVISE: hOptions in WM_DDE_ADVISE message */
580 fprintf(stddeb,"fDeferUpd=%d,fAckReq=%d,cfFormat=0x%x",
581 ddeadvise->fDeferUpd, ddeadvise->fAckReq,
582 ddeadvise->cfFormat);
584 fprintf(stddeb,"NO-DATA");
585 fprintf(stddeb," atom=0x%x",hWord);
588 case WM_DDE_UNADVISE:
589 fprintf(stddeb,"format=0x%x, atom=0x%x",wStatus,hWord);
592 ddeack=(DDEACK*)&wStatus;
593 fprintf(stddeb,"bAppReturnCode=%d,fBusy=%d,fAck=%d",
594 ddeack->bAppReturnCode, ddeack->fBusy, ddeack->fAck);
596 fprintf(stddeb,"(True)");
598 fprintf(stddeb,"(False)");
604 fprintf(stddeb,"fResponse=%d,fRelease=%d,"
605 "fAckReq=%d,cfFormat=0x%x,value=\"%.*s\"",
606 ddedata->fResponse, ddedata->fRelease,
607 ddedata->fAckReq, ddedata->cfFormat,
608 debug_last_handle_size- (int)sizeof(*ddedata)+1,
611 fprintf(stddeb,"NO-DATA");
612 fprintf(stddeb," atom=0x%04x",hWord);
618 fprintf(stddeb,"fRelease=%d,cfFormat=0x%x,value[0]='%c'",
619 ddepoke->fRelease, ddepoke->cfFormat, ddepoke->Value[0]);
621 fprintf(stddeb,"NO-DATA");
622 fprintf(stddeb," atom=0x%04x",hWord);
625 fprintf(stddeb,"\n");
628 void dde_proc_done(dde_proc proc)
631 msgctl(proc->msg, IPC_RMID, NULL);
634 shm_delete_chain(&proc->shmid);
635 shm_sem_done(&proc->sem);
638 /* delete entry, if old junk */
639 void dde_proc_refresh(dde_proc proc)
644 if (kill(proc->pid, 0) != -1)
647 /* get here if entry non empty, and the process does not exist */
655 for (i=0 ; i < DDE_WINDOWS ; i++)
656 main_block->windows[i].proc_idx = FREE_WND;
659 static BOOL DDE_ProcHasWindows(int proc_idx)
664 for ( i=0 ; i < DDE_WINDOWS ; i++) {
665 tested= &main_block->windows[ i ];
667 if (tested->proc_idx == proc_idx)
672 /* Look for hwnd in the hash table of DDE windows,
673 * Delete it from there. If there are no more windows for this
674 * process, remove the process from the DDE data-structure.
675 * If there are no more processes - delete the whole DDE struff.
677 * This is inefficient, but who cares for the efficiency of this rare
680 void DDE_DestroyWindow(HWND hwnd)
686 if (main_block == NULL)
689 dde_wnd_idx= hwnd % DDE_WINDOWS;
691 for ( i=0 ; i < DDE_WINDOWS ; i++, dde_wnd_idx++) {
692 if (dde_wnd_idx >= DDE_WINDOWS)
693 dde_wnd_idx -= DDE_WINDOWS; /* wrap-around */
695 tested= &main_block->windows[ dde_wnd_idx ];
696 if (tested->proc_idx == FREE_WND)
697 return; /* No window will get deleted here */
699 if (tested->wnd == hwnd && tested->proc_idx == curr_proc_idx) {
701 tested->proc_idx= DELETED_WND;
702 if (DDE_ProcHasWindows( curr_proc_idx ))
704 while (dde_reschedule()) /* make sure there are no other */
705 /* processes waiting for acknowledgment */
707 dde_proc_delete( curr_proc_idx );
708 if (DDE_no_of_attached() == 1)
711 shmdt( (void *) main_block);