Release 950901
[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__)
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 "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"
31
32 int curr_proc_idx= -1;
33
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;
38
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
53
54 struct msg_dat {
55         struct msgbuf dat;
56         char filler[DDE_MSG_SIZE];
57 } ;
58
59 typedef struct fifo_element {
60         int value;
61         struct fifo_element *next;
62 } fifo_element;
63
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 */
67 };
68 static struct fifo fifo = {NULL,NULL};
69
70 void dde_proc_delete(int proc_idx);
71
72 void dde_proc_add_fifo(int val)
73 {
74   fifo_element *created;
75
76   created= (fifo_element*) malloc( sizeof(fifo_element) );
77   created->value = val;
78   created->next = NULL;
79   
80   if (fifo.first==NULL) 
81      fifo.first= created;
82   else 
83      fifo.last->next= created;
84   fifo.last = created;
85 }
86
87 /* get an item from the fifo, and return it.
88  * If fifo is empty, return -1
89  */
90 int dde_proc_shift_fifo()
91 {
92   int val;
93   fifo_element *deleted;
94   
95   if (fifo.first == NULL)
96      return -1;
97   
98   deleted= fifo.first;
99   val= deleted->value;
100   fifo.first= deleted->next;
101   if (fifo.first == NULL)
102      fifo.last= NULL;
103
104   free(deleted);
105   return val;
106 }
107
108 static void print_dde_message(char *desc, MSG *msg);
109
110 /* This should be run only when main_block is first allocated.  */
111 void dde_proc_init(dde_proc proc)
112 {
113   int proc_num;
114
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;
120   }
121 }
122
123 /* add current process to the list of processes */
124 void dde_proc_add(dde_proc procs)
125 {
126   dde_proc proc;
127   int proc_idx;
128   dprintf_dde(stddeb,"dde_proc_add(..)\n");
129   shm_write_wait(main_block->sem);
130
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! */
135
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);
141   }
142   else  {
143      fflush(stdout);
144      fprintf(stderr,"dde_proc_add: Can't allocate process\n");
145   }
146   shm_write_signal(main_block->sem);
147 }
148
149 /* wait for dde - acknowledge message - or timout */
150 static BOOL get_ack()
151 {
152     struct timeval timeout;
153     int size;
154     struct msg_dat ack_buff;
155
156     /* timeout after exactly one seconf */
157     timeout.tv_sec = 1;
158     timeout.tv_usec = 0;
159
160     sigsetjmp(env_get_ack, 1);
161     /* get here after normal execution, or after siglongjmp */
162
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;
171        }
172        if (DDE_GetRemoteMessage()) {
173              had_SIGUSR2=1;  /* might have recieved SIGUSR2 */
174        }
175        stop_wait_op=STOP_WAIT_ACK; /* allow siglongjmp */
176
177     } while (had_SIGUSR2);         /* loop if SIGUSR2 was recieved */
178
179     /* siglongjmp should be enabled at this moment */
180     select( 0, NULL, NULL, NULL, &timeout );
181     stop_wait_op=CONT;             /* disallow further siglongjmp */
182
183     /* timeout !! (otherwise there would have been a siglongjmp) */
184     return FALSE;
185 }
186
187 /* Transfer one message to a given process */
188 static BOOL DDE_DoOneMessage (int proc_idx, int size, struct msgbuf *msgbuf)
189 {
190   dde_proc proc= &main_block->proc[ proc_idx ];
191
192
193   if (proc_idx == curr_proc_idx)
194      return FALSE;
195
196   if (kill(proc->pid,0) < 0) {
197      /* pid does not exist, or not our */
198      dde_proc_delete(proc_idx);
199      return FALSE;
200   }
201
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);
215   }
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);
223
224      if (size<0) {
225          fflush(stdout);
226          perror("msgsnd");
227      }
228      kill(proc->pid,SIGUSR2);      /* tell the process there is a message */
229
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;
241      }
242   }
243   else {
244      dprintf_msg(stddeb,"DDE_DoOneMessage: message not sent, "
245                  "target has no message queue\n");
246      return FALSE;
247   }
248 }
249
250 /* Do some sort of premitive hash table */
251 static HWND HWND_Local2Remote(HWND orig)
252 {
253   int dde_wnd_idx;
254   int deleted_idx= -1;
255   WND_DATA *tested;
256   WND_DATA *deleted= NULL;
257   int i;
258   
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 */
263     
264     tested= &main_block->windows[ dde_wnd_idx ];
265     if (tested->proc_idx == FREE_WND)
266       break;
267     
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);
273     }
274   }
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);
280   }
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);
285   }
286
287   fprintf(stderr,
288           "HWND_Local2Remote: Can't map any more windows to DDE windows\n");
289   return 0;                     
290 }
291
292 static BOOL DDE_DoMessage( MSG *msg, int type )
293 {
294   int proc_idx;
295
296   MSG *remote_message;
297   struct msg_dat msg_dat;
298   BOOL success;
299   
300   if (msg->wParam == 0)
301       return FALSE;
302   
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;
308   }
309
310
311   if (msg->wParam == (HWND)-1)
312      return FALSE;
313
314   if ( ! DDE_IsRemoteWindow(msg->hwnd) && msg->hwnd!= (HWND)-1)
315      return FALSE;
316
317   dprintf_msg(stddeb, "%s: DDE_DoMessage(hwnd=0x%x,msg=0x%x,..)\n",
318               msg_type[type], (int)msg->hwnd,(int)msg->message);
319
320
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;
325   
326   memcpy(remote_message, msg, sizeof(*msg));
327   remote_message->wParam= HWND_Local2Remote(msg->wParam);
328   if (remote_message->wParam == 0)
329     return FALSE;
330   
331   msg_dat.dat.mtype=type;
332
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);
340      }
341      return success;
342   } else {
343      return DDE_DoOneMessage(DDE_WIN2PROC(msg->hwnd), DDE_MSG_SIZE,
344                              &msg_dat.dat);
345   }
346 }
347
348 BOOL DDE_SendMessage( MSG *msg)
349 {
350   return DDE_DoMessage(msg, DDE_SEND);
351 }
352
353 BOOL DDE_PostMessage( MSG *msg)
354 {
355   return DDE_DoMessage(msg, DDE_POST);
356 }
357
358
359 void dde_proc_send_ack(HWND wnd, BOOL val) {
360    int proc,msg;
361
362    static struct msgbuf msg_ack={DDE_ACK,{'0'}};
363
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
369      );
370
371    msg_ack.mtext[0]=val;
372    msgsnd (msg, &msg_ack, 1, 0);
373    kill(main_block->proc[proc].pid, SIGUSR2);
374 }
375
376 /* return true (non zero) if had a remote message */
377 #undef DDE_GetRemoteMessage
378
379 int DDE_GetRemoteMessage()
380 {
381   static int nesting=0;            /* to avoid infinite recursion */
382
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;
390
391   if (curr_proc_idx==-1)           /* do we have DDE initialized ? */
392      return 0;
393
394   if (nesting>10) {
395      fflush(stdout);
396      fprintf(stderr,"DDE_GetRemoteMessage: suspecting infinite recursion, exiting");
397      return 0;
398   }
399
400   remote_message=(void*)&msg_dat.dat.mtext;
401
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);
405
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);
416
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);
424      }
425      else
426         return 0;                  /* no DDE message found */
427   }
428
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
431    */
432
433   nesting++;
434
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);
442   }
443
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);
453
454         /* execute the recieved message */
455         passed= SendMessage(dde_window, remote_message->message,
456                             remote_message->wParam, remote_message->lParam);
457
458         /* Tell the sended, that the message is here */
459         dde_proc_send_ack(remote_message->wParam, passed);
460      }
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);
467         }
468         else {
469            /* ack will be sent later, at the first peek/get message  */
470            dde_proc_add_fifo(remote_message->wParam);
471         }
472      }
473      nesting--;
474      return 1;
475   }
476
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 */
490
491   /* replay with DDE_ACK after broadcasting in DDE_GetRemoteMessage */
492   dde_proc_send_ack(remote_message->wParam, TRUE);
493
494   nesting--;
495   return 1;
496 }
497
498 int dde_reschedule()
499 {
500     int ack_wnd;
501         
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;
507     }
508     return 0;
509 }
510 void dde_msg_setup(int *msg_ptr)
511 {
512   *msg_ptr= msgget (IPC_PRIVATE, IPC_CREAT | 0700);
513   if (*msg_ptr==-1)
514      perror("dde_msg_setup fails to get message queue");
515 }
516
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.
520  */
521 void DDE_TestDDE(HWND hwnd)        
522 {
523
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);
531 }
532
533 void dde_proc_delete(int proc_idx)
534 {
535   dde_proc_done(&main_block->proc[proc_idx]);
536 }
537 void stop_wait(int a)
538 {
539
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 */
550   }
551 }
552
553 static void print_dde_message(char *desc, MSG *msg)
554 {
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;
563
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);
570
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;
593
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;
606
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;
620
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;
630     }
631     fprintf(stddeb,"\n");
632 }
633
634 void dde_proc_done(dde_proc proc)
635 {
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);
642 }
643
644 /* delete entry, if old junk */
645 void dde_proc_refresh(dde_proc proc)
646 {
647   if (proc->pid == -1)            
648      return;
649   
650   if (kill(proc->pid, 0) != -1)
651      return;
652
653   /* get here if entry non empty, and the process does not exist */
654   dde_proc_done(proc);
655 }
656
657 void dde_wnd_setup()
658 {
659   int i;
660
661   for (i=0 ; i < DDE_WINDOWS ; i++)
662     main_block->windows[i].proc_idx = FREE_WND;
663 }
664
665 static BOOL DDE_ProcHasWindows(int proc_idx)
666 {
667   WND_DATA *tested;
668   int i;
669   
670   for ( i=0 ; i < DDE_WINDOWS ; i++) {
671     tested= &main_block->windows[ i ];
672     
673     if (tested->proc_idx == proc_idx) 
674       return TRUE;
675   }
676   return FALSE;
677 }
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.
682  *
683  * This is inefficient, but who cares for the efficiency of this rare
684  * operation... 
685  */
686 void DDE_DestroyWindow(HWND hwnd)
687 {
688   int dde_wnd_idx;
689   WND_DATA *tested;
690   int i;
691   
692   if (main_block == NULL)
693     return;
694   
695   dde_wnd_idx= hwnd % DDE_WINDOWS;
696   
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 */
700     
701     tested= &main_block->windows[ dde_wnd_idx ];
702     if (tested->proc_idx == FREE_WND)
703       return;                   /* No window will get deleted here */
704     
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 */
712         ;
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;
719       }
720       return;
721     }
722   }
723 }
724
725 #endif  /* CONFIG_IPC */