| /*************************************************************************** |
| * Copyright 1995, Technion, Israel Institute of Technology |
| * Electrical Eng, Software Lab. |
| * Author: Michael Veksler. |
| *************************************************************************** |
| * File: dde_proc.c |
| * Purpose : DDE signals and processes functionality for DDE |
| *************************************************************************** |
| */ |
| #ifdef CONFIG_IPC |
| |
| #if defined(__FreeBSD__) || defined(__NetBSD__) || defined(__OpenBSD__) |
| #define msgbuf mymsg |
| #endif |
| |
| #include <sys/time.h> |
| #include <unistd.h> |
| #include <stdlib.h> |
| #include <signal.h> |
| #include <errno.h> |
| #include <sys/msg.h> |
| #include "windef.h" |
| #include "win.h" |
| #include "shm_semaph.h" |
| #include "shm_main_blk.h" |
| #include "dde_proc.h" |
| #include "dde_mem.h" |
| #include "dde.h" |
| #include "debug.h" |
| #include "xmalloc.h" |
| |
| int curr_proc_idx= -1; |
| |
| enum stop_wait_op stop_wait_op=CONT; |
| int had_SIGUSR2 = 0; |
| sigjmp_buf env_get_ack; |
| sigjmp_buf env_wait_x; |
| |
| #define IDX_TO_HWND(idx) (0xfffe - (idx)) |
| #define HWND_TO_IDX(wnd) (0xfffe - (wnd)) |
| #define DDE_WIN_INFO(win) ( main_block->windows[HWND_TO_IDX(win)] ) |
| #define DDE_WIN2PROC(win) ( DDE_WIN_INFO(win).proc_idx ) |
| #define DDE_IsRemoteWindow(win) ( (win)<0xffff && (win)>=(0xffff-DDE_PROCS)) |
| #define DDE_SEND 1 |
| #define DDE_POST 2 |
| #define DDE_ACK 3 |
| #define DDE_MSG_SIZE sizeof(MSG16) |
| #define FREE_WND (WORD)(-2) |
| #define DELETED_WND (WORD)(-3) |
| static char *msg_type[4]={"********", "DDE_SEND", "DDE_POST", "DDE_ACK"}; |
| |
| struct msg_dat { |
| struct msgbuf dat; |
| char filler[DDE_MSG_SIZE]; |
| } ; |
| |
| typedef struct fifo_element { |
| int value; |
| struct fifo_element *next; |
| } fifo_element; |
| |
| struct fifo { |
| fifo_element *first; /* first element in the fifo or NULL */ |
| fifo_element *last; /* last element in the fifo or NULL */ |
| }; |
| static struct fifo fifo = {NULL,NULL}; |
| |
| void dde_proc_delete(int proc_idx); |
| |
| void dde_proc_add_fifo(int val) |
| { |
| fifo_element *created; |
| |
| created= (fifo_element*) xmalloc( sizeof(fifo_element) ); |
| created->value = val; |
| created->next = NULL; |
| |
| if (fifo.first==NULL) |
| fifo.first= created; |
| else |
| fifo.last->next= created; |
| fifo.last = created; |
| } |
| |
| /* get an item from the fifo, and return it. |
| * If fifo is empty, return -1 |
| */ |
| int dde_proc_shift_fifo() |
| { |
| int val; |
| fifo_element *deleted; |
| |
| if (fifo.first == NULL) |
| return -1; |
| |
| deleted= fifo.first; |
| val= deleted->value; |
| fifo.first= deleted->next; |
| if (fifo.first == NULL) |
| fifo.last= NULL; |
| |
| free(deleted); |
| return val; |
| } |
| |
| static void print_dde_message(char *desc, MSG16 *msg); |
| |
| /* This should be run only when main_block is first allocated. */ |
| void dde_proc_init(dde_proc proc) |
| { |
| int proc_num; |
| |
| for (proc_num=0 ; proc_num<DDE_PROCS ; proc_num++, proc++) { |
| proc->msg=-1; |
| proc->sem=-1; |
| proc->shmid=-1; |
| proc->pid=-1; |
| } |
| } |
| |
| /* add current process to the list of processes */ |
| void dde_proc_add(dde_proc procs) |
| { |
| dde_proc proc; |
| int proc_idx; |
| TRACE(dde,"(..)\n"); |
| shm_write_wait(main_block->sem); |
| |
| /* find free proc_idx and allocate it */ |
| for (proc_idx=0, proc=procs ; proc_idx<DDE_PROCS ; proc_idx++, proc++) |
| if (proc->pid==-1) |
| break; /* found! */ |
| |
| if (proc_idx<DDE_PROCS) { /* got here beacuse a free was found ? */ |
| dde_msg_setup(&proc->msg); |
| proc->pid=getpid(); |
| curr_proc_idx=proc_idx; |
| shm_sem_init(&proc->sem); |
| } |
| else { |
| fflush(stdout); |
| WARN(dde,"Can't allocate process\n"); |
| } |
| shm_write_signal(main_block->sem); |
| } |
| |
| /* wait for dde - acknowledge message - or timout */ |
| static BOOL get_ack() |
| { |
| struct timeval timeout; |
| int size; |
| struct msg_dat ack_buff; |
| |
| /* timeout after exactly one seconf */ |
| timeout.tv_sec = 1; |
| timeout.tv_usec = 0; |
| |
| sigsetjmp(env_get_ack, 1); |
| /* get here after normal execution, or after siglongjmp */ |
| |
| do { /* loop to wait for DDE_ACK */ |
| had_SIGUSR2=0; |
| stop_wait_op=CONT; /* sensitive code: disallow siglongjmp */ |
| size= msgrcv( main_block->proc[curr_proc_idx].msg , &ack_buff.dat, |
| 1, DDE_ACK, IPC_NOWAIT); |
| if (size>=0) { |
| TRACE(msg,"get_ack: received DDE_ACK message\n"); |
| return TRUE; |
| } |
| if (DDE_GetRemoteMessage()) { |
| had_SIGUSR2=1; /* might have recieved SIGUSR2 */ |
| } |
| stop_wait_op=STOP_WAIT_ACK; /* allow siglongjmp */ |
| |
| } while (had_SIGUSR2); /* loop if SIGUSR2 was recieved */ |
| |
| /* siglongjmp should be enabled at this moment */ |
| select( 0, NULL, NULL, NULL, &timeout ); |
| stop_wait_op=CONT; /* disallow further siglongjmp */ |
| |
| /* timeout !! (otherwise there would have been a siglongjmp) */ |
| return FALSE; |
| } |
| |
| /* Transfer one message to a given process */ |
| static BOOL DDE_DoOneMessage (int proc_idx, int size, struct msgbuf *msgbuf) |
| { |
| dde_proc proc= &main_block->proc[ proc_idx ]; |
| |
| |
| if (proc_idx == curr_proc_idx) |
| return FALSE; |
| |
| if (kill(proc->pid,0) < 0) { |
| /* pid does not exist, or not our */ |
| dde_proc_delete(proc_idx); |
| return FALSE; |
| } |
| |
| if (TRACE_ON(dde) || WARN_ON_dde) { |
| MSG16 *msg=(MSG16*) &msgbuf->mtext; |
| char *title; |
| if (msgbuf->mtype==DDE_SEND) |
| title="sending dde:"; |
| else if (msgbuf->mtype==DDE_POST) |
| title="posting dde:"; |
| else |
| title=NULL; |
| if (title) |
| print_dde_message(title, msg); |
| else |
| WARN(dde, "Unknown message type=0x%lx\n", msgbuf->mtype); |
| } |
| TRACE(msg, "to proc_idx=%d (pid=%d), queue=%u\n", |
| proc_idx, proc->pid, (unsigned)proc->msg); |
| if ( proc->msg != -1) { |
| TRACE(msg, "doing...(type=%s)\n", msg_type[msgbuf->mtype]); |
| size=msgsnd (proc->msg, msgbuf, size, 0); |
| |
| if (size<0) { |
| fflush(stdout); |
| perror("msgsnd"); |
| } |
| kill(proc->pid,SIGUSR2); /* tell the process there is a message */ |
| |
| TRACE(msg, "Trying to get acknowledgment from msg queue=%d\n", |
| proc->msg); |
| Yield16(); /* force task switch, and */ |
| /* acknowledgment sending */ |
| if (get_ack()) { |
| return TRUE; |
| } else { |
| fflush(stdout); |
| WARN(dde,"get_ack: DDE_DoOneMessage: timeout\n"); |
| return FALSE; |
| } |
| } |
| else { |
| WARN(msg, "message not sent, target has no message queue\n"); |
| return FALSE; |
| } |
| } |
| |
| /* Do some sort of premitive hash table */ |
| static HWND16 HWND_Local2Remote(HWND16 orig) |
| { |
| int dde_wnd_idx; |
| int deleted_idx= -1; |
| WND_DATA *tested; |
| WND_DATA *deleted= NULL; |
| int i; |
| |
| dde_wnd_idx= orig % DDE_WINDOWS; |
| for ( i=0 ; i < DDE_WINDOWS ; i++, dde_wnd_idx++) { |
| if (dde_wnd_idx >= DDE_WINDOWS) |
| dde_wnd_idx -= DDE_WINDOWS; /* wrap-around */ |
| |
| tested= &main_block->windows[ dde_wnd_idx ]; |
| if (tested->proc_idx == FREE_WND) |
| break; |
| |
| if (deleted == NULL && tested->proc_idx == DELETED_WND) { |
| deleted= tested; |
| deleted_idx= dde_wnd_idx; |
| } else if (tested->wnd == orig && tested->proc_idx == curr_proc_idx) { |
| return IDX_TO_HWND(dde_wnd_idx); |
| } |
| } |
| if (deleted != NULL) { /* deleted is preferable */ |
| /* free item, allocate it */ |
| deleted->proc_idx= curr_proc_idx; |
| deleted->wnd = orig; |
| return IDX_TO_HWND(deleted_idx); |
| } |
| if (tested->proc_idx == FREE_WND) { |
| tested->proc_idx= curr_proc_idx; |
| tested->wnd = orig; |
| return IDX_TO_HWND(dde_wnd_idx); |
| } |
| |
| WARN(dde, "Can't map any more windows to DDE windows\n"); |
| return 0; |
| } |
| |
| static BOOL DDE_DoMessage( MSG16 *msg, int type ) |
| { |
| int proc_idx; |
| |
| MSG16 *remote_message; |
| struct msg_dat msg_dat; |
| BOOL success; |
| |
| if (msg->wParam == 0) |
| return FALSE; |
| |
| if (main_block==NULL) { |
| if (msg->message >= WM_DDE_FIRST && msg->message <= WM_DDE_LAST) |
| DDE_IPC_init(); |
| else |
| return FALSE; |
| } |
| |
| |
| if (msg->wParam == (HWND16)-1) |
| return FALSE; |
| |
| if ( ! DDE_IsRemoteWindow(msg->hwnd) && msg->hwnd!= (HWND16)-1) |
| return FALSE; |
| |
| TRACE(msg, "(hwnd=0x%x,msg=0x%x,..) - %s\n", |
| (int)msg->hwnd,(int)msg->message,msg_type[type]); |
| |
| |
| TRACE(msg, "(hwnd=0x%x,msg=0x%x,..) -- HWND_BROADCAST !\n", |
| (int)msg->hwnd,(int)msg->message); |
| remote_message=(void*)&msg_dat.dat.mtext; |
| |
| memcpy(remote_message, msg, sizeof(*msg)); |
| remote_message->wParam= HWND_Local2Remote(msg->wParam); |
| if (remote_message->wParam == 0) |
| return FALSE; |
| |
| msg_dat.dat.mtype=type; |
| |
| if (msg->hwnd == (HWND16)-1) { |
| success= FALSE; |
| for ( proc_idx=0; proc_idx < DDE_PROCS ; proc_idx++) { |
| if (proc_idx == curr_proc_idx) |
| continue; |
| if (main_block->proc[ proc_idx ].msg != -1) |
| success|=DDE_DoOneMessage(proc_idx, DDE_MSG_SIZE, &msg_dat.dat); |
| } |
| return success; |
| } else { |
| return DDE_DoOneMessage(DDE_WIN2PROC(msg->hwnd), DDE_MSG_SIZE, |
| &msg_dat.dat); |
| } |
| } |
| |
| BOOL DDE_SendMessage( MSG16 *msg) |
| { |
| return DDE_DoMessage(msg, DDE_SEND); |
| } |
| |
| BOOL DDE_PostMessage( MSG16 *msg) |
| { |
| return DDE_DoMessage(msg, DDE_POST); |
| } |
| |
| |
| void dde_proc_send_ack(HWND16 wnd, BOOL val) { |
| int proc,msg; |
| |
| static struct msgbuf msg_ack={DDE_ACK,{'0'}}; |
| |
| proc=DDE_WIN2PROC(wnd); |
| msg=main_block->proc[proc].msg; |
| TRACE(msg,"sending ACK to wnd=%4x, proc=%d,msg=%d, pid=%d\n", |
| wnd,proc,msg,main_block->proc[proc].pid); |
| |
| msg_ack.mtext[0]=val; |
| msgsnd (msg, &msg_ack, 1, 0); |
| kill(main_block->proc[proc].pid, SIGUSR2); |
| } |
| |
| /* return true (non zero) if had a remote message */ |
| #undef DDE_GetRemoteMessage |
| |
| int DDE_GetRemoteMessage() |
| { |
| static int nesting=0; /* to avoid infinite recursion */ |
| |
| MSG16 *remote_message; |
| int size; |
| struct msg_dat msg_dat; |
| BOOL was_sent; /* sent/received */ |
| BOOL passed; |
| WND *wndPtr; |
| |
| if (curr_proc_idx==-1) /* do we have DDE initialized ? */ |
| return 0; |
| |
| if (nesting>10) { |
| fflush(stdout); |
| ERR(msg, "suspecting infinite recursion, exiting"); |
| return 0; |
| } |
| |
| remote_message=(void*)&msg_dat.dat.mtext; |
| |
| /* test for SendMessage */ |
| size= msgrcv( main_block->proc[curr_proc_idx].msg , &msg_dat.dat, |
| DDE_MSG_SIZE, DDE_SEND, IPC_NOWAIT); |
| |
| if (size==DDE_MSG_SIZE) { /* is this a correct message (if any) ?*/ |
| was_sent=TRUE; |
| TRACE(msg, "DDE:receive sent message. msg=%04x wPar=%04x" |
| " lPar=%08lx\n", |
| remote_message->message, remote_message->wParam, |
| remote_message->lParam); |
| } else { |
| size= msgrcv( main_block->proc[curr_proc_idx].msg , &msg_dat.dat, |
| DDE_MSG_SIZE, DDE_POST, IPC_NOWAIT); |
| |
| if (size==DDE_MSG_SIZE) { /* is this a correct message (if any) ?*/ |
| was_sent=FALSE; |
| TRACE(msg, "DDE:receive posted message. " |
| "msg=%04x wPar=%04x lPar=%08lx\n", |
| remote_message->message, remote_message->wParam, |
| remote_message->lParam); |
| } |
| else |
| return 0; /* no DDE message found */ |
| } |
| |
| /* At this point we are sure that there is a DDE message, |
| * was_sent is TRUE is the message was sent, and false if it was posted |
| */ |
| |
| nesting++; |
| |
| if (TRACE_ON(dde)) { |
| char *title; |
| if (was_sent) |
| title="receive sent dde:"; |
| else |
| title="receive posted dde:"; |
| print_dde_message(title, remote_message); |
| } |
| |
| if (remote_message->hwnd != (HWND16) -1 ) { |
| HWND16 dde_window= DDE_WIN_INFO(remote_message->hwnd).wnd; |
| /* we should know exactly where to send the message (locally)*/ |
| if (was_sent) { |
| TRACE(dde, "SendMessage(wnd=0x%04x, msg=0x%04x, wPar=0x%04x," |
| "lPar=0x%08x\n", dde_window, remote_message->message, |
| remote_message->wParam, (int)remote_message->lParam); |
| |
| /* execute the recieved message */ |
| passed= SendMessage16(dde_window, remote_message->message, |
| remote_message->wParam, remote_message->lParam); |
| |
| /* Tell the sended, that the message is here */ |
| dde_proc_send_ack(remote_message->wParam, passed); |
| } |
| else { |
| passed= PostMessage16(dde_window, remote_message->message, |
| remote_message->wParam, remote_message->lParam); |
| if (passed == FALSE) { |
| /* Tell the sender, that the message is here, and failed */ |
| dde_proc_send_ack(remote_message->wParam, FALSE); |
| } |
| else { |
| /* ack will be sent later, at the first peek/get message */ |
| dde_proc_add_fifo(remote_message->wParam); |
| } |
| } |
| nesting--; |
| return 1; |
| } |
| |
| /* iterate through all the windows */ |
| for (wndPtr = WIN_FindWndPtr(GetTopWindow(GetDesktopWindow())); |
| wndPtr != NULL; |
| wndPtr = wndPtr->next) |
| { |
| if (wndPtr->dwStyle & WS_POPUP || wndPtr->dwStyle & WS_CAPTION) { |
| if (was_sent) |
| SendMessage16( wndPtr->hwndSelf, remote_message->message, |
| remote_message->wParam, remote_message->lParam ); |
| else |
| PostMessage16( wndPtr->hwndSelf, remote_message->message, |
| remote_message->wParam, remote_message->lParam ); |
| } /* if */ |
| } /* for */ |
| |
| /* replay with DDE_ACK after broadcasting in DDE_GetRemoteMessage */ |
| dde_proc_send_ack(remote_message->wParam, TRUE); |
| |
| nesting--; |
| return 1; |
| } |
| |
| int dde_reschedule() |
| { |
| int ack_wnd; |
| |
| ack_wnd= dde_proc_shift_fifo(); |
| if (ack_wnd != -1) { |
| dde_proc_send_ack(ack_wnd, TRUE); |
| usleep(10000); /* force unix task switch */ |
| return 1; |
| } |
| return 0; |
| } |
| void dde_msg_setup(int *msg_ptr) |
| { |
| *msg_ptr= msgget (IPC_PRIVATE, IPC_CREAT | 0700); |
| if (*msg_ptr==-1) |
| perror("dde_msg_setup fails to get message queue"); |
| } |
| |
| /* do we have dde handling in the window ? |
| * If we have, atom usage will make this instance of wine set up |
| * it's IPC stuff. |
| */ |
| void DDE_TestDDE(HWND16 hwnd) |
| { |
| static in_test = 0; |
| if (in_test++) return; |
| if (main_block != NULL) { |
| in_test--; |
| return; |
| } |
| TRACE(msg,"(0x%04x)\n", hwnd); |
| if (hwnd==0) |
| hwnd=-1; |
| /* just send a message to see how things are going */ |
| SendMessage16( hwnd, WM_DDE_INITIATE, 0, 0); |
| in_test--; |
| } |
| |
| void dde_proc_delete(int proc_idx) |
| { |
| dde_proc_done(&main_block->proc[proc_idx]); |
| } |
| void stop_wait(int a) |
| { |
| |
| had_SIGUSR2=1; |
| switch(stop_wait_op) { |
| case STOP_WAIT_ACK: |
| siglongjmp(env_get_ack,1); |
| break; /* never reached */ |
| case STOP_WAIT_X: |
| siglongjmp(env_wait_x,1); |
| break; /* never reached */ |
| case CONT: |
| /* do nothing */ |
| } |
| } |
| |
| static void print_dde_message(char *desc, MSG16 *msg) |
| { |
| /* extern const char *MessageTypeNames[];*/ |
| extern int debug_last_handle_size; |
| WORD wStatus,hWord; |
| void *ptr; |
| DDEACK *ddeack; |
| DDEADVISE *ddeadvise; |
| DDEDATA *ddedata; |
| DDEPOKE *ddepoke; |
| dbg_decl_str(dde, 2048); |
| |
| if (is_dde_handle(msg->lParam & 0xffff) ) |
| ptr=DDE_AttachHandle(msg->lParam&0xffff, NULL); |
| else |
| ptr =NULL; |
| wStatus=LOWORD(msg->lParam); |
| hWord=HIWORD(msg->lParam); |
| |
| dsprintf(dde,"%s", desc); |
| dsprintf(dde,"%04x %04x==%s %04x %08lx ", |
| msg->hwnd, msg->message,"",/*MessageTypeNames[msg->message],*/ |
| msg->wParam, msg->lParam); |
| switch(msg->message) { |
| case WM_DDE_INITIATE: |
| case WM_DDE_REQUEST: |
| case WM_DDE_EXECUTE: |
| case WM_DDE_TERMINATE: |
| /* nothing to do */ |
| break; |
| case WM_DDE_ADVISE: |
| /* DDEADVISE: hOptions in WM_DDE_ADVISE message */ |
| if (ptr) { |
| ddeadvise=ptr; |
| dsprintf(dde,"fDeferUpd=%d,fAckReq=%d,cfFormat=0x%x", |
| ddeadvise->fDeferUpd, ddeadvise->fAckReq, |
| ddeadvise->cfFormat); |
| } else |
| dsprintf(dde,"NO-DATA"); |
| dsprintf(dde," atom=0x%x",hWord); |
| break; |
| |
| case WM_DDE_UNADVISE: |
| dsprintf(dde,"format=0x%x, atom=0x%x",wStatus,hWord); |
| break; |
| case WM_DDE_ACK: |
| ddeack=(DDEACK*)&wStatus; |
| dsprintf(dde,"bAppReturnCode=%d,fBusy=%d,fAck=%d", |
| ddeack->bAppReturnCode, ddeack->fBusy, ddeack->fAck); |
| if (ddeack->fAck) |
| dsprintf(dde,"(True)"); |
| else |
| dsprintf(dde,"(False)"); |
| break; |
| |
| case WM_DDE_DATA: |
| if (ptr) { |
| ddedata=ptr; |
| dsprintf(dde,"fResponse=%d,fRelease=%d," |
| "fAckReq=%d,cfFormat=0x%x,value=\"%.*s\"", |
| ddedata->fResponse, ddedata->fRelease, |
| ddedata->fAckReq, ddedata->cfFormat, |
| debug_last_handle_size- (int)sizeof(*ddedata)+1, |
| ddedata->Value); |
| } else |
| dsprintf(dde,"NO-DATA"); |
| dsprintf(dde," atom=0x%04x",hWord); |
| break; |
| |
| case WM_DDE_POKE: |
| if (ptr) { |
| ddepoke=ptr; |
| dsprintf(dde,"fRelease=%d,cfFormat=0x%x,value[0]='%c'", |
| ddepoke->fRelease, ddepoke->cfFormat, ddepoke->Value[0]); |
| } else |
| dsprintf(dde,"NO-DATA"); |
| dsprintf(dde," atom=0x%04x",hWord); |
| break; |
| } |
| TRACE(dde,"%s\n", dbg_str(dde)); |
| } |
| |
| void dde_proc_done(dde_proc proc) |
| { |
| if (proc->msg != -1) |
| msgctl(proc->msg, IPC_RMID, NULL); |
| proc->msg=-1; |
| proc->pid=-1; |
| shm_delete_chain(&proc->shmid); |
| shm_sem_done(&proc->sem); |
| } |
| |
| /* delete entry, if old junk */ |
| void dde_proc_refresh(dde_proc proc) |
| { |
| if (proc->pid == -1) |
| return; |
| |
| if (kill(proc->pid, 0) != -1) |
| return; |
| |
| /* get here if entry non empty, and the process does not exist */ |
| dde_proc_done(proc); |
| } |
| |
| void dde_wnd_setup() |
| { |
| int i; |
| |
| for (i=0 ; i < DDE_WINDOWS ; i++) |
| main_block->windows[i].proc_idx = FREE_WND; |
| } |
| |
| static BOOL DDE_ProcHasWindows(int proc_idx) |
| { |
| WND_DATA *tested; |
| int i; |
| |
| for ( i=0 ; i < DDE_WINDOWS ; i++) { |
| tested= &main_block->windows[ i ]; |
| |
| if (tested->proc_idx == proc_idx) |
| return TRUE; |
| } |
| return FALSE; |
| } |
| /* Look for hwnd in the hash table of DDE windows, |
| * Delete it from there. If there are no more windows for this |
| * process, remove the process from the DDE data-structure. |
| * If there are no more processes - delete the whole DDE struff. |
| * |
| * This is inefficient, but who cares for the efficiency of this rare |
| * operation... |
| */ |
| void DDE_DestroyWindow(HWND16 hwnd) |
| { |
| int dde_wnd_idx; |
| WND_DATA *tested; |
| int i; |
| |
| if (main_block == NULL) |
| return; |
| |
| dde_wnd_idx= hwnd % DDE_WINDOWS; |
| |
| for ( i=0 ; i < DDE_WINDOWS ; i++, dde_wnd_idx++) { |
| if (dde_wnd_idx >= DDE_WINDOWS) |
| dde_wnd_idx -= DDE_WINDOWS; /* wrap-around */ |
| |
| tested= &main_block->windows[ dde_wnd_idx ]; |
| if (tested->proc_idx == FREE_WND) |
| return; /* No window will get deleted here */ |
| |
| if (tested->wnd == hwnd && tested->proc_idx == curr_proc_idx) { |
| dde_reschedule(); |
| tested->proc_idx= DELETED_WND; |
| if (DDE_ProcHasWindows( curr_proc_idx )) |
| return; |
| while (dde_reschedule()) /* make sure there are no other */ |
| /* processes waiting for acknowledgment */ |
| ; |
| dde_proc_delete( curr_proc_idx ); |
| if (DDE_no_of_attached() == 1) |
| shm_delete_all(-1); |
| else { |
| shmdt( (void *) main_block); |
| main_block= NULL; |
| } |
| return; |
| } |
| } |
| } |
| |
| #endif /* CONFIG_IPC */ |