|
|
/**MOD+**********************************************************************/ /* Module: cclip.cpp */ /* */ /* Purpose: Shared Clipboard Client Addin */ /* */ /* Copyright(C) Microsoft Corporation 1998-1999 */ /* */ /**MOD-**********************************************************************/
/****************************************************************************/ /* Precompiled header */ /****************************************************************************/ #include <precom.h>
/****************************************************************************/ /* Trace definitions */ /****************************************************************************/
#define TRC_GROUP TRC_GROUP_NETWORK
#define TRC_FILE "cclip"
#include <atrcapi.h>
#include "vcint.h"
#include "drapi.h"
/****************************************************************************/ // Headers
/****************************************************************************/ #include <cclip.h>
#ifndef OS_WINCE
#include <shlobj.h>
#endif
#ifdef OS_WINCE
#include "ceclip.h"
#endif
#ifdef CLIP_TRANSITION_RECORDING
UINT g_rguiDbgLastClipState[DBG_RECORD_SIZE]; UINT g_rguiDbgLastClipEvent[DBG_RECORD_SIZE]; LONG g_uiDbgPosition = -1;
#endif // CLIP_TRANSITION_RECORDING
/****************************************************************************/ /* CTor */ /****************************************************************************/ CClip::CClip(VCManager *virtualChannelMgr) { PRDPDR_DATA prdpdrData; DC_BEGIN_FN("CClip::CClip"); /********************************************************************/ /* Initialize the data */ /********************************************************************/ _GetDataSync[TS_RECEIVE_COMPLETED] = NULL; _GetDataSync[TS_RESET_EVENT] = NULL; DC_MEMSET(&_CB, 0, sizeof(_CB)); _pVCMgr = virtualChannelMgr; prdpdrData = _pVCMgr->GetInitData(); _CB.fDrivesRedirected = prdpdrData->fEnableRedirectDrives; _CB.fFileCutCopyOn = _CB.fDrivesRedirected; _pClipData = new CClipData(this); if (_pClipData) { _pClipData->AddRef(); } _pUtObject = (CUT*) LocalAlloc(LPTR, sizeof(CUT)); if (_pUtObject) { _pUtObject->UT_Init(); } if (prdpdrData->szClipPasteInfoString[0] != 0) { if (!WideCharToMultiByte(CP_ACP, 0, prdpdrData->szClipPasteInfoString, -1, _CB.pasteInfoA, sizeof(_CB.pasteInfoA), NULL, NULL)) { StringCbCopyA(_CB.pasteInfoA, sizeof(_CB.pasteInfoA), "Preparing paste information..."); } } else { StringCbCopyA(_CB.pasteInfoA, sizeof(_CB.pasteInfoA), "Preparing paste information..."); }
/********************************************************************/ /* Store the hInstance */ /********************************************************************/ _CB.hInst = GetModuleHandle(NULL); TRC_NRM((TB, _T("Store hInst %p"), _CB.hInst)); DC_END_FN(); } /****************************************************************************/ /* Wrappers for Malloc, Free & Memcpy */ /****************************************************************************/
#ifdef OS_WIN32
#define ClipAlloc(size) LocalAlloc(LMEM_FIXED, size)
#define ClipFree(pData) LocalFree(pData)
#define ClipMemcpy(pTrg, pSrc, len) DC_MEMCPY(pTrg, pSrc, len)
#endif
DCUINT CClip::GetOsMinorType() { DCUINT minorType = 0; if (_pUtObject) { minorType = _pUtObject->UT_GetOsMinorType(); } return minorType; } /****************************************************************************/ // ClipCheckState
/****************************************************************************/ DCUINT DCINTERNAL CClip::ClipCheckState(DCUINT event) { DCUINT tableVal = cbStateTable[event][_CB.state];
DC_BEGIN_FN("CClip::ClipCheckState");
TRC_DBG((TB, _T("Test event %s in state %s"), cbEvent[event], cbState[_CB.state]));
if (tableVal != CB_TABLE_OK) { if (tableVal == CB_TABLE_WARN) { TRC_ALT((TB, _T("Unusual event %s in state %s"), cbEvent[event], cbState[_CB.state])); } else { TRC_ABORT((TB, _T("Invalid event %s in state %s"), cbEvent[event], cbState[_CB.state])); } }
DC_END_FN(); return(tableVal); }
/****************************************************************************/ // ClipGetPermBuf - get a permanently allocated buffer
/****************************************************************************/ PTS_CLIP_PDU DCINTERNAL CClip::ClipGetPermBuf(DCVOID) { PTS_CLIP_PDU pClipPDU;
DC_BEGIN_FN("CClip::ClipGetPermBuf");
#ifdef USE_SEMAPHORE
/************************************************************************/ // On Win32, access to the permanent buffer is synchronised via a
// semaphore
/************************************************************************/ TRC_NRM((TB, _T("Wait for perm TX buffer"))); WaitForSingleObject(_CB.txPermBufSem, INFINITE); pClipPDU = (PTS_CLIP_PDU)(_CB.txPermBuffer); #endif
TRC_DBG((TB, _T("Return buffer at %#p"), pClipPDU));
DC_END_FN(); return(pClipPDU); } /* ClipGetPermBuf */
/****************************************************************************/ /* ClipFreeBuf */ /****************************************************************************/ DCVOID DCINTERNAL CClip::ClipFreeBuf(PDCUINT8 pBuf) { #ifndef OS_WINCE
INT i; #endif
DC_BEGIN_FN("CClip::ClipFreeBuf");
TRC_DBG((TB, _T("Release buffer at %p"), pBuf)); #ifdef USE_SEMAPHORE
if (pBuf == _CB.txPermBuffer) { TRC_DBG((TB, _T("Free Permanent buffer at %p"), pBuf)); if (!ReleaseSemaphore(_CB.txPermBufSem, 1, NULL)) { TRC_SYSTEM_ERROR("ReleaseSemaphore"); } } else { TRC_DBG((TB, _T("Free Temporary buffer at %p"), pBuf)); ClipFree(pBuf); } #else
#ifdef OS_WINCE
INT i; #endif
for (i = 0; i < CB_PERM_BUF_COUNT; i++) { TRC_DBG((TB, _T("Test buf %d, %p vs %p"), i, pBuf, _CB.txPermBuffer[i])); if (pBuf == _CB.txPermBuffer[i]) { TRC_NRM((TB, _T("Free perm buffer %d"), i)); _CB.txPermBufInUse[i] = FALSE; break; } }
if (i == CB_PERM_BUF_COUNT) { TRC_DBG((TB, _T("Temporary buffer"))); ClipFree(pBuf); } #endif
DC_END_FN(); return; } /* ClipFreePermBuf */
/****************************************************************************/ /* ClipDrawClipboard - send the local formats to the remote */ /****************************************************************************/ DCBOOL DCINTERNAL CClip::ClipDrawClipboard(DCBOOL mustSend) { DCUINT32 numFormats; DCUINT formatCount; DCUINT formatID; //
// formatlist is extracted from a PDU at a non-word boundary
// so it causes an alignment fault on WIN64. Marked UNALIGNED.
//
PTS_CLIP_FORMAT formatList; DCUINT nameLen;
PTS_CLIP_PDU pClipPDU = NULL; DCUINT32 pduLen; DCUINT32 dataLen; DCBOOL rc = TRUE; DCBOOL fHdrop = FALSE ;
DC_BEGIN_FN("CClip::ClipDrawClipboard");
_CB.dropEffect = FO_COPY ; _CB.fAlreadyCopied = FALSE ; #ifndef OS_WINCE
_CB.dwVersion = GetVersion() ; #else
OSVERSIONINFO osv; memset(&osv, 0, sizeof(osv)); osv.dwOSVersionInfoSize = sizeof(osv); if (!GetVersionEx(&osv)) { TRC_ERR((TB, _T("GetVersionEx failed!"))); rc = FALSE; DC_QUIT; } _CB.dwVersion = MAKELPARAM(MAKEWORD(osv.dwMajorVersion, osv.dwMinorVersion), osv.dwBuildNumber); #endif
_CB.fAlreadyCopied = FALSE ; /************************************************************************/ /* First we open the clipboard */ /************************************************************************/
if (!OpenClipboard(_CB.viewerWindow)) { TRC_ERR((TB, _T("Failed to open CB"))); rc = FALSE; DC_QUIT; }
/************************************************************************/ /* It was/is open */ /************************************************************************/ TRC_NRM((TB, _T("CB opened"))); _CB.clipOpen = TRUE; /************************************************************************/ /* Count the formats available, checking we don't blow our limit */ /************************************************************************/ numFormats = CountClipboardFormats(); if (numFormats > CB_MAX_FORMATS) { TRC_ALT((TB, _T("Num formats %ld too large - limit to %d"), numFormats, CB_MAX_FORMATS)); numFormats = CB_MAX_FORMATS; } TRC_DBG((TB, _T("found %ld formats"), numFormats));
/************************************************************************/ /* if there are no formats available, and we don't have to send the */ /* info, then don't! */ /************************************************************************/ if ((numFormats == 0) && (mustSend == FALSE)) { TRC_NRM((TB, _T("No formats: skipping send"))); DC_QUIT; }
/************************************************************************/ /* Get a send buffer. First work out how big it needs to be */ /************************************************************************/ dataLen = numFormats * sizeof(TS_CLIP_FORMAT); pduLen = dataLen + sizeof(TS_CLIP_PDU);
/************************************************************************/ /* and make sure that's not too big! */ /************************************************************************/ if (pduLen > CHANNEL_CHUNK_LENGTH) { /********************************************************************/ /* we'll have to limit the number of formats. How many will fit in */ /* the max buffer size? */ /********************************************************************/ pduLen = CHANNEL_CHUNK_LENGTH; dataLen = pduLen - sizeof(TS_CLIP_PDU); numFormats = dataLen / sizeof(TS_CLIP_FORMAT);
/********************************************************************/ /* no point in having empty space for the last fractional format! */ /********************************************************************/ dataLen = numFormats * sizeof(TS_CLIP_FORMAT); pduLen = dataLen + sizeof(TS_CLIP_PDU);
TRC_ALT((TB, _T("Too many formats! Limited to %ld"), numFormats)); }
pClipPDU = ClipGetPermBuf();
/************************************************************************/ /* Fill in the common parts of the PDU */ /************************************************************************/ DC_MEMSET(pClipPDU, 0, sizeof(*pClipPDU));
/************************************************************************/ /* and now the clip bits */ /************************************************************************/ pClipPDU->msgType = TS_CB_FORMAT_LIST; pClipPDU->dataLen = dataLen; #ifndef UNICODE
pClipPDU->msgFlags = TS_CB_ASCII_NAMES; #endif
/************************************************************************/ /* if there were any formats, list them */ /************************************************************************/ if (numFormats) { /********************************************************************/ /* set up the format list */ /********************************************************************/ formatList = (PTS_CLIP_FORMAT)(pClipPDU->data);
/********************************************************************/ /* and enumerate the formats */ /********************************************************************/ _CB.DIBFormatExists = FALSE; formatCount = 0; formatID = EnumClipboardFormats(0); /* 0 starts the enumeration */
while ((formatID != 0) && (formatCount < numFormats)) { #ifdef OS_WINCE
DCUINT dwTempID = formatID; if (formatID == gfmtShellPidlArray) { formatID = CF_HDROP; } #endif
/****************************************************************/ /* store the ID */ /****************************************************************/ formatList[formatCount].formatID = formatID;
/****************************************************************/ /* find the name for the format */ /****************************************************************/ nameLen = GetClipboardFormatName(formatID, (PDCTCHAR)formatList[formatCount].formatName, TS_FORMAT_NAME_LEN);
/****************************************************************/ /* check for predefined formats - they have no name */ /****************************************************************/ if (nameLen == 0) { TRC_NRM((TB, _T("no name for format %d - predefined"), formatID)); *(formatList[formatCount].formatName) = '\0'; }
TRC_DBG((TB, _T("found format id %ld, name '%s'"), formatList[formatCount].formatID, formatList[formatCount].formatName));
/****************************************************************/ /* look for formats we don't send */ /****************************************************************/
if ((formatID == CF_DSPBITMAP) || (formatID == CF_ENHMETAFILE) || ((!_CB.fFileCutCopyOn || !_CB.fDrivesRedirected) && (formatID == CF_HDROP)) || (formatID == CF_OWNERDISPLAY)) { // We drop enhanced metafile formats, since the local CB
// will provide conversion where supported
//
// Ownerdisplay just isn't going to work since the two
// windows are on different machines!
//
// File cut/copy isn't going to work if there is no drive
// redirection!
TRC_ALT((TB, _T("Dropping format ID %d"), formatID)); formatList[formatCount].formatID = 0; *(formatList[formatCount].formatName) = '\0'; } else if (ClipIsExcludedFormat((PDCTCHAR)formatList[formatCount].formatName)) { //
// We don't support file cut/paste, so we drop
// file related formats.
//
TRC_ALT((TB, _T("Dropping format name '%s'"), (PDCTCHAR)formatList[formatCount].formatName)); formatList[formatCount].formatID = 0; *(formatList[formatCount].formatName) = '\0'; } else { /************************************************************/ /* We support the CF_BITMAP format by converting it to */ /* CF_DIB. If there is already a CF_DIB format, we don't */ /* need to do this. */ /************************************************************/ if ((formatID == CF_BITMAP) && (_CB.DIBFormatExists)) { TRC_NRM((TB, _T("Dropping CF_BITMAP - CF_DIB is supported"))); } else { /********************************************************/ /* It's a supported format */ /********************************************************/ if (formatID == CF_BITMAP) { TRC_NRM((TB, _T("Convert CF_BITMAP to CF_DIB"))); formatList[formatCount].formatID = CF_DIB; } else if (formatID == CF_DIB) { TRC_NRM((TB, _T("Really found DIB format"))); _CB.DIBFormatExists = TRUE; } if (CF_HDROP == formatID) { fHdrop = TRUE ; } /********************************************************/ /* update the count and move on */ /********************************************************/ formatCount++; } }
#ifdef OS_WINCE
if (formatID == CF_HDROP) formatID = dwTempID; //reset the enumeration index, in case we changed it to accommodate CF_HDROP
#endif
/****************************************************************/ /* get the next format */ /****************************************************************/ formatID = EnumClipboardFormats(formatID); }
/********************************************************************/ /* Update the PDU len - we may have dropped some formats along the */ /* way */ /********************************************************************/ dataLen = formatCount * sizeof(TS_CLIP_FORMAT); pduLen = dataLen + sizeof(TS_CLIP_PDU); TRC_NRM((TB, _T("Final count: %d formats in data len %ld"), formatCount, dataLen));
pClipPDU->dataLen = dataLen; }
// if we're NT/2000 and we're going to send an HDROP
if (fHdrop) { TRC_NRM((TB, _T("Creating new temp directory for file data"))) ;
// How about handling errors from these fs calls?
#ifndef OS_WINCE
if (GetOsMinorType() == TS_OSMINORTYPE_WINDOWS_NT) #endif
{ #ifndef OS_WINCE
if (0 == GetTempFileNameW(_CB.baseTempDirW, L"_TS", 0, _CB.tempDirW)) { #else
if (0 == GetTempFileNameW(_CB.baseTempDirW, L"_TS", 0, _CB.tempDirW, MAX_PATH)) { #endif
TRC_ERR((TB, _T("Getting temp file name failed; GetLastError=%u"), GetLastError())); rc = FALSE; DC_QUIT; } // GetACP always returns a valid value
if (0 == WideCharToMultiByte(GetACP(), NULL, _CB.tempDirW, -1, _CB.tempDirA, (MAX_PATH + 1), NULL, NULL)) { TRC_ERR((TB, _T("Getting temp file name failed; GetLastError=%u"), GetLastError())); rc = FALSE; DC_QUIT; } DeleteFileW(_CB.tempDirW) ; if (0 == CreateDirectoryW(_CB.tempDirW, NULL)) { TRC_ERR((TB, _T("Creating temp directory failed; GetLastError=%u"), GetLastError())); rc = FALSE; DC_QUIT; } } #ifndef OS_WINCE
else { if (0 == GetTempFileNameA(_CB.baseTempDirA, "_TS", 0, _CB.tempDirA)) { TRC_ERR((TB, _T("Getting temp file name failed; GetLastError=%u"), GetLastError())); rc = FALSE; DC_QUIT; } // GetACP always returns a valid value
if (0 == MultiByteToWideChar(GetACP(), MB_ERR_INVALID_CHARS, _CB.tempDirA, -1, _CB.tempDirW, sizeof(_CB.tempDirW)/(sizeof(_CB.tempDirW[0])) - 1)) { TRC_ERR((TB, _T("Failed conversion to wide char; error %d"), GetLastError())) ; rc = FALSE ; DC_QUIT ; }
// Do not check return value
DeleteFileA(_CB.tempDirA) ; if (0 == CreateDirectoryA(_CB.tempDirA, NULL)) { TRC_ERR((TB, _T("Creating temp directory failed; GetLastError=%u"), GetLastError())); rc = FALSE; DC_QUIT; } } #endif
}
/************************************************************************/ /* Update the state */ /************************************************************************/ CB_SET_STATE(CB_STATE_PENDING_FORMAT_LIST_RSP, CB_EVENT_WM_DRAWCLIPBOARD);
/************************************************************************/ /* Send the PDU */ /************************************************************************/ TRC_NRM((TB, _T("Sending format list"))); if (_CB.channelEP.pVirtualChannelWriteEx (_CB.initHandle, _CB.channelHandle, pClipPDU, pduLen, (LPVOID)pClipPDU) != CHANNEL_RC_OK) { ClipFreeBuf((PDCUINT8)pClipPDU); }
DC_EXIT_POINT: /************************************************************************/ /* tidy up */ /************************************************************************/ if (_CB.clipOpen) { TRC_DBG((TB, _T("closing CB"))); _CB.clipOpen = FALSE; if (!CloseClipboard()) { TRC_SYSTEM_ERROR("CloseClipboard"); } }
DC_END_FN();
return(rc);
} /* ClipDrawClipboard */
#ifndef OS_WINCE
/****************************************************************************/ /* ClipGetMFData */ /****************************************************************************/ HANDLE DCINTERNAL CClip::ClipGetMFData(HANDLE hData, PDCUINT32 pDataLen) { DCUINT32 lenMFBits = 0; DCBOOL rc = FALSE; LPMETAFILEPICT pMFP = NULL; HDC hMFDC = NULL; HMETAFILE hMF = NULL; HGLOBAL hMFBits = NULL; HANDLE hNewData = NULL; PDCUINT8 pNewData = NULL; PDCVOID pBits = NULL;
DC_BEGIN_FN("CClip::ClipGetMFData");
TRC_NRM((TB, _T("Getting MF data"))); /************************************************************************/ /* Lock the memory to get a pointer to a METAFILEPICT header structure */ /* and create a METAFILEPICT DC. */ /************************************************************************/ if (GlobalSize(hData) < sizeof(METAFILEPICT)) { TRC_ERR((TB, _T("Unexpected global memory size!"))); _CB.channelEP.pVirtualChannelCloseEx(_CB.initHandle, _CB.channelHandle); DC_QUIT; } pMFP = (LPMETAFILEPICT)GlobalLock(hData); if (pMFP == NULL) { TRC_SYSTEM_ERROR("GlobalLock"); DC_QUIT; }
hMFDC = CreateMetaFile(NULL); if (hMFDC == NULL) { TRC_SYSTEM_ERROR("CreateMetaFile"); DC_QUIT; }
/************************************************************************/ /* Copy the MFP by playing it into the DC and closing it. */ /************************************************************************/ if (!PlayMetaFile(hMFDC, pMFP->hMF)) { TRC_SYSTEM_ERROR("PlayMetaFile"); CloseMetaFile(hMFDC); DC_QUIT; } hMF = CloseMetaFile(hMFDC); if (hMF == NULL) { TRC_SYSTEM_ERROR("CloseMetaFile"); DC_QUIT; }
/************************************************************************/ /* Get the MF bits and determine how long they are. */ /************************************************************************/ lenMFBits = GetMetaFileBitsEx(hMF, 0, NULL); if (lenMFBits == 0) { TRC_SYSTEM_ERROR("GetMetaFileBitsEx"); DC_QUIT; } TRC_DBG((TB, _T("length MF bits %ld"), lenMFBits));
/************************************************************************/ /* Work out how much memory we need and get a buffer */ /************************************************************************/ *pDataLen = sizeof(TS_CLIP_MFPICT) + lenMFBits; hNewData = GlobalAlloc(GHND, *pDataLen); if (hNewData == NULL) { TRC_ERR((TB, _T("Failed to get MF buffer"))); DC_QUIT; } pNewData = (PDCUINT8)GlobalLock(hNewData); if (NULL == pNewData) { TRC_ERR((TB,_T("Failed to lock MF buffer"))); DC_QUIT; } TRC_DBG((TB, _T("Got data to send len %ld"), *pDataLen));
/************************************************************************/ /* Copy the MF header and bits into the buffer. */ /************************************************************************/ ((PTS_CLIP_MFPICT)pNewData)->mm = pMFP->mm; ((PTS_CLIP_MFPICT)pNewData)->xExt = pMFP->xExt; ((PTS_CLIP_MFPICT)pNewData)->yExt = pMFP->yExt;
lenMFBits = GetMetaFileBitsEx(hMF, lenMFBits, (pNewData + sizeof(TS_CLIP_MFPICT))); if (lenMFBits == 0) { TRC_SYSTEM_ERROR("GetMetaFileBitsEx"); DC_QUIT; }
/************************************************************************/ /* all OK */ /************************************************************************/ TRC_NRM((TB, _T("Got %ld bits of MF data"), lenMFBits)); TRC_DATA_DBG("MF bits", (pNewData + sizeof(TS_CLIP_MFPICT)), (DCUINT)lenMFBits); rc = TRUE;
DC_EXIT_POINT: /************************************************************************/ /* Unlock any global mem. */ /************************************************************************/ if (pMFP) { GlobalUnlock(hData); } if (pNewData) { GlobalUnlock(hNewData); } if (hMF) { DeleteMetaFile(hMF); }
/************************************************************************/ /* if things went wrong, then free the new data */ /************************************************************************/ if ((rc == FALSE) && (hNewData != NULL)) { GlobalFree(hNewData); hNewData = NULL; }
DC_END_FN(); return(hNewData); } /* ClipGetMFData */
/****************************************************************************/ /* ClipSetMFData */ /****************************************************************************/ HANDLE DCINTERNAL CClip::ClipSetMFData(DCUINT32 dataLen, PDCVOID pData) { DCBOOL rc = FALSE; HGLOBAL hMFBits = NULL; PDCVOID pMFMem = NULL; HMETAFILE hMF = NULL; HGLOBAL hMFPict = NULL; LPMETAFILEPICT pMFPict = NULL;
DC_BEGIN_FN("CClip::ClipSetMFData");
TRC_DATA_DBG("Received MF data", pData, (DCUINT)dataLen);
/************************************************************************/ /* Allocate memory to hold the MF bits (we need the handle to pass to */ /* SetMetaFileBits). */ /************************************************************************/ hMFBits = GlobalAlloc(GHND, dataLen - (DCUINT32)sizeof(TS_CLIP_MFPICT)); if (hMFBits == NULL) { TRC_SYSTEM_ERROR("GlobalAlloc"); DC_QUIT; }
/************************************************************************/ /* Lock the handle and copy in the MF header. */ /************************************************************************/ pMFMem = GlobalLock(hMFBits); if (pMFMem == NULL) { TRC_ERR((TB, _T("Failed to lock MF mem"))); DC_QUIT; }
DC_HMEMCPY(pMFMem, (PDCVOID)((PDCUINT8)pData + sizeof(TS_CLIP_MFPICT)), dataLen - sizeof(TS_CLIP_MFPICT) );
GlobalUnlock(hMFBits);
/************************************************************************/ /* Now use the copied MF bits to create the actual MF bits and get a */ /* handle to the MF. */ /************************************************************************/ hMF = SetMetaFileBitsEx(dataLen - sizeof(TS_CLIP_MFPICT), (PDCUINT8)pMFMem); if (hMF == NULL) { TRC_SYSTEM_ERROR("SetMetaFileBits"); DC_QUIT; }
/************************************************************************/ /* Allocate a new METAFILEPICT structure, and use the data from the */ /* sent header. */ /************************************************************************/ hMFPict = GlobalAlloc(GHND, sizeof(METAFILEPICT)); pMFPict = (LPMETAFILEPICT)GlobalLock(hMFPict); if (!pMFPict) { TRC_ERR((TB, _T("Couldn't allocate METAFILEPICT"))); DC_QUIT; }
pMFPict->mm = (LONG)((PTS_CLIP_MFPICT)pData)->mm; pMFPict->xExt = (LONG)((PTS_CLIP_MFPICT)pData)->xExt; pMFPict->yExt = (LONG)((PTS_CLIP_MFPICT)pData)->yExt; pMFPict->hMF = hMF;
GlobalUnlock(hMFPict);
rc = TRUE;
DC_EXIT_POINT: /************************************************************************/ /* tidy up */ /************************************************************************/ if (!rc) { if (hMFPict) { GlobalFree(hMFPict); } }
{ if (hMFBits) { GlobalFree(hMFBits); } }
DC_END_FN(); return(hMFPict);
} /* ClipSetMFData */ #endif
/****************************************************************************/ /* ClipBitmapToDIB - convert CF_BITMAP format to CF_DIB format */ /****************************************************************************/ HANDLE DCINTERNAL CClip::ClipBitmapToDIB(HANDLE hData, PDCUINT32 pDataLen) { BITMAP bmpDetails = {0}; DWORD buffSize, buffWidth; DWORD paletteBytes; WORD bpp; DWORD numCols; int rc; HANDLE hDIBitmap = NULL; HPDCVOID pDIBitmap = NULL; HPDCVOID pBits = NULL; PBITMAPINFO pBmpInfo = NULL; HDC hDC = NULL; DCBOOL allOK = FALSE;
DC_BEGIN_FN("CClip::ClipBitmapToDIB");
*pDataLen = 0;
/************************************************************************/ /* get the details of the bitmap */ /************************************************************************/ if (0 == GetObject(hData, sizeof(bmpDetails), &bmpDetails)) { TRC_ERR((TB, _T("Failed to get bitmap details"))); DC_QUIT; } TRC_NRM((TB, _T("Bitmap details: width %d, height %d, #planes %d, bpp %d"), bmpDetails.bmWidth, bmpDetails.bmHeight, bmpDetails.bmPlanes, bmpDetails.bmBitsPixel));
/************************************************************************/ /* Space required for bits is */ /* */ /* (width * bpp / 8) rounded up to multiple of 4 bytes */ /* * height */ /* */ /************************************************************************/ bpp = (WORD)(bmpDetails.bmBitsPixel * bmpDetails.bmPlanes); buffWidth = ((bmpDetails.bmWidth * bpp) + 7) / 8; buffWidth = DC_ROUND_UP_4(buffWidth);
buffSize = buffWidth * bmpDetails.bmHeight; TRC_DBG((TB, _T("Buffer size %ld (W %ld, H %d)"), buffSize, buffWidth, bmpDetails.bmHeight));
/************************************************************************/ /* Now add some space for the bitmapinfo - this includes a color table */ /************************************************************************/ numCols = 1 << bpp; if (bpp <= 8) { paletteBytes = numCols * sizeof(RGBQUAD); TRC_NRM((TB, _T("%ld colors => %ld palette bytes"), numCols, paletteBytes)); } else { if (bpp == 24) { /****************************************************************/ /* No bitmasks or palette info (compression==BI_RGB) */ /****************************************************************/ paletteBytes = 0; TRC_NRM((TB, _T("%ld colors => 0 bitfield bytes"), numCols)); } else { /****************************************************************/ /* 3 DWORD color masks for >8bpp (compression==BI_BITFIELDS) */ /****************************************************************/ paletteBytes = 3 * sizeof(DWORD); TRC_NRM((TB, _T("%ld colors => %ld bitfield bytes"), numCols, paletteBytes)); } } buffSize += (sizeof(BITMAPINFOHEADER) + paletteBytes); TRC_NRM((TB, _T("Buffer size %ld"), buffSize));
/************************************************************************/ /* Allocate memory to hold everything */ /************************************************************************/ hDIBitmap = GlobalAlloc(GHND, buffSize); if (hDIBitmap == NULL) { TRC_ERR((TB, _T("Failed to alloc %ld bytes"), buffSize)); DC_QUIT; } pDIBitmap = GlobalLock(hDIBitmap); if (pDIBitmap == NULL) { TRC_ERR((TB, _T("Failed to lock hDIBitmap"))); DC_QUIT; }
/************************************************************************/ /* bmp info is at the start */ /* space for bits are in the middle somewhere */ /************************************************************************/ pBmpInfo = (PBITMAPINFO)pDIBitmap; pBits = (HPDCVOID)((HPDCUINT8)pDIBitmap + sizeof(BITMAPINFOHEADER) + paletteBytes); TRC_NRM((TB, _T("pBmpInfo at %p, pBits at %p"), pBmpInfo, pBits));
/************************************************************************/ /* set up the desired bitmap info */ /************************************************************************/ pBmpInfo->bmiHeader.biSize = sizeof(BITMAPINFOHEADER); pBmpInfo->bmiHeader.biWidth = bmpDetails.bmWidth; pBmpInfo->bmiHeader.biHeight = bmpDetails.bmHeight; pBmpInfo->bmiHeader.biPlanes = 1; pBmpInfo->bmiHeader.biBitCount = bpp; if ((bpp <= 8) || (bpp == 24)) { pBmpInfo->bmiHeader.biCompression = BI_RGB; } else { pBmpInfo->bmiHeader.biCompression = BI_BITFIELDS; } pBmpInfo->bmiHeader.biSizeImage = 0; pBmpInfo->bmiHeader.biXPelsPerMeter = 0; pBmpInfo->bmiHeader.biYPelsPerMeter = 0; pBmpInfo->bmiHeader.biClrUsed = 0; pBmpInfo->bmiHeader.biClrImportant = 0;
/************************************************************************/ /* get a DC */ /************************************************************************/ hDC = GetDC(NULL); if (!hDC) { TRC_SYSTEM_ERROR("GetDC"); DC_QUIT; }
/************************************************************************/ /* now get the bits */ /************************************************************************/ TRC_NRM((TB, _T("GetDIBits"))); rc = GetDIBits(hDC, // hdc
(HBITMAP)hData, // hbm
0, // nStartScan
bmpDetails.bmHeight, // nNumScans
pBits, // pBits
pBmpInfo, // pbmi
DIB_RGB_COLORS); // iUsage
TRC_NRM((TB, _T("GetDIBits returns %d"), rc)); if (!rc) { TRC_SYSTEM_ERROR("GetDIBits"); DC_QUIT; }
/************************************************************************/ /* All seems to be OK */ /************************************************************************/ *pDataLen = buffSize; TRC_NRM((TB, _T("All done: data %p, len %ld"), hDIBitmap, *pDataLen)); allOK = TRUE;
DC_EXIT_POINT: /************************************************************************/ /* Finished with the DC - free it */ /************************************************************************/ if (hDC) { TRC_DBG((TB, _T("Free the DC"))); ReleaseDC(NULL, hDC); }
/************************************************************************/ /* Free the return buffer if this didn't work */ /************************************************************************/ if (!allOK) { if (pDIBitmap) { TRC_DBG((TB, _T("Unlock DIBitmap"))); GlobalUnlock(hDIBitmap); } if (hDIBitmap) { TRC_DBG((TB, _T("Free DIBitmap"))); GlobalFree(hDIBitmap); hDIBitmap = NULL; } }
DC_END_FN(); return(hDIBitmap);
} /* ClipBitmapToDIB */
DCBOOL DCINTERNAL CClip::ClipIsExcludedFormat(PDCTCHAR formatName) { DCBOOL rc = FALSE; DCINT i;
DC_BEGIN_FN("CClip::ClipIsExcludedFormat");
/************************************************************************/ /* check there is a format name - all banned formats have one! */ /************************************************************************/ if (*formatName == _T('\0')) { TRC_ALT((TB, _T("No format name supplied!"))); DC_QUIT; }
/************************************************************************/ /* search the banned format list for the supplied format name */ /************************************************************************/ TRC_DBG((TB, _T("Looking at format '%s'"), formatName)); TRC_DATA_DBG("Format name data", formatName, TS_FORMAT_NAME_LEN);
// if File Cut/Copy is on AND Drive Redirection is on, we can handle
// more formats
if (_CB.fFileCutCopyOn && _CB.fDrivesRedirected) { for (i = 0; i < CB_EXCLUDED_FORMAT_COUNT; i++) { TRC_DBG((TB, _T("comparing with '%s'"), g_excludedFormatList[i])); if (DC_WSTRCMP((PDCWCHAR)formatName, (PDCWCHAR)g_excludedFormatList[i]) == 0) { TRC_NRM((TB, _T("Found excluded format '%s'"), formatName)); rc = TRUE; break; } } } else { for (i = 0; i < CB_EXCLUDED_FORMAT_COUNT_NO_RD; i++) { TRC_DBG((TB, _T("comparing with '%s'"), g_excludedFormatList_NO_RD[i])); if (DC_WSTRCMP((PDCWCHAR)formatName, (PDCWCHAR)g_excludedFormatList_NO_RD[i]) == 0) { TRC_NRM((TB, _T("Found excluded format '%s'"), formatName)); rc = TRUE; break; } } } DC_EXIT_POINT: DC_END_FN();
return(rc); } /* ClipIsExcludedFormat */
#ifndef OS_WINCE
//
// ClipCleanTempPath
// - Returns 0 if successful
// nonzero if failed
// - Attempts to wipe the temp directory of TS related files
//
int CClip::ClipCleanTempPath() { int result; SHFILEOPSTRUCTW fileOpStructW; PRDPDR_DATA prdpdrData = _pVCMgr->GetInitData();
#ifndef UNICODE
#error function assumes unicode
#endif
_CB.baseTempDirW[wcslen(_CB.baseTempDirW)] = L'\0' ; fileOpStructW.pFrom = _CB.baseTempDirW ; fileOpStructW.pTo = NULL ; fileOpStructW.hwnd = NULL ; fileOpStructW.wFunc = FO_DELETE ; fileOpStructW.fFlags = FOF_NOCONFIRMATION | FOF_NOERRORUI | FOF_SIMPLEPROGRESS; fileOpStructW.hNameMappings = NULL ;
if (prdpdrData->szClipCleanTempDirString[0] != 0) { fileOpStructW.lpszProgressTitle = prdpdrData->szClipCleanTempDirString; } else { fileOpStructW.lpszProgressTitle = L"Cleaning temp directory"; }
//
// Use SHFileOperation instead of SHFileOperationW to ensure
// it goes through the unicode wrapper. Note SHFileOperationW
// is not available on 95 so the wrapper dynamically binds to
// the entry point.
//
result = SHFileOperation(&fileOpStructW) ; return result ; }
#else
//We dont want to use the recycle bin on CE
int CClip::ClipCleanTempPath() { return (_CB.fFileCutCopyOn) ? DeleteDirectory(_CB.baseTempDirW, FALSE) : ERROR_SUCCESS; } #endif
//
// ClipCopyToTempDirectory, ClipCopyToTempDirectoryA, ClipCopyToTempDirectoryW
// - Arguments:
// pSrcFiles = buffer containing the names/path of the files to be copied
// - Returns 0 if successful
// nonzero if failed
// - Given a list of file names/paths, this function will attempt to copy them
// to the temp directory
//
int CClip::ClipCopyToTempDirectory(PVOID pSrcFiles, BOOL fWide) { int result ; if (fWide) result = ClipCopyToTempDirectoryW(pSrcFiles) ; else result = ClipCopyToTempDirectoryA(pSrcFiles) ;
return result ; }
#ifndef OS_WINCE
int CClip::ClipCopyToTempDirectoryW(PVOID pSrcFiles) { SHFILEOPSTRUCTW fileOpStructW ; HMODULE hmodSH32DLL; PRDPDR_DATA prdpdrData = _pVCMgr->GetInitData(); int result = 1; typedef HRESULT (STDAPICALLTYPE FNSHFileOperationW)(LPSHFILEOPSTRUCT); FNSHFileOperationW *pfnSHFileOperationW;
// get the handle to shell32.dll library
hmodSH32DLL = LoadLibrary(TEXT("SHELL32.DLL"));
if (hmodSH32DLL != NULL) { // get the proc address for SHFileOperation
pfnSHFileOperationW = (FNSHFileOperationW *)GetProcAddress(hmodSH32DLL, "SHFileOperationW");
if (pfnSHFileOperationW != NULL) {
_CB.tempDirW[wcslen(_CB.tempDirW)] = L'\0' ; fileOpStructW.pFrom = (WCHAR*) pSrcFiles ; fileOpStructW.pTo = _CB.tempDirW ; fileOpStructW.hwnd = NULL ; fileOpStructW.wFunc = _CB.dropEffect ; fileOpStructW.fFlags = FOF_NOCONFIRMATION | FOF_NOCONFIRMMKDIR | FOF_SIMPLEPROGRESS | FOF_ALLOWUNDO ; fileOpStructW.hNameMappings = NULL ;
if (prdpdrData->szClipPasteInfoString[0] != 0) { fileOpStructW.lpszProgressTitle = prdpdrData->szClipPasteInfoString; } else { fileOpStructW.lpszProgressTitle = L"Preparing paste information..."; } //result = SHFileOperationW(&fileOpStructW) ;
result = (*pfnSHFileOperationW) (&fileOpStructW); } FreeLibrary(hmodSH32DLL); }
return result ; } #else
//SHFileOperation on CE does not support copying multiple files
int CClip::ClipCopyToTempDirectoryW(PVOID pSrcFiles) { DC_BEGIN_FN("CClip::ClipCopyToTempDirectoryW") ; TRC_ASSERT((pSrcFiles != NULL), (TB, _T("pSrcFiles is NULL")));
WCHAR *pFiles = (WCHAR *)pSrcFiles; WCHAR szDest[MAX_PATH+1]; wcsncpy(szDest, _CB.tempDirW, MAX_PATH); int nTempLen = wcslen(szDest);
while(*pFiles) { int nLen = wcslen(pFiles); WCHAR *pFile = wcsrchr(pFiles, L'\\'); if (pFile && nLen < MAX_PATH) { wcsncat(szDest, pFile, MAX_PATH - nTempLen - 1);
DWORD dwAttrib = GetFileAttributes(pFiles); if ((dwAttrib != 0xffffffff) && (dwAttrib & FILE_ATTRIBUTE_DIRECTORY)) { WIN32_FIND_DATA fd; WCHAR szSrc[MAX_PATH];
wcscpy(szSrc, pFiles); if (!CopyDirectory(szSrc, szDest, &fd)) { TRC_ERR((TB, _T("CopyDirectory from %s to %s failed. GLE=0x%08x"), pFiles, szDest, GetLastError())) ; return GetLastError(); } } else if (!CopyFile(pFiles, szDest, FALSE)) { TRC_ERR((TB, _T("CopyFile from %s to %s failed. GLE=0x%08x"), pFiles, szDest, GetLastError())) ; return GetLastError(); } szDest[nTempLen] = L'\0'; } else { TRC_ERR((TB, _T("Invalid filename : %s"), pFiles)) ; } pFiles += nLen + 1; }
DC_END_FN(); return 0; } #endif
int CClip::ClipCopyToTempDirectoryA(PVOID pSrcFiles) { #ifndef OS_WINCE
SHFILEOPSTRUCTA fileOpStructA ; int result ;
_CB.tempDirA[strlen(_CB.tempDirA)] = '\0' ; fileOpStructA.pFrom = (char*) pSrcFiles ; fileOpStructA.pTo = _CB.tempDirA ; fileOpStructA.hwnd = NULL ; fileOpStructA.wFunc = _CB.dropEffect ; fileOpStructA.fFlags = FOF_NOCONFIRMATION | FOF_NOCONFIRMMKDIR | FOF_SIMPLEPROGRESS | FOF_ALLOWUNDO ; fileOpStructA.hNameMappings = NULL ; fileOpStructA.lpszProgressTitle = _CB.pasteInfoA;
result = SHFileOperationA(&fileOpStructA) ; return result ; #else
DC_BEGIN_FN("CClip::ClipConvertToTempPathA") ; TRC_ASSERT((FALSE), (TB, _T("CE doesnt support ClipConvertToTempPathA"))); DC_END_FN() ; return E_FAIL; #endif
}
//
// ClipConvertToTempPath, ClipConvertToTempPathA, ClipConvertToTempPathW
// - Arguments:
// pOldData = Buffer containing the original file path
// pData = Buffer receiving the new file path
// fWide = Wide or Ansi characters
// - Returns S_OK if pOldData was a network path
// S_FALSE if pOldData was not a network path
// E_FAIL if it failed
// - Given a unc file path, this function will strip out the old path, and
// prepend a path to the client's TS temp directory
//
HRESULT CClip::ClipConvertToTempPath(PVOID pOldData, PVOID pData, ULONG cbData, BOOL fWide) { HRESULT result ; DC_BEGIN_FN("CClip::ClipConvertToTempPath") ; if (!pOldData) { TRC_ERR((TB, _T("Original string pointer is NULL"))) ; result = E_FAIL ; DC_QUIT ; } if (!pData) { TRC_ERR((TB, _T("Destination string pointer is NULL"))) ; result = E_FAIL ; DC_QUIT ; } if (fWide) { result = ClipConvertToTempPathW(pOldData, pData, cbData / sizeof(WCHAR)) ; } else { result = ClipConvertToTempPathA(pOldData, pData, cbData) ; } DC_EXIT_POINT: return result ; DC_END_FN() ; }
HRESULT CClip::ClipConvertToTempPathW(PVOID pOldData, PVOID pData, ULONG cchData) { WCHAR* filePath ; #ifndef OS_WINCE
WCHAR* driveLetter ; WCHAR* uncPath ; WCHAR* prependText ; DWORD charSize ; DWORD driveLetterLength ; #endif
HRESULT hr;
DC_BEGIN_FN("CClip::ClipConvertToTempPathW") ;
// if this is a UNC path beginning with a "\\"
if (((WCHAR*)pOldData)[0] == L'\\' && ((WCHAR*)pOldData)[1] == L'\\') { // prepend the new file path with the temp directory
hr = StringCchCopyW((WCHAR*) pData, cchData, _CB.tempDirW); if (SUCCEEDED(hr)) { filePath = wcsrchr((WCHAR*) pOldData, L'\\'); hr = StringCchCatW((WCHAR*) pData, cchData, filePath); } if (FAILED(hr)) { TRC_ERR((TB,_T("Failed to copy and cat string: 0x%x"),hr)); } } else { TRC_NRM((TB, _T("Not a UNC path"))) ; hr = StringCchCopyW((WCHAR*) pData, cchData, (WCHAR*) pOldData); if (SUCCEEDED(hr)) { hr = S_FALSE; } } #ifdef OS_WINCE
//Send it as "Files:" to the server
if( (((WCHAR*)pData)[0] == L'\\') && ((wcslen((WCHAR *)pData) + sizeof(CEROOTDIRNAME)/sizeof(WCHAR)) < MAX_PATH) ) { WCHAR szFile[MAX_PATH]; wcscpy(szFile, (WCHAR *)pData); wcscpy((WCHAR *)pData, CEROOTDIRNAME); wcscat((WCHAR *)pData, szFile); } else { DC_END_FN() ; return S_FALSE; } #endif
DC_END_FN() ; return hr; }
HRESULT CClip::ClipConvertToTempPathA(PVOID pOldData, PVOID pData, ULONG cchData) { #ifndef OS_WINCE
char* filePath ; char* driveLetter ; char* uncPath ; char* prependText ; DWORD charSize ; DWORD driveLetterLength ; HRESULT hr = E_FAIL;
DC_BEGIN_FN("CClip::ClipConvertToTempPathA") ;
charSize = sizeof(char) ;
// if this is a UNC path beginning with a "\\"
if (((char*) pOldData)[0] == '\\' && ((char*) pOldData)[1] == '\\') { // prepend the new file path with the temp directory
hr = StringCchCopyA((char*) pData, cchData, _CB.tempDirA); if (SUCCEEDED(hr)) { filePath = strrchr((char*) pOldData, '\\'); if (filePath) { hr = StringCchCatA((char*) pData, cchData, filePath); } else { hr = E_FAIL; } } if (FAILED(hr)) { TRC_ERR((TB,_T("Failed to copy and cat string: 0x%x"),hr)); } } else { TRC_NRM((TB, _T("Not a UNC path"))) ; hr = StringCchCopyA((char*) pData, cchData, (char*) pOldData); if (SUCCEEDED(hr)) { hr = S_FALSE; } } DC_END_FN() ;
return hr; #else
DC_BEGIN_FN("CClip::ClipConvertToTempPathA") ; TRC_ASSERT((FALSE), (TB, _T("CE doesnt support ClipConvertToTempPathA"))); DC_END_FN() ; return S_FALSE ; #endif
}
#ifndef OS_WINCE
//
// ClipGetNewFilePathLength
// - Arguments:
// pData = Buffer containing a filepath
// fWide = Wide or Ansi (TRUE if wide, FALSE if ansi)
// - Returns new size of the drop file
// 0 if it fails
// - Given a UNC file path, this returns the new size required
// if the directory structure is removed, and is replaced by
// the temp directory path
// - Otherwise, if it doesn't explicitly fail, it returns the
// old length
//
UINT CClip::ClipGetNewFilePathLength(PVOID pData, BOOL fWide) { UINT result ; DC_BEGIN_FN("CClip::ClipGetNewFilePathLength") ; if (!pData) { TRC_ERR((TB, _T("Filename is NULL"))) ; result = 0 ; } if (fWide) result = ClipGetNewFilePathLengthW((WCHAR*)pData) ; else result = ClipGetNewFilePathLengthA((char*)pData) ; DC_EXIT_POINT: DC_END_FN() ;
return result ; }
UINT CClip::ClipGetNewFilePathLengthW(WCHAR* wszOldFilepath) { UINT oldLength = wcslen(wszOldFilepath) ; UINT newLength = oldLength ; UINT remainingLength = oldLength ; byte charSize = sizeof(WCHAR) ; DC_BEGIN_FN("CClip::ClipGetNewFilePathLengthW") ;
// if the old filename didn't even have space for "c:\" (with NULL),
// then its probably invalid
if (4 > oldLength) { newLength = 0 ; DC_QUIT ; } if ((L'\\' ==wszOldFilepath[0]) && (L'\\' ==wszOldFilepath[1])) { while ((0 != remainingLength) && (L'\\' != wszOldFilepath[remainingLength])) { remainingLength-- ; } // Add the length of the temp directory path, and subtract the
// path preceeding the filename ("path\filename" -> "\filename")
// (\\server\sharename\path\morepath\filename
newLength = oldLength - remainingLength + wcslen(_CB.tempDirW) ; } DC_EXIT_POINT: DC_END_FN() ; return (newLength + 1) * charSize ; // +1 is for the NULL terminator
}
UINT CClip::ClipGetNewFilePathLengthA(char* szOldFilepath) { UINT oldLength = strlen(szOldFilepath) ; UINT newLength = oldLength ; UINT remainingLength = oldLength ; byte charSize = sizeof(char) ; DC_BEGIN_FN("CClip::ClipGetNewFilePathLengthA") ;
// if the old filename didn't even have space for "c:\" (with NULL),
// then it's probably invalid
if (4 > oldLength) { newLength = 0 ; DC_QUIT ; } if (('\\' == szOldFilepath[0]) && ('\\' == szOldFilepath[1])) { while ((0 != remainingLength) && ('\\' != szOldFilepath[remainingLength])) { remainingLength-- ; } // Add the length of the temp directory path, and subtract the
// path preceeding the filename ("path\filename" -> "\filename")
// (\\server\sharename\path\morepath\filename
newLength = oldLength - remainingLength + strlen(_CB.tempDirA) ; } DC_EXIT_POINT: DC_END_FN() ; return (newLength + 1) * charSize ; // +1 is for the NULL terminator
} #endif
//
// ClipGetNewDropfilesSize
// - Arguments:
// pData = Buffer containing a DROPFILES struct
// oldSize = The size of the DROPFILES struct
// fWide = Wide or Ansi (TRUE if wide, FALSE if ansi)
// - Returns new size of the drop file
// 0 if it fails
// - Given a set of paths, this function will return the new
// size required by the DROPFILES struct, if the UNC paths
// are replaced by the temp directory path
//
ULONG CClip::ClipGetNewDropfilesSize(PVOID pData, ULONG oldSize, BOOL fWide) { DC_BEGIN_FN("CClip::TS_GetNewDropfilesSize") ; if (fWide) return ClipGetNewDropfilesSizeW(pData, oldSize) ; else return ClipGetNewDropfilesSizeA(pData, oldSize) ; DC_END_FN() ; } ULONG CClip::ClipGetNewDropfilesSizeW(PVOID pData, ULONG oldSize) { ULONG newSize = oldSize ; #ifndef OS_WINCE
WCHAR* filenameW ; #endif
WCHAR* fullFilePathW ; byte charSize ;
DC_BEGIN_FN("CClip::TS_GetNewDropfilesSizeW") ; charSize = sizeof(WCHAR) ; if (!pData) { TRC_ERR((TB,_T("Pointer to dropfile is NULL"))) ; return 0 ; }
#ifdef OS_WINCE
newSize = 0; #endif
// The start of the first filename
fullFilePathW = (WCHAR*) ((byte*) pData + ((DROPFILES*) pData)->pFiles) ; while (L'\0' != fullFilePathW[0]) { #ifndef OS_WINCE
// If it is a UNC path
if (fullFilePathW[0] == L'\\' && fullFilePathW[1] == L'\\') { filenameW = wcsrchr(fullFilePathW, L'\\'); // Add the length of the temp directory path, and subtract the
// path preceeding the filename ("path\filename" -> "\filename")
// (\\server\sharename\path\morepath\filename
newSize += (wcslen(_CB.tempDirW) - (filenameW - fullFilePathW) ) * charSize ; } #else
newSize++; #endif
fullFilePathW = fullFilePathW + (wcslen(fullFilePathW) + 1) ; } #ifdef OS_WINCE
newSize = oldSize + (newSize*sizeof(CEROOTDIRNAME)); //for the "Files:" (the sizeof operator includes space for the extra null)
#else
// Add space for extra null character
newSize += charSize ; #endif
DC_END_FN() ; return newSize ; }
ULONG CClip::ClipGetNewDropfilesSizeA(PVOID pData, ULONG oldSize) { #ifndef OS_WINCE
ULONG newSize = oldSize ; char* filename ; char* fullFilePath ; byte charSize ;
DC_BEGIN_FN("CClip::TS_GetNewDropfilesSizeW") ; charSize = sizeof(char) ; if (!pData) { TRC_ERR((TB,_T("Pointer to dropfile is NULL"))) ; return 0 ; }
// The start of the first filename
fullFilePath = (char*) ((byte*) pData + ((DROPFILES*) pData)->pFiles) ; while ('\0' != fullFilePath[0]) { // If it is a UNC path
if (fullFilePath[0] == '\\' && fullFilePath[1] == '\\') { filename = strrchr(fullFilePath, '\\'); // Add the length of the temp directory path, and subtract
// the path preceeding the filename itself, excluding the backlash
// (\\server\sharename\path\morepath\filename
newSize += (strlen(_CB.tempDirA) - (filename - fullFilePath) ) * charSize ; } fullFilePath = fullFilePath + (strlen(fullFilePath) + 1) ; } // Add space for extra null character
newSize += charSize ; DC_END_FN() ; return newSize ; #else
DC_BEGIN_FN("CClip::TS_GetNewDropfilesSizeA") ; TRC_ASSERT((FALSE), (TB, _T("CE doesnt support ClipGetNewDropfilesSizeA"))); DC_END_FN() ; return 0 ; #endif
}
//
// ClipSetAndSendTempDirectory
// - Returns TRUE if temp directory was successfully set and sent
// FALSE otherwise (no file redirection, or failed sending path)
// - Sets the Temp paths for the client, and sends the path
// in wide characters to the Server
//
BOOL CClip::ClipSetAndSendTempDirectory(void) { UINT wResult ; BOOL fSuccess ; PTS_CLIP_PDU pClipPDU ; DCINT32 pduLen ; HRESULT hr; DC_BEGIN_FN("CClip::ClipSetAndSendTempDirectory") ; // if we don't have drive redirection, then don't bother sending a path
if (!_CB.fDrivesRedirected) { TRC_ALT((TB, _T("File redirection is off; don't set temp path."))) ; fSuccess = FALSE ; DC_QUIT ; } #ifdef OS_WINCE
if ((fSuccess = InitializeCeShell(_CB.viewerWindow)) == FALSE) { TRC_ALT((TB, _T("Failed to initialize ceshell. File copy through clipboard disabled."))) ; DC_QUIT ; } #endif
#ifndef OS_WINCE
if (0 == GetTempPathA(MAX_PATH, _CB.baseTempDirA)) { TRC_ERR((TB, _T("Failed getting path to temp directory."))) ; fSuccess = FALSE ; DC_QUIT ; }
// Each session gets it own temp directory
if (0 == GetTempFileNameA(_CB.baseTempDirA, "_TS", 0, _CB.tempDirA)) { TRC_ERR((TB, _T("Getting temp file name failed; GetLastError=%u"), GetLastError())); fSuccess = FALSE; DC_QUIT; } DeleteFileA(_CB.tempDirA) ; if (0 == CreateDirectoryA(_CB.tempDirA, NULL)) { TRC_ERR((TB, _T("Creating temp directory failed; GetLastError=%u"), GetLastError())); fSuccess = FALSE; DC_QUIT; }
hr = StringCbCopyA(_CB.baseTempDirA, sizeof(_CB.baseTempDirA), _CB.tempDirA); if (FAILED(hr)) { TRC_ERR((TB,_T("Failed to cpy tempdir to basetempdir: 0x%x"),hr)); fSuccess = FALSE; DC_QUIT; }
// We always send MAX_PATH*sizeof(WCHAR) byte for simplicity
pduLen = MAX_PATH*sizeof(WCHAR) + sizeof(TS_CLIP_PDU); // GetACP always returns a valid value
if (0 == MultiByteToWideChar(GetACP(), MB_ERR_INVALID_CHARS, _CB.baseTempDirA, -1, _CB.baseTempDirW, sizeof(_CB.baseTempDirW)/(sizeof(_CB.baseTempDirW[0])) - 1)) { TRC_ERR((TB, _T("Failed conversion to wide char; error %d"), GetLastError())) ; fSuccess = FALSE ; DC_QUIT ; } #else
if (0 == GetTempPathW(MAX_PATH, _CB.baseTempDirW)) { TRC_ERR((TB, _T("Failed getting path to temp directory."))) ; fSuccess = FALSE ; DC_QUIT ; }
// Each session gets it own temp directory
if (0 == GetTempFileNameW(_CB.baseTempDirW, L"_TS", 0, _CB.tempDirW, MAX_PATH-(sizeof(CEROOTDIRNAME)/sizeof(WCHAR)) ) { TRC_ERR((TB, _T("Getting temp file name failed; GetLastError=%u"), GetLastError())); fSuccess = FALSE; DC_QUIT; } DeleteFile(_CB.tempDirW) ; if (0 == CreateDirectory(_CB.tempDirW, NULL)) { TRC_ERR((TB, _T("Creating temp directory failed; GetLastError=%u"), GetLastError())); fSuccess = FALSE; DC_QUIT; }
wcscpy(_CB.baseTempDirW, _CB.tempDirW) ; pduLen = (MAX_PATH*sizeof(WCHAR)) + sizeof(TS_CLIP_PDU); #endif
pClipPDU = (PTS_CLIP_PDU) ClipAlloc(pduLen) ; if (!pClipPDU) { TRC_ERR((TB,_T("Unable to allocate %d bytes"), pduLen)); fSuccess = FALSE; DC_QUIT; } // Fill in the PDU ; we send a packet of size MAX_PATH for simplicity
DC_MEMSET(pClipPDU, 0, sizeof(TS_CLIP_PDU)); pClipPDU->msgType = TS_CB_TEMP_DIRECTORY; pClipPDU->dataLen = MAX_PATH*sizeof(WCHAR) ;
TRC_DBG((TB, _T("Copying all the data"))); #ifndef OS_WINCE
ClipMemcpy(pClipPDU->data, _CB.baseTempDirW, pClipPDU->dataLen) ; #else
TSUINT8 *pData; int nDSize;
pData = pClipPDU->data; nDSize = sizeof(CEROOTDIRNAME) - sizeof(WCHAR); ClipMemcpy(pData, CEROOTDIRNAME, nDSize) ; pData += nDSize; ClipMemcpy(pData, _CB.baseTempDirW, pClipPDU->dataLen - nDSize) ; #endif
TRC_NRM((TB, _T("Sending temp directory path."))); wResult = _CB.channelEP.pVirtualChannelWriteEx (_CB.initHandle, _CB.channelHandle, pClipPDU, pduLen, (LPVOID)pClipPDU); if (CHANNEL_RC_OK != wResult) { TRC_ERR((TB, _T("Failed sending temp directory 0x%08x"), GetLastError())) ; ClipFreeBuf((PDCUINT8)pClipPDU); fSuccess = FALSE ; DC_QUIT ; } fSuccess = TRUE ; DC_EXIT_POINT: DC_END_FN() ; return fSuccess ; } /****************************************************************************/ /* ClipOnFormatList - we got a list of formats from the server */ /****************************************************************************/ DCVOID DCINTERNAL CClip::ClipOnFormatList(PTS_CLIP_PDU pClipPDU) { DCUINT16 response = TS_CB_RESPONSE_OK; DCUINT numFormats; TS_CLIP_FORMAT UNALIGNED* fmtList; DCUINT i; DCTCHAR formatName[TS_FORMAT_NAME_LEN + 1] = { 0 }; PTS_CLIP_PDU pClipRsp; #ifndef OS_WINCE
DCBOOL fSuccess; LPFORMATETC pFormatEtc ; #endif
LPDATAOBJECT pIDataObject = NULL ; HRESULT hr ; TS_CLIP_PDU UNALIGNED* pUlClipPDU = (TS_CLIP_PDU UNALIGNED*)pClipPDU; #ifdef OS_WINCE
DCUINT uRtf1 = 0xffffffff, uRtf2 = 0xffffffff; #endif
DC_BEGIN_FN("CClip::ClipOnFormatList");
if (_pClipData == NULL) { TRC_ALT((TB, _T("The clipData is NULL, we just bail"))); DC_QUIT; }
/************************************************************************/ /* Do state checks */ /************************************************************************/ CB_CHECK_STATE(CB_EVENT_FORMAT_LIST); if (_CB.state == CB_STATE_PENDING_FORMAT_LIST_RSP) { /********************************************************************/ /* we've just sent a format list to the server. We always win, so */ /* we just ignore this message. */ /********************************************************************/ TRC_ALT((TB, _T("Format list race - we win so ignoring"))); DC_QUIT; }
/************************************************************************/ /* Sanity check */ /************************************************************************/ if (_CB.clipOpen) { TRC_ALT((TB, _T("Clipboard is still open"))); } /****************************************************************/ /* empty the client/server mapping table */ /****************************************************************/ DC_MEMSET(_CB.idMap, 0, sizeof(_CB.idMap));
/****************************************************************/ /* work out how many formats we got */ /****************************************************************/ numFormats = (pUlClipPDU->dataLen) / sizeof(TS_CLIP_FORMAT); TRC_NRM((TB, _T("PDU contains %d formats"), numFormats)); hr = _pClipData->SetNumFormats(numFormats) ; if (SUCCEEDED(hr)) { hr = _pClipData->QueryInterface(IID_IDataObject, (PPVOID) &pIDataObject) ; } #ifdef OS_WINCE
if (SUCCEEDED(hr)) { if (OpenClipboard(_CB.dataWindow)) { if (EmptyClipboard()) { hr = S_OK; } else { CloseClipboard(); hr = MAKE_HRESULT(SEVERITY_ERROR, FACILITY_WINDOWS, GetLastError()); DC_QUIT; } } else { hr = MAKE_HRESULT(SEVERITY_ERROR, FACILITY_WINDOWS, GetLastError()); DC_QUIT; } } #endif
if (SUCCEEDED(hr)) { TRC_ASSERT((numFormats <= CB_MAX_FORMATS), (TB, _T("Format list contains more than %d formats"), CB_MAX_FORMATS)); /****************************************************************/ /* and register them */ /****************************************************************/ fmtList = (TS_CLIP_FORMAT UNALIGNED*)pUlClipPDU->data; for (i = 0; i < numFormats; i++) { TRC_DBG((TB, _T("format number %d, server id %d"), i, fmtList[i].formatID)); //
// If file copy and paste is disabled, we don't accept HDROPs.
//
if (fmtList[i].formatID == CF_HDROP && _CB.fFileCutCopyOn == FALSE) { continue; } /****************************************************************/ /* If we got a name... */ /****************************************************************/ if (fmtList[i].formatName[0] != 0) { /************************************************************/ /* clear out any garbage */ /************************************************************/ #ifndef OS_WINCE
DC_MEMSET(formatName, 0, TS_FORMAT_NAME_LEN); #else
DC_MEMSET(formatName, 0, sizeof(formatName)); #endif
//
// fmtList[i].formatName is not NULL terminated so explicity
// do a byte count copy
//
StringCbCopy(formatName, TS_FORMAT_NAME_LEN + sizeof(TCHAR), (PDCTCHAR)(fmtList[i].formatName));
if (ClipIsExcludedFormat(formatName)) { TRC_NRM((TB, _T("Dropped format '%s'"), formatName)); continue; } /************************************************************/ /* name is sorted */ /************************************************************/ TRC_NRM((TB, _T("Got name '%s'"), formatName));
} else { DC_MEMSET(formatName, 0, TS_FORMAT_NAME_LEN); } /****************************************************************/ /* store the server id */ /****************************************************************/ _CB.idMap[i].serverID = fmtList[i].formatID; TRC_NRM((TB, _T("server id %d"), _CB.idMap[i].serverID));
/****************************************************************/ /* get local name (if needed) */ /****************************************************************/ if (formatName[0] != 0) { #ifdef OS_WINCE
//The protocol limits clipboard format names to 16 widechars. Thus it becomes impossible
//to distinguish between "Rich Text Format" and "Rich Text Format Without Objects"
//This should be removed once the protocol is fixed in Longhorn
if (0 == DC_TSTRNCMP(formatName, CFSTR_RTF, (sizeof(CFSTR_RTF)/sizeof(TCHAR)) - 1)) { if (uRtf1 == 0xffffffff) uRtf1 = i; else uRtf2 = i; continue; } else #endif
_CB.idMap[i].clientID = RegisterClipboardFormat(formatName); } else { /************************************************************/ /* it's a predefined format so we can just use the ID */ /************************************************************/ _CB.idMap[i].clientID = _CB.idMap[i].serverID; } #ifdef OS_WINCE
if (_CB.idMap[i].serverID == CF_HDROP) _CB.idMap[i].clientID = gfmtShellPidlArray; #endif
/************************************************************/ /* and add the format to the local CB */ /************************************************************/ TRC_DBG((TB, _T("Adding format '%s', server ID %d, client ID %d"), fmtList[i].formatName, _CB.idMap[i].serverID, _CB.idMap[i].clientID));
if (0 != _CB.idMap[i].clientID) { #ifndef OS_WINCE
pFormatEtc = new FORMATETC ;
if (pFormatEtc) {
pFormatEtc->cfFormat = (CLIPFORMAT) _CB.idMap[i].clientID ; pFormatEtc->dwAspect = DVASPECT_CONTENT ; pFormatEtc->ptd = NULL ; pFormatEtc->lindex = -1 ; pFormatEtc->tymed = TYMED_HGLOBAL ; // Need to set the clipboard state before SetData.
CB_SET_STATE(CB_STATE_LOCAL_CB_OWNER, CB_EVENT_FORMAT_LIST); pIDataObject->SetData(pFormatEtc, NULL, TRUE) ; delete pFormatEtc; }
#else
CB_SET_STATE(CB_STATE_LOCAL_CB_OWNER, CB_EVENT_FORMAT_LIST); SetClipboardData((CLIPFORMAT) _CB.idMap[i].clientID, NULL); #endif
} else TRC_NRM((TB,_T("Invalid format dropped"))) ; } #ifdef OS_WINCE
//we will choose the lower format id as belonging to "Rich Text Format"
//This is our best guess and it seems to work
ClipFixupRichTextFormats(uRtf1, uRtf2); #endif
#ifndef OS_WINCE
hr = OleSetClipboard(pIDataObject) ; #else
EnterCriticalSection(&gcsDataObj); if (gpDataObj) gpDataObj->Release(); pIDataObject->AddRef(); gpDataObj = pIDataObject;
LeaveCriticalSection(&gcsDataObj); hr = S_OK; CloseClipboard(); #endif
if (pIDataObject) pIDataObject->Release(); if (SUCCEEDED(hr)) { response = TS_CB_RESPONSE_OK; _CB.clipOpen = FALSE ; } else { TRC_ERR((TB, _T("OleSetClipboard failed, error = 0x%08x"), hr)) ; response = TS_CB_RESPONSE_FAIL; _CB.clipOpen = FALSE ; } } else { if (pIDataObject) pIDataObject->Release(); TRC_ERR((TB, _T("Error getting pointer to an IDataObject"))) ; pIDataObject = NULL ; response = TS_CB_RESPONSE_FAIL ; }
/************************************************************************/ /* Now build the response */ /************************************************************************/ TRC_NRM((TB, _T("Get perm TX buffer"))); pClipRsp = ClipGetPermBuf();
/************************************************************************/ /* and now the specific bits */ /************************************************************************/ pClipRsp->msgType = TS_CB_FORMAT_LIST_RESPONSE; pClipRsp->msgFlags = response; pClipRsp->dataLen = 0;
/************************************************************************/ /* finally we send it */ /************************************************************************/ if (_CB.channelEP.pVirtualChannelWriteEx (_CB.initHandle, _CB.channelHandle, pClipRsp, sizeof(TS_CLIP_PDU), (LPVOID)pClipRsp) != CHANNEL_RC_OK) { TRC_ERR((TB, _T("Failed VC write: setting clip data to NULL"))); ClipFreeBuf((PDCUINT8)pClipRsp); response = TS_CB_RESPONSE_FAIL ; } /************************************************************************/ /* Update the state according to how we got on */ /************************************************************************/ if (response == TS_CB_RESPONSE_OK) { CB_SET_STATE(CB_STATE_LOCAL_CB_OWNER, CB_EVENT_FORMAT_LIST); } else { CB_SET_STATE(CB_STATE_ENABLED, CB_EVENT_FORMAT_LIST); } DC_EXIT_POINT: DC_END_FN(); return; } /* ClipOnFormatList */
/****************************************************************************/ /* ClipOnFormatListResponse - got the format list response */ /****************************************************************************/ DCVOID DCINTERNAL CClip::ClipOnFormatListResponse(PTS_CLIP_PDU pClipPDU) { DC_BEGIN_FN("CClip::ClipOnFormatListResponse");
CB_CHECK_STATE(CB_EVENT_FORMAT_LIST_RSP);
/************************************************************************/ /* if the response is OK... */ /************************************************************************/ if (pClipPDU->msgFlags & TS_CB_RESPONSE_OK) { /********************************************************************/ /* we are now the shared CB owner */ /********************************************************************/ TRC_NRM((TB, _T("Got OK fmt list rsp"))); CB_SET_STATE(CB_STATE_SHARED_CB_OWNER, CB_EVENT_FORMAT_LIST_RSP); } else { /********************************************************************/ /* nothing specific to do */ /********************************************************************/ TRC_ALT((TB, _T("Got fmt list rsp failed"))); CB_SET_STATE(CB_STATE_ENABLED, CB_EVENT_FORMAT_LIST_RSP); }
/************************************************************************/ /* There may have been another update while we were waiting - deal with */ /* it by faking an update here */ /************************************************************************/ if (_CB.moreToDo == TRUE) { TRC_ALT((TB, _T("More to do on list rsp"))); _CB.moreToDo = FALSE; ClipDrawClipboard(FALSE); }
DC_EXIT_POINT: DC_END_FN(); return; } /* ClipOnFormatListResponse */
/****************************************************************************/ // ClipOnFormatRequest
// - Server wants a format
/****************************************************************************/ DCVOID DCINTERNAL CClip::ClipOnFormatRequest(PTS_CLIP_PDU pClipPDU) { DCUINT32 formatID; DCUINT32 dataLen = 0; DCUINT numEntries; DCUINT16 dwEntries;
HANDLE hData = NULL; HANDLE hNewData = NULL; HPDCVOID pData = NULL; DROPFILES* pDropFiles ; #ifndef OS_WINCE
DROPFILES tempDropfile ; #endif
HPDCVOID pNewData = NULL; DCUINT16 response = TS_CB_RESPONSE_OK; PTS_CLIP_PDU pClipRsp = NULL; PTS_CLIP_PDU pClipNew; DCUINT32 pduLen; BOOL fDrivePath ; BOOL fWide ; byte charSize ; ULONG newSize, oldSize ; HPDCVOID pOldFilename ; HPDCVOID pFileList = NULL ; HPDCVOID pTmpFileList = NULL; HPDCVOID pFilename = NULL ; #ifndef OS_WINCE
char* fileList ; WCHAR* fileListW ; SHFILEOPSTRUCTA fileOpStructA ; SHFILEOPSTRUCTW fileOpStructW ; HRESULT result ; DCTCHAR formatName[TS_FORMAT_NAME_LEN] ; #endif
HRESULT hr;
DC_BEGIN_FN("CClip::ClipOnFormatRequest");
//
// Set the response to failure before making the state check
//
response = TS_CB_RESPONSE_FAIL; CB_CHECK_STATE(CB_EVENT_FORMAT_DATA_RQ); response = TS_CB_RESPONSE_OK;
/************************************************************************/ /* Make sure the local CB is open */ /************************************************************************/ if ((_CB.rcvOpen) || OpenClipboard(_CB.viewerWindow)) { /********************************************************************/ /* It was/is open */ /********************************************************************/ TRC_NRM((TB, _T("CB opened"))); _CB.rcvOpen = TRUE;
/********************************************************************/ /* Extract the format from the PDU */ /********************************************************************/ TRC_DATA_DBG("pdu data", pClipPDU->data, (DCUINT)pClipPDU->dataLen);
//
// Verify that we have enough data to extract a format ID.
//
if (pClipPDU->dataLen < sizeof(DCUINT32)) { TRC_ERR((TB,_T("Not enough data to extract a format ID."))); _CB.channelEP.pVirtualChannelCloseEx(_CB.initHandle, _CB.channelHandle); response = TS_CB_RESPONSE_FAIL; dataLen = 0; DC_QUIT ; } formatID = *((PDCUINT32_UA)pClipPDU->data); TRC_NRM((TB, _T("Requesting format %ld"), formatID));
/********************************************************************/ /* If the Server asked for CF_DIB, we may have to translate from */ /* CF_BITMAP */ /********************************************************************/ if ((formatID == CF_DIB) && (!_CB.DIBFormatExists)) { TRC_NRM((TB, _T("Server asked for CF_DIB - get CF_BITMAP"))); formatID = CF_BITMAP; }
/********************************************************************/ /* Get a handle to the data */ /********************************************************************/ #ifdef OS_WINCE
if (formatID == CF_HDROP) formatID = gfmtShellPidlArray; #endif
hData = GetClipboardData((UINT)formatID); TRC_DBG((TB, _T("Got format %ld at %p"), formatID, hData)); if (hData == NULL) { /****************************************************************/ /* Oops! */ /****************************************************************/ TRC_ERR((TB, _T("Failed to get format %ld"), formatID)); response = TS_CB_RESPONSE_FAIL; dataLen = 0; DC_QUIT ; } else { /****************************************************************/ /* Got handle, now what happens next depends on the flavour of */ /* data we're looking at... */ /****************************************************************/ if (formatID == CF_PALETTE) { TRC_DBG((TB, _T("CF_PALETTE requested"))); /************************************************************/ /* Find out how many entries there are in the palette and */ /* allocate enough memory to hold them all. */ /************************************************************/ if (GetObject(hData, sizeof(DCUINT16), &dwEntries) == 0) { TRC_DBG((TB, _T("Failed to get count of palette entries"))); dwEntries = 256; } numEntries = (DCUINT)dwEntries; TRC_DBG((TB, _T("Need mem for %u palette entries"), numEntries));
dataLen = sizeof(LOGPALETTE) - sizeof(PALETTEENTRY) + (numEntries * sizeof(PALETTEENTRY));
hNewData = GlobalAlloc(GHND, dataLen); if (hNewData == 0) { TRC_ERR((TB, _T("Failed to get %ld bytes for palette"), dataLen)); response = TS_CB_RESPONSE_FAIL; dataLen = 0; DC_QUIT ; } else { /********************************************************/ /* now get the palette entries into the new buffer */ /********************************************************/ pData = (HPDCUINT8)GlobalLock(hNewData); if (NULL == pData) { TRC_ERR((TB,_T("Failed to lock palette entries"))); response = TS_CB_RESPONSE_FAIL; dataLen = 0; DC_QUIT; } numEntries = GetPaletteEntries((HPALETTE)hData, 0, numEntries, (PALETTEENTRY*)pData); TRC_DATA_DBG("Palette entries", pData, (DCUINT)dataLen); GlobalUnlock(hNewData); TRC_DBG((TB, _T("Got %u palette entries"), numEntries)); if (numEntries == 0) { TRC_ERR((TB, _T("Failed to get any palette entries"))); response = TS_CB_RESPONSE_FAIL; dataLen = 0; DC_QUIT ; } dataLen = numEntries * sizeof(PALETTEENTRY);
/********************************************************/ /* all ok - set up hData to point to the new data */ /********************************************************/ hData = hNewData; }
} #ifndef OS_WINCE
else if (formatID == CF_METAFILEPICT) { TRC_NRM((TB, _T("Metafile data to get"))); hNewData = ClipGetMFData(hData, &dataLen); if (!hNewData) { TRC_ERR((TB, _T("Failed to set MF data"))); response = TS_CB_RESPONSE_FAIL; dataLen = 0; DC_QUIT ; } else { /********************************************************/ /* all ok - set up hData to point to the new data */ /********************************************************/ hData = hNewData; } } #endif
else if (formatID == CF_BITMAP) { /************************************************************/ /* We've gt CF_BITMAP data. This will be because the */ /* Server has asked for CF_DIB data - we never send */ /* CF_BITMAP to the Server. Convert it to CF_DIB format. */ /************************************************************/ TRC_NRM((TB, _T("Convert CF_BITMAP to CF_DIB"))); hNewData = ClipBitmapToDIB(hData, &dataLen); if (hNewData) { hData = hNewData; } else { response = TS_CB_RESPONSE_FAIL; dataLen = 0; DC_QUIT ; }
} // Since we won't even send an HDROP format to the server if the
// local drives are redirected, and we always send a new formatlist
// when we reconnect to a server, this does not have to be touched
#ifndef OS_WINCE
else if (formatID == CF_HDROP) #else
else if (formatID == gfmtShellPidlArray) #endif
{ SIZE_T cbDropFiles; BYTE *pbLastByte, *pbStartByte, *pbLastPossibleNullStart; BOOL fTrailingFileNamesValid; ULONG cbRemaining;
TRC_NRM((TB,_T("HDROP requested"))) ; #ifdef OS_WINCE
HANDLE hPidlArray = IDListToHDrop(hData); if (!hPidlArray) { TRC_ERR((TB,_T("Failed to get file list from clipboard"))) ; response = TS_CB_RESPONSE_FAIL; dataLen = 0; DC_QUIT ; } hData = hPidlArray; #endif
//
// Make sure that we have at least a DROPFILES structure in
// memory.
cbDropFiles = GlobalSize(hData); if (cbDropFiles < sizeof(DROPFILES)) { TRC_ERR((TB,_T("Unexpected global memory size!"))) ; _CB.channelEP.pVirtualChannelCloseEx(_CB.initHandle, _CB.channelHandle); response = TS_CB_RESPONSE_FAIL; dataLen = 0; DC_QUIT ; } pDropFiles = (DROPFILES*) GlobalLock(hData) ; if (!pDropFiles) { TRC_ERR((TB,_T("Failed to lock %p"), hData)) ; response = TS_CB_RESPONSE_FAIL; dataLen = 0; DC_QUIT ;
} fWide = ((DROPFILES*) pDropFiles)->fWide ; charSize = fWide ? sizeof(WCHAR) : sizeof(char) ;
//
// Check that the data behind the DROPFILES data structure
// pointed to by pDropFiles is valid. Every drop file list
// is terminated by two NULL characters. So, simply scan
// through the memory after the DROPFILES structure and make
// sure that there is a double NULL before the last byte.
//
if (pDropFiles->pFiles < sizeof(DROPFILES) || pDropFiles->pFiles > cbDropFiles) { TRC_ERR((TB,_T("File name offset invalid!"))) ; _CB.channelEP.pVirtualChannelCloseEx(_CB.initHandle, _CB.channelHandle); response = TS_CB_RESPONSE_FAIL; dataLen = 0; DC_QUIT ; }
pbStartByte = (BYTE*) pDropFiles + pDropFiles->pFiles; pbLastByte = (BYTE*) pDropFiles + cbDropFiles - 1; fTrailingFileNamesValid = FALSE;
//
// Make pbLastPossibleNullStart point to the last place where a
// double NULL could possibly start.
//
// Examples: Assume pbLastByte = 9
// Then for ASCII: pbLastPossibleNullStart = 8 (9 - 2 * 1 + 1)
// And for UNICODE: pbLastPossibleNullStart = 6 (9 - 2 * 2 + 1)
//
pbLastPossibleNullStart = pbLastByte - (2 * charSize) + 1; if (fWide) { for (WCHAR* pwch = (WCHAR*) pbStartByte; (BYTE*) pwch <= pbLastPossibleNullStart; pwch++) { if (*pwch == NULL && *(pwch + 1) == NULL) { fTrailingFileNamesValid = TRUE; } } } else { for (BYTE* pch = pbStartByte; pch <= pbLastPossibleNullStart; pch++) { if (*pch == NULL && *(pch + 1) == NULL) { fTrailingFileNamesValid = TRUE; } } }
if (!fTrailingFileNamesValid) { TRC_ERR((TB,_T("DROPFILES structure invalid!"))) ; _CB.channelEP.pVirtualChannelCloseEx(_CB.initHandle, _CB.channelHandle); response = TS_CB_RESPONSE_FAIL; dataLen = 0; DC_QUIT; }
//
// DROPFILES are valid so we can continue.
//
if (!_CB.fAlreadyCopied) { // if it's not a drive path, then copy to a temp directory
pFileList = (byte*)pDropFiles + pDropFiles->pFiles ; #ifndef OS_WINCE
fDrivePath = fWide ? (0 != wcschr((WCHAR*) pFileList, L':')) : (0 != strchr((char*) pFileList, ':')) ; #else //copy to temp dir if it is a network path
fDrivePath = fWide ? (! ( (((WCHAR *)pFileList)[0] == L'\\') && (((WCHAR *)pFileList)[1] == L'\\')) ) : (! ( (((CHAR *)pFileList)[0] == '\\') && (((CHAR *)pFileList)[1] == '\\')) ) ; #endif
if (!fDrivePath) { // ClipCopyToTempDirectory returns 0 if successful
if (0 != ClipCopyToTempDirectory(pFileList, fWide)) { TRC_ERR((TB,_T("Copy to tmp directory failed"))) ; response = TS_CB_RESPONSE_FAIL; dataLen = 0; _CB.fAlreadyCopied = TRUE ; DC_QUIT ; } } _CB.fAlreadyCopied = TRUE ; }
// Now that we copied the files, we want to convert the file
// paths to something the server will understand
// Allocate space for new filepaths
oldSize = (ULONG) GlobalSize(hData) ; newSize = ClipGetNewDropfilesSize(pDropFiles, oldSize, fWide) ; hNewData = GlobalAlloc(GMEM_DISCARDABLE | GMEM_MOVEABLE, newSize) ; if (!hNewData) { TRC_ERR((TB, _T("Failed to get %ld bytes for HDROP"), newSize)); response = TS_CB_RESPONSE_FAIL; dataLen = 0; DC_QUIT ; } pNewData = GlobalLock(hNewData) ; if (!pNewData) { TRC_ERR((TB, _T("Failed to get lock %p for HDROP"), hNewData)); response = TS_CB_RESPONSE_FAIL; dataLen = 0; DC_QUIT ; } // Just copy the old DROPFILES data members (unchanged)
((DROPFILES*) pNewData)->pFiles = pDropFiles->pFiles ; ((DROPFILES*) pNewData)->pt = pDropFiles->pt ; ((DROPFILES*) pNewData)->fNC = pDropFiles->fNC ; ((DROPFILES*) pNewData)->fWide = pDropFiles->fWide ;
// The first filename in a DROPFILES data structure begins
// DROPFILES.pFiles bytes away from the head of the DROPFILES
pOldFilename = (byte*) pDropFiles + ((DROPFILES*) pDropFiles)->pFiles ; pFilename = (byte*) pNewData + ((DROPFILES*) pNewData)->pFiles ; pbLastByte = (BYTE*) pNewData + newSize - 1; cbRemaining = (ULONG) (pbLastByte - (BYTE*) pFilename + 1); while (fWide ? (L'\0' != ((WCHAR*) pOldFilename)[0]) : ('\0' != ((char*) pOldFilename)[0])) { if (FAILED(ClipConvertToTempPath(pOldFilename, pFilename, cbRemaining, fWide))) { TRC_ERR((TB, _T("Failed conversion"))) ; response = TS_CB_RESPONSE_FAIL; dataLen = 0 ; DC_QUIT ; } if (fWide) { pOldFilename = (byte*) pOldFilename + (wcslen((WCHAR*)pOldFilename) + 1) * sizeof(WCHAR) ; pFilename = (byte*) pFilename + (wcslen((WCHAR*)pFilename) + 1) * sizeof(WCHAR) ; } else { pOldFilename = (byte*) pOldFilename + (strlen((char*)pOldFilename) + 1) * sizeof(char) ; pFilename = (byte*) pFilename + (strlen((char*)pFilename) + 1) * sizeof(char) ; } cbRemaining = (ULONG) (pbLastByte - (BYTE*) pFilename + 1); } if (fWide) { ((WCHAR*) pFilename)[0] = L'\0' ; } else { ((char*) pFilename)[0] = '\0' ; } GlobalUnlock(hNewData) ; hData = hNewData ; response = TS_CB_RESPONSE_OK ; dataLen = (ULONG) GlobalSize(hData) ; #ifdef OS_WINCE
GlobalFree(hPidlArray); #endif
} else { #ifndef OS_WINCE
// Check to see if we are processing the FileName/FileNameW
// OLE 1 formats; if so, we convert th
if (0 != GetClipboardFormatName(formatID, formatName, TS_FORMAT_NAME_LEN)) { if ((0 == _tcscmp(formatName, TEXT("FileName"))) || (0 == _tcscmp(formatName, TEXT("FileNameW")))) { size_t cbOldFileName;
if (!_tcscmp(formatName, TEXT("FileNameW"))) { fWide = TRUE ; charSize = sizeof(WCHAR) ; } else { fWide = FALSE ; charSize = 1 ; } //
// Extract the file name, but ensure that it is properly
// NULL terminated.
//
pOldFilename = GlobalLock(hData);
if (!pOldFilename) { TRC_ERR((TB, _T("No filename/Unable to lock %p"), hData)); response = TS_CB_RESPONSE_FAIL; dataLen = 0; DC_QUIT ; }
oldSize = (ULONG) GlobalSize(hData) ; if (fWide) { hr = StringCbLengthW((WCHAR*) pOldFilename, oldSize, &cbOldFileName); } else { hr = StringCbLengthA((CHAR*) pOldFilename, oldSize, &cbOldFileName); } if (FAILED(hr)) { TRC_ERR((TB, _T("File name not NULL terminated!"))); _CB.channelEP.pVirtualChannelCloseEx(_CB.initHandle, _CB.channelHandle); response = TS_CB_RESPONSE_FAIL; dataLen = 0; DC_QUIT ; } if (!_CB.fAlreadyCopied) { // if its not a drive path, then copy to a temp
// directory. We have to copy over the filename to
// string that is one character larger, because we
// need to add an extra NULL for the SHFileOperation
UINT cbSize= oldSize + charSize; pTmpFileList = LocalAlloc(LPTR, cbSize); if (NULL == pTmpFileList) { TRC_ERR((TB,_T("pTmpFileList alloc failed"))); response = TS_CB_RESPONSE_FAIL; dataLen = 0; _CB.fAlreadyCopied = TRUE; DC_QUIT ; } if (fWide) { hr = StringCbCopyW((WCHAR*)pTmpFileList, cbSize, (WCHAR*)pOldFilename) ; fDrivePath = (0 != wcschr((WCHAR*) pTmpFileList, L':')) ; } else { hr = StringCbCopyA((char*)pTmpFileList, cbSize, (char*)pOldFilename) ; fDrivePath = (0 != strchr((char*) pTmpFileList, ':')) ; } if (FAILED(hr)) { TRC_ERR((TB,_T("Failed to cpy filelist string: 0x%x"),hr)); response = TS_CB_RESPONSE_FAIL; dataLen = 0; _CB.fAlreadyCopied = TRUE; DC_QUIT ; } if (fDrivePath) { // ClipCopyToTempDirectory returns 0 if successful
if (0 != ClipCopyToTempDirectory(pTmpFileList, fWide)) { TRC_ERR((TB,_T("Copy to tmp directory failed"))) ; response = TS_CB_RESPONSE_FAIL; dataLen = 0; _CB.fAlreadyCopied = TRUE ; DC_QUIT ; } } _CB.fAlreadyCopied = TRUE ; LocalFree(pTmpFileList); pTmpFileList = NULL; } newSize = ClipGetNewFilePathLength(pOldFilename, fWide) ; hNewData = GlobalAlloc(GMEM_DISCARDABLE | GMEM_MOVEABLE, newSize) ; if (!hNewData) { TRC_ERR((TB, _T("Failed to get %ld bytes for HDROP"), newSize)); response = TS_CB_RESPONSE_FAIL; dataLen = 0; DC_QUIT ; } pFilename = GlobalLock(hNewData) ; if (!pFilename) { TRC_ERR((TB, _T("Failed to get lock %p for HDROP"), hNewData)); response = TS_CB_RESPONSE_FAIL; dataLen = 0; DC_QUIT ; } if (FAILED(ClipConvertToTempPath(pOldFilename, pFilename, newSize, fWide))) { TRC_ERR((TB, _T("Failed conversion"))) ; response = TS_CB_RESPONSE_FAIL; dataLen = 0; DC_QUIT ; } GlobalUnlock(hNewData) ; hData = hNewData ; response = TS_CB_RESPONSE_OK ; dataLen = newSize ; DC_QUIT ; } } #endif
/************************************************************/ /* just get the length of the block */ /************************************************************/ dataLen = (DCUINT32)GlobalSize(hData); TRC_DBG((TB, _T("Got data len %ld"), dataLen)); } } } else { /********************************************************************/ /* Failed to open CB - send a failure response */ /********************************************************************/ TRC_ERR((TB, _T("Failed to open CB"))); response = TS_CB_RESPONSE_FAIL; dataLen = 0; DC_QUIT ; }
DC_EXIT_POINT:
/************************************************************************/ /* By default, we'll use the permanent send buffer */ /************************************************************************/ TRC_NRM((TB, _T("Get perm TX buffer")));
pduLen = dataLen + sizeof(TS_CLIP_PDU); pClipNew = (PTS_CLIP_PDU)ClipAlloc(pduLen);
if (pClipNew != NULL) { /****************************************************************/ /* Use the new buffer */ /****************************************************************/ TRC_NRM((TB, _T("Free perm TX buffer"))); pClipRsp = pClipNew; } else { /****************************************************************/ /* Fail the request */ /****************************************************************/ TRC_ERR((TB, _T("Failed to alloc %ld bytes"), pduLen)); pClipRsp = ClipGetPermBuf(); response = TS_CB_RESPONSE_FAIL; dataLen = 0; pduLen = sizeof(TS_CLIP_PDU); }
DC_MEMSET(pClipRsp, 0, sizeof(*pClipRsp)); pClipRsp->msgType = TS_CB_FORMAT_DATA_RESPONSE; pClipRsp->msgFlags = response; pClipRsp->dataLen = dataLen;
if (pTmpFileList) { LocalFree(pTmpFileList); pTmpFileList = NULL; }
// Copy data, if any
if (dataLen != 0) { TRC_DBG((TB, _T("Copying all the data"))); pData = (HPDCUINT8)GlobalLock(hData); if (NULL != pData) { ClipMemcpy(pClipRsp->data, pData, dataLen); GlobalUnlock(hData); } else { TRC_ERR(( TB, _T("Failed to lock data"))); pClipRsp->msgFlags = TS_CB_RESPONSE_FAIL; pClipRsp->dataLen = 0; pduLen = sizeof(TS_CLIP_PDU); } }
// Send the PDU
TRC_NRM((TB, _T("Sending format data rsp"))); if (_CB.channelEP.pVirtualChannelWriteEx (_CB.initHandle, _CB.channelHandle, (LPVOID)pClipRsp, pduLen, pClipRsp) != CHANNEL_RC_OK) { ClipFreeBuf((PDCUINT8)pClipRsp); }
// close the clipboard if we need to
if (_CB.rcvOpen) { TRC_DBG((TB, _T("Closing CB"))); _CB.rcvOpen = FALSE; if (!CloseClipboard()) { TRC_SYSTEM_ERROR("CloseClipboard"); } } // if we got any new data, we need to free it
if (hNewData) { TRC_DBG((TB, _T("Freeing new data"))); GlobalFree(hNewData); }
DC_END_FN(); return; } /* ClipOnFormatRequest */
/****************************************************************************/ // ClipOnFormatDataComplete
// - Server response to our request for data
/****************************************************************************/ DCVOID DCINTERNAL CClip::ClipOnFormatDataComplete(PTS_CLIP_PDU pClipPDU) { HANDLE hData = NULL; HPDCVOID pData; LOGPALETTE * pLogPalette = NULL; DCUINT32 numEntries; DCUINT32 memLen; #ifndef OS_WINCE
HRESULT hr ; #endif
DC_BEGIN_FN("CClip::ClipOnFormatDataComplete");
/************************************************************************/ /* check the response */ /************************************************************************/ if (_pClipData == NULL) { TRC_ALT((TB, _T("The clipData is NULL, we just bail"))); DC_QUIT; }
if (!(pClipPDU->msgFlags & TS_CB_RESPONSE_OK)) { TRC_ALT((TB, _T("Got fmt data rsp failed for %d"), _CB.pendingClientID)); DC_QUIT; }
/************************************************************************/ /* Got the data */ /************************************************************************/ TRC_NRM((TB, _T("Got OK fmt data rsp for %d"), _CB.pendingClientID));
#ifndef OS_WINCE
/************************************************************************/ /* For some formats we still need to do some work */ /************************************************************************/ if (_CB.pendingClientID == CF_METAFILEPICT) { /********************************************************************/ /* Metafile format - create a metafile from the data */ /********************************************************************/ TRC_NRM((TB, _T("Rx data is for metafile"))); hData = ClipSetMFData(pClipPDU->dataLen, pClipPDU->data); if (hData == NULL) { TRC_ERR((TB, _T("Failed to set MF data"))); } } else #endif
if (_CB.pendingClientID == CF_PALETTE) { /********************************************************************/ /* Palette format - create a palette from the data */ /********************************************************************/
/********************************************************************/ /* Allocate memory for a LOGPALETTE structure large enough to hold */ /* all the PALETTE ENTRY structures, and fill it in. */ /********************************************************************/ TRC_NRM((TB, _T("Rx data is for palette"))); numEntries = (pClipPDU->dataLen / sizeof(PALETTEENTRY)); memLen = (sizeof(LOGPALETTE) + ((numEntries - 1) * sizeof(PALETTEENTRY))); TRC_DBG((TB, _T("%ld palette entries, allocate %ld bytes"), numEntries, memLen)); pLogPalette = (LOGPALETTE*)ClipAlloc(memLen); if (pLogPalette != NULL) { pLogPalette->palVersion = 0x300; pLogPalette->palNumEntries = (WORD)numEntries;
ClipMemcpy(pLogPalette->palPalEntry, pClipPDU->data, pClipPDU->dataLen);
/****************************************************************/ /* now create a palette */ /****************************************************************/ hData = CreatePalette(pLogPalette); if (hData == NULL) { TRC_SYSTEM_ERROR("CreatePalette"); } } else { TRC_ERR((TB, _T("Failed to get %ld bytes"), memLen)); } } else { TRC_NRM((TB, _T("Rx data can just go on CB"))); /********************************************************************/ /* We need to copy the data, as the receive buffer will be freed on */ /* return from this function. */ /********************************************************************/ hData = GlobalAlloc(GMEM_DISCARDABLE | GMEM_MOVEABLE, pClipPDU->dataLen); if (hData != NULL) { pData = GlobalLock(hData); if (pData != NULL) { TRC_NRM((TB, _T("Copy %ld bytes from %p to %p"), pClipPDU->dataLen, pClipPDU->data, pData)); ClipMemcpy(pData, pClipPDU->data, pClipPDU->dataLen); GlobalUnlock(hData); } else { TRC_ERR((TB, _T("Failed to lock %p (%ld bytes)"), hData, pClipPDU->dataLen)); GlobalFree(hData); hData = NULL; } } else { TRC_ERR((TB, _T("Failed to alloc %ld bytes"), pClipPDU->dataLen)); } }
DC_EXIT_POINT:
/************************************************************************/ /* tidy up */ /************************************************************************/ if (pLogPalette != NULL) { ClipFree(pLogPalette); }
/************************************************************************/ /* Set the state, and we're done. Note that this is done when we get a */ /* failure response too. */ /************************************************************************/ CB_SET_STATE(CB_STATE_LOCAL_CB_OWNER, CB_EVENT_FORMAT_DATA_RSP); _pClipData->SetClipData(hData, _CB.pendingClientID ) ;
TRC_ASSERT( NULL != _GetDataSync[TS_RECEIVE_COMPLETED], (TB,_T("data sync is NULL"))); SetEvent(_GetDataSync[TS_RECEIVE_COMPLETED]) ;
DC_END_FN(); return; } /* ClipOnFormatDataComplete */
/****************************************************************************/ /* ClipRemoteFormatFromLocalID */ /****************************************************************************/ DCUINT DCINTERNAL CClip::ClipRemoteFormatFromLocalID(DCUINT id) { DCUINT i; DCUINT retID = 0;
for (i = 0; i < CB_MAX_FORMATS; i++) { if (_CB.idMap[i].clientID == id) { retID = _CB.idMap[i].serverID; break; } }
return(retID); }
/****************************************************************************/ /* ClipOnWriteComplete */ /****************************************************************************/ DCVOID DCINTERNAL CClip::ClipOnWriteComplete(LPVOID pData) { PTS_CLIP_PDU pClipPDU;
DC_BEGIN_FN("CClip::ClipOnWriteComplete");
TRC_NRM((TB, _T("Free buffer at %p"), pData)); pClipPDU = (PTS_CLIP_PDU)pData; TRC_DBG((TB, _T("Message type %hx, flags %hx"), pClipPDU->msgType, pClipPDU->msgFlags));
/************************************************************************/ /* Free the buffer */ /************************************************************************/ TRC_DBG((TB, _T("Write from buffer %p complete"), pData)); ClipFreeBuf((PDCUINT8)pData);
DC_END_FN(); return; }
HRESULT CClip::ClipCreateDataSyncEvents() { HRESULT hr = E_FAIL ;
DC_BEGIN_FN("CClip::ClipCreateDataSyncEvents") ; // Create events for controlling the Clipboard thread
_GetDataSync[TS_RECEIVE_COMPLETED] = CreateEvent(NULL, FALSE, FALSE, NULL) ; _GetDataSync[TS_RESET_EVENT] = CreateEvent(NULL, FALSE, FALSE, NULL) ;
if (!_GetDataSync[TS_RECEIVE_COMPLETED]) { TRC_ERR((TB, _T("Failed CreateEvent RECEIVE_COMPLETED; Error = %d"), GetLastError())) ; hr = E_FAIL ; DC_QUIT ; } if (!_GetDataSync[TS_RESET_EVENT]) { TRC_ERR((TB, _T("Failed CreateEvent RESET_EVENT; Error = %d"), GetLastError())) ; hr = E_FAIL ; DC_QUIT ; } hr = S_OK ; DC_EXIT_POINT: DC_END_FN() ; return hr ; }
/****************************************************************************/ /* ClipOnInitialized */ /****************************************************************************/ DCINT32 DCAPI CClip::ClipOnInitialized(DCVOID) { DC_BEGIN_FN("CClip::ClipOnInitialized") ; HRESULT hr = E_FAIL ; BOOL fthreadStarted = FALSE ;
hr = ClipCreateDataSyncEvents() ; DC_QUIT_ON_FAIL(hr); /************************************************************************/ /* Register a message for communication between the two threads */ /************************************************************************/ _CB.regMsg = WM_USER_CHANGE_THREAD; TRC_NRM((TB, _T("Registered window message %x"), _CB.regMsg)); _CB.pClipThreadData = (PUT_THREAD_DATA) LocalAlloc(LPTR, sizeof(UT_THREAD_DATA)) ; if (NULL == _CB.pClipThreadData) { TRC_ERR((TB, _T("Unable to allocate %d bytes for thread data"), sizeof(UT_THREAD_DATA))) ; hr = E_FAIL ; DC_QUIT ; } if (_pUtObject) { fthreadStarted = _pUtObject->UT_StartThread(ClipStaticMain, _CB.pClipThreadData, this); }
if (!fthreadStarted) { hr = E_FAIL ; DC_QUIT ; }
// If we got to this point, then we succeeded initialized everything
hr = S_OK ; DC_EXIT_POINT:
// On failure be sure to clear out the data syncs.
// we will not connect the virtual channel if the
// data sync are NULL
if (FAILED(hr)) { _GetDataSync[TS_RECEIVE_COMPLETED] = NULL; _GetDataSync[TS_RESET_EVENT] = NULL; } return hr ; } /****************************************************************************/ /* ClipStaticMain */ /****************************************************************************/ DCVOID DCAPI ClipStaticMain(PDCVOID param) { ((CClip*) param)->ClipMain() ; }
/****************************************************************************/ /* ClipOnInit */ /****************************************************************************/ DCINT DCAPI CClip::ClipOnInit(DCVOID) { ATOM registerClassRc; WNDCLASS viewerWindowClass; WNDCLASS tmpWndClass; DCINT allOk = FALSE ;
DC_BEGIN_FN("CClip::ClipOnInit");
/************************************************************************/ /* Create an invisible window which we will register as a clipboard */ /* viewer */ /* Only register if prev instance did not already register the class */ /************************************************************************/ if(!GetClassInfo(_CB.hInst, CB_VIEWER_CLASS, &tmpWndClass)) { TRC_NRM((TB, _T("Register Main Window class, data %p, hInst %p"), &viewerWindowClass, _CB.hInst)); viewerWindowClass.style = 0; viewerWindowClass.lpfnWndProc = StaticClipViewerWndProc; viewerWindowClass.cbClsExtra = 0; viewerWindowClass.cbWndExtra = sizeof(void*); viewerWindowClass.hInstance = _CB.hInst ; viewerWindowClass.hIcon = NULL; viewerWindowClass.hCursor = NULL; viewerWindowClass.hbrBackground = (HBRUSH)GetStockObject(HOLLOW_BRUSH); viewerWindowClass.lpszMenuName = NULL; viewerWindowClass.lpszClassName = CB_VIEWER_CLASS; TRC_DATA_NRM("Register class data", &viewerWindowClass, sizeof(WNDCLASS)); registerClassRc = RegisterClass (&viewerWindowClass); if (registerClassRc == 0) { /****************************************************************/ /* Failed to register CB viewer class */ /****************************************************************/ TRC_ERR((TB, _T("Failed to register Cb Viewer class"))); } TRC_NRM((TB, _T("Registered class"))); }
_CB.viewerWindow = CreateWindowEx( #ifndef OS_WINCE
WS_EX_NOPARENTNOTIFY, #else
0, #endif
CB_VIEWER_CLASS, /* window class name */ _T("CB Viewer Window"), /* window caption */ #ifndef OS_WINCE
WS_OVERLAPPEDWINDOW, /* window style */ #else
WS_OVERLAPPED | WS_CAPTION | WS_SYSMENU | WS_MINIMIZEBOX | WS_MAXIMIZEBOX, #endif
0, /* initial x position */ 0, /* initial y position */ 100, /* initial x size */ 100, /* initial y size */ NULL, /* parent window */ NULL, /* window menu handle */ _CB.hInst, /* program inst handle */ this); /* creation parameters */
/************************************************************************/ /* Check we created the window OK */ /************************************************************************/ if (_CB.viewerWindow == NULL) { TRC_ERR((TB, _T("Failed to create CB Viewer Window"))); DC_QUIT ; } TRC_DBG((TB, _T("Viewer Window handle %p"), _CB.viewerWindow));
#ifdef OS_WINCE
if ((_CB.dataWindow = CECreateCBDataWindow(_CB.hInst)) == NULL) { TRC_ERR((TB, _T("Failed to create CB Data Window"))); DC_QUIT ; } #endif
#ifdef USE_SEMAPHORE
/************************************************************************/ /* Create the permanent TX buffer semaphore */ /************************************************************************/ _CB.txPermBufSem = CreateSemaphore(NULL, 1, 1, NULL); if (_CB.txPermBufSem == NULL) { TRC_ERR((TB, _T("Failed to create semaphore"))); DC_QUIT; } TRC_NRM((TB, _T("Create perm TX buffer sem %p"), _CB.txPermBufSem)); #endif
#ifdef OS_WINCE
gfmtShellPidlArray = RegisterClipboardFormat(CFSTR_SHELLPIDLARRAY); #endif
/************************************************************************/ /* Update the state */ /************************************************************************/ CB_SET_STATE(CB_STATE_INITIALIZED, CB_TRACE_EVENT_CB_CLIPMAIN);
allOk = TRUE ; DC_EXIT_POINT: DC_END_FN();
return allOk;
} /* ClipOnInit */
/****************************************************************************/ /* ClipOnTerm */ /****************************************************************************/ DCBOOL DCAPI CClip::ClipOnTerm(LPVOID pInitHandle) { BOOL fSuccess = FALSE ; BOOL fThreadEnded = FALSE ; DC_BEGIN_FN("CClip::ClipOnTerm");
/************************************************************************/ /* Check the state - if we're still connected, we should disconnect */ /* before shutting down */ /************************************************************************/ ClipCheckState(CB_EVENT_CB_TERM); if (_CB.state != CB_STATE_INITIALIZED) { TRC_ALT((TB, _T("Terminated when not disconnected"))); ClipOnDisconnected(pInitHandle); }
// If we had file cut/copy on, we should clean up after ourselves
if (_CB.fFileCutCopyOn) { SendMessage(_CB.viewerWindow, WM_USER_CLEANUP_ON_TERM, 0, 0); }
/************************************************************************/ /* Destroy the window and unregister the class (the WM_DESTROY handling */ /* will deal with removing the window from the viewer chain) */ /************************************************************************/ TRC_NRM((TB, _T("Destroying CB window..."))); if (!PostMessage(_CB.viewerWindow, WM_CLOSE, 0, 0)) { TRC_SYSTEM_ERROR("DestroyWindow"); }
if (!UnregisterClass(CB_VIEWER_CLASS, _CB.hInst)) { TRC_SYSTEM_ERROR("UnregisterClass"); }
#ifdef OS_WINCE
TRC_NRM((TB, _T("Destroying CB data window..."))); if (!PostMessage(_CB.dataWindow, WM_CLOSE, 0, 0)) { TRC_SYSTEM_ERROR("DestroyWindow"); }
if (!UnregisterClass(CB_DATAWINDOW_CLASS, _CB.hInst)) { TRC_SYSTEM_ERROR("UnregisterClass"); } #endif
if (_pClipData) { // Decrement the reference count of the IDataObject object. At this stage,
// this should cause the reference count to drop to zero and the IDataObject
// object's destructor should be called. This destructor will release the
// reference to this CClipData object, resulting in a reference count of 1.
// Hence the call to Release() below will result in the CClipData destructor
// being called.
_pClipData->TearDown(); _pClipData->Release() ; _pClipData = NULL; } if (_CB.pClipThreadData) { fThreadEnded = _pUtObject->UT_DestroyThread(*_CB.pClipThreadData); if (!fThreadEnded) { TRC_ERR((TB, _T("Error while ending thread"))) ; fSuccess = FALSE; DC_QUIT ; } LocalFree( _CB.pClipThreadData ); _CB.pClipThreadData = NULL; }
if (_pUtObject) { LocalFree(_pUtObject); _pUtObject = NULL; } fSuccess = TRUE ; DC_EXIT_POINT: /************************************************************************/ /* Update our state */ /************************************************************************/ CB_SET_STATE(CB_STATE_NOT_INIT, CB_EVENT_CB_TERM);
DC_END_FN(); return fSuccess ;
} /* ClipOnTerm */
DCVOID DCAPI CClip::ClipMain(DCVOID) { DC_BEGIN_FN("CClip::ClipMain"); MSG msg ;
#ifndef OS_WINCE
HRESULT result = OleInitialize(NULL) ; #else
HRESULT result = CoInitializeEx(NULL, COINIT_MULTITHREADED) ; #endif
if (SUCCEEDED(result)) { if (0 != ClipOnInit()) { TRC_NRM((TB, _T("Start Clip Thread message loop"))) ; while (GetMessage (&msg, NULL, 0, 0)) { TranslateMessage(&msg); DispatchMessage(&msg); } } else { TRC_ERR((TB, _T("Failed initialized clipboard thread"))) ; }
#ifndef OS_WINCE
// We assume OleUninitialize works, as it has no return value
OleUninitialize() ; #else
CoUninitialize() ; #endif
} else { TRC_ERR((TB, _T("OleInitialize Failed"))) ; }
DC_EXIT_POINT: TRC_NRM((TB, _T("Exit Clip Thread message loop"))) ; DC_END_FN(); } /****************************************************************************/ /* ClipOnConnected */ /****************************************************************************/ VOID DCINTERNAL CClip::ClipOnConnected(LPVOID pInitHandle) { UINT rc;
DC_BEGIN_FN("CClip::ClipOnConnected");
if (!IsDataSyncReady()) { TRC_ERR((TB, _T("Data Sync not ready"))); DC_QUIT; } _CB.fDrivesRedirected = _pVCMgr->GetInitData()->fEnableRedirectDrives; _CB.fFileCutCopyOn = _CB.fDrivesRedirected; /************************************************************************/ /* Open our channel */ /************************************************************************/ TRC_NRM((TB, _T("Entry points are at %p"), &(_CB.channelEP))); TRC_NRM((TB, _T("Call ChannelOpen at %p"), _CB.channelEP.pVirtualChannelOpenEx)); rc = _CB.channelEP.pVirtualChannelOpenEx(pInitHandle, &_CB.channelHandle, CLIP_CHANNEL, (PCHANNEL_OPEN_EVENT_EX_FN)MakeProcInstance( (FARPROC)ClipOpenEventFnEx, _CB.hInst) );
TRC_NRM((TB, _T("Opened %s: %ld, rc %d"), CLIP_CHANNEL,_CB.channelHandle, rc));
DC_EXIT_POINT: DC_END_FN(); return; }
/****************************************************************************/ /* ClipOnConnected */ /****************************************************************************/ VOID DCINTERNAL CClip::ClipOnMonitorReady(VOID) { DC_BEGIN_FN("CClip::ClipOnMonitorReady");
/************************************************************************/ /* The monitor has woken up. Check the state */ /************************************************************************/ CB_CHECK_STATE(CB_EVENT_CB_ENABLE);
// Update the state
CB_SET_STATE(CB_STATE_ENABLED, CB_TRACE_EVENT_CB_MONITOR_READY);
// Get the temp directory, and send it off to the server
// if it fails, then we turn off File Cut/Copy
_CB.fFileCutCopyOn = ClipSetAndSendTempDirectory() ; // We now send the list of clipboard formats we have at this end to the
// server by faking a draw of the local clipboard. We pass TRUE to
// force a send because the server needs to have the value of our
// TS_CB_ASCII_NAMES flag (RAID #313251).
ClipDrawClipboard(TRUE);
DC_EXIT_POINT: DC_END_FN(); return; }
/****************************************************************************/ /* ClipOnDisconnected */ /****************************************************************************/ VOID DCINTERNAL CClip::ClipOnDisconnected(LPVOID pInitHandle) { DC_BEGIN_FN("CClip::ClipOnDisconnected");
DC_IGNORE_PARAMETER(pInitHandle);
//
// Reset the clipboard thread
// if it waits for data
//
if ( NULL != _GetDataSync[TS_RESET_EVENT] ) { SetEvent( _GetDataSync[TS_RESET_EVENT] ); } /************************************************************************/ /* Check the state */ /************************************************************************/ ClipCheckState(CB_EVENT_CB_DISABLE);
/************************************************************************/ /* If we are the local clipboard owner, then we must empty it - once */ /* disconnected, we won't be able to satisfy any further format */ /* requests. Note that we are still the local CB owner even if we are */ /* waiting on some data from the server */ /************************************************************************/ if (_CB.state == CB_STATE_LOCAL_CB_OWNER) { TRC_NRM((TB, _T("Disable received while local CB owner")));
/********************************************************************/ /* Open the clipboard if needed */ /********************************************************************/ if ((!_CB.rcvOpen) && !OpenClipboard(NULL)) { TRC_ERR((TB, _T("Failed to open CB when emptying required"))); } else { /****************************************************************/ /* It was/is open */ /****************************************************************/ TRC_NRM((TB, _T("CB opened"))); _CB.rcvOpen = TRUE;
/****************************************************************/ /* Empty it */ /****************************************************************/ if (!EmptyClipboard()) { TRC_SYSTEM_ERROR("EmptyClipboard"); } } } /************************************************************************/ /* If there is pending format data, we should SetClipboardData to NULL */ /* so that app can close the clipboard */ /************************************************************************/ else if (_CB.state == CB_STATE_PENDING_FORMAT_DATA_RSP) { TRC_NRM((TB, _T("Pending format data: setting clipboard data to NULL"))); SetClipboardData(_CB.pendingClientID, NULL); }
/************************************************************************/ /* Ensure that we close the local CB */ /************************************************************************/ if (_CB.rcvOpen) { _CB.rcvOpen = FALSE; if (!CloseClipboard()) { TRC_SYSTEM_ERROR("CloseClipboard"); } TRC_NRM((TB, _T("CB closed"))); }
/************************************************************************/ /* If we were sending or receiving data, unlock and free the buffers as */ /* required */ /************************************************************************/ if (_CB.rxpBuffer) { TRC_NRM((TB, _T("Freeing recieve buffer %p"), _CB.rxpBuffer)); ClipFree(_CB.rxpBuffer); _CB.rxpBuffer = NULL; }
DC_EXIT_POINT: /************************************************************************/ /* Update our state */ /************************************************************************/ CB_SET_STATE(CB_STATE_INITIALIZED, CB_TRACE_EVENT_CB_DISCONNECT);
DC_END_FN(); return; } /* ClipOnDisconnected */
/****************************************************************************/ // ClipOnDataReceived
/****************************************************************************/ DCVOID DCAPI CClip::ClipOnDataReceived(LPVOID pData, UINT32 dataLength, UINT32 totalLength, UINT32 dataFlags) { PTS_CLIP_PDU pClipPDU; DCBOOL freeTheBuffer = TRUE; DC_BEGIN_FN("CClip::ClipOnDataReceived");
//
// Verify that there is enough data to make up or create a clip PDU header.
//
if (totalLength < sizeof(TS_CLIP_PDU)) { TRC_ERR((TB, _T("Not enough data to form a clip header."))); _CB.channelEP.pVirtualChannelCloseEx(_CB.initHandle, _CB.channelHandle); DC_QUIT; }
/************************************************************************/ /* Check we're all up and running */ /************************************************************************/ if (_CB.state == CB_STATE_NOT_INIT) { pClipPDU = (PTS_CLIP_PDU)pData; TRC_ERR((TB, _T("Clip message type %hd received when not init"), pClipPDU->msgType)); DC_QUIT; }
/************************************************************************/ /* Special case: if the entire message fits in one chunk, there's no */ /* need to copy it */ /************************************************************************/ if (CHANNEL_FLAG_ONLY == (dataFlags & CHANNEL_FLAG_ONLY)) { TRC_DBG((TB, _T("Single chunk message"))); pClipPDU = (PTS_CLIP_PDU)pData; } else {
/********************************************************************/ /* It's a segmented message - rebuild it */ /********************************************************************/ if (dataFlags & CHANNEL_FLAG_FIRST) { /****************************************************************/ /* If it's the first segment, allocate a buffer to rebuild the */ /* message in. */ /****************************************************************/ TRC_DBG((TB, _T("Alloc %ld-byte buffer"), totalLength)); _CB.rxpBuffer = (HPDCUINT8)ClipAlloc(totalLength); if (_CB.rxpBuffer == NULL) { /************************************************************/ /* Failed to alloc a buffer. We have to do something, */ /* otherwise the Client app can hang waiting for data. */ /* Fake a failure response. */ /************************************************************/ TRC_ERR((TB, _T("Failed to alloc %ld-byte buffer"), totalLength)); pClipPDU = (PTS_CLIP_PDU)pData; pClipPDU->msgFlags = TS_CB_RESPONSE_FAIL; pClipPDU->dataLen = 0; dataFlags |= CHANNEL_FLAG_LAST;
/************************************************************/ /* Now handle it as if it were complete. Subsequent chunks */ /* will be discarded. */ /************************************************************/ goto MESSAGE_COMPLETE; }
_CB.rxpBufferCurrent = _CB.rxpBuffer; _CB.rxBufferLen = totalLength; _CB.rxBufferLeft = totalLength; }
/********************************************************************/ /* Check that we have a buffer to copy into */ /********************************************************************/ if (_CB.rxpBuffer == NULL) { TRC_NRM((TB, _T("Previous buffer alloc failure - discard data"))); DC_QUIT; }
/********************************************************************/ /* Check that there is enough room */ /********************************************************************/ if (dataLength > _CB.rxBufferLeft) { TRC_ERR((TB, _T("Not enough room in rx buffer: need/got %ld/%ld"), dataLength, _CB.rxBufferLeft)); DC_QUIT; }
/********************************************************************/ /* Copy the data */ /********************************************************************/ TRC_DBG((TB, _T("Copy %ld bytes from %p to %p"), dataLength, pData, _CB.rxpBufferCurrent)); ClipMemcpy(_CB.rxpBufferCurrent, pData, dataLength); _CB.rxpBufferCurrent += dataLength; _CB.rxBufferLeft -= dataLength; TRC_DBG((TB, _T("Next copy to %p, left %ld"), _CB.rxpBufferCurrent, _CB.rxBufferLeft));
/********************************************************************/ /* If this wasn't the last chunk, there's nothing more to do */ /********************************************************************/ if (!(dataFlags & CHANNEL_FLAG_LAST)) { TRC_DBG((TB, _T("Not last chunk"))); freeTheBuffer = FALSE; DC_QUIT; }
/********************************************************************/ /* Check we got the entire message */ /********************************************************************/ if (_CB.rxBufferLeft != 0) { TRC_ERR((TB, _T("Incomplete data, expected/got %ld/%ld"), _CB.rxBufferLen, _CB.rxBufferLen - _CB.rxBufferLeft)); DC_QUIT; }
pClipPDU = (PTS_CLIP_PDU)(_CB.rxpBuffer); }
/************************************************************************/ /* We allow monitor ready thru because that's what put us in the call! */ /************************************************************************/ if ((_CB.state == CB_STATE_INITIALIZED) && (pClipPDU->msgType != TS_CB_MONITOR_READY)) { TRC_ERR((TB, _T("Clip message type %hd received when not in call"), pClipPDU->msgType)); DC_QUIT; }
/************************************************************************/ /* now switch on the packet type */ /************************************************************************/ MESSAGE_COMPLETE: TRC_NRM((TB, _T("Processing msg type %hd when in state %d"), pClipPDU->msgType, _CB.state)); TRC_DATA_DBG("pdu", pClipPDU, (DCUINT)pClipPDU->dataLen + sizeof(TS_CLIP_PDU));
//
// Verify that the data in the dataLen in pClipPDU is consistent with the
// length given in the dataLength parameter.
//
if (pClipPDU->dataLen > totalLength - sizeof(TS_CLIP_PDU)) { TRC_ERR((TB, _T("Length from network differs from published length."))); _CB.channelEP.pVirtualChannelCloseEx(_CB.initHandle, _CB.channelHandle); DC_QUIT; }
switch (pClipPDU->msgType) { case TS_CB_MONITOR_READY: { /****************************************************************/ /* The monitor has initialised - we can complete our start up */ /* now. */ /****************************************************************/ TRC_NRM((TB, _T("rx monitor ready"))); TRC_ASSERT( NULL != _GetDataSync[TS_RESET_EVENT], (TB,_T("data sync is NULL"))); SetEvent(_GetDataSync[TS_RESET_EVENT]) ;
ClipOnMonitorReady(); } break;
case TS_CB_FORMAT_LIST: { /****************************************************************/ // The server has some new formats for us.
/****************************************************************/ TRC_NRM((TB, _T("Rx Format list"))); // Free the Clipboard thread, if locked
TRC_ASSERT( NULL != _GetDataSync[TS_RESET_EVENT], (TB,_T("data sync is NULL"))); SetEvent(_GetDataSync[TS_RESET_EVENT]) ; ClipDecoupleToClip(pClipPDU) ; } break;
case TS_CB_FORMAT_LIST_RESPONSE: { /****************************************************************/ // The server has received our new formats.
/****************************************************************/ TRC_NRM((TB, _T("Rx Format list Rsp"))); ClipOnFormatListResponse(pClipPDU); } break;
case TS_CB_FORMAT_DATA_REQUEST: { /****************************************************************/ // An app on the server wants to paste one of the formats from
// our clipboard.
/****************************************************************/ TRC_NRM((TB, _T("Rx Data Request"))); ClipOnFormatRequest(pClipPDU); } break;
case TS_CB_FORMAT_DATA_RESPONSE: { /****************************************************************/ // Here's some format data for us
/****************************************************************/ TRC_NRM((TB, _T("Rx Format Data rsp in state %d with flags %02x"), _CB.state, pClipPDU->msgFlags)); ClipOnFormatDataComplete(pClipPDU); } break;
default: { /****************************************************************/ /* Don't know what this one is! */ /****************************************************************/ TRC_ERR((TB, _T("Unknown clip message type %hd"), pClipPDU->msgType)); } break; }
DC_EXIT_POINT: /************************************************************************/ /* Maybe free the receive buffer */ /************************************************************************/ if (freeTheBuffer && _CB.rxpBuffer) { TRC_NRM((TB, _T("Free receive buffer"))); ClipFree(_CB.rxpBuffer); _CB.rxpBuffer = NULL; } DC_END_FN(); return;
} /* CB_OnPacketReceived */
DCVOID DCAPI CClip::ClipDecoupleToClip (PTS_CLIP_PDU pData) { ULONG cbPDU ; DC_BEGIN_FN("CClip::ClipDecoupleToClip"); // Allocate space for the PDU and its data, and then copy it
cbPDU = sizeof(TS_CLIP_PDU) + pData->dataLen ; PDCVOID newBuffer = LocalAlloc(LPTR, cbPDU) ;
if (NULL != newBuffer) DC_MEMCPY(newBuffer, pData, cbPDU) ; else return;
TRC_NRM((TB, _T("Pass %d bytes to clipboard thread"), cbPDU)); PostMessage(_CB.viewerWindow, _CB.regMsg, cbPDU, (LPARAM) newBuffer);
DC_END_FN(); }
/****************************************************************************/ /* Open Event callback */ /****************************************************************************/ VOID VCAPITYPE VCEXPORT DCLOADDS CClip::ClipOpenEventFnEx(LPVOID lpUserParam, DWORD openHandle, UINT event, LPVOID pData, UINT32 dataLength, UINT32 totalLength, UINT32 dataFlags) { DC_BEGIN_FN("CClip::ClipOpenEventFnEx"); TRC_ASSERT(((VCManager*)lpUserParam != NULL), (TB, _T("lpUserParam is NULL, no instance data"))); if(!lpUserParam) { return; }
CClip* pClip = ((VCManager*)lpUserParam)->GetClip(); TRC_ASSERT((pClip != NULL), (TB, _T("pClip is NULL in ClipOpenEventFnEx"))); if(!pClip) { return; } pClip->ClipInternalOpenEventFn(openHandle, event, pData, dataLength, totalLength, dataFlags); DC_END_FN(); return; }
VOID VCAPITYPE VCEXPORT DCLOADDS CClip::ClipInternalOpenEventFn(DWORD openHandle, UINT event, LPVOID pData, UINT32 dataLength, UINT32 totalLength, UINT32 dataFlags) { DC_BEGIN_FN("CClip::ClipOpenEventFn"); DC_IGNORE_PARAMETER(openHandle) switch (event) { /********************************************************************/ /* Data received from Server */ /********************************************************************/ case CHANNEL_EVENT_DATA_RECEIVED: { TRC_NRM((TB, _T("Data in: handle %ld, len %ld (of %ld), flags %lx"), openHandle, dataLength, totalLength, dataFlags)) ; TRC_DATA_NRM("Data", pData, (DCUINT)dataLength) ; ClipOnDataReceived(pData, dataLength, totalLength, dataFlags) ; } break;
/********************************************************************/ /* Write operation completed */ /********************************************************************/ case CHANNEL_EVENT_WRITE_COMPLETE: case CHANNEL_EVENT_WRITE_CANCELLED: { TRC_NRM((TB, _T("Write %s %p"), event == CHANNEL_EVENT_WRITE_COMPLETE ? "complete" : "cancelled", pData)); ClipOnWriteComplete(pData); } break;
/********************************************************************/ /* Er, that didn't happen, did it? */ /********************************************************************/ default: { TRC_ERR((TB, _T("Unexpected event %d"), event)); } break; }
DC_END_FN(); return; }
/****************************************************************************/ /* Init Event callback */ /****************************************************************************/ VOID VCAPITYPE VCEXPORT CClip::ClipInitEventFn(LPVOID pInitHandle, UINT event, LPVOID pData, UINT dataLength) { DC_BEGIN_FN("CClip::ClipInitEventFn");
DC_IGNORE_PARAMETER(dataLength) DC_IGNORE_PARAMETER(pData)
switch (event) { /********************************************************************/ /* Client initialized (no data) */ /********************************************************************/ case CHANNEL_EVENT_INITIALIZED: { TRC_NRM((TB, _T("CHANNEL_EVENT_INITIALIZED: %p"), pInitHandle)); ClipOnInitialized(); } break;
/********************************************************************/ /* Connection established (data = name of Server) */ /********************************************************************/ case CHANNEL_EVENT_CONNECTED: { TRC_NRM((TB, _T("CHANNEL_EVENT_CONNECTED: %p, Server %s"), pInitHandle, pData));
if (IsDataSyncReady()) { ClipOnConnected(pInitHandle); } else { TRC_ERR((TB,_T("data sync not ready on CHANNEL_EVENT_CONNECTED"))); } } break;
/********************************************************************/ /* Connection established with old Server, so no channel support */ /********************************************************************/ case CHANNEL_EVENT_V1_CONNECTED: { TRC_NRM((TB, _T("CHANNEL_EVENT_V1_CONNECTED: %p, Server %s"), pInitHandle, pData)); } break;
/********************************************************************/ /* Connection ended (no data) */ /********************************************************************/ case CHANNEL_EVENT_DISCONNECTED: { TRC_NRM((TB, _T("CHANNEL_EVENT_DISCONNECTED: %p"), pInitHandle)); ClipOnDisconnected(pInitHandle); } break;
/********************************************************************/ /* Client terminated (no data) */ /********************************************************************/ case CHANNEL_EVENT_TERMINATED: { TRC_NRM((TB, _T("CHANNEL_EVENT_TERMINATED: %p"), pInitHandle)); ClipOnTerm(pInitHandle); } break;
/********************************************************************/ /* Unknown event */ /********************************************************************/ default: { TRC_ERR((TB, _T("Unkown channel event %d: %p"), event, pInitHandle)); } break; }
DC_END_FN(); return; }
/****************************************************************************/ /* Clip window proc */ /****************************************************************************/ LRESULT CALLBACK DCEXPORT DCLOADDS CClip::StaticClipViewerWndProc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam) { CClip* pClip = (CClip*)GetWindowLongPtr(hwnd, GWLP_USERDATA); if(WM_CREATE == message) { //pull out the this pointer and stuff it in the window class
LPCREATESTRUCT lpcs = (LPCREATESTRUCT) lParam; pClip = (CClip*)lpcs->lpCreateParams;
SetWindowLongPtr( hwnd, GWLP_USERDATA, (LONG_PTR)pClip); } //
// Delegate the message to the appropriate instance
//
if(pClip) { return pClip->ClipViewerWndProc(hwnd, message, wParam, lParam); } else { return DefWindowProc(hwnd, message, wParam, lParam); } }
LRESULT CALLBACK DCEXPORT DCLOADDS CClip::ClipViewerWndProc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam) { PTS_CLIP_PDU pClipPDU = NULL; #ifndef OS_WINCE
DCUINT32 pduLen; DCUINT32 dataLen; PDCUINT32 pFormatID; MSG msg; #endif
DCBOOL drawRc; DCBOOL gotRsp = FALSE; LRESULT rc = 0; HRESULT hr ;
DC_BEGIN_FN("CClip::ClipViewerWndProc");
// We first handle messages from the other thread
if (message == _CB.regMsg) { pClipPDU = (PTS_CLIP_PDU)lParam; switch (pClipPDU->msgType) { case TS_CB_FORMAT_LIST: { TRC_NRM((TB, _T("TS_CB_FORMAT_LIST received"))); ClipOnFormatList(pClipPDU); } break;
default: { TRC_ERR((TB, _T("Unknown event %d"), pClipPDU->msgType)); } break; }
TRC_NRM((TB, _T("Freeing processed PDU"))); LocalFree(pClipPDU);
DC_QUIT; } else if (message == WM_USER_CLEANUP_ON_TERM) { TRC_NRM((TB, _T("Cleanup temp directory")));
if (0 != ClipCleanTempPath()) { TRC_NRM((TB, _T("Failed while trying to clean temp directory"))) ; }
DC_QUIT; } switch (message) { case WM_CREATE: { /****************************************************************/ /* We've been created - check the state */ /****************************************************************/ CB_CHECK_STATE(CB_EVENT_WM_CREATE);
#ifndef OS_WINCE
/****************************************************************/ /* Add the window to the clipboard viewer chain. */ /****************************************************************/ _CB.nextViewer = SetClipboardViewer(hwnd); #else
ghwndClip = hwnd; InitializeCriticalSection(&gcsDataObj); #endif
} break;
case WM_DESTROY: { /****************************************************************/ /* We're being destroyed - check the state */ /****************************************************************/ CB_CHECK_STATE(CB_EVENT_WM_DESTROY);
#ifndef OS_WINCE
/****************************************************************/ /* Remove ourselves from the CB Chain */ /****************************************************************/ ChangeClipboardChain(hwnd, _CB.nextViewer); #endif
#ifdef OS_WINCE
ghwndClip = NULL; EnterCriticalSection(&gcsDataObj); if (gpDataObj) { gpDataObj->Release(); gpDataObj = NULL; } LeaveCriticalSection(&gcsDataObj); DeleteCriticalSection(&gcsDataObj);
if (ghCeshellDll) { pfnEDList_Uninitialize(); FreeLibrary(ghCeshellDll); } #endif
_CB.nextViewer = NULL; PostQuitMessage(0); } break;
case WM_CLOSE: { DestroyWindow(hwnd); } break;
#ifndef OS_WINCE
case WM_CHANGECBCHAIN: { /****************************************************************/ /* The CB viewer chain is chainging - check the state */ /****************************************************************/ CB_CHECK_STATE(CB_EVENT_WM_CHANGECBCHAIN);
/****************************************************************/ /* If the next window is closing, repair the chain. */ /****************************************************************/ if ((HWND)wParam == _CB.nextViewer) { _CB.nextViewer = (HWND) lParam; } else if (_CB.nextViewer != NULL) { /************************************************************/ /* pass the message to the next link. */ /************************************************************/ SendMessage(_CB.nextViewer, message, wParam, lParam); }
} break; #endif
case WM_DRAWCLIPBOARD: { /****************************************************************/ /* The local clipboard contents have been changed. Check the */ /* state */ /****************************************************************/ if (ClipCheckState(CB_EVENT_WM_DRAWCLIPBOARD) != CB_TABLE_OK) { TRC_NRM((TB, _T("dropping drawcb - pass on to next viewer"))); /************************************************************/ /* check for state pending format list response */ /************************************************************/ if (_CB.state == CB_STATE_PENDING_FORMAT_LIST_RSP) { TRC_ALT((TB, _T("got a draw while processing last"))); /********************************************************/ /* we were still waiting for the server to acknowledge */ /* the last format list when we got a new one - when it */ /* does, we'll have to to send it the new one. */ /********************************************************/ _CB.moreToDo = TRUE; }
if (_CB.nextViewer != NULL) { /********************************************************/ /* But not before we pass the message to the next link. */ /********************************************************/ SendMessage(_CB.nextViewer, message, wParam, lParam); } break; }
/****************************************************************/ /* If it wasn't us that generated this change, then notify the */ /* remote */ /****************************************************************/ TRC_NRM((TB, _T("CB contents have changed..."))); drawRc = FALSE; _CB.moreToDo = FALSE; #ifndef OS_WINCE
LPDATAOBJECT pIDataObject = NULL;
if (_pClipData != NULL) { _pClipData->QueryInterface(IID_IDataObject, (PPVOID) &pIDataObject) ; hr = OleIsCurrentClipboard(pIDataObject) ; #else
hr = S_FALSE; #endif
if ((S_FALSE == hr)) { TRC_NRM((TB, _T("...and it wasn't us"))); #ifdef OS_WINCE
if (_CB.fFileCutCopyOn) DeleteDirectory(_CB.baseTempDirW);//Temp space is at a premium on CE. So delete any copied files now
#endif
drawRc = ClipDrawClipboard(TRUE); } else { TRC_NRM((TB, _T("...and it was us - ignoring"))); } #ifndef OS_WINCE
}
/****************************************************************/ /* Maybe pass on the draw clipboard message? */ /****************************************************************/ if (_CB.nextViewer != NULL) { TRC_NRM((TB, _T("Notify next viewer"))); SendMessage(_CB.nextViewer, message, wParam, lParam); } if (pIDataObject) { pIDataObject->Release(); } #endif
} break;
case WM_EMPTY_CLIPBOARD: { /****************************************************************/ /* Open the clipboard if needed */ /****************************************************************/ if ((!_CB.clipOpen) && !OpenClipboard(NULL)) { UINT count = (DCUINT) wParam;
TRC_ERR((TB, _T("Failed to open CB when emptying required")));
// Unfortunately, we are in the racing condition with the app that
// has the clipboard open. So, we need to keep trying until the app
// closes the clipboard.
if (count++ < 10) {
#ifdef OS_WIN32
Sleep(0); #endif
PostMessage(_CB.viewerWindow, WM_EMPTY_CLIPBOARD, count, 0); }
break; } else { /************************************************************/ /* It was/is open */ /************************************************************/ TRC_NRM((TB, _T("CB opened")));
_CB.clipOpen = TRUE;
/************************************************************/ /* Empty it */ /************************************************************/ if (!EmptyClipboard()) { TRC_SYSTEM_ERROR("EmptyClipboard"); }
/************************************************************/ /* update the state */ /************************************************************/ CB_SET_STATE(CB_STATE_LOCAL_CB_OWNER, CB_TRACE_EVENT_WM_EMPTY_CLIPBOARD); }
/****************************************************************/ /* Ensure that we close the local CB */ /****************************************************************/ if (_CB.clipOpen) { _CB.clipOpen = FALSE; if (!CloseClipboard()) { TRC_SYSTEM_ERROR("CloseClipboard"); } TRC_NRM((TB, _T("CB closed"))); } } break; case WM_CLOSE_CLIPBOARD: { _CB.pendingClose = FALSE; TRC_DBG((TB, _T("Maybe close clipboard on WM_CLOSE_CLIPBOARD"))); if (_CB.clipOpen) { TRC_NRM((TB, _T("Closing clipboard on WM_CLOSE_CLIPBOARD"))); _CB.clipOpen = FALSE; if (!CloseClipboard()) { TRC_SYSTEM_ERROR("CloseClipboard"); } TRC_DBG((TB, _T("CB closed on WM_CLOSE_CLIPBOARD"))); } } break;
default: { /****************************************************************/ /* Ignore all other messages. */ /****************************************************************/ rc = DefWindowProc(hwnd, message, wParam, lParam); } break; }
DC_EXIT_POINT: DC_END_FN(); return(rc); } /* ClipViewerWndProc */
/****************************************************************************/ /* ClipChannelEntry - called from VirtualChannelEntry in vcint.cpp */ /****************************************************************************/ BOOL VCAPITYPE VCEXPORT CClip::ClipChannelEntry(PCHANNEL_ENTRY_POINTS_EX pEntryPoints) { DC_BEGIN_FN("CClip::ClipChannelEntry");
TRC_NRM((TB, _T("Size %ld, Init %p, Open %p, Close %p, Write %p"), pEntryPoints->cbSize, pEntryPoints->pVirtualChannelInitEx, pEntryPoints->pVirtualChannelOpenEx, pEntryPoints->pVirtualChannelCloseEx, pEntryPoints->pVirtualChannelWriteEx));
/************************************************************************/ /* Save the function pointers -- the memory pointed to by pEntryPoints */ /* is only valid for the duration of this call. */ /************************************************************************/ DC_MEMCPY(&(_CB.channelEP), pEntryPoints, sizeof(CHANNEL_ENTRY_POINTS_EX)); TRC_NRM((TB, _T("Save entry points %p at address %p"), pEntryPoints, &(_CB.channelEP)));
DC_END_FN(); return TRUE; }
DCINT DCAPI CClip::ClipGetData (DCUINT cfFormat) { PTS_CLIP_PDU pClipPDU = NULL; DCUINT32 pduLen; DCUINT32 dataLen; PDCUINT32 pFormatID; BOOL success = 0 ; DC_BEGIN_FN("CClip::ClipGetData"); CB_CHECK_STATE(CB_EVENT_WM_RENDERFORMAT); /****************************************************************/ /* and record the requested format */ /****************************************************************/ _CB.pendingClientID = cfFormat ; _CB.pendingServerID = ClipRemoteFormatFromLocalID (_CB.pendingClientID); if (!_CB.pendingServerID) { TRC_NRM((TB, _T("Client format %d not supported/found. Failing"), _CB.pendingClientID)) ; DC_QUIT ; } TRC_NRM((TB, _T("Render format received for %d (server ID %d)"), _CB.pendingClientID, _CB.pendingServerID)); dataLen = sizeof(DCUINT32); pduLen = sizeof(TS_CLIP_PDU) + dataLen; // We can use the permanent send buffer for this
TRC_NRM((TB, _T("Get perm TX buffer"))); pClipPDU = ClipGetPermBuf();
// Fill in the PDU
DC_MEMSET(pClipPDU, 0, sizeof(*pClipPDU)); pClipPDU->msgType = TS_CB_FORMAT_DATA_REQUEST; pClipPDU->dataLen = dataLen; pFormatID = (PDCUINT32)(pClipPDU->data); *pFormatID = (DCUINT32)_CB.pendingServerID; // Send the PDU
TRC_NRM((TB, _T("Sending format data request"))); success = (_CB.channelEP.pVirtualChannelWriteEx (_CB.initHandle, _CB.channelHandle, pClipPDU, pduLen, pClipPDU) == CHANNEL_RC_OK) ; if (!success) { TRC_ERR((TB, _T("Failed VC write: setting clip data to NULL"))); ClipFreeBuf((PDCUINT8)pClipPDU); SetClipboardData(_CB.pendingClientID, NULL); // Yes, the exit point is just below, but it may not be always be
DC_QUIT ; } DC_EXIT_POINT: // Update the state
if (success) CB_SET_STATE(CB_STATE_PENDING_FORMAT_DATA_RSP, CB_EVENT_WM_RENDERFORMAT);
DC_END_FN(); return success ; }
#ifdef OS_WINCE
DCVOID CClip::ClipFixupRichTextFormats(UINT uRtf1, UINT uRtf2) { DC_BEGIN_FN("CClip::ClipFixupRichTextFormats"); if (uRtf1 == 0xffffffff) { TRC_ASSERT((uRtf2 == 0xffffffff), (TB, _T("uRtf2 is invalid"))); return; }
if (uRtf2 == 0xffffffff) { _CB.idMap[uRtf1].clientID = RegisterClipboardFormat(CFSTR_RTF); SetClipboardData(_CB.idMap[uRtf1].clientID, NULL); TRC_DBG((TB, _T("Adding format '%s', server ID %d, client ID %d"), CFSTR_RTF, _CB.idMap[uRtf1].serverID, _CB.idMap[uRtf1].clientID)); return; }
DCTCHAR *pFormat1 = CFSTR_RTF, *pFormat2 = CFSTR_RTFNOOBJECTS; if (_CB.idMap[uRtf1].serverID > _CB.idMap[uRtf2].serverID) { pFormat1 = CFSTR_RTFNOOBJECTS; pFormat2 = CFSTR_RTF; }
_CB.idMap[uRtf1].clientID = RegisterClipboardFormat(pFormat1); _CB.idMap[uRtf2].clientID = RegisterClipboardFormat(pFormat2);
TRC_DBG((TB, _T("Adding format '%s', server ID %d, client ID %d"), CFSTR_RTF, _CB.idMap[uRtf1].serverID, _CB.idMap[uRtf1].clientID)); SetClipboardData(_CB.idMap[uRtf1].clientID, NULL);
TRC_DBG((TB, _T("Adding format '%s', server ID %d, client ID %d"), CFSTR_RTFNOOBJECTS, _CB.idMap[uRtf2].serverID, _CB.idMap[uRtf2].clientID)); SetClipboardData(_CB.idMap[uRtf2].clientID, NULL);
DC_END_FN(); } #endif //OS_WINCE
CClipData::CClipData(PCClip pClip) { DWORD status = ERROR_SUCCESS;
DC_BEGIN_FN("CClipData::CClipData") ;
_pClip = pClip ; _cRef = 0 ; _pImpIDataObject = NULL ;
//
// Initialize the single instance critical
// section lock. This is used to ensure only one
// thread is accessing _pImpIDataObject at the time
//
//
__try { InitializeCriticalSection(&_csLock); } __except(EXCEPTION_EXECUTE_HANDLER) { status = GetExceptionCode(); }
if(ERROR_SUCCESS == status) { _fLockInitialized = TRUE; } else { _fLockInitialized = FALSE; TRC_ERR((TB,_T("InitializeCriticalSection failed 0x%x."),status)); }
DC_END_FN(); }
//
// Call Release() on the contained IDataObject implementation. This is necessary because
// SetNumFormats() calls AddRef() and if we are terminating, then there must be a way
// to balance this AddRef() so that the circular reference between CClipData and
// CImpIDataObject will be broken.
//
void CClipData::TearDown() { if (_pImpIDataObject != NULL) { _pImpIDataObject->Release(); _pImpIDataObject = NULL; } }
CClipData::~CClipData(void) { DC_BEGIN_FN("CClipData::~CClipData");
if(_fLockInitialized) { DeleteCriticalSection(&_csLock); }
DC_END_FN(); }
HRESULT DCINTERNAL CClipData::SetNumFormats(ULONG numFormats) { HRESULT hr = S_OK;
DC_BEGIN_FN("CClipData::SetNumFormats");
if (_fLockInitialized) { EnterCriticalSection(&_csLock); if (_pImpIDataObject) { _pImpIDataObject->Release(); _pImpIDataObject = NULL; } _pImpIDataObject = new CImpIDataObject(this) ; if (_pImpIDataObject == NULL) { TRC_ERR((TB, _T("Unable to create IDataObject"))); hr = E_OUTOFMEMORY; DC_QUIT; } else { _pImpIDataObject->AddRef() ; hr = _pImpIDataObject->Init(numFormats); DC_QUIT_ON_FAIL(hr); } LeaveCriticalSection(&_csLock); }
DC_EXIT_POINT: DC_END_FN(); return hr; }
DCVOID CClipData::SetClipData(HGLOBAL hGlobal, DCUINT clipType) { DC_BEGIN_FN("CClipData::SetClipData");
if (_fLockInitialized) { EnterCriticalSection(&_csLock); if (_pImpIDataObject != NULL) { _pImpIDataObject->SetClipData(hGlobal, clipType) ; } LeaveCriticalSection(&_csLock); }
DC_END_FN(); }
STDMETHODIMP CClipData::QueryInterface(REFIID riid, PPVOID ppv) { DC_BEGIN_FN("CClipData::QueryInterface");
//set ppv to NULL just in case the interface isn't found
*ppv=NULL;
if (IID_IUnknown==riid) { *ppv=this; //AddRef any interface we'll return.
((LPUNKNOWN)*ppv)->AddRef(); } if (IID_IDataObject==riid) { if (_fLockInitialized) { EnterCriticalSection(&_csLock); *ppv=_pImpIDataObject ;
if (_pImpIDataObject != NULL) { //AddRef any interface we'll return.
((LPUNKNOWN)*ppv)->AddRef(); }
LeaveCriticalSection(&_csLock); } } if (NULL==*ppv) return ResultFromScode(E_NOINTERFACE);
DC_END_FN(); return NOERROR; }
STDMETHODIMP_(ULONG) CClipData::AddRef(void) { DC_BEGIN_FN("CClipData::AddRef"); DC_END_FN(); return InterlockedIncrement(&_cRef); }
STDMETHODIMP_(ULONG) CClipData::Release(void) { LONG cRef; DC_BEGIN_FN("CClipData::Release");
cRef = InterlockedDecrement(&_cRef);
if (cRef == 0) { delete this; }
DC_END_FN(); return cRef; }
CImpIDataObject::CImpIDataObject(LPUNKNOWN lpUnk) { #ifndef OS_WINCE
byte i ; #endif
DC_BEGIN_FN("CImpIDataObject::CImplDataObject") ;
_numFormats = 0 ; _maxNumFormats = 0 ; _cRef = 0 ; _pUnkOuter = lpUnk ; if (_pUnkOuter) { _pUnkOuter->AddRef(); } _pFormats = NULL ; _pSTGMEDIUM = NULL ; _lastFormatRequested = 0 ; _cfDropEffect = (CLIPFORMAT) RegisterClipboardFormat(CFSTR_PREFERREDDROPEFFECT) ;
DC_END_FN(); }
HRESULT CImpIDataObject::Init(ULONG numFormats) { DC_BEGIN_FN("CImpIDataObject::Init") ; HRESULT hr = S_OK; _maxNumFormats = numFormats ;
// Allocate space for the formats only
if (_pFormats) { LocalFree(_pFormats); } _pFormats = (LPFORMATETC) LocalAlloc(LPTR,_maxNumFormats*sizeof(FORMATETC)) ; if (NULL == _pFormats) { TRC_ERR((TB,_T("failed to allocate _pFormats"))); hr = E_OUTOFMEMORY; DC_QUIT; } if (_pSTGMEDIUM) { LocalFree(_pSTGMEDIUM); } _pSTGMEDIUM = (STGMEDIUM*) LocalAlloc(LPTR, sizeof(STGMEDIUM)) ; if (NULL == _pSTGMEDIUM) { TRC_ERR((TB,_T("Failed to allocate STGMEDIUM"))); hr = E_OUTOFMEMORY; DC_QUIT; } _pSTGMEDIUM->tymed = TYMED_HGLOBAL ; _pSTGMEDIUM->pUnkForRelease = NULL ; _pSTGMEDIUM->hGlobal = NULL ;
_uiSTGType = 0;
DC_EXIT_POINT: DC_END_FN(); return hr; } DCVOID CImpIDataObject::SetClipData(HGLOBAL hGlobal, DCUINT clipType) { DC_BEGIN_FN("CImpIDataObject::SetClipData");
if (!_pSTGMEDIUM) _pSTGMEDIUM = (STGMEDIUM*) LocalAlloc(LPTR, sizeof(STGMEDIUM)) ; if (NULL != _pSTGMEDIUM) { if (CF_PALETTE == clipType) { _pSTGMEDIUM->tymed = TYMED_GDI; } else if (CF_METAFILEPICT == clipType) { _pSTGMEDIUM->tymed = TYMED_MFPICT; } else { _pSTGMEDIUM->tymed = TYMED_HGLOBAL; }
_pSTGMEDIUM->pUnkForRelease = NULL ; FreeSTGMEDIUM(); _pSTGMEDIUM->hGlobal = hGlobal ; _uiSTGType = clipType; }
DC_END_FN(); }
DCVOID CImpIDataObject::FreeSTGMEDIUM(void) { if ( NULL == _pSTGMEDIUM->hGlobal ) { return; }
switch( _uiSTGType ) { case CF_PALETTE: DeleteObject( _pSTGMEDIUM->hGlobal ); break; #ifndef OS_WINCE
case CF_METAFILEPICT: { LPMETAFILEPICT pMFPict = (LPMETAFILEPICT)GlobalLock( _pSTGMEDIUM->hGlobal ); if ( NULL != pMFPict ) { if ( NULL != pMFPict->hMF ) { DeleteMetaFile( pMFPict->hMF ); } GlobalUnlock( _pSTGMEDIUM->hGlobal ); } GlobalFree( _pSTGMEDIUM->hGlobal ); } break; #endif
default: GlobalFree( _pSTGMEDIUM->hGlobal ); } _pSTGMEDIUM->hGlobal = NULL; }
CImpIDataObject::~CImpIDataObject(void) { DC_BEGIN_FN("CImpIDataObject::~CImplDataObject") ;
if (_pFormats) LocalFree(_pFormats) ;
if (_pSTGMEDIUM) { FreeSTGMEDIUM(); LocalFree(_pSTGMEDIUM) ; }
if (_pUnkOuter) { _pUnkOuter->Release(); _pUnkOuter = NULL; } DC_END_FN(); }
// IUnknown members
// - Delegate to "outer" IUnknown
STDMETHODIMP CImpIDataObject::QueryInterface(REFIID riid, PPVOID ppv) { DC_BEGIN_FN("CImpIDataObject::QueryInterface"); DC_END_FN(); return _pUnkOuter->QueryInterface(riid, ppv); }
STDMETHODIMP_(ULONG) CImpIDataObject::AddRef(void) { DC_BEGIN_FN("CImpIDataObject::AddRef");
InterlockedIncrement(&_cRef);
DC_END_FN(); return _pUnkOuter->AddRef(); }
STDMETHODIMP_(ULONG) CImpIDataObject::Release(void) { LONG cRef;
DC_BEGIN_FN("CImpIDataObject::Release");
_pUnkOuter->Release();
cRef = InterlockedDecrement(&_cRef) ; if (0 == cRef) delete this;
DC_END_FN() ; return cRef; }
// IDataObject members
// ***************************************************************************
// CImpIDataObject::GetData
// - Here, we have to wait for the data to actually get here before we return.
// ***************************************************************************
STDMETHODIMP CImpIDataObject::GetData(LPFORMATETC pFE, LPSTGMEDIUM pSTM) { HRESULT result = E_FAIL; // Assume we fail until we know we haven't
#ifndef OS_WINCE
TCHAR formatName[TS_FORMAT_NAME_LEN] ; byte charSize ; BOOL fWide ; WCHAR* fileListW ; HPDCVOID pFilename ; HPDCVOID pOldFilename ; #endif
HGLOBAL hData = NULL ; HPDCVOID pData ; HPDCVOID pOldData ; #ifndef OS_WINCE
DROPFILES* pDropFiles ; DROPFILES tempDropfile ; ULONG oldSize ; ULONG newSize ; #endif
DWORD eventSignaled ; DWORD* pDropEffect ; #ifndef OS_WINCE
char* fileList ; #endif
PCClip pClip ; DC_BEGIN_FN("CImpIDataObject::GetData");
// Should never occur, but we check for sanity's sake
if (NULL == (PCClipData)_pUnkOuter) { TRC_ERR((TB, _T("Ptr to outer unknown is NULL"))) ; result = E_FAIL ; DC_QUIT ; } if (NULL == ((PCClipData)_pUnkOuter)->_pClip) { TRC_ERR((TB, _T("Ptr to clip class is NULL"))) ; result = E_FAIL ; DC_QUIT ; } // Since we need to have the CClip class do work for us,
// we pull out a pointer to it that we stored in the beginning
pClip = (PCClip) ((PCClipData)_pUnkOuter)->_pClip ; if (!_pSTGMEDIUM) { TRC_ERR((TB, _T("Transfer medium (STGMEDIUM) is NULL"))) ; result = E_FAIL ; DC_QUIT ; }
TRC_ASSERT( pClip->IsDataSyncReady(), (TB, _T("Data Sync not ready"))); if (!_pSTGMEDIUM->hGlobal || (pFE->cfFormat != _lastFormatRequested)) { TRC_ASSERT( pClip->IsDataSyncReady(), (TB,_T("data sync is NULL"))); ResetEvent(pClip->_GetDataSync[TS_RESET_EVENT]) ; if (!((PCClipData)_pUnkOuter)->_pClip->ClipGetData(pFE->cfFormat)) { result = E_FAIL ; DC_QUIT ; } eventSignaled = WaitForMultipleObjects( TS_NUM_EVENTS, ((PCClipData)_pUnkOuter)->_pClip->_GetDataSync, FALSE, INFINITE ) ; if ((WAIT_OBJECT_0+TS_RESET_EVENT) == eventSignaled) { TRC_NRM((TB, _T("Other thread told us to reset. Failing GetData"))) ; ResetEvent(((PCClipData)_pUnkOuter)->_pClip->_GetDataSync[TS_RESET_EVENT]) ; result = E_FAIL ; DC_QUIT ; }
// Make sure that we actually got data from the server.
if (_pSTGMEDIUM->hGlobal == NULL) { TRC_ERR((TB, _T("No format data received from server!"))); result = E_FAIL; DC_QUIT; }
#ifndef OS_WINCE
if (CF_HDROP == pFE->cfFormat) { // if we got an HDROP and we're not NT/2000, we check to see if we
// have to convert to ansi; otherwise, we're done
if (pClip->GetOsMinorType() != TS_OSMINORTYPE_WINDOWS_NT) { pDropFiles = (DROPFILES*) GlobalLock(_pSTGMEDIUM->hGlobal) ; if (!pDropFiles) { TRC_ERR((TB, _T("Failed to lock %p"), hData)) ; result = E_FAIL ; DC_QUIT ; } // if we definitely have wide characters, then convert
if (pDropFiles->fWide) { // temporarily store the original's base dropfile info
tempDropfile.pFiles = pDropFiles->pFiles ; tempDropfile.pt = pDropFiles->pt ; tempDropfile.fNC = pDropFiles->fNC ; tempDropfile.fWide = 0 ; // we are converting to ANSI now
// We divide by the size of wchar_t because we need half as many
// bytes with ansi as opposed to fWide character strings
oldSize = (ULONG) GlobalSize(_pSTGMEDIUM->hGlobal) - pDropFiles->pFiles ; newSize = oldSize / sizeof(WCHAR) ; fileList = (char*) (LocalAlloc(LPTR,newSize)) ; if ( NULL == fileList ) { TRC_ERR((TB, _T("Unable to allocate %d bytes"), newSize )); result = E_FAIL; DC_QUIT; }
// This will convert the wide HDROP filelist to ansi, and
// put the ansi version into filelist
// 11-12
// pDropFiles is probably "foo\0bar\0baz\0\0"
// I don't believe WC2MB will go past the first \0
if (!WideCharToMultiByte(GetACP(), NULL, (wchar_t*) ((byte*) pDropFiles + pDropFiles->pFiles), newSize, fileList, newSize, NULL, NULL)) { TRC_ERR((TB, _T("Unable convert wide to ansi"), newSize)) ; LocalFree( fileList ); result = E_FAIL ; DC_QUIT ; } // Output the first filename for a sanity check
TRC_NRM((TB, _T("Filename 1 = %hs"), fileList)) ; GlobalUnlock(_pSTGMEDIUM->hGlobal) ; // Reallocate the space for the dropfile
hData = GlobalAlloc(GMEM_DISCARDABLE | GMEM_MOVEABLE, newSize + tempDropfile.pFiles) ; if (!hData) { TRC_ERR((TB, _T("Allocate memory; err=%d"), GetLastError())) ; LocalFree( fileList ); result = E_FAIL ; DC_QUIT ; } pDropFiles = (DROPFILES*) GlobalLock(hData) ; if (!pDropFiles) { TRC_ERR((TB, _T("Unable to lock %p"), hData)) ; LocalFree( fileList ); result = E_FAIL ; DC_QUIT ; } pDropFiles->pFiles = tempDropfile.pFiles ; pDropFiles->pt = tempDropfile.pt ; pDropFiles->fNC = tempDropfile.fNC ; pDropFiles->fWide = tempDropfile.fWide ; DC_MEMCPY((byte*) pDropFiles + pDropFiles->pFiles, fileList, newSize) ; // Output the first filename for another sanity check
TRC_NRM((TB, _T("Filename = %s"), (byte*) pDropFiles + pDropFiles->pFiles)) ; LocalFree( fileList ); } GlobalUnlock(hData) ; GlobalFree(_pSTGMEDIUM->hGlobal) ; _pSTGMEDIUM->hGlobal = hData ; } } #else
if (gfmtShellPidlArray == pFE->cfFormat) { HANDLE hNewData = HDropToIDList(_pSTGMEDIUM->hGlobal); GlobalFree(_pSTGMEDIUM->hGlobal); _pSTGMEDIUM->hGlobal = hNewData; } #endif
// We check the dropeffect format, because we strip out
// shortcuts/links, and store the dropeffects. The dropeffect is
// what some apps (explorer) use to decide if they should copy, move
// or link
else if (_cfDropEffect == pFE->cfFormat) { if (GlobalSize(_pSTGMEDIUM->hGlobal) < sizeof(DWORD)) { TRC_ERR((TB, _T("Unexpected global memory size!"))); result = E_FAIL; DC_QUIT; }
pDropEffect = (DWORD*) GlobalLock(_pSTGMEDIUM->hGlobal) ; if (!pDropEffect) { TRC_NRM((TB, _T("Unable to lock %p"), _pSTGMEDIUM->hGlobal)) ; result = E_FAIL ; DC_QUIT ; } // Strip out shortcuts/links
*pDropEffect = *pDropEffect ^ DROPEFFECT_LINK ; // Strip out moves
*pDropEffect = *pDropEffect ^ DROPEFFECT_MOVE ; pClip->SetDropEffect(*pDropEffect) ; if (GlobalUnlock(_pSTGMEDIUM->hGlobal)) { TRC_ASSERT(GetLastError() == NO_ERROR, (TB, _T("Unable to unlock HGLOBAL we just locked"))) ; } } pSTM->tymed = _pSTGMEDIUM->tymed ; pSTM->hGlobal = _pSTGMEDIUM->hGlobal ; _pSTGMEDIUM->hGlobal = NULL; pSTM->pUnkForRelease = _pSTGMEDIUM->pUnkForRelease ; result = S_OK ; DC_QUIT ; } else { pSTM->tymed = _pSTGMEDIUM->tymed ; pSTM->hGlobal = GlobalAlloc(GMEM_DISCARDABLE | GMEM_MOVEABLE, GlobalSize(_pSTGMEDIUM->hGlobal)) ; pData = GlobalLock(pSTM->hGlobal) ; pOldData = GlobalLock(_pSTGMEDIUM->hGlobal) ; if (!pData || !pOldData) return E_FAIL ; DC_MEMCPY(pData, pOldData, GlobalSize(_pSTGMEDIUM->hGlobal)) ; GlobalUnlock(pSTM->hGlobal) ; GlobalUnlock(_pSTGMEDIUM->hGlobal) ;
pSTM->pUnkForRelease = _pSTGMEDIUM->pUnkForRelease ; } if (!pSTM->hGlobal) { TRC_NRM((TB, _T("Clipboard data request failed"))) ; return E_FAIL ; } DC_EXIT_POINT:
DC_END_FN(); return result ; }
STDMETHODIMP CImpIDataObject::GetDataHere(LPFORMATETC pFE, LPSTGMEDIUM pSTM) { DC_BEGIN_FN("CImpIDataObject::GetDataHere") ; DC_END_FN(); return ResultFromScode(E_NOTIMPL) ; }
STDMETHODIMP CImpIDataObject::QueryGetData(LPFORMATETC pFE) { ULONG i = 0 ; HRESULT hr = DV_E_CLIPFORMAT ; DC_BEGIN_FN("CImpIDataObject::QueryGetData") ;
TRC_NRM((TB, _T("Format ID %d requested"), pFE->cfFormat)) ; while (i < _numFormats) { if (_pFormats[i].cfFormat == pFE->cfFormat) { hr = S_OK ; break ; } i++ ; }
DC_END_FN(); return hr ; }
STDMETHODIMP CImpIDataObject::GetCanonicalFormatEtc(LPFORMATETC pFEIn, LPFORMATETC pFEOut) { DC_BEGIN_FN("CImpIDataObject::GetCanonicalFormatEtc") ; DC_END_FN(); return ResultFromScode(E_NOTIMPL) ; }
// ***************************************************************************
// CImpIDataObject::SetData
// - Due to the fact that the RDP only passes the simple clipboard format, and
// the fact that we obtain all of our clipboard data from memory later, pSTM
// is really ignored at this point. It isn't until GetData is called that
// the remote clipboard data is received, and a valid global memory handle
// is generated.
// - Thus, pSTM and fRelease are ignored.
// - So out _pSTGMEDIUM is generated using generic values
// ***************************************************************************
STDMETHODIMP CImpIDataObject::SetData(LPFORMATETC pFE, LPSTGMEDIUM pSTM, BOOL fRelease) { TCHAR formatName[TS_FORMAT_NAME_LEN] = {0} ; byte i ; DC_BEGIN_FN("CImpIDataObject::SetData");
DC_IGNORE_PARAMETER(pSTM) ; // Reset the the last format requested to 0
_lastFormatRequested = 0 ;
TRC_NRM((TB, _T("Adding format %d to IDataObject"), pFE->cfFormat)) ; if (_numFormats < _maxNumFormats) { for (i=0; i < _numFormats; i++) { if (pFE->cfFormat == _pFormats[i].cfFormat) { TRC_NRM((TB, _T("Duplicate format. Discarded"))) ; return DV_E_FORMATETC ; } } _pFormats[_numFormats] = *pFE ; _numFormats++ ; } else { TRC_ERR((TB, _T("Cannot add any more formats"))) ; return E_FAIL ; }
DC_END_FN(); return S_OK ; }
STDMETHODIMP CImpIDataObject::EnumFormatEtc(DWORD dwDir, LPENUMFORMATETC *ppEnum) { PCEnumFormatEtc pEnum;
*ppEnum=NULL;
/*
* From an external point of view there are no SET formats, * because we want to allow the user of this component object * to be able to stuff ANY format in via Set. Only external * users will call EnumFormatEtc and they can only Get. */
switch (dwDir) { case DATADIR_GET: pEnum=new CEnumFormatEtc(_pUnkOuter); break;
case DATADIR_SET: default: pEnum=new CEnumFormatEtc(_pUnkOuter); break; }
if (NULL==pEnum) return ResultFromScode(E_FAIL); else { //Let the enumerator copy our format list.
pEnum->Init(_pFormats, _numFormats) ;
pEnum->AddRef(); }
*ppEnum=pEnum; return NO_ERROR ; } STDMETHODIMP CImpIDataObject::DAdvise(LPFORMATETC pFE, DWORD dwFlags, LPADVISESINK pIAdviseSink, LPDWORD pdwConn) { return ResultFromScode(E_NOTIMPL) ; } STDMETHODIMP CImpIDataObject::DUnadvise(DWORD dwConn) { return ResultFromScode(E_NOTIMPL) ; } STDMETHODIMP CImpIDataObject::EnumDAdvise(LPENUMSTATDATA *ppEnum) { return ResultFromScode(E_NOTIMPL) ; }
CEnumFormatEtc::CEnumFormatEtc(LPUNKNOWN pUnkRef) { DC_BEGIN_FN("CEnumFormatEtc::CEnumFormatEtc");
_cRef = 0 ; _pUnkRef = pUnkRef ; if (_pUnkRef) { _pUnkRef->AddRef(); } _iCur = 0;
DC_END_FN() ; }
DCVOID CEnumFormatEtc::Init(LPFORMATETC pFormats, ULONG numFormats) { DC_BEGIN_FN("CEnumFormatEtc::Init");
_cItems = numFormats; _pFormats = (LPFORMATETC) LocalAlloc(LPTR,_cItems*sizeof(FORMATETC)) ; if (_pFormats) { memcpy(_pFormats, pFormats, _cItems*sizeof(FORMATETC)) ; } else { TRC_ERR((TB, _T("Unable to allocate memory for formats"))) ; }
DC_END_FN() ; } CEnumFormatEtc::~CEnumFormatEtc() { DC_BEGIN_FN("CEnumFormatEtc::~CEnumFormatEtc"); if (_pUnkRef) { _pUnkRef->Release(); _pUnkRef = NULL; } if (NULL !=_pFormats) LocalFree(_pFormats) ; DC_END_FN() ; }
STDMETHODIMP CEnumFormatEtc::QueryInterface(REFIID riid, PPVOID ppv) { DC_BEGIN_FN("CEnumFormatEtc::QueryInterface"); *ppv=NULL;
/*
* Enumerators are separate objects, not the data object, so * we only need to support out IUnknown and IEnumFORMATETC * interfaces here with no concern for aggregation. */ if (IID_IUnknown==riid || IID_IEnumFORMATETC==riid) *ppv=this;
if (NULL!=*ppv) { ((LPUNKNOWN)*ppv)->AddRef(); return NOERROR; }
DC_END_FN() ; return ResultFromScode(E_NOINTERFACE); }
STDMETHODIMP_(ULONG) CEnumFormatEtc::AddRef(void) { LONG cRef;
cRef = InterlockedIncrement(&_cRef);
_pUnkRef->AddRef();
return cRef; }
STDMETHODIMP_(ULONG) CEnumFormatEtc::Release(void) { LONG cRef; DC_BEGIN_FN("CEnumFormatEtc::Release");
_pUnkRef->Release();
cRef = InterlockedDecrement(&_cRef) ; if (0 == cRef) delete this;
DC_END_FN() ; return cRef; }
STDMETHODIMP CEnumFormatEtc::Next(ULONG cFE, LPFORMATETC pFE, ULONG *pulFE) { ULONG cReturn=0L;
if (NULL==_pFormats) return ResultFromScode(S_FALSE);
if (NULL==pulFE) { if (1L!=cFE) return ResultFromScode(E_POINTER); } else *pulFE=0L;
if (NULL==pFE || _iCur >= _cItems) return ResultFromScode(S_FALSE);
while (_iCur < _cItems && cFE > 0) { *pFE=_pFormats[_iCur]; pFE++; _iCur++; cReturn++; cFE--; }
if (NULL!=pulFE) *pulFE=cReturn;
return NOERROR; }
STDMETHODIMP CEnumFormatEtc::Skip(ULONG cSkip) { if ((_iCur+cSkip) >= _cItems) return ResultFromScode(S_FALSE);
_iCur+=cSkip; return NOERROR; }
STDMETHODIMP CEnumFormatEtc::Reset(void) { _iCur=0; return NOERROR; }
STDMETHODIMP CEnumFormatEtc::Clone(LPENUMFORMATETC *ppEnum) { #ifndef OS_WINCE
PCEnumFormatEtc pNew = NULL; LPMALLOC pIMalloc; LPFORMATETC prgfe; BOOL fRet=TRUE; ULONG cb;
*ppEnum=NULL; #else
BOOL fRet=FALSE; #endif
#ifndef OS_WINCE
//Copy the memory for the list.
if (FAILED(CoGetMalloc(MEMCTX_TASK, &pIMalloc))) return ResultFromScode(E_OUTOFMEMORY);
cb=_cItems*sizeof(FORMATETC); prgfe=(LPFORMATETC)pIMalloc->Alloc(cb);
if (NULL!=prgfe) { //Copy the formats
memcpy(prgfe, _pFormats, (int)cb);
//Create the clone
pNew=new CEnumFormatEtc(_pUnkRef);
if (NULL != pNew) { pNew->_iCur=_iCur; pNew->_pFormats=prgfe; pNew->AddRef(); fRet=TRUE; } else { fRet = FALSE; } }
pIMalloc->Release();
*ppEnum=pNew; #endif
return fRet ? NOERROR : ResultFromScode(E_OUTOFMEMORY); }
|