/* DDSERVER.C -- Demonstrates server end of Drag and Drop protocol in both 3.0 and 3.1 using DragObject Copyright (c) Dave Maxey 1992 From Chapter 6 of "Undocumented Windows" (Addison-Wesley 1992) by Andrew Schulman, Dave Maxey and Matt Pietrek Build using: WINIOBC DDSERVER (for Borland C++ v3.00) WINIOMS DDSERVER (for Microsoft C/SDK) */ #include #include #include "wmhandlr.h" #include "winio.h" #include "dragdrop.h" #ifndef __BORLANDC__ #define MK_FP(a,b) ((void far *)(((unsigned long)(a) << 16) | (b))) #endif #define ID_HELP 1 void usage_help(HWND hwnd, WORD wId) { HWND hSave; static HWND hwndHelp = NULL; if (IsWindow(hwndHelp)) { BringWindowToTop(hwndHelp); return; } if (! (hwndHelp = winio_window("HELP", 1, WW_HASMENU))) return; hSave = winio_setcurrent(hwndHelp); winio_setpaint(hwndHelp, FALSE); printf( "At any stage, in response to the prompt,\n" "\tyou may enter a list of one or more\n" "\tfilenames or directories. If more\n" "\tthan one is entered, each filename\n" "\tin the list should be separated by\n" "\ta space, eg:\n" "\t\tfile.001 file.002\n" "\n" "The currently defined files may be dragged\n" "\tout of DDSERVER into, for example the\n" "\tDDCLIENT program, or Program Manager.\n" "\n" "Note that when the program starts, no files\n" "\thave yet been defined, so dragging is\n" "\tnot possible until you have entered\n" "\tat least one file or directory.\n" "\n" "For more information, please refer to the\n" "\tDragObject entry in Chapter 6 of\n" "\t\"Undocumented Windows\".\n"); winio_setpaint(hwndHelp, TRUE); winio_home(hwndHelp); winio_setcurrent(hSave); } /* Undocumented function DRAGOBJ */ /* Compile with 3.0 SDK, run with 3.0/3.1 */ extern DWORD FAR PASCAL DragObject(HWND hwndScope, HWND hwndOwner, WORD wFlags, WORD hOfstruct, char *szList, HCURSOR hDragCursor); char filelist[128]; char szSaveTitle[128]; WMHANDLER prev_lbuttondown, prev_lbuttonup, prev_mousemove; HCURSOR hDragCursor; BOOL bDrag = FALSE; WORD wDragType; HANDLE hOfstruct = 0; LPOFSTRUCT lpof; int cObjs; char *szArgv0; #include "checkord.c" WORD verr(WORD sel) { _asm mov ax, 1 _asm verr word ptr sel _asm je short ok _asm dec ax ok:; } BOOL do_DragObject(void) { DWORD lRet; puts("Dragging..."); GetWindowText(__hMainWnd, szSaveTitle, sizeof(szSaveTitle)); winio_settitle(__hMainWnd, szArgv0); lRet = DragObject(GetDesktopWindow(), __hMainWnd, wDragType, hOfstruct, (char *) &filelist, hDragCursor); winio_settitle(__hMainWnd, szSaveTitle); printf("Returned %08lX\n", lRet); switch (lRet) { case DRAG_PRNT : printf("Dropped onto a print oriented app.\n"); break; case DRAG_FILE : printf("Dropped onto a file oriented app.\n"); break; case 1 : printf("Drop accepted (rejected if v3.1).\n"); break; default : printf("Drop not completed.\n"); return FALSE; } return TRUE; } void do_31Protocol(void) { DWORD pntDrop; HANDLE hDropInfo; DWORD dwSizeBlk; LPDROPINFO lpDropInfo; int i; LPSTR lpsz; char *sz; char szBuf[80]; HWND hwndDrop; pntDrop = GetMessagePos(); // Estimate size of allocation needed. This should be plenty. dwSizeBlk = (DWORD) cObjs * 128; hDropInfo = GlobalAlloc(GMEM_DDESHARE | GMEM_ZEROINIT, dwSizeBlk); lpDropInfo = (LPDROPINFO) GlobalLock(hDropInfo); lpDropInfo->wOfsFirst = 8; lpDropInfo->xDrop = LOWORD(pntDrop); lpDropInfo->yDrop = HIWORD(pntDrop); lpsz = (LPSTR) &lpDropInfo->chBuffer; // WinFile emulation! lstrcpy((LPSTR) &szBuf, szArgv0); // remove filename to leave \ terminated path *(strrchr(szBuf, '\\') + 1) = 0; sz = filelist; szBuf[0] = 0; // vl // copy in complete pathed filenames for (i = 0; i < cObjs; i++) { lstrcpy(lpsz, (LPSTR) &szBuf); lstrcat(lpsz, (LPSTR) strtok(sz, " ")); lpsz = (LPSTR) ((DWORD) lpsz + lstrlen(lpsz) + 1); sz = NULL; } for (; i > 0; i--) filelist[strlen(filelist)] = ' '; GlobalUnlock(hDropInfo); // Find out who to send WM_DROPFILES to hwndDrop = WindowFromPoint(MAKEPOINT(pntDrop)); SendMessage(hwndDrop, WM_DROPFILES, hDropInfo, 0L); // In case the client app doesn't follow the rules if (verr(hDropInfo)) GlobalFree(hDropInfo); } BOOL free_sel(HWND hwnd) { if (hOfstruct) GlobalFree(hOfstruct); return TRUE; } long my_lbuttondown(HWND hwnd, WORD wMsg, WORD wParam, DWORD lParam) { // Only allow dragging if there is something to drag if (filelist[0]) bDrag = TRUE; return (*prev_lbuttondown)(hwnd, wMsg, wParam, lParam); } long my_lbuttonup(HWND hwnd, WORD wMsg, WORD wParam, DWORD lParam) { bDrag = FALSE; return (*prev_lbuttonup)(hwnd, wMsg, wParam, lParam); } long my_mousemove(HWND hwnd, WORD wMsg, WORD wParam, DWORD lParam) { if (bDrag) { // Avoid 'reentrancy' bDrag = FALSE; if (do_DragObject()) do_31Protocol(); } return (*prev_mousemove)(hwnd, wMsg, wParam, lParam); } int main(int argc, char *argv[]) { int i; char *sz; if (! CheckOrdName("DragObject", "USER", 464)) return 0; winio_settitle(__hMainWnd, "Drag'n'Drop Server"); winio_about("DDSERVER" "\nDemonstrates server end of Drag and Drop protocol" "\nin both 3.0 and 3.1 using DragObject" "\n\nFrom Chapter 6 of" "\n\"Undocumented Windows\" (Addison-Wesley, 1992)" "\nby Andrew Schulman, David Maxey and Matt Pietrek" ); winio_setmenufunc(__hMainWnd, ID_HELP, (MENU_FUNC) usage_help); InsertMenu(winio_hmenuhelp(__hMainWnd), 0, MF_STRING | MF_ENABLED | MF_BYPOSITION, ID_HELP, "&Usage"); // for later WinFile emulation (!) szArgv0 = argv[0]; prev_lbuttondown = wmhandler_set(__hMainWnd, WM_LBUTTONDOWN, (WMHANDLER) my_lbuttondown); prev_lbuttonup = wmhandler_set(__hMainWnd, WM_LBUTTONUP, (WMHANDLER) my_lbuttonup); prev_mousemove = wmhandler_set(__hMainWnd, WM_MOUSEMOVE, (WMHANDLER) my_mousemove); winio_onclose(__hMainWnd, (DESTROY_FUNC) free_sel); // Use the class icon for the drag cursor hDragCursor = GetClassWord(__hMainWnd, GCW_HICON); while (TRUE) { printf("Enter file(s) and/or dir(s)\n" "separated by a single space:\n"); gets(filelist); strupr(filelist); // Ensure it is space char terminated if (filelist[strlen(filelist) - 1] != ' ') strcat(filelist, " "); printf("List is <%s>\n", filelist); for (i = 0, cObjs = 0; filelist[i]; i++) if (filelist[i] == ' ') cObjs++; // Free up the last allocation if necessary if (hOfstruct) { GlobalFree(hOfstruct); hOfstruct = 0; } // Detect the 'object' type if (cObjs > 1) wDragType = DRAGOBJ_MULTIPLE; else if (filelist[strlen(filelist) - 2] == '\\') wDragType = DRAGOBJ_DIRECTORY; else { // Allocate ourselves a global block for a single file hOfstruct = GlobalAlloc(GMEM_DDESHARE, sizeof(OFSTRUCT)); lpof = (LPOFSTRUCT) GlobalLock(hOfstruct); OpenFile((LPSTR) &filelist, lpof, OF_PARSE); printf("Filename parsed to: %Fs\n", (LPSTR) &lpof->szPathName); if (((sz = strchr(filelist, '.')) != NULL) && ((strncmp((char *) (sz+1), "EXE", 3) == 0) || (strncmp((char *) (sz+1), "BAT", 3) == 0) || (strncmp((char *) (sz+1), "COM", 3) == 0))) wDragType = DRAGOBJ_PROGRAM; else wDragType = DRAGOBJ_DATA; wDragType |= DRAGOBJ_EXTERNAL; GlobalUnlock(hOfstruct); } } return 0; }