/**************/ /* 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 13.8.1995 lisäsi optiodialogin 3.9.1995 nyt isojenkin joukkojen pudottaminen mahdollista 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,sep); kun halutaan siirtää tiedostojen nimiä toiseen ohjelmaan. files on merkkijonomuuttuja, joka on muotoa (jonojen välissä sep) "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 opt) -------------------------------------------------------------- - ottaa Drop listassa olevat nimet ja laittaa ne list-boxiin hWnd,id. opt == 1 => poistaa nimistä polkuosan DAD_ONLYNAME == 2 => tyhjentää ensin list-boxin DAD_RESET == 3 => molemmat edelliset ( == 1 | 2 ) == 4 => nimet muutetaan ensin pieniksi DAD_SMALL == 8 => dublikaattit huolitaan DAD_DUB 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 int GetSinglePathName (LPCSTR szFileOpenStr, int wIndex, LPSTR szPathName, int 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. int SetNotifyDrag(HWND hWnd) ------------------------------------------------------- - laittaa ikkunalle tiedon siitä, että sille ilmoitetaan lun kursoria siirretään ikkunassa hieman sitä pohajassa pitäen. Tämä on yleensä alku Drag and Dropia verten (yleensä LISTBOXille). Käytännössä ikkuna saa viestin WM_BEGINDRAG ja tämän jälkeen sen on kutsuttava esim aliohjelmaa DropListBoxFiles int InitDaDOptions(const char *inifile) ------------------------------------------------------- - sama kuin InitDragAndDrop(ininame,0); int SaveDaDOptions(const char *inifile) ------------------------------------------------------- - sama kuin InitDragAndDrop(ininame,1); int DaDOptionDialog(HWND hWnd) ------------------------------------------------------- - DaD optioiden dialogi näyttöön Suunnitelmia: ------------- - optioita: pudotusnimeen: levyasema, hakemisto, tiedoston nimi 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 #include #include #ifdef CLIPDROP # include "mjonot.h" # include "clipboar.h" #endif #include "Dropfile.h" #define SPACE 0x01 #define ITEM_SEPARATOR ((char)0xff) #define ITEMSEPSTR "\0177" #define DOMESSAGE DoMessage /****************** ConvertPt **********************************************/ void ConvertPt(const POINT *pt,POINTS *pts) { pts->x = (short)pt->x; pts->y = (short)pt->y; } void ConvertPts(const POINTS *pts,POINT *pt) { pt->x = pts->x; pt->y = pts->y; } void ScreenToClientPt(HWND hwnd, POINTS *pts) { POINT pt; ConvertPts(pts,&pt); ScreenToClient(hwnd, &pt); ConvertPt(&pt,pts); } void SetActiveWindow32(HWND hwnd) { #ifdef WIN32 SetForegroundWindow(hwnd); #else SetActiveWindow(hwnd); #endif } /****************************************************************************/ static LPSTR ReplaceChars(LPSTR s,char cfrom,char cto) { LPSTR p; if ( s == NULL ) return ""; 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,int 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; } /****************************************************************************/ int GetSinglePathName (LPCSTR szFileOpenStr, int wIndex, LPSTR szPathName, int 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 => "" */ { int wNumFiles, 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 *****************/ /****************** *****************/ /***************************************************************/ #define EXTRA_ZEROS 4 #ifdef WIN32 typedef struct { LONG wSize; // Size of data structure POINT ptMousePos; // Position of mouse cursor LONG fInNonClientArea; // Was the mouse in the window's non-client area LONG dummy; } DROPFILESTRUCT, FAR *LPDROPFILESTRUCT; #else typedef struct { WORD wSize; // Size of data structure POINTS ptMousePos; // Position of mouse cursor BOOL fInNonClientArea; // Was the mouse in the // window's non-client area } DROPFILESTRUCT, FAR *LPDROPFILESTRUCT; #endif //*************************************************************** HDROP DragCreateFiles (LPPOINTS 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) + EXTRA_ZEROS); // 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.x = lpptMousePos->x; lpDropFileStruct->ptMousePos.y = lpptMousePos->y; lpDropFileStruct->fInNonClientArea = fInNonClientArea; GlobalUnlock(hDrop); return(hDrop); } //*************************************************************** int DragSetPoint(HGLOBAL hDrop,LPPOINTS lpptMousePos) { LPDROPFILESTRUCT lpDropFileStruct; lpDropFileStruct = (LPDROPFILESTRUCT) GlobalLock(hDrop); lpDropFileStruct->ptMousePos.x = lpptMousePos->x; lpDropFileStruct->ptMousePos.y = lpptMousePos->y; GlobalUnlock(hDrop); return 0; } //*************************************************************** HDROP DragAppendFile (HGLOBAL hDrop, LPCSTR szPathname) { LPDROPFILESTRUCT lpDropFileStruct; LPCSTR lpCrnt; WORD wSize; WORD plen = (WORD)lstrlen(szPathname); int i; 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); GlobalUnlock(hDrop); // Increase block size to accommodate // the new pathname being appended hDrop = GlobalReAlloc(hDrop, wSize + EXTRA_ZEROS + plen + 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, szPathname); for (i=1; i<=EXTRA_ZEROS; i++ ) *((LPSTR)lpDropFileStruct + wSize + plen + i) = 0; GlobalUnlock(hDrop); return(hDrop); // Return the new handle to the block } /****************************************************************************/ /********************** **************************/ /********************** FILE OPEN UTILITY FUNCTION **************************/ /********************** **************************/ /****************************************************************************/ static char szAllFileNames[500]; static char szDropPathName[200]; //static char szModDropPathName[200]; /****************** MultiSelectFiles ****************************************/ LPSTR MultiSelectFiles(HWND hWnd,LPSTR szAllFileNames,int mb) { OPENFILENAME ofn; if ( szAllFileNames == NULL ) return NULL; // 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 = mb; if ( !GetOpenFileName(&ofn) ) return NULL; if ( szAllFileNames[0] == 0 ) return NULL; return szAllFileNames; } /****************** SelectDropFiles *****************************************/ int DropSelectFiles(HWND hWnd) { return DropFiles(hWnd,MultiSelectFiles(hWnd,N_S(szAllFileNames)),SPACE); } /****************************************************************************/ /********************** **************************/ /********************** Drop functions **************************************/ /********************** **************************/ /****************************************************************************/ /****************************************************************************/ typedef struct { 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 */ char droptime; /* 1 = optiot muutuvat pysyvästi myös tiputuksen aikana*/ } tDaDOptions; typedef struct { int init; int optiot; int Stop; int wNumFiles; BOOL fInNonClientArea, fOkToDrop; POINTS ptMousePos; POINTS clipMousePos; HWND hWndSubject; /* Ikkuna jonne pudotetaan */ HWND hWndCur; /* Leikekirjapudotuksessa alla oleva ikkuna */ HWND hMainWnd; /* Ikkuna, josta pudotus on lähtenyt */ HINSTANCE hInstance; char IsSelf; /* Ollaan vielä ikkunassa itsessään */ char HasBeenOther; /* To see not to drop over self */ tDaDOptions opt; } tDrop; static tDrop Drop; static tDaDOptions DaDOpt; /****************************************************************************/ static void InitializeDrop(void) { if ( Drop.init ) return; Drop.init = 1; DaDOpt.enter = 1; DaDOpt.clipmode = 3; } /****************************************************************************/ /* Optioiden käsittely */ /****************************************************************************/ #include "optdlg.h" #include "dropfile.rh" #define NPK N_P_K #define DO tDaDOptions #define K2(t) t,t static const KontrolliKuvaus DaDOptCtrl[] = { {IDC_DAD_FILEDROP,IDC_DAD_KEYBDROP, C_arbu, NPK(DO,mode) ,T_byte ,0,NULL}, {K2(IDC_DAD_ENTER ) , C_acbo, NPK(DO,enter) ,T_byte ,0,NULL}, {K2(IDC_DAD_POSITION) , C_acbo, NPK(DO,position) ,T_byte ,0,NULL}, {K2(IDC_DAD_ACTIVE) , C_acbo, NPK(DO,active) ,T_byte ,0,NULL}, {K2(IDC_DAD_SAVEWIN) , C_acbo, NPK(DO,savewin) ,T_byte ,0,NULL}, {IDC_DAD_CTRLV,IDC_DAD_CTRLVS , C_arbu, NPK(DO,clipmode) ,T_byte ,0,NULL}, {K2(IDC_DAD_DROPTIME) , C_acbo, NPK(DO,droptime) ,T_byte ,0,NULL}, {K2(0) , 0 , 0 ,0, 0,NULL} }; #undef NPK #undef DO #undef K2 static DialogiParam DaDOptDlgParam = { "DADOPTIONS", D_modal, DaDOptCtrl, "DAD", "DAD", &DaDOpt, sizeof(DaDOpt) }; int DaDOptionDialog(HWND hWnd) { return OptioDialogiJaIni(hWnd,&DaDOptDlgParam,OPT_SAVE); } static int ChangeIniName(const char *inifile) { static char name[100]; strncpy(name,inifile,sizeof(name)-1); name[sizeof(name)-1] = 0; DaDOptDlgParam.odTiedosto = name; return 0; } int InitDaDOptions(const char *inifile) { InitializeDrop(); ChangeIniName(inifile); return AlustaOptiot(&DaDOptDlgParam); } int SaveDaDOptions(const char *inifile) { ChangeIniName(inifile); return TalletaOptiot(&DaDOptDlgParam); } /****************************************************************************/ /* Optioiden käsittely tehty */ /****************************************************************************/ /****************************************************************************/ static HCURSOR hCrsrDrpNotAllow, hCrsrDrpSingle, hCrsrDrpMultiple; #ifdef CLIPDROP // *************************************************************** // 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 szFileNames,int wNumFiles) { int i; Selection[0]=0; for (i = 0; i < wNumFiles; i++) { GetSinglePathName(szFileNames,i,N_S(szDropPathName)); liita_jono(N_S(Selection),szDropPathName); if ( Drop.opt.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, (UINT)ms, lpfnMyTimerProc); while ( Waiting && timer) { if ( PeekMessage(&msg,NULL /*Drop.hMainWnd*/,NULL,NULL,PM_REMOVE) ) DispatchMessage(&msg); } KillTimer(Drop.hMainWnd,timer); (void)FreeProcInstance((FARPROC)lpfnMyTimerProc); return 0; } /****************************************************************************/ static void PutSelectionToClipboard(HWND hWnd, LPCSTR szFileNames,int wNumFiles) { char *s = SelectionText(szFileNames,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] &= (BYTE)(~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 szFileNames,int wNumFiles) { int i; Selection[0]=0; for (i = 0; i < wNumFiles; i++) { GetSinglePathName(szFileNames,i, szDropPathName, sizeof(szDropPathName)); SendStr(hWnd,szDropPathName); if ( Drop.opt.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 { POINTS 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; POINT pt; GetWindowRect(hWnd,&rc); pt.x = FB.Mousept.x; pt.y = FB.Mousept.y; if ( !PtInRect(&rc,pt) ) 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 MarkSuitableWindowUnderCursor(HWND hWnd,HWND *hWndCur,POINT *ptMousePos) /* Jos shift alhaalla, niin tutkitaan tarkemmin */ { #pragma argsused HWND hParent; FARPROC EnumProc; //study_windows: EnumProc = MakeProcInstance((FARPROC)EnumChildsToFindBest, GetWindowInstance(hWnd)); hParent = GetParent(*hWndCur); ConvertPt(ptMousePos,&FB.Mousept); FB.hWndCur = *hWndCur; FB.CurWndFound = 0; FB.hBest = NULL; EnumChildWindows(hParent,(WNDENUMPROC)EnumProc,0); (void)FreeProcInstance(EnumProc); ConvertPt(ptMousePos,&Drop.clipMousePos); if ( FB.CurWndFound && FB.hBest ) *hWndCur = FB.hBest; MarkWindow(*hWndCur); return 0; } /****************** DropClipboard *******************************************/ static int DropClipboard(HWND hWnd,HWND hWndCur, LPCSTR szFileNames,int wNumFiles) { #pragma argsused HWND hFoc; LPARAM lParam; POINT pt; pt.x = Drop.clipMousePos.x; pt.y = Drop.clipMousePos.y; MarkWindow(NULL); ScreenToClient(hWndCur, &pt); SetActiveWindow32(hWndCur); #ifdef WIN32 // hFoc = GetForegroundWindow(); hFoc = hWndCur; #else SetFocus(hWndCur); hFoc =GetFocus(); #endif lParam=MAKELONG(pt.x,pt.y); if ( Drop.opt.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.opt.mode == 1) { PutSelectionToClipboard(hWnd,szFileNames,wNumFiles); switch ( Drop.opt.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.opt.mode == 2 ) { SendChars(hFoc,szFileNames,wNumFiles); } if ( Drop.opt.active ) SetActiveWindow32(hWnd); return 1; } #endif /* CLIPDROP */ /*********************** GLOBAL VARIABLES ***********************************/ static char _szAppName[] = "Drop Server"; static char *Mode[] ={"Drop Files","Drop using clipBoard","Drop using Keyboard"}; static char *Enter[] ={"e","E"}; static char *Position[] ={"p","P"}; static char *Active[] ={"a","A"}; static char *SaveWin[] ={"w","W"}; static char *ClipMode[] ={" I:v"," I:m"," I:i"," I:c"}; /****************** ShowDropCursor ******************************************/ void ShowDropCursor(void) { if ( Drop.opt.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.opt.mode]); liita_jono(N_S(s)," ["); liita_jono(N_S(s),Enter[Drop.opt.enter]); liita_jono(N_S(s),Position[Drop.opt.position]); liita_jono(N_S(s),Active[Drop.opt.active]); liita_jono(N_S(s),SaveWin[Drop.opt.savewin]); liita_jono(N_S(s),ClipMode[Drop.opt.clipmode]); liita_jono(N_S(s),"]"); ShowDropCursor(); SetWindowText(hWnd,s); MarkWindow( (Drop.opt.mode>0) ? Drop.hWndCur : (HWND)NULL ); } /****************** DropWndProc *********************************************/ LONG CALLBACK _export DropWndProc(HWND hWnd, unsigned message, WPARAM wParam, LPARAM lParam) { 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.opt.mode = 2; break; case 'B': case 'b': Drop.opt.mode = 1; break; case 'P': case 'p': Drop.opt.position ^= 1; break; case 'E': case 'e': Drop.opt.enter ^= 1; break; case 'A': case 'a': Drop.opt.active ^= 1; break; case 'W': case 'w': Drop.opt.savewin ^= 1; break; case 'V': case 'v': Drop.opt.clipmode = 0; break; case 'M': case 'm': Drop.opt.clipmode = 1; break; case 'I': case 'i': Drop.opt.clipmode = 2; break; case 'C': case 'c': Drop.opt.clipmode = 3; break; case 'O': case 'o' : Drop.optiot = 1; /* HUOM! Tahallinen jatko! */ case 0x1b : Drop.Stop = 1; Drop.IsSelf = 1; Drop.HasBeenOther = 0; break; default : Drop.opt.mode = 0; break; } ShowStatus(hWnd); return NULL; case WM_MOUSEMOVE: GetCursorPos(&pt); hWndS = WindowFromPoint(pt); if ( !Drop.HasBeenOther && Drop.opt.savewin ) { /* Suojaa ikkunan vaiht. */ GetWindowRect(Drop.hMainWnd,&rc); /* jos halutaan edellin. */ if ( PtInRect(&rc,pt) ) goto ShowCursor; Drop.HasBeenOther = 1; } if ( Drop.opt.mode > 0 && Drop.HasBeenOther ) { Drop.hWndCur = hWndS; MarkSuitableWindowUnderCursor(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 ) { /* Ollaan lähtö ikkunassa */ Drop.IsSelf = 1; if ( Drop.HasBeenOther == 0 ) Drop.fOkToDrop = FALSE; } else { /* Ollaan eri ikkunassa */ Drop.IsSelf = 0; Drop.HasBeenOther = 1; } goto ShowCursor; } hWndS = GetParent(hWndS); } Drop.HasBeenOther = 1; ShowCursor: if ( Drop.HasBeenOther ) { Drop.hWndSubject = hWndS; ConvertPt(&pt,&Drop.ptMousePos); } 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.optiot = 0; Drop.opt = DaDOpt; 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.opt.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); if ( DaDOpt.droptime ) DaDOpt = Drop.opt; if ( Drop.optiot ) DaDOptionDialog(GetFocus()); return ret; } /****************************************************************************/ int DropText(HWND hWnd,LPCSTR szFileNames) { WORD x; BOOL fInNonClientArea; HDROP hDrop, hDropT; HINSTANCE _hInstance = GetWindowInstance(hWnd); int retval = 0; Drop.hMainWnd = hWnd; if ( !szFileNames ) return 0; // Make sure that there are some selected // files to be dropped Drop.wNumFiles = GetSinglePathName(szFileNames, -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.opt.mode > 0 ) retval = DropClipboard(hWnd,Drop.hWndCur,szFileNames,Drop.wNumFiles); if ( !Drop.fOkToDrop || Drop.opt.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 ScreenToClientPt(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(szFileNames, x,szDropPathName, sizeof(szDropPathName)); // QueteIfNeeded(N_S(szModDropPathName),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, (WPARAM)hDrop, 0L); // Clear our own state SendMessage(hWnd, UM_UPDATECAPTION, 0, 0); // Dont't free the memory, the Dropfile // client will do it if ( !Drop.opt.active ) SetActiveWindow32(Drop.hWndSubject); } return Drop.wNumFiles; } /****************************************************************************/ int DropFiles(HWND hWnd,LPSTR szFileNames,char sep) { int ret; if ( szFileNames == NULL ) return 0; if ( sep != SPACE ) ReplaceChars(szFileNames,sep,SPACE); ReplaceChars(szFileNames,';',ITEM_SEPARATOR); ret = DropText(hWnd, szFileNames); ReplaceChars(szFileNames,ITEM_SEPARATOR,';'); if ( sep != SPACE ) ReplaceChars(szFileNames,SPACE,sep); return ret; } /****************************************************************************/ int CollectListBoxItems(HWND hWnd,UINT id,LPCSTR path,char **szAllFileNames, const char *pads,const char *separator,char space) { int i,lkm,koko; int *items; char *p; int ret = 0; int eka = 0; char sepi[2] = {ITEM_SEPARATOR,0}; char sepc[2] = {SPACE,0}; // vl-97 " "; const char *sep = separator; const char *pad =pads; int seplen; int padlen; int is_path = ( path && path[0] ); HWND lhWnd = GetDlgItem(hWnd,id); sepc[0] = space; if ( sep == NULL ) sep = sepi; if ( is_path ) sep = sepc; seplen = strlen(sep); if ( pad == NULL ) pad = ""; padlen = strlen(pad); lkm = ListBox_GetSelCount(lhWnd); if ( lkm == LB_ERR || lkm == 0) return 0; items = malloc(sizeof(int)*lkm); if ( !items ) return 0; lkm = ListBox_GetSelItems(lhWnd,lkm,items); if ( lkm == LB_ERR ) goto lopetus; /* ------------ Lasketaan merkityn alueen koko ---------------------------*/ koko = 0; if ( is_path ) koko = strlen(path); else eka = 1; for (i=0; i mb-2 ) break; _fstrcat(s,st); if ( i < n-1 ) _fstrcat(s,ITEMSEPSTR); } DragFinish(hDrop); /* Muistilohkon vapautus! */ return s; } /****************************************************************************/ LPCSTR RemovePath(LPCSTR s) { int i = lstrlen(s)-1; for ( ;i>0; i-- ) if ( strchr("\\:",s[i]) ) return s+i+1; return s; } /****************************************************************************/ static LPSTR ToSmall(LPSTR st) { LPSTR s; for (s=st; *s; s++ ) *s = (char)tolower(*s); return st; } /****************************************************************************/ int DropFilesToListBox(HDROP hDrop,HWND hWnd,int id,int opt) { int i,n = DragQueryFile(hDrop,-1,NULL,0); /* Nimien määrä*/ LPSTR sd; HWND lhWnd = GetDlgItem(hWnd,id); if ( opt & DAD_RESET ) (void)ListBox_ResetContent(lhWnd); for (i=0; i= 0 ) continue; (void)ListBox_AddString(lhWnd,sd); } DragFinish(hDrop); /* Muistilohkon vapautus! */ return n; } /****************************************************************************/ int InitDragAndDrop(const char *inifilename,int write) { if ( write ) return SaveDaDOptions(inifilename); return InitDaDOptions(inifilename); } int SetNotifyDrag(HWND hWnd) { SetWindowLong(hWnd,GWL_EXSTYLE,GetWindowLong(hWnd,GWL_EXSTYLE) | WES_NOTIFYDRAG); return 0; }