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.

2006 lines
74 KiB

  1. /**MOD+**********************************************************************/
  2. /* Module: sclip2.cpp */
  3. /* */
  4. /* Purpose: Second thread */
  5. /* Receives RDP clipboard messages */
  6. /* */
  7. /* Copyright(C) Microsoft Corporation 1998 */
  8. /* */
  9. /**MOD-**********************************************************************/
  10. #include <adcg.h>
  11. #define TRC_GROUP TRC_GROUP_CORE
  12. #define TRC_FILE "sclip2"
  13. #include <atrcapi.h>
  14. #include <pclip.h>
  15. #include <sclip.h>
  16. #include <pchannel.h>
  17. #include <shlobj.h>
  18. /****************************************************************************/
  19. /* Global data */
  20. /****************************************************************************/
  21. #include <sclipdat.h>
  22. //
  23. // CBMConvertToClientPath, CBMConvertToClientPathA, CBMConvertToClientPathW
  24. // - Arguments:
  25. // pOldData = Buffer containing the original file path
  26. // pData = Buffer receiving the new file path
  27. // - Returns S_OK if pOldData was a drive path
  28. // E_FAIL if it failed
  29. // - Given a file path with drive letter, this function will strip out the
  30. // colon, and prepend the UNC prefix defined by TS_PREPEND_STRING
  31. //
  32. //
  33. // ***** NOTE *****
  34. // - Currently, if the path is a network path, and not a drive path (C:\path)
  35. // it simply fails
  36. //
  37. HRESULT CBMConvertToClientPath(PVOID pOldData, PVOID pData, size_t cbDest,
  38. BOOL fWide)
  39. {
  40. DC_BEGIN_FN("CBMConvertToClientPath") ;
  41. if (!pOldData)
  42. {
  43. TRC_ERR((TB, _T("Original string pointer is NULL"))) ;
  44. return E_FAIL ;
  45. }
  46. if (!pData)
  47. {
  48. TRC_ERR((TB, _T("Destination string pointer is NULL"))) ;
  49. return E_FAIL ;
  50. }
  51. if (fWide)
  52. return CBMConvertToClientPathW(pOldData, pData, cbDest) ;
  53. else
  54. return CBMConvertToClientPathA(pOldData, pData, cbDest) ;
  55. DC_END_FN() ;
  56. }
  57. HRESULT CBMConvertToClientPathW(PVOID pOldData, PVOID pData, size_t cbDest)
  58. {
  59. wchar_t* filePath ;
  60. wchar_t* driveLetter ;
  61. size_t driveLetterLength ;
  62. HRESULT hr;
  63. DC_BEGIN_FN("CBMConvertToClientPathW") ;
  64. // if this is a filepath with a drive letter, we strip the colon, and
  65. // prefix the path with the temp Directory
  66. filePath = wcschr((wchar_t*)pOldData, L':') ;
  67. if (filePath)
  68. {
  69. hr = StringCbCopyW((wchar_t*)pData, cbDest, CBM.tempDirW);
  70. DC_QUIT_ON_FAIL(hr);
  71. // Now, we start from after the colon in the drive path, and
  72. // find the last '\\' so we have just "\filename"
  73. filePath = wcsrchr(filePath + 1, L'\\');
  74. // Add the leftover "\filename"
  75. if (filePath != NULL) {
  76. hr = StringCbCatW((wchar_t*)pData, cbDest, filePath);
  77. DC_QUIT_ON_FAIL(hr);
  78. }
  79. TRC_DBG((TB,_T("New filename = %s"), (wchar_t*)pData)) ;
  80. }
  81. // else if this is a UNC path beginning with a "\\"
  82. else if (((wchar_t*) pOldData)[0] == L'\\' &&
  83. ((wchar_t*) pOldData)[1] == L'\\')
  84. {
  85. // if we receive a path beginning with the TS_PREPEND_STRING then
  86. // we should be smart and convert it back to a path with drive letter
  87. if (0 == _wcsnicmp ((wchar_t *) pOldData,
  88. LTS_PREPEND_STRING, TS_PREPEND_LENGTH))
  89. {
  90. // Skip TS_PREPEND_STRING
  91. driveLetter = ((wchar_t*) pOldData)+TS_PREPEND_LENGTH ;
  92. driveLetterLength = (BYTE*)wcschr(driveLetter, L'\\') -
  93. (BYTE*)driveLetter;
  94. hr = StringCbCopyNW((wchar_t*)pData, cbDest, driveLetter,
  95. driveLetterLength);
  96. DC_QUIT_ON_FAIL(hr);
  97. ((wchar_t*)pData)[driveLetterLength] = L'\0' ;
  98. hr = StringCbCatW((wchar_t*)pData, cbDest, L":");
  99. DC_QUIT_ON_FAIL(hr);
  100. filePath = wcschr(driveLetter, L'\\');
  101. if (filePath != NULL) {
  102. hr = StringCbCatW((wchar_t*)pData, cbDest, filePath);
  103. DC_QUIT_ON_FAIL(hr);
  104. }
  105. }
  106. // otherwise, we just got a regular UNC path.
  107. else
  108. {
  109. // Stary by prepending the new file path with the temp directory
  110. hr = StringCbCopyW((wchar_t*) pData, cbDest, CBM.tempDirW) ;
  111. DC_QUIT_ON_FAIL(hr);
  112. // Now, we start from the beginning of the original path,
  113. // find the last '\\' so we have just "\filename"
  114. filePath = wcsrchr((wchar_t*)pOldData, L'\\');
  115. if (filePath != NULL) {
  116. hr = StringCbCatW((wchar_t*) pData, cbDest, filePath) ;
  117. DC_QUIT_ON_FAIL(hr);
  118. }
  119. }
  120. }
  121. else
  122. {
  123. TRC_ERR((TB, _T("Bad path"))) ;
  124. hr = E_FAIL; ;
  125. }
  126. DC_EXIT_POINT:
  127. if (FAILED(hr)) {
  128. TRC_ERR((TB,_T("returning failure; hr=0x%x"), hr));
  129. }
  130. DC_END_FN() ;
  131. return hr ;
  132. }
  133. HRESULT CBMConvertToClientPathA(PVOID pOldData, PVOID pData, size_t cbDest)
  134. {
  135. char* filePath ;
  136. char* driveLetter ;
  137. char* tempPath ;
  138. size_t driveLetterLength ;
  139. HRESULT hr;
  140. DC_BEGIN_FN("CBMConvertToClientPathA") ;
  141. // if this is a filepath with a drive letter, we strip the colon, and
  142. // prefix the path with the temp Directory
  143. filePath = strchr((char*)pOldData, ':') ;
  144. if (filePath)
  145. {
  146. hr = StringCbCopyA( (char*)pData, cbDest, CBM.tempDirA) ;
  147. DC_QUIT_ON_FAIL(hr);
  148. // Now, we start from after the colon in the drive path, and
  149. // find the last '\\' so we have just "\filename"
  150. filePath = strrchr(filePath + 1, '\\');
  151. // Add the leftover "\filename"
  152. if (filePath != NULL) {
  153. hr = StringCbCatA((char*)pData, cbDest, filePath) ;
  154. DC_QUIT_ON_FAIL(hr);
  155. }
  156. }
  157. // else if this is a UNC path beginning with a "\\"
  158. else if (((char*) pOldData)[0] == '\\' &&
  159. ((char*) pOldData)[1] == '\\')
  160. {
  161. // if this we receive a path beginning with the TS_PREPEND_STRING then
  162. // we should be smart and convert it back to a path with drive letter
  163. if (0 == _strnicmp ((char*)pOldData,
  164. TS_PREPEND_STRING, TS_PREPEND_LENGTH))
  165. {
  166. // Skip TS_PREPEND_STRING
  167. driveLetter = ((char*) pOldData) + TS_PREPEND_LENGTH ;
  168. driveLetterLength = (BYTE*)strchr(driveLetter, '\\') -
  169. (BYTE*)driveLetter;
  170. hr = StringCbCopyNA((char*)pData, cbDest, driveLetter,
  171. driveLetterLength) ;
  172. DC_QUIT_ON_FAIL(hr);
  173. ((char*)pData)[driveLetterLength] = '\0' ;
  174. hr = StringCbCatA((char*)pData, cbDest, ":") ;
  175. DC_QUIT_ON_FAIL(hr);
  176. filePath = strchr(driveLetter, '\\');
  177. if (filePath != NULL) {
  178. hr = StringCbCatA((char*)pData, cbDest, filePath) ;
  179. DC_QUIT_ON_FAIL(hr);
  180. }
  181. }
  182. // otherwise, we just got a regular UNC path.
  183. else
  184. {
  185. // Stary by prepending the new file path with the temp directory
  186. hr = StringCbCopyA((char*) pData, cbDest, CBM.tempDirA) ;
  187. DC_QUIT_ON_FAIL(hr);
  188. // Now, we start from the beginning of the original path,
  189. // find the last '\\' so we have just "\filename"
  190. filePath = strrchr((char*)pOldData, L'\\');
  191. if (filePath != NULL) {
  192. hr = StringCbCatA((char*) pData, cbDest, filePath) ;
  193. DC_QUIT_ON_FAIL(hr);
  194. }
  195. }
  196. }
  197. else
  198. {
  199. TRC_ERR((TB, _T("Bad path"))) ;
  200. hr = E_FAIL ;
  201. }
  202. DC_EXIT_POINT:
  203. if (FAILED(hr)) {
  204. TRC_ERR((TB,_T("returning failure; hr=0x%x"), hr));
  205. }
  206. DC_END_FN() ;
  207. return hr;
  208. }
  209. //
  210. // CBMGetNewFilePathLengthForClient
  211. // - Arguments:
  212. // pData = Buffer containing a filepath
  213. // fWide = Wide or Ansi (TRUE if wide, FALSE if ansi)
  214. // - Returns the size (in bytes) required to convert the path to a client path
  215. // 0 if it fails
  216. //
  217. UINT CBMGetNewFilePathLengthForClient(PVOID pData, BOOL fWide)
  218. {
  219. UINT result ;
  220. DC_BEGIN_FN("CBMGetNewFilePathLengthForClient") ;
  221. if (!pData)
  222. {
  223. TRC_ERR((TB, _T("Filename is NULL"))) ;
  224. result = 0 ;
  225. }
  226. if (fWide)
  227. result = CBMGetNewFilePathLengthForClientW((WCHAR*)pData) ;
  228. else
  229. result = CBMGetNewFilePathLengthForClientA((char*)pData) ;
  230. DC_EXIT_POINT:
  231. DC_END_FN() ;
  232. return result ;
  233. }
  234. UINT CBMGetNewFilePathLengthForClientW(WCHAR* wszOldFilepath)
  235. {
  236. UINT oldLength = wcslen(wszOldFilepath) ;
  237. UINT newLength ;
  238. UINT remainingLength = oldLength ;
  239. byte charSize = sizeof(WCHAR) ;
  240. DC_BEGIN_FN("CBMGetNewFilePathLengthForClientW") ;
  241. // if the old filename didn't even have space for "c:\" (with NULL),
  242. // then its probably invalid
  243. if (4 > oldLength)
  244. {
  245. newLength = 0 ;
  246. DC_QUIT ;
  247. }
  248. // We check to see if the filepath is prefixed by the TS_PREPEND_STRING
  249. // If so, we should be smart, and return the size of it with the prepend
  250. // string removed, and the colon added.
  251. if (0 == _wcsnicmp(wszOldFilepath,
  252. LTS_PREPEND_STRING, TS_PREPEND_LENGTH))
  253. {
  254. newLength = oldLength - TS_PREPEND_LENGTH + 1 ; // +1 is for the colon
  255. DC_QUIT ;
  256. }
  257. while ((0 != remainingLength) && (L'\\' != wszOldFilepath[remainingLength]))
  258. {
  259. remainingLength-- ;
  260. }
  261. // Add the length of the temp directory path, and subtract the
  262. // path preceeding the filename ("path\filename" -> "\filename")
  263. // (\\server\sharename\path\morepath\filename
  264. newLength = oldLength - remainingLength + wcslen(CBM.tempDirW) + 1;
  265. DC_EXIT_POINT:
  266. DC_END_FN() ;
  267. return newLength * charSize ;
  268. }
  269. UINT CBMGetNewFilePathLengthForClientA(char* szOldFilepath)
  270. {
  271. UINT oldLength = strlen(szOldFilepath) ;
  272. UINT newLength ;
  273. UINT remainingLength = oldLength ;
  274. byte charSize = sizeof(char) ;
  275. DC_BEGIN_FN("CBMGetNewFilePathLengthForClientA") ;
  276. // if the old filename didn't even have space for "c:\" (with NULL),
  277. // then its probably invalid
  278. if (4 > oldLength)
  279. {
  280. newLength = 0 ;
  281. DC_QUIT ;
  282. }
  283. // We check to see if the filepath is prefixed by the TS_PREPEND_STRING
  284. // If so, we should be smart, and return the size of it with the prepend
  285. // string removed, and the colon added.
  286. if (0 == _strnicmp(szOldFilepath,
  287. TS_PREPEND_STRING, TS_PREPEND_LENGTH))
  288. {
  289. newLength = oldLength - TS_PREPEND_LENGTH + 1 ; // +1 is for the colon
  290. DC_QUIT ;
  291. }
  292. while ((0 != remainingLength) && ('\\' != szOldFilepath[remainingLength]))
  293. {
  294. remainingLength-- ;
  295. }
  296. // Add the length of the temp directory path, and subtract the
  297. // path preceeding the filename ("path\filename" -> "\filename")
  298. // (\\server\sharename\path\morepath\filename
  299. newLength = oldLength - remainingLength + strlen(CBM.tempDirA) + 1;
  300. DC_EXIT_POINT:
  301. DC_END_FN() ;
  302. return newLength * charSize ;
  303. }
  304. //
  305. // CBMGetNewDropfilesSizeForClientSize
  306. // - Arguments:
  307. // pData = Buffer containing a DROPFILES struct
  308. // oldSize = The size of the DROPFILES struct
  309. // fWide = Wide or Ansi (TRUE if wide, FALSE if ansi)
  310. // - Returns the size required for a conversion of the paths to client paths
  311. // 0 if it fails
  312. //
  313. ULONG CBMGetNewDropfilesSizeForClient(PVOID pData, ULONG oldSize, BOOL fWide)
  314. {
  315. DC_BEGIN_FN("CBMGetNewDropfilesSizeForClientSize") ;
  316. if (fWide)
  317. return CBMGetNewDropfilesSizeForClientW(pData, oldSize) ;
  318. else
  319. return CBMGetNewDropfilesSizeForClientA(pData, oldSize) ;
  320. DC_END_FN() ;
  321. }
  322. ULONG CBMGetNewDropfilesSizeForClientW(PVOID pData, ULONG oldSize)
  323. {
  324. ULONG newSize = oldSize ;
  325. wchar_t* filenameW ;
  326. wchar_t* filePathW ;
  327. wchar_t* fullFilePathW ;
  328. byte charSize ;
  329. DC_BEGIN_FN("CBMGetNewDropfilesSizeForClientSizeW") ;
  330. charSize = sizeof(wchar_t) ;
  331. if (!pData)
  332. {
  333. TRC_ERR((TB,_T("Pointer to dropfile is NULL"))) ;
  334. return 0 ;
  335. }
  336. // The start of the first filename
  337. fullFilePathW = (wchar_t*) ((byte*) pData + ((DROPFILES*) pData)->pFiles) ;
  338. while (L'\0' != fullFilePathW[0])
  339. {
  340. filePathW = wcschr(fullFilePathW, L':') ;
  341. // If the file path has a colon in it, then it's a valid drive path
  342. if (filePathW)
  343. {
  344. // we add space for (strlen(tempDir)-1+1) characters because
  345. // although we are adding strlen(tempDir) characters, we are
  346. // stripping out the colon from the filepath; however, we add
  347. // an extra "\" to the string because the tempDir does not have
  348. // a trailing "\"
  349. filenameW = wcsrchr(filePathW, L'\\');
  350. // Add the length of the temp directory path, and subtract the
  351. // path preceeding the filename ("path\filename" -> "\filename")
  352. // (\\server\sharename\path\morepath\filename
  353. newSize += (wcslen(CBM.tempDirW) + (filenameW - fullFilePathW))
  354. * charSize ;
  355. }
  356. // Otherwise, it is a UNC path
  357. else if (fullFilePathW[0] == L'\\' &&
  358. fullFilePathW[1] == L'\\')
  359. {
  360. // if we receive a path beginning with the TS_PREPEND_STRING then
  361. // we should be smart and convert it back to a path with drive letter
  362. if (0 == _wcsnicmp(fullFilePathW,
  363. LTS_PREPEND_STRING, TS_PREPEND_LENGTH))
  364. {
  365. newSize = newSize - (TS_PREPEND_LENGTH - 1) * charSize ;
  366. }
  367. else
  368. {
  369. filenameW = wcsrchr(fullFilePathW, L'\\');
  370. // Add the length of the temp directory path, and subtract the
  371. // path preceeding the filename ("path\filename" -> "\filename")
  372. // (\\server\sharename\path\morepath\filename
  373. newSize += (wcslen(CBM.tempDirW) - (filenameW - fullFilePathW))
  374. * charSize ;
  375. }
  376. }
  377. else
  378. {
  379. TRC_ERR((TB,_T("Bad path"))) ;
  380. return 0 ;
  381. }
  382. fullFilePathW = fullFilePathW + (wcslen(fullFilePathW) + 1) ;
  383. }
  384. // Add space for extra null character
  385. newSize += charSize ;
  386. DC_END_FN() ;
  387. return newSize ;
  388. }
  389. ULONG CBMGetNewDropfilesSizeForClientA(PVOID pData, ULONG oldSize)
  390. {
  391. ULONG newSize = oldSize ;
  392. char* filename ;
  393. char* filePath ;
  394. char* fullFilePath ;
  395. byte charSize ;
  396. DC_BEGIN_FN("CBMGetNewDropfilesSizeForClientSizeW") ;
  397. charSize = sizeof(char) ;
  398. if (!pData)
  399. {
  400. TRC_ERR((TB,_T("Pointer to dropfile is NULL"))) ;
  401. return 0 ;
  402. }
  403. // The start of the first filename
  404. fullFilePath = (char*) ((byte*) pData + ((DROPFILES*) pData)->pFiles) ;
  405. while ('\0' != fullFilePath[0])
  406. {
  407. filePath = strchr(fullFilePath, ':') ;
  408. // If the file path has a colon in it, then its a valid drive path
  409. if (filePath)
  410. {
  411. // we add space for (strlen(tempDir)-1+1) characters because
  412. // although we are adding strlen(tempDir) characters, we are
  413. // stripping out the colon from the filepath; however, we add
  414. // an extra "\" to the string because the tempDir does not have
  415. // a trailing "\"
  416. filename = strrchr(filePath, '\\');
  417. // Add the length of the temp directory path, and subtract the
  418. // path preceeding the filename ("path\filename" -> "\filename")
  419. // (\\server\sharename\path\morepath\filename
  420. newSize += (strlen(CBM.tempDirA) + (filename - fullFilePath))
  421. * charSize ;
  422. }
  423. // Otherwise, it is a UNC path
  424. else if (fullFilePath[0] == '\\' &&
  425. fullFilePath[1] == '\\')
  426. {
  427. // if we receive a path beginning with the TS_PREPEND_STRING then
  428. // we should be smart and convert it back to a path with drive letter
  429. if (0 == _strnicmp(fullFilePath,
  430. TS_PREPEND_STRING, TS_PREPEND_LENGTH))
  431. {
  432. newSize = newSize - (TS_PREPEND_LENGTH - 1) * charSize ;
  433. }
  434. else
  435. {
  436. filename = strrchr(fullFilePath, '\\');
  437. // Add the length of the temp directory path, and subtract the
  438. // path preceeding the filename ("path\filename" -> "\filename")
  439. // (\\server\sharename\path\morepath\filename
  440. newSize += (strlen(CBM.tempDirA) + (filename - fullFilePath))
  441. * charSize ;
  442. }
  443. }
  444. else
  445. {
  446. TRC_ERR((TB,_T("Bad path"))) ;
  447. return 0 ;
  448. }
  449. fullFilePath = fullFilePath + (strlen(fullFilePath) + 1) ;
  450. }
  451. // Add space for extra null character
  452. newSize += charSize ;
  453. DC_END_FN() ;
  454. return newSize ;
  455. }
  456. //
  457. // ClipConvertToTempPath, ClipConvertToTempPathA, ClipConvertToTempPathW
  458. // - Arguments:
  459. // pSrcFiles = buffer containing the names/path of the files to be copied
  460. // - Returns 0 if successful
  461. // nonzero if failed
  462. // - Given a list of file names/paths, this function will attempt to copy them
  463. // to the temp directory
  464. //
  465. int CBMCopyToTempDirectory(PVOID pSrcFiles, BOOL fWide)
  466. {
  467. int result ;
  468. if (fWide)
  469. result = CBMCopyToTempDirectoryW(pSrcFiles) ;
  470. else
  471. result = CBMCopyToTempDirectoryA(pSrcFiles) ;
  472. return result ;
  473. }
  474. int CBMCopyToTempDirectoryW(PVOID pSrcFiles)
  475. {
  476. DC_BEGIN_FN("CBMCopyToTempDirectoryW") ;
  477. SHFILEOPSTRUCTW fileOpStructW ;
  478. int result ;
  479. HRESULT hr;
  480. // these are the temp, "temp directories"; they are used because we cannot
  481. // directly perform a conversion to client path CBM.tempDir*, because they
  482. // are used within the conversion routines!
  483. wchar_t tempDirW[MAX_PATH] ;
  484. hr = CBMConvertToServerPath(CBM.tempDirW, tempDirW, sizeof(tempDirW), 1) ;
  485. if (FAILED(hr)) {
  486. TRC_ERR((TB,_T("CBMConvertToServerPath failed hr=0x%x"), hr));
  487. result = hr;
  488. DC_QUIT;
  489. }
  490. fileOpStructW.pFrom = (WCHAR*) pSrcFiles ;
  491. fileOpStructW.pTo = tempDirW ;
  492. fileOpStructW.hwnd = NULL ;
  493. fileOpStructW.wFunc = CBM.dropEffect ;
  494. fileOpStructW.fFlags = FOF_NOCONFIRMATION | FOF_NOCONFIRMMKDIR |
  495. FOF_SIMPLEPROGRESS | FOF_ALLOWUNDO ;
  496. fileOpStructW.hNameMappings = NULL ;
  497. fileOpStructW.lpszProgressTitle = CBM.szPasteInfoStringW;
  498. result = SHFileOperationW(&fileOpStructW) ;
  499. DC_EXIT_POINT:
  500. DC_END_FN();
  501. return result ;
  502. }
  503. int CBMCopyToTempDirectoryA(PVOID pSrcFiles)
  504. {
  505. DC_BEGIN_FN("CBMCopyToTempDirectoryA") ;
  506. SHFILEOPSTRUCTA fileOpStructA ;
  507. int result ;
  508. HRESULT hr;
  509. char tempDirA[MAX_PATH] ;
  510. hr = CBMConvertToServerPath(CBM.tempDirA, tempDirA, sizeof(tempDirA), 0) ;
  511. if (FAILED(hr)) {
  512. TRC_ERR((TB,_T("CBMConvertToServerPath failed hr=0x%x"), hr));
  513. result = hr;
  514. DC_QUIT;
  515. }
  516. fileOpStructA.pFrom = (char*) pSrcFiles ;
  517. fileOpStructA.pTo = tempDirA ;
  518. fileOpStructA.hwnd = NULL ;
  519. fileOpStructA.wFunc = CBM.dropEffect ;
  520. fileOpStructA.fFlags = FOF_NOCONFIRMATION | FOF_NOCONFIRMMKDIR |
  521. FOF_SIMPLEPROGRESS | FOF_ALLOWUNDO ;
  522. fileOpStructA.hNameMappings = NULL ;
  523. fileOpStructA.lpszProgressTitle = CBM.szPasteInfoStringA;
  524. result = SHFileOperationA(&fileOpStructA) ;
  525. DC_EXIT_POINT:
  526. DC_END_FN();
  527. return result ;
  528. }
  529. /****************************************************************************/
  530. /* CBMOnDataReceived - handle incoming data */
  531. /****************************************************************************/
  532. DCVOID DCINTERNAL CBMOnDataReceived(PDCUINT8 pBuffer, DCUINT cbBytes)
  533. {
  534. PCHANNEL_PDU_HEADER pHdr;
  535. PDCUINT8 pData;
  536. DCUINT copyLen;
  537. DCBOOL freeTheBuffer = FALSE;
  538. PTS_CLIP_PDU pClipPDU;
  539. DC_BEGIN_FN("CBMOnDataReceived");
  540. SetEvent(CBM.GetDataSync[TS_BLOCK_RECEIVED]) ;
  541. pHdr = (PCHANNEL_PDU_HEADER)pBuffer;
  542. pData = (PDCUINT8)(pHdr + 1);
  543. TRC_DBG((TB, _T("Header at %p: flags %#x, length %d"),
  544. pHdr, pHdr->flags, pHdr->length));
  545. // Check to be sure we have at least a header worth of data
  546. if (sizeof(CHANNEL_PDU_HEADER) > cbBytes) {
  547. TRC_ERR((TB,_T("Packet not large enough to contain header; cbBytes=%u"),
  548. cbBytes));
  549. freeTheBuffer = TRUE;
  550. DC_QUIT;
  551. }
  552. /************************************************************************/
  553. /* First chunk - allocate memory to hold the entire message */
  554. /************************************************************************/
  555. if (pHdr->flags & CHANNEL_FLAG_FIRST)
  556. {
  557. TRC_NRM((TB, _T("First chunk - %d of %d"), cbBytes, pHdr->length));
  558. CBM.rxpBuffer = (PDCUINT8) LocalAlloc(LMEM_FIXED, pHdr->length);
  559. if (CBM.rxpBuffer)
  560. {
  561. CBM.rxpNext = CBM.rxpBuffer;
  562. CBM.rxSize = pHdr->length;
  563. CBM.rxLeft = pHdr->length;
  564. }
  565. else
  566. {
  567. TRC_ERR((TB, _T("Failed to alloc %d bytes for rx buffer"),
  568. pHdr->length));
  569. DC_QUIT;
  570. }
  571. }
  572. /************************************************************************/
  573. /* Check that we have a buffer available */
  574. /************************************************************************/
  575. if (!CBM.rxpBuffer)
  576. {
  577. TRC_ERR((TB, _T("No rx buffer")));
  578. DC_QUIT;
  579. }
  580. /************************************************************************/
  581. /* Check there's enough space left */
  582. /************************************************************************/
  583. copyLen = cbBytes - sizeof(*pHdr);
  584. if (CBM.rxLeft < copyLen)
  585. {
  586. TRC_ERR((TB, _T("Not enough space in rx buffer: need/got %d/%d"),
  587. copyLen, CBM.rxLeft));
  588. freeTheBuffer = TRUE;
  589. DC_QUIT;
  590. }
  591. /************************************************************************/
  592. /* Copy the data */
  593. /************************************************************************/
  594. TRC_DBG((TB, _T("Copy %d bytes to %p"), copyLen, CBM.rxpNext));
  595. DC_MEMCPY(CBM.rxpNext, pData, copyLen);
  596. CBM.rxpNext += copyLen;
  597. CBM.rxLeft -= copyLen;
  598. /************************************************************************/
  599. /* If we have a complete buffer, tell the main thread */
  600. /************************************************************************/
  601. if (pHdr->flags & CHANNEL_FLAG_LAST)
  602. {
  603. /********************************************************************/
  604. /* Check that we received all the data */
  605. /********************************************************************/
  606. if (CBM.rxLeft != 0)
  607. {
  608. TRC_ERR((TB, _T("Didn't receive all the data: expect/got: %d/%d"),
  609. CBM.rxSize, CBM.rxSize - CBM.rxLeft));
  610. freeTheBuffer = TRUE;
  611. DC_QUIT;
  612. }
  613. // Check that we received at least a TS_CLIP_PDU in length
  614. if (FIELDOFFSET(TS_CLIP_PDU, data) > CBM.rxSize) {
  615. TRC_ERR((TB,_T("Assembled buffer to short for TS_CLIP_PDU ")
  616. _T(" [need=%u got=%u]"), FIELDOFFSET(TS_CLIP_PDU, data),
  617. CBM.rxSize));
  618. freeTheBuffer = TRUE;
  619. DC_QUIT;
  620. }
  621. /********************************************************************/
  622. // If this message contains a response to our format list, a request
  623. // for clipboard data or the clipboard data that we requested
  624. // handle it in this thread (it will not block us for long)
  625. // Otherwise,
  626. // Tell the main thread. The main thread will free the buffer when
  627. // it's done with this message.
  628. /********************************************************************/
  629. pClipPDU = (PTS_CLIP_PDU) CBM.rxpBuffer ;
  630. // Validate that there is enough data to read whatever is advertised
  631. // in the pClipPDU->dataLen
  632. if (pClipPDU->dataLen + FIELDOFFSET(TS_CLIP_PDU, data) > CBM.rxSize) {
  633. TRC_ERR((TB,_T("TS_CLIP_PDU.dataLen field too large")));
  634. freeTheBuffer = TRUE;
  635. DC_QUIT;
  636. }
  637. switch (pClipPDU->msgType)
  638. {
  639. case TS_CB_FORMAT_LIST_RESPONSE:
  640. {
  641. TRC_NRM((TB, _T("TS_CB_FORMAT_LIST_RESPONSE received")));
  642. CBMOnFormatListResponse(pClipPDU);
  643. LocalFree(pClipPDU);
  644. }
  645. break;
  646. case TS_CB_FORMAT_DATA_REQUEST:
  647. {
  648. TRC_NRM((TB, _T("TS_CB_FORMAT_DATA_REQUEST received")));
  649. CBMOnFormatDataRequest(pClipPDU);
  650. LocalFree(pClipPDU);
  651. }
  652. break;
  653. case TS_CB_FORMAT_DATA_RESPONSE:
  654. {
  655. TRC_NRM((TB, _T("TS_CB_FORMAT_DATA_RESPONSE received")));
  656. CBMOnFormatDataResponse(pClipPDU);
  657. LocalFree(pClipPDU);
  658. }
  659. break;
  660. case TS_CB_TEMP_DIRECTORY:
  661. {
  662. TRC_NRM((TB, _T("TS_CB_TEMP_DIRECTORY received")));
  663. CBM.fFileCutCopyOn = CBMOnReceivedTempDirectory(pClipPDU);
  664. LocalFree(pClipPDU);
  665. }
  666. break;
  667. default:
  668. {
  669. // Free the Clipboard thread, if locked
  670. if (TS_CB_FORMAT_LIST == pClipPDU->msgType)
  671. {
  672. SetEvent(CBM.GetDataSync[TS_RESET_EVENT]) ;
  673. TRC_NRM((TB,_T("Reset state; free clipboard if locked"))) ;
  674. }
  675. TRC_NRM((TB, _T("Pass %d bytes to main thread"), CBM.rxSize));
  676. PostMessage(CBM.viewerWindow,
  677. CBM.regMsg,
  678. CBM.rxSize,
  679. (LPARAM)CBM.rxpBuffer);
  680. }
  681. break;
  682. }
  683. }
  684. DC_EXIT_POINT:
  685. /************************************************************************/
  686. /* Free the buffer if necessary */
  687. /************************************************************************/
  688. if (freeTheBuffer && CBM.rxpBuffer)
  689. {
  690. TRC_DBG((TB, _T("Free rx buffer")));
  691. LocalFree(CBM.rxpBuffer);
  692. CBM.rxpBuffer = NULL;
  693. }
  694. DC_END_FN();
  695. return;
  696. } /* CBMOnDataReceived */
  697. /****************************************************************************/
  698. /* the second thread procedure */
  699. /****************************************************************************/
  700. DWORD WINAPI CBMDataThreadProc( LPVOID pParam )
  701. {
  702. DWORD waitRc = 0;
  703. BOOL fSuccess;
  704. DWORD dwResult;
  705. DCUINT8 readBuffer[CHANNEL_PDU_LENGTH];
  706. DWORD cbBytes = 0;
  707. DCBOOL dataRead;
  708. DCBOOL tryToDoRead;
  709. DC_BEGIN_FN("CBMDataThreadProc");
  710. DC_IGNORE_PARAMETER(pParam);
  711. /************************************************************************/
  712. /* loop until we're told to stop */
  713. /************************************************************************/
  714. while (CBM.runThread)
  715. {
  716. dataRead = FALSE;
  717. tryToDoRead = (CBM.vcHandle != NULL) ? TRUE : FALSE;
  718. if (tryToDoRead)
  719. {
  720. /****************************************************************/
  721. /* Issue a read */
  722. /****************************************************************/
  723. cbBytes = sizeof(readBuffer);
  724. TRC_DBG((TB, _T("Issue the read")));
  725. fSuccess = ReadFile(CBM.vcHandle,
  726. readBuffer,
  727. sizeof(readBuffer),
  728. &cbBytes,
  729. &CBM.readOL);
  730. if (fSuccess)
  731. {
  732. TRC_NRM((TB, _T("Data read instantly")));
  733. dataRead = TRUE;
  734. }
  735. else
  736. {
  737. dwResult = GetLastError();
  738. TRC_DBG((TB, _T("Read failed, %d"), dwResult));
  739. if (dwResult != ERROR_IO_PENDING)
  740. {
  741. /********************************************************/
  742. /* The read failed. Treat this like a disconnection - */
  743. /* stick around and wait to be reconnected. */
  744. /********************************************************/
  745. TRC_ERR((TB, _T("Read failed, %d"), dwResult));
  746. tryToDoRead = FALSE;
  747. }
  748. }
  749. }
  750. /********************************************************************/
  751. /* If we haven't read any data, wait for something to happen now */
  752. /********************************************************************/
  753. if (!dataRead)
  754. {
  755. waitRc = WaitForMultipleObjects(CLIP_EVENT_COUNT,
  756. CBM.hEvent,
  757. FALSE,
  758. INFINITE);
  759. switch (waitRc)
  760. {
  761. /************************************************************/
  762. /* Handle Disconnect and Reconnect synchronously, so that */
  763. /* all state changes are complete on return. */
  764. /************************************************************/
  765. case WAIT_OBJECT_0 + CLIP_EVENT_DISCONNECT:
  766. {
  767. TRC_NRM((TB, _T("Session disconnected")));
  768. // Make sure that if the other rdpclip thread is waiting
  769. // for a response in GetData() it is notified of the
  770. // disconnection.
  771. if (CBM.GetDataSync[TS_DISCONNECT_EVENT]) {
  772. SetEvent(CBM.GetDataSync[TS_DISCONNECT_EVENT]);
  773. }
  774. ResetEvent(CBM.hEvent[CLIP_EVENT_DISCONNECT]);
  775. SendMessage(CBM.viewerWindow,
  776. CBM.regMsg,
  777. 0,
  778. CLIP_EVENT_DISCONNECT);
  779. tryToDoRead = FALSE;
  780. }
  781. break;
  782. case WAIT_OBJECT_0 + CLIP_EVENT_RECONNECT:
  783. {
  784. TRC_NRM((TB, _T("Session reconnected")));
  785. ResetEvent(CBM.hEvent[CLIP_EVENT_RECONNECT]);
  786. SendMessage(CBM.viewerWindow,
  787. CBM.regMsg,
  788. 0,
  789. CLIP_EVENT_RECONNECT);
  790. tryToDoRead = TRUE;
  791. }
  792. break;
  793. /************************************************************/
  794. /* Data received */
  795. /************************************************************/
  796. case WAIT_OBJECT_0 + CLIP_EVENT_READ:
  797. {
  798. TRC_DBG((TB, _T("Read complete")));
  799. fSuccess = GetOverlappedResult(CBM.vcHandle,
  800. &CBM.readOL,
  801. &cbBytes,
  802. FALSE);
  803. if (fSuccess)
  804. {
  805. dataRead = TRUE;
  806. }
  807. else
  808. {
  809. dwResult = GetLastError();
  810. TRC_ERR((TB, _T("GetOverlappedResult failed %d"),
  811. dwResult));
  812. tryToDoRead = FALSE;
  813. }
  814. /********************************************************/
  815. /* Reset the event, otherwise we can come straight back */
  816. /* in here if we don't retry the read. */
  817. /********************************************************/
  818. ResetEvent(CBM.hEvent[CLIP_EVENT_READ]);
  819. }
  820. break;
  821. /************************************************************/
  822. /* Error occurred - treat as disconnect */
  823. /************************************************************/
  824. case WAIT_FAILED:
  825. default:
  826. {
  827. dwResult = GetLastError();
  828. TRC_ERR((TB, _T("Wait failed, result %d"), dwResult));
  829. tryToDoRead = FALSE;
  830. }
  831. break;
  832. }
  833. }
  834. /********************************************************************/
  835. /* Once we get here, the read is complete - see what we got */
  836. /********************************************************************/
  837. if (dataRead && CBM.runThread)
  838. {
  839. TRC_NRM((TB, _T("%d bytes of data received"), cbBytes));
  840. TRC_DATA_DBG("Data received", readBuffer, cbBytes);
  841. CBMOnDataReceived(readBuffer, cbBytes);
  842. }
  843. } /* while */
  844. TRC_NRM((TB, _T("Thread ending")));
  845. DC_EXIT_POINT:
  846. DC_END_FN();
  847. ExitThread(waitRc);
  848. return(waitRc);
  849. }
  850. /****************************************************************************/
  851. /* CBMOnReceivedTempDirectory */
  852. /* Caller must have validated that the PDU contained enough data for the */
  853. /* length specified in pClipPDU->dataLen */
  854. /****************************************************************************/
  855. DCBOOL DCINTERNAL CBMOnReceivedTempDirectory(PTS_CLIP_PDU pClipPDU)
  856. {
  857. DCBOOL fSuccess = FALSE ;
  858. WCHAR tempDirW[MAX_PATH] ;
  859. UINT pathLength = pClipPDU->dataLen / sizeof(WCHAR) ;
  860. HRESULT hr;
  861. wchar_t *pDummy;
  862. size_t cbDummy;
  863. DC_BEGIN_FN("CBMOnReceivedTempDirectory");
  864. if (pathLength > MAX_PATH)
  865. {
  866. TRC_ERR((TB, _T("Path too big for us. Failing"))) ;
  867. fSuccess = FALSE ;
  868. DC_QUIT ;
  869. }
  870. if (sizeof(WCHAR) > pClipPDU->dataLen) {
  871. TRC_ERR((TB,_T("Not enough data to read anything from buffer")));
  872. fSuccess = FALSE;
  873. DC_QUIT;
  874. }
  875. // The incoming data is not necessarily NULL terminated
  876. hr = StringCbCopyNExW(tempDirW, sizeof(tempDirW), (WCHAR*) pClipPDU->data,
  877. pClipPDU->dataLen, &pDummy, &cbDummy, 0 );
  878. if (FAILED(hr)) {
  879. fSuccess = FALSE;
  880. DC_QUIT;
  881. }
  882. // Check that the string is NULL terminated
  883. hr = StringCbLengthW(tempDirW, sizeof(tempDirW), &cbDummy);
  884. if (FAILED(hr)) {
  885. fSuccess = FALSE;
  886. DC_QUIT;
  887. }
  888. hr = CBMConvertToServerPath(tempDirW, CBM.baseTempDirW,
  889. sizeof(CBM.baseTempDirW), 1) ;
  890. if (FAILED(hr)) {
  891. TRC_ERR((TB,_T("CBMConvertToServerPath failed hr=0x%x"), hr ));
  892. fSuccess = FALSE;
  893. DC_QUIT;
  894. }
  895. fSuccess = TRUE ;
  896. DC_EXIT_POINT:
  897. DC_END_FN() ;
  898. return fSuccess ;
  899. }
  900. /****************************************************************************/
  901. /* CBMOnFormatListResponse */
  902. /* Caller must have validated that the PDU contained enough data for the */
  903. /* length specified in pClipPDU->dataLen */
  904. /****************************************************************************/
  905. DCVOID DCINTERNAL CBMOnFormatListResponse(PTS_CLIP_PDU pClipPDU)
  906. {
  907. DC_BEGIN_FN("CBMOnFormatListResponse");
  908. /************************************************************************/
  909. /* The client has received our format list */
  910. /************************************************************************/
  911. TRC_NRM((TB, _T("Received FORMAT_LIST_REPSONSE")));
  912. CBM_CHECK_STATE(CBM_EVENT_FORMAT_LIST_RSP);
  913. /************************************************************************/
  914. /* This may arrive just after we've sent the client a format list - */
  915. /* since the client always wins, we must accept the list */
  916. /************************************************************************/
  917. if (CBM.state != CBM_STATE_PENDING_FORMAT_LIST_RSP)
  918. {
  919. TRC_ALT((TB, _T("Got unexpected list response")));
  920. CBM.formatResponseCount = 0;
  921. }
  922. else
  923. {
  924. /********************************************************************/
  925. /* update our state according to the result */
  926. /********************************************************************/
  927. CBM.formatResponseCount--;
  928. TRC_NRM((TB, _T("Waiting for %d format response(s)"),
  929. CBM.formatResponseCount));
  930. if (CBM.formatResponseCount <= 0)
  931. {
  932. if (pClipPDU->msgFlags == TS_CB_RESPONSE_OK)
  933. {
  934. TRC_DBG((TB, _T("Fmt list response OK")));
  935. CBM_SET_STATE(CBM_STATE_SHARED_CB_OWNER, CBM_EVENT_FORMAT_LIST_RSP);
  936. }
  937. else
  938. {
  939. TRC_ALT((TB, _T("Fmt list rsp failed")));
  940. CBM_SET_STATE(CBM_STATE_CONNECTED, CBM_EVENT_FORMAT_LIST_RSP);
  941. }
  942. CBM.formatResponseCount = 0;
  943. }
  944. /********************************************************************/
  945. /* close the local CB - if it's open - and tell the next viewer */
  946. /* about the updated list */
  947. /********************************************************************/
  948. if (CBM.open)
  949. {
  950. TRC_NRM((TB, _T("Close clipboard - didn't expect that")));
  951. if (!CloseClipboard())
  952. {
  953. TRC_SYSTEM_ERROR("CloseClipboard");
  954. }
  955. CBM.open = FALSE;
  956. }
  957. if (CBM.nextViewer != NULL)
  958. {
  959. PostMessage(CBM.nextViewer, WM_DRAWCLIPBOARD,0,0);
  960. }
  961. }
  962. DC_EXIT_POINT:
  963. DC_END_FN();
  964. return;
  965. } /* CBMOnFormatListResponse */
  966. //
  967. // CBMOnFormatDataRequest
  968. // - Sends client format data it requested
  969. /* Caller must have validated that the PDU contained enough data for the */
  970. /* length specified in pClipPDU->dataLen */
  971. //
  972. DCVOID DCINTERNAL CBMOnFormatDataRequest(PTS_CLIP_PDU pClipPDU)
  973. {
  974. DCUINT16 response = TS_CB_RESPONSE_OK;
  975. HANDLE hData = NULL;
  976. PDCVOID pData;
  977. PDCVOID pNewData;
  978. HANDLE hNewData = NULL;
  979. HANDLE hDropData = NULL;
  980. HANDLE hTempData = NULL;
  981. DCINT32 numEntries;
  982. DCUINT32 dataLen = 0;
  983. DCUINT32 pduLen;
  984. DCUINT formatID;
  985. LOGPALETTE * pLogPalette = NULL;
  986. PTS_CLIP_PDU pClipRsp;
  987. TS_CLIP_PDU clipRsp;
  988. DCBOOL fSuccess = TRUE ;
  989. BOOL fWide ;
  990. byte charSize ;
  991. DROPFILES* pDropFiles ;
  992. BOOL fDrivePath ;
  993. ULONG newSize, oldSize ;
  994. HPDCVOID pFileList ;
  995. HPDCVOID pFilename ;
  996. HPDCVOID pOldFilename ;
  997. SHFILEOPSTRUCTA fileOpStructA ;
  998. SHFILEOPSTRUCTW fileOpStructW ;
  999. wchar_t tempDirW[MAX_PATH] ;
  1000. char tempDir[MAX_PATH] ;
  1001. DCTCHAR formatName[TS_FORMAT_NAME_LEN] ;
  1002. DC_BEGIN_FN("CBMOnFormatDataRequest");
  1003. // The client wants a format from us
  1004. TRC_NRM((TB, _T("Received FORMAT_DATA_REQUEST")));
  1005. // This may arrive just after we've sent the client a format list -
  1006. // since the client has not confirmed our list, this request is out-of-
  1007. // date. Fail it.
  1008. if (CBMCheckState(CBM_EVENT_FORMAT_DATA_RQ) != CBM_TABLE_OK)
  1009. {
  1010. TRC_ALT((TB, _T("Unexpected format data rq")));
  1011. // close the local CB - if it's open - and tell the next viewer
  1012. // about the updated list
  1013. if (CBM.open)
  1014. {
  1015. TRC_NRM((TB, _T("Close clipboard")));
  1016. if (!CloseClipboard())
  1017. {
  1018. TRC_SYSTEM_ERROR("CloseClipboard");
  1019. }
  1020. CBM.open = FALSE;
  1021. }
  1022. if (CBM.nextViewer != NULL)
  1023. {
  1024. PostMessage(CBM.nextViewer, WM_DRAWCLIPBOARD,0,0);
  1025. }
  1026. //
  1027. // Fail the data request
  1028. //
  1029. response = TS_CB_RESPONSE_FAIL;
  1030. goto CB_SEND_RESPONSE;
  1031. }
  1032. if (sizeof(DCUINT) > pClipPDU->dataLen) {
  1033. TRC_ERR((TB,_T("Not enough data to read format [need=%u got=%u]"),
  1034. sizeof(DCUINT), pClipPDU->dataLen ));
  1035. response = TS_CB_RESPONSE_FAIL;
  1036. goto CB_SEND_RESPONSE;
  1037. }
  1038. formatID = *((PDCUINT)(pClipPDU->data));
  1039. TRC_NRM((TB, _T("format ID %d"), formatID));
  1040. /************************************************************************/
  1041. /* Open the local clipboard */
  1042. /************************************************************************/
  1043. if (!CBM.open)
  1044. {
  1045. if (!OpenClipboard(CBM.viewerWindow))
  1046. {
  1047. TRC_SYSTEM_ERROR("OpenCB");
  1048. response = TS_CB_RESPONSE_FAIL;
  1049. goto CB_SEND_RESPONSE;
  1050. }
  1051. }
  1052. /************************************************************************/
  1053. /* It was/is open */
  1054. /************************************************************************/
  1055. TRC_NRM((TB, _T("CB opened")));
  1056. CBM.open = TRUE;
  1057. /************************************************************************/
  1058. /* Get a handle to the data */
  1059. /************************************************************************/
  1060. hData = GetClipboardData(formatID);
  1061. if (hData == NULL)
  1062. {
  1063. /********************************************************************/
  1064. /* Oops! */
  1065. /********************************************************************/
  1066. TRC_ERR((TB, _T("Failed to get format %d"),formatID));
  1067. response = TS_CB_RESPONSE_FAIL;
  1068. dataLen = 0;
  1069. goto CB_SEND_RESPONSE;
  1070. }
  1071. /************************************************************************/
  1072. /* Got handle, now what happens next depends on the flavour of data */
  1073. /* we're looking at... */
  1074. /************************************************************************/
  1075. if (formatID == CF_PALETTE)
  1076. {
  1077. DCUINT16 entries;
  1078. TRC_DBG((TB, _T("CF_PALETTE requested")));
  1079. /********************************************************************/
  1080. /* Find out how many entries there are in the palette and allocate */
  1081. /* enough memory to hold them all. */
  1082. /********************************************************************/
  1083. if (GetObject(hData, sizeof(DCUINT16), &entries) == 0)
  1084. {
  1085. TRC_DBG((TB, _T("Failed count of palette entries")));
  1086. entries = 256;
  1087. }
  1088. numEntries = entries;
  1089. TRC_DBG((TB, _T("Need mem for %d palette entries"), numEntries));
  1090. dataLen = sizeof(LOGPALETTE) +
  1091. ((numEntries - 1) * sizeof(PALETTEENTRY));
  1092. hNewData = GlobalAlloc(GHND, dataLen);
  1093. if (hNewData == 0)
  1094. {
  1095. TRC_ERR((TB, _T("Failed to get %d bytes for palette"), dataLen));
  1096. response = TS_CB_RESPONSE_FAIL;
  1097. dataLen = 0;
  1098. }
  1099. else
  1100. {
  1101. hDropData = hNewData;
  1102. /****************************************************************/
  1103. /* now get the palette entries into the new buffer */
  1104. /****************************************************************/
  1105. pData = GlobalLock(hNewData);
  1106. numEntries = GetPaletteEntries((HPALETTE)hData,
  1107. 0,
  1108. numEntries,
  1109. (PALETTEENTRY*)pData);
  1110. GlobalUnlock(hNewData);
  1111. TRC_DBG((TB, _T("Got %d pal entries"), numEntries));
  1112. if (numEntries == 0)
  1113. {
  1114. TRC_ERR((TB, _T("Failed to get any pal entries")));
  1115. response = TS_CB_RESPONSE_FAIL;
  1116. dataLen = 0;
  1117. }
  1118. dataLen = numEntries * sizeof(PALETTEENTRY);
  1119. /****************************************************************/
  1120. /* all ok - set up hData to point to the new data */
  1121. /****************************************************************/
  1122. //GlobalFree(hData);
  1123. hData = hNewData;
  1124. }
  1125. }
  1126. else if (formatID == CF_METAFILEPICT)
  1127. {
  1128. TRC_NRM((TB, _T("Metafile data to get")));
  1129. /********************************************************************/
  1130. /* Metafiles are copied as Handles - we need to send across the */
  1131. /* actual bits */
  1132. /********************************************************************/
  1133. hNewData = CBMGetMFData(hData, &dataLen);
  1134. if (!hNewData)
  1135. {
  1136. TRC_ERR((TB, _T("Failed to set MF data")));
  1137. response = TS_CB_RESPONSE_FAIL;
  1138. dataLen = 0;
  1139. }
  1140. else
  1141. {
  1142. hDropData = hNewData;
  1143. /****************************************************************/
  1144. /* all ok - set up hData to point to the new data */
  1145. /****************************************************************/
  1146. hData = hNewData;
  1147. }
  1148. }
  1149. else if (formatID == CF_HDROP)
  1150. {
  1151. TRC_NRM((TB,_T("HDROP requested"))) ;
  1152. pDropFiles = (DROPFILES*) GlobalLock(hData) ;
  1153. fWide = pDropFiles->fWide ;
  1154. charSize = fWide ? sizeof(wchar_t) : sizeof(char) ;
  1155. if (!CBM.fAlreadyCopied)
  1156. {
  1157. // if its not a drive path, then copy to a temp directory
  1158. pFileList = (byte*) pDropFiles + pDropFiles->pFiles ;
  1159. // CBMCopyToTempDirectory returns 0 if successful
  1160. if (0 != CBMCopyToTempDirectory(pFileList, fWide))
  1161. {
  1162. TRC_ERR((TB,_T("Copy to tmp directory failed"))) ;
  1163. response = TS_CB_RESPONSE_FAIL;
  1164. dataLen = 0;
  1165. CBM.fAlreadyCopied = TRUE ;
  1166. goto CB_SEND_RESPONSE;
  1167. }
  1168. CBM.fAlreadyCopied = TRUE ;
  1169. }
  1170. // Now that we copied the files, we want to convert the file
  1171. // paths to something the client will understand
  1172. // Allocate space for new filepaths
  1173. oldSize = (ULONG) GlobalSize(hData) ;
  1174. newSize = CBMGetNewDropfilesSizeForClient(pDropFiles, oldSize, fWide) ;
  1175. hNewData = GlobalAlloc(GMEM_DISCARDABLE | GMEM_MOVEABLE, newSize) ;
  1176. if (hNewData == NULL)
  1177. {
  1178. TRC_ERR((TB, _T("Failed to get %ld bytes for HDROP"),
  1179. newSize));
  1180. response = TS_CB_RESPONSE_FAIL;
  1181. dataLen = 0;
  1182. goto CB_SEND_RESPONSE;
  1183. }
  1184. hDropData = hNewData;
  1185. pNewData = GlobalLock(hNewData) ;
  1186. if (pNewData == NULL)
  1187. {
  1188. TRC_ERR((TB, _T("Failed to get lock %p for HDROP"),
  1189. hNewData));
  1190. response = TS_CB_RESPONSE_FAIL;
  1191. dataLen = 0;
  1192. goto CB_SEND_RESPONSE;
  1193. }
  1194. // Just copy the old DROPFILES data members (unchanged)
  1195. ((DROPFILES*) pNewData)->pFiles = pDropFiles->pFiles ;
  1196. ((DROPFILES*) pNewData)->pt = pDropFiles->pt ;
  1197. ((DROPFILES*) pNewData)->fNC = pDropFiles->fNC ;
  1198. ((DROPFILES*) pNewData)->fWide = pDropFiles->fWide ;
  1199. // The first filename in a DROPFILES data structure begins
  1200. // DROPFILES.pFiles bytes away from the head of the DROPFILES
  1201. pOldFilename = (byte*) pDropFiles + pDropFiles->pFiles ;
  1202. pFilename = (byte*) pNewData + ((DROPFILES*) pNewData)->pFiles ;
  1203. while (fWide ? (L'\0' != ((wchar_t*) pOldFilename)[0]) : ('\0' != ((char*) pOldFilename)[0]))
  1204. {
  1205. if ((ULONG)((BYTE*)pFilename-(BYTE*)pNewData) > newSize) {
  1206. TRC_ERR((TB,_T("Failed filename conversion, not enough data")));
  1207. }
  1208. else {
  1209. if (!SUCCEEDED(CBMConvertToClientPath(pOldFilename, pFilename,
  1210. newSize - ((BYTE*)pFilename-(BYTE*)pNewData), fWide)))
  1211. {
  1212. TRC_ERR((TB, _T("Failed conversion"))) ;
  1213. }
  1214. else
  1215. {
  1216. if (fWide)
  1217. {
  1218. TRC_NRM((TB,_T("oldname %ls; newname %ls"), (wchar_t*)pOldFilename, (wchar_t*)pFilename)) ;
  1219. }
  1220. else
  1221. {
  1222. TRC_NRM((TB,_T("oldname %hs; newname %hs"), (char*)pOldFilename, (char*)pFilename)) ;
  1223. }
  1224. }
  1225. }
  1226. if (fWide)
  1227. {
  1228. pOldFilename = (byte*) pOldFilename + (wcslen((wchar_t*)pOldFilename) + 1) * sizeof(wchar_t) ;
  1229. pFilename = (byte*) pFilename + (wcslen((wchar_t*)pFilename) + 1) * sizeof(wchar_t) ;
  1230. }
  1231. else
  1232. {
  1233. pOldFilename = (byte*) pOldFilename + (strlen((char*)pOldFilename) + 1) * sizeof(char) ;
  1234. pFilename = (byte*) pFilename + (strlen((char*)pFilename) + 1) * sizeof(char) ;
  1235. }
  1236. }
  1237. if (fWide)
  1238. ((wchar_t*)pFilename)[0] = L'\0' ;
  1239. else
  1240. ((char*)pFilename)[0] = '\0' ;
  1241. GlobalUnlock(hNewData) ;
  1242. hData = hNewData ;
  1243. dataLen = (DWORD) GlobalSize(hData) ;
  1244. }
  1245. else
  1246. {
  1247. // Check to see if we are processing the FileName/FileNameW
  1248. // OLE 1 formats; if so, we convert the filenames
  1249. if (0 != GetClipboardFormatName(formatID, formatName, TS_FORMAT_NAME_LEN))
  1250. {
  1251. if ((0 == _tcscmp(formatName, TEXT("FileName"))) ||
  1252. (0 == _tcscmp(formatName, TEXT("FileNameW"))))
  1253. {
  1254. if (0 == _tcscmp(formatName, TEXT("FileNameW")))
  1255. {
  1256. fWide = TRUE ;
  1257. charSize = sizeof(WCHAR) ;
  1258. }
  1259. else
  1260. {
  1261. fWide = FALSE ;
  1262. charSize = 1 ;
  1263. }
  1264. pOldFilename = GlobalLock(hData) ;
  1265. if (!pOldFilename)
  1266. {
  1267. TRC_ERR((TB, _T("No filename/Unable to lock %p"),
  1268. hData));
  1269. response = TS_CB_RESPONSE_FAIL;
  1270. dataLen = 0;
  1271. goto CB_SEND_RESPONSE;
  1272. }
  1273. oldSize = (ULONG)GlobalSize(hData) ;
  1274. if (!CBM.fAlreadyCopied)
  1275. {
  1276. // if its not a drive path, then copy to a temp
  1277. // directory. We have to copy over the filename to
  1278. // string that is one character larger, because we
  1279. // need to add an extra NULL for the SHFileOperation
  1280. pFileList = (char*) LocalAlloc(LPTR, oldSize + charSize) ;
  1281. if (fWide)
  1282. {
  1283. wcscpy((WCHAR*)pFileList, (WCHAR*)pOldFilename) ;
  1284. fDrivePath = (0 != wcschr((WCHAR*) pFileList, L':')) ;
  1285. }
  1286. else
  1287. {
  1288. strcpy((char*)pFileList, (char*)pOldFilename) ;
  1289. fDrivePath = (0 != strchr((char*) pFileList, ':')) ;
  1290. }
  1291. // CBMCopyToTempDirectory returns 0 if successful
  1292. if (0 != CBMCopyToTempDirectory(pFileList, fWide))
  1293. {
  1294. TRC_ERR((TB,_T("Copy to tmp directory failed"))) ;
  1295. response = TS_CB_RESPONSE_FAIL;
  1296. dataLen = 0;
  1297. CBM.fAlreadyCopied = TRUE ;
  1298. goto CB_SEND_RESPONSE;
  1299. }
  1300. CBM.fAlreadyCopied = TRUE ;
  1301. }
  1302. newSize = CBMGetNewFilePathLengthForClient(pOldFilename, fWide) ;
  1303. hNewData = GlobalAlloc(GMEM_DISCARDABLE | GMEM_MOVEABLE, newSize) ;
  1304. if (!hNewData)
  1305. {
  1306. TRC_ERR((TB, _T("Failed to get %ld bytes for FileName(W)"),
  1307. newSize));
  1308. response = TS_CB_RESPONSE_FAIL;
  1309. dataLen = 0;
  1310. goto CB_SEND_RESPONSE;
  1311. }
  1312. hDropData = hNewData;
  1313. pFilename= GlobalLock(hNewData) ;
  1314. if (!pFilename)
  1315. {
  1316. TRC_ERR((TB, _T("Failed to get lock %p for FileName(W)"),
  1317. hNewData));
  1318. response = TS_CB_RESPONSE_FAIL;
  1319. dataLen = 0;
  1320. goto CB_SEND_RESPONSE;
  1321. }
  1322. if (FAILED(CBMConvertToClientPath(pOldFilename, pFilename,
  1323. newSize, fWide)))
  1324. {
  1325. response = TS_CB_RESPONSE_FAIL;
  1326. dataLen = 0;
  1327. goto CB_SEND_RESPONSE;
  1328. }
  1329. GlobalUnlock(hNewData) ;
  1330. response = TS_CB_RESPONSE_OK;
  1331. hData = hNewData ;
  1332. dataLen = newSize ;
  1333. goto CB_SEND_RESPONSE ;
  1334. }
  1335. }
  1336. /********************************************************************/
  1337. /* just get the length of the block */
  1338. /********************************************************************/
  1339. dataLen = (DCUINT32)GlobalSize(hData);
  1340. TRC_DBG((TB, _T("Got data len %d"), dataLen));
  1341. }
  1342. CB_SEND_RESPONSE:
  1343. /************************************************************************/
  1344. /* Get some memory for a message to send to the Client if necessary */
  1345. /************************************************************************/
  1346. if (hData && (dataLen != 0))
  1347. {
  1348. pduLen = dataLen + sizeof(TS_CLIP_PDU);
  1349. pClipRsp = (PTS_CLIP_PDU) LocalAlloc(LMEM_FIXED, pduLen);
  1350. if (pClipRsp == NULL)
  1351. {
  1352. TRC_ERR((TB, _T("Failed to alloc %d bytes"), pduLen));
  1353. response = TS_CB_RESPONSE_FAIL;
  1354. dataLen = 0;
  1355. pClipRsp = &clipRsp;
  1356. pduLen = sizeof(clipRsp);
  1357. }
  1358. }
  1359. else
  1360. {
  1361. TRC_DBG((TB, _T("No data to send")));
  1362. pClipRsp = &clipRsp;
  1363. pduLen = sizeof(clipRsp);
  1364. }
  1365. /************************************************************************/
  1366. /* Build the PDU */
  1367. /************************************************************************/
  1368. pClipRsp->msgType = TS_CB_FORMAT_DATA_RESPONSE;
  1369. pClipRsp->msgFlags = response;
  1370. pClipRsp->dataLen = dataLen;
  1371. /************************************************************************/
  1372. /* copy the data if necessary */
  1373. /************************************************************************/
  1374. if (dataLen != 0)
  1375. {
  1376. TRC_DBG((TB, _T("Copy %d bytes of data"), dataLen));
  1377. pData = GlobalLock(hData);
  1378. DC_MEMCPY(pClipRsp->data, pData, dataLen);
  1379. GlobalUnlock(hData);
  1380. }
  1381. /************************************************************************/
  1382. /* Close the CB if open */
  1383. /************************************************************************/
  1384. TRC_DBG((TB, _T("Closing CB")));
  1385. if (!CloseClipboard())
  1386. {
  1387. TRC_SYSTEM_ERROR("CloseClipboard");
  1388. }
  1389. CBM.open = FALSE;
  1390. /************************************************************************/
  1391. /* Send the data to the Client */
  1392. /************************************************************************/
  1393. CBMSendToClient(pClipRsp, pduLen);
  1394. /************************************************************************/
  1395. /* Free the PDU, if any */
  1396. /************************************************************************/
  1397. if (pClipRsp != &clipRsp)
  1398. {
  1399. TRC_DBG((TB, _T("Free the clip PDU")));
  1400. LocalFree(pClipRsp);
  1401. }
  1402. DC_EXIT_POINT:
  1403. if ( NULL != hDropData )
  1404. {
  1405. GlobalFree( hDropData );
  1406. }
  1407. DC_END_FN();
  1408. return;
  1409. } /* CBMOnFormatDataRequest */
  1410. //
  1411. // CBMOnFormatDataRespons
  1412. // - Client response to our request for data
  1413. /* Caller must have validated that the PDU contained enough data for the */
  1414. /* length specified in pClipPDU->dataLen */
  1415. //
  1416. DCVOID DCINTERNAL CBMOnFormatDataResponse(PTS_CLIP_PDU pClipPDU)
  1417. {
  1418. HANDLE hData = NULL;
  1419. HPDCVOID pData;
  1420. LOGPALETTE * pLogPalette = NULL;
  1421. DCUINT32 numEntries;
  1422. DCUINT32 memLen;
  1423. HRESULT hr ;
  1424. DC_BEGIN_FN("CBMOnFormatDataResponse");
  1425. /************************************************************************/
  1426. /* check the response */
  1427. /************************************************************************/
  1428. if (!(pClipPDU->msgFlags & TS_CB_RESPONSE_OK))
  1429. {
  1430. TRC_ALT((TB, _T("Got fmt data rsp failed for %d"), CBM.pendingClientID));
  1431. DC_QUIT;
  1432. }
  1433. /************************************************************************/
  1434. /* Got the data */
  1435. /************************************************************************/
  1436. TRC_NRM((TB, _T("Got OK fmt data rsp for %d"), CBM.pendingClientID));
  1437. /************************************************************************/
  1438. /* For some formats we still need to do some work */
  1439. /************************************************************************/
  1440. if (CBM.pendingClientID == CF_METAFILEPICT)
  1441. {
  1442. /********************************************************************/
  1443. /* Metafile format - create a metafile from the data */
  1444. /********************************************************************/
  1445. TRC_NRM((TB, _T("Rx data is for metafile")));
  1446. hData = CBMSetMFData(pClipPDU->dataLen, pClipPDU->data);
  1447. if (hData == NULL)
  1448. {
  1449. TRC_ERR((TB, _T("Failed to set MF data")));
  1450. }
  1451. }
  1452. else if (CBM.pendingClientID == CF_PALETTE)
  1453. {
  1454. /********************************************************************/
  1455. /* Palette format - create a palette from the data */
  1456. /********************************************************************/
  1457. /********************************************************************/
  1458. /* Allocate memory for a LOGPALETTE structure large enough to hold */
  1459. /* all the PALETTE ENTRY structures, and fill it in. */
  1460. /********************************************************************/
  1461. TRC_NRM((TB, _T("Rx data is for palette")));
  1462. numEntries = (pClipPDU->dataLen / sizeof(PALETTEENTRY));
  1463. memLen = (sizeof(LOGPALETTE) +
  1464. ((numEntries - 1) * sizeof(PALETTEENTRY)));
  1465. TRC_DBG((TB, _T("%ld palette entries, allocate %ld bytes"),
  1466. numEntries, memLen));
  1467. pLogPalette = (LOGPALETTE*) GlobalAlloc(GPTR, memLen);
  1468. if (pLogPalette != NULL)
  1469. {
  1470. pLogPalette->palVersion = 0x300;
  1471. pLogPalette->palNumEntries = (WORD)numEntries;
  1472. DC_MEMCPY(pLogPalette->palPalEntry,
  1473. pClipPDU->data,
  1474. pClipPDU->dataLen);
  1475. /****************************************************************/
  1476. /* now create a palette */
  1477. /****************************************************************/
  1478. hData = CreatePalette(pLogPalette);
  1479. if (hData == NULL)
  1480. {
  1481. TRC_SYSTEM_ERROR("CreatePalette");
  1482. }
  1483. }
  1484. else
  1485. {
  1486. TRC_ERR((TB, _T("Failed to get %ld bytes"), memLen));
  1487. }
  1488. }
  1489. else
  1490. {
  1491. TRC_NRM((TB, _T("Rx data can just go on CB")));
  1492. /********************************************************************/
  1493. /* We need to copy the data, as the receive buffer will be freed on */
  1494. /* return from this function. */
  1495. /********************************************************************/
  1496. hData = GlobalAlloc(GMEM_DISCARDABLE | GMEM_MOVEABLE,
  1497. pClipPDU->dataLen);
  1498. if (hData != NULL)
  1499. {
  1500. pData = GlobalLock(hData);
  1501. if (pData != NULL)
  1502. {
  1503. TRC_NRM((TB, _T("Copy %ld bytes from %p to %p"),
  1504. pClipPDU->dataLen, pClipPDU->data, pData));
  1505. DC_MEMCPY(pData, pClipPDU->data, pClipPDU->dataLen);
  1506. GlobalUnlock(hData);
  1507. }
  1508. else
  1509. {
  1510. TRC_ERR((TB, _T("Failed to lock %p (%ld bytes)"),
  1511. hData, pClipPDU->dataLen));
  1512. GlobalFree(hData);
  1513. hData = NULL;
  1514. }
  1515. }
  1516. else
  1517. {
  1518. TRC_ERR((TB, _T("Failed to alloc %ld bytes"), pClipPDU->dataLen));
  1519. }
  1520. }
  1521. DC_EXIT_POINT:
  1522. /************************************************************************/
  1523. /* Set the state, and we're done. Note that this is done when we get a */
  1524. /* failure response too. */
  1525. /************************************************************************/
  1526. CBM_SET_STATE(CBM_STATE_LOCAL_CB_OWNER, CBM_EVENT_FORMAT_DATA_RSP);
  1527. CBM.pClipData->SetClipData(hData, CBM.pendingClientID ) ;
  1528. SetEvent(CBM.GetDataSync[TS_RECEIVE_COMPLETED]) ;
  1529. /************************************************************************/
  1530. /* tidy up */
  1531. /************************************************************************/
  1532. if (pLogPalette)
  1533. {
  1534. TRC_NRM((TB, _T("Free pLogPalette %p"), pLogPalette));
  1535. GlobalFree(pLogPalette);
  1536. }
  1537. DC_END_FN();
  1538. return;
  1539. } /* CBMOnFormatDataResponse */
  1540. /****************************************************************************/
  1541. /* CBMSendToClient */
  1542. /****************************************************************************/
  1543. DCBOOL DCINTERNAL CBMSendToClient(PTS_CLIP_PDU pClipRsp, DCUINT size)
  1544. {
  1545. BOOL fSuccess;
  1546. DWORD dwResult;
  1547. DWORD cbBytes;
  1548. DC_BEGIN_FN("CBMSendToClient");
  1549. cbBytes = size;
  1550. fSuccess = WriteFile(CBM.vcHandle,
  1551. pClipRsp,
  1552. size,
  1553. &cbBytes,
  1554. &CBM.writeOL);
  1555. if (!fSuccess)
  1556. {
  1557. dwResult = GetLastError();
  1558. if (ERROR_IO_PENDING == dwResult)
  1559. {
  1560. TRC_DBG((TB, _T("Asynchronous write")));
  1561. fSuccess = GetOverlappedResult(CBM.vcHandle,
  1562. &CBM.writeOL,
  1563. &cbBytes,
  1564. TRUE);
  1565. if (fSuccess)
  1566. {
  1567. TRC_DATA_DBG("Data sent", pClipRsp, size);
  1568. }
  1569. else
  1570. {
  1571. TRC_SYSTEM_ERROR("GetOverlappedResult failed");
  1572. }
  1573. }
  1574. else
  1575. {
  1576. TRC_ERR((TB, _T("Write failed, %#x"), dwResult));
  1577. }
  1578. }
  1579. else
  1580. {
  1581. TRC_DATA_DBG("Data sent immediately", pClipRsp, size);
  1582. }
  1583. DC_END_FN();
  1584. return(fSuccess);
  1585. } /* CBMSendToClient */
  1586. /****************************************************************************/
  1587. /* CBMGetMFData */
  1588. /****************************************************************************/
  1589. HANDLE DCINTERNAL CBMGetMFData(HANDLE hData, PDCUINT32 pDataLen)
  1590. {
  1591. DCUINT32 lenMFBits = 0;
  1592. DCBOOL rc = FALSE;
  1593. LPMETAFILEPICT pMFP = NULL;
  1594. HDC hMFDC = NULL;
  1595. HMETAFILE hMF = NULL;
  1596. HGLOBAL hMFBits = NULL;
  1597. HANDLE hNewData = NULL;
  1598. PDCUINT8 pNewData = NULL;
  1599. PDCVOID pBits = NULL;
  1600. DC_BEGIN_FN("CBMGetMFData");
  1601. TRC_NRM((TB, _T("Getting MF data")));
  1602. /************************************************************************/
  1603. /* Lock the memory to get a pointer to a METAFILEPICT header structure */
  1604. /* and create a METAFILEPICT DC. */
  1605. /************************************************************************/
  1606. pMFP = (LPMETAFILEPICT)GlobalLock(hData);
  1607. if (pMFP == NULL)
  1608. {
  1609. TRC_SYSTEM_ERROR("GlobalLock");
  1610. DC_QUIT;
  1611. }
  1612. hMFDC = CreateMetaFile(NULL);
  1613. if (hMFDC == NULL)
  1614. {
  1615. TRC_SYSTEM_ERROR("CreateMetaFile");
  1616. DC_QUIT;
  1617. }
  1618. /************************************************************************/
  1619. /* Copy the MFP by playing it into the DC and closing it. */
  1620. /************************************************************************/
  1621. if (!PlayMetaFile(hMFDC, pMFP->hMF))
  1622. {
  1623. TRC_SYSTEM_ERROR("PlayMetaFile");
  1624. CloseMetaFile(hMFDC);
  1625. DC_QUIT;
  1626. }
  1627. hMF = CloseMetaFile(hMFDC);
  1628. if (hMF == NULL)
  1629. {
  1630. TRC_SYSTEM_ERROR("CloseMetaFile");
  1631. DC_QUIT;
  1632. }
  1633. /************************************************************************/
  1634. /* Get the MF bits and determine how long they are. */
  1635. /************************************************************************/
  1636. lenMFBits = GetMetaFileBitsEx(hMF, 0, NULL);
  1637. if (lenMFBits == 0)
  1638. {
  1639. TRC_SYSTEM_ERROR("GetMetaFileBitsEx");
  1640. DC_QUIT;
  1641. }
  1642. TRC_DBG((TB, _T("length MF bits %ld"), lenMFBits));
  1643. /************************************************************************/
  1644. /* Work out how much memory we need and get a buffer */
  1645. /************************************************************************/
  1646. *pDataLen = sizeof(TS_CLIP_MFPICT) + lenMFBits;
  1647. hNewData = GlobalAlloc(GHND, *pDataLen);
  1648. if (hNewData == NULL)
  1649. {
  1650. TRC_ERR((TB, _T("Failed to get MF buffer")));
  1651. DC_QUIT;
  1652. }
  1653. pNewData = (PDCUINT8) GlobalLock(hNewData);
  1654. TRC_DBG((TB, _T("Got data to send len %ld"), *pDataLen));
  1655. /************************************************************************/
  1656. /* Copy the MF header and bits into the buffer. */
  1657. /************************************************************************/
  1658. ((PTS_CLIP_MFPICT)pNewData)->mm = pMFP->mm;
  1659. ((PTS_CLIP_MFPICT)pNewData)->xExt = pMFP->xExt;
  1660. ((PTS_CLIP_MFPICT)pNewData)->yExt = pMFP->yExt;
  1661. lenMFBits = GetMetaFileBitsEx(hMF, lenMFBits,
  1662. (pNewData + sizeof(TS_CLIP_MFPICT)));
  1663. if (lenMFBits == 0)
  1664. {
  1665. TRC_SYSTEM_ERROR("GetMetaFileBitsEx");
  1666. DC_QUIT;
  1667. }
  1668. /************************************************************************/
  1669. /* all OK */
  1670. /************************************************************************/
  1671. TRC_NRM((TB, _T("Got %d bits of MF data"), lenMFBits));
  1672. TRC_DATA_DBG("MF bits", (pNewData + sizeof(TS_CLIP_MFPICT)), lenMFBits);
  1673. rc = TRUE;
  1674. DC_EXIT_POINT:
  1675. /************************************************************************/
  1676. /* Unlock any global mem. */
  1677. /************************************************************************/
  1678. if (pMFP)
  1679. {
  1680. GlobalUnlock(hData);
  1681. }
  1682. if (pNewData)
  1683. {
  1684. GlobalUnlock(hNewData);
  1685. }
  1686. if (hMF)
  1687. {
  1688. DeleteMetaFile(hMF);
  1689. }
  1690. /************************************************************************/
  1691. /* if things went wrong, then free the new data */
  1692. /************************************************************************/
  1693. if ((rc == FALSE) && (hNewData != NULL))
  1694. {
  1695. GlobalFree(hNewData);
  1696. hNewData = NULL;
  1697. }
  1698. DC_END_FN();
  1699. return(hNewData);
  1700. } /* CBMGetMFData */
  1701. /****************************************************************************/
  1702. /* CBMSetMFData */
  1703. /****************************************************************************/
  1704. HANDLE DCINTERNAL CBMSetMFData(DCUINT32 dataLen, PDCVOID pData)
  1705. {
  1706. DCBOOL rc = FALSE;
  1707. HGLOBAL hMFBits = NULL;
  1708. PDCVOID pMFMem = NULL;
  1709. HMETAFILE hMF = NULL;
  1710. HGLOBAL hMFPict = NULL;
  1711. LPMETAFILEPICT pMFPict = NULL;
  1712. DC_BEGIN_FN("CBMSetMFData");
  1713. TRC_DATA_DBG("Received MF data", pData, dataLen);
  1714. /************************************************************************/
  1715. /* Allocate memory to hold the MF bits (we need the handle to pass to */
  1716. /* SetMetaFileBits). */
  1717. /************************************************************************/
  1718. hMFBits = (PDCVOID)GlobalAlloc(GHND, dataLen - sizeof(TS_CLIP_MFPICT));
  1719. if (hMFBits == NULL)
  1720. {
  1721. TRC_SYSTEM_ERROR("GlobalAlloc");
  1722. DC_QUIT;
  1723. }
  1724. /************************************************************************/
  1725. /* Lock the handle and copy in the MF header. */
  1726. /************************************************************************/
  1727. pMFMem = GlobalLock(hMFBits);
  1728. if (pMFMem == NULL)
  1729. {
  1730. TRC_ERR((TB, _T("Failed to lock MF mem")));
  1731. DC_QUIT;
  1732. }
  1733. TRC_DBG((TB, _T("copying %d MF bits"), dataLen - sizeof(TS_CLIP_MFPICT) ));
  1734. DC_MEMCPY(pMFMem,
  1735. (PDCVOID)((PDCUINT8)pData + sizeof(TS_CLIP_MFPICT)),
  1736. dataLen - sizeof(TS_CLIP_MFPICT) );
  1737. GlobalUnlock(pMFMem);
  1738. /************************************************************************/
  1739. /* Now use the copied MF bits to create the actual MF bits and get a */
  1740. /* handle to the MF. */
  1741. /************************************************************************/
  1742. hMF = SetMetaFileBitsEx(dataLen - sizeof(TS_CLIP_MFPICT), (byte *) pMFMem);
  1743. if (hMF == NULL)
  1744. {
  1745. TRC_SYSTEM_ERROR("SetMetaFileBits");
  1746. DC_QUIT;
  1747. }
  1748. /************************************************************************/
  1749. /* Allocate a new METAFILEPICT structure, and use the data from the */
  1750. /* sent header. */
  1751. /************************************************************************/
  1752. hMFPict = GlobalAlloc(GHND, sizeof(METAFILEPICT));
  1753. pMFPict = (LPMETAFILEPICT)GlobalLock(hMFPict);
  1754. if (!pMFPict)
  1755. {
  1756. TRC_ERR((TB, _T("Couldn't allocate METAFILEPICT")));
  1757. DC_QUIT;
  1758. }
  1759. pMFPict->mm = (long)((PTS_CLIP_MFPICT)pData)->mm;
  1760. pMFPict->xExt = (long)((PTS_CLIP_MFPICT)pData)->xExt;
  1761. pMFPict->yExt = (long)((PTS_CLIP_MFPICT)pData)->yExt;
  1762. pMFPict->hMF = hMF;
  1763. TRC_DBG((TB, _T("Created MF size %d, %d"), pMFPict->xExt, pMFPict->yExt ));
  1764. GlobalUnlock(hMFPict);
  1765. rc = TRUE;
  1766. DC_EXIT_POINT:
  1767. /************************************************************************/
  1768. /* tidy up */
  1769. /************************************************************************/
  1770. if (rc == FALSE)
  1771. {
  1772. if (hMFPict)
  1773. {
  1774. GlobalFree(hMFPict);
  1775. }
  1776. }
  1777. if (hMFBits)
  1778. {
  1779. GlobalFree(hMFBits);
  1780. }
  1781. DC_END_FN();
  1782. return(hMFPict);
  1783. } /* CBMSetMFData */