/* Authors: Frank da Cruz (fdc@columbia.edu, FDCCU@CUVMA.BITNET), Columbia University Academic Information Systems, New York City. Jeffrey E Altman (jaltman@secure-endpoints.com) Secure Endpoints Inc., New York City Copyright (C) 1985, 2004, Trustees of Columbia University in the City of New York. */ #define INCL_WIN #define INCL_WINMLE #define INCL_GPICONTROL #define INCL_WINCLIPBOARD #define INCL_DOSPROCESS #define INCL_DOSSEMAPHORES #define INCL_DOSMEMMGR #include #undef COMMENT #include #include #include "ckoclip.h" /* definitions & macros */ #define PAPA( x) WinQueryWindow( x, QW_PARENT) #define MENU( x) WinWindowFromID( x, FID_MENU) #define HAB( x) WinQueryAnchorBlock( x) #define FCF_WPS FCF_HIDEMAX | FCF_STANDARD & ~FCF_MINMAX #define CT_MLE 1000 #define MAXCHARS 65535 #define WM_PASSPROC WM_USER + 0 #define WM_GETDATA WM_USER + 1 #define WM_PUTDATA WM_USER + 2 /* function prototypes */ int main( void) ; MRESULT EXPENTRY ClientWndProc( HWND hwnd, ULONG msg, MPARAM mp1, MPARAM mp2) ; /* globals */ HAB hab ; /* Handle to the Anchor Block */ HWND hwndFrame, /* Handle to the Frame Window */ hwndClient ; /* Handle to the Client Window ! */ int killthread = 0 ; /* Signal to Server thread to die */ HMUX hmuxClipbrdSrv = 0 ; /* Only allow one client at a time */ HEV hevClipbrdGet = 0 ; /* Signal to get clipboard data */ HEV hevClipbrdPut = 0 ; /* Signal to put clipboard data */ HEV hevClipbrdReady = 0 ; /* The data is ready for client */ HEV hevClipbrdData = 0 ; /* Let the client know its ready */ HEV hevClipbrdDone = 0 ; /* The Client is done; reset */ PSZ pSharedMem =0; /* The shared memory buffer */ /* This function is the Clipboard Server thread. It handles all communication with our clients via Named Shared Semaphores. We can't access the clipboard from here, so we post a message to our message queue thread when we need the clipboard data. The Window Procedure then gets the data and signals us via a private semaphore that it the data is ready. At that time we signal our client, and wait for the client to complete. If the client, doesn't release us we will wait forever. But better that then allow two clients to possibly crash into each other */ void clipsrv( void * param ) { ULONG clipsize =0; PBYTE * clipdata =0; ULONG postcount =0; APIRET rc = 0 ; HMUX hmuxWaitForWork = 0 ; SEMRECORD work_rec[2] ; ULONG jobtype ; #define GETTEXT 0L #define PUTTEXT 1L rc = DosAllocSharedMem( (PPVOID) &pSharedMem, "\\SHAREMEM\\CKERMIT\\CLIPBRD\\DATA", MAXCHARS, PAG_COMMIT | PAG_READ | PAG_WRITE | OBJ_TILE ) ; work_rec[0].hsemCur = (HSEM) hevClipbrdGet ; work_rec[0].ulUser = GETTEXT ; work_rec[1].hsemCur = (HSEM) hevClipbrdPut ; work_rec[1].ulUser = PUTTEXT ; rc = DosCreateMuxWaitSem( NULL, &hmuxWaitForWork, 2, work_rec, DCMW_WAIT_ANY | DC_SEM_SHARED ) ; while ( !killthread ) { pSharedMem[0] = '\0' ; /* Wait for something to do */ rc = DosWaitMuxWaitSem( hmuxWaitForWork, SEM_INDEFINITE_WAIT, &jobtype ) ; switch ( jobtype ) { case GETTEXT: rc = DosResetEventSem( hevClipbrdGet, &postcount ) ; WinPostMsg( hwndClient, WM_GETDATA, 0, 0 ); rc = DosWaitEventSem( hevClipbrdReady, SEM_INDEFINITE_WAIT ); rc = DosResetEventSem( hevClipbrdReady, &postcount ); /* Now let the requester know its ready */ rc = DosPostEventSem( hevClipbrdData ) ; /* Now wait for the requester to finish using the memory */ rc = DosWaitEventSem( hevClipbrdDone, SEM_INDEFINITE_WAIT ) ; rc = DosResetEventSem( hevClipbrdDone, &postcount ) ; break; case PUTTEXT: rc = DosResetEventSem( hevClipbrdPut, &postcount ) ; /* There is text in the shared memory to be sent to the Clipboard */ /* so let the Window Message thread know */ WinPostMsg( hwndClient, WM_PUTDATA, 0 , 0 ) ; /* Wait for the Window Message thread to finish the Copy */ rc = DosWaitEventSem( hevClipbrdReady, SEM_INDEFINITE_WAIT ); rc = DosResetEventSem( hevClipbrdReady, &postcount ); /* Let the client know we are Done */ rc = DosPostEventSem( hevClipbrdDone ) ; break; } } rc = DosCloseMuxWaitSem( hmuxWaitForWork ) ; rc = DosFreeMem( pSharedMem ) ; } int initserver( void ) { APIRET rc ; if ( rc = DosCreateMutexSem( "\\SEM32\\CKERMIT\\CLIPBRD\\MUX", &hmuxClipbrdSrv, DC_SEM_SHARED, TRUE ) ) return 1 ; if ( rc = DosCreateEventSem( "\\SEM32\\CKERMIT\\CLIPBRD\\GET", &hevClipbrdGet, DC_SEM_SHARED, FALSE ) ) { DosCloseMutexSem( hmuxClipbrdSrv ) ; return 1 ; } if ( rc = DosCreateEventSem( "\\SEM32\\CKERMIT\\CLIPBRD\\DATA", &hevClipbrdData, DC_SEM_SHARED, FALSE ) ) { DosCloseMutexSem( hmuxClipbrdSrv ) ; DosCloseEventSem( hevClipbrdGet ) ; return 1 ; } if ( rc = DosCreateEventSem( "\\SEM32\\CKERMIT\\CLIPBRD\\DONE", &hevClipbrdDone, DC_SEM_SHARED, FALSE ) ) { DosCloseMutexSem( hmuxClipbrdSrv ) ; DosCloseEventSem( hevClipbrdGet ) ; DosCloseEventSem( hevClipbrdData ) ; return 1 ; } if ( rc = DosCreateEventSem( NULL, &hevClipbrdReady, 0, FALSE ) ) { DosCloseMutexSem( hmuxClipbrdSrv ) ; DosCloseEventSem( hevClipbrdGet ) ; DosCloseEventSem( hevClipbrdData ) ; DosCloseEventSem( hevClipbrdDone ) ; return 1 ; } if ( rc = DosCreateEventSem( "\\SEM32\\CKERMIT\\CLIPBRD\\PUT", &hevClipbrdPut, DC_SEM_SHARED, FALSE ) ) { DosCloseMutexSem( hmuxClipbrdSrv ) ; DosCloseEventSem( hevClipbrdGet ) ; DosCloseEventSem( hevClipbrdData ) ; DosCloseEventSem( hevClipbrdDone ) ; DosCloseEventSem( hevClipbrdReady ) ; return 1 ; } return 0 ; } void killserver( void ) { DosRequestMutexSem( hmuxClipbrdSrv, SEM_INDEFINITE_WAIT ) ; killthread = 1 ; DosCloseMutexSem( hmuxClipbrdSrv ) ; DosCloseEventSem( hevClipbrdGet ) ; DosCloseEventSem( hevClipbrdData ) ; DosCloseEventSem( hevClipbrdDone ) ; DosCloseEventSem( hevClipbrdPut ) ; } /* Main thread. Allocate all semaphores. If we can't it probably means that another copy of is already running. So just die. */ int main( void) { CHAR szWindowTitle[255] ; HMQ hmq ; QMSG qmsg ; ULONG flFrameFlags = FCF_WPS & ~FCF_ACCELTABLE ; APIRET rc ; hab = WinInitialize( 0) ; hmq = WinCreateMsgQueue( hab, 0L) ; if ( initserver() ) { /* couldn't create semaphores */ WinLoadString( hab, NULLHANDLE, ST_CREATION_ERROR, sizeof( szWindowTitle), szWindowTitle) ; WinMessageBox( HWND_DESKTOP, HWND_DESKTOP, szWindowTitle, (PSZ) NULL, 1, MB_ERROR ) ; return 1 ; } else { /* load window title from resource file */ WinLoadString( hab, NULLHANDLE, ST_WINDOWTITLE, sizeof( szWindowTitle), szWindowTitle) ; /* create main window */ hwndFrame = WinCreateStdWindow( HWND_DESKTOP, 0, &flFrameFlags, WC_MLE, szWindowTitle, WS_CLIPCHILDREN, NULLHANDLE, RS_ALL, &hwndClient) ; WinSetWindowPos( hwndFrame, HWND_BOTTOM, 0L, 0L, 450L, 100L, SWP_SIZE | SWP_SHOW | SWP_ZORDER) ; WinShowWindow( hwndFrame, FALSE ) ; /* subclass the MLE */ WinSendMsg( hwndClient, WM_PASSPROC, MPFROMP( WinSubclassWindow( hwndClient, ClientWndProc)), 0L) ; /* Start processing client requests */ _beginthread( clipsrv, NULL, 65535, NULL ) ; rc = DosReleaseMutexSem( hmuxClipbrdSrv ) ; while( WinGetMsg( hab, &qmsg, NULLHANDLE, 0L, 0L)) WinDispatchMsg( hab, &qmsg) ; /* destroy resources */ killserver() ; WinDestroyWindow (hwndFrame) ; WinDestroyMsgQueue (hmq) ; WinTerminate (hab) ; } return 0L ; } /* The Clients Window Procedure. It is here that we actually get the Clipboard Data and place it into the shared memory. */ MRESULT EXPENTRY ClientWndProc( HWND hwnd, ULONG msg, MPARAM mp1, MPARAM mp2) { static PFNWP pfnwp ; static HWND hmenu ; APIRET rc ; PSZ pClipboard ; switch( msg) { case WM_PASSPROC: pfnwp = (PFNWP)mp1 ; /* limit text to MAXCHARS characters and make it readonly*/ WinSendMsg( hwnd, MLM_SETTEXTLIMIT, MPFROMLONG(MAXCHARS), 0L) ; WinSendMsg( hwnd, MLM_SETREADONLY, MPFROMLONG(1L), 0L) ; /* get the menu handle */ hmenu = MENU(PAPA(hwnd)) ; return 0L ; case WM_GETDATA: /* Get the data from the clipboard */ rc = WinOpenClipbrd(hab) ; if ( rc ) { pClipboard = (PSZ) WinQueryClipbrdData( hab, CF_TEXT ) ; /* Copy it to our Shared Memory */ if ( pClipboard ) strcpy( pSharedMem, pClipboard ) ; WinCloseClipbrd(hab) ; } /* set text in the MLE window */ WinSetWindowText( hwnd, pSharedMem) ; DosPostEventSem( hevClipbrdReady ); return 0L; case WM_PUTDATA: /* The data is in our named shared memory */ /* we must allocate shared memory to give to the clipboard */ /* copy the text into it */ /* and pass it off to the clipboard */ rc = DosAllocSharedMem( (PPVOID) &pClipboard, NULL, strlen(pSharedMem)+1, PAG_COMMIT | PAG_WRITE | OBJ_GIVEABLE ); if ( pClipboard ) { strcpy( pClipboard, pSharedMem ) ; rc = WinOpenClipbrd(hab); if ( rc ) { rc = WinSetClipbrdData( hab, (ULONG) pClipboard, CF_TEXT, CFI_POINTER ) ; WinCloseClipbrd( hab ) ; WinSetWindowText( hwnd, pSharedMem ) ; } else { WinSetWindowText( hwnd, "Unable to open Clipboard." ) ; } } else { WinSetWindowText( hwnd, "Unable to allocate Shared Memory for PUT operation."); } DosPostEventSem( hevClipbrdReady ); return 0L; case WM_INITMENU: break ; case WM_COMMAND: switch( COMMANDMSG( &msg) -> cmd) { case MN_EXIT: WinPostMsg( hwnd, WM_QUIT, NULL, NULL) ; break ; default: break ; } break ; default: break; } return (*pfnwp)( hwnd, msg, mp1, mp2) ; }