mirror of https://github.com/lianthony/NT4.0
You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
566 lines
16 KiB
566 lines
16 KiB
/*
|
|
* Code for Drag/Drop APITEXT('s. - Originally dragdrop.c in shell\library.
|
|
*
|
|
* This code assumes something else does all the dragging work; it just
|
|
* takes a list of files after all the extra stuff.
|
|
*
|
|
* The File Manager is responsible for doing the drag loop, determining
|
|
* what files will be dropped, formatting the file list, and posting
|
|
* the WM_DROPFILES message.
|
|
*
|
|
* The list of files is a sequence of zero terminated filenames, fully
|
|
* qualified, ended by an empty name (double NUL). The memory is allocated
|
|
* DDESHARE.
|
|
*/
|
|
|
|
#include "shellprv.h"
|
|
#pragma hdrstop
|
|
|
|
#ifdef WIN32
|
|
|
|
// BUGBUG (See davepl) possible non-32 bit build problem. May need
|
|
// to move views.h out of precompiled header if this will
|
|
// be compiled for 16-bit
|
|
|
|
#else
|
|
// this is defined in shlobj.h (32 bit only header)
|
|
//
|
|
// format of CF_HDROP and CF_PRINTERS, in the HDROP case the data that follows
|
|
// is a double null terinated list of file names, for printers they are printer
|
|
// friendly names
|
|
//
|
|
typedef struct _DROPFILES {
|
|
DWORD pFiles; // offset of file list
|
|
POINTL pt; // drop point (client coords)
|
|
DWORD fNC; // is it on NonClient area
|
|
// and pt is in screen coords
|
|
DWORD fWide; // WIDE character switch
|
|
} DROPFILES, FAR * LPDROPFILES;
|
|
|
|
//
|
|
// Win 3.1 style HDROP
|
|
//
|
|
// Notes: Our API works only if pFiles == sizeof(DROPFILES16)
|
|
//
|
|
typedef struct _DROPFILES16 {
|
|
WORD pFiles; // offset to double null list of files
|
|
POINTS pt; // drop point (client coords)
|
|
WORD fNC; // is it on non client area
|
|
// and pt is in screen coords
|
|
} DROPFILES16, FAR * LPDROPFILES16;
|
|
#endif // WIN32
|
|
|
|
|
|
#ifdef WIN32
|
|
|
|
// new chicago API
|
|
// in:
|
|
// hDrop drop handle
|
|
//
|
|
// out:
|
|
// a bunch of info about the hdrop
|
|
// (mostly the pointer to the double NULL file name list)
|
|
//
|
|
// returns:
|
|
// TRUE the DROPINFO struct was filled in
|
|
// FALSE the hDrop was bad
|
|
//
|
|
// return Source HWND. This will be NULL if from an old APP.
|
|
// return dwEffect which contains possible effects such as "copy" or "move".
|
|
|
|
BOOL WINAPI DragQueryInfo(HDROP hDrop, LPDRAGINFO lpdi)
|
|
{
|
|
LPTSTR lpOldFileList;
|
|
|
|
if (hDrop && (lpdi->uSize == SIZEOF(DRAGINFO))) {
|
|
|
|
LPDROPFILES lpdfx = (LPDROPFILES)GlobalLock((HGLOBAL)hDrop);
|
|
|
|
//
|
|
// REVIEW: Don')t we need this assert here?
|
|
//
|
|
// Assert(lpdfx == (LPDROPFILES)hDrop);
|
|
|
|
lpdi->lpFileList = NULL;
|
|
|
|
if (lpdfx)
|
|
{
|
|
if (LOWORD(lpdfx->pFiles)==SIZEOF(DROPFILES16))
|
|
{
|
|
//
|
|
// This is Win31-stye HDROP
|
|
//
|
|
LPDROPFILES16 pdf16 = (LPDROPFILES16)lpdfx;
|
|
lpdi->pt.x = pdf16->pt.x;
|
|
lpdi->pt.y = pdf16->pt.y;
|
|
lpdi->fNC = pdf16->fNC;
|
|
lpdi->grfKeyState = 0;
|
|
lpOldFileList = (LPTSTR)((LPBYTE)pdf16 + pdf16->pFiles);
|
|
}
|
|
else
|
|
{
|
|
//
|
|
// This is a new (NT-compatible) HDROP.
|
|
//
|
|
lpdi->pt.x = lpdfx->pt.x;
|
|
lpdi->pt.y = lpdfx->pt.y;
|
|
lpdi->fNC = lpdfx->fNC;
|
|
lpdi->grfKeyState = 0;
|
|
lpOldFileList = (LPTSTR)((LPBYTE)lpdfx + lpdfx->pFiles);
|
|
|
|
// there could be other data in there, but all
|
|
// the HDROPs we build should be this size
|
|
Assert(lpdfx->pFiles == SIZEOF(DROPFILES));
|
|
}
|
|
|
|
{
|
|
BOOL fListMatchesBuild;
|
|
|
|
#ifdef UNICODE
|
|
if ((LOWORD(lpdfx->pFiles) == SIZEOF(DROPFILES16)) || lpdfx->fWide == FALSE)
|
|
{
|
|
fListMatchesBuild = FALSE;
|
|
}
|
|
else
|
|
{
|
|
fListMatchesBuild = TRUE;
|
|
}
|
|
#else
|
|
if ((LOWORD(lpdfx->pFiles) != SIZEOF(DROPFILES16)) && lpdfx->fWide == TRUE)
|
|
{
|
|
Assert(0 && "Unicode drop to Ansi explorer not supported");
|
|
GlobalUnlock((HGLOBAL)hDrop);
|
|
return FALSE;
|
|
}
|
|
else
|
|
{
|
|
fListMatchesBuild = TRUE;
|
|
}
|
|
#endif
|
|
|
|
if (fListMatchesBuild)
|
|
{
|
|
LPTSTR pTStr = (LPTSTR) lpOldFileList;
|
|
LPTSTR pNewFileList;
|
|
UINT cbAlloc;
|
|
|
|
// Look for the end of the file list
|
|
|
|
while (*pTStr || *(pTStr + 1))
|
|
{
|
|
pTStr++;
|
|
}
|
|
pTStr++; // Advance to last NUL of double terminator
|
|
|
|
cbAlloc = (pTStr - lpOldFileList + 1) * SIZEOF(TCHAR);
|
|
|
|
pNewFileList = (LPTSTR) SHAlloc(cbAlloc);
|
|
if (NULL == pNewFileList)
|
|
{
|
|
GlobalUnlock((HGLOBAL)hDrop);
|
|
return FALSE;
|
|
}
|
|
|
|
// Copy strings to new buffer and set LPDROPINFO filelist
|
|
// pointer to point to this new buffer
|
|
|
|
CopyMemory(pNewFileList, lpOldFileList, cbAlloc);
|
|
lpdi->lpFileList = pNewFileList;
|
|
}
|
|
else
|
|
{
|
|
LPXSTR pXStr = (LPXSTR) lpOldFileList;
|
|
LPTSTR pNewFileList;
|
|
LPTSTR pSaveFileList;
|
|
UINT cbAlloc;
|
|
UINT cchConverted;
|
|
|
|
// Look for the end of the file list
|
|
|
|
while (*pXStr || (*(pXStr + 1)))
|
|
{
|
|
pXStr++;
|
|
}
|
|
pXStr++; // Advance to the last NUL of the double terminator
|
|
|
|
cbAlloc = (pXStr - ((LPXSTR) lpOldFileList) + 1) * SIZEOF(TCHAR);
|
|
|
|
pNewFileList = (LPTSTR) SHAlloc(cbAlloc);
|
|
if (NULL == pNewFileList)
|
|
{
|
|
GlobalUnlock((HGLOBAL)hDrop);
|
|
return FALSE;
|
|
}
|
|
pSaveFileList = pNewFileList;
|
|
|
|
pXStr = (LPXSTR) lpOldFileList;
|
|
|
|
do
|
|
{
|
|
#ifdef UNICODE
|
|
|
|
cchConverted = MultiByteToWideChar(CP_ACP,
|
|
0,
|
|
pXStr,
|
|
-1,
|
|
pNewFileList,
|
|
cbAlloc); // Not really, but... "trust me"
|
|
|
|
#else
|
|
|
|
Assert(0 && "Unicode drop to Ansi explorer not supported");
|
|
cchConverted = 0;
|
|
|
|
#endif
|
|
|
|
if (0 == cchConverted)
|
|
{
|
|
Assert(0 && "Unable to convert HDROP filename ANSI -> UNICODE");
|
|
GlobalUnlock((HGLOBAL)hDrop);
|
|
SHFree(pSaveFileList);
|
|
return FALSE;
|
|
}
|
|
|
|
pNewFileList += cchConverted;
|
|
pXStr += cchConverted;
|
|
} while (*pXStr);
|
|
|
|
// Add the double-null-terminator to the output list
|
|
|
|
*pNewFileList = TEXT('\0');
|
|
lpdi->lpFileList = pSaveFileList;
|
|
}
|
|
}
|
|
|
|
GlobalUnlock((HGLOBAL)hDrop);
|
|
|
|
return TRUE;
|
|
}
|
|
}
|
|
return FALSE;
|
|
}
|
|
|
|
#endif // WIN32
|
|
|
|
// 3.1 API
|
|
|
|
BOOL WINAPI DragQueryPoint(HDROP hDrop, LPPOINT lppt)
|
|
{
|
|
LPDROPFILES lpdfs = (LPDROPFILES)GlobalLock((HGLOBAL)hDrop);
|
|
BOOL fRet=FALSE;
|
|
if (lpdfs)
|
|
{
|
|
if (LOWORD(lpdfs->pFiles)==SIZEOF(DROPFILES16))
|
|
{
|
|
//
|
|
// This is Win31-stye HDROP
|
|
//
|
|
LPDROPFILES16 pdf16 = (LPDROPFILES16)lpdfs;
|
|
lppt->x = pdf16->pt.x;
|
|
lppt->y = pdf16->pt.y;
|
|
fRet = !pdf16->fNC;
|
|
}
|
|
else
|
|
{
|
|
//
|
|
// This is a new (NT-compatible) HDROP
|
|
//
|
|
lppt->x = (UINT)lpdfs->pt.x;
|
|
lppt->y = (UINT)lpdfs->pt.y;
|
|
fRet = !lpdfs->fNC;
|
|
|
|
// there could be other data in there, but all
|
|
// the HDROPs we build should be this size
|
|
Assert(lpdfs->pFiles == SIZEOF(DROPFILES));
|
|
}
|
|
GlobalUnlock((HGLOBAL)hDrop);
|
|
}
|
|
|
|
return fRet;
|
|
}
|
|
|
|
#ifdef WINNT
|
|
//
|
|
// Unfortunately we need it split out this way because WOW needs to
|
|
// able to call a function named DragQueryFileAorW (so it can shorten them)
|
|
// BUGBUG - BobDay - If there is time, try to change WOW and the SHELL at
|
|
// the same time so that they don't need this function
|
|
//
|
|
UINT APIENTRY DragQueryFileAorW(
|
|
HDROP hDrop,
|
|
UINT iFile,
|
|
PVOID lpFile,
|
|
UINT cb,
|
|
BOOL fNeedAnsi,
|
|
BOOL fShorten)
|
|
{
|
|
UINT i;
|
|
LPDROPFILESTRUCT lpdfs;
|
|
BOOL fWide;
|
|
|
|
lpdfs = (LPDROPFILESTRUCT)GlobalLock(hDrop);
|
|
|
|
if (lpdfs)
|
|
{
|
|
fWide = (LOWORD(lpdfs->pFiles) == SIZEOF(DROPFILES));
|
|
if (fWide)
|
|
{
|
|
//
|
|
// This is a new (NT-compatible) HDROP
|
|
//
|
|
fWide = lpdfs->fWide; // Redetermine fWide from struct
|
|
// since it is present.
|
|
}
|
|
|
|
if (fWide)
|
|
{
|
|
LPWSTR lpList;
|
|
WCHAR szPath[MAX_PATH];
|
|
|
|
//
|
|
// UNICODE HDROP
|
|
//
|
|
|
|
lpList = (LPWSTR)((LPBYTE)lpdfs + lpdfs->pFiles);
|
|
|
|
// find either the number of files or the start of the file
|
|
// we're looking for
|
|
//
|
|
for (i = 0; (iFile == (UINT)-1 || i != iFile) && *lpList; i++)
|
|
{
|
|
while (*lpList++)
|
|
;
|
|
}
|
|
|
|
if (iFile == (UINT)-1)
|
|
goto Exit;
|
|
|
|
|
|
iFile = i = lstrlenW(lpList);
|
|
if (fShorten && iFile < MAX_PATH)
|
|
{
|
|
wcscpy(szPath, lpList);
|
|
SheShortenPathW(szPath, TRUE);
|
|
lpList = szPath;
|
|
iFile = i = lstrlenW(lpList);
|
|
}
|
|
|
|
if (!i || !cb || !lpFile)
|
|
goto Exit;
|
|
|
|
cb--;
|
|
if (cb < i)
|
|
i = cb;
|
|
|
|
if (fNeedAnsi) {
|
|
|
|
WideCharToMultiByte(CP_ACP, 0, lpList, -1, (LPSTR)lpFile,
|
|
cb, NULL, NULL);
|
|
|
|
// Null terminate the ANSI string
|
|
((LPSTR)lpFile)[cb] = 0;
|
|
|
|
} else {
|
|
lstrcpynW((LPWSTR)lpFile, lpList, i + 1);
|
|
}
|
|
}
|
|
else
|
|
{
|
|
LPSTR lpList;
|
|
CHAR szPath[MAX_PATH];
|
|
|
|
//
|
|
// This is Win31-style HDROP or an ANSI NT Style HDROP
|
|
//
|
|
lpList = (LPSTR)((LPBYTE)lpdfs + lpdfs->pFiles);
|
|
|
|
// find either the number of files or the start of the file
|
|
// we're looking for
|
|
//
|
|
for (i = 0; (iFile == (UINT)-1 || i != iFile) && *lpList; i++)
|
|
{
|
|
while (*lpList++)
|
|
;
|
|
}
|
|
|
|
if (iFile == (UINT)-1)
|
|
goto Exit;
|
|
|
|
iFile = i = lstrlenA(lpList);
|
|
if (fShorten && iFile < MAX_PATH)
|
|
{
|
|
strcpy(szPath, lpList);
|
|
SheShortenPathA(szPath, TRUE);
|
|
lpList = szPath;
|
|
iFile = i = lstrlenA(lpList);
|
|
}
|
|
|
|
if (!i || !cb || !lpFile)
|
|
goto Exit;
|
|
|
|
cb--;
|
|
if (cb < i)
|
|
i = cb;
|
|
|
|
if (fNeedAnsi) {
|
|
lstrcpynA((LPSTR)lpFile, lpList, i + 1);
|
|
} else {
|
|
MultiByteToWideChar(CP_ACP, 0, lpList, -1, (LPWSTR)lpFile, cb);
|
|
}
|
|
}
|
|
}
|
|
|
|
i = iFile;
|
|
|
|
Exit:
|
|
GlobalUnlock(hDrop);
|
|
|
|
return(i);
|
|
}
|
|
|
|
UINT APIENTRY DragQueryFileW(
|
|
HDROP hDrop,
|
|
UINT wFile,
|
|
LPWSTR lpFile,
|
|
UINT cb)
|
|
{
|
|
return(DragQueryFileAorW(hDrop, wFile, lpFile, cb, FALSE, FALSE));
|
|
}
|
|
|
|
UINT APIENTRY DragQueryFileA(
|
|
HDROP hDrop,
|
|
UINT wFile,
|
|
LPSTR lpFile,
|
|
UINT cb)
|
|
{
|
|
return(DragQueryFileAorW(hDrop, wFile, lpFile, cb, TRUE, FALSE));
|
|
}
|
|
#else
|
|
#ifndef WIN32
|
|
|
|
// win16 version of win32 api, takes/returns ANSI strings
|
|
|
|
BOOL GetShortPathName(LPCTSTR pszLong, LPTSTR pszShort)
|
|
{
|
|
TCHAR szLongOEM[MAX_PATH];
|
|
LPTSTR pszLongOEM = szLongOEM;
|
|
BOOL fSuccess = TRUE;
|
|
|
|
CharToOem(pszLong, szLongOEM);
|
|
|
|
_asm {
|
|
push ds
|
|
push si
|
|
push di
|
|
mov ax, 7160h
|
|
mov cx, 1 ; Get Short Path Name
|
|
lds si, pszLongOEM ; address of source string
|
|
les di, pszShort ; address of dest string
|
|
int 21h
|
|
pop di
|
|
pop si
|
|
pop ds
|
|
jnc done
|
|
mov fSuccess, FALSE
|
|
done:
|
|
}
|
|
|
|
if (fSuccess)
|
|
OemToChar(pszShort, pszShort);
|
|
|
|
return fSuccess;
|
|
}
|
|
#endif
|
|
|
|
// 3.1 API
|
|
|
|
UINT WINAPI DragQueryFile(HDROP hDrop, UINT iFile, LPTSTR lpFile, UINT cb)
|
|
{
|
|
#ifndef WIN32
|
|
TCHAR szShortName[MAX_PATH];
|
|
#endif
|
|
LPTSTR lpList;
|
|
int i;
|
|
LPDROPFILES lpdfs;
|
|
|
|
lpdfs = (LPDROPFILES)GlobalLock((HGLOBAL)hDrop);
|
|
|
|
if (LOWORD(lpdfs->pFiles)==SIZEOF(DROPFILES16))
|
|
{
|
|
//
|
|
// This is Win31-stye HDROP
|
|
//
|
|
LPDROPFILES16 pdf16 = (LPDROPFILES16)lpdfs;
|
|
lpList = (LPTSTR)((LPBYTE)pdf16 + pdf16->pFiles);
|
|
}
|
|
else
|
|
{
|
|
//
|
|
// This is a new (NT-compatible) HDROP
|
|
//
|
|
lpList = (LPTSTR)((LPBYTE)lpdfs + lpdfs->pFiles);
|
|
|
|
// there could be other data in there, but all
|
|
// the HDROPs we build should be this size
|
|
Assert(lpdfs->pFiles == SIZEOF(DROPFILES));
|
|
}
|
|
|
|
/* find either the number of files or the start of the file
|
|
* we're looking for
|
|
*/
|
|
for (i = 0; ((int)iFile == -1 || i != (int)iFile) && *lpList; i++)
|
|
{
|
|
while (*lpList++)
|
|
;
|
|
}
|
|
if (iFile == -1)
|
|
goto Exit;
|
|
|
|
// Note that HDROP contains a long name.
|
|
#ifndef WIN32
|
|
if (*lpList && GetShortPathName(lpList, szShortName))
|
|
lpList = szShortName;
|
|
#endif // WIN32
|
|
|
|
iFile = i = lstrlen(lpList);
|
|
|
|
if (!i || !cb || !lpFile)
|
|
goto Exit;
|
|
|
|
cb--;
|
|
if (cb < (UINT)i)
|
|
i = cb;
|
|
|
|
lstrcpyn(lpFile, lpList, cb+1);
|
|
|
|
// Note that we are returning the length of the string NOT INCLUDING the
|
|
// NULL. The DOCs are in error.
|
|
i = iFile;
|
|
|
|
Exit:
|
|
GlobalUnlock((HGLOBAL)hDrop);
|
|
|
|
return i;
|
|
}
|
|
#endif
|
|
|
|
// 3.1 API
|
|
|
|
void WINAPI DragFinish(HDROP hDrop)
|
|
{
|
|
GlobalFree((HGLOBAL)hDrop);
|
|
}
|
|
|
|
// 3.1 API
|
|
|
|
void WINAPI DragAcceptFiles(HWND hwnd, BOOL fAccept)
|
|
{
|
|
long exstyle;
|
|
|
|
exstyle = GetWindowLong(hwnd,GWL_EXSTYLE);
|
|
if (fAccept)
|
|
exstyle |= WS_EX_ACCEPTFILES;
|
|
else
|
|
exstyle &= (~WS_EX_ACCEPTFILES);
|
|
SetWindowLong(hwnd,GWL_EXSTYLE,exstyle);
|
|
}
|