Changeset 81843 in vbox
- Timestamp:
- Nov 14, 2019 4:30:44 PM (5 years ago)
- Location:
- trunk
- Files:
-
- 10 edited
Legend:
- Unmodified
- Added
- Removed
-
trunk/include/VBox/GuestHost/SharedClipboard.h
r81820 r81843 110 110 { 111 111 /** Available format(s) as bit map. */ 112 SHCLFORMATS uFormats;112 SHCLFORMATS Formats; 113 113 /** Formats flags. Currently unused. */ 114 114 uint32_t fFlags; … … 284 284 * @{ 285 285 */ 286 extern DECLCALLBACK(int) ClipRequestDataForX11Callback(SHCLCONTEXT *pCtx, uint32_t u32Format, void **ppv, uint32_t *pcb);287 extern DECLCALLBACK(void) ClipReportX11FormatsCallback(SHCLCONTEXT *pCtx, uint32_t u32Formats);286 extern DECLCALLBACK(int) ClipRequestDataForX11Callback(SHCLCONTEXT *pCtx, SHCLFORMAT Format, void **ppv, uint32_t *pcb); 287 extern DECLCALLBACK(void) ClipReportX11FormatsCallback(SHCLCONTEXT *pCtx, SHCLFORMATS Formats); 288 288 extern DECLCALLBACK(void) ClipRequestFromX11CompleteCallback(SHCLCONTEXT *pCtx, int rc, CLIPREADCBREQ *pReq, void *pv, uint32_t cb); 289 289 /** @} */ -
trunk/src/VBox/Additions/WINNT/VBoxTray/VBoxClipboard.cpp
r81768 r81843 257 257 if (RT_SUCCESS(rc)) 258 258 { 259 LogFunc(("WM_CLIPBOARDUPDATE: Reporting formats 0x%x\n", Formats. uFormats));259 LogFunc(("WM_CLIPBOARDUPDATE: Reporting formats 0x%x\n", Formats.Formats)); 260 260 rc = VbglR3ClipboardFormatsReportEx(&pCtx->CmdCtx, &Formats); 261 261 } … … 303 303 rc = SharedClipboardWinGetFormats(pWinCtx, &Formats); 304 304 if (RT_SUCCESS(rc) 305 && Formats. uFormats != VBOX_SHCL_FMT_NONE)305 && Formats.Formats != VBOX_SHCL_FMT_NONE) 306 306 { 307 307 rc = VbglR3ClipboardFormatsReportEx(&pCtx->CmdCtx, &Formats); … … 515 515 Assert(pEvent->enmType == VBGLR3CLIPBOARDEVENTTYPE_REPORT_FORMATS); 516 516 517 const SHCLFORMATS fFormats = pEvent->u.ReportedFormats. uFormats;517 const SHCLFORMATS fFormats = pEvent->u.ReportedFormats.Formats; 518 518 519 519 if (fFormats != VBOX_SHCL_FMT_NONE) /* Could arrive with some older GA versions. */ … … 1016 1016 { 1017 1017 pEvent->enmType = VBGLR3CLIPBOARDEVENTTYPE_REPORT_FORMATS; 1018 pEvent->u.ReportedFormats. uFormats = uFormats;1018 pEvent->u.ReportedFormats.Formats = uFormats; 1019 1019 break; 1020 1020 } -
trunk/src/VBox/Additions/common/VBoxGuest/lib/VBoxGuestR3LibClipboard.cpp
r81831 r81843 200 200 rc = Msg.u.v1.uContext.GetUInt64(&pCtx->uContextID); 201 201 if (RT_SUCCESS(rc)) 202 rc = Msg.u.v1.uFormats.GetUInt32(&pFormats-> uFormats);202 rc = Msg.u.v1.uFormats.GetUInt32(&pFormats->Formats); 203 203 if (RT_SUCCESS(rc)) 204 204 rc = Msg.u.v1.fFlags.GetUInt32(&pFormats->fFlags); … … 2363 2363 int rc; 2364 2364 2365 LogFlowFunc(("uFormats=0x%x\n", pFormats-> uFormats));2365 LogFlowFunc(("uFormats=0x%x\n", pFormats->Formats)); 2366 2366 2367 2367 if (pCtx->fUseLegacyProtocol) 2368 2368 { 2369 2369 VBGL_HGCM_HDR_INIT(&Msg.hdr, pCtx->uClientID, VBOX_SHCL_GUEST_FN_FORMATS_REPORT, 1); 2370 Msg.u.v0.uFormats.SetUInt32(pFormats-> uFormats);2370 Msg.u.v0.uFormats.SetUInt32(pFormats->Formats); 2371 2371 2372 2372 rc = VbglR3HGCMCall(&Msg.hdr, sizeof(Msg.hdr) + sizeof(Msg.u.v0)); … … 2377 2377 2378 2378 Msg.u.v1.uContext.SetUInt64(pCtx->uContextID); 2379 Msg.u.v1.uFormats.SetUInt32(pFormats-> uFormats);2379 Msg.u.v1.uFormats.SetUInt32(pFormats->Formats); 2380 2380 Msg.u.v1.fFlags.SetUInt32(pFormats->fFlags); 2381 2381 -
trunk/src/VBox/Additions/x11/VBoxClient/clipboard.cpp
r81820 r81843 46 46 struct _SHCLCONTEXT 47 47 { 48 /** Client ID for the clipboard subsystem */ 49 uint32_t client; 50 51 /** Pointer to the X11 clipboard backend */ 52 CLIPBACKEND *pBackend; 48 /** Client command context */ 49 VBGLR3SHCLCMDCTX CmdCtx; 50 #ifdef VBOX_WITH_SHARED_CLIPBOARD_TRANSFERS 51 /** Associated transfer data. */ 52 SHCLTRANSFERCTX TransferCtx; 53 #endif 54 /** Pointer to the X11 clipboard backend. */ 55 CLIPBACKEND *pBackend; 53 56 }; 54 57 55 58 /** Only one client is supported. There seems to be no need for more clients. */ 56 static SHCLCONTEXT g_ctx; 57 58 59 /** 60 * Transfer clipboard data from the guest to the host. 61 * 62 * @returns VBox result code 63 * @param u32Format The format of the data being sent 64 * @param pv Pointer to the data being sent 65 * @param cb Size of the data being sent in bytes 66 */ 67 static int vboxClipboardSendData(uint32_t u32Format, void *pv, uint32_t cb) 68 { 69 int rc; 70 LogFlowFunc(("u32Format=%d, pv=%p, cb=%d\n", u32Format, pv, cb)); 71 rc = VbglR3ClipboardWriteData(g_ctx.client, u32Format, pv, cb); 72 LogFlowFuncLeaveRC(rc); 73 return rc; 74 } 59 static SHCLCONTEXT g_Ctx; 75 60 76 61 … … 79 64 * 80 65 * @returns VBox result code 81 * @param pCtx Our context information82 * @param u32Format The format of the data being requested83 * @param ppv On success and if pcb > 0, this will point to a buffer84 * to be freed with RTMemFree containing the data read.85 * @param pcb On success, this contains the number of bytes of data86 * returned87 */ 88 DECLCALLBACK(int) ClipRequestDataForX11Callback(SHCLCONTEXT *pCtx, uint32_t u32Format, void **ppv, uint32_t *pcb)66 * @param pCtx Our context information. 67 * @param Format The format of the data being requested. 68 * @param ppv On success and if pcb > 0, this will point to a buffer 69 * to be freed with RTMemFree containing the data read. 70 * @param pcb On success, this contains the number of bytes of data 71 * returned. 72 */ 73 DECLCALLBACK(int) ClipRequestDataForX11Callback(SHCLCONTEXT *pCtx, SHCLFORMAT Format, void **ppv, uint32_t *pcb) 89 74 { 90 75 RT_NOREF(pCtx); 76 77 LogFlowFunc(("Format=0x%x\n", Format)); 78 91 79 int rc = VINF_SUCCESS; 92 uint32_t cb = 1024; 93 void *pv = RTMemAlloc(cb); 94 95 *ppv = 0; 96 LogFlowFunc(("u32Format=%u\n", u32Format)); 97 if (RT_UNLIKELY(!pv)) 98 rc = VERR_NO_MEMORY; 99 if (RT_SUCCESS(rc)) 100 rc = VbglR3ClipboardReadData(g_ctx.client, u32Format, pv, cb, pcb); 101 if (RT_SUCCESS(rc) && (rc != VINF_BUFFER_OVERFLOW)) 102 *ppv = pv; 103 /* A return value of VINF_BUFFER_OVERFLOW tells us to try again with a 104 * larger buffer. The size of the buffer needed is placed in *pcb. 105 * So we start all over again. */ 106 if (rc == VINF_BUFFER_OVERFLOW) 107 { 108 cb = *pcb; 109 RTMemFree(pv); 110 pv = RTMemAlloc(cb); 111 if (RT_UNLIKELY(!pv)) 80 81 uint32_t cbRead = 0; 82 83 #ifdef VBOX_WITH_SHARED_CLIPBOARD_TRANSFERS 84 if (Format == VBOX_SHCL_FMT_URI_LIST) 85 { 86 //rc = VbglR3ClipboardRootListRead() 87 } 88 else 89 #endif 90 { 91 SHCLDATABLOCK dataBlock; 92 RT_ZERO(dataBlock); 93 94 dataBlock.uFormat = Format; 95 dataBlock.cbData = _4K; 96 dataBlock.pvData = RTMemAlloc(dataBlock.cbData); 97 if (dataBlock.pvData) 98 { 99 rc = VbglR3ClipboardReadDataEx(&pCtx->CmdCtx, &dataBlock, &cbRead); 100 } 101 else 112 102 rc = VERR_NO_MEMORY; 113 if (RT_SUCCESS(rc)) 114 rc = VbglR3ClipboardReadData(g_ctx.client, u32Format, pv, cb, pcb); 115 if (RT_SUCCESS(rc) && (rc != VINF_BUFFER_OVERFLOW)) 116 *ppv = pv; 117 } 118 /* Catch other errors. This also catches the case in which the buffer was 119 * too small a second time, possibly because the clipboard contents 120 * changed half-way through the operation. Since we can't say whether or 121 * not this is actually an error, we just return size 0. 122 */ 123 if (RT_FAILURE(rc) || (VINF_BUFFER_OVERFLOW == rc)) 124 { 125 *pcb = 0; 126 if (pv != NULL) 127 RTMemFree(pv); 128 } 103 104 /* 105 * A return value of VINF_BUFFER_OVERFLOW tells us to try again with a 106 * larger buffer. The size of the buffer needed is placed in *pcb. 107 * So we start all over again. 108 */ 109 if (rc == VINF_BUFFER_OVERFLOW) 110 { 111 /* cbRead contains the size required. */ 112 113 dataBlock.cbData = cbRead; 114 dataBlock.pvData = RTMemRealloc(dataBlock.pvData, cbRead); 115 if (dataBlock.pvData) 116 { 117 rc = VbglR3ClipboardReadDataEx(&pCtx->CmdCtx, &dataBlock, &cbRead); 118 if ( RT_SUCCESS(rc) 119 && (rc != VINF_BUFFER_OVERFLOW)) 120 { 121 *pcb = cbRead; /* Actual bytes read. */ 122 *ppv = dataBlock.pvData; 123 } 124 } 125 else 126 rc = VERR_NO_MEMORY; 127 } 128 129 /* 130 * Catch other errors. This also catches the case in which the buffer was 131 * too small a second time, possibly because the clipboard contents 132 * changed half-way through the operation. Since we can't say whether or 133 * not this is actually an error, we just return size 0. 134 */ 135 if ( RT_FAILURE(rc) 136 || (VINF_BUFFER_OVERFLOW == rc)) 137 { 138 RTMemFree(dataBlock.pvData); 139 } 140 } 141 129 142 LogFlowFuncLeaveRC(rc); 130 if (RT_SUCCESS(rc))131 LogFlow((" *pcb=%d\n", *pcb));132 143 return rc; 133 144 } 134 145 135 /** Opaque data structure describing a request from the host for clipboard 146 /** 147 * Opaque data structure describing a request from the host for clipboard 136 148 * data, passed in when the request is forwarded to the X11 backend so that 137 * it can be completed correctly. */ 149 * it can be completed correctly. 150 */ 138 151 struct _CLIPREADCBREQ 139 152 { 140 153 /** The data format that was requested. */ 141 uint32_t u32Format;154 SHCLFORMAT Format; 142 155 }; 143 156 … … 146 159 * 147 160 * @param pCtx Our context information. 148 * @param u32FormatsThe formats to report.149 */ 150 DECLCALLBACK(void) ClipReportX11FormatsCallback(SHCLCONTEXT *pCtx, uint32_t u32Formats)161 * @param Formats The formats to report. 162 */ 163 DECLCALLBACK(void) ClipReportX11FormatsCallback(SHCLCONTEXT *pCtx, SHCLFORMATS Formats) 151 164 { 152 165 RT_NOREF(pCtx); 153 166 154 LogFlowFunc(("u32Formats=%RU32\n", u32Formats)); 155 156 int rc = VbglR3ClipboardFormatsReport(g_ctx.client, u32Formats); 157 RT_NOREF(rc); 158 159 LogFlowFuncLeaveRC(rc); 160 } 161 162 /** This is called by the backend to tell us that a request for data from 167 LogFlowFunc(("Formats=0x%x\n", Formats)); 168 169 SHCLFORMATDATA formatData; 170 RT_ZERO(formatData); 171 172 formatData.Formats = Formats; 173 174 int rc2 = VbglR3ClipboardFormatsReportEx(&pCtx->CmdCtx, &formatData); 175 RT_NOREF(rc2); 176 LogFlowFuncLeaveRC(rc2); 177 } 178 179 /** 180 * This is called by the backend to tell us that a request for data from 163 181 * X11 has completed. 164 * @param pCtx Our context information165 * @param rc the iprt result code of the request166 * @param pReq the request structure that we passed in when we started167 * the request. We RTMemFree() this in this function.168 * @param pv the clipboard data returned from X11 if the request169 * succeeded (see @a rc)170 * @param cb the size of the data in @a pv182 * 183 * @param pCtx Our context information. 184 * @param rc The IPRT result code of the request. 185 * @param pReq The request structure that we passed in when we started 186 * the request. We RTMemFree() this in this function. 187 * @param pv The clipboard data returned from X11 if the request succeeded (see @a rc). 188 * @param cb The size of the data in @a pv. 171 189 */ 172 190 DECLCALLBACK(void) ClipRequestFromX11CompleteCallback(SHCLCONTEXT *pCtx, int rc, CLIPREADCBREQ *pReq, void *pv, uint32_t cb) 173 191 { 174 192 RT_NOREF(pCtx); 193 194 LogFlowFunc(("rc=%Rrc, Format=0x%x, pv=%p, cb=%RU32\n", rc, pReq->Format, pv, cb)); 195 196 SHCLDATABLOCK dataBlock; 197 RT_ZERO(dataBlock); 198 199 dataBlock.uFormat = pReq->Format; 200 175 201 if (RT_SUCCESS(rc)) 176 vboxClipboardSendData(pReq->u32Format, pv, cb); 177 else 178 vboxClipboardSendData(0, NULL, 0); 202 { 203 dataBlock.pvData = pv; 204 dataBlock.cbData = cb; 205 } 206 207 int rc2 = VbglR3ClipboardWriteDataEx(&pCtx->CmdCtx, &dataBlock); 208 RT_NOREF(rc2); 209 179 210 RTMemFree(pReq); 211 212 LogFlowFuncLeaveRC(rc2); 180 213 } 181 214 … … 183 216 * Connect the guest clipboard to the host. 184 217 * 185 * @returns VBox status code 218 * @returns VBox status code. 186 219 */ 187 220 static int vboxClipboardConnect(void) … … 189 222 LogFlowFuncEnter(); 190 223 191 /* Sanity */192 AssertReturn(g_ctx.client == 0, VERR_WRONG_ORDER);193 AssertReturn(g_ctx.pBackend == NULL, VERR_WRONG_ORDER);194 195 224 int rc; 196 225 197 g_ ctx.pBackend = ClipConstructX11(&g_ctx, false);198 if (g_ ctx.pBackend)199 { 200 rc = ClipStartX11(g_ ctx.pBackend, false /* grab */);226 g_Ctx.pBackend = ClipConstructX11(&g_Ctx, false); 227 if (g_Ctx.pBackend) 228 { 229 rc = ClipStartX11(g_Ctx.pBackend, false /* grab */); 201 230 if (RT_SUCCESS(rc)) 202 231 { 203 rc = VbglR3ClipboardConnect(&g_ctx.client); 204 if (RT_SUCCESS(rc)) 205 { 206 Assert(g_ctx.client); 207 } 208 else 209 VBClLogError("Error connecting to host, rc=%Rrc\n", rc); 232 rc = VbglR3ClipboardConnectEx(&g_Ctx.CmdCtx); 210 233 } 211 234 } … … 213 236 rc = VERR_NO_MEMORY; 214 237 215 if (rc != VINF_SUCCESS && g_ctx.pBackend) 216 ClipDestructX11(g_ctx.pBackend); 238 if (RT_FAILURE(rc)) 239 { 240 VBClLogError("Error connecting to host service, rc=%Rrc\n", rc); 241 242 VbglR3ClipboardDisconnectEx(&g_Ctx.CmdCtx); 243 ClipDestructX11(g_Ctx.pBackend); 244 } 217 245 218 246 LogFlowFuncLeaveRC(rc); … … 225 253 int vboxClipboardMain(void) 226 254 { 255 LogRel2(("Worker loop running\n")); 256 227 257 int rc; 228 LogFlowFunc(("Starting guest clipboard service\n")); 229 bool fExiting = false; 230 231 while (!fExiting) 232 { 233 uint32_t Msg; 234 uint32_t fFormats; 235 rc = VbglR3ClipboardGetHostMsgOld(g_ctx.client, &Msg, &fFormats); 236 if (RT_SUCCESS(rc)) 237 { 238 switch (Msg) 239 { 240 case VBOX_SHCL_HOST_MSG_FORMATS_REPORT: 241 { 242 /* The host has announced available clipboard formats. 243 * Save the information so that it is available for 244 * future requests from guest applications. 245 */ 246 LogFlowFunc(("VBOX_SHCL_HOST_MSG_FORMATS_WRITE fFormats=%x\n", fFormats)); 247 ClipAnnounceFormatToX11(g_ctx.pBackend, fFormats); 248 break; 249 } 250 251 case VBOX_SHCL_HOST_MSG_READ_DATA: 258 259 SHCLCONTEXT *pCtx = &g_Ctx; 260 261 bool fShutdown = false; 262 263 /* The thread waits for incoming messages from the host. */ 264 for (;;) 265 { 266 PVBGLR3CLIPBOARDEVENT pEvent = NULL; 267 268 LogFlowFunc(("Waiting for host message (fUseLegacyProtocol=%RTbool, fHostFeatures=%#RX64) ...\n", 269 pCtx->CmdCtx.fUseLegacyProtocol, pCtx->CmdCtx.fHostFeatures)); 270 271 if (pCtx->CmdCtx.fUseLegacyProtocol) 272 { 273 uint32_t uMsg; 274 uint32_t uFormats; 275 276 rc = VbglR3ClipboardGetHostMsgOld(pCtx->CmdCtx.uClientID, &uMsg, &uFormats); 277 if (RT_FAILURE(rc)) 278 { 279 if (rc == VERR_INTERRUPTED) 280 break; 281 282 LogFunc(("Error getting host message, rc=%Rrc\n", rc)); 283 } 284 else 285 { 286 pEvent = (PVBGLR3CLIPBOARDEVENT)RTMemAllocZ(sizeof(VBGLR3CLIPBOARDEVENT)); 287 AssertPtrBreakStmt(pEvent, rc = VERR_NO_MEMORY); 288 289 switch (uMsg) 290 { 291 case VBOX_SHCL_HOST_MSG_FORMATS_REPORT: 292 { 293 pEvent->enmType = VBGLR3CLIPBOARDEVENTTYPE_REPORT_FORMATS; 294 pEvent->u.ReportedFormats.Formats = uFormats; 295 break; 296 } 297 298 case VBOX_SHCL_HOST_MSG_READ_DATA: 299 { 300 pEvent->enmType = VBGLR3CLIPBOARDEVENTTYPE_READ_DATA; 301 pEvent->u.ReadData.uFmt = uFormats; 302 break; 303 } 304 305 case VBOX_SHCL_HOST_MSG_QUIT: 306 { 307 pEvent->enmType = VBGLR3CLIPBOARDEVENTTYPE_QUIT; 308 break; 309 } 310 311 default: 312 rc = VERR_NOT_SUPPORTED; 313 break; 314 } 315 316 if (RT_SUCCESS(rc)) 317 { 318 /* Copy over our command context to the event. */ 319 pEvent->cmdCtx = pCtx->CmdCtx; 320 } 321 } 322 } 323 else /* Host service has peeking for messages support. */ 324 { 325 pEvent = (PVBGLR3CLIPBOARDEVENT)RTMemAllocZ(sizeof(VBGLR3CLIPBOARDEVENT)); 326 AssertPtrBreakStmt(pEvent, rc = VERR_NO_MEMORY); 327 328 uint32_t uMsg = 0; 329 uint32_t cParms = 0; 330 rc = VbglR3ClipboardMsgPeekWait(&pCtx->CmdCtx, &uMsg, &cParms, NULL /* pidRestoreCheck */); 331 if (RT_SUCCESS(rc)) 332 { 333 #ifdef VBOX_WITH_SHARED_CLIPBOARD_TRANSFERS 334 rc = VbglR3ClipboardEventGetNextEx(uMsg, cParms, &pCtx->CmdCtx, &pCtx->TransferCtx, pEvent); 335 #else 336 rc = VbglR3ClipboardEventGetNext(uMsg, cParms, &pCtx->CmdCtx, pEvent); 337 #endif 338 } 339 } 340 341 if (RT_FAILURE(rc)) 342 { 343 LogFlowFunc(("Getting next event failed with %Rrc\n", rc)); 344 345 VbglR3ClipboardEventFree(pEvent); 346 pEvent = NULL; 347 348 if (fShutdown) 349 break; 350 351 /* Wait a bit before retrying. */ 352 RTThreadSleep(1000); 353 continue; 354 } 355 else 356 { 357 AssertPtr(pEvent); 358 LogFlowFunc(("Event uType=%RU32\n", pEvent->enmType)); 359 360 switch (pEvent->enmType) 361 { 362 case VBGLR3CLIPBOARDEVENTTYPE_REPORT_FORMATS: 363 { 364 ClipAnnounceFormatToX11(g_Ctx.pBackend, pEvent->u.ReportedFormats.Formats); 365 break; 366 } 367 368 case VBGLR3CLIPBOARDEVENTTYPE_READ_DATA: 252 369 { 253 370 /* The host needs data in the specified format. */ 254 LogFlowFunc(("VBOX_SHCL_HOST_MSG_READ_DATA fFormats=%x\n", fFormats));255 371 CLIPREADCBREQ *pReq; 256 pReq = (CLIPREADCBREQ *)RTMemAllocZ(sizeof( *pReq));257 if ( !pReq)372 pReq = (CLIPREADCBREQ *)RTMemAllocZ(sizeof(CLIPREADCBREQ)); 373 if (pReq) 258 374 { 259 rc = VERR_NO_MEMORY;260 fExiting = true;375 pReq->Format = pEvent->u.ReadData.uFmt; 376 ClipReadDataFromX11(g_Ctx.pBackend, pReq->Format, pReq); 261 377 } 262 378 else 263 { 264 pReq->u32Format = fFormats; 265 ClipReadDataFromX11(g_ctx.pBackend, fFormats, 266 pReq); 267 } 268 break; 269 } 270 271 case VBOX_SHCL_HOST_MSG_QUIT: 272 { 273 /* The host is terminating. */ 274 LogFlowFunc(("VBOX_SHCL_HOST_MSG_QUIT\n")); 275 if (RT_SUCCESS(ClipStopX11(g_ctx.pBackend))) 276 ClipDestructX11(g_ctx.pBackend); 277 fExiting = true; 379 rc = VERR_NO_MEMORY; 380 break; 381 } 382 383 case VBGLR3CLIPBOARDEVENTTYPE_QUIT: 384 { 385 LogRel2(("Host requested termination\n")); 386 fShutdown = true; 387 break; 388 } 389 390 #ifdef VBOX_WITH_SHARED_CLIPBOARD_TRANSFERS 391 case VBGLR3CLIPBOARDEVENTTYPE_TRANSFER_STATUS: 392 { 393 /* Nothing to do here. */ 394 rc = VINF_SUCCESS; 395 break; 396 } 397 #endif 398 case VBGLR3CLIPBOARDEVENTTYPE_NONE: 399 { 400 /* Nothing to do here. */ 401 rc = VINF_SUCCESS; 278 402 break; 279 403 } … … 281 405 default: 282 406 { 283 VBClLogInfo("Unsupported message from host (%RU32)\n", Msg); 284 break; 285 } 286 } 287 } 288 289 LogFlow(("processed host event rc = %d\n", rc)); 290 } 407 AssertMsgFailedBreakStmt(("Event type %RU32 not implemented\n", pEvent->enmType), rc = VERR_NOT_SUPPORTED); 408 } 409 } 410 411 if (pEvent) 412 { 413 VbglR3ClipboardEventFree(pEvent); 414 pEvent = NULL; 415 } 416 } 417 418 if (fShutdown) 419 break; 420 } 421 422 LogRel(("Worker loop ended\n")); 423 291 424 LogFlowFuncLeaveRC(rc); 292 425 return rc; … … 343 476 }; 344 477 345 struct VBCLSERVICE **VBClGetClipboardService( )478 struct VBCLSERVICE **VBClGetClipboardService(void) 346 479 { 347 480 struct CLIPBOARDSERVICE *pService = -
trunk/src/VBox/GuestHost/SharedClipboard/clipboard-win.cpp
r81321 r81843 459 459 LogFlowFunc(("fFormats=0x%08X\n", fFormats)); 460 460 461 pFormats-> uFormats = fFormats;461 pFormats->Formats = fFormats; 462 462 pFormats->fFlags = 0; /** @todo Handle flags. */ 463 463 } -
trunk/src/VBox/GuestHost/SharedClipboard/clipboard-x11.cpp
r81829 r81843 252 252 #endif 253 253 /** What formats does VBox have on offer? */ 254 uint32_tvboxFormats;254 SHCLFORMATS vboxFormats; 255 255 /** Cache of the last unicode data that we received */ 256 256 void *pvUnicodeCache; … … 1100 1100 void ClipDestructX11(CLIPBACKEND *pCtx) 1101 1101 { 1102 if (!pCtx) 1103 return; 1104 1102 1105 if (pCtx->fHaveX11) 1106 { 1103 1107 /* We set this to NULL when the event thread exits. It really should 1104 1108 * have exited at this point, when we are about to unload the code from 1105 1109 * memory. */ 1106 1110 Assert(pCtx->widget == NULL); 1111 } 1112 1107 1113 RTMemFree(pCtx); 1108 1114 } … … 1251 1257 * data returned. 1252 1258 */ 1253 static int clipReadVBoxShCl(CLIPBACKEND *pCtx, uint32_t u32Format,1259 static int clipReadVBoxShCl(CLIPBACKEND *pCtx, SHCLFORMAT Format, 1254 1260 void **ppv, uint32_t *pcb) 1255 1261 { 1262 LogFlowFunc(("pCtx=%p, Format=%02X, ppv=%p, pcb=%p\n", pCtx, Format, ppv, pcb)); 1263 1256 1264 int rc = VINF_SUCCESS; 1257 LogFlowFunc(("pCtx=%p, u32Format=%02X, ppv=%p, pcb=%p\n", pCtx, 1258 u32Format, ppv, pcb)); 1259 if (u32Format == VBOX_SHCL_FMT_UNICODETEXT) 1265 1266 if (Format == VBOX_SHCL_FMT_UNICODETEXT) 1260 1267 { 1261 1268 if (pCtx->pvUnicodeCache == NULL) 1262 rc = ClipRequestDataForX11Callback(pCtx->pFrontend, u32Format,1269 rc = ClipRequestDataForX11Callback(pCtx->pFrontend, Format, 1263 1270 &pCtx->pvUnicodeCache, 1264 1271 &pCtx->cbUnicodeCache); … … 1272 1279 } 1273 1280 else 1274 rc = ClipRequestDataForX11Callback(pCtx->pFrontend, u32Format,1281 rc = ClipRequestDataForX11Callback(pCtx->pFrontend, Format, 1275 1282 ppv, pcb); 1276 1283 if (RT_SUCCESS(rc)) … … 1489 1496 1490 1497 CLIPX11FORMAT x11Format = clipFindX11FormatByAtom(pCtx, *atomTarget); 1491 CLIPFORMAT format = clipRealFormatForX11Format(x11Format); 1492 1493 if ( ((format == UTF8) || (format == TEXT)) 1498 CLIPFORMAT clipFormat = clipRealFormatForX11Format(x11Format); 1499 1500 LogFlowFunc(("fFormats=0x%x, x11Format=%u, clipFormat=%u\n", pCtx->vboxFormats, x11Format, clipFormat)); 1501 1502 if ( ((clipFormat == UTF8) || (clipFormat == TEXT)) 1494 1503 && (pCtx->vboxFormats & VBOX_SHCL_FMT_UNICODETEXT)) 1495 1504 { … … 1499 1508 if (RT_SUCCESS(rc) && (cb == 0)) 1500 1509 rc = VERR_NO_DATA; 1501 if (RT_SUCCESS(rc) && (( format == UTF8) || (format == TEXT)))1510 if (RT_SUCCESS(rc) && ((clipFormat == UTF8) || (clipFormat == TEXT))) 1502 1511 rc = clipWinTxtToUtf8ForX11CB(XtDisplay(pCtx->widget), 1503 1512 (PRTUTF16)pv, cb, atomTarget, … … 1505 1514 pcLenReturn, piFormatReturn); 1506 1515 if (RT_SUCCESS(rc)) 1507 clipTrimTrailingNul(*(XtPointer *)pValReturn, pcLenReturn, format);1516 clipTrimTrailingNul(*(XtPointer *)pValReturn, pcLenReturn, clipFormat); 1508 1517 1509 1518 RTMemFree(pv); 1510 1519 } 1511 else if ( ( format == BMP)1520 else if ( (clipFormat == BMP) 1512 1521 && (pCtx->vboxFormats & VBOX_SHCL_FMT_BITMAP)) 1513 1522 { … … 1517 1526 if (RT_SUCCESS(rc) && (cb == 0)) 1518 1527 rc = VERR_NO_DATA; 1519 if (RT_SUCCESS(rc) && ( format == BMP))1528 if (RT_SUCCESS(rc) && (clipFormat == BMP)) 1520 1529 { 1521 1530 /* Create a full BMP from it */ … … 1534 1543 RTMemFree(pv); 1535 1544 } 1536 else if ( ( format == HTML)1545 else if ( (clipFormat == HTML) 1537 1546 && (pCtx->vboxFormats & VBOX_SHCL_FMT_HTML)) 1538 1547 { … … 1557 1566 pcLenReturn, piFormatReturn); 1558 1567 if (RT_SUCCESS(rc)) 1559 clipTrimTrailingNul(*(XtPointer *)pValReturn, pcLenReturn, format);1568 clipTrimTrailingNul(*(XtPointer *)pValReturn, pcLenReturn, clipFormat); 1560 1569 1561 1570 RTMemFree(pv); 1562 1571 } 1563 1572 } 1573 #ifdef VBOX_WITH_SHARED_CLIPBOARD_TRANSFERS 1574 else if (pCtx->vboxFormats & VBOX_SHCL_FMT_URI_LIST) 1575 { 1576 switch (clipFormat) 1577 { 1578 case TEXT: 1579 RT_FALL_THROUGH(); 1580 case UTF8: 1581 { 1582 void *pv = NULL; 1583 uint32_t cb = 0; 1584 rc = clipReadVBoxShCl(pCtx, VBOX_SHCL_FMT_URI_LIST, &pv, &cb); 1585 1586 RTMemFree(pv); 1587 break; 1588 } 1589 1590 case URI_LIST: 1591 { 1592 break; 1593 } 1594 1595 default: 1596 rc = VERR_NOT_SUPPORTED; 1597 break; 1598 } 1599 } 1600 #endif 1564 1601 else 1602 { 1603 *atomTypeReturn = XT_CONVERT_FAIL; 1604 *pValReturn = (XtPointer)NULL; 1605 *pcLenReturn = 0; 1606 *piFormatReturn = 0; 1607 1565 1608 rc = VERR_NOT_SUPPORTED; 1609 } 1610 1611 if (RT_FAILURE(rc)) 1612 LogRel2(("Shared Clipboard: Converting format 0x%x for X11 (x11Format=%u, clipFormat=%u) failed, rc=%Rrc\n", 1613 pCtx->vboxFormats, x11Format, clipFormat, rc)); 1566 1614 1567 1615 LogFlowFuncLeaveRC(rc); … … 1587 1635 1588 1636 if (!pCtx) 1589 return false;1637 return False; 1590 1638 1591 1639 if (!clipIsSupportedSelectionType(pCtx, *atomSelection)) 1592 return false;1640 return False; 1593 1641 1594 1642 if (*atomTarget == clipGetAtom(pCtx, "TARGETS")) … … 1599 1647 pValReturn, pcLenReturn, piFormatReturn); 1600 1648 1601 LogFlowFunc(("returning , internal status code %Rrc\n", rc));1602 return RT_SUCCESS(rc) ;1649 LogFlowFunc(("returning %RTbool, internal status code %Rrc\n", RT_SUCCESS(rc), rc)); 1650 return RT_SUCCESS(rc) ? True : False; 1603 1651 } 1604 1652 … … 1611 1659 CLIPBACKEND *pCtx; 1612 1660 /** Formats supported by VBox. */ 1613 SHCLFORMATS formats;1661 SHCLFORMATS Formats; 1614 1662 } CLIPNEWVBOXFORMATS, *PCLIPNEWVBOXFORMATS; 1615 1663 … … 1627 1675 * Takes possession of the X11 clipboard (and middle-button selection). 1628 1676 */ 1629 static void clipGrabX11CB(CLIPBACKEND *pCtx, uint32_t u32Formats) 1630 { 1677 static void clipGrabX11CB(CLIPBACKEND *pCtx, SHCLFORMATS Formats) 1678 { 1679 LogFlowFuncEnter(); 1680 1631 1681 if (XtOwnSelection(pCtx->widget, clipGetAtom(pCtx, "CLIPBOARD"), 1632 1682 CurrentTime, clipXtConvertSelectionProc, NULL, 0)) 1633 1683 { 1634 pCtx->vboxFormats = u32Formats;1684 pCtx->vboxFormats = Formats; 1635 1685 /* Grab the middle-button paste selection too. */ 1636 1686 XtOwnSelection(pCtx->widget, clipGetAtom(pCtx, "PRIMARY"), … … 1663 1713 CLIPBACKEND *pCtx = pFormats->pCtx; 1664 1714 1665 uint32_t fFormats = pFormats-> formats;1715 uint32_t fFormats = pFormats->Formats; 1666 1716 1667 1717 RTMemFree(pFormats); … … 1680 1730 * 1681 1731 * @returns VBox status code. 1682 * @param u32FormatsClipboard formats offered.1683 */ 1684 int ClipAnnounceFormatToX11(CLIPBACKEND *pCtx, uint32_t u32Formats)1732 * @param Formats Clipboard formats offered. 1733 */ 1734 int ClipAnnounceFormatToX11(CLIPBACKEND *pCtx, uint32_t Formats) 1685 1735 { 1686 1736 /* … … 1697 1747 { 1698 1748 pFormats->pCtx = pCtx; 1699 pFormats-> formats = u32Formats;1749 pFormats->Formats = Formats; 1700 1750 1701 1751 rc = clipQueueToEventThread(pCtx, clipAnnounceFormatToX11Worker, … … 2289 2339 * @returns VBox status code. 2290 2340 * @param pCtx Context data for the clipboard backend. 2291 * @param u32FormatThe format that the VBox would like to receive the data in.2341 * @param Format The format that the VBox would like to receive the data in. 2292 2342 * @param pReq Read callback request to use. Must be free'd in the callback. 2293 2343 * 2294 2344 * @note We allocate a request structure which must be freed by the worker. 2295 2345 */ 2296 int ClipReadDataFromX11(CLIPBACKEND *pCtx, uint32_t u32Format, CLIPREADCBREQ *pReq)2346 int ClipReadDataFromX11(CLIPBACKEND *pCtx, SHCLFORMAT Format, CLIPREADCBREQ *pReq) 2297 2347 { 2298 2348 /* … … 2308 2358 { 2309 2359 pX11Req->mpCtx = pCtx; 2310 pX11Req->mFormat = u32Format;2360 pX11Req->mFormat = Format; 2311 2361 pX11Req->mpReq = pReq; 2312 2362 … … 2386 2436 2387 2437 /* Return the data in the simulated VBox clipboard. */ 2388 DECLCALLBACK(int) ClipRequestDataForX11Callback(SHCLCONTEXT *pCtx, uint32_t u32Format, void **ppv, uint32_t *pcb)2389 { 2390 RT_NOREF(pCtx, u32Format);2438 DECLCALLBACK(int) ClipRequestDataForX11Callback(SHCLCONTEXT *pCtx, uint32_t Format, void **ppv, uint32_t *pcb) 2439 { 2440 RT_NOREF(pCtx, Format); 2391 2441 *pcb = g_tstVBoxDataCb; 2392 2442 if (g_tstVBoxDataPv != NULL) … … 2503 2553 } 2504 2554 2505 /* The formats currently on offer from X11 via the shared clipboard */2555 /* The formats currently on offer from X11 via the shared clipboard. */ 2506 2556 static uint32_t g_fX11Formats = 0; 2507 2557 2508 DECLCALLBACK(void) ClipReportX11FormatsCallback(SHCLCONTEXT *pCtx, uint32_t u32Formats)2558 DECLCALLBACK(void) ClipReportX11FormatsCallback(SHCLCONTEXT *pCtx, SHCLFORMATS Formats) 2509 2559 { 2510 2560 RT_NOREF(pCtx); 2511 g_fX11Formats = u32Formats;2561 g_fX11Formats = Formats; 2512 2562 } 2513 2563 … … 3145 3195 # include <iprt/test.h> 3146 3196 3147 DECLCALLBACK(int) ClipRequestDataForX11Callback(SHCLCONTEXT *pCtx, uint32_t u32Format, void **ppv, uint32_t *pcb)3148 { 3149 RT_NOREF(pCtx, u32Format, ppv, pcb);3197 DECLCALLBACK(int) ClipRequestDataForX11Callback(SHCLCONTEXT *pCtx, SHCLFORMAT Format, void **ppv, uint32_t *pcb) 3198 { 3199 RT_NOREF(pCtx, Format, ppv, pcb); 3150 3200 return VERR_NO_DATA; 3151 3201 } 3152 3202 3153 DECLCALLBACK(void) ClipReportX11FormatsCallback(SHCLCONTEXT *pCtx, uint32_t u32Formats)3154 { 3155 RT_NOREF(pCtx, u32Formats);3203 DECLCALLBACK(void) ClipReportX11FormatsCallback(SHCLCONTEXT *pCtx, SHCLFORMATS Formats) 3204 { 3205 RT_NOREF(pCtx, Formats); 3156 3206 } 3157 3207 -
trunk/src/VBox/HostServices/SharedClipboard/VBoxSharedClipboardSvc-darwin.cpp
r81825 r81843 74 74 RT_ZERO(formatData); 75 75 76 formatData. uFormats = fFormats;76 formatData.Formats = fFormats; 77 77 78 78 rc = ShClSvcFormatsReport(pCtx->pClient, &formatData); … … 202 202 RT_NOREF(pCmdCtx); 203 203 204 LogFlowFunc(("uFormats=%02X\n", pFormats-> uFormats));205 206 if (pFormats-> uFormats == VBOX_SHCL_FMT_NONE)204 LogFlowFunc(("uFormats=%02X\n", pFormats->Formats)); 205 206 if (pFormats->Formats == VBOX_SHCL_FMT_NONE) 207 207 { 208 208 /* This is just an automatism, not a genuine announcement */ … … 211 211 212 212 #ifdef VBOX_WITH_SHARED_CLIPBOARD_TRANSFERS 213 if (pFormats-> uFormats & VBOX_SHCL_FMT_URI_LIST) /* No transfer support yet. */213 if (pFormats->Formats & VBOX_SHCL_FMT_URI_LIST) /* No transfer support yet. */ 214 214 return VINF_SUCCESS; 215 215 #endif … … 218 218 RT_ZERO(dataReq); 219 219 220 dataReq.uFmt = pFormats-> uFormats;220 dataReq.uFmt = pFormats->Formats; 221 221 dataReq.cbSize = _64K; /** @todo Make this more dynamic. */ 222 222 -
trunk/src/VBox/HostServices/SharedClipboard/VBoxSharedClipboardSvc-win.cpp
r81824 r81843 595 595 rc = SharedClipboardWinGetFormats(&pCtx->Win, &Formats); 596 596 if ( RT_SUCCESS(rc) 597 && Formats. uFormats != VBOX_SHCL_FMT_NONE)597 && Formats.Formats != VBOX_SHCL_FMT_NONE) 598 598 { 599 599 rc = ShClSvcFormatsReport(pCtx->pClient, &Formats); … … 726 726 AssertPtrReturn(pCtx, VERR_INVALID_POINTER); 727 727 728 LogFlowFunc(("uFormats=0x%x, hWnd=%p\n", pFormats-> uFormats, pCtx->Win.hWnd));728 LogFlowFunc(("uFormats=0x%x, hWnd=%p\n", pFormats->Formats, pCtx->Win.hWnd)); 729 729 730 730 /* … … 732 732 */ 733 733 PostMessage(pCtx->Win.hWnd, SHCL_WIN_WM_REPORT_FORMATS, 734 0 /* wParam */, pFormats-> uFormats /* lParam */);734 0 /* wParam */, pFormats->Formats /* lParam */); 735 735 736 736 rc = VINF_SUCCESS; -
trunk/src/VBox/HostServices/SharedClipboard/VBoxSharedClipboardSvc-x11.cpp
r81829 r81843 119 119 RT_ZERO(formatData); 120 120 121 formatData. uFormats = VBOX_SHCL_FMT_NONE;121 formatData.Formats = VBOX_SHCL_FMT_NONE; 122 122 123 123 return ShClSvcFormatsReport(pClient, &formatData); … … 161 161 RT_NOREF(pCmdCtx); 162 162 163 int rc = ClipAnnounceFormatToX11(pClient->State.pCtx->pBackend, pFormats-> uFormats);163 int rc = ClipAnnounceFormatToX11(pClient->State.pCtx->pBackend, pFormats->Formats); 164 164 165 165 LogFlowFuncLeaveRC(rc); … … 255 255 * 256 256 * @param pCtx Opaque context pointer for the glue code. 257 * @param u32FormatsThe formats available.258 */ 259 DECLCALLBACK(void) ClipReportX11FormatsCallback(PSHCLCONTEXT pCtx, uint32_t u32Formats)260 { 261 LogFlowFunc(("pCtx=%p, u32Formats=%02X\n", pCtx, u32Formats));262 263 if ( u32Formats == VBOX_SHCL_FMT_NONE) /* No formats to report? Bail out early. */257 * @param Formats The formats available. 258 */ 259 DECLCALLBACK(void) ClipReportX11FormatsCallback(PSHCLCONTEXT pCtx, uint32_t Formats) 260 { 261 LogFlowFunc(("pCtx=%p, Formats=%02X\n", pCtx, Formats)); 262 263 if (Formats == VBOX_SHCL_FMT_NONE) /* No formats to report? Bail out early. */ 264 264 return; 265 265 … … 267 267 RT_ZERO(formatData); 268 268 269 formatData. uFormats = u32Formats;269 formatData.Formats = Formats; 270 270 271 271 int rc = ShClSvcFormatsReport(pCtx->pClient, &formatData); … … 322 322 * 323 323 * @param pCtx Pointer to the host clipboard structure. 324 * @param u32Format The format in which the data should be transferred324 * @param Format The format in which the data should be transferred. 325 325 * @param ppv On success and if pcb > 0, this will point to a buffer 326 326 * to be freed with RTMemFree containing the data read. … … 328 328 * returned. 329 329 */ 330 DECLCALLBACK(int) ClipRequestDataForX11Callback(PSHCLCONTEXT pCtx, uint32_t u32Format, void **ppv, uint32_t *pcb)331 { 332 LogFlowFunc(("pCtx=%p, u32Format=%02X, ppv=%p\n", pCtx, u32Format, ppv));330 DECLCALLBACK(int) ClipRequestDataForX11Callback(PSHCLCONTEXT pCtx, SHCLFORMAT Format, void **ppv, uint32_t *pcb) 331 { 332 LogFlowFunc(("pCtx=%p, Format=0x%x\n", pCtx, Format)); 333 333 334 334 if (pCtx->fShuttingDown) … … 339 339 } 340 340 341 /* Request data from the guest. */ 342 SHCLDATAREQ dataReq; 343 RT_ZERO(dataReq); 344 345 dataReq.uFmt = u32Format; 346 dataReq.cbSize = _64K; /** @todo Make this more dynamic. */ 347 348 SHCLEVENTID uEvent; 349 int rc = ShClSvcDataReadRequest(pCtx->pClient, &dataReq, &uEvent); 350 if (RT_SUCCESS(rc)) 351 { 352 PSHCLEVENTPAYLOAD pPayload; 353 rc = ShClEventWait(&pCtx->pClient->Events, uEvent, 30 * 1000, &pPayload); 341 int rc; 342 343 #ifdef VBOX_WITH_SHARED_CLIPBOARD_TRANSFERS 344 if (Format == VBOX_SHCL_FMT_URI_LIST) 345 { 346 rc = 0; 347 } 348 else 349 #endif 350 { 351 /* Request data from the guest. */ 352 SHCLDATAREQ dataReq; 353 RT_ZERO(dataReq); 354 355 dataReq.uFmt = Format; 356 dataReq.cbSize = _64K; /** @todo Make this more dynamic. */ 357 358 SHCLEVENTID uEvent; 359 rc = ShClSvcDataReadRequest(pCtx->pClient, &dataReq, &uEvent); 354 360 if (RT_SUCCESS(rc)) 355 361 { 356 *ppv = pPayload->pvData; 357 *pcb = pPayload->cbData; 358 359 /* Detach the payload, as the caller then will own the data. */ 360 ShClEventPayloadDetach(&pCtx->pClient->Events, uEvent); 361 } 362 363 ShClEventUnregister(&pCtx->pClient->Events, uEvent); 362 PSHCLEVENTPAYLOAD pPayload; 363 rc = ShClEventWait(&pCtx->pClient->Events, uEvent, 30 * 1000, &pPayload); 364 if (RT_SUCCESS(rc)) 365 { 366 *ppv = pPayload->pvData; 367 *pcb = pPayload->cbData; 368 369 /* Detach the payload, as the caller then will own the data. */ 370 ShClEventPayloadDetach(&pCtx->pClient->Events, uEvent); 371 } 372 373 ShClEventUnregister(&pCtx->pClient->Events, uEvent); 374 } 364 375 } 365 376 -
trunk/src/VBox/HostServices/SharedClipboard/VBoxSharedClipboardSvc.cpp
r81824 r81843 1209 1209 HGCMSvcSetU64(&pMsg->paParms[0], VBOX_SHCL_CONTEXTID_MAKE(pClient->State.uSessionID, 1210 1210 pClient->Events.uID, uEvent)); 1211 HGCMSvcSetU32(&pMsg->paParms[1], pFormats-> uFormats);1211 HGCMSvcSetU32(&pMsg->paParms[1], pFormats->Formats); 1212 1212 HGCMSvcSetU32(&pMsg->paParms[2], 0 /* fFlags */); 1213 1213 … … 1218 1218 /* If this is an URI list, create a transfer locally and also tell the guest to create 1219 1219 * a transfer on the guest side. */ 1220 if (pFormats-> uFormats & VBOX_SHCL_FMT_URI_LIST)1220 if (pFormats->Formats & VBOX_SHCL_FMT_URI_LIST) 1221 1221 { 1222 1222 rc = shClSvcTransferStart(pClient, SHCLTRANSFERDIR_WRITE, SHCLSOURCE_LOCAL, … … 1354 1354 RT_ZERO(formatData); 1355 1355 1356 formatData. uFormats = g_ExtState.uDelayedFormats;1357 Assert(formatData. uFormats != VBOX_SHCL_FMT_NONE); /* There better is *any* format here now. */1356 formatData.Formats = g_ExtState.uDelayedFormats; 1357 Assert(formatData.Formats != VBOX_SHCL_FMT_NONE); /* There better is *any* format here now. */ 1358 1358 1359 1359 int rc2 = ShClSvcFormatsReport(pClient, &formatData); … … 1811 1811 RT_ZERO(formatData); 1812 1812 1813 formatData. uFormats = uFormats;1814 Assert(formatData. uFormats != VBOX_SHCL_FMT_NONE); /* Sanity. */1813 formatData.Formats = uFormats; 1814 Assert(formatData.Formats != VBOX_SHCL_FMT_NONE); /* Sanity. */ 1815 1815 1816 1816 rc = ShClSvcImplFormatAnnounce(pClient, &cmdCtx, &formatData); … … 2323 2323 RT_ZERO(formatData); 2324 2324 2325 formatData. uFormats = u32Format;2325 formatData.Formats = u32Format; 2326 2326 2327 2327 rc = ShClSvcFormatsReport(pClient, &formatData);
Note:
See TracChangeset
for help on using the changeset viewer.