Release 960928
[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 #include "xmalloc.h"
32
33 int curr_proc_idx= -1;
34
35 enum stop_wait_op stop_wait_op=CONT;
36 int had_SIGUSR2 = 0;
37 sigjmp_buf env_get_ack;
38 sigjmp_buf env_wait_x;
39
40 #define IDX_TO_HWND(idx)  (0xfffe - (idx))
41 #define HWND_TO_IDX(wnd)  (0xfffe - (wnd))
42 #define DDE_WIN_INFO(win) ( main_block->windows[HWND_TO_IDX(win)] )
43 #define DDE_WIN2PROC(win) ( DDE_WIN_INFO(win).proc_idx )
44 #define DDE_IsRemoteWindow(win)  (  (win)<0xffff && (win)>=(0xffff-DDE_PROCS))
45 #define DDE_SEND 1
46 #define DDE_POST 2
47 #define DDE_ACK  3
48 #define DDE_MSG_SIZE   sizeof(MSG16)
49 #define FREE_WND (WORD)(-2)
50 #define DELETED_WND (WORD)(-3)
51 #if defined(DEBUG_MSG) || defined(DEBUG_RUNTIME)
52 static char *msg_type[4]={"********", "DDE_SEND", "DDE_POST", "DDE_ACK"};
53 #endif
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   dprintf_dde(stddeb,"dde_proc_add(..)\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      fprintf(stderr,"dde_proc_add: 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           dprintf_msg(stddeb,"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 (debugging_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        fprintf(stddeb,"Unknown message type=0x%lx\n",msgbuf->mtype);
216   }
217   dprintf_msg(stddeb,
218               "DDE_DoOneMessage: to proc_idx=%d (pid=%d), queue=%u\n",
219               proc_idx, proc->pid, (unsigned)proc->msg);
220   if ( proc->msg != -1) {
221      dprintf_msg(stddeb, "DDE_DoOneMessage: doing...(type=%s)\n",
222                  msg_type[msgbuf->mtype]);
223      size=msgsnd (proc->msg, msgbuf, size, 0);
224
225      if (size<0) {
226          fflush(stdout);
227          perror("msgsnd");
228      }
229      kill(proc->pid,SIGUSR2);      /* tell the process there is a message */
230
231      dprintf_msg(stddeb,"DDE_DoOneMessage: "
232                  "Trying to get acknowledgment from msg queue=%d\n",
233                  proc->msg);
234      Yield();                   /* force task switch, and */
235                                 /* acknowledgment sending */
236      if (get_ack()) {
237         return TRUE;
238      } else {
239         fflush(stdout);
240         fprintf(stderr,"get_ack: DDE_DoOneMessage: timeout\n");
241         return FALSE;
242      }
243   }
244   else {
245      dprintf_msg(stddeb,"DDE_DoOneMessage: message not sent, "
246                  "target has no message queue\n");
247      return FALSE;
248   }
249 }
250
251 /* Do some sort of premitive hash table */
252 static HWND HWND_Local2Remote(HWND orig)
253 {
254   int dde_wnd_idx;
255   int deleted_idx= -1;
256   WND_DATA *tested;
257   WND_DATA *deleted= NULL;
258   int i;
259   
260   dde_wnd_idx= orig % DDE_WINDOWS;
261   for ( i=0 ; i < DDE_WINDOWS ; i++, dde_wnd_idx++) {
262     if (dde_wnd_idx >= DDE_WINDOWS)
263       dde_wnd_idx -= DDE_WINDOWS; /* wrap-around */
264     
265     tested= &main_block->windows[ dde_wnd_idx ];
266     if (tested->proc_idx == FREE_WND)
267       break;
268     
269     if (deleted == NULL && tested->proc_idx == DELETED_WND) {
270       deleted= tested;
271       deleted_idx= dde_wnd_idx;
272     } else if (tested->wnd == orig && tested->proc_idx == curr_proc_idx) {
273       return IDX_TO_HWND(dde_wnd_idx);
274     }
275   }
276   if (deleted != NULL)  {       /* deleted is preferable */
277     /* free item, allocate it */
278     deleted->proc_idx= curr_proc_idx;
279     deleted->wnd = orig;
280     return IDX_TO_HWND(deleted_idx);
281   }
282   if (tested->proc_idx == FREE_WND) {
283     tested->proc_idx= curr_proc_idx;
284     tested->wnd = orig;
285     return IDX_TO_HWND(dde_wnd_idx);
286   }
287
288   fprintf(stderr,
289           "HWND_Local2Remote: Can't map any more windows to DDE windows\n");
290   return 0;                     
291 }
292
293 static BOOL DDE_DoMessage( MSG16 *msg, int type )
294 {
295   int proc_idx;
296
297   MSG16 *remote_message;
298   struct msg_dat msg_dat;
299   BOOL success;
300   
301   if (msg->wParam == 0)
302       return FALSE;
303   
304   if (main_block==NULL) {
305     if (msg->message >=  WM_DDE_FIRST && msg->message <= WM_DDE_LAST) 
306       DDE_IPC_init();
307     else 
308       return FALSE;
309   }
310
311
312   if (msg->wParam == (HWND)-1)
313      return FALSE;
314
315   if ( ! DDE_IsRemoteWindow(msg->hwnd) && msg->hwnd!= (HWND)-1)
316      return FALSE;
317
318   dprintf_msg(stddeb, "%s: DDE_DoMessage(hwnd=0x%x,msg=0x%x,..)\n",
319               msg_type[type], (int)msg->hwnd,(int)msg->message);
320
321
322   dprintf_msg(stddeb,
323               "DDE_DoMessage(hwnd=0x%x,msg=0x%x,..) // HWND_BROADCAST !\n",
324               (int)msg->hwnd,(int)msg->message);
325   remote_message=(void*)&msg_dat.dat.mtext;
326   
327   memcpy(remote_message, msg, sizeof(*msg));
328   remote_message->wParam= HWND_Local2Remote(msg->wParam);
329   if (remote_message->wParam == 0)
330     return FALSE;
331   
332   msg_dat.dat.mtype=type;
333
334   if (msg->hwnd == (HWND)-1) {
335      success= FALSE;
336      for ( proc_idx=0; proc_idx < DDE_PROCS ; proc_idx++) {
337         if (proc_idx == curr_proc_idx)
338            continue;
339         if (main_block->proc[ proc_idx ].msg != -1)
340            success|=DDE_DoOneMessage(proc_idx, DDE_MSG_SIZE, &msg_dat.dat);
341      }
342      return success;
343   } else {
344      return DDE_DoOneMessage(DDE_WIN2PROC(msg->hwnd), DDE_MSG_SIZE,
345                              &msg_dat.dat);
346   }
347 }
348
349 BOOL DDE_SendMessage( MSG16 *msg)
350 {
351   return DDE_DoMessage(msg, DDE_SEND);
352 }
353
354 BOOL DDE_PostMessage( MSG16 *msg)
355 {
356   return DDE_DoMessage(msg, DDE_POST);
357 }
358
359
360 void dde_proc_send_ack(HWND wnd, BOOL val) {
361    int proc,msg;
362
363    static struct msgbuf msg_ack={DDE_ACK,{'0'}};
364
365    proc=DDE_WIN2PROC(wnd);
366    msg=main_block->proc[proc].msg;
367    dprintf_msg(stddeb,"DDE_GetRemoteMessage: sending ACK "
368                "to wnd=%4x, proc=%d,msg=%d, pid=%d\n",wnd,proc,msg,
369                main_block->proc[proc].pid
370      );
371
372    msg_ack.mtext[0]=val;
373    msgsnd (msg, &msg_ack, 1, 0);
374    kill(main_block->proc[proc].pid, SIGUSR2);
375 }
376
377 /* return true (non zero) if had a remote message */
378 #undef DDE_GetRemoteMessage
379
380 int DDE_GetRemoteMessage()
381 {
382   static int nesting=0;            /* to avoid infinite recursion */
383
384   MSG16 *remote_message;
385   int size;
386   struct msg_dat msg_dat;
387   BOOL was_sent;                   /* sent/received */
388   BOOL passed;
389   WND *wndPtr;
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= SendMessage16(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 (wndPtr = WIN_FindWndPtr(GetTopWindow(GetDesktopWindow32()));
479        wndPtr != NULL;
480        wndPtr = wndPtr->next)
481   {
482      if (wndPtr->dwStyle & WS_POPUP || wndPtr->dwStyle & WS_CAPTION) {
483         if (was_sent)
484            SendMessage16( wndPtr->hwndSelf, remote_message->message,
485                         remote_message->wParam, remote_message->lParam );
486         else
487            PostMessage( wndPtr->hwndSelf, remote_message->message,
488                         remote_message->wParam, remote_message->lParam );
489      } /* if */
490   } /* for */
491
492   /* replay with DDE_ACK after broadcasting in DDE_GetRemoteMessage */
493   dde_proc_send_ack(remote_message->wParam, TRUE);
494
495   nesting--;
496   return 1;
497 }
498
499 int dde_reschedule()
500 {
501     int ack_wnd;
502         
503     ack_wnd= dde_proc_shift_fifo();
504     if (ack_wnd != -1) {
505         dde_proc_send_ack(ack_wnd, TRUE);
506         usleep(10000);          /* force unix task switch */
507         return 1;
508     }
509     return 0;
510 }
511 void dde_msg_setup(int *msg_ptr)
512 {
513   *msg_ptr= msgget (IPC_PRIVATE, IPC_CREAT | 0700);
514   if (*msg_ptr==-1)
515      perror("dde_msg_setup fails to get message queue");
516 }
517
518 /* do we have dde handling in the window ?
519  * If we have, atom usage will make this instance of wine set up
520  * it's IPC stuff.
521  */
522 void DDE_TestDDE(HWND hwnd)        
523 {
524   static in_test = 0;
525   if (in_test++) return;
526   if (main_block != NULL) {
527      in_test--;
528      return;
529   }
530   dprintf_msg(stddeb,"DDE_TestDDE(0x%04x)\n", hwnd);
531   if (hwnd==0)
532       hwnd=-1;
533   /* just send a message to see how things are going */
534   SendMessage16( hwnd, WM_DDE_INITIATE, 0, 0);
535   in_test--;
536 }
537
538 void dde_proc_delete(int proc_idx)
539 {
540   dde_proc_done(&main_block->proc[proc_idx]);
541 }
542 void stop_wait(int a)
543 {
544
545   had_SIGUSR2=1;
546   switch(stop_wait_op) {
547     case STOP_WAIT_ACK:
548       siglongjmp(env_get_ack,1);
549       break;  /* never reached */
550     case STOP_WAIT_X:
551       siglongjmp(env_wait_x,1);
552       break;  /* never reached */
553     case CONT:
554       /* do nothing */
555   }
556 }
557
558 static void print_dde_message(char *desc, MSG16 *msg)
559 {
560 /*    extern const char *MessageTypeNames[];*/
561     extern int debug_last_handle_size;
562     WORD wStatus,hWord;
563     void *ptr;
564     DDEACK *ddeack;
565     DDEADVISE *ddeadvise;
566     DDEDATA *ddedata;
567     DDEPOKE *ddepoke;
568
569     if (is_dde_handle(msg->lParam & 0xffff) )
570         ptr=DDE_AttachHandle(msg->lParam&0xffff, NULL);
571     else
572         ptr =NULL;
573     wStatus=LOWORD(msg->lParam);
574     hWord=HIWORD(msg->lParam);
575
576     fprintf(stddeb,"%s", desc);
577     fprintf(stddeb,"%04x %04x==%s %04x %08lx ",
578             msg->hwnd, msg->message,"",/*MessageTypeNames[msg->message],*/
579             msg->wParam, msg->lParam);
580     switch(msg->message) {
581       case WM_DDE_INITIATE:
582       case WM_DDE_REQUEST:
583       case WM_DDE_EXECUTE:
584       case WM_DDE_TERMINATE:
585         /* nothing to do */
586         break;
587       case WM_DDE_ADVISE:
588         /* DDEADVISE: hOptions in WM_DDE_ADVISE message */
589         if (ptr) {
590            ddeadvise=ptr;
591            fprintf(stddeb,"fDeferUpd=%d,fAckReq=%d,cfFormat=0x%x",
592                    ddeadvise->fDeferUpd, ddeadvise->fAckReq,
593                    ddeadvise->cfFormat);
594         } else
595            fprintf(stddeb,"NO-DATA");
596         fprintf(stddeb," atom=0x%x",hWord);
597         break;
598
599       case WM_DDE_UNADVISE:
600         fprintf(stddeb,"format=0x%x, atom=0x%x",wStatus,hWord);
601         break;
602       case WM_DDE_ACK:
603         ddeack=(DDEACK*)&wStatus;
604         fprintf(stddeb,"bAppReturnCode=%d,fBusy=%d,fAck=%d",
605                 ddeack->bAppReturnCode, ddeack->fBusy, ddeack->fAck);
606         if (ddeack->fAck)
607            fprintf(stddeb,"(True)");
608         else
609            fprintf(stddeb,"(False)");
610         break;
611
612       case WM_DDE_DATA:
613         if (ptr) {
614            ddedata=ptr;
615            fprintf(stddeb,"fResponse=%d,fRelease=%d,"
616                    "fAckReq=%d,cfFormat=0x%x,value=\"%.*s\"",
617                    ddedata->fResponse, ddedata->fRelease,
618                    ddedata->fAckReq, ddedata->cfFormat,
619                    debug_last_handle_size- (int)sizeof(*ddedata)+1,
620                    ddedata->Value);
621         } else
622            fprintf(stddeb,"NO-DATA");
623         fprintf(stddeb," atom=0x%04x",hWord);
624         break;
625
626       case WM_DDE_POKE:
627         if (ptr) {
628            ddepoke=ptr;
629            fprintf(stddeb,"fRelease=%d,cfFormat=0x%x,value[0]='%c'",
630                    ddepoke->fRelease, ddepoke->cfFormat, ddepoke->Value[0]);
631         } else
632            fprintf(stddeb,"NO-DATA");
633         fprintf(stddeb," atom=0x%04x",hWord);
634         break;
635     }
636     fprintf(stddeb,"\n");
637 }
638
639 void dde_proc_done(dde_proc proc)
640 {
641   if (proc->msg != -1)
642      msgctl(proc->msg, IPC_RMID, NULL);
643   proc->msg=-1;
644   proc->pid=-1;
645   shm_delete_chain(&proc->shmid);
646   shm_sem_done(&proc->sem);
647 }
648
649 /* delete entry, if old junk */
650 void dde_proc_refresh(dde_proc proc)
651 {
652   if (proc->pid == -1)            
653      return;
654   
655   if (kill(proc->pid, 0) != -1)
656      return;
657
658   /* get here if entry non empty, and the process does not exist */
659   dde_proc_done(proc);
660 }
661
662 void dde_wnd_setup()
663 {
664   int i;
665
666   for (i=0 ; i < DDE_WINDOWS ; i++)
667     main_block->windows[i].proc_idx = FREE_WND;
668 }
669
670 static BOOL DDE_ProcHasWindows(int proc_idx)
671 {
672   WND_DATA *tested;
673   int i;
674   
675   for ( i=0 ; i < DDE_WINDOWS ; i++) {
676     tested= &main_block->windows[ i ];
677     
678     if (tested->proc_idx == proc_idx) 
679       return TRUE;
680   }
681   return FALSE;
682 }
683 /* Look for hwnd in the hash table of DDE windows,
684  * Delete it from there. If there are no more windows for this
685  * process, remove the process from the DDE data-structure.
686  * If there are no more processes - delete the whole DDE struff.
687  *
688  * This is inefficient, but who cares for the efficiency of this rare
689  * operation... 
690  */
691 void DDE_DestroyWindow(HWND hwnd)
692 {
693   int dde_wnd_idx;
694   WND_DATA *tested;
695   int i;
696   
697   if (main_block == NULL)
698     return;
699   
700   dde_wnd_idx= hwnd % DDE_WINDOWS;
701   
702   for ( i=0 ; i < DDE_WINDOWS ; i++, dde_wnd_idx++) {
703     if (dde_wnd_idx >= DDE_WINDOWS)
704       dde_wnd_idx -= DDE_WINDOWS; /* wrap-around */
705     
706     tested= &main_block->windows[ dde_wnd_idx ];
707     if (tested->proc_idx == FREE_WND)
708       return;                   /* No window will get deleted here */
709     
710     if (tested->wnd == hwnd && tested->proc_idx == curr_proc_idx) {
711       dde_reschedule();
712       tested->proc_idx= DELETED_WND;
713       if (DDE_ProcHasWindows( curr_proc_idx ))
714         return;
715       while (dde_reschedule())  /* make sure there are no other */
716                                 /* processes waiting for acknowledgment */
717         ;
718       dde_proc_delete( curr_proc_idx );
719       if (DDE_no_of_attached() == 1)
720         shm_delete_all(-1);
721       else {
722         shmdt( (void *) main_block);
723         main_block= NULL;
724       }
725       return;
726     }
727   }
728 }
729
730 #endif  /* CONFIG_IPC */