Leaked source code of windows server 2003
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

5425 lines
196 KiB

  1. /**MOD+**********************************************************************/
  2. /* Module: cclip.cpp */
  3. /* */
  4. /* Purpose: Shared Clipboard Client Addin */
  5. /* */
  6. /* Copyright(C) Microsoft Corporation 1998-1999 */
  7. /* */
  8. /**MOD-**********************************************************************/
  9. /****************************************************************************/
  10. /* Precompiled header */
  11. /****************************************************************************/
  12. #include <precom.h>
  13. /****************************************************************************/
  14. /* Trace definitions */
  15. /****************************************************************************/
  16. #define TRC_GROUP TRC_GROUP_NETWORK
  17. #define TRC_FILE "cclip"
  18. #include <atrcapi.h>
  19. #include "vcint.h"
  20. #include "drapi.h"
  21. /****************************************************************************/
  22. // Headers
  23. /****************************************************************************/
  24. #include <cclip.h>
  25. #ifndef OS_WINCE
  26. #include <shlobj.h>
  27. #endif
  28. #ifdef OS_WINCE
  29. #include "ceclip.h"
  30. #endif
  31. #ifdef CLIP_TRANSITION_RECORDING
  32. UINT g_rguiDbgLastClipState[DBG_RECORD_SIZE];
  33. UINT g_rguiDbgLastClipEvent[DBG_RECORD_SIZE];
  34. LONG g_uiDbgPosition = -1;
  35. #endif // CLIP_TRANSITION_RECORDING
  36. /****************************************************************************/
  37. /* CTor */
  38. /****************************************************************************/
  39. CClip::CClip(VCManager *virtualChannelMgr)
  40. {
  41. PRDPDR_DATA prdpdrData;
  42. DC_BEGIN_FN("CClip::CClip");
  43. /********************************************************************/
  44. /* Initialize the data */
  45. /********************************************************************/
  46. _GetDataSync[TS_RECEIVE_COMPLETED] = NULL;
  47. _GetDataSync[TS_RESET_EVENT] = NULL;
  48. DC_MEMSET(&_CB, 0, sizeof(_CB));
  49. _pVCMgr = virtualChannelMgr;
  50. prdpdrData = _pVCMgr->GetInitData();
  51. _CB.fDrivesRedirected = prdpdrData->fEnableRedirectDrives;
  52. _CB.fFileCutCopyOn = _CB.fDrivesRedirected;
  53. _pClipData = new CClipData(this);
  54. if (_pClipData)
  55. {
  56. _pClipData->AddRef();
  57. }
  58. _pUtObject = (CUT*) LocalAlloc(LPTR, sizeof(CUT));
  59. if (_pUtObject) {
  60. _pUtObject->UT_Init();
  61. }
  62. if (prdpdrData->szClipPasteInfoString[0] != 0) {
  63. if (!WideCharToMultiByte(CP_ACP, 0, prdpdrData->szClipPasteInfoString,
  64. -1, _CB.pasteInfoA, sizeof(_CB.pasteInfoA), NULL, NULL)) {
  65. StringCbCopyA(_CB.pasteInfoA,
  66. sizeof(_CB.pasteInfoA),
  67. "Preparing paste information...");
  68. }
  69. }
  70. else {
  71. StringCbCopyA(_CB.pasteInfoA,
  72. sizeof(_CB.pasteInfoA),
  73. "Preparing paste information...");
  74. }
  75. /********************************************************************/
  76. /* Store the hInstance */
  77. /********************************************************************/
  78. _CB.hInst = GetModuleHandle(NULL);
  79. TRC_NRM((TB, _T("Store hInst %p"), _CB.hInst));
  80. DC_END_FN();
  81. }
  82. /****************************************************************************/
  83. /* Wrappers for Malloc, Free & Memcpy */
  84. /****************************************************************************/
  85. #ifdef OS_WIN32
  86. #define ClipAlloc(size) LocalAlloc(LMEM_FIXED, size)
  87. #define ClipFree(pData) LocalFree(pData)
  88. #define ClipMemcpy(pTrg, pSrc, len) DC_MEMCPY(pTrg, pSrc, len)
  89. #endif
  90. DCUINT CClip::GetOsMinorType()
  91. {
  92. DCUINT minorType = 0;
  93. if (_pUtObject) {
  94. minorType = _pUtObject->UT_GetOsMinorType();
  95. }
  96. return minorType;
  97. }
  98. /****************************************************************************/
  99. // ClipCheckState
  100. /****************************************************************************/
  101. DCUINT DCINTERNAL CClip::ClipCheckState(DCUINT event)
  102. {
  103. DCUINT tableVal = cbStateTable[event][_CB.state];
  104. DC_BEGIN_FN("CClip::ClipCheckState");
  105. TRC_DBG((TB, _T("Test event %s in state %s"),
  106. cbEvent[event], cbState[_CB.state]));
  107. if (tableVal != CB_TABLE_OK)
  108. {
  109. if (tableVal == CB_TABLE_WARN)
  110. {
  111. TRC_ALT((TB, _T("Unusual event %s in state %s"),
  112. cbEvent[event], cbState[_CB.state]));
  113. }
  114. else
  115. {
  116. TRC_ABORT((TB, _T("Invalid event %s in state %s"),
  117. cbEvent[event], cbState[_CB.state]));
  118. }
  119. }
  120. DC_END_FN();
  121. return(tableVal);
  122. }
  123. /****************************************************************************/
  124. // ClipGetPermBuf - get a permanently allocated buffer
  125. /****************************************************************************/
  126. PTS_CLIP_PDU DCINTERNAL CClip::ClipGetPermBuf(DCVOID)
  127. {
  128. PTS_CLIP_PDU pClipPDU;
  129. DC_BEGIN_FN("CClip::ClipGetPermBuf");
  130. #ifdef USE_SEMAPHORE
  131. /************************************************************************/
  132. // On Win32, access to the permanent buffer is synchronised via a
  133. // semaphore
  134. /************************************************************************/
  135. TRC_NRM((TB, _T("Wait for perm TX buffer")));
  136. WaitForSingleObject(_CB.txPermBufSem, INFINITE);
  137. pClipPDU = (PTS_CLIP_PDU)(_CB.txPermBuffer);
  138. #endif
  139. TRC_DBG((TB, _T("Return buffer at %#p"), pClipPDU));
  140. DC_END_FN();
  141. return(pClipPDU);
  142. } /* ClipGetPermBuf */
  143. /****************************************************************************/
  144. /* ClipFreeBuf */
  145. /****************************************************************************/
  146. DCVOID DCINTERNAL CClip::ClipFreeBuf(PDCUINT8 pBuf)
  147. {
  148. #ifndef OS_WINCE
  149. INT i;
  150. #endif
  151. DC_BEGIN_FN("CClip::ClipFreeBuf");
  152. TRC_DBG((TB, _T("Release buffer at %p"), pBuf));
  153. #ifdef USE_SEMAPHORE
  154. if (pBuf == _CB.txPermBuffer)
  155. {
  156. TRC_DBG((TB, _T("Free Permanent buffer at %p"), pBuf));
  157. if (!ReleaseSemaphore(_CB.txPermBufSem, 1, NULL))
  158. {
  159. TRC_SYSTEM_ERROR("ReleaseSemaphore");
  160. }
  161. }
  162. else
  163. {
  164. TRC_DBG((TB, _T("Free Temporary buffer at %p"), pBuf));
  165. ClipFree(pBuf);
  166. }
  167. #else
  168. #ifdef OS_WINCE
  169. INT i;
  170. #endif
  171. for (i = 0; i < CB_PERM_BUF_COUNT; i++)
  172. {
  173. TRC_DBG((TB, _T("Test buf %d, %p vs %p"), i, pBuf, _CB.txPermBuffer[i]));
  174. if (pBuf == _CB.txPermBuffer[i])
  175. {
  176. TRC_NRM((TB, _T("Free perm buffer %d"), i));
  177. _CB.txPermBufInUse[i] = FALSE;
  178. break;
  179. }
  180. }
  181. if (i == CB_PERM_BUF_COUNT)
  182. {
  183. TRC_DBG((TB, _T("Temporary buffer")));
  184. ClipFree(pBuf);
  185. }
  186. #endif
  187. DC_END_FN();
  188. return;
  189. } /* ClipFreePermBuf */
  190. /****************************************************************************/
  191. /* ClipDrawClipboard - send the local formats to the remote */
  192. /****************************************************************************/
  193. DCBOOL DCINTERNAL CClip::ClipDrawClipboard(DCBOOL mustSend)
  194. {
  195. DCUINT32 numFormats;
  196. DCUINT formatCount;
  197. DCUINT formatID;
  198. //
  199. // formatlist is extracted from a PDU at a non-word boundary
  200. // so it causes an alignment fault on WIN64. Marked UNALIGNED.
  201. //
  202. PTS_CLIP_FORMAT formatList;
  203. DCUINT nameLen;
  204. PTS_CLIP_PDU pClipPDU = NULL;
  205. DCUINT32 pduLen;
  206. DCUINT32 dataLen;
  207. DCBOOL rc = TRUE;
  208. DCBOOL fHdrop = FALSE ;
  209. DC_BEGIN_FN("CClip::ClipDrawClipboard");
  210. _CB.dropEffect = FO_COPY ;
  211. _CB.fAlreadyCopied = FALSE ;
  212. #ifndef OS_WINCE
  213. _CB.dwVersion = GetVersion() ;
  214. #else
  215. OSVERSIONINFO osv;
  216. memset(&osv, 0, sizeof(osv));
  217. osv.dwOSVersionInfoSize = sizeof(osv);
  218. if (!GetVersionEx(&osv))
  219. {
  220. TRC_ERR((TB, _T("GetVersionEx failed!")));
  221. rc = FALSE;
  222. DC_QUIT;
  223. }
  224. _CB.dwVersion = MAKELPARAM(MAKEWORD(osv.dwMajorVersion, osv.dwMinorVersion), osv.dwBuildNumber);
  225. #endif
  226. _CB.fAlreadyCopied = FALSE ;
  227. /************************************************************************/
  228. /* First we open the clipboard */
  229. /************************************************************************/
  230. if (!OpenClipboard(_CB.viewerWindow))
  231. {
  232. TRC_ERR((TB, _T("Failed to open CB")));
  233. rc = FALSE;
  234. DC_QUIT;
  235. }
  236. /************************************************************************/
  237. /* It was/is open */
  238. /************************************************************************/
  239. TRC_NRM((TB, _T("CB opened")));
  240. _CB.clipOpen = TRUE;
  241. /************************************************************************/
  242. /* Count the formats available, checking we don't blow our limit */
  243. /************************************************************************/
  244. numFormats = CountClipboardFormats();
  245. if (numFormats > CB_MAX_FORMATS)
  246. {
  247. TRC_ALT((TB, _T("Num formats %ld too large - limit to %d"),
  248. numFormats, CB_MAX_FORMATS));
  249. numFormats = CB_MAX_FORMATS;
  250. }
  251. TRC_DBG((TB, _T("found %ld formats"), numFormats));
  252. /************************************************************************/
  253. /* if there are no formats available, and we don't have to send the */
  254. /* info, then don't! */
  255. /************************************************************************/
  256. if ((numFormats == 0) && (mustSend == FALSE))
  257. {
  258. TRC_NRM((TB, _T("No formats: skipping send")));
  259. DC_QUIT;
  260. }
  261. /************************************************************************/
  262. /* Get a send buffer. First work out how big it needs to be */
  263. /************************************************************************/
  264. dataLen = numFormats * sizeof(TS_CLIP_FORMAT);
  265. pduLen = dataLen + sizeof(TS_CLIP_PDU);
  266. /************************************************************************/
  267. /* and make sure that's not too big! */
  268. /************************************************************************/
  269. if (pduLen > CHANNEL_CHUNK_LENGTH)
  270. {
  271. /********************************************************************/
  272. /* we'll have to limit the number of formats. How many will fit in */
  273. /* the max buffer size? */
  274. /********************************************************************/
  275. pduLen = CHANNEL_CHUNK_LENGTH;
  276. dataLen = pduLen - sizeof(TS_CLIP_PDU);
  277. numFormats = dataLen / sizeof(TS_CLIP_FORMAT);
  278. /********************************************************************/
  279. /* no point in having empty space for the last fractional format! */
  280. /********************************************************************/
  281. dataLen = numFormats * sizeof(TS_CLIP_FORMAT);
  282. pduLen = dataLen + sizeof(TS_CLIP_PDU);
  283. TRC_ALT((TB, _T("Too many formats! Limited to %ld"), numFormats));
  284. }
  285. pClipPDU = ClipGetPermBuf();
  286. /************************************************************************/
  287. /* Fill in the common parts of the PDU */
  288. /************************************************************************/
  289. DC_MEMSET(pClipPDU, 0, sizeof(*pClipPDU));
  290. /************************************************************************/
  291. /* and now the clip bits */
  292. /************************************************************************/
  293. pClipPDU->msgType = TS_CB_FORMAT_LIST;
  294. pClipPDU->dataLen = dataLen;
  295. #ifndef UNICODE
  296. pClipPDU->msgFlags = TS_CB_ASCII_NAMES;
  297. #endif
  298. /************************************************************************/
  299. /* if there were any formats, list them */
  300. /************************************************************************/
  301. if (numFormats)
  302. {
  303. /********************************************************************/
  304. /* set up the format list */
  305. /********************************************************************/
  306. formatList = (PTS_CLIP_FORMAT)(pClipPDU->data);
  307. /********************************************************************/
  308. /* and enumerate the formats */
  309. /********************************************************************/
  310. _CB.DIBFormatExists = FALSE;
  311. formatCount = 0;
  312. formatID = EnumClipboardFormats(0); /* 0 starts the enumeration */
  313. while ((formatID != 0) && (formatCount < numFormats))
  314. {
  315. #ifdef OS_WINCE
  316. DCUINT dwTempID = formatID;
  317. if (formatID == gfmtShellPidlArray)
  318. {
  319. formatID = CF_HDROP;
  320. }
  321. #endif
  322. /****************************************************************/
  323. /* store the ID */
  324. /****************************************************************/
  325. formatList[formatCount].formatID = formatID;
  326. /****************************************************************/
  327. /* find the name for the format */
  328. /****************************************************************/
  329. nameLen = GetClipboardFormatName(formatID,
  330. (PDCTCHAR)formatList[formatCount].formatName,
  331. TS_FORMAT_NAME_LEN);
  332. /****************************************************************/
  333. /* check for predefined formats - they have no name */
  334. /****************************************************************/
  335. if (nameLen == 0)
  336. {
  337. TRC_NRM((TB, _T("no name for format %d - predefined"), formatID));
  338. *(formatList[formatCount].formatName) = '\0';
  339. }
  340. TRC_DBG((TB, _T("found format id %ld, name '%s'"),
  341. formatList[formatCount].formatID,
  342. formatList[formatCount].formatName));
  343. /****************************************************************/
  344. /* look for formats we don't send */
  345. /****************************************************************/
  346. if ((formatID == CF_DSPBITMAP) ||
  347. (formatID == CF_ENHMETAFILE) ||
  348. ((!_CB.fFileCutCopyOn || !_CB.fDrivesRedirected) && (formatID == CF_HDROP)) ||
  349. (formatID == CF_OWNERDISPLAY))
  350. {
  351. // We drop enhanced metafile formats, since the local CB
  352. // will provide conversion where supported
  353. //
  354. // Ownerdisplay just isn't going to work since the two
  355. // windows are on different machines!
  356. //
  357. // File cut/copy isn't going to work if there is no drive
  358. // redirection!
  359. TRC_ALT((TB, _T("Dropping format ID %d"), formatID));
  360. formatList[formatCount].formatID = 0;
  361. *(formatList[formatCount].formatName) = '\0';
  362. }
  363. else if (ClipIsExcludedFormat((PDCTCHAR)formatList[formatCount].formatName))
  364. {
  365. //
  366. // We don't support file cut/paste, so we drop
  367. // file related formats.
  368. //
  369. TRC_ALT((TB, _T("Dropping format name '%s'"), (PDCTCHAR)formatList[formatCount].formatName));
  370. formatList[formatCount].formatID = 0;
  371. *(formatList[formatCount].formatName) = '\0';
  372. }
  373. else
  374. {
  375. /************************************************************/
  376. /* We support the CF_BITMAP format by converting it to */
  377. /* CF_DIB. If there is already a CF_DIB format, we don't */
  378. /* need to do this. */
  379. /************************************************************/
  380. if ((formatID == CF_BITMAP) && (_CB.DIBFormatExists))
  381. {
  382. TRC_NRM((TB, _T("Dropping CF_BITMAP - CF_DIB is supported")));
  383. }
  384. else
  385. {
  386. /********************************************************/
  387. /* It's a supported format */
  388. /********************************************************/
  389. if (formatID == CF_BITMAP)
  390. {
  391. TRC_NRM((TB, _T("Convert CF_BITMAP to CF_DIB")));
  392. formatList[formatCount].formatID = CF_DIB;
  393. }
  394. else if (formatID == CF_DIB)
  395. {
  396. TRC_NRM((TB, _T("Really found DIB format")));
  397. _CB.DIBFormatExists = TRUE;
  398. }
  399. if (CF_HDROP == formatID)
  400. {
  401. fHdrop = TRUE ;
  402. }
  403. /********************************************************/
  404. /* update the count and move on */
  405. /********************************************************/
  406. formatCount++;
  407. }
  408. }
  409. #ifdef OS_WINCE
  410. if (formatID == CF_HDROP)
  411. formatID = dwTempID; //reset the enumeration index, in case we changed it to accommodate CF_HDROP
  412. #endif
  413. /****************************************************************/
  414. /* get the next format */
  415. /****************************************************************/
  416. formatID = EnumClipboardFormats(formatID);
  417. }
  418. /********************************************************************/
  419. /* Update the PDU len - we may have dropped some formats along the */
  420. /* way */
  421. /********************************************************************/
  422. dataLen = formatCount * sizeof(TS_CLIP_FORMAT);
  423. pduLen = dataLen + sizeof(TS_CLIP_PDU);
  424. TRC_NRM((TB, _T("Final count: %d formats in data len %ld"),
  425. formatCount, dataLen));
  426. pClipPDU->dataLen = dataLen;
  427. }
  428. // if we're NT/2000 and we're going to send an HDROP
  429. if (fHdrop)
  430. {
  431. TRC_NRM((TB, _T("Creating new temp directory for file data"))) ;
  432. // How about handling errors from these fs calls?
  433. #ifndef OS_WINCE
  434. if (GetOsMinorType() == TS_OSMINORTYPE_WINDOWS_NT)
  435. #endif
  436. {
  437. #ifndef OS_WINCE
  438. if (0 == GetTempFileNameW(_CB.baseTempDirW, L"_TS", 0, _CB.tempDirW)) {
  439. #else
  440. if (0 == GetTempFileNameW(_CB.baseTempDirW, L"_TS", 0, _CB.tempDirW, MAX_PATH)) {
  441. #endif
  442. TRC_ERR((TB, _T("Getting temp file name failed; GetLastError=%u"),
  443. GetLastError()));
  444. rc = FALSE;
  445. DC_QUIT;
  446. }
  447. // GetACP always returns a valid value
  448. if (0 == WideCharToMultiByte(GetACP(), NULL, _CB.tempDirW, -1,
  449. _CB.tempDirA, (MAX_PATH + 1), NULL, NULL)) {
  450. TRC_ERR((TB, _T("Getting temp file name failed; GetLastError=%u"),
  451. GetLastError()));
  452. rc = FALSE;
  453. DC_QUIT;
  454. }
  455. DeleteFileW(_CB.tempDirW) ;
  456. if (0 == CreateDirectoryW(_CB.tempDirW, NULL)) {
  457. TRC_ERR((TB, _T("Creating temp directory failed; GetLastError=%u"),
  458. GetLastError()));
  459. rc = FALSE;
  460. DC_QUIT;
  461. }
  462. }
  463. #ifndef OS_WINCE
  464. else
  465. {
  466. if (0 == GetTempFileNameA(_CB.baseTempDirA, "_TS", 0, _CB.tempDirA)) {
  467. TRC_ERR((TB, _T("Getting temp file name failed; GetLastError=%u"),
  468. GetLastError()));
  469. rc = FALSE;
  470. DC_QUIT;
  471. }
  472. // GetACP always returns a valid value
  473. if (0 == MultiByteToWideChar(GetACP(), MB_ERR_INVALID_CHARS,
  474. _CB.tempDirA, -1, _CB.tempDirW,
  475. sizeof(_CB.tempDirW)/(sizeof(_CB.tempDirW[0])) - 1)) {
  476. TRC_ERR((TB, _T("Failed conversion to wide char; error %d"),
  477. GetLastError())) ;
  478. rc = FALSE ;
  479. DC_QUIT ;
  480. }
  481. // Do not check return value
  482. DeleteFileA(_CB.tempDirA) ;
  483. if (0 == CreateDirectoryA(_CB.tempDirA, NULL)) {
  484. TRC_ERR((TB, _T("Creating temp directory failed; GetLastError=%u"),
  485. GetLastError()));
  486. rc = FALSE;
  487. DC_QUIT;
  488. }
  489. }
  490. #endif
  491. }
  492. /************************************************************************/
  493. /* Update the state */
  494. /************************************************************************/
  495. CB_SET_STATE(CB_STATE_PENDING_FORMAT_LIST_RSP, CB_EVENT_WM_DRAWCLIPBOARD);
  496. /************************************************************************/
  497. /* Send the PDU */
  498. /************************************************************************/
  499. TRC_NRM((TB, _T("Sending format list")));
  500. if (_CB.channelEP.pVirtualChannelWriteEx
  501. (_CB.initHandle, _CB.channelHandle, pClipPDU, pduLen, (LPVOID)pClipPDU)
  502. != CHANNEL_RC_OK) {
  503. ClipFreeBuf((PDCUINT8)pClipPDU);
  504. }
  505. DC_EXIT_POINT:
  506. /************************************************************************/
  507. /* tidy up */
  508. /************************************************************************/
  509. if (_CB.clipOpen)
  510. {
  511. TRC_DBG((TB, _T("closing CB")));
  512. _CB.clipOpen = FALSE;
  513. if (!CloseClipboard())
  514. {
  515. TRC_SYSTEM_ERROR("CloseClipboard");
  516. }
  517. }
  518. DC_END_FN();
  519. return(rc);
  520. } /* ClipDrawClipboard */
  521. #ifndef OS_WINCE
  522. /****************************************************************************/
  523. /* ClipGetMFData */
  524. /****************************************************************************/
  525. HANDLE DCINTERNAL CClip::ClipGetMFData(HANDLE hData,
  526. PDCUINT32 pDataLen)
  527. {
  528. DCUINT32 lenMFBits = 0;
  529. DCBOOL rc = FALSE;
  530. LPMETAFILEPICT pMFP = NULL;
  531. HDC hMFDC = NULL;
  532. HMETAFILE hMF = NULL;
  533. HGLOBAL hMFBits = NULL;
  534. HANDLE hNewData = NULL;
  535. PDCUINT8 pNewData = NULL;
  536. PDCVOID pBits = NULL;
  537. DC_BEGIN_FN("CClip::ClipGetMFData");
  538. TRC_NRM((TB, _T("Getting MF data")));
  539. /************************************************************************/
  540. /* Lock the memory to get a pointer to a METAFILEPICT header structure */
  541. /* and create a METAFILEPICT DC. */
  542. /************************************************************************/
  543. if (GlobalSize(hData) < sizeof(METAFILEPICT)) {
  544. TRC_ERR((TB, _T("Unexpected global memory size!")));
  545. _CB.channelEP.pVirtualChannelCloseEx(_CB.initHandle, _CB.channelHandle);
  546. DC_QUIT;
  547. }
  548. pMFP = (LPMETAFILEPICT)GlobalLock(hData);
  549. if (pMFP == NULL)
  550. {
  551. TRC_SYSTEM_ERROR("GlobalLock");
  552. DC_QUIT;
  553. }
  554. hMFDC = CreateMetaFile(NULL);
  555. if (hMFDC == NULL)
  556. {
  557. TRC_SYSTEM_ERROR("CreateMetaFile");
  558. DC_QUIT;
  559. }
  560. /************************************************************************/
  561. /* Copy the MFP by playing it into the DC and closing it. */
  562. /************************************************************************/
  563. if (!PlayMetaFile(hMFDC, pMFP->hMF))
  564. {
  565. TRC_SYSTEM_ERROR("PlayMetaFile");
  566. CloseMetaFile(hMFDC);
  567. DC_QUIT;
  568. }
  569. hMF = CloseMetaFile(hMFDC);
  570. if (hMF == NULL)
  571. {
  572. TRC_SYSTEM_ERROR("CloseMetaFile");
  573. DC_QUIT;
  574. }
  575. /************************************************************************/
  576. /* Get the MF bits and determine how long they are. */
  577. /************************************************************************/
  578. lenMFBits = GetMetaFileBitsEx(hMF, 0, NULL);
  579. if (lenMFBits == 0)
  580. {
  581. TRC_SYSTEM_ERROR("GetMetaFileBitsEx");
  582. DC_QUIT;
  583. }
  584. TRC_DBG((TB, _T("length MF bits %ld"), lenMFBits));
  585. /************************************************************************/
  586. /* Work out how much memory we need and get a buffer */
  587. /************************************************************************/
  588. *pDataLen = sizeof(TS_CLIP_MFPICT) + lenMFBits;
  589. hNewData = GlobalAlloc(GHND, *pDataLen);
  590. if (hNewData == NULL)
  591. {
  592. TRC_ERR((TB, _T("Failed to get MF buffer")));
  593. DC_QUIT;
  594. }
  595. pNewData = (PDCUINT8)GlobalLock(hNewData);
  596. if (NULL == pNewData) {
  597. TRC_ERR((TB,_T("Failed to lock MF buffer")));
  598. DC_QUIT;
  599. }
  600. TRC_DBG((TB, _T("Got data to send len %ld"), *pDataLen));
  601. /************************************************************************/
  602. /* Copy the MF header and bits into the buffer. */
  603. /************************************************************************/
  604. ((PTS_CLIP_MFPICT)pNewData)->mm = pMFP->mm;
  605. ((PTS_CLIP_MFPICT)pNewData)->xExt = pMFP->xExt;
  606. ((PTS_CLIP_MFPICT)pNewData)->yExt = pMFP->yExt;
  607. lenMFBits = GetMetaFileBitsEx(hMF, lenMFBits,
  608. (pNewData + sizeof(TS_CLIP_MFPICT)));
  609. if (lenMFBits == 0)
  610. {
  611. TRC_SYSTEM_ERROR("GetMetaFileBitsEx");
  612. DC_QUIT;
  613. }
  614. /************************************************************************/
  615. /* all OK */
  616. /************************************************************************/
  617. TRC_NRM((TB, _T("Got %ld bits of MF data"), lenMFBits));
  618. TRC_DATA_DBG("MF bits",
  619. (pNewData + sizeof(TS_CLIP_MFPICT)),
  620. (DCUINT)lenMFBits);
  621. rc = TRUE;
  622. DC_EXIT_POINT:
  623. /************************************************************************/
  624. /* Unlock any global mem. */
  625. /************************************************************************/
  626. if (pMFP)
  627. {
  628. GlobalUnlock(hData);
  629. }
  630. if (pNewData)
  631. {
  632. GlobalUnlock(hNewData);
  633. }
  634. if (hMF)
  635. {
  636. DeleteMetaFile(hMF);
  637. }
  638. /************************************************************************/
  639. /* if things went wrong, then free the new data */
  640. /************************************************************************/
  641. if ((rc == FALSE) && (hNewData != NULL))
  642. {
  643. GlobalFree(hNewData);
  644. hNewData = NULL;
  645. }
  646. DC_END_FN();
  647. return(hNewData);
  648. } /* ClipGetMFData */
  649. /****************************************************************************/
  650. /* ClipSetMFData */
  651. /****************************************************************************/
  652. HANDLE DCINTERNAL CClip::ClipSetMFData(DCUINT32 dataLen,
  653. PDCVOID pData)
  654. {
  655. DCBOOL rc = FALSE;
  656. HGLOBAL hMFBits = NULL;
  657. PDCVOID pMFMem = NULL;
  658. HMETAFILE hMF = NULL;
  659. HGLOBAL hMFPict = NULL;
  660. LPMETAFILEPICT pMFPict = NULL;
  661. DC_BEGIN_FN("CClip::ClipSetMFData");
  662. TRC_DATA_DBG("Received MF data", pData, (DCUINT)dataLen);
  663. /************************************************************************/
  664. /* Allocate memory to hold the MF bits (we need the handle to pass to */
  665. /* SetMetaFileBits). */
  666. /************************************************************************/
  667. hMFBits = GlobalAlloc(GHND, dataLen - (DCUINT32)sizeof(TS_CLIP_MFPICT));
  668. if (hMFBits == NULL)
  669. {
  670. TRC_SYSTEM_ERROR("GlobalAlloc");
  671. DC_QUIT;
  672. }
  673. /************************************************************************/
  674. /* Lock the handle and copy in the MF header. */
  675. /************************************************************************/
  676. pMFMem = GlobalLock(hMFBits);
  677. if (pMFMem == NULL)
  678. {
  679. TRC_ERR((TB, _T("Failed to lock MF mem")));
  680. DC_QUIT;
  681. }
  682. DC_HMEMCPY(pMFMem,
  683. (PDCVOID)((PDCUINT8)pData + sizeof(TS_CLIP_MFPICT)),
  684. dataLen - sizeof(TS_CLIP_MFPICT) );
  685. GlobalUnlock(hMFBits);
  686. /************************************************************************/
  687. /* Now use the copied MF bits to create the actual MF bits and get a */
  688. /* handle to the MF. */
  689. /************************************************************************/
  690. hMF = SetMetaFileBitsEx(dataLen - sizeof(TS_CLIP_MFPICT), (PDCUINT8)pMFMem);
  691. if (hMF == NULL)
  692. {
  693. TRC_SYSTEM_ERROR("SetMetaFileBits");
  694. DC_QUIT;
  695. }
  696. /************************************************************************/
  697. /* Allocate a new METAFILEPICT structure, and use the data from the */
  698. /* sent header. */
  699. /************************************************************************/
  700. hMFPict = GlobalAlloc(GHND, sizeof(METAFILEPICT));
  701. pMFPict = (LPMETAFILEPICT)GlobalLock(hMFPict);
  702. if (!pMFPict)
  703. {
  704. TRC_ERR((TB, _T("Couldn't allocate METAFILEPICT")));
  705. DC_QUIT;
  706. }
  707. pMFPict->mm = (LONG)((PTS_CLIP_MFPICT)pData)->mm;
  708. pMFPict->xExt = (LONG)((PTS_CLIP_MFPICT)pData)->xExt;
  709. pMFPict->yExt = (LONG)((PTS_CLIP_MFPICT)pData)->yExt;
  710. pMFPict->hMF = hMF;
  711. GlobalUnlock(hMFPict);
  712. rc = TRUE;
  713. DC_EXIT_POINT:
  714. /************************************************************************/
  715. /* tidy up */
  716. /************************************************************************/
  717. if (!rc)
  718. {
  719. if (hMFPict)
  720. {
  721. GlobalFree(hMFPict);
  722. }
  723. }
  724. {
  725. if (hMFBits)
  726. {
  727. GlobalFree(hMFBits);
  728. }
  729. }
  730. DC_END_FN();
  731. return(hMFPict);
  732. } /* ClipSetMFData */
  733. #endif
  734. /****************************************************************************/
  735. /* ClipBitmapToDIB - convert CF_BITMAP format to CF_DIB format */
  736. /****************************************************************************/
  737. HANDLE DCINTERNAL CClip::ClipBitmapToDIB(HANDLE hData, PDCUINT32 pDataLen)
  738. {
  739. BITMAP bmpDetails = {0};
  740. DWORD buffSize, buffWidth;
  741. DWORD paletteBytes;
  742. WORD bpp;
  743. DWORD numCols;
  744. int rc;
  745. HANDLE hDIBitmap = NULL;
  746. HPDCVOID pDIBitmap = NULL;
  747. HPDCVOID pBits = NULL;
  748. PBITMAPINFO pBmpInfo = NULL;
  749. HDC hDC = NULL;
  750. DCBOOL allOK = FALSE;
  751. DC_BEGIN_FN("CClip::ClipBitmapToDIB");
  752. *pDataLen = 0;
  753. /************************************************************************/
  754. /* get the details of the bitmap */
  755. /************************************************************************/
  756. if (0 == GetObject(hData, sizeof(bmpDetails), &bmpDetails)) {
  757. TRC_ERR((TB, _T("Failed to get bitmap details")));
  758. DC_QUIT;
  759. }
  760. TRC_NRM((TB, _T("Bitmap details: width %d, height %d, #planes %d, bpp %d"),
  761. bmpDetails.bmWidth, bmpDetails.bmHeight, bmpDetails.bmPlanes,
  762. bmpDetails.bmBitsPixel));
  763. /************************************************************************/
  764. /* Space required for bits is */
  765. /* */
  766. /* (width * bpp / 8) rounded up to multiple of 4 bytes */
  767. /* * height */
  768. /* */
  769. /************************************************************************/
  770. bpp = (WORD)(bmpDetails.bmBitsPixel * bmpDetails.bmPlanes);
  771. buffWidth = ((bmpDetails.bmWidth * bpp) + 7) / 8;
  772. buffWidth = DC_ROUND_UP_4(buffWidth);
  773. buffSize = buffWidth * bmpDetails.bmHeight;
  774. TRC_DBG((TB, _T("Buffer size %ld (W %ld, H %d)"),
  775. buffSize, buffWidth, bmpDetails.bmHeight));
  776. /************************************************************************/
  777. /* Now add some space for the bitmapinfo - this includes a color table */
  778. /************************************************************************/
  779. numCols = 1 << bpp;
  780. if (bpp <= 8)
  781. {
  782. paletteBytes = numCols * sizeof(RGBQUAD);
  783. TRC_NRM((TB, _T("%ld colors => %ld palette bytes"), numCols, paletteBytes));
  784. }
  785. else
  786. {
  787. if (bpp == 24)
  788. {
  789. /****************************************************************/
  790. /* No bitmasks or palette info (compression==BI_RGB) */
  791. /****************************************************************/
  792. paletteBytes = 0;
  793. TRC_NRM((TB, _T("%ld colors => 0 bitfield bytes"), numCols));
  794. }
  795. else
  796. {
  797. /****************************************************************/
  798. /* 3 DWORD color masks for >8bpp (compression==BI_BITFIELDS) */
  799. /****************************************************************/
  800. paletteBytes = 3 * sizeof(DWORD);
  801. TRC_NRM((TB, _T("%ld colors => %ld bitfield bytes"), numCols, paletteBytes));
  802. }
  803. }
  804. buffSize += (sizeof(BITMAPINFOHEADER) + paletteBytes);
  805. TRC_NRM((TB, _T("Buffer size %ld"), buffSize));
  806. /************************************************************************/
  807. /* Allocate memory to hold everything */
  808. /************************************************************************/
  809. hDIBitmap = GlobalAlloc(GHND, buffSize);
  810. if (hDIBitmap == NULL)
  811. {
  812. TRC_ERR((TB, _T("Failed to alloc %ld bytes"), buffSize));
  813. DC_QUIT;
  814. }
  815. pDIBitmap = GlobalLock(hDIBitmap);
  816. if (pDIBitmap == NULL)
  817. {
  818. TRC_ERR((TB, _T("Failed to lock hDIBitmap")));
  819. DC_QUIT;
  820. }
  821. /************************************************************************/
  822. /* bmp info is at the start */
  823. /* space for bits are in the middle somewhere */
  824. /************************************************************************/
  825. pBmpInfo = (PBITMAPINFO)pDIBitmap;
  826. pBits = (HPDCVOID)((HPDCUINT8)pDIBitmap +
  827. sizeof(BITMAPINFOHEADER) + paletteBytes);
  828. TRC_NRM((TB, _T("pBmpInfo at %p, pBits at %p"), pBmpInfo, pBits));
  829. /************************************************************************/
  830. /* set up the desired bitmap info */
  831. /************************************************************************/
  832. pBmpInfo->bmiHeader.biSize = sizeof(BITMAPINFOHEADER);
  833. pBmpInfo->bmiHeader.biWidth = bmpDetails.bmWidth;
  834. pBmpInfo->bmiHeader.biHeight = bmpDetails.bmHeight;
  835. pBmpInfo->bmiHeader.biPlanes = 1;
  836. pBmpInfo->bmiHeader.biBitCount = bpp;
  837. if ((bpp <= 8) || (bpp == 24))
  838. {
  839. pBmpInfo->bmiHeader.biCompression = BI_RGB;
  840. }
  841. else
  842. {
  843. pBmpInfo->bmiHeader.biCompression = BI_BITFIELDS;
  844. }
  845. pBmpInfo->bmiHeader.biSizeImage = 0;
  846. pBmpInfo->bmiHeader.biXPelsPerMeter = 0;
  847. pBmpInfo->bmiHeader.biYPelsPerMeter = 0;
  848. pBmpInfo->bmiHeader.biClrUsed = 0;
  849. pBmpInfo->bmiHeader.biClrImportant = 0;
  850. /************************************************************************/
  851. /* get a DC */
  852. /************************************************************************/
  853. hDC = GetDC(NULL);
  854. if (!hDC)
  855. {
  856. TRC_SYSTEM_ERROR("GetDC");
  857. DC_QUIT;
  858. }
  859. /************************************************************************/
  860. /* now get the bits */
  861. /************************************************************************/
  862. TRC_NRM((TB, _T("GetDIBits")));
  863. rc = GetDIBits(hDC, // hdc
  864. (HBITMAP)hData, // hbm
  865. 0, // nStartScan
  866. bmpDetails.bmHeight, // nNumScans
  867. pBits, // pBits
  868. pBmpInfo, // pbmi
  869. DIB_RGB_COLORS); // iUsage
  870. TRC_NRM((TB, _T("GetDIBits returns %d"), rc));
  871. if (!rc)
  872. {
  873. TRC_SYSTEM_ERROR("GetDIBits");
  874. DC_QUIT;
  875. }
  876. /************************************************************************/
  877. /* All seems to be OK */
  878. /************************************************************************/
  879. *pDataLen = buffSize;
  880. TRC_NRM((TB, _T("All done: data %p, len %ld"), hDIBitmap, *pDataLen));
  881. allOK = TRUE;
  882. DC_EXIT_POINT:
  883. /************************************************************************/
  884. /* Finished with the DC - free it */
  885. /************************************************************************/
  886. if (hDC)
  887. {
  888. TRC_DBG((TB, _T("Free the DC")));
  889. ReleaseDC(NULL, hDC);
  890. }
  891. /************************************************************************/
  892. /* Free the return buffer if this didn't work */
  893. /************************************************************************/
  894. if (!allOK)
  895. {
  896. if (pDIBitmap)
  897. {
  898. TRC_DBG((TB, _T("Unlock DIBitmap")));
  899. GlobalUnlock(hDIBitmap);
  900. }
  901. if (hDIBitmap)
  902. {
  903. TRC_DBG((TB, _T("Free DIBitmap")));
  904. GlobalFree(hDIBitmap);
  905. hDIBitmap = NULL;
  906. }
  907. }
  908. DC_END_FN();
  909. return(hDIBitmap);
  910. } /* ClipBitmapToDIB */
  911. DCBOOL DCINTERNAL CClip::ClipIsExcludedFormat(PDCTCHAR formatName)
  912. {
  913. DCBOOL rc = FALSE;
  914. DCINT i;
  915. DC_BEGIN_FN("CClip::ClipIsExcludedFormat");
  916. /************************************************************************/
  917. /* check there is a format name - all banned formats have one! */
  918. /************************************************************************/
  919. if (*formatName == _T('\0'))
  920. {
  921. TRC_ALT((TB, _T("No format name supplied!")));
  922. DC_QUIT;
  923. }
  924. /************************************************************************/
  925. /* search the banned format list for the supplied format name */
  926. /************************************************************************/
  927. TRC_DBG((TB, _T("Looking at format '%s'"), formatName));
  928. TRC_DATA_DBG("Format name data", formatName, TS_FORMAT_NAME_LEN);
  929. // if File Cut/Copy is on AND Drive Redirection is on, we can handle
  930. // more formats
  931. if (_CB.fFileCutCopyOn && _CB.fDrivesRedirected)
  932. {
  933. for (i = 0; i < CB_EXCLUDED_FORMAT_COUNT; i++)
  934. {
  935. TRC_DBG((TB, _T("comparing with '%s'"), g_excludedFormatList[i]));
  936. if (DC_WSTRCMP((PDCWCHAR)formatName,
  937. (PDCWCHAR)g_excludedFormatList[i]) == 0)
  938. {
  939. TRC_NRM((TB, _T("Found excluded format '%s'"), formatName));
  940. rc = TRUE;
  941. break;
  942. }
  943. }
  944. }
  945. else
  946. {
  947. for (i = 0; i < CB_EXCLUDED_FORMAT_COUNT_NO_RD; i++)
  948. {
  949. TRC_DBG((TB, _T("comparing with '%s'"), g_excludedFormatList_NO_RD[i]));
  950. if (DC_WSTRCMP((PDCWCHAR)formatName,
  951. (PDCWCHAR)g_excludedFormatList_NO_RD[i]) == 0)
  952. {
  953. TRC_NRM((TB, _T("Found excluded format '%s'"), formatName));
  954. rc = TRUE;
  955. break;
  956. }
  957. }
  958. }
  959. DC_EXIT_POINT:
  960. DC_END_FN();
  961. return(rc);
  962. } /* ClipIsExcludedFormat */
  963. #ifndef OS_WINCE
  964. //
  965. // ClipCleanTempPath
  966. // - Returns 0 if successful
  967. // nonzero if failed
  968. // - Attempts to wipe the temp directory of TS related files
  969. //
  970. int CClip::ClipCleanTempPath()
  971. {
  972. int result;
  973. SHFILEOPSTRUCTW fileOpStructW;
  974. PRDPDR_DATA prdpdrData = _pVCMgr->GetInitData();
  975. #ifndef UNICODE
  976. #error function assumes unicode
  977. #endif
  978. _CB.baseTempDirW[wcslen(_CB.baseTempDirW)] = L'\0' ;
  979. fileOpStructW.pFrom = _CB.baseTempDirW ;
  980. fileOpStructW.pTo = NULL ;
  981. fileOpStructW.hwnd = NULL ;
  982. fileOpStructW.wFunc = FO_DELETE ;
  983. fileOpStructW.fFlags = FOF_NOCONFIRMATION | FOF_NOERRORUI |
  984. FOF_SIMPLEPROGRESS;
  985. fileOpStructW.hNameMappings = NULL ;
  986. if (prdpdrData->szClipCleanTempDirString[0] != 0) {
  987. fileOpStructW.lpszProgressTitle = prdpdrData->szClipCleanTempDirString;
  988. }
  989. else {
  990. fileOpStructW.lpszProgressTitle = L"Cleaning temp directory";
  991. }
  992. //
  993. // Use SHFileOperation instead of SHFileOperationW to ensure
  994. // it goes through the unicode wrapper. Note SHFileOperationW
  995. // is not available on 95 so the wrapper dynamically binds to
  996. // the entry point.
  997. //
  998. result = SHFileOperation(&fileOpStructW) ;
  999. return result ;
  1000. }
  1001. #else
  1002. //We dont want to use the recycle bin on CE
  1003. int CClip::ClipCleanTempPath()
  1004. {
  1005. return (_CB.fFileCutCopyOn) ? DeleteDirectory(_CB.baseTempDirW, FALSE) : ERROR_SUCCESS;
  1006. }
  1007. #endif
  1008. //
  1009. // ClipCopyToTempDirectory, ClipCopyToTempDirectoryA, ClipCopyToTempDirectoryW
  1010. // - Arguments:
  1011. // pSrcFiles = buffer containing the names/path of the files to be copied
  1012. // - Returns 0 if successful
  1013. // nonzero if failed
  1014. // - Given a list of file names/paths, this function will attempt to copy them
  1015. // to the temp directory
  1016. //
  1017. int CClip::ClipCopyToTempDirectory(PVOID pSrcFiles, BOOL fWide)
  1018. {
  1019. int result ;
  1020. if (fWide)
  1021. result = ClipCopyToTempDirectoryW(pSrcFiles) ;
  1022. else
  1023. result = ClipCopyToTempDirectoryA(pSrcFiles) ;
  1024. return result ;
  1025. }
  1026. #ifndef OS_WINCE
  1027. int CClip::ClipCopyToTempDirectoryW(PVOID pSrcFiles)
  1028. {
  1029. SHFILEOPSTRUCTW fileOpStructW ;
  1030. HMODULE hmodSH32DLL;
  1031. PRDPDR_DATA prdpdrData = _pVCMgr->GetInitData();
  1032. int result = 1;
  1033. typedef HRESULT (STDAPICALLTYPE FNSHFileOperationW)(LPSHFILEOPSTRUCT);
  1034. FNSHFileOperationW *pfnSHFileOperationW;
  1035. // get the handle to shell32.dll library
  1036. hmodSH32DLL = LoadLibrary(TEXT("SHELL32.DLL"));
  1037. if (hmodSH32DLL != NULL) {
  1038. // get the proc address for SHFileOperation
  1039. pfnSHFileOperationW = (FNSHFileOperationW *)GetProcAddress(hmodSH32DLL, "SHFileOperationW");
  1040. if (pfnSHFileOperationW != NULL) {
  1041. _CB.tempDirW[wcslen(_CB.tempDirW)] = L'\0' ;
  1042. fileOpStructW.pFrom = (WCHAR*) pSrcFiles ;
  1043. fileOpStructW.pTo = _CB.tempDirW ;
  1044. fileOpStructW.hwnd = NULL ;
  1045. fileOpStructW.wFunc = _CB.dropEffect ;
  1046. fileOpStructW.fFlags = FOF_NOCONFIRMATION | FOF_NOCONFIRMMKDIR |
  1047. FOF_SIMPLEPROGRESS | FOF_ALLOWUNDO ;
  1048. fileOpStructW.hNameMappings = NULL ;
  1049. if (prdpdrData->szClipPasteInfoString[0] != 0) {
  1050. fileOpStructW.lpszProgressTitle = prdpdrData->szClipPasteInfoString;
  1051. }
  1052. else {
  1053. fileOpStructW.lpszProgressTitle = L"Preparing paste information...";
  1054. }
  1055. //result = SHFileOperationW(&fileOpStructW) ;
  1056. result = (*pfnSHFileOperationW) (&fileOpStructW);
  1057. }
  1058. FreeLibrary(hmodSH32DLL);
  1059. }
  1060. return result ;
  1061. }
  1062. #else
  1063. //SHFileOperation on CE does not support copying multiple files
  1064. int CClip::ClipCopyToTempDirectoryW(PVOID pSrcFiles)
  1065. {
  1066. DC_BEGIN_FN("CClip::ClipCopyToTempDirectoryW") ;
  1067. TRC_ASSERT((pSrcFiles != NULL), (TB, _T("pSrcFiles is NULL")));
  1068. WCHAR *pFiles = (WCHAR *)pSrcFiles;
  1069. WCHAR szDest[MAX_PATH+1];
  1070. wcsncpy(szDest, _CB.tempDirW, MAX_PATH);
  1071. int nTempLen = wcslen(szDest);
  1072. while(*pFiles)
  1073. {
  1074. int nLen = wcslen(pFiles);
  1075. WCHAR *pFile = wcsrchr(pFiles, L'\\');
  1076. if (pFile && nLen < MAX_PATH)
  1077. {
  1078. wcsncat(szDest, pFile, MAX_PATH - nTempLen - 1);
  1079. DWORD dwAttrib = GetFileAttributes(pFiles);
  1080. if ((dwAttrib != 0xffffffff) && (dwAttrib & FILE_ATTRIBUTE_DIRECTORY))
  1081. {
  1082. WIN32_FIND_DATA fd;
  1083. WCHAR szSrc[MAX_PATH];
  1084. wcscpy(szSrc, pFiles);
  1085. if (!CopyDirectory(szSrc, szDest, &fd))
  1086. {
  1087. TRC_ERR((TB, _T("CopyDirectory from %s to %s failed. GLE=0x%08x"), pFiles, szDest, GetLastError())) ;
  1088. return GetLastError();
  1089. }
  1090. }
  1091. else if (!CopyFile(pFiles, szDest, FALSE))
  1092. {
  1093. TRC_ERR((TB, _T("CopyFile from %s to %s failed. GLE=0x%08x"), pFiles, szDest, GetLastError())) ;
  1094. return GetLastError();
  1095. }
  1096. szDest[nTempLen] = L'\0';
  1097. }
  1098. else
  1099. {
  1100. TRC_ERR((TB, _T("Invalid filename : %s"), pFiles)) ;
  1101. }
  1102. pFiles += nLen + 1;
  1103. }
  1104. DC_END_FN();
  1105. return 0;
  1106. }
  1107. #endif
  1108. int CClip::ClipCopyToTempDirectoryA(PVOID pSrcFiles)
  1109. {
  1110. #ifndef OS_WINCE
  1111. SHFILEOPSTRUCTA fileOpStructA ;
  1112. int result ;
  1113. _CB.tempDirA[strlen(_CB.tempDirA)] = '\0' ;
  1114. fileOpStructA.pFrom = (char*) pSrcFiles ;
  1115. fileOpStructA.pTo = _CB.tempDirA ;
  1116. fileOpStructA.hwnd = NULL ;
  1117. fileOpStructA.wFunc = _CB.dropEffect ;
  1118. fileOpStructA.fFlags = FOF_NOCONFIRMATION | FOF_NOCONFIRMMKDIR |
  1119. FOF_SIMPLEPROGRESS | FOF_ALLOWUNDO ;
  1120. fileOpStructA.hNameMappings = NULL ;
  1121. fileOpStructA.lpszProgressTitle = _CB.pasteInfoA;
  1122. result = SHFileOperationA(&fileOpStructA) ;
  1123. return result ;
  1124. #else
  1125. DC_BEGIN_FN("CClip::ClipConvertToTempPathA") ;
  1126. TRC_ASSERT((FALSE), (TB, _T("CE doesnt support ClipConvertToTempPathA")));
  1127. DC_END_FN() ;
  1128. return E_FAIL;
  1129. #endif
  1130. }
  1131. //
  1132. // ClipConvertToTempPath, ClipConvertToTempPathA, ClipConvertToTempPathW
  1133. // - Arguments:
  1134. // pOldData = Buffer containing the original file path
  1135. // pData = Buffer receiving the new file path
  1136. // fWide = Wide or Ansi characters
  1137. // - Returns S_OK if pOldData was a network path
  1138. // S_FALSE if pOldData was not a network path
  1139. // E_FAIL if it failed
  1140. // - Given a unc file path, this function will strip out the old path, and
  1141. // prepend a path to the client's TS temp directory
  1142. //
  1143. HRESULT CClip::ClipConvertToTempPath(PVOID pOldData, PVOID pData, ULONG cbData, BOOL fWide)
  1144. {
  1145. HRESULT result ;
  1146. DC_BEGIN_FN("CClip::ClipConvertToTempPath") ;
  1147. if (!pOldData)
  1148. {
  1149. TRC_ERR((TB, _T("Original string pointer is NULL"))) ;
  1150. result = E_FAIL ;
  1151. DC_QUIT ;
  1152. }
  1153. if (!pData)
  1154. {
  1155. TRC_ERR((TB, _T("Destination string pointer is NULL"))) ;
  1156. result = E_FAIL ;
  1157. DC_QUIT ;
  1158. }
  1159. if (fWide) {
  1160. result = ClipConvertToTempPathW(pOldData, pData, cbData / sizeof(WCHAR)) ;
  1161. } else {
  1162. result = ClipConvertToTempPathA(pOldData, pData, cbData) ;
  1163. }
  1164. DC_EXIT_POINT:
  1165. return result ;
  1166. DC_END_FN() ;
  1167. }
  1168. HRESULT CClip::ClipConvertToTempPathW(PVOID pOldData, PVOID pData, ULONG cchData)
  1169. {
  1170. WCHAR* filePath ;
  1171. #ifndef OS_WINCE
  1172. WCHAR* driveLetter ;
  1173. WCHAR* uncPath ;
  1174. WCHAR* prependText ;
  1175. DWORD charSize ;
  1176. DWORD driveLetterLength ;
  1177. #endif
  1178. HRESULT hr;
  1179. DC_BEGIN_FN("CClip::ClipConvertToTempPathW") ;
  1180. // if this is a UNC path beginning with a "\\"
  1181. if (((WCHAR*)pOldData)[0] == L'\\' &&
  1182. ((WCHAR*)pOldData)[1] == L'\\')
  1183. {
  1184. // prepend the new file path with the temp directory
  1185. hr = StringCchCopyW((WCHAR*) pData, cchData, _CB.tempDirW);
  1186. if (SUCCEEDED(hr)) {
  1187. filePath = wcsrchr((WCHAR*) pOldData, L'\\');
  1188. hr = StringCchCatW((WCHAR*) pData, cchData, filePath);
  1189. }
  1190. if (FAILED(hr)) {
  1191. TRC_ERR((TB,_T("Failed to copy and cat string: 0x%x"),hr));
  1192. }
  1193. }
  1194. else
  1195. {
  1196. TRC_NRM((TB, _T("Not a UNC path"))) ;
  1197. hr = StringCchCopyW((WCHAR*) pData, cchData, (WCHAR*) pOldData);
  1198. if (SUCCEEDED(hr)) {
  1199. hr = S_FALSE;
  1200. }
  1201. }
  1202. #ifdef OS_WINCE
  1203. //Send it as "Files:" to the server
  1204. if( (((WCHAR*)pData)[0] == L'\\') && ((wcslen((WCHAR *)pData) + sizeof(CEROOTDIRNAME)/sizeof(WCHAR)) < MAX_PATH) )
  1205. {
  1206. WCHAR szFile[MAX_PATH];
  1207. wcscpy(szFile, (WCHAR *)pData);
  1208. wcscpy((WCHAR *)pData, CEROOTDIRNAME);
  1209. wcscat((WCHAR *)pData, szFile);
  1210. }
  1211. else
  1212. {
  1213. DC_END_FN() ;
  1214. return S_FALSE;
  1215. }
  1216. #endif
  1217. DC_END_FN() ;
  1218. return hr;
  1219. }
  1220. HRESULT CClip::ClipConvertToTempPathA(PVOID pOldData, PVOID pData, ULONG cchData)
  1221. {
  1222. #ifndef OS_WINCE
  1223. char* filePath ;
  1224. char* driveLetter ;
  1225. char* uncPath ;
  1226. char* prependText ;
  1227. DWORD charSize ;
  1228. DWORD driveLetterLength ;
  1229. HRESULT hr = E_FAIL;
  1230. DC_BEGIN_FN("CClip::ClipConvertToTempPathA") ;
  1231. charSize = sizeof(char) ;
  1232. // if this is a UNC path beginning with a "\\"
  1233. if (((char*) pOldData)[0] == '\\' &&
  1234. ((char*) pOldData)[1] == '\\')
  1235. {
  1236. // prepend the new file path with the temp directory
  1237. hr = StringCchCopyA((char*) pData, cchData, _CB.tempDirA);
  1238. if (SUCCEEDED(hr)) {
  1239. filePath = strrchr((char*) pOldData, '\\');
  1240. if (filePath) {
  1241. hr = StringCchCatA((char*) pData, cchData, filePath);
  1242. } else {
  1243. hr = E_FAIL;
  1244. }
  1245. }
  1246. if (FAILED(hr)) {
  1247. TRC_ERR((TB,_T("Failed to copy and cat string: 0x%x"),hr));
  1248. }
  1249. }
  1250. else
  1251. {
  1252. TRC_NRM((TB, _T("Not a UNC path"))) ;
  1253. hr = StringCchCopyA((char*) pData, cchData, (char*) pOldData);
  1254. if (SUCCEEDED(hr)) {
  1255. hr = S_FALSE;
  1256. }
  1257. }
  1258. DC_END_FN() ;
  1259. return hr;
  1260. #else
  1261. DC_BEGIN_FN("CClip::ClipConvertToTempPathA") ;
  1262. TRC_ASSERT((FALSE), (TB, _T("CE doesnt support ClipConvertToTempPathA")));
  1263. DC_END_FN() ;
  1264. return S_FALSE ;
  1265. #endif
  1266. }
  1267. #ifndef OS_WINCE
  1268. //
  1269. // ClipGetNewFilePathLength
  1270. // - Arguments:
  1271. // pData = Buffer containing a filepath
  1272. // fWide = Wide or Ansi (TRUE if wide, FALSE if ansi)
  1273. // - Returns new size of the drop file
  1274. // 0 if it fails
  1275. // - Given a UNC file path, this returns the new size required
  1276. // if the directory structure is removed, and is replaced by
  1277. // the temp directory path
  1278. // - Otherwise, if it doesn't explicitly fail, it returns the
  1279. // old length
  1280. //
  1281. UINT CClip::ClipGetNewFilePathLength(PVOID pData, BOOL fWide)
  1282. {
  1283. UINT result ;
  1284. DC_BEGIN_FN("CClip::ClipGetNewFilePathLength") ;
  1285. if (!pData)
  1286. {
  1287. TRC_ERR((TB, _T("Filename is NULL"))) ;
  1288. result = 0 ;
  1289. }
  1290. if (fWide)
  1291. result = ClipGetNewFilePathLengthW((WCHAR*)pData) ;
  1292. else
  1293. result = ClipGetNewFilePathLengthA((char*)pData) ;
  1294. DC_EXIT_POINT:
  1295. DC_END_FN() ;
  1296. return result ;
  1297. }
  1298. UINT CClip::ClipGetNewFilePathLengthW(WCHAR* wszOldFilepath)
  1299. {
  1300. UINT oldLength = wcslen(wszOldFilepath) ;
  1301. UINT newLength = oldLength ;
  1302. UINT remainingLength = oldLength ;
  1303. byte charSize = sizeof(WCHAR) ;
  1304. DC_BEGIN_FN("CClip::ClipGetNewFilePathLengthW") ;
  1305. // if the old filename didn't even have space for "c:\" (with NULL),
  1306. // then its probably invalid
  1307. if (4 > oldLength)
  1308. {
  1309. newLength = 0 ;
  1310. DC_QUIT ;
  1311. }
  1312. if ((L'\\' ==wszOldFilepath[0]) && (L'\\' ==wszOldFilepath[1]))
  1313. {
  1314. while ((0 != remainingLength) && (L'\\' != wszOldFilepath[remainingLength]))
  1315. {
  1316. remainingLength-- ;
  1317. }
  1318. // Add the length of the temp directory path, and subtract the
  1319. // path preceeding the filename ("path\filename" -> "\filename")
  1320. // (\\server\sharename\path\morepath\filename
  1321. newLength = oldLength - remainingLength + wcslen(_CB.tempDirW) ;
  1322. }
  1323. DC_EXIT_POINT:
  1324. DC_END_FN() ;
  1325. return (newLength + 1) * charSize ; // +1 is for the NULL terminator
  1326. }
  1327. UINT CClip::ClipGetNewFilePathLengthA(char* szOldFilepath)
  1328. {
  1329. UINT oldLength = strlen(szOldFilepath) ;
  1330. UINT newLength = oldLength ;
  1331. UINT remainingLength = oldLength ;
  1332. byte charSize = sizeof(char) ;
  1333. DC_BEGIN_FN("CClip::ClipGetNewFilePathLengthA") ;
  1334. // if the old filename didn't even have space for "c:\" (with NULL),
  1335. // then it's probably invalid
  1336. if (4 > oldLength)
  1337. {
  1338. newLength = 0 ;
  1339. DC_QUIT ;
  1340. }
  1341. if (('\\' == szOldFilepath[0]) && ('\\' == szOldFilepath[1]))
  1342. {
  1343. while ((0 != remainingLength) && ('\\' != szOldFilepath[remainingLength]))
  1344. {
  1345. remainingLength-- ;
  1346. }
  1347. // Add the length of the temp directory path, and subtract the
  1348. // path preceeding the filename ("path\filename" -> "\filename")
  1349. // (\\server\sharename\path\morepath\filename
  1350. newLength = oldLength - remainingLength + strlen(_CB.tempDirA) ;
  1351. }
  1352. DC_EXIT_POINT:
  1353. DC_END_FN() ;
  1354. return (newLength + 1) * charSize ; // +1 is for the NULL terminator
  1355. }
  1356. #endif
  1357. //
  1358. // ClipGetNewDropfilesSize
  1359. // - Arguments:
  1360. // pData = Buffer containing a DROPFILES struct
  1361. // oldSize = The size of the DROPFILES struct
  1362. // fWide = Wide or Ansi (TRUE if wide, FALSE if ansi)
  1363. // - Returns new size of the drop file
  1364. // 0 if it fails
  1365. // - Given a set of paths, this function will return the new
  1366. // size required by the DROPFILES struct, if the UNC paths
  1367. // are replaced by the temp directory path
  1368. //
  1369. ULONG CClip::ClipGetNewDropfilesSize(PVOID pData, ULONG oldSize, BOOL fWide)
  1370. {
  1371. DC_BEGIN_FN("CClip::TS_GetNewDropfilesSize") ;
  1372. if (fWide)
  1373. return ClipGetNewDropfilesSizeW(pData, oldSize) ;
  1374. else
  1375. return ClipGetNewDropfilesSizeA(pData, oldSize) ;
  1376. DC_END_FN() ;
  1377. }
  1378. ULONG CClip::ClipGetNewDropfilesSizeW(PVOID pData, ULONG oldSize)
  1379. {
  1380. ULONG newSize = oldSize ;
  1381. #ifndef OS_WINCE
  1382. WCHAR* filenameW ;
  1383. #endif
  1384. WCHAR* fullFilePathW ;
  1385. byte charSize ;
  1386. DC_BEGIN_FN("CClip::TS_GetNewDropfilesSizeW") ;
  1387. charSize = sizeof(WCHAR) ;
  1388. if (!pData)
  1389. {
  1390. TRC_ERR((TB,_T("Pointer to dropfile is NULL"))) ;
  1391. return 0 ;
  1392. }
  1393. #ifdef OS_WINCE
  1394. newSize = 0;
  1395. #endif
  1396. // The start of the first filename
  1397. fullFilePathW = (WCHAR*) ((byte*) pData + ((DROPFILES*) pData)->pFiles) ;
  1398. while (L'\0' != fullFilePathW[0])
  1399. {
  1400. #ifndef OS_WINCE
  1401. // If it is a UNC path
  1402. if (fullFilePathW[0] == L'\\' &&
  1403. fullFilePathW[1] == L'\\')
  1404. {
  1405. filenameW = wcsrchr(fullFilePathW, L'\\');
  1406. // Add the length of the temp directory path, and subtract the
  1407. // path preceeding the filename ("path\filename" -> "\filename")
  1408. // (\\server\sharename\path\morepath\filename
  1409. newSize += (wcslen(_CB.tempDirW) - (filenameW - fullFilePathW) )
  1410. * charSize ;
  1411. }
  1412. #else
  1413. newSize++;
  1414. #endif
  1415. fullFilePathW = fullFilePathW + (wcslen(fullFilePathW) + 1) ;
  1416. }
  1417. #ifdef OS_WINCE
  1418. newSize = oldSize + (newSize*sizeof(CEROOTDIRNAME)); //for the "Files:" (the sizeof operator includes space for the extra null)
  1419. #else
  1420. // Add space for extra null character
  1421. newSize += charSize ;
  1422. #endif
  1423. DC_END_FN() ;
  1424. return newSize ;
  1425. }
  1426. ULONG CClip::ClipGetNewDropfilesSizeA(PVOID pData, ULONG oldSize)
  1427. {
  1428. #ifndef OS_WINCE
  1429. ULONG newSize = oldSize ;
  1430. char* filename ;
  1431. char* fullFilePath ;
  1432. byte charSize ;
  1433. DC_BEGIN_FN("CClip::TS_GetNewDropfilesSizeW") ;
  1434. charSize = sizeof(char) ;
  1435. if (!pData)
  1436. {
  1437. TRC_ERR((TB,_T("Pointer to dropfile is NULL"))) ;
  1438. return 0 ;
  1439. }
  1440. // The start of the first filename
  1441. fullFilePath = (char*) ((byte*) pData + ((DROPFILES*) pData)->pFiles) ;
  1442. while ('\0' != fullFilePath[0])
  1443. {
  1444. // If it is a UNC path
  1445. if (fullFilePath[0] == '\\' &&
  1446. fullFilePath[1] == '\\')
  1447. {
  1448. filename = strrchr(fullFilePath, '\\');
  1449. // Add the length of the temp directory path, and subtract
  1450. // the path preceeding the filename itself, excluding the backlash
  1451. // (\\server\sharename\path\morepath\filename
  1452. newSize += (strlen(_CB.tempDirA) - (filename - fullFilePath) )
  1453. * charSize ;
  1454. }
  1455. fullFilePath = fullFilePath + (strlen(fullFilePath) + 1) ;
  1456. }
  1457. // Add space for extra null character
  1458. newSize += charSize ;
  1459. DC_END_FN() ;
  1460. return newSize ;
  1461. #else
  1462. DC_BEGIN_FN("CClip::TS_GetNewDropfilesSizeA") ;
  1463. TRC_ASSERT((FALSE), (TB, _T("CE doesnt support ClipGetNewDropfilesSizeA")));
  1464. DC_END_FN() ;
  1465. return 0 ;
  1466. #endif
  1467. }
  1468. //
  1469. // ClipSetAndSendTempDirectory
  1470. // - Returns TRUE if temp directory was successfully set and sent
  1471. // FALSE otherwise (no file redirection, or failed sending path)
  1472. // - Sets the Temp paths for the client, and sends the path
  1473. // in wide characters to the Server
  1474. //
  1475. BOOL CClip::ClipSetAndSendTempDirectory(void)
  1476. {
  1477. UINT wResult ;
  1478. BOOL fSuccess ;
  1479. PTS_CLIP_PDU pClipPDU ;
  1480. DCINT32 pduLen ;
  1481. HRESULT hr;
  1482. DC_BEGIN_FN("CClip::ClipSetAndSendTempDirectory") ;
  1483. // if we don't have drive redirection, then don't bother sending a path
  1484. if (!_CB.fDrivesRedirected)
  1485. {
  1486. TRC_ALT((TB, _T("File redirection is off; don't set temp path."))) ;
  1487. fSuccess = FALSE ;
  1488. DC_QUIT ;
  1489. }
  1490. #ifdef OS_WINCE
  1491. if ((fSuccess = InitializeCeShell(_CB.viewerWindow)) == FALSE)
  1492. {
  1493. TRC_ALT((TB, _T("Failed to initialize ceshell. File copy through clipboard disabled."))) ;
  1494. DC_QUIT ;
  1495. }
  1496. #endif
  1497. #ifndef OS_WINCE
  1498. if (0 == GetTempPathA(MAX_PATH, _CB.baseTempDirA))
  1499. {
  1500. TRC_ERR((TB, _T("Failed getting path to temp directory."))) ;
  1501. fSuccess = FALSE ;
  1502. DC_QUIT ;
  1503. }
  1504. // Each session gets it own temp directory
  1505. if (0 == GetTempFileNameA(_CB.baseTempDirA, "_TS", 0, _CB.tempDirA)) {
  1506. TRC_ERR((TB, _T("Getting temp file name failed; GetLastError=%u"),
  1507. GetLastError()));
  1508. fSuccess = FALSE;
  1509. DC_QUIT;
  1510. }
  1511. DeleteFileA(_CB.tempDirA) ;
  1512. if (0 == CreateDirectoryA(_CB.tempDirA, NULL)) {
  1513. TRC_ERR((TB, _T("Creating temp directory failed; GetLastError=%u"),
  1514. GetLastError()));
  1515. fSuccess = FALSE;
  1516. DC_QUIT;
  1517. }
  1518. hr = StringCbCopyA(_CB.baseTempDirA,
  1519. sizeof(_CB.baseTempDirA),
  1520. _CB.tempDirA);
  1521. if (FAILED(hr)) {
  1522. TRC_ERR((TB,_T("Failed to cpy tempdir to basetempdir: 0x%x"),hr));
  1523. fSuccess = FALSE;
  1524. DC_QUIT;
  1525. }
  1526. // We always send MAX_PATH*sizeof(WCHAR) byte for simplicity
  1527. pduLen = MAX_PATH*sizeof(WCHAR) + sizeof(TS_CLIP_PDU);
  1528. // GetACP always returns a valid value
  1529. if (0 == MultiByteToWideChar(GetACP(), MB_ERR_INVALID_CHARS,
  1530. _CB.baseTempDirA, -1, _CB.baseTempDirW,
  1531. sizeof(_CB.baseTempDirW)/(sizeof(_CB.baseTempDirW[0])) - 1))
  1532. {
  1533. TRC_ERR((TB, _T("Failed conversion to wide char; error %d"),
  1534. GetLastError())) ;
  1535. fSuccess = FALSE ;
  1536. DC_QUIT ;
  1537. }
  1538. #else
  1539. if (0 == GetTempPathW(MAX_PATH, _CB.baseTempDirW))
  1540. {
  1541. TRC_ERR((TB, _T("Failed getting path to temp directory."))) ;
  1542. fSuccess = FALSE ;
  1543. DC_QUIT ;
  1544. }
  1545. // Each session gets it own temp directory
  1546. if (0 == GetTempFileNameW(_CB.baseTempDirW, L"_TS", 0, _CB.tempDirW, MAX_PATH-(sizeof(CEROOTDIRNAME)/sizeof(WCHAR)) ) {
  1547. TRC_ERR((TB, _T("Getting temp file name failed; GetLastError=%u"),
  1548. GetLastError()));
  1549. fSuccess = FALSE;
  1550. DC_QUIT;
  1551. }
  1552. DeleteFile(_CB.tempDirW) ;
  1553. if (0 == CreateDirectory(_CB.tempDirW, NULL)) {
  1554. TRC_ERR((TB, _T("Creating temp directory failed; GetLastError=%u"),
  1555. GetLastError()));
  1556. fSuccess = FALSE;
  1557. DC_QUIT;
  1558. }
  1559. wcscpy(_CB.baseTempDirW, _CB.tempDirW) ;
  1560. pduLen = (MAX_PATH*sizeof(WCHAR)) + sizeof(TS_CLIP_PDU);
  1561. #endif
  1562. pClipPDU = (PTS_CLIP_PDU) ClipAlloc(pduLen) ;
  1563. if (!pClipPDU)
  1564. {
  1565. TRC_ERR((TB,_T("Unable to allocate %d bytes"), pduLen));
  1566. fSuccess = FALSE;
  1567. DC_QUIT;
  1568. }
  1569. // Fill in the PDU ; we send a packet of size MAX_PATH for simplicity
  1570. DC_MEMSET(pClipPDU, 0, sizeof(TS_CLIP_PDU));
  1571. pClipPDU->msgType = TS_CB_TEMP_DIRECTORY;
  1572. pClipPDU->dataLen = MAX_PATH*sizeof(WCHAR) ;
  1573. TRC_DBG((TB, _T("Copying all the data")));
  1574. #ifndef OS_WINCE
  1575. ClipMemcpy(pClipPDU->data, _CB.baseTempDirW, pClipPDU->dataLen) ;
  1576. #else
  1577. TSUINT8 *pData;
  1578. int nDSize;
  1579. pData = pClipPDU->data;
  1580. nDSize = sizeof(CEROOTDIRNAME) - sizeof(WCHAR);
  1581. ClipMemcpy(pData, CEROOTDIRNAME, nDSize) ;
  1582. pData += nDSize;
  1583. ClipMemcpy(pData, _CB.baseTempDirW, pClipPDU->dataLen - nDSize) ;
  1584. #endif
  1585. TRC_NRM((TB, _T("Sending temp directory path.")));
  1586. wResult = _CB.channelEP.pVirtualChannelWriteEx
  1587. (_CB.initHandle, _CB.channelHandle, pClipPDU, pduLen, (LPVOID)pClipPDU);
  1588. if (CHANNEL_RC_OK != wResult)
  1589. {
  1590. TRC_ERR((TB, _T("Failed sending temp directory 0x%08x"),
  1591. GetLastError())) ;
  1592. ClipFreeBuf((PDCUINT8)pClipPDU);
  1593. fSuccess = FALSE ;
  1594. DC_QUIT ;
  1595. }
  1596. fSuccess = TRUE ;
  1597. DC_EXIT_POINT:
  1598. DC_END_FN() ;
  1599. return fSuccess ;
  1600. }
  1601. /****************************************************************************/
  1602. /* ClipOnFormatList - we got a list of formats from the server */
  1603. /****************************************************************************/
  1604. DCVOID DCINTERNAL CClip::ClipOnFormatList(PTS_CLIP_PDU pClipPDU)
  1605. {
  1606. DCUINT16 response = TS_CB_RESPONSE_OK;
  1607. DCUINT numFormats;
  1608. TS_CLIP_FORMAT UNALIGNED* fmtList;
  1609. DCUINT i;
  1610. DCTCHAR formatName[TS_FORMAT_NAME_LEN + 1] = { 0 };
  1611. PTS_CLIP_PDU pClipRsp;
  1612. #ifndef OS_WINCE
  1613. DCBOOL fSuccess;
  1614. LPFORMATETC pFormatEtc ;
  1615. #endif
  1616. LPDATAOBJECT pIDataObject = NULL ;
  1617. HRESULT hr ;
  1618. TS_CLIP_PDU UNALIGNED* pUlClipPDU = (TS_CLIP_PDU UNALIGNED*)pClipPDU;
  1619. #ifdef OS_WINCE
  1620. DCUINT uRtf1 = 0xffffffff, uRtf2 = 0xffffffff;
  1621. #endif
  1622. DC_BEGIN_FN("CClip::ClipOnFormatList");
  1623. if (_pClipData == NULL) {
  1624. TRC_ALT((TB, _T("The clipData is NULL, we just bail")));
  1625. DC_QUIT;
  1626. }
  1627. /************************************************************************/
  1628. /* Do state checks */
  1629. /************************************************************************/
  1630. CB_CHECK_STATE(CB_EVENT_FORMAT_LIST);
  1631. if (_CB.state == CB_STATE_PENDING_FORMAT_LIST_RSP)
  1632. {
  1633. /********************************************************************/
  1634. /* we've just sent a format list to the server. We always win, so */
  1635. /* we just ignore this message. */
  1636. /********************************************************************/
  1637. TRC_ALT((TB, _T("Format list race - we win so ignoring")));
  1638. DC_QUIT;
  1639. }
  1640. /************************************************************************/
  1641. /* Sanity check */
  1642. /************************************************************************/
  1643. if (_CB.clipOpen)
  1644. {
  1645. TRC_ALT((TB, _T("Clipboard is still open")));
  1646. }
  1647. /****************************************************************/
  1648. /* empty the client/server mapping table */
  1649. /****************************************************************/
  1650. DC_MEMSET(_CB.idMap, 0, sizeof(_CB.idMap));
  1651. /****************************************************************/
  1652. /* work out how many formats we got */
  1653. /****************************************************************/
  1654. numFormats = (pUlClipPDU->dataLen) / sizeof(TS_CLIP_FORMAT);
  1655. TRC_NRM((TB, _T("PDU contains %d formats"), numFormats));
  1656. hr = _pClipData->SetNumFormats(numFormats) ;
  1657. if (SUCCEEDED(hr)) {
  1658. hr = _pClipData->QueryInterface(IID_IDataObject, (PPVOID) &pIDataObject) ;
  1659. }
  1660. #ifdef OS_WINCE
  1661. if (SUCCEEDED(hr))
  1662. {
  1663. if (OpenClipboard(_CB.dataWindow))
  1664. {
  1665. if (EmptyClipboard())
  1666. {
  1667. hr = S_OK;
  1668. }
  1669. else
  1670. {
  1671. CloseClipboard();
  1672. hr = MAKE_HRESULT(SEVERITY_ERROR, FACILITY_WINDOWS, GetLastError());
  1673. DC_QUIT;
  1674. }
  1675. }
  1676. else
  1677. {
  1678. hr = MAKE_HRESULT(SEVERITY_ERROR, FACILITY_WINDOWS, GetLastError());
  1679. DC_QUIT;
  1680. }
  1681. }
  1682. #endif
  1683. if (SUCCEEDED(hr)) {
  1684. TRC_ASSERT((numFormats <= CB_MAX_FORMATS),
  1685. (TB, _T("Format list contains more than %d formats"),
  1686. CB_MAX_FORMATS));
  1687. /****************************************************************/
  1688. /* and register them */
  1689. /****************************************************************/
  1690. fmtList = (TS_CLIP_FORMAT UNALIGNED*)pUlClipPDU->data;
  1691. for (i = 0; i < numFormats; i++)
  1692. {
  1693. TRC_DBG((TB, _T("format number %d, server id %d"),
  1694. i, fmtList[i].formatID));
  1695. //
  1696. // If file copy and paste is disabled, we don't accept HDROPs.
  1697. //
  1698. if (fmtList[i].formatID == CF_HDROP && _CB.fFileCutCopyOn == FALSE) {
  1699. continue;
  1700. }
  1701. /****************************************************************/
  1702. /* If we got a name... */
  1703. /****************************************************************/
  1704. if (fmtList[i].formatName[0] != 0)
  1705. {
  1706. /************************************************************/
  1707. /* clear out any garbage */
  1708. /************************************************************/
  1709. #ifndef OS_WINCE
  1710. DC_MEMSET(formatName, 0, TS_FORMAT_NAME_LEN);
  1711. #else
  1712. DC_MEMSET(formatName, 0, sizeof(formatName));
  1713. #endif
  1714. //
  1715. // fmtList[i].formatName is not NULL terminated so explicity
  1716. // do a byte count copy
  1717. //
  1718. StringCbCopy(formatName, TS_FORMAT_NAME_LEN + sizeof(TCHAR),
  1719. (PDCTCHAR)(fmtList[i].formatName));
  1720. if (ClipIsExcludedFormat(formatName))
  1721. {
  1722. TRC_NRM((TB, _T("Dropped format '%s'"), formatName));
  1723. continue;
  1724. }
  1725. /************************************************************/
  1726. /* name is sorted */
  1727. /************************************************************/
  1728. TRC_NRM((TB, _T("Got name '%s'"), formatName));
  1729. }
  1730. else
  1731. {
  1732. DC_MEMSET(formatName, 0, TS_FORMAT_NAME_LEN);
  1733. }
  1734. /****************************************************************/
  1735. /* store the server id */
  1736. /****************************************************************/
  1737. _CB.idMap[i].serverID = fmtList[i].formatID;
  1738. TRC_NRM((TB, _T("server id %d"), _CB.idMap[i].serverID));
  1739. /****************************************************************/
  1740. /* get local name (if needed) */
  1741. /****************************************************************/
  1742. if (formatName[0] != 0)
  1743. {
  1744. #ifdef OS_WINCE
  1745. //The protocol limits clipboard format names to 16 widechars. Thus it becomes impossible
  1746. //to distinguish between "Rich Text Format" and "Rich Text Format Without Objects"
  1747. //This should be removed once the protocol is fixed in Longhorn
  1748. if (0 == DC_TSTRNCMP(formatName, CFSTR_RTF, (sizeof(CFSTR_RTF)/sizeof(TCHAR)) - 1))
  1749. {
  1750. if (uRtf1 == 0xffffffff)
  1751. uRtf1 = i;
  1752. else
  1753. uRtf2 = i;
  1754. continue;
  1755. }
  1756. else
  1757. #endif
  1758. _CB.idMap[i].clientID = RegisterClipboardFormat(formatName);
  1759. }
  1760. else
  1761. {
  1762. /************************************************************/
  1763. /* it's a predefined format so we can just use the ID */
  1764. /************************************************************/
  1765. _CB.idMap[i].clientID = _CB.idMap[i].serverID;
  1766. }
  1767. #ifdef OS_WINCE
  1768. if (_CB.idMap[i].serverID == CF_HDROP)
  1769. _CB.idMap[i].clientID = gfmtShellPidlArray;
  1770. #endif
  1771. /************************************************************/
  1772. /* and add the format to the local CB */
  1773. /************************************************************/
  1774. TRC_DBG((TB, _T("Adding format '%s', server ID %d, client ID %d"),
  1775. fmtList[i].formatName,
  1776. _CB.idMap[i].serverID,
  1777. _CB.idMap[i].clientID));
  1778. if (0 != _CB.idMap[i].clientID) {
  1779. #ifndef OS_WINCE
  1780. pFormatEtc = new FORMATETC ;
  1781. if (pFormatEtc) {
  1782. pFormatEtc->cfFormat = (CLIPFORMAT) _CB.idMap[i].clientID ;
  1783. pFormatEtc->dwAspect = DVASPECT_CONTENT ;
  1784. pFormatEtc->ptd = NULL ;
  1785. pFormatEtc->lindex = -1 ;
  1786. pFormatEtc->tymed = TYMED_HGLOBAL ;
  1787. // Need to set the clipboard state before SetData.
  1788. CB_SET_STATE(CB_STATE_LOCAL_CB_OWNER, CB_EVENT_FORMAT_LIST);
  1789. pIDataObject->SetData(pFormatEtc, NULL, TRUE) ;
  1790. delete pFormatEtc;
  1791. }
  1792. #else
  1793. CB_SET_STATE(CB_STATE_LOCAL_CB_OWNER, CB_EVENT_FORMAT_LIST);
  1794. SetClipboardData((CLIPFORMAT) _CB.idMap[i].clientID, NULL);
  1795. #endif
  1796. }
  1797. else
  1798. TRC_NRM((TB,_T("Invalid format dropped"))) ;
  1799. }
  1800. #ifdef OS_WINCE
  1801. //we will choose the lower format id as belonging to "Rich Text Format"
  1802. //This is our best guess and it seems to work
  1803. ClipFixupRichTextFormats(uRtf1, uRtf2);
  1804. #endif
  1805. #ifndef OS_WINCE
  1806. hr = OleSetClipboard(pIDataObject) ;
  1807. #else
  1808. EnterCriticalSection(&gcsDataObj);
  1809. if (gpDataObj)
  1810. gpDataObj->Release();
  1811. pIDataObject->AddRef();
  1812. gpDataObj = pIDataObject;
  1813. LeaveCriticalSection(&gcsDataObj);
  1814. hr = S_OK;
  1815. CloseClipboard();
  1816. #endif
  1817. if (pIDataObject)
  1818. pIDataObject->Release();
  1819. if (SUCCEEDED(hr))
  1820. {
  1821. response = TS_CB_RESPONSE_OK;
  1822. _CB.clipOpen = FALSE ;
  1823. }
  1824. else
  1825. {
  1826. TRC_ERR((TB, _T("OleSetClipboard failed, error = 0x%08x"), hr)) ;
  1827. response = TS_CB_RESPONSE_FAIL;
  1828. _CB.clipOpen = FALSE ;
  1829. }
  1830. }
  1831. else
  1832. {
  1833. if (pIDataObject)
  1834. pIDataObject->Release();
  1835. TRC_ERR((TB, _T("Error getting pointer to an IDataObject"))) ;
  1836. pIDataObject = NULL ;
  1837. response = TS_CB_RESPONSE_FAIL ;
  1838. }
  1839. /************************************************************************/
  1840. /* Now build the response */
  1841. /************************************************************************/
  1842. TRC_NRM((TB, _T("Get perm TX buffer")));
  1843. pClipRsp = ClipGetPermBuf();
  1844. /************************************************************************/
  1845. /* and now the specific bits */
  1846. /************************************************************************/
  1847. pClipRsp->msgType = TS_CB_FORMAT_LIST_RESPONSE;
  1848. pClipRsp->msgFlags = response;
  1849. pClipRsp->dataLen = 0;
  1850. /************************************************************************/
  1851. /* finally we send it */
  1852. /************************************************************************/
  1853. if (_CB.channelEP.pVirtualChannelWriteEx
  1854. (_CB.initHandle, _CB.channelHandle, pClipRsp, sizeof(TS_CLIP_PDU), (LPVOID)pClipRsp)
  1855. != CHANNEL_RC_OK)
  1856. {
  1857. TRC_ERR((TB, _T("Failed VC write: setting clip data to NULL")));
  1858. ClipFreeBuf((PDCUINT8)pClipRsp);
  1859. response = TS_CB_RESPONSE_FAIL ;
  1860. }
  1861. /************************************************************************/
  1862. /* Update the state according to how we got on */
  1863. /************************************************************************/
  1864. if (response == TS_CB_RESPONSE_OK)
  1865. {
  1866. CB_SET_STATE(CB_STATE_LOCAL_CB_OWNER, CB_EVENT_FORMAT_LIST);
  1867. }
  1868. else
  1869. {
  1870. CB_SET_STATE(CB_STATE_ENABLED, CB_EVENT_FORMAT_LIST);
  1871. }
  1872. DC_EXIT_POINT:
  1873. DC_END_FN();
  1874. return;
  1875. } /* ClipOnFormatList */
  1876. /****************************************************************************/
  1877. /* ClipOnFormatListResponse - got the format list response */
  1878. /****************************************************************************/
  1879. DCVOID DCINTERNAL CClip::ClipOnFormatListResponse(PTS_CLIP_PDU pClipPDU)
  1880. {
  1881. DC_BEGIN_FN("CClip::ClipOnFormatListResponse");
  1882. CB_CHECK_STATE(CB_EVENT_FORMAT_LIST_RSP);
  1883. /************************************************************************/
  1884. /* if the response is OK... */
  1885. /************************************************************************/
  1886. if (pClipPDU->msgFlags & TS_CB_RESPONSE_OK)
  1887. {
  1888. /********************************************************************/
  1889. /* we are now the shared CB owner */
  1890. /********************************************************************/
  1891. TRC_NRM((TB, _T("Got OK fmt list rsp")));
  1892. CB_SET_STATE(CB_STATE_SHARED_CB_OWNER, CB_EVENT_FORMAT_LIST_RSP);
  1893. }
  1894. else
  1895. {
  1896. /********************************************************************/
  1897. /* nothing specific to do */
  1898. /********************************************************************/
  1899. TRC_ALT((TB, _T("Got fmt list rsp failed")));
  1900. CB_SET_STATE(CB_STATE_ENABLED, CB_EVENT_FORMAT_LIST_RSP);
  1901. }
  1902. /************************************************************************/
  1903. /* There may have been another update while we were waiting - deal with */
  1904. /* it by faking an update here */
  1905. /************************************************************************/
  1906. if (_CB.moreToDo == TRUE)
  1907. {
  1908. TRC_ALT((TB, _T("More to do on list rsp")));
  1909. _CB.moreToDo = FALSE;
  1910. ClipDrawClipboard(FALSE);
  1911. }
  1912. DC_EXIT_POINT:
  1913. DC_END_FN();
  1914. return;
  1915. } /* ClipOnFormatListResponse */
  1916. /****************************************************************************/
  1917. // ClipOnFormatRequest
  1918. // - Server wants a format
  1919. /****************************************************************************/
  1920. DCVOID DCINTERNAL CClip::ClipOnFormatRequest(PTS_CLIP_PDU pClipPDU)
  1921. {
  1922. DCUINT32 formatID;
  1923. DCUINT32 dataLen = 0;
  1924. DCUINT numEntries;
  1925. DCUINT16 dwEntries;
  1926. HANDLE hData = NULL;
  1927. HANDLE hNewData = NULL;
  1928. HPDCVOID pData = NULL;
  1929. DROPFILES* pDropFiles ;
  1930. #ifndef OS_WINCE
  1931. DROPFILES tempDropfile ;
  1932. #endif
  1933. HPDCVOID pNewData = NULL;
  1934. DCUINT16 response = TS_CB_RESPONSE_OK;
  1935. PTS_CLIP_PDU pClipRsp = NULL;
  1936. PTS_CLIP_PDU pClipNew;
  1937. DCUINT32 pduLen;
  1938. BOOL fDrivePath ;
  1939. BOOL fWide ;
  1940. byte charSize ;
  1941. ULONG newSize, oldSize ;
  1942. HPDCVOID pOldFilename ;
  1943. HPDCVOID pFileList = NULL ;
  1944. HPDCVOID pTmpFileList = NULL;
  1945. HPDCVOID pFilename = NULL ;
  1946. #ifndef OS_WINCE
  1947. char* fileList ;
  1948. WCHAR* fileListW ;
  1949. SHFILEOPSTRUCTA fileOpStructA ;
  1950. SHFILEOPSTRUCTW fileOpStructW ;
  1951. HRESULT result ;
  1952. DCTCHAR formatName[TS_FORMAT_NAME_LEN] ;
  1953. #endif
  1954. HRESULT hr;
  1955. DC_BEGIN_FN("CClip::ClipOnFormatRequest");
  1956. //
  1957. // Set the response to failure before making the state check
  1958. //
  1959. response = TS_CB_RESPONSE_FAIL;
  1960. CB_CHECK_STATE(CB_EVENT_FORMAT_DATA_RQ);
  1961. response = TS_CB_RESPONSE_OK;
  1962. /************************************************************************/
  1963. /* Make sure the local CB is open */
  1964. /************************************************************************/
  1965. if ((_CB.rcvOpen) || OpenClipboard(_CB.viewerWindow))
  1966. {
  1967. /********************************************************************/
  1968. /* It was/is open */
  1969. /********************************************************************/
  1970. TRC_NRM((TB, _T("CB opened")));
  1971. _CB.rcvOpen = TRUE;
  1972. /********************************************************************/
  1973. /* Extract the format from the PDU */
  1974. /********************************************************************/
  1975. TRC_DATA_DBG("pdu data", pClipPDU->data, (DCUINT)pClipPDU->dataLen);
  1976. //
  1977. // Verify that we have enough data to extract a format ID.
  1978. //
  1979. if (pClipPDU->dataLen < sizeof(DCUINT32)) {
  1980. TRC_ERR((TB,_T("Not enough data to extract a format ID.")));
  1981. _CB.channelEP.pVirtualChannelCloseEx(_CB.initHandle, _CB.channelHandle);
  1982. response = TS_CB_RESPONSE_FAIL;
  1983. dataLen = 0;
  1984. DC_QUIT ;
  1985. }
  1986. formatID = *((PDCUINT32_UA)pClipPDU->data);
  1987. TRC_NRM((TB, _T("Requesting format %ld"), formatID));
  1988. /********************************************************************/
  1989. /* If the Server asked for CF_DIB, we may have to translate from */
  1990. /* CF_BITMAP */
  1991. /********************************************************************/
  1992. if ((formatID == CF_DIB) && (!_CB.DIBFormatExists))
  1993. {
  1994. TRC_NRM((TB, _T("Server asked for CF_DIB - get CF_BITMAP")));
  1995. formatID = CF_BITMAP;
  1996. }
  1997. /********************************************************************/
  1998. /* Get a handle to the data */
  1999. /********************************************************************/
  2000. #ifdef OS_WINCE
  2001. if (formatID == CF_HDROP)
  2002. formatID = gfmtShellPidlArray;
  2003. #endif
  2004. hData = GetClipboardData((UINT)formatID);
  2005. TRC_DBG((TB, _T("Got format %ld at %p"), formatID, hData));
  2006. if (hData == NULL)
  2007. {
  2008. /****************************************************************/
  2009. /* Oops! */
  2010. /****************************************************************/
  2011. TRC_ERR((TB, _T("Failed to get format %ld"), formatID));
  2012. response = TS_CB_RESPONSE_FAIL;
  2013. dataLen = 0;
  2014. DC_QUIT ;
  2015. }
  2016. else
  2017. {
  2018. /****************************************************************/
  2019. /* Got handle, now what happens next depends on the flavour of */
  2020. /* data we're looking at... */
  2021. /****************************************************************/
  2022. if (formatID == CF_PALETTE)
  2023. {
  2024. TRC_DBG((TB, _T("CF_PALETTE requested")));
  2025. /************************************************************/
  2026. /* Find out how many entries there are in the palette and */
  2027. /* allocate enough memory to hold them all. */
  2028. /************************************************************/
  2029. if (GetObject(hData, sizeof(DCUINT16), &dwEntries) == 0)
  2030. {
  2031. TRC_DBG((TB, _T("Failed to get count of palette entries")));
  2032. dwEntries = 256;
  2033. }
  2034. numEntries = (DCUINT)dwEntries;
  2035. TRC_DBG((TB, _T("Need mem for %u palette entries"), numEntries));
  2036. dataLen = sizeof(LOGPALETTE) - sizeof(PALETTEENTRY) +
  2037. (numEntries * sizeof(PALETTEENTRY));
  2038. hNewData = GlobalAlloc(GHND, dataLen);
  2039. if (hNewData == 0)
  2040. {
  2041. TRC_ERR((TB, _T("Failed to get %ld bytes for palette"),
  2042. dataLen));
  2043. response = TS_CB_RESPONSE_FAIL;
  2044. dataLen = 0;
  2045. DC_QUIT ;
  2046. }
  2047. else
  2048. {
  2049. /********************************************************/
  2050. /* now get the palette entries into the new buffer */
  2051. /********************************************************/
  2052. pData = (HPDCUINT8)GlobalLock(hNewData);
  2053. if (NULL == pData) {
  2054. TRC_ERR((TB,_T("Failed to lock palette entries")));
  2055. response = TS_CB_RESPONSE_FAIL;
  2056. dataLen = 0;
  2057. DC_QUIT;
  2058. }
  2059. numEntries = GetPaletteEntries((HPALETTE)hData,
  2060. 0,
  2061. numEntries,
  2062. (PALETTEENTRY*)pData);
  2063. TRC_DATA_DBG("Palette entries", pData, (DCUINT)dataLen);
  2064. GlobalUnlock(hNewData);
  2065. TRC_DBG((TB, _T("Got %u palette entries"), numEntries));
  2066. if (numEntries == 0)
  2067. {
  2068. TRC_ERR((TB, _T("Failed to get any palette entries")));
  2069. response = TS_CB_RESPONSE_FAIL;
  2070. dataLen = 0;
  2071. DC_QUIT ;
  2072. }
  2073. dataLen = numEntries * sizeof(PALETTEENTRY);
  2074. /********************************************************/
  2075. /* all ok - set up hData to point to the new data */
  2076. /********************************************************/
  2077. hData = hNewData;
  2078. }
  2079. }
  2080. #ifndef OS_WINCE
  2081. else if (formatID == CF_METAFILEPICT)
  2082. {
  2083. TRC_NRM((TB, _T("Metafile data to get")));
  2084. hNewData = ClipGetMFData(hData, &dataLen);
  2085. if (!hNewData)
  2086. {
  2087. TRC_ERR((TB, _T("Failed to set MF data")));
  2088. response = TS_CB_RESPONSE_FAIL;
  2089. dataLen = 0;
  2090. DC_QUIT ;
  2091. }
  2092. else
  2093. {
  2094. /********************************************************/
  2095. /* all ok - set up hData to point to the new data */
  2096. /********************************************************/
  2097. hData = hNewData;
  2098. }
  2099. }
  2100. #endif
  2101. else if (formatID == CF_BITMAP)
  2102. {
  2103. /************************************************************/
  2104. /* We've gt CF_BITMAP data. This will be because the */
  2105. /* Server has asked for CF_DIB data - we never send */
  2106. /* CF_BITMAP to the Server. Convert it to CF_DIB format. */
  2107. /************************************************************/
  2108. TRC_NRM((TB, _T("Convert CF_BITMAP to CF_DIB")));
  2109. hNewData = ClipBitmapToDIB(hData, &dataLen);
  2110. if (hNewData)
  2111. {
  2112. hData = hNewData;
  2113. }
  2114. else
  2115. {
  2116. response = TS_CB_RESPONSE_FAIL;
  2117. dataLen = 0;
  2118. DC_QUIT ;
  2119. }
  2120. }
  2121. // Since we won't even send an HDROP format to the server if the
  2122. // local drives are redirected, and we always send a new formatlist
  2123. // when we reconnect to a server, this does not have to be touched
  2124. #ifndef OS_WINCE
  2125. else if (formatID == CF_HDROP)
  2126. #else
  2127. else if (formatID == gfmtShellPidlArray)
  2128. #endif
  2129. {
  2130. SIZE_T cbDropFiles;
  2131. BYTE *pbLastByte, *pbStartByte, *pbLastPossibleNullStart;
  2132. BOOL fTrailingFileNamesValid;
  2133. ULONG cbRemaining;
  2134. TRC_NRM((TB,_T("HDROP requested"))) ;
  2135. #ifdef OS_WINCE
  2136. HANDLE hPidlArray = IDListToHDrop(hData);
  2137. if (!hPidlArray)
  2138. {
  2139. TRC_ERR((TB,_T("Failed to get file list from clipboard"))) ;
  2140. response = TS_CB_RESPONSE_FAIL;
  2141. dataLen = 0;
  2142. DC_QUIT ;
  2143. }
  2144. hData = hPidlArray;
  2145. #endif
  2146. //
  2147. // Make sure that we have at least a DROPFILES structure in
  2148. // memory.
  2149. cbDropFiles = GlobalSize(hData);
  2150. if (cbDropFiles < sizeof(DROPFILES)) {
  2151. TRC_ERR((TB,_T("Unexpected global memory size!"))) ;
  2152. _CB.channelEP.pVirtualChannelCloseEx(_CB.initHandle, _CB.channelHandle);
  2153. response = TS_CB_RESPONSE_FAIL;
  2154. dataLen = 0;
  2155. DC_QUIT ;
  2156. }
  2157. pDropFiles = (DROPFILES*) GlobalLock(hData) ;
  2158. if (!pDropFiles)
  2159. {
  2160. TRC_ERR((TB,_T("Failed to lock %p"), hData)) ;
  2161. response = TS_CB_RESPONSE_FAIL;
  2162. dataLen = 0;
  2163. DC_QUIT ;
  2164. }
  2165. fWide = ((DROPFILES*) pDropFiles)->fWide ;
  2166. charSize = fWide ? sizeof(WCHAR) : sizeof(char) ;
  2167. //
  2168. // Check that the data behind the DROPFILES data structure
  2169. // pointed to by pDropFiles is valid. Every drop file list
  2170. // is terminated by two NULL characters. So, simply scan
  2171. // through the memory after the DROPFILES structure and make
  2172. // sure that there is a double NULL before the last byte.
  2173. //
  2174. if (pDropFiles->pFiles < sizeof(DROPFILES)
  2175. || pDropFiles->pFiles > cbDropFiles) {
  2176. TRC_ERR((TB,_T("File name offset invalid!"))) ;
  2177. _CB.channelEP.pVirtualChannelCloseEx(_CB.initHandle, _CB.channelHandle);
  2178. response = TS_CB_RESPONSE_FAIL;
  2179. dataLen = 0;
  2180. DC_QUIT ;
  2181. }
  2182. pbStartByte = (BYTE*) pDropFiles + pDropFiles->pFiles;
  2183. pbLastByte = (BYTE*) pDropFiles + cbDropFiles - 1;
  2184. fTrailingFileNamesValid = FALSE;
  2185. //
  2186. // Make pbLastPossibleNullStart point to the last place where a
  2187. // double NULL could possibly start.
  2188. //
  2189. // Examples: Assume pbLastByte = 9
  2190. // Then for ASCII: pbLastPossibleNullStart = 8 (9 - 2 * 1 + 1)
  2191. // And for UNICODE: pbLastPossibleNullStart = 6 (9 - 2 * 2 + 1)
  2192. //
  2193. pbLastPossibleNullStart = pbLastByte - (2 * charSize) + 1;
  2194. if (fWide) {
  2195. for (WCHAR* pwch = (WCHAR*) pbStartByte; (BYTE*) pwch <= pbLastPossibleNullStart; pwch++) {
  2196. if (*pwch == NULL && *(pwch + 1) == NULL) {
  2197. fTrailingFileNamesValid = TRUE;
  2198. }
  2199. }
  2200. } else {
  2201. for (BYTE* pch = pbStartByte; pch <= pbLastPossibleNullStart; pch++) {
  2202. if (*pch == NULL && *(pch + 1) == NULL) {
  2203. fTrailingFileNamesValid = TRUE;
  2204. }
  2205. }
  2206. }
  2207. if (!fTrailingFileNamesValid) {
  2208. TRC_ERR((TB,_T("DROPFILES structure invalid!"))) ;
  2209. _CB.channelEP.pVirtualChannelCloseEx(_CB.initHandle, _CB.channelHandle);
  2210. response = TS_CB_RESPONSE_FAIL;
  2211. dataLen = 0;
  2212. DC_QUIT;
  2213. }
  2214. //
  2215. // DROPFILES are valid so we can continue.
  2216. //
  2217. if (!_CB.fAlreadyCopied)
  2218. {
  2219. // if it's not a drive path, then copy to a temp directory
  2220. pFileList = (byte*)pDropFiles + pDropFiles->pFiles ;
  2221. #ifndef OS_WINCE
  2222. fDrivePath = fWide ? (0 != wcschr((WCHAR*) pFileList, L':'))
  2223. : (0 != strchr((char*) pFileList, ':')) ;
  2224. #else //copy to temp dir if it is a network path
  2225. fDrivePath = fWide ? (! ( (((WCHAR *)pFileList)[0] == L'\\') && (((WCHAR *)pFileList)[1] == L'\\')) )
  2226. : (! ( (((CHAR *)pFileList)[0] == '\\') && (((CHAR *)pFileList)[1] == '\\')) ) ;
  2227. #endif
  2228. if (!fDrivePath)
  2229. {
  2230. // ClipCopyToTempDirectory returns 0 if successful
  2231. if (0 != ClipCopyToTempDirectory(pFileList, fWide))
  2232. {
  2233. TRC_ERR((TB,_T("Copy to tmp directory failed"))) ;
  2234. response = TS_CB_RESPONSE_FAIL;
  2235. dataLen = 0;
  2236. _CB.fAlreadyCopied = TRUE ;
  2237. DC_QUIT ;
  2238. }
  2239. }
  2240. _CB.fAlreadyCopied = TRUE ;
  2241. }
  2242. // Now that we copied the files, we want to convert the file
  2243. // paths to something the server will understand
  2244. // Allocate space for new filepaths
  2245. oldSize = (ULONG) GlobalSize(hData) ;
  2246. newSize = ClipGetNewDropfilesSize(pDropFiles, oldSize, fWide) ;
  2247. hNewData = GlobalAlloc(GMEM_DISCARDABLE | GMEM_MOVEABLE, newSize) ;
  2248. if (!hNewData)
  2249. {
  2250. TRC_ERR((TB, _T("Failed to get %ld bytes for HDROP"),
  2251. newSize));
  2252. response = TS_CB_RESPONSE_FAIL;
  2253. dataLen = 0;
  2254. DC_QUIT ;
  2255. }
  2256. pNewData = GlobalLock(hNewData) ;
  2257. if (!pNewData)
  2258. {
  2259. TRC_ERR((TB, _T("Failed to get lock %p for HDROP"),
  2260. hNewData));
  2261. response = TS_CB_RESPONSE_FAIL;
  2262. dataLen = 0;
  2263. DC_QUIT ;
  2264. }
  2265. // Just copy the old DROPFILES data members (unchanged)
  2266. ((DROPFILES*) pNewData)->pFiles = pDropFiles->pFiles ;
  2267. ((DROPFILES*) pNewData)->pt = pDropFiles->pt ;
  2268. ((DROPFILES*) pNewData)->fNC = pDropFiles->fNC ;
  2269. ((DROPFILES*) pNewData)->fWide = pDropFiles->fWide ;
  2270. // The first filename in a DROPFILES data structure begins
  2271. // DROPFILES.pFiles bytes away from the head of the DROPFILES
  2272. pOldFilename = (byte*) pDropFiles + ((DROPFILES*) pDropFiles)->pFiles ;
  2273. pFilename = (byte*) pNewData + ((DROPFILES*) pNewData)->pFiles ;
  2274. pbLastByte = (BYTE*) pNewData + newSize - 1;
  2275. cbRemaining = (ULONG) (pbLastByte - (BYTE*) pFilename + 1);
  2276. while (fWide ? (L'\0' != ((WCHAR*) pOldFilename)[0]) : ('\0' != ((char*) pOldFilename)[0]))
  2277. {
  2278. if (FAILED(ClipConvertToTempPath(pOldFilename, pFilename, cbRemaining, fWide)))
  2279. {
  2280. TRC_ERR((TB, _T("Failed conversion"))) ;
  2281. response = TS_CB_RESPONSE_FAIL;
  2282. dataLen = 0 ;
  2283. DC_QUIT ;
  2284. }
  2285. if (fWide)
  2286. {
  2287. pOldFilename = (byte*) pOldFilename + (wcslen((WCHAR*)pOldFilename) + 1) * sizeof(WCHAR) ;
  2288. pFilename = (byte*) pFilename + (wcslen((WCHAR*)pFilename) + 1) * sizeof(WCHAR) ;
  2289. }
  2290. else
  2291. {
  2292. pOldFilename = (byte*) pOldFilename + (strlen((char*)pOldFilename) + 1) * sizeof(char) ;
  2293. pFilename = (byte*) pFilename + (strlen((char*)pFilename) + 1) * sizeof(char) ;
  2294. }
  2295. cbRemaining = (ULONG) (pbLastByte - (BYTE*) pFilename + 1);
  2296. }
  2297. if (fWide)
  2298. {
  2299. ((WCHAR*) pFilename)[0] = L'\0' ;
  2300. }
  2301. else
  2302. {
  2303. ((char*) pFilename)[0] = '\0' ;
  2304. }
  2305. GlobalUnlock(hNewData) ;
  2306. hData = hNewData ;
  2307. response = TS_CB_RESPONSE_OK ;
  2308. dataLen = (ULONG) GlobalSize(hData) ;
  2309. #ifdef OS_WINCE
  2310. GlobalFree(hPidlArray);
  2311. #endif
  2312. }
  2313. else
  2314. {
  2315. #ifndef OS_WINCE
  2316. // Check to see if we are processing the FileName/FileNameW
  2317. // OLE 1 formats; if so, we convert th
  2318. if (0 != GetClipboardFormatName(formatID, formatName, TS_FORMAT_NAME_LEN))
  2319. {
  2320. if ((0 == _tcscmp(formatName, TEXT("FileName"))) ||
  2321. (0 == _tcscmp(formatName, TEXT("FileNameW"))))
  2322. {
  2323. size_t cbOldFileName;
  2324. if (!_tcscmp(formatName, TEXT("FileNameW")))
  2325. {
  2326. fWide = TRUE ;
  2327. charSize = sizeof(WCHAR) ;
  2328. }
  2329. else
  2330. {
  2331. fWide = FALSE ;
  2332. charSize = 1 ;
  2333. }
  2334. //
  2335. // Extract the file name, but ensure that it is properly
  2336. // NULL terminated.
  2337. //
  2338. pOldFilename = GlobalLock(hData);
  2339. if (!pOldFilename)
  2340. {
  2341. TRC_ERR((TB, _T("No filename/Unable to lock %p"),
  2342. hData));
  2343. response = TS_CB_RESPONSE_FAIL;
  2344. dataLen = 0;
  2345. DC_QUIT ;
  2346. }
  2347. oldSize = (ULONG) GlobalSize(hData) ;
  2348. if (fWide) {
  2349. hr = StringCbLengthW((WCHAR*) pOldFilename,
  2350. oldSize,
  2351. &cbOldFileName);
  2352. } else {
  2353. hr = StringCbLengthA((CHAR*) pOldFilename,
  2354. oldSize,
  2355. &cbOldFileName);
  2356. }
  2357. if (FAILED(hr)) {
  2358. TRC_ERR((TB, _T("File name not NULL terminated!")));
  2359. _CB.channelEP.pVirtualChannelCloseEx(_CB.initHandle, _CB.channelHandle);
  2360. response = TS_CB_RESPONSE_FAIL;
  2361. dataLen = 0;
  2362. DC_QUIT ;
  2363. }
  2364. if (!_CB.fAlreadyCopied)
  2365. {
  2366. // if its not a drive path, then copy to a temp
  2367. // directory. We have to copy over the filename to
  2368. // string that is one character larger, because we
  2369. // need to add an extra NULL for the SHFileOperation
  2370. UINT cbSize= oldSize + charSize;
  2371. pTmpFileList = LocalAlloc(LPTR, cbSize);
  2372. if (NULL == pTmpFileList) {
  2373. TRC_ERR((TB,_T("pTmpFileList alloc failed")));
  2374. response = TS_CB_RESPONSE_FAIL;
  2375. dataLen = 0;
  2376. _CB.fAlreadyCopied = TRUE;
  2377. DC_QUIT ;
  2378. }
  2379. if (fWide)
  2380. {
  2381. hr = StringCbCopyW((WCHAR*)pTmpFileList, cbSize,
  2382. (WCHAR*)pOldFilename) ;
  2383. fDrivePath = (0 != wcschr((WCHAR*) pTmpFileList, L':')) ;
  2384. }
  2385. else
  2386. {
  2387. hr = StringCbCopyA((char*)pTmpFileList, cbSize,
  2388. (char*)pOldFilename) ;
  2389. fDrivePath = (0 != strchr((char*) pTmpFileList, ':')) ;
  2390. }
  2391. if (FAILED(hr)) {
  2392. TRC_ERR((TB,_T("Failed to cpy filelist string: 0x%x"),hr));
  2393. response = TS_CB_RESPONSE_FAIL;
  2394. dataLen = 0;
  2395. _CB.fAlreadyCopied = TRUE;
  2396. DC_QUIT ;
  2397. }
  2398. if (fDrivePath)
  2399. {
  2400. // ClipCopyToTempDirectory returns 0 if successful
  2401. if (0 != ClipCopyToTempDirectory(pTmpFileList, fWide))
  2402. {
  2403. TRC_ERR((TB,_T("Copy to tmp directory failed"))) ;
  2404. response = TS_CB_RESPONSE_FAIL;
  2405. dataLen = 0;
  2406. _CB.fAlreadyCopied = TRUE ;
  2407. DC_QUIT ;
  2408. }
  2409. }
  2410. _CB.fAlreadyCopied = TRUE ;
  2411. LocalFree(pTmpFileList);
  2412. pTmpFileList = NULL;
  2413. }
  2414. newSize = ClipGetNewFilePathLength(pOldFilename, fWide) ;
  2415. hNewData = GlobalAlloc(GMEM_DISCARDABLE | GMEM_MOVEABLE, newSize) ;
  2416. if (!hNewData)
  2417. {
  2418. TRC_ERR((TB, _T("Failed to get %ld bytes for HDROP"),
  2419. newSize));
  2420. response = TS_CB_RESPONSE_FAIL;
  2421. dataLen = 0;
  2422. DC_QUIT ;
  2423. }
  2424. pFilename = GlobalLock(hNewData) ;
  2425. if (!pFilename)
  2426. {
  2427. TRC_ERR((TB, _T("Failed to get lock %p for HDROP"),
  2428. hNewData));
  2429. response = TS_CB_RESPONSE_FAIL;
  2430. dataLen = 0;
  2431. DC_QUIT ;
  2432. }
  2433. if (FAILED(ClipConvertToTempPath(pOldFilename, pFilename, newSize, fWide)))
  2434. {
  2435. TRC_ERR((TB, _T("Failed conversion"))) ;
  2436. response = TS_CB_RESPONSE_FAIL;
  2437. dataLen = 0;
  2438. DC_QUIT ;
  2439. }
  2440. GlobalUnlock(hNewData) ;
  2441. hData = hNewData ;
  2442. response = TS_CB_RESPONSE_OK ;
  2443. dataLen = newSize ;
  2444. DC_QUIT ;
  2445. }
  2446. }
  2447. #endif
  2448. /************************************************************/
  2449. /* just get the length of the block */
  2450. /************************************************************/
  2451. dataLen = (DCUINT32)GlobalSize(hData);
  2452. TRC_DBG((TB, _T("Got data len %ld"), dataLen));
  2453. }
  2454. }
  2455. }
  2456. else
  2457. {
  2458. /********************************************************************/
  2459. /* Failed to open CB - send a failure response */
  2460. /********************************************************************/
  2461. TRC_ERR((TB, _T("Failed to open CB")));
  2462. response = TS_CB_RESPONSE_FAIL;
  2463. dataLen = 0;
  2464. DC_QUIT ;
  2465. }
  2466. DC_EXIT_POINT:
  2467. /************************************************************************/
  2468. /* By default, we'll use the permanent send buffer */
  2469. /************************************************************************/
  2470. TRC_NRM((TB, _T("Get perm TX buffer")));
  2471. pduLen = dataLen + sizeof(TS_CLIP_PDU);
  2472. pClipNew = (PTS_CLIP_PDU)ClipAlloc(pduLen);
  2473. if (pClipNew != NULL)
  2474. {
  2475. /****************************************************************/
  2476. /* Use the new buffer */
  2477. /****************************************************************/
  2478. TRC_NRM((TB, _T("Free perm TX buffer")));
  2479. pClipRsp = pClipNew;
  2480. }
  2481. else
  2482. {
  2483. /****************************************************************/
  2484. /* Fail the request */
  2485. /****************************************************************/
  2486. TRC_ERR((TB, _T("Failed to alloc %ld bytes"), pduLen));
  2487. pClipRsp = ClipGetPermBuf();
  2488. response = TS_CB_RESPONSE_FAIL;
  2489. dataLen = 0;
  2490. pduLen = sizeof(TS_CLIP_PDU);
  2491. }
  2492. DC_MEMSET(pClipRsp, 0, sizeof(*pClipRsp));
  2493. pClipRsp->msgType = TS_CB_FORMAT_DATA_RESPONSE;
  2494. pClipRsp->msgFlags = response;
  2495. pClipRsp->dataLen = dataLen;
  2496. if (pTmpFileList) {
  2497. LocalFree(pTmpFileList);
  2498. pTmpFileList = NULL;
  2499. }
  2500. // Copy data, if any
  2501. if (dataLen != 0)
  2502. {
  2503. TRC_DBG((TB, _T("Copying all the data")));
  2504. pData = (HPDCUINT8)GlobalLock(hData);
  2505. if (NULL != pData) {
  2506. ClipMemcpy(pClipRsp->data, pData, dataLen);
  2507. GlobalUnlock(hData);
  2508. }
  2509. else {
  2510. TRC_ERR(( TB, _T("Failed to lock data")));
  2511. pClipRsp->msgFlags = TS_CB_RESPONSE_FAIL;
  2512. pClipRsp->dataLen = 0;
  2513. pduLen = sizeof(TS_CLIP_PDU);
  2514. }
  2515. }
  2516. // Send the PDU
  2517. TRC_NRM((TB, _T("Sending format data rsp")));
  2518. if (_CB.channelEP.pVirtualChannelWriteEx
  2519. (_CB.initHandle, _CB.channelHandle, (LPVOID)pClipRsp, pduLen, pClipRsp)
  2520. != CHANNEL_RC_OK)
  2521. {
  2522. ClipFreeBuf((PDCUINT8)pClipRsp);
  2523. }
  2524. // close the clipboard if we need to
  2525. if (_CB.rcvOpen)
  2526. {
  2527. TRC_DBG((TB, _T("Closing CB")));
  2528. _CB.rcvOpen = FALSE;
  2529. if (!CloseClipboard())
  2530. {
  2531. TRC_SYSTEM_ERROR("CloseClipboard");
  2532. }
  2533. }
  2534. // if we got any new data, we need to free it
  2535. if (hNewData)
  2536. {
  2537. TRC_DBG((TB, _T("Freeing new data")));
  2538. GlobalFree(hNewData);
  2539. }
  2540. DC_END_FN();
  2541. return;
  2542. } /* ClipOnFormatRequest */
  2543. /****************************************************************************/
  2544. // ClipOnFormatDataComplete
  2545. // - Server response to our request for data
  2546. /****************************************************************************/
  2547. DCVOID DCINTERNAL CClip::ClipOnFormatDataComplete(PTS_CLIP_PDU pClipPDU)
  2548. {
  2549. HANDLE hData = NULL;
  2550. HPDCVOID pData;
  2551. LOGPALETTE * pLogPalette = NULL;
  2552. DCUINT32 numEntries;
  2553. DCUINT32 memLen;
  2554. #ifndef OS_WINCE
  2555. HRESULT hr ;
  2556. #endif
  2557. DC_BEGIN_FN("CClip::ClipOnFormatDataComplete");
  2558. /************************************************************************/
  2559. /* check the response */
  2560. /************************************************************************/
  2561. if (_pClipData == NULL) {
  2562. TRC_ALT((TB, _T("The clipData is NULL, we just bail")));
  2563. DC_QUIT;
  2564. }
  2565. if (!(pClipPDU->msgFlags & TS_CB_RESPONSE_OK))
  2566. {
  2567. TRC_ALT((TB, _T("Got fmt data rsp failed for %d"), _CB.pendingClientID));
  2568. DC_QUIT;
  2569. }
  2570. /************************************************************************/
  2571. /* Got the data */
  2572. /************************************************************************/
  2573. TRC_NRM((TB, _T("Got OK fmt data rsp for %d"), _CB.pendingClientID));
  2574. #ifndef OS_WINCE
  2575. /************************************************************************/
  2576. /* For some formats we still need to do some work */
  2577. /************************************************************************/
  2578. if (_CB.pendingClientID == CF_METAFILEPICT)
  2579. {
  2580. /********************************************************************/
  2581. /* Metafile format - create a metafile from the data */
  2582. /********************************************************************/
  2583. TRC_NRM((TB, _T("Rx data is for metafile")));
  2584. hData = ClipSetMFData(pClipPDU->dataLen, pClipPDU->data);
  2585. if (hData == NULL)
  2586. {
  2587. TRC_ERR((TB, _T("Failed to set MF data")));
  2588. }
  2589. }
  2590. else
  2591. #endif
  2592. if (_CB.pendingClientID == CF_PALETTE)
  2593. {
  2594. /********************************************************************/
  2595. /* Palette format - create a palette from the data */
  2596. /********************************************************************/
  2597. /********************************************************************/
  2598. /* Allocate memory for a LOGPALETTE structure large enough to hold */
  2599. /* all the PALETTE ENTRY structures, and fill it in. */
  2600. /********************************************************************/
  2601. TRC_NRM((TB, _T("Rx data is for palette")));
  2602. numEntries = (pClipPDU->dataLen / sizeof(PALETTEENTRY));
  2603. memLen = (sizeof(LOGPALETTE) +
  2604. ((numEntries - 1) * sizeof(PALETTEENTRY)));
  2605. TRC_DBG((TB, _T("%ld palette entries, allocate %ld bytes"),
  2606. numEntries, memLen));
  2607. pLogPalette = (LOGPALETTE*)ClipAlloc(memLen);
  2608. if (pLogPalette != NULL)
  2609. {
  2610. pLogPalette->palVersion = 0x300;
  2611. pLogPalette->palNumEntries = (WORD)numEntries;
  2612. ClipMemcpy(pLogPalette->palPalEntry,
  2613. pClipPDU->data,
  2614. pClipPDU->dataLen);
  2615. /****************************************************************/
  2616. /* now create a palette */
  2617. /****************************************************************/
  2618. hData = CreatePalette(pLogPalette);
  2619. if (hData == NULL)
  2620. {
  2621. TRC_SYSTEM_ERROR("CreatePalette");
  2622. }
  2623. }
  2624. else
  2625. {
  2626. TRC_ERR((TB, _T("Failed to get %ld bytes"), memLen));
  2627. }
  2628. }
  2629. else
  2630. {
  2631. TRC_NRM((TB, _T("Rx data can just go on CB")));
  2632. /********************************************************************/
  2633. /* We need to copy the data, as the receive buffer will be freed on */
  2634. /* return from this function. */
  2635. /********************************************************************/
  2636. hData = GlobalAlloc(GMEM_DISCARDABLE | GMEM_MOVEABLE,
  2637. pClipPDU->dataLen);
  2638. if (hData != NULL)
  2639. {
  2640. pData = GlobalLock(hData);
  2641. if (pData != NULL)
  2642. {
  2643. TRC_NRM((TB, _T("Copy %ld bytes from %p to %p"),
  2644. pClipPDU->dataLen, pClipPDU->data, pData));
  2645. ClipMemcpy(pData, pClipPDU->data, pClipPDU->dataLen);
  2646. GlobalUnlock(hData);
  2647. }
  2648. else
  2649. {
  2650. TRC_ERR((TB, _T("Failed to lock %p (%ld bytes)"),
  2651. hData, pClipPDU->dataLen));
  2652. GlobalFree(hData);
  2653. hData = NULL;
  2654. }
  2655. }
  2656. else
  2657. {
  2658. TRC_ERR((TB, _T("Failed to alloc %ld bytes"), pClipPDU->dataLen));
  2659. }
  2660. }
  2661. DC_EXIT_POINT:
  2662. /************************************************************************/
  2663. /* tidy up */
  2664. /************************************************************************/
  2665. if (pLogPalette != NULL)
  2666. {
  2667. ClipFree(pLogPalette);
  2668. }
  2669. /************************************************************************/
  2670. /* Set the state, and we're done. Note that this is done when we get a */
  2671. /* failure response too. */
  2672. /************************************************************************/
  2673. CB_SET_STATE(CB_STATE_LOCAL_CB_OWNER, CB_EVENT_FORMAT_DATA_RSP);
  2674. _pClipData->SetClipData(hData, _CB.pendingClientID ) ;
  2675. TRC_ASSERT( NULL != _GetDataSync[TS_RECEIVE_COMPLETED],
  2676. (TB,_T("data sync is NULL")));
  2677. SetEvent(_GetDataSync[TS_RECEIVE_COMPLETED]) ;
  2678. DC_END_FN();
  2679. return;
  2680. } /* ClipOnFormatDataComplete */
  2681. /****************************************************************************/
  2682. /* ClipRemoteFormatFromLocalID */
  2683. /****************************************************************************/
  2684. DCUINT DCINTERNAL CClip::ClipRemoteFormatFromLocalID(DCUINT id)
  2685. {
  2686. DCUINT i;
  2687. DCUINT retID = 0;
  2688. for (i = 0; i < CB_MAX_FORMATS; i++)
  2689. {
  2690. if (_CB.idMap[i].clientID == id)
  2691. {
  2692. retID = _CB.idMap[i].serverID;
  2693. break;
  2694. }
  2695. }
  2696. return(retID);
  2697. }
  2698. /****************************************************************************/
  2699. /* ClipOnWriteComplete */
  2700. /****************************************************************************/
  2701. DCVOID DCINTERNAL CClip::ClipOnWriteComplete(LPVOID pData)
  2702. {
  2703. PTS_CLIP_PDU pClipPDU;
  2704. DC_BEGIN_FN("CClip::ClipOnWriteComplete");
  2705. TRC_NRM((TB, _T("Free buffer at %p"), pData));
  2706. pClipPDU = (PTS_CLIP_PDU)pData;
  2707. TRC_DBG((TB, _T("Message type %hx, flags %hx"),
  2708. pClipPDU->msgType, pClipPDU->msgFlags));
  2709. /************************************************************************/
  2710. /* Free the buffer */
  2711. /************************************************************************/
  2712. TRC_DBG((TB, _T("Write from buffer %p complete"), pData));
  2713. ClipFreeBuf((PDCUINT8)pData);
  2714. DC_END_FN();
  2715. return;
  2716. }
  2717. HRESULT CClip::ClipCreateDataSyncEvents()
  2718. {
  2719. HRESULT hr = E_FAIL ;
  2720. DC_BEGIN_FN("CClip::ClipCreateDataSyncEvents") ;
  2721. // Create events for controlling the Clipboard thread
  2722. _GetDataSync[TS_RECEIVE_COMPLETED] = CreateEvent(NULL, FALSE, FALSE, NULL) ;
  2723. _GetDataSync[TS_RESET_EVENT] = CreateEvent(NULL, FALSE, FALSE, NULL) ;
  2724. if (!_GetDataSync[TS_RECEIVE_COMPLETED])
  2725. {
  2726. TRC_ERR((TB, _T("Failed CreateEvent RECEIVE_COMPLETED; Error = %d"),
  2727. GetLastError())) ;
  2728. hr = E_FAIL ;
  2729. DC_QUIT ;
  2730. }
  2731. if (!_GetDataSync[TS_RESET_EVENT])
  2732. {
  2733. TRC_ERR((TB, _T("Failed CreateEvent RESET_EVENT; Error = %d"),
  2734. GetLastError())) ;
  2735. hr = E_FAIL ;
  2736. DC_QUIT ;
  2737. }
  2738. hr = S_OK ;
  2739. DC_EXIT_POINT:
  2740. DC_END_FN() ;
  2741. return hr ;
  2742. }
  2743. /****************************************************************************/
  2744. /* ClipOnInitialized */
  2745. /****************************************************************************/
  2746. DCINT32 DCAPI CClip::ClipOnInitialized(DCVOID)
  2747. {
  2748. DC_BEGIN_FN("CClip::ClipOnInitialized") ;
  2749. HRESULT hr = E_FAIL ;
  2750. BOOL fthreadStarted = FALSE ;
  2751. hr = ClipCreateDataSyncEvents() ;
  2752. DC_QUIT_ON_FAIL(hr);
  2753. /************************************************************************/
  2754. /* Register a message for communication between the two threads */
  2755. /************************************************************************/
  2756. _CB.regMsg = WM_USER_CHANGE_THREAD;
  2757. TRC_NRM((TB, _T("Registered window message %x"), _CB.regMsg));
  2758. _CB.pClipThreadData = (PUT_THREAD_DATA) LocalAlloc(LPTR, sizeof(UT_THREAD_DATA)) ;
  2759. if (NULL == _CB.pClipThreadData)
  2760. {
  2761. TRC_ERR((TB, _T("Unable to allocate %d bytes for thread data"),
  2762. sizeof(UT_THREAD_DATA))) ;
  2763. hr = E_FAIL ;
  2764. DC_QUIT ;
  2765. }
  2766. if (_pUtObject) {
  2767. fthreadStarted = _pUtObject->UT_StartThread(ClipStaticMain,
  2768. _CB.pClipThreadData, this);
  2769. }
  2770. if (!fthreadStarted)
  2771. {
  2772. hr = E_FAIL ;
  2773. DC_QUIT ;
  2774. }
  2775. // If we got to this point, then we succeeded initialized everything
  2776. hr = S_OK ;
  2777. DC_EXIT_POINT:
  2778. // On failure be sure to clear out the data syncs.
  2779. // we will not connect the virtual channel if the
  2780. // data sync are NULL
  2781. if (FAILED(hr)) {
  2782. _GetDataSync[TS_RECEIVE_COMPLETED] = NULL;
  2783. _GetDataSync[TS_RESET_EVENT] = NULL;
  2784. }
  2785. return hr ;
  2786. }
  2787. /****************************************************************************/
  2788. /* ClipStaticMain */
  2789. /****************************************************************************/
  2790. DCVOID DCAPI ClipStaticMain(PDCVOID param)
  2791. {
  2792. ((CClip*) param)->ClipMain() ;
  2793. }
  2794. /****************************************************************************/
  2795. /* ClipOnInit */
  2796. /****************************************************************************/
  2797. DCINT DCAPI CClip::ClipOnInit(DCVOID)
  2798. {
  2799. ATOM registerClassRc;
  2800. WNDCLASS viewerWindowClass;
  2801. WNDCLASS tmpWndClass;
  2802. DCINT allOk = FALSE ;
  2803. DC_BEGIN_FN("CClip::ClipOnInit");
  2804. /************************************************************************/
  2805. /* Create an invisible window which we will register as a clipboard */
  2806. /* viewer */
  2807. /* Only register if prev instance did not already register the class */
  2808. /************************************************************************/
  2809. if(!GetClassInfo(_CB.hInst, CB_VIEWER_CLASS, &tmpWndClass))
  2810. {
  2811. TRC_NRM((TB, _T("Register Main Window class, data %p, hInst %p"),
  2812. &viewerWindowClass, _CB.hInst));
  2813. viewerWindowClass.style = 0;
  2814. viewerWindowClass.lpfnWndProc = StaticClipViewerWndProc;
  2815. viewerWindowClass.cbClsExtra = 0;
  2816. viewerWindowClass.cbWndExtra = sizeof(void*);
  2817. viewerWindowClass.hInstance = _CB.hInst ;
  2818. viewerWindowClass.hIcon = NULL;
  2819. viewerWindowClass.hCursor = NULL;
  2820. viewerWindowClass.hbrBackground = (HBRUSH)GetStockObject(HOLLOW_BRUSH);
  2821. viewerWindowClass.lpszMenuName = NULL;
  2822. viewerWindowClass.lpszClassName = CB_VIEWER_CLASS;
  2823. TRC_DATA_NRM("Register class data", &viewerWindowClass, sizeof(WNDCLASS));
  2824. registerClassRc = RegisterClass (&viewerWindowClass);
  2825. if (registerClassRc == 0)
  2826. {
  2827. /****************************************************************/
  2828. /* Failed to register CB viewer class */
  2829. /****************************************************************/
  2830. TRC_ERR((TB, _T("Failed to register Cb Viewer class")));
  2831. }
  2832. TRC_NRM((TB, _T("Registered class")));
  2833. }
  2834. _CB.viewerWindow =
  2835. CreateWindowEx(
  2836. #ifndef OS_WINCE
  2837. WS_EX_NOPARENTNOTIFY,
  2838. #else
  2839. 0,
  2840. #endif
  2841. CB_VIEWER_CLASS, /* window class name */
  2842. _T("CB Viewer Window"), /* window caption */
  2843. #ifndef OS_WINCE
  2844. WS_OVERLAPPEDWINDOW, /* window style */
  2845. #else
  2846. WS_OVERLAPPED | WS_CAPTION | WS_SYSMENU | WS_MINIMIZEBOX | WS_MAXIMIZEBOX,
  2847. #endif
  2848. 0, /* initial x position */
  2849. 0, /* initial y position */
  2850. 100, /* initial x size */
  2851. 100, /* initial y size */
  2852. NULL, /* parent window */
  2853. NULL, /* window menu handle */
  2854. _CB.hInst, /* program inst handle */
  2855. this); /* creation parameters */
  2856. /************************************************************************/
  2857. /* Check we created the window OK */
  2858. /************************************************************************/
  2859. if (_CB.viewerWindow == NULL)
  2860. {
  2861. TRC_ERR((TB, _T("Failed to create CB Viewer Window")));
  2862. DC_QUIT ;
  2863. }
  2864. TRC_DBG((TB, _T("Viewer Window handle %p"), _CB.viewerWindow));
  2865. #ifdef OS_WINCE
  2866. if ((_CB.dataWindow = CECreateCBDataWindow(_CB.hInst)) == NULL)
  2867. {
  2868. TRC_ERR((TB, _T("Failed to create CB Data Window")));
  2869. DC_QUIT ;
  2870. }
  2871. #endif
  2872. #ifdef USE_SEMAPHORE
  2873. /************************************************************************/
  2874. /* Create the permanent TX buffer semaphore */
  2875. /************************************************************************/
  2876. _CB.txPermBufSem = CreateSemaphore(NULL, 1, 1, NULL);
  2877. if (_CB.txPermBufSem == NULL)
  2878. {
  2879. TRC_ERR((TB, _T("Failed to create semaphore")));
  2880. DC_QUIT;
  2881. }
  2882. TRC_NRM((TB, _T("Create perm TX buffer sem %p"), _CB.txPermBufSem));
  2883. #endif
  2884. #ifdef OS_WINCE
  2885. gfmtShellPidlArray = RegisterClipboardFormat(CFSTR_SHELLPIDLARRAY);
  2886. #endif
  2887. /************************************************************************/
  2888. /* Update the state */
  2889. /************************************************************************/
  2890. CB_SET_STATE(CB_STATE_INITIALIZED, CB_TRACE_EVENT_CB_CLIPMAIN);
  2891. allOk = TRUE ;
  2892. DC_EXIT_POINT:
  2893. DC_END_FN();
  2894. return allOk;
  2895. } /* ClipOnInit */
  2896. /****************************************************************************/
  2897. /* ClipOnTerm */
  2898. /****************************************************************************/
  2899. DCBOOL DCAPI CClip::ClipOnTerm(LPVOID pInitHandle)
  2900. {
  2901. BOOL fSuccess = FALSE ;
  2902. BOOL fThreadEnded = FALSE ;
  2903. DC_BEGIN_FN("CClip::ClipOnTerm");
  2904. /************************************************************************/
  2905. /* Check the state - if we're still connected, we should disconnect */
  2906. /* before shutting down */
  2907. /************************************************************************/
  2908. ClipCheckState(CB_EVENT_CB_TERM);
  2909. if (_CB.state != CB_STATE_INITIALIZED)
  2910. {
  2911. TRC_ALT((TB, _T("Terminated when not disconnected")));
  2912. ClipOnDisconnected(pInitHandle);
  2913. }
  2914. // If we had file cut/copy on, we should clean up after ourselves
  2915. if (_CB.fFileCutCopyOn)
  2916. {
  2917. SendMessage(_CB.viewerWindow, WM_USER_CLEANUP_ON_TERM, 0, 0);
  2918. }
  2919. /************************************************************************/
  2920. /* Destroy the window and unregister the class (the WM_DESTROY handling */
  2921. /* will deal with removing the window from the viewer chain) */
  2922. /************************************************************************/
  2923. TRC_NRM((TB, _T("Destroying CB window...")));
  2924. if (!PostMessage(_CB.viewerWindow, WM_CLOSE, 0, 0))
  2925. {
  2926. TRC_SYSTEM_ERROR("DestroyWindow");
  2927. }
  2928. if (!UnregisterClass(CB_VIEWER_CLASS, _CB.hInst))
  2929. {
  2930. TRC_SYSTEM_ERROR("UnregisterClass");
  2931. }
  2932. #ifdef OS_WINCE
  2933. TRC_NRM((TB, _T("Destroying CB data window...")));
  2934. if (!PostMessage(_CB.dataWindow, WM_CLOSE, 0, 0))
  2935. {
  2936. TRC_SYSTEM_ERROR("DestroyWindow");
  2937. }
  2938. if (!UnregisterClass(CB_DATAWINDOW_CLASS, _CB.hInst))
  2939. {
  2940. TRC_SYSTEM_ERROR("UnregisterClass");
  2941. }
  2942. #endif
  2943. if (_pClipData)
  2944. {
  2945. // Decrement the reference count of the IDataObject object. At this stage,
  2946. // this should cause the reference count to drop to zero and the IDataObject
  2947. // object's destructor should be called. This destructor will release the
  2948. // reference to this CClipData object, resulting in a reference count of 1.
  2949. // Hence the call to Release() below will result in the CClipData destructor
  2950. // being called.
  2951. _pClipData->TearDown();
  2952. _pClipData->Release() ;
  2953. _pClipData = NULL;
  2954. }
  2955. if (_CB.pClipThreadData)
  2956. {
  2957. fThreadEnded = _pUtObject->UT_DestroyThread(*_CB.pClipThreadData);
  2958. if (!fThreadEnded)
  2959. {
  2960. TRC_ERR((TB, _T("Error while ending thread"))) ;
  2961. fSuccess = FALSE;
  2962. DC_QUIT ;
  2963. }
  2964. LocalFree( _CB.pClipThreadData );
  2965. _CB.pClipThreadData = NULL;
  2966. }
  2967. if (_pUtObject)
  2968. {
  2969. LocalFree(_pUtObject);
  2970. _pUtObject = NULL;
  2971. }
  2972. fSuccess = TRUE ;
  2973. DC_EXIT_POINT:
  2974. /************************************************************************/
  2975. /* Update our state */
  2976. /************************************************************************/
  2977. CB_SET_STATE(CB_STATE_NOT_INIT, CB_EVENT_CB_TERM);
  2978. DC_END_FN();
  2979. return fSuccess ;
  2980. } /* ClipOnTerm */
  2981. DCVOID DCAPI CClip::ClipMain(DCVOID)
  2982. {
  2983. DC_BEGIN_FN("CClip::ClipMain");
  2984. MSG msg ;
  2985. #ifndef OS_WINCE
  2986. HRESULT result = OleInitialize(NULL) ;
  2987. #else
  2988. HRESULT result = CoInitializeEx(NULL, COINIT_MULTITHREADED) ;
  2989. #endif
  2990. if (SUCCEEDED(result))
  2991. {
  2992. if (0 != ClipOnInit())
  2993. {
  2994. TRC_NRM((TB, _T("Start Clip Thread message loop"))) ;
  2995. while (GetMessage (&msg, NULL, 0, 0))
  2996. {
  2997. TranslateMessage(&msg);
  2998. DispatchMessage(&msg);
  2999. }
  3000. }
  3001. else
  3002. {
  3003. TRC_ERR((TB, _T("Failed initialized clipboard thread"))) ;
  3004. }
  3005. #ifndef OS_WINCE
  3006. // We assume OleUninitialize works, as it has no return value
  3007. OleUninitialize() ;
  3008. #else
  3009. CoUninitialize() ;
  3010. #endif
  3011. }
  3012. else
  3013. {
  3014. TRC_ERR((TB, _T("OleInitialize Failed"))) ;
  3015. }
  3016. DC_EXIT_POINT:
  3017. TRC_NRM((TB, _T("Exit Clip Thread message loop"))) ;
  3018. DC_END_FN();
  3019. }
  3020. /****************************************************************************/
  3021. /* ClipOnConnected */
  3022. /****************************************************************************/
  3023. VOID DCINTERNAL CClip::ClipOnConnected(LPVOID pInitHandle)
  3024. {
  3025. UINT rc;
  3026. DC_BEGIN_FN("CClip::ClipOnConnected");
  3027. if (!IsDataSyncReady()) {
  3028. TRC_ERR((TB, _T("Data Sync not ready")));
  3029. DC_QUIT;
  3030. }
  3031. _CB.fDrivesRedirected = _pVCMgr->GetInitData()->fEnableRedirectDrives;
  3032. _CB.fFileCutCopyOn = _CB.fDrivesRedirected;
  3033. /************************************************************************/
  3034. /* Open our channel */
  3035. /************************************************************************/
  3036. TRC_NRM((TB, _T("Entry points are at %p"), &(_CB.channelEP)));
  3037. TRC_NRM((TB, _T("Call ChannelOpen at %p"), _CB.channelEP.pVirtualChannelOpenEx));
  3038. rc = _CB.channelEP.pVirtualChannelOpenEx(pInitHandle,
  3039. &_CB.channelHandle,
  3040. CLIP_CHANNEL,
  3041. (PCHANNEL_OPEN_EVENT_EX_FN)MakeProcInstance(
  3042. (FARPROC)ClipOpenEventFnEx, _CB.hInst)
  3043. );
  3044. TRC_NRM((TB, _T("Opened %s: %ld, rc %d"), CLIP_CHANNEL,_CB.channelHandle, rc));
  3045. DC_EXIT_POINT:
  3046. DC_END_FN();
  3047. return;
  3048. }
  3049. /****************************************************************************/
  3050. /* ClipOnConnected */
  3051. /****************************************************************************/
  3052. VOID DCINTERNAL CClip::ClipOnMonitorReady(VOID)
  3053. {
  3054. DC_BEGIN_FN("CClip::ClipOnMonitorReady");
  3055. /************************************************************************/
  3056. /* The monitor has woken up. Check the state */
  3057. /************************************************************************/
  3058. CB_CHECK_STATE(CB_EVENT_CB_ENABLE);
  3059. // Update the state
  3060. CB_SET_STATE(CB_STATE_ENABLED, CB_TRACE_EVENT_CB_MONITOR_READY);
  3061. // Get the temp directory, and send it off to the server
  3062. // if it fails, then we turn off File Cut/Copy
  3063. _CB.fFileCutCopyOn = ClipSetAndSendTempDirectory() ;
  3064. // We now send the list of clipboard formats we have at this end to the
  3065. // server by faking a draw of the local clipboard. We pass TRUE to
  3066. // force a send because the server needs to have the value of our
  3067. // TS_CB_ASCII_NAMES flag (RAID #313251).
  3068. ClipDrawClipboard(TRUE);
  3069. DC_EXIT_POINT:
  3070. DC_END_FN();
  3071. return;
  3072. }
  3073. /****************************************************************************/
  3074. /* ClipOnDisconnected */
  3075. /****************************************************************************/
  3076. VOID DCINTERNAL CClip::ClipOnDisconnected(LPVOID pInitHandle)
  3077. {
  3078. DC_BEGIN_FN("CClip::ClipOnDisconnected");
  3079. DC_IGNORE_PARAMETER(pInitHandle);
  3080. //
  3081. // Reset the clipboard thread
  3082. // if it waits for data
  3083. //
  3084. if ( NULL != _GetDataSync[TS_RESET_EVENT] )
  3085. {
  3086. SetEvent( _GetDataSync[TS_RESET_EVENT] );
  3087. }
  3088. /************************************************************************/
  3089. /* Check the state */
  3090. /************************************************************************/
  3091. ClipCheckState(CB_EVENT_CB_DISABLE);
  3092. /************************************************************************/
  3093. /* If we are the local clipboard owner, then we must empty it - once */
  3094. /* disconnected, we won't be able to satisfy any further format */
  3095. /* requests. Note that we are still the local CB owner even if we are */
  3096. /* waiting on some data from the server */
  3097. /************************************************************************/
  3098. if (_CB.state == CB_STATE_LOCAL_CB_OWNER)
  3099. {
  3100. TRC_NRM((TB, _T("Disable received while local CB owner")));
  3101. /********************************************************************/
  3102. /* Open the clipboard if needed */
  3103. /********************************************************************/
  3104. if ((!_CB.rcvOpen) && !OpenClipboard(NULL))
  3105. {
  3106. TRC_ERR((TB, _T("Failed to open CB when emptying required")));
  3107. }
  3108. else
  3109. {
  3110. /****************************************************************/
  3111. /* It was/is open */
  3112. /****************************************************************/
  3113. TRC_NRM((TB, _T("CB opened")));
  3114. _CB.rcvOpen = TRUE;
  3115. /****************************************************************/
  3116. /* Empty it */
  3117. /****************************************************************/
  3118. if (!EmptyClipboard())
  3119. {
  3120. TRC_SYSTEM_ERROR("EmptyClipboard");
  3121. }
  3122. }
  3123. }
  3124. /************************************************************************/
  3125. /* If there is pending format data, we should SetClipboardData to NULL */
  3126. /* so that app can close the clipboard */
  3127. /************************************************************************/
  3128. else if (_CB.state == CB_STATE_PENDING_FORMAT_DATA_RSP) {
  3129. TRC_NRM((TB, _T("Pending format data: setting clipboard data to NULL")));
  3130. SetClipboardData(_CB.pendingClientID, NULL);
  3131. }
  3132. /************************************************************************/
  3133. /* Ensure that we close the local CB */
  3134. /************************************************************************/
  3135. if (_CB.rcvOpen)
  3136. {
  3137. _CB.rcvOpen = FALSE;
  3138. if (!CloseClipboard())
  3139. {
  3140. TRC_SYSTEM_ERROR("CloseClipboard");
  3141. }
  3142. TRC_NRM((TB, _T("CB closed")));
  3143. }
  3144. /************************************************************************/
  3145. /* If we were sending or receiving data, unlock and free the buffers as */
  3146. /* required */
  3147. /************************************************************************/
  3148. if (_CB.rxpBuffer)
  3149. {
  3150. TRC_NRM((TB, _T("Freeing recieve buffer %p"), _CB.rxpBuffer));
  3151. ClipFree(_CB.rxpBuffer);
  3152. _CB.rxpBuffer = NULL;
  3153. }
  3154. DC_EXIT_POINT:
  3155. /************************************************************************/
  3156. /* Update our state */
  3157. /************************************************************************/
  3158. CB_SET_STATE(CB_STATE_INITIALIZED, CB_TRACE_EVENT_CB_DISCONNECT);
  3159. DC_END_FN();
  3160. return;
  3161. } /* ClipOnDisconnected */
  3162. /****************************************************************************/
  3163. // ClipOnDataReceived
  3164. /****************************************************************************/
  3165. DCVOID DCAPI CClip::ClipOnDataReceived(LPVOID pData,
  3166. UINT32 dataLength,
  3167. UINT32 totalLength,
  3168. UINT32 dataFlags)
  3169. {
  3170. PTS_CLIP_PDU pClipPDU;
  3171. DCBOOL freeTheBuffer = TRUE;
  3172. DC_BEGIN_FN("CClip::ClipOnDataReceived");
  3173. //
  3174. // Verify that there is enough data to make up or create a clip PDU header.
  3175. //
  3176. if (totalLength < sizeof(TS_CLIP_PDU)) {
  3177. TRC_ERR((TB, _T("Not enough data to form a clip header.")));
  3178. _CB.channelEP.pVirtualChannelCloseEx(_CB.initHandle, _CB.channelHandle);
  3179. DC_QUIT;
  3180. }
  3181. /************************************************************************/
  3182. /* Check we're all up and running */
  3183. /************************************************************************/
  3184. if (_CB.state == CB_STATE_NOT_INIT)
  3185. {
  3186. pClipPDU = (PTS_CLIP_PDU)pData;
  3187. TRC_ERR((TB, _T("Clip message type %hd received when not init"),
  3188. pClipPDU->msgType));
  3189. DC_QUIT;
  3190. }
  3191. /************************************************************************/
  3192. /* Special case: if the entire message fits in one chunk, there's no */
  3193. /* need to copy it */
  3194. /************************************************************************/
  3195. if (CHANNEL_FLAG_ONLY == (dataFlags & CHANNEL_FLAG_ONLY))
  3196. {
  3197. TRC_DBG((TB, _T("Single chunk message")));
  3198. pClipPDU = (PTS_CLIP_PDU)pData;
  3199. }
  3200. else
  3201. {
  3202. /********************************************************************/
  3203. /* It's a segmented message - rebuild it */
  3204. /********************************************************************/
  3205. if (dataFlags & CHANNEL_FLAG_FIRST)
  3206. {
  3207. /****************************************************************/
  3208. /* If it's the first segment, allocate a buffer to rebuild the */
  3209. /* message in. */
  3210. /****************************************************************/
  3211. TRC_DBG((TB, _T("Alloc %ld-byte buffer"), totalLength));
  3212. _CB.rxpBuffer = (HPDCUINT8)ClipAlloc(totalLength);
  3213. if (_CB.rxpBuffer == NULL)
  3214. {
  3215. /************************************************************/
  3216. /* Failed to alloc a buffer. We have to do something, */
  3217. /* otherwise the Client app can hang waiting for data. */
  3218. /* Fake a failure response. */
  3219. /************************************************************/
  3220. TRC_ERR((TB, _T("Failed to alloc %ld-byte buffer"), totalLength));
  3221. pClipPDU = (PTS_CLIP_PDU)pData;
  3222. pClipPDU->msgFlags = TS_CB_RESPONSE_FAIL;
  3223. pClipPDU->dataLen = 0;
  3224. dataFlags |= CHANNEL_FLAG_LAST;
  3225. /************************************************************/
  3226. /* Now handle it as if it were complete. Subsequent chunks */
  3227. /* will be discarded. */
  3228. /************************************************************/
  3229. goto MESSAGE_COMPLETE;
  3230. }
  3231. _CB.rxpBufferCurrent = _CB.rxpBuffer;
  3232. _CB.rxBufferLen = totalLength;
  3233. _CB.rxBufferLeft = totalLength;
  3234. }
  3235. /********************************************************************/
  3236. /* Check that we have a buffer to copy into */
  3237. /********************************************************************/
  3238. if (_CB.rxpBuffer == NULL)
  3239. {
  3240. TRC_NRM((TB, _T("Previous buffer alloc failure - discard data")));
  3241. DC_QUIT;
  3242. }
  3243. /********************************************************************/
  3244. /* Check that there is enough room */
  3245. /********************************************************************/
  3246. if (dataLength > _CB.rxBufferLeft)
  3247. {
  3248. TRC_ERR((TB, _T("Not enough room in rx buffer: need/got %ld/%ld"),
  3249. dataLength, _CB.rxBufferLeft));
  3250. DC_QUIT;
  3251. }
  3252. /********************************************************************/
  3253. /* Copy the data */
  3254. /********************************************************************/
  3255. TRC_DBG((TB, _T("Copy %ld bytes from %p to %p"),
  3256. dataLength, pData, _CB.rxpBufferCurrent));
  3257. ClipMemcpy(_CB.rxpBufferCurrent, pData, dataLength);
  3258. _CB.rxpBufferCurrent += dataLength;
  3259. _CB.rxBufferLeft -= dataLength;
  3260. TRC_DBG((TB, _T("Next copy to %p, left %ld"),
  3261. _CB.rxpBufferCurrent, _CB.rxBufferLeft));
  3262. /********************************************************************/
  3263. /* If this wasn't the last chunk, there's nothing more to do */
  3264. /********************************************************************/
  3265. if (!(dataFlags & CHANNEL_FLAG_LAST))
  3266. {
  3267. TRC_DBG((TB, _T("Not last chunk")));
  3268. freeTheBuffer = FALSE;
  3269. DC_QUIT;
  3270. }
  3271. /********************************************************************/
  3272. /* Check we got the entire message */
  3273. /********************************************************************/
  3274. if (_CB.rxBufferLeft != 0)
  3275. {
  3276. TRC_ERR((TB, _T("Incomplete data, expected/got %ld/%ld"),
  3277. _CB.rxBufferLen, _CB.rxBufferLen - _CB.rxBufferLeft));
  3278. DC_QUIT;
  3279. }
  3280. pClipPDU = (PTS_CLIP_PDU)(_CB.rxpBuffer);
  3281. }
  3282. /************************************************************************/
  3283. /* We allow monitor ready thru because that's what put us in the call! */
  3284. /************************************************************************/
  3285. if ((_CB.state == CB_STATE_INITIALIZED)
  3286. && (pClipPDU->msgType != TS_CB_MONITOR_READY))
  3287. {
  3288. TRC_ERR((TB, _T("Clip message type %hd received when not in call"),
  3289. pClipPDU->msgType));
  3290. DC_QUIT;
  3291. }
  3292. /************************************************************************/
  3293. /* now switch on the packet type */
  3294. /************************************************************************/
  3295. MESSAGE_COMPLETE:
  3296. TRC_NRM((TB, _T("Processing msg type %hd when in state %d"),
  3297. pClipPDU->msgType, _CB.state));
  3298. TRC_DATA_DBG("pdu", pClipPDU,
  3299. (DCUINT)pClipPDU->dataLen + sizeof(TS_CLIP_PDU));
  3300. //
  3301. // Verify that the data in the dataLen in pClipPDU is consistent with the
  3302. // length given in the dataLength parameter.
  3303. //
  3304. if (pClipPDU->dataLen > totalLength - sizeof(TS_CLIP_PDU)) {
  3305. TRC_ERR((TB, _T("Length from network differs from published length.")));
  3306. _CB.channelEP.pVirtualChannelCloseEx(_CB.initHandle, _CB.channelHandle);
  3307. DC_QUIT;
  3308. }
  3309. switch (pClipPDU->msgType)
  3310. {
  3311. case TS_CB_MONITOR_READY:
  3312. {
  3313. /****************************************************************/
  3314. /* The monitor has initialised - we can complete our start up */
  3315. /* now. */
  3316. /****************************************************************/
  3317. TRC_NRM((TB, _T("rx monitor ready")));
  3318. TRC_ASSERT( NULL != _GetDataSync[TS_RESET_EVENT],
  3319. (TB,_T("data sync is NULL")));
  3320. SetEvent(_GetDataSync[TS_RESET_EVENT]) ;
  3321. ClipOnMonitorReady();
  3322. }
  3323. break;
  3324. case TS_CB_FORMAT_LIST:
  3325. {
  3326. /****************************************************************/
  3327. // The server has some new formats for us.
  3328. /****************************************************************/
  3329. TRC_NRM((TB, _T("Rx Format list")));
  3330. // Free the Clipboard thread, if locked
  3331. TRC_ASSERT( NULL != _GetDataSync[TS_RESET_EVENT],
  3332. (TB,_T("data sync is NULL")));
  3333. SetEvent(_GetDataSync[TS_RESET_EVENT]) ;
  3334. ClipDecoupleToClip(pClipPDU) ;
  3335. }
  3336. break;
  3337. case TS_CB_FORMAT_LIST_RESPONSE:
  3338. {
  3339. /****************************************************************/
  3340. // The server has received our new formats.
  3341. /****************************************************************/
  3342. TRC_NRM((TB, _T("Rx Format list Rsp")));
  3343. ClipOnFormatListResponse(pClipPDU);
  3344. }
  3345. break;
  3346. case TS_CB_FORMAT_DATA_REQUEST:
  3347. {
  3348. /****************************************************************/
  3349. // An app on the server wants to paste one of the formats from
  3350. // our clipboard.
  3351. /****************************************************************/
  3352. TRC_NRM((TB, _T("Rx Data Request")));
  3353. ClipOnFormatRequest(pClipPDU);
  3354. }
  3355. break;
  3356. case TS_CB_FORMAT_DATA_RESPONSE:
  3357. {
  3358. /****************************************************************/
  3359. // Here's some format data for us
  3360. /****************************************************************/
  3361. TRC_NRM((TB, _T("Rx Format Data rsp in state %d with flags %02x"),
  3362. _CB.state, pClipPDU->msgFlags));
  3363. ClipOnFormatDataComplete(pClipPDU);
  3364. }
  3365. break;
  3366. default:
  3367. {
  3368. /****************************************************************/
  3369. /* Don't know what this one is! */
  3370. /****************************************************************/
  3371. TRC_ERR((TB, _T("Unknown clip message type %hd"), pClipPDU->msgType));
  3372. }
  3373. break;
  3374. }
  3375. DC_EXIT_POINT:
  3376. /************************************************************************/
  3377. /* Maybe free the receive buffer */
  3378. /************************************************************************/
  3379. if (freeTheBuffer && _CB.rxpBuffer)
  3380. {
  3381. TRC_NRM((TB, _T("Free receive buffer")));
  3382. ClipFree(_CB.rxpBuffer);
  3383. _CB.rxpBuffer = NULL;
  3384. }
  3385. DC_END_FN();
  3386. return;
  3387. } /* CB_OnPacketReceived */
  3388. DCVOID DCAPI CClip::ClipDecoupleToClip (PTS_CLIP_PDU pData)
  3389. {
  3390. ULONG cbPDU ;
  3391. DC_BEGIN_FN("CClip::ClipDecoupleToClip");
  3392. // Allocate space for the PDU and its data, and then copy it
  3393. cbPDU = sizeof(TS_CLIP_PDU) + pData->dataLen ;
  3394. PDCVOID newBuffer = LocalAlloc(LPTR, cbPDU) ;
  3395. if (NULL != newBuffer)
  3396. DC_MEMCPY(newBuffer, pData, cbPDU) ;
  3397. else
  3398. return;
  3399. TRC_NRM((TB, _T("Pass %d bytes to clipboard thread"), cbPDU));
  3400. PostMessage(_CB.viewerWindow,
  3401. _CB.regMsg,
  3402. cbPDU,
  3403. (LPARAM) newBuffer);
  3404. DC_END_FN();
  3405. }
  3406. /****************************************************************************/
  3407. /* Open Event callback */
  3408. /****************************************************************************/
  3409. VOID VCAPITYPE VCEXPORT DCLOADDS CClip::ClipOpenEventFnEx(LPVOID lpUserParam,
  3410. DWORD openHandle,
  3411. UINT event,
  3412. LPVOID pData,
  3413. UINT32 dataLength,
  3414. UINT32 totalLength,
  3415. UINT32 dataFlags)
  3416. {
  3417. DC_BEGIN_FN("CClip::ClipOpenEventFnEx");
  3418. TRC_ASSERT(((VCManager*)lpUserParam != NULL), (TB, _T("lpUserParam is NULL, no instance data")));
  3419. if(!lpUserParam)
  3420. {
  3421. return;
  3422. }
  3423. CClip* pClip = ((VCManager*)lpUserParam)->GetClip();
  3424. TRC_ASSERT((pClip != NULL), (TB, _T("pClip is NULL in ClipOpenEventFnEx")));
  3425. if(!pClip)
  3426. {
  3427. return;
  3428. }
  3429. pClip->ClipInternalOpenEventFn(openHandle, event, pData, dataLength,
  3430. totalLength, dataFlags);
  3431. DC_END_FN();
  3432. return;
  3433. }
  3434. VOID VCAPITYPE VCEXPORT DCLOADDS CClip::ClipInternalOpenEventFn(DWORD openHandle,
  3435. UINT event,
  3436. LPVOID pData,
  3437. UINT32 dataLength,
  3438. UINT32 totalLength,
  3439. UINT32 dataFlags)
  3440. {
  3441. DC_BEGIN_FN("CClip::ClipOpenEventFn");
  3442. DC_IGNORE_PARAMETER(openHandle)
  3443. switch (event)
  3444. {
  3445. /********************************************************************/
  3446. /* Data received from Server */
  3447. /********************************************************************/
  3448. case CHANNEL_EVENT_DATA_RECEIVED:
  3449. {
  3450. TRC_NRM((TB, _T("Data in: handle %ld, len %ld (of %ld), flags %lx"),
  3451. openHandle, dataLength, totalLength, dataFlags)) ;
  3452. TRC_DATA_NRM("Data", pData, (DCUINT)dataLength) ;
  3453. ClipOnDataReceived(pData, dataLength, totalLength, dataFlags) ;
  3454. }
  3455. break;
  3456. /********************************************************************/
  3457. /* Write operation completed */
  3458. /********************************************************************/
  3459. case CHANNEL_EVENT_WRITE_COMPLETE:
  3460. case CHANNEL_EVENT_WRITE_CANCELLED:
  3461. {
  3462. TRC_NRM((TB, _T("Write %s %p"),
  3463. event == CHANNEL_EVENT_WRITE_COMPLETE ? "complete" : "cancelled",
  3464. pData));
  3465. ClipOnWriteComplete(pData);
  3466. }
  3467. break;
  3468. /********************************************************************/
  3469. /* Er, that didn't happen, did it? */
  3470. /********************************************************************/
  3471. default:
  3472. {
  3473. TRC_ERR((TB, _T("Unexpected event %d"), event));
  3474. }
  3475. break;
  3476. }
  3477. DC_END_FN();
  3478. return;
  3479. }
  3480. /****************************************************************************/
  3481. /* Init Event callback */
  3482. /****************************************************************************/
  3483. VOID VCAPITYPE VCEXPORT CClip::ClipInitEventFn(LPVOID pInitHandle,
  3484. UINT event,
  3485. LPVOID pData,
  3486. UINT dataLength)
  3487. {
  3488. DC_BEGIN_FN("CClip::ClipInitEventFn");
  3489. DC_IGNORE_PARAMETER(dataLength)
  3490. DC_IGNORE_PARAMETER(pData)
  3491. switch (event)
  3492. {
  3493. /********************************************************************/
  3494. /* Client initialized (no data) */
  3495. /********************************************************************/
  3496. case CHANNEL_EVENT_INITIALIZED:
  3497. {
  3498. TRC_NRM((TB, _T("CHANNEL_EVENT_INITIALIZED: %p"), pInitHandle));
  3499. ClipOnInitialized();
  3500. }
  3501. break;
  3502. /********************************************************************/
  3503. /* Connection established (data = name of Server) */
  3504. /********************************************************************/
  3505. case CHANNEL_EVENT_CONNECTED:
  3506. {
  3507. TRC_NRM((TB, _T("CHANNEL_EVENT_CONNECTED: %p, Server %s"),
  3508. pInitHandle, pData));
  3509. if (IsDataSyncReady()) {
  3510. ClipOnConnected(pInitHandle);
  3511. }
  3512. else {
  3513. TRC_ERR((TB,_T("data sync not ready on CHANNEL_EVENT_CONNECTED")));
  3514. }
  3515. }
  3516. break;
  3517. /********************************************************************/
  3518. /* Connection established with old Server, so no channel support */
  3519. /********************************************************************/
  3520. case CHANNEL_EVENT_V1_CONNECTED:
  3521. {
  3522. TRC_NRM((TB, _T("CHANNEL_EVENT_V1_CONNECTED: %p, Server %s"),
  3523. pInitHandle, pData));
  3524. }
  3525. break;
  3526. /********************************************************************/
  3527. /* Connection ended (no data) */
  3528. /********************************************************************/
  3529. case CHANNEL_EVENT_DISCONNECTED:
  3530. {
  3531. TRC_NRM((TB, _T("CHANNEL_EVENT_DISCONNECTED: %p"), pInitHandle));
  3532. ClipOnDisconnected(pInitHandle);
  3533. }
  3534. break;
  3535. /********************************************************************/
  3536. /* Client terminated (no data) */
  3537. /********************************************************************/
  3538. case CHANNEL_EVENT_TERMINATED:
  3539. {
  3540. TRC_NRM((TB, _T("CHANNEL_EVENT_TERMINATED: %p"), pInitHandle));
  3541. ClipOnTerm(pInitHandle);
  3542. }
  3543. break;
  3544. /********************************************************************/
  3545. /* Unknown event */
  3546. /********************************************************************/
  3547. default:
  3548. {
  3549. TRC_ERR((TB, _T("Unkown channel event %d: %p"), event, pInitHandle));
  3550. }
  3551. break;
  3552. }
  3553. DC_END_FN();
  3554. return;
  3555. }
  3556. /****************************************************************************/
  3557. /* Clip window proc */
  3558. /****************************************************************************/
  3559. LRESULT CALLBACK DCEXPORT DCLOADDS CClip::StaticClipViewerWndProc(HWND hwnd,
  3560. UINT message,
  3561. WPARAM wParam,
  3562. LPARAM lParam)
  3563. {
  3564. CClip* pClip = (CClip*)GetWindowLongPtr(hwnd, GWLP_USERDATA);
  3565. if(WM_CREATE == message)
  3566. {
  3567. //pull out the this pointer and stuff it in the window class
  3568. LPCREATESTRUCT lpcs = (LPCREATESTRUCT) lParam;
  3569. pClip = (CClip*)lpcs->lpCreateParams;
  3570. SetWindowLongPtr( hwnd, GWLP_USERDATA, (LONG_PTR)pClip);
  3571. }
  3572. //
  3573. // Delegate the message to the appropriate instance
  3574. //
  3575. if(pClip)
  3576. {
  3577. return pClip->ClipViewerWndProc(hwnd, message, wParam, lParam);
  3578. }
  3579. else
  3580. {
  3581. return DefWindowProc(hwnd, message, wParam, lParam);
  3582. }
  3583. }
  3584. LRESULT CALLBACK DCEXPORT DCLOADDS CClip::ClipViewerWndProc(HWND hwnd,
  3585. UINT message,
  3586. WPARAM wParam,
  3587. LPARAM lParam)
  3588. {
  3589. PTS_CLIP_PDU pClipPDU = NULL;
  3590. #ifndef OS_WINCE
  3591. DCUINT32 pduLen;
  3592. DCUINT32 dataLen;
  3593. PDCUINT32 pFormatID;
  3594. MSG msg;
  3595. #endif
  3596. DCBOOL drawRc;
  3597. DCBOOL gotRsp = FALSE;
  3598. LRESULT rc = 0;
  3599. HRESULT hr ;
  3600. DC_BEGIN_FN("CClip::ClipViewerWndProc");
  3601. // We first handle messages from the other thread
  3602. if (message == _CB.regMsg)
  3603. {
  3604. pClipPDU = (PTS_CLIP_PDU)lParam;
  3605. switch (pClipPDU->msgType)
  3606. {
  3607. case TS_CB_FORMAT_LIST:
  3608. {
  3609. TRC_NRM((TB, _T("TS_CB_FORMAT_LIST received")));
  3610. ClipOnFormatList(pClipPDU);
  3611. }
  3612. break;
  3613. default:
  3614. {
  3615. TRC_ERR((TB, _T("Unknown event %d"), pClipPDU->msgType));
  3616. }
  3617. break;
  3618. }
  3619. TRC_NRM((TB, _T("Freeing processed PDU")));
  3620. LocalFree(pClipPDU);
  3621. DC_QUIT;
  3622. }
  3623. else if (message == WM_USER_CLEANUP_ON_TERM) {
  3624. TRC_NRM((TB, _T("Cleanup temp directory")));
  3625. if (0 != ClipCleanTempPath())
  3626. {
  3627. TRC_NRM((TB, _T("Failed while trying to clean temp directory"))) ;
  3628. }
  3629. DC_QUIT;
  3630. }
  3631. switch (message)
  3632. {
  3633. case WM_CREATE:
  3634. {
  3635. /****************************************************************/
  3636. /* We've been created - check the state */
  3637. /****************************************************************/
  3638. CB_CHECK_STATE(CB_EVENT_WM_CREATE);
  3639. #ifndef OS_WINCE
  3640. /****************************************************************/
  3641. /* Add the window to the clipboard viewer chain. */
  3642. /****************************************************************/
  3643. _CB.nextViewer = SetClipboardViewer(hwnd);
  3644. #else
  3645. ghwndClip = hwnd;
  3646. InitializeCriticalSection(&gcsDataObj);
  3647. #endif
  3648. }
  3649. break;
  3650. case WM_DESTROY:
  3651. {
  3652. /****************************************************************/
  3653. /* We're being destroyed - check the state */
  3654. /****************************************************************/
  3655. CB_CHECK_STATE(CB_EVENT_WM_DESTROY);
  3656. #ifndef OS_WINCE
  3657. /****************************************************************/
  3658. /* Remove ourselves from the CB Chain */
  3659. /****************************************************************/
  3660. ChangeClipboardChain(hwnd, _CB.nextViewer);
  3661. #endif
  3662. #ifdef OS_WINCE
  3663. ghwndClip = NULL;
  3664. EnterCriticalSection(&gcsDataObj);
  3665. if (gpDataObj)
  3666. {
  3667. gpDataObj->Release();
  3668. gpDataObj = NULL;
  3669. }
  3670. LeaveCriticalSection(&gcsDataObj);
  3671. DeleteCriticalSection(&gcsDataObj);
  3672. if (ghCeshellDll)
  3673. {
  3674. pfnEDList_Uninitialize();
  3675. FreeLibrary(ghCeshellDll);
  3676. }
  3677. #endif
  3678. _CB.nextViewer = NULL;
  3679. PostQuitMessage(0);
  3680. }
  3681. break;
  3682. case WM_CLOSE:
  3683. {
  3684. DestroyWindow(hwnd);
  3685. }
  3686. break;
  3687. #ifndef OS_WINCE
  3688. case WM_CHANGECBCHAIN:
  3689. {
  3690. /****************************************************************/
  3691. /* The CB viewer chain is chainging - check the state */
  3692. /****************************************************************/
  3693. CB_CHECK_STATE(CB_EVENT_WM_CHANGECBCHAIN);
  3694. /****************************************************************/
  3695. /* If the next window is closing, repair the chain. */
  3696. /****************************************************************/
  3697. if ((HWND)wParam == _CB.nextViewer)
  3698. {
  3699. _CB.nextViewer = (HWND) lParam;
  3700. }
  3701. else if (_CB.nextViewer != NULL)
  3702. {
  3703. /************************************************************/
  3704. /* pass the message to the next link. */
  3705. /************************************************************/
  3706. SendMessage(_CB.nextViewer, message, wParam, lParam);
  3707. }
  3708. }
  3709. break;
  3710. #endif
  3711. case WM_DRAWCLIPBOARD:
  3712. {
  3713. /****************************************************************/
  3714. /* The local clipboard contents have been changed. Check the */
  3715. /* state */
  3716. /****************************************************************/
  3717. if (ClipCheckState(CB_EVENT_WM_DRAWCLIPBOARD) != CB_TABLE_OK)
  3718. {
  3719. TRC_NRM((TB, _T("dropping drawcb - pass on to next viewer")));
  3720. /************************************************************/
  3721. /* check for state pending format list response */
  3722. /************************************************************/
  3723. if (_CB.state == CB_STATE_PENDING_FORMAT_LIST_RSP)
  3724. {
  3725. TRC_ALT((TB, _T("got a draw while processing last")));
  3726. /********************************************************/
  3727. /* we were still waiting for the server to acknowledge */
  3728. /* the last format list when we got a new one - when it */
  3729. /* does, we'll have to to send it the new one. */
  3730. /********************************************************/
  3731. _CB.moreToDo = TRUE;
  3732. }
  3733. if (_CB.nextViewer != NULL)
  3734. {
  3735. /********************************************************/
  3736. /* But not before we pass the message to the next link. */
  3737. /********************************************************/
  3738. SendMessage(_CB.nextViewer, message, wParam, lParam);
  3739. }
  3740. break;
  3741. }
  3742. /****************************************************************/
  3743. /* If it wasn't us that generated this change, then notify the */
  3744. /* remote */
  3745. /****************************************************************/
  3746. TRC_NRM((TB, _T("CB contents have changed...")));
  3747. drawRc = FALSE;
  3748. _CB.moreToDo = FALSE;
  3749. #ifndef OS_WINCE
  3750. LPDATAOBJECT pIDataObject = NULL;
  3751. if (_pClipData != NULL) {
  3752. _pClipData->QueryInterface(IID_IDataObject, (PPVOID) &pIDataObject) ;
  3753. hr = OleIsCurrentClipboard(pIDataObject) ;
  3754. #else
  3755. hr = S_FALSE;
  3756. #endif
  3757. if ((S_FALSE == hr))
  3758. {
  3759. TRC_NRM((TB, _T("...and it wasn't us")));
  3760. #ifdef OS_WINCE
  3761. if (_CB.fFileCutCopyOn)
  3762. DeleteDirectory(_CB.baseTempDirW);//Temp space is at a premium on CE. So delete any copied files now
  3763. #endif
  3764. drawRc = ClipDrawClipboard(TRUE);
  3765. }
  3766. else
  3767. {
  3768. TRC_NRM((TB, _T("...and it was us - ignoring")));
  3769. }
  3770. #ifndef OS_WINCE
  3771. }
  3772. /****************************************************************/
  3773. /* Maybe pass on the draw clipboard message? */
  3774. /****************************************************************/
  3775. if (_CB.nextViewer != NULL)
  3776. {
  3777. TRC_NRM((TB, _T("Notify next viewer")));
  3778. SendMessage(_CB.nextViewer, message, wParam, lParam);
  3779. }
  3780. if (pIDataObject)
  3781. {
  3782. pIDataObject->Release();
  3783. }
  3784. #endif
  3785. }
  3786. break;
  3787. case WM_EMPTY_CLIPBOARD:
  3788. {
  3789. /****************************************************************/
  3790. /* Open the clipboard if needed */
  3791. /****************************************************************/
  3792. if ((!_CB.clipOpen) && !OpenClipboard(NULL))
  3793. {
  3794. UINT count = (DCUINT) wParam;
  3795. TRC_ERR((TB, _T("Failed to open CB when emptying required")));
  3796. // Unfortunately, we are in the racing condition with the app that
  3797. // has the clipboard open. So, we need to keep trying until the app
  3798. // closes the clipboard.
  3799. if (count++ < 10) {
  3800. #ifdef OS_WIN32
  3801. Sleep(0);
  3802. #endif
  3803. PostMessage(_CB.viewerWindow, WM_EMPTY_CLIPBOARD, count, 0);
  3804. }
  3805. break;
  3806. }
  3807. else
  3808. {
  3809. /************************************************************/
  3810. /* It was/is open */
  3811. /************************************************************/
  3812. TRC_NRM((TB, _T("CB opened")));
  3813. _CB.clipOpen = TRUE;
  3814. /************************************************************/
  3815. /* Empty it */
  3816. /************************************************************/
  3817. if (!EmptyClipboard())
  3818. {
  3819. TRC_SYSTEM_ERROR("EmptyClipboard");
  3820. }
  3821. /************************************************************/
  3822. /* update the state */
  3823. /************************************************************/
  3824. CB_SET_STATE(CB_STATE_LOCAL_CB_OWNER, CB_TRACE_EVENT_WM_EMPTY_CLIPBOARD);
  3825. }
  3826. /****************************************************************/
  3827. /* Ensure that we close the local CB */
  3828. /****************************************************************/
  3829. if (_CB.clipOpen)
  3830. {
  3831. _CB.clipOpen = FALSE;
  3832. if (!CloseClipboard())
  3833. {
  3834. TRC_SYSTEM_ERROR("CloseClipboard");
  3835. }
  3836. TRC_NRM((TB, _T("CB closed")));
  3837. }
  3838. }
  3839. break;
  3840. case WM_CLOSE_CLIPBOARD:
  3841. {
  3842. _CB.pendingClose = FALSE;
  3843. TRC_DBG((TB, _T("Maybe close clipboard on WM_CLOSE_CLIPBOARD")));
  3844. if (_CB.clipOpen)
  3845. {
  3846. TRC_NRM((TB, _T("Closing clipboard on WM_CLOSE_CLIPBOARD")));
  3847. _CB.clipOpen = FALSE;
  3848. if (!CloseClipboard())
  3849. {
  3850. TRC_SYSTEM_ERROR("CloseClipboard");
  3851. }
  3852. TRC_DBG((TB, _T("CB closed on WM_CLOSE_CLIPBOARD")));
  3853. }
  3854. }
  3855. break;
  3856. default:
  3857. {
  3858. /****************************************************************/
  3859. /* Ignore all other messages. */
  3860. /****************************************************************/
  3861. rc = DefWindowProc(hwnd, message, wParam, lParam);
  3862. }
  3863. break;
  3864. }
  3865. DC_EXIT_POINT:
  3866. DC_END_FN();
  3867. return(rc);
  3868. } /* ClipViewerWndProc */
  3869. /****************************************************************************/
  3870. /* ClipChannelEntry - called from VirtualChannelEntry in vcint.cpp */
  3871. /****************************************************************************/
  3872. BOOL VCAPITYPE VCEXPORT CClip::ClipChannelEntry(PCHANNEL_ENTRY_POINTS_EX pEntryPoints)
  3873. {
  3874. DC_BEGIN_FN("CClip::ClipChannelEntry");
  3875. TRC_NRM((TB, _T("Size %ld, Init %p, Open %p, Close %p, Write %p"),
  3876. pEntryPoints->cbSize,
  3877. pEntryPoints->pVirtualChannelInitEx, pEntryPoints->pVirtualChannelOpenEx,
  3878. pEntryPoints->pVirtualChannelCloseEx, pEntryPoints->pVirtualChannelWriteEx));
  3879. /************************************************************************/
  3880. /* Save the function pointers -- the memory pointed to by pEntryPoints */
  3881. /* is only valid for the duration of this call. */
  3882. /************************************************************************/
  3883. DC_MEMCPY(&(_CB.channelEP), pEntryPoints, sizeof(CHANNEL_ENTRY_POINTS_EX));
  3884. TRC_NRM((TB, _T("Save entry points %p at address %p"),
  3885. pEntryPoints, &(_CB.channelEP)));
  3886. DC_END_FN();
  3887. return TRUE;
  3888. }
  3889. DCINT DCAPI CClip::ClipGetData (DCUINT cfFormat)
  3890. {
  3891. PTS_CLIP_PDU pClipPDU = NULL;
  3892. DCUINT32 pduLen;
  3893. DCUINT32 dataLen;
  3894. PDCUINT32 pFormatID;
  3895. BOOL success = 0 ;
  3896. DC_BEGIN_FN("CClip::ClipGetData");
  3897. CB_CHECK_STATE(CB_EVENT_WM_RENDERFORMAT);
  3898. /****************************************************************/
  3899. /* and record the requested format */
  3900. /****************************************************************/
  3901. _CB.pendingClientID = cfFormat ;
  3902. _CB.pendingServerID = ClipRemoteFormatFromLocalID
  3903. (_CB.pendingClientID);
  3904. if (!_CB.pendingServerID)
  3905. {
  3906. TRC_NRM((TB, _T("Client format %d not supported/found. Failing"), _CB.pendingClientID)) ;
  3907. DC_QUIT ;
  3908. }
  3909. TRC_NRM((TB, _T("Render format received for %d (server ID %d)"),
  3910. _CB.pendingClientID, _CB.pendingServerID));
  3911. dataLen = sizeof(DCUINT32);
  3912. pduLen = sizeof(TS_CLIP_PDU) + dataLen;
  3913. // We can use the permanent send buffer for this
  3914. TRC_NRM((TB, _T("Get perm TX buffer")));
  3915. pClipPDU = ClipGetPermBuf();
  3916. // Fill in the PDU
  3917. DC_MEMSET(pClipPDU, 0, sizeof(*pClipPDU));
  3918. pClipPDU->msgType = TS_CB_FORMAT_DATA_REQUEST;
  3919. pClipPDU->dataLen = dataLen;
  3920. pFormatID = (PDCUINT32)(pClipPDU->data);
  3921. *pFormatID = (DCUINT32)_CB.pendingServerID;
  3922. // Send the PDU
  3923. TRC_NRM((TB, _T("Sending format data request")));
  3924. success = (_CB.channelEP.pVirtualChannelWriteEx
  3925. (_CB.initHandle, _CB.channelHandle, pClipPDU, pduLen, pClipPDU)
  3926. == CHANNEL_RC_OK) ;
  3927. if (!success) {
  3928. TRC_ERR((TB, _T("Failed VC write: setting clip data to NULL")));
  3929. ClipFreeBuf((PDCUINT8)pClipPDU);
  3930. SetClipboardData(_CB.pendingClientID, NULL);
  3931. // Yes, the exit point is just below, but it may not be always be
  3932. DC_QUIT ;
  3933. }
  3934. DC_EXIT_POINT:
  3935. // Update the state
  3936. if (success)
  3937. CB_SET_STATE(CB_STATE_PENDING_FORMAT_DATA_RSP, CB_EVENT_WM_RENDERFORMAT);
  3938. DC_END_FN();
  3939. return success ;
  3940. }
  3941. #ifdef OS_WINCE
  3942. DCVOID CClip::ClipFixupRichTextFormats(UINT uRtf1, UINT uRtf2)
  3943. {
  3944. DC_BEGIN_FN("CClip::ClipFixupRichTextFormats");
  3945. if (uRtf1 == 0xffffffff)
  3946. {
  3947. TRC_ASSERT((uRtf2 == 0xffffffff), (TB, _T("uRtf2 is invalid")));
  3948. return;
  3949. }
  3950. if (uRtf2 == 0xffffffff)
  3951. {
  3952. _CB.idMap[uRtf1].clientID = RegisterClipboardFormat(CFSTR_RTF);
  3953. SetClipboardData(_CB.idMap[uRtf1].clientID, NULL);
  3954. TRC_DBG((TB, _T("Adding format '%s', server ID %d, client ID %d"), CFSTR_RTF, _CB.idMap[uRtf1].serverID, _CB.idMap[uRtf1].clientID));
  3955. return;
  3956. }
  3957. DCTCHAR *pFormat1 = CFSTR_RTF, *pFormat2 = CFSTR_RTFNOOBJECTS;
  3958. if (_CB.idMap[uRtf1].serverID > _CB.idMap[uRtf2].serverID)
  3959. {
  3960. pFormat1 = CFSTR_RTFNOOBJECTS;
  3961. pFormat2 = CFSTR_RTF;
  3962. }
  3963. _CB.idMap[uRtf1].clientID = RegisterClipboardFormat(pFormat1);
  3964. _CB.idMap[uRtf2].clientID = RegisterClipboardFormat(pFormat2);
  3965. TRC_DBG((TB, _T("Adding format '%s', server ID %d, client ID %d"), CFSTR_RTF, _CB.idMap[uRtf1].serverID, _CB.idMap[uRtf1].clientID));
  3966. SetClipboardData(_CB.idMap[uRtf1].clientID, NULL);
  3967. TRC_DBG((TB, _T("Adding format '%s', server ID %d, client ID %d"), CFSTR_RTFNOOBJECTS, _CB.idMap[uRtf2].serverID, _CB.idMap[uRtf2].clientID));
  3968. SetClipboardData(_CB.idMap[uRtf2].clientID, NULL);
  3969. DC_END_FN();
  3970. }
  3971. #endif //OS_WINCE
  3972. CClipData::CClipData(PCClip pClip)
  3973. {
  3974. DWORD status = ERROR_SUCCESS;
  3975. DC_BEGIN_FN("CClipData::CClipData") ;
  3976. _pClip = pClip ;
  3977. _cRef = 0 ;
  3978. _pImpIDataObject = NULL ;
  3979. //
  3980. // Initialize the single instance critical
  3981. // section lock. This is used to ensure only one
  3982. // thread is accessing _pImpIDataObject at the time
  3983. //
  3984. //
  3985. __try
  3986. {
  3987. InitializeCriticalSection(&_csLock);
  3988. }
  3989. __except(EXCEPTION_EXECUTE_HANDLER)
  3990. {
  3991. status = GetExceptionCode();
  3992. }
  3993. if(ERROR_SUCCESS == status)
  3994. {
  3995. _fLockInitialized = TRUE;
  3996. }
  3997. else
  3998. {
  3999. _fLockInitialized = FALSE;
  4000. TRC_ERR((TB,_T("InitializeCriticalSection failed 0x%x."),status));
  4001. }
  4002. DC_END_FN();
  4003. }
  4004. //
  4005. // Call Release() on the contained IDataObject implementation. This is necessary because
  4006. // SetNumFormats() calls AddRef() and if we are terminating, then there must be a way
  4007. // to balance this AddRef() so that the circular reference between CClipData and
  4008. // CImpIDataObject will be broken.
  4009. //
  4010. void CClipData::TearDown()
  4011. {
  4012. if (_pImpIDataObject != NULL)
  4013. {
  4014. _pImpIDataObject->Release();
  4015. _pImpIDataObject = NULL;
  4016. }
  4017. }
  4018. CClipData::~CClipData(void)
  4019. {
  4020. DC_BEGIN_FN("CClipData::~CClipData");
  4021. if(_fLockInitialized)
  4022. {
  4023. DeleteCriticalSection(&_csLock);
  4024. }
  4025. DC_END_FN();
  4026. }
  4027. HRESULT DCINTERNAL CClipData::SetNumFormats(ULONG numFormats)
  4028. {
  4029. HRESULT hr = S_OK;
  4030. DC_BEGIN_FN("CClipData::SetNumFormats");
  4031. if (_fLockInitialized) {
  4032. EnterCriticalSection(&_csLock);
  4033. if (_pImpIDataObject)
  4034. {
  4035. _pImpIDataObject->Release();
  4036. _pImpIDataObject = NULL;
  4037. }
  4038. _pImpIDataObject = new CImpIDataObject(this) ;
  4039. if (_pImpIDataObject == NULL)
  4040. {
  4041. TRC_ERR((TB, _T("Unable to create IDataObject")));
  4042. hr = E_OUTOFMEMORY;
  4043. DC_QUIT;
  4044. }
  4045. else
  4046. {
  4047. _pImpIDataObject->AddRef() ;
  4048. hr = _pImpIDataObject->Init(numFormats);
  4049. DC_QUIT_ON_FAIL(hr);
  4050. }
  4051. LeaveCriticalSection(&_csLock);
  4052. }
  4053. DC_EXIT_POINT:
  4054. DC_END_FN();
  4055. return hr;
  4056. }
  4057. DCVOID CClipData::SetClipData(HGLOBAL hGlobal, DCUINT clipType)
  4058. {
  4059. DC_BEGIN_FN("CClipData::SetClipData");
  4060. if (_fLockInitialized) {
  4061. EnterCriticalSection(&_csLock);
  4062. if (_pImpIDataObject != NULL) {
  4063. _pImpIDataObject->SetClipData(hGlobal, clipType) ;
  4064. }
  4065. LeaveCriticalSection(&_csLock);
  4066. }
  4067. DC_END_FN();
  4068. }
  4069. STDMETHODIMP CClipData::QueryInterface(REFIID riid, PPVOID ppv)
  4070. {
  4071. DC_BEGIN_FN("CClipData::QueryInterface");
  4072. //set ppv to NULL just in case the interface isn't found
  4073. *ppv=NULL;
  4074. if (IID_IUnknown==riid) {
  4075. *ppv=this;
  4076. //AddRef any interface we'll return.
  4077. ((LPUNKNOWN)*ppv)->AddRef();
  4078. }
  4079. if (IID_IDataObject==riid) {
  4080. if (_fLockInitialized) {
  4081. EnterCriticalSection(&_csLock);
  4082. *ppv=_pImpIDataObject ;
  4083. if (_pImpIDataObject != NULL) {
  4084. //AddRef any interface we'll return.
  4085. ((LPUNKNOWN)*ppv)->AddRef();
  4086. }
  4087. LeaveCriticalSection(&_csLock);
  4088. }
  4089. }
  4090. if (NULL==*ppv)
  4091. return ResultFromScode(E_NOINTERFACE);
  4092. DC_END_FN();
  4093. return NOERROR;
  4094. }
  4095. STDMETHODIMP_(ULONG) CClipData::AddRef(void)
  4096. {
  4097. DC_BEGIN_FN("CClipData::AddRef");
  4098. DC_END_FN();
  4099. return InterlockedIncrement(&_cRef);
  4100. }
  4101. STDMETHODIMP_(ULONG) CClipData::Release(void)
  4102. {
  4103. LONG cRef;
  4104. DC_BEGIN_FN("CClipData::Release");
  4105. cRef = InterlockedDecrement(&_cRef);
  4106. if (cRef == 0)
  4107. {
  4108. delete this;
  4109. }
  4110. DC_END_FN();
  4111. return cRef;
  4112. }
  4113. CImpIDataObject::CImpIDataObject(LPUNKNOWN lpUnk)
  4114. {
  4115. #ifndef OS_WINCE
  4116. byte i ;
  4117. #endif
  4118. DC_BEGIN_FN("CImpIDataObject::CImplDataObject") ;
  4119. _numFormats = 0 ;
  4120. _maxNumFormats = 0 ;
  4121. _cRef = 0 ;
  4122. _pUnkOuter = lpUnk ;
  4123. if (_pUnkOuter)
  4124. {
  4125. _pUnkOuter->AddRef();
  4126. }
  4127. _pFormats = NULL ;
  4128. _pSTGMEDIUM = NULL ;
  4129. _lastFormatRequested = 0 ;
  4130. _cfDropEffect = (CLIPFORMAT) RegisterClipboardFormat(CFSTR_PREFERREDDROPEFFECT) ;
  4131. DC_END_FN();
  4132. }
  4133. HRESULT CImpIDataObject::Init(ULONG numFormats)
  4134. {
  4135. DC_BEGIN_FN("CImpIDataObject::Init") ;
  4136. HRESULT hr = S_OK;
  4137. _maxNumFormats = numFormats ;
  4138. // Allocate space for the formats only
  4139. if (_pFormats) {
  4140. LocalFree(_pFormats);
  4141. }
  4142. _pFormats = (LPFORMATETC) LocalAlloc(LPTR,_maxNumFormats*sizeof(FORMATETC)) ;
  4143. if (NULL == _pFormats) {
  4144. TRC_ERR((TB,_T("failed to allocate _pFormats")));
  4145. hr = E_OUTOFMEMORY;
  4146. DC_QUIT;
  4147. }
  4148. if (_pSTGMEDIUM) {
  4149. LocalFree(_pSTGMEDIUM);
  4150. }
  4151. _pSTGMEDIUM = (STGMEDIUM*) LocalAlloc(LPTR, sizeof(STGMEDIUM)) ;
  4152. if (NULL == _pSTGMEDIUM)
  4153. {
  4154. TRC_ERR((TB,_T("Failed to allocate STGMEDIUM")));
  4155. hr = E_OUTOFMEMORY;
  4156. DC_QUIT;
  4157. }
  4158. _pSTGMEDIUM->tymed = TYMED_HGLOBAL ;
  4159. _pSTGMEDIUM->pUnkForRelease = NULL ;
  4160. _pSTGMEDIUM->hGlobal = NULL ;
  4161. _uiSTGType = 0;
  4162. DC_EXIT_POINT:
  4163. DC_END_FN();
  4164. return hr;
  4165. }
  4166. DCVOID CImpIDataObject::SetClipData(HGLOBAL hGlobal, DCUINT clipType)
  4167. {
  4168. DC_BEGIN_FN("CImpIDataObject::SetClipData");
  4169. if (!_pSTGMEDIUM)
  4170. _pSTGMEDIUM = (STGMEDIUM*) LocalAlloc(LPTR, sizeof(STGMEDIUM)) ;
  4171. if (NULL != _pSTGMEDIUM)
  4172. {
  4173. if (CF_PALETTE == clipType) {
  4174. _pSTGMEDIUM->tymed = TYMED_GDI;
  4175. }
  4176. else if (CF_METAFILEPICT == clipType) {
  4177. _pSTGMEDIUM->tymed = TYMED_MFPICT;
  4178. }
  4179. else {
  4180. _pSTGMEDIUM->tymed = TYMED_HGLOBAL;
  4181. }
  4182. _pSTGMEDIUM->pUnkForRelease = NULL ;
  4183. FreeSTGMEDIUM();
  4184. _pSTGMEDIUM->hGlobal = hGlobal ;
  4185. _uiSTGType = clipType;
  4186. }
  4187. DC_END_FN();
  4188. }
  4189. DCVOID
  4190. CImpIDataObject::FreeSTGMEDIUM(void)
  4191. {
  4192. if ( NULL == _pSTGMEDIUM->hGlobal )
  4193. {
  4194. return;
  4195. }
  4196. switch( _uiSTGType )
  4197. {
  4198. case CF_PALETTE:
  4199. DeleteObject( _pSTGMEDIUM->hGlobal );
  4200. break;
  4201. #ifndef OS_WINCE
  4202. case CF_METAFILEPICT:
  4203. {
  4204. LPMETAFILEPICT pMFPict = (LPMETAFILEPICT)GlobalLock( _pSTGMEDIUM->hGlobal );
  4205. if ( NULL != pMFPict )
  4206. {
  4207. if ( NULL != pMFPict->hMF )
  4208. {
  4209. DeleteMetaFile( pMFPict->hMF );
  4210. }
  4211. GlobalUnlock( _pSTGMEDIUM->hGlobal );
  4212. }
  4213. GlobalFree( _pSTGMEDIUM->hGlobal );
  4214. }
  4215. break;
  4216. #endif
  4217. default:
  4218. GlobalFree( _pSTGMEDIUM->hGlobal );
  4219. }
  4220. _pSTGMEDIUM->hGlobal = NULL;
  4221. }
  4222. CImpIDataObject::~CImpIDataObject(void)
  4223. {
  4224. DC_BEGIN_FN("CImpIDataObject::~CImplDataObject") ;
  4225. if (_pFormats)
  4226. LocalFree(_pFormats) ;
  4227. if (_pSTGMEDIUM)
  4228. {
  4229. FreeSTGMEDIUM();
  4230. LocalFree(_pSTGMEDIUM) ;
  4231. }
  4232. if (_pUnkOuter)
  4233. {
  4234. _pUnkOuter->Release();
  4235. _pUnkOuter = NULL;
  4236. }
  4237. DC_END_FN();
  4238. }
  4239. // IUnknown members
  4240. // - Delegate to "outer" IUnknown
  4241. STDMETHODIMP CImpIDataObject::QueryInterface(REFIID riid, PPVOID ppv)
  4242. {
  4243. DC_BEGIN_FN("CImpIDataObject::QueryInterface");
  4244. DC_END_FN();
  4245. return _pUnkOuter->QueryInterface(riid, ppv);
  4246. }
  4247. STDMETHODIMP_(ULONG) CImpIDataObject::AddRef(void)
  4248. {
  4249. DC_BEGIN_FN("CImpIDataObject::AddRef");
  4250. InterlockedIncrement(&_cRef);
  4251. DC_END_FN();
  4252. return _pUnkOuter->AddRef();
  4253. }
  4254. STDMETHODIMP_(ULONG) CImpIDataObject::Release(void)
  4255. {
  4256. LONG cRef;
  4257. DC_BEGIN_FN("CImpIDataObject::Release");
  4258. _pUnkOuter->Release();
  4259. cRef = InterlockedDecrement(&_cRef) ;
  4260. if (0 == cRef)
  4261. delete this;
  4262. DC_END_FN() ;
  4263. return cRef;
  4264. }
  4265. // IDataObject members
  4266. // ***************************************************************************
  4267. // CImpIDataObject::GetData
  4268. // - Here, we have to wait for the data to actually get here before we return.
  4269. // ***************************************************************************
  4270. STDMETHODIMP CImpIDataObject::GetData(LPFORMATETC pFE, LPSTGMEDIUM pSTM)
  4271. {
  4272. HRESULT result = E_FAIL; // Assume we fail until we know we haven't
  4273. #ifndef OS_WINCE
  4274. TCHAR formatName[TS_FORMAT_NAME_LEN] ;
  4275. byte charSize ;
  4276. BOOL fWide ;
  4277. WCHAR* fileListW ;
  4278. HPDCVOID pFilename ;
  4279. HPDCVOID pOldFilename ;
  4280. #endif
  4281. HGLOBAL hData = NULL ;
  4282. HPDCVOID pData ;
  4283. HPDCVOID pOldData ;
  4284. #ifndef OS_WINCE
  4285. DROPFILES* pDropFiles ;
  4286. DROPFILES tempDropfile ;
  4287. ULONG oldSize ;
  4288. ULONG newSize ;
  4289. #endif
  4290. DWORD eventSignaled ;
  4291. DWORD* pDropEffect ;
  4292. #ifndef OS_WINCE
  4293. char* fileList ;
  4294. #endif
  4295. PCClip pClip ;
  4296. DC_BEGIN_FN("CImpIDataObject::GetData");
  4297. // Should never occur, but we check for sanity's sake
  4298. if (NULL == (PCClipData)_pUnkOuter)
  4299. {
  4300. TRC_ERR((TB, _T("Ptr to outer unknown is NULL"))) ;
  4301. result = E_FAIL ;
  4302. DC_QUIT ;
  4303. }
  4304. if (NULL == ((PCClipData)_pUnkOuter)->_pClip)
  4305. {
  4306. TRC_ERR((TB, _T("Ptr to clip class is NULL"))) ;
  4307. result = E_FAIL ;
  4308. DC_QUIT ;
  4309. }
  4310. // Since we need to have the CClip class do work for us,
  4311. // we pull out a pointer to it that we stored in the beginning
  4312. pClip = (PCClip) ((PCClipData)_pUnkOuter)->_pClip ;
  4313. if (!_pSTGMEDIUM)
  4314. {
  4315. TRC_ERR((TB, _T("Transfer medium (STGMEDIUM) is NULL"))) ;
  4316. result = E_FAIL ;
  4317. DC_QUIT ;
  4318. }
  4319. TRC_ASSERT( pClip->IsDataSyncReady(),
  4320. (TB, _T("Data Sync not ready")));
  4321. if (!_pSTGMEDIUM->hGlobal || (pFE->cfFormat != _lastFormatRequested))
  4322. {
  4323. TRC_ASSERT( pClip->IsDataSyncReady(),
  4324. (TB,_T("data sync is NULL")));
  4325. ResetEvent(pClip->_GetDataSync[TS_RESET_EVENT]) ;
  4326. if (!((PCClipData)_pUnkOuter)->_pClip->ClipGetData(pFE->cfFormat))
  4327. {
  4328. result = E_FAIL ;
  4329. DC_QUIT ;
  4330. }
  4331. eventSignaled = WaitForMultipleObjects(
  4332. TS_NUM_EVENTS,
  4333. ((PCClipData)_pUnkOuter)->_pClip->_GetDataSync,
  4334. FALSE,
  4335. INFINITE
  4336. ) ;
  4337. if ((WAIT_OBJECT_0+TS_RESET_EVENT) == eventSignaled)
  4338. {
  4339. TRC_NRM((TB, _T("Other thread told us to reset. Failing GetData"))) ;
  4340. ResetEvent(((PCClipData)_pUnkOuter)->_pClip->_GetDataSync[TS_RESET_EVENT]) ;
  4341. result = E_FAIL ;
  4342. DC_QUIT ;
  4343. }
  4344. // Make sure that we actually got data from the server.
  4345. if (_pSTGMEDIUM->hGlobal == NULL) {
  4346. TRC_ERR((TB, _T("No format data received from server!")));
  4347. result = E_FAIL;
  4348. DC_QUIT;
  4349. }
  4350. #ifndef OS_WINCE
  4351. if (CF_HDROP == pFE->cfFormat)
  4352. {
  4353. // if we got an HDROP and we're not NT/2000, we check to see if we
  4354. // have to convert to ansi; otherwise, we're done
  4355. if (pClip->GetOsMinorType() != TS_OSMINORTYPE_WINDOWS_NT)
  4356. {
  4357. pDropFiles = (DROPFILES*) GlobalLock(_pSTGMEDIUM->hGlobal) ;
  4358. if (!pDropFiles)
  4359. {
  4360. TRC_ERR((TB, _T("Failed to lock %p"), hData)) ;
  4361. result = E_FAIL ;
  4362. DC_QUIT ;
  4363. }
  4364. // if we definitely have wide characters, then convert
  4365. if (pDropFiles->fWide)
  4366. {
  4367. // temporarily store the original's base dropfile info
  4368. tempDropfile.pFiles = pDropFiles->pFiles ;
  4369. tempDropfile.pt = pDropFiles->pt ;
  4370. tempDropfile.fNC = pDropFiles->fNC ;
  4371. tempDropfile.fWide = 0 ; // we are converting to ANSI now
  4372. // We divide by the size of wchar_t because we need half as many
  4373. // bytes with ansi as opposed to fWide character strings
  4374. oldSize = (ULONG) GlobalSize(_pSTGMEDIUM->hGlobal) - pDropFiles->pFiles ;
  4375. newSize = oldSize / sizeof(WCHAR) ;
  4376. fileList = (char*) (LocalAlloc(LPTR,newSize)) ;
  4377. if ( NULL == fileList )
  4378. {
  4379. TRC_ERR((TB, _T("Unable to allocate %d bytes"), newSize ));
  4380. result = E_FAIL;
  4381. DC_QUIT;
  4382. }
  4383. // This will convert the wide HDROP filelist to ansi, and
  4384. // put the ansi version into filelist
  4385. // 11-12
  4386. // pDropFiles is probably "foo\0bar\0baz\0\0"
  4387. // I don't believe WC2MB will go past the first \0
  4388. if (!WideCharToMultiByte(GetACP(), NULL, (wchar_t*)
  4389. ((byte*) pDropFiles + pDropFiles->pFiles),
  4390. newSize, fileList,
  4391. newSize, NULL, NULL))
  4392. {
  4393. TRC_ERR((TB, _T("Unable convert wide to ansi"), newSize)) ;
  4394. LocalFree( fileList );
  4395. result = E_FAIL ;
  4396. DC_QUIT ;
  4397. }
  4398. // Output the first filename for a sanity check
  4399. TRC_NRM((TB, _T("Filename 1 = %hs"), fileList)) ;
  4400. GlobalUnlock(_pSTGMEDIUM->hGlobal) ;
  4401. // Reallocate the space for the dropfile
  4402. hData = GlobalAlloc(GMEM_DISCARDABLE | GMEM_MOVEABLE,
  4403. newSize + tempDropfile.pFiles) ;
  4404. if (!hData)
  4405. {
  4406. TRC_ERR((TB, _T("Allocate memory; err=%d"), GetLastError())) ;
  4407. LocalFree( fileList );
  4408. result = E_FAIL ;
  4409. DC_QUIT ;
  4410. }
  4411. pDropFiles = (DROPFILES*) GlobalLock(hData) ;
  4412. if (!pDropFiles)
  4413. {
  4414. TRC_ERR((TB, _T("Unable to lock %p"), hData)) ;
  4415. LocalFree( fileList );
  4416. result = E_FAIL ;
  4417. DC_QUIT ;
  4418. }
  4419. pDropFiles->pFiles = tempDropfile.pFiles ;
  4420. pDropFiles->pt = tempDropfile.pt ;
  4421. pDropFiles->fNC = tempDropfile.fNC ;
  4422. pDropFiles->fWide = tempDropfile.fWide ;
  4423. DC_MEMCPY((byte*) pDropFiles + pDropFiles->pFiles,
  4424. fileList, newSize) ;
  4425. // Output the first filename for another sanity check
  4426. TRC_NRM((TB, _T("Filename = %s"), (byte*) pDropFiles + pDropFiles->pFiles)) ;
  4427. LocalFree( fileList );
  4428. }
  4429. GlobalUnlock(hData) ;
  4430. GlobalFree(_pSTGMEDIUM->hGlobal) ;
  4431. _pSTGMEDIUM->hGlobal = hData ;
  4432. }
  4433. }
  4434. #else
  4435. if (gfmtShellPidlArray == pFE->cfFormat)
  4436. {
  4437. HANDLE hNewData = HDropToIDList(_pSTGMEDIUM->hGlobal);
  4438. GlobalFree(_pSTGMEDIUM->hGlobal);
  4439. _pSTGMEDIUM->hGlobal = hNewData;
  4440. }
  4441. #endif
  4442. // We check the dropeffect format, because we strip out
  4443. // shortcuts/links, and store the dropeffects. The dropeffect is
  4444. // what some apps (explorer) use to decide if they should copy, move
  4445. // or link
  4446. else if (_cfDropEffect == pFE->cfFormat)
  4447. {
  4448. if (GlobalSize(_pSTGMEDIUM->hGlobal) < sizeof(DWORD)) {
  4449. TRC_ERR((TB, _T("Unexpected global memory size!")));
  4450. result = E_FAIL;
  4451. DC_QUIT;
  4452. }
  4453. pDropEffect = (DWORD*) GlobalLock(_pSTGMEDIUM->hGlobal) ;
  4454. if (!pDropEffect)
  4455. {
  4456. TRC_NRM((TB, _T("Unable to lock %p"), _pSTGMEDIUM->hGlobal)) ;
  4457. result = E_FAIL ;
  4458. DC_QUIT ;
  4459. }
  4460. // Strip out shortcuts/links
  4461. *pDropEffect = *pDropEffect ^ DROPEFFECT_LINK ;
  4462. // Strip out moves
  4463. *pDropEffect = *pDropEffect ^ DROPEFFECT_MOVE ;
  4464. pClip->SetDropEffect(*pDropEffect) ;
  4465. if (GlobalUnlock(_pSTGMEDIUM->hGlobal))
  4466. {
  4467. TRC_ASSERT(GetLastError() == NO_ERROR,
  4468. (TB, _T("Unable to unlock HGLOBAL we just locked"))) ;
  4469. }
  4470. }
  4471. pSTM->tymed = _pSTGMEDIUM->tymed ;
  4472. pSTM->hGlobal = _pSTGMEDIUM->hGlobal ;
  4473. _pSTGMEDIUM->hGlobal = NULL;
  4474. pSTM->pUnkForRelease = _pSTGMEDIUM->pUnkForRelease ;
  4475. result = S_OK ;
  4476. DC_QUIT ;
  4477. }
  4478. else
  4479. {
  4480. pSTM->tymed = _pSTGMEDIUM->tymed ;
  4481. pSTM->hGlobal = GlobalAlloc(GMEM_DISCARDABLE | GMEM_MOVEABLE,
  4482. GlobalSize(_pSTGMEDIUM->hGlobal)) ;
  4483. pData = GlobalLock(pSTM->hGlobal) ;
  4484. pOldData = GlobalLock(_pSTGMEDIUM->hGlobal) ;
  4485. if (!pData || !pOldData)
  4486. return E_FAIL ;
  4487. DC_MEMCPY(pData, pOldData, GlobalSize(_pSTGMEDIUM->hGlobal)) ;
  4488. GlobalUnlock(pSTM->hGlobal) ;
  4489. GlobalUnlock(_pSTGMEDIUM->hGlobal) ;
  4490. pSTM->pUnkForRelease = _pSTGMEDIUM->pUnkForRelease ;
  4491. }
  4492. if (!pSTM->hGlobal)
  4493. {
  4494. TRC_NRM((TB, _T("Clipboard data request failed"))) ;
  4495. return E_FAIL ;
  4496. }
  4497. DC_EXIT_POINT:
  4498. DC_END_FN();
  4499. return result ;
  4500. }
  4501. STDMETHODIMP CImpIDataObject::GetDataHere(LPFORMATETC pFE, LPSTGMEDIUM pSTM)
  4502. {
  4503. DC_BEGIN_FN("CImpIDataObject::GetDataHere") ;
  4504. DC_END_FN();
  4505. return ResultFromScode(E_NOTIMPL) ;
  4506. }
  4507. STDMETHODIMP CImpIDataObject::QueryGetData(LPFORMATETC pFE)
  4508. {
  4509. ULONG i = 0 ;
  4510. HRESULT hr = DV_E_CLIPFORMAT ;
  4511. DC_BEGIN_FN("CImpIDataObject::QueryGetData") ;
  4512. TRC_NRM((TB, _T("Format ID %d requested"), pFE->cfFormat)) ;
  4513. while (i < _numFormats)
  4514. {
  4515. if (_pFormats[i].cfFormat == pFE->cfFormat) {
  4516. hr = S_OK ;
  4517. break ;
  4518. }
  4519. i++ ;
  4520. }
  4521. DC_END_FN();
  4522. return hr ;
  4523. }
  4524. STDMETHODIMP CImpIDataObject::GetCanonicalFormatEtc(LPFORMATETC pFEIn, LPFORMATETC pFEOut)
  4525. {
  4526. DC_BEGIN_FN("CImpIDataObject::GetCanonicalFormatEtc") ;
  4527. DC_END_FN();
  4528. return ResultFromScode(E_NOTIMPL) ;
  4529. }
  4530. // ***************************************************************************
  4531. // CImpIDataObject::SetData
  4532. // - Due to the fact that the RDP only passes the simple clipboard format, and
  4533. // the fact that we obtain all of our clipboard data from memory later, pSTM
  4534. // is really ignored at this point. It isn't until GetData is called that
  4535. // the remote clipboard data is received, and a valid global memory handle
  4536. // is generated.
  4537. // - Thus, pSTM and fRelease are ignored.
  4538. // - So out _pSTGMEDIUM is generated using generic values
  4539. // ***************************************************************************
  4540. STDMETHODIMP CImpIDataObject::SetData(LPFORMATETC pFE, LPSTGMEDIUM pSTM, BOOL fRelease)
  4541. {
  4542. TCHAR formatName[TS_FORMAT_NAME_LEN] = {0} ;
  4543. byte i ;
  4544. DC_BEGIN_FN("CImpIDataObject::SetData");
  4545. DC_IGNORE_PARAMETER(pSTM) ;
  4546. // Reset the the last format requested to 0
  4547. _lastFormatRequested = 0 ;
  4548. TRC_NRM((TB, _T("Adding format %d to IDataObject"), pFE->cfFormat)) ;
  4549. if (_numFormats < _maxNumFormats)
  4550. {
  4551. for (i=0; i < _numFormats; i++)
  4552. {
  4553. if (pFE->cfFormat == _pFormats[i].cfFormat)
  4554. {
  4555. TRC_NRM((TB, _T("Duplicate format. Discarded"))) ;
  4556. return DV_E_FORMATETC ;
  4557. }
  4558. }
  4559. _pFormats[_numFormats] = *pFE ;
  4560. _numFormats++ ;
  4561. }
  4562. else
  4563. {
  4564. TRC_ERR((TB, _T("Cannot add any more formats"))) ;
  4565. return E_FAIL ;
  4566. }
  4567. DC_END_FN();
  4568. return S_OK ;
  4569. }
  4570. STDMETHODIMP CImpIDataObject::EnumFormatEtc(DWORD dwDir, LPENUMFORMATETC *ppEnum)
  4571. {
  4572. PCEnumFormatEtc pEnum;
  4573. *ppEnum=NULL;
  4574. /*
  4575. * From an external point of view there are no SET formats,
  4576. * because we want to allow the user of this component object
  4577. * to be able to stuff ANY format in via Set. Only external
  4578. * users will call EnumFormatEtc and they can only Get.
  4579. */
  4580. switch (dwDir)
  4581. {
  4582. case DATADIR_GET:
  4583. pEnum=new CEnumFormatEtc(_pUnkOuter);
  4584. break;
  4585. case DATADIR_SET:
  4586. default:
  4587. pEnum=new CEnumFormatEtc(_pUnkOuter);
  4588. break;
  4589. }
  4590. if (NULL==pEnum)
  4591. return ResultFromScode(E_FAIL);
  4592. else
  4593. {
  4594. //Let the enumerator copy our format list.
  4595. pEnum->Init(_pFormats, _numFormats) ;
  4596. pEnum->AddRef();
  4597. }
  4598. *ppEnum=pEnum;
  4599. return NO_ERROR ;
  4600. }
  4601. STDMETHODIMP CImpIDataObject::DAdvise(LPFORMATETC pFE, DWORD dwFlags,
  4602. LPADVISESINK pIAdviseSink, LPDWORD pdwConn)
  4603. {
  4604. return ResultFromScode(E_NOTIMPL) ;
  4605. }
  4606. STDMETHODIMP CImpIDataObject::DUnadvise(DWORD dwConn)
  4607. {
  4608. return ResultFromScode(E_NOTIMPL) ;
  4609. }
  4610. STDMETHODIMP CImpIDataObject::EnumDAdvise(LPENUMSTATDATA *ppEnum)
  4611. {
  4612. return ResultFromScode(E_NOTIMPL) ;
  4613. }
  4614. CEnumFormatEtc::CEnumFormatEtc(LPUNKNOWN pUnkRef)
  4615. {
  4616. DC_BEGIN_FN("CEnumFormatEtc::CEnumFormatEtc");
  4617. _cRef = 0 ;
  4618. _pUnkRef = pUnkRef ;
  4619. if (_pUnkRef)
  4620. {
  4621. _pUnkRef->AddRef();
  4622. }
  4623. _iCur = 0;
  4624. DC_END_FN() ;
  4625. }
  4626. DCVOID CEnumFormatEtc::Init(LPFORMATETC pFormats, ULONG numFormats)
  4627. {
  4628. DC_BEGIN_FN("CEnumFormatEtc::Init");
  4629. _cItems = numFormats;
  4630. _pFormats = (LPFORMATETC) LocalAlloc(LPTR,_cItems*sizeof(FORMATETC)) ;
  4631. if (_pFormats)
  4632. {
  4633. memcpy(_pFormats, pFormats, _cItems*sizeof(FORMATETC)) ;
  4634. }
  4635. else
  4636. {
  4637. TRC_ERR((TB, _T("Unable to allocate memory for formats"))) ;
  4638. }
  4639. DC_END_FN() ;
  4640. }
  4641. CEnumFormatEtc::~CEnumFormatEtc()
  4642. {
  4643. DC_BEGIN_FN("CEnumFormatEtc::~CEnumFormatEtc");
  4644. if (_pUnkRef)
  4645. {
  4646. _pUnkRef->Release();
  4647. _pUnkRef = NULL;
  4648. }
  4649. if (NULL !=_pFormats)
  4650. LocalFree(_pFormats) ;
  4651. DC_END_FN() ;
  4652. }
  4653. STDMETHODIMP CEnumFormatEtc::QueryInterface(REFIID riid, PPVOID ppv)
  4654. {
  4655. DC_BEGIN_FN("CEnumFormatEtc::QueryInterface");
  4656. *ppv=NULL;
  4657. /*
  4658. * Enumerators are separate objects, not the data object, so
  4659. * we only need to support out IUnknown and IEnumFORMATETC
  4660. * interfaces here with no concern for aggregation.
  4661. */
  4662. if (IID_IUnknown==riid || IID_IEnumFORMATETC==riid)
  4663. *ppv=this;
  4664. if (NULL!=*ppv)
  4665. {
  4666. ((LPUNKNOWN)*ppv)->AddRef();
  4667. return NOERROR;
  4668. }
  4669. DC_END_FN() ;
  4670. return ResultFromScode(E_NOINTERFACE);
  4671. }
  4672. STDMETHODIMP_(ULONG) CEnumFormatEtc::AddRef(void)
  4673. {
  4674. LONG cRef;
  4675. cRef = InterlockedIncrement(&_cRef);
  4676. _pUnkRef->AddRef();
  4677. return cRef;
  4678. }
  4679. STDMETHODIMP_(ULONG) CEnumFormatEtc::Release(void)
  4680. {
  4681. LONG cRef;
  4682. DC_BEGIN_FN("CEnumFormatEtc::Release");
  4683. _pUnkRef->Release();
  4684. cRef = InterlockedDecrement(&_cRef) ;
  4685. if (0 == cRef)
  4686. delete this;
  4687. DC_END_FN() ;
  4688. return cRef;
  4689. }
  4690. STDMETHODIMP CEnumFormatEtc::Next(ULONG cFE, LPFORMATETC pFE, ULONG *pulFE)
  4691. {
  4692. ULONG cReturn=0L;
  4693. if (NULL==_pFormats)
  4694. return ResultFromScode(S_FALSE);
  4695. if (NULL==pulFE)
  4696. {
  4697. if (1L!=cFE)
  4698. return ResultFromScode(E_POINTER);
  4699. }
  4700. else
  4701. *pulFE=0L;
  4702. if (NULL==pFE || _iCur >= _cItems)
  4703. return ResultFromScode(S_FALSE);
  4704. while (_iCur < _cItems && cFE > 0)
  4705. {
  4706. *pFE=_pFormats[_iCur];
  4707. pFE++;
  4708. _iCur++;
  4709. cReturn++;
  4710. cFE--;
  4711. }
  4712. if (NULL!=pulFE)
  4713. *pulFE=cReturn;
  4714. return NOERROR;
  4715. }
  4716. STDMETHODIMP CEnumFormatEtc::Skip(ULONG cSkip)
  4717. {
  4718. if ((_iCur+cSkip) >= _cItems)
  4719. return ResultFromScode(S_FALSE);
  4720. _iCur+=cSkip;
  4721. return NOERROR;
  4722. }
  4723. STDMETHODIMP CEnumFormatEtc::Reset(void)
  4724. {
  4725. _iCur=0;
  4726. return NOERROR;
  4727. }
  4728. STDMETHODIMP CEnumFormatEtc::Clone(LPENUMFORMATETC *ppEnum)
  4729. {
  4730. #ifndef OS_WINCE
  4731. PCEnumFormatEtc pNew = NULL;
  4732. LPMALLOC pIMalloc;
  4733. LPFORMATETC prgfe;
  4734. BOOL fRet=TRUE;
  4735. ULONG cb;
  4736. *ppEnum=NULL;
  4737. #else
  4738. BOOL fRet=FALSE;
  4739. #endif
  4740. #ifndef OS_WINCE
  4741. //Copy the memory for the list.
  4742. if (FAILED(CoGetMalloc(MEMCTX_TASK, &pIMalloc)))
  4743. return ResultFromScode(E_OUTOFMEMORY);
  4744. cb=_cItems*sizeof(FORMATETC);
  4745. prgfe=(LPFORMATETC)pIMalloc->Alloc(cb);
  4746. if (NULL!=prgfe)
  4747. {
  4748. //Copy the formats
  4749. memcpy(prgfe, _pFormats, (int)cb);
  4750. //Create the clone
  4751. pNew=new CEnumFormatEtc(_pUnkRef);
  4752. if (NULL != pNew)
  4753. {
  4754. pNew->_iCur=_iCur;
  4755. pNew->_pFormats=prgfe;
  4756. pNew->AddRef();
  4757. fRet=TRUE;
  4758. }
  4759. else
  4760. {
  4761. fRet = FALSE;
  4762. }
  4763. }
  4764. pIMalloc->Release();
  4765. *ppEnum=pNew;
  4766. #endif
  4767. return fRet ? NOERROR : ResultFromScode(E_OUTOFMEMORY);
  4768. }