349 lines
10 KiB
C
349 lines
10 KiB
C
#include "shellprv.h"
|
|
#pragma hdrstop
|
|
|
|
// warning: this will fail given a UNICODE hDrop on an ANSI build and
|
|
// the DRAGINFO is esentially a TCHAR struct with no A/W versions exported
|
|
//
|
|
// in:
|
|
// hDrop drop handle
|
|
//
|
|
// out:
|
|
// a bunch of info about the hdrop
|
|
// (mostly the pointer to the double NULL file name list in TCHAR format)
|
|
//
|
|
// returns:
|
|
// TRUE the DRAGINFO struct was filled in
|
|
// FALSE the hDrop was bad
|
|
//
|
|
|
|
STDAPI_(BOOL) DragQueryInfo(HDROP hDrop, DRAGINFO *pdi)
|
|
{
|
|
if (hDrop && (pdi->uSize == sizeof(DRAGINFO)))
|
|
{
|
|
LPDROPFILES lpdfx = (LPDROPFILES)GlobalLock((HGLOBAL)hDrop);
|
|
|
|
pdi->lpFileList = NULL;
|
|
|
|
if (lpdfx)
|
|
{
|
|
LPTSTR lpOldFileList;
|
|
if (LOWORD(lpdfx->pFiles) == sizeof(DROPFILES16))
|
|
{
|
|
//
|
|
// This is Win31-stye HDROP
|
|
//
|
|
LPDROPFILES16 pdf16 = (LPDROPFILES16)lpdfx;
|
|
pdi->pt.x = pdf16->pt.x;
|
|
pdi->pt.y = pdf16->pt.y;
|
|
pdi->fNC = pdf16->fNC;
|
|
pdi->grfKeyState = 0;
|
|
lpOldFileList = (LPTSTR)((LPBYTE)pdf16 + pdf16->pFiles);
|
|
}
|
|
else
|
|
{
|
|
//
|
|
// This is a new (NT-compatible) HDROP.
|
|
//
|
|
pdi->pt.x = lpdfx->pt.x;
|
|
pdi->pt.y = lpdfx->pt.y;
|
|
pdi->fNC = lpdfx->fNC;
|
|
pdi->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;
|
|
|
|
if ((LOWORD(lpdfx->pFiles) == sizeof(DROPFILES16)) || lpdfx->fWide == FALSE)
|
|
{
|
|
fListMatchesBuild = FALSE;
|
|
}
|
|
else
|
|
{
|
|
fListMatchesBuild = TRUE;
|
|
}
|
|
if (fListMatchesBuild)
|
|
{
|
|
LPTSTR pTStr = (LPTSTR) lpOldFileList;
|
|
LPTSTR pNewFileList;
|
|
UINT cChar;
|
|
|
|
// Look for the end of the file list
|
|
|
|
while (*pTStr || *(pTStr + 1))
|
|
{
|
|
pTStr++;
|
|
}
|
|
pTStr++; // Advance to last NUL of double terminator
|
|
|
|
cChar = (UINT)(pTStr - lpOldFileList);
|
|
|
|
pNewFileList = (LPTSTR) SHAlloc((cChar + 1) * sizeof(TCHAR));
|
|
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, ((cChar + 1) * sizeof(TCHAR)));
|
|
pdi->lpFileList = pNewFileList;
|
|
}
|
|
else
|
|
{
|
|
LPXSTR pXStr = (LPXSTR) lpOldFileList;
|
|
LPTSTR pNewFileList;
|
|
LPTSTR pSaveFileList;
|
|
UINT cChar;
|
|
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
|
|
|
|
cChar = (UINT)(pXStr - ((LPXSTR) lpOldFileList));
|
|
|
|
pNewFileList = (LPTSTR) SHAlloc((cChar + 1) * sizeof(TCHAR));
|
|
if (NULL == pNewFileList)
|
|
{
|
|
GlobalUnlock((HGLOBAL)hDrop);
|
|
return FALSE;
|
|
}
|
|
pSaveFileList = pNewFileList;
|
|
|
|
pXStr = (LPXSTR) lpOldFileList;
|
|
|
|
do
|
|
{
|
|
cchConverted = MultiByteToWideChar(CP_ACP, 0, pXStr, -1,
|
|
pNewFileList, ((cChar + 1) * sizeof(TCHAR))); // Not really, but... "trust me"
|
|
|
|
if (0 == cchConverted)
|
|
{
|
|
ASSERT(0 && "Unable to convert HDROP filename ANSI -> UNICODE");
|
|
GlobalUnlock((HGLOBAL)hDrop);
|
|
SHFree(pSaveFileList);
|
|
return FALSE;
|
|
}
|
|
|
|
pNewFileList += cchConverted;
|
|
pXStr += lstrlenX(pXStr) + 1;
|
|
} while (*pXStr);
|
|
|
|
// Add the double-null-terminator to the output list
|
|
|
|
*pNewFileList = 0;
|
|
pdi->lpFileList = pSaveFileList;
|
|
}
|
|
}
|
|
|
|
GlobalUnlock((HGLOBAL)hDrop);
|
|
|
|
return TRUE;
|
|
}
|
|
}
|
|
return FALSE;
|
|
}
|
|
|
|
// 3.1 API
|
|
|
|
STDAPI_(BOOL) DragQueryPoint(HDROP hDrop, POINT *ppt)
|
|
{
|
|
BOOL fRet = FALSE;
|
|
LPDROPFILES lpdfs = (LPDROPFILES)GlobalLock((HGLOBAL)hDrop);
|
|
if (lpdfs)
|
|
{
|
|
if (LOWORD(lpdfs->pFiles) == sizeof(DROPFILES16))
|
|
{
|
|
//
|
|
// This is Win31-stye HDROP
|
|
//
|
|
LPDROPFILES16 pdf16 = (LPDROPFILES16)lpdfs;
|
|
ppt->x = pdf16->pt.x;
|
|
ppt->y = pdf16->pt.y;
|
|
fRet = !pdf16->fNC;
|
|
}
|
|
else
|
|
{
|
|
//
|
|
// This is a new (NT-compatible) HDROP
|
|
//
|
|
ppt->x = (UINT)lpdfs->pt.x;
|
|
ppt->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;
|
|
}
|
|
|
|
//
|
|
// Unfortunately we need it split out this way because WOW needs to
|
|
// able to call a function named DragQueryFileAorW (so it can shorten them)
|
|
//
|
|
STDAPI_(UINT) DragQueryFileAorW(HDROP hDrop, UINT iFile, void *lpFile, UINT cb, BOOL fNeedAnsi, BOOL fShorten)
|
|
{
|
|
UINT i;
|
|
LPDROPFILESTRUCT lpdfs = (LPDROPFILESTRUCT)GlobalLock(hDrop);
|
|
if (lpdfs)
|
|
{
|
|
// see if it is the new format
|
|
BOOL fWide = LOWORD(lpdfs->pFiles) == sizeof(DROPFILES) && lpdfs->fWide;
|
|
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 (fNeedAnsi)
|
|
{
|
|
// Do not assume that a count of characters == a count of bytes
|
|
i = WideCharToMultiByte(CP_ACP, 0, lpList, -1, NULL, 0, NULL, NULL);
|
|
iFile = i ? --i : i;
|
|
}
|
|
|
|
if (!i || !cb || !lpFile)
|
|
goto Exit;
|
|
|
|
if (fNeedAnsi)
|
|
{
|
|
SHUnicodeToAnsi(lpList, (LPSTR)lpFile, cb);
|
|
}
|
|
else
|
|
{
|
|
cb--;
|
|
if (cb < i)
|
|
i = cb;
|
|
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 (!fNeedAnsi)
|
|
{
|
|
i = MultiByteToWideChar(CP_ACP, 0, lpList, -1, NULL, 0);
|
|
iFile = i ? --i : i;
|
|
}
|
|
|
|
if (!i || !cb || !lpFile)
|
|
goto Exit;
|
|
|
|
if (fNeedAnsi)
|
|
{
|
|
cb--;
|
|
if (cb < i)
|
|
i = cb;
|
|
|
|
lstrcpynA((LPSTR)lpFile, lpList, i + 1);
|
|
}
|
|
else
|
|
{
|
|
SHAnsiToUnicode(lpList, (LPWSTR)lpFile, cb);
|
|
}
|
|
}
|
|
}
|
|
|
|
i = iFile;
|
|
|
|
Exit:
|
|
GlobalUnlock(hDrop);
|
|
|
|
return i;
|
|
}
|
|
|
|
STDAPI_(UINT) DragQueryFileW(HDROP hDrop, UINT wFile, LPWSTR lpFile, UINT cb)
|
|
{
|
|
return DragQueryFileAorW(hDrop, wFile, lpFile, cb, FALSE, FALSE);
|
|
}
|
|
|
|
STDAPI_(UINT) DragQueryFileA(HDROP hDrop, UINT wFile, LPSTR lpFile, UINT cb)
|
|
{
|
|
return DragQueryFileAorW(hDrop, wFile, lpFile, cb, TRUE, FALSE);
|
|
}
|
|
|
|
STDAPI_(void) DragFinish(HDROP hDrop)
|
|
{
|
|
GlobalFree((HGLOBAL)hDrop);
|
|
}
|
|
|
|
STDAPI_(void) DragAcceptFiles(HWND hwnd, BOOL fAccept)
|
|
{
|
|
long exstyle = GetWindowLong(hwnd, GWL_EXSTYLE);
|
|
if (fAccept)
|
|
exstyle |= WS_EX_ACCEPTFILES;
|
|
else
|
|
exstyle &= (~WS_EX_ACCEPTFILES);
|
|
SetWindowLong(hwnd, GWL_EXSTYLE, exstyle);
|
|
}
|