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