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.

3183 lines
116 KiB

  1. /**MOD+**********************************************************************/
  2. /* Module: sclip.cpp */
  3. /* */
  4. /* Purpose: Server-side shared clipboard support */
  5. /* */
  6. /* Copyright(C) Microsoft Corporation 1998-1999 */
  7. /* */
  8. /**MOD-**********************************************************************/
  9. #include <adcg.h>
  10. #define TRC_GROUP TRC_GROUP_CORE
  11. #define TRC_FILE "sclip"
  12. #include <atrcapi.h>
  13. #include <pclip.h>
  14. #include <sclip.h>
  15. #include <winsta.h>
  16. #include <pchannel.h>
  17. #include <shlobj.h>
  18. #include <wtsapi32.h>
  19. #include <sclipids.h>
  20. BOOL TSSNDD_Init( VOID );
  21. BOOL TSSNDD_Loop( HINSTANCE );
  22. VOID TSSNDD_Term( VOID );
  23. LRESULT TSSNDD_PowerMessage( WPARAM, LPARAM );
  24. #ifdef CLIP_TRANSITION_RECORDING
  25. UINT g_rguiDbgLastClipState[DBG_RECORD_SIZE];
  26. UINT g_rguiDbgLastClipEvent[DBG_RECORD_SIZE];
  27. LONG g_uiDbgPosition = -1;
  28. #endif // CLIP_TRANSITION_RECORDING
  29. /****************************************************************************/
  30. /* Global data */
  31. /****************************************************************************/
  32. #define DC_DEFINE_GLOBAL_DATA
  33. #include <sclipdat.h>
  34. #undef DC_DEFINE_GLOBAL_DATA
  35. /**PROC+*********************************************************************/
  36. /* Name: WinMain */
  37. /* */
  38. /* Purpose: Main procedure */
  39. /* */
  40. /* Returns: See Windows documentation */
  41. /* */
  42. /**PROC-*********************************************************************/
  43. int WINAPI WinMain(HINSTANCE hInstance,
  44. HINSTANCE hPrevInstance,
  45. LPSTR lpszCmdParam,
  46. int unusedParam2)
  47. {
  48. int wParam = 0;
  49. TRC_CONFIG trcConfig;
  50. WINSTATIONCONFIG config;
  51. BOOLEAN fSuccess;
  52. ULONG returnedLength;
  53. DC_BEGIN_FN("WinMain");
  54. DC_IGNORE_PARAMETER(hPrevInstance);
  55. DC_IGNORE_PARAMETER(lpszCmdParam);
  56. DC_IGNORE_PARAMETER(unusedParam2);
  57. /************************************************************************/
  58. /* Exit immediately if more than one copy is running */
  59. /************************************************************************/
  60. CBM.hMutex = CreateMutex(NULL, FALSE, TEXT("RDPCLIP is already running"));
  61. if (CBM.hMutex == NULL)
  62. {
  63. // An error (like out of memory) has occurred.
  64. TRC_ERR((TB, _T("Unable to create already running mutex!")));
  65. DC_QUIT;
  66. }
  67. if (GetLastError() == ERROR_ALREADY_EXISTS)
  68. {
  69. TRC_ERR((TB, _T("Second copy!")));
  70. DC_QUIT;
  71. }
  72. //
  73. // Initialize Random number generator
  74. //
  75. TSRNG_Initialize();
  76. #ifdef DC_DEBUG
  77. /************************************************************************/
  78. /* Call trace's DLLMain, since it's directly built into RDPCLIP */
  79. /************************************************************************/
  80. DllMain(hInstance, DLL_PROCESS_ATTACH, NULL);
  81. /************************************************************************/
  82. /* Switch off trace to file */
  83. /************************************************************************/
  84. TRC_GetConfig(&trcConfig, sizeof(trcConfig));
  85. CLEAR_FLAG(trcConfig.flags, TRC_OPT_FILE_OUTPUT);
  86. TRC_SetConfig(&trcConfig, sizeof(trcConfig));
  87. #endif
  88. /************************************************************************/
  89. /* Get WinStation configuration */
  90. /************************************************************************/
  91. fSuccess = WinStationQueryInformation(NULL, LOGONID_CURRENT,
  92. WinStationConfiguration, &config,
  93. sizeof(config), &returnedLength);
  94. if (!fSuccess)
  95. {
  96. TRC_ERR((TB, _T("Failed to get WinStation config, %d"), GetLastError()));
  97. goto exitme;
  98. }
  99. if ( !config.User.fDisableCam )
  100. TSSNDD_Init();
  101. if ( !config.User.fDisableClip )
  102. wParam = CBM_Main(hInstance);
  103. else
  104. {
  105. //
  106. // we need some window to handle the close event
  107. //
  108. if ( !config.User.fDisableCam )
  109. wParam = TSSNDD_Loop(hInstance);
  110. }
  111. if ( !config.User.fDisableCam )
  112. TSSNDD_Term();
  113. //
  114. // Terminate Random number generator
  115. //
  116. TSRNG_Shutdown();
  117. exitme:
  118. #ifdef DC_DEBUG
  119. /****************************************************************************/
  120. /* Tell trace we're terminating */
  121. /****************************************************************************/
  122. DllMain(hInstance, DLL_PROCESS_DETACH, NULL);
  123. #endif
  124. DC_EXIT_POINT:
  125. /************************************************************************/
  126. /* Release the run once mutex */
  127. /************************************************************************/
  128. if (CBM.hMutex != NULL) {
  129. TRC_NRM((TB, _T("Closing already running mutex")));
  130. CloseHandle(CBM.hMutex);
  131. }
  132. DC_END_FN();
  133. return(wParam);
  134. }
  135. /****************************************************************************/
  136. /* CBM_Main */
  137. /****************************************************************************/
  138. DCINT DCAPI CBM_Main(HINSTANCE hInstance)
  139. {
  140. ATOM registerClassRc = 0;
  141. DCUINT32 threadID;
  142. MSG msg;
  143. HANDLE hEvent;
  144. DCTCHAR eventName[64];
  145. DWORD dwResult;
  146. HRESULT hr ;
  147. INT iRet;
  148. INT cbWritten;
  149. DC_BEGIN_FN("CBM_Main");
  150. /************************************************************************/
  151. // Clear global memory
  152. /************************************************************************/
  153. DC_MEMSET(&CBM, 0, sizeof(CBM));
  154. //
  155. // Load the paste information string.
  156. //
  157. iRet = LoadStringW(
  158. hInstance,
  159. IDS_PASTE_PROGRESS_STRING,
  160. CBM.szPasteInfoStringW,
  161. PASTE_PROGRESS_STRING_LENGTH);
  162. if (iRet == 0) {
  163. TRC_SYSTEM_ERROR("LoadString");
  164. CBM.szPasteInfoStringW[0] = NULL;
  165. }
  166. cbWritten = WideCharToMultiByte(
  167. CP_ACP,
  168. 0,
  169. CBM.szPasteInfoStringW,
  170. -1,
  171. CBM.szPasteInfoStringA,
  172. sizeof(CBM.szPasteInfoStringA),
  173. NULL,
  174. NULL);
  175. if (cbWritten == 0) {
  176. TRC_ERR((TB, _T("Failed to load ANSI paste progress string: %s")));
  177. CBM.szPasteInfoStringA[0] = NULL;
  178. }
  179. //
  180. // Initialize the data transfer object that contains the IDataObject,
  181. // and then initialize Ole
  182. CBM.pClipData = new CClipData();
  183. if (CBM.pClipData == NULL) {
  184. TRC_ERR((TB, _T("Failed to allocate memory for CClipData")));
  185. DC_QUIT;
  186. }
  187. else
  188. {
  189. CBM.pClipData->AddRef();
  190. }
  191. hr = OleInitialize(NULL);
  192. if (FAILED(hr)) {
  193. TRC_ERR((TB, _T("Failed to initialize OLE")));
  194. DC_QUIT;
  195. }
  196. /************************************************************************/
  197. // Get session information
  198. /************************************************************************/
  199. if (!ProcessIdToSessionId(GetCurrentProcessId(), &CBM.logonId))
  200. {
  201. dwResult = GetLastError();
  202. TRC_ERR((TB, _T("Failed to get Session Id info, %d"), dwResult));
  203. DC_QUIT;
  204. }
  205. TRC_NRM((TB, _T("Logon ID %d"), CBM.logonId));
  206. //
  207. // Create DataSync events
  208. //
  209. CBM.GetDataSync[TS_BLOCK_RECEIVED] = CreateEvent(NULL, FALSE, FALSE, NULL) ;
  210. CBM.GetDataSync[TS_RECEIVE_COMPLETED] = CreateEvent(NULL, FALSE, FALSE, NULL) ;
  211. CBM.GetDataSync[TS_DISCONNECT_EVENT] = CreateEvent(NULL, TRUE, FALSE, NULL) ;
  212. CBM.GetDataSync[TS_RESET_EVENT] = CreateEvent(NULL, TRUE, FALSE, NULL) ;
  213. if (!CBM.GetDataSync[TS_BLOCK_RECEIVED] || !CBM.GetDataSync[TS_RECEIVE_COMPLETED] ||
  214. !CBM.GetDataSync[TS_RESET_EVENT] || !CBM.GetDataSync[TS_DISCONNECT_EVENT]) {
  215. TRC_ERR((TB, _T("CreateEvent Failed; a GetDataSync is NULL"))) ;
  216. DC_QUIT;
  217. }
  218. /************************************************************************/
  219. /* Create read and write completion events */
  220. /************************************************************************/
  221. CBM.readOL.hEvent = CreateEvent(NULL, // no security attribute
  222. TRUE, // manual-reset event
  223. FALSE, // initial state = not signaled
  224. NULL); // unnamed event object
  225. if (CBM.readOL.hEvent == NULL)
  226. {
  227. dwResult = GetLastError();
  228. TRC_ERR((TB, _T("Failed to create read completion event, %d"),
  229. dwResult));
  230. DC_QUIT;
  231. }
  232. CBM.hEvent[CLIP_EVENT_READ] = CBM.readOL.hEvent;
  233. CBM.writeOL.hEvent = CreateEvent(NULL, // no security attribute
  234. TRUE, // manual-reset event
  235. FALSE, // initial state = not signaled
  236. NULL); // unnamed event object
  237. if (CBM.writeOL.hEvent == NULL)
  238. {
  239. dwResult = GetLastError();
  240. TRC_ERR((TB, _T("Failed to create write completion event, %d"),
  241. dwResult));
  242. DC_QUIT;
  243. }
  244. /************************************************************************/
  245. /* Create disconnect & reconnect events */
  246. /************************************************************************/
  247. DC_TSTRCPY(eventName,
  248. _T("RDPClip-Disconnect"));
  249. hEvent = CreateEvent(NULL, FALSE, FALSE, eventName);
  250. if (hEvent == NULL)
  251. {
  252. dwResult = GetLastError();
  253. TRC_ERR((TB, _T("Failed to create event %s, %d"),
  254. eventName, dwResult));
  255. DC_QUIT;
  256. }
  257. CBM.hEvent[CLIP_EVENT_DISCONNECT] = hEvent;
  258. TRC_NRM((TB, _T("Created event %s, %p"), eventName, hEvent));
  259. DC_TSTRCPY(eventName,
  260. _T("RDPClip-Reconnect"));
  261. hEvent = CreateEvent(NULL, FALSE, FALSE, eventName);
  262. if (hEvent == NULL)
  263. {
  264. dwResult = GetLastError();
  265. TRC_ERR((TB, _T("Failed to create event %s, %d"),
  266. eventName, dwResult));
  267. DC_QUIT;
  268. }
  269. CBM.hEvent[CLIP_EVENT_RECONNECT] = hEvent;
  270. TRC_NRM((TB, _T("Created event %s, %p"), eventName, hEvent));
  271. TRC_NRM((TB, _T("Created events: Read %p, Write %p, Disc %p, Reco %p"),
  272. CBM.hEvent[CLIP_EVENT_READ], CBM.writeOL.hEvent,
  273. CBM.hEvent[CLIP_EVENT_DISCONNECT], CBM.hEvent[CLIP_EVENT_RECONNECT]));
  274. CBM.fFileCutCopyOn = FALSE;
  275. /************************************************************************/
  276. /* Create our (invisible) window which we will register as a clipboard */
  277. /* viewer */
  278. /************************************************************************/
  279. TRC_NRM((TB, _T("Register Main Window class")));
  280. CBM.viewerWindowClass.style = 0;
  281. CBM.viewerWindowClass.lpfnWndProc = CBMWndProc;
  282. CBM.viewerWindowClass.cbClsExtra = 0;
  283. CBM.viewerWindowClass.cbWndExtra = 0;
  284. CBM.viewerWindowClass.hInstance = hInstance;
  285. CBM.viewerWindowClass.hIcon = NULL;
  286. CBM.viewerWindowClass.hCursor = NULL;
  287. CBM.viewerWindowClass.hbrBackground = (HBRUSH) GetStockObject(HOLLOW_BRUSH);
  288. CBM.viewerWindowClass.lpszMenuName = NULL;
  289. CBM.viewerWindowClass.lpszClassName = CBM_VIEWER_CLASS;
  290. registerClassRc = RegisterClass (&(CBM.viewerWindowClass));
  291. if (registerClassRc == 0)
  292. {
  293. /********************************************************************/
  294. /* Failed to register CB viewer class */
  295. /********************************************************************/
  296. TRC_ERR((TB, _T("Failed to register Cb Viewer class")));
  297. DC_QUIT;
  298. }
  299. TRC_DBG((TB, _T("Create main window")));
  300. CBM.viewerWindow =
  301. CreateWindow(CBM_VIEWER_CLASS, /* window class name */
  302. _T("CB Monitor Window"), /* window caption */
  303. WS_OVERLAPPEDWINDOW, /* window style */
  304. 0, /* initial x position */
  305. 0, /* initial y position */
  306. 100, /* initial x size */
  307. 100, /* initial y size */
  308. NULL, /* parent window */
  309. NULL, /* window menu handle */
  310. hInstance, /* program inst handle */
  311. NULL); /* creation parameters */
  312. /************************************************************************/
  313. /* Check we created the window OK */
  314. /************************************************************************/
  315. if (CBM.viewerWindow == NULL)
  316. {
  317. TRC_ERR((TB, _T("Failed to create CB Viewer Window")));
  318. DC_QUIT;
  319. }
  320. TRC_DBG((TB, _T("Viewer Window handle %x"), CBM.viewerWindow));
  321. /************************************************************************/
  322. /* Register a message for communication between the two threads */
  323. /************************************************************************/
  324. CBM.regMsg = RegisterWindowMessage(_T("Clip Message"));
  325. if (CBM.regMsg == 0)
  326. {
  327. /********************************************************************/
  328. /* Failed to register a message - use a WM_USER message instead */
  329. /********************************************************************/
  330. TRC_ERR((TB, _T("Failed to register a window message")));
  331. CBM.regMsg = WM_USER_DD_KICK;
  332. }
  333. TRC_NRM((TB, _T("Registered window message %x"), CBM.regMsg));
  334. /************************************************************************/
  335. /* we're now finished with creating things */
  336. /************************************************************************/
  337. CBM_SET_STATE(CBM_STATE_INITIALIZED, CBM_EVENT_CBM_MAIN);
  338. /************************************************************************/
  339. /* Do (re)connection stuff */
  340. /************************************************************************/
  341. CBMReconnect();
  342. /************************************************************************/
  343. /* set up the second thread */
  344. /************************************************************************/
  345. TRC_DBG((TB, _T("Start second thread")));
  346. CBM.runThread = TRUE;
  347. CBM.hDataThread = CreateThread
  348. ( NULL, // pointer to thread security attribs
  349. 0, // initial thread stack size, in bytes
  350. CBMDataThreadProc, // pointer to thread function
  351. NULL, // argument for new thread
  352. 0, // creation flags
  353. &threadID); // pointer to returned thread id
  354. if (CBM.hDataThread == NULL)
  355. {
  356. /********************************************************************/
  357. /* thread creation failed - oh dear! */
  358. /********************************************************************/
  359. TRC_ERR((TB, _T("Failed to create second thread - quit")));
  360. DC_QUIT;
  361. }
  362. TRC_DBG((TB,_T("Entering message loop")));
  363. while (GetMessage (&msg, NULL, 0, 0))
  364. {
  365. TranslateMessage(&msg);
  366. DispatchMessage(&msg);
  367. }
  368. TRC_DBG((TB,_T("Exiting message loop")));
  369. DC_EXIT_POINT:
  370. /************************************************************************/
  371. /* Do the tidy up... */
  372. /* */
  373. /* Start by stopping the second thread (if any!) and removing the */
  374. /* event. */
  375. /************************************************************************/
  376. CBMTerm();
  377. /************************************************************************/
  378. /* Destroy the window */
  379. /************************************************************************/
  380. if (CBM.viewerWindow)
  381. {
  382. TRC_DBG((TB, _T("destroying window %p"), CBM.viewerWindow));
  383. if (!DestroyWindow(CBM.viewerWindow))
  384. {
  385. TRC_SYSTEM_ERROR("DestroyWindow");
  386. }
  387. }
  388. /************************************************************************/
  389. /* Unregister the class */
  390. /************************************************************************/
  391. if (registerClassRc != 0)
  392. {
  393. TRC_NRM((TB, _T("Unregister window class")));
  394. if (!UnregisterClass(CBM_VIEWER_CLASS, hInstance))
  395. {
  396. TRC_SYSTEM_ERROR("UnregisterClass");
  397. }
  398. }
  399. DC_END_FN();
  400. return(0);
  401. } /* CBM_Main */
  402. /****************************************************************************/
  403. /* CBMRemoteFormatFromLocalID */
  404. /****************************************************************************/
  405. DCUINT DCINTERNAL CBMRemoteFormatFromLocalID(DCUINT id)
  406. {
  407. DCUINT i ;
  408. DCUINT retID = 0;
  409. DC_BEGIN_FN("CBMRemoteFormatFromLocalID");
  410. for (i = 0; i < CB_MAX_FORMATS; i++)
  411. {
  412. if (CBM.idMap[i].serverID == id)
  413. {
  414. retID = CBM.idMap[i].clientID;
  415. break;
  416. }
  417. }
  418. //TRC_ASSERT((retID != 0), (TB, _T("0 client id for server id %d"), id));
  419. DC_END_FN();
  420. return(retID);
  421. }
  422. /****************************************************************************/
  423. /* CBMCheckState */
  424. /****************************************************************************/
  425. DCUINT DCINTERNAL CBMCheckState(DCUINT event)
  426. {
  427. DCUINT tableVal = cbmStateTable[event][CBM.state];
  428. DC_BEGIN_FN("CBMCheckState");
  429. TRC_DBG((TB, _T("Test event %d (%s) in state %d (%s), result = %d (%s)"),
  430. event, cbmEvent[event],
  431. CBM.state, cbmState[CBM.state],
  432. tableVal, tableVal == CBM_TABLE_OK ? _T("OK") :
  433. tableVal == CBM_TABLE_WARN ? _T("Warn") :
  434. _T("Error") ));
  435. if (tableVal != CBM_TABLE_OK)
  436. {
  437. if (tableVal == CBM_TABLE_WARN)
  438. {
  439. TRC_ALT((TB, _T("Unusual event %s in state %s"),
  440. cbmEvent[event], cbmState[CBM.state]));
  441. }
  442. else
  443. {
  444. TRC_ABORT((TB, _T("Invalid event %s in state %s"),
  445. cbmEvent[event], cbmState[CBM.state]));
  446. }
  447. }
  448. DC_END_FN();
  449. return(tableVal);
  450. }
  451. /****************************************************************************/
  452. /* CB window proc */
  453. /****************************************************************************/
  454. LRESULT CALLBACK CBMWndProc(HWND hwnd,
  455. UINT message,
  456. WPARAM wParam,
  457. LPARAM lParam)
  458. {
  459. LRESULT rc = 0;
  460. DCBOOL drawRc;
  461. PTS_CLIP_PDU pClipPDU;
  462. ULONG_PTR size;
  463. #ifdef DC_DEBUG
  464. HDC hdc;
  465. PAINTSTRUCT ps;
  466. RECT rect;
  467. #endif
  468. DC_BEGIN_FN("CBMWndProc");
  469. /************************************************************************/
  470. /* First of all, handle messages from the 2nd thread */
  471. /************************************************************************/
  472. if (message == CBM.regMsg)
  473. {
  474. TRC_NRM((TB, _T("Message from second thread")));
  475. /********************************************************************/
  476. /* Handle 0-length messages (lParam = event) */
  477. /********************************************************************/
  478. if (wParam == 0)
  479. {
  480. TRC_NRM((TB, _T("0-length")));
  481. if (lParam == CLIP_EVENT_DISCONNECT)
  482. {
  483. TRC_NRM((TB, _T("Disconnected indication")));
  484. CBMDisconnect();
  485. }
  486. else if (lParam == CLIP_EVENT_RECONNECT)
  487. {
  488. TRC_NRM((TB, _T("Reconnected indication")));
  489. CBMReconnect();
  490. }
  491. else
  492. {
  493. TRC_ERR((TB, _T("Unknown event %d"), lParam));
  494. }
  495. DC_QUIT;
  496. }
  497. /********************************************************************/
  498. /* Handle real messages (lParam = PDU) */
  499. /********************************************************************/
  500. size = (ULONG_PTR)wParam;
  501. pClipPDU = (PTS_CLIP_PDU)lParam;
  502. switch (pClipPDU->msgType)
  503. {
  504. case TS_CB_FORMAT_LIST:
  505. {
  506. // Validate a full TS_CLIP_PDU can be read
  507. if (FIELDOFFSET(TS_CLIP_PDU, data) > size) {
  508. TRC_ERR((TB,_T("TS_CB_FORMAT_LIST Not enough header ")
  509. _T("data [needed=%u got=%u]"),
  510. FIELDOFFSET(TS_CLIP_PDU, data), size));
  511. break;
  512. }
  513. // Validate there is as much data as the packet advertises
  514. if (FIELDOFFSET(TS_CLIP_PDU,data) + pClipPDU->dataLen > size) {
  515. TRC_ERR((TB,_T("TS_CB_FORMAT_LIST Not enough packet ")
  516. _T("data [needed=%u got=%u]"),
  517. FIELDOFFSET(TS_CLIP_PDU, data) + pClipPDU->dataLen,
  518. size));
  519. break;
  520. }
  521. TRC_NRM((TB, _T("TS_CB_FORMAT_LIST received")));
  522. CBMOnFormatList(pClipPDU);
  523. }
  524. break;
  525. case TS_CB_MONITOR_READY:
  526. {
  527. TRC_ERR((TB, _T("Unexpected Monitor ready event!")));
  528. }
  529. break;
  530. default:
  531. {
  532. TRC_ERR((TB, _T("Unknown event %d"), pClipPDU->msgType));
  533. }
  534. break;
  535. }
  536. TRC_NRM((TB, _T("Freeing processed PDU")));
  537. LocalFree(pClipPDU);
  538. DC_QUIT;
  539. }
  540. /************************************************************************/
  541. /* Now process constant messages */
  542. /************************************************************************/
  543. switch (message)
  544. {
  545. case WM_CREATE:
  546. {
  547. /****************************************************************/
  548. /* We've been created - check the state */
  549. /****************************************************************/
  550. CBM_CHECK_STATE(CBM_EVENT_WM_CREATE);
  551. TRC_NRM((TB, _T("Event CBM_EVENT_WM_CREATE OK")));
  552. /****************************************************************/
  553. /* Add the window to the clipboard viewer chain. */
  554. /****************************************************************/
  555. TRC_NRM((TB, _T("SetClipboardViewer")));
  556. CBM.nextViewer = SetClipboardViewer(hwnd);
  557. CBM.fInClipboardChain = TRUE;
  558. TRC_NRM((TB,_T("CBM.fInClipboardChain=%d"),
  559. CBM.fInClipboardChain ? 1 : 0 ));
  560. TRC_NRM((TB, _T("Back from SetClipboardViewer")));
  561. /************************************************************************/
  562. /* Register for TS session notifications */
  563. /************************************************************************/
  564. CBM.fRegisteredForSessNotif = WTSRegisterSessionNotification(hwnd, NOTIFY_FOR_THIS_SESSION);
  565. if (0 == CBM.fRegisteredForSessNotif) {
  566. TRC_ERR((TB,_T("Failed to register for session notifications")));
  567. }
  568. }
  569. break;
  570. #ifdef DC_DEBUG
  571. case WM_PAINT:
  572. {
  573. /****************************************************************/
  574. /* paint the window! */
  575. /****************************************************************/
  576. hdc = BeginPaint(hwnd, &ps);
  577. GetClientRect(hwnd, &rect);
  578. FillRect(hdc, &rect, WHITE_BRUSH);
  579. EndPaint(hwnd, &ps);
  580. }
  581. break;
  582. #endif
  583. case WM_DESTROY:
  584. {
  585. /****************************************************************/
  586. /* We're being destroyed - check the state */
  587. /****************************************************************/
  588. CBM_CHECK_STATE(CBM_EVENT_WM_DESTROY);
  589. TRC_NRM((TB, _T("WM_DESTROY")));
  590. /****************************************************************/
  591. /* Remove ourselves from the CB Chain */
  592. /****************************************************************/
  593. if (CBM.fInClipboardChain) {
  594. if (!ChangeClipboardChain(hwnd, CBM.nextViewer))
  595. {
  596. TRC_SYSTEM_ERROR("ChangeClipboardChain");
  597. }
  598. CBM.nextViewer = NULL;
  599. CBM.fInClipboardChain = FALSE;
  600. TRC_NRM((TB,_T("CBM.fInClipboardChain=%d"),
  601. CBM.fInClipboardChain ? 1 : 0 ));
  602. }
  603. if (CBM.fRegisteredForSessNotif) {
  604. WTSUnRegisterSessionNotification(hwnd);
  605. CBM.fRegisteredForSessNotif = FALSE;
  606. }
  607. /****************************************************************/
  608. /* and quit */
  609. /****************************************************************/
  610. PostQuitMessage(0);
  611. }
  612. break;
  613. case WM_CLOSE:
  614. {
  615. /****************************************************************/
  616. /* We're closing down. If this is not happening cleanly, then */
  617. /* make sure we disconnect first */
  618. /****************************************************************/
  619. CBM_CHECK_STATE(CBM_EVENT_WM_CLOSE);
  620. TRC_NRM((TB, _T("WM_CLOSE")));
  621. if (CBM.state != CBM_STATE_INITIALIZED)
  622. {
  623. TRC_ALT((TB, _T("Close when not already back to state Init")));
  624. CBMDisconnect();
  625. }
  626. /****************************************************************/
  627. /* and having done that, its safe to finish. */
  628. /****************************************************************/
  629. DestroyWindow(CBM.viewerWindow);
  630. }
  631. break;
  632. case WM_CHANGECBCHAIN:
  633. {
  634. /****************************************************************/
  635. /* The CB viewer chain is chainging - check the state */
  636. /****************************************************************/
  637. CBM_CHECK_STATE(CBM_EVENT_WM_CHANGECBCHAIN);
  638. /****************************************************************/
  639. /* If the next window is closing, repair the chain. */
  640. /****************************************************************/
  641. if ((HWND)wParam == CBM.nextViewer)
  642. {
  643. CBM.nextViewer = (HWND) lParam;
  644. }
  645. else if (CBM.nextViewer != NULL)
  646. {
  647. /************************************************************/
  648. /* pass the message to the next link. */
  649. /************************************************************/
  650. PostMessage(CBM.nextViewer, message, wParam, lParam);
  651. }
  652. }
  653. break;
  654. case WM_DRAWCLIPBOARD:
  655. {
  656. LPDATAOBJECT pIDataObject = NULL;
  657. HRESULT hr ;
  658. /****************************************************************/
  659. /* The local clipboard contents have been changed. Check the */
  660. /* state */
  661. /****************************************************************/
  662. if (CBMCheckState(CBM_EVENT_WM_DRAWCLIPBOARD) != CBM_TABLE_OK)
  663. {
  664. /************************************************************/
  665. /* We're not interested at the moment - pass the message to */
  666. /* the next link */
  667. /************************************************************/
  668. if (CBM.nextViewer != NULL)
  669. {
  670. TRC_NRM((TB, _T("Tell next viewer anyway")));
  671. PostMessage(CBM.nextViewer, message, wParam, lParam);
  672. }
  673. break;
  674. }
  675. /****************************************************************/
  676. /* If it wasn't us that generated this change, then tell the */
  677. /* client */
  678. /****************************************************************/
  679. drawRc = FALSE;
  680. CBM.pClipData->QueryInterface(IID_IDataObject, (PPVOID) &pIDataObject) ;
  681. hr = OleIsCurrentClipboard(pIDataObject) ;
  682. if ((S_FALSE == hr))
  683. {
  684. TRC_NRM((TB, _T("...and it wasn't us"))) ;
  685. drawRc = CBMDrawClipboard() ;
  686. }
  687. else
  688. {
  689. TRC_NRM((TB, _T("CB contents changed by us - ignoring")));
  690. }
  691. /****************************************************************/
  692. /* If the draw processing failed, or it was us that changed the */
  693. /* CB, pass the message to the next window in the chain (if */
  694. /* any) */
  695. /****************************************************************/
  696. if (!drawRc)
  697. {
  698. if (CBM.nextViewer != NULL)
  699. {
  700. /********************************************************/
  701. /* pass the message to the next link. */
  702. /********************************************************/
  703. TRC_NRM((TB, _T("Tell next viewer")));
  704. PostMessage(CBM.nextViewer, message, wParam, lParam);
  705. }
  706. }
  707. if (pIDataObject)
  708. {
  709. pIDataObject->Release();
  710. pIDataObject = NULL;
  711. }
  712. }
  713. break;
  714. case WM_POWERBROADCAST:
  715. rc = TSSNDD_PowerMessage( wParam, lParam );
  716. break;
  717. case WM_ENDSESSION:
  718. {
  719. /****************************************************************/
  720. /* The session is ending. Clean up here - we don't get a */
  721. /* WM_QUIT, so we can't clean up in the normal place. We must */
  722. /* clean up however, otherwise we generate a */
  723. /* SESSION_HAS_VALID_PAGES fault. */
  724. /****************************************************************/
  725. /****************************************************************/
  726. /* Remove ourselves from the CB Chain */
  727. /****************************************************************/
  728. if (CBM.fInClipboardChain) {
  729. if (!ChangeClipboardChain(hwnd, CBM.nextViewer))
  730. {
  731. TRC_SYSTEM_ERROR("ChangeClipboardChain");
  732. }
  733. CBM.nextViewer = NULL;
  734. CBM.fInClipboardChain = FALSE;
  735. TRC_NRM((TB,_T("CBM.fInClipboardChain=%d"),
  736. CBM.fInClipboardChain ? 1 : 0 ));
  737. }
  738. TRC_NRM((TB,_T("WM_ENDSESSION")));
  739. CBMTerm();
  740. TSSNDD_Term();
  741. }
  742. break;
  743. case WM_WTSSESSION_CHANGE:
  744. {
  745. switch(wParam) {
  746. case WTS_REMOTE_CONNECT: //A session was connected to the remote session.
  747. {
  748. TRC_NRM((TB,_T("WM_WTSSESSION_CHANGE WTS_REMOTE_CONNECT")));
  749. if (FALSE == CBM.fInClipboardChain) {
  750. /****************************************************************/
  751. /* Add the window to the clipboard viewer chain. */
  752. /****************************************************************/
  753. TRC_NRM((TB, _T("SetClipboardViewer")));
  754. // Check to see that the first clipboard viewer in the chain is
  755. // not this process. This helps to partially address RAID
  756. // Bug #646295. A better fix would be to have a reliable means of
  757. // removing ourselves from the clipboard viewer chain, but that
  758. // does not currently exist with the current set of clipboard
  759. // functions.
  760. if (CBM.viewerWindow != GetClipboardViewer()) {
  761. TRC_ERR((TB, _T("RDPClip already in clipboard chain.")));
  762. CBM.nextViewer = SetClipboardViewer(hwnd);
  763. }
  764. CBM.fInClipboardChain = TRUE;
  765. }
  766. TRC_NRM((TB,_T("CBM.fInClipboardChain=%d"),
  767. CBM.fInClipboardChain ? 1 : 0 ));
  768. TRC_NRM((TB, _T("Back from SetClipboardViewer")));
  769. break;
  770. }
  771. case WTS_REMOTE_DISCONNECT: //A session was disconnected from the remote session.
  772. {
  773. TRC_NRM((TB,_T("WM_WTSSESSION_CHANGE WTS_REMOTE_DISCONNECT")));
  774. /****************************************************************/
  775. /* Remove ourselves from the CB Chain */
  776. /****************************************************************/
  777. if (CBM.fInClipboardChain) {
  778. if (!ChangeClipboardChain(hwnd, CBM.nextViewer))
  779. {
  780. TRC_SYSTEM_ERROR("ChangeClipboardChain");
  781. }
  782. CBM.nextViewer = NULL;
  783. CBM.fInClipboardChain = FALSE;
  784. TRC_NRM((TB,_T("CBM.fInClipboardChain=%d"),
  785. CBM.fInClipboardChain ? 1 : 0 ));
  786. }
  787. break;
  788. }
  789. default:
  790. TRC_NRM((TB,_T("WM_WTSSESSION_CHANGE wParam=0x%x"), wParam));
  791. break;
  792. }
  793. break;
  794. }
  795. default:
  796. {
  797. /****************************************************************/
  798. /* Ignore all other messages. */
  799. /****************************************************************/
  800. rc = DefWindowProc(hwnd, message, wParam, lParam);
  801. }
  802. break;
  803. }
  804. DC_EXIT_POINT:
  805. DC_END_FN();
  806. return(rc);
  807. } /* CBMWndProc */
  808. /****************************************************************************/
  809. /* CBMDrawClipboard - send the local formats to the remote */
  810. /****************************************************************************/
  811. DCBOOL DCINTERNAL CBMDrawClipboard(DCVOID)
  812. {
  813. DCUINT numFormats;
  814. DCUINT formatCount;
  815. DCUINT formatID;
  816. PTS_CLIP_FORMAT formatList;
  817. PTS_CLIP_PDU pClipRsp = NULL;
  818. TS_CLIP_PDU clipRsp;
  819. DCUINT nameLen;
  820. DCUINT pduLen;
  821. DCUINT32 dataLen = 0;
  822. DCINT rc1;
  823. DCTCHAR formatName[TS_FORMAT_NAME_LEN + 1] = { 0 };
  824. DCBOOL rc = TRUE;
  825. DCBOOL fHdrop = FALSE ;
  826. wchar_t tempDirW[MAX_PATH] ;
  827. DC_BEGIN_FN("CBMDrawClipboard");
  828. CBM.dropEffect = FO_COPY ;
  829. CBM.fAlreadyCopied = FALSE ;
  830. CBM_CHECK_STATE(CBM_EVENT_WM_DRAWCLIPBOARD);
  831. /************************************************************************/
  832. /* @@@ what tidy up is needed here if state is unusual? */
  833. /************************************************************************/
  834. /************************************************************************/
  835. /* First we open the clipboard */
  836. /************************************************************************/
  837. if (!CBM.open)
  838. {
  839. if (!OpenClipboard(CBM.viewerWindow))
  840. {
  841. TRC_SYSTEM_ERROR("OpenCB");
  842. rc = FALSE;
  843. DC_QUIT;
  844. }
  845. }
  846. /************************************************************************/
  847. /* It was/is open */
  848. /************************************************************************/
  849. TRC_NRM((TB, _T("CB opened")));
  850. CBM.open = TRUE;
  851. /************************************************************************/
  852. /* Count the formats available, checking we don't blow our limit */
  853. /************************************************************************/
  854. numFormats = CountClipboardFormats();
  855. if (numFormats == 0)
  856. {
  857. /********************************************************************/
  858. /* clipboard has been emptied - send an empty list */
  859. /********************************************************************/
  860. pClipRsp = &clipRsp;
  861. pduLen = sizeof(clipRsp);
  862. dataLen = 0;
  863. TRC_NRM((TB, _T("CB emptied")));
  864. }
  865. else
  866. {
  867. /********************************************************************/
  868. /* build the format list */
  869. /********************************************************************/
  870. if (numFormats > CB_MAX_FORMATS)
  871. {
  872. TRC_ALT((TB, _T("Num formats %d too large - limit to %d"),
  873. numFormats, CB_MAX_FORMATS));
  874. numFormats = CB_MAX_FORMATS;
  875. }
  876. TRC_DBG((TB, _T("found %d formats"), numFormats));
  877. /********************************************************************/
  878. /* We need some memory for the format list - how much? */
  879. /********************************************************************/
  880. dataLen = numFormats * sizeof(TS_CLIP_FORMAT);
  881. pduLen = dataLen + sizeof(TS_CLIP_PDU);
  882. /********************************************************************/
  883. /* and make sure that's not too big! */
  884. /********************************************************************/
  885. if (pduLen > CHANNEL_CHUNK_LENGTH)
  886. {
  887. /****************************************************************/
  888. /* we'll have to limit the number of formats. How many will */
  889. /* fit in the max buffer size? */
  890. /****************************************************************/
  891. pduLen = CHANNEL_CHUNK_LENGTH;
  892. dataLen = pduLen - sizeof(TS_CLIP_PDU);
  893. numFormats = dataLen / sizeof(TS_CLIP_FORMAT);
  894. /****************************************************************/
  895. /* no point in having empty space for the last fractional */
  896. /* format! */
  897. /****************************************************************/
  898. dataLen = numFormats * sizeof(TS_CLIP_FORMAT);
  899. pduLen = dataLen + sizeof(TS_CLIP_PDU);
  900. TRC_ALT((TB, _T("Too many formats! Limited to %d"), numFormats));
  901. }
  902. /********************************************************************/
  903. /* now get the buffer */
  904. /********************************************************************/
  905. pClipRsp = (PTS_CLIP_PDU)GlobalAlloc(GPTR, pduLen);
  906. if (pClipRsp == NULL)
  907. {
  908. /****************************************************************/
  909. /* If we supplied the last format list, we can no longer */
  910. /* satisfy any requests, so empty the remote clipboard even */
  911. /* though we can't send the new list */
  912. /****************************************************************/
  913. TRC_ERR((TB, _T("Failed to get format list mem - emptying remote")));
  914. pClipRsp = &clipRsp;
  915. pduLen = sizeof(clipRsp);
  916. dataLen = 0;
  917. }
  918. else
  919. {
  920. /****************************************************************/
  921. /* enumerate the formats */
  922. /****************************************************************/
  923. TRC_NRM((TB, _T("Building list...")));
  924. formatList = (PTS_CLIP_FORMAT)pClipRsp->data;
  925. formatCount = 0;
  926. formatID = EnumClipboardFormats(0); /* 0 starts enumeration */
  927. while ((formatID != 0) && (formatCount < numFormats))
  928. {
  929. if ((CF_HDROP == formatID) && (CBM.fFileCutCopyOn))
  930. {
  931. fHdrop = TRUE ;
  932. }
  933. /************************************************************/
  934. /* look for formats we don't send */
  935. /************************************************************/
  936. if ((formatID == CF_BITMAP) ||
  937. (formatID == CF_DSPBITMAP) ||
  938. (formatID == CF_ENHMETAFILE) ||
  939. (formatID == CF_OWNERDISPLAY) ||
  940. ((formatID == CF_HDROP) && (!CBM.fFileCutCopyOn)))
  941. {
  942. // We send DIB not bitmap to avoid potential palette
  943. // problems - this is a Windows recommendation. The
  944. // remote Windows CB will provide the conversion to
  945. // CF_BITMAP
  946. //
  947. // Similarly we drop enhanced metafile formats, since
  948. // the local CB will provide conversion where supported
  949. //
  950. // Ownerdisplay just isn't going to work since the two
  951. // windows are on different machines!
  952. //
  953. // And if File Cut/Copy is off, we can't do HDROP
  954. TRC_NRM((TB, _T("Dropping format ID %d"), formatID));
  955. goto CONTINUE_FORMAT_ENUM;
  956. }
  957. /************************************************************/
  958. /* find the name for the format */
  959. /************************************************************/
  960. nameLen = GetClipboardFormatName(formatID,
  961. formatName,
  962. TS_FORMAT_NAME_LEN);
  963. if (nameLen == 0)
  964. {
  965. /********************************************************/
  966. /* predefined formats have no name */
  967. /********************************************************/
  968. TRC_NRM((TB, _T("predefined format %d - "), formatID));
  969. formatList[formatCount].formatID = formatID;
  970. *(formatList[formatCount].formatName) = '\0';
  971. }
  972. else if (CBMIsExcludedFormat(formatName))
  973. {
  974. /********************************************************/
  975. /* We drop the various DDE formats, again because they */
  976. /* just won't work where the apps are running on */
  977. /* different machines */
  978. /********************************************************/
  979. TRC_NRM((TB, _T("Dropping format '%s'"), formatName));
  980. goto CONTINUE_FORMAT_ENUM;
  981. }
  982. else
  983. {
  984. /********************************************************/
  985. /* its got a name and its not excluded! */
  986. /********************************************************/
  987. formatList[formatCount].formatID = formatID;
  988. /********************************************************/
  989. /* Convert the name to Ascii? */
  990. /********************************************************/
  991. if (CBM.fUseAsciiNames)
  992. {
  993. /****************************************************/
  994. /* Convert over to the ANSI codepage. Set no flags */
  995. /* to maximise the speed of the conversion Set */
  996. /* length to -1 since null-terminated. Set default */
  997. /* chars to NULL to maximise speed. */
  998. /****************************************************/
  999. TRC_DBG((TB, _T("Converting to Ascii")));
  1000. rc1 = WideCharToMultiByte(
  1001. CP_ACP,
  1002. 0,
  1003. (LPCWSTR)formatName,
  1004. -1,
  1005. (LPSTR)formatList[formatCount].formatName,
  1006. TS_FORMAT_NAME_LEN,
  1007. NULL,
  1008. NULL);
  1009. TRC_ASSERT((0 != rc1),
  1010. (TB, _T("Wide char conversion failed")));
  1011. TRC_DATA_DBG("Ascii name",
  1012. formatList[formatCount].formatName,
  1013. TS_FORMAT_NAME_LEN);
  1014. }
  1015. /********************************************************/
  1016. /* just copy the name */
  1017. /********************************************************/
  1018. else
  1019. {
  1020. //
  1021. // There is no explicit NULL termination at this
  1022. // point if the format name is more than 32 bytes.
  1023. // This will be rectified in Longhorn when we
  1024. // eliminate truncation of format names.
  1025. //
  1026. TRC_DBG((TB, _T("copying Unicode name")));
  1027. DC_TSTRNCPY(
  1028. (PDCTCHAR)(formatList[formatCount].formatName),
  1029. formatName,
  1030. TS_FORMAT_NAME_LEN / sizeof(WCHAR));
  1031. }
  1032. }
  1033. TRC_DBG((TB, _T("found format id %d, name '%s'"),
  1034. formatList[formatCount].formatID,
  1035. formatList[formatCount].formatName));
  1036. /************************************************************/
  1037. /* update the count and move on */
  1038. /************************************************************/
  1039. formatCount++;
  1040. CONTINUE_FORMAT_ENUM:
  1041. /************************************************************/
  1042. /* get the next format */
  1043. /************************************************************/
  1044. formatID = EnumClipboardFormats(formatID);
  1045. }
  1046. /****************************************************************/
  1047. /* Update the PDU len - we may have dropped some formats along */
  1048. /* the way */
  1049. /****************************************************************/
  1050. dataLen = formatCount * sizeof(TS_CLIP_FORMAT);
  1051. pduLen = dataLen + sizeof(TS_CLIP_PDU);
  1052. TRC_NRM((TB, _T("Final count: %d formats in data len %d"),
  1053. formatCount, dataLen));
  1054. }
  1055. }
  1056. /************************************************************************/
  1057. /* Close the Clipboard now */
  1058. /************************************************************************/
  1059. if (CBM.open)
  1060. {
  1061. TRC_NRM((TB, _T("Close clipboard")));
  1062. if (!CloseClipboard())
  1063. {
  1064. TRC_SYSTEM_ERROR("CloseClipboard");
  1065. }
  1066. CBM.open = FALSE;
  1067. }
  1068. // Only if we got an HDROP should we make a new temp directory
  1069. if (fHdrop)
  1070. {
  1071. if (GetTempFileNameW(CBM.baseTempDirW, L"_TS", 0, CBM.tempDirW)) {
  1072. DeleteFile(CBM.tempDirW) ;
  1073. CreateDirectoryW(CBM.tempDirW, NULL) ;
  1074. if (CBMConvertToClientPathW(CBM.tempDirW, tempDirW,
  1075. sizeof(tempDirW)) == S_OK) {
  1076. wcscpy(CBM.tempDirW, tempDirW) ;
  1077. WideCharToMultiByte(CP_ACP, NULL, CBM.tempDirW, -1,
  1078. CBM.tempDirA, wcslen(CBM.tempDirW), NULL, NULL) ;
  1079. }
  1080. else {
  1081. CBM.tempDirW[0] = L'\0';
  1082. CBM.tempDirA[0] = '\0';
  1083. }
  1084. }
  1085. else {
  1086. CBM.tempDirW[0] = L'\0';
  1087. CBM.tempDirA[0] = '\0';
  1088. }
  1089. }
  1090. /************************************************************************/
  1091. /* Update the state */
  1092. /************************************************************************/
  1093. CBM_SET_STATE(CBM_STATE_PENDING_FORMAT_LIST_RSP, CBM_EVENT_WM_DRAWCLIPBOARD);
  1094. /************************************************************************/
  1095. /* Complete the PDU */
  1096. /************************************************************************/
  1097. pClipRsp->msgType = TS_CB_FORMAT_LIST;
  1098. pClipRsp->msgFlags = 0;
  1099. pClipRsp->dataLen = dataLen;
  1100. /************************************************************************/
  1101. /* and send it to the Client */
  1102. /************************************************************************/
  1103. CBM.formatResponseCount++;
  1104. TRC_NRM((TB, _T("Pass format data to Client - %d response(s) pending"),
  1105. CBM.formatResponseCount));
  1106. CBMSendToClient(pClipRsp, pduLen);
  1107. DC_EXIT_POINT:
  1108. /************************************************************************/
  1109. /* free any memory we got */
  1110. /************************************************************************/
  1111. if ((pClipRsp != NULL) && (pClipRsp != &clipRsp))
  1112. {
  1113. GlobalFree(pClipRsp);
  1114. }
  1115. DC_END_FN();
  1116. return(rc);
  1117. } /* CBMDrawClipboard */
  1118. /****************************************************************************/
  1119. /* CBMOnFormatList */
  1120. /* Caller must have validated that the PDU contained enough data for the */
  1121. /* length specified in pClipPDU->dataLen */
  1122. /****************************************************************************/
  1123. DCVOID DCINTERNAL CBMOnFormatList(PTS_CLIP_PDU pClipPDU)
  1124. {
  1125. DCUINT16 response = TS_CB_RESPONSE_OK;
  1126. DCUINT numFormats;
  1127. PTS_CLIP_FORMAT fmtList;
  1128. DCUINT i;
  1129. DCTCHAR formatName[TS_FORMAT_NAME_LEN + 1] = { 0 };
  1130. TS_CLIP_PDU clipRsp;
  1131. DCBOOL fSuccess;
  1132. LPDATAOBJECT pIDataObject = NULL;
  1133. LPFORMATETC pFormatEtc = NULL;
  1134. HRESULT hr ;
  1135. DC_BEGIN_FN("CBMOnFormatList");
  1136. /************************************************************************/
  1137. /* The client has sent us some new formats */
  1138. /************************************************************************/
  1139. TRC_NRM((TB, _T("Received FORMAT_LIST")));
  1140. CBM_CHECK_STATE(CBM_EVENT_FORMAT_LIST);
  1141. /************************************************************************/
  1142. /* This may arrive just after we've sent the client a format list - */
  1143. /* since the client always wins, we must accept the list */
  1144. /************************************************************************/
  1145. if (CBM.state == CBM_STATE_PENDING_FORMAT_LIST_RSP)
  1146. {
  1147. TRC_ALT((TB, _T("Got list while pending list response")));
  1148. /********************************************************************/
  1149. /* close the local CB - if it's open - and tell the next viewer */
  1150. /* about the updated list */
  1151. /********************************************************************/
  1152. if (CBM.open)
  1153. {
  1154. TRC_NRM((TB, _T("Close clipboard")));
  1155. if (!CloseClipboard())
  1156. {
  1157. TRC_SYSTEM_ERROR("CloseClipboard");
  1158. }
  1159. CBM.open = FALSE;
  1160. }
  1161. if (CBM.nextViewer != NULL)
  1162. {
  1163. PostMessage(CBM.nextViewer, WM_DRAWCLIPBOARD,0,0);
  1164. }
  1165. }
  1166. CBM.formatResponseCount = 0;
  1167. /********************************************************************/
  1168. /* empty the CB and the client/server mapping table */
  1169. /********************************************************************/
  1170. //OleSetClipboard(NULL) ;
  1171. DC_MEMSET(CBM.idMap, 0, sizeof(CBM.idMap));
  1172. /********************************************************************/
  1173. /* See if we must use ASCII format names */
  1174. /********************************************************************/
  1175. CBM.fUseAsciiNames = (pClipPDU->msgFlags & TS_CB_ASCII_NAMES) ?
  1176. TRUE : FALSE;
  1177. /********************************************************************/
  1178. /* work out how many formats we got */
  1179. /********************************************************************/
  1180. numFormats = (pClipPDU->dataLen) / sizeof(TS_CLIP_FORMAT);
  1181. TRC_ASSERT(numFormats < CB_MAX_FORMATS,
  1182. (TB,_T("Too many formats recevied %d"),
  1183. numFormats));
  1184. TRC_NRM((TB, _T("PDU contains %d formats"), numFormats));
  1185. hr = CBM.pClipData->SetNumFormats(numFormats + 5) ; // Add 5 extra format slots
  1186. if (SUCCEEDED(hr)) {
  1187. hr = CBM.pClipData->QueryInterface(IID_IDataObject, (PPVOID) &pIDataObject);
  1188. if (FAILED(hr)) {
  1189. TRC_ERR((TB,_T("Error getting pointer to an IDataObject"))) ;
  1190. pIDataObject = NULL;
  1191. }
  1192. }
  1193. if (SUCCEEDED(hr)) {
  1194. /********************************************************************/
  1195. /* and add them to the clipboard */
  1196. /********************************************************************/
  1197. fmtList = (PTS_CLIP_FORMAT)pClipPDU->data;
  1198. for (i = 0; i < numFormats; i++)
  1199. {
  1200. TRC_DBG((TB, _T("format number %d, client id %d"),
  1201. i, fmtList[i].formatID));
  1202. /****************************************************************/
  1203. /* If we got a name... */
  1204. /****************************************************************/
  1205. if (fmtList[i].formatName[0] != 0)
  1206. {
  1207. /************************************************************/
  1208. /* clear out any garbage */
  1209. /************************************************************/
  1210. DC_MEMSET(formatName, 0, TS_FORMAT_NAME_LEN + 1);
  1211. /************************************************************/
  1212. /* Convert from Ascii? */
  1213. /************************************************************/
  1214. if (CBM.fUseAsciiNames)
  1215. {
  1216. TRC_NRM((TB, _T("Converting to Unicode")));
  1217. MultiByteToWideChar(
  1218. CP_ACP,
  1219. MB_ERR_INVALID_CHARS,
  1220. (LPCSTR)fmtList[i].formatName,
  1221. -1,
  1222. (LPWSTR)formatName,
  1223. TS_FORMAT_NAME_LEN);
  1224. }
  1225. else
  1226. {
  1227. /********************************************************/
  1228. /* just copy it */
  1229. /********************************************************/
  1230. //
  1231. // fmtList[i].formatName is not NULL terminated so
  1232. // explicity do a byte count copy
  1233. //
  1234. StringCbCopy(formatName, TS_FORMAT_NAME_LEN + sizeof(TCHAR),
  1235. (PDCTCHAR)(fmtList[i].formatName));
  1236. }
  1237. /************************************************************/
  1238. /* Check for excluded formats */
  1239. /************************************************************/
  1240. if (CBMIsExcludedFormat(formatName))
  1241. {
  1242. TRC_NRM((TB, _T("Dropped format '%s'"), formatName));
  1243. continue;
  1244. }
  1245. /************************************************************/
  1246. /* name is sorted */
  1247. /************************************************************/
  1248. TRC_NRM((TB, _T("Got name '%s'"), formatName));
  1249. }
  1250. else
  1251. {
  1252. DC_MEMSET(formatName, 0, TS_FORMAT_NAME_LEN);
  1253. }
  1254. /****************************************************************/
  1255. /* store the client id */
  1256. /****************************************************************/
  1257. CBM.idMap[i].clientID = fmtList[i].formatID;
  1258. TRC_NRM((TB, _T("client id %d"), CBM.idMap[i].clientID));
  1259. /****************************************************************/
  1260. /* get local name (if needed) */
  1261. /****************************************************************/
  1262. if (formatName[0] != 0)
  1263. {
  1264. CBM.idMap[i].serverID = RegisterClipboardFormat(formatName);
  1265. }
  1266. else
  1267. {
  1268. /************************************************************/
  1269. /* it's a predefined format so we can just use the ID */
  1270. /************************************************************/
  1271. CBM.idMap[i].serverID = CBM.idMap[i].clientID;
  1272. }
  1273. /****************************************************************/
  1274. /* and add the format to the local CB */
  1275. /****************************************************************/
  1276. TRC_DBG((TB, _T("Adding format '%s', client ID %d, server ID %d"),
  1277. formatName,
  1278. CBM.idMap[i].clientID,
  1279. CBM.idMap[i].serverID));
  1280. if (CBM.idMap[i].serverID != 0) {
  1281. pFormatEtc = new FORMATETC ;
  1282. if (pFormatEtc) {
  1283. pFormatEtc->cfFormat = (CLIPFORMAT) CBM.idMap[i].serverID ;
  1284. pFormatEtc->dwAspect = DVASPECT_CONTENT ;
  1285. pFormatEtc->ptd = NULL ;
  1286. pFormatEtc->lindex = -1 ;
  1287. pFormatEtc->tymed = TYMED_HGLOBAL ;
  1288. pIDataObject->SetData(pFormatEtc, NULL, TRUE) ;
  1289. delete pFormatEtc;
  1290. }
  1291. }
  1292. else {
  1293. TRC_NRM((TB,_T("Invalid format dropped"))) ;
  1294. }
  1295. }
  1296. }
  1297. hr = OleSetClipboard(pIDataObject) ;
  1298. if (pIDataObject)
  1299. {
  1300. pIDataObject->Release();
  1301. pIDataObject = NULL ;
  1302. }
  1303. if (FAILED(hr)) {
  1304. response = TS_CB_RESPONSE_FAIL;
  1305. }
  1306. CBM.open = FALSE ;
  1307. /************************************************************************/
  1308. // Now we can pass the response to the client
  1309. /************************************************************************/
  1310. clipRsp.msgType = TS_CB_FORMAT_LIST_RESPONSE;
  1311. clipRsp.msgFlags = response;
  1312. clipRsp.dataLen = 0;
  1313. fSuccess = CBMSendToClient(&clipRsp, sizeof(clipRsp));
  1314. TRC_NRM((TB, _T("Write to Client %s"), fSuccess ? _T("OK") : _T("failed")));
  1315. /************************************************************************/
  1316. /* Update the state according to how we got on */
  1317. /************************************************************************/
  1318. if (response == TS_CB_RESPONSE_OK)
  1319. {
  1320. CBM_SET_STATE(CBM_STATE_LOCAL_CB_OWNER, CBM_EVENT_FORMAT_LIST);
  1321. }
  1322. else
  1323. {
  1324. CBM_SET_STATE(CBM_STATE_CONNECTED, CBM_EVENT_FORMAT_LIST);
  1325. }
  1326. DC_EXIT_POINT:
  1327. DC_END_FN();
  1328. return;
  1329. } /* CBMOnFormatList */
  1330. /****************************************************************************/
  1331. /* CBMDisconnect - either the client has disconnected, or we have been */
  1332. /* closed */
  1333. /****************************************************************************/
  1334. DCVOID DCINTERNAL CBMDisconnect(DCVOID)
  1335. {
  1336. DC_BEGIN_FN("CBMDisconnect");
  1337. /************************************************************************/
  1338. /* If we are the local clipboard owner, then we must empty it - once */
  1339. /* disconnected, we won't be able to satisfy any further format */
  1340. /* requests. Note that we are still the local CB owner even if we are */
  1341. /* waiting on some data from the client */
  1342. /************************************************************************/
  1343. if ((CBM.state == CBM_STATE_LOCAL_CB_OWNER) ||
  1344. (CBM.state == CBM_STATE_PENDING_FORMAT_DATA_RSP))
  1345. {
  1346. TRC_NRM((TB, _T("Disable received while local CB owner")));
  1347. /********************************************************************/
  1348. /* Open the clipboard if needed */
  1349. /********************************************************************/
  1350. if (!CBM.open)
  1351. {
  1352. if (!OpenClipboard(CBM.viewerWindow))
  1353. {
  1354. TRC_SYSTEM_ERROR("OpenCB");
  1355. DC_QUIT;
  1356. }
  1357. CBM.open = TRUE;
  1358. }
  1359. /****************************************************************/
  1360. /* It was/is open */
  1361. /****************************************************************/
  1362. TRC_NRM((TB, _T("CB opened")));
  1363. CBM.open = TRUE;
  1364. /****************************************************************/
  1365. /* Empty it */
  1366. /****************************************************************/
  1367. if (!EmptyClipboard())
  1368. {
  1369. TRC_SYSTEM_ERROR("EmptyClipboard");
  1370. }
  1371. else
  1372. {
  1373. TRC_NRM((TB, _T("Clipboard emptied")));
  1374. }
  1375. }
  1376. /************************************************************************/
  1377. /* Ensure that we close the local CB */
  1378. /************************************************************************/
  1379. if (CBM.open)
  1380. {
  1381. if (!CloseClipboard())
  1382. {
  1383. TRC_SYSTEM_ERROR("CloseClipboard");
  1384. }
  1385. CBM.open = FALSE;
  1386. TRC_NRM((TB, _T("CB closed")));
  1387. }
  1388. /************************************************************************/
  1389. /* Virtual channel has been closed */
  1390. /************************************************************************/
  1391. CloseHandle(CBM.vcHandle);
  1392. CBM.vcHandle = NULL;
  1393. //
  1394. // Switch off the file clipboard redirection flag, otherwise if a client
  1395. // with drive redirection disabled connects, we will still attempt to
  1396. // send file copy formats.
  1397. //
  1398. CBM.fFileCutCopyOn = FALSE;
  1399. DC_EXIT_POINT:
  1400. /************************************************************************/
  1401. /* Update our state */
  1402. /************************************************************************/
  1403. CBM_SET_STATE(CBM_STATE_INITIALIZED, CBM_EVENT_DISCONNECT);
  1404. DC_END_FN();
  1405. return;
  1406. } /* CBMDisconnect */
  1407. /****************************************************************************/
  1408. /* CBMReconnect */
  1409. /****************************************************************************/
  1410. DCVOID DCINTERNAL CBMReconnect(DCVOID)
  1411. {
  1412. TS_CLIP_PDU clipRsp;
  1413. DC_BEGIN_FN("CBMReconnect");
  1414. SetEvent(CBM.GetDataSync[TS_RESET_EVENT]) ;
  1415. CBM_CHECK_STATE(CBM_EVENT_CONNECT);
  1416. CBM.vcHandle = NULL;
  1417. /************************************************************************/
  1418. /* Open our virtual channel */
  1419. /************************************************************************/
  1420. CBM.vcHandle = WinStationVirtualOpen(NULL, LOGONID_CURRENT, CLIP_CHANNEL);
  1421. if (CBM.vcHandle == NULL)
  1422. {
  1423. TRC_ERR((TB, _T("Failed to open virtual channel %S"), CLIP_CHANNEL));
  1424. DC_QUIT;
  1425. }
  1426. /************************************************************************/
  1427. /* Send the Monitor Ready message to the Client */
  1428. /************************************************************************/
  1429. clipRsp.msgType = TS_CB_MONITOR_READY;
  1430. clipRsp.msgFlags = 0;
  1431. clipRsp.dataLen = 0;
  1432. if (!CBMSendToClient(&clipRsp, sizeof(clipRsp)))
  1433. {
  1434. /********************************************************************/
  1435. /* Failed to send the Monitor Ready message. Clip redirection is */
  1436. /* not available. */
  1437. /********************************************************************/
  1438. TRC_ERR((TB, _T("Failed to send MONITOR_READY to Client - Exit")));
  1439. CloseHandle(CBM.vcHandle);
  1440. CBM.vcHandle = NULL;
  1441. DC_QUIT;
  1442. }
  1443. TRC_NRM((TB, _T("Sent MONITOR_READY to Client")));
  1444. /************************************************************************/
  1445. /* Client support is enabled - we're all set */
  1446. /************************************************************************/
  1447. CBM_SET_STATE(CBM_STATE_CONNECTED, CBM_EVENT_CONNECT);
  1448. DC_EXIT_POINT:
  1449. DC_END_FN();
  1450. return;
  1451. } /* CBMReconnect */
  1452. /****************************************************************************/
  1453. /* CBMTerm - terminate the Clipboard Monitor */
  1454. /**PROC-*********************************************************************/
  1455. DCVOID DCINTERNAL CBMTerm(DCVOID)
  1456. {
  1457. HRESULT hr ;
  1458. DC_BEGIN_FN("CBMTerm");
  1459. /************************************************************************/
  1460. /* Tell the second thread to end */
  1461. /************************************************************************/
  1462. if (CBM.readOL.hEvent)
  1463. {
  1464. TRC_NRM((TB, _T("Signalling thread to stop")));
  1465. CBM.runThread = FALSE;
  1466. SetEvent(CBM.readOL.hEvent);
  1467. /********************************************************************/
  1468. /* Give the second thread a chance to finish */
  1469. /********************************************************************/
  1470. TRC_NRM((TB, _T("Wait a sec ...")));
  1471. if ( NULL != CBM.hDataThread )
  1472. {
  1473. WaitForSingleObject( CBM.hDataThread, INFINITE );
  1474. CloseHandle( CBM.hDataThread );
  1475. CBM.hDataThread = NULL;
  1476. }
  1477. }
  1478. /************************************************************************/
  1479. /* Destroy the events */
  1480. /************************************************************************/
  1481. if (CBM.readOL.hEvent)
  1482. {
  1483. TRC_NRM((TB, _T("destroying read event %p"), CBM.readOL.hEvent));
  1484. if (!CloseHandle(CBM.readOL.hEvent))
  1485. {
  1486. TRC_SYSTEM_ERROR("CloseHandle");
  1487. }
  1488. CBM.readOL.hEvent = NULL;
  1489. }
  1490. if (CBM.writeOL.hEvent)
  1491. {
  1492. TRC_NRM((TB, _T("destroying write event %p"), CBM.writeOL.hEvent));
  1493. if (!CloseHandle(CBM.writeOL.hEvent))
  1494. {
  1495. TRC_SYSTEM_ERROR("CloseHandle");
  1496. }
  1497. CBM.writeOL.hEvent = NULL;
  1498. }
  1499. /************************************************************************/
  1500. /* Empty the clipboard if we own its contents */
  1501. /************************************************************************/
  1502. if (CBM.viewerWindow && (GetClipboardOwner() == CBM.viewerWindow))
  1503. {
  1504. TRC_NRM((TB, _T("We own the clipboard - empty it")));
  1505. hr = OleSetClipboard(NULL) ;
  1506. if (FAILED(hr)) {
  1507. TRC_SYSTEM_ERROR("Unable to clear clipboard") ;
  1508. }
  1509. }
  1510. if (CBM.pClipData)
  1511. {
  1512. CBM.pClipData->Release() ;
  1513. CBM.pClipData = NULL;
  1514. }
  1515. /************************************************************************/
  1516. /* Close thc clipboard if we have it open */
  1517. /************************************************************************/
  1518. if (CBM.open)
  1519. {
  1520. TRC_NRM((TB, _T("Close clipboard")));
  1521. if (!CloseClipboard())
  1522. {
  1523. TRC_SYSTEM_ERROR("CloseClipboard");
  1524. }
  1525. CBM.open = FALSE;
  1526. }
  1527. DC_EXIT_POINT:
  1528. DC_END_FN();
  1529. return;
  1530. } /* CBMTerm */
  1531. /****************************************************************************/
  1532. // CBMIsExcludedFormat - test to see if the suplied format is on our
  1533. // "banned list"
  1534. /****************************************************************************/
  1535. DCBOOL DCINTERNAL CBMIsExcludedFormat(PDCTCHAR formatName)
  1536. {
  1537. DCBOOL rc = FALSE;
  1538. DCINT i;
  1539. DC_BEGIN_FN("CBMIsExcludedFormat");
  1540. /************************************************************************/
  1541. /* check there is a format name - all banned formats have one! */
  1542. /************************************************************************/
  1543. if (*formatName == _T('\0'))
  1544. {
  1545. TRC_ALT((TB, _T("No format name supplied!")));
  1546. DC_QUIT;
  1547. }
  1548. /************************************************************************/
  1549. /* search the banned format list for the supplied format name */
  1550. /************************************************************************/
  1551. TRC_DBG((TB, _T("Looking at format '%s'"), formatName));
  1552. TRC_DATA_DBG("Format name data", formatName, TS_FORMAT_NAME_LEN);
  1553. if (CBM.fFileCutCopyOn)
  1554. {
  1555. for (i = 0; i < CBM_EXCLUDED_FORMAT_COUNT; i++)
  1556. {
  1557. TRC_DBG((TB, _T("comparing with '%s'"), cbmExcludedFormatList[i]));
  1558. if (DC_WSTRCMP((PDCWCHAR)formatName,
  1559. (PDCWCHAR)cbmExcludedFormatList[i]) == 0)
  1560. {
  1561. TRC_NRM((TB, _T("Found excluded format '%s'"), formatName));
  1562. rc = TRUE;
  1563. break;
  1564. }
  1565. }
  1566. }
  1567. else
  1568. {
  1569. for (i = 0; i < CBM_EXCLUDED_FORMAT_COUNT_NO_RD; i++)
  1570. {
  1571. TRC_DBG((TB, _T("comparing with '%s'"), cbmExcludedFormatList_NO_RD[i]));
  1572. if (DC_WSTRCMP((PDCWCHAR)formatName,
  1573. (PDCWCHAR)cbmExcludedFormatList[i]) == 0)
  1574. {
  1575. TRC_NRM((TB, _T("Found excluded format '%s'"), formatName));
  1576. rc = TRUE;
  1577. break;
  1578. }
  1579. }
  1580. }
  1581. DC_EXIT_POINT:
  1582. DC_END_FN();
  1583. return(rc);
  1584. } /* CBMIsExcludedFormat */
  1585. //
  1586. // CBMConvertToServerPath, CBMConvertToServerPathA, CBMConvertToServerPathW
  1587. // - Arguments:
  1588. // pOldData = Buffer containing the original file path
  1589. // pData = Buffer receiving the new file path
  1590. // - Returns S_OK if pOldData was a drive path
  1591. // E_FAIL if it failed
  1592. // - Given a file path with a colon, this function will strip out the old path,
  1593. // and prepend it with TS_PREPEND_STRING; otherwise, we just copy it over
  1594. // because we can already understand it
  1595. HRESULT CBMConvertToServerPath(PVOID pOldData, PVOID pData, size_t cbDest, BOOL wide)
  1596. {
  1597. HRESULT result ;
  1598. DC_BEGIN_FN("CBMConvertToServerPath") ;
  1599. if (!pOldData)
  1600. {
  1601. TRC_ERR((TB, _T("Original string pointer is NULL"))) ;
  1602. result = E_FAIL ;
  1603. DC_QUIT ;
  1604. }
  1605. if (!pData)
  1606. {
  1607. TRC_ERR((TB, _T("Destination string pointer is NULL"))) ;
  1608. result = E_FAIL ;
  1609. DC_QUIT ;
  1610. }
  1611. if (wide)
  1612. result = CBMConvertToServerPathW(pOldData, pData, cbDest) ;
  1613. else
  1614. result = CBMConvertToServerPathA(pOldData, pData, cbDest) ;
  1615. DC_EXIT_POINT:
  1616. DC_END_FN() ;
  1617. return result ;
  1618. }
  1619. HRESULT CBMConvertToServerPathW(PVOID pOldData, PVOID pData, size_t cbDest)
  1620. {
  1621. wchar_t* filePath ;
  1622. wchar_t* driveLetter ;
  1623. size_t driveLetterLength ;
  1624. HRESULT result = E_FAIL ;
  1625. DC_BEGIN_FN("CBMConvertToServerPathW") ;
  1626. // if this is a filepath with a drive letter
  1627. filePath = wcschr((wchar_t*)pOldData, L':') ;
  1628. if (filePath)
  1629. {
  1630. driveLetter = (wchar_t*)pOldData ;
  1631. result = StringCbCopyW( (wchar_t*)pData, cbDest, LTS_PREPEND_STRING) ;
  1632. DC_QUIT_ON_FAIL(result);
  1633. // Since there is actually a constant for the max
  1634. // drive letter length, we can't assume it will
  1635. // always be 1 character
  1636. driveLetterLength = (BYTE*)filePath - (BYTE*)driveLetter;
  1637. result = StringCbCatNW( (wchar_t*)pData, cbDest, driveLetter,
  1638. driveLetterLength);
  1639. DC_QUIT_ON_FAIL(result);
  1640. filePath = (wchar_t*) filePath + 1 ; // character after the ':'
  1641. result = StringCbCatW( (wchar_t*)pData, cbDest, filePath);
  1642. DC_QUIT_ON_FAIL(result);
  1643. TRC_NRM((TB,_T("New filename = %ls"), (wchar_t*)pData)) ;
  1644. result = S_OK ;
  1645. }
  1646. else
  1647. {
  1648. TRC_ERR((TB, _T("Not a filepath with drive letter. Nothing converted"))) ;
  1649. result = StringCbCopyW((wchar_t*)pData, cbDest, (wchar_t*)pOldData);
  1650. DC_QUIT_ON_FAIL(result);
  1651. result = E_FAIL ;
  1652. DC_QUIT ;
  1653. }
  1654. DC_EXIT_POINT:
  1655. if (FAILED(result)) {
  1656. TRC_ERR((TB,_T("Returning failure; hr=0x%x"), result));
  1657. }
  1658. DC_END_FN() ;
  1659. return result ;
  1660. }
  1661. HRESULT CBMConvertToServerPathA(PVOID pOldData, PVOID pData, size_t cbDest)
  1662. {
  1663. char* filePath ;
  1664. char* driveLetter ;
  1665. size_t driveLetterLength ;
  1666. HRESULT result = E_FAIL ;
  1667. DC_BEGIN_FN("CBMConvertToServerPathW") ;
  1668. // if this is a filepath with a drive letter
  1669. filePath = strchr((char*)pOldData, ':') ;
  1670. if (filePath)
  1671. {
  1672. driveLetter = (char*)pOldData ;
  1673. result = StringCbCopyA( (char*)pData, cbDest, TS_PREPEND_STRING) ;
  1674. DC_QUIT_ON_FAIL(result);
  1675. // Since there is actually a constant for the max
  1676. // drive letter length, we can't assume it will
  1677. // always be 1 character
  1678. driveLetterLength = (BYTE*)filePath - (BYTE*)driveLetter;
  1679. result = StringCbCatNA( (char*)pData, cbDest, driveLetter,
  1680. driveLetterLength);
  1681. DC_QUIT_ON_FAIL(result);
  1682. filePath = (char*) filePath + 1 ; // character after the ':'
  1683. result = StringCbCatA( (char*)pData, cbDest, filePath);
  1684. DC_QUIT_ON_FAIL(result);
  1685. result = S_OK ;
  1686. }
  1687. else
  1688. {
  1689. TRC_ERR((TB, _T("Not a filepath with drive letter. Nothing converted"))) ;
  1690. result = StringCbCopyA((char*)pData, cbDest, (char*)pOldData);
  1691. DC_QUIT_ON_FAIL(result);
  1692. result = E_FAIL ;
  1693. }
  1694. DC_EXIT_POINT:
  1695. if (FAILED(result)) {
  1696. TRC_ERR((TB,_T("Returning failure; 0x%x"), result));
  1697. }
  1698. DC_END_FN() ;
  1699. return result ;
  1700. }
  1701. //
  1702. // CBMGetNewDropfilesSizeForServer,
  1703. // CBMGetNewDropfilesSizeForServerW,
  1704. // CBMGetNewDropfilesSizeForServerA
  1705. // - Arguments:
  1706. // pData = Buffer containing a DROPFILES struct
  1707. // oldSize = The size of the DROPFILES struct
  1708. // wide = Wide or Ansi (TRUE if wide, FALSE if ansi)
  1709. // - Returns new size of the drop file
  1710. // 0 if it fails
  1711. // - Given a file path with drive letter, this function will calculate
  1712. // the needed space for the new string, when changed to \\tsclient
  1713. // format
  1714. //
  1715. //
  1716. // ***** NOTE *****
  1717. // - Currently, if the path is a network path, and not a drive path (C:\path)
  1718. // it simply fails
  1719. //
  1720. ULONG CBMGetNewDropfilesSizeForServer(PVOID pData, ULONG oldSize, BOOL wide)
  1721. {
  1722. DC_BEGIN_FN("CBMGetNewDropfilesSizeForServer") ;
  1723. if (wide)
  1724. return CBMGetNewDropfilesSizeForServerW(pData, oldSize) ;
  1725. else
  1726. return CBMGetNewDropfilesSizeForServerA(pData, oldSize) ;
  1727. DC_END_FN() ;
  1728. }
  1729. ULONG CBMGetNewDropfilesSizeForServerW(PVOID pData, ULONG oldSize)
  1730. {
  1731. ULONG newSize = oldSize ;
  1732. wchar_t* filenameW ;
  1733. wchar_t* filePathW ;
  1734. byte charSize ;
  1735. DC_BEGIN_FN("CBMGetNewDropfilesSizeForServerW") ;
  1736. charSize = sizeof(wchar_t) ;
  1737. if (!pData)
  1738. {
  1739. TRC_ERR((TB,_T("Pointer to dropfile is NULL"))) ;
  1740. return 0 ;
  1741. }
  1742. // The start of the first filename
  1743. filenameW = (wchar_t*) ((byte*) pData + ((DROPFILES*) pData)->pFiles) ;
  1744. while (L'\0' != filenameW[0])
  1745. {
  1746. TRC_NRM((TB,_T("First filename = %ls"), filenameW)) ;
  1747. filePathW = wcschr(filenameW, L':') ;
  1748. // If the file path has a colon in it, then it's a drive path
  1749. if (filePathW)
  1750. {
  1751. // we add space for (TS_PREPEND_LENGTH - 1) characters because
  1752. // although we are adding TS_PREPEND_LENGTH characters, we are
  1753. // stripping out the colon from the filepath
  1754. newSize = newSize + (TS_PREPEND_LENGTH - 1) * charSize ;
  1755. // going from c:\foo.txt -> \\tsclient\c\foo.txt adds
  1756. // \\tsclient\ and subtracts :
  1757. }
  1758. else
  1759. {
  1760. TRC_ERR((TB,_T("Bad path"))) ;
  1761. return 0 ;
  1762. }
  1763. filenameW = filenameW + (wcslen((wchar_t*)filenameW) + 1) ;
  1764. }
  1765. DC_END_FN() ;
  1766. return newSize ;
  1767. }
  1768. ULONG CBMGetNewDropfilesSizeForServerA(PVOID pData, ULONG oldSize)
  1769. {
  1770. ULONG newSize = oldSize ;
  1771. char* filename ;
  1772. char* filePath ;
  1773. byte charSize ;
  1774. DC_BEGIN_FN("CBMGetNewDropfilesSizeForServerW") ;
  1775. charSize = sizeof(wchar_t) ;
  1776. if (!pData)
  1777. {
  1778. TRC_ERR((TB,_T("Pointer to dropfile is NULL"))) ;
  1779. return 0 ;
  1780. }
  1781. // The start of the first filename
  1782. filename = (char*) ((byte*) pData + ((DROPFILES*) pData)->pFiles) ;
  1783. while ('\0' != filename[0])
  1784. {
  1785. filePath = strchr(filename, ':') ;
  1786. // If the file path has a colon in it, then its a drive path
  1787. if (filePath)
  1788. {
  1789. // we add space for (TS_PREPEND_LENGTH - 1) characters because
  1790. // although we are adding TS_PREPEND_LENGTH characters, we are
  1791. // stripping out the colon from the filepath
  1792. newSize = newSize + (TS_PREPEND_LENGTH - 1) * charSize ;
  1793. // going from c:\foo.txt -> \\tsclient\c\foo.txt adds
  1794. // \\tsclient\ and subtracts :
  1795. }
  1796. else
  1797. {
  1798. TRC_ERR((TB,_T("Bad path"))) ;
  1799. return 0 ;
  1800. }
  1801. filename = filename + (strlen(filename) + 1) ;
  1802. }
  1803. DC_END_FN() ;
  1804. return newSize ;
  1805. }
  1806. DCINT DCAPI CBMGetData (DCUINT cfFormat)
  1807. {
  1808. PTS_CLIP_PDU pClipPDU = NULL;
  1809. DCUINT32 pduLen;
  1810. DCUINT32 dataLen;
  1811. PDCUINT32 pFormatID;
  1812. DCUINT8 clipRsp[sizeof(TS_CLIP_PDU) + sizeof(DCUINT32)];
  1813. BOOL success = 0 ;
  1814. DC_BEGIN_FN("ClipGetData");
  1815. CBM_CHECK_STATE(CBM_EVENT_WM_RENDERFORMAT);
  1816. // Record the requested format
  1817. CBM.pendingServerID = cfFormat ;
  1818. CBM.pendingClientID = CBMRemoteFormatFromLocalID(CBM.pendingServerID);
  1819. // if we don't get a valid client ID, then fail
  1820. if (!CBM.pendingClientID)
  1821. {
  1822. TRC_NRM((TB, _T("Server format %d not supported/found. Failing"), CBM.pendingServerID)) ;
  1823. DC_QUIT ;
  1824. }
  1825. TRC_NRM((TB, _T("Render format received for %d (client ID %d)"),
  1826. CBM.pendingServerID, CBM.pendingClientID));
  1827. dataLen = sizeof(DCUINT32);
  1828. pduLen = sizeof(TS_CLIP_PDU) + dataLen;
  1829. // We can use the permanent send buffer for this
  1830. TRC_NRM((TB, _T("Get perm TX buffer"))) ;
  1831. pClipPDU = (PTS_CLIP_PDU)(&clipRsp) ;
  1832. DC_MEMSET(pClipPDU, 0, sizeof(*pClipPDU)) ;
  1833. pClipPDU->msgType = TS_CB_FORMAT_DATA_REQUEST ;
  1834. pClipPDU->dataLen = dataLen ;
  1835. pFormatID = (PDCUINT32)(pClipPDU->data) ;
  1836. *pFormatID = (DCUINT32)CBM.pendingClientID ;
  1837. // Reset the TS_RECEIVE_COMPLETED event since we expect it to be signaled
  1838. // if any data is received from the client.
  1839. ResetEvent(CBM.GetDataSync[TS_RECEIVE_COMPLETED]);
  1840. // Send the PDU
  1841. TRC_NRM((TB, _T("Sending format data request"))) ;
  1842. success = CBMSendToClient(pClipPDU, sizeof(TS_CLIP_PDU) + sizeof(DCUINT32)) ;
  1843. DC_EXIT_POINT:
  1844. // Update the state if successful
  1845. if (success)
  1846. CBM_SET_STATE(CBM_STATE_PENDING_FORMAT_DATA_RSP, CBM_EVENT_WM_RENDERFORMAT) ;
  1847. DC_END_FN() ;
  1848. return success ;
  1849. }
  1850. CClipData::CClipData()
  1851. {
  1852. DC_BEGIN_FN("CClipData") ;
  1853. _cRef = 0 ;
  1854. _pImpIDataObject = NULL ;
  1855. DC_END_FN();
  1856. }
  1857. CClipData::~CClipData(void)
  1858. {
  1859. DC_BEGIN_FN("~CClipData");
  1860. if (_pImpIDataObject != NULL)
  1861. {
  1862. _pImpIDataObject->Release();
  1863. _pImpIDataObject = NULL;
  1864. }
  1865. DC_END_FN();
  1866. }
  1867. HRESULT DCINTERNAL CClipData::SetNumFormats(ULONG numFormats)
  1868. {
  1869. DC_BEGIN_FN("SetNumFormats");
  1870. HRESULT hr = S_OK;
  1871. if (_pImpIDataObject)
  1872. {
  1873. _pImpIDataObject->Release();
  1874. _pImpIDataObject = NULL;
  1875. }
  1876. _pImpIDataObject = new CImpIDataObject(this) ;
  1877. if (_pImpIDataObject != NULL) {
  1878. _pImpIDataObject->AddRef() ;
  1879. hr = _pImpIDataObject->Init(numFormats) ;
  1880. DC_QUIT_ON_FAIL(hr);
  1881. }
  1882. else {
  1883. TRC_ERR((TB,_T("Unable to create IDataObject")));
  1884. hr = E_OUTOFMEMORY;
  1885. DC_QUIT;
  1886. }
  1887. DC_EXIT_POINT:
  1888. DC_END_FN();
  1889. return hr;
  1890. }
  1891. DCVOID CClipData::SetClipData(HGLOBAL hGlobal, DCUINT clipType)
  1892. {
  1893. DC_BEGIN_FN("SetClipData");
  1894. if (_pImpIDataObject != NULL) {
  1895. _pImpIDataObject->SetClipData(hGlobal, clipType) ;
  1896. }
  1897. DC_END_FN();
  1898. }
  1899. STDMETHODIMP CClipData::QueryInterface(REFIID riid, PPVOID ppv)
  1900. {
  1901. DC_BEGIN_FN("QueryInterface");
  1902. //set ppv to NULL just in case the interface isn't found
  1903. *ppv=NULL;
  1904. if (IID_IUnknown==riid)
  1905. *ppv=this;
  1906. if (IID_IDataObject==riid)
  1907. *ppv=_pImpIDataObject ;
  1908. if (NULL==*ppv)
  1909. return ResultFromScode(E_NOINTERFACE);
  1910. //AddRef any interface we'll return.
  1911. ((LPUNKNOWN)*ppv)->AddRef();
  1912. DC_END_FN();
  1913. return NOERROR;
  1914. }
  1915. STDMETHODIMP_(ULONG) CClipData::AddRef(void)
  1916. {
  1917. LONG cRef;
  1918. DC_BEGIN_FN("AddRef");
  1919. cRef = InterlockedIncrement(&_cRef) ;
  1920. DC_END_FN();
  1921. return cRef ;
  1922. }
  1923. STDMETHODIMP_(ULONG) CClipData::Release(void)
  1924. {
  1925. LONG cRef;
  1926. DC_BEGIN_FN("CClipData::Release");
  1927. cRef = InterlockedDecrement(&_cRef);
  1928. if (cRef == 0)
  1929. {
  1930. delete this;
  1931. }
  1932. DC_END_FN();
  1933. return cRef;
  1934. }
  1935. CImpIDataObject::CImpIDataObject(LPUNKNOWN lpUnk)
  1936. {
  1937. DC_BEGIN_FN("CImplDataObject") ;
  1938. _numFormats = 0 ;
  1939. _maxNumFormats = 0 ;
  1940. _cRef = 0 ;
  1941. _pUnkOuter = lpUnk ;
  1942. if (_pUnkOuter)
  1943. {
  1944. _pUnkOuter->AddRef();
  1945. }
  1946. _pFormats = NULL ;
  1947. _pSTGMEDIUM = NULL ;
  1948. _lastFormatRequested = 0 ;
  1949. _dropEffect = FO_COPY ;
  1950. _cfDropEffect = (CLIPFORMAT) RegisterClipboardFormat(CFSTR_PREFERREDDROPEFFECT) ;
  1951. _fAlreadyCopied = FALSE ;
  1952. DC_END_FN();
  1953. }
  1954. HRESULT CImpIDataObject::Init(ULONG numFormats)
  1955. {
  1956. DC_BEGIN_FN("Init");
  1957. HRESULT hr = S_OK;
  1958. _maxNumFormats = numFormats ;
  1959. // Allocate space for the formats only
  1960. if (_pFormats) {
  1961. LocalFree(_pFormats);
  1962. }
  1963. _pFormats = (LPFORMATETC) LocalAlloc(LPTR, _maxNumFormats*sizeof(FORMATETC)) ;
  1964. if (NULL == _pFormats) {
  1965. TRC_ERR((TB,_T("Failed to allocate _pFormats")));
  1966. hr = E_OUTOFMEMORY;
  1967. DC_QUIT;
  1968. }
  1969. if (_pSTGMEDIUM) {
  1970. LocalFree(_pSTGMEDIUM);
  1971. }
  1972. _pSTGMEDIUM = (STGMEDIUM*) LocalAlloc(LPTR, sizeof(STGMEDIUM)) ;
  1973. if (NULL == _pFormats) {
  1974. TRC_ERR((TB,_T("Failed to allocate STGMEDIUM")));
  1975. hr = E_OUTOFMEMORY;
  1976. DC_QUIT;
  1977. }
  1978. if (_pSTGMEDIUM != NULL) {
  1979. _pSTGMEDIUM->tymed = TYMED_HGLOBAL ;
  1980. _pSTGMEDIUM->pUnkForRelease = NULL ;
  1981. _pSTGMEDIUM->hGlobal = NULL ;
  1982. }
  1983. _uiSTGType = 0;
  1984. DC_EXIT_POINT:
  1985. if (FAILED(hr)) {
  1986. _maxNumFormats = 0;
  1987. }
  1988. DC_END_FN() ;
  1989. return hr;
  1990. }
  1991. DCVOID CImpIDataObject::SetClipData(HGLOBAL hGlobal, DCUINT clipType)
  1992. {
  1993. DC_BEGIN_FN("SetClipData");
  1994. if (!_pSTGMEDIUM)
  1995. _pSTGMEDIUM = (STGMEDIUM*) LocalAlloc(LPTR, sizeof(STGMEDIUM)) ;
  1996. if (_pSTGMEDIUM)
  1997. {
  1998. if (CF_PALETTE == clipType) {
  1999. _pSTGMEDIUM->tymed = TYMED_GDI ;
  2000. }
  2001. else if (CF_METAFILEPICT == clipType) {
  2002. _pSTGMEDIUM->tymed = TYMED_MFPICT;
  2003. }
  2004. else {
  2005. _pSTGMEDIUM->tymed = TYMED_HGLOBAL ;
  2006. }
  2007. _pSTGMEDIUM->pUnkForRelease = NULL ;
  2008. FreeSTGMEDIUM();
  2009. _pSTGMEDIUM->hGlobal = hGlobal ;
  2010. _uiSTGType = clipType;
  2011. }
  2012. DC_END_FN();
  2013. }
  2014. DCVOID
  2015. CImpIDataObject::FreeSTGMEDIUM(void)
  2016. {
  2017. if ( NULL == _pSTGMEDIUM->hGlobal )
  2018. {
  2019. return;
  2020. }
  2021. switch( _uiSTGType )
  2022. {
  2023. case CF_PALETTE:
  2024. DeleteObject( _pSTGMEDIUM->hGlobal );
  2025. break;
  2026. case CF_METAFILEPICT:
  2027. {
  2028. LPMETAFILEPICT pMFPict = (LPMETAFILEPICT)GlobalLock( _pSTGMEDIUM->hGlobal );
  2029. if ( NULL != pMFPict )
  2030. {
  2031. if ( NULL != pMFPict->hMF )
  2032. {
  2033. DeleteMetaFile( pMFPict->hMF );
  2034. }
  2035. GlobalUnlock( _pSTGMEDIUM->hGlobal );
  2036. }
  2037. GlobalFree( _pSTGMEDIUM->hGlobal );
  2038. }
  2039. break;
  2040. default:
  2041. GlobalFree( _pSTGMEDIUM->hGlobal );
  2042. }
  2043. _pSTGMEDIUM->hGlobal = NULL;
  2044. }
  2045. CImpIDataObject::~CImpIDataObject(void)
  2046. {
  2047. DC_BEGIN_FN("~CImplDataObject") ;
  2048. if (_pFormats)
  2049. LocalFree(_pFormats) ;
  2050. if (_pSTGMEDIUM)
  2051. {
  2052. FreeSTGMEDIUM();
  2053. LocalFree(_pSTGMEDIUM) ;
  2054. }
  2055. if (_pUnkOuter)
  2056. {
  2057. _pUnkOuter->Release();
  2058. _pUnkOuter = NULL;
  2059. }
  2060. DC_END_FN();
  2061. }
  2062. // IUnknown members
  2063. // - Delegate to "outer" IUnknown
  2064. STDMETHODIMP CImpIDataObject::QueryInterface(REFIID riid, PPVOID ppv)
  2065. {
  2066. DC_BEGIN_FN("QueryInterface");
  2067. DC_END_FN();
  2068. return _pUnkOuter->QueryInterface(riid, ppv);
  2069. }
  2070. STDMETHODIMP_(ULONG) CImpIDataObject::AddRef(void)
  2071. {
  2072. DC_BEGIN_FN("AddRef");
  2073. InterlockedIncrement(&_cRef);
  2074. DC_END_FN();
  2075. return _pUnkOuter->AddRef();
  2076. }
  2077. STDMETHODIMP_(ULONG) CImpIDataObject::Release(void)
  2078. {
  2079. LONG cRef;
  2080. DC_BEGIN_FN("CImpIDataObject::Release");
  2081. _pUnkOuter->Release();
  2082. cRef = InterlockedDecrement(&_cRef) ;
  2083. if (cRef == 0)
  2084. {
  2085. delete this;
  2086. }
  2087. DC_END_FN() ;
  2088. return 0;
  2089. }
  2090. // IDataObject members
  2091. // ***************************************************************************
  2092. // CImpIDataObject::GetData
  2093. // - Here, we have to wait for the data to actually get here before we return.
  2094. // ***************************************************************************
  2095. STDMETHODIMP CImpIDataObject::GetData(LPFORMATETC pFE, LPSTGMEDIUM pSTM)
  2096. {
  2097. HRESULT result = E_FAIL; // Assume we fail until we know we haven't
  2098. TCHAR formatName[TS_FORMAT_NAME_LEN] ;
  2099. HGLOBAL hData = NULL ;
  2100. HPDCVOID pData ;
  2101. HPDCVOID pOldData ;
  2102. HPDCVOID pFilename ;
  2103. HPDCVOID pOldFilename ;
  2104. ULONG oldSize ;
  2105. ULONG newSize ;
  2106. byte charSize ;
  2107. DWORD eventSignaled ;
  2108. BOOL wide ;
  2109. DWORD* pDropEffect ;
  2110. DROPFILES tempDropfile ;
  2111. char* fileList ;
  2112. wchar_t* fileListW ;
  2113. HRESULT hr;
  2114. DC_BEGIN_FN("GetData");
  2115. if (!_pSTGMEDIUM)
  2116. {
  2117. TRC_ERR((TB, _T("Transfer medium (STGMEDIUM) is NULL"))) ;
  2118. DC_QUIT ;
  2119. }
  2120. if (!_pSTGMEDIUM->hGlobal || (pFE->cfFormat != _lastFormatRequested))
  2121. {
  2122. ResetEvent(CBM.GetDataSync[TS_RESET_EVENT]) ;
  2123. ResetEvent(CBM.GetDataSync[TS_DISCONNECT_EVENT]) ;
  2124. if (!CBMGetData(pFE->cfFormat))
  2125. DC_QUIT ;
  2126. do {
  2127. eventSignaled = WaitForMultipleObjects(
  2128. TS_NUM_EVENTS,
  2129. CBM.GetDataSync,
  2130. FALSE,
  2131. INFINITE);
  2132. } while (eventSignaled == (WAIT_OBJECT_0)) ;
  2133. TRC_NRM((TB, _T("EventSignaled = %d; GetLastError = %d"), eventSignaled, GetLastError())) ;
  2134. if ((WAIT_OBJECT_0 + TS_RESET_EVENT) == eventSignaled)
  2135. {
  2136. ResetEvent(CBM.GetDataSync[TS_RESET_EVENT]) ;
  2137. result = E_FAIL ;
  2138. DC_QUIT ;
  2139. } else if ((WAIT_OBJECT_0 + TS_DISCONNECT_EVENT) == eventSignaled) {
  2140. ResetEvent(CBM.GetDataSync[TS_DISCONNECT_EVENT]) ;
  2141. CBM_SET_STATE(CBM_STATE_INITIALIZED, CBM_EVENT_DISCONNECT);
  2142. result = E_FAIL ;
  2143. DC_QUIT ;
  2144. }
  2145. // Make sure that we actually got data from the client.
  2146. if (_pSTGMEDIUM->hGlobal == NULL) {
  2147. TRC_ERR((TB, _T("No format data received from client!")));
  2148. result = E_FAIL;
  2149. DC_QUIT;
  2150. }
  2151. // We check the dropeffect format, because we strip out
  2152. // shortcuts/links, and store the dropeffects. The dropeffect is
  2153. // what some apps (explorer) use to decide if they should copy, move
  2154. // or link
  2155. if (_cfDropEffect == pFE->cfFormat)
  2156. {
  2157. if (GlobalSize(_pSTGMEDIUM->hGlobal) < sizeof(DWORD)) {
  2158. TRC_ERR((TB, _T("Unexpected global memory size!")));
  2159. result = E_FAIL;
  2160. DC_QUIT;
  2161. }
  2162. pDropEffect = (DWORD*) GlobalLock(_pSTGMEDIUM->hGlobal) ;
  2163. if (!pDropEffect)
  2164. {
  2165. TRC_ERR((TB, _T("Unable to lock %p"), _pSTGMEDIUM->hGlobal)) ;
  2166. _pSTGMEDIUM->hGlobal = NULL ;
  2167. DC_QUIT ;
  2168. }
  2169. // We strip shortcuts and moves this way
  2170. *pDropEffect = *pDropEffect ^ DROPEFFECT_LINK ;
  2171. *pDropEffect = *pDropEffect ^ DROPEFFECT_MOVE ;
  2172. CBM.dropEffect = *pDropEffect ;
  2173. GlobalUnlock(_pSTGMEDIUM->hGlobal) ;
  2174. pSTM->tymed = _pSTGMEDIUM->tymed ;
  2175. pSTM->hGlobal = _pSTGMEDIUM->hGlobal ;
  2176. // bugbug
  2177. _pSTGMEDIUM->hGlobal = NULL;
  2178. // bugbug: end
  2179. pSTM->pUnkForRelease = _pSTGMEDIUM->pUnkForRelease ;
  2180. result = S_OK ;
  2181. DC_QUIT ;
  2182. }
  2183. else if (CF_HDROP == pFE->cfFormat)
  2184. {
  2185. BYTE *pbLastByte, *pbStartByte, *pbLastPossibleNullStart, charSize;
  2186. BOOL fTrailingFileNamesValid;
  2187. SIZE_T cbDropFiles;
  2188. //
  2189. // Make sure that we have at least a DROPFILES structure in
  2190. // memory.
  2191. cbDropFiles = GlobalSize(_pSTGMEDIUM->hGlobal);
  2192. if (cbDropFiles < sizeof(DROPFILES)) {
  2193. TRC_ERR((TB, _T("Unexpected global memory size!")));
  2194. result = E_FAIL;
  2195. DC_QUIT;
  2196. }
  2197. pOldData = GlobalLock(_pSTGMEDIUM->hGlobal) ;
  2198. if (!pOldData)
  2199. {
  2200. TRC_ERR((TB, _T("Unable to lock %p"), _pSTGMEDIUM->hGlobal)) ;
  2201. _pSTGMEDIUM->hGlobal = NULL ;
  2202. DC_QUIT ;
  2203. }
  2204. wide = ((DROPFILES*) pOldData)->fWide ;
  2205. //
  2206. // Check that the data behind the DROPFILES data structure
  2207. // pointed to by pDropFiles is valid. Every drop file list
  2208. // is terminated by two NULL characters. So, simply scan
  2209. // through the memory after the DROPFILES structure and make sure
  2210. // that there is a double NULL before the last byte.
  2211. //
  2212. if (((DROPFILES*) pOldData)->pFiles < sizeof(DROPFILES)
  2213. || ((DROPFILES*) pOldData)->pFiles > cbDropFiles) {
  2214. TRC_ERR((TB,_T("File name offset invalid!"))) ;
  2215. result = E_FAIL;
  2216. DC_QUIT;
  2217. }
  2218. pbStartByte = (BYTE*) pOldData + ((DROPFILES*) pOldData)->pFiles;
  2219. pbLastByte = (BYTE*) pOldData + cbDropFiles - 1;
  2220. fTrailingFileNamesValid = FALSE;
  2221. charSize = wide ? sizeof(WCHAR) : sizeof(CHAR);
  2222. //
  2223. // Make pbLastPossibleNullStart point to the last place where a
  2224. // double NULL could possibly start.
  2225. //
  2226. // Examples: Assume pbLastByte = 9
  2227. // Then for ASCII: pbLastPossibleNullStart = 8 (9 - 2 * 1 + 1)
  2228. // And for UNICODE: pbLastPossibleNullStart = 6 (9 - 2 * 2 + 1)
  2229. //
  2230. pbLastPossibleNullStart = pbLastByte - (2 * charSize) + 1;
  2231. if (wide) {
  2232. for (WCHAR* pwch = (WCHAR*) pbStartByte; (BYTE*) pwch <= pbLastPossibleNullStart; pwch++) {
  2233. if (*pwch == NULL && *(pwch + 1) == NULL) {
  2234. fTrailingFileNamesValid = TRUE;
  2235. }
  2236. }
  2237. } else {
  2238. for (BYTE* pch = pbStartByte; pch <= pbLastPossibleNullStart; pch++) {
  2239. if (*pch == NULL && *(pch + 1) == NULL) {
  2240. fTrailingFileNamesValid = TRUE;
  2241. }
  2242. }
  2243. }
  2244. if (!fTrailingFileNamesValid) {
  2245. TRC_ERR((TB,_T("DROPFILES structure invalid!"))) ;
  2246. result = E_FAIL;
  2247. DC_QUIT;
  2248. }
  2249. //
  2250. // DROPFILES are valid so we can continue.
  2251. //
  2252. oldSize = (ULONG) GlobalSize(_pSTGMEDIUM->hGlobal) ;
  2253. newSize = CBMGetNewDropfilesSizeForServer(pOldData, oldSize, wide) ;
  2254. if (!newSize)
  2255. {
  2256. TRC_ERR((TB, _T("Unable to parse DROPFILES"))) ;
  2257. }
  2258. else
  2259. {
  2260. TRC_NRM((TB, _T("DROPFILES Old size= %d New size = %d"),
  2261. GlobalSize(_pSTGMEDIUM->hGlobal), newSize)) ;
  2262. }
  2263. hData = GlobalAlloc(GMEM_DISCARDABLE | GMEM_MOVEABLE,
  2264. newSize) ;
  2265. if (!hData)
  2266. {
  2267. TRC_ERR((TB, _T("Failed to alloc %ld bytes"),
  2268. hData, newSize));
  2269. GlobalFree(hData);
  2270. hData = NULL;
  2271. return E_FAIL ;
  2272. }
  2273. pData = GlobalLock(hData) ;
  2274. if (!pData)
  2275. {
  2276. TRC_ERR((TB, _T("Failed to lock %p (%ld bytes)"),
  2277. pData, newSize));
  2278. return E_FAIL ;
  2279. }
  2280. ((DROPFILES*) pData)->pFiles = ((DROPFILES*) pOldData)->pFiles ;
  2281. ((DROPFILES*) pData)->pt = ((DROPFILES*) pOldData)->pt ;
  2282. ((DROPFILES*) pData)->fNC = ((DROPFILES*) pOldData)->fNC ;
  2283. ((DROPFILES*) pData)->fWide = ((DROPFILES*) pOldData)->fWide ;
  2284. pOldFilename = (byte*) pOldData + ((DROPFILES*) pOldData)->pFiles ;
  2285. pFilename = (byte*) pData + ((DROPFILES*) pData)->pFiles ;
  2286. // We keep looping until the current
  2287. if (wide)
  2288. {
  2289. while (L'\0' != ((wchar_t*) pOldFilename)[0])
  2290. {
  2291. if ( (ULONG)((BYTE*)pFilename - (BYTE*)pData) > newSize) {
  2292. TRC_ERR((TB,_T("Out of space, failed to convert")));
  2293. result = E_FAIL;
  2294. GlobalUnlock(hData) ;
  2295. GlobalUnlock(_pSTGMEDIUM->hGlobal) ;
  2296. DC_QUIT;
  2297. }
  2298. if (S_OK != CBMConvertToServerPath(pOldFilename, pFilename,
  2299. newSize - ((BYTE*)pFilename - (BYTE*)pData), wide))
  2300. {
  2301. TRC_ERR((TB, _T("Failed conversion"))) ;
  2302. result = E_FAIL ;
  2303. GlobalUnlock(hData) ;
  2304. GlobalUnlock(_pSTGMEDIUM->hGlobal) ;
  2305. DC_QUIT ;
  2306. }
  2307. TRC_NRM((TB,_T("oldname %ls; newname %ls"), (wchar_t*)pOldFilename, (wchar_t*)pFilename)) ;
  2308. pOldFilename = (byte*) pOldFilename + (wcslen((wchar_t*)pOldFilename) + 1) * sizeof(wchar_t) ;
  2309. pFilename = (byte*) pFilename + (wcslen((wchar_t*)pFilename) + 1) * sizeof(wchar_t) ;
  2310. }
  2311. }
  2312. else
  2313. {
  2314. while ('\0' != ((char*) pOldFilename)[0])
  2315. {
  2316. if ( (ULONG)((BYTE*)pFilename - (BYTE*)pData) > newSize) {
  2317. TRC_ERR((TB,_T("Out of space, failed to convert")));
  2318. result = E_FAIL;
  2319. GlobalUnlock(hData) ;
  2320. GlobalUnlock(_pSTGMEDIUM->hGlobal) ;
  2321. DC_QUIT;
  2322. }
  2323. if (S_OK != CBMConvertToServerPath(pOldFilename, pFilename,
  2324. newSize - ((BYTE*)pFilename - (BYTE*)pData), wide))
  2325. {
  2326. TRC_ERR((TB, _T("Failed conversion"))) ;
  2327. result = E_FAIL ;
  2328. GlobalUnlock(hData) ;
  2329. GlobalUnlock(_pSTGMEDIUM->hGlobal) ;
  2330. DC_QUIT ;
  2331. }
  2332. TRC_NRM((TB,_T("oldname %hs; newname %hs"), (char*)pOldFilename, (char*)pFilename)) ;
  2333. pOldFilename = (byte*) pOldFilename + (strlen((char*)pOldFilename) + 1) * sizeof(char) ;
  2334. pFilename = (byte*) pFilename + (strlen((char*)pFilename) + 1) * sizeof(char) ;
  2335. }
  2336. }
  2337. if (wide)
  2338. {
  2339. (((wchar_t*) pFilename)[0]) = L'\0';
  2340. }
  2341. else
  2342. {
  2343. (((char*) pFilename)[0]) = '\0';
  2344. }
  2345. GlobalUnlock(hData) ;
  2346. GlobalUnlock(_pSTGMEDIUM->hGlobal) ;
  2347. pSTM->tymed = _pSTGMEDIUM->tymed ;
  2348. pSTM->hGlobal = hData ;
  2349. pSTM->pUnkForRelease = _pSTGMEDIUM->pUnkForRelease ;
  2350. result = S_OK ;
  2351. DC_QUIT ;
  2352. }
  2353. else
  2354. {
  2355. DC_MEMSET(formatName, 0, TS_FORMAT_NAME_LEN*sizeof(TCHAR));
  2356. if (0 != GetClipboardFormatName(pFE->cfFormat, formatName,
  2357. TS_FORMAT_NAME_LEN))
  2358. {
  2359. // if the remote system is requesting a filename, then we
  2360. // must translate the path from Driveletter:\path to
  2361. // \\tsclient\Driveletter\path before we hand this off
  2362. if ((0 == _tcscmp(formatName, TEXT("FileName"))) ||
  2363. (0 == _tcscmp(formatName, TEXT("FileNameW"))))
  2364. {
  2365. if (0 == _tcscmp(formatName, TEXT("FileNameW")))
  2366. {
  2367. wide = TRUE ;
  2368. charSize = sizeof(wchar_t);
  2369. }
  2370. else
  2371. {
  2372. wide = FALSE ;
  2373. charSize = sizeof(char);
  2374. }
  2375. pOldFilename = GlobalLock(_pSTGMEDIUM->hGlobal) ;
  2376. if (pOldFilename != NULL)
  2377. {
  2378. //
  2379. // Check that pOldFilename is NULL terminated.
  2380. //
  2381. size_t cbMaxOldFileName, cbOldFileName;
  2382. cbMaxOldFileName = (ULONG) GlobalSize(_pSTGMEDIUM->hGlobal);
  2383. if (wide) {
  2384. hr = StringCbLengthW((WCHAR*) pOldFilename,
  2385. cbMaxOldFileName,
  2386. &cbOldFileName);
  2387. } else {
  2388. hr = StringCbLengthA((CHAR*) pOldFilename,
  2389. cbMaxOldFileName,
  2390. &cbOldFileName);
  2391. }
  2392. if (FAILED(hr)) {
  2393. TRC_ERR((TB, _T("File name not NULL terminated!")));
  2394. result = E_FAIL;
  2395. DC_QUIT;
  2396. }
  2397. //
  2398. // We are now assured that pOldFilename is NULL terminated
  2399. // and can continue.
  2400. //
  2401. newSize = cbMaxOldFileName + (TS_PREPEND_LENGTH - 1) * charSize;
  2402. hData = GlobalAlloc(GMEM_DISCARDABLE | GMEM_MOVEABLE, newSize);
  2403. if (hData != NULL)
  2404. {
  2405. pFilename = GlobalLock(hData);
  2406. if (pFilename != NULL)
  2407. {
  2408. if (S_OK != CBMConvertToServerPath(pOldFilename,
  2409. pFilename, newSize, wide))
  2410. {
  2411. TRC_ERR((TB, _T("Failed filename conversion"))) ;
  2412. }
  2413. GlobalUnlock(hData) ;
  2414. GlobalFree(_pSTGMEDIUM->hGlobal) ;
  2415. _pSTGMEDIUM->hGlobal = hData ;
  2416. }
  2417. else
  2418. {
  2419. TRC_ERR((TB, _T("Failed to lock %p (%ld bytes)"),
  2420. hData, newSize));
  2421. GlobalFree(hData);
  2422. hData = NULL;
  2423. return E_FAIL ;
  2424. }
  2425. }
  2426. else
  2427. {
  2428. TRC_ERR((TB, _T("Failed to alloc %ld bytes"), newSize));
  2429. return E_FAIL;
  2430. }
  2431. }
  2432. else
  2433. {
  2434. TRC_ERR((TB, _T("Failed to lock %p"),
  2435. _pSTGMEDIUM->hGlobal)) ;
  2436. return E_FAIL ;
  2437. }
  2438. }
  2439. }
  2440. else {
  2441. TRC_NRM((TB,_T("Requested format %d"), pFE->cfFormat)) ;
  2442. }
  2443. pSTM->tymed = _pSTGMEDIUM->tymed ;
  2444. pSTM->hGlobal = _pSTGMEDIUM->hGlobal ;
  2445. // bugbug
  2446. _pSTGMEDIUM->hGlobal = NULL;
  2447. // bugbug: end
  2448. pSTM->pUnkForRelease = _pSTGMEDIUM->pUnkForRelease ;
  2449. result = S_OK ;
  2450. }
  2451. }
  2452. else
  2453. {
  2454. pSTM->tymed = _pSTGMEDIUM->tymed ;
  2455. pSTM->hGlobal = GlobalAlloc(GMEM_DISCARDABLE | GMEM_MOVEABLE,
  2456. GlobalSize(_pSTGMEDIUM->hGlobal)) ;
  2457. pData = GlobalLock(pSTM->hGlobal) ;
  2458. pOldData = GlobalLock(_pSTGMEDIUM->hGlobal) ;
  2459. if (!pData || !pOldData) {
  2460. return E_FAIL ;
  2461. }
  2462. DC_MEMCPY(pData, pOldData, GlobalSize(_pSTGMEDIUM->hGlobal)) ;
  2463. GlobalUnlock(pSTM->hGlobal) ;
  2464. GlobalUnlock(_pSTGMEDIUM->hGlobal) ;
  2465. pSTM->pUnkForRelease = _pSTGMEDIUM->pUnkForRelease ;
  2466. }
  2467. #if bugbug
  2468. if (!_pSTGMEDIUM->hGlobal)
  2469. #else
  2470. if (!pSTM->hGlobal)
  2471. #endif // bugbug
  2472. {
  2473. TRC_NRM((TB, _T("Clipboard data request failed"))) ;
  2474. return E_FAIL ;
  2475. }
  2476. DC_EXIT_POINT:
  2477. DC_END_FN();
  2478. return result ;
  2479. }
  2480. STDMETHODIMP CImpIDataObject::GetDataHere(LPFORMATETC pFE, LPSTGMEDIUM pSTM)
  2481. {
  2482. DC_BEGIN_FN("GetDataHere") ;
  2483. DC_END_FN();
  2484. return ResultFromScode(E_NOTIMPL) ;
  2485. }
  2486. STDMETHODIMP CImpIDataObject::QueryGetData(LPFORMATETC pFE)
  2487. {
  2488. ULONG i = 0 ;
  2489. HRESULT hr = DV_E_CLIPFORMAT ;
  2490. DC_BEGIN_FN("QueryGetData") ;
  2491. TRC_NRM((TB, _T("Format ID %d requested"), pFE->cfFormat)) ;
  2492. while (i < _numFormats)
  2493. {
  2494. if (_pFormats[i].cfFormat == pFE->cfFormat) {
  2495. hr = S_OK ;
  2496. break ;
  2497. }
  2498. i++ ;
  2499. }
  2500. DC_END_FN();
  2501. return hr ;
  2502. }
  2503. STDMETHODIMP CImpIDataObject::GetCanonicalFormatEtc(LPFORMATETC pFEIn, LPFORMATETC pFEOut)
  2504. {
  2505. DC_BEGIN_FN("GetCanonicalFormatEtc") ;
  2506. DC_END_FN();
  2507. return ResultFromScode(E_NOTIMPL) ;
  2508. }
  2509. // ***************************************************************************
  2510. // CImpIDataObject::SetData
  2511. // - Due to the fact that the RDP only passes the simple clipboard format, and
  2512. // the fact that we obtain all of our clipboard data from memory later, pSTM
  2513. // is really ignored at this point. It isn't until GetData is called that
  2514. // the remote clipboard data is received, and a valid global memory handle
  2515. // is generated.
  2516. // - Thus, pSTM and fRelease are ignored.
  2517. // - So our _pSTGMEDIUM is generated using generic values
  2518. // ***************************************************************************
  2519. STDMETHODIMP CImpIDataObject::SetData(LPFORMATETC pFE, LPSTGMEDIUM pSTM, BOOL fRelease)
  2520. {
  2521. TCHAR formatName[TS_FORMAT_NAME_LEN] = {0} ;
  2522. unsigned i ;
  2523. DC_BEGIN_FN("SetData");
  2524. DC_IGNORE_PARAMETER(pSTM) ;
  2525. // Reset the the last format requested to 0
  2526. _lastFormatRequested = 0 ;
  2527. TRC_NRM((TB,_T("Adding format %d to IDataObject"), pFE->cfFormat)) ;
  2528. if (_numFormats < _maxNumFormats)
  2529. {
  2530. for (i = 0; i < _numFormats; i++)
  2531. {
  2532. if (pFE->cfFormat == _pFormats[i].cfFormat)
  2533. {
  2534. TRC_NRM((TB,_T("Duplicate format. Discarded"))) ;
  2535. return DV_E_FORMATETC ;
  2536. }
  2537. }
  2538. _pFormats[_numFormats] = *pFE ;
  2539. _numFormats++ ;
  2540. }
  2541. else
  2542. {
  2543. TRC_ERR((TB,_T("Cannot add any more formats"))) ;
  2544. return E_FAIL ;
  2545. }
  2546. DC_END_FN();
  2547. return S_OK ;
  2548. }
  2549. STDMETHODIMP CImpIDataObject::EnumFormatEtc(DWORD dwDir, LPENUMFORMATETC *ppEnum)
  2550. {
  2551. PCEnumFormatEtc pEnum;
  2552. DC_BEGIN_FN("CImpIDataObject::EnumFormatEtc");
  2553. *ppEnum=NULL;
  2554. /*
  2555. * From an external point of view there are no SET formats,
  2556. * because we want to allow the user of this component object
  2557. * to be able to stuff ANY format in via Set. Only external
  2558. * users will call EnumFormatEtc and they can only Get.
  2559. */
  2560. switch (dwDir)
  2561. {
  2562. case DATADIR_GET:
  2563. pEnum=new CEnumFormatEtc(_pUnkOuter);
  2564. break;
  2565. case DATADIR_SET:
  2566. default:
  2567. pEnum=new CEnumFormatEtc(_pUnkOuter);
  2568. break;
  2569. }
  2570. if (NULL==pEnum)
  2571. {
  2572. return ResultFromScode(E_FAIL);
  2573. }
  2574. else
  2575. {
  2576. //Let the enumerator copy our format list.
  2577. pEnum->Init(_pFormats, _numFormats) ;
  2578. pEnum->AddRef();
  2579. }
  2580. *ppEnum=pEnum;
  2581. return NO_ERROR ;
  2582. DC_END_FN() ;
  2583. }
  2584. STDMETHODIMP CImpIDataObject::DAdvise(LPFORMATETC pFE, DWORD dwFlags,
  2585. LPADVISESINK pIAdviseSink, LPDWORD pdwConn)
  2586. {
  2587. DC_BEGIN_FN("CImpIDataObject::DAdvise");
  2588. DC_END_FN() ;
  2589. return ResultFromScode(E_NOTIMPL) ;
  2590. }
  2591. STDMETHODIMP CImpIDataObject::DUnadvise(DWORD dwConn)
  2592. {
  2593. DC_BEGIN_FN("CImpIDataObject::DUnadvise");
  2594. DC_END_FN() ;
  2595. return ResultFromScode(E_NOTIMPL) ;
  2596. }
  2597. STDMETHODIMP CImpIDataObject::EnumDAdvise(LPENUMSTATDATA *ppEnum)
  2598. {
  2599. DC_BEGIN_FN("CImpIDataObject::EnumDAdvise");
  2600. DC_END_FN() ;
  2601. return ResultFromScode(E_NOTIMPL) ;
  2602. }
  2603. CEnumFormatEtc::CEnumFormatEtc(LPUNKNOWN pUnkRef)
  2604. {
  2605. DC_BEGIN_FN("CEnumFormatEtc::CEnumFormatEtc");
  2606. _cRef = 0 ;
  2607. _pUnkRef = pUnkRef ;
  2608. if (_pUnkRef)
  2609. {
  2610. _pUnkRef->AddRef();
  2611. }
  2612. _iCur = 0;
  2613. DC_END_FN() ;
  2614. }
  2615. DCVOID CEnumFormatEtc::Init(LPFORMATETC pFormats, ULONG numFormats)
  2616. {
  2617. DC_BEGIN_FN("CEnumFormatEtc::Init");
  2618. _cItems = numFormats;
  2619. _pFormats = (LPFORMATETC) LocalAlloc(LPTR, _cItems*sizeof(FORMATETC)) ;
  2620. if (_pFormats)
  2621. {
  2622. memcpy(_pFormats, pFormats, _cItems*sizeof(FORMATETC)) ;
  2623. }
  2624. else
  2625. {
  2626. TRC_ERR((TB, _T("Unable to allocate memory for formats"))) ;
  2627. }
  2628. DC_END_FN() ;
  2629. }
  2630. CEnumFormatEtc::~CEnumFormatEtc()
  2631. {
  2632. DC_BEGIN_FN("CEnumFormatEtc::~CEnumFormatEtc");
  2633. if (NULL != _pFormats)
  2634. LocalFree(_pFormats) ;
  2635. if (_pUnkRef)
  2636. {
  2637. _pUnkRef->Release();
  2638. _pUnkRef = NULL;
  2639. }
  2640. DC_END_FN() ;
  2641. }
  2642. STDMETHODIMP CEnumFormatEtc::QueryInterface(REFIID riid, PPVOID ppv)
  2643. {
  2644. DC_BEGIN_FN("CEnumFormatEtc::QueryInterface");
  2645. *ppv=NULL;
  2646. /*
  2647. * Enumerators are separate objects, not the data object, so
  2648. * we only need to support out IUnknown and IEnumFORMATETC
  2649. * interfaces here with no concern for aggregation.
  2650. */
  2651. if (IID_IUnknown==riid || IID_IEnumFORMATETC==riid)
  2652. *ppv=this;
  2653. if (NULL!=*ppv)
  2654. {
  2655. ((LPUNKNOWN)*ppv)->AddRef();
  2656. return NOERROR;
  2657. }
  2658. DC_END_FN() ;
  2659. return ResultFromScode(E_NOINTERFACE);
  2660. }
  2661. STDMETHODIMP_(ULONG) CEnumFormatEtc::AddRef(void)
  2662. {
  2663. LONG cRef;
  2664. cRef = InterlockedIncrement(&_cRef) ;
  2665. // should return UnkRef's RefCount?
  2666. _pUnkRef->AddRef();
  2667. return cRef;
  2668. }
  2669. STDMETHODIMP_(ULONG) CEnumFormatEtc::Release(void)
  2670. {
  2671. LONG cRef;
  2672. DC_BEGIN_FN("CEnumFormatEtc::Release");
  2673. _pUnkRef->Release();
  2674. cRef = InterlockedDecrement(&_cRef) ;
  2675. if (cRef == 0)
  2676. {
  2677. delete this;
  2678. }
  2679. DC_END_FN() ;
  2680. return 0;
  2681. }
  2682. STDMETHODIMP CEnumFormatEtc::Next(ULONG cFE, LPFORMATETC pFE, ULONG *pulFE)
  2683. {
  2684. ULONG cReturn=0L;
  2685. if (NULL == _pFormats)
  2686. return ResultFromScode(S_FALSE);
  2687. if (NULL == pulFE)
  2688. {
  2689. if (1L != cFE)
  2690. return ResultFromScode(E_POINTER);
  2691. }
  2692. else
  2693. *pulFE=0L;
  2694. if (NULL == pFE || _iCur >= _cItems)
  2695. return ResultFromScode(S_FALSE);
  2696. while (_iCur < _cItems && cFE > 0)
  2697. {
  2698. *pFE = _pFormats[_iCur];
  2699. pFE++;
  2700. _iCur++;
  2701. cReturn++;
  2702. cFE--;
  2703. }
  2704. if (NULL!=pulFE)
  2705. *pulFE=cReturn;
  2706. return NOERROR;
  2707. }
  2708. STDMETHODIMP CEnumFormatEtc::Skip(ULONG cSkip)
  2709. {
  2710. if ((_iCur+cSkip) >= _cItems)
  2711. return ResultFromScode(S_FALSE);
  2712. _iCur+=cSkip;
  2713. return NOERROR;
  2714. }
  2715. STDMETHODIMP CEnumFormatEtc::Reset(void)
  2716. {
  2717. _iCur=0;
  2718. return NOERROR;
  2719. }
  2720. STDMETHODIMP CEnumFormatEtc::Clone(LPENUMFORMATETC *ppEnum)
  2721. {
  2722. PCEnumFormatEtc pNew = NULL;
  2723. LPMALLOC pIMalloc;
  2724. LPFORMATETC prgfe;
  2725. BOOL fRet=TRUE;
  2726. ULONG cb;
  2727. *ppEnum=NULL;
  2728. //Copy the memory for the list.
  2729. if (FAILED(CoGetMalloc(MEMCTX_TASK, &pIMalloc)))
  2730. return ResultFromScode(E_OUTOFMEMORY);
  2731. cb=_cItems*sizeof(FORMATETC);
  2732. prgfe=(LPFORMATETC)pIMalloc->Alloc(cb);
  2733. if (NULL!=prgfe)
  2734. {
  2735. //Copy the formats
  2736. memcpy(prgfe, _pFormats, (int)cb);
  2737. //Create the clone
  2738. pNew=new CEnumFormatEtc(_pUnkRef);
  2739. if (NULL!=pNew)
  2740. {
  2741. pNew->_iCur=_iCur;
  2742. pNew->_pFormats=prgfe;
  2743. pNew->AddRef();
  2744. fRet=TRUE;
  2745. }
  2746. }
  2747. pIMalloc->Release();
  2748. *ppEnum=pNew;
  2749. return fRet ? NOERROR : ResultFromScode(E_OUTOFMEMORY);
  2750. }