/**************/ /* dropfile.c */ /**************************************************************************** PROGRAM: dropfile.c PURPOSE: Drag and Drop-palvelin AUTHOR: Idea: Jeffrey M. Richter. Vesa Lappalainen: 27.8.1993 muutti aliohjelmiksi 9.10.1993 lisäsi leikekirja ja näppäimistöpudotuksen USAGE: Projektiin laitettava dropfile.c dropfile.rc (Jos on oma.RC dropfile.rc voidaan laittaa omaan .RChen inludina) 1) Omaan ohjelmaan lisätään kutsu: DropFiles(hWnd,files); kun halutaan siirtää tiedostojen nimiä toiseen ohjelmaan. files on merkkijonomuuttuja, joka on muotoa: "hak1 t1 t2 t3;hak2 t4 t5 t6;hak3\t7" Eli esimerkiksi: "C:\DOS SUBST.COM FC.EXE;C:\BIN\TGREP.COM tarkoittaisi tiedostoja: C:\DOS\SUBST.COM C:\DOS\FC.EXE C:\BIN\TGREP.COM Itse asiassa merkkijono voi sisältää mitä tahansa merkkijonoja puolipisteellä erotettuna, jollei niissä ole välilyöntejä. Jos vastaanottaja ymmärtää nämä nimet niin hyvä on. (DropText sallii myös välilyönnit.) 2) Alla on myös aliohjelmia tiedostojen valitsemiseksi dialogin avulla edellä mainittuun merkkijonomuotoon. Drag and drop (DaD) asiakkaanahan ohjelma voi toimia seuraavasti: ----------------------------------------------------------------- 1) Ilmoitetaan että hyvksytään DaD: DragAcceptFiles(hWnd,TRUE); 2) Vastataan viestiin: WM_DROPFILES ottamalla tiedostot kahvalla hDrop = (HDROP)wParam käyttäen kutsuja: lkm = DragQueryFile(hDrop,-1,NULL,0); ... DragQueryFile(hDrop,i,FileStr[i],msize); ... DragFinish(hDrop); /! Muistilohkon vapautus muistettava!!! ============ Aliohjelmat: (dropfile.c) ============ int DropFiles(HWND hWnd,LPCSTR files); -------------------------------------- int DropFiles(HWND hWnd,LPCSTR files); -------------------------------------- - käynnistää Drop toiminnon files-listan tiedostoille. Mikäli hiiren vasen nappi ei ole alhaalla, on toiminto aktiivinen kunnes nappi painetaan alas ja päästetään ylös. Kursori muuttuu sen mukaan pystyykö alla oleva sovellus ottamaan pudotuksen vastaan vaiko ei. Jos nappi päästetään ylös ei-asiakkaan kohdalla, palautetaan 0, muuten pudotettujen tiedostojen lukumäärä Kun pudotus on tehty, lähetetään kutsuneelle ohjelmalle viesti: UM_UPDATECAPTION jonka saamisen jälkeen esim. pyyhitään pois pudotuksen mahdollistaminen. Tosin tätä harvoin tarvitaan, koska funktio palauttaa jo nimessään tiedon onnistuiko homma vai ei. int DropText(HWND hWnd,LPCSTR files); -------------------------------------- Kuten edellä, mutta välilöynneistä ei välitetä, vaan ainoastaan jonojen välisestä erottimesta, joka on 0xff LPCSTR MultiSelectFiles(HWND hWnd) ---------------------------------- - tiedostojen valitsemiseksi DropFiles-vaatimaan muotoon. Kutsulla saadaan osoite staattiseen merkkijonoon tai NULL. Jono on muotoa "hak t1 t2 t3" tai "hak\t1" Kutsu käyttää common-dialogin tiedostovalitsinta. int DropSelectFiles(hWnd) ------------------------- - Kutsuu edellistä, laittaa tiedostot pudotukseen ja palauttaa pudotettujen tiedostojen lukumäärän. int DropListBoxFiles(HWND hWnd,UINT id,LPCSTR path) --------------------------------------------------- - laittaa list-boxissa hWnd,id olevat nimet pudotukseen. Kunkin nimen eteen lisätään jono path. int DropListBoxText(HWND hWnd,UINT id) --------------------------------------------------- - kuten edellä, mutta ei mitään polkuja ja jonot saavat sisältää välilyöntejä int DropFilesToListBox(HDROP hDrop,HWND hWnd,int id,int clear) -------------------------------------------------------------- - ottaa Drop listassa olevat nimet ja laittaa ne list-boxiin hWnd,id. clear == 1 => poistaa nimistä polkuosan == 2 => tyhjentää ensin list-boxin == 3 => molemmat edelliset ( == 1 | 2 ) LPSTR RemovePath(LPSTR s) ------------------------- - paluttaa osoitteminen saman merkkijono pelkkään tiedoston nimeen. LPSTR DropFilesToString(HDROP hDrop,LPSTR s,int mb) --------------------------------------------------- - ottaa Drop-listassa olevat nimet ja palauttaa ne muodossa path1\n1;path2\n2;path3\n3 WORD GetSinglePathName (LPCSTR szFileOpenStr, int wIndex, LPSTR szPathName, WORD wMaxLen) --------------------------------------------------------- - palautetaan szFileOpenStr-muuttujasta wIndex-numeroinen kokonainen tiedoston nimi. Numerointi alkaa nollasta. Seuraavalla kutsulla saadaan selville tiedostonimien lukumäärä merkkijonossa: wNumFiles = GetSinglePathName(szAllFileNames, -1, NULL, 0); HDROP DragCreateFiles (LPPOINT lpptMousePos,BOOL fInNonClientArea) ------------------------------------------------------------------ - luodaan Drop-struktuuri, Hiirren ilmoitettava paikka ja ollaanko asiakkaan otsikossa vaiko ei. HDROP DragAppendFile (HGLOBAL hDrop, LPCSTR szPathname) ------------------------------------------------------- - lisätään tiedoston nimi Drop-struktuuriin. Tuloksena kahva, joka välitetään asiakkaalle ja jonka asiakas on velvollinen hävittämään. Kolme viimeistä on lähinnä kirjaston sisäiseen käyttöön, mutta tietysti niitä voi käyttää itsekin. Tällöin tosin joudutaan tekemään itse kursorin muodon muutokset, jotka nyt hoituvat automaattisesti aliohjelman DropFiles-ansiosta. int InitDragAndDrop(char *inifilename,int write) ------------------------------------------------------- - lukee (write=0) tai kirjoittaa (write=1) DaD-tiedot .INI-tiedostoon, jonka nimi on inifilename:ssa. Vikoja: ------- Totetus perustuu Jeffrey M. Richter "nuuskimaan" tietorakenteeseen Drop-tiedostoille. Windows itse ei käytä (esim. FileManager) tietorakennetta näin suoraan, vaan lähettää viestejä jollekin Drop-palvelimelle. Näiden viestien käyttöyritys kuitenkin kaataa vastaanottaja ohjelman heti kun tullaan sen jonkin lapsi-ikkunan kohdalle. Viestien käyttö olisi kuitenkin varmasti parempi tapa hoitaa homma, mutta kun sitä ei ole dokumentoitu! - Jumiintuu joskus *****************************************************************************/ #define CLIPDROP #include #include #include #include #include "Dropfile.h" #define SPACE 0x01 #define ITEM_SEPARATOR ((char)0xff) #define ITEMSEPSTR "\0177" #define DOMESSAGE DoMessage /****************************************************************************/ static LPSTR ReplaceChars(LPSTR s,char cfrom,char cto) { LPSTR p; for ( p = s; *p; p++ ) if ( *p == cfrom ) *p = cto; return s; } /****************************************************************************/ static int AdvToFileNr(LPCSTR *file,int wIndex,int *Only1file) /* ** Siirrytään wIndex numeroiseen tiedoston nimeen tässä ** sectionissa (; erotettu osa). Palautetaan ** se indeksi, johon siirryttiin tai sectionion nimien lkm. ** Jos haluttuun indeksiin ei päästä, siirrytään seuraavan ** section alkuun. ** ** 0123456789012345678901234567890 wIndex ret *c file ** ' c:\dos f0 f1 f2' 9 ==> 3 24 0 ** ' c:\dos f0 f1 ; c:\bat f2 ' 9 ==> 2 21 0 ** ' c:\dos f0 f1 ; c:\bat f2 ' 1 ==> 2 14 0 ** ' c:\dos\f0 ' 9 ==> 1 16 1 ** ' c:\dos\f0 ' 0 ==> 1 4 1 ** ' c:\dos f0 ' 0 ==> 1 11 0 ** ' ' 9 ==> 0 16 0 */ { int num = -1; char prev=SPACE; LPCSTR p = *file; *Only1file = 0; while ( *p == SPACE ) p++; for (prev=SPACE; *p && *p != ITEM_SEPARATOR; prev=*p,p++) { if (*p != SPACE && prev == SPACE) { // Came into first char num++; *file = p; if ( num > wIndex ) return num; } } if ( num == 0 ) { // Form "c:\dos\f1.com" *Only1file = 1; num = 1; if ( wIndex == 0 ) return num; } while ( *p ==ITEM_SEPARATOR || *p ==SPACE ) p++; *file = p; return max(num,0); } /****************************************************************************/ static int AdvContainingSection(LPCSTR *sec,LPCSTR *file,WORD wIndex, int *Only1file) /* ** Siirrytään tiedostonnimilistassa wIndex numeroisen tiedoston alkuun. ** sec muuttujassa palautetaan vastaavan sectionin alkuosoite. ** Jos indeksipyyntö on liian iso, palautetaan alkioiden lukumäärä. ** Välilyönti on korvattu ^A:lla ** ** wInd 0123456789012345678901234567890123 ret *sec *file Only1file ** 1 ' c:\dos f0 f1 f2' ==> 2 4 17 0 ** 10 ' c:\dos f0 f1 ; c:\bat f2 ' ==> 3 33 33 0 ** 2 ' c:\dos\f0;c:\bat\f1;c:\bin\f2' ==> 3 14 14 1 */ { LPCSTR f = *sec; int num = 0; while ( 1 ) { num += AdvToFileNr(&f,wIndex-num,Only1file); if ( *f == 0 || num > wIndex ) break; *sec = f; // Passed whole section, so now in begining of next one } *file = f; while ( **sec == SPACE ) (*sec)++; // Skip leading spaces return num; } /****************************************************************************/ WORD GetSinglePathName (LPCSTR szFileOpenStr, int wIndex, LPSTR szPathName, WORD wMaxLen) /* ** sec 1 sec 2 sec 3 wIndex ** c:\dos f0 f1 f2;c:\bat f3 f4 f5;c:\bin f6 f7 f8 5 => c:\bat\f5 ** c:\dos\f0 ;c:\bat f1 f2 f3 0 => c:\dos\f0 ** c:\dos f0 f1 f2; 3 => "" */ { WORD wNumFiles = 0, x; LPCSTR sec = szFileOpenStr,file; int Only1file; char szBuf[200]; static char SEPAR[3]={SPACE,ITEM_SEPARATOR,0}; if ( szPathName != NULL ) szPathName[0] = 0; if ( !szFileOpenStr ) return 0; // Initialize the buffer by clearing it _fmemset(szBuf, 0, sizeof(szBuf)); wNumFiles = AdvContainingSection(&sec,&file,10000,&Only1file); // If the user only wants the number of files, return that if (wIndex == -1) return wNumFiles; // User requested more files than exist if (wIndex >= wNumFiles) return 0; // *** Construct the full pathname of the requested string *** sec = szFileOpenStr; AdvContainingSection(&sec,&file,wIndex,&Only1file); x = min(_fstrcspn(sec, SEPAR),sizeof(szBuf)-1); // Copy the path portion of the string into a temp buffer _fstrncpy(szBuf, sec, x); if ( !Only1file ) { // Form c:\dos f1 // Append a backslash if necessary if ( !strchr("\\:",szBuf[x-1]) ) szBuf[x++] = '\\'; // Copy the filename into the temp buffer _fstrncpy(&szBuf[x], file, _fstrcspn(file,SEPAR)); } if (szPathName != NULL) { // If the user passed an address, copy the string into its buffer _fstrncpy(szPathName, szBuf, wMaxLen); szPathName[wMaxLen - 1] = 0; // Force zero-termination } return lstrlen(szBuf); // Returns length of string } //*************************************************************** //****************** ***************** //****************** DROP-FILE SERVER FUNCTIONS ***************** //****************** ***************** //*************************************************************** typedef struct { WORD wSize; // Size of data structure POINT ptMousePos; // Position of mouse cursor BOOL fInNonClientArea; // Was the mouse in the // window's non-client area } DROPFILESTRUCT, FAR *LPDROPFILESTRUCT; //*************************************************************** HDROP DragCreateFiles (LPPOINT lpptMousePos, BOOL fInNonClientArea) { HGLOBAL hDrop; LPDROPFILESTRUCT lpDropFileStruct; // GMEM_SHARE must be specified because the block will // be passed to another application hDrop = GlobalAlloc(GMEM_SHARE | GMEM_MOVEABLE | GMEM_ZEROINIT, sizeof(DROPFILESTRUCT) + 1); // If unsuccessful, return NULL if (hDrop == NULL) return(hDrop); // Lock block and initialize the data members lpDropFileStruct = (LPDROPFILESTRUCT) GlobalLock(hDrop); lpDropFileStruct->wSize = sizeof(DROPFILESTRUCT); lpDropFileStruct->ptMousePos = *lpptMousePos; lpDropFileStruct->fInNonClientArea = fInNonClientArea; GlobalUnlock(hDrop); return(hDrop); } //*************************************************************** int DragSetPoint(HGLOBAL hDrop,LPPOINT lpptMousePos) { LPDROPFILESTRUCT lpDropFileStruct; lpDropFileStruct = (LPDROPFILESTRUCT) GlobalLock(hDrop); lpDropFileStruct->ptMousePos = *lpptMousePos; GlobalUnlock(hDrop); return 0; } //*************************************************************** HDROP DragAppendFile (HGLOBAL hDrop, LPCSTR szPathname) { LPDROPFILESTRUCT lpDropFileStruct; LPCSTR lpCrnt; WORD wSize; lpDropFileStruct = (LPDROPFILESTRUCT) GlobalLock(hDrop); // Point to first pathname in list lpCrnt = (LPSTR) lpDropFileStruct + lpDropFileStruct->wSize; // Search for a pathname were first byte is a zero byte while (*lpCrnt) { // While the 1st char of path is non-zero while (*lpCrnt) lpCrnt++; // Skip to zero byte lpCrnt++; } // Calculate current size of block wSize = (WORD) (lpCrnt - (LPSTR) lpDropFileStruct + 1); GlobalUnlock(hDrop); // Increase block size to accommodate // the new pathname being appended hDrop = GlobalReAlloc(hDrop, wSize + lstrlen(szPathname) + 1, GMEM_MOVEABLE | GMEM_ZEROINIT | GMEM_SHARE); // Return NULL if insufficient memory if (hDrop == NULL) return(hDrop); lpDropFileStruct = (LPDROPFILESTRUCT) GlobalLock(hDrop); // Append the pathname to the block lstrcpy((LPSTR) lpDropFileStruct + wSize - 1, szPathname); GlobalUnlock(hDrop); return(hDrop); // Return the new handle to the block } /****************************************************************************/ /********************** **************************/ /********************** FILE OPEN UTILITY FUNCTION **************************/ /********************** **************************/ /****************************************************************************/ static char szAllFileNames[800]; static char szDropPathName[200]; /****************** MultiSelectFiles ****************************************/ LPSTR MultiSelectFiles(HWND hWnd) { OPENFILENAME ofn; // Initialize structure for calling the "Open File" common dialog _fmemset(&ofn, 0, sizeof(ofn)); ofn.lStructSize = sizeof(ofn); ofn.hwndOwner = hWnd; ofn.lpstrFilter = "All files\0*.*\0"; ofn.Flags = OFN_ALLOWMULTISELECT | OFN_FILEMUSTEXIST | OFN_HIDEREADONLY; // Set up the buffer to receive the selected file(s) szAllFileNames[0] = 0; ofn.lpstrFile = szAllFileNames; ofn.nMaxFile = sizeof(szAllFileNames); if ( !GetOpenFileName(&ofn) ) return NULL; if ( szAllFileNames[0] == 0 ) return NULL; return szAllFileNames; } /****************** SelectDropFiles *****************************************/ int DropSelectFiles(HWND hWnd) { return DropFiles(hWnd,MultiSelectFiles(hWnd)); } /****************************************************************************/ /********************** **************************/ /********************** Drop functions **************************************/ /********************** **************************/ /****************************************************************************/ /****************************************************************************/ typedef struct { int init; int Stop; WORD wNumFiles; BOOL fInNonClientArea, fOkToDrop; POINT ptMousePos; POINT clipMousePos; HWND hWndSubject; HWND hWndCur; HWND hMainWnd; HINSTANCE hInstance; char IsSelf; char HasBeenOther; /* To see not to drop over self */ char mode; /* 0 = filedrop, 1 = using clip, 2 = using keyb */ char enter; /* 1 = enter jonojen väliin */ char position; /* 1 = lähetetään paikka ennen pudottamista */ char active; /* 1 = tehdään pudottanut ikkuna aktiiviseksi */ char savewin; /* 1 = jätetään tiedot paikalleen jotta seuraava pudot.*/ /* menisi ilman hiiren liikettä */ char clipmode; /* 0 = Ctrl-V, 1=WM_PASTE, 2=Shift-Ins (vaatii Shift) */ /* 3 = Ctrl-V statuksen avulla */ } tDrop; static tDrop Drop; /****************************************************************************/ static void InitializeDrop(void) { if ( Drop.init ) return; Drop.enter = 1; Drop.clipmode = 3; } /****************************************************************************/ static HCURSOR hCrsrDrpNotAllow, hCrsrDrpSingle, hCrsrDrpMultiple; #ifdef CLIPDROP # include "mjonot.h" # include "clipboard.h" // *************************************************************** // This functions draws a frame around a given window. The frame // is drawn in the inverse screen color. This allows a second // call to this function to restore the screen display to its // original appearance. void DrawWindowFrame (HWND hWnd) { HDC hDC; RECT rc; HPEN hPen; // Retrieve location of window on screen GetWindowRect(hWnd, &rc); // Get a Device context that allows us to write anywhere within // the window. NOTE: GetDC would only allow us to write in the // window's client area. hDC = GetWindowDC(hWnd); // To guarantee that the frame will be visible, tell Windows to // draw the frame using the inverse screen color. SetROP2(hDC, R2_NOT); // Create a pen that is 3 times the width of a non-sizeable // border. The color will not be used to draw the frame, so // its value could be anything. PS_INSIDEFRAME tells windows // that the entire frame should be enclosed within the window. hPen = CreatePen(PS_INSIDEFRAME, 5 * GetSystemMetrics(SM_CXBORDER), RGB(0, 0, 0)); SelectObject(hDC, hPen); // We must select a NULL brush so that the contents of the // window will not be covered. SelectObject(hDC, GetStockObject(NULL_BRUSH)); // Draw the frame. Because the Device Context is relative to // the window, the left-top corner is (0, 0) and the // right-bottom corner is (width of window, height of window) Rectangle(hDC, 0, 0, rc.right - rc.left, rc.bottom - rc.top); ReleaseDC(hWnd, hDC); // We can only destroy the pen AFTER we have released the DC // because the DC must have valid "tools" in it at all times. DeleteObject(hPen); } /****************************************************************************/ void MarkWindow(HWND hWnd) { static HWND prevhWnd = NULL; if ( ( hWnd != prevhWnd || hWnd == NULL ) && prevhWnd ) { DrawWindowFrame(prevhWnd); prevhWnd = NULL; } if ( hWnd && hWnd != prevhWnd ) { prevhWnd = hWnd; DrawWindowFrame(prevhWnd); prevhWnd = hWnd; } } static char Selection[1000]; /****************************************************************************/ static char *SelectionText(LPCSTR szAllFileNames,WORD wNumFiles) { int i; Selection[0]=0; for (i = 0; i < wNumFiles; i++) { GetSinglePathName(szAllFileNames,i, szDropPathName, sizeof(szDropPathName)); liita_jono(N_S(Selection),szDropPathName); if ( Drop.enter ) liita_jono(N_S(Selection),"\r\n"); } return Selection; } static int Waiting = 0; /****************************************************************************/ LONG CALLBACK _export MyDelayProc(HWND hwnd,UINT msg, WPARAM idTimer,LPARAM dwTime) { #pragma argsused Waiting = 0; return 0; } /****************************************************************************/ static int DoDelay(LONG ms) { MSG msg; TIMERPROC lpfnMyTimerProc = (TIMERPROC) MakeProcInstance((FARPROC)MyDelayProc, Drop.hInstance); int timer; Waiting = 1; if ( !lpfnMyTimerProc ) return 1; timer = SetTimer(Drop.hMainWnd, 1, ms, lpfnMyTimerProc); while ( Waiting && timer) { if ( PeekMessage(&msg,NULL /*Drop.hMainWnd*/,NULL,NULL,PM_REMOVE) ) DispatchMessage(&msg); } KillTimer(Drop.hMainWnd,timer); FreeProcInstance(lpfnMyTimerProc); return 0; } /****************************************************************************/ static void PutSelectionToClipboard(HWND hWnd, LPCSTR szAllFileNames,WORD wNumFiles) { char *s = SelectionText(szAllFileNames,wNumFiles); AddToClipboard(hWnd,CF_TEXT,s,strlen(s)+1,TRUE); } #if 0 /****************************************************************************/ static int DoMessageDelay(HWND hWnd) { while ( PostMessage(hWnd,WM_COMMAND,0xfedc,0x0L) != 0 ); return 1; } #endif /****************************************************************************/ static BYTE pbKeyState[256]; static BYTE pbOldKeyState[256]; /****************************************************************************/ static void RestoreState(HWND hWnd) { #pragma argsused // WaitMessage(); // DoMessageDelay(hWnd); DoDelay(100); SetKeyboardState((LPBYTE) &pbOldKeyState); } /****************************************************************************/ static void SetState(int key,int down) { DoDelay(100); GetKeyboardState((LPBYTE) &pbKeyState); GetKeyboardState((LPBYTE) &pbOldKeyState); if ( down ) pbKeyState[key] |= 0x80; else pbKeyState[key] &= ~0x80; SetKeyboardState((LPBYTE) &pbKeyState); } /****************************************************************************/ static int DoMessage(HWND hWnd,UINT message,WPARAM wParam,LPARAM lParam) { MSG msg; int i; while ( PostMessage(hWnd,message,wParam,lParam) == 0 ) { if ( !IsWindow(hWnd) ) { /* Jos ikkuna hävinnyt, odotetaan sitä 5s tak. */ for (i=0; i<10; i++) { DoDelay(500); if ( IsWindow(hWnd) ) goto try_again; } return 0; } if ( PeekMessage(&msg,NULL /*Drop.hMainWnd*/,NULL,NULL,PM_REMOVE) ) DispatchMessage(&msg); try_again: } return 1; } /****************************************************************************/ static void SendStr(HWND hWnd,LPSTR s) { LPSTR p; for (p=s; *p; p++) DOMESSAGE(hWnd,WM_CHAR,*p,0x00000001L); } /****************************************************************************/ static void SendChars(HWND hWnd, LPCSTR szAllFileNames,WORD wNumFiles) { int i; Selection[0]=0; for (i = 0; i < wNumFiles; i++) { GetSinglePathName(szAllFileNames,i, szDropPathName, sizeof(szDropPathName)); SendStr(hWnd,szDropPathName); if ( Drop.enter ) { DOMESSAGE(hWnd,WM_KEYDOWN,VK_RETURN,0x1L); DoDelay(200); // DoMessageDelay(hWnd); // SendMessage } // if ( Drop.enter ) DOMESSAGE(hWnd,WM_CHAR,0x0d,0x001c0001L); } } /****************************************************************************/ /* Yritetään löytää "paras" ikkuna kursorin alta. Metodi: 1. pyydetään isä-ikkuna ja numeroidaan sen lapset. 2. jos lapsista kukaan ei ole alkuperäinen ikkuna, palautetaan alkuperäinen ikkuna 3. Jos lapsista on kokin kursorin kohdalla ja vielä luokkana "edit", niin palautetaan se. */ /****************************************************************************/ typedef struct { POINT Mousept; HWND hWndCur; int CurWndFound; HWND hBest; } tFindBest; static tFindBest FB; /****************************************************************************/ int IsEdit(HWND hWnd) { static char cname[30]; GetClassName(hWnd,cname,sizeof(cname)); return strncmpi(cname,"edit",40) == 0; } /****************************************************************************/ BOOL CALLBACK _export EnumChildsToFindBest(HWND hWnd,LPARAM back) { #pragma argsused RECT rc; GetWindowRect(hWnd,&rc); if ( !PtInRect(&rc,FB.Mousept) ) return TRUE; if ( FB.hWndCur == hWnd ) FB.CurWndFound = 1; if ( IsEdit(hWnd) ) { FB.hBest = hWnd; if ( FB.CurWndFound ) return 0; } return TRUE; } /****************** IsClipboardDrop *****************************************/ static int IsClipbordDrop(HWND hWnd,HWND *hWndCur,POINT *ptMousePos) /* Jos shift alhaalla, niin tutkitaan tarkemmin */ { #pragma argsused char s[50]; POINT pt; HWND hPrev,hFoc,hParent,hChild; int state; FARPROC EnumProc; study_windows: EnumProc = MakeProcInstance((FARPROC)EnumChildsToFindBest, GetWindowWord(hWnd,GWW_HINSTANCE)); hParent = GetParent(*hWndCur); FB.Mousept = *ptMousePos; FB.hWndCur = *hWndCur; FB.CurWndFound = 0; FB.hBest = NULL; EnumChildWindows(hParent,(WNDENUMPROC)EnumProc,0); FreeProcInstance(EnumProc); Drop.clipMousePos = *ptMousePos; if ( FB.CurWndFound && FB.hBest ) *hWndCur = FB.hBest; MarkWindow(*hWndCur); return 0; } /****************** DropClipboard *******************************************/ static int DropClipboard(HWND hWnd,HWND hWndCur, LPCSTR szAllFileNames,WORD wNumFiles) { #pragma argsused char s[50]; HWND hFoc; LPARAM lParam; MarkWindow(NULL); ScreenToClient(hWndCur, &Drop.clipMousePos); SetActiveWindow(hWndCur); SetFocus(hWndCur); hFoc =GetFocus(); lParam=MAKELONG(Drop.clipMousePos.x,Drop.clipMousePos.y); if ( Drop.position ) { DOMESSAGE(hFoc,WM_LBUTTONDOWN,0,lParam); DOMESSAGE(hFoc,WM_LBUTTONUP,0,lParam); DOMESSAGE(hFoc,WM_LBUTTONDOWN,0,lParam); DOMESSAGE(hFoc,WM_LBUTTONUP,0,lParam); DOMESSAGE(hFoc,WM_LBUTTONDOWN,0,lParam); DOMESSAGE(hFoc,WM_LBUTTONUP,0,lParam); } if ( Drop.mode == 1) { PutSelectionToClipboard(hWnd,szAllFileNames,wNumFiles); switch ( Drop.clipmode ) { case 0: DOMESSAGE(hFoc,WM_CHAR,0x16,0x01L); /* Ctrl-V */ break; case 1: DOMESSAGE(hFoc,WM_PASTE,0x0,0x0L); break; case 2: SetState(VK_SHIFT,1); /* Shift-Ins */ DOMESSAGE(hFoc,WM_KEYDOWN,0x002d,0x08520001L); RestoreState(hFoc); break; case 3: SetState(VK_CONTROL,1); /* Ctrl-V */ DOMESSAGE(hFoc,WM_KEYDOWN,0x0056,0x002f0001L); RestoreState(hFoc); break; } } if ( Drop.mode == 2 ) { SendChars(hFoc,szAllFileNames,wNumFiles); } if ( Drop.active ) SetActiveWindow(hWnd); return 1; } #endif /* CLIPDROP */ /*********************** GLOBAL VARIABLES ***********************************/ char _szAppName[] = "Drop Server"; char *Mode[] ={"Drop Files","Drop using clipBoard","Drop using Keyboard"}; char *Enter[] ={"e","E"}; char *Position[] ={"p","P"}; char *Active[] ={"a","A"}; char *SaveWin[] ={"w","W"}; char *ClipMode[] ={" I:v"," I:p"," I:i"," I:c"}; /****************** ShowDropCursor ******************************************/ void ShowDropCursor(void) { if ( Drop.mode > 0 && Drop.HasBeenOther ) SetCursor(LoadCursor(NULL, IDC_IBEAM)); else if ( Drop.fOkToDrop && Drop.HasBeenOther ) SetCursor((Drop.wNumFiles > 1) ? hCrsrDrpMultiple : hCrsrDrpSingle); else SetCursor(hCrsrDrpNotAllow); } /****************** ShowStatus **********************************************/ void ShowStatus(HWND hWnd) { char s[100]; kopioi_jono(N_S(s),Mode[Drop.mode]); liita_jono(N_S(s)," ["); liita_jono(N_S(s),Enter[Drop.enter]); liita_jono(N_S(s),Position[Drop.position]); liita_jono(N_S(s),Active[Drop.active]); liita_jono(N_S(s),SaveWin[Drop.savewin]); liita_jono(N_S(s),ClipMode[Drop.clipmode]); liita_jono(N_S(s),"]"); ShowDropCursor(); SetWindowText(hWnd,s); MarkWindow((Drop.mode>0)?Drop.hWndCur:NULL); } /****************** DropWndProc *********************************************/ LONG CALLBACK _export DropWndProc(HWND hWnd, unsigned message, WPARAM wParam, LPARAM lParam) { PAINTSTRUCT ps; HWND hWndS; POINT pt; RECT rc; switch (message) { case WM_LBUTTONUP: MarkWindow(NULL); Drop.Stop = 1; return NULL; case WM_CHAR: switch ( wParam ) { case 'K': case 'k': Drop.mode = 2; break; case 'B': case 'b': Drop.mode = 1; break; case 'P': case 'p': Drop.position ^= 1; break; case 'E': case 'e': Drop.enter ^= 1; break; case 'A': case 'a': Drop.active ^= 1; break; case 'W': case 'w': Drop.savewin ^= 1; break; case 'I': case 'i': if ( ++Drop.clipmode > 3 ) Drop.clipmode = 0; break; default : Drop.mode = 0; break; } ShowStatus(hWnd); return NULL; case WM_MOUSEMOVE: GetCursorPos(&pt); hWndS = WindowFromPoint(pt); if ( !Drop.HasBeenOther && Drop.savewin ) { /* Suojaa ikkunan vaiht. */ GetWindowRect(Drop.hMainWnd,&rc); /* jos halutaan edellin. */ if ( PtInRect(&rc,pt) ) goto ShowCursor; Drop.HasBeenOther = 1; } if ( Drop.mode > 0 && Drop.HasBeenOther ) { Drop.hWndCur = hWndS; IsClipbordDrop(hWnd,&Drop.hWndCur,&pt); goto ShowCursor; } Drop.fOkToDrop = FALSE; while ( IsWindow(hWndS) ) { /* Etsitään ikkuna joka hyväksyy dropin */ if ( (GetWindowLong(hWndS, GWL_EXSTYLE) & WS_EX_ACCEPTFILES)) { Drop.fOkToDrop = TRUE; if ( hWndS == Drop.hMainWnd ) { Drop.IsSelf = 1; if ( Drop.HasBeenOther == 0 ) Drop.fOkToDrop = FALSE; } else { Drop.IsSelf = 0; Drop.HasBeenOther = 1; } goto ShowCursor; } hWndS = GetParent(hWndS); } Drop.HasBeenOther = 1; ShowCursor: if ( Drop.HasBeenOther ) { Drop.hWndSubject = hWndS; Drop.ptMousePos = pt; } ShowDropCursor(); return NULL; case WM_DESTROY: /* Viesti: ikkuna hävitetään */ return NULL; default: /* Antaa Windowsin käsitellä muut */ break; } return (DefWindowProc(hWnd, message, wParam, lParam)); } /****************** DropMain ***********************************************/ int DropMain(HINSTANCE hInstance, HCURSOR hCursor,HWND mainhWnd) { RECT rc; WNDCLASS wc; /* Ikkunaluokka */ HWND hWnd; /* Pääikkunan kahva */ MSG msg; /* Viesti */ int ret = 0; InitializeDrop(); Drop.hInstance = hInstance; wc.style = NULL; wc.lpfnWndProc = DropWndProc; wc.cbClsExtra = 0; wc.cbWndExtra = 0; wc.hInstance = hInstance; wc.hIcon = LoadIcon(NULL, IDI_APPLICATION); wc.hCursor = hCursor; wc.hbrBackground = GetStockObject(WHITE_BRUSH); wc.lpszMenuName = NULL; wc.lpszClassName = "WDropClass"; if (!RegisterClass(&wc)) return ret; GetWindowRect(mainhWnd,&rc); hWnd = CreateWindow("WDropClass",_szAppName,WS_OVERLAPPED | WS_CAPTION, rc.left,rc.top,rc.right-rc.left,0, NULL,NULL,hInstance,NULL); if (!hWnd) goto ret; ShowWindow(hWnd, SW_SHOWNORMAL);/* Näytetään ikkuna */ UpdateWindow(hWnd); /* Lähetetään WM_PAINT viesti */ SetCapture(hWnd); Drop.IsSelf = 0; Drop.HasBeenOther = 0; Drop.Stop = 0; if ( Drop.savewin == 0 ) { Drop.hWndSubject = NULL; Drop.hWndCur = NULL; Drop.IsSelf = 1; Drop.HasBeenOther = 0; } ShowStatus(hWnd); while (!Drop.Stop && GetMessage(&msg,NULL,NULL,NULL)) { TranslateMessage(&msg); /* Tulkitaan virtuaaliset näp. koodit */ DispatchMessage(&msg); /* Lähetetään viesti ikkunalle */ } ReleaseCapture(); DestroyWindow(hWnd); ret: UnregisterClass("WDropClass",hInstance); return ret; } /****************************************************************************/ int DropFiles(HWND hWnd,LPSTR szAllFileNames) { int ret; ReplaceChars(szAllFileNames,' ',SPACE); ReplaceChars(szAllFileNames,';',ITEM_SEPARATOR); ret = DropText(hWnd, szAllFileNames); ReplaceChars(szAllFileNames,ITEM_SEPARATOR,';'); ReplaceChars(szAllFileNames,SPACE,' '); return ret; } /****************************************************************************/ int DropText(HWND hWnd,LPCSTR szAllFileNames) { WORD x; BOOL fInNonClientArea; HDROP hDrop, hDropT; HINSTANCE _hInstance = GetWindowWord(hWnd,GWW_HINSTANCE); int retval = 0; Drop.hMainWnd = hWnd; if ( !szAllFileNames ) return 0; // Make sure that there are some selected // files to be dropped Drop.wNumFiles = GetSinglePathName(szAllFileNames, -1, NULL, 0); if ( Drop.wNumFiles == 0 ) { MessageBox(hWnd, "Nothing to drop.",_szAppName, MB_OK); return 0; } // Get the handles to the cursors // that will shown to the user. hCrsrDrpNotAllow = LoadCursor(_hInstance, "DRPFIL_NOTALLOWED"); hCrsrDrpSingle = LoadCursor(_hInstance, "DRPFIL_SINGLE"); hCrsrDrpMultiple = LoadCursor(_hInstance, "DRPFIL_MULTIPLE"); //#define DROP_MESSAGE #ifdef DROP_MESSAGE #include "drop2.inc" #endif DropMain(_hInstance,hCrsrDrpNotAllow,hWnd); // Free the loaded cursors from memory DestroyCursor(hCrsrDrpNotAllow); DestroyCursor(hCrsrDrpSingle); DestroyCursor(hCrsrDrpMultiple); #ifdef DROP_MESSAGE GlobalFree(hDrop); #endif if ( Drop.IsSelf && Drop.HasBeenOther == 0 ) return 0; if ( Drop.mode > 0 ) retval = DropClipboard(hWnd,Drop.hWndCur,szAllFileNames,Drop.wNumFiles); if ( !Drop.fOkToDrop || Drop.mode > 0 ) return retval; // Is the cursor in the window's non-client area? fInNonClientArea = (HTCLIENT != SendMessage(Drop.hWndSubject, WM_NCHITTEST, 0, MAKELPARAM(Drop.ptMousePos.x, Drop.ptMousePos.y))); // Create drop-file memory block and initialize it ScreenToClient(Drop.hWndSubject, &Drop.ptMousePos); hDrop = DragCreateFiles(&Drop.ptMousePos, fInNonClientArea); if (hDrop == NULL) { MessageBox(hWnd, "Insufficient memory to drop file(s).", _szAppName, MB_OK); return 0; } // Append each full pathname to // the drop-file memory block for (x = 0; x < Drop.wNumFiles; x++) { GetSinglePathName(szAllFileNames, x, szDropPathName, sizeof(szDropPathName)); // Append pathname to end of drop-file memory block hDropT = DragAppendFile(hDrop, szDropPathName); if (hDropT == NULL) { MessageBox(hWnd, "Insufficient memory to drop file(s).", _szAppName, MB_OK); GlobalFree(hDrop); hDrop = NULL; return 0; } else { hDrop = hDropT; } } if (hDrop != NULL) { // All pathnames appended successfully, post // the message to the drop-file client window PostMessage(Drop.hWndSubject, WM_DROPFILES, hDrop, 0L); // Clear our own state SendMessage(hWnd, UM_UPDATECAPTION, 0, 0); // Dont't free the memory, the Dropfile // client will do it } return Drop.wNumFiles; } #include /****************************************************************************/ int CollectListBoxItems(HWND hWnd,UINT id,LPCSTR path) { int pit,i,lkm,n=sizeof(szAllFileNames); int *items; int ret = 0; int eka = 0; char sep[2] = {ITEM_SEPARATOR,0}; int is_path = ( path && path[0] ); lkm = (int)SendDlgItemMessage(hWnd,id,LB_GETSELCOUNT,0,0); if ( lkm == LB_ERR || lkm == 0) return 0; items = malloc(sizeof(int)*lkm); if ( !items ) return 0; lkm = (int)SendDlgItemMessage(hWnd,id,LB_GETSELITEMS,lkm,(LPARAM)(int FAR*)items); if ( lkm == LB_ERR ) goto lopetus; szAllFileNames[0] = 0; if ( is_path ) { _fstrncpy(szAllFileNames, path,n-1); sep[0]=' '; } else eka = 1; n -= strlen(szAllFileNames); for (i=0; i mb-2 ) break; _fstrcat(s,st); if ( i < n-1 ) _fstrcat(s,ITEMSEPSTR); } DragFinish(hDrop); /* Muistilohkon vapautus! */ return s; } /****************************************************************************/ LPSTR RemovePath(LPSTR s) { int i = lstrlen(s)-1; for ( ;i>0; i-- ) if ( strchr("\\:",s[i]) ) return s+i+1; return s; } /****************************************************************************/ int DropFilesToListBox(HDROP hDrop,HWND hWnd,int id,int clear) { int i,n = DragQueryFile(hDrop,-1,NULL,0); /* Nimien määrä*/ LPSTR sd; if ( clear & 2 ) SendDlgItemMessage(hWnd,id,LB_RESETCONTENT,0,0); for (i=0; i