Authors: Chris Morgan <cmorgan@wpi.edu>, James Abbatiello <abbeyj@wpi.edu>
[wine] / ipc / dde_proc.c
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
11
12 #if defined(__FreeBSD__) || defined(__NetBSD__) || defined(__OpenBSD__)
13 #define msgbuf mymsg
14 #endif
15
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 "windef.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 "debugtools.h"
30 #include "xmalloc.h"
31
32 DECLARE_DEBUG_CHANNEL(dde)
33 DECLARE_DEBUG_CHANNEL(msg)
34
35 int curr_proc_idx= -1;
36
37 enum stop_wait_op stop_wait_op=CONT;
38 int had_SIGUSR2 = 0;
39 sigjmp_buf env_get_ack;
40 sigjmp_buf env_wait_x;
41
42 #define IDX_TO_HWND(idx)  (0xfffe - (idx))
43 #define HWND_TO_IDX(wnd)  (0xfffe - (wnd))
44 #define DDE_WIN_INFO(win) ( main_block->windows[HWND_TO_IDX(win)] )
45 #define DDE_WIN2PROC(win) ( DDE_WIN_INFO(win).proc_idx )
46 #define DDE_IsRemoteWindow(win)  (  (win)<0xffff && (win)>=(0xffff-DDE_PROCS))
47 #define DDE_SEND 1
48 #define DDE_POST 2
49 #define DDE_ACK  3
50 #define DDE_MSG_SIZE   sizeof(MSG16)
51 #define FREE_WND (WORD)(-2)
52 #define DELETED_WND (WORD)(-3)
53 static char *msg_type[4]={"********", "DDE_SEND", "DDE_POST", "DDE_ACK"};
54
55 struct msg_dat {
56         struct msgbuf dat;
57         char filler[DDE_MSG_SIZE];
58 } ;
59
60 typedef struct fifo_element {
61         int value;
62         struct fifo_element *next;
63 } fifo_element;
64
65 struct fifo {
66         fifo_element *first;       /* first element in the fifo or NULL */
67         fifo_element *last;        /* last element in the fifo or NULL */
68 };
69 static struct fifo fifo = {NULL,NULL};
70
71 void dde_proc_delete(int proc_idx);
72
73 void dde_proc_add_fifo(int val)
74 {
75   fifo_element *created;
76
77   created= (fifo_element*) xmalloc( sizeof(fifo_element) );
78   created->value = val;
79   created->next = NULL;
80   
81   if (fifo.first==NULL) 
82      fifo.first= created;
83   else 
84      fifo.last->next= created;
85   fifo.last = created;
86 }
87
88 /* get an item from the fifo, and return it.
89  * If fifo is empty, return -1
90  */
91 int dde_proc_shift_fifo()
92 {
93   int val;
94   fifo_element *deleted;
95   
96   if (fifo.first == NULL)
97      return -1;
98   
99   deleted= fifo.first;
100   val= deleted->value;
101   fifo.first= deleted->next;
102   if (fifo.first == NULL)
103      fifo.last= NULL;
104
105   free(deleted);
106   return val;
107 }
108
109 static void print_dde_message(char *desc, MSG16 *msg);
110
111 /* This should be run only when main_block is first allocated.  */
112 void dde_proc_init(dde_proc proc)
113 {
114   int proc_num;
115
116   for (proc_num=0 ; proc_num<DDE_PROCS ; proc_num++, proc++) {
117      proc->msg=-1;
118      proc->sem=-1;
119      proc->shmid=-1;
120      proc->pid=-1;
121   }
122 }
123
124 /* add current process to the list of processes */
125 void dde_proc_add(dde_proc procs)
126 {
127   dde_proc proc;
128   int proc_idx;
129   TRACE_(dde)("(..)\n");
130   shm_write_wait(main_block->sem);
131
132   /* find free proc_idx and allocate it */
133   for (proc_idx=0, proc=procs ; proc_idx<DDE_PROCS ; proc_idx++, proc++)
134      if (proc->pid==-1)
135         break;                     /* found! */
136
137   if (proc_idx<DDE_PROCS) {        /* got here beacuse a free was found ? */
138      dde_msg_setup(&proc->msg);
139      proc->pid=getpid();
140      curr_proc_idx=proc_idx;
141      shm_sem_init(&proc->sem);
142   }
143   else  {
144      fflush(stdout);
145      WARN_(dde)("Can't allocate process\n");
146   }
147   shm_write_signal(main_block->sem);
148 }
149
150 /* wait for dde - acknowledge message - or timout */
151 static BOOL get_ack()
152 {
153     struct timeval timeout;
154     int size;
155     struct msg_dat ack_buff;
156
157     /* timeout after exactly one seconf */
158     timeout.tv_sec = 1;
159     timeout.tv_usec = 0;
160
161     sigsetjmp(env_get_ack, 1);
162     /* get here after normal execution, or after siglongjmp */
163
164     do {                           /* loop to wait for DDE_ACK */
165        had_SIGUSR2=0;
166        stop_wait_op=CONT;          /*  sensitive code: disallow siglongjmp */
167        size= msgrcv( main_block->proc[curr_proc_idx].msg , &ack_buff.dat,
168                      1, DDE_ACK, IPC_NOWAIT);
169        if (size>=0) {
170           TRACE_(msg)("get_ack: received DDE_ACK message\n");
171           return TRUE;
172        }
173        if (DDE_GetRemoteMessage()) {
174              had_SIGUSR2=1;  /* might have recieved SIGUSR2 */
175        }
176        stop_wait_op=STOP_WAIT_ACK; /* allow siglongjmp */
177
178     } while (had_SIGUSR2);         /* loop if SIGUSR2 was recieved */
179
180     /* siglongjmp should be enabled at this moment */
181     select( 0, NULL, NULL, NULL, &timeout );
182     stop_wait_op=CONT;             /* disallow further siglongjmp */
183
184     /* timeout !! (otherwise there would have been a siglongjmp) */
185     return FALSE;
186 }
187
188 /* Transfer one message to a given process */
189 static BOOL DDE_DoOneMessage (int proc_idx, int size, struct msgbuf *msgbuf)
190 {
191   dde_proc proc= &main_block->proc[ proc_idx ];
192
193
194   if (proc_idx == curr_proc_idx)
195      return FALSE;
196
197   if (kill(proc->pid,0) < 0) {
198      /* pid does not exist, or not our */
199      dde_proc_delete(proc_idx);
200      return FALSE;
201   }
202
203   if (TRACE_ON(dde) || WARN_ON_dde) {
204      MSG16 *msg=(MSG16*) &msgbuf->mtext;
205      char *title;
206      if (msgbuf->mtype==DDE_SEND)
207         title="sending dde:";
208      else if (msgbuf->mtype==DDE_POST)
209         title="posting dde:";
210      else
211         title=NULL;
212      if (title)
213          print_dde_message(title, msg);
214      else
215        WARN_(dde)("Unknown message type=0x%lx\n", msgbuf->mtype);
216   }
217   TRACE_(msg)("to proc_idx=%d (pid=%d), queue=%u\n",
218                proc_idx, proc->pid, (unsigned)proc->msg);
219   if ( proc->msg != -1) {
220      TRACE_(msg)("doing...(type=%s)\n", msg_type[msgbuf->mtype]);
221      size=msgsnd (proc->msg, msgbuf, size, 0);
222
223      if (size<0) {
224          fflush(stdout);
225          perror("msgsnd");
226      }
227      kill(proc->pid,SIGUSR2);      /* tell the process there is a message */
228
229      TRACE_(msg)("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         WARN_(dde)("get_ack: DDE_DoOneMessage: timeout\n");
238         return FALSE;
239      }
240   }
241   else {
242      WARN_(msg)("message not sent, target has no message queue\n");
243      return FALSE;
244   }
245 }
246
247 /* Do some sort of premitive hash table */
248 static HWND16 HWND_Local2Remote(HWND16 orig)
249 {
250   int dde_wnd_idx;
251   int deleted_idx= -1;
252   WND_DATA *tested;
253   WND_DATA *deleted= NULL;
254   int i;
255   
256   dde_wnd_idx= orig % DDE_WINDOWS;
257   for ( i=0 ; i < DDE_WINDOWS ; i++, dde_wnd_idx++) {
258     if (dde_wnd_idx >= DDE_WINDOWS)
259       dde_wnd_idx -= DDE_WINDOWS; /* wrap-around */
260     
261     tested= &main_block->windows[ dde_wnd_idx ];
262     if (tested->proc_idx == FREE_WND)
263       break;
264     
265     if (deleted == NULL && tested->proc_idx == DELETED_WND) {
266       deleted= tested;
267       deleted_idx= dde_wnd_idx;
268     } else if (tested->wnd == orig && tested->proc_idx == curr_proc_idx) {
269       return IDX_TO_HWND(dde_wnd_idx);
270     }
271   }
272   if (deleted != NULL)  {       /* deleted is preferable */
273     /* free item, allocate it */
274     deleted->proc_idx= curr_proc_idx;
275     deleted->wnd = orig;
276     return IDX_TO_HWND(deleted_idx);
277   }
278   if (tested->proc_idx == FREE_WND) {
279     tested->proc_idx= curr_proc_idx;
280     tested->wnd = orig;
281     return IDX_TO_HWND(dde_wnd_idx);
282   }
283
284   WARN_(dde)("Can't map any more windows to DDE windows\n");
285   return 0;                     
286 }
287
288 static BOOL DDE_DoMessage( MSG16 *msg, int type )
289 {
290   int proc_idx;
291
292   MSG16 *remote_message;
293   struct msg_dat msg_dat;
294   BOOL success;
295   
296   if (msg->wParam == 0)
297       return FALSE;
298   
299   if (main_block==NULL) {
300     if (msg->message >=  WM_DDE_FIRST && msg->message <= WM_DDE_LAST) 
301       DDE_IPC_init();
302     else 
303       return FALSE;
304   }
305
306
307   if (msg->wParam == (HWND16)-1)
308      return FALSE;
309
310   if ( ! DDE_IsRemoteWindow(msg->hwnd) && msg->hwnd!= (HWND16)-1)
311      return FALSE;
312
313   TRACE_(msg)("(hwnd=0x%x,msg=0x%x,..) - %s\n",
314                (int)msg->hwnd,(int)msg->message,msg_type[type]);
315   
316
317   TRACE_(msg)("(hwnd=0x%x,msg=0x%x,..) -- HWND_BROADCAST !\n",
318                (int)msg->hwnd,(int)msg->message);
319   remote_message=(void*)&msg_dat.dat.mtext;
320   
321   memcpy(remote_message, msg, sizeof(*msg));
322   remote_message->wParam= HWND_Local2Remote(msg->wParam);
323   if (remote_message->wParam == 0)
324     return FALSE;
325   
326   msg_dat.dat.mtype=type;
327
328   if (msg->hwnd == (HWND16)-1) {
329      success= FALSE;
330      for ( proc_idx=0; proc_idx < DDE_PROCS ; proc_idx++) {
331         if (proc_idx == curr_proc_idx)
332            continue;
333         if (main_block->proc[ proc_idx ].msg != -1)
334            success|=DDE_DoOneMessage(proc_idx, DDE_MSG_SIZE, &msg_dat.dat);
335      }
336      return success;
337   } else {
338      return DDE_DoOneMessage(DDE_WIN2PROC(msg->hwnd), DDE_MSG_SIZE,
339                              &msg_dat.dat);
340   }
341 }
342
343 BOOL DDE_SendMessage( MSG16 *msg)
344 {
345   return DDE_DoMessage(msg, DDE_SEND);
346 }
347
348 BOOL DDE_PostMessage( MSG16 *msg)
349 {
350   return DDE_DoMessage(msg, DDE_POST);
351 }
352
353
354 void dde_proc_send_ack(HWND16 wnd, BOOL val) {
355    int proc,msg;
356
357    static struct msgbuf msg_ack={DDE_ACK,{'0'}};
358
359    proc=DDE_WIN2PROC(wnd);
360    msg=main_block->proc[proc].msg;
361    TRACE_(msg)("sending ACK to wnd=%4x, proc=%d,msg=%d, pid=%d\n",
362                 wnd,proc,msg,main_block->proc[proc].pid);
363
364    msg_ack.mtext[0]=val;
365    msgsnd (msg, &msg_ack, 1, 0);
366    kill(main_block->proc[proc].pid, SIGUSR2);
367 }
368
369 /* return true (non zero) if had a remote message */
370 #undef DDE_GetRemoteMessage
371
372 int DDE_GetRemoteMessage()
373 {
374   static int nesting=0;            /* to avoid infinite recursion */
375
376   MSG16 *remote_message;
377   int size;
378   struct msg_dat msg_dat;
379   BOOL was_sent;                   /* sent/received */
380   BOOL passed;
381   WND *wndPtr;
382
383   if (curr_proc_idx==-1)           /* do we have DDE initialized ? */
384      return 0;
385
386   if (nesting>10) {
387      fflush(stdout);
388      ERR_(msg)("suspecting infinite recursion, exiting");
389      return 0;
390   }
391
392   remote_message=(void*)&msg_dat.dat.mtext;
393
394   /* test for SendMessage */
395   size= msgrcv( main_block->proc[curr_proc_idx].msg , &msg_dat.dat,
396                 DDE_MSG_SIZE, DDE_SEND, IPC_NOWAIT);
397
398   if (size==DDE_MSG_SIZE) {        /* is this a correct message (if any) ?*/
399      was_sent=TRUE;
400      TRACE_(msg)("DDE:receive sent message. msg=%04x wPar=%04x"
401                   " lPar=%08lx\n",
402                   remote_message->message, remote_message->wParam,
403                   remote_message->lParam);
404   } else {
405      size= msgrcv( main_block->proc[curr_proc_idx].msg , &msg_dat.dat,
406                    DDE_MSG_SIZE, DDE_POST, IPC_NOWAIT);
407
408      if (size==DDE_MSG_SIZE) {     /* is this a correct message (if any) ?*/
409         was_sent=FALSE;
410         TRACE_(msg)("DDE:receive posted message. "
411                     "msg=%04x wPar=%04x lPar=%08lx\n",
412                     remote_message->message, remote_message->wParam,
413                     remote_message->lParam);
414      }
415      else
416         return 0;                  /* no DDE message found */
417   }
418
419   /* At this point we are sure that there is a DDE message,
420    * was_sent is TRUE is the message was sent, and false if it was posted
421    */
422
423   nesting++;
424
425   if (TRACE_ON(dde)) {
426      char *title;
427      if (was_sent)
428         title="receive sent dde:";
429      else
430         title="receive posted dde:";
431      print_dde_message(title, remote_message);
432   }
433
434   if (remote_message->hwnd != (HWND16) -1 ) {
435     HWND16 dde_window= DDE_WIN_INFO(remote_message->hwnd).wnd;
436      /* we should know exactly where to send the message (locally)*/
437      if (was_sent) {
438         TRACE_(dde)("SendMessage(wnd=0x%04x, msg=0x%04x, wPar=0x%04x,"
439                     "lPar=0x%08x\n", dde_window, remote_message->message,
440                     remote_message->wParam, (int)remote_message->lParam);
441
442         /* execute the recieved message */
443         passed= SendMessage16(dde_window, remote_message->message,
444                             remote_message->wParam, remote_message->lParam);
445
446         /* Tell the sended, that the message is here */
447         dde_proc_send_ack(remote_message->wParam, passed);
448      }
449      else {
450         passed= PostMessage16(dde_window, remote_message->message,
451                             remote_message->wParam, remote_message->lParam);
452         if (passed == FALSE) {
453            /* Tell the sender, that the message is here, and failed */
454             dde_proc_send_ack(remote_message->wParam, FALSE);
455         }
456         else {
457            /* ack will be sent later, at the first peek/get message  */
458            dde_proc_add_fifo(remote_message->wParam);
459         }
460      }
461      nesting--;
462      return 1;
463   }
464
465   /* iterate through all the windows */
466   for (wndPtr = WIN_FindWndPtr(GetTopWindow(GetDesktopWindow()));
467        wndPtr != NULL;
468        WIN_UpdateWndPtr(&wndPtr,wndPtr->next))
469   {
470      if (wndPtr->dwStyle & WS_POPUP || wndPtr->dwStyle & WS_CAPTION) {
471         if (was_sent)
472            SendMessage16( wndPtr->hwndSelf, remote_message->message,
473                         remote_message->wParam, remote_message->lParam );
474         else
475            PostMessage16( wndPtr->hwndSelf, remote_message->message,
476                         remote_message->wParam, remote_message->lParam );
477      } /* if */
478   } /* for */
479
480   /* replay with DDE_ACK after broadcasting in DDE_GetRemoteMessage */
481   dde_proc_send_ack(remote_message->wParam, TRUE);
482
483   nesting--;
484   return 1;
485 }
486
487 int dde_reschedule()
488 {
489     int ack_wnd;
490         
491     ack_wnd= dde_proc_shift_fifo();
492     if (ack_wnd != -1) {
493         dde_proc_send_ack(ack_wnd, TRUE);
494         usleep(10000);          /* force unix task switch */
495         return 1;
496     }
497     return 0;
498 }
499 void dde_msg_setup(int *msg_ptr)
500 {
501   *msg_ptr= msgget (IPC_PRIVATE, IPC_CREAT | 0700);
502   if (*msg_ptr==-1)
503      perror("dde_msg_setup fails to get message queue");
504 }
505
506 /* do we have dde handling in the window ?
507  * If we have, atom usage will make this instance of wine set up
508  * it's IPC stuff.
509  */
510 void DDE_TestDDE(HWND16 hwnd)      
511 {
512   static in_test = 0;
513   if (in_test++) return;
514   if (main_block != NULL) {
515      in_test--;
516      return;
517   }
518   TRACE_(msg)("(0x%04x)\n", hwnd);
519   if (hwnd==0)
520       hwnd=-1;
521   /* just send a message to see how things are going */
522   SendMessage16( hwnd, WM_DDE_INITIATE, 0, 0);
523   in_test--;
524 }
525
526 void dde_proc_delete(int proc_idx)
527 {
528   dde_proc_done(&main_block->proc[proc_idx]);
529 }
530 void stop_wait(int a)
531 {
532
533   had_SIGUSR2=1;
534   switch(stop_wait_op) {
535     case STOP_WAIT_ACK:
536       siglongjmp(env_get_ack,1);
537       break;  /* never reached */
538     case STOP_WAIT_X:
539       siglongjmp(env_wait_x,1);
540       break;  /* never reached */
541     case CONT:
542       /* do nothing */
543   }
544 }
545
546 static void print_dde_message(char *desc, MSG16 *msg)
547 {
548 /*    extern const char *MessageTypeNames[];*/
549     extern int debug_last_handle_size;
550     WORD wStatus,hWord;
551     void *ptr;
552     DDEACK *ddeack;
553     DDEADVISE *ddeadvise;
554     DDEDATA *ddedata;
555     DDEPOKE *ddepoke;
556     dbg_decl_str(dde, 2048);
557
558     if (is_dde_handle(msg->lParam & 0xffff) )
559         ptr=DDE_AttachHandle(msg->lParam&0xffff, NULL);
560     else
561         ptr =NULL;
562     wStatus=LOWORD(msg->lParam);
563     hWord=HIWORD(msg->lParam);
564
565     dsprintf(dde,"%s", desc);
566     dsprintf(dde,"%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:
571       case WM_DDE_REQUEST:
572       case WM_DDE_EXECUTE:
573       case WM_DDE_TERMINATE:
574         /* nothing to do */
575         break;
576       case WM_DDE_ADVISE:
577         /* DDEADVISE: hOptions in WM_DDE_ADVISE message */
578         if (ptr) {
579            ddeadvise=ptr;
580            dsprintf(dde,"fDeferUpd=%d,fAckReq=%d,cfFormat=0x%x",
581                    ddeadvise->fDeferUpd, ddeadvise->fAckReq,
582                    ddeadvise->cfFormat);
583         } else
584            dsprintf(dde,"NO-DATA");
585         dsprintf(dde," atom=0x%x",hWord);
586         break;
587
588       case WM_DDE_UNADVISE:
589         dsprintf(dde,"format=0x%x, atom=0x%x",wStatus,hWord);
590         break;
591       case WM_DDE_ACK:
592         ddeack=(DDEACK*)&wStatus;
593         dsprintf(dde,"bAppReturnCode=%d,fBusy=%d,fAck=%d",
594                 ddeack->bAppReturnCode, ddeack->fBusy, ddeack->fAck);
595         if (ddeack->fAck)
596            dsprintf(dde,"(True)");
597         else
598            dsprintf(dde,"(False)");
599         break;
600
601       case WM_DDE_DATA:
602         if (ptr) {
603            ddedata=ptr;
604            dsprintf(dde,"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,
609                    ddedata->Value);
610         } else
611            dsprintf(dde,"NO-DATA");
612         dsprintf(dde," atom=0x%04x",hWord);
613         break;
614
615       case WM_DDE_POKE:
616         if (ptr) {
617            ddepoke=ptr;
618            dsprintf(dde,"fRelease=%d,cfFormat=0x%x,value[0]='%c'",
619                    ddepoke->fRelease, ddepoke->cfFormat, ddepoke->Value[0]);
620         } else
621            dsprintf(dde,"NO-DATA");
622         dsprintf(dde," atom=0x%04x",hWord);
623         break;
624     }
625     TRACE_(dde)("%s\n", dbg_str(dde));
626 }
627
628 void dde_proc_done(dde_proc proc)
629 {
630   if (proc->msg != -1)
631      msgctl(proc->msg, IPC_RMID, NULL);
632   proc->msg=-1;
633   proc->pid=-1;
634   shm_delete_chain(&proc->shmid);
635   shm_sem_done(&proc->sem);
636 }
637
638 /* delete entry, if old junk */
639 void dde_proc_refresh(dde_proc proc)
640 {
641   if (proc->pid == -1)            
642      return;
643   
644   if (kill(proc->pid, 0) != -1)
645      return;
646
647   /* get here if entry non empty, and the process does not exist */
648   dde_proc_done(proc);
649 }
650
651 void dde_wnd_setup()
652 {
653   int i;
654
655   for (i=0 ; i < DDE_WINDOWS ; i++)
656     main_block->windows[i].proc_idx = FREE_WND;
657 }
658
659 static BOOL DDE_ProcHasWindows(int proc_idx)
660 {
661   WND_DATA *tested;
662   int i;
663   
664   for ( i=0 ; i < DDE_WINDOWS ; i++) {
665     tested= &main_block->windows[ i ];
666     
667     if (tested->proc_idx == proc_idx) 
668       return TRUE;
669   }
670   return FALSE;
671 }
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.
676  *
677  * This is inefficient, but who cares for the efficiency of this rare
678  * operation... 
679  */
680 void DDE_DestroyWindow(HWND16 hwnd)
681 {
682   int dde_wnd_idx;
683   WND_DATA *tested;
684   int i;
685   
686   if (main_block == NULL)
687     return;
688   
689   dde_wnd_idx= hwnd % DDE_WINDOWS;
690   
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 */
694     
695     tested= &main_block->windows[ dde_wnd_idx ];
696     if (tested->proc_idx == FREE_WND)
697       return;                   /* No window will get deleted here */
698     
699     if (tested->wnd == hwnd && tested->proc_idx == curr_proc_idx) {
700       dde_reschedule();
701       tested->proc_idx= DELETED_WND;
702       if (DDE_ProcHasWindows( curr_proc_idx ))
703         return;
704       while (dde_reschedule())  /* make sure there are no other */
705                                 /* processes waiting for acknowledgment */
706         ;
707       dde_proc_delete( curr_proc_idx );
708       if (DDE_no_of_attached() == 1)
709         shm_delete_all(-1);
710       else {
711         shmdt( (void *) main_block);
712         main_block= NULL;
713       }
714       return;
715     }
716   }
717 }
718
719 #endif  /* CONFIG_IPC */